Skip to content

perf(agc): reuse unchanged depth layers with source invalidation - #22

Draft
p3n1cillin wants to merge 3 commits into
codex/depth-copy-profilingfrom
codex/depth-layer-reuse
Draft

p3n1cillin wants to merge 3 commits into
codex/depth-copy-profilingfrom
codex/depth-layer-reuse

Conversation

@p3n1cillin

@p3n1cillin p3n1cillin commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Repeated sampling of a mixed resident/guest depth array uploaded and detiled every guest layer and copied the entire array on every use. The measured ASTRO BOT boot had a 1536x1536, 16-layer array with 14 guest layers: 126 MiB per refresh, often 59 refreshes in one slow frame. The preceding six-minute profile accumulated 2,517,557,575,680 guest-upload bytes and 124.211 s in the CPU guest-upload stage across 19,055 refreshes.

Integrates upstream #2490, commit 5f0e7304189174bbfc033f37138b06ed15e4e77a, and #2491, commit 8085ddae5d8326194483da312e50ed9a3d96c702, onto the local ASTRO BOT integration stack. Preserves their authorship, caller buffer-pool reuse, kept-upload byte accounting and the existing CPU/GPU profiling. Unchanged guest layers retain their detiled contents; unchanged resident slices use their write serial; partial copies preserve the other image layers. Unwatched guest ranges retain per-use reads.

Native tests exposed three additional invalidation gaps, addressed here:

  • A guest layer protected to PAGE_NOACCESS must be read as zeros rather than reuse its former pixels. Reuse now includes the guest mapping generation and mip layout identity.
  • A failed command-batch begin must not publish freshness for an upload that never executed. Layer proofs are committed after recording succeeds; the initial image layout is committed after successful submission/recording.
  • A deferred storage-image GPU write can precede any pending buffer-write snapshot. A changed storage registry serial checks pending images and unpublished unit shadows before reusing a layer.

Validation on Windows, GCC 15.2, NVIDIA RTX 5070, driver 617.42:

  • Full Release build passed. CTest: 715 passed, five skipped, zero failed; 54.91 s.
  • Upstream guest-layer test failed before integration and passed after; unchanged-copy test failed before the second integration and passed after.
  • Protected mapping, failed recording and deferred storage-write regressions each failed before their guard and passed after.
  • Real Vulkan image readback checks every pixel of both array layers after initial upload, partial updates, protection changes, failure retry and resident-to-guest transitions. The test adds transfer-source usage only through its device-procedure interceptor.
  • Traced native depth tests: two passed, zero skipped, 0.71 s. Existing mixed-depth upload budget/pool and last-writer checks retained.
  • Conventions and whitespace checks passed. Shader-cache source namespace remains 34e1ebc06cf63a45, format 26.

Measured ASTRO BOT PPSA21564 v01.007.000 run at e105fc2, RTX 5070 / driver 617.42, 16 GiB host imports, profiling enabled, preserved shader namespace and pipeline cache. Six-minute timed boot/title diagnostic; the monitor intentionally stopped it at the deadline. No builds or tests overlapped the game. All game/collector/monitor processes are terminal.

Measurement Previous profiling build dea275f This build e105fc2
Completed flips, entire run 1,772 3,370
Entire-run completed flips/s 5.387 10.143
Entire-run p95 interval 702.144 ms 144.887 ms
Title frame-counter window 1440-1771, flips/s 1.580 8.341
Same window p95 interval 756.408 ms 152.903 ms
Same window depth-refresh CPU time/present 355.682 ms 0.143 ms
Same window guest uploads/present 7,148,837,432 bytes 0 bytes
Same window array copy bytes/present 8,170,099,922 bytes 47,185,920 bytes
Peak working set 22,942.621 MiB 22,132.629 MiB
Peak private memory 9,726.578 MiB 9,136.750 MiB

The candidate uploaded the 14 guest layers once (132,120,576 bytes), then reused them through 74,567 depth refreshes across 2,043 measured frames containing that metric. Recorded only 8,172 array updates. Late GPU staging-in class reports were 1.81-1.84 ms/present, versus 244-338 ms/present in the previous capture; these are inclusive class timings, not exclusive attribution to this function.

Shader cache: 1,831 hits, zero misses/writes. No fatal abort, device loss, BDA fault, presentation failure, alternate-heap allocation or host-pool reclamation report. The captured final image is the ASTRO BOT title with PRESS ANY BUTTON; diagonal banding remains.

One run per build; matching frame counters do not control animation position or run-to-run variance. Entire-run averages include startup and differing time spent in each stage. Full-game completion, correct graphics/audio, controller progression, saves, stable 60 FPS and other-title runtime regression testing remain unverified. The next performance work is CPU draw recording/resource validation and frequent recorder waits now exposed after removing repeated depth transfers.

Linux validation of this local integration remains pending; upstream reports Linux testing of its changes.

Depends on #21. This is a draft integration PR in the personal fork. Original upstream commits are by Dean Galvin; conflict resolution, invalidation guards and expanded tests are AI-assisted. Private game assets, frame captures and diagnostic dumps are excluded from source control and public records.

oneandonlydean and others added 3 commits October 10, 2026 14:05
Sampling a depth surface as a 2D array, a cube or its integer bits
copies its planes into a per-use image. Each use read every slice no
depth surface holds from guest memory and detiled it again, even when
nothing had written it since: in one level of a heavier title that was
about 165,000 layer reads, about 650 GiB, in a five-minute run.

A slice read from guest memory now stays in the copy's staging buffer
with the write generation it was read at. The next use reads and
detiles it again only when its address, size or tiling changed, the
write tracker reports a write since, or recorded GPU work writes the
range; a slice a depth surface held in between is read again. Without
write watching every use reads, as before.
Sampling a depth array, cube or R16_UINT view of depth surfaces went
through DepthPlaneCopy::Refresh on every use. Each use copied every slice
a depth surface holds into the staging buffer and the whole staging buffer
into the copy image, with three ALL_COMMANDS barriers, although nothing
had written the slices since the previous use.

Each depth surface now carries a write serial, bumped when a draw binds it
as its depth target, when a pending fast clear is applied and when a
storage image's writes are transferred into it. The copy keeps the image
and serial of every slice it copied. A use copies only the slices whose
surface or serial changed and the guest layers that changed (as before),
and records nothing when none did. A slice whose surface is the depth
target of the latest depth draw is copied at every use until another depth
target is bound, since that draw may still be recorded after the copy.

Test: agc_driver_depth_plane_guest_layers counts the recorded slice copies
and copy fills; a second use with nothing written records none (it records
one of each without this change), a draw to a slice's surface or a CPU write
to a guest layer copies only that layer.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants