zink: use smaller keys for surface/bufferview caching and switch to sets

this should be a bit more efficient

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35722>
This commit is contained in:
Mike Blumenkrantz 2025-06-24 10:56:05 -04:00
parent 9ac256645e
commit 5cfaa6cd5f
8 changed files with 165 additions and 85 deletions

View file

@ -947,10 +947,9 @@ sampler_aspect_from_format(enum pipe_format fmt)
}
static uint32_t
hash_bufferview(void *bvci)
hash_bufferview_key(void *key)
{
size_t offset = offsetof(VkBufferViewCreateInfo, flags);
return _mesa_hash_data((char*)bvci + offset, sizeof(VkBufferViewCreateInfo) - offset);
return _mesa_hash_data(key, sizeof(struct zink_bufferview_key));
}
static VkBufferViewCreateInfo
@ -990,30 +989,37 @@ get_buffer_view(struct zink_context *ctx, struct zink_resource *res, enum pipe_f
{
struct zink_screen *screen = zink_screen(ctx->base.screen);
struct zink_buffer_view *buffer_view = NULL;
struct zink_bufferview_key key = {
format,
offset,
size
};
VkBufferViewCreateInfo bvci = create_bvci(ctx, res, format, offset, size);
uint32_t hash = hash_bufferview(&bvci);
uint32_t hash = hash_bufferview_key(&key);
simple_mtx_lock(&res->obj->surface_mtx);
struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&res->obj->surface_cache, hash, &bvci);
if (he) {
buffer_view = he->data;
bool found = false;
struct set_entry *he = _mesa_set_search_or_add_pre_hashed(&res->obj->surface_cache, hash, &key, &found);
if (found) {
buffer_view = (void*)he->key;
} else {
VkBufferView view;
VkResult result = VKSCR(CreateBufferView)(screen->dev, &bvci, NULL, &view);
if (result != VK_SUCCESS) {
_mesa_set_remove(&res->obj->surface_cache, he);
mesa_loge("ZINK: vkCreateBufferView failed (%s)", vk_Result_to_str(result));
goto out;
}
buffer_view = CALLOC_STRUCT(zink_buffer_view);
if (!buffer_view) {
_mesa_set_remove(&res->obj->surface_cache, he);
VKSCR(DestroyBufferView)(screen->dev, view, NULL);
goto out;
}
buffer_view->pres = &res->base.b;
buffer_view->bvci = bvci;
buffer_view->key = key;
buffer_view->buffer_view = view;
buffer_view->hash = hash;
_mesa_hash_table_insert_pre_hashed(&res->obj->surface_cache, hash, &buffer_view->bvci, buffer_view);
he->key = buffer_view;
}
out:
simple_mtx_unlock(&res->obj->surface_mtx);

View file

@ -370,7 +370,7 @@ kopper_GetSwapchainImages(struct zink_screen *screen, struct kopper_swapchain *c
if (zink_screen_handle_vkresult(screen, error)) {
for (unsigned i = 0; i < cswap->num_images; i++) {
cswap->images[i].image = images[i];
_mesa_hash_table_init(&cswap->images[i].surface_cache, NULL, NULL, equals_ivci);
_mesa_set_init(&cswap->images[i].surface_cache, NULL, NULL, equals_surface_key);
}
}
cswap->max_acquires = cswap->num_images - cswap->scci.minImageCount + 1;

View file

@ -29,7 +29,7 @@
#include "kopper_interface.h"
#include "util/u_queue.h"
#include "util/hash_table.h"
#include "util/set.h"
#ifdef __cplusplus
extern "C" {
@ -51,7 +51,7 @@ struct kopper_swapchain_image {
VkSemaphore acquire;
VkImageLayout layout;
struct hash_table surface_cache;
struct set surface_cache;
};
struct kopper_swapchain {

View file

@ -180,12 +180,9 @@ image_hic_transition(struct zink_screen *screen, struct zink_resource *res, VkIm
}
static bool
equals_bvci(const void *a, const void *b)
equals_bufferview_key(const void *a, const void *b)
{
const uint8_t *pa = a;
const uint8_t *pb = b;
size_t offset = offsetof(VkBufferViewCreateInfo, flags);
return memcmp(pa + offset, pb + offset, sizeof(VkBufferViewCreateInfo) - offset) == 0;
return memcmp(a, b, sizeof(struct zink_bufferview_key)) == 0;
}
static void
@ -200,20 +197,19 @@ debug_describe_zink_resource_object(char *buf, const struct zink_resource_object
}
void
zink_destroy_resource_surface_cache(struct zink_screen *screen, struct hash_table *ht, bool is_buffer)
zink_destroy_resource_surface_cache(struct zink_screen *screen, struct set *ht, bool is_buffer)
{
if (is_buffer) {
hash_table_foreach_remove(ht, he) {
struct zink_buffer_view *bv = he->data;
set_foreach_remove(ht, he) {
struct zink_buffer_view *bv = (void*)he->key;
VKSCR(DestroyBufferView)(screen->dev, bv->buffer_view, NULL);
FREE(bv);
}
ralloc_free(ht->table);
} else {
hash_table_foreach_remove(ht, he) {
struct zink_surface *surf = he->data;
set_foreach_remove(ht, he) {
struct zink_surface *surf = (void*)he->key;
VKSCR(DestroyImageView)(screen->dev, surf->image_view, NULL);
free((void*)he->key);
FREE(surf);
}
ralloc_free(ht->table);
@ -1250,7 +1246,7 @@ create_buffer(struct zink_screen *screen, struct zink_resource_object *obj,
return roc_fail_and_cleanup_all;
}
}
_mesa_hash_table_init(&obj->surface_cache, NULL, NULL, equals_bvci);
_mesa_set_init(&obj->surface_cache, NULL, NULL, equals_bufferview_key);
return roc_success;
}
@ -1482,7 +1478,7 @@ create_image(struct zink_screen *screen, struct zink_resource_object *obj,
return roc_fail_and_cleanup_all;
}
}
_mesa_hash_table_init(&obj->surface_cache, NULL, NULL, equals_ivci);
_mesa_set_init(&obj->surface_cache, NULL, NULL, equals_surface_key);
return roc_success;
}

View file

@ -203,7 +203,7 @@ zink_resource_reference(struct zink_resource **d, struct zink_resource *s)
}
void
zink_destroy_resource_surface_cache(struct zink_screen *screen, struct hash_table *ht, bool is_buffer);
zink_destroy_resource_surface_cache(struct zink_screen *screen, struct set *ht, bool is_buffer);
#ifdef __cplusplus
}

View file

@ -32,6 +32,38 @@
#include "util/u_inlines.h"
#include "util/u_memory.h"
static VkImageViewType
vkviewtype_from_pipe(enum pipe_texture_target target, bool need_2D)
{
switch (target) {
case PIPE_TEXTURE_1D:
return need_2D ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_1D;
case PIPE_TEXTURE_1D_ARRAY:
return need_2D ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_1D_ARRAY;
case PIPE_TEXTURE_2D:
case PIPE_TEXTURE_RECT:
return VK_IMAGE_VIEW_TYPE_2D;
case PIPE_TEXTURE_2D_ARRAY:
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
case PIPE_TEXTURE_CUBE:
return VK_IMAGE_VIEW_TYPE_CUBE;
case PIPE_TEXTURE_CUBE_ARRAY:
return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
break;
case PIPE_TEXTURE_3D:
return VK_IMAGE_VIEW_TYPE_3D;
default:
unreachable("unsupported target");
}
}
VkImageViewCreateInfo
create_ivci(struct zink_screen *screen,
struct zink_resource *res,
@ -43,41 +75,7 @@ create_ivci(struct zink_screen *screen,
memset(&ivci, 0, sizeof(VkImageViewCreateInfo));
ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
ivci.image = res->obj->image;
switch (target) {
case PIPE_TEXTURE_1D:
ivci.viewType = res->need_2D ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_1D;
break;
case PIPE_TEXTURE_1D_ARRAY:
ivci.viewType = res->need_2D ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_1D_ARRAY;
break;
case PIPE_TEXTURE_2D:
case PIPE_TEXTURE_RECT:
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
break;
case PIPE_TEXTURE_2D_ARRAY:
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
break;
case PIPE_TEXTURE_CUBE:
ivci.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
break;
case PIPE_TEXTURE_CUBE_ARRAY:
ivci.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
break;
case PIPE_TEXTURE_3D:
ivci.viewType = VK_IMAGE_VIEW_TYPE_3D;
break;
default:
unreachable("unsupported target");
}
ivci.viewType = vkviewtype_from_pipe(target, res->need_2D);
ivci.format = res->base.b.format == PIPE_FORMAT_A8_UNORM ? res->format : zink_get_format(screen, templ->format);
assert(ivci.format != VK_FORMAT_UNDEFINED);
@ -136,7 +134,7 @@ apply_view_usage_for_format(struct zink_screen *screen, struct pipe_resource *pr
static struct zink_surface *
create_surface(struct pipe_context *pctx,
struct pipe_resource *pres,
const struct pipe_surface *templ,
const struct zink_surface_key *templ,
VkImageViewCreateInfo *ivci)
{
struct zink_screen *screen = zink_screen(pctx->screen);
@ -155,17 +153,18 @@ create_surface(struct pipe_context *pctx,
FREE(surface);
return NULL;
}
surface->key = *templ;
return surface;
}
static uint32_t
hash_ivci(const void *key)
hash_key(const void *key)
{
return _mesa_hash_data((char*)key + offsetof(VkImageViewCreateInfo, flags), sizeof(VkImageViewCreateInfo) - offsetof(VkImageViewCreateInfo, flags));
return _mesa_hash_data(key, sizeof(struct zink_surface_key));
}
static struct hash_table *
static struct set *
get_surface_cache(struct zink_resource *res)
{
struct kopper_displaytarget *cdt = res->obj->dt;
@ -173,6 +172,59 @@ get_surface_cache(struct zink_resource *res)
return res->obj->dt ? &cdt->swapchain->images[res->obj->dt_idx].surface_cache : &res->obj->surface_cache;
}
static unsigned
componentmapping_to_pipe(VkComponentSwizzle c)
{
switch (c) {
case VK_COMPONENT_SWIZZLE_ZERO:
return PIPE_SWIZZLE_0;
case VK_COMPONENT_SWIZZLE_ONE:
return PIPE_SWIZZLE_1;
case VK_COMPONENT_SWIZZLE_R:
return PIPE_SWIZZLE_X;
case VK_COMPONENT_SWIZZLE_G:
return PIPE_SWIZZLE_Y;
case VK_COMPONENT_SWIZZLE_B:
return PIPE_SWIZZLE_Z;
case VK_COMPONENT_SWIZZLE_A:
return PIPE_SWIZZLE_W;
default:
unreachable("unknown swizzle");
}
}
static struct zink_surface_key
templ_to_key(const struct pipe_surface *templ, const VkImageViewCreateInfo *ivci)
{
VkImageViewType baseviewtype = vkviewtype_from_pipe(templ->texture->target, zink_resource(templ->texture)->need_2D);
enum zink_surface_type type = ZINK_SURFACE_NORMAL;
if (baseviewtype != ivci->viewType) {
switch (ivci->viewType) {
case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
type = ZINK_SURFACE_ARRAYED;
break;
default:
type = ZINK_SURFACE_LAYERED;
break;
}
}
struct zink_surface_key key = {
.format = templ->format,
.viewtype = type,
.stencil = ivci->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT,
.swizzle_r = componentmapping_to_pipe(ivci->components.r),
.swizzle_g = componentmapping_to_pipe(ivci->components.g),
.swizzle_b = componentmapping_to_pipe(ivci->components.b),
.swizzle_a = componentmapping_to_pipe(ivci->components.a),
.first_level = ivci->subresourceRange.baseMipLevel,
.level_count = ivci->subresourceRange.levelCount,
.first_layer = templ->first_layer,
.last_layer = templ->last_layer,
};
return key;
}
/* get a cached surface for a shader descriptor */
struct zink_surface *
zink_get_surface(struct zink_context *ctx,
@ -190,23 +242,24 @@ zink_get_surface(struct zink_context *ctx,
zink_resource_object_init_mutable(ctx, res);
/* reset for mutable obj switch */
ivci->image = res->obj->image;
uint32_t hash = hash_ivci(ivci);
struct zink_surface_key key = templ_to_key(templ, ivci);
uint32_t hash = hash_key(&key);
simple_mtx_lock(&res->obj->surface_mtx);
struct hash_table *ht = get_surface_cache(res);
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ht, hash, ivci);
struct set *ht = get_surface_cache(res);
bool found = false;
struct set_entry *entry = _mesa_set_search_or_add_pre_hashed(ht, hash, &key, &found);
if (!entry) {
surface = create_surface(&ctx->base, &res->base.b, templ, ivci);
entry = _mesa_hash_table_insert_pre_hashed(ht, hash, mem_dup(ivci, sizeof(*ivci)), surface);
if (!entry) {
if (!found) {
surface = create_surface(&ctx->base, &res->base.b, &key, ivci);
if (!surface) {
_mesa_set_remove(ht, entry);
simple_mtx_unlock(&res->obj->surface_mtx);
return NULL;
}
surface = entry->data;
entry->key = surface;
} else {
surface = entry->data;
surface = (void*)entry->key;
}
simple_mtx_unlock(&res->obj->surface_mtx);

View file

@ -27,12 +27,9 @@
#include "zink_types.h"
static inline bool
equals_ivci(const void *a, const void *b)
equals_surface_key(const void *a, const void *b)
{
const uint8_t *pa = a;
const uint8_t *pb = b;
size_t offset = offsetof(VkImageViewCreateInfo, flags);
return memcmp(pa + offset, pb + offset, sizeof(VkImageViewCreateInfo) - offset) == 0;
return memcmp(a, b, sizeof(struct zink_surface_key)) == 0;
}
VkImageViewCreateInfo

View file

@ -1199,7 +1199,7 @@ struct zink_resource_object {
};
VkDeviceAddress bda;
struct hash_table surface_cache;
struct set surface_cache;
simple_mtx_t surface_mtx;
VkSampleLocationsInfoEXT zs_evaluate;
@ -1519,9 +1519,32 @@ zink_screen(struct pipe_screen *pipe)
}
/** surface types */
enum zink_surface_type {
ZINK_SURFACE_NORMAL,
ZINK_SURFACE_LAYERED,
ZINK_SURFACE_ARRAYED,
};
/* compact hash table key based on pipe_surface */
struct zink_surface_key {
enum pipe_format format:12; /**< typed PIPE_FORMAT_x */
unsigned swizzle_r:3; /**< PIPE_SWIZZLE_x for red component */
unsigned swizzle_g:3; /**< PIPE_SWIZZLE_x for green component */
unsigned swizzle_b:3; /**< PIPE_SWIZZLE_x for blue component */
unsigned swizzle_a:3; /**< PIPE_SWIZZLE_x for alpha component */
unsigned first_level:4; /**< first mipmap level to use */
unsigned level_count:4;
enum zink_surface_type viewtype:2; /**< layered view of an array/3d iamge */
unsigned stencil:1; /**< stencil-only view */
unsigned pad:29;
unsigned first_layer:16; /**< first layer to use for array textures */
unsigned last_layer:16; /**< last layer to use for array textures */
};
/* this type only exists for compat with 32bit builds because vk types are 64bit */
struct zink_surface {
struct zink_surface_key key;
VkImageView image_view;
};
@ -1534,11 +1557,16 @@ struct zink_sampler_state {
bool emulate_nonseamless;
};
struct zink_bufferview_key {
enum pipe_format format:12;
unsigned offset;
unsigned size;
};
struct zink_buffer_view {
struct pipe_resource *pres;
VkBufferViewCreateInfo bvci;
struct zink_bufferview_key key;
VkBufferView buffer_view;
uint32_t hash;
};
struct zink_sampler_view {