Conflicts resolved:
- libSceAgcDriver CMakeLists.txt: main moved test registration into tests/cmake/<exe>.cmake (tools/agc_test_split.py resolve); this branch's nested image table tests now sit in agc_driver_image_table_tests.cmake, and its nested snapshot retry test sits next to main's descriptor phis test in agc_shader_memory_tests.cmake.
- ResourceMaterializer.cpp: table equality compares both this branch's nested/pointers and main's resourceViews; the footprint counts main's resource views and this branch's pointers.
- ShaderDiskCache.cpp: both sides grew the descriptor source record (this branch: TableColumn::buffer, 1 byte; main: requiredBlocks, an 8-byte count), so the decoder minimum is 72 + 1 + 8 = 81, and the field-count asserts are DescriptorSource 4 and TableColumn 19.
- ShaderDiskCache.hpp: FormatVersion 56, an unclaimed number (main has 52; 53, 54 and 55 are already set by other open PRs).
- ResourceMaterializer.cpp (semantic, no text conflict): main added the per-image resourceViews loop to Snapshot(source, table), and it uses the top-level table index; this branch moved that copying into CopyRecords(), which nested tables share and which has no table index. The loop now runs in Snapshot right after CopyRecords, as on main; nested tables carry no resource views, as before.
A 3D sample of the same image through another sampler no longer feeds the gather's
state, z modes 4 and 5 no longer count as border addressing, a null image no
longer divides by a zero extent, and the test covers per-axis modes, rounding
ties, denormals, null images and the vertex stage.
NVIDIA's front end spends tens of seconds per large compute program on the
dynamically indexed Function arrays that held the per-lane scratch. A compute
program that uses scratch (scratch_* or a FLAT access that the aperture split
routes to the private aperture) now keeps it in a storage buffer instead, so
no Function array is declared or indexed. FLAT routing is unchanged.
The driver allocates one buffer per compute pipeline on its first dispatch,
capped by APS5_SCRATCH_POOL_MIB (default 64), holding a lock word and an
invocation counter per slot followed by the slots, and binds it in descriptor
set 2 (the layout of the device-memory LDS buffer). The shader takes the slot
count from the array length. Invocation 0 of each workgroup claims a slot with
a compare-exchange scan that starts at its linear workgroup id and spins until
it wins one; a barrier publishes the slot. Every invocation decrements the
slot's counter on every compute exit and the last one frees the lock, so
divergent exits and concurrent dispatches of one pipeline share the buffer
safely. The emitter fails the compile if a compute return lacks the release.
Programs without scratch keep their SPIR-V and pipeline layout.
The buffer is decorated Coherent: without it NVIDIA lost earlier byte stores
of a sequence of byte read-modify-writes to one dword. Lane-private
read-modify-writes no longer use atomics.
Tests: a new execution test covers the private aperture reached through a
table load, a literal and a computed address (store, atomic, and both ways
through scratch_*), a callee reached through s_swappc_b64, isolation of 64
workgroups over one or two slots, divergent wave exits with a second dispatch
reusing the slots, and the module shape (no Function array, no binding in a
program without scratch). The guarded memory load fixture skips the slot
acquisition.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Null buffer descriptors still split modules on unused specialization
fields after buffer presence moved to run time. Learn the first valid
bound fields per slot and use them for absent descriptors, retaining
actual runtime presence and independent bound formats.
Snapshot the learned fields once for result memo keys and materialization
so identical null captures cannot retain a module made before learning.
Cover direct, captured and prepared calls, null stores, and changed formats.
Keep the process-local table and an off switch for main's module selection.
AI-assisted: yes
The conflict in core/libs/prx/libSceAgcDriver/CMakeLists.txt from #12862's split is resolved with tools/agc_test_split.py resolve, which moves this PR's test registrations into tests/cmake/.
ResourceTracker masks the adjust bit before deciding cubeFaceSample, so the 2D
MSAA plane read takes image_sample_a. That predicate also feeds the cube-face and
2D-array-through-3D modes, which nothing has measured with _a. An image now
records adjustedSample when any of its samples sets the bit, and those two modes
refuse it. Disk cache format 50 for the new ImageResource field.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
On NVIDIA's proprietary driver, function arrays that live in local memory
and are read under a data-dependent branch return wrong values in
subgroups 1-3 of a mesh workgroup; subgroup 0 is correct. A wave64
geometry program whose relative addressing keeps its VGPRs in the vector
window therefore loses register writes in every wave but the first. In
the clipping geometry program of Sony's PS5 PSP emulator (PPSA07550) the
empty waves never cleared their candidate primitive slots and wrote
degenerate triangles over wave 0's, so the 3D menu drew spikes.
On that driver a mesh program's window now lives in a device-local
storage buffer of 256 workgroup slots of 65536 dwords, claimed through a
per-slot lock and released after the final barrier. The pool is created
before the first draw that uses it records anything, and its header is
zeroed in a batch of its own that is submitted and waited for; the pool
is published only after that wait, and a failure releases it. Direct
register accesses keep one function variable per register; a direct
store also writes the buffer when a buffer read can see it, relative
reads load the buffer, relative writes store only to it, and a direct
read that may follow a relative write loads the buffer and refreshes the
variable. A buffer entry is zeroed only when a buffer read can see it
before a write. APS5_NO_MESH_WINDOW_BUFFER=1 keeps the arrays.
The MinGW std::filesystem::last_write_time reads and sets file times
through the UCRT stat and utime calls, which convert through local time
using TZ. With a TZ other than the Windows zone, including the one libc
applies from the guest environment, times shifted by the difference:
under TZ=IST-5:30 on an Eastern host a temporary written that second
was 9.5 hours old, so housekeeping deleted it, and a TZ west of the host
set the active cache stamp hours in the past. Housekeeping now reads
times with GetFileAttributesExW, refreshes the stamp with SetFileTime
and compares in system_clock. The housekeeping test runs its child
with a TZ 12 hours from the host zone.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A sampled 1D array view with at least maxImageArrayLayers slices, read
only by image_sample_lz or image_sample_l, gets a runtime image mode that
binds a 2D image holding each viewed slice in two adjacent rows. The
shader rounds and clamps the layer as Vulkan array layer selection does
and samples on the boundary between the two copies, so filtering never
reaches another slice. Other uses keep throwing.
Co-Authored-By: Claude Opus 5.5 <[email protected]>