From 2e8cac328a4a7954f9727b695acf063cfaae0e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Fri, 11 Apr 2025 20:04:04 -0400 Subject: [PATCH] radeonsi: move si_nir_mark_divergent_texture_non_uniform to its own file Reviewed-by: Pierre-Eric Pelloux-Prayer Part-of: --- src/gallium/drivers/radeonsi/meson.build | 1 + ...i_nir_mark_divergent_texture_non_uniform.c | 60 +++++++++++++++++++ .../drivers/radeonsi/si_shader_internal.h | 1 + src/gallium/drivers/radeonsi/si_shader_nir.c | 56 +---------------- 4 files changed, 63 insertions(+), 55 deletions(-) create mode 100644 src/gallium/drivers/radeonsi/si_nir_mark_divergent_texture_non_uniform.c diff --git a/src/gallium/drivers/radeonsi/meson.build b/src/gallium/drivers/radeonsi/meson.build index b0a8c8450b9..65f7923e6c1 100644 --- a/src/gallium/drivers/radeonsi/meson.build +++ b/src/gallium/drivers/radeonsi/meson.build @@ -55,6 +55,7 @@ files_libradeonsi = files( 'si_nir_lower_ps_color_inputs.c', 'si_nir_lower_resource.c', 'si_nir_lower_vs_inputs.c', + 'si_nir_mark_divergent_texture_non_uniform.c', 'si_nir_optim.c', 'si_sdma_copy_image.c', 'si_shader.c', diff --git a/src/gallium/drivers/radeonsi/si_nir_mark_divergent_texture_non_uniform.c b/src/gallium/drivers/radeonsi/si_nir_mark_divergent_texture_non_uniform.c new file mode 100644 index 00000000000..e999d1a2c02 --- /dev/null +++ b/src/gallium/drivers/radeonsi/si_nir_mark_divergent_texture_non_uniform.c @@ -0,0 +1,60 @@ +/* Copyright 2025 Advanced Micro Devices, Inc. + * SPDX-License-Identifier: MIT + */ + +#include "si_shader_internal.h" +#include "nir.h" + +bool si_nir_mark_divergent_texture_non_uniform(struct nir_shader *nir) +{ + /* 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_metadata_require(impl, nir_metadata_divergence); + + 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 = nir_src_is_divergent(&tex->src[i].src); + + 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->def.divergent && + (tex->texture_non_uniform || tex->sampler_non_uniform); + } + } + return nir_progress(divergence_changed, impl, + nir_metadata_all & ~nir_metadata_divergence); +} diff --git a/src/gallium/drivers/radeonsi/si_shader_internal.h b/src/gallium/drivers/radeonsi/si_shader_internal.h index e66233e1efc..e2bc7ebed73 100644 --- a/src/gallium/drivers/radeonsi/si_shader_internal.h +++ b/src/gallium/drivers/radeonsi/si_shader_internal.h @@ -156,6 +156,7 @@ bool si_nir_lower_resource(nir_shader *nir, struct si_shader *shader, struct si_shader_args *args); bool si_nir_lower_vs_inputs(nir_shader *nir, struct si_shader *shader, struct si_shader_args *args); +bool si_nir_mark_divergent_texture_non_uniform(struct nir_shader *nir); /* si_shader_llvm.c */ bool si_llvm_compile_shader(struct si_screen *sscreen, struct ac_llvm_compiler *compiler, diff --git a/src/gallium/drivers/radeonsi/si_shader_nir.c b/src/gallium/drivers/radeonsi/si_shader_nir.c index f278745575c..e45a65e3e58 100644 --- a/src/gallium/drivers/radeonsi/si_shader_nir.c +++ b/src/gallium/drivers/radeonsi/si_shader_nir.c @@ -346,60 +346,6 @@ static void si_lower_nir(struct si_screen *sscreen, struct nir_shader *nir) NIR_PASS_V(nir, nir_lower_fp16_casts, nir_lower_fp16_split_fp64); } -static bool si_mark_divergent_texture_non_uniform(struct nir_shader *nir) -{ - /* 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_metadata_require(impl, nir_metadata_divergence); - - 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 = nir_src_is_divergent(&tex->src[i].src); - - 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->def.divergent && - (tex->texture_non_uniform || tex->sampler_non_uniform); - } - } - return nir_progress(divergence_changed, impl, - nir_metadata_all & ~nir_metadata_divergence); -} - char *si_finalize_nir(struct pipe_screen *screen, struct nir_shader *nir) { struct si_screen *sscreen = (struct si_screen *)screen; @@ -454,7 +400,7 @@ char *si_finalize_nir(struct pipe_screen *screen, struct nir_shader *nir) if (progress) si_nir_opts(sscreen, nir, false); - NIR_PASS(_, nir, si_mark_divergent_texture_non_uniform); + NIR_PASS(_, nir, si_nir_mark_divergent_texture_non_uniform); /* Require divergence analysis to identify divergent loops. */ nir_metadata_require(nir_shader_get_entrypoint(nir), nir_metadata_divergence);