mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
fix(agc): preserve inputs for deferred buffer copies
This commit is contained in:
1 parent
c6a3e25573
commit
143aec54c2
1 file changed
+44
-7
@@ -4,6 +4,7 @@
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Recorder.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/UnitShadow.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/CaptureTrace.hpp"
|
||||
#include "prx/libc/include/CpuTopology.hpp"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
@@ -1767,6 +1768,8 @@ void GuestBufferMemory::copyRegion(Region& region, bool addressable) {
|
||||
|
||||
void GuestBufferMemory::recordGpuCopies(std::span<Region* const> copies, bool addressable) {
|
||||
static const bool profile = std::getenv("APS5_PROFILE_DRAW") != nullptr;
|
||||
static const bool capture = std::getenv("APS5_CAPTURE_GPU_COPIES") != nullptr;
|
||||
Require(!capture || CaptureTrace::Enabled(), "GPU copy capture requires APS5_CAPTURE_TRACE");
|
||||
auto* recorder = Recorder::Active();
|
||||
Require(recorder != nullptr, "GPU buffer copies need an active recorder");
|
||||
// A queued DCC key store or label store over a copied range lands before the copy reads it.
|
||||
@@ -1781,9 +1784,6 @@ void GuestBufferMemory::recordGpuCopies(std::span<Region* const> copies, bool ad
|
||||
for (const auto* region : copies) reads.emplace_back(region->begin, region->end);
|
||||
recorder->NoteAccess(Recorder::CommandClass::StagingIn, Recorder::Access{reads, {}, {}, VK_PIPELINE_STAGE_TRANSFER_BIT});
|
||||
}
|
||||
// Every earlier recorded store into the imports (dispatches in place, fills, GPU labels,
|
||||
// GPU-direct write-backs and the flushes just recorded) and the host's own writes precede the
|
||||
// copies. A CPU write made after the batch is submitted is the game's race, as on hardware.
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
Recorder::CountBarriers(Recorder::CommandClass::StagingIn);
|
||||
bool stagedAny = false;
|
||||
@@ -1803,10 +1803,47 @@ void GuestBufferMemory::recordGpuCopies(std::span<Region* const> copies, bool ad
|
||||
}
|
||||
if (profile) allocateUs.fetch_add(microsecondsSince(allocateStart), std::memory_order_relaxed);
|
||||
}
|
||||
CopyBuffer(context, commands, region->copySource, region->begin - region->copySourceBase, region->buffer->Handle(), 0, bytes);
|
||||
// The copy reads the import in place when the batch runs: a CPU store into the range before
|
||||
// then would be copied instead of the bytes recorded here.
|
||||
recorder->NotePendingRead(region->begin, static_cast<std::size_t>(bytes), Recorder::ReadKind::GpuCopy);
|
||||
std::vector<std::byte> expected;
|
||||
const auto address = region->begin;
|
||||
const auto batch = static_cast<unsigned long long>(recorder->Submissions() + 1);
|
||||
const bool pendingWriter = recorder->PendingWriteOverlaps(address, static_cast<std::size_t>(bytes));
|
||||
const bool writable = WritesOverlap(address, static_cast<std::size_t>(bytes));
|
||||
std::shared_ptr<Buffer> inputSnapshot;
|
||||
auto copySource = region->copySource;
|
||||
auto copyOffset = region->begin - region->copySourceBase;
|
||||
if (!pendingWriter && !writable) {
|
||||
inputSnapshot = std::make_shared<Buffer>(context, static_cast<std::size_t>(bytes), VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
|
||||
std::memcpy(inputSnapshot->Bytes().data(), reinterpret_cast<const void*>(address), static_cast<std::size_t>(bytes));
|
||||
copySource = inputSnapshot->Handle();
|
||||
copyOffset = 0;
|
||||
recorder->Keep(inputSnapshot);
|
||||
CaptureTrace::Log("copy-input-snapshot batch=%llu address=%llx bytes=%llu", batch, static_cast<unsigned long long>(address), static_cast<unsigned long long>(bytes));
|
||||
}
|
||||
if (capture && bytes == 32) {
|
||||
CaptureTrace::Log("copy-input-candidate batch=%llu address=%llx bytes=%llu pendingWriter=%d writable=%d", batch, static_cast<unsigned long long>(address), static_cast<unsigned long long>(bytes), pendingWriter, writable);
|
||||
if (inputSnapshot != nullptr) {
|
||||
const auto snapshotBytes = inputSnapshot->Bytes();
|
||||
expected.assign(snapshotBytes.begin(), snapshotBytes.end());
|
||||
}
|
||||
}
|
||||
CopyBuffer(context, commands, copySource, copyOffset, region->buffer->Handle(), 0, bytes);
|
||||
if (!expected.empty()) {
|
||||
auto readback = std::make_shared<Buffer>(context, expected.size(), VK_BUFFER_USAGE_TRANSFER_DST_BIT);
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
CopyBuffer(context, commands, region->buffer->Handle(), 0, readback->Handle(), 0, bytes);
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_HOST_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
recorder->OnComplete([readback, expected = std::move(expected), address, batch] {
|
||||
const auto actual = readback->Bytes();
|
||||
std::size_t changed = 0;
|
||||
for (std::size_t index = 0; index < expected.size(); ++index) {
|
||||
if (expected[index] == actual[index]) continue;
|
||||
++changed;
|
||||
CaptureTrace::Log("copy-input-byte batch=%llu address=%llx offset=%zu cpu=%02x gpu=%02x", batch, static_cast<unsigned long long>(address), index, std::to_integer<unsigned>(expected[index]), std::to_integer<unsigned>(actual[index]));
|
||||
}
|
||||
CaptureTrace::Log("copy-input-result batch=%llu address=%llx bytes=%zu changed=%zu", batch, static_cast<unsigned long long>(address), expected.size(), changed);
|
||||
});
|
||||
}
|
||||
if (inputSnapshot == nullptr) recorder->NotePendingRead(region->begin, static_cast<std::size_t>(bytes), Recorder::ReadKind::GpuCopy);
|
||||
// Kept by the batch at record time, as every other recorded target is: the caller keeps
|
||||
// the resources only after descriptor and pipeline work that may throw, and a released
|
||||
// buffer would go back to the pool (reused or destroyed) under this copy command. The
|
||||
|
||||
Reference in new issue
Block a user