feat(agc): trace shader addresses for each draw

This commit is contained in:
MarcZX100 authored and Adrià Franch committed 2026-10-14 23:39:27 +02:00
1 parent 153d5d469d
commit fffa0f3865
6 files changed
+148

No files matched your search

@@ -145,6 +145,7 @@ set(agcDriverSources
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Dispatch/IndirectDispatch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Dispatch/VariantValidation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/Draw.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawProgramTrace.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawCache.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawCacheStatistics.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Execution/src/Driver/Draw/DrawCapture.cpp
@@ -290,6 +291,21 @@ if(APS5_ENABLE_TRACY)
target_link_libraries(libSceAgcDriver PUBLIC TracyClient)
endif()
if(BUILD_TESTING)
add_test_executable(agc_driver_draw_program_trace_tests
tests/DrawProgramTrace.cpp
Execution/src/Driver/Draw/DrawProgramTrace.cpp
)
target_include_directories(agc_driver_draw_program_trace_tests PRIVATE
${LIBS_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/core/shader/recompiler
)
set_target_properties(agc_driver_draw_program_trace_tests PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_driver_draw_program_trace_tests)
add_test(NAME agc_driver_draw_program_trace COMMAND agc_driver_draw_program_trace_tests)
set_tests_properties(agc_driver_draw_program_trace PROPERTIES TIMEOUT 20)
endif()
set_target_properties(libSceAgcDriver PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(libSceAgcDriver)
@@ -0,0 +1,22 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_DRAW_DRAWPROGRAMTRACE_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_EXECUTION_INCLUDE_DRIVER_DRAW_DRAWPROGRAMTRACE_HPP
#include "Recompiler.hpp"
#include <cstdint>
#include <span>
#include <string>
namespace AgcDriver::DriverDetail {
struct DrawProgramTraceEntry {
ShaderRecompiler::ShaderStage stage;
ShaderRecompiler::ProgramRole role;
std::uint64_t codeAddress;
std::uint64_t entryAddress;
};
std::string FormatDrawProgramTrace(std::uint64_t submission, std::uint32_t queue, std::span<const DrawProgramTraceEntry> programs);
}
#endif
@@ -1,11 +1,13 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Diagnostics.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawProgramTrace.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include "prx/libSceAgcDriver/Execution/include/PerformanceTimer.hpp"
#include "prx/libSceAgcDriver/Execution/include/Pm4.hpp"
#include "Optimization/ResourceProgram.hpp"
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
namespace AgcDriver::DriverDetail {
@@ -147,6 +149,16 @@ DrawVerdict Driver::draw(QueueState& queue, std::span<const std::uint32_t> packe
if (!drawParameters.indirect) setMeshIndexBuffer(drawParameters);
else if (graphics.stages.mesh) setMeshIndexBuffer(Pm4::DrawParameters{drawParameters.indexAddress, std::max(drawParameters.indexCount, 1u), drawParameters.indexSize, 1, 0, drawParameters.indexed});
const std::vector<Role>& roles = decode->roles;
static const bool tracePrograms = std::getenv("APS5_TRACE_DRAW_PROGRAMS") != nullptr;
if (tracePrograms) {
std::vector<DrawProgramTraceEntry> identities;
identities.reserve(programs.size());
for (std::size_t i = 0; i < programs.size(); ++i) {
identities.push_back({programs[i].binary.stage, roles[i], programs[i].snapshot->codeAddress, programs[i].binary.codeAddress});
}
const auto line = FormatDrawProgramTrace(submission.serial, submission.queue, identities);
std::fprintf(stderr, "%s\n", line.c_str());
}
phaseTiming.Phase(DrawRowDecode);
const auto locate = [&](std::uint32_t location) -> std::optional<std::pair<std::size_t, std::size_t>> {
@@ -0,0 +1,55 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawProgramTrace.hpp"
#include <cstdio>
#include <stdexcept>
namespace AgcDriver::DriverDetail {
namespace {
const char* StageName(ShaderRecompiler::ShaderStage stage) {
using ShaderRecompiler::ShaderStage;
switch (stage) {
case ShaderStage::Compute: return "compute";
case ShaderStage::Vertex: return "vertex";
case ShaderStage::TessellationControl: return "tess-control";
case ShaderStage::TessellationEvaluation: return "tess-evaluation";
case ShaderStage::Geometry: return "geometry";
case ShaderStage::Fragment: return "fragment";
case ShaderStage::Local: return "local";
case ShaderStage::Mesh: return "mesh";
}
throw std::invalid_argument("unknown shader stage in draw trace");
}
const char* RoleName(ShaderRecompiler::ProgramRole role) {
using ShaderRecompiler::ProgramRole;
switch (role) {
case ProgramRole::Main: return "main";
case ProgramRole::GeometryBack: return "geometry-back";
case ProgramRole::Local: return "local";
case ProgramRole::Hull: return "hull";
case ProgramRole::Domain: return "domain";
case ProgramRole::Fragment: return "fragment";
}
throw std::invalid_argument("unknown program role in draw trace");
}
}
std::string FormatDrawProgramTrace(std::uint64_t submission, std::uint32_t queue, std::span<const DrawProgramTraceEntry> programs) {
char prefix[128];
const auto size = std::snprintf(prefix, sizeof(prefix), "[draw-programs] submission=%llu queue=0x%x count=%zu",
static_cast<unsigned long long>(submission), queue, programs.size());
if (size < 0 || static_cast<std::size_t>(size) >= sizeof(prefix)) throw std::runtime_error("draw program trace prefix overflow");
std::string result(prefix, static_cast<std::size_t>(size));
char item[160];
for (const auto& program : programs) {
const auto itemSize = std::snprintf(item, sizeof(item), " %s/%s=0x%llx(entry=0x%llx)",
StageName(program.stage), RoleName(program.role),
static_cast<unsigned long long>(program.codeAddress), static_cast<unsigned long long>(program.entryAddress));
if (itemSize < 0 || static_cast<std::size_t>(itemSize) >= sizeof(item)) throw std::runtime_error("draw program trace entry overflow");
result.append(item, static_cast<std::size_t>(itemSize));
}
return result;
}
}
@@ -0,0 +1,41 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Draw/DrawProgramTrace.hpp"
#include <iostream>
#include <stdexcept>
#include <string>
namespace {
void Check(bool condition, const char* message) {
if (!condition) throw std::runtime_error(message);
}
void EmptyTrace() {
const auto trace = AgcDriver::DriverDetail::FormatDrawProgramTrace(12, 3, {});
Check(trace == "[draw-programs] submission=12 queue=0x3 count=0", "empty draw trace changed shape");
}
void ProgramAddresses() {
using namespace AgcDriver::DriverDetail;
using ShaderRecompiler::ProgramRole;
using ShaderRecompiler::ShaderStage;
const DrawProgramTraceEntry entries[]{
{ShaderStage::Vertex, ProgramRole::Main, 0x100000, 0x100040},
{ShaderStage::Fragment, ProgramRole::Fragment, 0x200000, 0x200020},
};
const auto trace = FormatDrawProgramTrace(42, 0x9, entries);
Check(trace == "[draw-programs] submission=42 queue=0x9 count=2 vertex/main=0x100000(entry=0x100040) fragment/fragment=0x200000(entry=0x200020)",
"draw trace omitted the selected shader code or entry address");
}
}
int main() {
try {
EmptyTrace();
ProgramAddresses();
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';
return 1;
}
return 0;
}
+2
View File
@@ -252,11 +252,13 @@ function(add_shader_recompiler target runtimeTarget)
SampledTextureNumericClass
SetDebugProbeActive
ShaderCacheDirectory
ShaderStage
SrgbDecodeBit
SrgbUnormFormat
FindUserDataTail
LinkUserDataTail
ThreadOwned
ProgramRole
UnresolvableSwappcTarget
ValidateAndOptimizeSpirv
FindUserDataCalls