269 lines
8.9 KiB
Diff
269 lines
8.9 KiB
Diff
From d4937adc5cd04ac7df98fc5616e40319fb52fdee Mon Sep 17 00:00:00 2001
|
|
From: Austin Shafer <ashafer@nvidia.com>
|
|
Date: Wed, 27 Oct 2021 06:37:07 -0400
|
|
Subject: [PATCH] wayland: Fail eglGetDisplay if wl_drm is not available
|
|
|
|
This patch does two things:
|
|
- checks if wl_drm is in use on the server, and uses it to get the name
|
|
of the drm device the compositor is driving.
|
|
- Find an EGLDevice that matches the path returned by wl_drm.
|
|
|
|
If wl_drm and the needed extensions are not present, or if a matching
|
|
EGLDevice is not found, then we fail. Right now we only support
|
|
running on the same GPU as the compositor, so any of these being
|
|
missing means that is not the case.
|
|
---
|
|
src/wayland-egldisplay.c | 153 +++++++++++++++++++++++++++++++++++----
|
|
1 file changed, 138 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/src/wayland-egldisplay.c b/src/wayland-egldisplay.c
|
|
index a0370a5..8b7394a 100644
|
|
--- a/src/wayland-egldisplay.c
|
|
+++ b/src/wayland-egldisplay.c
|
|
@@ -29,13 +29,19 @@
|
|
#include "wayland-eglsurface.h"
|
|
#include "wayland-eglhandle.h"
|
|
#include "wayland-eglutils.h"
|
|
+#include "wayland-drm-client-protocol.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
+#include <unistd.h>
|
|
+#include <fcntl.h>
|
|
|
|
typedef struct WlServerProtocolsRec {
|
|
EGLBoolean hasEglStream;
|
|
EGLBoolean hasDmaBuf;
|
|
+ EGLBoolean hasDrm;
|
|
+ struct wl_drm *wldrm;
|
|
+ char *drm_name;
|
|
} WlServerProtocols;
|
|
|
|
/* TODO: Make global display lists hang off platform data */
|
|
@@ -241,6 +247,40 @@ static const struct wl_registry_listener registry_listener = {
|
|
registry_handle_global_remove
|
|
};
|
|
|
|
+static void wl_drm_device(void *data, struct wl_drm *wl_drm, const char *name)
|
|
+{
|
|
+ WlServerProtocols *protocols = (WlServerProtocols *)data;
|
|
+ (void) wl_drm;
|
|
+
|
|
+ protocols->drm_name = strdup(name);
|
|
+}
|
|
+
|
|
+static void wl_drm_authenticated(void *data, struct wl_drm *wl_drm)
|
|
+{
|
|
+ (void) data;
|
|
+ (void) wl_drm;
|
|
+}
|
|
+static void wl_drm_format(void *data, struct wl_drm *wl_drm, uint32_t format)
|
|
+{
|
|
+ (void) data;
|
|
+ (void) wl_drm;
|
|
+ (void) format;
|
|
+}
|
|
+static void wl_drm_capabilities(void *data, struct wl_drm *wl_drm, uint32_t value)
|
|
+{
|
|
+ (void) data;
|
|
+ (void) wl_drm;
|
|
+ (void) value;
|
|
+}
|
|
+
|
|
+static const struct wl_drm_listener drmListener = {
|
|
+ .device = wl_drm_device,
|
|
+ .authenticated = wl_drm_authenticated,
|
|
+ .format = wl_drm_format,
|
|
+ .capabilities = wl_drm_capabilities,
|
|
+};
|
|
+
|
|
+
|
|
static void
|
|
registry_handle_global_check_protocols(
|
|
void *data,
|
|
@@ -262,6 +302,12 @@ registry_handle_global_check_protocols(
|
|
(version >= 3)) {
|
|
protocols->hasDmaBuf = EGL_TRUE;
|
|
}
|
|
+
|
|
+ if ((strcmp(interface, "wl_drm") == 0) && (version >= 2)) {
|
|
+ protocols->hasDrm = EGL_TRUE;
|
|
+ protocols->wldrm = wl_registry_bind(registry, name, &wl_drm_interface, 2);
|
|
+ wl_drm_add_listener(protocols->wldrm, &drmListener, protocols);
|
|
+ }
|
|
}
|
|
|
|
static void
|
|
@@ -389,8 +435,8 @@ EGLBoolean wlEglTerminateHook(EGLDisplay dpy)
|
|
return res;
|
|
}
|
|
|
|
-static void checkServerProtocols(struct wl_display *nativeDpy,
|
|
- WlServerProtocols *protocols)
|
|
+static void getServerProtocolsInfo(struct wl_display *nativeDpy,
|
|
+ WlServerProtocols *protocols)
|
|
{
|
|
struct wl_display *wrapper = NULL;
|
|
struct wl_registry *wlRegistry = NULL;
|
|
@@ -418,6 +464,11 @@ static void checkServerProtocols(struct wl_display *nativeDpy,
|
|
protocols);
|
|
if (ret == 0) {
|
|
wl_display_roundtrip_queue(nativeDpy, queue);
|
|
+ if (protocols->hasDrm) {
|
|
+ wl_display_roundtrip_queue(nativeDpy, queue);
|
|
+ /* destroy our wl_drm object */
|
|
+ wl_drm_destroy(protocols->wldrm);
|
|
+ }
|
|
}
|
|
|
|
if (queue) {
|
|
@@ -438,9 +489,13 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data,
|
|
WlServerProtocols protocols;
|
|
EGLint numDevices = 0;
|
|
int i = 0;
|
|
+ EGLDeviceEXT *eglDeviceList = NULL;
|
|
EGLDeviceEXT eglDevice = NULL;
|
|
+ EGLDeviceEXT tmpDev = NULL;
|
|
EGLint err = EGL_SUCCESS;
|
|
EGLBoolean useInitRefCount = EGL_FALSE;
|
|
+ const char *dev_exts;
|
|
+ const char *dev_name;
|
|
|
|
if (platform != EGL_PLATFORM_WAYLAND_EXT) {
|
|
wlEglSetError(data, EGL_BAD_PARAMETER);
|
|
@@ -480,7 +535,6 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data,
|
|
|
|
display = calloc(1, sizeof(*display));
|
|
if (!display) {
|
|
- wlExternalApiUnlock();
|
|
err = EGL_BAD_ALLOC;
|
|
goto fail;
|
|
}
|
|
@@ -498,7 +552,6 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data,
|
|
if (!display->nativeDpy) {
|
|
display->nativeDpy = wl_display_connect(NULL);
|
|
if (!display->nativeDpy) {
|
|
- wlExternalApiUnlock();
|
|
err = EGL_BAD_ALLOC;
|
|
goto fail;
|
|
}
|
|
@@ -508,26 +561,85 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data,
|
|
}
|
|
|
|
memset(&protocols, 0, sizeof(protocols));
|
|
- checkServerProtocols(display->nativeDpy, &protocols);
|
|
+ /*
|
|
+ * This is where we check the supported protocols on the compositor,
|
|
+ * and bind to wl_drm to get the device name.
|
|
+ * protocols.drm_name will be allocated here if using wl_drm
|
|
+ */
|
|
+ getServerProtocolsInfo(display->nativeDpy, &protocols);
|
|
|
|
- if (!protocols.hasEglStream && !protocols.hasDmaBuf) {
|
|
- wlExternalApiUnlock();
|
|
- goto fail;
|
|
+ if (!protocols.hasDrm || (!protocols.hasEglStream && !protocols.hasDmaBuf)) {
|
|
+ goto fail_cleanup_protocols;
|
|
}
|
|
|
|
- if (!pData->egl.queryDevices(1, &eglDevice, &numDevices) || numDevices == 0) {
|
|
- wlExternalApiUnlock();
|
|
- goto fail;
|
|
+ /* Get the number of devices available */
|
|
+ if (!pData->egl.queryDevices(-1, NULL, &numDevices) || numDevices == 0) {
|
|
+ goto fail_cleanup_protocols;
|
|
+ }
|
|
+
|
|
+ eglDeviceList = calloc(numDevices, sizeof(*eglDeviceList));
|
|
+ if (!eglDeviceList) {
|
|
+ goto fail_cleanup_protocols;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Now we need to find an EGLDevice. If wl_drm is in use we will try to find one that
|
|
+ * matches the device the compositor is using. We know that device is an nvidia device
|
|
+ * since we just checked that above.
|
|
+ */
|
|
+ if (!pData->egl.queryDevices(numDevices, eglDeviceList, &numDevices) || numDevices == 0) {
|
|
+ goto fail_cleanup_devices;
|
|
}
|
|
+
|
|
+ if (protocols.drm_name) {
|
|
+ for (int i = 0; i < numDevices; i++) {
|
|
+ tmpDev = eglDeviceList[i];
|
|
+
|
|
+ /*
|
|
+ * To check against the wl_drm name, we need to check if we can use
|
|
+ * the drm extension
|
|
+ */
|
|
+ dev_exts = display->data->egl.queryDeviceString(tmpDev,
|
|
+ EGL_EXTENSIONS);
|
|
+ if (dev_exts) {
|
|
+ if (wlEglFindExtension("EGL_EXT_device_drm_render_node", dev_exts)) {
|
|
+ dev_name =
|
|
+ display->data->egl.queryDeviceString(tmpDev,
|
|
+ EGL_DRM_RENDER_NODE_FILE_EXT);
|
|
+
|
|
+ if (dev_name) {
|
|
+ /*
|
|
+ * At this point we have gotten the name from wl_drm, gotten
|
|
+ * the drm node from the EGLDevice. If they match, then
|
|
+ * this is the final device to use, since it is the compositor's
|
|
+ * device.
|
|
+ */
|
|
+ if (strcmp(dev_name, protocols.drm_name) == 0) {
|
|
+ eglDevice = eglDeviceList[0];
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Right now we are pretty much limited to running on the same GPU as the
|
|
+ * compositor. If we couldn't find an EGLDevice that has EGL_EXT_device_drm_render_node
|
|
+ * and the same DRM device path, then fail.
|
|
+ */
|
|
+ if (!eglDevice) {
|
|
+ goto fail_cleanup_devices;
|
|
+ }
|
|
+
|
|
display->devDpy = wlGetInternalDisplay(pData, eglDevice);
|
|
if (display->devDpy == NULL) {
|
|
- wlExternalApiUnlock();
|
|
- goto fail;
|
|
+ goto fail_cleanup_devices;
|
|
}
|
|
|
|
if (!wlEglInitializeMutex(&display->mutex)) {
|
|
- wlExternalApiUnlock();
|
|
- goto fail;
|
|
+ goto fail_cleanup_devices;
|
|
}
|
|
display->refCount = 1;
|
|
WL_LIST_INIT(&display->wlEglSurfaceList);
|
|
@@ -537,10 +649,21 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data,
|
|
// in wlEglDisplayList.
|
|
wl_list_insert(&wlEglDisplayList, &display->link);
|
|
|
|
+ free(eglDeviceList);
|
|
+ if (protocols.drm_name) {
|
|
+ free(protocols.drm_name);
|
|
+ }
|
|
wlExternalApiUnlock();
|
|
return display;
|
|
|
|
+fail_cleanup_devices:
|
|
+ free(eglDeviceList);
|
|
+fail_cleanup_protocols:
|
|
+ if (protocols.drm_name) {
|
|
+ free(protocols.drm_name);
|
|
+ }
|
|
fail:
|
|
+ wlExternalApiUnlock();
|
|
|
|
if (display->ownNativeDpy) {
|
|
wl_display_disconnect(display->nativeDpy);
|