perf(agc): read a fast-cleared surface's guest bytes only when the import is compared
#2096 keeps a copy of a storage image's guest bytes so that Refresh can compare memory the write watch does not cover. The host-import upload path takes that copy only when the range is unwatched, but the DCC fast-clear path took it on every upload. Reading the whole surface goes through the flush hook, so each 64 KiB block of a surface that a unit shadow covers recorded a publish and waited for the GPU. The clear path now resolves the surface's host import first (the import can unwatch the range, as a compared host-pointer import does) and takes the copy only when the range is then unwatched, like the import path. Write-watched memory, such as direct memory behind a dma-buf import, skips it; a range that is unwatched later re-uploads instead of comparing, as before #2096. agc_driver_dcc_keys_first_write checks that a fast-cleared upload keeps the copy exactly when its range is unwatched at that point. PPSA14632 (LEGO Horizon Adventures) on Linux, RX 9070 XT: the flush hook waited ~60,000 times per 10 s for these publishes (6.4 s), now ~3,500, and presents rise from ~24 to ~100 per 10 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b5f5362d3d
commit
4f9ddffce0
|
|
@ -288,6 +288,7 @@ public:
|
|||
// GuestMemory::GpuMutex only, as Refresh is; never from a build's stage A.
|
||||
DccKeys UploadedKeys() const { return uploadedKeys; }
|
||||
DccKeys FilledKeys() const { return filledKeys; }
|
||||
bool GuestSnapshotValid() const { return originalValid; }
|
||||
DccKeyProof& KeyProof() const { return keyProof; }
|
||||
DccKeys ProvedKeys() const;
|
||||
bool ServesKeysAt(std::uint64_t dccAddress) const;
|
||||
|
|
|
|||
|
|
@ -1686,7 +1686,9 @@ void StorageTexture::upload(const std::vector<bool>* layers) {
|
|||
// The clear is recorded into the open batch like a direct upload (the image kept by it): a
|
||||
// batch of its own submitted the recorder's work first and waited for all of it, 25-40 ms
|
||||
// under the GPU mutex at the movie stage. APS5_NO_RECORDED_CLEAR=1 waits as before.
|
||||
captureGuestBytes(nullptr);
|
||||
static_cast<void>(HostImportFor(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)));
|
||||
if (GuestMemory::Watched(descriptor.baseAddress, static_cast<std::size_t>(guestBytes))) originalValid = false;
|
||||
else captureGuestBytes(nullptr);
|
||||
forgetBorrowed(0, trackedLayers);
|
||||
stampLayers(false);
|
||||
static const bool recordClear = std::getenv("APS5_NO_RECORDED_CLEAR") == nullptr;
|
||||
|
|
|
|||
|
|
@ -209,6 +209,8 @@ void Run(AgcDriver::VulkanDevice& device, std::uint8_t* block) {
|
|||
Require(image != nullptr && image->Descriptor().dccAddress == AddressOf(keys), "the written surface has no pending image under its keys");
|
||||
Require(AgcDriver::Graphics::StorageImageServesKeys(*image, AddressOf(copied)), "the written image does not serve the copied keys");
|
||||
Require(image->UploadedKeys() == DccKeys::Uncompressed && image->FilledKeys() == DccKeys::Uncompressed, "the written image still holds the clear it was uploaded under");
|
||||
const bool stillWatched = AgcDriver::GuestMemory::Watched(surface, SurfaceBytes);
|
||||
Require(image->GuestSnapshotValid() != stillWatched, stillWatched ? "a fast-cleared upload of write-watched memory read its guest bytes" : "a fast-cleared upload of untracked memory kept no guest bytes to compare");
|
||||
const auto pendingVersion = image->Version();
|
||||
for (int repeat = 0; repeat < 3; ++repeat) {
|
||||
Require(image->Refresh(), "an unchanged pending image was uploaded again");
|
||||
|
|
|
|||
Loading…
Reference in New Issue