PPSA01325 stops on sceFontGlyphDefineAttribute right after generating a character glyph: it sets attribute 0x11 to 0 on that glyph, deletes it without using it, and draws the character with sceFontRenderCharGlyphImageHorizontal. The meaning of the attributes is unknown, so the call checks the glyph and ignores the rest; TechnicalDebt lists it under silent stubs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTjpbMX7BUFMZZaxJE98zV
Astro's Playroom (PPSA01325) fails eager binding on three imports. The two voice chat group requests follow the offline model of the other sceVoiceChatRequest* calls and return SIGNED_OUT; sceRudpActivate, whose signature is unknown, is declared as a throwing stub.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTjpbMX7BUFMZZaxJE98zV
PPSA16064 (Minecraft Dungeons II, Unreal Engine) failed to load because
these imports had no export:
- libkernel: sceCoredumpWriteUserString
- libSceSaveData: sceSaveDataConvert, sceSaveDataGetConvertProgress
- libSceVideoOut: sceVideoOutVrrPegToFixedRate,
sceVideoOutVrrUnpegFromFixedRate
None of them is called during the title's start-up, so they are added
as unimplemented exports that throw with their name if a title calls
them. Their signatures are unknown; TechnicalDebt records them. The
built libraries export the NIDs the title imports.
Every command writer checked bottom <= cursor_up <= cursor_down <= top.
PPSA16064 (Minecraft Dungeons II, Unreal Engine) builds small one-packet
buffers (8 dwords) with cursor_down left null, and the first
sceAgcDcbCopyData into one threw "invalid command buffer cursors".
Nothing in the library allocates downward, so cursor_down only bounds
the space above cursor_up. A null cursor_down now means that bound is
top. Non-null cursors are checked as before. TechnicalDebt records the
assumption.
agc_commands writes six dwords into such a buffer and checks that a
further allocation past top fails without moving the cursor.
NID fCWdlnmB1Ks was exported as an unknown function that threw. The
name scePadIsRemoteController hashes to it. PPSA16064 (Minecraft
Dungeons II) calls it once per controller after
scePadGetControllerInformation, with the pad handle and the address of a
byte it has just zeroed, and ignores the result.
It reports whether the controller is connected through Remote Play.
Controllers here are local devices, so the answer is always false. An
invalid handle returns INVALID_HANDLE and a null output INVALID_ARG, as
the other pad calls do. Without it the title aborted at the main menu.
scePadSetAngularVelocityBiasCorrectionState, which the title imports but
does not call during start-up, is added as an unimplemented export.
guest_pad checks the handle and null-output errors and the result.
sceHttp2SendRequestAsync no longer fails synchronously: it queues a
completion carrying the network error and triggers the user event named
by the kqueue option. sceHttp2WaitAsync returns queued completions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BREAKING CHANGE: CLI and Python callers must supply all seven float
controls. Add clamp, rounding and FP16 overflow settings so hardware
measurements cannot silently use an unintended mode.
Refs #981
Storage images of a SINT format threw "storage image descriptor uses
an unsupported format"; only write-only 32_SINT was accepted.
The recompiler now writes 16_SINT, 8_8_SINT, 32_SINT, 16_16_SINT,
8_8_8_8_SINT, 32_32_SINT, 16_16_16_16_SINT and 32_32_32_32_SINT
storage images with the Uint numeric class. 8- and 16-bit components
are saturated (EmitFormatStoreComponent) and 32-bit ones stored
unchanged, as measured on RDNA2 (gfx1035); image_store_pck stores
32-bit components unchanged too. The driver binds these surfaces
through a cached view of the same-size UINT format.
8_SINT, 32_32_32_SINT, the packed SINT formats (11_11_10, 10_11_11,
2_10_10_10, 10_10_10_2), D16 stores, packed stores of 8- and 16-bit
components and atomics other than 32-bit ones on 32_SINT and 64-bit
ones on 32_32_SINT still throw. New test: agc_driver_image_store_sint,
with DST_SEL X,Y,0,1 on the two-channel formats, as with X,Y,Z,W the
hardware writes channel 1 from the W data slot (TechnicalDebt).
NVIDIA 610.62 cannot sample R8G8_SRGB, and lavapipe can sample neither
it nor R8_SRGB, so an 8_8 sRGB T# made an image the device does not
support: creating it crashes the NVIDIA driver and lavapipe loads zeros.
The device's format support is read once. An 8 or 8_8 sRGB texture the
device cannot sample is created and viewed as R8_UNORM or R8G8_UNORM,
and SpirvTarget::srgbDecodeFormats makes the materializer mark the
image, so image loads map every channel through a 256-entry table of
the sRGB EOTF rounded to nearest even at bf16 precision, which is what
RDNA2 (gfx1035) returns; both channels of 8_8 are sRGB, and DST_SEL 0
and 1 map to themselves. Samples and gathers of such an image throw,
and its bindless table entries are unmapped like converted formats.
APS5_SRGB_SHADER_DECODE=1 takes this path on every device. Shader disk
cache entries and keys carry the mark: cache format version 7.
DS opcodes 0x6e and 0x6f exchange two qwords at offset0 and offset1
scaled by 8 (st64: 512) and return both old values. Each address is
exchanged with its own 64-bit LDS exchange on the locked 64-bit path.
Equal offsets and a destination past v255 throw, as for the b32 forms;
64-bit GDS throws like the other 64-bit DS atomics.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comparison sampling of a color texture threw on the _o, _b and _cl
forms and on a sampler LOD bias. The emulation fetches the texels
itself, so the 6-bit offsets of the address are added to the point or
bilinear texel indices, as on the hardware and in Vulkan. The emulation
runs only at level zero or on a single-level view, where an LOD bias or
clamp cannot select another level, so they are accepted with no effect.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LookBackScan runs a 43-instruction decoupled look-back written for the
test: one aggregate per block, the block index from an atomic counter,
{flag, value} published with buffer_atomic_swap_x2 and read back with
glc buffer_load_dwordx2. Seven single look-backs and 50 scans of 4096
blocks are checked against a CPU prefix sum; without the recompiler
change the first whole scan fails (3 of 3 runs).
TechnicalDebt records that only glc, aligned, in-bounds dwordx2 loads
in programs with the 64-bit storage view are one atomic load: loads
without glc, and loads in programs without 64-bit buffer atomics, can
still tear against a concurrent swap_x2.
image_atomic_* with a two-dword data mask (four for cmpswap) is the
64-bit form of an integer image atomic. The decoder rejected it with
"invalid MIMG data mask". PPSA14632 (Unreal Engine) uses
image_atomic_umax this way in a compute shader during its first frames.
Swap, add, sub, signed and unsigned min/max, and, or, xor and cmpswap
now decode with 64-bit data and translate to new ImageAtomic*64 IR
opcodes. An image updated by them gets its own descriptor binding
range, declared as an R64ui image of 64-bit integers, and the module
uses Int64ImageEXT from SPV_EXT_shader_image_int64. The driver enables
shaderImageInt64Atomics when the device offers it and binds an
R64_UINT view of the 32_32 UINT, SINT or FLOAT surface. Without the
feature, recompiling such a shader throws.
64-bit inc, dec and the float atomics still throw, as does any other
access in the same shader to an image it updates with 64-bit atomics.
The new agc_driver_image_atomics64 test runs every operation on 32_32
UINT, SINT and FLOAT surfaces and checks the returned and stored values
against edge cases across the dword boundary.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The resource tracker refused a program's 33rd distinct V# with "buffer
resource limit exceeded". The 32 was a recompiler constant, not a
Vulkan limit: every buffer is one constant-indexed element of the guest
buffers binding, which ShaderResources checks against the device's
storage-buffer limits.
Drop ShaderInfo::MaxBuffers and the tracker's refusal, and size the
SPIR-V emitter's per-buffer offset list from the binding layout. When
the user data and offsets do not fit in the push constants, they all go
to the shader data buffer as before. ShaderResources counted only
storage buffers against maxPerStageResources (200 on Intel UHD) and now
adds the stage's sampled and storage images.
agc_driver_many_buffers reads and writes 52 and 124 buffers, and
agc_driver_graphics rejects buffers plus an image above the limit.
An S# with FILTER_MODE (word0 bits 29-30) set threw in
DecodeSamplerResource. Modes 1 and 2 now map to Vulkan's MIN and MAX
sampler reduction through VK_EXT_sampler_filter_minmax, which the device
enables when it reports both filterMinmax properties; mode 3 throws.
Min/max still throws with anisotropy, a linear mip filter (lavapipe and
NVIDIA disagree there), depth comparison, color-texture compare
emulation, and, in PointFilteredSamplerWord (S# words 0 and 2), when it
filters between texels or mips of an image the recompiler point-samples.
A texture sampled through a linear min/max sampler needs
SAMPLED_IMAGE_FILTER_MINMAX on its view format; the image-sampler pairs
travel in DescriptorBinding::imageSamplers (shader disk cache format 5).
Adds the agc_driver_image_sample_reduction GPU test and extends the
sampler, emulated color compare and disk cache tests.
RADV (Mesa 26.0 and later) initialises a FREE_DESCRIPTOR_SET pool's
allocator with bo_size + RADV_POOL_HEAP_OFFSET as its size, so a set can
be placed up to 32 bytes past the pool's buffer. The chain pools are
0x26000 bytes, a page multiple, so a set at the end of a full pool has
its last descriptors on an unmapped page: the CPU descriptor write
faults, or the shader's scalar load raises a GPU page fault and the ring
is reset.
Two more storage buffer descriptors make the pool 0x26020 bytes; the
buffer's last page then holds those 32 bytes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CB_COLOR_INFO format 1 with number type 6 (8_SRGB) threw at decode.
It now decodes as R8_SRGB with component swap 0; the other swaps and
8_8_SRGB still throw.
A device that cannot attach and blend R8_SRGB (NVIDIA, lavapipe)
renders a resident 8_SRGB target through an RGBA8_SRGB view of an
RGBA8 copy of its R8 image: the image is blitted in before the pass
and back when the pass ends, and the write mask keeps R only, so the
encode, decode and blend are the device's sRGB attachment rules.
APS5_SRGB_ATTACHMENT_PROXY=1 forces the copy. Linear, mipmapped and
3D 8_SRGB targets throw on such a device.
PPSA26344 renders its G-buffer slot 5 and a multiply-blend pass into
8_SRGB targets.
LEGO Horizon Adventures imports 19 functions that no library exports
and no open pull request adds, so it fails eager binding. They are
declared as throwing stubs. The two libSceAjmWVorbis imports have no
known name and are exported by NID from libSceAjm.native.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>