zink: restrict implicit feedback loop detection using miplevels/layers

this improves perf by like 70-100% in games like Everspace, which draw
to a different miplevel of the same image that the fragment shader samples

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32950>
This commit is contained in:
Mike Blumenkrantz
2025-01-08 13:18:17 -05:00
committed by Marge Bot
parent 1d1d5653ac
commit 92d6351d02

View File

@@ -5635,6 +5635,20 @@ add_implicit_feedback_loop(struct zink_context *ctx, struct zink_resource *res)
/* if zsbuf isn't used then it effectively has no fb binds */
/* if zsbuf isn't written to then it'll be fine with read-only access */
return false;
/* build attachment array for miplevel/layer checks */
struct pipe_surface *psurfs[PIPE_MAX_COLOR_BUFS];
unsigned surf_idx = 0;
u_foreach_bit(idx, res->fb_binds) {
struct pipe_surface *psurf;
if (idx == PIPE_MAX_COLOR_BUFS)
psurf = ctx->fb_state.zsbuf;
else
psurf = ctx->fb_state.cbufs[idx];
if (psurf->texture == &res->base.b)
psurfs[surf_idx++] = psurf;
}
bool is_feedback = false;
/* avoid false positives when a texture is bound but not used */
u_foreach_bit(vkstage, res->gfx_barrier) {
@@ -5644,8 +5658,25 @@ add_implicit_feedback_loop(struct zink_context *ctx, struct zink_resource *res)
/* in-range VkPipelineStageFlagBits can be converted to VkShaderStageFlags with a bitshift */
gl_shader_stage stage = vk_to_mesa_shader_stage((VkShaderStageFlagBits)(vkstagebit >> 3));
/* check shader texture usage against resource's sampler binds */
if ((ctx->gfx_stages[stage] && (res->sampler_binds[stage] & ctx->gfx_stages[stage]->info.textures_used[0])))
is_feedback = true;
uint32_t texuse = res->sampler_binds[stage] & ctx->gfx_stages[stage]->info.textures_used[0];
if (!ctx->gfx_stages[stage] || !texuse)
continue;
/* check miplevel/layer: a feedback loop only exists if these overlap between fb and sampler */
u_foreach_bit(slot, texuse) {
struct pipe_sampler_view *sv = ctx->sampler_views[stage][slot];
for (unsigned i = 0; i < surf_idx; i++) {
if (sv->u.tex.first_level > psurfs[i]->u.tex.level || sv->u.tex.last_level < psurfs[i]->u.tex.level)
continue;
if (sv->u.tex.first_layer > psurfs[i]->u.tex.last_layer || sv->u.tex.last_layer < psurfs[i]->u.tex.first_layer)
continue;
is_feedback = true;
break;
}
if (is_feedback)
break;
}
}
if (!is_feedback)
return false;