tc: also inline depth resolves
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run

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: 8933b3ed39 ("tc: add resolve resource to rp info")

Acked-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36521>
This commit is contained in:
Mike Blumenkrantz 2025-08-01 13:18:58 -04:00 committed by Marge Bot
parent 71c4f13660
commit a71b6ac41a
4 changed files with 71 additions and 54 deletions

View file

@ -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 {

View file

@ -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

View file

@ -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;

View file

@ -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;