From 7b2dfdf15de9788eb20cfd5b9740e406b52ffab2 Mon Sep 17 00:00:00 2001 From: Job Noorman Date: Wed, 10 Jun 2026 08:16:12 +0200 Subject: [PATCH] nir/lower_ssbo: add option to only lower large SSBOs Some HW may have native SSBO instructions that only support a limited buffer size. It may be beneficial to use those instructions for small SSBOs and only fall back to global memory accesses for large ones. This commit adds an option (min_ssbo_size) that, if non-zero, will cause code like this to be emitted: if (@get_ssbo_size >= min_ssbo_size) { // global memory access } else { // original SSBO access } Signed-off-by: Job Noorman Reviewed-by: Emma Anholt Part-of: --- src/compiler/nir/nir.h | 8 ++++++++ src/compiler/nir/nir_lower_ssbo.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index df76df56d20..8a894878bbc 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -6712,6 +6712,14 @@ bool nir_dedup_inline_samplers(nir_shader *shader); typedef struct nir_lower_ssbo_options { bool native_loads; bool native_offset; + + /* If non-zero, use @get_ssbo_size to only use global memory accesses for + * SSBOs larger than this. Keep the existing SSBO accesses for smaller + * SSBOs. This is useful for HW hat has native SSBO access instructions + * that only support a limited size to only fall back to global memory for + * larger buffers. + */ + uint32_t min_ssbo_size; } nir_lower_ssbo_options; bool nir_lower_ssbo(nir_shader *shader, const nir_lower_ssbo_options *opts); diff --git a/src/compiler/nir/nir_lower_ssbo.c b/src/compiler/nir/nir_lower_ssbo.c index 95cedd5db9a..10378faf7e0 100644 --- a/src/compiler/nir/nir_lower_ssbo.c +++ b/src/compiler/nir/nir_lower_ssbo.c @@ -39,10 +39,30 @@ calc_address(nir_builder *b, nir_intrinsic_instr *intr, static bool pass(nir_builder *b, nir_intrinsic_instr *intr, void *data) { + /* Exit early for intrinsics that we don't lower to avoid emitting empty + * if/else blocks. + */ + switch (intr->intrinsic) { + case nir_intrinsic_load_ssbo: + case nir_intrinsic_store_ssbo: + case nir_intrinsic_ssbo_atomic: + case nir_intrinsic_ssbo_atomic_swap: + break; + default: + return false; + } + const nir_lower_ssbo_options *opts = data; + uint32_t min_ssbo_size = opts ? opts->min_ssbo_size : 0; b->cursor = nir_before_instr(&intr->instr); + if (min_ssbo_size) { + nir_def *ssbo_size = + nir_get_ssbo_size(b, 32, nir_get_io_index_src(intr)->ssa); + nir_push_if(b, nir_uge_imm(b, ssbo_size, min_ssbo_size)); + } + nir_def *def = NULL; switch (intr->intrinsic) { case nir_intrinsic_load_ssbo: @@ -82,6 +102,16 @@ pass(nir_builder *b, nir_intrinsic_instr *intr, void *data) return false; } + if (min_ssbo_size) { + nir_push_else(b, NULL); + nir_instr *ssbo_clone = nir_instr_clone(b->shader, &intr->instr); + nir_instr_insert(b->cursor, ssbo_clone); + nir_pop_if(b, NULL); + + if (def) + def = nir_if_phi(b, def, nir_instr_def(ssbo_clone)); + } + if (def) nir_def_rewrite_uses(&intr->def, def);