Repository navigation
fix(agc): execute the DB's out-of-place depth expand - #6146
Open
EagleBearerYS wants to merge 39 commits into
Open
EagleBearerYS wants to merge 39 commits into
EagleBearerYS wants to merge 39 commits into
Conversation
A draw with DB_RENDER_CONTROL compress-disable bits and DB_Z_WRITE_BASE != DB_Z_READ_BASE is a DB expand: it writes the read surface's depth plane, uncompressed and in the same swizzle, at the write base. It was drawn without a depth target, so the write base kept what the CPU wrote there. Resident Evil Village (PPSA01556) lights, fogs and blurs its first 3D scene from that copy, and zero depth is the far plane in its reverse Z. DecodeDepthExpandPass recognises the expand of a single-sample Z_32_FLOAT SW_64KB_Z_X surface with no tests and no color writes over the whole surface, and the draw precheck runs it instead of the draw. The depth plane of the live depth surface at the read base is copied into the storage image of an R32F SW_64KB_Z_X view of the write base, which the next flush of that range stores to guest memory. Every other out-of-place expand throws; an in-place expand still changes nothing modeled, and a read-only plane is not moved.
Draw a depth gradient into a 160x96 Z_32_FLOAT SW_64KB_Z_X surface with a stencil plane, then submit Resident Evil Village's (PPSA01556) DB expand: DB_RENDER_CONTROL 0x60, no depth or stencil tests, no color writes and DB_Z_WRITE_BASE at another address. The write base must then hold the read surface's depth, both sampled as an R32F SW_64KB_Z_X texture and read raw after a flush. The expand runs with one raster sample and with the game's two. On main the expand draws nothing, so the write base keeps the zeros the CPU wrote.
Resident Evil Village (PPSA01556) issues its out-of-place DB expand as DRAW_INDIRECT or DRAW_INDEX_INDIRECT, at boot and four times a frame at first control, and the draw precheck threw "indirect DB expands are unsupported" about 18 s into boot. The CP takes an indirect draw's counts from its records, so the precheck now reads them as the draw path's CPU route does: the queue's deferred labels are recorded first, the count (for the count-address forms) and the records go through the flush hook, which waits for the recorded work that writes them, and the expand runs when a record has a nonzero vertex or index count and instance count. Otherwise it writes nothing. The pass covers the surface whatever the records hold, as for a direct expand, whose geometry is not checked either; every refusal of the expand's decode stays.
During Resident Evil Village's (PPSA01556) boot the DB expand comes before any depth surface exists at its read base, and the expand threw "without a depth surface at the read base is not implemented". The DB writes what each tile of the read surface holds. Without a live depth surface there, a pending HTILE depth clear of the surface (the HTILE kernel NoteHtileDepthClear records before the surface exists) makes every tile read as DB_DEPTH_CLEAR, so the write base's storage image is cleared to it. Otherwise the tiles are taken as expanded, whose bytes the DB writes out as they are: the storage image of the read base's R32F SW_64KB_Z_X view, which holds its guest bytes, is copied into the write base's, same size and swizzle. The pending clear is only looked at, not taken: the expand changes nothing at the read base. The HTILE words in guest memory are not read, so an HTILE the CPU or a DMA fill cleared before any surface existed is taken as expanded. The expand still throws into a live depth surface and from a surface of another extent, format or sample count.
Resident Evil Village (PPSA01556) reads the expand's write base right after it with a compute shader, raw dwords through a V#, and the guest memory there was all zero: the expanded plane was left pending in the write base's storage image until the next flush of that range. A program that is address-based (a flat or global access, or a V# the resource tracker cannot follow) maps the registered heaps whole, and its build reads the imported ones in place without storing the results pending in them. With the cached address space it does not even reach the per-region flush that APS5_BDA_FLUSH=1 enables. A buffer read of the write base by such a program saw the CPU's bytes. The expand now stores the written image at once when the write base is host-imported. The store is recorded into the import, without a wait, ahead of anything recorded later. A write base that is not imported keeps the plane pending: nothing binds such memory in place, and the copy and mirror paths store pending results before they read.
Extend agc_driver_depth_expand_out_of_place with the variants of Resident Evil Village's (PPSA01556) DB expand that its boot reaches: - The expand issued as DRAW_INDIRECT and as DRAW_INDEX_INDIRECT, its record in guest memory behind SET_BASE, must write the read surface's depth at the write base like the direct expand. An empty record (no vertices, then no instances) must leave the write base as the CPU wrote it. - An expand before any depth surface exists at the read base must write DB_DEPTH_CLEAR when the title cleared the surface's HTILE (RADV's HTILE kernel), and the read base's guest bytes, byte for byte, when the HTILE says expanded. - A compute copy of the write base through a V#, raw dwords, right after the expand, as the title's copy shader reads it, must hold the depth detiled with the SW_64KB_Z_X equation, both from a plain program and from an address-based one (a global load added). A case name on the command line runs that case alone. At 305166f the indirect cases throw "indirect DB expands are unsupported", the surfaceless ones "without a depth surface at the read base is not implemented", and the address-based copy reads 0 in all 15360 texels. The plain copy already passes.
An always-pass depth draw with equal bases, with or without compress-disable bits, a draw without depth or stencil planes and a read-only stencil plane are not taken for an expand. A surface without a stencil plane or without HTILE is expanded depth-only; a stencil plane moving with the depth in place, Z_16 and Z_24 with and without stencil, and the SW_64KB_Z, SW_4KB_Z_X, SW_64KB_R_X and SW_VAR_Z_X modes throw.
agc_driver_depth_expand_review expands a surface without a stencil plane, keeps a drawn stencil plane and the read base, stencil and HTILE guest bytes unchanged, leaves an in-place expand and an always-pass depth draw with equal bases to the normal draw path, expands again after the read surface changed, reads the write base through GPU buffer loads right after the expand, and expands one surface to two write bases in one submission.
Each out-of-place DB expand copied the whole depth plane twice (depth image to a staging buffer, then into the write base's R32F image, 2 x 15.8 MiB at Resident Evil Village's 1920x2160) behind three global barriers, and then stored it, even when nothing had changed since the previous expand into the same write base. Village expands four times a frame at first control. The expand now remembers, per write base, the live depth surface it copied with that surface's write serial, and the write base's storage image with its content version after the write. When all four are unchanged it records nothing. Draws that bind the surface, fast clears and stores of the surface's storage views bump the serial; uploads of the image (after a CPU write to the write base) and writes to it bump the version. All of them precede the expand in queue order, so the image still holds what the copy would write. Expands without a depth surface at the read base always write. DepthExpandCounts() reports the expands run and skipped. A new repeated-expand case of agc_driver_depth_expand_out_of_place makes seven expands into one write base. It requires three copies: the first, one after a second depth draw and one after a CPU write to the write base. Sampled, raw and address-based reads of the write base in between must not force a copy. With the skip disabled, all seven copy.
166fa21 stored every expand's plane into a host-imported write base at once, because an address-based build reads the imported heaps in place without storing the results pending in them. That write-back is a retile of the whole plane into guest memory, 15.9 MiB at Resident Evil Village's 1920x2160: on lavapipe it took each expand from about 3 ms to 35-50 ms, whether or not anything read the plane as a buffer. The plane now stays pending, as it did before 166fa21, and the expand notes its write base. Before an address-based build binds the imported heaps, GuestBufferMemory::UploadFinish calls StoreDepthExpandWrites, which stores the noted planes still pending in host-imported write bases and forgets the notes. The store is recorded into the import ahead of the build's work, so the program reads the expanded plane. Every other reader stores the plane before it reads, as for any written storage image: an in-place bind or GPU copy of the range, a mirror refresh, and the CPU through the flush hook. Several expands before the next address-based build cost one store, and none if no such build follows. DepthExpandCounts() also reports these stores. The buffer-read cases of agc_driver_depth_expand_out_of_place now require none at the expand, one ahead of the address-based copy, and none for the plain copy, which stores the range it binds itself.
A depth view with DB_DEPTH_VIEW.STENCIL_READ_ONLY on an out-of-place expand of the depth plane threw "of a depth view with a base slice, a mip level or a read-only plane". The stencil plane of such a view already counts as not moving, and the expand copies only the depth plane, so the read-only bit changes nothing it does. The refusal now covers the rest of the view, a base slice or a mip level, and says so. A read-only depth plane never reaches it: such a plane does not move, so the draw is no expand of it. agc_driver_graphics takes the game's expand with a read-only stencil view, and refuses it with a mip level as well.
…only The refusal of an expand into a live depth surface used DepthSurfaceAt, which scans the depth surfaces of every Vulkan device, while the read surface is looked up for the expand's own device. A surface of another device at the write base refused a valid expand. It now asks planeSurface for the expand's device, as the read side does, under the surfaces' lock.
PM-019's review of the out-of-place DB expand found four limits the debt entry did not state: - the whole plane is written whenever the viewport and scissor cover the surface, so a partial-coverage expand would overwrite texels the console leaves alone; - the expand's pixel shader never runs, so any memory it writes is lost; - a 32-bit integer (depth-bits) view of the write base still throws, by an older rule; - a depth surface later bound at the write base starts from its own image, and the next expand into it throws "into a live depth surface". The entry also gives the cost of an expand's first use of a write base, which uploads guest bytes the copy then overwrites (35-47 ms at 1920x2160 on lavapipe, against about 3 ms later). It also states that a read-only stencil view is taken, and names agc_driver_depth_expand_review among the tests.
This was referenced Oct 15, 2026
…face.cpp Other open changes add includes at the top of DepthSurface.cpp and lines at the end of ClearDepthSurfaces. The expand's two includes now follow TextureTiling.hpp, and its two teardown erases run right after the surfaces are erased.
11 tasks done
The expand tests compared every texel of the drawn depth gradient with its expected value within 4e-6. On an NVIDIA GeForce RTX 3070 Laptop GPU the review test's second gradient, offset by 0.5, came back 4.05e-6 and 4.11e-6 low at its two far-corner texels (68 and 69 ulps at 0.875), so the test failed there while lavapipe matched exactly. Both tests now accept an error of half the gradient's step in x (0.5 / 65536). A read of the wrong texel is still one full step off.
…port serves Resident Evil Village fills its host import budget, so the DB expand's write base may be served to address-based builds by a heap mirror or a per-build copy instead of an import. Two cases of agc_driver_depth_expand_out_of_place refuse every host import (SetHostImportBudget(1)), copy the write base once with an address-based program before the expand, so the address space and its mirror already exist, and copy it again right after the expand. In write-watched memory the build serves the write base through a heap mirror; outside the write watch it copies it. Both copies must hold the read surface's depth. Both cases pass at e1a94e7: the mirror refresh and the copy store the pending plane through the flush hook before they read it.
StoreDepthExpandWrites stores the expanded planes still pending ahead of an address-based build, whose build reads the imported heaps in place without storing the results pending in them. It stored a plane only when one host import held the whole plane. Imports are made per registered range: adjacent ranges share one import only when they fill an 8 MiB aligned window, or once a buffer bound across them joins them. A write base across the edge of two registered ranges imported apart, or of an imported range and one that is heap-mirrored or copied, was therefore not stored. An address-based build then read the imported part in place, so copies of the write base right after the expand held the guest bytes: zeros in the tests, the symptom of Resident Evil Village's copy shader at its write base. The plane is now stored when any import overlaps it (HostImportOverlaps). The storage image's write-back records it into each range's import when every registered range under it has one, and goes through the CPU, after a wait for the expand, only when part of it has no import. A plane one import holds is still recorded into that import, and a plane no import touches still stays pending for the mirror refresh or the copy that reads it, so both cost what they did.
Four cases of agc_driver_depth_expand_out_of_place register the write base's memory as two adjacent 16 MiB ranges, with the plane across their edge, and copy the write base with address-based programs right after the expand: - both ranges imported, one buffer copy inside each range; - both ranges imported, one copy of the whole plane through global loads, with no V# for the write base; - the first range imported and the second heap-mirrored, or copied (an import budget that admits the first range only), one buffer copy inside each range. Each copy must hold the read surface's depth, and the plane must be stored once ahead of the copies. A single buffer copy across the edge is not among them: binding it joins the two ranges into one import and stores the plane it overlaps. At 7283aa6 no plane is stored ahead of the copies. With both ranges imported the copies hold 0 of 15360 texels; with the second range mirrored or copied they hold 3072, the second range's 64 KiB block, which its mirror refresh or copy stores. Each split case first runs an address-based copy with no import budget, so the ranges that earlier cases left registered are imported before the case sets its budget. Without it, on Windows a range left by the heap-mirrored case was imported inside the copied case, took the budget, and kept the case's first range from being imported.
…ad-only V#s An address-based build binds the registered heaps it maps whole in place and does not store the storage-image results pending in them. A read-only V# inside such a heap was merged into the heap's region on the per-build path, or dropped inside a base region of the cached address space, so nothing stored the results pending under it and the GPU read the import's older bytes. Written V#s were already stored through their write ranges. UploadFinish now stores the results pending under every read-only V# of an address-based build, as it does for written ones. Pointer reads keep the exemption; the out-of-place DB expand still stores its planes ahead of every such build for them. The debt text says both.
The address-based-storage-image-read case stores a value to every texel of an image with one compute dispatch, then copies the image's bytes with the address-based copy kernel through a read-only V#. It does so twice with different values: the first copy takes the per-build path, the second goes through the cached address space. Each copy must hold what was stored; before the fix both held 0 of 15360 texels.
… pending plane The out-of-place expand's debt entry said that every reader of the write base stores the pending plane first. The driver does not see a guest CPU read after a label, which reads the bytes from before the expand, as the pending storage-image results entry already says.
12 tasks done
EagleBearerYS
added a commit
to EagleBearerYS/AnyPS5
that referenced
this pull request
Oct 15, 2026
Merged
10 tasks done
Since 8fec47a (boykopovar#5111), decodeDepth places a slice's HTILE one slice of pipe-aligned metadata per slice after DB_HTILE_DATA_BASE, as addrlib addresses it. The entry still said that every slice shares slice 0's HTILE and that the per-slice stride is not derived.
12 tasks done
11 tasks done
11 tasks done
EagleBearerYS
added a commit
to EagleBearerYS/AnyPS5
that referenced
this pull request
Oct 17, 2026
11 tasks done
11 tasks done
Main adds the depth and stencil plane fill entry to the debt file next to the HTILE array slice entry this branch drops, which main's decodeDepth no longer needs. Keep main's new entry.
11 tasks done
12 tasks done
11 tasks done
Open
12 tasks done
This was referenced Oct 19, 2026
12 tasks done
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A draw that sets DB_RENDER_CONTROL's DEPTH_COMPRESS_DISABLE with DB_Z_WRITE_BASE different from DB_Z_READ_BASE is a DB expand. The DB writes the read surface's depth plane, uncompressed and in the same swizzle, at the write base. With DB_DEPTH_CONTROL 0,
DecodeStatetook the "always-pass depth/stencil state is rendered without a depth target" path, so the draw drew nothing and the write base kept whatever the CPU had written there.Resident Evil Village (PPSA01556, 01.210.000) issues four such draws per frame in its first 3D scene, then lights, fogs, resolves and blends the scene from the copy. With zeros there, which is the far plane in its reverse Z, the scene renders as soft light discs on black. One of the game's draws, from a register trace at first player control:
That's Z_32_FLOAT, one sample, SW_64KB_Z_X, 1920x2160. All other depth draws in the frame read and write at the same base.
Recognition:
DecodeDepthExpandPassdecodes the target with the draw state's own decoder (depthTargetFor) and takes exactly this shape:ColorWriteMask's rule, so an INVALID-format target writes nothing, as for a draw;The copy: each moving plane of the live depth surface at the read base, with any pending fast clear applied, is copied into the storage image of a view of its write base and marked written: R32F or R16 UNORM SW_64KB_Z_X for the depth plane, and R8 UINT at DB_STENCIL_WRITE_BASE for the stencil plane. A slice of a depth array goes to the same slice of the write base. Sampled views of the write base use that image. Raw and CPU reads store it into guest memory in the Z swizzle, as for any written storage image.
In order: the expand runs only from the draw precheck, which decodes it and the colour-metadata pass as one outcome and runs either the same way: it drains the draw pipeline, takes the GPU lock, writes the packet's labels and runs the pass.
Address-based builds: they read host-imported heaps in place without storing the results pending there. So the expanded planes still pending in imported write bases are stored ahead of every address-based build (
StoreDepthExpandWrites). Resident Evil Village's copy shader reads its write base through a V# right after the expand.HostImportOverlaps), not only when one import holds all of it.main, since ea3a215). When part of it has no import, the write-back goes through the CPU after a wait for the expand.UploadFinishstores again after the build's own imports, so a build that imports the range itself stores the plane before reading it. When nothing is noted, that second call is a lock and a scan of an empty map.UploadFinishnow stores the results pending under every read-only V# of an address-based build, as it already did for written ones. Pointer reads keep the exemption; for them the expand's planes are still stored ahead of every such build, as above.Indirect expands: Resident Evil Village issues its expands as indirect draws.
DRAW_INDIRECT,DRAW_INDEX_INDIRECTand their multi forms read their count and records on the CPU, as the draw path's CPU route does.No depth surface at the read base yet (Resident Evil Village does this once during boot): the write base takes DB_DEPTH_CLEAR when an HTILE depth clear of the surface is pending, and otherwise the read base's guest bytes.
Repeats: an expand whose plane the write base's image already holds is skipped. The surface's write serial and the image's content version decide that; 7 expands in the test make 3 copies.
What throws: every other out-of-place expand, naming the reason: Z_24 or no depth plane, multisampled, other swizzles, mips and layer exports, partial coverage, and one into a live depth surface of the same device or from one of another extent, format or sample count. An in-place expand changes nothing modelled, as before.
Debt: a new "Out-of-place DB expand" entry under Unknown function info lists what is inferred and what is left:
TakeStorage, fix(agc): start a new depth surface from the storage writes over its plane #5446); one bound with HTILE doesn't;"Reused depth storage" notes the exception. A second new entry, "Pending storage-image results under the heaps of an address-based build", says what such a build stores and what it leaves to pointer reads. The "HTILE address of a depth array slice" entry goes: since fix(agc): give each slice of a depth array its own HTILE #5111 each slice has its own HTILE.
Not done here, with the reasons:
Tested
agc_driver_depth_expand_out_of_place, an execution test through PM4 using the game's register values:image_loadand throughGuestMemory::Read, detiled with the driver's SW_64KB_Z_X equation.main9f03c4f the write base holds 0 of 15,360 texels of the depth. With the change it holds 15,360 of 15,360 both ways, with one raster sample and with the game's two (PA_SC_AA_CONFIG 0x00108001).DRAW_INDIRECT,DRAW_INDEX_INDIRECT, and a record that draws nothing;agc_driver_depth_expand_reviewchecks the expand beyond the game's case:agc_driver_pipelined_filldoes for fills, and puts the depth draw and the expand in one submission. On GitHub's Linux runner, withmain'sDrawPrecheck.cpp, each of 10 runs failed all three cases on the texture read of the write base, with the draw queued every time; with the drain, all three passed 20 of 20 (run).agc_driver_depth_expand_out_of_placecopy the write base with address-based programs right after the expand:split-imported-buffer-read,split-imported-pointer-read), or one imported and the other heap-mirrored (split-mirrored-buffer-read) or copied (split-copied-buffer-read).mainand on this branch's base, all four fail:expanded planes stored ahead of the copies: 0 (expected 1), then0 of 15360 texels hold the read surface's depthwith both ranges imported, or3072 of 15360with one mirrored or copied.15360 of 15360.main, a temporary print in the write-back showedDB expand: GPU path, 2 segment(s), 131072 byteswith both ranges imported. With one mirrored or copied it showedDB expand: CPU path, 0 segment(s), 65536 bytes, after that range's own write-back of the other 64 KiB.unimported-mirrored-buffer-read,unimported-copied-buffer-read): these pass with and without 103316e, because the mirror refresh and the copy store the pending plane themselves.address-based-storage-image-readinagc_driver_depth_expand_out_of_placestores a value to every texel of an image with one compute dispatch, then copies the image's bytes through a read-only V# with the address-based copy kernel. It does that twice with different values: the first copy takes the per-build path, the second the cached address space. Without bfcd183 both copies hold 0 of 15360 texels; with it, 15360 of 15360.depthExpandPassTestsinagc_driver_graphicscheck the decoder on the game's values and every refusal.agc_driver_graphics: the state-only refusal (with it reverted: "an out-of-place DB expand that reached the draw path was not refused"), the 0xc0 shape, an INVALID-format colour target and a non-finite clear (with the old decode: "… with color writes is not implemented"), Z_16 and Z_24, slices and layer exports, and the stencil decode.agc_driver_depth_expand_review, each read through a texture and raw:agc_driver_depth_expand_out_of_place:direct-indexed: DRAW_INDEX_2 with no indices, or no instances, keeps 32768 of 32768 dwords the CPU wrote (before: 17408), and a three-index expand matches 15360 of 15360;five-range-write-base(a write base across five registered ranges, as Resident Evil Village's spans five 4 MiB mappings),compute-queue-read(an ACB copy),dma-read(DMA_DATA),depth-bind-of-write-baseandstore-without-import-room: 15360 of 15360 in each check. The last pins the import-neutral store, which no lavapipe run can make fail: every address-based build there imports its ranges itself.agc_driver_depth_expand_out_of_place_inline, withAPS5_PIPELINED_DRAWS=0.maina86577e (13ad1f4, the head), which brings perf(agc): replace the plane copies around a depth plane's UAV clear by a depth clear #7178's depth clear and fix(agc): read a 32-bit depth-bits T# over guest memory through a float view #7346's 32-bit depth-bits debt entry. The debt file keeps both ofmain's entries, with this PR's note in "Reused depth storage". The merges before it:mainf474fb7 (c053a55;decodeDepthtakesmain's DB_RENDER_CONTROL check) andmain55f82fe (24ec2d4; the debt file keepsmain's plane-fill entry and drops the HTILE slice entry, as 2559452 does). On GitHub's runners (run): the^agctests (709, 0 failed), with the expand tests, pass 3 runs in a row on Linux, and the libc and libkernel suites pass. On Windows the only failures areagc_driver_pm4_replay_toolandagc_shader_replay_tool, which fail the same way on that runner for an unrelated branch (run).ctest -R '^agc'ran 604 tests, 1 failed (agc_driver_preparation_scope_settle, as onmain), 41 skipped on Linux, and 598 tests, 1 failed (agc_driver_pm4_replay_tool, as onmain), 466 skipped on Windows (run). The expand tests andagc_driver_graphicspass 10 runs in a row on Linux, andagc_driver_graphicson Windows, whose runner has no Vulkan driver for the others; with the sources of the previous head (d359e15) the new cases don't build (run).main2e5dd5a, which brought fix(agc): take depth fast clears from HTILE written by any kernel #5627, fix(agc): apply completion-proven native depth clears #5554 and fix(agc): retire fully released native depth owners #5524's changes toDepthSurface.cpp: the HTILE clear,ApplyFastClearand surface retirement, which the expand uses. The only conflict was one include block, wheremaindropped a duplicateGuestMemory.hppinclude next to the two this PR adds.ctest -R '^agc'ran 603 tests, 1 failed (agc_driver_preparation_scope_settle), 41 skipped (run). Onmain2e5dd5a alone: 601 tests, the same one failed, 41 skipped (run). The two extra tests are this PR's. The two expand tests and seven others around the code the merge changed passed 10 of 10 at the head (run).agc_driver_depth_expand_out_of_placefails with 103316e's code reverted (run), and again with bfcd183's reverted (run). With the code, the two expand tests pass 3 of 3, and in the second run so doagc_driver_graphics,agc_driver_bda_device,agc_driver_bda_span_readsandagc_sparse_buffer_holes. The libc and libkernel suites pass in every build.main8856f18, in WSL:ctest -R '^agc'at 6596a1d ran 558 tests, 0 failed, 40 skipped (the same 40 as onmain), and the two expand tests passed 10 of 10. Merged intomaind92a8da: 579 of 579 in two of three runs (41 skipped), the third failing onlyagc_driver_preparation_scope_settle, which also fails onmain. The full suite there: 1195 of 1201; the other 6 are 5 network tests that need IPv6, which the build VM lacks, and that flake.ctest: 1,293 of 1,293 pass, 488 skipped, all expected bycheck_skips.py.main8856f18, the tree of the head's merge commit (run): MinGW build, thenctest: 1267 tests, 0 failed, 475 skipped, all expected bycheck_skips.py.agc_driver_graphicspassed. The workflow carried the runner-image CA-bundle fix (CI only, no source change). The head itself built with MinGW in the sweep's Windows job (run), wherectest -R '^agc'ran 597 tests: 465 skipped, and 1 failed,agc_driver_pm4_replay_tool, which fails the same way onmain2e5dd5a in that job (the tool exits 0xc0000139 there). Windows runners have no Vulkan driver, so the expand execution tests are skip stubs there and ran on a GPU separately (next item).ANYPS5_REQUIRE_VULKAN=1with only the NVIDIA driver visible,ctest -R '^agc_driver_depth_expand_(out_of_place|review)$' --repeat until-fail:5.ctest -R '^agc_driver_depth_expand_(out_of_place|out_of_place_inline|review)$|^agc_driver_graphics$' --repeat until-fail:5passes all four 5 of 5. Every expand case holds 15360 of 15360 in every run: the Z_16 read base within one 16-bit step, and its 16-bit raw read and R16 UNORM texture read; the stencil-only and depth-and-stencil expands (7696 texels of 0x5a and 7664 of 0xa5); slice 1 of a depth array, with slice 0 keeping the CPU's bytes; and the queued-draw, two-write-base, in-place and always-pass cases.main8856f18 and the drain, merged with fix(agc): bind a read-only V# over the cached address space through the region that holds it #5815's follow-up for one combined run, both pass 5 of 5. The four split cases printexpanded planes stored ahead of the copies: 1 (expected 1)and15360 of 15360, and the address-based storage-image read prints15360 of 15360 texels hold itfor both copies, through the cached address space and without it.agc_driver_depth_expand_reviewfailed 3 of 3 withsecond expand: second read base: 15358 of 15360 texels hold the drawn depth.main23be5a0, plus fix(agc): store a written storage image over a depth plane into the surface #5113 and fix(agc): give each slice of a depth array its own HTILE #5111 (merged since; this change builds on both);[gpu] DB expand: the depth plane of 0x202a8a0000 (1920x2160) is written at 0x20298b0000and, once during boot,[gpu] DB expand: 0x202a8a0000 (1920x2160) has no depth surface; its guest bytes are written at 0x20298b0000;main2e5dd5a with the local commits Resident Evil Village needs on this PC (the merge with this change is clean), withAPS5_LAZY_SHADER_PREPARE=1 APS5_HOST_IMPORT_MIB=6400 APS5_NO_GPL=1:python3 tools/check_conventions.py --base origin/main: passed.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)Overlap: #6188 (draws compiled ahead of queue 0) rewrites most of
DrawPrecheck.cpp, includingprecheckDraw, where this PR runs the DB expand and the colour-metadata pass as one outcome. Whichever merges second carries the other's change: in #6188's design, aDepthExpandoutcome next toMetadataPass, decoded byDecodeDepthExpandPassand run by the executor after the drain. Without one, #6188's ahead classification gets the state-only refusal, so a merge that forgets the expand fails loudly instead of dropping it.#5925 (resolving ahead) guards only the colour-metadata branch of
precheckDrawwithresolvingAhead(). Here both passes share one block, soDrawPrecheck.cppconflicts there, and the guard belongs on that block's first line, where it covers both.#1395 (DB_RENDER_OVERRIDE depth copies) decodes other bits, so the two decodes don't overlap. If both merge, a draw with both takes the expand, and #1395's copy could write through this PR's plane views and pending notes so that its result reaches guest memory the same way.
#6682 (publish unit-shadow results before an address-based build maps its heaps) also adds a line at the end of
UploadFinishinGuestBufferMemory.cpp. Whichever merges second keeps both, with this PR'sStoreDepthExpandWritesfirst.