You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
8.9 KiB
268 lines
8.9 KiB
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);
|
|
|