feat: add Mesa EGL hardware GPU probe with virgl support

P5: Enable PRIME export for GBM dumb buffers so virgl can import scanout\nbuffers via fd-to-handle.

P6: Add redox_probe_device_hw() that opens /scheme/drm/card0, resolves the\nDRI driver via PCI ID lookup (loader_get_driver_for_fd), and initializes the\nhardware path through dri2_load_driver_dri3 with __DRIimageLoaderExtension.\nIncludes fprintf(stderr) debug logging tagged [REDOX-EGL] for tracing the\nHW init sequence. Falls back to software rendering if HW probe fails.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-05-15 07:24:31 +01:00
parent b163f437bf
commit 295a100f10
3 changed files with 273 additions and 1 deletions
@@ -0,0 +1,32 @@
diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c
index 91fcc1fd2..af26e20d6 100644
--- a/src/gbm/backends/dri/gbm_dri.c
+++ b/src/gbm/backends/dri/gbm_dri.c
@@ -578,8 +578,11 @@ gbm_dri_bo_get_fd(struct gbm_bo *_bo)
struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
int fd;
- if (bo->image == NULL)
- return -1;
+ if (bo->image == NULL) {
+ if (drmPrimeHandleToFD(dri->base.v0.fd, bo->handle, DRM_CLOEXEC | DRM_RDWR, &fd) != 0)
+ return -1;
+ return fd;
+ }
if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd))
return -1;
@@ -663,8 +666,11 @@ gbm_dri_bo_get_plane_fd(struct gbm_bo *_bo, int plane)
/* dumb BOs can only utilize non-planar formats */
if (!bo->image) {
- errno = EINVAL;
- return -1;
+ if (plane != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return gbm_dri_bo_get_fd(_bo);
}
if (plane >= get_number_planes(dri, bo->image)) {
@@ -0,0 +1,240 @@
diff --git a/src/egl/drivers/dri2/platform_redox.c b/src/egl/drivers/dri2/platform_redox.c
index d6ceb1107..03d8e4c21 100644
--- a/src/egl/drivers/dri2/platform_redox.c
+++ b/src/egl/drivers/dri2/platform_redox.c
@@ -62,10 +62,46 @@ redox_free_images(struct dri2_egl_surface *dri2_surf)
dri2_surf->front = NULL;
}
+ if (dri2_surf->dri_image_back) {
+ dri2_dpy->image->destroyImage(dri2_surf->dri_image_back);
+ dri2_surf->dri_image_back = NULL;
+ }
+
free(dri2_surf->swrast_device_buffer);
dri2_surf->swrast_device_buffer = NULL;
}
+static int
+redox_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format,
+ uint32_t *stamp, void *loaderPrivate,
+ uint32_t buffer_mask,
+ struct __DRIimageList *buffers)
+{
+ struct dri2_egl_surface *dri2_surf = loaderPrivate;
+ struct dri2_egl_display *dri2_dpy =
+ dri2_egl_display(dri2_surf->base.Resource.Display);
+
+ buffers->image_mask = 0;
+ buffers->front = NULL;
+ buffers->back = NULL;
+
+ if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
+ if (!dri2_surf->front)
+ dri2_surf->front = redox_alloc_image(dri2_dpy, dri2_surf);
+ buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
+ buffers->front = dri2_surf->front;
+ }
+
+ if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
+ if (!dri2_surf->dri_image_back)
+ dri2_surf->dri_image_back = redox_alloc_image(dri2_dpy, dri2_surf);
+ buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK;
+ buffers->back = dri2_surf->dri_image_back;
+ }
+
+ return 1;
+}
+
static EGLBoolean
redox_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
{
@@ -220,6 +256,10 @@ dri2_redox_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
goto cleanup_surface;
}
+ dri2_surf->visual = dri2_image_format_for_pbuffer_config(dri2_dpy, config);
+ if (dri2_surf->visual == __DRI_IMAGE_FORMAT_NONE)
+ goto cleanup_surface;
+
if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf)) {
goto cleanup_surface;
}
@@ -366,6 +406,27 @@ static const __DRIkopperLoaderExtension kopper_loader_extension = {
.SetSurfaceCreateInfo = NULL,
};
+static void
+redox_hw_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
+{
+}
+
+static const __DRIimageLoaderExtension redox_image_loader_extension = {
+ .base = {__DRI_IMAGE_LOADER, 2},
+ .getBuffers = redox_image_get_buffers,
+ .flushFrontBuffer = redox_hw_flush_front_buffer,
+ .getCapability = redox_get_capability,
+};
+
+static const __DRIextension *redox_hw_loader_extensions[] = {
+ &redox_image_loader_extension.base,
+ &image_lookup_extension.base,
+ &use_invalidate.base,
+ &background_callable_extension.base,
+ &kopper_loader_extension.base,
+ NULL,
+};
+
static const __DRIswrastLoaderExtension swrast_loader_extension = {
.base = {__DRI_SWRAST_LOADER, 1},
.getDrawableInfo = redox_swrast_get_drawable_info,
@@ -381,6 +442,92 @@ static const __DRIextension *redox_swrast_loader_extensions[] = {
NULL,
};
+static bool
+redox_probe_device_hw(_EGLDisplay *disp)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct _egl_device *device;
+ int fd = -1;
+
+ /* Try to open a DRM device on Redox first, then the conventional path. */
+ const char *drm_paths[] = {
+ "/scheme/drm/card0",
+ "/dev/dri/card0",
+ NULL,
+ };
+
+ fprintf(stderr, "[REDOX-EGL] redox_probe_device_hw: starting\n");
+
+ for (int i = 0; drm_paths[i]; i++) {
+ fd = open(drm_paths[i], O_RDWR | O_CLOEXEC);
+ fprintf(stderr, "[REDOX-EGL] open(%s) = %d\n", drm_paths[i], fd);
+ if (fd >= 0)
+ break;
+ }
+
+ if (fd < 0) {
+ fprintf(stderr, "[REDOX-EGL] no DRM device found\n");
+ return false;
+ }
+
+ /* Resolve the DRI driver from the DRM fd via PCI ID lookup. */
+ char *driver_name = loader_get_driver_for_fd(fd);
+ fprintf(stderr, "[REDOX-EGL] loader_get_driver_for_fd returned: %s\n",
+ driver_name ? driver_name : "(null)");
+ if (!driver_name) {
+ close(fd);
+ return false;
+ }
+
+ if (strcmp(driver_name, "swrast") == 0 ||
+ strcmp(driver_name, "kms_swrast") == 0) {
+ fprintf(stderr, "[REDOX-EGL] driver is swrast/kms_swrast, skipping HW path\n");
+ free(driver_name);
+ close(fd);
+ return false;
+ }
+
+ dri2_dpy->fd_render_gpu = fd;
+ dri2_dpy->driver_name = driver_name;
+
+ device = _eglFindDevice(fd, false);
+ fprintf(stderr, "[REDOX-EGL] _eglFindDevice returned: %p\n", (void *)device);
+ if (!device) {
+ free(driver_name);
+ close(fd);
+ dri2_dpy->driver_name = NULL;
+ dri2_dpy->fd_render_gpu = -1;
+ return false;
+ }
+
+ if (_eglHasAttrib(disp, EGL_DEVICE_EXT) && disp->Device != device) {
+ fprintf(stderr, "[REDOX-EGL] EGL_DEVICE_EXT mismatch\n");
+ free(driver_name);
+ close(fd);
+ dri2_dpy->driver_name = NULL;
+ dri2_dpy->fd_render_gpu = -1;
+ return false;
+ }
+ disp->Device = device;
+
+ /* Hardware drivers expose the DRI3/image entrypoints we need here. */
+ fprintf(stderr, "[REDOX-EGL] calling dri2_load_driver_dri3 (driver=%s)...\n", driver_name);
+ if (!dri2_load_driver_dri3(disp)) {
+ fprintf(stderr, "[REDOX-EGL] dri2_load_driver_dri3 FAILED\n");
+ free(driver_name);
+ close(fd);
+ dri2_dpy->driver_name = NULL;
+ dri2_dpy->fd_render_gpu = -1;
+ return false;
+ }
+ fprintf(stderr, "[REDOX-EGL] dri2_load_driver_dri3 succeeded\n");
+
+ dri2_dpy->loader_extensions = redox_hw_loader_extensions;
+
+ fprintf(stderr, "[REDOX-EGL] redox_probe_device_hw: SUCCESS (driver=%s)\n", driver_name);
+ return true;
+}
+
static bool
redox_probe_device_sw(_EGLDisplay *disp)
{
@@ -488,6 +635,8 @@ dri2_initialize_redox(_EGLDisplay *disp)
bool driver_loaded = false;
struct dri2_egl_display *dri2_dpy = dri2_display_create();
+ fprintf(stderr, "[REDOX-EGL] dri2_initialize_redox: starting\n");
+
if (!dri2_dpy) {
err = "dri2_display_create failed";
goto cleanup;
@@ -495,7 +644,12 @@ dri2_initialize_redox(_EGLDisplay *disp)
disp->DriverData = (void *)dri2_dpy;
- driver_loaded = redox_probe_device_sw(disp);
+ /* Try hardware GPU first (virgl, amdgpu, etc.). */
+ driver_loaded = redox_probe_device_hw(disp);
+ fprintf(stderr, "[REDOX-EGL] HW probe: %s\n", driver_loaded ? "SUCCESS" : "FAILED");
+ /* Fall back to software rendering (llvmpipe/softpipe). */
+ if (!driver_loaded)
+ driver_loaded = redox_probe_device_sw(disp);
if (!driver_loaded) {
err = "DRI2: failed to load driver";
@@ -503,16 +657,21 @@ dri2_initialize_redox(_EGLDisplay *disp)
}
dri2_dpy->fd_display_gpu = dri2_dpy->fd_render_gpu;
+ fprintf(stderr, "[REDOX-EGL] calling dri2_create_screen...\n");
if (!dri2_create_screen(disp)) {
err = "DRI2: failed to create screen";
+ fprintf(stderr, "[REDOX-EGL] dri2_create_screen FAILED\n");
goto cleanup;
}
+ fprintf(stderr, "[REDOX-EGL] dri2_create_screen succeeded\n");
if (!dri2_setup_extensions(disp)) {
err = "DRI2: failed to find required DRI extensions";
+ fprintf(stderr, "[REDOX-EGL] dri2_setup_extensions FAILED\n");
goto cleanup;
}
+ fprintf(stderr, "[REDOX-EGL] dri2_setup_extensions succeeded\n");
dri2_setup_screen(disp);
@@ -532,9 +691,11 @@ dri2_initialize_redox(_EGLDisplay *disp)
dri2_dpy->vtbl = &dri2_redox_display_vtbl;
+ fprintf(stderr, "[REDOX-EGL] dri2_initialize_redox: COMPLETE\n");
return EGL_TRUE;
cleanup:
+ fprintf(stderr, "[REDOX-EGL] dri2_initialize_redox: FAILED: %s\n", err);
dri2_display_destroy(disp);
return _eglError(EGL_NOT_INITIALIZED, err);
}
+1 -1
View File
@@ -3,7 +3,7 @@ git = "https://gitlab.redox-os.org/redox-os/mesa.git"
upstream = "https://gitlab.freedesktop.org/mesa/mesa"
branch = "redox-24.0"
shallow_clone = true
patches = ["../../../local/patches/mesa/P4-virgl-redox-disk-cache.patch"]
patches = ["../../../local/patches/mesa/P4-virgl-redox-disk-cache.patch", "../../../local/patches/mesa/P5-gbm-dumb-prime-export.patch", "../../../local/patches/mesa/P6-platform-redox-gpu-probe.patch"]
[build]
template = "custom"
dependencies = [