Repository navigation
perf(agc): take an aliased storage image's units on the device without a host import - #13251
EagleBearerYS wants to merge 16 commits into
Conversation
…t a host import A refresh of a storage image over memory where another image of the same shape has results pending (same base, size, tiling, element size, layers and mips, another format) takes those results on the device (borrowUnits) instead of storing them to guest memory and uploading them again. It did so only when the surface had a host import, because the units were borrowed before the upload and a CPU upload of a 2D image replaces the whole image, the borrowed units with stale guest bytes. The alias is now kept whenever the refreshed image's keys are uncompressed, and the units are borrowed after the upload. Units held from an earlier borrow of the same alias version that the upload replaced (it forgets them, as every upload path does for what it overwrites) are borrowed again. Through an import the upload is per unit and leaves the borrowed units alone, so the new order is equivalent there. The refresh's flush already leaves the alias's results on the GPU; its own guest reads (the compare with the saved bytes, the CPU upload's read) went through the memory hook, which stored them anyway. While a kept alias is being refreshed over, a hook flush now leaves it out too, on the same grounds: each of its pending units is either taken on the device by this refresh or stamped since its results, which its own write-back would drop. agc_storage_alias_borrow makes an RGBA8 and an R32 image over the same four 64 KiB units without a host import, clears the R32 one on the GPU and refreshes the RGBA8 one: the R32 image must stay pending and the RGBA8 one sample its texels. The R32 image is then stored, written again over units 1-3 only, and a driver store hits unit 0: the next refresh must upload unit 0 from guest memory and still sample the R32 results in the units it takes after that upload, and after a second store over unit 0 and refresh it must sample them in the units it held, which the whole upload replaced. Its write-back must leave unit 0 with the store, units 1-3 with the R32 results, and the R32 image no longer pending.
…rite-back A refresh that takes an alias image's units on the device (borrowUnits) sets the borrowed units' generation to the moment of the borrow. When the lender later stores those units, for a flush or a CPU read of the range, its stamps come after that generation although the borrower's texels are the very bytes it stored. If the borrower is then written without another refresh, its own write-back takes those blocks for CPU stores and keeps the guest bytes, so its newer results are lost; and an alias refresh over it finds the units stamped and neither borrows nor stores them, so the refreshed image keeps the lender's older texels. A lender now remembers its borrowers. At its write-back it takes, before stamping, the borrowed units it stores at the version they were lent at whose memory is unchanged since the borrower's generation, and once its stamps are made it advances them past those stamps, as the write-back already does for adjacent pending images (advanceAdjacent). Their saved guest bytes no longer match the memory, so they stop vouching for it. The case needed a host import before; with the device handoff for surfaces without one it is reached by any such store between two passes. agc_storage_alias_round_trip's cached-image passes, in the next commit, fail without this: the flushing pass of the RGBA8/R32 pair reports that Y does not hold X's last results after its lookup.
…are not uncompressed A refresh keeps a pending alias on the keys it proves before its flush, and leaves the alias out of every flush until it ends so that the borrow can take the alias's units on the device. That flush may store keys itself, though. When the keys proved after it were not uncompressed, the borrow did not run, yet the alias stayed exempt: its results never reached guest memory, and the image uploaded the surface without them (a single-key surface is read from guest memory). The refresh now drops the alias as soon as the keys after the flush are not uncompressed. It ends the alias's exemption, stores it over the surface as a refresh without an alias does, and proves the keys again, all before anything reads the surface for the upload. The store's stamps then mark the units it wrote as changed, as the first flush's do. The test refreshes a DCC image over a pending alias while a linear image, pending over the image's keys and first unit, is stored by the refresh's own flush and turns the keys single.
…at the handoff removes agc_storage_alias_round_trip runs two storage images, X and Y, over the same 256 KiB of write-watched guest memory through four rounds of: Y looked up, Y written on the GPU, X looked up, X written. The pairs are R32_UINT 256x256 against 512x128, R32_UINT against RGBA8 256x256 (both R 64 KiB X), and tiled against linear. Each pair runs a measured pass, which prints the storage traffic of every step from StorageTexture::CumulativeTraffic() (the totals behind the [storage] line, never cleared, counted under APS5_PROFILE_DRAW), and a flushing pass, which also stores and compares guest memory after every lookup. Both passes check the images' contents after every lookup and at the end. It runs with copied and with imported guest memory, each once with images made directly (StorageTexture::Create) and once through the texture cache, as a title's images are. For the RGBA8/R32 pair, with cached images and copied guest memory, the measured pass now asserts what the device handoff removes: no 'storage refresh' write-back and no 'flushed' upload, no other upload than the two creations and the 'alias' device copies (one whole surface for each of the seven lookups after a write, path 3), and no other write-back than the test's final flush. The other runs keep printing their traffic unasserted: images made directly are not cached and stay refused, the other two pairs differ in dimensions or tiling, and imported memory that the probe leaves compared has no write stamps for the handoff to rely on. The harness is BF-296's (fork test/agc-storage-alias-roundtrip), with the cached-image runs and the assertions added.
|
This pull request is labeled |
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
… lender A refresh took an alias's pending units on the device from one image of exactly its surface: one lender per borrower (borrowedFrom, borrowedVersion) and the same unit index on both sides. The bookkeeping now records, for each borrowed unit, the lender, the lender's version at the borrow and the lender's unit (BorrowedUnit). The refresh works through a list of alias plans (pendingAliases), each mapping the refreshed image's units to a lender's units and saying which of them a device copy can take: - a refresh's hook exemption (refreshingAlias) is a set of images; - borrowUnits copies from each lender into the units mapped to it; - markLayersPending supersedes each lender's own unit, borrowersUnchanged maps the units a lender stores to its borrowers' units, and forgetBorrowed resets units one by one; - the refresh's checks on an alias (an untracked or generation-0 pending unit, a unit pending in both images) run per alias, a unit that two kept aliases have pending refuses the later one, and an alias's pending, unstamped units that a device copy cannot take are stored over their own range before the refresh's flush, as that flush would store them. pendingAliases still returns at most the one cached, uncompressed image of exactly this surface that pendingAlias returned, and every unit of that image maps to the same unit and can be taken, so nothing changes: agc_storage_alias_borrow, agc_storage_alias_keys and agc_storage_alias_round_trip pass as before.
…izes, one 64 KiB tile at a time A refresh took a pending alias's units on the device only from an image of the same base, size and shape. A transient pool hands its memory to images at other offsets and sizes: on Resident Evil Village's menu, R 64 KiB X images of one element size alias each other at other bases, widths and mip counts. Every refresh there stores the other image's results and uploads them again. Under a 64 KiB tile mode whose swizzle equation reads only coordinate bits inside the block (TextureSwizzleEquations.hpp), a tile block's byte arrangement depends only on the texel's position inside the block, the array slice and the pipe/bank XOR. Each mip that is not a tail lays its blocks out in rows (ComputeTiledMipLayout). So when a 64 KiB unit of this image and the alias's unit over the same guest block are each one whole tile block of such a mip, have the same slice, and hold texel rectangles of the same extent (unitTile), the two images hold the same texels in the same bytes there. One vkCmdCopyImage region from the alias's tile to this image's tile moves them bit for bit, at other tile coordinates. pendingAliases now also returns the pending images that overlap this surface with such units. They need the same tile mode, element size and pipe/bank XOR, an equation inside the block, and no block compression, and each plan says per unit whether the copy holds. The image of exactly this surface stays first, so its path is unchanged. For the alias's pending, unstamped units the copy does not cover (a mip tail, an edge tile of another extent), the refresh first stores those units over their own range, as its flush would, and then uploads them again. boykopovar#13251's rules hold per unit: - a unit taken must be unstamped since the alias's generation and not pending in this image; - a stamped unit is dead; - an untracked or generation-0 unit refuses the alias; - this image's next write supersedes exactly the alias unit it took (BorrowedUnit), which holds the same texels. agc_storage_alias_blocks runs four pairs of R32 R 64 KiB X images. Each pair writes X, looks Y up, writes Y and looks X up, twice. It does so once with a store after every write (the old path) and once without. The patterns differ per texel, mip and round. After every lookup Y and X must hold the same texels in both runs, and after the final flush guest memory must hold the same bytes. Without the stores, every lookup checks three things. The guest blocks it takes on the device must be unchanged in guest memory: no round trip through memory. The blocks no tile of the same extent covers must have received the other image's results first. Only those blocks' image is stored, with one 'storage refresh' write-back, and the device copies must move exactly the taken units: - a 512x128 image two units into a 256x256 one: blocks 2-3 each way, and no other upload or 'storage refresh' write-back; - a 128x128 image at the base of a 256x256 one: block 0 each way; - a 128x64 image at the base (a partial tile): nothing taken, block 0 stored, as before; - a 512x128 image over a 256x256 chain of four mips: blocks 1-3 taken, the tail block 0 stored. agc_storage_alias_round_trip's R32 256x256/512x128 pair now asserts the handoff too: no 'storage refresh' write-back, no 'flushed' upload, and one whole-surface device copy for each lookup after a write. Before this change both fail. The blocks test's first lookup takes 0 bytes on the device instead of two units, and the round trip stores 7x 1835008 bytes.
# Conflicts: # core/libs/prx/libSceAgcDriver/CMakeLists.txt
The conflict in core/libs/prx/libSceAgcDriver/CMakeLists.txt from boykopovar#12862's split is resolved with tools/agc_test_split.py resolve, which moves this PR's test registrations into tests/cmake/.
# Conflicts: # core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp # core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
|
@EagleBearerYS A data point for this PR from Crysis Remastered (CUSA18659, PS4 GCN), and a case the tile path does not reach yet. The round trip. CryEngine renders the bloom chain one level at a time: the 1920x1080 10-level chain at What made it work here. Two changes on top of this PR, in
Measured in the same scripted scene, 10 s windows at ~390 s:
Frame time did not move (p50 107 to 110 ms both ways, the title is CPU-bound on the draw committer), but the chain's round trip through guest memory is gone. Happy to send this as a follow-up on top of this PR ( AI-assisted: yes |
|
@ntamas94 thanks, that's a clear case, and the table shows the round trip going away. A follow-up on top of this PR ( A heads-up before you base it: this branch is about to take a merge of On the two changes, the level rule (same base and pitch, a single level, checked both ways) and the padding-row units would each want a test. |
# Conflicts: # core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp # core/libs/prx/libSceAgcDriver/tests/cmake/agc_driver_recorder_tests.cmake
# Conflicts: # core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
Texture.cpp conflicts in refresh, where boykopovar#14868 prunes the adopted sources after the refresh's flush. This branch's flush with its alias plans stays, and pruneAdoptedSources follows it.
agc_driver_recorder_tests.cmake conflicts in the Windows ENVIRONMENT_MODIFICATION list, where boykopovar#14261 adds agc_untracked_forget; the list takes both sides' names, each once.
|
Independent native Windows / AMD Radeon RX 7800 XT focused run of #13251 head The The This adds real Windows AMD hardware evidence where the hosted Windows GPU cases were skipped. The validation layer was requested; these focused logs contain no VUID ID, but I did not run a paired |
|
Thanks @DonRyuzaki. This is the first run of the four |
What
When a storage image is refreshed over memory where another storage image still has results on the GPU,
StorageTexture::refreshcan take those results on the device.borrowUnitsrecords onevkCmdCopyImageof the other image's pending units. Onmainthat path needs two images of the same shape over the same memory (for example an RGBA8 view and an R32 view of one surface), and it also needs the refreshed surface to have a host import (Texture.cppL2196 and L2342 on 08a10d2).Without an import, the refresh takes the round trip instead:
storage refreshwrite-back;flushedupload.The four commits:
perf(agc): take the units on the device without a host import. The import wasn't needed for correctness, but removing it needs two other changes, because without an import:forgetBorrowed) are borrowed again.ReadCommittedgo through the recorder's memory-access hook, which would store the alias anyway. While a kept alias is being refreshed over,FlushPendingleaves it out, exactly as the refresh's own flush already does. A thread-localrefreshingAliassits next torefreshing.fix(agc): advance a borrower's generation past its lender's write-back.main: the gap exists only with a write-watched host import. Commit 1 would widen it to every surface.advanceAdjacent).fix(agc): store a kept alias when the refreshed image's keys aren't uncompressed.main: the same gap exists on the import path.test(agc): measure the round trip and assert what the handoff removes (below).Unchanged: the conditions for keeping the alias are main's.
The fifth commit merges
main(f7f03da). #12559 and #12927 had added tests at the same places intests/Recorder.cppand the AGCCMakeLists.txt, and the merge keeps both sides.The last two commits take overlaps at other bases and sizes, one 64 KiB tile at a time.
refactor(agc): keep a storage image's borrowed units per unit and per lender. No behaviour change on its own.borrowedFrom/borrowedVersionbecome oneBorrowedUnit{from, version, unit, held}per unit, because one image can now hold units from several lenders, and a lender's unit index can differ from the borrower's.markLayersPending) supersedes exactly the lender unit recorded for each unit it writes, while the lender is still at the version lent. The lender's write-back maps its stored units to each borrower's own units (borrowersUnchanged).pendingAliases()returns alias plans (each unit mapped to a lender unit, with which units are copyable).refreshingAliasbecomes a set, andFlushPendingwithout anexceptleaves out every kept alias, as it did for the single one.perf(agc): borrow an aliased storage image's units across bases and sizes, one 64 KiB tile at a time.swizzleWithinBlock; for SW_64KB_R_X at 4 bytes, x and y bits 0-6 plus the slice);vkCmdCopyImageregion, from B's tile to A's tile at their own tile coordinates, moves the block bit for bit.kStandard*, GCN and 4 KiB modes are refused this way, conservatively).Prior art: #4286 (AlxcBTW, closed unmerged on 10-12) handed aliased storage memory over without the guest round trip, unit by unit and at any base. It retiled through a device buffer and needed a host import.
APS5_NO_ALIAS_BORROW=1turns it off), needs no host import, and copies image to image.Resident Evil Village (PPSA01556)
Static menu, profiled boot (
APS5_PROFILE_DRAW=1) onmainebb4075 plus #12478, without this change. Its 10 s[storage]lines at the menu show:storage refreshwrite-backs;flushedCPU uploads;The highest window:
The first four commits alone don't take Village's pairs.
Tested
New tests. Each runs
agc_driver_recorder_testswith its own--…-onlyswitch. All use a write-watched allocation with host imports off, and cached 256x256 RGBA8 and R32_UINT storage images over the same surface, with the same tiling.agc_storage_alias_borrow(commit 1):agc_storage_alias_keys(commit 3): a pending linear image over the RGBA8 image's DCC keys turns them single when the refresh's flush stores it. The RGBA8 image must still sample the R32 image's value, and the R32 image must no longer be pending.agc_storage_alias_round_trip(commit 4): four rounds of the pattern a frame makes. Each image is looked up, then written, over the same memory. Three pairs run in copied and imported memory, with images made directly and from the cache.[storage]line, per step.storage refreshwrite-backs, 0flusheduploads, no other reason taking their place, and one device copy per lookup after a write (7 × 256 KiB).agc_storage_alias_blocks(commit 7): R32 images in tile mode 7 (R 64 KiB X), cached, over copied write-watched memory.Each case: X is written, Y looked up, Y written, X looked up, for two rounds.
Two runs per case: stored (
FlushPendingafter every write, the old path) and borrowed (no stores). The patterns differ per texel, mip, image and round.Content: after every lookup, the looked-up image holds the same texels in both runs, at every mip. After the final flush, guest memory is byte-identical between the runs.
Bytes, borrowed run:
aliascopies are exactly the taken units × 64 KiB;storage refreshwrite-back.agc_storage_alias_round_trip, extended (commit 7): its R32 256x256/512x128 pair (same base and size, other width) now asserts the handoff for cached images over copied memory: nostorage refreshwrite-back, noflushedupload, and 7 whole-surfacealiascopies (7 × 256 KiB).Reds (Linux). Each was built from the named commit with only the named change:
Texture.cppfrommainagc_storage_alias_borrowcase A: "refreshing the RGBA8 image over the surface wrote the pending R32 image back instead of taking its units on the device"APS5_NO_ALIAS_BORROW=1mainagc_storage_alias_round_trip: "... cached images, other format, same bytes per texel (R32_UINT / RGBA8 256x256, R 64 KiB X), flushing, round 1: Y does not hold X's last results after its lookup"Texture.cppagc_storage_alias_keys: "the RGBA8 image sampled 17.000000 after a refresh whose flush turned its keys single over the R32 image's pending results, expected 48"Texture.cppfrommainagc_storage_alias_round_trip: "'storage refresh' write-backs 7x 1835008 bytes, although the device handoff covers this pair"agc_storage_alias_blocks: "a 512x128 image two units into a 256x256 one, round 0, Y looked up: took 0 bytes from the other image on the device, expected 2 units";agc_storage_alias_round_trip: "same format, other dimensions: 'storage refresh' write-backs 7x 1835008 bytes, although the device handoff covers this pair"agc_storage_alias_blockscontent check: "lookup 0 (Y) holds 32768 texels other than the store-and-upload path gives (first 0x10000000 where 0x10020000)", that is, X's row 0 where row 128 belonged;agc_storage_alias_round_tripfails tooLinux runs (Ubuntu 24.04, GCC 13.3, Release, CI's flags, lavapipe/llvmpipe 20.1.2, as an unprivileged user):
the new tests ×10 on their commits;
the 52 DCC and storage tests ×10 on commit 3: 44 passed every time, 8 skipped;
ctest -R '^agc'once:commits 6 and 7:
ctest -R '^agc'once, 1,139 tests (agc_storage_alias_blocksadded), 0 failed, 75 skipped, the same set as on commit 5; the 4 alias tests ×10, 40 of 40; commit 6 alone, the storage, clear hand-over, unit shadow and recorder tests, 18 of 18 (2 skipped, as on commit 5).GitHub, ×10 on both runners:
agc_storage_alias_blocksandagc_storage_alias_round_tripfail with the messages above.main(run): the three new tests,main's newagc_storage_typed_fill_clear, and the storage tests around them.main's arm doesn't build there, because the round-trip test reads a test-only accessor inTexture.hpp. The reds above are the per-commit ones.main's code also failedagc_driver_storage_read_during_idle_storeonce, at its own precondition ("the GPU producer left no pending image"). It passed onmainin the next run, and with this change in every run.Validation layer (CONTRIBUTING's AGC rule), on GitHub's Linux runner (llvmpipe, Mesa 25.2.8, Ubuntu 24.04.5), commit 1 against
main(run):mainand 81 with the change, with 0 "was not found".VUID-VkDeviceCreateInfo-pNext-pNext, on both. The change adds none.Windows hardware, by DonRyuzaki (report): an AMD Radeon RX 7800 XT on Windows, head f6e8382 merged onto
maina992b80, withANYPS5_REQUIRE_VULKAN=1andANYPS5_NO_SHADER_CACHE=1. It is the first run of these tests on Windows hardware, since GitHub's Windows runner has no Vulkan device.agc_storage_alias_round_trip,agc_storage_alias_borrow,agc_storage_alias_blocksandagc_storage_alias_keys, 3 of 3 each, none skipped.APS5_PROFILE_DRAW=1): on the cached pairs over copied write-watched memory, 0storage refreshwrite-backs, 0 flushed uploads and 7 alias copies (1,835,008 bytes). The uncached copied pairs keep their 7 write-backs and 7 flushed uploads. Inagc_storage_alias_blocks, the offset 512x128 image takes 131,072 bytes by alias per lookup, the partial 128x64 tile falls back, and the four-mip image takes 196,608 bytes by alias with its tail on the fallback.mainrun, and the layer's insertion wasn't checked. There was no game or performance capture, so the same-scene capture the performance bot asks for is still outstanding.Checks:
check_conventions.pyandcheck_test_registration.pypass.-fsyntax-onlyonTexture.cppandtests/Recorder.cppshows no new diagnostic.Recorder.cppstops at the same_fflush_nolockdeclaration gap as onmain.Overlap: checked with
git merge-treeof this head against every open pull request that changesTexture.cpporTexture.hpp.directto surfaces over several imports.direct =line and this PR's borrow condition. They compose: take perf(agc): upload a storage image over several host imports on the GPU #11485'sdirectand this PR'skeys == DccKeys::Uncompressedcondition.direct, the clash is the same kind of one-line overlap (HostImportForCached): take its lookup and keep this PR's test.mainalready, so whichever lands second rebases.main. The merge below keeps itsUnitFlags borrowedUnitsas the held bitmap and adds this PR's per-unit lender beside it.directwith this PR's alias test, then check that the upload still runs before the borrow (and held units are borrowed again after it) when the upload is perf(agc): upload a storage image over several host imports on the GPU #11485's GPU segment upload.FlushPending's registry filter; keep both conditions.Resolved. The per-tile copy's calls can take the same form.HintedComparisontoTexture.hppnext to where commit 2 adds the lender'sborrowerslist. The clash is textual only: whichever lands second keeps both.CMakeLists.txtortests/Recorder.cpp. The clashes are textual only: whichever lands second keeps both.mainnow conflicts the same way, through fix(agc): free a completed batch's command buffer instead of keeping it #9565'sagc_recorder_command_buffer_releaseon the WIN32 test-list line, and the next merge ofmainkeeps both names.refresh'sFlushPendingcall in a GPU-ordered flush scope. The clash is that call. They compose: keep this PR's alias plans and exempt scope, put perf(agc): order a storage flush behind its GPU writer when the write-back is a GPU copy #15569's scope around the call, and readaliases.empty()in itsorderedEligible. Either order works (note).main0a148be (run). build(agc): register each AGC test executable in its own CMake fragment #12862 movedlibSceAgcDriver's test registrations intotests/cmake/; the conflict inCMakeLists.txtis resolved withtools/agc_test_split.py resolve, which moves this PR's registrations intotests/cmake/agc_driver_recorder_tests.cmake(+13 −1 lines). Nothing else conflicted, and apart from the move this PR's diff is unchanged. With-DBUILD_TESTING=ON,ctest -Ngives 3109 tests:main's 3105 plus its 4 tests, each listed once. The tests of this PR's verify set pass 10 runs in a row. Linux: 11 run, 11 pass, 0 skip, 0 fail. Windows: 11 run, 0 pass, 11 skip (no Vulkan device), 0 fail. Suites: libc and libkernel pass on Linux (199 and 308) and on Windows (226 and 330). The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.main2ff700f, which brings meh7an's perf(agc): track pending and borrowed texture units in 64-bit words #10886 (run).Texture.hppand two functions ofTexture.cpp,markLayersPendingandforgetBorrowed. perf(agc): track pending and borrowed texture units in 64-bit words #10886 storesborrowedUnitsas aUnitFlags, where commit 6 kept aBorrowedUnitper unit with its lender, the lender's version and unit, and a held flag.UnitFlags borrowedUnits.std::vector<BorrowedSource> borrowedSourcesbeside it, holding the lender, its version and its unit. It is read only when the unit's flag is set, and the two are sized and cleared together.AnyIngate inmarkLayersPendingand itsSetRangeclear inforgetBorrowedare kept, and this PR's two scans for a held unit becameUnitFlags::Any().-DBUILD_TESTING=ON,ctest -Ngives 3,130 tests:main2ff700f's 3,126 plus this PR's 4, each listed once.^agc_storage,^agc_driver_storageand perf(agc): track pending and borrowed texture units in 64-bit words #10886'sagc_unit_flags_allocation_failure_*.agc_storage_clear_hand_over, since lavapipe imports no watched host memory.APS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.agc_driver_recorder_tests: 85 run, 77 pass, 8 skip (host imports and the pipeline cache, which lavapipe lacks), 0 fail.main88e804b (e75bd22) and 3c3b3cd (3731709).refresh()andwriteBackLayersrecord its generation. The merge keeps those calls inside this PR's reworked loops:borrowUnits(aliases, …)and theborrowed[unit] >= 0check inrefresh(), and theheld.empty()early return inwriteBackLayers. Inagc_driver_recorder_tests.cmake, both sides' registrations are kept.FlushPendinga device. The pending-texture filter there keeps both conditions: this PR's alias exemption and fix(agc): keep a device's idle stores and storage write-backs on its own recorder #10940's device check.mainis otherwise unchanged.agc_repeated_neighbour_stores. Linux: 34 run, 33 pass, 1 skip (agc_storage_clear_hand_over), 0 fail. Windows: 35 run, 2 pass, 33 skip (no Vulkan device), 0 fail. Suites: libc and libkernel pass on Linux (214 and 316) and on Windows (241 and 337). The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.agctest, once (run): Linux: 1,240 run, 1,161 pass, 78 skip, 1 fail. Windows: 1,276 run, 387 pass, 889 skip (no Vulkan device), 0 fail. The one failure isagc_driver_pipeline_journal's 120-second timeout, whichmain88e804b's own run of every test hits too (run).main4f41f4c (run).Texture.hpp, the conflict is next tomain's newOccasionalLabelStoresdeclaration, which stays. Intests/Recorder.cpp, perf(agc): store whole words of 1- and 2-byte texels in the detile shader #6905'sSmallElementDetileTestand this PR'sstorageAliasBorrowTestsboth landed beforemain(), and both stay. Intests/cmake/agc_driver_recorder_tests.cmake, the WindowsENVIRONMENT_MODIFICATIONlist, wheremainaddsagc_changed_copy, the resolution is the union of both sides' names, each once. This PR's own lines are unchanged, and that list line is the only difference in its diff.agc_changed_copyand every test matching^agc_storage, which takes in this PR'sagc_storage_alias_*tests and fix(agc): keep a CPU store that rewrote a pending block with its baseline bytes #14302'sagc_storage_rewritten_blocksandagc_storage_rewritten_stale_units. Linux: 21 run, 20 pass, 1 skip (agc_storage_clear_hand_over), 0 fail. Windows: 22 run, 0 pass, 22 skip (no Vulkan device), 0 fail. The libc and libkernel suites run 300 and 322 tests on Linux and 327 and 342 on Windows, with 0 failed. The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.main086c068 (run).tests/cmake/agc_driver_recorder_tests.cmake, in the same WindowsENVIRONMENT_MODIFICATIONlist, where savvaniss's perf(agc): keep constant RAM dumps and unregistered labels on the GPU without draining #9898 addsagc_recorder_stored_bytes. The resolution is again the union of both sides' names, each once. This PR's diff overmainis unchanged.agc_changed_copy,agc_recorder_stored_bytesand every test matching^agc_storage. Linux: 23 run, 22 pass, 1 skip (agc_storage_clear_hand_over), 0 fail. Windows: 24 run, 0 pass, 24 skip (no Vulkan device), 0 fail. The libc and libkernel suites run 300 and 324 tests on Linux and 330 and 342 on Windows, with 0 failed. The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.main1c8c0ef, which brings PrivacyOnion's perf(agc): hand pending results over to storage images created under clear keys #14868 (run).Texture.cpp'srefresh. perf(agc): hand pending results over to storage images created under clear keys #14868 prunes the sources an image adopted (pruneAdoptedSources()) right after the refresh's flush. This PR's flush with its alias plans stays, and the prune follows it. This PR's diff overmainis unchanged.agc_changed_copy,agc_recorder_stored_bytes,agc_driver_recorder(the whole recorder run, which takes in perf(agc): hand pending results over to storage images created under clear keys #14868's changed cases) and every test matching^agc_storage. Linux: 24 run, 23 pass, 1 skip (agc_storage_clear_hand_over), 0 fail. Windows: 25 run, 0 pass, 25 skip (no Vulkan device), 0 fail. The libc and libkernel suites run 300 and 324 tests on Linux and 330 and 342 on Windows, with 0 failed. The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.mainc2eafe4, which brings oneandonlydean's perf(agc): an untracked comparison memo holds until memory it covers is forgotten #14261 (×10).tests/cmake/agc_driver_recorder_tests.cmake, in the same WindowsENVIRONMENT_MODIFICATIONlist, where perf(agc): an untracked comparison memo holds until memory it covers is forgotten #14261 addsagc_untracked_forget. The resolution is again the union of both sides' names, each once. This PR's own lines are unchanged, and that list line is the only difference in its diff.agc_changed_copy,agc_recorder_stored_bytes, perf(agc): an untracked comparison memo holds until memory it covers is forgotten #14261'sagc_untracked_forgetand every test matching^agc_storage. Linux: 24 run, 23 pass, 1 skip (agc_storage_clear_hand_over), 0 fail. Windows: 25 run, 0 pass, 25 skip (no Vulkan device), 0 fail. The libc and libkernel suites run 301 and 325 tests on Linux and 331 and 343 on Windows, with 0 failed. The suites ran withAPS5_SKIP_TIMING_TESTS=1, which relaxesprecise_wait's median bounds on GitHub's hosted runners.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)