fix(agc): store GPU results over CPU-stamped bytes the CPU left unchanged
A write-back keeps the CPU's bytes for a block stamped since the layer's generation. Stamps can fall on bytes the CPU did not change (PPSA12544's font atlas: the stamped pages still hold the allocator fill the image was uploaded from), and the GPU results there were lost. Images up to 1 MiB keep the guest bytes of their generation point; a stamped range that still equals them stores the GPU results. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
71ea4d5ee0
commit
dfe147feaa
|
|
@ -310,6 +310,7 @@ private:
|
|||
// APS5_BLOCK_WRITEBACK_EACH=1 stores the touched units only).
|
||||
void writeBack(std::uint64_t address, std::size_t bytes);
|
||||
void writeBackLayers(const std::vector<bool>& layers);
|
||||
bool unchangedSinceBaseline(std::uint64_t from, std::uint64_t to) const;
|
||||
// Tracked units as 64 KiB write-stamp blocks (`blockUnits`: a thin tiled surface at a 64 KiB
|
||||
// aligned base; APS5_NO_BLOCK_TRACKING=1 tracks array layers as above instead): a fill of one
|
||||
// layer, a CPU write or another image's store then costs the blocks it touched, moved through
|
||||
|
|
@ -438,6 +439,7 @@ private:
|
|||
SurfaceGeometry geometry;
|
||||
std::vector<std::byte> original;
|
||||
mutable std::array<std::uint64_t, 4> comparedGuestBytes{};
|
||||
std::vector<std::byte> generationBaseline;
|
||||
// DCC keys the image content was uploaded under: a fast-cleared surface starts as its clear value.
|
||||
DccKeys uploadedKeys = DccKeys::Uncompressed;
|
||||
mutable DccKeys filledKeys = DccKeys::Uncompressed;
|
||||
|
|
|
|||
|
|
@ -1551,6 +1551,8 @@ bool StorageTexture::compareUntracked(std::uint64_t address, std::size_t bytes,
|
|||
return true;
|
||||
}
|
||||
|
||||
constexpr std::uint64_t GenerationBaselineBytes = 1ull << 20;
|
||||
|
||||
void StorageTexture::upload(const std::vector<bool>* layers) {
|
||||
CaptureTrace::Log("upload image=%llx bytes=%llu generation=%llu reason=%s partial=%d", static_cast<unsigned long long>(descriptor.baseAddress), static_cast<unsigned long long>(guestBytes), static_cast<unsigned long long>(generation), uploadReason, layers != nullptr);
|
||||
const bool profile = LookupOutcomes::Profiled();
|
||||
|
|
@ -1563,8 +1565,18 @@ void StorageTexture::upload(const std::vector<bool>* layers) {
|
|||
if (layers != nullptr && ((!blockUnits && trackedLayers != arrayLayers) || std::all_of(layers->begin(), layers->end(), [](bool selected) { return selected; }))) layers = nullptr;
|
||||
const auto now = GuestMemory::CollectWrites(descriptor.baseAddress, static_cast<std::size_t>(guestBytes));
|
||||
const auto stampLayers = [&](bool selectedOnly) {
|
||||
const bool whole = !selectedOnly || layers == nullptr;
|
||||
if (guestBytes > GenerationBaselineBytes) generationBaseline.clear();
|
||||
else if (whole) {
|
||||
generationBaseline.resize(static_cast<std::size_t>(guestBytes));
|
||||
GuestMemory::ReadCommitted(descriptor.baseAddress, generationBaseline);
|
||||
}
|
||||
for (std::uint32_t layer = 0; layer < trackedLayers; ++layer) {
|
||||
if (!selectedOnly || layers == nullptr || (*layers)[layer]) layerGeneration[layer] = now;
|
||||
if (!whole && !(*layers)[layer]) continue;
|
||||
layerGeneration[layer] = now;
|
||||
if (whole || generationBaseline.size() != guestBytes) continue;
|
||||
const auto offset = static_cast<std::size_t>(layerBegin(layer) - descriptor.baseAddress);
|
||||
GuestMemory::ReadCommitted(layerBegin(layer), std::span<std::byte>(generationBaseline).subspan(offset, static_cast<std::size_t>(layerBytes(layer))));
|
||||
}
|
||||
refreshGeneration();
|
||||
};
|
||||
|
|
@ -3449,6 +3461,13 @@ void StorageTexture::writeBack(std::uint64_t address, std::size_t bytes) {
|
|||
writeBackLayers(layers);
|
||||
}
|
||||
|
||||
bool StorageTexture::unchangedSinceBaseline(std::uint64_t from, std::uint64_t to) const {
|
||||
const auto& baseline = originalValid ? original : generationBaseline;
|
||||
if (baseline.size() != guestBytes) return false;
|
||||
const auto offset = static_cast<std::size_t>(from - descriptor.baseAddress);
|
||||
return GuestMemory::EqualsCommittedUnsynced(from, std::span<const std::byte>(baseline).subspan(offset, static_cast<std::size_t>(to - from)));
|
||||
}
|
||||
|
||||
void StorageTexture::writeBackLayers(const std::vector<bool>& layers) {
|
||||
CaptureTrace::Log("writeback image=%llx generation=%llu reason=%s units=%zu", static_cast<unsigned long long>(descriptor.baseAddress), static_cast<unsigned long long>(generation), flushReason, static_cast<std::size_t>(std::count(layers.begin(), layers.end(), true)));
|
||||
static const bool profile = std::getenv("APS5_PROFILE_DRAW") != nullptr;
|
||||
|
|
@ -3510,7 +3529,7 @@ void StorageTexture::writeBackLayers(const std::vector<bool>& layers) {
|
|||
const auto to = std::min(at + block, end);
|
||||
if (from >= to) continue;
|
||||
const bool edge = from != at || to != at + block;
|
||||
if (changedBlocks[static_cast<std::size_t>((at - spanBegin) / block)] == GuestMemory::BlockWritten && (compared || !edge || GuestMemory::StoredOver(from, static_cast<std::size_t>(to - from), layerGeneration[layer]))) {
|
||||
if (changedBlocks[static_cast<std::size_t>((at - spanBegin) / block)] == GuestMemory::BlockWritten && (compared || !edge || GuestMemory::StoredOver(from, static_cast<std::size_t>(to - from), layerGeneration[layer])) && !unchangedSinceBaseline(from, to)) {
|
||||
skippedAny = true;
|
||||
skippedLayer[layer] = true;
|
||||
++skipped;
|
||||
|
|
|
|||
Loading…
Reference in New Issue