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.
*/
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().

View file

@ -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;

View file

@ -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;

View file

@ -10,7 +10,6 @@
#define WLR_RENDER_GLES2_H
#include <GLES2/gl2.h>
#include <wlr/render/wlr_renderer.h>
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);

View file

@ -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,

View file

@ -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);

View file

@ -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.
*

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);
// 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) {

View file

@ -5,6 +5,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <gbm.h>
#include <sys/stat.h>
#include <wlr/render/egl.h>
#include <wlr/util/log.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 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;
}

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);
}
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;

View file

@ -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);
}

View file

@ -2,7 +2,6 @@
#undef _POSIX_C_SOURCE
#endif
#include <assert.h>
#include <fcntl.h>
#include <math.h>
#include <stdlib.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);
}
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);

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 &&
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};

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_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;
}

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};
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 =