From ceb154d9e44e5d64ee6fde90c8cf91930fcb4276 Mon Sep 17 00:00:00 2001 From: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com> Date: Mon, 26 Oct 2026 05:28:56 +0100 Subject: [PATCH] shader: acquire stored buffers and images at S_BARRIER --- .../backend/spirv/spirvEmitterFlow.cpp | 13 +++++++--- tests/shaderCfgTests.cpp | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterFlow.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterFlow.cpp index 2629d282c..7b2260b1f 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterFlow.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterFlow.cpp @@ -712,9 +712,16 @@ void EmitBarrier(EmitterState& state) { return; } const auto memory_scope = tessellation ? spv::ScopeInvocation : spv::ScopeWorkgroup; - const auto memory = state.lds_storage_class == spv::StorageClassStorageBuffer - ? spv::MemorySemanticsUniformMemoryMask - : spv::MemorySemanticsWorkgroupMemoryMask; + auto memory = state.lds_storage_class == spv::StorageClassStorageBuffer + ? spv::MemorySemanticsUniformMemoryMask + : spv::MemorySemanticsWorkgroupMemoryMask; + // Shaders read other waves' buffer and image stores with plain loads right after S_BARRIER. + const auto written = [](const auto& resource) { return resource.written; }; + if (std::ranges::any_of(state.program.info.buffers, written) || + std::ranges::any_of(state.program.info.images, written)) { + memory = memory | spv::MemorySemanticsUniformMemoryMask | + spv::MemorySemanticsImageMemoryMask; + } const auto semantics = tessellation ? spv::MemorySemanticsMaskNone : spv::MemorySemanticsAcquireReleaseMask | memory; state.builder.AddFunction(spv::OpControlBarrier, ConstantU32(state, spv::ScopeWorkgroup), diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index bcec112d0..d78c1ec9c 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -1847,6 +1847,31 @@ void TestShaderStageBarriers() { "SPIR-V barrier does not use workgroup acquire-release memory semantics"); CheckSpirvBinaryValidates(result.spirv); + // s_barrier also acquires other waves' buffer and image stores. + const auto acquires = [](std::span code, + const ShaderRecompiler::CompileOptions &options) { + const auto result = RecompileForTest(code, options); + CheckSpirvBinaryValidates(result.spirv); + // AcquireRelease | UniformMemory | WorkgroupMemory | ImageMemory. + return DisassembleSpirvBinary(result.spirv).find( + "OpControlBarrier %uint_2 %uint_2 %uint_2376") != std::string::npos; + }; + const uint32_t buffer_store[] = { + EncodeMubuf0(0x1c, 0, false), EncodeMubuf1(1, 0, 0), // buffer_store_dword + EncodeSopp(0x0a), EncodeSopp(0x01), + }; + Check(acquires(buffer_store, MakeCompileOptions(ShaderType::Compute)), + "s_barrier after buffer stores does not acquire buffer memory"); + const uint32_t image_store[] = { + EncodeMimg0(0x08, 0xf), EncodeMimg1(20, 0, 0, 4), // image_store + EncodeSopp(0x0a), EncodeSopp(0x01), + }; + const auto image_user_data = ImageTestUserData(); + auto image_options = MakeCompileOptions(ShaderType::Compute); + image_options.user_data = image_user_data; + Check(acquires(image_store, image_options), + "s_barrier after image stores does not acquire image memory"); + const auto vertex_result = RecompileForTest(shader, MakeCompileOptions(ShaderType::Vertex)); CheckSpirvBinaryValidates(vertex_result.spirv);