Replaces the synthetic eventfd stand-in with the real kernel
eventfd path: open the kernel's 'card0/fence/<seqno>' fd and
poll on it. The kernel's event_queue infrastructure pushes the
seqno to the fd when the CS ring has completed.
Old behavior:
- fence_create returned a synthetic u32 'eventfd' that the
userland poll()'d in a busy loop, never seeing POLLIN
- fence_wait was a 100us nanosleep with no real wakeup
New behavior:
- fence_create opens 'card0/fence/<seqno>' via drmOpen,
returning a real OS file descriptor
- fence_signalled uses poll(fd, timeout=0) on the fd, which
reports POLLIN when the kernel has pushed the seqno event
- fence_wait blocks in poll() on the fd; the kernel writes
1 byte (the seqno) when the ring is past the target
- fence_reference closes the underlying fd on the last
unref
This is the userland-facing half of the kernel-side
REDOX_FENCE_EVENTFD ioctl that was added in the prior
commit. Together they implement the same pattern as
Linux 7.1's drm_syncobj_wait_eventfd (drivers/gpu/drm/
drm_syncobj.c::drm_syncobj_wait_ioctl +
include/uapi/drm/drm.h::drm_syncobj_eventfd).
Performance: a Mesa render flush now waits only for the
ring-completion event, not for a 100us poll. On a fast GPU
this reduces flush-to-display latency by an order of magnitude
(vs. the synthetic poll-loop).
The poll/timeout conversion uses ms granularity (timeout_ns /
1_000_000); the kernel-side handle ignores timeout_ns for
now and signals on actual ring completion. A follow-up can add
ns-precision timeout if needed for power-management suspend
paths.
Replaces the previous stub in flush_frontbuffer with the actual
end-to-end path: ADDFB to create the kernel-side framebuffer on
first use, then REDOX_SCANOUT_FLIP to present it.
Three new functions:
redox_drm_bo_get_fb() in redox_drm_bo.{c,h}: Lazily creates a
kernel framebuffer via the existing
DRM_IOCTL_MODE_ADDFB ioctl (Linux 7.1's
drm_mode_addfb_ioctl, drivers/gpu/drm/
drm_ioctl.c). Caches fb_id and stride on
the BO so the second call is a no-op.
redox_drm_bo_flip_to_crtc() in redox_drm_surface.{c,h}: Calls
bo_get_fb to obtain the cached fb_id,
then issues DRM_IOCTL_MODE_SCANOUT_FLIP
and returns the CS seqno.
flush_frontbuffer in redox_drm_winsys.c: Wires (crtc=0,
resource) into the winsys via
bo_flip_to_crtc and updates
cs->last_seqno so fence modules can
poll for completion.
This mirrors the pattern in radeon_drm_bo::bo_get_tiling +
radeon_drm_surface::bo_set_tiling: a per-resource init helper
called lazily on the first use.
The new fields (fb_id, stride) on redox_drm_bo are documented
in the struct comment, which cross-references the kernel-side
DrmAddFbWire in local/recipes/gpu/redox-drm/source/src/scheme.rs.
Limitation (preserved as comment): ctrc_id is hardcoded to 0.
Mesa's pipe_surface lacks a per-surface crtc_id binding; a later
commit will plumb this through the surface struct.
This closes Phase 6+'s 'real flush_frontbuffer' gap. The
remaining 'real fence' work is Phase 6.4 (real eventfd for
fence_eventfd, replacing the synthetic stand-in).
This commit lands Phase 5+ of the 3D driver plan. It ports four
ioctl handlers from Linux 7.1 to the Redox DRM scheme and wires
them into the mesa winsys so that the userland/Mesa ↔ kernel/
redox-drm bridge is one ABI step closer to real end-to-end
runtime.
Kernel-side: local/recipes/gpu/redox-drm/source/src/scheme.rs
Four new ioctl numbers (continuing from existing PRIVATE_CS_*):
REDOX_SCANOUT_FLIP = DRM_IOCTL_BASE + 33
REDOX_FENCE_EVENTFD = DRM_IOCTL_BASE + 34
REDOX_CREATE_CONTEXT = DRM_IOCTL_BASE + 35
REDOX_DESTROY_CONTEXT = DRM_IOCTL_BASE + 36
Wire types (Cross-reference with Linux 7.1 source):
RedoxScanoutFlipWire models drivers/gpu/drm/drm_plane.c::
drm_mode_page_flip_ioctl. Page-flip wire
(crtc_id, fb_handle, flags) -> (seqno).
RedoxFenceEventfdWire models drivers/gpu/drm/drm_syncobj.c::
drm_syncobj_wait_ioctl. Fence-eventfd
wire (seqno, timeout_ns). The kernel
watches the CS ring and writes 1 byte
to a userland-supplied eventfd.
RedoxCreateContextWire models drivers/gpu/drm/i915/
i915_gem_context.c. Per-process
context handle (client_handle -> context_id)
so multiple pipe_contexts can submit CS
independently.
Handler functions in the impl block:
handle_scanout_flip() validates fb against active mode and
dispatches to driver.page_flip(). Updates
active_crtc_fb tracking. Pending_flip_fb
bookkeeping mirrors Linux's
drm_mode_page_flip_ioctl behaviour.
handle_fence_eventfd() non-blocking check first (replaces
Phase 4's polling fence); records (seqno,
eventfd) for completion. TODO: real async
via kernel-side epoll (matches drm_syncobj
wait_eventfd).
context_create() allocates a context_id. Per-process CS
state is needed for multi-context iris
+ radeonsi sharing the same winsys.
context_destroy() releases a context_id.
Mesa winsys-side: local/recipes/libs/mesa/source/src/gallium/winsys/redox/
redox_drm_cs.c replaces placeholder ioctl numbers 0x40/0x41
with the real REDOX_PRIVATE_CS_SUBMIT (0xBF)
and REDOX_PRIVATE_CS_WAIT (0xC0) constants,
mirrored from scheme.rs.
redox_drm_fence.c switches from the spin-loop (Phase 4) to
a proper eventfd-backed wait. The fence struct
now has an eventfd field; fence_create()
calls eventfd() and drmIoctl(REDOX_FENCE_EVENTFD).
fence_wait() uses poll(2) on the eventfd. The
eventfd itself is a synthetic stand-in until
the kernel adds epoll to the CS ring (TODO).
redox_drm_surface.c wires the surface_flush path. The TODO
(binding pipe_resource to a framebuffer, then
calling REDOX_SCANOUT_FLIP) is preserved as
the design intent. Mirrors drm_plane.c::
drm_mode_page_flip_ioctl pattern.
redox_drm_winsys.c updates flush_frontbuffer to a stub that
hooks the (screen, resource, surface) triple
for future fb-binding. Multi-context support
is added to the winsys state (next_context_id
+ contexts map).
This is a foundation commit, not a runtime-complete one. The
kernel handlers do basic validation and dispatch; the userland
fence works for the first eventfd wakeup; the surface_flush
waits on the next Phase for pipe_resource→fb_id binding in the
kernel.
Cross-reference: All wire types and handler comments cite
the specific Linux 7.1 source file being ported. Per the AGENTS
rule, these are necessary for cross-reference documentation.
The kernel ABI extension plus winsys update closes Phase 5 of
local/docs/3D-DRIVER-PLAN.md. The remaining work is:
- bind pipe_resource to a framebuffer in the kernel
- real eventfd wakeup (epoll on the CS ring)
- multi-context CS dispatch
- radeonsi SDMA + VM paging (Phase 6+)
- iris full i915 batch buffer path (Phase 6+)
The Redox gallium winsys (src/gallium/winsys/redox/drm/) is built
but not wired into the build system. This commit adds the necessary
entries in src/gallium/meson.build so the winsys symbols are
exported when targeting Redox:
1. sym_config: add 'redox_drm_winsys_create' to the foreach
loop alongside radeon_drm_winsys_create, amdgpu_winsys_create,
etc. The winsys_create symbol is now exported whenever iris or
radeonsi are enabled (both drivers can use this winsys).
2. subdir: add a new conditional block that builds the winsys
directory when with_platform_redox is true AND either iris or
radeonsi is enabled. This avoids building the winsys on
non-Redox targets where libdrm's redox patch isn't present.
The meson.build file itself is a new file — it was missing from
HEAD. The upstream Mesa source tree has a top-level meson.build in
src/gallium/ that orchestrates the subdirectory builds. This commit
adds it.
Build verification:
- meson setup with -Dplatforms=wayland,redox
-Dgallium-drivers=iris,radeonsi succeeds through the winsys
configuration (libclc and LLVMSPIRVLib are separate blockers
that don't affect this winsys wiring).
- The redox_drm_winsys module is added to the build for both iris
and radeonsi on the Redox target.
This completes Phase 4 of local/docs/3D-DRIVER-PLAN.md. The
remaining work (Phase 5 + 7) is kernel ABI expansion for surface
flip and hardware-specific command submission paths.
Updates the canonical planning authority for the driver-manager migration
to v4.6, which adds three contract tests for linux-kpi's
pci_register_error_handler (env-missing, malformed-fd, double-register).
The 'Driver-level Driver::on_error adoption' item is now annotated
as a follow-up for the redbear-iwlwifi Rust port rather than an
active v4.6 task — the Wi-Fi Rust port is in-progress and adopting
now risks destabilizing that work. The infrastructure (linux-kpi
function + wire protocol + manager-side consultation) is fully
ready; the C side just needs a real daemon to call
pci_register_error_handler once the Rust port lands.
Status table: no v4.0 P3 items remain. The remaining open items
(hardware validation matrix, two-week soak) are operator-only
gates and explicitly noted as such.
Last reviewed line updated to 2026-07-24 (v4.6).
The Redox EGL platform was in-tree from a prior session (the
egldisplay.h enum entry, eglapi.c dispatch, egl_dri2.c case,
meson.build / meson.options / src/egl/meson.build wiring,
recipe.toml platforms list). This commit closes the remaining
gaps so the platform actually builds.
What was missing / what this fixes:
1. dri2_initialize_redox prototype was not declared in
egl_dri2.h. The function definition in platform_redox.c
produced a -Werror=missing-prototypes error when the dispatch
case in egl_dri2.c tried to call it. Added the prototype
under HAVE_REDOX_PLATFORM.
2. platform_redox.c used the old Mesa API names
(__DRIdrawable, flush_get_images, use_invalidate) that
were renamed/removed in Mesa 26.1.4. The codebase is a
2022-era RedoxOS fork updated to a 26.1.4-shaped tree, so
the platform needed to follow the new API:
- __DRIdrawable -> struct dri_drawable
- removed flush_get_images / image_get_buffers from
dri2_egl_display_vtbl (the vtbl no longer has them)
- removed use_invalidate from loader_extensions arrays
(it was removed from the extension set)
- dri2_load_driver_dri3 -> not in current API; the driver
is loaded automatically by dri2_create_screen() when
dri2_dpy->driver_name and dri2_dpy->loader_extensions
are set. Added a comment explaining the removal so the
next maintainer doesn't re-add it.
- dri2_setup_extensions -> removed in 26.1.4; the equivalent
is dri2_setup_screen which is called from
dri2_initialize_<platform>(). Removed the call.
3. image_loader_extensions[] is now declared with
__attribute__((unused)). The redox_image_loader_extension
is referenced directly in swrast_loader_extensions, so the
array as a top-level symbol is unused. Kept for future
expansion (e.g. hardware image loading) where the array
might be reused.
Build verified: 'meson setup' succeeds with the
existing patches applied; 'ninja src/egl/libEGL_mesa.so.0.0.0'
links cleanly with the redox platform included. dri2_initialize_redox
is a local symbol inside libEGL_mesa.so, called from
dri2_initialize() in egl_dri2.c via the _EGL_PLATFORM_REDOX case.
Runtime path (untested in this session):
EGL_PLATFORM=redox -> _eglGetRedoxDisplay() -> _eglFindDisplay()
-> eglInitialize() -> dri2_initialize_redox() ->
redox_probe_device_hw() opens /scheme/drm/card0, calls
loader_get_driver_for_fd which is intercepted by libdrm's
redox.patch to redirect to scheme:drm, returns a driver
name, dri2_dpy->driver_name is set, dri2_create_screen() loads
it. Falls back to swrast when no DRM device is present.
What this commit does NOT do:
- The dri_image_back / dri_image_front fields in
dri2_egl_surface are NOT added. The basic pbuffer +
front-buffer path works without them. Hardware-backed
image rendering would need them (deferred to follow-up).
- iris / radeonsi runtime: not affected by this commit; the
winsys gap remains. But with the Redox EGL platform in
place, EGL_PLATFORM=redox now resolves to a real platform
(not an undefined-platform error), and the runtime can
begin the work of building a Redox winsys for the gallium
hardware drivers.
The previously-orphaned patches 03 (platform-redox-gpu-probe)
and 06 (redox-surface-image-fields) in local/patches/mesa/
remain as historical record but are no longer needed (their
work is now in-tree). A follow-up commit can move them to
local/patches/legacy-superseded-2026-07-12/mesa/ to clean up
the patch archive.
The relibc-consumer ABI sweep looped over the whole shared repo/*.pkgar, so a
redbear-mini build invalidated (deleted) redbear-full-only packages -- the entire
Qt/mesa/sddm/greeter stack -- just because their pkgars were older than
relibc.pkgar. Building mini now resolves the config package closure via
`repo push-tree --filesystem` and only invalidates packages inside it. Build
mini, touch mini; full artifacts are never collateral. No env flag needed for
the common case.