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>
diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c
index a24184c..cac9fac 100644
--- a/src/gallium/drivers/zink/zink_context.c
+++ b/src/gallium/drivers/zink/zink_context.c
@@ -947,10 +947,9 @@
}
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 @@
{
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);
diff --git a/src/gallium/drivers/zink/zink_kopper.c b/src/gallium/drivers/zink/zink_kopper.c
index 5bd44ae..3523382 100644
--- a/src/gallium/drivers/zink/zink_kopper.c
+++ b/src/gallium/drivers/zink/zink_kopper.c
@@ -370,7 +370,7 @@
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;
diff --git a/src/gallium/drivers/zink/zink_kopper.h b/src/gallium/drivers/zink/zink_kopper.h
index 9e52f51..fba05a0 100644
--- a/src/gallium/drivers/zink/zink_kopper.h
+++ b/src/gallium/drivers/zink/zink_kopper.h
@@ -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 @@
VkSemaphore acquire;
VkImageLayout layout;
- struct hash_table surface_cache;
+ struct set surface_cache;
};
struct kopper_swapchain {
diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c
index 47436c6..70d5463 100644
--- a/src/gallium/drivers/zink/zink_resource.c
+++ b/src/gallium/drivers/zink/zink_resource.c
@@ -180,12 +180,9 @@
}
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 @@
}
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 @@
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 @@
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;
}
diff --git a/src/gallium/drivers/zink/zink_resource.h b/src/gallium/drivers/zink/zink_resource.h
index 3001ff2..157e7a1 100644
--- a/src/gallium/drivers/zink/zink_resource.h
+++ b/src/gallium/drivers/zink/zink_resource.h
@@ -203,7 +203,7 @@
}
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
}
diff --git a/src/gallium/drivers/zink/zink_surface.c b/src/gallium/drivers/zink/zink_surface.c
index bf4334f..c45d278 100644
--- a/src/gallium/drivers/zink/zink_surface.c
+++ b/src/gallium/drivers/zink/zink_surface.c
@@ -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 @@
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 @@
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 @@
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 @@
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_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);
diff --git a/src/gallium/drivers/zink/zink_surface.h b/src/gallium/drivers/zink/zink_surface.h
index 65d1c36..a6c90ef 100644
--- a/src/gallium/drivers/zink/zink_surface.h
+++ b/src/gallium/drivers/zink/zink_surface.h
@@ -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
diff --git a/src/gallium/drivers/zink/zink_types.h b/src/gallium/drivers/zink/zink_types.h
index e5bdea9..6302f76 100644
--- a/src/gallium/drivers/zink/zink_types.h
+++ b/src/gallium/drivers/zink/zink_types.h
@@ -1199,7 +1199,7 @@
};
VkDeviceAddress bda;
- struct hash_table surface_cache;
+ struct set surface_cache;
simple_mtx_t surface_mtx;
VkSampleLocationsInfoEXT zs_evaluate;
@@ -1519,9 +1519,32 @@
}
/** 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 @@
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 {