From fe908ffefa56a1e61b94f1db694d8bb08d3bac32 Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Fri, 24 Feb 2023 02:25:44 -0800 Subject: [PATCH] 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 Acked-by: Rob Clark Reviewed-by: Alyssa Rosenzweig Part-of: --- src/compiler/glsl/glsl_to_nir.cpp | 98 +++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 10 deletions(-) diff --git a/src/compiler/glsl/glsl_to_nir.cpp b/src/compiler/glsl/glsl_to_nir.cpp index 492caa0d854..7a8f4d751ac 100644 --- a/src/compiler/glsl/glsl_to_nir.cpp +++ b/src/compiler/glsl/glsl_to_nir.cpp @@ -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); }