diff --git a/include/render/egl.h b/include/render/egl.h index e8b85964a..db167ec93 100644 --- a/include/render/egl.h +++ b/include/render/egl.h @@ -7,7 +7,6 @@ struct wlr_egl { EGLDisplay display; EGLContext context; EGLDeviceEXT device; // may be EGL_NO_DEVICE_EXT - struct gbm_device *gbm_device; struct { // Display extensions @@ -23,7 +22,6 @@ struct wlr_egl { // Client extensions bool EXT_device_query; - bool KHR_platform_gbm; bool EXT_platform_device; bool KHR_display_reference; } exts; diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 450d61e2d..4275c83d3 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -146,6 +146,8 @@ bool wlr_renderer_init_wl_shm(struct wlr_renderer *r, /** * Obtains the FD of the DRM device used for rendering, or -1 if unavailable. * + * The FD is guaranteed to be a DRM render node. + * * The caller doesn't have ownership of the FD, it must not close it. */ int wlr_renderer_get_drm_fd(struct wlr_renderer *r); diff --git a/render/egl.c b/render/egl.c index 8a1e6daed..d0cf8d745 100644 --- a/render/egl.c +++ b/render/egl.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -219,8 +218,6 @@ static struct wlr_egl *egl_create(void) { load_egl_proc(&egl->procs.eglGetPlatformDisplayEXT, "eglGetPlatformDisplayEXT"); - egl->exts.KHR_platform_gbm = check_egl_ext(client_exts_str, - "EGL_KHR_platform_gbm"); egl->exts.EXT_platform_device = check_egl_ext(client_exts_str, "EGL_EXT_platform_device"); egl->exts.KHR_display_reference = check_egl_ext(client_exts_str, @@ -496,28 +493,6 @@ static EGLDeviceEXT get_egl_device_from_drm_fd(struct wlr_egl *egl, return egl_device; } -static int open_render_node(int drm_fd) { - char *render_name = drmGetRenderDeviceNameFromFd(drm_fd); - if (render_name == NULL) { - // This can happen on split render/display platforms, fallback to - // primary node - render_name = drmGetPrimaryDeviceNameFromFd(drm_fd); - if (render_name == NULL) { - wlr_log_errno(WLR_ERROR, "drmGetPrimaryDeviceNameFromFd failed"); - return -1; - } - wlr_log(WLR_DEBUG, "DRM device '%s' has no render node, " - "falling back to primary node", render_name); - } - - int render_fd = open(render_name, O_RDWR | O_CLOEXEC); - if (render_fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to open DRM node '%s'", render_name); - } - free(render_name); - return render_fd; -} - struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) { struct wlr_egl *egl = egl_create(); if (egl == NULL) { @@ -525,49 +500,22 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) { return NULL; } - if (egl->exts.EXT_platform_device) { - /* - * Search for the EGL device matching the DRM fd using the - * EXT_device_enumeration extension. - */ - EGLDeviceEXT egl_device = get_egl_device_from_drm_fd(egl, drm_fd); - if (egl_device != EGL_NO_DEVICE_EXT) { - if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) { - wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_DEVICE_EXT"); - return egl; - } - goto error; - } - /* Falls back on GBM in case the device was not found */ - } else { + if (!egl->exts.EXT_platform_device) { wlr_log(WLR_DEBUG, "EXT_platform_device not supported"); + goto error; } - if (egl->exts.KHR_platform_gbm) { - int gbm_fd = open_render_node(drm_fd); - if (gbm_fd < 0) { - wlr_log(WLR_ERROR, "Failed to open DRM render node"); - goto error; - } - - egl->gbm_device = gbm_create_device(gbm_fd); - if (!egl->gbm_device) { - close(gbm_fd); - wlr_log(WLR_ERROR, "Failed to create GBM device"); - goto error; - } - - if (egl_init(egl, EGL_PLATFORM_GBM_KHR, egl->gbm_device)) { - wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_GBM_KHR"); - return egl; - } - - gbm_device_destroy(egl->gbm_device); - close(gbm_fd); - } else { - wlr_log(WLR_DEBUG, "KHR_platform_gbm not supported"); + EGLDeviceEXT egl_device = get_egl_device_from_drm_fd(egl, drm_fd); + if (egl_device == EGL_NO_DEVICE_EXT) { + goto error; } + if (!egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) { + goto error; + } + + return egl; + error: wlr_log(WLR_ERROR, "Failed to initialize EGL context"); free(egl); @@ -623,12 +571,6 @@ void wlr_egl_destroy(struct wlr_egl *egl) { eglReleaseThread(); - if (egl->gbm_device) { - int gbm_fd = gbm_device_get_fd(egl->gbm_device); - gbm_device_destroy(egl->gbm_device); - close(gbm_fd); - } - free(egl); } @@ -936,12 +878,7 @@ static char *get_render_name(const char *name) { if (match == NULL) { wlr_log(WLR_ERROR, "Cannot find DRM device %s", name); } else if (!(match->available_nodes & (1 << DRM_NODE_RENDER))) { - // Likely a split display/render setup. Pick the primary node and hope - // Mesa will open the right render node under-the-hood. - wlr_log(WLR_DEBUG, "DRM device %s has no render node, " - "falling back to primary node", name); - assert(match->available_nodes & (1 << DRM_NODE_PRIMARY)); - render_name = strdup(match->nodes[DRM_NODE_PRIMARY]); + wlr_log(WLR_ERROR, "DRM device has no render node"); } else { render_name = strdup(match->nodes[DRM_NODE_RENDER]); } diff --git a/render/meson.build b/render/meson.build index f09905c71..ae8e7455a 100644 --- a/render/meson.build +++ b/render/meson.build @@ -23,9 +23,8 @@ endif if 'gles2' in renderers or 'auto' in renderers egl = dependency('egl', required: 'gles2' in renderers) - gbm = dependency('gbm', required: 'gles2' in renderers) - if egl.found() and gbm.found() - wlr_deps += [egl, gbm] + if egl.found() + wlr_deps += egl wlr_files += files('egl.c') internal_features += { 'egl': true } endif diff --git a/render/vulkan/vulkan.c b/render/vulkan/vulkan.c index b8ba0b480..4679f9be8 100644 --- a/render/vulkan/vulkan.c +++ b/render/vulkan/vulkan.c @@ -376,32 +376,24 @@ int vulkan_open_phdev_drm_fd(VkPhysicalDevice phdev) { }; vkGetPhysicalDeviceProperties2(phdev, &props); - dev_t devid; - if (drm_props.hasRender) { - devid = makedev(drm_props.renderMajor, drm_props.renderMinor); - } else if (drm_props.hasPrimary) { - devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor); - } else { - wlr_log(WLR_ERROR, "Physical device is missing both render and primary nodes"); + if (!drm_props.hasRender) { + wlr_log(WLR_ERROR, "Physical device is missing render node"); return -1; } + dev_t devid = makedev(drm_props.renderMajor, drm_props.renderMinor); drmDevice *device = NULL; if (drmGetDeviceFromDevId(devid, 0, &device) != 0) { wlr_log_errno(WLR_ERROR, "drmGetDeviceFromDevId failed"); return -1; } - const char *name = NULL; - if (device->available_nodes & (1 << DRM_NODE_RENDER)) { - name = device->nodes[DRM_NODE_RENDER]; - } else { - assert(device->available_nodes & (1 << DRM_NODE_PRIMARY)); - name = device->nodes[DRM_NODE_PRIMARY]; - wlr_log(WLR_DEBUG, "DRM device %s has no render node, " - "falling back to primary node", name); + if (!(device->available_nodes & (1 << DRM_NODE_RENDER))) { + wlr_log(WLR_ERROR, "DRM device has no render node"); + return -1; } + const char *name = device->nodes[DRM_NODE_RENDER]; int drm_fd = open(name, O_RDWR | O_NONBLOCK | O_CLOEXEC); if (drm_fd < 0) { wlr_log_errno(WLR_ERROR, "Failed to open DRM node %s", name); diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index d4043b435..a7269134d 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -245,27 +245,42 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, return true; } -static int open_drm_render_node(void) { +static drmDevice **list_drm_devices(void) { uint32_t flags = 0; int devices_len = drmGetDevices2(flags, NULL, 0); if (devices_len < 0) { wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len)); - return -1; + return NULL; } - drmDevice **devices = calloc(devices_len, sizeof(*devices)); + drmDevice **devices = calloc(devices_len + 1, sizeof(*devices)); if (devices == NULL) { wlr_log_errno(WLR_ERROR, "Allocation failed"); - return -1; + return NULL; } devices_len = drmGetDevices2(flags, devices, devices_len); if (devices_len < 0) { free(devices); wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len)); + return NULL; + } + return devices; +} + +static void destroy_drm_devices(drmDevice **devices) { + for (size_t i = 0; devices[i] != NULL; i++) { + drmFreeDevice(&devices[i]); + } + free(devices); +} + +static int open_drm_render_node(void) { + drmDevice **devices = list_drm_devices(); + if (devices == NULL) { return -1; } int fd = -1; - for (int i = 0; i < devices_len; i++) { + for (size_t i = 0; devices[i] != NULL; i++) { drmDevice *dev = devices[i]; if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { const char *name = dev->nodes[DRM_NODE_RENDER]; @@ -283,11 +298,73 @@ static int open_drm_render_node(void) { } out: - for (int i = 0; i < devices_len; i++) { - drmFreeDevice(&devices[i]); - } - free(devices); + destroy_drm_devices(devices); + return fd; +} +static int open_backend_drm_render_node(int backend_drm_fd) { + // First, try to open the render node of the DRM device used by the backend + drmDevice *dev = NULL; + if (drmGetDevice2(backend_drm_fd, 0, &dev) != 0) { + wlr_log(WLR_ERROR, "drmGetDevice2 failed"); + return -1; + } + + if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { + const char *name = dev->nodes[DRM_NODE_RENDER]; + wlr_log(WLR_DEBUG, "Opening DRM render node '%s'", name); + int fd = open(name, O_RDWR | O_CLOEXEC); + if (fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); + } + drmFreeDevice(&dev); + return fd; + } + + if (dev->bustype != DRM_BUS_PLATFORM) { + wlr_log(WLR_ERROR, "DRM device '%s' does not have a render node", + dev->nodes[DRM_NODE_PRIMARY]); + drmFreeDevice(&dev); + return -1; + } + + drmFreeDevice(&dev); + + // Try to find another platform device with a render node + drmDevice **devices = list_drm_devices(); + if (devices == NULL) { + return -1; + } + + int fd = -1; + for (size_t i = 0; devices[i] != NULL; i++) { + drmDevice *dev = devices[i]; + if (dev->bustype != DRM_BUS_PLATFORM || + !(dev->available_nodes & (1 << DRM_NODE_RENDER))) { + continue; + } + + if (fd >= 0) { + close(fd); + fd = -1; + wlr_log(WLR_ERROR, "Found multiple platform device DRM render nodes"); + break; + } + + const char *name = dev->nodes[DRM_NODE_RENDER]; + wlr_log(WLR_DEBUG, "Opening platform device DRM render node '%s'", name); + fd = open(name, O_RDWR | O_CLOEXEC); + if (fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); + goto out_devices; + } + } + if (fd < 0) { + wlr_log(WLR_ERROR, "Failed to find any platform device DRM render node"); + } + +out_devices: + destroy_drm_devices(devices); return fd; } @@ -318,11 +395,15 @@ static bool open_preferred_drm_fd(struct wlr_backend *backend, int *drm_fd_ptr, return true; } - // Prefer the backend's DRM node, if any + // Prefer the backend's DRM device, if any int backend_drm_fd = wlr_backend_get_drm_fd(backend); if (backend_drm_fd >= 0) { - *drm_fd_ptr = backend_drm_fd; - *own_drm_fd = false; + int drm_fd = open_backend_drm_render_node(backend_drm_fd); + if (drm_fd < 0) { + return false; + } + *drm_fd_ptr = drm_fd; + *own_drm_fd = true; return true; } diff --git a/types/wlr_drm.c b/types/wlr_drm.c index a75f3042e..18e96c6a1 100644 --- a/types/wlr_drm.c +++ b/types/wlr_drm.c @@ -214,15 +214,13 @@ struct wlr_drm *wlr_drm_create(struct wl_display *display, return NULL; } - char *node_name = NULL; - if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { - node_name = strdup(dev->nodes[DRM_NODE_RENDER]); - } else { - assert(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); - wlr_log(WLR_DEBUG, "No DRM render node available, " - "falling back to primary node '%s'", dev->nodes[DRM_NODE_PRIMARY]); - node_name = strdup(dev->nodes[DRM_NODE_PRIMARY]); + if (!(dev->available_nodes & (1 << DRM_NODE_RENDER))) { + wlr_log(WLR_DEBUG, "No DRM render node available"); + drmFreeDevice(&dev); + return NULL; } + + char *node_name = strdup(dev->nodes[DRM_NODE_RENDER]); drmFreeDevice(&dev); if (node_name == NULL) { return NULL; diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index f598af18e..3c7e82d30 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -884,24 +884,20 @@ static bool set_default_feedback(struct wlr_linux_dmabuf_v1 *linux_dmabuf, goto error_compiled; } - const char *name = NULL; - if (device->available_nodes & (1 << DRM_NODE_RENDER)) { - name = device->nodes[DRM_NODE_RENDER]; - } else { - // Likely a split display/render setup - assert(device->available_nodes & (1 << DRM_NODE_PRIMARY)); - name = device->nodes[DRM_NODE_PRIMARY]; - wlr_log(WLR_DEBUG, "DRM device %s has no render node, " - "falling back to primary node", name); - } - - int main_device_fd = open(name, O_RDWR | O_CLOEXEC); - drmFreeDevice(&device); - if (main_device_fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to open DRM device %s", name); + if (!(device->available_nodes & (1 << DRM_NODE_RENDER))) { + wlr_log(WLR_DEBUG, "DRM device has no render node"); goto error_compiled; } + const char *name = device->nodes[DRM_NODE_RENDER]; + int main_device_fd = open(name, O_RDWR | O_CLOEXEC); + if (main_device_fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open DRM device %s", name); + drmFreeDevice(&device); + goto error_compiled; + } + drmFreeDevice(&device); + size_t tranches_len = feedback->tranches.size / sizeof(struct wlr_linux_dmabuf_feedback_v1_tranche); const struct wlr_linux_dmabuf_feedback_v1_tranche *tranches = feedback->tranches.data;