From: Mike Blumenkrantz Date: Sat, 12 Dec 2020 06:45:29 +0000 (-0500) Subject: zink: create separate vk image/buffer objects for shader image use X-Git-Tag: upstream/21.2.3~5813 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=69cdb6b776536822930e7a090961cae47ee4c067;p=platform%2Fupstream%2Fmesa.git 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 Part-of: --- diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 2fbe9f6..7d3fba1 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, @@ -2327,6 +2360,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) { assert(res->base.target == PIPE_BUFFER); @@ -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 81912b4..e2030a0 100644 --- a/src/gallium/drivers/zink/zink_context.h +++ b/src/gallium/drivers/zink/zink_context.h @@ -324,6 +324,9 @@ 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, const struct pipe_draw_indirect_info *indirect, diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c index decab3b..a211981 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 a8658e4..920a253 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 2f57285..798911e 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 6a88a10..c8931ca 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