Scope native barriers to shaders with shared execution

This commit is contained in:
nmzik
2026-09-21 09:22:10 +04:00
parent 61761b65f2
commit f9e56ef8a0
3 changed files with 16 additions and 39 deletions
@@ -559,6 +559,10 @@ void EmitVoid(ValueEmitContext&) {}
void EmitBarrier(EmitterState& state) { void EmitBarrier(EmitterState& state) {
const auto tessellation = state.program.stage == ShaderType::TessellationControl; const auto tessellation = state.program.stage == ShaderType::TessellationControl;
if (!tessellation && ShaderWorkgroupInput(state.program.stage, state.input_info) == nullptr) {
// Independent graphics invocations have no native workgroup left to synchronize.
return;
}
const auto memory_scope = tessellation ? spv::ScopeInvocation : spv::ScopeWorkgroup; const auto memory_scope = tessellation ? spv::ScopeInvocation : spv::ScopeWorkgroup;
const auto semantics = tessellation ? spv::MemorySemanticsMaskNone const auto semantics = tessellation ? spv::MemorySemanticsMaskNone
: spv::MemorySemanticsAcquireReleaseMask | : spv::MemorySemanticsAcquireReleaseMask |
@@ -1,4 +1,4 @@
#include "graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h" #include "graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h"
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
namespace { namespace {
@@ -127,10 +127,7 @@ void EmitMeshEntryPoint(EmitterState& state) {
state.builder.AddFunction(spv::OpFunctionCall, TypeVoid(state), state.builder.AllocateId(), state.builder.AddFunction(spv::OpFunctionCall, TypeVoid(state), state.builder.AllocateId(),
state.mesh_guest_func); state.mesh_guest_func);
// All guest waves finish before the uniform Vulkan allocation and output stores. // All guest waves finish before the uniform Vulkan allocation and output stores.
state.builder.AddFunction(spv::OpControlBarrier, ConstantU32(state, spv::ScopeWorkgroup), EmitBarrier(state);
ConstantU32(state, spv::ScopeWorkgroup),
ConstantU32(state, spv::MemorySemanticsAcquireReleaseMask |
spv::MemorySemanticsWorkgroupMemoryMask));
const auto vertices = MeshLoad(state, state.mesh_allocation, spv::StorageClassWorkgroup, const auto vertices = MeshLoad(state, state.mesh_allocation, spv::StorageClassWorkgroup,
TypeU32(state), ConstantU32(state, 0)); TypeU32(state), ConstantU32(state, 0));
const auto primitives = MeshLoad(state, state.mesh_allocation, spv::StorageClassWorkgroup, const auto primitives = MeshLoad(state, state.mesh_allocation, spv::StorageClassWorkgroup,
+10 -34
View File
@@ -1679,45 +1679,14 @@ void TestNewShaderRecompilerSMovB32() {
CheckSpirvBinaryValidates(result.spirv); CheckSpirvBinaryValidates(result.spirv);
} }
void TestNewShaderRecompilerSoppMarkers() { void TestShaderStageBarriers() {
const uint32_t shader[] = { const uint32_t shader[] = {
EncodeSopp(0x00, 3), // s_nop 3
EncodeSopp(0x0c, 0), // s_waitcnt 0
EncodeSopp(0x10, 0x0f), // s_sendmsg 15
EncodeSopp(0x16, 0x2a), // s_ttracedata 42
EncodeSopp(0x20, 1), // s_inst_prefetch 1
EncodeSopp(0x0a, 0), // s_barrier EncodeSopp(0x0a, 0), // s_barrier
EncodeSopp(0x01, 0), // s_endpgm EncodeSopp(0x01, 0), // s_endpgm
}; };
auto options = MakeCompileOptions(ShaderType::Compute); const auto result =
options.dump_ir = true; RecompileForTest(shader, MakeCompileOptions(ShaderType::Compute));
auto result = RecompileForTest(shader, options);
Check((result.decoded_dump.find("s_nop 0x00000003") != std::string::npos),
"new decoder did not decode SOPP s_nop");
Check((result.decoded_dump.find("s_waitcnt 0x00000000") != std::string::npos),
"new decoder did not decode SOPP s_waitcnt");
Check((result.decoded_dump.find("s_sendmsg 0x0000000f") != std::string::npos),
"new decoder did not decode SOPP s_sendmsg");
Check((result.decoded_dump.find("s_ttracedata 0x0000002a") != std::string::npos),
"new decoder did not decode SOPP s_ttracedata");
Check((result.decoded_dump.find("s_inst_prefetch 0x00000001") != std::string::npos),
"new decoder did not decode SOPP s_inst_prefetch");
Check((result.decoded_dump.find("s_barrier") != std::string::npos),
"new decoder did not decode SOPP s_barrier");
Check((result.ir_dump.find("ControlNop null, 0x00000003") != std::string::npos),
"SOPP s_nop did not lower to an IR marker");
Check((result.ir_dump.find("Waitcnt null, 0x00000000") != std::string::npos),
"SOPP s_waitcnt did not lower to an IR marker");
Check((result.ir_dump.find("Sendmsg null, 0x0000000f") != std::string::npos),
"SOPP s_sendmsg did not lower to an IR marker");
Check((result.ir_dump.find("TtraceData null, 0x0000002a") != std::string::npos),
"SOPP s_ttracedata did not lower to an IR marker");
Check((result.ir_dump.find("InstPrefetch null, 0x00000001") != std::string::npos),
"SOPP s_inst_prefetch did not lower to an IR marker");
Check((result.ir_dump.find("Barrier null") != std::string::npos),
"SOPP s_barrier did not lower to an IR marker");
Check(SpirvContainsOpcode(result.spirv, 224), Check(SpirvContainsOpcode(result.spirv, 224),
"SPIR-V binary does not contain OpControlBarrier"); "SPIR-V binary does not contain OpControlBarrier");
Check( Check(
@@ -1725,6 +1694,12 @@ void TestNewShaderRecompilerSoppMarkers() {
result.spirv.end(), result.spirv.end(),
"SPIR-V barrier does not use workgroup acquire-release memory semantics"); "SPIR-V barrier does not use workgroup acquire-release memory semantics");
CheckSpirvBinaryValidates(result.spirv); CheckSpirvBinaryValidates(result.spirv);
const auto vertex_result =
RecompileForTest(shader, MakeCompileOptions(ShaderType::Vertex));
CheckSpirvBinaryValidates(vertex_result.spirv);
Check(!SpirvContainsOpcode(vertex_result.spirv, 224),
"independent vertex invocations retained a workgroup barrier");
} }
void TestNewShaderRecompilerSopkWaitcntMarkers() { void TestNewShaderRecompilerSopkWaitcntMarkers() {
@@ -13443,6 +13418,7 @@ int main() {
TestNewShaderRecompilerSpirvSizeBaselines(); TestNewShaderRecompilerSpirvSizeBaselines();
TestDemandDrivenSpirvDeclarations(); TestDemandDrivenSpirvDeclarations();
TestNewShaderRecompilerSMovB32(); TestNewShaderRecompilerSMovB32();
TestShaderStageBarriers();
TestNewShaderRecompilerClipDisabledPosition(); TestNewShaderRecompilerClipDisabledPosition();
TestNewShaderRecompilerAuxPositionExports(); TestNewShaderRecompilerAuxPositionExports();
TestNewShaderRecompilerNativeWideScalarMemoryIr(); TestNewShaderRecompilerNativeWideScalarMemoryIr();