diff --git a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp index f8ec573ee..d5f8f46cd 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp @@ -2853,6 +2853,20 @@ KYTY_CP_OP_PARSER(CpOpSetShaderReg) { auto pfunc = g_hw_sh_func[cmd_offset]; if (pfunc == nullptr) { + auto num_values = KYTY_PM4_LEN(cmd_id) - 2u; + bool handled = num_values != 0; + for (uint32_t i = 0; i < num_values; i++) { + if (cmd_offset + i >= Pm4::SH_NUM || g_hw_sh_indirect_func[cmd_offset + i] == nullptr) { + handled = false; + break; + } + } + if (handled) { + for (uint32_t i = 0; i < num_values; i++) { + g_hw_sh_indirect_func[cmd_offset + i](cp, cmd_offset + i, buffer[1 + i]); + } + return num_values + 1u; + } EXIT("unknown shader register\n\t%05" PRIx32 ":\n\tcmd_id = %08" PRIx32 "\n\tcmd_offset = %08" PRIx32 "\n", num_dw - dw, cmd_id, cmd_offset); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 139f18758..8a723f799 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -22084,6 +22084,25 @@ void CheckPm4StencilInfoValueLane(RenderContext &renderer) { std::printf("[host] %-32s ok\n", "Pm4StencilInfoValueLane"); } +void CheckPm4DirectShaderRegisterFallback(RenderContext &renderer) { + GraphicsInitJmpTables(); + CommandProcessor processor(renderer); + constexpr uint64_t shader_address = 0x0000123456789a00ull; + std::array packet{ + KYTY_PM4(4, Pm4::IT_SET_SH_REG, Pm4::R_ZERO), + Pm4::SPI_SHADER_PGM_LO_ES, + static_cast(shader_address >> 8u), + static_cast(shader_address >> 40u), + }; + Pm4Execution execution; + Require("Pm4DirectShaderRegisterFallback", "ES program base", + processor.Process(execution, packet.data(), packet.size()) == + Pm4ProcessResult::Complete && + processor.GetShCtx().GetVs().es_regs.data_addr == shader_address, + "direct SET_SH_REG did not route its ES base pair through the register handlers"); + std::printf("[host] %-32s ok\n", "Pm4DirectShaderRegisterFallback"); +} + void CheckPm4PolygonOffsetRegisters(RenderContext &renderer) { GraphicsInitJmpTables(); CommandProcessor processor(renderer); @@ -22676,6 +22695,7 @@ int main(int argc, char **argv) { CheckVulkan13FeatureRequirements(); CheckPm4AcquireMemNoOp(vulkan.RuntimeRenderer()); CheckPm4StencilInfoValueLane(vulkan.RuntimeRenderer()); + CheckPm4DirectShaderRegisterFallback(vulkan.RuntimeRenderer()); CheckPm4PolygonOffsetRegisters(vulkan.RuntimeRenderer()); CheckPm4ContextStateOperations(vulkan.RuntimeRenderer()); CheckPm4WaitResume(vulkan.RuntimeRenderer());