summaryrefslogtreecommitdiff
path: root/d4937adc5cd04ac7df98fc5616e40319fb52fdee.patch
diff options
context:
space:
mode:
Diffstat (limited to 'd4937adc5cd04ac7df98fc5616e40319fb52fdee.patch')
-rw-r--r--d4937adc5cd04ac7df98fc5616e40319fb52fdee.patch268
1 files changed, 268 insertions, 0 deletions
diff --git a/d4937adc5cd04ac7df98fc5616e40319fb52fdee.patch b/d4937adc5cd04ac7df98fc5616e40319fb52fdee.patch
new file mode 100644
index 0000000..48845f9
--- /dev/null
+++ b/d4937adc5cd04ac7df98fc5616e40319fb52fdee.patch
@@ -0,0 +1,268 @@
+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);