kmsro: look for graphics capable screen as renderonly device

Exposing a rendernode from a supported driver is not a sufficient
matching criteria to qualify as the render part of a renderonly
device, as the rendernode might only expose compute or 2D accel
capabilities.

Look for a screen that actually supports gallium graphics operations
to qualify as a renderonly screen.

v2 (Tomeu): Have pipe-loader return a list of FDs for kmsro to choose
            based on capabilities.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30096>
This commit is contained in:
Lucas Stach 2025-02-10 13:10:43 +01:00 committed by Marge Bot
parent cfad6fb037
commit 7e76c67632
5 changed files with 145 additions and 62 deletions

View file

@ -234,6 +234,15 @@ pipe_loader_drm_zink_probe(struct pipe_loader_device **devs, int ndev);
int
pipe_loader_get_compatible_render_capable_device_fd(int kms_only_fd);
/**
* Get the fds of render-capable devices compatible with a given display-only
* device fd.
*
* Caller must close the returned fds and free the array.
*/
int *
pipe_loader_get_compatible_render_capable_device_fds(int kms_only_fd, unsigned int *n_devices);
/**
* Initialize a DRM device in an already opened fd.
*

View file

@ -309,6 +309,24 @@ pipe_loader_drm_release(struct pipe_loader_device **dev)
int
pipe_loader_get_compatible_render_capable_device_fd(int kms_only_fd)
{
unsigned int n_devices = 0;
int result = -1;
int *gpu_fds = pipe_loader_get_compatible_render_capable_device_fds(kms_only_fd, &n_devices);
if (n_devices > 0) {
result = gpu_fds[0];
for(unsigned int i = 1; i < n_devices; i++)
close(gpu_fds[i]);
}
free(gpu_fds);
return result;
}
int *
pipe_loader_get_compatible_render_capable_device_fds(int kms_only_fd, unsigned int *n_devices)
{
bool is_platform_device;
struct pipe_loader_device *dev;
@ -335,22 +353,22 @@ pipe_loader_get_compatible_render_capable_device_fd(int kms_only_fd)
};
if (!pipe_loader_drm_probe_fd(&dev, kms_only_fd, false))
return -1;
return NULL;
is_platform_device = (dev->type == PIPE_LOADER_DEVICE_PLATFORM);
pipe_loader_release(&dev, 1);
/* For display-only devices that are not on the platform bus, we can't assume
* that any of the rendering devices are compatible. */
if (!is_platform_device)
return -1;
return NULL;
/* For platform display-only devices, we try to find a render-capable device
* on the platform bus and that should be compatible with the display-only
* device. */
if (ARRAY_SIZE(drivers) == 0)
return -1;
return NULL;
return loader_open_render_node_platform_device(drivers, ARRAY_SIZE(drivers));
return loader_open_render_node_platform_devices(drivers, ARRAY_SIZE(drivers), n_devices);
}
static const struct driOptionDescription *

View file

@ -56,74 +56,94 @@ struct pipe_screen *kmsro_drm_screen_create(int kms_fd,
const struct pipe_screen_config *config)
{
struct pipe_screen *screen = NULL;
struct renderonly *ro = CALLOC_STRUCT(renderonly);
char *render_dev_name = NULL;
int *gpu_fds = NULL;
unsigned int n_devices = 0;
if (!ro)
return NULL;
ro->kms_fd = kms_fd;
ro->gpu_fd = pipe_loader_get_compatible_render_capable_device_fd(kms_fd);
if (ro->gpu_fd < 0) {
FREE(ro);
return NULL;
gpu_fds = pipe_loader_get_compatible_render_capable_device_fds(kms_fd, &n_devices);
if (n_devices == 0) {
goto out;
}
render_dev_name = loader_get_kernel_driver_name(ro->gpu_fd);
if (!render_dev_name) {
close(ro->gpu_fd);
FREE(ro);
return NULL;
}
for (unsigned int i = 0; i < n_devices; i++) {
struct renderonly *ro = CALLOC_STRUCT(renderonly);
ro->destroy = kmsro_ro_destroy;
util_sparse_array_init(&ro->bo_map, sizeof(struct renderonly_scanout), 64);
simple_mtx_init(&ro->bo_map_lock, mtx_plain);
if (!ro)
goto out;
if (strcmp(render_dev_name, "asahi") == 0) {
ro->kms_fd = kms_fd;
ro->gpu_fd = dup(gpu_fds[i]);
render_dev_name = loader_get_kernel_driver_name(ro->gpu_fd);
if (!render_dev_name) {
close(ro->gpu_fd);
FREE(ro);
goto out;
}
ro->destroy = kmsro_ro_destroy;
util_sparse_array_init(&ro->bo_map, sizeof(struct renderonly_scanout), 64);
simple_mtx_init(&ro->bo_map_lock, mtx_plain);
if (strcmp(render_dev_name, "asahi") == 0) {
#if defined(GALLIUM_ASAHI)
ro->create_for_resource = renderonly_create_gpu_import_for_resource;
screen = asahi_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
ro->create_for_resource = renderonly_create_gpu_import_for_resource;
screen = asahi_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
#endif
}
else if (strcmp(render_dev_name, "etnaviv") == 0) {
}
else if (strcmp(render_dev_name, "etnaviv") == 0) {
#if defined(GALLIUM_ETNAVIV)
ro->create_for_resource = renderonly_create_kms_dumb_buffer_for_resource;
screen = etna_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
ro->create_for_resource = renderonly_create_kms_dumb_buffer_for_resource;
screen = etna_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
#endif
} else if (strcmp(render_dev_name, "msm") == 0) {
} else if (strcmp(render_dev_name, "msm") == 0) {
#if defined(GALLIUM_FREEDRENO)
ro->create_for_resource = renderonly_create_kms_dumb_buffer_for_resource;
screen = fd_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
ro->create_for_resource = renderonly_create_kms_dumb_buffer_for_resource;
screen = fd_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
#endif
} else if (strcmp(render_dev_name, "lima") == 0) {
} else if (strcmp(render_dev_name, "lima") == 0) {
#if defined(GALLIUM_LIMA)
ro->create_for_resource = renderonly_create_kms_dumb_buffer_for_resource;
screen = lima_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
ro->create_for_resource = renderonly_create_kms_dumb_buffer_for_resource;
screen = lima_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
#endif
} else if (strcmp(render_dev_name, "panfrost") == 0 ||
strcmp(render_dev_name, "panthor") == 0) {
} else if (strcmp(render_dev_name, "panfrost") == 0 ||
strcmp(render_dev_name, "panthor") == 0) {
#if defined(GALLIUM_PANFROST)
ro->create_for_resource = panfrost_create_kms_dumb_buffer_for_resource;
screen = panfrost_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
ro->create_for_resource = panfrost_create_kms_dumb_buffer_for_resource;
screen = panfrost_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
#endif
} else if (strcmp(render_dev_name, "v3d") == 0) {
} else if (strcmp(render_dev_name, "v3d") == 0) {
#if defined(GALLIUM_V3D)
ro->create_for_resource = renderonly_create_kms_dumb_buffer_for_resource;
screen = v3d_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
ro->create_for_resource = renderonly_create_kms_dumb_buffer_for_resource;
screen = v3d_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
#endif
} else if (strcmp(render_dev_name, "vc4") == 0) {
} else if (strcmp(render_dev_name, "vc4") == 0) {
#if defined(GALLIUM_VC4)
/* Passes the vc4-allocated BO through to the KMS-only DRM device using
* PRIME buffer sharing. The VC4 BO must be linear, which the SCANOUT
* flag on allocation will have ensured.
*/
ro->create_for_resource = renderonly_create_gpu_import_for_resource;
screen = vc4_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
/* Passes the vc4-allocated BO through to the KMS-only DRM device using
* PRIME buffer sharing. The VC4 BO must be linear, which the SCANOUT
* flag on allocation will have ensured.
*/
ro->create_for_resource = renderonly_create_gpu_import_for_resource;
screen = vc4_drm_screen_create_renderonly(ro->gpu_fd, ro, config);
#endif
}
free(render_dev_name);
/* test if the screen is actually graphics render capable */
if (screen) {
if (screen->caps.graphics)
goto out;
else {
screen->destroy(screen);
screen = NULL;
}
}
}
free(render_dev_name);
out:
for (unsigned int i = 0; i < n_devices; i++)
close(gpu_fds[i]);
free(gpu_fds);
return screen;
}

View file

@ -173,16 +173,46 @@ nouveau_zink_predicate(int fd, const char *driver)
int
loader_open_render_node_platform_device(const char * const drivers[],
unsigned int n_drivers)
{
unsigned int n_devices;
int *fds = loader_open_render_node_platform_devices(drivers, n_drivers, &n_devices);
int fd = -1;
if (n_devices > 0) {
fd = fds[0];
free(fds);
}
return fd;
}
/**
* Goes through all the platform devices whose driver is on the given list and
* try to open their render node. It returns an array with the fds of all the
* devices that it can open.
*
* Caller must close the returned fds and free the array.
*/
int *
loader_open_render_node_platform_devices(const char * const drivers[],
unsigned int n_drivers,
unsigned int *n_devices)
{
drmDevicePtr devices[MAX_DRM_DEVICES], device;
int num_devices, fd = -1;
int i, j;
bool found = false;
int *result;
num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
if (num_devices <= 0)
return -ENOENT;
if (num_devices <= 0) {
*n_devices = 0;
return NULL;
}
result = calloc(n_drivers, num_devices);
*n_devices = 0;
for (i = 0; i < num_devices; i++) {
device = devices[i];
@ -206,22 +236,23 @@ loader_open_render_node_platform_device(const char * const drivers[],
break;
}
}
if (!found) {
drmFreeVersion(version);
close(fd);
continue;
}
drmFreeVersion(version);
break;
if (found)
result[(*n_devices)++] = fd;
else
close(fd);
}
}
drmFreeDevices(devices, num_devices);
if (i == num_devices)
return -ENOENT;
if (*n_devices == 0) {
free(result);
return NULL;
}
return fd;
return result;
}
bool

View file

@ -48,6 +48,11 @@ int
loader_open_render_node_platform_device(const char * const drivers[],
unsigned int n_drivers);
int *
loader_open_render_node_platform_devices(const char * const drivers[],
unsigned int n_drivers,
unsigned int *n_devices);
bool
loader_is_device_render_capable(int fd);