glsl: Implement use_scoped_barrier option for lowering memory barriers

When the option is enabled, lower memory barriers to the
unified nir_intrinsic_scoped_barrier.

The translation of the following is based on
https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_gl_spirv.txt

- memoryBarrier()
- memoryBarrierBuffer()
- memoryBarrierImage()
- memoryBarrierShared()
- groupMemoryBarrier()

Also use scoped barrier for the memory counterparts of the GLSL
(control) barrier() when the option is enabled.  The execution
part of a (control) barrier() remains using the old intrinsic.

For memoryBarrierAtomicCounter() there's no corresponding
nir_var_atomic_counter mode. Since atomic counters are lowered
to SSBOs, use the nir_var_mem_ssbo mode in the scoped barrier
instead.

Reviewed-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Acked-by: Rob Clark <robclark@freedesktop.org>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3339>
This commit is contained in:
Caio Oliveira
2023-02-24 02:25:44 -08:00
committed by Marge Bot
parent 2178a8da51
commit fe908ffefa

View File

@@ -1085,7 +1085,9 @@ nir_visitor::visit(ir_call *ir)
op = nir_intrinsic_image_deref_atomic_dec_wrap;
break;
case ir_intrinsic_memory_barrier:
op = nir_intrinsic_memory_barrier;
op = shader->options->use_scoped_barrier
? nir_intrinsic_scoped_barrier
: nir_intrinsic_memory_barrier;
break;
case ir_intrinsic_image_size:
op = nir_intrinsic_image_deref_size;
@@ -1106,19 +1108,29 @@ nir_visitor::visit(ir_call *ir)
op = nir_intrinsic_end_invocation_interlock;
break;
case ir_intrinsic_group_memory_barrier:
op = nir_intrinsic_group_memory_barrier;
op = shader->options->use_scoped_barrier
? nir_intrinsic_scoped_barrier
: nir_intrinsic_group_memory_barrier;
break;
case ir_intrinsic_memory_barrier_atomic_counter:
op = nir_intrinsic_memory_barrier_atomic_counter;
op = shader->options->use_scoped_barrier
? nir_intrinsic_scoped_barrier
: nir_intrinsic_memory_barrier_atomic_counter;
break;
case ir_intrinsic_memory_barrier_buffer:
op = nir_intrinsic_memory_barrier_buffer;
op = shader->options->use_scoped_barrier
? nir_intrinsic_scoped_barrier
: nir_intrinsic_memory_barrier_buffer;
break;
case ir_intrinsic_memory_barrier_image:
op = nir_intrinsic_memory_barrier_image;
op = shader->options->use_scoped_barrier
? nir_intrinsic_scoped_barrier
: nir_intrinsic_memory_barrier_image;
break;
case ir_intrinsic_memory_barrier_shared:
op = nir_intrinsic_memory_barrier_shared;
op = shader->options->use_scoped_barrier
? nir_intrinsic_scoped_barrier
: nir_intrinsic_memory_barrier_shared;
break;
case ir_intrinsic_shared_load:
op = nir_intrinsic_load_shared;
@@ -1437,6 +1449,62 @@ nir_visitor::visit(ir_call *ir)
case nir_intrinsic_memory_barrier_shared:
nir_builder_instr_insert(&b, &instr->instr);
break;
case nir_intrinsic_scoped_barrier: {
/* The nir_intrinsic_scoped_barrier follows the general
* semantics of SPIR-V memory barriers, so this and other memory
* barriers use the mapping based on GLSL->SPIR-V from
*
* https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_gl_spirv.txt
*/
nir_scope scope;
unsigned modes;
switch (ir->callee->intrinsic_id) {
case ir_intrinsic_memory_barrier:
scope = NIR_SCOPE_DEVICE;
modes = nir_var_image |
nir_var_mem_ssbo |
nir_var_mem_shared |
nir_var_mem_global;
break;
case ir_intrinsic_memory_barrier_buffer:
scope = NIR_SCOPE_DEVICE;
modes = nir_var_mem_ssbo |
nir_var_mem_global;
break;
case ir_intrinsic_memory_barrier_image:
scope = NIR_SCOPE_DEVICE;
modes = nir_var_image;
break;
case ir_intrinsic_memory_barrier_shared:
/* Both ARB_gl_spirv and glslang lower this to Device scope, so
* follow their lead. Note GL_KHR_vulkan_glsl also does
* something similar.
*/
scope = NIR_SCOPE_DEVICE;
modes = nir_var_mem_shared;
break;
case ir_intrinsic_group_memory_barrier:
scope = NIR_SCOPE_WORKGROUP;
modes = nir_var_image |
nir_var_mem_ssbo |
nir_var_mem_shared |
nir_var_mem_global;
break;
case ir_intrinsic_memory_barrier_atomic_counter:
/* There's no nir_var_atomic_counter, but since atomic counters are lowered
* to SSBOs, we use nir_var_mem_ssbo instead.
*/
scope = NIR_SCOPE_DEVICE;
modes = nir_var_mem_ssbo;
break;
default:
unreachable("invalid intrinsic id for memory barrier");
}
nir_scoped_memory_barrier(&b, scope, NIR_MEMORY_ACQ_REL,
(nir_variable_mode)modes);
break;
}
case nir_intrinsic_shader_clock:
nir_ssa_dest_init(&instr->instr, &instr->dest, 2, 32, NULL);
nir_intrinsic_set_memory_scope(instr, NIR_SCOPE_SUBGROUP);
@@ -2693,10 +2761,20 @@ nir_visitor::visit(ir_dereference_array *ir)
void
nir_visitor::visit(ir_barrier *)
{
if (shader->info.stage == MESA_SHADER_COMPUTE)
nir_memory_barrier_shared(&b);
else if (shader->info.stage == MESA_SHADER_TESS_CTRL)
nir_memory_barrier_tcs_patch(&b);
if (shader->options->use_scoped_barrier) {
if (shader->info.stage == MESA_SHADER_COMPUTE) {
nir_scoped_memory_barrier(&b, NIR_SCOPE_WORKGROUP, NIR_MEMORY_ACQ_REL,
nir_var_mem_shared);
} else if (shader->info.stage == MESA_SHADER_TESS_CTRL) {
nir_scoped_memory_barrier(&b, NIR_SCOPE_WORKGROUP, NIR_MEMORY_ACQ_REL,
nir_var_shader_out);
}
} else {
if (shader->info.stage == MESA_SHADER_COMPUTE)
nir_memory_barrier_shared(&b);
else if (shader->info.stage == MESA_SHADER_TESS_CTRL)
nir_memory_barrier_tcs_patch(&b);
}
nir_control_barrier(&b);
}