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:
Maíra Canal 2024-11-13 08:04:15 -03:00 committed by Marge Bot
parent 2a35d1a13f
commit 2af12c5b36

View file

@ -29,6 +29,7 @@
#include <sys/sysinfo.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
@ -1315,17 +1316,7 @@ create_physical_device(struct v3dv_instance *instance,
#endif
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;
} else {
close(primary_fd);
device->display_fd = -1;
primary_fd = -1;
}
device->display_fd = primary_fd;
if (!v3d_get_device_info(device->render_fd, &device->devinfo, &v3dv_ioctl)) {
result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
@ -1473,10 +1464,76 @@ fail:
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
* allocation error happened) if no compatible device is found. If a
* compatible device is found, it may return an error code if device
* inialization failed.
* initialization failed.
*/
static VkResult
enumerate_devices(struct vk_instance *vk_instance)
@ -1509,12 +1566,10 @@ enumerate_devices(struct vk_instance *vk_instance)
}
#else
/* 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
* buffers and share them with the render node via prime, but that is a
* privileged operation so we need t have an authenticated display fd
* and for that we need the display server to provide the it (with DRI3),
* so here we only check that the device is present but we don't try to
* open it.
* device. We will need to use the display device to allocate WSI
* buffers and share them with the render node via prime. We want to
* allocate the display buffer on the WSI device as the display device
* may not have a MMU (this is true at least on Raspberry Pi 4).
*/
if (devices[i]->bustype != DRM_BUS_PLATFORM)
continue;
@ -1522,7 +1577,7 @@ enumerate_devices(struct vk_instance *vk_instance)
if ((devices[i]->available_nodes & 1 << DRM_NODE_RENDER))
try_device(devices[i]->nodes[DRM_NODE_RENDER], &render_fd, "v3d");
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
if (render_fd >= 0 && primary_fd >= 0)