Mesa (master): zink: create separate vk image/buffer objects for shader image use
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Mon Mar 29 02:27:05 UTC 2021
Module: Mesa
Branch: master
Commit: 69cdb6b776536822930e7a090961cae47ee4c067
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=69cdb6b776536822930e7a090961cae47ee4c067
Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date: Sat Dec 12 01:45:29 2020 -0500
zink: create separate vk image/buffer objects for shader image use
the STORAGE_TEXEL and STORAGE_IMAGE bits can't be accurately applied due
to opengl allowing all resources to be used everywhere, so instead we can
create a separate object on demand which is used only by shaders and gets
extra barriers inferred along with the base object to avoid desync whenever
it is used
Reviewed-by: Dave Airlie <airlied at redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9788>
---
src/gallium/drivers/zink/zink_context.c | 53 ++++++++++++++++++
src/gallium/drivers/zink/zink_context.h | 3 +
src/gallium/drivers/zink/zink_resource.c | 94 ++++++++++++++++++++++++++++----
src/gallium/drivers/zink/zink_resource.h | 6 ++
src/gallium/drivers/zink/zink_surface.c | 45 +++++++++++++++
src/gallium/drivers/zink/zink_surface.h | 5 ++
6 files changed, 196 insertions(+), 10 deletions(-)
diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c
index 2fbe9f65ed0..7d3fba19ae1 100644
--- a/src/gallium/drivers/zink/zink_context.c
+++ b/src/gallium/drivers/zink/zink_context.c
@@ -984,6 +984,10 @@ zink_set_shader_images(struct pipe_context *pctx,
if (images && images[i].resource) {
util_dynarray_init(&image_view->desc_set_refs.refs, NULL);
struct zink_resource *res = zink_resource(images[i].resource);
+ if (!zink_resource_object_init_storage(ctx, res)) {
+ debug_printf("couldn't create storage image!");
+ continue;
+ }
res->bind_history |= BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_IMAGE);
res->bind_stages |= 1 << p_stage;
util_copy_image_view(&image_view->base, images + i);
@@ -1055,6 +1059,12 @@ zink_set_sampler_views(struct pipe_context *pctx,
sampler_view_buffer_clear(ctx, b);
b->buffer_view = buffer_view;
}
+ } else if (!res->obj->is_buffer) {
+ if (res->obj != b->image_view->obj) {
+ struct pipe_surface *psurf = &b->image_view->base;
+ zink_rebind_surface(ctx, &psurf);
+ b->image_view = zink_surface(psurf);
+ }
}
res->bind_history |= BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW);
res->bind_stages |= 1 << shader_type;
@@ -1375,6 +1385,27 @@ zink_flush_queue(struct zink_context *ctx)
flush_batch(ctx);
}
+static bool
+rebind_fb_surface(struct zink_context *ctx, struct pipe_surface **surf, struct zink_resource *match_res)
+{
+ if (!*surf)
+ return false;
+ struct zink_resource *surf_res = zink_resource((*surf)->texture);
+ if ((match_res == surf_res) || surf_res->obj != zink_surface(*surf)->obj)
+ return zink_rebind_surface(ctx, surf);
+ return false;
+}
+
+static bool
+rebind_fb_state(struct zink_context *ctx, struct zink_resource *match_res)
+{
+ bool rebind = false;
+ for (int i = 0; i < ctx->fb_state.nr_cbufs; i++)
+ rebind |= rebind_fb_surface(ctx, &ctx->fb_state.cbufs[i], match_res);
+ rebind |= rebind_fb_surface(ctx, &ctx->fb_state.zsbuf, match_res);
+ return rebind;
+}
+
static void
zink_set_framebuffer_state(struct pipe_context *pctx,
const struct pipe_framebuffer_state *state)
@@ -1398,6 +1429,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx,
}
util_copy_framebuffer_state(&ctx->fb_state, state);
+ rebind_fb_state(ctx, NULL);
/* get_framebuffer adds a ref if the fb is reused or created;
* always do get_framebuffer first to avoid deleting the same fb
* we're about to use
@@ -1632,6 +1664,7 @@ zink_resource_image_barrier(struct zink_context *ctx, struct zink_batch *batch,
/* only barrier if we're changing layout or doing something besides read -> read */
batch = zink_batch_no_rp(ctx);
assert(!batch->in_rp);
+ assert(new_layout);
vkCmdPipelineBarrier(
batch->state->cmdbuf,
res->access_stage ? res->access_stage : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
@@ -2326,6 +2359,22 @@ zink_set_stream_output_targets(struct pipe_context *pctx,
}
}
+void
+zink_rebind_framebuffer(struct zink_context *ctx, struct zink_resource *res)
+{
+ if (!ctx->framebuffer)
+ return;
+ for (unsigned i = 0; i < ctx->framebuffer->state.num_attachments; i++) {
+ if (!ctx->framebuffer->surfaces[i] ||
+ zink_resource(ctx->framebuffer->surfaces[i]->texture) != res)
+ continue;
+ zink_rebind_surface(ctx, &ctx->framebuffer->surfaces[i]);
+ zink_batch_no_rp(ctx);
+ }
+ if (rebind_fb_state(ctx, res))
+ zink_batch_no_rp(ctx);
+}
+
void
zink_resource_rebind(struct zink_context *ctx, struct zink_resource *res)
{
@@ -2368,6 +2417,10 @@ zink_resource_rebind(struct zink_context *ctx, struct zink_resource *res)
struct zink_image_view *image_view = &ctx->image_views[shader][i];
zink_descriptor_set_refs_clear(&image_view->desc_set_refs, image_view);
zink_buffer_view_reference(zink_screen(ctx->base.screen), &image_view->buffer_view, NULL);
+ if (!zink_resource_object_init_storage(ctx, res)) {
+ debug_printf("couldn't create storage image!");
+ continue;
+ }
image_view->buffer_view = get_buffer_view(ctx, res, image_view->base.format,
image_view->base.u.buf.offset, image_view->base.u.buf.size);
assert(image_view->buffer_view);
diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h
index 81912b4263d..e2030a0aa33 100644
--- a/src/gallium/drivers/zink/zink_context.h
+++ b/src/gallium/drivers/zink/zink_context.h
@@ -323,6 +323,9 @@ zink_rect_from_box(const struct pipe_box *box)
void
zink_resource_rebind(struct zink_context *ctx, struct zink_resource *res);
+void
+zink_rebind_framebuffer(struct zink_context *ctx, struct zink_resource *res);
+
void
zink_draw_vbo(struct pipe_context *pctx,
const struct pipe_draw_info *dinfo,
diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c
index decab3bbe80..a2119813dd5 100644
--- a/src/gallium/drivers/zink/zink_resource.c
+++ b/src/gallium/drivers/zink/zink_resource.c
@@ -123,10 +123,13 @@ void
zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_object *obj)
{
assert(!obj->map_count);
- if (obj->is_buffer)
+ if (obj->is_buffer) {
+ if (obj->sbuffer)
+ vkDestroyBuffer(screen->dev, obj->sbuffer, NULL);
vkDestroyBuffer(screen->dev, obj->buffer, NULL);
- else
+ } else {
vkDestroyImage(screen->dev, obj->image, NULL);
+ }
zink_descriptor_set_refs_clear(&obj->desc_set_refs, obj);
cache_or_free_mem(screen, obj);
@@ -201,9 +204,6 @@ create_bci(struct zink_screen *screen, const struct pipe_resource *templ, unsign
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
- VkFormatProperties props = screen->format_props[templ->format];
- if (props.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)
- bci.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
}
if (bind & PIPE_BIND_VERTEX_BUFFER)
@@ -222,6 +222,9 @@ create_bci(struct zink_screen *screen, const struct pipe_resource *templ, unsign
if (bind & PIPE_BIND_SHADER_BUFFER)
bci.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ if (bind & PIPE_BIND_SHADER_IMAGE)
+ bci.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+
if (bind & PIPE_BIND_COMMAND_ARGS_BUFFER)
bci.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
@@ -294,12 +297,8 @@ create_ici(struct zink_screen *screen, const struct pipe_resource *templ, unsign
VK_IMAGE_USAGE_SAMPLED_BIT;
if ((templ->nr_samples <= 1 || screen->info.feats.features.shaderStorageImageMultisample) &&
- (bind & PIPE_BIND_SHADER_IMAGE ||
- (bind & PIPE_BIND_SAMPLER_VIEW && templ->flags & PIPE_RESOURCE_FLAG_TEXTURING_MORE_LIKELY))) {
+ (bind & PIPE_BIND_SHADER_IMAGE)) {
VkFormatProperties props = screen->format_props[templ->format];
- /* gallium doesn't provide any way to actually know whether this will be used as a shader image,
- * so we have to just assume and set the bit if it's available
- */
if ((ici.tiling == VK_IMAGE_TILING_LINEAR && props.linearTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) ||
(ici.tiling == VK_IMAGE_TILING_OPTIMAL && props.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
ici.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
@@ -929,6 +928,81 @@ zink_resource_get_separate_stencil(struct pipe_resource *pres)
}
+bool
+zink_resource_object_init_storage(struct zink_context *ctx, struct zink_resource *res)
+{
+ struct zink_screen *screen = zink_screen(ctx->base.screen);
+ /* base resource already has the cap */
+ if (res->base.bind & PIPE_BIND_SHADER_IMAGE)
+ return true;
+ if (res->obj->is_buffer) {
+ if (res->obj->sbuffer)
+ return true;
+ VkBufferCreateInfo bci = create_bci(screen, &res->base, res->base.bind | PIPE_BIND_SHADER_IMAGE);
+ VkBuffer buffer;
+ if (vkCreateBuffer(screen->dev, &bci, NULL, &buffer) != VK_SUCCESS)
+ return false;
+ vkBindBufferMemory(screen->dev, buffer, res->obj->mem, res->obj->offset);
+ res->obj->sbuffer = res->obj->buffer;
+ res->obj->buffer = buffer;
+ } else {
+ zink_fb_clears_apply_region(ctx, &res->base, (struct u_rect){0, res->base.width0, 0, res->base.height0});
+ zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 0);
+ res->base.bind |= PIPE_BIND_SHADER_IMAGE;
+ struct zink_resource_object *old_obj = res->obj;
+ struct zink_resource_object *new_obj = resource_object_create(screen, &res->base, NULL, &res->optimal_tiling);
+ if (!new_obj) {
+ debug_printf("new backing resource alloc failed!");
+ res->base.bind &= ~PIPE_BIND_SHADER_IMAGE;
+ return false;
+ }
+ struct zink_resource staging = *res;
+ staging.obj = old_obj;
+ res->obj = new_obj;
+ zink_descriptor_set_refs_clear(&old_obj->desc_set_refs, old_obj);
+ for (unsigned i = 0; i <= res->base.last_level; i++) {
+ struct pipe_box box = {0, 0, 0,
+ u_minify(res->base.width0, i),
+ u_minify(res->base.height0, i), res->base.array_size};
+ box.depth = util_num_layers(&res->base, i);
+ ctx->base.resource_copy_region(&ctx->base, &res->base, i, 0, 0, 0, &staging.base, i, &box);
+ }
+ zink_resource_object_reference(screen, &old_obj, NULL);
+ }
+
+ if (res->bind_history & BITFIELD64_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW)) {
+ for (unsigned shader = 0; shader < PIPE_SHADER_TYPES; shader++) {
+ if (res->bind_stages & (1 << shader)) {
+ for (unsigned i = 0; i < ZINK_DESCRIPTOR_TYPE_IMAGE; i++) {
+ if (res->bind_history & BITFIELD64_BIT(i))
+ zink_context_invalidate_descriptor_state(ctx, shader, i);
+ }
+ }
+ }
+ }
+ if (res->obj->is_buffer)
+ zink_resource_rebind(ctx, res);
+ else {
+ zink_rebind_framebuffer(ctx, res);
+ /* this will be cleaned up in future commits */
+ if (res->bind_history & BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW)) {
+ for (unsigned i = 0; i < PIPE_SHADER_TYPES; i++) {
+ for (unsigned j = 0; j < ctx->num_sampler_views[i]; j++) {
+ struct zink_sampler_view *sv = zink_sampler_view(ctx->sampler_views[i][j]);
+ if (sv && sv->base.texture == &res->base) {
+ struct pipe_surface *psurf = &sv->image_view->base;
+ zink_rebind_surface(ctx, &psurf);
+ sv->image_view = zink_surface(psurf);
+ zink_context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW);
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
void
zink_resource_setup_transfer_layouts(struct zink_context *ctx, struct zink_resource *src, struct zink_resource *dst)
{
diff --git a/src/gallium/drivers/zink/zink_resource.h b/src/gallium/drivers/zink/zink_resource.h
index a8658e4d2fa..920a2537f05 100644
--- a/src/gallium/drivers/zink/zink_resource.h
+++ b/src/gallium/drivers/zink/zink_resource.h
@@ -57,6 +57,10 @@ struct zink_resource_object {
VkBuffer buffer;
VkImage image;
};
+
+ VkBuffer sbuffer;
+ bool storage_init; //layout was set for image
+
VkDeviceMemory mem;
uint32_t mem_hash;
struct mem_key mkey;
@@ -154,4 +158,6 @@ zink_resource_object_reference(struct zink_screen *screen,
if (dst) *dst = src;
}
+bool
+zink_resource_object_init_storage(struct zink_context *ctx, struct zink_resource *res);
#endif
diff --git a/src/gallium/drivers/zink/zink_surface.c b/src/gallium/drivers/zink/zink_surface.c
index 2f57285e221..798911ea437 100644
--- a/src/gallium/drivers/zink/zink_surface.c
+++ b/src/gallium/drivers/zink/zink_surface.c
@@ -116,6 +116,7 @@ create_surface(struct pipe_context *pctx,
surface->base.u.tex.level = level;
surface->base.u.tex.first_layer = templ->u.tex.first_layer;
surface->base.u.tex.last_layer = templ->u.tex.last_layer;
+ surface->obj = zink_resource(pres)->obj;
util_dynarray_init(&surface->framebuffer_refs, NULL);
if (vkCreateImageView(screen->dev, ivci, NULL,
@@ -218,11 +219,14 @@ zink_destroy_surface(struct zink_screen *screen, struct pipe_surface *psurface)
simple_mtx_lock(&screen->surface_mtx);
struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);
assert(he);
+ assert(he->data == surface);
_mesa_hash_table_remove(&screen->surface_cache, he);
simple_mtx_unlock(&screen->surface_mtx);
surface_clear_fb_refs(screen, psurface);
util_dynarray_fini(&surface->framebuffer_refs);
pipe_resource_reference(&psurface->texture, NULL);
+ if (surface->simage_view)
+ vkDestroyImageView(screen->dev, surface->simage_view, NULL);
vkDestroyImageView(screen->dev, surface->image_view, NULL);
FREE(surface);
}
@@ -234,6 +238,47 @@ zink_surface_destroy(struct pipe_context *pctx,
zink_destroy_surface(zink_screen(pctx->screen), psurface);
}
+bool
+zink_rebind_surface(struct zink_context *ctx, struct pipe_surface **psurface)
+{
+ struct zink_surface *surface = zink_surface(*psurface);
+ struct zink_screen *screen = zink_screen(ctx->base.screen);
+ if (surface->simage_view)
+ return false;
+ VkImageViewCreateInfo ivci = create_ivci(screen,
+ zink_resource((*psurface)->texture), (*psurface));
+ uint32_t hash = hash_ivci(&ivci);
+
+ simple_mtx_lock(&screen->surface_mtx);
+ struct hash_entry *new_entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, hash, &ivci);
+ surface_clear_fb_refs(screen, *psurface);
+ if (new_entry) {
+ /* reuse existing surface; old one will be cleaned up naturally */
+ struct zink_surface *new_surface = new_entry->data;
+ simple_mtx_unlock(&screen->surface_mtx);
+ zink_surface_reference(screen, (struct zink_surface**)psurface, new_surface);
+ return true;
+ }
+ struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);
+ assert(entry);
+ _mesa_hash_table_remove(&screen->surface_cache, entry);
+ VkImageView image_view;
+ if (vkCreateImageView(screen->dev, &ivci, NULL, &image_view) != VK_SUCCESS) {
+ debug_printf("zink: failed to create new imageview");
+ simple_mtx_unlock(&screen->surface_mtx);
+ return false;
+ }
+ surface->hash = hash;
+ surface->ivci = ivci;
+ entry = _mesa_hash_table_insert_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci, surface);
+ assert(entry);
+ surface->simage_view = surface->image_view;
+ surface->image_view = image_view;
+ surface->obj = zink_resource(surface->base.texture)->obj;
+ simple_mtx_unlock(&screen->surface_mtx);
+ return true;
+}
+
void
zink_context_surface_init(struct pipe_context *context)
{
diff --git a/src/gallium/drivers/zink/zink_surface.h b/src/gallium/drivers/zink/zink_surface.h
index 6a88a10350f..c8931ca32fe 100644
--- a/src/gallium/drivers/zink/zink_surface.h
+++ b/src/gallium/drivers/zink/zink_surface.h
@@ -34,6 +34,8 @@ struct zink_surface {
struct pipe_surface base;
VkImageViewCreateInfo ivci;
VkImageView image_view;
+ VkImageView simage_view;//old iview after storage replacement/rebind
+ void *obj; //backing resource object
uint32_t hash;
struct zink_batch_usage batch_uses;
struct util_dynarray framebuffer_refs;
@@ -93,4 +95,7 @@ zink_surface_clamp_viewtype(VkImageViewType viewType, unsigned first_layer, unsi
}
return viewType;
}
+
+bool
+zink_rebind_surface(struct zink_context *ctx, struct pipe_surface **psurface);
#endif
More information about the mesa-commit
mailing list