Blame SOURCES/d4937adc5cd04ac7df98fc5616e40319fb52fdee.patch

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