SET_PREDICATION threw, and packets with the predicate header bit were
rejected. The executor now keeps the queue's predication: operations 3
and 4 read a 64- or 32-bit value and bit 8 selects whether predicated
packets run when it is non-zero or zero; operation 0 clears it. Before
a predicated packet runs while predication is active, queued labels are
recorded and the value is read, as for COND_EXEC; the packet is skipped
when the predicate fails.
Indirect buffers are inlined when a submission is copied, so a
predicated INDIRECT_BUFFER call keeps its header in front of the
inlined commands and records their end like a COND_EXEC range; the
block runs or is skipped on one evaluation, as on the command
processor. Query predication, a predicated COND_EXEC, predicated chains
and flips inside predicated command buffers throw.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WRITE_DATA's control dword carries a two-bit cache policy in bits
26:25 (LRU, stream, no-allocate, bypass). Validate refused it, so a
submission with a WRITE_DATA built with a non-zero policy was rejected
as a whole.
The policy only steers how the GPU L2 keeps the written lines; the
stored words are the same, and Execute already writes them to guest
memory in queue order. The mask now accepts bits 26:25, as was done
for DMA_DATA's cache policy hints. The CE engine and the remaining
reserved bits still throw, and the message no longer names the cache.
agc_driver_pm4 stores both dwords of a WRITE_DATA with control
0x04100200 and checks that reserved bit 27 is still refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Validate refused every COND_EXEC, so a submission that uses one was
rejected as a whole. The packet now reads the dword at its address once
the earlier packets of its queue and their GPU writes have completed,
and skips the exec_count dwords after it when the dword is zero.
The command copy that inlines INDIRECT_BUFFERs records where each range
ends, so a range over an INDIRECT_BUFFER skips the whole buffer.
Unaligned addresses, address bits 48 and up, and reserved control and
count bits throw; the cache policy is accepted on compute queues only,
as the MEC defines it. A flip inside a range, a range that ends inside
a packet or past its command buffer, and a chained INDIRECT_BUFFER or
REWIND inside a range throw.
agc_driver_pm4 and agc_driver_flip cover the skips and the rejections.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WRITE_DATA's ENGINE_SEL (control bits 31:30) picks the CP engine that
performs the write: 0 the micro engine, 1 the prefetch parser, 2 the
constant engine. Validate refused every engine bit, so a submission
with a PFP WRITE_DATA failed as a whole. The prefetch parser handles
packets in queue order ahead of the micro engine, and the driver already
performs the write in queue order, so PFP is accepted like ME. The
constant engine stays refused.
Tests: agc_driver_pm4_tests runs a PFP WRITE_DATA and checks that a CE
one is still refused.
A DMA_DATA too large to resolve as a store drained the device and then
copied on the submitting worker's thread. For a large range that copy takes
milliseconds, and meanwhile another queue's worker records, submits and runs
work that reads the destination in place. PPSA21564 copies each 12 MiB
frame of its intro video into one of two textures with a single DMA_DATA on
one queue and samples it on queue 0 without waiting for that queue; the
GPU's own DMA finishes in microseconds, so the title never needed to. Here
queue 0's upload of the texture ran while the CPU copy was still writing
it, and a frame showed the new frame's luma over the chroma of the frame
two before.
Such a copy (both addresses memory and incrementing, ranges disjoint and
non-empty) now goes through VulkanDevice::CopyBuffer like the copy kernel:
a transfer between the host imports, recorded in order, so everything
recorded after the packet reads the whole copy. The drain and CPU copy
remain the fallback when either range is not host-imported.
Every SET_*_REG packet stored each register into a std::map, and every
draw read dozens of them back through map lookups (the decoders, the
draw key's range walks, the prechecks). PPSA21564 sends ~350k register
packets per 10 s at the title, and the map's node allocations and tree
walks were a visible share of the graphics queue worker's time.
Registers is now a flat value array with a presence bitmap per bank. It
keeps the map's interface and semantics: absent registers stay absent,
iteration and lower_bound walk the present registers in offset order,
emplace does not overwrite and at() throws for an unset register.
The GE adds GE_INDX_OFFSET to every index it fetches. The driver applied
it to auto draws only, so DRAW_INDEX_2 and DRAW_INDEX_OFFSET_2 fetched
from vertex 0 whatever the register held. Both packets now take it as
their base vertex, and like an auto draw they refuse a queue state without
the register (its reset value, 0, is part of the initial state).
Only the lines this branch added lose their comments; the commits before
keep them, with the reasoning behind each change, for whoever digs into
that code later.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EVENT_WRITE PIXEL_PIPE_STAT_DUMP (event 0x39) dumps the DB sample
counters. The recorder, once a title asks for them, keeps an occlusion
query open over each batch (precise when the device supports it) and adds
the result to a running count when the batch is reaped. A dump drains
recorded work like a label and writes the count in the PS5 layout: 16 DBs
16 bytes apart, begin and end counters interleaved, the count in the
first and bit 63 marking each ready. Kyty and SharpEmu write a fixed
"visible" result instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Depth/stencil: draws that test depth or stencil against a bound surface
render with a GPU-only depth/stencil attachment (DepthSurface), cleared
to DB_DEPTH_CLEAR/DB_STENCIL_CLEAR when made. Z test/write/function and
per face the stencil function, operations and masks (BACKFACE_ENABLE);
replacements by another value where Vulkan's single reference can carry
them. Clear and copy draws, add/sub other than 1, array or mip views
and MSAA throw, and texture reads of a surface's memory are refused.
Scaleform menus mask with the stencil (REPLACE 0, ADD_CLAMP, EQUAL);
their masked content was skipped before.
- Mipmapped color targets render through the resident image of the whole
chain with a view of the mip, so mips in the packed tail are drawn too;
CB_COLOR_VIEW's mip level is read from bits 26-29 (GFX10).
- Color: SNORM targets, UNORM16/SNORM16 exports, one-component formats
honouring COMP_SWAP (A8), 32_R/32_GR/32_AR exports, linear rows padded
to 256 bytes, BLEND_BYPASS.
- INDIRECT_BUFFER jumps are followed when copying a submission; thin 3D
textures in display and rotated XOR swizzles; only the bytes the GPU
changed are written back; resource registration.
- VideoOut: a flip stalls the GPU queue while the flip queue is full and
holds the submitter back.
- APS5_DUMP_FRAMES_EVERY dumps every k-th presented frame.
- The graphics test target builds again (missing sources, a hand-aligned
64 KiB buffer, stale expectations updated) and gains DepthStencilTests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DISPATCH_INITIATOR bit 13 (TUNNEL_ENABLE) asks the SPI to launch the dispatch's waves ahead of
other work. It is a scheduling priority hint with no effect on the results, so direct and indirect
dispatches accept it like the other ignored modifier bits.
Dispatch cache with per-key value variants and data-only hits (flat-SRT leaves the recompiler
proves pure are refreshed into the resource template instead of re-captured), dispatch and draw
recipes replaying a proven prepare, register-keyed draw entries, template data refresh, unit
shadows in device-local slabs, 64 KiB block-unit storage tracking with windowed detile, DCC
clear-key proofs, per-class GPU timing, a CPU copy path with batch read tracking, present slot
ring, rate-limited reaps and lazy completion counting, plan-failure and poisoned source memos,
bindless image tables (runtime-indexed descriptor arrays from a CPU-read table) so the
per-frame compute program that failed its plan now compiles. Worker affinity opt-in, per-draw
logs behind APS5_TRACE_DRAWS, wait-timeout reports include the recorder's view of the label.
Fixes a use-after-free behind BDA-miss dispatch snapshots and the CPU-write stamp of
UnchangedSinceCollected. Intro-video stage: 154 -> ~500 presents per 10 s at 4K.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177gthrWEBBfBu5xJDXgBfo