From 768929bb76f847ba28285f20b5b49688fb2d286d Mon Sep 17 00:00:00 2001 From: danzaio Date: Sat, 10 Oct 2026 13:41:45 -0300 Subject: [PATCH 1/3] test(agc): preparation failures name the shader address and stage FailureCapture now requires the code address and stage in the diagnosed failure, with and without the request dump. Fails before the wrap, passes after. AI-assisted: yes. --- .../tests/execution/PreparedShaders.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp index ed91e5570..e34258828 100644 --- a/core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp @@ -200,7 +200,11 @@ void FailureCapture(AgcDriver::VulkanDevice& device) { #else Require(unsetenv("APS5_DUMP_SHADERS") == 0, "cannot disable shader capture"); #endif - Require(failure([&] { static_cast(AgcDriver::DriverDetail::PrepareShaderWithDiagnostics(request)); }) == expected, "disabled shader capture changed the preparation failure"); + std::ostringstream prefix; + prefix << "shader 0x" << std::hex << request.shader.codeAddress << " stage " << static_cast(request.shader.stage) << ": "; + const auto diagnosed = failure([&] { static_cast(AgcDriver::DriverDetail::PrepareShaderWithDiagnostics(request)); }); + Require(diagnosed.rfind(prefix.str(), 0) == 0, "diagnosed failure names no shader address and stage"); + Require(diagnosed.substr(prefix.str().size()) == expected, "diagnosed failure changed the reason"); Require(!std::ifstream(path, std::ios::binary).is_open(), "disabled shader capture created a request"); #ifdef _WIN32 Require(_putenv_s("APS5_DUMP_SHADERS", "1") == 0, "cannot enable shader capture"); @@ -208,12 +212,14 @@ void FailureCapture(AgcDriver::VulkanDevice& device) { Require(setenv("APS5_DUMP_SHADERS", "1", 1) == 0, "cannot enable shader capture"); #endif const auto actual = failure([&] { static_cast(AgcDriver::DriverDetail::PrepareShaderWithDiagnostics(request)); }); + std::ostringstream dumpedPrefix; + dumpedPrefix << "shader 0x" << std::hex << request.shader.codeAddress << " stage " << static_cast(request.shader.stage) << " (" << path << "): "; + Require(actual == dumpedPrefix.str() + expected, "enabled shader capture changed the diagnosed failure"); #ifdef _WIN32 Require(_putenv_s("APS5_DUMP_SHADERS", saved.c_str()) == 0, "cannot restore shader capture"); #else Require((previous != nullptr ? setenv("APS5_DUMP_SHADERS", saved.c_str(), 1) : unsetenv("APS5_DUMP_SHADERS")) == 0, "cannot restore shader capture"); #endif - Require(actual == expected, "shader capture changed the preparation failure"); std::ifstream file(path, std::ios::binary); std::ostringstream text; text << file.rdbuf(); From e71e3a4b3faefd0642206ec1f95c61fa67eac1d1 Mon Sep 17 00:00:00 2001 From: danzaio Date: Sun, 11 Oct 2026 23:51:39 -0300 Subject: [PATCH 2/3] fix(agc): name the shader address and stage in preparation failures PrepareShaderWithDiagnostics dumped the request but rethrew the raw error, so a failure never said which shader it came from. Wrap it with the shader address and stage, keeping the dump. AI-assisted: yes. --- .../Execution/src/Driver/Shaders/ShaderRegistry.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 580d119af..457ce1b55 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include "RdnaDecoder/RdnaInstructionDecoder.hpp" @@ -31,6 +32,16 @@ namespace AgcDriver::DriverDetail { std::shared_ptr PrepareShaderWithDiagnostics(const ShaderRecompiler::RecompileRequest& request, ShaderRecompiler::ShaderPreparationContext* preparation) { try { return ShaderRecompiler::PrepareShader(request, preparation); + } catch (const std::exception& error) { + std::string dump; + try { + if (std::getenv("APS5_DUMP_SHADERS") != nullptr) dump = Driver::dumpRequest(request.shader.codeAddress, request); + } catch (...) {} + std::ostringstream where; + where << "shader 0x" << std::hex << request.shader.codeAddress << " stage " << static_cast(request.shader.stage); + if (!dump.empty()) where << " (" << dump << ")"; + where << ": "; + throw std::runtime_error(where.str() + error.what()); } catch (...) { try { if (std::getenv("APS5_DUMP_SHADERS") != nullptr) static_cast(Driver::dumpRequest(request.shader.codeAddress, request)); From 56df893667a484c8e2e4057871f55804fca30f9f Mon Sep 17 00:00:00 2001 From: danzaio Date: Mon, 12 Oct 2026 00:46:50 -0300 Subject: [PATCH 3/3] fix(agc): preserve dumps for non-standard shader failures Capture the request once before rethrowing from the shared handler. Standard exceptions keep the shader address, stage, optional dump filename and full message; non-standard exceptions remain unchanged after capture. AI-assisted: yes. --- .../src/Driver/Shaders/ShaderRegistry.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) 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 457ce1b55..e31f423ba 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -30,23 +31,24 @@ namespace AgcDriver::DriverDetail { std::shared_ptr PrepareShaderWithDiagnostics(const ShaderRecompiler::RecompileRequest& request, ShaderRecompiler::ShaderPreparationContext* preparation) { + std::exception_ptr failure; + std::string dump; try { return ShaderRecompiler::PrepareShader(request, preparation); - } catch (const std::exception& error) { - std::string dump; + } catch (...) { + failure = std::current_exception(); try { if (std::getenv("APS5_DUMP_SHADERS") != nullptr) dump = Driver::dumpRequest(request.shader.codeAddress, request); } catch (...) {} + } + try { + std::rethrow_exception(failure); + } catch (const std::exception& error) { std::ostringstream where; where << "shader 0x" << std::hex << request.shader.codeAddress << " stage " << static_cast(request.shader.stage); if (!dump.empty()) where << " (" << dump << ")"; where << ": "; throw std::runtime_error(where.str() + error.what()); - } catch (...) { - try { - if (std::getenv("APS5_DUMP_SHADERS") != nullptr) static_cast(Driver::dumpRequest(request.shader.codeAddress, request)); - } catch (...) {} - throw; } }