A guest buffer view off minStorageBufferOffsetAlignment is bound from the
aligned offset below it, and the difference goes into the shader's memory
byte offsets (3dec6ced), but only when those live in the push constants:
a shader whose shader data is a buffer failed with "a guest buffer off the
storage buffer offset alignment in a shader whose shader data is a buffer
is not implemented".
The adjustment now goes into the shader data buffer's byte at
memoryOffsetDword * 4 + element, and a template's data refresh writes the
dispatch's words with the same patches applied.
The geometry path's merged ES/GS programs (VGT_SHADER_STAGES_EN.GS_EN)
were compiled as mesh-stage programs whose input metadata was never
filled in, so every such draw failed with "mesh shader translation
configuration is not supported".
Recompiler:
- BuildShaderStageInputInfo takes the draw's MeshConfiguration; the mesh
input helpers (primitive size, step and counts) are implemented.
- The prologue emulates one NGG subgroup per workgroup: s2 GS_TG_INFO,
s3 the merged wave info per wave, the GS vertex offsets (ES thread
index times VGT_ESGS_RING_ITEMSIZE, odd strip triangles swapped), the
primitive id, and the ES vertex and instance ids. An indexed draw's
vertex id is read from the index buffer through a raw V# the driver
puts in hidden user words 4..7.
- s_sendmsg GS_ALLOC_REQ becomes MeshAllocate. The epilogue zeroes the
allocation first, clamps it to the output limits, culls primitives no
thread exported and decodes the 9-bit vertex indices.
- The draw parameters live in the last six push dwords. A BDA fault in
a mesh program no longer stops the invocation (as for other programs
with barriers, the fault is recorded and the read returns zero), so
every invocation reaches the subgroup barriers and the epilogue.
- The cache keys cover the mesh configuration; requests serialize its
new esgsItemSize field (version 4).
Driver:
- DecodeShaderStages reads VGT_ESGS_RING_ITEMSIZE (now in the draw key)
and sizes the subgroup for its ES vertices, GS primitives and outputs.
- Stages compile below the mesh draw parameters, which every mesh draw
pushes; the mesh stage always takes part in the push range.
- The index-buffer V# is set per draw (per record on the CPU-resolved
indirect path); the index-buffer alias check spares read-only
elements.
- The workgroup and LocalSize checks count two guest lanes per
invocation on 32-wide subgroups; mesh draws may carry a first vertex
or instance.
agc_driver_mesh_tests (EXCLUDE_FROM_ALL, needs VK_EXT_mesh_shader)
recompiles a hand-assembled merged ES/GS program in the PS5 compiler's
layout and draws indexed and non-indexed triangle lists in one- and
two-wave subgroups and a triangle strip across odd-starting subgroups,
reading the pixels back. agc_shader_replay prints a request's draw and
mesh configuration.
Nothing built the graphics test target, so it is now registered with the other AGC tests. It set
APS5_PIN_WAIT_MS through _putenv_s only, which does not exist outside Windows; it now uses setenv
there. The heap mirror tests need a write-watched guest arena and are skipped with a notice
without one, as the recorder tests already do.
S_CBRANCH_CDBGSYS, S_CBRANCH_CDBGUSER, S_CBRANCH_CDBGSYS_OR_USER and S_CBRANCH_CDBGSYS_AND_USER
(SOPP 0x17-0x1a) branch only while a debugger sets the conditional debug bits in the wave's
status, which never happens on a retail console, so they decode to one no-op opcode.
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>
An address-based build maps every readable registered range. A heap
range past APS5_HOST_IMPORT_MIB (or refused by the driver) was copied by
every such build: about 3200 ranges, 670 MiB and 500 ms per build on the
story-mode load, which then stalled. Such ranges are now served by
persistent host-cached mirrors, as the main image is, and the load
reaches its next failure.
- a heap mirror keeps no shadow; it keeps a write-tracking generation
per 64 KiB block and a build copies only the blocks stamped since. The
generation is stored by the copy, so a build that throws before it
leaves no block marked current with stale bytes
- the build gathers its heap mirrors, sorts them and collects each run
of adjacent ranges once (a collect costs about 4 us whatever its size;
~3000 mirrors took 16 ms per build, now about 3 ms)
- writable ranges are mirrored too: each build keeps the bytes its merged
written ranges held at upload and write-back stores only what the GPU
changed from them, so a CPU store made meanwhile stays; recorded work
writing a range completes before a refresh reads it
- the mirrors are limited by APS5_HEAP_MIRROR_MIB (24 GiB by default); a
mirror past it, or one whose buffer the driver refuses, stops the
process. Heap mirrors are not given to descriptor sub-ranges, image
mirror serials or reusable direct regions
- past APS5_ADDRESS_COPY_MAX_MIB (64 MiB by default) of committed bytes
still copied, a build stops the process, naming the largest ranges and
why each is copied (unreadable pages, an image mirror the driver
refused, a range outside the write-watched arena, mirrors disabled)
- a direct memory page mapped at several addresses is read-only in every
view while its range stays writable: copies, descriptor regions and
mirrors take every readable page, write-back stores the writable ones
and fails on a GPU change inside a read-only page instead of dropping it
- a store through the BDA table into a mirrored or copied range faults
as before (only writable ranges imported in place are writable there);
the fault now names the table range and that rule
- the BDA resource tests run with a storage range limit that holds the
fault buffer and cover a mirror's fill, reuse, per-block refill, an
interrupted refresh, a descriptor store beside a concurrent CPU store,
and the copy limit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both suites stopped at their first stale expectation, so nothing after
it ran; the BDA device tests did not link.
- the BDA device tests define the one recorder entry Resources.cpp
reaches (no recorder) and fail loudly on the others
- Buffer::Invalidate refuses memory that is not host mapped again (lost
in 8a69fef); the device tests expect it for a device-local buffer
- APS5_PIN_WAIT_MS (60000 by default, unchanged) bounds the wait before
a mutation of a leased range is refused, and the refusal names it; the
graphics tests set 200 ms, as they expect about a dozen refusals
- the expectations follow the behaviour the code chose since: a buffer's
four-DWORD V# is refused as a T#, a sampler exceeds the mock's zero
sampler slots, a V# at unmapped memory binds its committed pages only,
a rect-list fragment input without a vertex export reads as zero,
detiled rows span the padded block width, mip ranges are checked in
address order, block-compressed and 128/129/132 formats use render
target tiling, an XOR swizzle is refused only over a base that is not
64 KiB aligned, DCC and partial mip chain views decode, a cube reads as
a 2D array, the sampler fixture's max LOD fits the 4.8 field, a BDA
program with barriers is accepted, a tessellation control stage is
refused, a corrupt request fails on its signature and a newer one on
its version
- the DCC comment in the texture decoder no longer claims metadata
compression is refused
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A V# with records but a base address of 0 threw at bind time ("null shader
buffer descriptor address"), although a shader that never reaches that slot
works on hardware; an access through it would fault there, so a working
title does not make one.
Such a V# is specialized empty like one without records (every access out of
bounds) and binds the placeholder buffer; the draw cache's alias check skips
it as the build does. The tests expecting the old rejections are dropped.
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>
An MRT export to a slot past the draw's color attachments (outside
CB_TARGET_MASK & CB_SHADER_MASK, e.g. MRT1 with only slot 0 enabled) is
dropped by the color backend. Vulkan discards a fragment output without
an attachment the same way, but validation rejected the draw ("fragment
shader must export float4 colors at locations below the attachment
count"). Such outputs are now left out of the written locations, and
only the exports that reach an attachment must be float4.
Vertex buffer formats 50-55 (2_10_10_10 UNORM, SNORM, USCALED, SSCALED, UINT, SINT: X in the low
10 bits, the 2-bit W on top) map to Vulkan's A2B10G10R10 packings, and format 36 (10_11_11_FLOAT:
X in the low 11 bits) to B10G11R11_UFLOAT, the same mapping TextureFormat uses for textures.
11_11_10_FLOAT (43), whose 10-bit X has no Vulkan packing, stays rejected.
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