mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-31 12:35:51 +00:00
feat(agc): APS5_DUMP_SHADERS takes a list of program addresses
A comma-separated list of hex program addresses (optional 0x prefix) now writes only those programs' requests, so one expensive shader can be captured without serializing every request a title prepares. Any other value, such as 1, keeps writing every request. A filtered-out program returns no name, so diagnostics never point at a file that was not written, and it stays eligible for a later list. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
750cf6cf48
commit
ae305dfd5d
3 files changed
+72
-1
No files matched your search
@@ -1,12 +1,37 @@
|
||||
#include "prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/Mutex.hpp"
|
||||
#include "ControlFlow/RequestSerializer.hpp"
|
||||
#include <charconv>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace AgcDriver::DriverDetail {
|
||||
|
||||
namespace {
|
||||
|
||||
std::optional<std::set<std::uint64_t>> selectedPrograms() {
|
||||
const char* value = std::getenv("APS5_DUMP_SHADERS");
|
||||
if (value == nullptr || std::string_view(value) == "1") return std::nullopt;
|
||||
std::set<std::uint64_t> programs;
|
||||
std::string_view rest(value);
|
||||
while (!rest.empty()) {
|
||||
const auto comma = rest.find(',');
|
||||
auto token = rest.substr(0, comma);
|
||||
rest = comma == std::string_view::npos ? std::string_view{} : rest.substr(comma + 1);
|
||||
if (token.starts_with("0x") || token.starts_with("0X")) token.remove_prefix(2);
|
||||
std::uint64_t address = 0;
|
||||
const auto [end, error] = std::from_chars(token.data(), token.data() + token.size(), address, 16);
|
||||
if (token.empty() || error != std::errc{} || end != token.data() + token.size()) return std::nullopt;
|
||||
programs.insert(address);
|
||||
}
|
||||
if (programs.empty()) return std::nullopt;
|
||||
return programs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Driver::reportSkip(const char* kind, const std::string& what) {
|
||||
static AgcDriver::Mutex reportedMutex;
|
||||
static std::set<std::size_t> reported;
|
||||
@@ -56,6 +81,7 @@ std::string Driver::dumpRequest(std::uint64_t address, const ShaderRecompiler::R
|
||||
char hex[32];
|
||||
std::snprintf(hex, sizeof(hex), "%llx", static_cast<unsigned long long>(address));
|
||||
const std::string name = "shader_" + std::string(hex) + std::string(suffix) + ".req";
|
||||
if (const auto selected = selectedPrograms(); selected.has_value() && !selected->contains(address)) return {};
|
||||
std::lock_guard lock(dumpMutex);
|
||||
if (!dumped.insert(name).second) return name;
|
||||
try {
|
||||
|
||||
@@ -195,6 +195,50 @@ void Run(AgcDriver::VulkanDevice& device) {
|
||||
ExpectFailure([&] { static_cast<void>(AgcDriver::DriverDetail::SourceHandleFor(snapshot, 0, request)); }, "does not refer to registered code");
|
||||
}
|
||||
|
||||
void DumpSelection(AgcDriver::VulkanDevice& device) {
|
||||
using namespace ShaderRecompiler;
|
||||
const std::array<std::uint32_t, 1> code{0xffffffffu};
|
||||
const std::vector<std::byte> header(2048, std::byte{0x5a});
|
||||
RecompileRequest request{{ShaderStage::Compute, 0x12345cafeull, code, 0x20000, header},
|
||||
{32, 0, {}, ShaderComputeStageInfo{{1, 1, 1}, 0, {}, false, 1, {}}, {}, {}, {}}, device.ComputeTarget(32), {0, 0, 0, 128}};
|
||||
const char* previous = std::getenv("APS5_DUMP_SHADERS");
|
||||
const std::string saved = previous != nullptr ? previous : "";
|
||||
const auto setCapture = [](const char* value) {
|
||||
#ifdef _WIN32
|
||||
Require(_putenv_s("APS5_DUMP_SHADERS", value) == 0, "cannot set shader capture");
|
||||
#else
|
||||
Require(setenv("APS5_DUMP_SHADERS", value, 1) == 0, "cannot set shader capture");
|
||||
#endif
|
||||
};
|
||||
const auto written = [](const std::string& name) {
|
||||
const bool exists = std::ifstream(name, std::ios::binary).is_open();
|
||||
std::remove(name.c_str());
|
||||
return exists;
|
||||
};
|
||||
const std::string excludedPath = "shader_12345cafe_excluded.req";
|
||||
const std::string listedPath = "shader_12345cafe_listed.req";
|
||||
const std::string otherPath = "shader_feedface_unlisted.req";
|
||||
std::remove(excludedPath.c_str());
|
||||
std::remove(listedPath.c_str());
|
||||
std::remove(otherPath.c_str());
|
||||
setCapture("feedface");
|
||||
Require(AgcDriver::DriverDetail::Driver::dumpRequest(request.shader.codeAddress, request, "_excluded").empty(), "a program outside the APS5_DUMP_SHADERS list was named as dumped");
|
||||
Require(!written(excludedPath), "a program outside the APS5_DUMP_SHADERS list was dumped");
|
||||
setCapture("feedface,0x12345CAFE");
|
||||
Require(AgcDriver::DriverDetail::Driver::dumpRequest(request.shader.codeAddress, request, "_excluded") == excludedPath, "a program dropped by an earlier list was not dumped once listed");
|
||||
Require(written(excludedPath), "a listed program's request was not written after an earlier list dropped it");
|
||||
Require(AgcDriver::DriverDetail::Driver::dumpRequest(request.shader.codeAddress, request, "_listed") == listedPath, "a listed program was not dumped");
|
||||
Require(written(listedPath), "a listed program's request was not written");
|
||||
setCapture("12345cafe,not-an-address");
|
||||
Require(AgcDriver::DriverDetail::Driver::dumpRequest(0xfeedfaceull, request, "_unlisted") == otherPath, "a value that is not an address list did not dump every program");
|
||||
Require(written(otherPath), "a value that is not an address list did not write the request");
|
||||
#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
|
||||
}
|
||||
|
||||
void FailureCapture(AgcDriver::VulkanDevice& device) {
|
||||
using namespace ShaderRecompiler;
|
||||
const std::array<std::uint32_t, 1> code{0xffffffffu};
|
||||
@@ -1543,6 +1587,7 @@ int main(int argc, char** argv) {
|
||||
Run(*device);
|
||||
RegisteredVertexWorkgroup(device->Target());
|
||||
FailureCapture(*device);
|
||||
DumpSelection(*device);
|
||||
PendingRegistrationPreparation(*device);
|
||||
AwaitedRegistrationPreparation();
|
||||
Require(argc != 2 || std::string_view(argv[1]) != "--fail-before-registration", "injected failure before registration");
|
||||
|
||||
@@ -148,7 +148,7 @@ The code reads environment names through `getenv`, `IsEnvironmentSet`, `kibSetti
|
||||
| `APS5_DUMP_QUEUE` | integer | `core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp` | | dumps the first submissions of the queue with this hex id |
|
||||
| `APS5_DUMP_REJECTED` | presence | `core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/CommandValidation.cpp` | | writes a rejected submission to rejected_submission_<n>.bin |
|
||||
| `APS5_DUMP_SCALE` | integer | `core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp` | 4 | keeps every n-th pixel in each direction of a dumped frame (1 to 16384; any other value fails) |
|
||||
| `APS5_DUMP_SHADERS` | presence | `core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp` | | writes each prepared shader's request to shader_<address>.req |
|
||||
| `APS5_DUMP_SHADERS` | string | `core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp` | | writes each prepared shader's request to shader_<address>.req; a comma-separated list of hex program addresses (for example `807b90a100,0x807b925400`) writes only those programs' requests, and any other value (such as `1`) writes every request |
|
||||
| `APS5_DUMP_STORAGE` | string | `core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp` | | selects storage textures to dump by hex address or WxHxL[:format] extent as storage_<address>_<n>.raw |
|
||||
| `APS5_DUMP_STORAGE_GATE` | path | `core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp` | | with `APS5_DUMP_STORAGE`, waits for this path to exist and reads matching live images directly without guest writeback; at most eight addresses, 8 MiB linear storage per image; writes `storage_direct_<address>_<n>.raw` with the existing pitch, height and VkFormat header and first-mip pixels |
|
||||
| `APS5_TEST_DIRECT_READBACK` | set | `core/libs/prx/libSceAgcDriver/tests/execution/LayeredVolumeDraw.cpp` | | runs the clean-volume gated live-image readback regression in the layered volume execution test |
|
||||
|
||||
Reference in new issue
Block a user