Merge branch 'renderer-drm-devid' into 'master'

render: replace wlr_renderer_get_drm_fd() with drm_dev_id

See merge request wlroots/wlroots!4368
This commit is contained in:
Simon Ser 2024-08-04 06:57:04 +00:00
commit 779f37e846
15 changed files with 177 additions and 225 deletions

View file

@ -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. * 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 * 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); 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(). * Restore EGL context that was previously saved using wlr_egl_save_current().

View file

@ -41,8 +41,8 @@ struct wlr_gles2_tex_shader {
struct wlr_gles2_renderer { struct wlr_gles2_renderer {
struct wlr_renderer wlr_renderer; struct wlr_renderer wlr_renderer;
dev_t drm_dev_id;
struct wlr_egl *egl; struct wlr_egl *egl;
int drm_fd;
struct wlr_drm_format_set shm_texture_formats; struct wlr_drm_format_set shm_texture_formats;

View file

@ -38,8 +38,6 @@ struct wlr_vk_device {
VkPhysicalDevice phdev; VkPhysicalDevice phdev;
VkDevice dev; VkDevice dev;
int drm_fd;
bool implicit_sync_interop; bool implicit_sync_interop;
bool sampler_ycbcr_conversion; bool sampler_ycbcr_conversion;
@ -63,10 +61,10 @@ struct wlr_vk_device {
struct wlr_drm_format_set shm_texture_formats; 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. // 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);
int vulkan_open_phdev_drm_fd(VkPhysicalDevice phdev); bool vulkan_get_phdev_drm_dev_id(VkPhysicalDevice phdev, dev_t *dev_id);
// Creates a device for the given instance and physical device. // Creates a device for the given instance and physical device.
struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini, 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_renderer wlr_renderer;
struct wlr_backend *backend; struct wlr_backend *backend;
struct wlr_vk_device *dev; struct wlr_vk_device *dev;
dev_t drm_dev_id;
VkCommandPool command_pool; VkCommandPool command_pool;

View file

@ -10,7 +10,6 @@
#define WLR_RENDER_GLES2_H #define WLR_RENDER_GLES2_H
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
struct wlr_egl; struct wlr_egl;
@ -28,7 +27,7 @@ struct wlr_egl;
* render pass can't be used before the nested render pass is submitted. * 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_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl);
struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *renderer); struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *renderer);

View file

@ -25,7 +25,6 @@ struct wlr_renderer_impl {
const struct wlr_drm_format_set *(*get_render_formats)( const struct wlr_drm_format_set *(*get_render_formats)(
struct wlr_renderer *renderer); struct wlr_renderer *renderer);
void (*destroy)(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_texture *(*texture_from_buffer)(struct wlr_renderer *renderer,
struct wlr_buffer *buffer); struct wlr_buffer *buffer);
struct wlr_render_pass *(*begin_buffer_pass)(struct wlr_renderer *renderer, struct wlr_render_pass *(*begin_buffer_pass)(struct wlr_renderer *renderer,

View file

@ -18,7 +18,7 @@ struct wlr_vk_image_attribs {
VkFormat format; 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); VkInstance wlr_vk_renderer_get_instance(struct wlr_renderer *renderer);
VkPhysicalDevice wlr_vk_renderer_get_physical_device(struct wlr_renderer *renderer); VkPhysicalDevice wlr_vk_renderer_get_physical_device(struct wlr_renderer *renderer);

View file

@ -29,6 +29,8 @@ struct wlr_renderer {
// Capabilities required for the buffer used as a render target (bitmask of // Capabilities required for the buffer used as a render target (bitmask of
// enum wlr_buffer_cap) // enum wlr_buffer_cap)
uint32_t render_buffer_caps; uint32_t render_buffer_caps;
// DRM device used for rendering, if any
const dev_t *drm_dev_id;
struct { struct {
struct wl_signal destroy; 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, bool wlr_renderer_init_wl_shm(struct wlr_renderer *r,
struct wl_display *wl_display); 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. * Destroys the renderer.
* *

View file

@ -150,11 +150,40 @@ struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend,
uint32_t backend_caps = backend_get_buffer_caps(backend); uint32_t backend_caps = backend_get_buffer_caps(backend);
// Note, drm_fd may be negative if unavailable // Note, drm_fd may be negative if unavailable
int drm_fd = wlr_backend_get_drm_fd(backend); 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) { void wlr_allocator_destroy(struct wlr_allocator *alloc) {

View file

@ -5,6 +5,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <gbm.h> #include <gbm.h>
#include <sys/stat.h>
#include <wlr/render/egl.h> #include <wlr/render/egl.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <wlr/util/region.h> #include <wlr/util/region.h>
@ -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 bool device_has_name(const drmDevice *device, const char *name);
static EGLDeviceEXT get_egl_device_from_drm_fd(struct wlr_egl *egl, static EGLDeviceEXT get_egl_device_from_drm_dev_id(struct wlr_egl *egl, dev_t dev_id) {
int drm_fd) {
if (egl->procs.eglQueryDevicesEXT == NULL) { if (egl->procs.eglQueryDevicesEXT == NULL) {
wlr_log(WLR_DEBUG, "EGL_EXT_device_enumeration not supported"); wlr_log(WLR_DEBUG, "EGL_EXT_device_enumeration not supported");
return EGL_NO_DEVICE_EXT; return EGL_NO_DEVICE_EXT;
@ -468,9 +468,8 @@ static EGLDeviceEXT get_egl_device_from_drm_fd(struct wlr_egl *egl,
} }
drmDevice *device = NULL; drmDevice *device = NULL;
int ret = drmGetDevice(drm_fd, &device); if (drmGetDeviceFromDevId(dev_id, 0, &device) != 0) {
if (ret < 0) { wlr_log(WLR_ERROR, "drmGetDeviceFromdev_id() failed");
wlr_log(WLR_ERROR, "Failed to get DRM device: %s", strerror(-ret));
return EGL_NO_DEVICE_EXT; return EGL_NO_DEVICE_EXT;
} }
@ -495,29 +494,32 @@ static EGLDeviceEXT get_egl_device_from_drm_fd(struct wlr_egl *egl,
return egl_device; return egl_device;
} }
static int open_render_node(int drm_fd) { static int open_render_node(dev_t dev_id) {
char *render_name = drmGetRenderDeviceNameFromFd(drm_fd); drmDevice *dev;
if (render_name == NULL) { if (drmGetDeviceFromDevId(dev_id, 0, &dev) != 0) {
// This can happen on split render/display platforms, fallback to wlr_log(WLR_ERROR, "drmGetDeviceFromdev_id() failed");
// primary node return -1;
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); const char *node_name;
if (render_fd < 0) { if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
wlr_log_errno(WLR_ERROR, "Failed to open DRM node '%s'", render_name); 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; 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(); struct wlr_egl *egl = egl_create();
if (egl == NULL) { if (egl == NULL) {
wlr_log(WLR_ERROR, "Failed to create EGL context"); 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 * Search for the EGL device matching the DRM fd using the
* EXT_device_enumeration extension. * 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_device != EGL_NO_DEVICE_EXT) {
if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) { if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) {
wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_DEVICE_EXT"); 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) { 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) { if (gbm_fd < 0) {
wlr_log(WLR_ERROR, "Failed to open DRM render node"); wlr_log(WLR_ERROR, "Failed to open DRM render node");
goto error; goto error;
@ -949,68 +951,53 @@ static char *get_render_name(const char *name) {
return render_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 && if (egl->device == EGL_NO_DEVICE_EXT || (!egl->exts.EXT_device_drm &&
!egl->exts.EXT_device_drm_render_node)) { !egl->exts.EXT_device_drm_render_node)) {
return -1; return NULL;
} }
char *render_name = NULL;
#ifdef EGL_EXT_device_drm_render_node #ifdef EGL_EXT_device_drm_render_node
if (egl->exts.EXT_device_drm_render_node) { if (egl->exts.EXT_device_drm_render_node) {
const char *name = egl->procs.eglQueryDeviceStringEXT(egl->device, const char *name = egl->procs.eglQueryDeviceStringEXT(egl->device,
EGL_DRM_RENDER_NODE_FILE_EXT); EGL_DRM_RENDER_NODE_FILE_EXT);
if (name == NULL) { if (name == NULL) {
wlr_log(WLR_DEBUG, "EGL device has no render node"); wlr_log(WLR_DEBUG, "EGL device has no render node");
return -1; return false;
} }
render_name = strdup(name); return strdup(name);
} }
#endif #endif
if (render_name == NULL) { const char *primary_name = egl->procs.eglQueryDeviceStringEXT(egl->device,
const char *primary_name = egl->procs.eglQueryDeviceStringEXT(egl->device, EGL_DRM_DEVICE_FILE_EXT);
EGL_DRM_DEVICE_FILE_EXT); if (primary_name == NULL) {
if (primary_name == NULL) { wlr_log(WLR_ERROR,
wlr_log(WLR_ERROR, "eglQueryDeviceStringEXT(EGL_DRM_DEVICE_FILE_EXT) failed");
"eglQueryDeviceStringEXT(EGL_DRM_DEVICE_FILE_EXT) failed"); return false;
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;
}
} }
int render_fd = open(render_name, O_RDWR | O_NONBLOCK | O_CLOEXEC); return get_render_name(primary_name);
if (render_fd < 0) { }
wlr_log_errno(WLR_ERROR, "Failed to open DRM render node %s",
render_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); free(render_name);
return -1; return false;
} }
free(render_name); free(render_name);
return render_fd; *dev_id = render_stat.st_rdev;
} return true;
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;
} }

View file

@ -183,17 +183,6 @@ static const struct wlr_drm_format_set *gles2_get_render_formats(
return wlr_egl_get_dmabuf_render_formats(renderer->egl); 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_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *wlr_renderer) {
struct wlr_gles2_renderer *renderer = struct wlr_gles2_renderer *renderer =
gles2_get_renderer(wlr_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_egl_destroy(renderer->egl);
wlr_drm_format_set_finish(&renderer->shm_texture_formats); wlr_drm_format_set_finish(&renderer->shm_texture_formats);
if (renderer->drm_fd >= 0) {
close(renderer->drm_fd);
}
free(renderer); free(renderer);
} }
@ -356,7 +340,6 @@ static const struct wlr_renderer_impl renderer_impl = {
.destroy = gles2_destroy, .destroy = gles2_destroy,
.get_texture_formats = gles2_get_texture_formats, .get_texture_formats = gles2_get_texture_formats,
.get_render_formats = gles2_get_render_formats, .get_render_formats = gles2_get_render_formats,
.get_drm_fd = gles2_get_drm_fd,
.texture_from_buffer = gles2_texture_from_buffer, .texture_from_buffer = gles2_texture_from_buffer,
.begin_buffer_pass = gles2_begin_buffer_pass, .begin_buffer_pass = gles2_begin_buffer_pass,
.render_timer_create = gles2_render_timer_create, .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; *(void **)proc_ptr = proc;
} }
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_egl *egl = wlr_egl_create_with_drm_fd(drm_fd); struct wlr_egl *egl = wlr_egl_create_with_drm_dev_id(dev_id);
if (egl == NULL) { if (egl == NULL) {
wlr_log(WLR_ERROR, "Could not initialize EGL"); wlr_log(WLR_ERROR, "Could not initialize EGL");
return NULL; return NULL;
@ -533,7 +516,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) {
renderer->egl = egl; renderer->egl = egl;
renderer->exts_str = exts_str; renderer->exts_str = exts_str;
renderer->drm_fd = -1;
wlr_log(WLR_INFO, "Creating GLES2 renderer"); wlr_log(WLR_INFO, "Creating GLES2 renderer");
wlr_log(WLR_INFO, "Using %s", glGetString(GL_VERSION)); 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); 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); push_gles2_debug(renderer);
GLuint prog; GLuint prog;

View file

@ -1384,11 +1384,6 @@ destroy_image:
return false; 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, 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_buffer *buffer, const struct wlr_buffer_pass_options *options) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); 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_texture_formats = vulkan_get_texture_formats,
.get_render_formats = vulkan_get_render_formats, .get_render_formats = vulkan_get_render_formats,
.destroy = vulkan_destroy, .destroy = vulkan_destroy,
.get_drm_fd = vulkan_get_drm_fd,
.texture_from_buffer = vulkan_texture_from_buffer, .texture_from_buffer = vulkan_texture_from_buffer,
.begin_buffer_pass = vulkan_begin_buffer_pass, .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->color_transforms);
wl_list_init(&renderer->pipeline_layouts); 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)) { if (!init_static_render_data(renderer)) {
goto error; goto error;
} }
@ -2462,7 +2460,7 @@ error:
return NULL; 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 " wlr_log(WLR_INFO, "The vulkan renderer is only experimental and "
"not expected to be ready for daily use"); "not expected to be ready for daily use");
wlr_log(WLR_INFO, "Run with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation " 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; return NULL;
} }
VkPhysicalDevice phdev = vulkan_find_drm_phdev(ini, drm_fd); VkPhysicalDevice phdev = vulkan_find_drm_phdev(ini, dev_id);
if (!phdev) { if (!phdev) {
// We rather fail here than doing some guesswork // We rather fail here than doing some guesswork
wlr_log(WLR_ERROR, "Could not match drm and vulkan device"); 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; 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); return vulkan_renderer_create_for_device(dev);
} }

View file

@ -2,7 +2,6 @@
#undef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE
#endif #endif
#include <assert.h> #include <assert.h>
#include <fcntl.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
@ -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); 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; VkResult res;
uint32_t num_phdevs; 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; 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) { for (uint32_t i = 0; i < num_phdevs; ++i) {
VkPhysicalDevice phdev = 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 primary_devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor);
dev_t render_devid = makedev(drm_props.renderMajor, drm_props.renderMinor); dev_t render_devid = makedev(drm_props.renderMajor, drm_props.renderMinor);
if (primary_devid == drm_stat.st_rdev || if (primary_devid == devid || render_devid == devid) {
render_devid == drm_stat.st_rdev) {
wlr_log(WLR_INFO, "Found matching Vulkan physical device: %s", wlr_log(WLR_INFO, "Found matching Vulkan physical device: %s",
phdev_props.deviceName); phdev_props.deviceName);
return phdev; return phdev;
@ -364,7 +356,7 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd)
return VK_NULL_HANDLE; 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 // vulkan_find_drm_phdev() already checks that VK_EXT_physical_device_drm
// is supported // is supported
VkPhysicalDeviceDrmPropertiesEXT drm_props = { VkPhysicalDeviceDrmPropertiesEXT drm_props = {
@ -376,38 +368,16 @@ int vulkan_open_phdev_drm_fd(VkPhysicalDevice phdev) {
}; };
vkGetPhysicalDeviceProperties2(phdev, &props); vkGetPhysicalDeviceProperties2(phdev, &props);
dev_t devid;
if (drm_props.hasRender) { 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) { } else if (drm_props.hasPrimary) {
devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor); *dev_id = makedev(drm_props.primaryMajor, drm_props.primaryMinor);
} else { } else {
wlr_log(WLR_ERROR, "Physical device is missing both render and primary nodes"); wlr_log(WLR_ERROR, "Physical device is missing both render and primary nodes");
return -1; return false;
} }
drmDevice *device = NULL; return true;
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;
} }
static void load_device_proc(struct wlr_vk_device *dev, const char *name, 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->phdev = phdev;
dev->instance = ini; dev->instance = ini;
dev->drm_fd = -1;
// For dmabuf import we require at least the external_memory_fd, // For dmabuf import we require at least the external_memory_fd,
// external_memory_dma_buf, queue_family_foreign, // external_memory_dma_buf, queue_family_foreign,
@ -650,10 +619,6 @@ void vulkan_device_destroy(struct wlr_vk_device *dev) {
vkDestroyDevice(dev->dev, NULL); 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_render_formats);
wlr_drm_format_set_finish(&dev->dmabuf_texture_formats); wlr_drm_format_set_finish(&dev->dmabuf_texture_formats);
wlr_drm_format_set_finish(&dev->shm_texture_formats); wlr_drm_format_set_finish(&dev->shm_texture_formats);

View file

@ -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 && 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) { wlr_linux_dmabuf_v1_create_with_renderer(wl_display, 4, r) == NULL) {
return false; return false;
} }
@ -91,40 +91,41 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r,
return true; return true;
} }
static int open_drm_render_node(void) { static bool pick_drm_render_node(dev_t *dev_id) {
uint32_t flags = 0; uint32_t flags = 0;
int devices_len = drmGetDevices2(flags, NULL, 0); int devices_len = drmGetDevices2(flags, NULL, 0);
if (devices_len < 0) { if (devices_len < 0) {
wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len)); wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len));
return -1; return false;
} }
drmDevice **devices = calloc(devices_len, sizeof(*devices)); drmDevice **devices = calloc(devices_len, sizeof(*devices));
if (devices == NULL) { if (devices == NULL) {
wlr_log_errno(WLR_ERROR, "Allocation failed"); wlr_log_errno(WLR_ERROR, "Allocation failed");
return -1; return false;
} }
devices_len = drmGetDevices2(flags, devices, devices_len); devices_len = drmGetDevices2(flags, devices, devices_len);
if (devices_len < 0) { if (devices_len < 0) {
free(devices); free(devices);
wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len)); 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++) { for (int i = 0; i < devices_len; i++) {
drmDevice *dev = devices[i]; drmDevice *dev = devices[i];
if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
const char *name = dev->nodes[DRM_NODE_RENDER]; const char *name = dev->nodes[DRM_NODE_RENDER];
wlr_log(WLR_DEBUG, "Opening DRM render node '%s'", name); wlr_log(WLR_DEBUG, "Picking DRM render node '%s'", name);
fd = open(name, O_RDWR | O_CLOEXEC); struct stat st;
if (fd < 0) { if (stat(name, &st) != 0) {
wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); wlr_log_errno(WLR_ERROR, "stat() failed for %s", name);
goto out; goto out;
} }
*dev_id = st.st_rdev;
break; break;
} }
} }
if (fd < 0) { if (!ok) {
wlr_log(WLR_ERROR, "Failed to find any DRM render node"); wlr_log(WLR_ERROR, "Failed to find any DRM render node");
} }
@ -134,15 +135,31 @@ out:
} }
free(devices); free(devices);
return fd; return ok;
} }
static bool open_preferred_drm_fd(struct wlr_backend *backend, int *drm_fd_ptr, static bool dev_id_from_fd(int fd, dev_t *dev_id, bool *has_dev_id) {
bool *own_drm_fd) { struct stat st;
if (*drm_fd_ptr >= 0) { 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; 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 // Allow the user to override the render node
const char *render_name = getenv("WLR_RENDER_DRM_DEVICE"); const char *render_name = getenv("WLR_RENDER_DRM_DEVICE");
if (render_name != NULL) { 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); close(drm_fd);
return false; return false;
} }
*drm_fd_ptr = drm_fd; bool ok = dev_id_from_fd(drm_fd, dev_id, has_dev_id);
*own_drm_fd = true; close(drm_fd);
return true; return ok;
} }
// Prefer the backend's DRM node, if any // Prefer the backend's DRM node, if any
int backend_drm_fd = wlr_backend_get_drm_fd(backend); int backend_drm_fd = wlr_backend_get_drm_fd(backend);
if (backend_drm_fd >= 0) { if (backend_drm_fd >= 0) {
*drm_fd_ptr = backend_drm_fd; return dev_id_from_fd(backend_drm_fd, dev_id, has_dev_id);
*own_drm_fd = false;
return true;
} }
// If the backend hasn't picked a DRM FD, but accepts DMA-BUFs, pick an // If the backend hasn't picked a DRM FD, but accepts DMA-BUFs, pick an
// arbitrary render node // arbitrary render node
uint32_t backend_caps = backend_get_buffer_caps(backend); uint32_t backend_caps = backend_get_buffer_caps(backend);
if (backend_caps & WLR_BUFFER_CAP_DMABUF) { if (backend_caps & WLR_BUFFER_CAP_DMABUF) {
int drm_fd = open_drm_render_node(); if (!pick_drm_render_node(dev_id)) {
if (drm_fd < 0) {
return false; return false;
} }
*drm_fd_ptr = drm_fd; *has_dev_id = true;
*own_drm_fd = true;
return 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; bool is_auto = strcmp(renderer_name, "auto") == 0;
struct wlr_renderer *renderer = NULL; 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 (is_auto || strcmp(renderer_name, "gles2") == 0) {
if (!open_preferred_drm_fd(backend, &drm_fd, &own_drm_fd)) { 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 FD available"); log_creation_failure(is_auto, "Cannot create GLES2 renderer: no DRM device available");
} else { } else {
#if WLR_HAS_GLES2_RENDERER #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 #else
wlr_log(WLR_ERROR, "Cannot create GLES renderer: disabled at compile-time"); wlr_log(WLR_ERROR, "Cannot create GLES renderer: disabled at compile-time");
#endif #endif
@ -242,11 +259,11 @@ static struct wlr_renderer *renderer_autocreate(struct wlr_backend *backend, int
} }
if (strcmp(renderer_name, "vulkan") == 0) { if (strcmp(renderer_name, "vulkan") == 0) {
if (!open_preferred_drm_fd(backend, &drm_fd, &own_drm_fd)) { 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 FD available"); log_creation_failure(is_auto, "Cannot create Vulkan renderer: no DRM device available");
} else { } else {
#if WLR_HAS_VULKAN_RENDERER #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 #else
wlr_log(WLR_ERROR, "Cannot create Vulkan renderer: disabled at compile-time"); wlr_log(WLR_ERROR, "Cannot create Vulkan renderer: disabled at compile-time");
#endif #endif
@ -271,9 +288,6 @@ out:
if (renderer == NULL) { if (renderer == NULL) {
wlr_log(WLR_ERROR, "Could not initialize renderer"); wlr_log(WLR_ERROR, "Could not initialize renderer");
} }
if (own_drm_fd && drm_fd >= 0) {
close(drm_fd);
}
return renderer; return renderer;
} }
@ -287,13 +301,6 @@ struct wlr_renderer *wlr_renderer_autocreate(struct wlr_backend *backend) {
return renderer_autocreate(backend, -1); 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_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 *buffer, const struct wlr_buffer_pass_options *options) {
struct wlr_buffer_pass_options default_options = {0}; struct wlr_buffer_pass_options default_options = {0};

View file

@ -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_drm *wlr_drm_create(struct wl_display *display,
struct wlr_renderer *renderer) { struct wlr_renderer *renderer) {
int drm_fd = wlr_renderer_get_drm_fd(renderer); if (renderer->drm_dev_id == NULL) {
if (drm_fd < 0) { wlr_log(WLR_ERROR, "Failed to get DRM device from renderer");
wlr_log(WLR_ERROR, "Failed to get DRM FD from renderer");
return NULL; return NULL;
} }
drmDevice *dev = NULL; drmDevice *dev = NULL;
if (drmGetDevice2(drm_fd, 0, &dev) != 0) { if (drmGetDeviceFromDevId(*renderer->drm_dev_id, 0, &dev) != 0) {
wlr_log(WLR_ERROR, "drmGetDevice2 failed"); wlr_log(WLR_ERROR, "drmGetDeviceFromDevId failed");
return NULL; return NULL;
} }

View file

@ -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}; *feedback = (struct wlr_linux_dmabuf_feedback_v1){0};
int renderer_drm_fd = wlr_renderer_get_drm_fd(options->main_renderer); if (options->main_renderer->drm_dev_id == NULL) {
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)) {
goto error; goto error;
} }
dev_t renderer_dev = *options->main_renderer->drm_dev_id;
feedback->main_device = renderer_dev; feedback->main_device = renderer_dev;
const struct wlr_drm_format_set *renderer_formats = const struct wlr_drm_format_set *renderer_formats =