From a71b6ac41a190aa2d58dcf0770c040efe98dcf85 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Fri, 1 Aug 2025 13:18:58 -0400 Subject: [PATCH] tc: also inline depth resolves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this catches the case where an app resolves both color and depth buffers previously the inlining would only catch the first color buffer, then the depth resolve which followed would cause the whole of rp tracking to desync and explode, as seen in Transport Fever 2 Fixes: 8933b3ed399 ("tc: add resolve resource to rp info") Acked-by: Marek Olšák Part-of: --- .../auxiliary/util/u_threaded_context.c | 42 ++++++---- .../auxiliary/util/u_threaded_context.h | 2 +- src/gallium/drivers/zink/zink_blit.c | 3 +- src/gallium/drivers/zink/zink_context.c | 78 ++++++++++--------- 4 files changed, 71 insertions(+), 54 deletions(-) diff --git a/src/gallium/auxiliary/util/u_threaded_context.c b/src/gallium/auxiliary/util/u_threaded_context.c index 497ee5d652a..3b8227bb170 100644 --- a/src/gallium/auxiliary/util/u_threaded_context.c +++ b/src/gallium/auxiliary/util/u_threaded_context.c @@ -232,21 +232,23 @@ tc_batch_increment_renderpass_info(struct threaded_context *tc, unsigned batch_i /* copy the previous data in its entirety: this is still the same renderpass */ if (tc->renderpass_info_recording) { tc_info[batch->renderpass_info_idx].info.data = tc->renderpass_info_recording->data; - tc_info[batch->renderpass_info_idx].info.resolve = tc->renderpass_info_recording->resolve; - tc->renderpass_info_recording->resolve = NULL; + memcpy(tc_info[batch->renderpass_info_idx].info.resolve, tc->renderpass_info_recording->resolve, sizeof(tc->renderpass_info_recording->resolve)); + memset(tc->renderpass_info_recording->resolve, 0, sizeof(tc->renderpass_info_recording->resolve)); tc_batch_rp_info(tc->renderpass_info_recording)->next = &tc_info[batch->renderpass_info_idx]; tc_info[batch->renderpass_info_idx].prev = tc_batch_rp_info(tc->renderpass_info_recording); /* guard against deadlock scenario */ assert(&tc_batch_rp_info(tc->renderpass_info_recording)->next->info != tc->renderpass_info_recording); } else { tc_info[batch->renderpass_info_idx].info.data = 0; - pipe_resource_reference(&tc_info[batch->renderpass_info_idx].info.resolve, NULL); + for (unsigned i = 0; i < ARRAY_SIZE(tc_info[batch->renderpass_info_idx].info.resolve); i++) + pipe_resource_reference(&tc_info[batch->renderpass_info_idx].info.resolve[i], NULL); tc_info[batch->renderpass_info_idx].prev = NULL; } } else { /* selectively copy: only the CSO metadata is copied, and a new framebuffer state will be added later */ tc_info[batch->renderpass_info_idx].info.data = 0; - pipe_resource_reference(&tc_info[batch->renderpass_info_idx].info.resolve, NULL); + for (unsigned i = 0; i < ARRAY_SIZE(tc_info[batch->renderpass_info_idx].info.resolve); i++) + pipe_resource_reference(&tc_info[batch->renderpass_info_idx].info.resolve[i], NULL); if (tc->renderpass_info_recording) { tc_info[batch->renderpass_info_idx].info.data16[2] = tc->renderpass_info_recording->data16[2]; tc_batch_rp_info(tc->renderpass_info_recording)->next = NULL; @@ -1513,7 +1515,8 @@ tc_set_framebuffer_state(struct pipe_context *_pipe, tc->batch_slots[tc->next].renderpass_info_idx = 0; tc->renderpass_info_recording->has_resolve = false; } - assert(!tc->renderpass_info_recording->resolve); + assert(!tc->renderpass_info_recording->resolve[0] && + !tc->renderpass_info_recording->resolve[1]); tc->seen_fb_state = true; } /* ref for cmd */ @@ -4579,11 +4582,11 @@ tc_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info) info->src.box.width != info->dst.box.width || info->src.box.height != info->dst.box.height || info->src.box.depth != info->dst.box.depth || + !tc->in_renderpass || #if TC_RESOLVE_STRICT info->src.box.width != tc->fb_width || info->src.box.height != tc->fb_height || #endif - tc->renderpass_info_recording->ended || (info->dst.resource->array_size && info->dst.resource->array_size != tc->fb_layers) || (!tc->renderpass_info_recording->has_draw && !tc->renderpass_info_recording->cbuf_clear && !tc->renderpass_info_recording->zsbuf_clear)) { if (tc->options.parse_renderpass_info && tc->in_renderpass) @@ -4592,7 +4595,9 @@ tc_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info) return; } - struct pipe_resource *src = tc->nr_cbufs ? tc->fb_resources[0] : tc->fb_resources[PIPE_MAX_COLOR_BUFS]; + bool is_depth = util_format_is_depth_or_stencil(info->src.format); + struct pipe_resource *src = !is_depth ? tc->fb_resources[0] : tc->fb_resources[PIPE_MAX_COLOR_BUFS]; + bool is_resolve = false; if (tc->fb_resolve == info->dst.resource) { #if TC_DEBUG >= 3 tc_printf("WSI RESOLVE MERGE"); @@ -4600,24 +4605,29 @@ tc_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info) /* optimize out this blit entirely */ tc->renderpass_info_recording->has_resolve = true; tc->renderpass_info_recording->ended = true; - tc_signal_renderpass_info_ready(tc); - } else if (src == info->src.resource && - (!tc->renderpass_info_recording->has_resolve || - tc->renderpass_info_recording->resolve == info->dst.resource)) { + is_resolve = true; + } else if (src == info->src.resource) { #if TC_DEBUG >= 3 tc_printf("RESOLVE MERGE"); #endif - /* can only optimize out the first resolve */ - tc->renderpass_info_recording->has_resolve = true; - pipe_resource_reference(&tc->renderpass_info_recording->resolve, info->dst.resource); + /* only optimizing out one depth and one color resolve */ + assert(!tc->renderpass_info_recording->resolve[is_depth] || tc->renderpass_info_recording->resolve[is_depth] == info->dst.resource); + pipe_resource_reference(&tc->renderpass_info_recording->resolve[is_depth], info->dst.resource); tc_set_resource_batch_usage(tc, info->dst.resource); + if (tc->renderpass_info_recording->has_resolve) { + assert(tc->renderpass_info_recording->ended); + /* driver will already expect a rp-terminating resolve, don't send a second one */ + return; + } + tc->renderpass_info_recording->has_resolve = true; tc->renderpass_info_recording->ended = true; - tc_signal_renderpass_info_ready(tc); + is_resolve = true; } else if (tc->in_renderpass) { tc_check_fb_access(tc, info->src.resource, info->dst.resource); } struct tc_blit_call *blit = tc_blit_enqueue(tc, info); - blit->base.call_id = TC_CALL_resolve; + if (is_resolve) + blit->base.call_id = TC_CALL_resolve; } struct tc_generate_mipmap { diff --git a/src/gallium/auxiliary/util/u_threaded_context.h b/src/gallium/auxiliary/util/u_threaded_context.h index 932967a85f7..4cad69edea4 100644 --- a/src/gallium/auxiliary/util/u_threaded_context.h +++ b/src/gallium/auxiliary/util/u_threaded_context.h @@ -476,7 +476,7 @@ struct tc_renderpass_info { uint8_t data8[8]; }; /* only valid if has_resolve is true and the resolve member of pipe_framebuffer_state is NULL */ - struct pipe_resource *resolve; + struct pipe_resource *resolve[2]; //[color, depth] }; static inline bool diff --git a/src/gallium/drivers/zink/zink_blit.c b/src/gallium/drivers/zink/zink_blit.c index 7c519ab3942..b2970d4c9a9 100644 --- a/src/gallium/drivers/zink/zink_blit.c +++ b/src/gallium/drivers/zink/zink_blit.c @@ -348,9 +348,10 @@ zink_blit(struct pipe_context *pctx, bool needs_present_readback = false; if (ctx->awaiting_resolve && ctx->in_rp && ctx->dynamic_fb.tc_info.has_resolve) { + bool is_depth = util_format_is_depth_or_stencil(info->src.format); struct pipe_resource *resolve = ctx->fb_state.resolve; if (!resolve) - resolve = ctx->dynamic_fb.tc_info.resolve; + resolve = ctx->dynamic_fb.tc_info.resolve[is_depth]; if (resolve == info->dst.resource) { zink_batch_no_rp_safe(ctx); ctx->awaiting_resolve = false; diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 6331e9a1fe8..6bc248a84a7 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -71,8 +71,7 @@ update_tc_info(struct zink_context *ctx) if (ctx->track_renderpasses) { const struct tc_renderpass_info *info = threaded_context_get_renderpass_info(ctx->tc); ctx->rp_changed |= ctx->dynamic_fb.tc_info.data != info->data; - ctx->dynamic_fb.tc_info.data = info->data; - ctx->dynamic_fb.tc_info.resolve = info->resolve; + ctx->dynamic_fb.tc_info = *info; ctx->awaiting_resolve = ctx->dynamic_fb.tc_info.has_resolve; } else { struct tc_renderpass_info info = ctx->dynamic_fb.tc_info; @@ -3163,41 +3162,48 @@ begin_rendering(struct zink_context *ctx, bool check_msaa_expand) } } if (use_tc_info && ctx->dynamic_fb.tc_info.has_resolve) { - struct zink_resource *res = zink_resource(ctx->fb_state.resolve); - if (!res) - res = zink_resource(ctx->dynamic_fb.tc_info.resolve); - assert(res); - zink_batch_resource_usage_set(ctx->bs, res, true, false); - bool is_depth = util_format_is_depth_or_stencil(res->base.b.format); - enum pipe_format format = res->base.b.format; - if (!ctx->fb_state.resolve) - format = is_depth ? ctx->fb_state.zsbuf.format : ctx->fb_state.cbufs[0].format; - if (zink_format_needs_mutable(res->base.b.format, format)) - /* mutable not set by default */ - zink_resource_object_init_mutable(ctx, res); - struct pipe_surface tmpl = { - .format = format, - .texture = &res->base.b + struct zink_resource *resolves[3] = { + zink_resource(ctx->fb_state.resolve), + zink_resource(ctx->dynamic_fb.tc_info.resolve[1]), }; - if (zink_is_swapchain(res)) { - if (!zink_kopper_acquire(ctx, res, UINT64_MAX)) - return 0; - } - VkImageViewCreateInfo ivci = create_ivci(screen, res, &tmpl, ctx->dynamic_fb.info.layerCount > 1 ? PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D); - struct zink_surface *surf = zink_get_surface(ctx, &tmpl, &ivci); - VkImageLayout layout = is_depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - if (screen->driver_workarounds.general_layout) - layout = VK_IMAGE_LAYOUT_GENERAL; - unsigned idx = util_format_is_depth_or_stencil(res->base.b.format) ? PIPE_MAX_COLOR_BUFS : 0; - screen->image_barrier(ctx, res, layout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - res->obj->unordered_read = res->obj->unordered_write = false; - ctx->dynamic_fb.attachments[idx].resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT; - ctx->dynamic_fb.attachments[idx].resolveImageLayout = res->layout; - ctx->dynamic_fb.attachments[idx].resolveImageView = surf->image_view; - if (idx == PIPE_MAX_COLOR_BUFS) { - ctx->dynamic_fb.attachments[idx + 1].resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT; - ctx->dynamic_fb.attachments[idx + 1].resolveImageLayout = res->layout; - ctx->dynamic_fb.attachments[idx + 1].resolveImageView = surf->image_view; + if (!resolves[0]) + resolves[0] = zink_resource(ctx->dynamic_fb.tc_info.resolve[0]); + for (unsigned i = 0; i < ARRAY_SIZE(resolves); i++) { + struct zink_resource *res = resolves[i]; + if (!res) + continue; + zink_batch_resource_usage_set(ctx->bs, res, true, false); + bool is_depth = util_format_is_depth_or_stencil(res->base.b.format); + enum pipe_format format = res->base.b.format; + if (!ctx->fb_state.resolve) + format = is_depth ? ctx->fb_state.zsbuf.format : ctx->fb_state.cbufs[0].format; + if (zink_format_needs_mutable(res->base.b.format, format)) + /* mutable not set by default */ + zink_resource_object_init_mutable(ctx, res); + struct pipe_surface tmpl = { + .format = format, + .texture = &res->base.b + }; + if (zink_is_swapchain(res)) { + if (!zink_kopper_acquire(ctx, res, UINT64_MAX)) + return 0; + } + VkImageViewCreateInfo ivci = create_ivci(screen, res, &tmpl, ctx->dynamic_fb.info.layerCount > 1 ? PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D); + struct zink_surface *surf = zink_get_surface(ctx, &tmpl, &ivci); + VkImageLayout layout = is_depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (screen->driver_workarounds.general_layout) + layout = VK_IMAGE_LAYOUT_GENERAL; + unsigned idx = is_depth ? PIPE_MAX_COLOR_BUFS : 0; + screen->image_barrier(ctx, res, layout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + res->obj->unordered_read = res->obj->unordered_write = false; + ctx->dynamic_fb.attachments[idx].resolveMode = is_depth ? VK_RESOLVE_MODE_SAMPLE_ZERO_BIT : VK_RESOLVE_MODE_AVERAGE_BIT; + ctx->dynamic_fb.attachments[idx].resolveImageLayout = res->layout; + ctx->dynamic_fb.attachments[idx].resolveImageView = surf->image_view; + if (idx == PIPE_MAX_COLOR_BUFS) { + ctx->dynamic_fb.attachments[idx + 1].resolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT; + ctx->dynamic_fb.attachments[idx + 1].resolveImageLayout = res->layout; + ctx->dynamic_fb.attachments[idx + 1].resolveImageView = surf->image_view; + } } } ctx->zsbuf_unused = !zsbuf_used;