tc: add resolve resource to rp info

this allows non-winsys resolves to be optimized out

Acked-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35477>
This commit is contained in:
Mike Blumenkrantz 2025-06-11 14:41:14 -04:00
parent e2d40aab6f
commit 8933b3ed39
6 changed files with 105 additions and 20 deletions

View file

@ -232,17 +232,21 @@ 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;
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);
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);
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;
@ -1477,6 +1481,9 @@ tc_set_framebuffer_state(struct pipe_context *_pipe,
tc_set_resource_batch_usage_persistent(tc, tc->fb_resources[i], true);
}
tc->nr_cbufs = nr_cbufs;
tc->fb_layers = util_framebuffer_get_num_layers(fb);
tc->fb_width = fb->width;
tc->fb_height = fb->height;
if (tc->options.parse_renderpass_info) {
/* store existing zsbuf data for possible persistence */
uint8_t zsbuf = tc->renderpass_info_recording->has_draw ?
@ -1500,7 +1507,9 @@ tc_set_framebuffer_state(struct pipe_context *_pipe,
* just increment the index and keep using the existing info for recording
*/
tc->batch_slots[tc->next].renderpass_info_idx = 0;
tc->renderpass_info_recording->has_resolve = false;
}
assert(!tc->renderpass_info_recording->resolve);
tc->seen_fb_state = true;
}
/* ref for cmd */
@ -4498,7 +4507,13 @@ tc_call_blit(struct pipe_context *pipe, void *call)
return call_size(tc_blit_call);
}
static void
static uint16_t ALWAYS_INLINE
tc_call_resolve(struct pipe_context *pipe, void *call)
{
return tc_call_blit(pipe, call);
}
static struct tc_blit_call *
tc_blit_enqueue(struct threaded_context *tc, const struct pipe_blit_info *info)
{
struct tc_blit_call *blit = tc_add_call(tc, TC_CALL_blit, tc_blit_call);
@ -4508,6 +4523,7 @@ tc_blit_enqueue(struct threaded_context *tc, const struct pipe_blit_info *info)
tc_set_resource_batch_usage(tc, info->src.resource);
tc_set_resource_reference(&blit->info.src.resource, info->src.resource);
memcpy(&blit->info, info, sizeof(*info));
return blit;
}
static void
@ -4518,29 +4534,62 @@ tc_blit(struct pipe_context *_pipe, const struct pipe_blit_info *info)
/* filter out untracked non-resolves */
if (!tc->options.parse_renderpass_info ||
info->src.resource->nr_samples <= 1 ||
info->dst.resource->nr_samples > 1) {
info->dst.resource->nr_samples > 1 ||
info->scissor_enable ||
info->swizzle_enable ||
info->alpha_blend ||
info->src.resource->format != info->src.format ||
info->dst.resource->format != info->dst.format ||
info->src.format != info->dst.format ||
info->src.box.width < 0 ||
info->src.box.height < 0 ||
info->src.box.depth < 0 ||
info->dst.box.width < 0 ||
info->dst.box.height < 0 ||
info->dst.box.depth < 0 ||
info->src.box.x != info->dst.box.x ||
info->src.box.y != info->dst.box.y ||
info->src.box.z != info->dst.box.z ||
info->src.box.width != info->dst.box.width ||
info->src.box.height != info->dst.box.height ||
info->src.box.depth != info->dst.box.depth ||
info->src.box.width != tc->fb_width ||
info->src.box.height != tc->fb_height ||
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)
tc_check_fb_access(tc, info->src.resource, info->dst.resource);
tc_blit_enqueue(tc, info);
return;
}
struct pipe_resource *src = tc->nr_cbufs ? tc->fb_resources[0] : tc->fb_resources[PIPE_MAX_COLOR_BUFS];
if (tc->fb_resolve == info->dst.resource) {
#if TC_DEBUG >= 3
tc_printf("WSI RESOLVE MERGE");
#endif
/* optimize out this blit entirely */
tc->renderpass_info_recording->has_resolve = true;
tc->renderpass_info_recording->ended = true;
tc_signal_renderpass_info_ready(tc);
return;
}
for (unsigned i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
if (tc->fb_resources[i] == info->src.resource) {
tc->renderpass_info_recording->has_resolve = true;
break;
}
}
if (tc->options.parse_renderpass_info && tc->in_renderpass)
} else if (src == info->src.resource &&
(!tc->renderpass_info_recording->has_resolve ||
tc->renderpass_info_recording->resolve == info->dst.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);
tc_set_resource_batch_usage(tc, info->dst.resource);
tc->renderpass_info_recording->ended = true;
tc_signal_renderpass_info_ready(tc);
} else if (tc->in_renderpass) {
tc_check_fb_access(tc, info->src.resource, info->dst.resource);
tc_blit_enqueue(tc, info);
}
struct tc_blit_call *blit = tc_blit_enqueue(tc, info);
blit->base.call_id = TC_CALL_resolve;
}
struct tc_generate_mipmap {

View file

@ -440,7 +440,7 @@ struct tc_renderpass_info {
bool zsbuf_invalidate : 1;
/* whether a draw occurs */
bool has_draw : 1;
/* whether a framebuffer resolve occurs on cbuf[0] */
/* whether a framebuffer resolve occurs on cbuf[0] or zsbuf */
bool has_resolve : 1;
/* whether queries are ended during this renderpass */
bool has_query_ends : 1;
@ -468,6 +468,8 @@ struct tc_renderpass_info {
/* zsbuf fb info is in data8[3] & BITFIELD_MASK(4) */
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;
};
static inline bool
@ -640,6 +642,9 @@ struct threaded_context {
unsigned max_images;
unsigned max_samplers;
unsigned nr_cbufs;
unsigned fb_layers;
uint16_t fb_width;
uint16_t fb_height;
unsigned last, next, next_buf_list;

View file

@ -75,6 +75,7 @@ CALL(draw_vstate_single)
CALL(draw_vstate_multi)
CALL(launch_grid)
CALL(blit)
CALL(resolve)
CALL(generate_mipmap)
CALL(invalidate_resource)
CALL(clear_render_target)

View file

@ -330,6 +330,18 @@ zink_blit(struct pipe_context *pctx,
struct zink_resource *use_src = src;
struct zink_resource *dst = zink_resource(info->dst.resource);
bool needs_present_readback = false;
if (ctx->awaiting_resolve && ctx->in_rp && ctx->dynamic_fb.tc_info.has_resolve) {
struct pipe_resource *resolve = ctx->fb_state.resolve;
if (!resolve)
resolve = ctx->dynamic_fb.tc_info.resolve;
if (resolve == info->dst.resource) {
zink_batch_no_rp_safe(ctx);
ctx->awaiting_resolve = false;
return;
}
}
if (zink_is_swapchain(dst)) {
if (!zink_kopper_acquire(ctx, dst, UINT64_MAX))
return;

View file

@ -72,6 +72,8 @@ update_tc_info(struct zink_context *ctx)
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->awaiting_resolve = ctx->dynamic_fb.tc_info.has_resolve;
} else {
struct tc_renderpass_info info = ctx->dynamic_fb.tc_info;
bool zsbuf_used = !ctx->zsbuf_unused;
@ -3204,22 +3206,37 @@ begin_rendering(struct zink_context *ctx, bool check_msaa_expand)
ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS + 1].resolveMode = 0;
}
}
if (ctx->fb_state.resolve && use_tc_info && ctx->dynamic_fb.tc_info.has_resolve) {
if (use_tc_info && ctx->dynamic_fb.tc_info.has_resolve) {
struct zink_resource *res = zink_resource(ctx->fb_state.resolve);
zink_surface_resolve_init(screen, res, ctx->fb_state.resolve->format);
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;
zink_surface_resolve_init(screen, res, format);
struct zink_surface *surf = zink_surface(res->surface);
if (zink_is_swapchain(res)) {
if (!zink_kopper_acquire(ctx, res, UINT64_MAX))
return 0;
zink_surface_swapchain_update(ctx, surf);
}
zink_batch_resource_usage_set(ctx->bs, res, true, false);
VkImageLayout layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
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, 0, 0);
res->obj->unordered_read = res->obj->unordered_write = false;
ctx->dynamic_fb.attachments[0].resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT;
ctx->dynamic_fb.attachments[0].resolveImageLayout = zink_resource(surf->base.texture)->layout;
ctx->dynamic_fb.attachments[0].resolveImageView = surf->image_view;
ctx->dynamic_fb.attachments[idx].resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT;
ctx->dynamic_fb.attachments[idx].resolveImageLayout = zink_resource(surf->base.texture)->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 = zink_resource(surf->base.texture)->layout;
ctx->dynamic_fb.attachments[idx + 1].resolveImageView = surf->image_view;
}
}
ctx->zsbuf_unused = !zsbuf_used;
assert(ctx->fb_state.width >= ctx->dynamic_fb.info.renderArea.extent.width);

View file

@ -1768,6 +1768,7 @@ struct zink_context {
struct set rendering_state_cache[6]; //[util_logbase2_ceil(msrtss samplecount)]
struct zink_resource *swapchain;
VkExtent2D swapchain_size;
bool awaiting_resolve; //from tc info
bool in_rp; //renderpass is currently active
bool rp_changed; //force renderpass restart
bool rp_layout_changed; //renderpass changed, maybe restart