diff --git a/include/render/egl.h b/include/render/egl.h index 6a9b81dbf..34bf55303 100644 --- a/include/render/egl.h +++ b/include/render/egl.h @@ -53,11 +53,11 @@ struct wlr_egl_context { }; /** - * Initializes an EGL context for the given DRM FD. + * Initializes an EGL context for the given DRM device ID. * * Will attempt to load all possibly required API functions. */ -struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd); +struct wlr_egl *wlr_egl_create_with_drm_dev_id(dev_t dev_id); /** * Frees all related EGL resources, makes the context not-current and diff --git a/include/render/vulkan.h b/include/render/vulkan.h index f7d44e7cd..33660bfe3 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -61,9 +61,9 @@ struct wlr_vk_device { struct wlr_drm_format_set shm_texture_formats; }; -// Tries to find the VkPhysicalDevice for the given drm fd. +// Tries to find the VkPhysicalDevice for the given DRM device ID. // Might find none and return VK_NULL_HANDLE. -VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd); +VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, dev_t dev_id); bool vulkan_get_phdev_drm_dev_id(VkPhysicalDevice phdev, dev_t *dev_id); // Creates a device for the given instance and physical device. diff --git a/include/wlr/render/gles2.h b/include/wlr/render/gles2.h index 454e7eb0e..7e16f8d28 100644 --- a/include/wlr/render/gles2.h +++ b/include/wlr/render/gles2.h @@ -10,7 +10,6 @@ #define WLR_RENDER_GLES2_H #include - #include struct wlr_egl; @@ -28,7 +27,7 @@ struct wlr_egl; * render pass can't be used before the nested render pass is submitted. */ -struct wlr_renderer *wlr_gles2_renderer_create_with_drm_fd(int drm_fd); +struct wlr_renderer *wlr_gles2_renderer_create_with_drm_dev_id(dev_t dev_id); struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl); struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *renderer); diff --git a/include/wlr/render/vulkan.h b/include/wlr/render/vulkan.h index 50f8c558d..0fbf4800c 100644 --- a/include/wlr/render/vulkan.h +++ b/include/wlr/render/vulkan.h @@ -18,7 +18,7 @@ struct wlr_vk_image_attribs { VkFormat format; }; -struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd); +struct wlr_renderer *wlr_vk_renderer_create_with_drm_dev_id(dev_t dev_id); VkInstance wlr_vk_renderer_get_instance(struct wlr_renderer *renderer); VkPhysicalDevice wlr_vk_renderer_get_physical_device(struct wlr_renderer *renderer); diff --git a/render/egl.c b/render/egl.c index 9e93b5837..e77001b9a 100644 --- a/render/egl.c +++ b/render/egl.c @@ -441,8 +441,7 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform, static bool device_has_name(const drmDevice *device, const char *name); -static EGLDeviceEXT get_egl_device_from_drm_fd(struct wlr_egl *egl, - int drm_fd) { +static EGLDeviceEXT get_egl_device_from_drm_dev_id(struct wlr_egl *egl, dev_t dev_id) { if (egl->procs.eglQueryDevicesEXT == NULL) { wlr_log(WLR_DEBUG, "EGL_EXT_device_enumeration not supported"); return EGL_NO_DEVICE_EXT; @@ -469,9 +468,8 @@ static EGLDeviceEXT get_egl_device_from_drm_fd(struct wlr_egl *egl, } drmDevice *device = NULL; - int ret = drmGetDevice(drm_fd, &device); - if (ret < 0) { - wlr_log(WLR_ERROR, "Failed to get DRM device: %s", strerror(-ret)); + if (drmGetDeviceFromDevId(dev_id, 0, &device) != 0) { + wlr_log(WLR_ERROR, "drmGetDeviceFromdev_id() failed"); return EGL_NO_DEVICE_EXT; } @@ -496,29 +494,32 @@ 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); +static int open_render_node(dev_t dev_id) { + drmDevice *dev; + if (drmGetDeviceFromDevId(dev_id, 0, &dev) != 0) { + wlr_log(WLR_ERROR, "drmGetDeviceFromdev_id() failed"); + return -1; } - 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); + const char *node_name; + if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { + node_name = dev->nodes[DRM_NODE_RENDER]; + } else { + assert(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); + node_name = dev->nodes[DRM_NODE_PRIMARY]; + wlr_log(WLR_DEBUG, "No DRM render node available, " + "falling back to primary node '%s'", node_name); } - free(render_name); + + int render_fd = open(node_name, O_RDWR | O_CLOEXEC); + if (render_fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open DRM node '%s'", node_name); + } + drmFreeDevice(&dev); return render_fd; } -struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) { +struct wlr_egl *wlr_egl_create_with_drm_dev_id(dev_t dev_id) { struct wlr_egl *egl = egl_create(); if (egl == NULL) { wlr_log(WLR_ERROR, "Failed to create EGL context"); @@ -530,7 +531,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) { * 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); + EGLDeviceEXT egl_device = get_egl_device_from_drm_dev_id(egl, dev_id); 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"); @@ -544,7 +545,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) { } if (egl->exts.KHR_platform_gbm) { - int gbm_fd = open_render_node(drm_fd); + int gbm_fd = open_render_node(dev_id); if (gbm_fd < 0) { wlr_log(WLR_ERROR, "Failed to open DRM render node"); goto error; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index e3b83f625..c95dd5333 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -476,8 +476,8 @@ static void load_gl_proc(void *proc_ptr, const char *name) { *(void **)proc_ptr = proc; } -struct wlr_renderer *wlr_gles2_renderer_create_with_drm_fd(int drm_fd) { - struct wlr_egl *egl = wlr_egl_create_with_drm_fd(drm_fd); +struct wlr_renderer *wlr_gles2_renderer_create_with_drm_dev_id(dev_t dev_id) { + struct wlr_egl *egl = wlr_egl_create_with_drm_dev_id(dev_id); if (egl == NULL) { wlr_log(WLR_ERROR, "Could not initialize EGL"); return NULL; diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 79babdf9d..41a726aa5 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -2193,7 +2193,7 @@ error: return NULL; } -struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) { +struct wlr_renderer *wlr_vk_renderer_create_with_drm_dev_id(dev_t dev_id) { wlr_log(WLR_INFO, "The vulkan renderer is only experimental and " "not expected to be ready for daily use"); wlr_log(WLR_INFO, "Run with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation " @@ -2205,7 +2205,7 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) { return NULL; } - VkPhysicalDevice phdev = vulkan_find_drm_phdev(ini, drm_fd); + VkPhysicalDevice phdev = vulkan_find_drm_phdev(ini, dev_id); if (!phdev) { // We rather fail here than doing some guesswork wlr_log(WLR_ERROR, "Could not match drm and vulkan device"); diff --git a/render/vulkan/vulkan.c b/render/vulkan/vulkan.c index 1aad40853..80740aeb9 100644 --- a/render/vulkan/vulkan.c +++ b/render/vulkan/vulkan.c @@ -255,7 +255,7 @@ static void log_phdev(const VkPhysicalDeviceProperties *props) { wlr_log(WLR_INFO, " Driver version: %u.%u.%u", dv_major, dv_minor, dv_patch); } -VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd) { +VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, dev_t devid) { VkResult res; uint32_t num_phdevs; @@ -272,12 +272,6 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd) return VK_NULL_HANDLE; } - struct stat drm_stat = {0}; - if (fstat(drm_fd, &drm_stat) != 0) { - wlr_log_errno(WLR_ERROR, "fstat failed"); - return VK_NULL_HANDLE; - } - for (uint32_t i = 0; i < num_phdevs; ++i) { VkPhysicalDevice phdev = phdevs[i]; @@ -352,8 +346,7 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd) dev_t primary_devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor); dev_t render_devid = makedev(drm_props.renderMajor, drm_props.renderMinor); - if (primary_devid == drm_stat.st_rdev || - render_devid == drm_stat.st_rdev) { + if (primary_devid == devid || render_devid == devid) { wlr_log(WLR_INFO, "Found matching Vulkan physical device: %s", phdev_props.deviceName); return phdev; diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 62a1b326c..319e1ff3f 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -91,40 +91,41 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, return true; } -static int open_drm_render_node(void) { +static bool pick_drm_render_node(dev_t *dev_id) { 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 false; } drmDevice **devices = calloc(devices_len, sizeof(*devices)); if (devices == NULL) { wlr_log_errno(WLR_ERROR, "Allocation failed"); - return -1; + return false; } devices_len = drmGetDevices2(flags, devices, devices_len); if (devices_len < 0) { free(devices); wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len)); - return -1; + return false; } - int fd = -1; + bool ok = false; for (int i = 0; i < devices_len; i++) { drmDevice *dev = devices[i]; 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); - fd = open(name, O_RDWR | O_CLOEXEC); - if (fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); + wlr_log(WLR_DEBUG, "Picking DRM render node '%s'", name); + struct stat st; + if (stat(name, &st) != 0) { + wlr_log_errno(WLR_ERROR, "stat() failed for %s", name); goto out; } + *dev_id = st.st_rdev; break; } } - if (fd < 0) { + if (!ok) { wlr_log(WLR_ERROR, "Failed to find any DRM render node"); } @@ -134,15 +135,31 @@ out: } free(devices); - return fd; + return ok; } -static bool open_preferred_drm_fd(struct wlr_backend *backend, int *drm_fd_ptr, - bool *own_drm_fd) { - if (*drm_fd_ptr >= 0) { +static bool dev_id_from_fd(int fd, dev_t *dev_id, bool *has_dev_id) { + struct stat st; + if (fstat(fd, &st) != 0) { + wlr_log_errno(WLR_ERROR, "fstat() failed"); + return false; + } + *dev_id = st.st_rdev; + *has_dev_id = true; + return true; +} + +static bool get_preferred_drm_dev_id(struct wlr_backend *backend, int drm_fd, + dev_t *dev_id, bool *has_dev_id) { + if (*has_dev_id) { return true; } + // If the caller passed in a DRM FD, use that + if (drm_fd >= 0) { + return dev_id_from_fd(drm_fd, dev_id, has_dev_id); + } + // Allow the user to override the render node const char *render_name = getenv("WLR_RENDER_DRM_DEVICE"); if (render_name != NULL) { @@ -159,29 +176,25 @@ static bool open_preferred_drm_fd(struct wlr_backend *backend, int *drm_fd_ptr, close(drm_fd); return false; } - *drm_fd_ptr = drm_fd; - *own_drm_fd = true; - return true; + bool ok = dev_id_from_fd(drm_fd, dev_id, has_dev_id); + close(drm_fd); + return ok; } // Prefer the backend's DRM node, 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; - return true; + return dev_id_from_fd(backend_drm_fd, dev_id, has_dev_id); } // If the backend hasn't picked a DRM FD, but accepts DMA-BUFs, pick an // arbitrary render node uint32_t backend_caps = backend_get_buffer_caps(backend); if (backend_caps & WLR_BUFFER_CAP_DMABUF) { - int drm_fd = open_drm_render_node(); - if (drm_fd < 0) { + if (!pick_drm_render_node(dev_id)) { return false; } - *drm_fd_ptr = drm_fd; - *own_drm_fd = true; + *has_dev_id = true; return true; } @@ -222,14 +235,18 @@ static struct wlr_renderer *renderer_autocreate(struct wlr_backend *backend, int bool is_auto = strcmp(renderer_name, "auto") == 0; struct wlr_renderer *renderer = NULL; - bool own_drm_fd = false; + dev_t drm_dev_id; + bool has_drm_dev_id = false; + (void)drm_dev_id; + (void)has_drm_dev_id; + (void)get_preferred_drm_dev_id; - if ((is_auto && WLR_HAS_GLES2_RENDERER) || strcmp(renderer_name, "gles2") == 0) { - if (!open_preferred_drm_fd(backend, &drm_fd, &own_drm_fd)) { - log_creation_failure(is_auto, "Cannot create GLES2 renderer: no DRM FD available"); + if (is_auto || strcmp(renderer_name, "gles2") == 0) { + if (!get_preferred_drm_dev_id(backend, drm_fd, &drm_dev_id, &has_drm_dev_id)) { + log_creation_failure(is_auto, "Cannot create GLES2 renderer: no DRM device available"); } else { #if WLR_HAS_GLES2_RENDERER - renderer = wlr_gles2_renderer_create_with_drm_fd(drm_fd); + renderer = wlr_gles2_renderer_create_with_drm_dev_id(drm_dev_id); #else wlr_log(WLR_ERROR, "Cannot create GLES renderer: disabled at compile-time"); #endif @@ -242,11 +259,11 @@ static struct wlr_renderer *renderer_autocreate(struct wlr_backend *backend, int } if (strcmp(renderer_name, "vulkan") == 0) { - if (!open_preferred_drm_fd(backend, &drm_fd, &own_drm_fd)) { - log_creation_failure(is_auto, "Cannot create Vulkan renderer: no DRM FD available"); + if (!get_preferred_drm_dev_id(backend, drm_fd, &drm_dev_id, &has_drm_dev_id)) { + log_creation_failure(is_auto, "Cannot create Vulkan renderer: no DRM device available"); } else { #if WLR_HAS_VULKAN_RENDERER - renderer = wlr_vk_renderer_create_with_drm_fd(drm_fd); + renderer = wlr_vk_renderer_create_with_drm_dev_id(drm_dev_id); #else wlr_log(WLR_ERROR, "Cannot create Vulkan renderer: disabled at compile-time"); #endif @@ -271,9 +288,6 @@ out: if (renderer == NULL) { wlr_log(WLR_ERROR, "Could not initialize renderer"); } - if (own_drm_fd && drm_fd >= 0) { - close(drm_fd); - } return renderer; }