diff --git a/src/gallium/auxiliary/pipe-loader/pipe_loader.h b/src/gallium/auxiliary/pipe-loader/pipe_loader.h index a54679bba7a..02720b9d63f 100644 --- a/src/gallium/auxiliary/pipe-loader/pipe_loader.h +++ b/src/gallium/auxiliary/pipe-loader/pipe_loader.h @@ -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. * diff --git a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c index 985ace997bd..945c447d272 100644 --- a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c +++ b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c @@ -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 * diff --git a/src/gallium/winsys/kmsro/drm/kmsro_drm_winsys.c b/src/gallium/winsys/kmsro/drm/kmsro_drm_winsys.c index 259e876dc8b..deb847d994e 100644 --- a/src/gallium/winsys/kmsro/drm/kmsro_drm_winsys.c +++ b/src/gallium/winsys/kmsro/drm/kmsro_drm_winsys.c @@ -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; } diff --git a/src/loader/loader.c b/src/loader/loader.c index e8a9b76913a..f1ee4c04c35 100644 --- a/src/loader/loader.c +++ b/src/loader/loader.c @@ -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 diff --git a/src/loader/loader.h b/src/loader/loader.h index b3f28418f35..6748cb5269d 100644 --- a/src/loader/loader.h +++ b/src/loader/loader.h @@ -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);