radeonsi: add si_mark_divergent_texture_non_uniform
authorQiang Yu <yuq825@gmail.com>
Fri, 14 Apr 2023 10:25:46 +0000 (18:25 +0800)
committerMarge Bot <emma+marge@anholt.net>
Wed, 19 Apr 2023 01:59:02 +0000 (01:59 +0000)
For handle divergent index problem later for both
llvm and aco.

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22523>

src/gallium/drivers/radeonsi/si_shader_nir.c

index db2ac4c..1b735d9 100644 (file)
@@ -352,6 +352,61 @@ static void si_lower_nir(struct si_screen *sscreen, struct nir_shader *nir)
    NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp, NULL);
 }
 
+static bool si_mark_divergent_texture_non_uniform(struct nir_shader *nir)
+{
+   assert(nir->info.divergence_analysis_run);
+
+   /* sampler_non_uniform and texture_non_uniform are always false in GLSL,
+    * but this can lead to unexpected behavior if texture/sampler index come from
+    * a vertex attribute.
+    *
+    * For instance, 2 consecutive draws using 2 different index values,
+    * could be squashed together by the hw - producing a single draw with
+    * non-dynamically uniform index.
+    *
+    * To avoid this, detect divergent indexing, mark them as non-uniform,
+    * so that we can apply waterfall loop on these index later (either llvm
+    * backend or nir_lower_non_uniform_access).
+    *
+    * See https://gitlab.freedesktop.org/mesa/mesa/-/issues/2253
+    */
+
+   bool divergence_changed = false;
+
+   nir_function_impl *impl = nir_shader_get_entrypoint(nir);
+   nir_foreach_block_safe(block, impl) {
+      nir_foreach_instr_safe(instr, block) {
+         if (instr->type != nir_instr_type_tex)
+            continue;
+
+         nir_tex_instr *tex = nir_instr_as_tex(instr);
+         for (int i = 0; i < tex->num_srcs; i++) {
+            bool divergent = tex->src[i].src.ssa->divergent;
+
+            switch (tex->src[i].src_type) {
+            case nir_tex_src_texture_deref:
+            case nir_tex_src_texture_handle:
+               tex->texture_non_uniform |= divergent;
+               break;
+            case nir_tex_src_sampler_deref:
+            case nir_tex_src_sampler_handle:
+               tex->sampler_non_uniform |= divergent;
+               break;
+            default:
+               break;
+            }
+         }
+
+         /* If dest is already divergent, divergence won't change. */
+         divergence_changed |= !tex->dest.ssa.divergent &&
+            (tex->texture_non_uniform || tex->sampler_non_uniform);
+      }
+   }
+
+   nir_metadata_preserve(impl, nir_metadata_all);
+   return divergence_changed;
+}
+
 char *si_finalize_nir(struct pipe_screen *screen, void *nirptr)
 {
    struct si_screen *sscreen = (struct si_screen *)screen;