libSceAgcDriver.prx failed to load in the patched library check with an undefined symbol for HostCpuModel, because the host report called libkernel's plain C++ functions, which the patched libkernel does not export to it. The report now calls the extern C helpers and splits the joined feature list back into names.
The presentation drew the system keyboard from SystemOverlayView and laid it out
inside its own recording. It now asks SystemOverlayLayout for the system panel
at the swapchain extent, which is already validated by then, and records
whichever of the keyboard and the dialog is set through the same overlay pass
and layout transitions. Presentations with neither set are unchanged.
LayOutDialog turns a ModalDialogView into the same rectangle list the system
keyboard uses: a centred panel, the message word-wrapped to 36 columns and at
most 8 lines (the last one ends in dots when the text is longer), and one to
three buttons in a row with an accent border on the focused one. The scale
follows the keyboard's rule and shrinks until the panel fits the target.
AgcDriverSetSystemDialog stores the view for the presenter, and
SystemOverlayLayout returns the keyboard's layout when a keyboard is set and the
dialog's otherwise, so only one system panel is drawn at a time.
On NVIDIA's proprietary driver, function arrays that live in local memory
and are read under a data-dependent branch return wrong values in
subgroups 1-3 of a mesh workgroup; subgroup 0 is correct. A wave64
geometry program whose relative addressing keeps its VGPRs in the vector
window therefore loses register writes in every wave but the first. In
the clipping geometry program of Sony's PS5 PSP emulator (PPSA07550) the
empty waves never cleared their candidate primitive slots and wrote
degenerate triangles over wave 0's, so the 3D menu drew spikes.
On that driver a mesh program's window now lives in a device-local
storage buffer of 256 workgroup slots of 65536 dwords, claimed through a
per-slot lock and released after the final barrier. The pool is created
before the first draw that uses it records anything, and its header is
zeroed in a batch of its own that is submitted and waited for; the pool
is published only after that wait, and a failure releases it. Direct
register accesses keep one function variable per register; a direct
store also writes the buffer when a buffer read can see it, relative
reads load the buffer, relative writes store only to it, and a direct
read that may follow a relative write loads the buffer and refreshes the
variable. A buffer entry is zeroed only when a buffer read can see it
before a write. APS5_NO_MESH_WINDOW_BUFFER=1 keeps the arrays.
In DrawPipeline::report, reads was appended to drainText in addition to being passed as parameter 10 to %s right before `; drains:%s`, causing the read range counters to print twice per profile report.
Remove the redundant drainText += reads; append.
Fixes#10756.
The barycentric tessellation path refused any draw with the primitive
restart bit set. A non-indexed strip ignores the bit, and on a device
without VK_EXT_primitive_topology_list_restart a list never restarts on
the host, since its indices are compacted on the CPU first, so both now
take the patches. Indexed strips with primitive restart still throw,
now also in Graphics::Draw, which knows the draw is indexed.
Patch-list pipelines never enable primitive restart, which Vulkan does not
allow for them without primitiveTopologyPatchListRestart.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
With the variable at 1, the first presenting device prints the report
(system, SDL, GPU and driver, Vulkan requirements, shader cache, APS5_,
ANYPS5_, VK_ and SDL_ switches) to stderr after the device is chosen, and
before a missing-requirement error so a failing start still has it. An
invalid value stops the start with an error that names the variable.
Unset, empty or 0 prints nothing and does no extra work beyond the GPU
query of the previous commit; compile-only devices never print.
Right after the device is chosen, the driver queries the facts of the
host report and, when a required extension or feature is missing, throws
the message of DescribeMissingRequirements: the GPU, its driver, every
missing item and what to try. The device-creation code keeps its own
checks, so nothing that passed before changes; only a device that was
already going to fail now fails earlier with a message that names it. The
query itself reads no more than the properties the driver reads anyway,
and a failure to query is ignored so it cannot add a new way to stop.
CollectHostGpuFacts takes a vkGetInstanceProcAddr and handles instead of
a VulkanDevice, so a test can answer the queries with a fake. It reads the
name, type, vendor and device ids, Vulkan version, driver name, info and
raw version (VK_KHR_driver_properties when offered), the largest
device-local heap, and the surface's present modes. The required list is
the extensions and features the device code refuses to start without:
VK_KHR_swapchain with a window, VK_KHR_8bit_storage,
VK_KHR_buffer_device_address, VK_KHR_shader_float_controls,
storageBuffer8BitAccess, bufferDeviceAddress, shaderInt64,
shaderSignedZeroInfNanPreserveFloat32, vertexPipelineStoresAndAtomics,
fragmentStoresAndAtomics, samplerAnisotropy and textureCompressionBC. A
list of optional extensions the driver code uses when present is
reported next to them as optional.
SystemHostSources fills HostSources from the OS (uname with the machine
type, or RtlGetVersion), the CPU brand string and CPU gate from
libkernel's HostCpu, the hardware thread count, physical memory, both SDL
versions, the shader cache directory (state and size, counted over at most
200000 entries without following links) and the process environment. The
names to redact come from USER or LOGNAME, the host name and the home
directory (USERNAME, COMPUTERNAME and USERPROFILE on Windows). Windows
and macOS branches are written from the existing PerformanceTrace and
HostCpu code and were not run here.
A fact whose source failed prints "unavailable" in its own line; the new
[unavailable] section, sorted and redacted like every other value, says
which source failed and why, so the report shows what is missing and
that the reader did not simply forget it. The section is absent when
every source worked, so the golden report is unchanged.
HostSources holds one callable per fact (OS, CPU model and threads,
memory, CPU gate, both SDL versions, shader cache, environment entries and
the names to redact). CollectHostFacts calls each one, keeps the values it
gets, and records the name and message of a source that throws or is
missing instead of stopping, so one failing query does not hide the rest.
FilterHostEnvironment keeps APS5_, ANYPS5_, VK_ and SDL_ entries sorted by
name, and HostRedactionNames turns the account name, the host name and
the home directory's last component into the list the formatter redacts.
Nothing here reads the machine; the real sources come in a later commit.
Today a driver that lacks a required extension or feature stops the game
with one line such as "Vulkan presentation: VK_KHR_8bit_storage is
unavailable": no GPU, no driver, only the first of the missing items, and
nothing to try. DescribeMissingRequirements names the GPU with its driver
and Vulkan version, lists every required item the GPU lacks, points to
the other Vulkan devices that ANYPS5_GPU can select and to
ANYPS5_HOST_REPORT=1 for the report to attach. It returns an empty string
when nothing required is missing.
Unset, empty or 0 leaves the report off and 1 turns it on. Any other
value throws an error that names ANYPS5_HOST_REPORT and the value, like
ANYPS5_OVERLAY, so a typo does not silently print nothing.
HostFacts::redactions carries the names that identify the machine (the
account name, the host name). The formatter replaces every occurrence
that is a whole word, so "al" does not damage "radeon" and "alice" is
not left inside "alice-pc".
Every string the formatter prints goes through RedactHostText first. A
word that starts with / or ~, contains a backslash or starts with a drive
letter and separator prints as <path>, a word with :// prints as <url>,
a MAC address prints as <redacted>, and control characters (newlines
included) become spaces so a value cannot add a line of its own. Names
such as LAHF/SAHF are not paths and are kept.
Nothing prints host facts in one place today: the CPU gate, the selected
GPU and the heaps are separate start-up lines, and the driver name and
version are only written into a performance trace summary.
HostFacts holds what an issue needs (OS, CPU, threads, memory, CPU gate,
SDL versions, the GPU with its driver and Vulkan requirements, present
modes, shader cache state, APS5/ANYPS5 switches). Every optional fact can
be absent and then prints as "unavailable". FormatHostReport turns it into
text with fixed sections and sorted entries, so two runs on one machine
give identical bytes. It reads no driver and no environment.
cacheDrawStages never admitted a draw an indirect packet runs on the CPU
path, so a title whose draws are mostly DRAW_INDEX_INDIRECT packets with
a patched user word the vertex program reads as a value missed the draw
cache on nearly every lookup whatever its size. On Demon's Souls 97 % of
the draw packets are such draws and the hit rate stayed at 9 % with
APS5_DRAW_CACHE_ENTRIES=32768.
APS5_DRAW_CACHE_INDIRECT admits them. A hit reuses the fragment stage
and skips the first vertex pass; the stage whose user word the record
patches is still re-materialized per record, as the hit path already
provided for.
Tested: agc_driver_draw_cache_reuse_indirect (three DRAW_INDIRECT draws
patching an unfolded user word: one insert and one hit with the knob,
none without), the other draw_cache_reuse, key_miss, register_key and
draw_cache_relocation tests on lavapipe and an RTX 5070 Ti.
Late-added ranges and write-watched blocks are read through the same
host-only-aware read as the snapshot, so a CPU store over a guarded
multisample target no longer aborts a capture. The read is a helper
tested for ranges in the middle, at either edge, overlapping and
outside a block, and against a native target and its neighbor.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A capture snapshot read every committed block through the coherent path,
which refuses memory under a multisampled color target, its FMASK or
native multisample depth whose samples exist only on the host, so the
capture stopped there. The snapshot now writes those bytes as zeros,
counts them as host_only_sample_bytes in capture.json and adds a
warning, and the replay starts those targets without their earlier
contents.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A comma-separated list of hex program addresses (optional 0x prefix) now
writes only those programs' requests, so one expensive shader can be
captured without serializing every request a title prepares. Any other
value, such as 1, keeps writing every request. A filtered-out program
returns no name, so diagnostics never point at a file that was not
written, and it stays eligible for a later list.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The GFX10 clear state sets SPI_PS_IN_CONTROL to 0x2 (amdgpu
clearstate_gfx10.h). radeonsi relies on it: si_set_tracked_regs_to_clear_state
records 0x2 after a CLEAR_STATE, so the register is not written for a pixel
shader with two interpolants. The driver cleared it to 0, and such a pixel
shader was recompiled with no inputs.
CLEAR_STATE and the push-clear CONTEXT_STATE now leave NUM_INTERP 2. The
starting context keeps 0, since registration-time decoding reads it and
prepares pixel programs only when NUM_INTERP is 0.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PS4 color and depth targets, PS4 graphics EOP events, and the PS4 tile
modes (1D/2D thin and display, depth with tile split, PRT, linear
general) on the AGC executor, with a GPU detiler for every mode.
Textures sampled over the padded corner of a render target are GPU block
copies, and the PS4 SDK pattern-fill compute kernel runs as a GPU fill
when it repeats one dword, so render targets and HTILE are cleared
without a CPU drain. Two-dword patterns keep running the kernel: as
fills, Limbo's clears of its 64-bit target made its gameplay advance
about half as far per frame.
Tests cover the tiling equations against addrlib formulas, the GPU
detiler for every mode and element size, and the fill ranges.