From bed19e5d8ce641663626cdbb73d43d64c250f67b Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 23 Aug 2026 03:45:57 +0200 Subject: [PATCH] shader: preserve concurrent subword buffer stores Co-authored-by: Senaxx --- .../backend/spirv/spirvEmitterMemory.cpp | 6 ++-- tests/ShaderRecompilerComputeTests.cpp | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp index 22216af91..10baff4e1 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemory.cpp @@ -436,12 +436,12 @@ void StoreSubwordInBounds(ValueEmitContext& ctx, const IR::MemoryInfo& mem, Unary(ctx.state, OpNot, TypeU32(ctx.state), mask)), value); }; - if (mem.kind == IR::ResourceKind::Lds || mem.kind == IR::ResourceKind::Gds) { - AtomicUpdate(ctx.state, pointer, mem.kind, merge); - } else { + if (mem.kind == IR::ResourceKind::Scratch) { const auto old = ctx.state.builder.AllocateId(); ctx.state.builder.AddFunction({OpLoad, TypeU32(ctx.state), old, pointer}); ctx.state.builder.AddFunction({OpStore, pointer, merge(old)}); + } else { + AtomicUpdate(ctx.state, pointer, mem.kind, merge); } } diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index ab08761df..67ef05856 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -16112,6 +16112,35 @@ TestCase BufferStoreFormatXResource16UintWritesHalfword() { return test; } +TestCase BufferStoreFormatXResource16UintPreservesAdjacentLanes() { + using O = ShaderOpcode; + + std::vector code; + code.push_back(EncodeVop2(0x25, 1, InlineU32(1), 0)); + code.push_back(EncodeMubuf0(0x04u, 0, true, false)); + code.push_back(EncodeMubuf1(1, 0, 0)); + AppendEnd(&code); + + TestCase test; + test.name = "BufferStoreFormatXResource16UintPreservesAdjacentLanes"; + test.code = code; + test.initial = std::vector(32, 0); + for (u32 index = 0; index < 32; index++) { + test.expected.push_back(((index * 2 + 2) << 16) | (index * 2 + 1)); + } + test.opcodes = {O::V_ADD_NC_U32, O::BUFFER_STORE_FORMAT_X, O::S_ENDPGM}; + test.compute_info.threads_num[0] = 64; + test.compute_info.threads_num[1] = 1; + test.compute_info.threads_num[2] = 1; + test.compute_info.thread_ids_num = 1; + test.compute_info.wave_size = 64; + test.has_compute_info = true; + test.user_data = MakeStructuredStorageBufferData(2, 64, false, 11); + test.has_user_data = true; + test.required_spirv = {"OpAtomicLoad", "OpAtomicCompareExchange"}; + return test; +} + TestCase BufferLoadFormatXyResource88UintExtractsBytes() { using O = ShaderOpcode; @@ -19742,6 +19771,7 @@ std::vector MakeCases() { AddCase(BufferLoadFormatXyzwInactiveExecPreservesOverlappingAddress); AddCase(BufferFormatStoreVariants); AddCase(BufferStoreFormatXResource16UintWritesHalfword); + AddCase(BufferStoreFormatXResource16UintPreservesAdjacentLanes); AddCase(BufferLoadFormatXResource8UintZeroExtendsByte); AddCase(BufferLoadFormatXyResource88UintExtractsBytes); AddCase(BufferLoadFormatXyResource8888UnormConvertsFirstTwoComponents);