diff options
| -rw-r--r-- | include/render/vulkan.h | 1 | ||||
| -rw-r--r-- | render/vulkan/renderer.c | 6 | ||||
| -rw-r--r-- | render/vulkan/vulkan.c | 50 | 
3 files changed, 54 insertions, 3 deletions
| diff --git a/include/render/vulkan.h b/include/render/vulkan.h index 66739c40..d61db616 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -66,6 +66,7 @@ struct wlr_vk_device {  // Tries to find the VkPhysicalDevice for the given drm fd.  // 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);  // Creates a device for the given instance and physical device.  struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini, diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 4e326c69..667301f9 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -2240,10 +2240,10 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) {  		return NULL;  	} -	// We duplicate it so it's not closed while we still need it. -	dev->drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); +	// 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) { -		wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");  		vulkan_device_destroy(dev);  		vulkan_instance_destroy(ini);  		return NULL; diff --git a/render/vulkan/vulkan.c b/render/vulkan/vulkan.c index 3849da66..418b7c8c 100644 --- a/render/vulkan/vulkan.c +++ b/render/vulkan/vulkan.c @@ -1,4 +1,8 @@ +#if !defined(__FreeBSD__) +#define _POSIX_C_SOURCE 200809L +#endif  #include <assert.h> +#include <fcntl.h>  #include <math.h>  #include <stdlib.h>  #include <stdint.h> @@ -366,6 +370,52 @@ 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) { +	// vulkan_find_drm_phdev() already checks that VK_EXT_physical_device_drm +	// is supported +	VkPhysicalDeviceDrmPropertiesEXT drm_props = { +		.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT, +	}; +	VkPhysicalDeviceProperties2 props = { +		.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, +		.pNext = &drm_props, +	}; +	vkGetPhysicalDeviceProperties2(phdev, &props); + +	dev_t devid; +	if (drm_props.hasRender) { +		devid = makedev(drm_props.renderMajor, drm_props.renderMinor); +	} else if (drm_props.hasPrimary) { +		devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor); +	} else { +		wlr_log(WLR_ERROR, "Physical device is missing both render and primary nodes"); +		return -1; +	} + +	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; +} +  static void load_device_proc(struct wlr_vk_device *dev, const char *name,  		void *proc_ptr) {  	void *proc = (void *)vkGetDeviceProcAddr(dev->dev, name); | 
