mesa/st: always use base_serialized_nir for draw

f2f640f35 introduces base variants, so we get 2 NIR shaders:
glsl-to-nir -> base_serialized_nir
            -> serialized_nir

Then, depending on who is using the shader the right one would be picked:

* draw uses base_serialized_nir
* hw driver uses serialized_nir

ef0c9231a7 made sure that base wasn't used when the shader is loaded from
the cache because it's missing, so in this case, glsl-to-nir does:

glsl-to-nir -> from-cache -> serialized_nir

The problem is that if draw tries to use this shader it may fail, for
the same reason as the referenced commits were introduced: draw may not
be compatible with some NIR passes used by the driver.

To fix this we need to serialize both NIR shaders, and pick the right
one depending on the user.

Fixes: ef0c9231a7 ("mesa/st: don't use serialized_nir for cached shaders")
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36411>
(cherry picked from commit 0e3ec9e82c)
This commit is contained in:
Pierre-Eric Pelloux-Prayer 2025-07-29 10:12:41 +02:00 committed by Eric Engestrom
parent e12c95c4bf
commit 654efa44e3
3 changed files with 13 additions and 3 deletions

View file

@ -5364,7 +5364,7 @@
"description": "mesa/st: always use base_serialized_nir for draw",
"nominated": true,
"nomination_type": 2,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": "ef0c9231a75e78fcf49436d2cfa20dbfb9968e85",
"notes": null

View file

@ -636,6 +636,9 @@ get_nir_shader(struct st_context *st, struct gl_program *prog, bool is_draw)
if ((!is_draw || !st->ctx->Const.PackedDriverUniformStorage) && prog->nir) {
nir_shader *nir = prog->nir;
if (nir->info.stage == MESA_SHADER_VERTEX)
assert(prog->base_serialized_nir && prog->base_serialized_nir_size);
/* The first shader variant takes ownership of NIR, so that there is
* no cloning. Additional shader variants are always generated from
* serialized NIR to save memory.
@ -649,8 +652,7 @@ get_nir_shader(struct st_context *st, struct gl_program *prog, bool is_draw)
const struct nir_shader_compiler_options *options =
is_draw ? &draw_nir_options : st_get_nir_compiler_options(st, prog->info.stage);
if (is_draw && st->ctx->Const.PackedDriverUniformStorage &&
(!prog->shader_program || prog->shader_program->data->LinkStatus != LINKING_SKIPPED)) {
if (is_draw && st->ctx->Const.PackedDriverUniformStorage) {
assert(prog->base_serialized_nir);
blob_reader_init(&blob_reader, prog->base_serialized_nir, prog->base_serialized_nir_size);
} else {

View file

@ -63,10 +63,15 @@ static void
write_nir_to_cache(struct blob *blob, struct gl_program *prog)
{
st_serialize_nir(prog);
if (prog->info.stage == MESA_SHADER_VERTEX)
st_serialize_base_nir(prog, prog->nir);
blob_write_intptr(blob, prog->serialized_nir_size);
blob_write_bytes(blob, prog->serialized_nir, prog->serialized_nir_size);
blob_write_intptr(blob, prog->base_serialized_nir_size);
blob_write_bytes(blob, prog->base_serialized_nir, prog->base_serialized_nir_size);
copy_blob_to_driver_cache_blob(blob, prog);
}
@ -182,6 +187,9 @@ st_deserialise_nir_program(struct gl_context *ctx,
prog->serialized_nir_size = blob_read_intptr(&blob_reader);
prog->serialized_nir = malloc(prog->serialized_nir_size);
blob_copy_bytes(&blob_reader, prog->serialized_nir, prog->serialized_nir_size);
prog->base_serialized_nir_size = blob_read_intptr(&blob_reader);
prog->base_serialized_nir = malloc(prog->base_serialized_nir_size);
blob_copy_bytes(&blob_reader, prog->base_serialized_nir, prog->base_serialized_nir_size);
prog->shader_program = shProg;
/* Make sure we don't try to read more data than we wrote. This should