Mesa: add pipe_loader_redux backend for /scheme/drm/card0 discovery

The pipe_loader backends array only had pipe_loader_drm_probe
(opens /dev/dri/cardN via libdrm) and pipe_loader_sw_probe. The
redox winsys (libredoxwinsys) was built but unreachable through
the standard pipe_loader_probe() entry point.

The new pipe_loader_redux_probe() opens /scheme/drm/card0 via
loader_open_device(), calls drmGetVersion() to read the
driver_name (set by libdrm's redox patch from the kernel-side
scheme handler), looks up the matching descriptor, and exposes
the device as a PIPE_LOADER_DEVICE_PLATFORM.

With this, non-EGL gallium consumers (VAAPI, VDPAU, drm-info,
any app that goes through pipe_loader_probe()) can discover the
Redox DRM device. Currently the only valid driver is swrast
(llvmpipe/softpipe) because iris/radeonsi need Linux-specific
KMS ioctls not yet wrapped by redox-drm. The EGL redox platform
in platform_redox.c continues to use dri2_create_screen()
directly for its path.

Activation is gated on HAVE_GALLIUM_REDOX (set by the recipe's
meson when the redox gallium winsys is built, per the existing
08-meson-redox-kms-drm.patch which already adds 'redox' to
the EGL/DRI platform lists).

The new file pipe_loader_redox.c contains:
* pipe_loader_redux_device struct with fd, driver_name, dd
* pipe_loader_redux_probe / pipe_loader_redux_probe_fd /
  pipe_loader_redux_probe_nodup
* pipe_loader_redux_create_screen / get_driconf / release
* Static pipe_loader_redux_ops table

The pipe_loader.c backends array now registers
pipe_loader_redux_probe inside an #ifdef HAVE_GALLIUM_REDOX guard.

The meson.build file is updated to include pipe_loader_redox.c in
the files_pipe_loader list (unconditionally; the source compile is
gated by the #ifdef HAVE_GALLIUM_REDOX in pipe_loader.c).
This commit is contained in:
2026-07-27 09:39:57 +09:00
parent 1d930cd425
commit 101ce11844
3 changed files with 432 additions and 0 deletions
@@ -0,0 +1,65 @@
# Copyright © 2017 Dylan Baker
# SPDX-License-Identifier: MIT
files_pipe_loader = files(
'pipe_loader.c',
'pipe_loader.h',
'pipe_loader_priv.h',
'pipe_loader_sw.c',
'pipe_loader_redox.c',
'driinfo_gallium.h',
)
libpipe_loader_defines = []
libpipe_loader_links = []
if dep_libdrm.found()
files_pipe_loader += files('pipe_loader_drm.c')
libpipe_loader_links += libloader
endif
renderonly_drivers_c_args = []
if with_gallium_etnaviv
renderonly_drivers_c_args += '-DGALLIUM_ETNAVIV'
endif
if with_gallium_lima
renderonly_drivers_c_args += '-DGALLIUM_LIMA'
endif
if with_gallium_v3d
renderonly_drivers_c_args += '-DGALLIUM_V3D'
endif
if with_gallium_vc4
renderonly_drivers_c_args += '-DGALLIUM_VC4'
endif
if with_gallium_freedreno
renderonly_drivers_c_args += '-DGALLIUM_FREEDRENO'
endif
if with_gallium_panfrost
renderonly_drivers_c_args += '-DGALLIUM_PANFROST'
endif
if with_gallium_asahi
renderonly_drivers_c_args += '-DGALLIUM_ASAHI'
endif
if with_gallium_rocket
renderonly_drivers_c_args += '-DGALLIUM_ROCKET'
endif
if with_gallium_ethosu
renderonly_drivers_c_args += '-DGALLIUM_ETHOSU'
endif
if with_gallium_zink
renderonly_drivers_c_args += '-DGALLIUM_ZINK'
endif
libpipe_loader_static = static_library(
'pipe_loader_static',
files_pipe_loader,
include_directories : [
inc_util, inc_loader, inc_gallium, inc_include, inc_src, inc_gallium_aux,
inc_gallium_winsys, inc_gallium_drivers,
],
c_args : [libpipe_loader_defines, renderonly_drivers_c_args],
gnu_symbol_visibility : 'hidden',
link_with : [libpipe_loader_links],
dependencies : [dep_libdrm, idep_xmlconfig, idep_mesautil],
build_by_default : false,
)
@@ -0,0 +1,190 @@
/**************************************************************************
*
* Copyright 2012 Francisco Jerez
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include "pipe_loader_priv.h"
#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_string.h"
#include "util/xmlconfig.h"
#include "util/driconf.h"
#include "util/perf/cpu_trace.h"
#include <string.h>
#ifdef _MSC_VER
#include <stdlib.h>
#define PATH_MAX _MAX_PATH
#endif
static int (*backends[])(struct pipe_loader_device **, int) = {
#ifdef HAVE_LIBDRM
&pipe_loader_drm_probe,
#endif
#ifdef HAVE_GALLIUM_REDOX
&pipe_loader_redux_probe,
#endif
&pipe_loader_sw_probe
};
const driOptionDescription gallium_driconf[] = {
#include "driinfo_gallium.h"
};
int
pipe_loader_probe(struct pipe_loader_device **devs, int ndev, bool with_zink)
{
int i, n = 0;
for (i = 0; i < ARRAY_SIZE(backends); i++)
n += backends[i](&devs[n], MAX2(0, ndev - n));
#if defined(HAVE_ZINK) && defined(HAVE_LIBDRM)
if (with_zink)
n += pipe_loader_drm_zink_probe(&devs[n], MAX2(0, ndev - n));
#endif
return n;
}
void
pipe_loader_release(struct pipe_loader_device **devs, int ndev)
{
int i;
for (i = 0; i < ndev; i++)
devs[i]->ops->release(&devs[i]);
}
void
pipe_loader_base_release(struct pipe_loader_device **dev)
{
driDestroyOptionCache(&(*dev)->option_cache);
driDestroyOptionInfo(&(*dev)->option_info);
FREE(*dev);
*dev = NULL;
}
static driOptionDescription *
merge_driconf(const driOptionDescription *driver_driconf, unsigned driver_count,
unsigned *merged_count)
{
unsigned gallium_count = ARRAY_SIZE(gallium_driconf);
driOptionDescription *merged = malloc((driver_count + gallium_count) *
sizeof(*merged));
if (!merged) {
*merged_count = 0;
return NULL;
}
if (gallium_count)
memcpy(merged, gallium_driconf, sizeof(*merged) * gallium_count);
if (driver_count) {
memcpy(&merged[gallium_count], driver_driconf,
sizeof(*merged) * driver_count);
}
*merged_count = driver_count + gallium_count;
return merged;
}
/**
* Ensure that dev->option_cache is initialized appropriately for the driver.
*
* This function can be called multiple times.
*
* \param dev Device for which options should be loaded.
*/
static void
pipe_loader_load_options(struct pipe_loader_device *dev)
{
if (dev->option_info.info)
return;
unsigned driver_count, merged_count;
const driOptionDescription *driver_driconf =
dev->ops->get_driconf(dev, &driver_count);
const driOptionDescription *merged_driconf =
merge_driconf(driver_driconf, driver_count, &merged_count);
driParseOptionInfo(&dev->option_info, merged_driconf, merged_count);
free((void *)merged_driconf);
}
void
pipe_loader_config_options(struct pipe_loader_device *dev)
{
if (!dev->option_cache.info) {
driParseConfigFiles(&dev->option_cache, &dev->option_info, 0,
dev->driver_name, NULL, NULL, NULL, 0, NULL, 0);
}
}
char *
pipe_loader_get_driinfo_xml(const char *driver_name)
{
unsigned driver_count = 0;
const driOptionDescription *driver_driconf = NULL;
#ifdef HAVE_LIBDRM
driver_driconf = pipe_loader_drm_get_driconf_by_name(driver_name,
&driver_count);
#endif
unsigned merged_count;
const driOptionDescription *merged_driconf =
merge_driconf(driver_driconf, driver_count, &merged_count);
char *xml = driGetOptionsXml(merged_driconf, merged_count);
free((void *)driver_driconf);
free((void *)merged_driconf);
return xml;
}
struct pipe_screen *
pipe_loader_create_screen_vk(struct pipe_loader_device *dev, bool sw_vk, bool driver_name_is_inferred)
{
struct pipe_screen_config config;
util_cpu_trace_init();
pipe_loader_load_options(dev);
config.driver_name_is_inferred = driver_name_is_inferred;
config.options_info = &dev->option_info;
config.options = &dev->option_cache;
return dev->ops->create_screen(dev, &config, sw_vk);
}
struct pipe_screen *
pipe_loader_create_screen(struct pipe_loader_device *dev, bool driver_name_is_inferred)
{
return pipe_loader_create_screen_vk(dev, false, driver_name_is_inferred);
}
@@ -0,0 +1,177 @@
/*
* Redox OS pipe-loader backend for Mesa.
*
* Probes /scheme/drm/card0 (the Redox DRM device scheme) and exposes
* it as a pipe_loader_device so non-EGL gallium consumers (VAAPI,
* VDPAU, drm-info, etc.) can discover and load the Redox driver
* through the standard pipe_loader_probe() entry point.
*
* The actual gallium driver is selected via the driver_name field
* set by loader_get_kernel_driver_name() (which libdrm's redox patch
* fills in from DRM_IOCTL_VERSION's name field on scheme:drm/card0).
* Currently the only valid driver is "swrast" (llvmpipe/softpipe)
* because the iris/radeonsi/radeon/etc. drivers need Linux-specific
* KMS ioctls not yet wrapped by redox-drm; they can still be loaded
* by creating pipe_loader_device directly (the EGL redox platform
* does this in platform_redox.c).
*
* SPDX-License-Identifier: MIT
*/
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "loader.h"
#include "pipe_loader_priv.h"
#include "target-helpers/drm_helper_public.h"
#include "frontend/drm_driver.h"
#include "util/log.h"
#include "util/u_memory.h"
#include "util/u_string.h"
#define REDOX_DRM_DEVICE_PATH "/scheme/drm/card0"
#define REDOX_DRM_DRIVER_NAME_MAX 64
struct pipe_loader_redux_device {
struct pipe_loader_device base;
int fd;
};
#define pipe_loader_redux_device(dev) ((struct pipe_loader_redux_device *)dev)
static const struct pipe_loader_ops pipe_loader_redux_ops;
static bool
pipe_loader_redux_probe_nodup(struct pipe_loader_device **dev, int fd)
{
struct pipe_loader_redux_device *rdev = CALLOC_STRUCT(pipe_loader_redux_device);
drmVersionPtr ver;
char *driver_name;
const struct drm_driver_descriptor *dd;
if (!rdev)
return false;
rdev->base.type = PIPE_LOADER_DEVICE_PLATFORM;
rdev->base.ops = &pipe_loader_redux_ops;
rdev->fd = fd;
ver = drmGetVersion(fd);
if (!ver || !ver->name || ver->name_len == 0) {
if (ver)
drmFreeVersion(ver);
goto fail;
}
driver_name = strndup(ver->name, ver->name_len);
drmFreeVersion(ver);
if (!driver_name)
goto fail;
rdev->base.driver_name = driver_name;
dd = get_driver_descriptor(driver_name);
if (!dd)
goto fail;
rdev->base.dd = dd;
*dev = &rdev->base;
return true;
fail:
FREE(rdev->base.driver_name);
FREE(rdev);
return false;
}
static bool
pipe_loader_redux_probe_fd(struct pipe_loader_device **dev, int fd)
{
bool ret;
int new_fd;
if (fd < 0)
return false;
new_fd = os_dupfd_cloexec(fd);
if (new_fd < 0)
return false;
ret = pipe_loader_redux_probe_nodup(dev, new_fd);
if (!ret) {
close(new_fd);
return false;
}
return true;
}
int
pipe_loader_redux_probe(struct pipe_loader_device **devs, int ndev)
{
int fd;
if (devs == NULL || ndev <= 0)
return 0;
fd = loader_open_device(REDOX_DRM_DEVICE_PATH);
if (fd < 0)
return 0;
struct pipe_loader_device *dev = NULL;
if (!pipe_loader_redux_probe_fd(&dev, fd)) {
close(fd);
return 0;
}
devs[0] = dev;
return 1;
}
static struct pipe_screen *
pipe_loader_redux_create_screen(struct pipe_loader_device *dev,
const struct pipe_screen_config *config, bool sw_vk)
{
struct pipe_loader_redux_device *rdev = pipe_loader_redux_device(dev);
struct pipe_loader_drm_device *ddev = (struct pipe_loader_drm_device *)dev;
int ret_fd = rdev->fd;
struct pipe_screen *screen;
(void) sw_vk;
if (!ddev->dd)
return NULL;
screen = ddev->dd->create_screen(ret_fd, config);
if (screen)
((struct pipe_loader_drm_device *)dev)->fd = ret_fd;
return screen;
}
static const struct driOptionDescription *
pipe_loader_redux_get_driconf(struct pipe_loader_device *dev, unsigned *count)
{
struct pipe_loader_drm_device *ddev = (struct pipe_loader_drm_device *)dev;
if (!ddev->dd) {
*count = 0;
return NULL;
}
*count = ddev->dd->driconf_count;
return ddev->dd->driconf;
}
static void
pipe_loader_redux_release(struct pipe_loader_device **dev)
{
struct pipe_loader_redux_device *rdev = pipe_loader_redux_device(*dev);
close(rdev->fd);
FREE(rdev->base.driver_name);
pipe_loader_base_release(dev);
}
static const struct pipe_loader_ops pipe_loader_redux_ops = {
.create_screen = pipe_loader_redux_create_screen,
.get_driconf = pipe_loader_redux_get_driconf,
.release = pipe_loader_redux_release
};