From 90834353a1041a03ce033974c1505fea4d3e06db Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 28 Jun 2023 19:07:20 +0900 Subject: [PATCH] asahi: Gather flat/linear shaded input info from uncompiled FS We need to propagate shading model metadata from the FS to the VS in order to correctly lay out the uniforms in the right order. This means we need VS variants depending on this data. We could use the existing shader info structure, but that applies to compiled shaders which would introduce a dependency from the VS compile to the FS compile. This information does not change with FS variants, so we can introduce an agx_uncompiled_shader_info structure and gather it early at precompilation time. Signed-off-by: Asahi Lina Part-of: --- src/asahi/compiler/agx_compile.c | 63 ++++++++++++++++++++++----- src/asahi/compiler/agx_compile.h | 8 +++- src/asahi/lib/agx_meta.c | 2 +- src/gallium/drivers/asahi/agx_state.c | 4 +- src/gallium/drivers/asahi/agx_state.h | 1 + 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/asahi/compiler/agx_compile.c b/src/asahi/compiler/agx_compile.c index fa3c839e734..661ad4be5b3 100644 --- a/src/asahi/compiler/agx_compile.c +++ b/src/asahi/compiler/agx_compile.c @@ -2094,33 +2094,60 @@ agx_gather_texcoords(nir_builder *b, nir_instr *instr, void *data) return false; } +struct interp_masks { + uint64_t flat; + uint64_t linear; +}; + static bool -agx_gather_flat(nir_builder *b, nir_instr *instr, void *data) +agx_gather_interp(nir_builder *b, nir_instr *instr, void *data) { - uint64_t *mask = data; + struct interp_masks *masks = data; if (instr->type != nir_instr_type_intrinsic) return false; nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); - if (intr->intrinsic != nir_intrinsic_load_input) - return false; - nir_io_semantics sem = nir_intrinsic_io_semantics(intr); - *mask |= BITFIELD64_BIT(sem.location); + if (intr->intrinsic == nir_intrinsic_load_input) { + nir_io_semantics sem = nir_intrinsic_io_semantics(intr); + masks->flat |= BITFIELD64_BIT(sem.location); + } else if (intr->intrinsic == nir_intrinsic_load_interpolated_input && + nir_intrinsic_interp_mode(nir_src_as_intrinsic(intr->src[0])) == + INTERP_MODE_NOPERSPECTIVE) { + nir_io_semantics sem = nir_intrinsic_io_semantics(intr); + masks->linear |= BITFIELD64_BIT(sem.location); + } + return false; } /* - * Build a bit mask of varyings (by location) that are flatshaded or used as - * texture coordinates. This information is needed by lower_mediump_io. + * Build a bit mask of varyings (by location) that are flatshaded and linear + * shaded. This information is needed by lower_mediump_io and + * agx_uncompiled_shader_info. + */ +static struct interp_masks +agx_interp_masks(nir_shader *nir) +{ + assert(nir->info.stage == MESA_SHADER_FRAGMENT); + + struct interp_masks masks = {0}; + nir_shader_instructions_pass(nir, agx_gather_interp, nir_metadata_all, + &masks); + + return masks; +} + +/* + * Build a bit mask of varyings (by location) that are used as texture + * coordinates. This information is needed by lower_mediump_io. */ static uint64_t -agx_fp32_varying_mask(nir_shader *nir) +agx_texcoord_mask(nir_shader *nir) { assert(nir->info.stage == MESA_SHADER_FRAGMENT); uint64_t mask = 0; - nir_shader_instructions_pass(nir, agx_gather_flat, nir_metadata_all, &mask); nir_shader_instructions_pass(nir, agx_gather_texcoords, nir_metadata_all, &mask); return mask; @@ -2287,8 +2314,12 @@ agx_compile_function_nir(nir_shader *nir, nir_function_impl *impl, * lowered here to avoid duplicate work with shader variants. */ void -agx_preprocess_nir(nir_shader *nir, bool support_lod_bias) +agx_preprocess_nir(nir_shader *nir, bool support_lod_bias, + struct agx_uncompiled_shader_info *out) { + if (out) + memset(out, 0, sizeof(*out)); + NIR_PASS_V(nir, nir_lower_vars_to_ssa); if (nir->info.stage == MESA_SHADER_VERTEX) { @@ -2313,6 +2344,9 @@ agx_preprocess_nir(nir_shader *nir, bool support_lod_bias) glsl_type_size, 0); NIR_PASS_V(nir, nir_lower_ssbo); if (nir->info.stage == MESA_SHADER_FRAGMENT) { + uint64_t texcoord = agx_texcoord_mask(nir); + struct interp_masks masks = agx_interp_masks(nir); + NIR_PASS_V(nir, agx_nir_lower_frag_sidefx); /* Interpolate varyings at fp16 and write to the tilebuffer at fp16. As an @@ -2322,7 +2356,12 @@ agx_preprocess_nir(nir_shader *nir, bool support_lod_bias) */ NIR_PASS_V(nir, nir_lower_mediump_io, nir_var_shader_in | nir_var_shader_out, - ~agx_fp32_varying_mask(nir), false); + ~(masks.flat | texcoord), false); + + if (out) { + out->inputs_flat_shaded = masks.flat; + out->inputs_linear_shaded = masks.linear; + } } /* Clean up deref gunk after lowering I/O */ diff --git a/src/asahi/compiler/agx_compile.h b/src/asahi/compiler/agx_compile.h index c959ad55edf..8dcca9dc824 100644 --- a/src/asahi/compiler/agx_compile.h +++ b/src/asahi/compiler/agx_compile.h @@ -76,6 +76,11 @@ union agx_varyings { struct agx_varyings_fs fs; }; +struct agx_uncompiled_shader_info { + uint64_t inputs_flat_shaded; + uint64_t inputs_linear_shaded; +}; + struct agx_shader_info { union agx_varyings varyings; @@ -171,7 +176,8 @@ struct agx_shader_key { }; }; -void agx_preprocess_nir(nir_shader *nir, bool support_lod_bias); +void agx_preprocess_nir(nir_shader *nir, bool support_lod_bias, + struct agx_uncompiled_shader_info *out); bool agx_nir_lower_discard_zs_emit(nir_shader *s); diff --git a/src/asahi/lib/agx_meta.c b/src/asahi/lib/agx_meta.c index 3f4121369b7..70c593c2493 100644 --- a/src/asahi/lib/agx_meta.c +++ b/src/asahi/lib/agx_meta.c @@ -17,7 +17,7 @@ agx_compile_meta_shader(struct agx_meta_cache *cache, nir_shader *shader, struct util_dynarray binary; util_dynarray_init(&binary, NULL); - agx_preprocess_nir(shader, false); + agx_preprocess_nir(shader, false, NULL); if (tib) { agx_nir_lower_tilebuffer(shader, tib, NULL, NULL); agx_nir_lower_monolithic_msaa( diff --git a/src/gallium/drivers/asahi/agx_state.c b/src/gallium/drivers/asahi/agx_state.c index bd9cd68b6df..809a30dd32c 100644 --- a/src/gallium/drivers/asahi/agx_state.c +++ b/src/gallium/drivers/asahi/agx_state.c @@ -1595,7 +1595,7 @@ agx_create_shader_state(struct pipe_context *pctx, blob_finish(&blob); so->nir = nir; - agx_preprocess_nir(nir, true); + agx_preprocess_nir(nir, true, &so->info); /* For shader-db, precompile a shader with a default key. This could be * improved but hopefully this is acceptable for now. @@ -1674,7 +1674,7 @@ agx_create_compute_state(struct pipe_context *pctx, blob_finish(&blob); so->nir = nir; - agx_preprocess_nir(nir, true); + agx_preprocess_nir(nir, true, &so->info); agx_get_shader_variant(agx_screen(pctx->screen), so, &pctx->debug, &key); /* We're done with the NIR, throw it away */ diff --git a/src/gallium/drivers/asahi/agx_state.h b/src/gallium/drivers/asahi/agx_state.h index f6b888d2551..2d015530078 100644 --- a/src/gallium/drivers/asahi/agx_state.h +++ b/src/gallium/drivers/asahi/agx_state.h @@ -171,6 +171,7 @@ struct agx_uncompiled_shader { enum pipe_shader_type type; const struct nir_shader *nir; uint8_t nir_sha1[20]; + struct agx_uncompiled_shader_info info; struct hash_table *variants; /* For compute kernels */