mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
Implement AGC async rewind imports
This commit is contained in:
@@ -50,6 +50,7 @@
|
||||
#include "libs/agc.h"
|
||||
#include "libs/dialog.h"
|
||||
#include "libs/errno.h"
|
||||
#include "loader/symbolDatabase.h"
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
|
||||
#if __has_include("graphics/host_gpu/renderer/renderTargetBarriers.h")
|
||||
@@ -104,6 +105,10 @@
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
namespace Libs {
|
||||
void InitAgcDriver_1(Loader::SymbolDatabase *symbols);
|
||||
}
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
template <typename Cache>
|
||||
@@ -41645,35 +41650,97 @@ void CheckPm4WaitResume(RenderContext &renderer) {
|
||||
}
|
||||
|
||||
void CheckPm4RewindResume(RenderContext &renderer) {
|
||||
constexpr const char *name = "Pm4RewindResume";
|
||||
Loader::SymbolDatabase symbols;
|
||||
Libs::InitAgcDriver_1(&symbols);
|
||||
const auto *emit_symbol = symbols.FindByNid("DwICrVxerkY", Loader::SymbolType::Func);
|
||||
const auto *patch_symbol = symbols.FindByNid("eWaWyFegzgQ", Loader::SymbolType::Func);
|
||||
Require(name, "async exports",
|
||||
emit_symbol != nullptr && patch_symbol != nullptr &&
|
||||
emit_symbol->vaddr == reinterpret_cast<uint64_t>(&Gen5::AgcAcbRewind) &&
|
||||
patch_symbol->vaddr ==
|
||||
reinterpret_cast<uint64_t>(&Gen5::AgcRewindPatchSetRewindState),
|
||||
"async rewind imports did not resolve to the emitter and state patch");
|
||||
const auto async_patch = reinterpret_cast<decltype(&Gen5::AgcRewindPatchSetRewindState)>(
|
||||
patch_symbol->vaddr);
|
||||
|
||||
constexpr uint32_t sentinel = 0x12345678u;
|
||||
std::array<uint32_t, 4> packet{sentinel, sentinel, sentinel, sentinel};
|
||||
CommandBufferLayout acb{packet.data(), packet.data() + packet.size(),
|
||||
packet.data() + 1, packet.data() + 3, nullptr, nullptr, 0};
|
||||
auto *buffer = reinterpret_cast<Gen5::CommandBuffer *>(&acb);
|
||||
for (const uint8_t state : {0, 1}) {
|
||||
for (const uint8_t offload : {0, 1}) {
|
||||
acb.cursor_up = packet.data() + 1;
|
||||
Require(name, "async packet",
|
||||
Gen5::AgcAcbRewind(buffer, state, offload) == packet.data() + 1 &&
|
||||
acb.cursor_up == packet.data() + 3 &&
|
||||
packet[0] == sentinel && packet[3] == sentinel &&
|
||||
packet[1] == 0xc0005900u &&
|
||||
packet[2] == ((uint32_t{state} << 31u) | (uint32_t{offload} << 24u)),
|
||||
"async rewind packet or two-DWORD allocation differs from the native command");
|
||||
}
|
||||
}
|
||||
const auto before = packet;
|
||||
acb.cursor_up = packet.data() + 1;
|
||||
acb.reserved_dw = 1;
|
||||
Require(name, "bounded allocation",
|
||||
Gen5::AgcAcbRewind(buffer, 1, 1) == nullptr &&
|
||||
Gen5::AgcAcbRewind(nullptr, 1, 1) == nullptr &&
|
||||
acb.cursor_up == packet.data() + 1 && packet == before,
|
||||
"failed rewind allocation changed the cursor or command storage");
|
||||
|
||||
// Native patchers inspect only the opcode, preserving the header and low 31 bits.
|
||||
std::array<uint32_t, 2> command{0xa5ff591fu, 0x0155aa55u};
|
||||
Require(name, "patch preserves fields",
|
||||
async_patch(command.data(), 1) == 0 && command[0] == 0xa5ff591fu &&
|
||||
command[1] == 0x8155aa55u && async_patch(command.data(), 0) == 0 &&
|
||||
command[0] == 0xa5ff591fu && command[1] == 0x0155aa55u,
|
||||
"rewind patch changed the offload bit, header, or unrelated payload bits");
|
||||
command[0] = 0xc0001000u;
|
||||
const auto invalid = command;
|
||||
Require(name, "wrong opcode",
|
||||
async_patch(command.data(), 1) == static_cast<int>(0x8a6c000cu) &&
|
||||
command == invalid,
|
||||
"rewind patch accepted or modified a packet with the wrong opcode");
|
||||
|
||||
GraphicsInitJmpTables();
|
||||
CommandProcessor processor(renderer, 0);
|
||||
|
||||
uint32_t suffix = 0;
|
||||
const auto address = reinterpret_cast<uint64_t>(&suffix);
|
||||
std::array<uint32_t, 7> commands{};
|
||||
commands[0] = KYTY_PM4(2, Pm4::IT_REWIND, 0);
|
||||
commands[1] = 0;
|
||||
commands[2] = KYTY_PM4(5, Pm4::IT_WRITE_DATA, 0);
|
||||
commands[3] = 0;
|
||||
commands[4] = static_cast<uint32_t>(address);
|
||||
commands[5] = static_cast<uint32_t>(address >> 32u);
|
||||
commands[6] = 33;
|
||||
|
||||
Pm4Execution execution;
|
||||
Require("Pm4RewindResume", "pending",
|
||||
processor.Process(execution, commands) == Pm4ProcessResult::Blocked &&
|
||||
suffix == 0,
|
||||
"pending rewind did not preserve its command position");
|
||||
Require("Pm4RewindResume", "patch valid",
|
||||
Gen5::AgcRewindPatchSetRewindState(commands.data(), 1) == 0 &&
|
||||
commands[1] == 0x80000000u,
|
||||
"rewind state patch did not set the valid bit");
|
||||
Require("Pm4RewindResume", "resume",
|
||||
processor.Process(execution, commands) ==
|
||||
Pm4ProcessResult::Complete &&
|
||||
suffix == 33,
|
||||
"valid rewind did not resume at the following packet");
|
||||
std::printf("[host] %-32s ok\n", "Pm4RewindResume");
|
||||
for (const bool async : {false, true}) {
|
||||
for (const uint8_t offload : {0, 1}) {
|
||||
if (!async && offload != 0) {
|
||||
continue;
|
||||
}
|
||||
uint32_t suffix = 0;
|
||||
const auto address = reinterpret_cast<uint64_t>(&suffix);
|
||||
std::array<uint32_t, 7> commands{
|
||||
0, 0, KYTY_PM4(5, Pm4::IT_WRITE_DATA, 0), 0,
|
||||
static_cast<uint32_t>(address), static_cast<uint32_t>(address >> 32u), 33};
|
||||
CommandBufferLayout cb{commands.data(), commands.data() + 2,
|
||||
commands.data(), commands.data() + 2, nullptr, nullptr, 0};
|
||||
auto *command_buffer = reinterpret_cast<Gen5::CommandBuffer *>(&cb);
|
||||
const auto *emitted = async ? Gen5::AgcAcbRewind(command_buffer, 0, offload)
|
||||
: Gen5::AgcDcbRewind(command_buffer, 0);
|
||||
const auto patch = async ? async_patch : &Gen5::AgcRewindPatchSetRewindState;
|
||||
Pm4Execution execution;
|
||||
Require(name, "pending",
|
||||
emitted == commands.data() &&
|
||||
processor.Process(execution, commands) == Pm4ProcessResult::Blocked &&
|
||||
suffix == 0,
|
||||
"pending rewind did not preserve its command position");
|
||||
Require(name, "still pending",
|
||||
processor.Process(execution, commands) == Pm4ProcessResult::Blocked &&
|
||||
!execution.MadeProgress() && suffix == 0,
|
||||
"pending rewind advanced before its state was patched");
|
||||
Require(name, "patch and resume",
|
||||
patch(commands.data(), 1) == 0 &&
|
||||
commands[1] == (0x80000000u | (uint32_t{offload} << 24u)) &&
|
||||
processor.Process(execution, commands) == Pm4ProcessResult::Complete &&
|
||||
suffix == 33,
|
||||
"patched rewind lost the offload bit or failed to resume");
|
||||
}
|
||||
}
|
||||
std::printf("[host] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckPm4CeCompletion(RenderContext &renderer) {
|
||||
|
||||
Reference in New Issue
Block a user