A sampled 32_UINT or 32_SINT T# with a depth swizzle that no live depth
surface matches threw, while the 16-bit case already falls back to guest
memory through an R16_UNORM view. The 32-bit case now reads the guest
bytes through an R32_SFLOAT view, which the shader casts back to the
stored dword.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Main's #7325 adds verifyChainedTableOffset to the image table tests
where this branch adds its selected-record tests. Keep both, with
main's call after this branch's.
Main's #7269 keeps the synchronous settle's buffer, memory and fence
per device in ImportSettle, so clearing one device's imports releases
only that device's objects. This branch's settle batches move there
too: each device's ImportSettle holds its batch target, memory and
batches with their fences, so switching devices no longer drops a
device's batch handles, and clearing a device waits for and destroys
only its own batches. The per-import settle state is renamed
pendingSettles to stay clear of main's per-device map, and a submitted
settle records the device whose batch it is in.
Main's #7101 reads a key buffer's words in one call where this branch
names the reason a narrowing is skipped. Keep main's bulk read and
count both of its unmapped-page skips as unmapped.
Color format 7 (COLOR_11_11_10, float) keeps its 10-bit component in the
low bits; with the reversed component order (COMP_SWAP 2) that is blue,
with red in the high 11 bits. Vulkan has no such layout, so the target was
refused at decode.
Render it the way 10_11_11 unorm targets are rendered: an R32_UINT
attachment, the reversed export mapping 0xc6, and a new
ColorExportPacking::Float11_11_10 that makes the pixel shader pack each
export with the format-43 image store conversion (toward zero, overflow to
the largest finite value, negatives to zero, NaN kept). Blending, partial
writes, 16-bit integer exports, DCC and the other component orders throw.
AI-assisted: yes
Texture format 43 holds unsigned floats of 10 bits (R, bit 0), 11 bits
(G, bit 10) and 11 bits (B, bit 21). VK_FORMAT_B10G11R11_UFLOAT_PACK32
holds R11 at bit 0, G11 at bit 11 and B10 at bit 22, so storing the
guest R field in the Vulkan B field and the guest B field in the Vulkan R
field moves every texel without changing a bit of any component. A
sampled texture of format 43 is now uploaded that way (a repack pass over
the detiled words, TextureRepack.comp) and viewed with R and B swapped
back (TextureComponentChannel), so the shader samples it natively: point
and bilinear filtering, every mip level and LOD, and cube faces
work as for any other float texture. A texture whose results a storage
image still holds is copied from that image (vkCmdCopyImageToBuffer, the
repack pass, vkCmdCopyBufferToImage) and copied again whenever the
image changed, like the depth and block copies. The recompiler treats a
sampled format-43 image as a float image without conversion; storage
reads and writes keep the packed R32_UINT path, and a 3D texture whose
results are still in a storage image is flushed and uploaded instead.
PPSA01317 samples a mipmapped format-43 texture at a LOD other than 0
and a format-43 cube map during boot.
AI-assisted: yes
The generated rect-list control stage gave every corner of a rectangle the
flat inputs of its first vertex, so last mode was refused for rect lists.
BuildRectListShaders now also builds a control stage that takes them from
the rectangle's third vertex when the pixel shader has a flat input, and a
draw in last mode uses it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A sparse import binds whole 64 KiB blocks, so a range whose memfd offset
is not a multiple of 64 KiB fell back to one UDMABUF_CREATE and, above
udmabuf's size limit, to copies. The sparse buffer now starts at the
block below the range: HostImport::lead holds that distance, the
import's device address points at the range itself, and every offset
into the import's buffer goes through HostImportOffset.
Goosebumps Terror in Little Creek (PPSA27305) aborts in gameplay with
"unsupported color format 16 number type 0 component swap 2": it renders
into a COLOR_5_6_5 UNORM target. The target now renders into
R5G6B5_UNORM_PACK16. AMD keeps X in bits 0-4 and Z in bits 11-15, and
Mesa's ac_translate_colorswap programs SWAP_STD_REV for a surface with
red in bits 11-15, so with SWAP_STD_REV the exports are written as they
are and with SWAP_STD they are written with X and Z exchanged, as for
1_5_5_5. The alternate swaps and other number types keep throwing.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A compute kernel that stores one colour to every texel of a storage image over a depth plane (a shadow atlas clear) copied
the whole plane depth image -> staging buffer -> mirror before the dispatch and mirror -> staging buffer -> depth image
after it, although the kernel reads nothing and writes every texel.
A dispatch of the 15-word 8x8x1 image clear kernel (direct, no partial last group) whose T# lies on a depth surface now
reads its colour from guest memory under the GPU mutex, the place the kernel reads it. When the dispatch covers the whole
plane, the plane is one layer of level 0, the colour is a value the plane's format holds exactly (0 or 1 for a 16-bit
unorm view, 0 or 0xffff for a 16-bit uint view, 0 or a normal float in (0, 1] for a 32-bit view) and nothing is waiting to
write the colour, the dispatch still writes the mirror but the copy-in is left out, and the copy-out becomes a clear of the
depth image to that value. The colour is read again when the copy-out is replaced; a changed value keeps the copy-out.
Every other dispatch, stencil planes and declined values keep both copies.
agc_driver_depth_clear_hle_tests runs the clear sequences with the clear taken and with the copies, and compares the depth
image texel by texel through the mirror, the guest memory and the depth tests.
A fill that covers a depth surface's whole stencil plane with four equal
bytes, or its whole depth plane with a value in 0.0-1.0, now reaches the
host image through the pending fast clear the next time the surface is
bound, sampled or stored to. An HTILE fill or HTILE clear kernel noted
afterwards replaces the value with DB_DEPTH_CLEAR/DB_STENCIL_CLEAR.
NoteDepthMetadataFill only reacted to fills of DB_HTILE_DATA_BASE, so the
Cohtml UI of Heretic + Hexen (PPSA26525) and DOOM + DOOM II (PPSA21444),
which resets its stencil plane to 1 with a 0x01010101 fill every frame and
then draws with stencil Equal 1 and 2, kept the stencil of earlier frames
and showed black squares and clipped text. agc_driver_depth_plane_fill
pins the rules.
StorageTextureBudget gave the storage image cache a quarter of the VK_EXT_memory_budget
budget of the largest device-local heap (capped at TextureCacheBudget, never below 512 MiB)
whatever else the heap held, while SampledTextureBudget takes what that budget leaves after
the heap's other use. On a 10 GB card the storage cache kept 2024-2170 MiB into a level load
whose depth and render target allocations then failed with VK_ERROR_OUT_OF_DEVICE_MEMORY
with the heap at its reported budget where a run logged it.
The storage image budget is now what the reported budget leaves after the heap's use other
than the cached storage images, the unused part of the sampled textures' 2 GiB floor and an
eighth of the budget; the caps at a quarter of the budget and at TextureCacheBudget and the
512 MiB floor stay. The sampled budget still reserves TextureCacheBudget for the storage
cache, at least the storage cap, and the storage budget reserves the sampled textures alive,
so neither counts bytes the other may take; while the sampled textures alive stay within
their floor the sampled budget falls first, then the storage budget, and above it both fall
together. The budget line also prints when the storage image budget moves by more than a
tenth, with its previous value, and StorageTextureCacheBudget is exported for the execution
test.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Both cases printed that the image storage table exceeds its capacity. They need different fixes, so each now has its own message with the set, the element's index in the set and the capacity. The debt entry now says that the index counts every table element before it in the set.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The non-split descriptor set's pool now counts the storage table binding's
descriptors, as the split path already did. A table storage element whose
minimum LOD clamps above the level it addresses is rejected per element, as
the direct path refuses it, and the element is looked up as written so a depth
surface under it is retired. The registration test checks again that
image_store_mip, image_store_pck and image_atomic_add through a table stay
unsupported operations that fault on use.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The debt entry cited ARB_multisample's centermost-sample shortcut as
what a single-sample scan into a multisampled depth target draws. The
draw tests each depth and stencil sample with the depth at the pixel
center, which is the rule above that shortcut (L185-L190 and
L422-L425); the shortcut is now named as an unmeasured alternative.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A draw with PA_SC_AA_CONFIG.MSAA_NUM_SAMPLES 0 and MSAA_ENABLE clear
into a 4x depth target threw "the depth target's sample count differs
from the rasterizer's", which stops METAL GEAR SOLID: Peace Walker
(PPSA18216) at its first presentation. Such a draw now rasterizes the
depth target's sample count with every sample at the pixel center, as
a single-sample scan into a multisampled color target already does.
radeonsi programs this MSAA_ENABLE and PA_SC_AA_CONFIG with the depth
buffer's own sample count when GL multisampling is disabled, and GL
then gives full coverage with every depth and stencil sample set from
the pixel center.
Triangles and rectangles are accepted. Points, lines, alpha-to-coverage,
DB_EQAA Z interpolation or overrasterization, a pixel program reading
the sample index and a sample-mask export throw on this path, as does
a single-sample color target next to the multisampled depth target.
The primitive check is shared with the single-sample MSAA_ENABLE rule,
whose behaviour and messages are unchanged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Main's #5905 settles Linux dma-buf imports with settleImport, which is
now built on both platforms. The batched settle of Windows imports under
1 MiB, its counters and adoptSettleDevice's batch reset stay Windows-only,
and ClearHostImports drains the batches only there.
An import made at map time settles inside the guest's map call, so the mapping thread waits while the kernel maps the pages. A device that imports shared memory through host pointers settles nothing, so the test expects a settle only for a dma-buf import.
A graphics pipeline the store builds or a compute pipeline a dispatch builds is
appended to pipelines.journal next to the shader cache entries, as the
materialized result of each stage (the specialized SPIR-V, bindings and push
constants) plus the recipe the pipeline was built from: the stages'
identities, vertex input layout, descriptor set layout keys and the state
fields the Pipeline constructor reads. When a VulkanDevice is created with a
window (a headless device waits for its first draw or dispatch, since the
window's device usually replaces it first) the journal is loaded and its
pipelines are built on a pool of threads while the title loads, so the first
draw or dispatch of a configuration seen on an earlier run finds its pipeline
resident instead of compiling it on the queue worker.
The pipeline stores key on RecompileResult::Identity, a hash of the module
words, specialization constants, subgroup width and bindings that is the same
on every run (SharedSpirv::ContentHash, computed once per shared module),
rather than on the process-lifetime variant ids; a generated stage is keyed
like any other. CachedPipeline builds outside the store's mutex and the
library parts and link are built outside the library store's mutex, so replay
threads and queue workers build in parallel; a concurrent build of the same
key keeps the first inserted. A replayed pipeline enters the store at its
least recently used end and a full store takes none, and its optimized relink
waits for the first draw that binds it, so the title's own pipelines come
first in both. The compute pipeline creation moves into
VulkanDevice::createComputePipeline, shared by dispatches and the replay. The
store key also covers the color component mapping, the depth target's sample
count and a depth bias clamp, which the constructor reads.
The file names the device it was written for (the properties the driver's
pipeline cache file is named by) and starts over for another; a torn tail is
cut at a record boundary; two runs sharing the directory take turns on a lock
file and keep each other's records; a read failure never starts the file
over. A device cancels its replay before it is replaced or destroyed, and a
replaced device destroys its pipelines then rather than at the driver's stop.
APS5_NO_PIPELINE_JOURNAL=1 disables it; APS5_PIPELINE_JOURNAL_THREADS,
APS5_PIPELINE_JOURNAL_ENTRIES (the first recorded), APS5_PIPELINE_STORE_ENTRIES
and APS5_PIPELINE_JOURNAL_MAX_MIB bound it; APS5_PROFILE_DRAW prints a
[pipeline-journal] summary. APS5_VERIFY_SET_LAYOUTS=1 now also checks a
dispatch's set layout against the one described from its shader. The lavapipe
test suite, which shares one cache directory, runs with the journal off except
for the journal's own tests.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01P6hw3kRAuQdfcU9YCZgaoK
A GPU hang or a crash in a title leaves no record of what the queues
were last given: APS5_TRACE_GPU prints every submission (too much to
leave on), and the WAIT_REG_MEM timeout message shows only the packet
before the wait on the waiting queue.
Each queue now keeps a ring of its last 16 submissions
(APS5_PM4_RING=<n>, 0 to 4096, 0 disables): the TraceMs time in tenths
of a millisecond, serial, size, guest address and a copy of the first
512 dwords after indirect buffers are inlined, recorded under the
driver lock next to the serial, REWIND tails included. The ring of a
queue and the failure report registration are set up at the top of
Submit, before any output is reserved, so recording under the lock
does not allocate. Disabled, Submit only tests a static flag; enabled,
it costs one bounded copy per submission.
DumpSubmissionRings decodes the kept dwords with Pm4::PacketWords and
the new Pm4::KnownName, which returns the decoder's names as views of
static strings (empty for an unknown opcode, printed as UNKNOWN_0x%02x);
Pm4::Name now builds its std::string from it. Every line is formatted
with integer and string conversions only into a 512-byte stack buffer
and written with one WriteFile / write(2) on the stderr handle, so the
dump does not allocate from the C runtime heap, lines from other
threads do not interleave and the CRT stream lock is not taken (the
rule of #3871). The header gives the number of queues and the ring
size, and each queue line the submissions recorded and kept.
libc gets a small registry of failure reports
(LibcRegisterFailureReport_nid_no_patch, Unregister, Run); Run runs
the registered reports the first time it is called and returns at once
after that. The Windows crash report runs it after the thread dump of
an unhandled exception, after SIGABRT (which also covers the
APS5_HANG_DUMP_SECS timed dump, since it aborts) and after an invalid
CRT parameter, so an abort after a reported exception does not print
the rings twice. The driver registers its dump at the first submission
and unregisters at static destruction; the dump there waits a bounded
time for each ring lock. What the crash-path dump cannot do (a ring
held by the crashed thread, rings corrupted by the crash, Linux) is
recorded in technical debt.
APS5_STALL_WATCHDOG_SECS=<n> (0 to 86400, 0 disables) makes a waiter
that has not progressed for n seconds dump the rings once per wait: a
WAIT_REG_MEM (progress as for APS5_GPU_WAIT_TIMEOUT_MS: another packet
runs or completes), a REWIND waiting for the title, and a compute
submission held behind queue 0. The last one prints under the driver
lock, so submissions and the other queues wait for it (USAGE.md says
so). Both variables are read at the top of Submit, so an invalid value
of either throws at the first submission and never later inside a GPU
worker. The order wait behind queue 0 releases its order hold on scope
exit, so a throwing dump cannot leave it counted.
No packet semantics change; packet sizes and names are those of the
existing decoder (PM4 type-3 header layout as in Mesa
src/amd/common/sid.h). The queue bound of Submit and of the rings is
one constant, SubmissionQueueEnd.
Tests: agc_driver_pm4_tests gets ten modes, each its own ctest:
agc_driver_pm4_ring (APS5_PM4_RING=4, six submissions on queue 0 and
two on 0x20: the dump holds #3..#6 and #1..#2 in order, nothing
older), agc_driver_pm4_ring_empty (one line), _ring_disabled (one
line), _ring_invalid and agc_driver_pm4_stall_watchdog_invalid
(APS5_STALL_WATCHDOG_SECS=1x: the submission throws and is not
executed), _ring_report (LibcRunFailureReports_nid_no_patch dumps the
rings), _ring_report_heap (Windows: with ucrtbase.dll's HeapAlloc and
HeapReAlloc imports counting calls from the reporting thread, the
failure report of a submission holding INDEX_BUFFER_SIZE names it and
allocates nothing, while Pm4::Name of the same header is seen
allocating), and with APS5_STALL_WATCHDOG_SECS=1 a WAIT_REG_MEM
(agc_driver_pm4_stall_watchdog), a REWIND (_stall_watchdog_rewind) and
a compute submission held behind a queue 0 rendering wait
(_stall_watchdog_order), each held for about 2.5 s, dump once and
complete when released. The PM4 catalog test checks KnownName against
every opcode and custom name. windows_backtrace_failure_report checks
that abort() runs the registered reports once and not an unregistered
one; windows_backtrace_failure_report_once that abort() does not run
them again after an earlier run. With the dump decoding through
Pm4::Name, agc_driver_pm4_ring_report_heap fails with "the failure
report allocated from the C runtime heap"; with Run resetting its
flag, windows_backtrace_failure_report_once prints the report twice.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A multisampled rasterizer drawing into one-sample targets keeps
PERSP_SAMPLE, LINEAR_SAMPLE and ANCILLARY inputs, and with PS_ITER_SAMPLE
also centroid inputs, since only sample 0's coverage reaches the targets.
Coverage inputs, and the sample index with POS_X_FLOAT or POS_Y_FLOAT,
still throw. The input rule for the non-iterated case follows
fdfawef324's proposal on #5907 (PPSA07411).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A draw whose rasterizer has more samples than its color or depth targets
threw "a color target's sample count differs from the rasterizer's" or
"the depth target's sample count differs from the rasterizer's". When
every target has one sample, MSAA_ENABLE is set, and there is no
alpha-to-coverage, no PS_ITER_SAMPLE and no sample-dependent pixel input,
only sample 0's coverage reaches the targets, so draw it with one sample
at sample 0's location in each pixel of the grid. One-sample depth images
are created sample-location compatible when the device allows it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>