mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-06-13 14:32:57 -04:00
render/vulkan: add support for split render/display devices
Some systems have a split render/display architecture: the display side is managed by a KMS driver and the render side is managed by a separate Vulkan driver. Figuring out that these two drivers can work together is not trivial. Currently, the Vulkan renderer tries to find a Vulkan physical device which matches the DRM device's dev_t. On split render/display, there is no such device. The platform bus has historically been abused for situations where no other bus would make sense (e.g. VKMS, evdi). A new "faux" bus has been introduced [1] for such devices, so the platform bus should now be a pretty good hint that all devices are on the same system-on-chip. When we don't find a Vulkan physical device and the DRM device is using the platform bus, fall back to any Vulkan physical which also uses the platform bus. [1]: https://lore.kernel.org/all/2025021023-sandstorm-precise-9f5d@gregkh/ Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/work_items/4055
This commit is contained in:
parent
2ab2775743
commit
f141edcd02
1 changed files with 75 additions and 15 deletions
|
|
@ -10,6 +10,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/version.h>
|
||||
|
|
@ -252,6 +253,14 @@ static void log_phdev(const VkPhysicalDeviceProperties *props) {
|
|||
wlr_log(WLR_INFO, " Driver version: %u.%u.%u", dv_major, dv_minor, dv_patch);
|
||||
}
|
||||
|
||||
struct wlr_vk_phdev_info {
|
||||
VkPhysicalDeviceType type;
|
||||
char name[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];
|
||||
|
||||
bool has_drm, has_render;
|
||||
dev_t primary_devid, render_devid;
|
||||
};
|
||||
|
||||
VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd) {
|
||||
VkResult res;
|
||||
uint32_t num_phdevs;
|
||||
|
|
@ -269,12 +278,7 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd)
|
|||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
struct stat drm_stat = {0};
|
||||
if (drm_fd >= 0 && fstat(drm_fd, &drm_stat) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "fstat failed");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
struct wlr_vk_phdev_info devices[1 + num_phdevs];
|
||||
for (uint32_t i = 0; i < num_phdevs; ++i) {
|
||||
VkPhysicalDevice phdev = phdevs[i];
|
||||
|
||||
|
|
@ -330,25 +334,81 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd)
|
|||
wlr_log(WLR_INFO, " Driver name: %s (%s)", driver_props.driverName, driver_props.driverInfo);
|
||||
}
|
||||
|
||||
struct wlr_vk_phdev_info info = {
|
||||
.type = phdev_props.deviceType,
|
||||
.has_drm = has_drm_props,
|
||||
};
|
||||
memcpy(info.name, phdev_props.deviceName, sizeof(phdev_props.deviceName));
|
||||
if (has_drm_props) {
|
||||
info.has_render = drm_props.hasRender;
|
||||
info.primary_devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor);
|
||||
info.render_devid = makedev(drm_props.renderMajor, drm_props.renderMinor);
|
||||
}
|
||||
devices[i] = info;
|
||||
}
|
||||
|
||||
// Find a Vulkan device matching the DRM device's dev_t
|
||||
struct stat drm_stat = {0};
|
||||
if (drm_fd >= 0 && fstat(drm_fd, &drm_stat) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "fstat failed");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_phdevs; ++i) {
|
||||
VkPhysicalDevice phdev = phdevs[i];
|
||||
const struct wlr_vk_phdev_info *info = &devices[i];
|
||||
|
||||
bool found;
|
||||
if (drm_fd >= 0) {
|
||||
if (!has_drm_props) {
|
||||
if (!info->has_drm) {
|
||||
wlr_log(WLR_DEBUG, " Ignoring physical device \"%s\": "
|
||||
"VK_EXT_physical_device_drm not supported",
|
||||
phdev_props.deviceName);
|
||||
"VK_EXT_physical_device_drm not supported", info->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_t primary_devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor);
|
||||
dev_t render_devid = makedev(drm_props.renderMajor, drm_props.renderMinor);
|
||||
found = primary_devid == drm_stat.st_rdev || render_devid == drm_stat.st_rdev;
|
||||
found = info->primary_devid == drm_stat.st_rdev || info->render_devid == drm_stat.st_rdev;
|
||||
} else {
|
||||
found = phdev_props.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU;
|
||||
found = info->type == VK_PHYSICAL_DEVICE_TYPE_CPU;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
wlr_log(WLR_INFO, "Found matching Vulkan physical device: %s",
|
||||
phdev_props.deviceName);
|
||||
wlr_log(WLR_INFO, "Found matching Vulkan physical device: %s", info->name);
|
||||
return phdev;
|
||||
}
|
||||
}
|
||||
|
||||
// If the DRM device we're interested in uses the platform bus, is
|
||||
// KMS-capable, and has no render node associated, search for a sibling
|
||||
// render-capable platform bus device. The platform bus is a good enough
|
||||
// hint that these two devices should be compatible.
|
||||
drmDevice *drm_dev = NULL;
|
||||
if (drmGetDevice2(drm_fd, 0, &drm_dev) != 0) {
|
||||
wlr_log(WLR_ERROR, "drmGetDevice2() failed");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
bool is_platform_lone_kms = drm_dev->bustype == DRM_BUS_PLATFORM &&
|
||||
!(drm_dev->available_nodes & (1 << DRM_NODE_RENDER)) && drmIsKMS(drm_fd);
|
||||
drmFreeDevice(&drm_dev);
|
||||
if (!is_platform_lone_kms) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_phdevs; ++i) {
|
||||
VkPhysicalDevice phdev = phdevs[i];
|
||||
const struct wlr_vk_phdev_info *info = &devices[i];
|
||||
|
||||
if (!info->has_render) {
|
||||
continue;
|
||||
}
|
||||
|
||||
drmDevice *drm_dev = NULL;
|
||||
if (drmGetDeviceFromDevId(info->render_devid, 0, &drm_dev) != 0) {
|
||||
wlr_log(WLR_ERROR, "drmGetDeviceFromDevId() failed");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (drm_dev->bustype == DRM_BUS_PLATFORM) {
|
||||
wlr_log(WLR_INFO, "Found Vulkan physical device on platform bus: %s", info->name);
|
||||
return phdev;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue