From ff2a214e5ff96013e68e3401dd1ecc2c7c9ea72d Mon Sep 17 00:00:00 2001 From: Benjamin Lee Date: Mon, 18 Nov 2024 09:32:36 -0800 Subject: [PATCH] panfrost: specialize VS on FS interpolation qualifiers This re-enables noperspective varying support for OpenGL. Because VS may depend on FS, we now need to wait for both VS and FS to be available before compiling shaders, and need to update VS when a new FS is bound. Signed-off-by: Benjamin Lee Reviewed-by: Eric R. Smith Reviewed-by: Erik Faye-Lund Part-of: --- src/gallium/drivers/panfrost/pan_context.h | 25 +++++++++----- src/gallium/drivers/panfrost/pan_shader.c | 39 +++++++++++++++++++--- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/gallium/drivers/panfrost/pan_context.h b/src/gallium/drivers/panfrost/pan_context.h index 660d0b266f8..809985231ca 100644 --- a/src/gallium/drivers/panfrost/pan_context.h +++ b/src/gallium/drivers/panfrost/pan_context.h @@ -356,17 +356,20 @@ struct panfrost_fs_key { bool line_smooth; }; +struct panfrost_vs_key { + /* We have a special "transform feedback" vertex program derived from a + * vertex shader. If is_xfb is set on a vertex shader, this is a transform + * feedback shader, else it is a regular vertex shader. */ + bool is_xfb; + + /* Bit mask of varyings in the linked FS that use noperspective + * interpolation, starting at VARYING_SLOT_VAR0 */ + uint32_t noperspective_varyings; +}; + struct panfrost_shader_key { union { - /* Vertex shaders do not use shader keys. However, we have a - * special "transform feedback" vertex program derived from a - * vertex shader. If vs_is_xfb is set on a vertex shader, this - * is a transform feedback shader, else it is a regular - * (unkeyed) vertex shader. - */ - bool vs_is_xfb; - - /* Fragment shaders use regular shader keys */ + struct panfrost_vs_key vs; struct panfrost_fs_key fs; }; }; @@ -423,6 +426,10 @@ struct panfrost_uncompiled_shader { */ uint32_t fixed_varying_mask; + /* On fragments shaders, bit mask of varyings using noprespective + * interpolation, starting at VARYING_SLOT_VAR0 */ + uint32_t noperspective_varyings; + /* If gl_FragColor was lowered, we need to optimize the stores later */ bool fragcolor_lowered; }; diff --git a/src/gallium/drivers/panfrost/pan_shader.c b/src/gallium/drivers/panfrost/pan_shader.c index cbe3286261d..979a693ddc5 100644 --- a/src/gallium/drivers/panfrost/pan_shader.c +++ b/src/gallium/drivers/panfrost/pan_shader.c @@ -156,6 +156,10 @@ panfrost_shader_compile(struct panfrost_screen *screen, const nir_shader *ir, panfrost_device_gpu_id(dev) < 0x700); } + if (s->info.stage == MESA_SHADER_VERTEX) + NIR_PASS(_, s, pan_nir_lower_static_noperspective, + key->vs.noperspective_varyings); + NIR_PASS(_, s, panfrost_nir_lower_sysvals, dev->arch, &out->sysvals); /* Lower resource indices */ @@ -222,6 +226,17 @@ panfrost_shader_get(struct pipe_screen *pscreen, panfrost_analyze_sysvals(state); } +static void +panfrost_build_vs_key(struct panfrost_context *ctx, + struct panfrost_vs_key *key, + struct panfrost_uncompiled_shader *uncompiled) +{ + struct panfrost_uncompiled_shader *fs = ctx->uncompiled[MESA_SHADER_FRAGMENT]; + + assert(fs != NULL && "too early"); + key->noperspective_varyings = fs->noperspective_varyings; +} + static void panfrost_build_fs_key(struct panfrost_context *ctx, struct panfrost_fs_key *key, @@ -280,9 +295,16 @@ panfrost_build_key(struct panfrost_context *ctx, { const nir_shader *nir = uncompiled->nir; - /* We don't currently have vertex shader variants */ - if (nir->info.stage == MESA_SHADER_FRAGMENT) + switch (nir->info.stage) { + case MESA_SHADER_VERTEX: + panfrost_build_vs_key(ctx, &key->vs, uncompiled); + break; + case MESA_SHADER_FRAGMENT: panfrost_build_fs_key(ctx, &key->fs, uncompiled); + break; + default: + break; + } } static struct panfrost_compiled_shader * @@ -329,7 +351,8 @@ panfrost_update_shader_variant(struct panfrost_context *ctx, return; /* We need linking information, defer this */ - if (type == PIPE_SHADER_FRAGMENT && !ctx->uncompiled[PIPE_SHADER_VERTEX]) + if ((type == PIPE_SHADER_FRAGMENT && !ctx->uncompiled[PIPE_SHADER_VERTEX]) || + (type == PIPE_SHADER_VERTEX && !ctx->uncompiled[PIPE_SHADER_FRAGMENT])) return; /* Also defer, happens with GALLIUM_HUD */ @@ -375,6 +398,10 @@ static void panfrost_bind_fs_state(struct pipe_context *pctx, void *hwcso) { panfrost_bind_shader_state(pctx, hwcso, PIPE_SHADER_FRAGMENT); + + /* Vertex shaders are linked with fragment shaders */ + struct panfrost_context *ctx = pan_context(pctx); + panfrost_update_shader_variant(ctx, PIPE_SHADER_VERTEX); } static void * @@ -415,6 +442,10 @@ panfrost_create_shader_state(struct pipe_context *pctx, struct panfrost_device *dev = pan_device(pctx->screen); pan_shader_preprocess(nir, panfrost_device_gpu_id(dev)); + if (nir->info.stage == MESA_SHADER_FRAGMENT) + so->noperspective_varyings = + pan_nir_collect_noperspective_varyings_fs(nir); + /* Vertex shaders get passed images through the vertex attribute descriptor * array. We need to add an offset to all image intrinsics so they point * to the right attribute. @@ -431,7 +462,7 @@ panfrost_create_shader_state(struct pipe_context *pctx, if (so->nir->xfb_info) { so->xfb = calloc(1, sizeof(struct panfrost_compiled_shader)); - so->xfb->key.vs_is_xfb = true; + so->xfb->key.vs.is_xfb = true; panfrost_shader_get(ctx->base.screen, &ctx->shaders, &ctx->descs, so, &ctx->base.debug, so->xfb, 0);