diff --git a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_bo.c b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_bo.c index 2285ee2a04..13cdd0ab5c 100644 --- a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_bo.c +++ b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_bo.c @@ -122,6 +122,8 @@ redox_drm_bo_create(struct redox_drm_winsys *rws, bo->base = *templat; bo->gem_handle = handle; + bo->fb_id = 0; + bo->stride = 0; bo->size = templat->width0; bo->map_ptr = NULL; @@ -171,3 +173,58 @@ redox_drm_bo_unmap(struct redox_drm_winsys *rws, munmap(bo->map_ptr, (size_t)bo->size); bo->map_ptr = NULL; } + +/* Wire struct that matches the kernel's DrmAddFbWire. The kernel's + * scheme.rs defines this struct as #[repr(C)]. + */ +struct DrmAddFbWire { + uint32_t height; + uint32_t width; + uint32_t bpp; + uint32_t flags; + uint32_t pitch; + uint64_t size; + uint32_t handle; + uint32_t fb_id; + uint32_t pad; +}; + +uint32_t +redox_drm_bo_get_fb(struct redox_drm_winsys *rws, + struct pipe_resource *pr, + uint32_t *out_stride) +{ + struct redox_drm_bo *bo = (struct redox_drm_bo *)pr; + struct DrmAddFbWire req = {0}; + int err; + + if (bo->fb_id != 0) { + if (out_stride) + *out_stride = bo->stride; + return bo->fb_id; + } + + req.handle = bo->gem_handle; + req.width = (uint32_t)bo->base.width0; + req.height = (uint32_t)bo->base.height0; + req.bpp = 32; + /* pitch = width * 4 (32-bit RGBA) — matches drm_mode_addfb's + * alignment behaviour when the userland supplies 0. The kernel + * recomputes if pitch is 0. + */ + req.pitch = req.width * 4; + + err = drmIoctl(rws->fd, /* DRM_IOCTL_MODE_ADDFB = 0xB5 (DRM_IOCTL_BASE+21) */ + 0xB5, &req); + if (err != 0) { + debug_printf("redox: ADDFB failed for handle=%u: errno=%d (%s)\n", + req.handle, errno, strerror(errno)); + return 0; + } + + bo->fb_id = req.fb_id; + bo->stride = req.pitch; + if (out_stride) + *out_stride = bo->stride; + return bo->fb_id; +} diff --git a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_bo.h b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_bo.h index 37ae188968..75da4d8fa5 100644 --- a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_bo.h +++ b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_bo.h @@ -27,6 +27,13 @@ struct redox_drm_winsys; struct redox_drm_bo { struct pipe_resource base; uint32_t gem_handle; + /* Cached framebuffer id from the kernel's ADDFB ioctl. 0 if no + * framebuffer has been created yet. The winsys creates the fb on + * first use (from flush_frontbuffer) and reuses it across flips. + */ + uint32_t fb_id; + /* Cached stride for ADDFB. 0 if not yet computed. */ + uint32_t stride; /* If the user has called resource_map, this is the mmap'd pointer. * NULL otherwise. The user must call resource_unmap to release. */ @@ -52,4 +59,17 @@ void redox_drm_bo_unmap(struct redox_drm_winsys *rws, struct pipe_resource *pr); +/* Create a kernel-side framebuffer object (ADDFB) for the BO. The + * first call sets up the cached fb_id and stride on the BO; subsequent + * calls return the cached values. On failure returns 0. + * + * Models Linux 7.1's drm_mode_addfb_ioctl (drivers/gpu/drm/drm_ioctl.c) + * and the winsys-side pattern used by radeon_drm_bo in + * src/gallium/winsys/radeon/drm/radeon_drm_bo.c. + */ +uint32_t +redox_drm_bo_get_fb(struct redox_drm_winsys *rws, + struct pipe_resource *pr, + uint32_t *out_stride); + #endif /* REDOX_DRM_BO_H */ diff --git a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_surface.c b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_surface.c index 43cd5758fc..1189d566e1 100644 --- a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_surface.c +++ b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_surface.c @@ -6,13 +6,14 @@ * model mirrors drivers/gpu/drm/drm_plane.c::drm_mode_page_flip_ioctl * (Linux 7.1): the userland caller hands the kernel a framebuffer * handle, the kernel programs the display device, and returns the - * CS seqno at which the flip will complete. + * CS seqno at which the flip completes. * * SPDX-License-Identifier: MIT */ #include "redox_drm_surface.h" #include "redox_drm_winsys.h" +#include "redox_drm_bo.h" #include "pipe/p_state.h" @@ -65,3 +66,55 @@ redox_drm_destroy_surface(struct pipe_surface *ps) FREE(surf); } + +/* Wire struct that matches the kernel's RedoxScanoutFlipWire. + * The struct is #[repr(C)] on the kernel side (scheme.rs). + */ +struct RedoxScanoutFlipWire { + uint32_t crtc_id; + uint32_t fb_handle; + uint32_t flags; + uint32_t pad; + uint64_t seqno; +}; + +/* Wire the winsys to the kernel ADDFB and SCANOUT_FLIP ioctls. + * On a pipe_resource bound to a framebuffer, this: + * 1. Lazily creates the kernel-side framebuffer via ADDFB + * (cached on the redox_drm_bo struct). + * 2. Issues REDOX_SCANOUT_FLIP and stashes the resulting seqno. + * + * Models i915_display.c::i9xx_queue_flip + the gallium + * radeon_drm_bo approach. + */ +uint64_t +redox_drm_bo_flip_to_crtc(struct redox_drm_winsys *rws, + uint32_t crtc_id, + struct pipe_resource *fb) +{ + struct redox_drm_bo *bo = (struct redox_drm_bo *)fb; + struct RedoxScanoutFlipWire req = {0}; + int err; + + if (!rws || !bo) + return 0; + + uint32_t fb_id = redox_drm_bo_get_fb(rws, fb, NULL); + if (!fb_id) { + debug_printf("redox: ADDFB failed for resource, cannot flip\n"); + return 0; + } + + req.crtc_id = crtc_id; + req.fb_handle = fb_id; + req.flags = 0; + + err = drmIoctl(rws->fd, REDOX_DRM_IOCTL_SCANOUT_FLIP, &req); + if (err != 0) { + debug_printf("redox: SCANOUT_FLIP failed for crtc=%u fb=%u: errno=%d (%s)\n", + crtc_id, fb_id, errno, strerror(errno)); + return 0; + } + + return req.seqno; +} diff --git a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_surface.h b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_surface.h index 7d15a88224..b465e58048 100644 --- a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_surface.h +++ b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_surface.h @@ -39,4 +39,14 @@ redox_drm_create_surface(struct pipe_screen *screen, void redox_drm_destroy_surface(struct pipe_surface *ps); +/* Per-resource flush that wires the BO through ADDFB (cached) and + * REDOX_SCANOUT_FLIP. Returns the kernel-assigned CS seqno on + * success, 0 on failure. The fence is created by the caller using + * redox_drm_fence_create(seqno) which polls the same ring. + */ +uint64_t +redox_drm_bo_flip_to_crtc(struct redox_drm_winsys *rws, + uint32_t crtc_id, + struct pipe_resource *fb); + #endif /* REDOX_DRM_SURFACE_H */ diff --git a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_winsys.c b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_winsys.c index 209d2c1bea..72d4ac3761 100644 --- a/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_winsys.c +++ b/local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/redox_drm_winsys.c @@ -147,15 +147,42 @@ redox_flush_frontbuffer(struct pipe_screen *screen, struct pipe_box *subbox) { struct redox_drm_winsys *rws = (struct redox_drm_winsys *)screen->winsys_priv; + uint32_t crtc_id; - (void) ctx; (void) resource; (void) level; (void) layer; - (void) winsys_drawable_handle; (void) nboxes; (void) subbox; + (void) ctx; (void) level; (void) layer; (void) nboxes; (void) subbox; - /* TODO: bind pipe_resource to a framebuffer, then call - * REDOX_SCANOUT_FLIP. Mirrors i915_display.c::i9xx_queue_flip. - */ - if (!rws) + if (!rws || !resource) return; + + /* winsys_drawable_handle is the pipe_surface's internal id; we + * don't have a pipe_surface->crtc_id mapping yet. For now, the + * Mesa frontend is expected to set up the surface on CRTC 0; a + * later commit will plumb per-surface crtc_id through pipe_surface. + */ + crtc_id = 0; + + /* Lazily create the kernel-side framebuffer (ADDFB) and submit + * the scanout flip (SCANOUT_FLIP). Returns the CS seqno; the + * caller is expected to track this in a fence. + * + * Models drm_plane.c::drm_mode_page_flip_ioctl + radeon_drm_bo + * + i915_display.c::i9xx_queue_flip. + */ + uint64_t seqno = redox_drm_bo_flip_to_crtc(rws, crtc_id, resource); + if (seqno == 0) { + /* SCANOUT_FLIP failed; the caller's fence will never signal. + * The flush isn't fatal — Mesa will continue normally — but + * the user will see a black scanout. Logged for diagnosis. + */ + debug_printf("redox: SCANOUT_FLIP failed; scanout will be blank\n"); + return; + } + + /* Update the winsys's last_submitted_seqno so the fence module + * can poll for completion. + */ + if (rws->cs && seqno > rws->cs->last_seqno) + rws->cs->last_seqno = seqno; } static struct pipe_fence_handle *