Vulkan for the PlayStation 5: Mesa's RADV on a PS5 winsys, on its way to a conformant Vulkan 1.4 device; ps5vk, the first driver; and the hardware probe behind both.
This repository builds Vulkan drivers for the PS5's GPU, together with the probe
harness that proves, one capability at a time on real hardware, what that GPU
actually does. The driver going forward is RADV, Mesa's Vulkan driver for AMD
GPUs, built from my Mesa fork with a PS5 winsys that allocates, submits and
presents through the console's exported AGC, kernel and VideoOut functions
(The RADV port). ps5vk, the first driver, is a Mesa-derived
Vulkan 1.1 implementation that programs AGC and VideoOut itself. vkQuake and
PS5 RetroArch have moved to RADV, and ProsperoEden's Vulkan renderer runs on it;
ps5vk stays vkQuake's and RetroArch's PS5_VULKAN_DRIVER=ps5vk build option. It is a
companion to the PS5 OpenGL SDK
(release 0.3.0, adapted into .deps/native/opengl-sdk by
tools/adapt-opengl-sdk.sh) and is developed with
the public ps5-payload-dev/sdk
toolchain.
RADV reports Vulkan 1.4 and runs the Khronos CTS on the console; its
conformanceVersionstays 0.0.0.0 until the pinned 1.4 CTS passes in full there, and every case it does not pass yet, and every "not supported" the port itself causes, is listed with its owner in docs/CTS_GAPS.md. ps5vk reports Vulkan 1.1, documented by command, limit and format audits and targeted console probes rather than by the CTS.
Contents: The RADV port · Progress and roadmap · vkQuake and performance · What this is · How it works · Findings · Getting started · Gates · Credits · License
Route B of docs/VULKAN_1_4_PLAN.md: RADV stays whole,
and only what the console does differently from Linux is new. The changes live in
my Mesa fork (PS5_Mesa, checked out
as ../PS5_Mesa, branch main: Mesa 26.2.0 with -Dradv-winsys=ps5), pinned
here by revision in
tools/build-radv.sh; gaps in the console's platform
(kernel declarations, libc, direct memory) go into the payload SDK fork's shared
platform layer, not into the Mesa fork. docs/RADV_PHASE.md
is the round-by-round record.
application (vkQuake, RetroArch, the CTS, the smoke test)
|
RADV + ACO + NIR ............ Mesa 26.2.0, unchanged but where the console
| differs (a GC 10.1.3 fixed-function block
| beside GFX10.3 shaders, below)
PS5 winsys .................. memory from direct memory, command streams
| copied into the ring as sceAgcDriverSubmitDcb
| submissions, each ending with a write of its
| sequence number, which the CPU waits for
VK_KHR_display on VideoOut .. the swapchain: buffers registered with
| VideoOut, flipped at vblank, 120 Hz where the
| title declares it and the display takes it
PS5 GPU
What stands on the console (2026-10-01, PS5 Mesa 504adad):
- The full CTS runs on the console, and its second full run had no
failure. The first full run of the pinned 1.4 CTS (vulkan-cts-1.4.6.2, my
fork
../PS5_VK-GL-CTS, title PPSA99015), main-1, ended on 2026-09-27 with 2,786,062 cases: 1,098,388 pass, 12,005 did not pass and 1,675,626 were not supported. Every case it did not pass was then fixed or traced, and the port gained compute and transfer queue families (on the graphics ring), host-cached memory types, tessellation and geometry shaders run as compute where the fixed-function block cannot, ray queries and pipelines, sparse resources, calibrated timestamps and the VideoOut swapchain, each proved by a targeted CTS run of the groups behind it (docs/CTS_GAPS.md). The second full run, full-1, on RADV6824f49, finished on 2026-09-29: of 2,919,757 cases, 1,569,390 pass, 0 fail, 1,350,306 are not supported and 60 are quality warnings (one more case is recorded as a crash because I closed the CTS title mid-batch). Before any further full run, those 61 cases get a targeted rerun, and each feature reported as not supported is either implemented for real or confirmed as absent from the hardware or the platform. - vkQuake ships on RADV. Since 2026-09-28 the vkQuake title builds against
the release archive by default and runs its demo loop at 119.88 fps, one
vblank a frame, in the display's 120 Hz mode (PS5_vkQuake
evidence/radv-r2-main). Since the same day RADV keeps its compiled pipelines in an on-disk cache in the title's folder, and since its exclusive mode (below) the first present comes 3.77 s after start from an empty cache and 2.44 s with it filled, of which the pipelines take 0.01 s. The rest, device and swapchain start-up against ps5vk's 0.55–0.77 s to a first frame, is still open. - RetroArch ships on RADV. PS5 RetroArch
moved to RADV with v0.5.0-alpha.5 (2026-09-28). Its current release,
v0.5.6-alpha.5 (2026-10-01), links PS5 Mesa
504adadand carries 15 cores. Six of them render through Vulkan on RADV: PPSSPP, Dolphin, LRPS2, Beetle PSX HW, Mupen64Plus-Next (ParaLLEl-RDP) and Azahar, at up to 18× internal resolution. Before the release, every core ran its game on the release build (Beetle Saturn up to its BIOS check): boot, the menu, Close Content and a reload, at full speed before and after, with no crash. PPSSPP needed a fix of its own: it used Vulkan 1.2 commands on a 1.1 instance. - ProsperoEden's Vulkan renderer runs on RADV. In my experimental fork of ProsperoEden, the PS5 port of the Eden emulator, which I use to benchmark this driver, the tested game (docked) holds 60 fps at 4K with the GPU about 19% busy, and mostly holds 60 at 8K with the GPU about 55% busy.
- Fifteen Vulkan samples run on RADV, as a test suite.
PS5 Vulkan Samples (PPSA99130),
built by PS5_VulkanTemplate (my fork of Sascha Willems' Vulkan examples, and the
foundation new titles are made on), links fifteen of them into one title:
glTF loading, mipmaps made with blits, PBR with image based lighting, shadow
mapping, deferred shading, bloom, MSAA, instancing, indirect draws, compute
particles, bindless textures, dynamic rendering, ImGui, mesh shaders and ray
queries. On 2026-10-01, on PS5 Mesa
504adad, each held 119.9 fps at 3840x2160 over a 300-frame test run, and its last frame matched the same frame drawn by the PC's driver (Intel ANV) within 4.5 levels in 255. A test run of every sample belongs beside the CTS after a RADV change. Its first run found a platform gap, not a driver bug: the console'slocaleconv()gives an empty decimal point, and tinygltf's JSON parser read material colours of 0.62 as 0. The payload SDK fork's platform layer now has a C-localelocaleconv(6b63a2a), whichtools/radv-link.shbinds for a title whose SDK pin has it. - Submissions cost the submitting thread less. The suspend point that makes the console start a submission on time used to hold the submitting thread about 0.3 ms a submission, which cost a renderer making 2,000 submissions in 10 s (RPCS3's, in my console builds of PS5 RetroArch) 0.5 to 0.7 s of every 10 s. A kick thread of the winsys now makes it, and the CPU flush of each submission uses CLFLUSHOPT instead of a serialising CLFLUSH for every line.
- Threaded command recording, off by default. With
RADV_THREADED_RECORDING=1, a worker thread records what the application'svkCmd*calls queue. Its CTS gate, threaded-1 (474,440 cases of the command-recording groups), gives every case the same status as without the layer, after two faults it found were fixed in the fork (docs/RADV_PHASE.md). It stays off until it measures faster in a game. - Mesh and task shaders are reported since 2026-09-28, though the GPU has neither per-primitive parameters nor the CP's task and mesh dispatch packets: mesh workgroups go out in parts that share one run's outputs, and task shaders run on the graphics ring in chunks (docs/RADV_PHASE.md).
- The shader cache is Mesa's cache database (
MESA_DISK_CACHE_DATABASE) in the title'sradv-shader-cache/folder, keyed by the pinned Mesa revision and open to the console's FTP service. On the console it runs in an exclusive mode, where each part stays open for the process instead of being reopened and locked on every read (docs/RADV_PHASE.md). Shader compiles on several threads no longer wait on one heap lock: the payload SDK fork's platform heap gives each thread an arena of its own. - Not there yet: conformance itself (
conformanceVersionstays 0.0.0.0, see above); concurrency between queues, since the compute and transfer families are served from the graphics ring and real asynchronous compute is in the backlog; and Dolphin's first start of a game with an empty shader cache, which compiles its ubershaders and loses 17% and 8% of its first two 10 s windows on RADV (ps5vk: 14% and 1%).
Building it:
tools/setup-native-dependencies.sh # the payload SDK fork at its pin
tools/build-radv.sh # .deps/native/radv: assertions on, for the smoke test and CTS
tools/build-radv.sh release # .deps/native/radv-release: what titles ship
tools/build-radv-title.sh # the smoke test title, PPSA99014
tools/build-cts-title.sh # the CTS title, PPSA99015 (tools/run-cts.py runs it)Titles link the archive with tools/radv-link.sh;
RADV_ARCHIVE names another one, such as the fork's own build while a change
to it is being worked on. Mesa's assertions and NIR validation make shader
compiles 5 to 6 times slower (docs/HARDWARE_FINDINGS.md), which is why titles
link the release build.
The rest of this README is mostly ps5vk's story: the probes, the findings both drivers rely on, and the vkQuake and RetroArch work done on it.
- ✅ The GPU can be programmed at all. The linked AGC canary loads, links shaders compiled from this repository's GLSL, and draws an exact 4K frame (M1–M2).
- ✅ Resources reach the shader. Uniform buffers, vertex and index buffers, sampled textures, arrays, cubemaps and texel uploads are all read back from a console frame (M3, D1).
- ✅ Fixed-function state is understood. Clears (colour and depth), the depth test and write, additive and constant-factor blending, render-to-texture, 4x MSAA and its resolve (M4, C8).
- ✅ SPIR-V compiles on the console. The AGC shader package built on the console is byte-identical to the package built on the PC (M5 A).
- ✅ A Vulkan 1.0 driver runs the tutorial ladder — command buffers, render passes, pipelines, descriptors, fences, semaphores, swapchain and display, one driver step per Vulkan Tutorial chapter (M5 B, M5 C).
- ✅ A real application works. RetroArch runs through the driver; a fragment input location defect found through it is fixed and confirmed on screen, with a 30-second watch recording zero refusals (evidence, findings).
- ✅ vkQuake runs at up to 120 FPS at 4K — on ps5vk, and since 2026-09-28 on RADV, which it now ships with (The RADV port). On ps5vk, walking the start map, every frame takes 8.29–8.40 ms (119.88 FPS) on a 4K120 VRR display with kstuff paused; 4K readbacks verify textured worlds, warps, particles, menu alpha and the HUD. Systematic gameplay acceptance continues. See vkQuake and performance.
- ✅ Input attachments read the complete frame correctly. R20 corrected the probe's tiled-memory reader; the earlier quarter-width diagnosis was a probe error, not a remaining descriptor-width defect (R20 proof).
- ✅ A shader the compiler cannot lower is refused, not fatal. The console's
own failure was a title gone minutes into start-up: the fork's SPIR-V front end
or its ACO printed one line and raised. The driver now reads a module's
addressing model and declared capabilities before the compiler runs and refuses
the ones it has no path for by name, and a
SIGABRT/SIGTRAPguard behind that turns any other raise into aVkResult— proven bydriver/tests/vk_v0_capability_test.con the host and by the round's console run, which shows the sentence where a title used to die (both recorded indocs/M5_PHASE_C.md). - ✅ Push constants and specialization constants reach a shader. Both are core
Vulkan 1.0 and both arrived through the compiler fork rather than around it. A
push-constant block is uploaded per draw, and the two halves of the target hold
the two values (
v0-push-constant); one module built with different specialization values draws the colour each set selects, read back word for word, with a hand-written literal twin as the compiler's own control (thev0-r9case). - ✅ The advertised set is audited, command by command. All 137 required Vulkan 1.0 commands are accounted for: 90 in the driver, 47 in Mesa's runtime, 0 refused, 0 gap, and six extensions are exposed, each after a console proof.
- ✅ The format audit has no gaps. All 179 formats in Vulkan 1.0's mandatory
tables are answered: 58 reported, 0 missing a required feature, 55 with
conditional requirements only, and
python3 tools/format_audit.py --checkexits 0. Getting there meant proving every descriptor type the rows needed (uniform texel buffers, storage texel buffers, storage images and their atomics -- 74 features across 38 rows), every vertex layout they name (29 rows, 8-bit and 16-bit components and the byte-reversed 8888 forms), the stencil path (D24_UNORM_S8_UINT,D32_SFLOAT_S8_UINT), and both byte-reversed sRGB formats (docs/V0_FORMATS_AUDIT.md,docs/BLOCKERS.md). - ✅ The console's SIGFPE was the runner's own divisor, and it is fixed. The
fault (
jobs/aco-min/queue.txt) was a division by zero in the sampled-format loop: a table declared ten rows and initialized seven, so the eighth row's texel size was zero. The addresses that had been read as ACO frames were consolerips left unrebased by the eboot's0x400000load address, which the crash report's ownxotext:line gives. The tables now declare their rows,static_asserts make a declared-but-unfilled row a build error, and the console run isjobs/aco-minpid 287: seven of seven tests, each uint case "7 of 7", nosignal:record (docs/HARDWARE_FINDINGS.md). - ✅ Offline oracles exist. The console's tile maps are derived from AMD's
own AddrLib in the console's exact configuration and checked against the
console's measured rows (
measured match), so a new map is computed rather than guessed (tools/mip-layout-oracle.cpp). - ✅ The loop is reproducible. A console run is captured from klog, reduced
to golden command streams, and replayed on the PC against the same driver code
(
tools/golden.py).
- ❌ No conformance yet. The console CTS runs on RADV, and its second full run (full-1) ended with no failure; the targeted rerun of its 61 quality warnings and the review of every not-supported feature come before the next one (docs/CTS_GAPS.md). ps5vk's host results are in docs/CTS.md.
- ❌ Rungs 1.1 → 1.4 on ps5vk. Superseded: the Vulkan 1.4 device is RADV (The RADV port).
- ✅ The SDK fork's compiler is migrated. The driver links ps5-opengl
0.3.0's own
opengnm-psbctree (metadata version 14, this repository's patches re-applied on top), assembled and verified against the release's ownpatched_treebytools/check-sdk-fork-migration.sh(docs/M5_PHASE_C.md). - ❌ Transfer coverage is not universal. Padded pitches, tiled mip chains, filtered mip generation and the copy/readback cases needed by vkQuake now have console proofs. Unproven format, aspect and multisample combinations still require their own cases; supported paths are bounded by the measured layouts. See R29 regression coverage.
- ❌ Line-list rendering does not draw right. The topology is linked,
compiled and programmed (DI_PT_LINELIST, the line's own registers), yet the
console case's segments do not match the rectangles they must cover: a core
1.0 topology is not yet correct on hardware, which is a defect in the drawing
rather than in what the device reports (the
v0-linescase). - ❌ Buffer device address is not advertised. Shaders that need it —
physical storage buffer addresses,
buffer_reference, and the bindless image store that comes with them — are refused by name rather than compiled into a fault. The vkQuake port uses compatible paths instead of requiring these kernels to compile. - ✅ A hardware-rendered emulator works. PPSSPP, as a RetroArch core, runs
the tested games at 10× internal resolution (4800×2720) with 16× anisotropy,
at full speed on a 120 Hz display.
What it needed is general driver work, not PPSSPP cases: every draw restates
the context registers that persist between draws (target mask, blend, colour
control, clip and rasteriser mode); a device-local memory type beside the
host-visible one; a three-image FIFO swapchain whose present does not wait for
the flip; GPU blits and copies through Mesa's
vk_metawith push descriptors; component mapping composed onto the view's swizzle; and CPU image copies that evict and fence once per copy rather than per row. Loading a save state went from 21.5 s to 61 ms. - ❌ A title cannot load a graphics module at run time. Every
dlopenandsceKernelLoadStartModuleof a repository-built.sois refused by the console, so the driver is delivered linked into the title; the untried route is publishing application exports from the module writer. - ❌ Occlusion queries are coarse. One
ZPASS_DONEcount is 16 samples, soocclusionQueryPreciseis reported false. - ❌ Broad application acceptance is incomplete. RetroArch with its six Vulkan cores, vkQuake and ProsperoEden run on RADV; vkQuake still needs systematic movement/fire/save/load, all-map and long-soak acceptance. Other applications remain separate compatibility work.
| Stage | What it means | Status |
|---|---|---|
| M1–M2 | AGC loads; shaders from this repo draw a 4K frame | ✅ |
| M3 | Uniform, vertex/index and sampled-texture resources | ✅ |
| M4 | Clear, depth, blend, render-to-texture | ✅ |
| M5 A | SPIR-V → AGC package, console and PC byte-identical | ✅ |
| M5 B–C | The Vulkan driver and the tutorial ladder | ✅ |
| M5 D | Breadth: dynamic state, compute, more formats | ✅ |
| Rung 1.0 audits | Entry-point, limit and format accounting; targeted console probes | ✅ audits: commands 90/47/0/0, limits 0 missing, formats 0 missing; semantic limitations remain |
| M5 E | The SDK fork's compiler (metadata 14) migrated and re-proven | ✅ migrated and re-proven |
| — | The console SIGFPE at jobs/aco-min |
✅ fixed: the runner's sampled-format table ran a row it never filled in |
| Rung 1.1–1.4 | ps5vk: one commit a rung, each gated by a CTS subset | superseded by RADV |
| RADV | Mesa's RADV on a PS5 winsys, Vulkan 1.4, the full CTS on the console | 🔄 second full CTS run with no failure; targeted reruns before the next one; vkQuake and RetroArch ship on it, ProsperoEden runs on it |
| Phase E1 | CTS-style semantic validation against the advertised set | ❌ recipe written |
| Real applications | RetroArch ✅ (ps5vk, and RADV since v0.5.0-alpha.5; v0.5.6-alpha.5 current) · PPSSPP, Dolphin, LRPS2, Beetle PSX HW, ParaLLEl-RDP and Azahar (hardware-rendered) ✅ tested games · vkQuake at up to 120 FPS at 4K, on RADV since 2026-09-28, acceptance 🔄 · ProsperoEden (Eden) on RADV ✅ the tested game at 4K60 · other frontends ❌ | 🔄 in progress |
The native PS5 vkQuake port in the sibling ../PS5_vkQuake checkout links this
repository's RADV release archive since 2026-09-28 (ps5vk's archives with
PS5_VULKAN_DRIVER=ps5vk); its README covers installation, controls and the
console settings below. This section is the ps5vk work that got it to 120 FPS;
the exact tested ps5vk driver and what is pending are in the
active state.
The compatibility rounds cover vertex stride, dynamic UBO offsets, descriptor arrays, padded pitches and mip tails, 32-bit indices, depth state leaking into colour-only UI, sampler LOD bias and menu blend control. Swapchain readback provides complete screenshots as evidence, rather than treating a successful present call as proof of a correct image.
Measured on the console at 3840×2160 (port evidence, steady windows):
| Round | Change | Effect |
|---|---|---|
| R29 | Common tile-address evaluation | Start map 14.8 → 19.7 FPS |
| R33–R36 | A nearly free profile (TSC timestamps, one write) | Found that a system call costs ~20 µs with kstuff active, and that the profile's own write was the "unexplained" multi-second stall |
| R37 | Flush colour targets only in memory the application maps | 256–384 MiB and 3.9–5.8 ms of cache flush a frame gone; full runner battery identical to before |
| R38 | Bounded spin on the completion marker before sleeping | Poll 1.12 → 0.15 ms a step |
| R42 | Blits resampled on five threads | Water-warp mips 2.3–8.2 → 0.4–1.2 ms; walking the start map 34–47 → 52–55 FPS |
| R43 | A per-frame hitch report | Located the port's New Game stutter (fixed in the port) |
| R46, R47 | Internal NIR cache; one cache directory per build, shippable | A launch compiles nothing |
With the console's kstuff paused at game launch (an etaHEN setting), a system call costs 0.73 µs instead of ~20 µs, and the same walk runs at the display's 120 Hz ceiling: 119.88 FPS, 4.0–4.4 ms of work a frame, application 2.4 ms, queue 2.1 ms. On a VRR display a frame presents as soon as it is ready, from 48 to 120 Hz; a frame over the 48 Hz window (20.8 ms) is held to ~29.2 ms.
Entries live in /app0/ps5vk-shader-cache/<first 16 hex digits of the driver build>/, one directory per build, since keys include the build. Directories are
0777 so the console's FTP service can read entries back and write shipped ones
in; PS5VK_SHADER_CACHE_DIR, or on the console /app0/ps5vk-shader-cache-dir.txt,
names another base for tests. Since R46 the driver's internal NIR stages are
cached too, and the port ships each build's compiled set, so a launch compiles
nothing (R47).
RADV offers both of these; they are ps5vk's own gaps.
- MSAA beyond 4×, with render pass 2. PPSSPP's MSAA needs
VK_KHR_create_renderpass2and depth/stencil resolve, and 8 samples; neither is offered yet. - Multiple colour attachments are still refused (
v0-mrt), and that case stops the test runner.
It is a probe that answers "what does this console's GPU actually do" with console runs instead of assumptions, and two drivers built on those answers: RADV with a PS5 winsys, and ps5vk, a Mesa-derived frontend with the NIR/ACO shader compiler and a PS5-specific AGC and VideoOut backend.
It is not a Sony SDK, a retail-package builder, an exploit, or a conformance submission. It ships no Sony file, no key and no game content. It needs a homebrew-enabled console that you own, and it never configures that console for you. ps5vk reports 1.1 (R84; the 1.1 row of docs/M5_REFERENCE.md stays open until the console CTS runs), with coverage recorded command by command, limit by limit and format by format. The audits, targeted pixel proofs and working applications are evidence of progress, not a claim of certified conformance.
RADV's is under The RADV port.
application (vkQuake, RetroArch, Vulkan Tutorial, probe runner)
|
Vulkan 1.0 frontend ......... Mesa's common runtime (vk_* entry points) +
| this repository's driver (driver/ps5vk_*.c)
shader translation .......... SPIR-V -> NIR -> ACO -> AGC shader package
| (opengnm-psbc, built for the console)
resource + command backend .. measured tile maps, register tables,
| PM4 command streams, direct memory
AGC and VideoOut ............ the console's own GPU command and display APIs
|
PS5 GPU
Nothing Linux-specific crosses over: no amdgpu, no DRM, no ioctls. ps5vk
programs AGC directly, and the PS5-specific parts —
tile maps, descriptor words, register values, synchronization — exist in this
repository because a console run measured them.
| Mode | What it is for |
|---|---|
Console (PPSA99988) |
The proof. Every claim in this repository comes from a run here. |
PC replay (build/host/runner_host) |
Runs the runner's own code on the host against golden captures, so a regression shows up without a console. |
PC replay through the driver (build/host/runner_host_driver) |
The same runner with the Vulkan driver linked, for a case that has no console capture yet (tools/build-host-runner.sh --driver). |
| Offline oracle (AddrLib, Vulkan-Docs) | Computes expected tile maps and version requirements, so a probe is written against a specification instead of a guess. |
- A queue of probe cases is uploaded and the runner title is launched
(
tools/ps5_console.py battery). - The run writes structured records to klog; the driver dumps its register tables, shader stages and command streams.
- The capture becomes a golden file (
tools/golden.py extract) and the PC replays it, comparing every word. - The result lands in a phase log and, when it changes a rule, in
docs/HARDWARE_FINDINGS.md.
| Property | Value |
|---|---|
| Instance API version | 1.3 (Mesa's instance level; promises nothing about the device) |
| Device API version | 1.0 |
| Extensions | VK_KHR_surface, VK_KHR_display, VK_KHR_swapchain, VK_KHR_get_physical_device_properties2, VK_EXT_debug_report, VK_EXT_debug_utils |
| Queue families | 1 |
| Features | robustBufferAccess, samplerAnisotropy (16×) |
| Limits | 97 of 106 required limits compared against the specification, 0 missing |
| Formats | 179 required: 58 reported, 0 missing a required feature, 55 conditional only |
| Commands | 137 required 1.0 commands: 90 driver, 47 runtime, 0 refused, 0 gap |
Probing paid for itself: this GPU does not behave the way a PC GPU does, and
each of these rules came from a console run that contradicted a reasonable
assumption. The evidence for every one is in
docs/HARDWARE_FINDINGS.md.
- Colour render targets are tiled, not row-major: 128×128 texels a 64 KiB tile with an XOR pixel map, so CPU access must convert the layout.
- A four-sample colour target is four 0x4000-byte sample planes a tile, while a four-sample depth target keeps all four samples in one 16-byte texel — a different map for the same idea.
- Element size changes the tiling: a two-byte element has its own 256×128-texel row, derived from AddrLib rather than scaled from the four-byte one. (A two-byte image can never be an attachment, so that row has no reachable path — recorded rather than pretended.)
- Blending needs more than
CB_BLEND0_CONTROL: the pixel shader must export the format the pipeline's SPI state names, and a blending 8-bit target takes FP16_ABGR. - Indirect register tables are dereferenced by the GPU and must live in GPU-mapped direct memory; a table on the stack faults.
- A PM4
INDIRECT_BUFFERinto title memory faults the GPU, so the driver copies command buffers into one stream instead. - A submission can complete without a flip, which is what makes marker-based fences safe for readback.
- The sRGB curve belongs to the fetch, not to a format's channels: the texture
unit linearises the first three fetched components before any selector, so a
byte-reversed sRGB texel is decoded correctly only if the image holds its
channels in the order the curve reads. The driver chooses that order for
A8B8G8R8_SRGB_PACK32and swaps the bytes where an application's bytes meet the image's. - A combined depth/stencil attachment's stencil plane is its own one-byte
surface, in the depth surface's 64 KiB
Z_Xswizzle at a 64 KiB-aligned offset beside it, andDB_STENCIL_INFOcarries that swizzle with the tile-stencil bit — which is what makes aD24_UNORM_S8_UINTorD32_SFLOAT_S8_UINTattachment work. - The shader compiler of the SDK fork is RADV's front end over a different
ACO, and the difference is where a title dies: upstream's call site lowers
subpassLoadto the tile coordinate intrinsic this ACO has no case for, so the descriptor form of the same pass is what compiles here, and an application's input attachment is bound from its subpass rather than from a descriptor write (which Vulkan forbids for that type). - A stage's descriptor metadata is the caller's declaration as the compiler echoes it back, not what the shader reads: a layout binding the stage never fetches still arrives in its metadata, so the table the driver builds has to be narrowed to the bindings the module itself declares — otherwise the draw demands an application write for a descriptor no instruction uses.
- A raise inside the compiler is a dead title, because
vkCreate*Pipelineshas no result to return from inside it. TurningSIGABRT/SIGTRAPinto a refusal on the thread that compiles is what lets a title survive a shader it cannot compile, and it is the backstop behind every named capability refusal.
| Path | What lives there |
|---|---|
driver/ |
The Vulkan driver: instance, device, images and tile maps, buffers, descriptors, pipelines, draws, queue and submission, WSI, debug capture |
src/ |
The probe application: the case table, the AGC canaries, and the diagnostics that produce the structured records |
host/ |
Host-side shims for the PC replay (the AGC host model and the runner host) |
probes/, shaders/ |
GLSL sources and their compiled AGC shader packages, one set per probe canary |
jobs/ |
Job queues and results — one directory per probe battery |
golden/ |
Golden command streams extracted from console runs |
evidence/ |
Captured evidence for app-level findings |
docs/ |
The plan, the phase logs, the audit tables and the hardware findings |
tools/ |
Build, check, oracle, decode and console tooling |
tooling/ |
The PS5 linker converter, FSELF writer and runtime-shim builder |
payload/ |
ps5vkctl, the small console agent that launches and kills probe runs |
runtime/ |
The generated clean-room libc.prx used by directory titles |
vendor/ |
Link-time import stubs for the console's own libraries (AGC and the canaries' imports), so a title links without the Sony SDK |
tests/ |
Host unit and integration tests, including the queue and audit guards |
Five titles build from this tree with make and tools/build-all-titles.sh.
Four are canaries or diagnostics; one is the runner that produces the
evidence. The RADV scripts build two more:
| Title | What it is |
|---|---|
PPSA99988 |
The probe runner: the Vulkan driver, the test runner and every probe package |
PPSA99999 |
The default diagnostics app (the graphical Hello World) |
PPSA99997 |
The AGC driver canary |
PPSA99998 |
The linked canary with the complete-state canary |
PPSA99996 |
The live-submission canary |
PPSA99014 |
RADV's smoke test (tools/build-radv-title.sh) |
PPSA99015 |
The Khronos CTS on RADV (tools/build-cts-title.sh, run by tools/run-cts.py) |
Arch/CachyOS is the supported host; make doctor is the authority. The short
list:
sudo pacman -S --needed base-devel clang llvm lld make python git curl wget \
unzip tar pkgconf cmake glslang
python3 -m pip install --user mako markupsafe # Mesa's Vulkan generators
make doctorglslang compiles the probe shaders, cmake builds the pinned BC7 encoder for
presentation art, and ccache is picked up automatically when installed.
Two SDKs are involved, and neither is vendored into the tree:
# 1. The public payload SDK (headers, sysroot, prospero-clang18/lld) plus the
# host test framework: make deps fetches the pinned releases into .deps/.
make deps
# 2. The PS5 OpenGL SDK, release 0.3.0: a release bundle or a checkout.
# tools/adapt-opengl-sdk.sh reconstructs the layout the tools read under
# .deps/native/opengl-sdk -- the shader-compiler fork the driver links, its
# headers, the C package writer and the Mesa version pin -- and pins the
# compiler half so a rebuild is reproducible. PS5_OPENGL_SDK overrides the
# tree every script reads (tools/sdk-root.sh).
tools/adapt-opengl-sdk.sh ../ps5-opengl-sdk-0.3.0The adapted tree is a frozen compiler: tools/adapt-opengl-sdk.sh copies the
Mesa-fork work copy tools/build-psbc-ps5.sh last built, so moving to the
0.3.0 fork's compiler is a deliberate migration with its own re-proof cost
(§ Not yet, tools/check-sdk-fork-migration.sh) rather than a side effect of
updating the SDK.
You need a console you own with an already configured homebrew environment. The
environment this repository was validated against uses
etaHEN as the enabler,
ShadowMountPlus for directory
titles under /data/homebrew,
ftpsrv on port 2121 for
deployment, and
klogsrv on port 3232 for
capture. The repository does not configure any of it: follow those projects'
own instructions, keep the services on a trusted local network, and load this
repository's agent once per boot:
tools/build-ps5vkctl.sh # needs PS5_PAYLOAD_SDK or ~/ps5-payload-sdk
python3 tools/ps5_console.py deploy-payload # /data/homebrew + /data/etaHEN/payloads
python3 tools/ps5_console.py payload # -> ok ps5vkctl 1 pid=<n>RADV's build is under The RADV port. ps5vk, the probe shaders and the titles:
tools/fetch-mesa.sh # pinned Mesa 26.2.0, checksum-verified, into .deps/
tools/build-psbc-ps5.sh # the SPIR-V -> AGC shader compiler for the console
tools/build-vulkan-runtime.sh # Mesa runtime: host and PS5 archives
tools/build-driver.sh # the driver: host and PS5 archives
tools/build-probe-shaders.sh # GLSL -> SPIR-V -> AGC packages (needs glslang)
tools/build-all-titles.sh # all five titles, warning-free, aligned segmentstools/build-all-titles.sh is also the strictest compiler gate here: it fails on
any warning or any misaligned PT_LOAD segment. ccache makes the Mesa-derived
builds cheap, and PS5VK_DISABLE_CCACHE=1 opts out. Measured build times are in
docs/NATIVE_TOOLING.md.
# Build and deploy the runner title (these definitions are what make it the runner)
PS5_HOST=192.168.1.100 PARAM_PATH=sce_sys/param-runner.json \
APP_DEFINITIONS="AGC_LINKED_CANARY=1 AGC_TEST_RUNNER=1 AGC_OUTPUT_4K=1 AGC_LIVE_SUBMIT_ARMED=1 AGC_SHADER_COMPILER=1 AGC_VULKAN_DRIVER=1" \
make deploy
# Upload a queue, arm the capture, restart the title, and summarise the run
python3 tools/ps5_console.py battery PPSA99988 jobs/format-items/queue.txt \
--output Klog_Logs/format-items.logA queue is a small text file — capture, hold <vblanks>, the case names,
m2-solid as the canary, exit — and jobs/ holds examples, one per
battery, each with the run it belongs to in its comments. The
battery exits 0 when the run ended and passed, 3 when the run never ended,
and 2 when no run arrived. To watch a run you launch yourself, use
python3 tools/ps5_console.py klog; to decode what a run recorded, use
python3 tools/pm4_decode.py stream <log>, which turns every captured stream
into named AMD PM4 packets.
Everything below must be green before a change lands. This is the project's definition of "verified":
tools/check-driver.sh # driver: loader, host, PS5 link and negative arms
tools/check-runner-cases.sh # the runner's cases on the PC, against golden streams
tools/check-mip-layout.sh # tile maps against AddrLib, the oracle
tools/check-probe-packages.sh # every committed probe package rebuilds to itself
tools/check-psbc-link.sh # the shader-compiler link, the SDK tree it comes from
tools/check-vulkan-runtime.sh # the runtime link
make test # host unit and integration tests, including the audits
make lint # format, static analysis, attribution, shell, assets
tools/build-all-titles.sh # every title, no warning, aligned segments
python3 tools/command_audit.py --check # 137 required commands, 0 gap
python3 tools/format_audit.py --check # 179 required formats, 0 missing (exit 0)
python3 tools/limits_audit.py --check # 106 required limits, 0 missingTwo reports are deliberately not gates, because their answer is "work remains":
tools/check-sdk-fork-migration.sh (the compiler migration's work list) and
python3 tools/format_audit.py without --check (the conditional rows).
The application half of this repository is a small, self-contained native app foundation, and the same commands apply to the probe titles:
make init TITLE_ID=PPSA12345 APP_NAME="My App"coordinates identity insce_sys/param.json; the checked-inPPSA99999is a development identity, so keep it local.makebuildsdist/<TITLE_ID>/;make ffpkgandmake ffpfscadd the optional UFS2 and compressed images;make deploy PS5_HOST=...updates a running console over FTP, uploading each file under a temporary name and publishingeboot.binlast.make inspect INSPECT_FILE=dist/<TITLE_ID>/eboot.binstatically validates the ELF or FSELF, andmake undeploy PS5_HOST=...removes only this title's staged files.- Releases are tagged with the exact
contentVersionfromparam.json(NN.NNN.NNN), andmake cireproduces the GitHub Actions job on your host first.
Details: configuration, deployment, output formats, presentation assets.
| Document | Read it for |
|---|---|
docs/VULKAN_PROBE_PLAN.md |
The top-level plan: gates, milestone map, invariants |
docs/VULKAN_PROBE_ACTIVE.md |
Volatile state: current step, next actions, last verified runs |
docs/PROBE_MILESTONES.md |
The M1–M4 canaries, the runner and the console tooling |
docs/M5_REFERENCE.md |
The driver phases, the version ladder and the workflow |
docs/HARDWARE_FINDINGS.md |
What console runs established, with build, run id and commit |
docs/M5_PHASE_A.md · _B · _C |
Append-only run logs |
docs/CTS.md |
The conformance-subset recipe that gates a version rise |
docs/V0_FORMATS_AUDIT.md |
Required format support, row by row -- and the record that none is missing |
docs/BLOCKERS.md |
The mechanism log: each blocker, the round that closed it, and what it cost |
docs/REQUESTS_RESPONSE.md |
The game port's capability requests (R1…R10) and this side's answers, measurement by measurement |
docs/NATIVE_TOOLING.md · docs/TESTING.md · docs/DEPLOYMENT.md |
Build, test and console workflows |
AGENTS.md |
The repository's own working rules: read order, volatility contract, caching rules |
This project stands on other people's work. Everything below is fetched, pinned and checksum-verified, or used from a sibling checkout; nothing is vendored into the tree.
| Project | Author / org | What it provides here | How it is used |
|---|---|---|---|
| ps5-opengl | BlackBearReloaded | The sibling PS5 OpenGL SDK: the pinned opengnm-psbc shader-compiler tree (Mesa NIR + ACO), the C shader-package writer, register knowledge, and the Mesa version pin |
Release 0.3.0, adapted into .deps/native/opengl-sdk by tools/adapt-opengl-sdk.sh (PS5_OPENGL_SDK overrides) |
| ps5-native-app-boilerplate | BlackBearReloaded | This repository's foundation: the PS5 ELF converter, the FSELF writer, the clean-room libc.prx, and the identity and packaging tooling |
The base of this repository (GPL-3.0-or-later) |
| ps5-payload-dev/sdk | ps5-payload-dev (John Törnblom) | Public PS5 headers and sysroot, the prospero-clang18/lld target toolchain, and libc++ headers |
Fetched, pinned to v0.42 by SHA-256 |
| PS5_PayloadSDK | Mihawk-99, on ps5-payload-dev's SDK | My fork of the payload SDK with the shared platform layer (heap, direct and executable memory, libc gaps) RADV's winsys and the titles build on | Built by tools/setup-native-dependencies.sh at a pinned revision |
| PS5_Mesa | Mihawk-99, on Mesa | My Mesa fork: RADV, ACO and NIR with the PS5 winsys and VideoOut WSI | Exported at a pinned revision by tools/build-radv.sh from ../PS5_Mesa |
| ps5-payload-dev/pacbrew-repo | ps5-payload-dev | Optional prebuilt PS5 ports (SDL2, OpenSSL, …) for applications | Optional, pinned to v0.40.2 |
| opengnm-psbc | PS4-OpenGNM | The Mesa-derived shader compiler (NIR + ACO) the driver links for SPIR-V, and the tree the 0.3.0 SDK patches | Fetched by the SDK's patch over its pinned revision; this project's compiler patches are re-applied on top (tooling/psbc/) |
| ps5-vulkan | mpereiraesaa | A second native PS5 Vulkan implementation: its per-format console evidence and its reporting inventory are cross-checks for this project's audit | Reference; read, not fetched or linked |
| Mesa 3D | Mesa contributors (freedesktop.org), with AMD's AddrLib inside | The Vulkan common runtime and utilities the driver builds on, and AddrLib, which the tiling oracle compiles | Fetched, pinned to 26.2.0, checksum-verified |
| LLVM / Clang | The LLVM project | The host compiler, and the target compiler the payload SDK packages | Host packages plus the SDK's toolchain |
| PS5 system modules (AGC, VideoOut) | Sony Interactive Entertainment | The console's real GPU command, register and display interfaces | Used on the console through the SDK's published import stubs; never redistributed |
| AMD GPU documentation · BC-250 documentation | AMD; elektricm | Instruction definitions, register fields, and an external reference for the PS5-derived BC-250 board | Reference |
| Vulkan-Docs · Vulkan-CTS | Khronos Group | The version requirement tables the ladder is built from (pinned v1.4.354), and the conformance suite RADV is gated on | Pinned docs; the CTS is vulkan-cts-1.4.6.2 in my fork ../PS5_VK-GL-CTS, with its PS5 platform, built by tools/build-cts-title.sh |
| GoogleTest | The host-only unit-test framework | Fetched, pinned to 1.17.0; never linked into console output | |
| zlib | Jean-loup Gailly and Mark Adler | Compression for the host FSELF tool | Fetched, pinned to 1.3.2 |
| bc7enc_rdo | Richard Geldreich | The BC7 encoder behind presentation-image conversion | Optional, pinned revision b9438627 |
| UFS2Tool | SvenGDK | Optional .ffpkg (UFS2 image) output |
Optional, pinned commit, built with .NET |
| MkPFS | PSBrew | Optional compressed .ffpfsc output |
Optional, pinned commit |
| SharpProspero | SvenGDK | A public PS5 format reference used during early research | Reference only; not fetched, linked or required |
| etaHEN | The etaHEN project | The homebrew enabler on the validation console | Console-side; the repository only talks to it |
| ShadowMountPlus | drakmor | Mounts directory-style titles from /data/homebrew |
Console-side |
| ftpsrv · klogsrv | ps5-payload-dev (John Törnblom) | The FTP service make deploy uploads to, and the klog stream (port 3232) every run is captured from |
Console-side |
| RetroArch / libretro | The libretro project | The real application this driver is exercised with, and the source of a real compiler defect it helped find | Consumer |
| ccache | The ccache project | Optional build acceleration for the Mesa-derived builds | Optional host tool |
Exact pins, digests and license notes are in NOTICE.md.
Contributions are welcome. The most useful ones are probes that turn an unproven claim into a console result, and fixes that make an advertised capability true.
Before opening a change:
- Add the case or the fix with a focused regression — a behaviour change without a probe or a test is not reviewable here.
- Run the gates in §5 and paste the results.
- For any platform-specific claim, state the firmware, the loader and the console run id you saw it on. "It works on my console" is not evidence without the log.
- Keep every file's copyright and
GPL-3.0-or-laterSPDX header. The holder is the file's own --Mihawk-99for this project's files,BlackBearReloadedfor the ones inherited from the boilerplate, both for the ones derived from it;NOTICE.mdrecords the split andmake lintaccepts either. - Never commit keys, Sony files, game data, console dumps or credentials.
The repository's own working rules — the read order, the volatility contract
that keeps the plan static and the active file volatile, and the
caching-friendly editing rules — are in AGENTS.md. They are
written for AI agents working in this tree, and they are also a good
description of how the project keeps its documentation honest.
Repository-authored code is Copyright (C) 2026 Mihawk-99 and GPL-3.0-or-later (LICENSE); the files inherited from the ps5-native-app-boilerplate are Copyright (C) 2026 BlackBearReloaded under the same licence. Fetched dependencies keep their upstream licenses and are never redistributed from this repository; the details are in NOTICE.md.
This project is independent and is not affiliated with or endorsed by Sony Interactive Entertainment. "PlayStation" and "PS5" are trademarks of Sony Interactive Entertainment.
Vulkan and the Vulkan logo are registered trademarks of the Khronos Group Inc.
This project is not a Khronos Adopter, and neither driver here is a conformant
Vulkan implementation or appears in Khronos's list of conformant products
(khronos.org/conformance). "Vulkan 1.4"
names the API version RADV reports; RADV's conformanceVersion on the PS5 stays
0.0.0.0. The CTS runs recorded here are my own runs on one console, not a
conformance submission, and passing the CTS would not by itself make either
driver conformant: that takes a submission Khronos accepts.
Built on the work of the ps5-payload-dev community, ps5-opengl, and the Mesa and LLVM projects. Thank you.
The shared GPU broker provides an owner/client backend for native subprocess graphics. Its optional Windows WGL/Zink recipe builds OpenGL over Vulkan; Wine integration remains in the consuming title. The ordinary title backend is unchanged. See the broker guide for pinned inputs, build commands and the boundary between prior console evidence and unqualified extracted builds.