mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-22 13:30:12 +01:00
v3dv: Check multiple DRM primary nodes before picking the display fd
Raspberry Pi 5 has different drivers for different types of connectors. For example, HDMI connections are handled through vc4, but DSI connections are handled through drm-rp1-dsi. Currently, we only allow vc4 as display driver, which means that, when we use VK_KHR_display with a DSI display, we won't get any available displays. In order to make sure we have available displays when using DSI/DPI/VEC displays, enumerate all DRM primary nodes and use the first fd that has a connected output. For example, in the case we have only a DSI display connected to the RPi 5, it will pick the drm-rp1-dsi as the device. In the case we have both DSI and HDMI displays connected, it will pick the first fd that it checks. Ideally, we would like to see all displays available in the return of `vkGetPhysicalDeviceDisplayProperties2KHR`, but `wsi->fd` is a variable, not an array. Therefore, it only supports one fd. Signed-off-by: Maíra Canal <mcanal@igalia.com> Reviewed-by: Iago Toral Quiroga <itoral@igalia.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32123>
This commit is contained in:
parent
2a35d1a13f
commit
2af12c5b36
1 changed files with 74 additions and 19 deletions
|
|
@ -29,6 +29,7 @@
|
||||||
#include <sys/sysinfo.h>
|
#include <sys/sysinfo.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
|
#include <xf86drmMode.h>
|
||||||
|
|
||||||
#ifdef MAJOR_IN_MKDEV
|
#ifdef MAJOR_IN_MKDEV
|
||||||
#include <sys/mkdev.h>
|
#include <sys/mkdev.h>
|
||||||
|
|
@ -1315,17 +1316,7 @@ create_physical_device(struct v3dv_instance *instance,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
device->render_fd = render_fd;
|
device->render_fd = render_fd;
|
||||||
if (instance->vk.enabled_extensions.KHR_display ||
|
|
||||||
instance->vk.enabled_extensions.KHR_xcb_surface ||
|
|
||||||
instance->vk.enabled_extensions.KHR_xlib_surface ||
|
|
||||||
instance->vk.enabled_extensions.KHR_wayland_surface ||
|
|
||||||
instance->vk.enabled_extensions.EXT_acquire_drm_display) {
|
|
||||||
device->display_fd = primary_fd;
|
device->display_fd = primary_fd;
|
||||||
} else {
|
|
||||||
close(primary_fd);
|
|
||||||
device->display_fd = -1;
|
|
||||||
primary_fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!v3d_get_device_info(device->render_fd, &device->devinfo, &v3dv_ioctl)) {
|
if (!v3d_get_device_info(device->render_fd, &device->devinfo, &v3dv_ioctl)) {
|
||||||
result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
|
result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
|
||||||
|
|
@ -1473,10 +1464,76 @@ fail:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
try_display_device(struct v3dv_instance *instance, const char *path,
|
||||||
|
int32_t *fd)
|
||||||
|
{
|
||||||
|
bool khr_display = instance->vk.enabled_extensions.KHR_display ||
|
||||||
|
instance->vk.enabled_extensions.EXT_acquire_drm_display;
|
||||||
|
*fd = open(path, O_RDWR | O_CLOEXEC);
|
||||||
|
if (*fd < 0) {
|
||||||
|
fprintf(stderr, "Opening %s failed: %s\n", path, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The display driver must have KMS capabilities */
|
||||||
|
if (!drmIsKMS(*fd))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* If using VK_KHR_display, we require the fd to have a connected output.
|
||||||
|
* We need to use this strategy because Raspberry Pi 5 can load different
|
||||||
|
* drivers for different types of connectors and the one with a connected
|
||||||
|
* output may not be vc4, which unlike Raspberry Pi 4, doesn't drive the
|
||||||
|
* DSI output for example.
|
||||||
|
*/
|
||||||
|
if (!khr_display) {
|
||||||
|
if (instance->vk.enabled_extensions.KHR_xcb_surface ||
|
||||||
|
instance->vk.enabled_extensions.KHR_xlib_surface ||
|
||||||
|
instance->vk.enabled_extensions.KHR_wayland_surface)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the display device isn't the DRM master, we can't get its resources */
|
||||||
|
if (!drmIsMaster(*fd))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
drmModeResPtr mode_res = drmModeGetResources(*fd);
|
||||||
|
if (!mode_res) {
|
||||||
|
fprintf(stderr, "Failed to get DRM mode resources: %s\n", strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeConnection connection = DRM_MODE_DISCONNECTED;
|
||||||
|
|
||||||
|
/* Only use a display device if there is at least one connected connector */
|
||||||
|
for (int c = 0; c < mode_res->count_connectors && connection == DRM_MODE_DISCONNECTED; c++) {
|
||||||
|
drmModeConnectorPtr connector = drmModeGetConnector(*fd, mode_res->connectors[c]);
|
||||||
|
|
||||||
|
if (!connector)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
connection = connector->connection;
|
||||||
|
drmModeFreeConnector(connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeResources(mode_res);
|
||||||
|
|
||||||
|
if (connection == DRM_MODE_DISCONNECTED)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close(*fd);
|
||||||
|
*fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* This driver hook is expected to return VK_SUCCESS (unless a memory
|
/* This driver hook is expected to return VK_SUCCESS (unless a memory
|
||||||
* allocation error happened) if no compatible device is found. If a
|
* allocation error happened) if no compatible device is found. If a
|
||||||
* compatible device is found, it may return an error code if device
|
* compatible device is found, it may return an error code if device
|
||||||
* inialization failed.
|
* initialization failed.
|
||||||
*/
|
*/
|
||||||
static VkResult
|
static VkResult
|
||||||
enumerate_devices(struct vk_instance *vk_instance)
|
enumerate_devices(struct vk_instance *vk_instance)
|
||||||
|
|
@ -1509,12 +1566,10 @@ enumerate_devices(struct vk_instance *vk_instance)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* On actual hardware, we should have a gpu device (v3d) and a display
|
/* On actual hardware, we should have a gpu device (v3d) and a display
|
||||||
* device (vc4). We will need to use the display device to allocate WSI
|
* device. We will need to use the display device to allocate WSI
|
||||||
* buffers and share them with the render node via prime, but that is a
|
* buffers and share them with the render node via prime. We want to
|
||||||
* privileged operation so we need t have an authenticated display fd
|
* allocate the display buffer on the WSI device as the display device
|
||||||
* and for that we need the display server to provide the it (with DRI3),
|
* may not have a MMU (this is true at least on Raspberry Pi 4).
|
||||||
* so here we only check that the device is present but we don't try to
|
|
||||||
* open it.
|
|
||||||
*/
|
*/
|
||||||
if (devices[i]->bustype != DRM_BUS_PLATFORM)
|
if (devices[i]->bustype != DRM_BUS_PLATFORM)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1522,7 +1577,7 @@ enumerate_devices(struct vk_instance *vk_instance)
|
||||||
if ((devices[i]->available_nodes & 1 << DRM_NODE_RENDER))
|
if ((devices[i]->available_nodes & 1 << DRM_NODE_RENDER))
|
||||||
try_device(devices[i]->nodes[DRM_NODE_RENDER], &render_fd, "v3d");
|
try_device(devices[i]->nodes[DRM_NODE_RENDER], &render_fd, "v3d");
|
||||||
if ((devices[i]->available_nodes & 1 << DRM_NODE_PRIMARY))
|
if ((devices[i]->available_nodes & 1 << DRM_NODE_PRIMARY))
|
||||||
try_device(devices[i]->nodes[DRM_NODE_PRIMARY], &primary_fd, "vc4");
|
try_display_device(instance, devices[i]->nodes[DRM_NODE_PRIMARY], &primary_fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (render_fd >= 0 && primary_fd >= 0)
|
if (render_fd >= 0 && primary_fd >= 0)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue