Blame SOURCES/d4937adc5cd04ac7df98fc5616e40319fb52fdee.patch

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