diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp index 585355b3b..2438ab9bb 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp @@ -179,6 +179,21 @@ void PublishRegisteredShader(std::shared_ptr& registry, const st transaction.Commit(); } +namespace { + +bool PreparedAtUse(const ShaderSnapshot& snapshot, const ShaderRecompiler::RecompileRequest& request) { + if (snapshot.codeAddress == NullPixelProgramAddress() && request.shader.stage == ShaderRecompiler::ShaderStage::Fragment) { + APS5_LOG_ERR("The null pixel program has no artifact for this draw (wave %u, %zu user SGPRs); preparing it at draw", request.context.waveSize, request.context.userData.size()); + return true; + } + if (!snapshot.header.empty()) return snapshot.prepared->deferred; + if (snapshot.type != 0 || request.shader.stage != ShaderRecompiler::ShaderStage::Compute) throw std::runtime_error("AGC driver: unregistered program is not a compute shader"); + APS5_LOG_ERR("Compute shader 0x%llx was not registered; preparing its artifact at dispatch", static_cast(snapshot.codeAddress)); + return true; +} + +} + std::shared_ptr SourceHandleFor(const ShaderSnapshot& snapshot, std::size_t codeOffset, const ShaderRecompiler::RecompileRequest& request) { struct PreparedKeyStorage {}; auto& key = HostThreadLocal, PreparedKeyStorage>(); @@ -187,11 +202,7 @@ std::shared_ptr SourceHandleFor(const Shad for (const auto& entry : snapshot.prepared->entries) { if (entry.codeOffset == codeOffset && ShaderRecompiler::MatchesPreparedShader(request, *entry.handle, key)) return entry.handle; } - if (snapshot.header.empty() || snapshot.prepared->deferred) { - if (snapshot.header.empty()) { - if (snapshot.type != 0 || request.shader.stage != ShaderRecompiler::ShaderStage::Compute) throw std::runtime_error("AGC driver: unregistered program is not a compute shader"); - APS5_LOG_ERR("Compute shader 0x%llx was not registered; preparing its artifact at dispatch", static_cast(snapshot.codeAddress)); - } + if (PreparedAtUse(snapshot, request)) { auto handle = PrepareShaderWithDiagnostics(request); snapshot.prepared->entries.push_back({codeOffset, handle}); return handle; @@ -241,11 +252,7 @@ ShaderRecompiler::PreparedShaderInvocation InvocationFor(const ShaderSnapshot& s invocationRequest.shader.code = ShaderRecompiler::GetPreparedCode(*entry.handle); if (auto invocation = ShaderRecompiler::PreparedShaderInvocation::TryCreate(invocationRequest, entry.handle, key)) return std::move(*invocation); } - if (snapshot.header.empty() || snapshot.prepared->deferred) { - if (snapshot.header.empty()) { - if (snapshot.type != 0 || request.shader.stage != ShaderRecompiler::ShaderStage::Compute) throw std::runtime_error("AGC driver: unregistered program is not a compute shader"); - APS5_LOG_ERR("Compute shader 0x%llx was not registered; preparing its artifact at dispatch", static_cast(snapshot.codeAddress)); - } + if (PreparedAtUse(snapshot, request)) { auto handle = PrepareShaderWithDiagnostics(request); invocationRequest = request; invocationRequest.shader.code = ShaderRecompiler::GetPreparedCode(*handle); diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp index 883ce2786..398982104 100644 --- a/core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp @@ -2,6 +2,7 @@ #include "Optimization/ResourceProgram.hpp" #include "ControlFlow/RequestSerializer.hpp" #include "prx/libSceAgcDriver/Execution/include/Driver/Shaders/ShaderRegistry.hpp" +#include "prx/libSceAgcDriver/Graphics/include/ShaderInputState.hpp" #include "prx/libSceAgcDriver/Execution/include/Driver.hpp" #include "prx/libSceAgcDriver/Submit/include/Acb.hpp" #include @@ -63,7 +64,24 @@ void RunUnregistered(AgcDriver::VulkanDevice& device, ShaderRecompiler::Recompil } } +void NullPixelAtDraw(AgcDriver::VulkanDevice& device) { + std::vector code(64, 0); + code.front() = 0xbf810000u; + AgcDriver::DriverDetail::ShaderSnapshot snapshot{AgcDriver::DriverDetail::NullPixelProgramAddress(), 0, 1, code, {}}; + snapshot.header.resize(sizeof(Shader)); + std::array users{}; + const auto pixel = AgcDriver::Graphics::DecodePixelStageInfo({}, {}, true); + const ShaderRecompiler::RecompileRequest registered{{ShaderRecompiler::ShaderStage::Fragment, snapshot.codeAddress, snapshot.code, 0, {}}, {64, 0, {}, {}, pixel, {}, {}}, device.Target(), {0, 0, 0, 128}}; + snapshot.prepared->entries.push_back({0, ShaderRecompiler::PrepareShader(registered)}); + ShaderRecompiler::RecompileRequest request{{ShaderRecompiler::ShaderStage::Fragment, snapshot.codeAddress, snapshot.code, 0, {}}, {32, 0, users, {}, pixel, {}, {}}, device.Target(), {0, 0, 20, 108}}; + static_cast(AgcDriver::DriverDetail::InvocationFor(snapshot, 0, request)); + Require(snapshot.prepared->entries.size() == 2, "the null pixel program was not prepared at draw"); + static_cast(AgcDriver::DriverDetail::InvocationFor(snapshot, 0, request)); + Require(AgcDriver::DriverDetail::SourceHandleFor(snapshot, 0, request) == snapshot.prepared->entries.back().handle && snapshot.prepared->entries.size() == 2, "the null pixel program was prepared again for the same draw"); +} + void Run(AgcDriver::VulkanDevice& device) { + NullPixelAtDraw(device); alignas(256) std::array code{0xbf810000u}; std::array users{}; const ShaderRecompiler::ShaderComputeStageInfo compute{{1, 1, 1}, 0, {false, false, false}, false, 1, {}};