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 <jnoorman@igalia.com>
Reviewed-by: Emma Anholt <emma@anholt.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41477>
This commit is contained in:
Job Noorman 2026-06-10 08:16:12 +02:00 committed by Marge Bot
parent ca9c01ddc5
commit 7b2dfdf15d
2 changed files with 38 additions and 0 deletions

View file

@ -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);

View file

@ -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);