Repository navigation
Conversation
…tion Add -Dimagination-g5p-experimental (default off) and, only when it is on, a device-info entry for the Apple A9 GPU, BVNC 9.15.6.2 as its legacy CORE_REVISION/CORE_ID registers decode, with a new feature bit apple_g5p next to the A10's apple_g9p. The bit sits in the trailing padding of pvr_device_features (after the derived features), so no other field moves; the entry, its table slot and its BVNC case are compiled only under PVR_APPLE_G5P, which meson defines for src/imagination when the option is on. With the option off the build is unchanged: same installed files, byte for byte. Nothing selects the entry yet. It is there so that later steps can gate shared pvr_* code on PVR_HAS_FEATURE(dev_info, apple_g5p) the way G9P does. Values marked "A9" are from the hardware or Apple's drivers; the others are the A10 entry's placeholders. Generated-by: LLM
Add src/imagination/g5p: the compiler backend of our A9 driver, moved out of src/imagination/pco (where our fork kept it as pco/*g5p*) into its own directory and static library, the way src/imagination/g9p holds the A10's. It is built only with -Dimagination-g5p-experimental=true, and nothing links it yet: our A9 Vulkan driver stays out of this tree for now (see README.md). pco/ is not touched: the two entry points our fork declared in pco/pco.h move to g5p/pco_g5p.h. The files are those of our fork's g5p-bench@b20fcfdcdb6, unchanged apart from that include, the attribution lines below, and one program: the varying fragment program of pco_g5p.c's shape matcher, which our fork held as a 12-byte literal, is built by g5p_usc.h's encoders (iterator, wait, emit, end), to the same 12 bytes. No program is held as bytes. On our offline corpus (270 compiles) the output is byte-identical to that branch's and to the device-proven g5p-perf60-hypr@bc82302f291. Parts of the backend were ported from Henrik Klee's G9P compiler and encoders (OrchardLinux/mesa src/imagination/g9p, MIT): discards in blending programs to a select (7013b55, 7a64e1d), multiply-add fusion (28cdfce), control flow on the execution-mask stack and its encoders (d914276), and registers above r31 with their moves (d1ab45d). His copyright lines are kept at those parts, without the e-mail address; README.md lists them. Co-developed-by: Henrik Klee Generated-by: LLM
The general backend wrote into a fixed 16 KiB buffer and refused any
program past it ("program exceeds 16384 bytes"). That bound was the
buffer's, not the GPU's: Apple's A9 compiler emits straight-line fragment
programs from 17546 to 1258052 bytes, each with one end and no jump,
USC code is a 32-bit offset from usc_base (code_window 4 GiB), and no
program state word holds a size.
The buffer now starts at 16 KiB and doubles, and is kept across the
compile retries. PCO_G5P_PROGRAM_MAX (1 MiB) only stops runaway growth.
What really bounds a program is the job memory the driver places it in;
our A9 ICD (not part of this series) refuses a pipeline at creation when
its programs cannot fit one job. Programs that fit in 16 KiB are
unchanged, byte for byte.
On the A9 (iPad 5, GPU at 723 MHz), fragment programs of 21234, 102834
and 2 x 74034 bytes from this backend ran pixel-exact (32768 of 32768
pixels against a CPU reference), with no GPU fault.
Generated-by: LLM
The jump encoder (ported from G9P, d914276) refused offsets past 64 KiB: it put offset bit 24 in bit 0 of the third word, so it could not place bit 16. Apple's A9 compiler keeps a long loop or if as one program and encodes the jump with the third word = offset >> 16, bit 16 in bit 0, bit 24 left out (bit 8 of the last word is the next-word flag), so offsets reach 16 MiB. Six of its jumps over long bodies (35 to 196 KiB programs, long loops and ifs, forward and backward) re-encode byte for byte, and every decoded target is an instruction start. Within 64 KiB both forms give the same bytes for every even offset, so no program that compiled before changes. On the A9 (iPad 5, GPU at 723 MHz), a 71110-byte fragment loop with a uniform trip count, whose two jumps are +0x11384 and -0x113a2, ran pixel-exact (32768 of 32768 pixels against a CPU reference), with no GPU fault. Co-developed-by: Henrik Klee Generated-by: LLM
The TA program slot of a G5P render (GET_RENDER_INFO's TA program) runs a
USC program at the end of the geometry stream: a branch to the next 64-byte
block, padding, and an end of task. Henrik Klee's G9P builds the same
program for the same register on the A10 ("Register 0x470's program").
Add the generator for its last word, beside g5p_usc_branch() and
g5p_usc_special(). Nothing calls it yet.
Generated-by: LLM
The A9 GPU's kernel driver (DRM name "apple_g5p") has its own typed UAPI: GEM objects, one VM per file, VM_BIND, GET_RENDER_INFO (the render layout: code window, user VA, PM/parameter-buffer limits) and render jobs submitted as typed passes (SUBMIT_RENDER_TYPED, TYPED_V3: the kernel validates every program address against the job's resource list and the layout, and builds the firmware records itself). Add winsys/apple_g5p: the UAPI header (apple_g5p_drm.h, with the layout asserts the A9's passes were proven with), its transport calls, and the pvr_winsys ops over it: - memory: BOs are slices of one arena placed at the code base, inside the kernel's code window, so any slice is a valid program address in any heap; heaps are carved from it, and vma_map returns the slice's address; - render contexts and render targets: the kernel's, created on first use; - render submit: the TYPED_V3 pass in the fragment stream, the arena as the job's resources, the two stages' waits and one signal (the kernel takes one per job; the geometry stage's syncobj takes the same fence through SYNCOBJ_TRANSFER); - null jobs: syncobj transfers, as the powervr winsys's; - compute and transfer submits are refused (not in this series). Nothing selects this winsys yet. It builds only with -Dimagination-g5p-experimental=true. Generated-by: LLM
A G5P render is one TA + 3D pass, which the A9 kernel takes as a TYPED_V3
pass. Add what builds it, in the shape of Henrik Klee's G9P
(pvr_arch_g9p_job_init(), pvr_arch_g9p_frag_stream()):
- device programs, uploaded once (pvr_arch_g5p_device_init()). Every PDS
program is built by pdsc, with the DOUT form of the A9's PDS
(PDSC_FEATURE_DOUT_EXT); every USC program by the G5P backend's
generators (g5p_mrt_programs.h, g5p_usc.h):
- the context store and resume programs are a lone PDS HALT, as on G9P;
- the TA's end-of-stream program: a branch to the next 64-byte block,
padding and an end of task, and its PDS kick (the same program G9P
builds for the A10's register 0x470);
- per colour-target count (1, 2, 4): the clear and end-of-tile USC
programs, their PDS kicks and DOUTD code;
- pvr_arch_g5p_job_init(): a clear-only render of 1, 2 or 4 linear
B8G8R8A8/R8G8B8A8 targets: the PBE words, the clear colours, the
background registers and the end-of-tile words. Everything else (draws,
depth/stencil, MSAA, LOAD, other formats) is refused by name;
- pvr_arch_g5p_frag_stream(): the TYPED_V3 pass. Its register words that are
not programs (context and TA size words, restore, scratch offsets, V1 pool
sizes) are named constants with the A9's values.
No captured program is used: the job runs the generated programs only.
pvr_device and pvr_render_job gain a g5p member, and pvr_job_render.h
includes pvr_g5p.h, under PVR_APPLE_G5P only. Nothing calls the new
functions yet.
Generated-by: LLM
Select G5P where the driver selects G9P, with a G5P branch in front of each G9P one: - pvr_instance.c, winsys/pvr_winsys.c: the A9 kernel's DRM name is a PowerVR node, served by the apple_g5p winsys; - pvr_arch_device.c: device init and finish of the G5P device programs; - pvr_arch_cmd_buffer.c: a G5P render job takes pvr_arch_g5p_job_init()'s background and end of tile; clears are background objects, so the start-of-render attachment clear and the "soft" background load op are skipped, as for G9P; - pvr_arch_job_render.c: the fragment stream is pvr_arch_g5p_frag_stream()'s pass, without a partial render. The geometry stream is left as is; the apple_g5p winsys does not read it. A build without -Dimagination-g5p-experimental keeps every byte of libvulkan_powervr_mesa.so. Where code after a hook passes __LINE__ (vk_error() and friends), the hook is one line, PVR_G5P_HOOK(name, ...), that takes the place of a blank line of the file and expands to nothing without the option (pvr_g5p_hooks.h lists every one and what it expands to). The other hooks are #ifdef PVR_APPLE_G5P blocks with no such code after them. Nothing on a G9P or Rogue path changes. Generated-by: LLM
This was referenced Nov 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is. Your first-PR scope, plus the smallest bring-up that lets you check it runs:
src/imagination/g5p/, built only with-Dimagination-g5p-experimental=true(default off);
apple_g5pfeature bit;pvr_*skeleton, in the shape of your G9P ones:It edits no
apple_g9ppath. If you want only the literal scope (backend and device info), commits 1–5 are that PRon their own; 6–8 are the bring-up.
This is AI-written. Every commit carries
Generated-by: LLM. It is for your fork only, not for upstream Mesa.Your conditions, one by one
mainbrkosebay/mesa:g5p-pr1, 8 commits on73a49abe247(your currentmain)src/imagination/g5p/behind an experimental option, the A9 device-info entry withapple_g5p, no edits to theapple_g9ppathsgit diff main -- src/imagination/g9p src/imagination/vulkan/*g9p*is empty. No G9P line is changed or removed (the only removed lines are 6 blank lines, each replaced by a one-line hook)libvulkan_powervr_mesa.somain's;cmpoflibvulkan_powervr_mesa.soidenticallibpowervr_g9pgets only an unused-DPVR_APPLE_G5PGenerated-by: LLMCommits
pvr: add the Apple A9 GPU (G5P) device info behind an experimental optioncommon/device_info/apple-a9.h, the table row and BVNC case;has_apple_g5pinpvr_device_features' trailing padding: a bit beside yours would move every later field.g5p: add the Apple A9 (G5P) shader backend beside g9p(Co-developed-by: Henrik Klee)pco/into its own directory and static library, asg9p/holds yours;pco/is untouched;(the same 12 bytes, checked by a host test).
pco/g5p: no program size limit of the backend's own: a growing buffer instead of 16 KiB.g5p: jumps up to 16 MiB, in Apple's form(Co-developed-by: Henrik Klee: your encoder).imagination/g5p: g5p_usc_task_end(): the last word of the TA's end-of-stream program.pvr/winsys: apple_g5p, a winsys over the Apple A9 kernel's typed UAPIwinsys/apple_g5p/;pvr: apple_g5p: the G5P device programs and its clear-only render jobpvr_arch_g5p.c,pvr_g5p.h, and ag5pmember inpvr_deviceandpvr_render_job;pvr_arch_g9p_job_init(),pvr_arch_g9p_frag_stream().pvr: apple_g5p: hook G5P into the shared driver files: the hooks below.Every edit outside the new files
New files:
src/imagination/g5p/*,common/device_info/apple-a9.h,vulkan/pvr_arch_g5p.c,vulkan/pvr_g5p.h,vulkan/pvr_g5p_hooks.h,vulkan/winsys/apple_g5p/*.meson.optionssrc/imagination/meson.build-DPVR_APPLE_G5Pandsubdir('g5p'), only with the optionsrc/imagination/vulkan/meson.buildcommon/pvr_device_info.hhas_apple_g5p, in the trailing padding (no field moves)common/pvr_device_info.c#ifdef PVR_APPLE_G5Pvulkan/pvr_device.hstruct pvr_g5p_device *g5p,#ifdefvulkan/pvr_job_render.h#include "pvr_g5p.h"andstruct pvr_g5p_job g5p,#ifdefvulkan/winsys/pvr_winsys.hvulkan/pvr_instance.cvulkan/winsys/pvr_winsys.cvulkan/pvr_arch_device.c#ifdefblocks: G5P device init, and finish on both pathsvulkan/pvr_arch_cmd_buffer.cvulkan/pvr_arch_job_render.c#ifdefblocks: the fragment stream is G5P's pass, no partial renderHow option-off stays byte-identical (the hook design). Your shared files pass
__LINE__tovk_error()andfriends, so an inserted line before such a call changes your binary even inside
#ifdef.__LINE__follows a hook, the hook is one line,PVR_G5P_HOOK(name, ...), and it takes the placeof a blank line of your file. Without the option it expands to nothing, so every line keeps its number. With it,
it expands to
PVR_G5P_HOOK_<name>inpvr_g5p_hooks.h, which lists every hook and what it does. A hook endingin
elseis the G5P branch of the if/else chain after it, in front of your G9P branch.CmdBeginRenderPass2) the hook must sit right before theif, so the blank line it replaces is theone after that block.
#ifdef PVR_APPLE_G5Pblocks, each with no__LINE__user after it in its file.#linedirectives: once merged, every line number is real, so a later edit of yours can't make one stale..clang-format. Formatting the files leaves them as they are.Gates
All builds: one container (Fedora, GCC 16, aarch64),
git archiveof the commit into fixed paths. The release gateuses
buildtype=release,strip=true,b_ndebug=true,vulkan-drivers=imagination,gallium-drivers=zink, LLVM,EGL/GBM/GLES2/OpenGL and Wayland.
3a, option off: PASS, byte for byte.
g5p-pr1and yourmain(73a49abe247) install the same165 files with identical bytes, and
cmpof the twolibvulkan_powervr_mesa.sofinds no difference:76e29856fe5011d2d63fd45756a6ed7fd9ad62de79a1a107df4d40c431cc7584in both. That is also the hash this check gave formilestone 1's backend-only branch. With the one-line hooks, no padding or line tricks are needed: it is a plain
build of the branch.
3b, compiler output: PASS by construction.
git diff main -- src/imagination/pco src/imagination/g9p src/compileris empty: no compiler source changes. Option off, the installed files,
libvulkan_powervr_mesa.sowith your compiler init included, are byte-identical to
main's (3a). Option on, the only change to your compiler's build is an unused-DPVR_APPLE_G5Ponlibpowervr_g9p. We don't have your offline corpus. If you run it on this branch, it should givethe same output byte for byte.
3c, CI: PASS. What your workflow would build, run in its place (see "CI" below): a fresh
meson setupof agit archiveof this branch,-Dbuildtype=debugoptimized -Dvulkan-drivers=imagination -Dgallium-drivers= -Dtools=imagination -Dbuild-tests=true -Dplatforms=wayland -Dglx=disabled, thenninjaandmeson test, once withthe option off and once with it on:
meson test26 OK, 0 failures;meson test26 OK, 0 failures (includingpvr symbols check);No Apple binaries
The 153 helper instructions and 14 PDS programs are not in this PR, nor is any other captured program.
and retires such jobs on hardware (below).
Scans:
What they find is encoding knowledge, not programs: opcode and field tables of
g5p_usc.c(the largest islit3_seen, 168 bytes: the measured routings of one literal-operand form), the field maps of the immediateencoder, and the parameterised instruction templates of
g5p_mrt_programs.h.What stays Apple-derived: register values, not code. They are named
#defines inpvr_arch_g5p.c:0x24001002,0x00030005,0x21001002,0x00030021,0x00004820,0x20000001;0x24000081;0x01800000;+0x20/+0x24/+0x28/+0x2c/+0x6240/+0x6040in a 32 KiB scratch;0x80000and0xc0000.They are words of the kernel's job contract (what our kernel validates and writes to the firmware's records),
in the same role as your G9P register block's values. They carry no instructions, and they are named field by
field.
apple-a9.hholds the BVNC and feature values, from the hardware and the kext, like yourapple-a10.h.Hardware results (iPad 5, A9, our kernel)
Bring-up, on
g5p-1b(this PR's code before the hook rework). Beside a live Hyprland session:vulkaninfoshowsPowerVR Apple A9on our kernel's real render node;Route (b), our question 1. The A9 renders and retires jobs whose context store/resume programs are a bare PDS
HALT, with no prologue or epilogue and every other template segment zeroed. Two contexts rendered at once.
The first real job. A clear-only render pass through
pvr_*, the G5P hooks, the generated programs and thekernel's TYPED_V3 pass. 4096 of 4096 pixels exact, 0 faults, on two kernels. Run 2 also used the HALT as the
TA context program (commit 7 has it), so the job runs no Apple program at all.
This PR's exact build (the tree of this branch's tip, the hooks as in this PR; 2026-11-04, kernel
7.3.0-rc1-release8-ga10a8556b98e,Apple's unmodified GPU firmware), beside a live Hyprland session: PASS.
in 15 of 15 fields, and its TA context program is the HALT;
The one BO left after the run is the kernel's own: it holds a closed render context's VM until another context's
job moves its parameter manager past it. It is reported, not leaked.
CI
Your only workflow,
.github/workflows/macos.yml(Mesa's GitHub mirror job), runs onmacos-11, a runner imageGitHub has retired. All 7 runs on your
mainwere cancelled after 24 hours without starting a step, so it would showthe same on any PR. What it would run, we ran in its place (3c above). Updating the runner image is a one-line change
in your workflow; we left it alone because it isn't ours to change.
After this PR: one PR per feature, each with its test program
Each follows the same rules (G5P files and one-line hooks, option-off identical, no Apple bytes) and comes with a
small Vulkan test program that checks its feature pixel-exactly. The test program is plain Vulkan, so the same binary
runs on your A10 to check that your path is unchanged, and on our A9 to check ours:
stacked on this one.
The goal at the end is OpenGL ES 3.0 through Zink on the A9, and labwc and Hyprland running on this driver.
🤖 Generated with Claude Code