diff --git a/include/render/egl.h b/include/render/egl.h index 0765cce74..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 @@ -88,7 +88,10 @@ const struct wlr_drm_format_set *wlr_egl_get_dmabuf_render_formats( */ bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image); -int wlr_egl_dup_drm_fd(struct wlr_egl *egl); +/** + * Get the DRM device ID used by EGL. + */ +bool wlr_egl_get_drm_dev_id(struct wlr_egl *egl, dev_t *devid); /** * Restore EGL context that was previously saved using wlr_egl_save_current(). diff --git a/include/render/gles2.h b/include/render/gles2.h index a472ee9c6..b39128591 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -41,8 +41,8 @@ struct wlr_gles2_tex_shader { struct wlr_gles2_renderer { struct wlr_renderer wlr_renderer; + dev_t drm_dev_id; struct wlr_egl *egl; - int drm_fd; struct wlr_drm_format_set shm_texture_formats; diff --git a/include/render/vulkan.h b/include/render/vulkan.h index 29403f01f..070d2ce2c 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -38,8 +38,6 @@ struct wlr_vk_device { VkPhysicalDevice phdev; VkDevice dev; - int drm_fd; - bool implicit_sync_interop; bool sampler_ycbcr_conversion; @@ -63,10 +61,10 @@ 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); -int vulkan_open_phdev_drm_fd(VkPhysicalDevice phdev); +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. struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini, @@ -262,6 +260,7 @@ struct wlr_vk_renderer { struct wlr_renderer wlr_renderer; struct wlr_backend *backend; struct wlr_vk_device *dev; + dev_t drm_dev_id; VkCommandPool command_pool; 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/interface.h b/include/wlr/render/interface.h index 89f6de970..d46caa80f 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -25,7 +25,6 @@ struct wlr_renderer_impl { const struct wlr_drm_format_set *(*get_render_formats)( struct wlr_renderer *renderer); void (*destroy)(struct wlr_renderer *renderer); - int (*get_drm_fd)(struct wlr_renderer *renderer); struct wlr_texture *(*texture_from_buffer)(struct wlr_renderer *renderer, struct wlr_buffer *buffer); struct wlr_render_pass *(*begin_buffer_pass)(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/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index bb9a55fcf..e9445e007 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -29,6 +29,8 @@ struct wlr_renderer { // Capabilities required for the buffer used as a render target (bitmask of // enum wlr_buffer_cap) uint32_t render_buffer_caps; + // DRM device used for rendering, if any + const dev_t *drm_dev_id; struct { struct wl_signal destroy; @@ -85,13 +87,6 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, bool wlr_renderer_init_wl_shm(struct wlr_renderer *r, struct wl_display *wl_display); -/** - * Obtains the FD of the DRM device used for rendering, or -1 if unavailable. - * - * The caller doesn't have ownership of the FD, it must not close it. - */ -int wlr_renderer_get_drm_fd(struct wlr_renderer *r); - /** * Destroys the renderer. * diff --git a/render/allocator/allocator.c b/render/allocator/allocator.c index 27b08fc82..ff8aefda2 100644 --- a/render/allocator/allocator.c +++ b/render/allocator/allocator.c @@ -150,11 +150,40 @@ struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend, uint32_t backend_caps = backend_get_buffer_caps(backend); // Note, drm_fd may be negative if unavailable int drm_fd = wlr_backend_get_drm_fd(backend); - if (drm_fd < 0) { - drm_fd = wlr_renderer_get_drm_fd(renderer); + + int render_drm_fd = -1; + if (drm_fd < 0 && renderer->drm_dev_id != NULL) { + drmDevice *dev = NULL; + if (drmGetDeviceFromDevId(*renderer->drm_dev_id, 0, &dev) != 0) { + wlr_log(WLR_ERROR, "drmGetDeviceFromDevId failed"); + return NULL; + } + + const char *node_name = NULL; + if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { + node_name = 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 = dev->nodes[DRM_NODE_PRIMARY]; + } + render_drm_fd = open(node_name, O_RDWR | O_NONBLOCK | O_CLOEXEC); + drmFreeDevice(&dev); + if (render_drm_fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open DRM node %s", node_name); + return NULL; + } + + drm_fd = render_drm_fd; } - return allocator_autocreate_with_drm_fd(backend_caps, renderer, drm_fd); + struct wlr_allocator *alloc = + allocator_autocreate_with_drm_fd(backend_caps, renderer, drm_fd); + if (render_drm_fd >= 0) { + close(render_drm_fd); + } + return alloc; } void wlr_allocator_destroy(struct wlr_allocator *alloc) { diff --git a/render/egl.c b/render/egl.c index 19868ca84..e77001b9a 100644 --- a/render/egl.c +++ b/render/egl.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -440,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; @@ -468,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; } @@ -495,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"); @@ -529,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"); @@ -543,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; @@ -949,68 +951,53 @@ static char *get_render_name(const char *name) { return render_name; } -static int dup_egl_device_drm_fd(struct wlr_egl *egl) { +static char *get_drm_node_path(struct wlr_egl *egl) { if (egl->device == EGL_NO_DEVICE_EXT || (!egl->exts.EXT_device_drm && !egl->exts.EXT_device_drm_render_node)) { - return -1; + return NULL; } - char *render_name = NULL; #ifdef EGL_EXT_device_drm_render_node if (egl->exts.EXT_device_drm_render_node) { const char *name = egl->procs.eglQueryDeviceStringEXT(egl->device, EGL_DRM_RENDER_NODE_FILE_EXT); if (name == NULL) { wlr_log(WLR_DEBUG, "EGL device has no render node"); - return -1; + return false; } - render_name = strdup(name); + return strdup(name); } #endif - if (render_name == NULL) { - const char *primary_name = egl->procs.eglQueryDeviceStringEXT(egl->device, - EGL_DRM_DEVICE_FILE_EXT); - if (primary_name == NULL) { - wlr_log(WLR_ERROR, - "eglQueryDeviceStringEXT(EGL_DRM_DEVICE_FILE_EXT) failed"); - return -1; - } - - render_name = get_render_name(primary_name); - if (render_name == NULL) { - wlr_log(WLR_ERROR, "Can't find render node name for device %s", - primary_name); - return -1; - } + const char *primary_name = egl->procs.eglQueryDeviceStringEXT(egl->device, + EGL_DRM_DEVICE_FILE_EXT); + if (primary_name == NULL) { + wlr_log(WLR_ERROR, + "eglQueryDeviceStringEXT(EGL_DRM_DEVICE_FILE_EXT) failed"); + return false; } - int render_fd = open(render_name, O_RDWR | O_NONBLOCK | O_CLOEXEC); - if (render_fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to open DRM render node %s", - render_name); + return get_render_name(primary_name); +} + +bool wlr_egl_get_drm_dev_id(struct wlr_egl *egl, dev_t *dev_id) { + char *render_name = get_drm_node_path(egl); + // Fallback to GBM's FD if we can't use EGLDevice + if (render_name == NULL && egl->gbm_device != NULL) { + render_name = drmGetDeviceNameFromFd2(gbm_device_get_fd(egl->gbm_device)); + } + if (render_name == NULL) { + return false; + } + + struct stat render_stat = {0}; + if (stat(render_name, &render_stat) != 0) { + wlr_log_errno(WLR_ERROR, "stat failed"); free(render_name); - return -1; + return false; } free(render_name); - return render_fd; -} - -int wlr_egl_dup_drm_fd(struct wlr_egl *egl) { - int fd = dup_egl_device_drm_fd(egl); - if (fd >= 0) { - return fd; - } - - // Fallback to GBM's FD if we can't use EGLDevice - if (egl->gbm_device == NULL) { - return -1; - } - - fd = fcntl(gbm_device_get_fd(egl->gbm_device), F_DUPFD_CLOEXEC, 0); - if (fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to dup GBM FD"); - } - return fd; + *dev_id = render_stat.st_rdev; + return true; } diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 4694b2a8f..9ecda827c 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -183,17 +183,6 @@ static const struct wlr_drm_format_set *gles2_get_render_formats( return wlr_egl_get_dmabuf_render_formats(renderer->egl); } -static int gles2_get_drm_fd(struct wlr_renderer *wlr_renderer) { - struct wlr_gles2_renderer *renderer = - gles2_get_renderer(wlr_renderer); - - if (renderer->drm_fd < 0) { - renderer->drm_fd = wlr_egl_dup_drm_fd(renderer->egl); - } - - return renderer->drm_fd; -} - struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); @@ -231,11 +220,6 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { wlr_egl_destroy(renderer->egl); wlr_drm_format_set_finish(&renderer->shm_texture_formats); - - if (renderer->drm_fd >= 0) { - close(renderer->drm_fd); - } - free(renderer); } @@ -356,7 +340,6 @@ static const struct wlr_renderer_impl renderer_impl = { .destroy = gles2_destroy, .get_texture_formats = gles2_get_texture_formats, .get_render_formats = gles2_get_render_formats, - .get_drm_fd = gles2_get_drm_fd, .texture_from_buffer = gles2_texture_from_buffer, .begin_buffer_pass = gles2_begin_buffer_pass, .render_timer_create = gles2_render_timer_create, @@ -493,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; @@ -533,7 +516,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->egl = egl; renderer->exts_str = exts_str; - renderer->drm_fd = -1; wlr_log(WLR_INFO, "Creating GLES2 renderer"); wlr_log(WLR_INFO, "Using %s", glGetString(GL_VERSION)); @@ -630,6 +612,10 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); } + if (wlr_egl_get_drm_dev_id(renderer->egl, &renderer->drm_dev_id)) { + renderer->wlr_renderer.drm_dev_id = &renderer->drm_dev_id; + } + push_gles2_debug(renderer); GLuint prog; diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 32effb5a7..888da7ea5 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -1384,11 +1384,6 @@ destroy_image: return false; } -static int vulkan_get_drm_fd(struct wlr_renderer *wlr_renderer) { - struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); - return renderer->dev->drm_fd; -} - static struct wlr_render_pass *vulkan_begin_buffer_pass(struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer, const struct wlr_buffer_pass_options *options) { struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); @@ -1413,7 +1408,6 @@ static const struct wlr_renderer_impl renderer_impl = { .get_texture_formats = vulkan_get_texture_formats, .get_render_formats = vulkan_get_render_formats, .destroy = vulkan_destroy, - .get_drm_fd = vulkan_get_drm_fd, .texture_from_buffer = vulkan_texture_from_buffer, .begin_buffer_pass = vulkan_begin_buffer_pass, }; @@ -2423,6 +2417,10 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev wl_list_init(&renderer->color_transforms); wl_list_init(&renderer->pipeline_layouts); + if (vulkan_get_phdev_drm_dev_id(dev->phdev, &renderer->drm_dev_id)) { + renderer->wlr_renderer.drm_dev_id = &renderer->drm_dev_id; + } + if (!init_static_render_data(renderer)) { goto error; } @@ -2462,7 +2460,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 " @@ -2474,7 +2472,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"); @@ -2488,15 +2486,6 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) { return NULL; } - // Do not use the drm_fd that was passed in: we should prefer the render - // node even if a primary node was provided - dev->drm_fd = vulkan_open_phdev_drm_fd(phdev); - if (dev->drm_fd < 0) { - vulkan_device_destroy(dev); - vulkan_instance_destroy(ini); - return NULL; - } - return vulkan_renderer_create_for_device(dev); } diff --git a/render/vulkan/vulkan.c b/render/vulkan/vulkan.c index 7cdc44a02..80740aeb9 100644 --- a/render/vulkan/vulkan.c +++ b/render/vulkan/vulkan.c @@ -2,7 +2,6 @@ #undef _POSIX_C_SOURCE #endif #include -#include #include #include #include @@ -256,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; @@ -273,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]; @@ -353,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; @@ -364,7 +356,7 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd) return VK_NULL_HANDLE; } -int vulkan_open_phdev_drm_fd(VkPhysicalDevice phdev) { +bool vulkan_get_phdev_drm_dev_id(VkPhysicalDevice phdev, dev_t *dev_id) { // vulkan_find_drm_phdev() already checks that VK_EXT_physical_device_drm // is supported VkPhysicalDeviceDrmPropertiesEXT drm_props = { @@ -376,38 +368,16 @@ 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); + *dev_id = makedev(drm_props.renderMajor, drm_props.renderMinor); } else if (drm_props.hasPrimary) { - devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor); + *dev_id = makedev(drm_props.primaryMajor, drm_props.primaryMinor); } else { wlr_log(WLR_ERROR, "Physical device is missing both render and primary nodes"); - return -1; + return false; } - 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); - } - - 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); - } - drmFreeDevice(&device); - return drm_fd; + return true; } static void load_device_proc(struct wlr_vk_device *dev, const char *name, @@ -452,7 +422,6 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini, dev->phdev = phdev; dev->instance = ini; - dev->drm_fd = -1; // For dmabuf import we require at least the external_memory_fd, // external_memory_dma_buf, queue_family_foreign, @@ -650,10 +619,6 @@ void vulkan_device_destroy(struct wlr_vk_device *dev) { vkDestroyDevice(dev->dev, NULL); } - if (dev->drm_fd > 0) { - close(dev->drm_fd); - } - wlr_drm_format_set_finish(&dev->dmabuf_render_formats); wlr_drm_format_set_finish(&dev->dmabuf_texture_formats); wlr_drm_format_set_finish(&dev->shm_texture_formats); diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 6a28908c4..f111d63d0 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -83,7 +83,7 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, } if (wlr_renderer_get_texture_formats(r, WLR_BUFFER_CAP_DMABUF) != NULL && - wlr_renderer_get_drm_fd(r) >= 0 && + r->drm_dev_id != NULL && wlr_linux_dmabuf_v1_create_with_renderer(wl_display, 4, r) == NULL) { return false; } @@ -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; } @@ -287,13 +301,6 @@ struct wlr_renderer *wlr_renderer_autocreate(struct wlr_backend *backend) { return renderer_autocreate(backend, -1); } -int wlr_renderer_get_drm_fd(struct wlr_renderer *r) { - if (!r->impl->get_drm_fd) { - return -1; - } - return r->impl->get_drm_fd(r); -} - struct wlr_render_pass *wlr_renderer_begin_buffer_pass(struct wlr_renderer *renderer, struct wlr_buffer *buffer, const struct wlr_buffer_pass_options *options) { struct wlr_buffer_pass_options default_options = {0}; diff --git a/types/wlr_drm.c b/types/wlr_drm.c index c58cdb4ec..290b9b20f 100644 --- a/types/wlr_drm.c +++ b/types/wlr_drm.c @@ -201,15 +201,14 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_drm *wlr_drm_create(struct wl_display *display, struct wlr_renderer *renderer) { - int drm_fd = wlr_renderer_get_drm_fd(renderer); - if (drm_fd < 0) { - wlr_log(WLR_ERROR, "Failed to get DRM FD from renderer"); + if (renderer->drm_dev_id == NULL) { + wlr_log(WLR_ERROR, "Failed to get DRM device from renderer"); return NULL; } drmDevice *dev = NULL; - if (drmGetDevice2(drm_fd, 0, &dev) != 0) { - wlr_log(WLR_ERROR, "drmGetDevice2 failed"); + if (drmGetDeviceFromDevId(*renderer->drm_dev_id, 0, &dev) != 0) { + wlr_log(WLR_ERROR, "drmGetDeviceFromDevId failed"); return NULL; } diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index bfd97637a..007a896fe 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -1087,16 +1087,11 @@ bool wlr_linux_dmabuf_feedback_v1_init_with_options(struct wlr_linux_dmabuf_feed *feedback = (struct wlr_linux_dmabuf_feedback_v1){0}; - int renderer_drm_fd = wlr_renderer_get_drm_fd(options->main_renderer); - if (renderer_drm_fd < 0) { - wlr_log(WLR_ERROR, "Failed to get renderer DRM FD"); - goto error; - } - dev_t renderer_dev; - if (!devid_from_fd(renderer_drm_fd, &renderer_dev)) { + if (options->main_renderer->drm_dev_id == NULL) { goto error; } + dev_t renderer_dev = *options->main_renderer->drm_dev_id; feedback->main_device = renderer_dev; const struct wlr_drm_format_set *renderer_formats =