Skip to content

Proposal: native RDNA4 path on Linux — PS5 shaders translated gfx1013 → gfx12, direct amdgpu submission (PoC: Dreaming Sarah) #1

Open

Description

@DenizSAHIN570

Status (2026-10-09)

  • Research: source-level results are in this comment. They answer these open questions:
    • SDWA is gone on gfx12.
    • gfx10 tiling isn't readable on gfx12, so shadow surfaces are required.
    • PS5 DCC/HTILE can't be consumed on gfx12.
    • V#/T#/S# layouts and format enums changed.
    • Waits must be regenerated per gfx12 counter.
    • Several PM4 packets are gone and the graphics registers were re-laid out.
    • The user low range [0x10000, 0x8000_0000_0000) is free for same-address guest mapping.
  • Tools: for M0, M1 and the first M4 goal, plus the gfx1013 → gfx12 opcode table, on branch groundwork.
  • Next: remaining work and the order to do it in: NATIVE_RDNA_NEXT.md.

Proposal

Linux, an RDNA4 GPU (Radeon RX 9070 XT, gfx1201), and a native GPU path: PS5 shaders (gfx1013) are translated instruction by instruction to gfx12 instead of recompiled through SPIR-V, and the title's command buffers are translated and submitted directly to amdgpu. A minimal proof of concept covers one simple title, Dreaming Sarah. It would show whether the per-draw cost really collapses.

Placing GPU-oriented guest memory in VRAM through SAM (Resizable BAR) is a separate proposal: #2. It is independent of this one and complements it.

Revisions

  • The proposal first targeted RDNA2. The only hardware available for this fork is an RDNA4 card, and that will not change, so the plan targets gfx12 throughout. RDNA2, RDNA3 and the BC-250 are out of scope. The translator keeps its target ISA pluggable so others can add them.
  • The backend now defaults to direct submission through libdrm_amdgpu instead of a RADV fork, based on BC5's results (see Prior art).
  • The SAM/VRAM memory placement part moved to its own issue, Proposal: place GPU-oriented guest memory in VRAM via SAM / Resizable BAR (Linux, RX 9070 XT) #2.
  • Correction: an earlier version said RDNA2 runs most gfx1013 shaders as they are. BC5's census found instructions removed in RDNA2 in 449 of 485 shader programs of one title, so nearly every shader would need patching even on RDNA2.

The upstream SPIR-V path stays as it is. It is the working reference during development and the fallback for every other GPU. It is not switched off first: nothing can execute gfx1013 code on RDNA4, so the native path is built next to it and replaces it only for a title it fully runs.


Why: where the time goes today

On the CPU side, upstream AnyPS5 runs the game natively. The relinker binds imports by NID, and there is no instruction translation. Nearly all of the overhead is on the GPU side, where the PS5's hardware command processor and unified memory are replaced by software. Testers' measurements upstream point the same way:

Title Result Bottleneck the tester reports Source
GTA V (PPSA04264) ~10 fps in the prologue, RTX 5080 / Ryzen 5 7600 "Most of each frame is the CPU recording draws (~60 µs per draw packet), not the GPU" #426
GTA V ~20–23 fps in the bank interior The committer is the limit at ~27 µs per draw, trimmed to ~23 µs #1202
LEGO Party! (PPSA29141) 15–35 fps, RTX 4070 Laptop "frame rate is limited by per-draw driver CPU cost" #2055
Demon's Souls (PPSA01341) ~490 ms/frame in the tutorial level, RTX 5070 Ti Draining for compute dispatches and WAIT_REG_MEM #1896
Demon's Souls Attract movie 30 → 57–59 fps once the driver threads get priority Driver queue workers lose their cores to the title's spinning job threads #1788
Hollow Knight: Silksong (PPSA12544) Correct at 0.9 fps (eager write-back) vs garbled at ~5 fps (lazy) before later fixes Keeping guest memory and the GPU coherent #1970
Astro Bot 1.6–1.9 fps, then out of device memory on a 16 GB RTX 5080 — upstream PR discussion
Dreaming Sarah (PPSA02929) 60 fps on a GTX 1050 Ti Few draws, so the overhead stays hidden COMPATIBILITY.md

The high-end GPUs are mostly idle. The cost is in three places:

  1. Per-draw translation on the CPU. The driver parses PM4 and tracks register state. For every draw it walks the resource tables against guest memory, hashes descriptor words, looks up the pipeline and shader variant, writes Vulkan descriptors and records the draw (core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/*, Graphics/src/Recorder.cpp).
  2. The split between CPU and GPU memory. CPU writes are detected with write-watch (Windows) or page queries (Linux, Execution/src/GuestMemory.cpp). The GPU reads guest memory through host imports over PCIe (Graphics/src/GuestBufferMemory.cpp). GPU results are written back, and textures are detiled in a compute shader (Graphics/src/TextureDetiler.cpp).
  3. The cost of emulating RDNA in SPIR-V. EXEC masks are kept as values, wave64 is split across 32-wide host subgroups, cross-lane ops are emulated, NaN and denormal behaviour is reproduced exactly, and every new shader is recompiled (core/shader/recompiler).

This issue targets (1) and (3): most of both can go away once shaders and draw state are translated once and then reused. (2) is the subject of #2.


Prior art

  • No public gfx10 → gfx12 shader translator exists, as far as we could find. GPU vendors don't need one, because drivers compile from source or IR on the user's machine. Upstream AnyPS5 and KytyPS5 both recompile to SPIR-V.
  • BC5 (GPL-2.0) is a native PS5 GPU path for the AMD BC-250, which uses the PS5's own GPU (gfx1013). It is the reference design for this fork's backend:
    • It submits the title's PM4 command streams directly to amdgpu through its own libdrm_amdgpu client: buffer allocation, 1:1 GPU virtual-address mapping, and submission with filtered packets. It notes that amdgpu does not parse GFX indirect buffers, so raw PM4 from user space is the normal path.
    • The game's own shaders run as they are, with no SPIR-V.
    • Guest memory is exposed to the GPU as dma-bufs of the host's backing files, mapped at the guest addresses. This avoids copies and per-submission page walks.
    • It emulates the console command processor's behaviour: the CLEAR_STATE context stack, waiting for CP DMA, cross-queue labels and events, the doorbell-queue protocol. Overlapping submissions gave a large share of its frame-rate gain.
    • Its hybrid mode (native shaders, commands through Vulkan/RADV) was skipped. Every result uses the direct mode.
    • Reported results (the author's claims; not verified here): Astro Bot fully playable, 47–55 fps in the first level and 40–51 in the second; a 30-minute run with 1,332,438 submissions and no failure.
    • It does not port to other GPUs. Its census found instructions removed in RDNA2 in 449 of 485 Astro Bot shader programs.
  • Building blocks:
    • AMD's machine-readable ISA specs: XML files with instructions, encodings and operands, including RDNA4, plus the IsaDecoder C++ API. Upstream's tools/rdna_isa.txt comes from these specs.
    • LLVM's AMDGPU backend: disassembles gfx1013 and assembles gfx1201, so llvm-objdump --mcpu=gfx1201 serves as a reference checker. Its gfx12 code shows the split wait counters (s_wait_loadcnt, s_wait_storecnt, s_wait_samplecnt, s_wait_bvhcnt, s_wait_kmcnt, s_wait_dscnt, s_wait_expcnt) and the VIMAGE/VSAMPLE instruction classes.
    • Mesa: ACO for gfx12 hazard rules, wait-counter insertion and encoding; the per-generation register databases (src/amd/registers) for translating gfx10 register state to gfx12; libdrm's tests/amdgpu for raw submission.
    • Upstream AnyPS5:
      • core/shader/recompiler/RdnaDecoder and ControlFlow/GraphBuilder.cpp (they decode every RDNA1/2 opcode and resolve s_getpc/s_setpc/s_swappc);
      • APS5_DUMP_SHADERS and the agc_shader_replay tool (libSceAgcDriver/tools/ShaderReplay.cpp);
      • the 197 GPU execution tests in core/libs/prx/libSceAgcDriver/tests/execution/, whose expected outputs were measured on RDNA2 hardware;
      • the hardware oracle (tools/hw-oracle/).

Target: RDNA4 (RX 9070 XT, gfx1201)

The card already works with upstream: there is a test entry for "AMD Radeon RX 9070 XT (RADV GFX1201)" (core/libs/prx/libSceAgcDriver/tests/SubgroupClock.cpp:18), and an RDNA4 wave32 bug was found and fixed (#487, #587).

What gfx12 keeps from gfx1013:

  • The same execution model: wave32 and wave64 run natively, and SGPR/VGPR files, EXEC and VCC behave as on the console. None of the SPIR-V path's emulation of EXEC-as-a-value, subgroup splitting or cross-lane ops is needed.
  • Most scalar and vector ALU operations map one-to-one with the same semantics, so the work is re-encoding, not recompiling.
  • Hardware descriptors (V#/T#/S#) live in memory, as on the PS5. Their layouts differ (see Step 3), but there is no binding model to emulate.

What the translator must handle. These are known so far. Each item is checked against LLVM's gfx12 instruction definitions and AMD's RDNA4 XML before it is implemented.

  • Encodings: opcodes are renumbered. MUBUF/MTBUF become VBUFFER, MIMG becomes VIMAGE/VSAMPLE, and FLAT/GLOBAL/SCRATCH change too.
  • Cache policy bits: GLC/SLC/DLC become gfx12's four-bit cache-control and temporal-hint fields.
  • Wait counters: split into separate counters (see Prior art).
  • SDWA: removed after gfx10 (to verify). Upstream's decoder handles it heavily, so it becomes bit-extract/insert sequences or op_sel forms.
  • Interpolation: v_interp_* is gone. Parameters load through LDS (ds_param_load, ds_direct_load) and are interpolated with VINTERP v_interp_p10/p2_*.
  • Vertex outputs: since gfx11, parameter exports from NGG shaders go through an attribute ring in memory instead of exp param.
  • Removed ops: gfx10.1-only ops (v_mad_legacy_f32, v_mac_legacy_f32, v_mul_lo_i32, s_dcache_discard, ..., see HW_ORACLE.md), and ops gfx12 removed (V_DOT2ACC_F32_F16 among others), become instruction sequences.
  • Hazards: gfx12 has its own hazard rules and s_delay_alu hints.
  • Textures: gfx12 has a new set of tiling modes and reworked compression, so PS5 (gfx10) tiling and DCC layouts do not map directly (see Step 3).
  • Registers and PM4: gfx12's register layout differs from gfx10.1, so draw state is translated, not passed through.

Steps

Step 0: Setup and study

  • Linux setup: a recent kernel and a Mesa release with gfx12 support. Install ROCm/HSA for the compute test harness.
  • Read BC5's design records and experiments, and compare its handling of each packet with upstream's driver. Check the exact license wording before reusing code: AnyPS5 is GPL-2.0-only, and BC5 states GPL-2.0.
  • M0, baseline: build upstream main on the RX 9070 XT under Linux/RADV, recording the Mesa and kernel versions. Run Dreaming Sarah and record frame time, 1% lows and per-draw CPU time with APS5_ENABLE_TIMING_LOG=ON (frame-timing.log) and APS5_PROFILE_DRAW=1 ([guestmem], [recorder], [lock] lines).

Step 1: Shader corpus and census (no GPU code)

  • Dump every shader Dreaming Sarah registers (APS5_DUMP_SHADERS).
  • A census tool on upstream's decoder counts, per shader and in total:
    • opcodes and their encodings;
    • wave32 vs wave64;
    • SDWA and DPP use;
    • s_getpc/s_setpc/s_swappc patterns and fetch-shader calls;
    • export targets and interpolation;
    • image, buffer and LDS ops;
    • descriptor sources (which SGPRs feed resource operands).
  • The census defines the exact, minimal scope of the translator for this title.

Step 2: The translator, as a standalone library

  • Input and output: gfx1013 code plus stage info in; gfx12 code plus metadata out (register counts, attribute-ring use, scratch needs).
  • Front end: upstream's RdnaDecoder and ControlFlow/GraphBuilder.
  • Mapping table: each gfx1013 opcode is re-encode, rename, sequence or unsupported. Unsupported cases throw, following upstream's rules. The table is generated from AMD's XML specs and cross-checked against LLVM.
  • Order of work:
    1. scalar ALU and control flow;
    2. vector ALU (VOP1/2/3/C, DPP);
    3. SDWA;
    4. scalar memory;
    5. LDS;
    6. buffer (VBUFFER);
    7. image (VIMAGE/VSAMPLE);
    8. interpolation and exports.
  • Wait counters and hazards are regenerated, not mapped. The original s_waitcnt instructions are dropped and the waits recomputed from data flow, as ACO and LLVM do. A combined vmcnt(N) does not split correctly across gfx12's separate counters, so mapping it one-to-one is subtly wrong.
  • Code layout:
    • Code is rebuilt with branch offsets fixed up.
    • s_getpc is replaced by the original guest PC as a constant, so data addressed relative to the shader's code still resolves in the guest copy.
    • Fetch shaders are inlined (as upstream does) or translated too.
  • Scratch registers: sequences that need temporaries use registers above the shader's declared VGPR/SGPR counts, raising the allocation when needed.
  • Caching: results are cached per shader in memory and on disk, following upstream's ShaderDiskCache design. Translation happens once per shader, never per draw.
  • Pluggable target: the encoder sits behind a target interface, so gfx10.3 or gfx11 can be added later.
  • Tests:
    1. Every output decodes cleanly with llvm-objdump --mcpu=gfx1201.
    2. Upstream's execution-test programs are translated and run on the RX 9070 XT through an HSA harness built like tools/hw-oracle/oracle.c. They must give the expected values measured on RDNA2.
    3. The hardware oracle measures gfx12 replacement sequences for removed instructions.

Step 3: Descriptor and surface formats (design before graphics)

Game shaders load V#/T#/S# descriptors from guest memory in gfx10 format, and textures use gfx10 tiling modes, which gfx12 cannot read (to verify against Mesa's gfx12 surface code). This is likely the hardest part of the project.

  • V# and S#: converted inside the shader, right before each use. The translator knows which SGPRs feed each buffer or image instruction and inserts a few scalar ALU ops there, so there is no per-draw CPU work. Format enumerations are converted through lookup tables.
  • T#: candidate design.
    • Every guest surface at address A lives as a gfx12-tiled shadow at A + a fixed offset, mapped into the GPU at that address.
    • The in-shader T# conversion becomes "add the offset, set the gfx12 tiling mode and fields".
    • Render targets and depth surfaces follow the same rule, so a texture that samples a render target finds the same shadow.
    • The driver re-detiles a shadow only when upstream's write tracking reports a CPU change to the guest copy. A CPU read of a GPU-written surface (rare) is written back, as upstream does today.
  • DCC and HTILE (compressed color and depth): decompress on detile at first; reuse later only if gfx12's compression allows it.

Step 4: Submission backend, first with native gfx12 shaders

  • Default route: a direct libdrm_amdgpu backend, as in BC5.
    • Alternative: a RADV fork with a private raw-shader extension.
    • Trade-off: the RADV route could fall back to SPIR-V per pipeline. The direct route owns the GPU queue and memory, so it runs a whole title or nothing. For the proof of concept, whole-title is simpler.
  • First goal: submit a hand-written gfx12 compute dispatch (libdrm tests/amdgpu as the example).
  • Second goal: dispatch a translated compute shader from the corpus with the user-data values from the title's command buffer.
  • PM4:
    • Most type-3 packets keep their opcodes. Register writes (SET_CONTEXT_REG, SET_SH_REG, SET_UCONFIG_REG) are translated through a gfx10.1 → gfx12 table generated from Mesa's register databases, cached per unique state block.
    • PS5-specific packets are handled as upstream's driver and BC5 already do.
    • Registers the kernel considers privileged need a workaround or must be emulated.
    • gfx11+ only has the NGG geometry pipeline, which PS5 titles already use. The backend sets up the attribute ring.
  • Memory:
  • Presentation: the display buffer is imported into Vulkan as a dma-buf and presented through upstream's SDL/Vulkan swapchain.

Step 5: Graphics

  • Vertex and pixel shaders: parameter loads, interpolation, attribute-ring exports, and color/depth export formats.
  • Translated draw state.
  • Goal: one Dreaming Sarah draw renders correctly, compared with a SPIR-V frame dump (APS5_DUMP_FRAMES) of the same scene.

Step 6: The whole title and measurement

  • A switch in libSceAgcDriver runs the whole title on the native backend.
  • Dreaming Sarah runs end to end. Compare it with M0.

Milestones

  • M0: baseline on the RX 9070 XT (Step 0)
  • M1: Dreaming Sarah shader corpus and census (Step 1)
  • M2: compute translator passes the covered upstream execution tests on gfx1201 (Step 2)
  • M3: descriptor and surface design written down (Step 3)
  • M4: direct backend runs a native, then a translated, compute dispatch (Step 4)
  • M5: one Dreaming Sarah draw renders correctly (Step 5)
  • M6: Dreaming Sarah runs end to end on the native path; compared with M0 (Step 6)

Success criteria

  • Per-draw CPU cost drops by an order of magnitude against M0, from tens of µs to a few µs or less.
  • Frames match the SPIR-V path (APS5_DUMP_FRAMES).
  • The translator passes the upstream execution tests it covers.
  • No new silent stubs. Unsupported states throw, as upstream requires.

Title choice. Dreaming Sarah (PPSA02929) is playable on upstream main at 60 fps, so it gives a clean baseline. Balatro (PPSA21402) is the second choice. It needs open upstream PRs and crashes after about 60 s while more than 2 flips are pending (#1034).


Open questions

  • Do guest GPU virtual addresses, and the shadow range A + offset, fit the GPU address range amdgpu lets user space allocate in?
  • How many gfx1013 instructions have no one-to-one gfx12 form? The exact list comes from the census and the XML/LLVM tables.
  • Is SDWA definitely absent on gfx12, and how much do PS5 shaders use it?
  • What do the attribute ring's layout and per-draw setup cost under direct submission?
  • Exactly how do the V#/T#/S# bit layouts and format enumerations differ between gfx10.1 and gfx12?
  • Can gfx12 read any gfx10 tiling mode, or does every tiled surface need a shadow?
  • PS5 DCC and HTILE: decompress on detile, or keep compressed under gfx12's reworked compression?
  • Which PS5-specific PM4 packets have no gfx12 equivalent, beyond those BC5 and upstream already document?
  • Which registers that PS5 titles write are privileged on desktop amdgpu?

Out of scope

  • RDNA2, RDNA3 and the BC-250: no hardware for them here. The pluggable target leaves room for others to add them.
  • Windows: AMD's Windows driver is closed, so there's no comparable path.
  • NVIDIA and Intel: they keep the upstream SPIR-V path.
  • Any change to the relinker. The CPU side is native already.

References

Activity

  1. changed the title [-]Proposal: native RDNA2 path on Linux — VRAM placement via SAM, PS5 shaders as-is through a RADV fork (PoC: Dreaming Sarah)[/-] [+]Proposal: native RDNA4 path on Linux — VRAM placement via SAM, PS5 shaders translated gfx1013 → gfx12 through a RADV fork (PoC: Dreaming Sarah)[/+] on Oct 9, 2026
  2. changed the title [-]Proposal: native RDNA4 path on Linux — VRAM placement via SAM, PS5 shaders translated gfx1013 → gfx12 through a RADV fork (PoC: Dreaming Sarah)[/-] [+]Proposal: native RDNA4 path on Linux — PS5 shaders translated gfx1013 → gfx12, direct amdgpu submission, VRAM placement via SAM (PoC: Dreaming Sarah)[/+] on Oct 9, 2026
  3. changed the title [-]Proposal: native RDNA4 path on Linux — PS5 shaders translated gfx1013 → gfx12, direct amdgpu submission, VRAM placement via SAM (PoC: Dreaming Sarah)[/-] [+]Proposal: native RDNA4 path on Linux — PS5 shaders translated gfx1013 → gfx12, direct amdgpu submission (PoC: Dreaming Sarah)[/+] on Oct 9, 2026
  4. DenizSAHIN570 commented on Oct 9, 2026

    @DenizSAHIN570
    OwnerAuthor

    Research results: gfx1013 → gfx12 ISA, descriptors, tiling, PM4 and submission

    This is from reading source code, not from runs on hardware.

    • Revisions read: Mesa 59f580b7a7f1, LLVM 3756ef84838e, libdrm b97cbde15c5c, IGT 556f2ad0c2b2, Linux af32da41b032, BC5 181ebf8e58bb.
    • AMD's machine-readable ISA: AMD_GPU_MR_ISA_XML_2026_08_06.zip, SHA-256 82404f11…c082e2, MIT-licensed.
    • Mesa paths below are relative to src/amd/; LLVM paths are relative to llvm/lib/Target/AMDGPU/.
    • UNCONFIRMED marks anything the sources don't settle.

    Open questions this answers

    Question Answer
    Is SDWA absent on gfx12? Yes. FeatureSDWA is in FeatureGFX10 but not GFX11 or GFX12 (AMDGPU.td:1804/1839/1874), and only *_Real_sdwa_gfx10 encodings exist. ACO's can_use_SDWA returns false for GFX11+ (compiler/aco_ir.cpp:298). Replacements: true16 .h/.l operands (v0–v127 only), VOP3 op_sel, v_bfe, v_perm_b32, 16-bit ops.
    How many gfx1013 instructions have no 1:1 gfx12 form? 149 of upstream's 1166-instruction inventory have no gfx12 form, each with a replacement listed in the new table (tools/native-rdna/data/gfx1013-to-gfx12.csv). The other 1017 map: 188 identical, 503 renumbered, 325 renamed (AMD's own AliasedInstructionNames in the RDNA4 XML). S_WAITCNT is the one unresolved row: LLVM still encodes it for gfx1201, but AMD's RDNA4 spec doesn't have it, so it is treated as unusable.
    Can gfx12 read gfx10 tiling modes? Almost never. Both use a 5-bit SW_MODE field, but the enums differ (addrlib/inc/addrtypes.h:225-275 vs :285-297). Comparing the expanded per-bit equations, a gfx10 non-XOR _D mode equals gfx12 2D only at 8 and 16 bytes per element. _X modes match only in a degenerate 1-pipe configuration, and no _S mode ever matches. The shadow-surface design in Step 3 is required, not optional.
    PS5 DCC/HTILE on gfx12? Can't be consumed. gfx12 compression is a page-table bit (PTE.D) plus descriptor bits. There is no metadata address in the T# and no DCC/CMASK/FMASK/HTILE base registers (common/ac_descriptors.c:706-724, registers/gfx12.json). Guest metadata has to be treated as opaque, with fast clears, decompress passes and FMASK MSAA emulated. Guest memory must stay out of PTE.D allocations.
    How do the V#/T#/S# layouts differ? Sizes are unchanged (128/256/128-bit), but fields moved in every word except T# word 0. Format enums agree for values 0–29 and are renumbered from 30 up (e.g. 8_8_8_8_UNORM 56→42, BC1..BC7 169..182→109..122). Gfx10's "must be 1" RESOURCE_LEVEL bit lands on gfx12's WRITE_COMPRESS_ENABLE, so a raw gfx10 descriptor is invalid on gfx12. V# and S# convert with bit shuffles plus a format lookup table. The T# also has to point at the shadow surface.
    How should combined s_waitcnt map to gfx12 counters? Regenerate the waits instead of mapping them. gfx12 has s_wait_{load,store,sample,bvh,exp,ds,km}cnt (SOPInstructions.td:2972, 3029-3036). Completion is in order only within a type, and SMEM is out of order. gfx12 also lacks FeatureVmemWriteVgprInOrder (AMDGPU.td:1356), so two VMEM loads writing the same VGPR need a wait between them.
    Vertex outputs? exp param and exp null are gone. Attributes go to the attribute ring as swizzled buffer stores (common/nir/ac_nir_prerast_utils.c:476), at the gs_attr_offset SGPR in 512-byte units. The ring's base and size registers are SPI_ATTRIBUTE_RING_BASE/SIZE (0x31118/0x3111c), set by ac_emit_cp_gfx11_ge_rings (common/ac_cmdbuf_cp.c:296). gfx12 adds GE_POS/PRIM rings, and pos/prim/mrt/mrtz exports remain.
    Interpolation? ds_param_load (M0 = prim mask, WQM, counted in expcnt), then v_interp_p10_f32 and v_interp_p2_f32. Flat inputs use a DPP quad_perm move (ACO emit_interp_instr_gfx11). The exact per-lane layout is UNCONFIRMED.
    Which PM4 packets are gone? CLEAR_STATE, all Constant Engine packets (including INDIRECT_BUFFER_CONST), EVENT_WRITE_EOP/EOS, SURFACE_SYNC, ATOMIC_GDS and STRMOUT_BUFFER_UPDATE (packets/pm4_it_opcodes_gfx12.h). PS5 EOPs become RELEASE_MEM, and CLEAR_STATE push/pop needs a CPU-side state stack, as BC5 does. DISPATCH_DIRECT and the DRAW_* packets are unchanged.
    Registers? The compute (SH) block is stable: same offsets, few field changes. Graphics context registers were re-laid out: 279 moved, 180 removed, 108 added. A gfx10→gfx12 command rewriter needs a full remap table, generated from registers/gfx10.json and gfx12.json.
    Privileged registers? The kernel doesn't parse GFX command buffers; CP firmware traps protected writes. The full gfx12 set is UNCONFIRMED; known cases are TBA/TMA, TA_CNTL2.TRUNCATE_COORD_MODE and VGT_GS_MAX_WAVE_ID. gfx12 kernel queues do no register shadowing, so full state is re-emitted with every submit.
    Do guest addresses fit the GPU address range? gfx1201 is 48-bit. The user low range is [0x10000, 0x8000_0000_0000) (amdgpu_kms.c:990-1006). RADV puts every buffer in the high range, which leaves the low 128 TiB free for a same-address guest mapping. AMDGPU_GEM_VA maps at any aligned address there.

    Other traps found

    • m0 and null swap encodings on gfx11+ (124 ↔ 125, SIRegisterInfo.td:226-231). Every SGPR operand field needs remapping.
    • s_getpc_b64 zero-extends on gfx12 (GCNSubtarget.h:750).
    • gfx12 removes DX10_CLAMP and IEEE_MODE from RSRC1/MODE, and hwreg IDs were reassigned. NaN/clamp behaviour without those bits is UNCONFIRMED.
    • Buffer out-of-bounds checks now include the payload size (common/ac_descriptors.c:815-832).
    • Cache policy: GLC/SLC/DLC become TH/SCOPE, and atomic return becomes TH bit 0.
    • Hazards: gfx12's main one is the VALU-read-SGPR hazard (s_wait_alu). s_delay_alu is only a performance hint. The gfx101x workarounds can be dropped.

    BC5 (reference for Step 4)

    • License: GPL-2.0-only in every SPDX header, the same as AnyPS5.
    • Approach:
      • guest memory: memfd → udmabuf (32–64 MiB) → GTT buffer import → va_op_raw at the guest address;
      • submissions: GFX ring only, each guest IB copied into an uncached scratch BO and padded, ending with a CP_SYNC DMA;
      • a CPU-side CLEAR_STATE stack, forced CONTEXT_CONTROL, and a host "soft CP" for labels and EOPs.
    • Its shader census: 449 of 485 shaders use v_mad/mac_f32, so the other-GPU path means rewriting shader binaries, which is this issue's plan.
    • Caveat: BC5's policy is keyed on gfx10 register offsets, so it doesn't carry over to gfx12 as is.

    Built on branch groundwork (nothing has run on the RX 9070 XT yet)

    • APS5_DUMP_REGISTERED_SHADERS: dumps every registered shader before preparation (Step 1 input).
    • tools/native-rdna/census + census_report.py: the per-title census against the gfx12 table (Step 1).
    • tools/native-rdna/opcode_map.py + data/gfx1013-to-gfx12.csv: the translator's mapping table (Step 2).
    • tools/hw-oracle: gfx12 template and --assemble-only (Step 2 tests).
    • tools/native-rdna/drm-dispatch: a gfx1201 compute kernel submitted as raw PM4 through amdgpu ioctls at fixed GPU addresses (the Step 4 first goal).
    • tools/native-rdna/baseline.py: M0 runs and summaries.

    Usage: NATIVE_RDNA.md. Remaining work and the order to do it in: NATIVE_RDNA_NEXT.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions