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>
The device constructor printed "Vulkan features tessellationAvailable"
before it read VkPhysicalDeviceFeatures and set tessellationShader, so
the line reported 0 on every GPU, including ones that enable the
feature. The rect-list and tessellation paths already read the enabled
value; only the diagnostic was wrong, and it suggested that
tessellation was unavailable.
Print the line right after the feature is enabled. The mesh, depth
clip and unrestricted depth range values it also reports are set
earlier and do not change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceVideoOutRegisterBuffers2 and sceVideoOutSubmitChangeBufferAttribute2
threw for every buffer attribute option other than 0. PPSA26344 builds
its display buffers with option 8 through the libSceAgc helper linked
into it, so its first registration failed.
Option 8, VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY (name
and value from KytyPS5), is now accepted and presented as option 0;
every other option still throws. What the console changes for it is
unknown and recorded in TechnicalDebt. The rejection now names the
tiling mode, pitch, aspect ratio and option it was given.
video_out_flip_tests decode checks that option 8 describes the same
buffer as option 0 and that options 1, 32 and 40 are rejected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PE writer marked relocatable executables HIGH_ENTROPY_VA. Windows
then places the main thread stack, TEB, PEB and the loader threads'
stacks, which exist before libc reserves the guest arena from
0x2_0000_0000, anywhere in the first TiB. Nearly half the time they
land inside the arena and stay there as holes that fixed guest
mappings cannot use.
DllCharacteristics is now 0x140 (DYNAMIC_BASE, NX_COMPAT). The image
is still relocated and bottom-up allocations keep the 8-bit
randomization, but they start near the bottom of the address space,
far below the arena. DLL placement does not depend on this flag.
windows_address_space checks the flags and, on Windows, runs a
relinked guest that returns the high dword of its stack pointer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scePsmlMfsrGetContextBufferRequirement1100, scePsmlMfsrCreateContext1100
and scePsmlMfsrGetDispatchMfsrPacket1100 were not exported, so a title
importing them failed to load.
In Sony's libScePsml all three return 0x8A810001 (not initialized)
without writing their outputs until scePsmlMfsrInit has succeeded.
AnyPS5's scePsmlMfsrInit throws, so that is the only state a title can
reach, and the three calls now return that error.
The existing stubs for scePsmlMfsrInit, scePsmlMfsrReleaseContext and
scePsmlMfsrGetDispatchMfsrPacketSizeInDwords get their real names and
still throw. libScePsml_debug gets a CMakeLists.txt for the new
guest_psml test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A title's own libc.prx implements __cxa_thread_atexit and the
destructor pass of exit() through _sceLibcInternalThreadAtexit and
_sceLibcInternalThreadDtors. Its __cxa_finalize calls
_sceLibcInternalForceTlsDestructor.
Destructors are kept per thread and run newest first, including those
registered while they run, as FreeBSD's __cxa_thread_call_dtors does.
A null destructor or one outside every loaded image throws instead of
being skipped. The first registration installs the pass as the
libkernel thread exit hook, so it runs on every guest thread before
the thread can be joined. _sceLibcInternalForceTlsDestructor throws.
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>
PPSA26344 imports libSceAgc NID dbOlWdppb4o, whose name is unknown,
and calls it with the (regs, gs, ps) arguments of
sceAgcCreateInterpolantMapping to fill the 32 SPI_PS_INPUT_CNTL
registers. It is exported as sceAgcUnknownCreateInterpolantMapping.
It differs from sceAgcCreateInterpolantMapping only for inputs that
carry the high f16 half alone (is_f16 2): these take the default bit
and DEFAULT_VAL from the high half, as KytyPS5 does.
Both exports share validation and the register loop. More than 32
pixel shader inputs now throw; before, they were written past the
32-register block. agc_interpolant_mapping covers both exports.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The resource materializer refused every atomic image descriptor whose
format was not 32_UINT. RDNA2 image atomics act on the raw dword and
the numeric format only affects addressing, so 32_SINT and 32_FLOAT
surfaces are now accepted with the Uint numeric class and run through
the existing integer atomics and float compare-exchange loops. Other
formats still throw, and the message now names the format.
DescriptorBinding gains imageAtomic, carried through the shader disk
cache (format version 4) and the resource content key. The driver
binds those elements through a cached R32_UINT view of R32_SINT and
R32_SFLOAT storage images.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceAgcGetIsTrinityMode takes a pointer to a one-byte flag; the only
known caller ignores the return value. The export took no argument and
never wrote the flag. That caller's flag is in zero-initialised .bss,
so this corrects the signature; it does not fix a visible failure.
The function now stores false, as sceKernelIsTrinityMode reports a base
PS5, returns 0 and throws on a null pointer, whose error code is
unknown. It moves from Unimplemented.cpp to Misc/src/Platform.cpp, and
the new agc_platform_tests ctest target covers it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EmitDppTargetLane threw "DPP control 336 is not supported" for the
DPP16 row_share controls 0x150-0x15f. row_share:sel now reads lane
sel of the reading lane's own row, (lane & ~15) | sel, as the RDNA2
ISA defines it. The source never leaves the row, so the target is
always valid and an inactive source follows the existing fi and
bound_ctrl rule, as for row_xmask.
The new agc_driver_dpp16_row_share_xmask execution test covers
v_mov_b32, v_add_nc_u32, v_sub_nc_u32 and v_max_f32 with row_share
and row_xmask under a partial exec mask, with fi, bound_ctrl and
row/bank masks, as wave32 and wave64; row_xmask had no test before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DecodeState and the draw precheck rejected PA_CL_CLIP_CNTL bit 24
(DX_LINEAR_ATTR_CLIP_ENA), so every draw that sets it was skipped.
Vulkan requires clipped NoPerspective outputs to vary linearly in
framebuffer space, and RADV and radeonsi set this bit for every draw
they emit. With the bit set the console therefore clips the way the
host driver already does, and the pipeline needs no extra state.
Clip space, depth clamping and the viewport depth range decode as
with the bit clear. Every other unsupported bit still rejects the
draw, with or without bit 24.
TechnicalDebt records that a clear bit, which was already accepted,
gets the same clipping.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>