diff --git a/0001-Add-a-capability-override-mechanism.patch b/0001-Add-a-capability-override-mechanism.patch new file mode 100644 index 0000000000000000000000000000000000000000..d887981743b6c0f7a1c1f9f4e93b7fb256537b42 --- /dev/null +++ b/0001-Add-a-capability-override-mechanism.patch @@ -0,0 +1,147 @@ +From b045a12334433213cf44736da727ac36df8ca58c Mon Sep 17 00:00:00 2001 +From: "Miguel A. Vico" +Date: Fri, 30 Nov 2018 15:21:28 -0800 +Subject: [PATCH] Add a capability override mechanism + +libnvidia-egl-wayland.so uses one method or another to create the +underlying EGLStream for a given EGLSurface according to the set of +capabilities advertised by the server, which in turn depend on the +available driver extensions. + +This change adds an environment variable to override the server +capabilities so we can force a specific stream creation method. + +Signed-off-by: Ashutosh Agarwal +--- + include/wayland-eglstream-server.h | 3 ++ + src/wayland-eglstream-server.c | 54 ++++++++++++++++++------------ + src/wayland-eglstream.c | 6 ++-- + 3 files changed, 40 insertions(+), 23 deletions(-) + +diff --git a/include/wayland-eglstream-server.h b/include/wayland-eglstream-server.h +index c4a75c4..0a983c8 100644 +--- a/include/wayland-eglstream-server.h ++++ b/include/wayland-eglstream-server.h +@@ -92,6 +92,9 @@ struct wl_eglstream_display { + int stream_socket_unix : 1; + } exts; + ++ int caps_override : 1; ++ int supported_caps; ++ + struct wl_buffer_interface wl_eglstream_interface; + + struct wl_list link; +diff --git a/src/wayland-eglstream-server.c b/src/wayland-eglstream-server.c +index 6218c9b..76990ad 100644 +--- a/src/wayland-eglstream-server.c ++++ b/src/wayland-eglstream-server.c +@@ -244,9 +244,8 @@ wl_eglstream_display_global_bind(struct wl_client *client, + uint32_t version, + uint32_t id) + { +- struct wl_eglstream_display *wlStreamDpy = NULL; +- struct wl_resource *resource = NULL; +- int caps = 0; ++ struct wl_eglstream_display *wlStreamDpy = NULL; ++ struct wl_resource *resource = NULL; + + wlStreamDpy = (struct wl_eglstream_display *)data; + resource = wl_resource_create(client, +@@ -263,21 +262,8 @@ wl_eglstream_display_global_bind(struct wl_client *client, + data, + NULL); + +- /* Advertise server capabilities */ +- if (wlStreamDpy->exts.stream_cross_process_fd) { +- caps |= WL_EGLSTREAM_DISPLAY_CAP_STREAM_FD; +- } +- if (wlStreamDpy->exts.stream_attrib && +- wlStreamDpy->exts.stream_remote && +- wlStreamDpy->exts.stream_socket) { +- if (wlStreamDpy->exts.stream_socket_inet) { +- caps |= WL_EGLSTREAM_DISPLAY_CAP_STREAM_INET; +- } +- if (wlStreamDpy->exts.stream_socket_unix) { +- caps |= WL_EGLSTREAM_DISPLAY_CAP_STREAM_SOCKET; +- } +- } +- wl_eglstream_display_send_caps(resource, caps); ++ ++ wl_eglstream_display_send_caps(resource, wlStreamDpy->supported_caps); + } + + EGLBoolean +@@ -287,6 +273,7 @@ wl_eglstream_display_bind(WlEglPlatformData *data, + { + struct wl_eglstream_display *wlStreamDpy = NULL; + const char *exts = NULL; ++ char *env = NULL; + + /* Check whether there's an EGLDisplay already bound to the given + * wl_display */ +@@ -299,9 +286,10 @@ wl_eglstream_display_bind(WlEglPlatformData *data, + return EGL_FALSE; + } + +- wlStreamDpy->data = data; +- wlStreamDpy->wlDisplay = wlDisplay; +- wlStreamDpy->eglDisplay = eglDisplay; ++ wlStreamDpy->data = data; ++ wlStreamDpy->wlDisplay = wlDisplay; ++ wlStreamDpy->eglDisplay = eglDisplay; ++ wlStreamDpy->caps_override = 0; + + exts = data->egl.queryString(eglDisplay, EGL_EXTENSIONS); + +@@ -318,6 +306,30 @@ wl_eglstream_display_bind(WlEglPlatformData *data, + + #undef CACHE_EXT + ++ /* Advertise server capabilities */ ++ if (wlStreamDpy->exts.stream_cross_process_fd) { ++ wlStreamDpy->supported_caps |= WL_EGLSTREAM_DISPLAY_CAP_STREAM_FD; ++ } ++ if (wlStreamDpy->exts.stream_attrib && ++ wlStreamDpy->exts.stream_remote && ++ wlStreamDpy->exts.stream_socket) { ++ if (wlStreamDpy->exts.stream_socket_inet) { ++ wlStreamDpy->supported_caps |= WL_EGLSTREAM_DISPLAY_CAP_STREAM_INET; ++ } ++ if (wlStreamDpy->exts.stream_socket_unix) { ++ wlStreamDpy->supported_caps |= WL_EGLSTREAM_DISPLAY_CAP_STREAM_SOCKET; ++ } ++ } ++ ++ env = getenv("WL_EGLSTREAM_CAP_OVERRIDE"); ++ if (env) { ++ int serverCapOverride = atoi(env); ++ wlStreamDpy->caps_override = (wlStreamDpy->supported_caps ++ & serverCapOverride) != ++ wlStreamDpy->supported_caps; ++ wlStreamDpy->supported_caps &= serverCapOverride; ++ } ++ + wlStreamDpy->wl_eglstream_interface.destroy = destroy_wl_eglstream; + wlStreamDpy->global = wl_global_create(wlDisplay, + &wl_eglstream_display_interface, 1, +diff --git a/src/wayland-eglstream.c b/src/wayland-eglstream.c +index 5b4b0ac..9be391d 100644 +--- a/src/wayland-eglstream.c ++++ b/src/wayland-eglstream.c +@@ -113,8 +113,10 @@ EGLStreamKHR wlEglCreateStreamAttribHook(EGLDisplay dpy, + /* eglCreateStreamFromFileDescriptorKHR from + * EGL_KHR_stream_cross_process_fd does not take attributes. Thus, only + * EGL_WAYLAND_EGLSTREAM_WL should have been specified and processed +- * above. */ +- if (nAttribs != 0) { ++ * above. caps_override is an exception to this, since the wayland ++ * compositor calling into this function wouldn't be aware of an ++ * override in place */ ++ if (nAttribs != 0 && !wlStreamDpy->caps_override) { + err = EGL_BAD_ATTRIBUTE; + goto fail; + } +-- +2.42.0.windows.2 + diff --git a/0001-Build-with-Wall-Werror.patch b/0001-Build-with-Wall-Werror.patch new file mode 100644 index 0000000000000000000000000000000000000000..768ac7e273102b92c0c9a27d9d77c8c98a343f1f --- /dev/null +++ b/0001-Build-with-Wall-Werror.patch @@ -0,0 +1,68 @@ +From 6d43a263ef6a5f327213fd3baa76ceea327e1cca Mon Sep 17 00:00:00 2001 +From: "Miguel A. Vico" +Date: Fri, 30 Nov 2018 14:18:58 -0800 +Subject: [PATCH] Build with -Wall -Werror + +--- + configure.ac | 2 +- + src/meson.build | 14 +++++--------- + src/wayland-eglsurface.c | 2 +- + 3 files changed, 7 insertions(+), 11 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 6d84b0a..90605f8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -87,7 +87,7 @@ AX_CHECK_LINK_FLAG([-Xlinker --no-undefined], + [AC_SUBST([LINKER_FLAG_NO_UNDEFINED], [""])]) + + # Default CFLAGS +-CFLAGS="$CFLAGS -Wall -Wno-deprecated-declarations -Werror -include config.h" ++CFLAGS="$CFLAGS -Wall -Werror -include config.h" + + PKG_NOARCH_INSTALLDIR + +diff --git a/src/meson.build b/src/meson.build +index af9775f..50b50ef 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -4,18 +4,14 @@ else + libdl = [] + endif + ++add_project_arguments('-Wall', language : 'c') ++add_project_arguments('-Werror', language : 'c') + add_project_arguments('-fvisibility=hidden', language : 'c') + add_project_link_arguments('-Wl,-Bsymbolic', language : 'c') + +-foreach arg : [ +- 'unused-parameter', +- 'pedantic', +- 'deprecated-declarations', +- ] +- if cc.has_argument('-W' + arg) +- add_project_arguments('-Wno-' + arg, language : 'c') +- endif +-endforeach ++if cc.has_argument('-Wpedantic') ++ add_project_arguments('-Wno-pedantic', language : 'c') ++endif + + src = [ + 'wayland-api-lock.c', +diff --git a/src/wayland-eglsurface.c b/src/wayland-eglsurface.c +index 531eaf2..6dc5b54 100644 +--- a/src/wayland-eglsurface.c ++++ b/src/wayland-eglsurface.c +@@ -84,7 +84,7 @@ wayland_throttleCallback(void *data, + + surface->throttleCallback = NULL; + wl_callback_destroy(callback); +-}; ++} + + static const struct wl_callback_listener throttle_listener = { + wayland_throttleCallback +-- +2.42.0.windows.2 + diff --git a/0001-Create-per-thread-wl_event_queues-and-use-proxy-wrap.patch b/0001-Create-per-thread-wl_event_queues-and-use-proxy-wrap.patch new file mode 100644 index 0000000000000000000000000000000000000000..1580664c98d76cbaf5bbbbe6e049c35e1edc76b4 --- /dev/null +++ b/0001-Create-per-thread-wl_event_queues-and-use-proxy-wrap.patch @@ -0,0 +1,1015 @@ +From bebe74982837be5fe4c7036b7e84a582bc38d19f Mon Sep 17 00:00:00 2001 +From: "Miguel A. Vico" +Date: Fri, 30 Nov 2018 15:00:17 -0800 +Subject: [PATCH] Create per-thread wl_event_queues and use proxy wrappers + +Our Wayland interaction model was written so that we would use a +separate per-display event queue. This was done to make sure responses +to requests originated from EGL were only handled by EGL, without +interfering with application requests or events. This approach is +suggested in Wayland's documentation: + + https://wayland.freedesktop.org/docs/html/apb.html#Client-classwl__display + +However, on a multi-threaded environment, using the same queue for all +threads may cause similar interaction issues, even when those threads +are internal to the EGL Wayland library. An example of that in our +implementation is when using EGL_NV_stream_fifo_synchronous, where we +employ a separate damage thread to monitor when images are finished and +notify the compositor. In that scenario, we would use a separate event +queue for the damage thread to avoid bad interactions with the main +thread. + +The problem with the above model is that we never took into account +multi-threaded environments when threads are originated at the +application level. The EGL specification does not forbid the same +EGLDisplay to be used by different threads within the same application. +Only different contexts are required. + +Therefore, given that we would use per-display event queues instead of +per-thread queues, we would make all threads share the same queues, with +higher chances of causing bad interactions between them. + +This change fixes this threading issue by creating per-thread event +queues and making use of proxy wrappers. +--- + Makefile.am | 2 +- + include/wayland-egldisplay.h | 6 +- + include/wayland-eglhandle.h | 4 + + include/wayland-eglsurface.h | 5 +- + include/wayland-thread.h | 87 ++++++++++++++++ + src/meson.build | 2 +- + src/wayland-egldisplay.c | 82 ++++++++------- + src/wayland-eglhandle.c | 2 +- + src/wayland-eglstream.c | 2 +- + src/wayland-eglsurface.c | 188 +++++++++++++++++++++-------------- + src/wayland-eglswap.c | 29 ++++-- + src/wayland-eglutils.c | 2 +- + src/wayland-thread.c | 148 +++++++++++++++++++++++++++ + 13 files changed, 424 insertions(+), 135 deletions(-) + create mode 100644 include/wayland-thread.h + create mode 100644 src/wayland-thread.c + +diff --git a/Makefile.am b/Makefile.am +index 70bcfc9..eda81ee 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -28,7 +28,7 @@ libnvidia_egl_wayland_la_LDFLAGS = + $(LINKER_FLAG_NO_UNDEFINED) + + libnvidia_egl_wayland_la_SOURCES = \ +- src/wayland-api-lock.c \ ++ src/wayland-thread.c \ + src/wayland-egldisplay.c \ + src/wayland-eglstream.c \ + src/wayland-eglstream-server.c \ +diff --git a/include/wayland-egldisplay.h b/include/wayland-egldisplay.h +index 713a32b..0630e8b 100644 +--- a/include/wayland-egldisplay.h ++++ b/include/wayland-egldisplay.h +@@ -48,11 +48,6 @@ typedef struct WlEglDisplayRec { + EGLBoolean ownNativeDpy; + struct wl_display *nativeDpy; + +- // wlQueue is used by main thread along with display sync points or frame syncpoint +- // depending upon where it is used +- struct wl_event_queue *wlQueue; +- // wlDamageEventQueue is only used by damage_thread along with display sync points +- struct wl_event_queue *wlDamageEventQueue; + struct wl_registry *wlRegistry; + struct wl_eglstream_display *wlStreamDpy; + struct wl_eglstream_controller *wlStreamCtl; +@@ -106,6 +101,7 @@ const char* wlEglQueryStringExport(void *data, + EGLDisplay dpy, + EGLExtPlatformString name); + ++struct wl_event_queue* wlGetEventQueue(struct wl_display *display); + int wlEglRoundtrip(WlEglDisplay *display, struct wl_event_queue *queue); + + #ifdef __cplusplus +diff --git a/include/wayland-eglhandle.h b/include/wayland-eglhandle.h +index 27e7c8c..d0f506d 100644 +--- a/include/wayland-eglhandle.h ++++ b/include/wayland-eglhandle.h +@@ -27,6 +27,7 @@ + #include + #include "wayland-external-exports.h" + #include "wayland-egl-ext.h" ++#include + + #ifdef __cplusplus + extern "C" { +@@ -111,6 +112,9 @@ typedef struct WlEglPlatformDataRec { + PEGLEXTFNSETERROR setError; + PEGLEXTFNSTREAMSWAPINTERVAL streamSwapInterval; + } callbacks; ++ ++ /* pthread key for TLS */ ++ pthread_key_t tlsKey; + } WlEglPlatformData; + + +diff --git a/include/wayland-eglsurface.h b/include/wayland-eglsurface.h +index 50ff2eb..79cbbfa 100644 +--- a/include/wayland-eglsurface.h ++++ b/include/wayland-eglsurface.h +@@ -72,6 +72,8 @@ typedef struct WlEglSurfaceRec { + struct wl_callback *throttleCallback; + + struct wl_list link; ++ ++ EGLBoolean isSurfaceProducer; + } WlEglSurface; + + extern struct wl_list wlEglSurfaceList; +@@ -102,7 +104,8 @@ EGLBoolean wlEglQueryNativeResourceHook(EGLDisplay dpy, + EGLint attribute, + int *value); + +-EGLBoolean wlEglSendDamageEvent(WlEglSurface *surface); ++EGLBoolean wlEglSendDamageEvent(WlEglSurface *surface, ++ struct wl_event_queue *queue); + + void wlEglCreateFrameSync(WlEglSurface *surface, struct wl_event_queue *queue); + EGLint wlEglWaitFrameSync(WlEglSurface *surface, struct wl_event_queue *queue); +diff --git a/include/wayland-thread.h b/include/wayland-thread.h +new file mode 100644 +index 0000000..caf3064 +--- /dev/null ++++ b/include/wayland-thread.h +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef WAYLAND_THREAD_H ++#define WAYLAND_THREAD_H ++ ++#include ++ ++/* ++ * wlExternalApiLock() ++ * ++ * Tries to acquire the external API lock. If the lock is already acquired by ++ * another thread, it will block until the lock is released. ++ * ++ * Calling this function twice without calling wlExternalApiUnlock() in between ++ * will fail. ++ * ++ * First call to wlExternalApiLock() will initialize the external API lock ++ * resources. ++ * ++ * Returns 0 upon success; otherwise returns -1. ++ */ ++int wlExternalApiLock(void); ++ ++/* ++ * wlExternalApiUnlock() ++ * ++ * Releases the external API lock. ++ * ++ * Calling this function without a previous call to wlExternalApiLock() will ++ * fail. ++ * ++ * Returns 0 upon success; otherwise returns -1. ++ */ ++int wlExternalApiUnlock(void); ++ ++/* ++ * wlExternalApiDestroyLock() ++ * ++ * Releases and frees the the external API lock resources. This call should only ++ * be called as part of the global teardown. ++ */ ++void wlExternalApiDestroyLock(void); ++ ++/* ++ * WlThread structure ++ * ++ * Keeps all thread-specific data required by the Wayland external platform ++ * implementation to manage resources relevant to multi-threaded environments. ++ */ ++typedef struct WlThreadRec { ++ struct wl_event_queue *queue; ++} WlThread; ++ ++ ++/* ++ * wlEglGetThread() ++ * ++ * Returns the current thread's WlThread storage. If it doesn't exist yet, it ++ * creates it. Callers don't need to worry about destroying the returned storage ++ * data since proper global destructors are set up. ++ * ++ * Returns a pointer to the thread's WlThread storage upon success; otherwise, ++ * returns NULL. ++ */ ++WlThread* wlGetThread(void); ++ ++#endif +diff --git a/src/meson.build b/src/meson.build +index 50b50ef..2482e33 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -14,7 +14,7 @@ if cc.has_argument('-Wpedantic') + endif + + src = [ +- 'wayland-api-lock.c', ++ 'wayland-thread.c', + 'wayland-egldisplay.c', + 'wayland-eglstream.c', + 'wayland-eglstream-server.c', +diff --git a/src/wayland-egldisplay.c b/src/wayland-egldisplay.c +index a7c0c12..326a180 100644 +--- a/src/wayland-egldisplay.c ++++ b/src/wayland-egldisplay.c +@@ -24,7 +24,7 @@ + #include "wayland-eglstream-client-protocol.h" + #include "wayland-eglstream-controller-client-protocol.h" + #include "wayland-eglstream-server.h" +-#include "wayland-api-lock.h" ++#include "wayland-thread.h" + #include "wayland-eglsurface.h" + #include "wayland-eglhandle.h" + #include "wayland-eglutils.h" +@@ -195,28 +195,40 @@ static const struct wl_callback_listener sync_listener = { + sync_callback + }; + ++struct wl_event_queue* wlGetEventQueue(struct wl_display *display) ++{ ++ WlThread *wlThread = wlGetThread(); ++ struct wl_event_queue *queue = NULL; ++ ++ if (wlThread != NULL) { ++ if (wlThread->queue == NULL) { ++ wlThread->queue = wl_display_create_queue(display); ++ } ++ queue = wlThread->queue; ++ } ++ ++ return queue; ++} ++ + int wlEglRoundtrip(WlEglDisplay *display, struct wl_event_queue *queue) + { ++ struct wl_display *wrapper; + struct wl_callback *callback; + int ret = 0, done = 0; + +- callback = wl_display_sync(display->nativeDpy); +- wl_proxy_set_queue((struct wl_proxy *)callback, queue); ++ wrapper = wl_proxy_create_wrapper(display->nativeDpy); ++ wl_proxy_set_queue((struct wl_proxy *)wrapper, queue); ++ callback = wl_display_sync(wrapper); ++ wl_proxy_wrapper_destroy(wrapper); /* Done with wrapper */ + ret = wl_callback_add_listener(callback, &sync_listener, &done); + + while (ret != -1 && !done) { + /* We are handing execution control over to Wayland here, so we need to + * release the lock just in case it re-enters the external platform (e.g + * calling into EGL or any of the configured wayland callbacks) +- * +- * XXX: Note that we are using display->wlQueue. If another +- * thread destroys display while we are still dispatching +- * events, it will become invalid. We need finer-grained locks to +- * solve this issue. + */ + wlExternalApiUnlock(); +- ret = wl_display_dispatch_queue(display->nativeDpy, +- queue); ++ ret = wl_display_dispatch_queue(display->nativeDpy, queue); + wlExternalApiLock(); + } + +@@ -258,12 +270,6 @@ static EGLBoolean terminateDisplay(EGLDisplay dpy, EGLBoolean skipDestroy) + if (display->wlRegistry) { + wl_registry_destroy(display->wlRegistry); + } +- if (display->wlQueue) { +- wl_event_queue_destroy(display->wlQueue); +- } +- if (display->wlDamageEventQueue) { +- wl_event_queue_destroy(display->wlDamageEventQueue); +- } + if (display->wlStreamDpy) { + wl_eglstream_display_destroy(display->wlStreamDpy); + } +@@ -327,14 +333,16 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + void *nativeDpy, + const EGLAttrib *attribs) + { +- WlEglPlatformData *pData = (WlEglPlatformData *)data; +- WlEglDeviceDpy *devDpy = NULL; +- WlEglDeviceDpy *tmpDpy = NULL; +- WlEglDisplay *display = NULL; +- WlEglDisplay *dpy = NULL; +- EGLBoolean ownNativeDpy = EGL_FALSE; +- EGLint numDevices = 0; +- int ret = 0; ++ WlEglPlatformData *pData = (WlEglPlatformData *)data; ++ WlEglDeviceDpy *devDpy = NULL; ++ WlEglDeviceDpy *tmpDpy = NULL; ++ WlEglDisplay *display = NULL; ++ WlEglDisplay *dpy = NULL; ++ EGLBoolean ownNativeDpy = EGL_FALSE; ++ EGLint numDevices = 0; ++ int ret = 0; ++ struct wl_display *wrapper = NULL; ++ struct wl_event_queue *queue = NULL; + + if (platform != EGL_PLATFORM_WAYLAND_EXT) { + wlEglSetError(data, EGL_BAD_PARAMETER); +@@ -376,18 +384,24 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + display->ownNativeDpy = ownNativeDpy; + display->nativeDpy = nativeDpy; + ++ queue = wlGetEventQueue(nativeDpy); ++ if (queue == NULL) { ++ wlExternalApiUnlock(); ++ goto fail; ++ } ++ ++ wrapper = wl_proxy_create_wrapper(nativeDpy); ++ wl_proxy_set_queue((struct wl_proxy *)wrapper, queue); ++ + /* Listen to wl_registry events and make a roundtrip in order to find the + * wl_eglstream_display global object */ +- display->wlQueue = wl_display_create_queue(nativeDpy); +- display->wlDamageEventQueue = wl_display_create_queue(nativeDpy); +- display->wlRegistry = wl_display_get_registry(nativeDpy); +- wl_proxy_set_queue((struct wl_proxy *)display->wlRegistry, +- display->wlQueue); ++ display->wlRegistry = wl_display_get_registry(wrapper); ++ wl_proxy_wrapper_destroy(wrapper); /* Done with wrapper */ + ret = wl_registry_add_listener(display->wlRegistry, + ®istry_listener, + display); + if (ret == 0) { +- ret = wlEglRoundtrip(display, display->wlQueue); ++ ret = wlEglRoundtrip(display, queue); + } + if (ret < 0 || !display->wlStreamDpy) { + wlExternalApiUnlock(); +@@ -396,23 +410,17 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + + /* Listen to wl_eglstream_display events and make another roundtrip so we + * catch any bind-related event (e.g. server capabilities) */ +- wl_proxy_set_queue((struct wl_proxy *)display->wlStreamDpy, +- display->wlQueue); + ret = wl_eglstream_display_add_listener(display->wlStreamDpy, + &eglstream_display_listener, + display); + if (ret == 0) { +- ret = wlEglRoundtrip(display, display->wlQueue); ++ ret = wlEglRoundtrip(display, queue); + } + if (ret < 0) { + wlExternalApiUnlock(); + goto fail; + } + +- /* Restore global registry default queue as other clients may rely on it and +- we are no longer interested in registry events */ +- wl_proxy_set_queue((struct wl_proxy *)display->wlRegistry, NULL); +- + /* + * Seek for the desired device in wlEglDeviceDpyList. If found, use it; + * otherwise, create a new WlEglDeviceDpy and add it to wlEglDeviceDpyList +diff --git a/src/wayland-eglhandle.c b/src/wayland-eglhandle.c +index 6770ad7..2027463 100644 +--- a/src/wayland-eglhandle.c ++++ b/src/wayland-eglhandle.c +@@ -23,7 +23,7 @@ + #include "wayland-eglhandle.h" + #include "wayland-egldisplay.h" + #include "wayland-eglsurface.h" +-#include "wayland-api-lock.h" ++#include "wayland-thread.h" + #include + #include + #include +diff --git a/src/wayland-eglstream.c b/src/wayland-eglstream.c +index 605e52b..5b4b0ac 100644 +--- a/src/wayland-eglstream.c ++++ b/src/wayland-eglstream.c +@@ -21,7 +21,7 @@ + */ + + #include "wayland-eglstream-server.h" +-#include "wayland-api-lock.h" ++#include "wayland-thread.h" + #include "wayland-eglhandle.h" + #include "wayland-egldisplay.h" + #include "wayland-eglutils.h" +diff --git a/src/wayland-eglsurface.c b/src/wayland-eglsurface.c +index 6dc5b54..db5478f 100644 +--- a/src/wayland-eglsurface.c ++++ b/src/wayland-eglsurface.c +@@ -24,7 +24,7 @@ + #include "wayland-eglstream-client-protocol.h" + #include "wayland-eglstream-controller-client-protocol.h" + #include "wayland-eglstream-server.h" +-#include "wayland-api-lock.h" ++#include "wayland-thread.h" + #include "wayland-eglutils.h" + #include "wayland-egl-priv.h" + #include "wayland-egl-ext.h" +@@ -69,7 +69,6 @@ EGLBoolean wlEglIsWaylandWindowValid(struct wl_egl_window *window) + return EGL_FALSE; + } + } +- + /* wl_surface is a wl_proxy, which is a wl_object. wl_objects's first + * element points to the interface type */ + return (((*(void **)surface)) == &wl_surface_interface); +@@ -92,14 +91,17 @@ static const struct wl_callback_listener throttle_listener = { + + void wlEglCreateFrameSync(WlEglSurface *surface, struct wl_event_queue *queue) + { ++ struct wl_surface *wrapper = NULL; ++ + if (surface->swapInterval > 0) { +- surface->throttleCallback = wl_surface_frame(surface->wlSurface); ++ wrapper = wl_proxy_create_wrapper(surface->wlSurface); ++ wl_proxy_set_queue((struct wl_proxy *)wrapper, queue); ++ surface->throttleCallback = wl_surface_frame(wrapper); ++ wl_proxy_wrapper_destroy(wrapper); /* Done with wrapper */ + if (wl_callback_add_listener(surface->throttleCallback, + &throttle_listener, surface) == -1) { + return; + } +- wl_proxy_set_queue((struct wl_proxy *)surface->throttleCallback, +- queue); + wl_surface_commit(surface->wlSurface); + + } +@@ -128,7 +130,7 @@ EGLint wlEglWaitFrameSync(WlEglSurface *surface, struct wl_event_queue *queue) + } + + EGLBoolean +-wlEglSendDamageEvent(WlEglSurface *surface) ++wlEglSendDamageEvent(WlEglSurface *surface, struct wl_event_queue *queue) + { + /* Attach same buffer to indicate new content for the surface is + * made available by the client */ +@@ -140,18 +142,19 @@ wlEglSendDamageEvent(WlEglSurface *surface) + surface->width, surface->height); + wl_surface_commit(surface->wlSurface); + surface->ctx.isAttached = EGL_TRUE; +- return (wlEglRoundtrip(surface->wlEglDpy, +- surface->wlEglDpy->wlDamageEventQueue) >= 0) ? EGL_TRUE : EGL_FALSE; ++ return (wlEglRoundtrip(surface->wlEglDpy, queue) >= 0) ? EGL_TRUE : ++ EGL_FALSE; + } + + static void* + damage_thread(void *args) + { +- WlEglSurface *surface = (WlEglSurface*)args; +- WlEglDisplay *display = surface->wlEglDpy; +- WlEglPlatformData *data = display->data; +- int ok = 1; +- EGLint state; ++ WlEglSurface *surface = (WlEglSurface*)args; ++ WlEglDisplay *display = surface->wlEglDpy; ++ WlEglPlatformData *data = display->data; ++ struct wl_event_queue *queue = wlGetEventQueue(display->nativeDpy); ++ int ok = (queue != NULL); ++ EGLint state; + + while (ok) { + // Unsignal sync and check latest frame and stream state +@@ -199,7 +202,7 @@ damage_thread(void *args) + } + /* wlEglSendDamageEvent() expects the API lock to be held */ + wlExternalApiLock(); +- ok = wlEglSendDamageEvent(surface); ++ ok = wlEglSendDamageEvent(surface, queue); + wlExternalApiUnlock(); + surface->ctx.framesProcessed++; + } +@@ -341,11 +344,58 @@ static struct wl_buffer_listener wl_buffer_listener = { + wl_buffer_release + }; + +-static EGLint create_surface_stream_fd(WlEglSurface *surface) ++static void * ++create_wl_eglstream(WlEglSurface *surface, ++ int32_t handle, ++ int32_t type, ++ struct wl_array *attribs, ++ struct wl_event_queue *queue) ++{ ++ WlEglDisplay *display = surface->wlEglDpy; ++ struct wl_egl_window *window = surface->wlEglWin; ++ struct wl_eglstream_display *wrapper = NULL; ++ struct wl_buffer *buffer = NULL; ++ int32_t width; ++ int32_t height; ++ ++ if (surface->isSurfaceProducer) { ++ assert(window); ++ width = window->width; ++ height = window->height; ++ } else { ++ width = surface->width; ++ height = surface->height; ++ } ++ ++ wrapper = wl_proxy_create_wrapper(display->wlStreamDpy); ++ wl_proxy_set_queue((struct wl_proxy *)wrapper, queue); ++ ++ buffer = wl_eglstream_display_create_stream(wrapper, ++ width, ++ height, ++ handle, ++ type, ++ attribs); ++ ++ wl_proxy_wrapper_destroy(wrapper); /* Done with wrapper */ ++ ++ if (!buffer) { ++ return NULL; ++ } ++ ++ if (wl_buffer_add_listener(buffer, &wl_buffer_listener, surface) == -1) { ++ wl_buffer_destroy(buffer); ++ return NULL; ++ } ++ ++ return buffer; ++} ++ ++static EGLint create_surface_stream_fd(WlEglSurface *surface, ++ struct wl_event_queue *queue) + { + WlEglDisplay *display = surface->wlEglDpy; + WlEglPlatformData *data = display->data; +- struct wl_egl_window *window = surface->wlEglWin; + int handle = EGL_NO_FILE_DESCRIPTOR_KHR; + struct wl_array wlAttribs; + EGLint eglAttribs[] = { +@@ -384,26 +434,16 @@ static EGLint create_surface_stream_fd(WlEglSurface *surface) + wl_array_init(&wlAttribs); /* Empty attributes list */ + + surface->ctx.wlStreamResource = +- wl_eglstream_display_create_stream(display->wlStreamDpy, +- window->width, +- window->height, +- handle, +- WL_EGLSTREAM_HANDLE_TYPE_FD, +- &wlAttribs); ++ create_wl_eglstream(surface, ++ handle, ++ WL_EGLSTREAM_HANDLE_TYPE_FD, ++ &wlAttribs, ++ queue); + if (!surface->ctx.wlStreamResource) { + err = EGL_BAD_ALLOC; + goto fail; + } + +- if (wl_buffer_add_listener(surface->ctx.wlStreamResource, +- &wl_buffer_listener, +- surface) == -1) { +- err = EGL_BAD_ALLOC; +- goto fail; +- } +- wl_proxy_set_queue((struct wl_proxy *)surface->ctx.wlStreamResource, +- display->wlQueue); +- + /* Clean-up */ + close(handle); + return EGL_SUCCESS; +@@ -498,11 +538,11 @@ static EGLint finishInetHandshake(pthread_t thread, int *socket) + } + + static EGLint create_surface_stream_remote(WlEglSurface *surface, +- EGLBoolean useInet) ++ EGLBoolean useInet, ++ struct wl_event_queue *queue) + { + WlEglDisplay *display = surface->wlEglDpy; + WlEglPlatformData *data = display->data; +- struct wl_egl_window *window = surface->wlEglWin; + struct wl_array wlAttribs; + intptr_t *wlAttribsData; + EGLint eglAttribs[] = { +@@ -559,31 +599,21 @@ static EGLint create_surface_stream_remote(WlEglSurface *surface, + } + } + +- /* Create the wl_eglstream */ + surface->ctx.wlStreamResource = +- wl_eglstream_display_create_stream( +- display->wlStreamDpy, +- window->width, +- window->height, +- socket[1], +- (useInet ? WL_EGLSTREAM_HANDLE_TYPE_INET : +- WL_EGLSTREAM_HANDLE_TYPE_SOCKET), +- &wlAttribs); ++ create_wl_eglstream(surface, ++ socket[1], ++ (useInet ? WL_EGLSTREAM_HANDLE_TYPE_INET : ++ WL_EGLSTREAM_HANDLE_TYPE_SOCKET), ++ &wlAttribs, ++ queue); + if (!surface->ctx.wlStreamResource) { + err = EGL_BAD_ALLOC; + goto fail; + } + +- /* Setup the wl_eglstream events queue and callbacks */ +- wl_proxy_set_queue((struct wl_proxy *)surface->ctx.wlStreamResource, +- display->wlQueue); +- ret = wl_buffer_add_listener(surface->ctx.wlStreamResource, +- &wl_buffer_listener, +- surface); +- if (ret == 0) { +- ret = wlEglRoundtrip(display, display->wlQueue); +- } +- if (ret < 0) { ++ /* Need a roundtrip for the consumer's endpoint to be created before the ++ * producer's */ ++ if (wlEglRoundtrip(display, queue) < 0) { + err = EGL_BAD_ALLOC; + goto fail; + } +@@ -632,7 +662,7 @@ fail: + #endif + + static EGLint +-create_surface_stream(WlEglSurface *surface) ++create_surface_stream(WlEglSurface *surface, struct wl_event_queue *queue) + { + WlEglDisplay *display = surface->wlEglDpy; + EGLint err = EGL_BAD_ACCESS; +@@ -650,21 +680,21 @@ create_surface_stream(WlEglSurface *surface) + if ((err != EGL_SUCCESS) && + display->caps.stream_socket && + display->exts.stream_remote) { +- err = create_surface_stream_remote(surface, EGL_FALSE); ++ err = create_surface_stream_remote(surface, EGL_FALSE, queue); + } + #endif + + if ((err != EGL_SUCCESS) && + display->caps.stream_fd && + display->exts.stream_cross_process_fd) { +- err = create_surface_stream_fd(surface); ++ err = create_surface_stream_fd(surface, queue); + } + + #ifdef EGL_NV_stream_remote + if ((err != EGL_SUCCESS) && + display->caps.stream_inet && + display->exts.stream_remote) { +- err = create_surface_stream_remote(surface, EGL_TRUE); ++ err = create_surface_stream_remote(surface, EGL_TRUE, queue); + } + #endif + +@@ -674,20 +704,27 @@ create_surface_stream(WlEglSurface *surface) + static EGLint + create_surface_context(WlEglSurface *surface) + { +- WlEglDisplay *display = surface->wlEglDpy; +- WlEglPlatformData *data = display->data; +- struct wl_egl_window *window = surface->wlEglWin; +- EGLint synchronous = EGL_FALSE; +- EGLint err = EGL_SUCCESS; ++ WlEglDisplay *display = surface->wlEglDpy; ++ WlEglPlatformData *data = display->data; ++ struct wl_egl_window *window = surface->wlEglWin; ++ struct wl_event_queue *queue = NULL; ++ EGLint synchronous = EGL_FALSE; ++ EGLint err = EGL_SUCCESS; + + assert(surface->ctx.eglSurface == EGL_NO_SURFACE); + ++ queue = wlGetEventQueue(display->nativeDpy); ++ if (!queue) { ++ err = EGL_BAD_ALLOC; ++ goto fail; ++ } ++ + /* Width and height are the first and second attributes respectively */ + surface->attribs[1] = window->width; + surface->attribs[3] = window->height; + + /* First, create the underlying wl_eglstream and EGLStream */ +- err = create_surface_stream(surface); ++ err = create_surface_stream(surface, queue); + if (err != EGL_SUCCESS) { + goto fail; + } +@@ -715,12 +752,10 @@ create_surface_context(WlEglSurface *surface) + surface->ctx.isAttached = EGL_TRUE; + } + +- wl_proxy_set_queue((struct wl_proxy *)surface->wlSurface, display->wlQueue); +- if (wlEglRoundtrip(display, display->wlQueue) < 0) { ++ if (wlEglRoundtrip(display, queue) < 0) { + err = EGL_BAD_ALLOC; + goto fail; + } +- wl_proxy_set_queue((struct wl_proxy *)surface->wlSurface, NULL); + + /* Finally, create the surface producer */ + surface->ctx.eglSurface = +@@ -926,14 +961,12 @@ static EGLint assignWlEglSurfaceAttribs(WlEglSurface *surface, + + static EGLint destroyEglSurface(EGLDisplay dpy, EGLSurface eglSurface) + { +- WlEglDisplay *display = (WlEglDisplay*)dpy; +- WlEglSurface *surface = (WlEglSurface*)eglSurface; +- WlEglSurfaceCtx *ctx, *next; +- int ret = 0; +- +- if (!wlEglIsWlEglDisplay(display)) { +- return EGL_BAD_DISPLAY; +- } ++ WlEglDisplay *display = (WlEglDisplay*)dpy; ++ WlEglSurface *surface = (WlEglSurface*)eglSurface; ++ struct wl_event_queue *queue = NULL; ++ WlEglSurfaceCtx *ctx = NULL; ++ WlEglSurfaceCtx *next = NULL; ++ int ret = 0; + + if (!wlEglIsWlEglSurface(surface)) { + return EGL_BAD_SURFACE; +@@ -945,9 +978,12 @@ static EGLint destroyEglSurface(EGLDisplay dpy, EGLSurface eglSurface) + + if (wlEglIsWaylandDisplay(display->nativeDpy) && + wlEglIsWaylandWindowValid(surface->wlEglWin)) { +- wl_surface_attach(surface->wlSurface, NULL, 0, 0); +- wl_surface_commit(surface->wlSurface); +- ret = wlEglRoundtrip(display, display->wlQueue); ++ queue = wlGetEventQueue(display->nativeDpy); ++ if (queue != NULL) { ++ wl_surface_attach(surface->wlSurface, NULL, 0, 0); ++ wl_surface_commit(surface->wlSurface); ++ ret = wlEglRoundtrip(display, queue); ++ } + + surface->wlEglWin->private = NULL; + surface->wlEglWin->resize_callback = NULL; +diff --git a/src/wayland-eglswap.c b/src/wayland-eglswap.c +index 7660eed..dd68a06 100644 +--- a/src/wayland-eglswap.c ++++ b/src/wayland-eglswap.c +@@ -22,7 +22,7 @@ + + #include "wayland-eglswap.h" + #include "wayland-eglstream-client-protocol.h" +-#include "wayland-api-lock.h" ++#include "wayland-thread.h" + #include "wayland-egldisplay.h" + #include "wayland-eglsurface.h" + #include "wayland-eglhandle.h" +@@ -36,13 +36,14 @@ EGLBoolean wlEglSwapBuffersHook(EGLDisplay eglDisplay, EGLSurface eglSurface) + + EGLBoolean wlEglSwapBuffersWithDamageHook(EGLDisplay eglDisplay, EGLSurface eglSurface, EGLint *rects, EGLint n_rects) + { +- WlEglDisplay *display = (WlEglDisplay *)eglDisplay; +- WlEglPlatformData *data = display->data; +- WlEglSurface *surface = (WlEglSurface *)eglSurface; +- EGLStreamKHR eglStream; +- EGLBoolean isOffscreen = EGL_FALSE; +- EGLBoolean res; +- EGLint err; ++ WlEglDisplay *display = (WlEglDisplay *)eglDisplay; ++ WlEglPlatformData *data = display->data; ++ WlEglSurface *surface = (WlEglSurface *)eglSurface; ++ struct wl_event_queue *queue = NULL; ++ EGLStreamKHR eglStream = EGL_NO_STREAM_KHR; ++ EGLBoolean isOffscreen = EGL_FALSE; ++ EGLBoolean res; ++ EGLint err; + + wlExternalApiLock(); + +@@ -59,12 +60,18 @@ EGLBoolean wlEglSwapBuffersWithDamageHook(EGLDisplay eglDisplay, EGLSurface eglS + isOffscreen = surface->ctx.isOffscreen; + + if (!isOffscreen) { ++ queue = wlGetEventQueue(display->nativeDpy); ++ if (queue == NULL) { ++ err = EGL_CONTEXT_LOST; /* XXX: Is this the right error? */ ++ goto fail; ++ } ++ + if (!wlEglIsWaylandWindowValid(surface->wlEglWin)) { + err = EGL_BAD_SURFACE; + goto fail; + } + +- wlEglWaitFrameSync(surface, display->wlQueue); ++ wlEglWaitFrameSync(surface, queue); + } + + /* Save the internal EGLDisplay, EGLSurface and EGLStream handles, as +@@ -98,10 +105,10 @@ EGLBoolean wlEglSwapBuffersWithDamageHook(EGLDisplay eglDisplay, EGLSurface eglS + if (surface->ctx.useDamageThread) { + surface->ctx.framesProduced++; + } else { +- res = wlEglSendDamageEvent(surface); ++ res = wlEglSendDamageEvent(surface, queue); + } + } +- wlEglCreateFrameSync(surface, display->wlQueue); ++ wlEglCreateFrameSync(surface, queue); + wlExternalApiUnlock(); + + done: +diff --git a/src/wayland-eglutils.c b/src/wayland-eglutils.c +index cf50a7f..e2c5f26 100644 +--- a/src/wayland-eglutils.c ++++ b/src/wayland-eglutils.c +@@ -25,7 +25,7 @@ + #endif + + #include "wayland-eglutils.h" +-#include "wayland-api-lock.h" ++#include "wayland-thread.h" + #include "wayland-eglhandle.h" + #include + #include +diff --git a/src/wayland-thread.c b/src/wayland-thread.c +new file mode 100644 +index 0000000..47724ba +--- /dev/null ++++ b/src/wayland-thread.c +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++/* To include PTHREAD_MUTEX_ERRORCHECK */ ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE ++#endif ++ ++#include "wayland-thread.h" ++#include ++#include ++#include ++ ++static pthread_mutex_t wlMutex; ++static pthread_once_t wlMutexOnceControl = PTHREAD_ONCE_INIT; ++static int wlMutexInitialized = 0; ++ ++static pthread_key_t wlTLSKey; ++static pthread_once_t wlTLSKeyOnceControl = PTHREAD_ONCE_INIT; ++static int wlTLSKeyInitialized = 0; ++ ++static void wlExternalApiInitializeLock(void) ++{ ++ pthread_mutexattr_t attr; ++ ++ if (pthread_mutexattr_init(&attr)) { ++ assert(!"failed to initialize pthread attribute mutex"); ++ return; ++ } ++ ++ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) { ++ assert(!"failed to set pthread attribute mutex errorcheck"); ++ goto fail; ++ } ++ ++ if (pthread_mutex_init(&wlMutex, &attr)) { ++ assert(!"failed to initialize pthread mutex"); ++ goto fail; ++ } ++ ++ wlMutexInitialized = 1; ++ ++fail: ++ if (pthread_mutexattr_destroy(&attr)) { ++ assert(!"failed to destroy pthread attribute mutex"); ++ } ++} ++ ++void wlExternalApiDestroyLock(void) ++{ ++ if (!wlMutexInitialized || pthread_mutex_destroy(&wlMutex)) { ++ assert(!"failed to destroy pthread mutex"); ++ } ++} ++ ++int wlExternalApiLock(void) ++{ ++ if (pthread_once(&wlMutexOnceControl, wlExternalApiInitializeLock)) { ++ assert(!"pthread once failed"); ++ return -1; ++ } ++ ++ if (!wlMutexInitialized || pthread_mutex_lock(&wlMutex)) { ++ assert(!"failed to lock pthread mutex"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int wlExternalApiUnlock(void) ++{ ++ if (!wlMutexInitialized || pthread_mutex_unlock(&wlMutex)) { ++ assert(!"failed to unlock pthread mutex"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void destroy_tls_key(void *data) ++{ ++ WlThread *wlThread = data; ++ if (wlThread) { ++ if (wlThread->queue) { ++ wl_event_queue_destroy(wlThread->queue); ++ } ++ free(wlThread); ++ } ++} ++ ++static void create_tls_key(void) ++{ ++ /* Create a pthread storage key to be used to set and retrieave TLS data */ ++ if (pthread_key_create(&wlTLSKey, destroy_tls_key) == 0) { ++ wlTLSKeyInitialized = 1; ++ } ++} ++ ++WlThread* wlGetThread(void) ++{ ++ WlThread *wlThread = NULL; ++ ++ if (pthread_once(&wlTLSKeyOnceControl, create_tls_key)) { ++ assert(!"pthread once failed"); ++ return NULL; ++ } ++ ++ if (!wlTLSKeyInitialized) { ++ assert(!"failed to create TLS key"); ++ return NULL; ++ } ++ ++ wlThread = pthread_getspecific(wlTLSKey); ++ if (wlThread == NULL) { ++ wlThread = calloc(1, sizeof(WlThread)); ++ if (wlThread == NULL) { ++ return NULL; ++ } ++ ++ if (pthread_setspecific(wlTLSKey, wlThread) != 0) { ++ assert(!"failed to set TLS data"); ++ free(wlThread); ++ return NULL; ++ } ++ } ++ ++ return wlThread; ++} +-- +2.42.0.windows.2 + diff --git a/0001-Fix-exports-regression.patch b/0001-Fix-exports-regression.patch new file mode 100644 index 0000000000000000000000000000000000000000..5db8a93fb06090e7d83eae3d3f9427b313bbc7cf --- /dev/null +++ b/0001-Fix-exports-regression.patch @@ -0,0 +1,31 @@ +From e3b96b859d6a6d8de717bd3e4a75139553fe7027 Mon Sep 17 00:00:00 2001 +From: "Miguel A. Vico" +Date: Fri, 30 Nov 2018 15:55:53 -0800 +Subject: [PATCH] Fix exports regression + +When "fixing" symbol visibility with commit +01230362591fe4b50135a1cd85736b506211e750, we accidentally hid +'loadEGLExternalPlatform()', making the library unusable. + +This change fixes that. +--- + include/wayland-external-exports.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/include/wayland-external-exports.h b/include/wayland-external-exports.h +index 9114663..6925302 100644 +--- a/include/wayland-external-exports.h ++++ b/include/wayland-external-exports.h +@@ -60,6 +60,9 @@ + #define EGL_EXTERNAL_PLATFORM_VERSION_MINOR WAYLAND_EXTERNAL_VERSION_MINOR + #include + ++#include ++ ++WL_EXPORT + EGLBoolean loadEGLExternalPlatform(int major, int minor, + const EGLExtDriver *driver, + EGLExtPlatform *platform); +-- +2.42.0.windows.2 + diff --git a/0001-Handle-EGL_KHR_track_references.patch b/0001-Handle-EGL_KHR_track_references.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ffe670983037aa00529527e4f1ce85cc8fb8d53 --- /dev/null +++ b/0001-Handle-EGL_KHR_track_references.patch @@ -0,0 +1,497 @@ +From a3ad6f375b23079f3eb96d1b046749fda9796a3a Mon Sep 17 00:00:00 2001 +From: "Miguel A. Vico" +Date: Fri, 30 Nov 2018 15:15:09 -0800 +Subject: [PATCH] Handle EGL_KHR_track_references + +As part of our automotive efforts to support Vulkan Wayland WSI, we are +building a custom EGLStreams producer to hook into our current +libnvidia-egl-wayland.so implementation. + +One of the issues encountered was that EGLDisplay would be completely +torn down when calling eglTerminate() on it without taking into account +how many entities were referencing it (e.g. when recreating the +corresponding Vulkan swapchain). + +To improve this, this change adds the appropriate refcounting and +handles EGL_KHR_track_references whenever that extension is used by the +application. + +Additionally, a new wlEglInitializeSurfaceExport() export has been added +to bootstrap a WlEglSurface that is not an EGLSurface producer +(EGL_KHR_stream_producer_eglsurface). + +Signed-off-by: Sam Ricker +--- + include/wayland-egldisplay.h | 3 + + include/wayland-eglhandle.h | 2 + + include/wayland-eglsurface.h | 3 + + src/wayland-egldisplay.c | 101 ++++++++++++++++++++++++++-------- + src/wayland-eglhandle.c | 4 ++ + src/wayland-eglsurface.c | 101 ++++++++++++++++++++++------------ + wayland-egl/wayland-egl-ext.h | 9 +++ + 7 files changed, 165 insertions(+), 58 deletions(-) + +diff --git a/include/wayland-egldisplay.h b/include/wayland-egldisplay.h +index 0630e8b..206869d 100644 +--- a/include/wayland-egldisplay.h ++++ b/include/wayland-egldisplay.h +@@ -67,9 +67,12 @@ typedef struct WlEglDisplayRec { + unsigned int stream_fifo_synchronous : 1; + unsigned int stream_sync : 1; + unsigned int stream_flush : 1; ++ unsigned int display_reference : 1; + } exts; + + struct wl_list link; ++ EGLBoolean useRefCount; ++ unsigned int refCount; + } WlEglDisplay; + + EGLBoolean wlEglIsValidNativeDisplayExport(void *data, void *nativeDpy); +diff --git a/include/wayland-eglhandle.h b/include/wayland-eglhandle.h +index d0f506d..8a9b678 100644 +--- a/include/wayland-eglhandle.h ++++ b/include/wayland-eglhandle.h +@@ -97,6 +97,8 @@ typedef struct WlEglPlatformDataRec { + PWLEGLFNGETERRORCOREPROC getError; + PWLEGLFNRELEASETHREADCOREPROC releaseThread; + ++ PFNEGLQUERYDISPLAYATTRIBKHRPROC queryDisplayAttrib; ++ + /* Used for fifo_synchronous support */ + PFNEGLQUERYSTREAMKHRPROC queryStream; + PFNEGLQUERYSTREAMU64KHRPROC queryStreamu64; +diff --git a/include/wayland-eglsurface.h b/include/wayland-eglsurface.h +index 79cbbfa..ae8cdf2 100644 +--- a/include/wayland-eglsurface.h ++++ b/include/wayland-eglsurface.h +@@ -78,6 +78,9 @@ typedef struct WlEglSurfaceRec { + + extern struct wl_list wlEglSurfaceList; + ++WL_EXPORT ++EGLBoolean wlEglInitializeSurfaceExport(WlEglSurface *surface); ++ + EGLSurface wlEglCreatePlatformWindowSurfaceHook(EGLDisplay dpy, + EGLConfig config, + void *nativeWin, +diff --git a/src/wayland-egldisplay.c b/src/wayland-egldisplay.c +index 326a180..29d2c3e 100644 +--- a/src/wayland-egldisplay.c ++++ b/src/wayland-egldisplay.c +@@ -262,6 +262,13 @@ static EGLBoolean terminateDisplay(EGLDisplay dpy, EGLBoolean skipDestroy) + EGLBoolean fullTerminate = EGL_FALSE; + EGLBoolean res = EGL_TRUE; + ++ if (display->useRefCount) { ++ display->refCount -= 1; ++ if (display->refCount > 0) { ++ return EGL_TRUE; ++ } ++ } ++ + /* First, destroy any surface associated to the given display. Then + * destroy the display connection itself */ + wlEglDestroyAllSurfaces(display); +@@ -341,6 +348,12 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + EGLBoolean ownNativeDpy = EGL_FALSE; + EGLint numDevices = 0; + int ret = 0; ++ int nAttribs = 0; ++ EGLint *attribs2 = NULL; ++ int i = 0; ++ EGLDisplay eglDisplay = NULL; ++ EGLDeviceEXT eglDevice = NULL; ++ EGLint err = EGL_SUCCESS; + struct wl_display *wrapper = NULL; + struct wl_event_queue *queue = NULL; + +@@ -349,6 +362,40 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + return EGL_NO_DISPLAY; + } + ++ if (!pData->egl.queryDevices(1, &eglDevice, &numDevices) || numDevices == 0) { ++ goto fail; ++ } ++ ++ /* We need to convert EGLAttrib style attributes to EGLint style attributes ++ before calling eglGetPlatformDisplayEXT which takes an EGLint* */ ++ ++ if (attribs) { ++ while (attribs[nAttribs] != EGL_NONE) { ++ nAttribs += 2; ++ } ++ ++ attribs2 = calloc(nAttribs + 1, sizeof(EGLint)); ++ if (!attribs2) { ++ err = EGL_BAD_ALLOC; ++ goto fail; ++ } ++ ++ for (i = 0; i < nAttribs; i += 2) { ++ attribs2[i] = (EGLint) attribs[i]; ++ attribs2[i+1] = (EGLint) attribs[i+1]; ++ } ++ ++ attribs2[nAttribs] = EGL_NONE; ++ } ++ ++ eglDisplay = pData->egl.getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, ++ eglDevice, ++ attribs2); ++ free(attribs2); ++ if (eglDisplay == EGL_NO_DISPLAY) { ++ goto fail; ++ } ++ + wlExternalApiLock(); + + /* If default display is requested, create a new Wayland display connection +@@ -366,7 +413,7 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + wl_display_dispatch_pending(nativeDpy); + } else { + wl_list_for_each(display, &wlEglDisplayList, link) { +- if (display->nativeDpy == nativeDpy) { ++ if (display->nativeDpy == nativeDpy && display->devDpy->eglDisplay == eglDisplay) { + wlExternalApiUnlock(); + return (EGLDisplay)display; + } +@@ -376,6 +423,7 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + display = calloc(1, sizeof(*display)); + if (!display) { + wlExternalApiUnlock(); ++ err = EGL_BAD_ALLOC; + goto fail; + } + +@@ -387,6 +435,7 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + queue = wlGetEventQueue(nativeDpy); + if (queue == NULL) { + wlExternalApiUnlock(); ++ err = EGL_BAD_ALLOC; + goto fail; + } + +@@ -405,6 +454,7 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + } + if (ret < 0 || !display->wlStreamDpy) { + wlExternalApiUnlock(); ++ err = EGL_BAD_ALLOC; + goto fail; + } + +@@ -418,6 +468,7 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + } + if (ret < 0) { + wlExternalApiUnlock(); ++ err = EGL_BAD_ALLOC; + goto fail; + } + +@@ -427,32 +478,23 @@ EGLDisplay wlEglGetPlatformDisplayExport(void *data, + */ + wl_list_for_each(devDpy, &wlEglDeviceDpyList, link) { + /* TODO: Add support for multiple devices/device selection */ +- display->devDpy = devDpy; +- display->devDpy->refCount++; +- break; ++ if (devDpy->eglDisplay == eglDisplay) { ++ display->devDpy = devDpy; ++ display->devDpy->refCount++; ++ break; ++ } + } + + if (!display->devDpy) { +- wlExternalApiUnlock(); +- + devDpy = calloc(1, sizeof(*devDpy)); + if (!devDpy) { ++ wlExternalApiUnlock(); ++ err = EGL_BAD_ALLOC; + goto fail; + } + +- if (!pData->egl.queryDevices(1, &devDpy->eglDevice, &numDevices) || numDevices == 0) { +- goto fail; +- } +- +- /* TODO: Parse and filter out incompatible attribues */ +- devDpy->eglDisplay = +- pData->egl.getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, +- devDpy->eglDevice, +- NULL); +- if (devDpy->eglDisplay == EGL_NO_DISPLAY) { +- goto fail; +- } +- wlExternalApiLock(); ++ devDpy->eglDevice = eglDevice; ++ devDpy->eglDisplay = eglDisplay; + } + + // Due to temporary unlock of wlMutex in wlEglRoundtrip, it is possible +@@ -514,14 +556,19 @@ fail: + + free(devDpy); + ++ if (err != EGL_SUCCESS) { ++ wlEglSetError(data, err); ++ } ++ + return EGL_NO_DISPLAY; + } + + EGLBoolean wlEglInitializeHook(EGLDisplay dpy, EGLint *major, EGLint *minor) + { +- WlEglDisplay *display = (WlEglDisplay *)dpy; +- WlEglPlatformData *data = display->data; +- EGLBoolean res = EGL_FALSE; ++ WlEglDisplay *display = (WlEglDisplay *)dpy; ++ WlEglPlatformData *data = display->data; ++ EGLBoolean res = EGL_FALSE; ++ EGLAttrib useRefCount = EGL_FALSE; + + dpy = display->devDpy->eglDisplay; + res = data->egl.initialize(dpy, major, minor); +@@ -543,12 +590,22 @@ EGLBoolean wlEglInitializeHook(EGLDisplay dpy, EGLint *major, EGLint *minor) + CACHE_EXT(NV, stream_fifo_synchronous); + CACHE_EXT(NV, stream_sync); + CACHE_EXT(NV, stream_flush); ++ CACHE_EXT(KHR, display_reference); + + #undef CACHE_EXT + + wlExternalApiUnlock(); + } + ++ if (display->exts.display_reference) { ++ data->egl.queryDisplayAttrib(dpy, EGL_TRACK_REFERENCES_KHR, &useRefCount); ++ display->useRefCount = (EGLBoolean) useRefCount; ++ } ++ ++ if (display->useRefCount) { ++ display->refCount += 1; ++ } ++ + return res; + } + +diff --git a/src/wayland-eglhandle.c b/src/wayland-eglhandle.c +index 2027463..937c150 100644 +--- a/src/wayland-eglhandle.c ++++ b/src/wayland-eglhandle.c +@@ -63,6 +63,8 @@ wlEglCreatePlatformData(int apiMajor, int apiMinor, const EGLExtDriver *driver) + GET_PROC(queryString, eglQueryString); + GET_PROC(queryDevices, eglQueryDevicesEXT); + ++ /* TODO: use eglGetPlatformDisplay instead of eglGetPlatformDisplayEXT ++ if EGL 1.5 is available */ + GET_PROC(getPlatformDisplay, eglGetPlatformDisplayEXT); + GET_PROC(initialize, eglInitialize); + GET_PROC(terminate, eglTerminate); +@@ -106,6 +108,8 @@ wlEglCreatePlatformData(int apiMajor, int apiMinor, const EGLExtDriver *driver) + /* Stream flush */ + GET_PROC(streamFlush, eglStreamFlushNV); + ++ GET_PROC(queryDisplayAttrib, eglQueryDisplayAttribKHR); ++ + #undef GET_PROC + + /* Check for required EGL client extensions */ +diff --git a/src/wayland-eglsurface.c b/src/wayland-eglsurface.c +index db5478f..cacfdf8 100644 +--- a/src/wayland-eglsurface.c ++++ b/src/wayland-eglsurface.c +@@ -76,8 +76,8 @@ EGLBoolean wlEglIsWaylandWindowValid(struct wl_egl_window *window) + + static void + wayland_throttleCallback(void *data, +- struct wl_callback *callback, +- uint32_t time) ++ struct wl_callback *callback, ++ uint32_t time) + { + WlEglSurface *surface = (WlEglSurface *)data; + +@@ -186,8 +186,10 @@ damage_thread(void *args) + ok = 0; + } + ++ // We only expect a valid wlEglWin to be set when using ++ // a surface created with EGL_KHR_platform_wayland. + if(!wlEglIsWaylandDisplay(display->nativeDpy) || +- !wlEglIsWaylandWindowValid(surface->wlEglWin)) { ++ (surface->isSurfaceProducer && !wlEglIsWaylandWindowValid(surface->wlEglWin))) { + ok = 0; + } + // If not done, keep handling frames +@@ -321,6 +323,25 @@ destroy_surface_context(WlEglSurface *surface, WlEglSurfaceCtx *ctx) + } + } + ++static void ++discard_surface_context(WlEglSurface *surface) ++{ ++ /* If the surface context is marked as attached, it means the compositor ++ * might still be using the resources because some content was actually ++ * displayed. In that case, defer its destruction until we make sure the ++ * compositor doesn't need it anymore (i.e. upon stream release); ++ * otherwise, we can just destroy it right away */ ++ if (surface->ctx.isAttached) { ++ WlEglSurfaceCtx *ctx = malloc(sizeof(WlEglSurfaceCtx)); ++ if (ctx) { ++ memcpy(ctx, &surface->ctx, sizeof(*ctx)); ++ wl_list_insert(&surface->oldCtxList, &ctx->link); ++ } ++ } else { ++ destroy_surface_context(surface, &surface->ctx); ++ } ++} ++ + static void + wl_buffer_release(void *data, struct wl_buffer *buffer) + { +@@ -720,8 +741,10 @@ create_surface_context(WlEglSurface *surface) + } + + /* Width and height are the first and second attributes respectively */ +- surface->attribs[1] = window->width; +- surface->attribs[3] = window->height; ++ if (surface->isSurfaceProducer) { ++ surface->attribs[1] = window->width; ++ surface->attribs[3] = window->height; ++ } + + /* First, create the underlying wl_eglstream and EGLStream */ + err = create_surface_stream(surface, queue); +@@ -757,17 +780,19 @@ create_surface_context(WlEglSurface *surface) + goto fail; + } + +- /* Finally, create the surface producer */ +- surface->ctx.eglSurface = +- data->egl.createStreamProducerSurface(display->devDpy->eglDisplay, +- surface->eglConfig, +- surface->ctx.eglStream, +- surface->attribs); +- if (surface->ctx.eglSurface == EGL_NO_SURFACE) { +- err = data->egl.getError(); +- goto fail; ++ if (surface->isSurfaceProducer) { ++ /* Finally, create the surface producer */ ++ surface->ctx.eglSurface = ++ data->egl.createStreamProducerSurface(display->devDpy->eglDisplay, ++ surface->eglConfig, ++ surface->ctx.eglStream, ++ surface->attribs); ++ if (surface->ctx.eglSurface == EGL_NO_SURFACE) { ++ err = data->egl.getError(); ++ goto fail; ++ } ++ wl_display_flush(display->nativeDpy); + } +- wl_display_flush(display->nativeDpy); + + /* Check whether we should use a damage thread */ + surface->ctx.useDamageThread = +@@ -786,12 +811,14 @@ create_surface_context(WlEglSurface *surface) + } + + /* Cache current window size and displacement for future checks */ +- surface->width = window->width; +- surface->height = window->height; +- surface->dx = window->dx; +- surface->dy = window->dy; +- window->attached_width = surface->width; +- window->attached_height = surface->height; ++ if (surface->isSurfaceProducer) { ++ surface->width = window->width; ++ surface->height = window->height; ++ surface->dx = window->dx; ++ surface->dy = window->dy; ++ window->attached_width = surface->width; ++ window->attached_height = surface->height; ++ } + + return EGL_SUCCESS; + +@@ -800,13 +827,26 @@ fail: + return err; + } + ++EGLBoolean wlEglInitializeSurfaceExport(WlEglSurface *surface) ++{ ++ wlExternalApiLock(); ++ wl_list_init(&surface->oldCtxList); ++ wl_list_insert(&wlEglSurfaceList, &surface->link); ++ if (create_surface_context(surface) != EGL_SUCCESS) { ++ wlExternalApiUnlock(); ++ return EGL_FALSE; ++ } ++ ++ wlExternalApiUnlock(); ++ return EGL_TRUE; ++} ++ + static void + resize_callback(struct wl_egl_window *window, void *data) + { + WlEglDisplay *display = NULL; + WlEglPlatformData *pData = NULL; + WlEglSurface *surface = (WlEglSurface *)data; +- WlEglSurfaceCtx *ctx = NULL; + EGLint err = EGL_SUCCESS; + + if (!window || !surface) { +@@ -831,20 +871,7 @@ resize_callback(struct wl_egl_window *window, void *data) + // pending frames + finish_wl_eglstream_damage_thread(surface, &surface->ctx, 0); + +- /* If the surface context is marked as attached, it means the compositor +- * might still be using the resources because some content was actually +- * displayed. In that case, defer its destruction until we make sure the +- * compositor doesn't need it anymore (i.e. upon stream release); +- * otherwise, we can just destroy it right away */ +- if (surface->ctx.isAttached) { +- ctx = malloc(sizeof(WlEglSurfaceCtx)); +- if (ctx) { +- memcpy(ctx, &surface->ctx, sizeof(*ctx)); +- wl_list_insert(&surface->oldCtxList, &ctx->link); +- } +- } else { +- destroy_surface_context(surface, &surface->ctx); +- } ++ discard_surface_context(surface); + surface->ctx.wlStreamResource = NULL; + surface->ctx.isAttached = EGL_FALSE; + surface->ctx.eglSurface = EGL_NO_SURFACE; +@@ -1106,6 +1133,8 @@ EGLSurface wlEglCreatePlatformWindowSurfaceHook(EGLDisplay dpy, + surface->ctx.eglStream = EGL_NO_STREAM_KHR; + surface->ctx.eglSurface = EGL_NO_SURFACE; + surface->ctx.isOffscreen = EGL_FALSE; ++ surface->isSurfaceProducer = EGL_TRUE; ++ + getWlEglWindowVersionAndSurface(window, + &surface->wlEglWinVer, + &surface->wlSurface); +diff --git a/wayland-egl/wayland-egl-ext.h b/wayland-egl/wayland-egl-ext.h +index 66e7e48..6ebcaa3 100644 +--- a/wayland-egl/wayland-egl-ext.h ++++ b/wayland-egl/wayland-egl-ext.h +@@ -50,4 +50,13 @@ EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamAttribNV(EGLDisplay dpy, const EG + typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMATTRIBNVPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list); + #endif /* EGL_NV_stream_attrib */ + ++#ifndef EGL_KHR_display_reference ++#define EGL_KHR_display_reference 1 ++#define EGL_TRACK_REFERENCES_KHR 0x3352 ++typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBKHRPROC) (EGLDisplay dpy, EGLint name, EGLAttrib *value); ++#ifdef EGL_EGLEXT_PROTOTYPES ++EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribKHR (EGLDisplay dpy, EGLint name, EGLAttrib *value); ++#endif ++#endif /* EGL_KHR_display_reference */ ++ + #endif +-- +2.42.0.windows.2 + diff --git a/0001-Properly-generate-private-public-protocols.patch b/0001-Properly-generate-private-public-protocols.patch new file mode 100644 index 0000000000000000000000000000000000000000..cd9d849eb0a98dd4f9390e05a2991eea792f5eeb --- /dev/null +++ b/0001-Properly-generate-private-public-protocols.patch @@ -0,0 +1,169 @@ +From 01230362591fe4b50135a1cd85736b506211e750 Mon Sep 17 00:00:00 2001 +From: "Miguel A. Vico" +Date: Mon, 26 Nov 2018 19:36:15 -0800 +Subject: [PATCH] Properly generate private/public protocols + +The 'code' option for wayland-scanner was deprecated in favor of +'private-code' and 'public-code'. + +This change updates the autotools build to properly use the new options +and updates the meson build to generate private-code by default and only +use public-code for public interfaces. + +Additionally, the default visibility for the entire library is set +hidden with '-fvisibility=hidden' +--- + Makefile.am | 50 ++++++++++++++++++++++++++--------- + configure.ac | 7 +++++ + src/meson.build | 1 + + wayland-eglstream/meson.build | 11 +++++--- + 4 files changed, 53 insertions(+), 16 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 8b81259..70bcfc9 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -9,10 +9,11 @@ libnvidia_egl_wayland_la_CFLAGS = \ + -I$(top_builddir)/wayland-eglstream + + # Required library flags +-libnvidia_egl_wayland_la_CFLAGS += \ +- $(PTHREAD_CFLAGS) \ +- $(EGL_EXTERNAL_PLATFORM_CFLAGS) \ +- $(WAYLAND_CFLAGS) ++libnvidia_egl_wayland_la_CFLAGS += \ ++ $(PTHREAD_CFLAGS) \ ++ $(EGL_EXTERNAL_PLATFORM_CFLAGS) \ ++ $(WAYLAND_CFLAGS) \ ++ $(COMPILER_FLAG_VISIBILITY_HIDDEN) + + # Make sure we don't use deprecated stuff + libnvidia_egl_wayland_la_CFLAGS += \ +@@ -37,13 +38,25 @@ libnvidia_egl_wayland_la_SOURCES = \ + src/wayland-eglhandle.c \ + src/wayland-external-exports.c + +-libnvidia_egl_wayland_la_built_sources = \ +- wayland-eglstream/wayland-eglstream-protocol.c \ +- wayland-eglstream/wayland-eglstream-client-protocol.h \ +- wayland-eglstream/wayland-eglstream-server-protocol.h \ +- wayland-eglstream/wayland-eglstream-controller-protocol.c \ ++libnvidia_egl_wayland_la_built_public_protocols = \ ++ wayland-eglstream/wayland-eglstream-controller-protocol.c ++ ++libnvidia_egl_wayland_la_built_private_protocols = \ ++ wayland-eglstream/wayland-eglstream-protocol.c ++ ++libnvidia_egl_wayland_la_built_client_headers = \ ++ wayland-eglstream/wayland-eglstream-client-protocol.h \ + wayland-eglstream/wayland-eglstream-controller-client-protocol.h + ++libnvidia_egl_wayland_la_built_server_headers = \ ++ wayland-eglstream/wayland-eglstream-server-protocol.h ++ ++libnvidia_egl_wayland_la_built_sources = \ ++ $(libnvidia_egl_wayland_la_built_public_protocols) \ ++ $(libnvidia_egl_wayland_la_built_private_protocols) \ ++ $(libnvidia_egl_wayland_la_built_client_headers) \ ++ $(libnvidia_egl_wayland_la_built_server_headers) ++ + nodist_libnvidia_egl_wayland_la_SOURCES = $(libnvidia_egl_wayland_la_built_sources) + + dist_pkgdata_DATA = \ +@@ -62,11 +75,22 @@ CLEANFILES = \ + + $(libnvidia_egl_wayland_la_SOURCES): $(libnvidia_egl_wayland_la_built_sources) + +-%-protocol.c : %.xml +- $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ ++if WAYLAND_SCANNER_HAS_PRIVATE_CODE ++ WAYLAND_PUBLIC_CODEGEN = public-code ++ WAYLAND_PRIVATE_CODEGEN = private-code ++else ++ WAYLAND_PUBLIC_CODEGEN = code ++ WAYLAND_PRIVATE_CODEGEN = code ++endif ++ ++$(libnvidia_egl_wayland_la_built_public_protocols):%-protocol.c : %.xml ++ $(AM_V_GEN)$(WAYLAND_SCANNER) $(WAYLAND_PUBLIC_CODEGEN) < $< > $@ ++ ++$(libnvidia_egl_wayland_la_built_private_protocols):%-protocol.c : %.xml ++ $(AM_V_GEN)$(WAYLAND_SCANNER) $(WAYLAND_PRIVATE_CODEGEN) < $< > $@ + +-%-client-protocol.h : %.xml ++$(libnvidia_egl_wayland_la_built_client_headers):%-client-protocol.h : %.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +-%-server-protocol.h : %.xml ++$(libnvidia_egl_wayland_la_built_server_headers):%-server-protocol.h : %.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@ +diff --git a/configure.ac b/configure.ac +index b55cd99..6d84b0a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -48,6 +48,8 @@ if test x$WAYLAND_SCANNER = x; then + PKG_CHECK_MODULES(WAYLAND_SCANNER, [wayland-scanner]) + WAYLAND_SCANNER=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` + fi ++AM_CONDITIONAL([WAYLAND_SCANNER_HAS_PRIVATE_CODE], ++ [test x$WAYLAND_SCANNER = x`$PKG_CONFIG --variable=wayland_scanner "wayland-scanner >= 1.14.91"`]) + + # Initialize libtool + LT_PREREQ([2.2]) +@@ -74,6 +76,11 @@ AC_TYPE_UINT32_T + AC_FUNC_MALLOC + AC_CHECK_FUNCS([getpagesize inet_ntoa memset socket strcasecmp strstr]) + ++# See if the compiler supports the -fvisibility=hidden flag. ++AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], ++ [AC_SUBST([COMPILER_FLAG_VISIBILITY_HIDDEN], ["-fvisibility=hidden"])], ++ [AC_SUBST([COMPILER_FLAG_VISIBILITY_HIDDEN], [""])]) ++ + # See if the linker supports the --no-undefined flag. + AX_CHECK_LINK_FLAG([-Xlinker --no-undefined], + [AC_SUBST([LINKER_FLAG_NO_UNDEFINED], ["-Xlinker --no-undefined"])], +diff --git a/src/meson.build b/src/meson.build +index 1747ea4..af9775f 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -4,6 +4,7 @@ else + libdl = [] + endif + ++add_project_arguments('-fvisibility=hidden', language : 'c') + add_project_link_arguments('-Wl,-Bsymbolic', language : 'c') + + foreach arg : [ +diff --git a/wayland-eglstream/meson.build b/wayland-eglstream/meson.build +index 124ae8e..a713900 100644 +--- a/wayland-eglstream/meson.build ++++ b/wayland-eglstream/meson.build +@@ -1,10 +1,13 @@ +-generated_protocols = [ ++generated_private_protocols = [ + 'wayland-eglstream', ++] ++ ++generated_public_protocols = [ + 'wayland-eglstream-controller', + ] + +-foreach proto : generated_protocols +- foreach output_type: ['client-header', 'server-header', 'public-code'] ++foreach proto : generated_private_protocols + generated_public_protocols ++ foreach output_type: ['client-header', 'server-header', 'private-code'] + if output_type == 'client-header' + output_file = '@0@-client-protocol.h'.format(proto) + elif output_type == 'server-header' +@@ -13,6 +16,8 @@ foreach proto : generated_protocols + output_file = '@0@-protocol.c'.format(proto) + if wl_scanner.version().version_compare('< 1.14.91') + output_type = 'code' ++ elif generated_public_protocols.contains(proto) ++ output_type = 'public-code' + endif + endif + +-- +2.42.0.windows.2 + diff --git a/0001-Remove-wayland-egl-priv.h.patch b/0001-Remove-wayland-egl-priv.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..d1fa43f05a62d434da1217ba384ffee62563b7b6 --- /dev/null +++ b/0001-Remove-wayland-egl-priv.h.patch @@ -0,0 +1,185 @@ +From 774e2226972aea8c8a646f206b8e8b97c8d46287 Mon Sep 17 00:00:00 2001 +From: "Miguel A. Vico" +Date: Fri, 30 Nov 2018 15:23:49 -0800 +Subject: [PATCH] Remove wayland-egl-priv.h + +Wayland now provides wayland-egl-backend.h as part of the +wayland-egl-backend package. +--- + configure.ac | 2 +- + meson.build | 1 + + src/meson.build | 1 + + src/wayland-eglsurface.c | 8 ++-- + src/wayland-eglswap.c | 2 +- + wayland-egl/wayland-egl-priv.h | 68 ---------------------------------- + 6 files changed, 8 insertions(+), 74 deletions(-) + delete mode 100644 wayland-egl/wayland-egl-priv.h + +diff --git a/configure.ac b/configure.ac +index 90605f8..67412f7 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -61,7 +61,7 @@ AC_CHECK_LIB([dl], [dlsym], + [], + [AC_MSG_ERROR("dlsym is needed to compile wayland-external")]) + PKG_CHECK_MODULES([EGL_EXTERNAL_PLATFORM], [eglexternalplatform >= ${EGL_EXTERNAL_PLATFORM_MIN_VERSION} eglexternalplatform < ${EGL_EXTERNAL_PLATFORM_MAX_VERSION}]) +-PKG_CHECK_MODULES([WAYLAND], [wayland-server wayland-client]) ++PKG_CHECK_MODULES([WAYLAND], [wayland-server wayland-client wayland-egl-backend >= 3]) + + # Checks for header files. + AC_CHECK_HEADERS([arpa/inet.h stddef.h stdint.h stdlib.h string.h sys/socket.h unistd.h]) +diff --git a/meson.build b/meson.build +index bae55e5..def7363 100644 +--- a/meson.build ++++ b/meson.build +@@ -21,6 +21,7 @@ wayland_eglstream_micro_version = ver_arr[2] + eglexternalplatform = dependency('eglexternalplatform', version : ['>=1.1', '<2']) + wayland_server = dependency('wayland-server') + wayland_client = dependency('wayland-client') ++wayland_egl_backend = dependency('wayland-egl-backend', version : ['>=3']) + threads = dependency('threads') + + wl_scanner = dependency('wayland-scanner', native: true) +diff --git a/src/meson.build b/src/meson.build +index 2482e33..80ea977 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -37,6 +37,7 @@ egl_wayland = library('nvidia-egl-wayland', + eglexternalplatform, + wayland_server, + wayland_client, ++ wayland_egl_backend, + threads, + libdl, + ], +diff --git a/src/wayland-eglsurface.c b/src/wayland-eglsurface.c +index cacfdf8..a72ddf4 100644 +--- a/src/wayland-eglsurface.c ++++ b/src/wayland-eglsurface.c +@@ -26,8 +26,8 @@ + #include "wayland-eglstream-server.h" + #include "wayland-thread.h" + #include "wayland-eglutils.h" +-#include "wayland-egl-priv.h" + #include "wayland-egl-ext.h" ++#include + #include + #include + #include +@@ -1012,7 +1012,7 @@ static EGLint destroyEglSurface(EGLDisplay dpy, EGLSurface eglSurface) + ret = wlEglRoundtrip(display, queue); + } + +- surface->wlEglWin->private = NULL; ++ surface->wlEglWin->driver_private = NULL; + surface->wlEglWin->resize_callback = NULL; + if (surface->wlEglWinVer >= WL_EGL_WINDOW_DESTROY_CALLBACK_SINCE) { + surface->wlEglWin->destroy_window_callback = NULL; +@@ -1099,7 +1099,7 @@ EGLSurface wlEglCreatePlatformWindowSurfaceHook(EGLDisplay dpy, + } + + // Check for existing associated surface +- if (window->private != NULL) { ++ if (window->driver_private != NULL) { + err = EGL_BAD_ALLOC; + goto fail; + } +@@ -1158,7 +1158,7 @@ EGLSurface wlEglCreatePlatformWindowSurfaceHook(EGLDisplay dpy, + wl_eglstream_display_swap_interval(display->wlStreamDpy, + surface->ctx.wlStreamResource, + surface->swapInterval); +- window->private = surface; ++ window->driver_private = surface; + window->resize_callback = resize_callback; + if (surface->wlEglWinVer >= WL_EGL_WINDOW_DESTROY_CALLBACK_SINCE) { + window->destroy_window_callback = destroy_callback; +diff --git a/src/wayland-eglswap.c b/src/wayland-eglswap.c +index dd68a06..c56a45e 100644 +--- a/src/wayland-eglswap.c ++++ b/src/wayland-eglswap.c +@@ -27,7 +27,7 @@ + #include "wayland-eglsurface.h" + #include "wayland-eglhandle.h" + #include "wayland-eglutils.h" +-#include "wayland-egl-priv.h" ++#include + + EGLBoolean wlEglSwapBuffersHook(EGLDisplay eglDisplay, EGLSurface eglSurface) + { +diff --git a/wayland-egl/wayland-egl-priv.h b/wayland-egl/wayland-egl-priv.h +deleted file mode 100644 +index 3b59908..0000000 +--- a/wayland-egl/wayland-egl-priv.h ++++ /dev/null +@@ -1,68 +0,0 @@ +-/* +- * Copyright © 2011 Benjamin Franzke +- * +- * Permission is hereby granted, free of charge, to any person obtaining a +- * copy of this software and associated documentation files (the "Software"), +- * to deal in the Software without restriction, including without limitation +- * the rights to use, copy, modify, merge, publish, distribute, sublicense, +- * and/or sell copies of the Software, and to permit persons to whom the +- * Software is furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice (including the next +- * paragraph) shall be included in all copies or substantial portions of the +- * Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +- * DEALINGS IN THE SOFTWARE. +- * +- * Authors: +- * Benjamin Franzke +- */ +- +-#ifndef _WAYLAND_EGL_PRIV_H +-#define _WAYLAND_EGL_PRIV_H +- +-/* GCC visibility */ +-#if defined(__GNUC__) +-#define WL_EGL_EXPORT __attribute__ ((visibility("default"))) +-#else +-#define WL_EGL_EXPORT +-#endif +- +-#include +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-#define WL_EGL_WINDOW_VERSION 3 +- +-struct wl_egl_window { +- const intptr_t version; +- +- int width; +- int height; +- int dx; +- int dy; +- +- int attached_width; +- int attached_height; +- +- void *private; +- void (*resize_callback)(struct wl_egl_window *, void *); +- void (*destroy_window_callback)(void *); +- +- struct wl_surface *surface; +-}; +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif +-- +2.42.0.windows.2 + diff --git a/0001-meson-replace-private-code-on-public-code.patch b/0001-meson-replace-private-code-on-public-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1dad5fdbbd920c5eea84b56afbca99ff6c5472d --- /dev/null +++ b/0001-meson-replace-private-code-on-public-code.patch @@ -0,0 +1,29 @@ +From 0eb29d4a84788b2abb3642ec2d3ccec0b0befe36 Mon Sep 17 00:00:00 2001 +From: fafryd +Date: Sun, 14 Oct 2018 13:34:23 +0200 +Subject: [PATCH] meson: replace 'private-code' on 'public-code' + +The option "code" was deprecated in favour of "public-code" with a +warning message produced to guide people. + +Fixes: https://github.com/NVIDIA/egl-wayland/issues/14 +--- + wayland-eglstream/meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/wayland-eglstream/meson.build b/wayland-eglstream/meson.build +index b81767c..124ae8e 100644 +--- a/wayland-eglstream/meson.build ++++ b/wayland-eglstream/meson.build +@@ -4,7 +4,7 @@ generated_protocols = [ + ] + + foreach proto : generated_protocols +- foreach output_type: ['client-header', 'server-header', 'private-code'] ++ foreach output_type: ['client-header', 'server-header', 'public-code'] + if output_type == 'client-header' + output_file = '@0@-client-protocol.h'.format(proto) + elif output_type == 'server-header' +-- +2.42.0.windows.2 + diff --git a/egl-wayland.spec b/egl-wayland.spec index cee6d4de89f277d6152c4541ebf4d79fcee8b7cd..eab80a17dc0c825b41e52fc8097e37d1f2d695ca 100644 --- a/egl-wayland.spec +++ b/egl-wayland.spec @@ -2,7 +2,7 @@ Name: egl-wayland Version: 1.1.0 -Release: 0.4 +Release: 0.5 Summary: Wayland EGL External Platform library License: MIT URL: https://github.com/NVIDIA/%{name} @@ -11,6 +11,16 @@ Source0: %url/archive/%{commit}.tar.gz#/%{name}-%{commit}.tar.gz BuildRequires: meson libtool eglexternalplatform-devel mesa-libEGL-devel wayland-devel Requires: libglvnd-egl%{?_isa} +#Patch0001: 0001-Add-a-capability-override-mechanism.patch +#Patch0002: 0001-Build-with-Wall-Werror.patch +#Patch0003: 0001-Create-per-thread-wl_event_queues-and-use-proxy-wrap.patch +#Patch0004: 0001-Fix-exports-regression.patch +#Patch0005: 0001-Handle-EGL_KHR_track_references.patch +Patch0006: 0001-Properly-generate-private-public-protocols.patch +#Patch0007: 0001-Remove-wayland-egl-priv.h.patch +#Patch0008: 0001-meson-replace-private-code-on-public-code.patch + + %description This is a work-in-progress implementation of a EGL External Platform library to add client-side Wayland support to EGL on top of EGLDevice and EGLStream @@ -53,6 +63,9 @@ install -m 0755 -d %{buildroot}%{_datadir}/egl/egl_external_platform.d/ %{_datadir}/wayland-eglstream/ %changelog +* Tue Dec 5 2023 liubo - 1.1.0-0.5 +- Add a capability override mechanism + * Sun Jan 19 2020 Jiangping Hu - 1.1.0-0.4 - Remove 1 unnecessary file