diff --git a/core/libs/prx/libSceAgcDriver/CMakeLists.txt b/core/libs/prx/libSceAgcDriver/CMakeLists.txt index 65091c14a..90d971f7a 100644 --- a/core/libs/prx/libSceAgcDriver/CMakeLists.txt +++ b/core/libs/prx/libSceAgcDriver/CMakeLists.txt @@ -764,6 +764,14 @@ if(BUILD_TESTING) set_tests_properties(scalar_bitcount64 PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + add_test_executable(scalar_scratch_load_tests ${LIBS_INCLUDE_DIR}/tests/ScalarScratchLoad.cpp) + target_link_libraries(scalar_scratch_load_tests PRIVATE shader_recompiler_agc_driver libc) + configure_windows_unwind(scalar_scratch_load_tests) + add_test(NAME scalar_scratch_load COMMAND scalar_scratch_load_tests) + if(WIN32) + set_tests_properties(scalar_scratch_load PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() add_test_executable(image_sample_gather_tests ${LIBS_INCLUDE_DIR}/tests/ImageSampleGather.cpp) target_link_libraries(image_sample_gather_tests PRIVATE shader_recompiler_agc_driver libc) configure_windows_unwind(image_sample_gather_tests) diff --git a/core/libs/tests/ScalarScratchLoad.cpp b/core/libs/tests/ScalarScratchLoad.cpp new file mode 100644 index 000000000..7c2c770ad --- /dev/null +++ b/core/libs/tests/ScalarScratchLoad.cpp @@ -0,0 +1,38 @@ +#include "Translation/TranslationContext.hpp" +#include "RdnaDecoder/RdnaMemoryOpDecoder.hpp" +#include +#include + +using namespace ShaderRecompiler; +static void Require(bool value) { if (!value) throw std::runtime_error("scalar scratch load regression"); } +static void Check(std::uint32_t opcode, RdnaOpcode expected, std::uint32_t dwords) { + const std::array code{ + (0x3du << 26u) | (opcode << 18u) | (2u << 6u) | 1u, + (125u << 25u) | 0x10u + }; + const RdnaInstruction instruction = DecodeRdnaSmem(0u, code, 0u); + Require(instruction.op == expected); + Require(instruction.family == RdnaInstructionFamily::SMEM); + Require(instruction.dataDwordCount == dwords); + Require(instruction.destination.kind == RdnaOperandKind::ScalarRegister); + Require(instruction.destination.reg == 2u); + Require(instruction.source0.kind == RdnaOperandKind::ScalarRegister); + Require(instruction.source0.reg == 2u); + Require(instruction.memoryOffset == 0x10); + IrProgram program; + auto& block = program.CreateBlock(); + program.SetEntryBlock(block); + TranslationContext context(program, block, 256); + bool threw = false; + try { + context.TranslateInstruction(instruction); + } catch (const std::runtime_error&) { + threw = true; + } + Require(threw); +} +int main() { + Check(0x05u, RdnaOpcode::SScratchLoadDword, 1u); + Check(0x06u, RdnaOpcode::SScratchLoadDwordx2, 2u); + Check(0x07u, RdnaOpcode::SScratchLoadDwordx4, 4u); +} diff --git a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp index 23d5277fa..5986b1d72 100644 --- a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp +++ b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp @@ -697,6 +697,9 @@ enum class RdnaOpcode : std::uint16_t { SBufferLoadDwordx4, SBufferLoadDwordx8, SBufferLoadDwordx16, + SScratchLoadDword, + SScratchLoadDwordx2, + SScratchLoadDwordx4, SGetWaveidInWorkgroup, BufferStoreFormatXy, BufferStoreFormatXyz, diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaMemoryOpDecoder.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaMemoryOpDecoder.cpp index a30ed3d3a..a1a6484f4 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaMemoryOpDecoder.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaMemoryOpDecoder.cpp @@ -59,6 +59,9 @@ constexpr MemoryOpcodeInfo smemOpcodes[] = { {0x02u, RdnaOpcode::SLoadDwordx4, 4, 32, false, false, false}, {0x03u, RdnaOpcode::SLoadDwordx8, 8, 32, false, false, false}, {0x04u, RdnaOpcode::SLoadDwordx16, 16, 32, false, false, false}, + {0x05u, RdnaOpcode::SScratchLoadDword, 1, 32, false, false, false}, + {0x06u, RdnaOpcode::SScratchLoadDwordx2, 2, 32, false, false, false}, + {0x07u, RdnaOpcode::SScratchLoadDwordx4, 4, 32, false, false, false}, {0x08u, RdnaOpcode::SBufferLoadDword, 1, 32, false, false, false}, {0x09u, RdnaOpcode::SBufferLoadDwordx2, 2, 32, false, false, false}, {0x0au, RdnaOpcode::SBufferLoadDwordx4, 4, 32, false, false, false}, diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp index 7473a018d..e68c49ad1 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp @@ -646,6 +646,9 @@ bool IsScalarMemoryOpcode(RdnaOpcode opcode) { case RdnaOpcode::SBufferLoadDwordx4: case RdnaOpcode::SBufferLoadDwordx8: case RdnaOpcode::SBufferLoadDwordx16: + case RdnaOpcode::SScratchLoadDword: + case RdnaOpcode::SScratchLoadDwordx2: + case RdnaOpcode::SScratchLoadDwordx4: return true; default: return false; diff --git a/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp b/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp index 4200d7197..50e26ccf8 100644 --- a/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp +++ b/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp @@ -86,6 +86,7 @@ private: IrU32 widenSubdword(IrValue* value, std::uint32_t bits, bool sign); IrValue* narrowSubdword(IrU32 value, std::uint32_t bits); bool sLoad(const RdnaInstruction& inst, bool raw); + bool sScratchLoad(const RdnaInstruction& inst); bool bufferLoad(const RdnaInstruction& inst); bool bufferLoadFormatD16(const RdnaInstruction& inst); bool bufferStoreFormatD16(const RdnaInstruction& inst); diff --git a/core/shader/recompiler/Translation/src/MemoryInstructions/MemoryInstructionDispatch.cpp b/core/shader/recompiler/Translation/src/MemoryInstructions/MemoryInstructionDispatch.cpp index 66bc02885..24993bd96 100644 --- a/core/shader/recompiler/Translation/src/MemoryInstructions/MemoryInstructionDispatch.cpp +++ b/core/shader/recompiler/Translation/src/MemoryInstructions/MemoryInstructionDispatch.cpp @@ -40,6 +40,10 @@ bool TranslationContext::emitMemory(const RdnaInstruction& inst) { case RdnaOpcode::SBufferLoadDwordx8: case RdnaOpcode::SBufferLoadDwordx16: return sLoad(inst, false); + case RdnaOpcode::SScratchLoadDword: + case RdnaOpcode::SScratchLoadDwordx2: + case RdnaOpcode::SScratchLoadDwordx4: + return sScratchLoad(inst); case RdnaOpcode::SGetWaveidInWorkgroup: { if (program.Resources().stage != IrShaderStage::Compute) { throw std::runtime_error("s_get_waveid_in_workgroup is supported only in compute shaders, at pc " + std::to_string(inst.programCounter)); diff --git a/core/shader/recompiler/Translation/src/MemoryInstructions/ScalarBufferInstructions.cpp b/core/shader/recompiler/Translation/src/MemoryInstructions/ScalarBufferInstructions.cpp index 5ae223245..27cf1eb5b 100644 --- a/core/shader/recompiler/Translation/src/MemoryInstructions/ScalarBufferInstructions.cpp +++ b/core/shader/recompiler/Translation/src/MemoryInstructions/ScalarBufferInstructions.cpp @@ -52,6 +52,10 @@ bool TranslationContext::sLoad(const RdnaInstruction& inst, bool raw) { return true; } +bool TranslationContext::sScratchLoad(const RdnaInstruction& /*inst*/) { + throw std::runtime_error("s_scratch_load not yet implemented: wave-uniform or swizzled scratch layout required"); +} + void TranslationContext::TranslateCodeTableLoad(const RdnaInstruction& instruction, const ControlFlowGraph::CodeTableLoad& table) { if (table.values.empty()) throw std::runtime_error("empty shader code table"); const IrU32 index = readRawU32(instruction.source1);