pax_global_header00006660000000000000000000000064134706417530014524gustar00rootroot0000000000000052 comment=d70ead930d458b4e0bcec4ef493f7d54e9fd5435 egl-wayland-1.1.3/000077500000000000000000000000001347064175300137325ustar00rootroot00000000000000egl-wayland-1.1.3/.gitignore000066400000000000000000000013651347064175300157270ustar00rootroot00000000000000# Taken from https://github.com/github/gitignore # Build system ignores # http://www.gnu.org/software/automake Makefile.in /ar-lib /mdate-sh /test-driver /ylwrap # http://www.gnu.org/software/autoconf /autom4te.cache /autoscan.log /autoscan-*.log /aclocal.m4 /compile /config.guess /config.h.in /config.sub /configure /configure.scan /depcomp /install-sh /missing /stamp-h1 # other stuff generated by us /m4/* /build/* # C ignores # Object files *.o *.ko *.obj *.elf # Prerequisites *.d # Object files *.o *.ko *.obj *.elf # Linker output *.ilk *.map *.exp # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects *.so *.so.* *.dylib # Executables *.out *.i*86 *.x86_64 *.hex # Debug files *.dSYM/ *.su *.idb *.pdb egl-wayland-1.1.3/COPYING000066400000000000000000000021761347064175300147730ustar00rootroot00000000000000 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. egl-wayland-1.1.3/Makefile.am000066400000000000000000000102241347064175300157650ustar00rootroot00000000000000 # Install libraries lib_LTLIBRARIES = libnvidia-egl-wayland.la # Include paths libnvidia_egl_wayland_la_CFLAGS = \ -I$(top_srcdir)/wayland-egl \ -I$(top_srcdir)/include \ -I$(top_builddir)/wayland-eglstream # Required library flags 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 += \ -DWL_HIDE_DEPRECATED libnvidia_egl_wayland_la_LDFLAGS = \ -shared \ -Wl,-Bsymbolic \ -ldl \ $(WAYLAND_LIBS) \ -version-number $(WAYLAND_EXTERNAL_MAJOR_VERSION):$(WAYLAND_EXTERNAL_MINOR_VERSION):$(WAYLAND_EXTERNAL_MICRO_VERSION) \ $(LINKER_FLAG_NO_UNDEFINED) libnvidia_egl_wayland_la_SOURCES = \ src/wayland-thread.c \ src/wayland-egldisplay.c \ src/wayland-eglstream.c \ src/wayland-eglstream-server.c \ src/wayland-eglsurface.c \ src/wayland-eglswap.c \ src/wayland-eglutils.c \ src/wayland-eglhandle.c \ src/wayland-external-exports.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 = \ wayland-eglstream/wayland-eglstream.xml \ wayland-eglstream/wayland-eglstream-controller.xml wayland_eglstream_pkgconfig_files = \ wayland-eglstream.pc \ wayland-eglstream-protocols.pc noarch_pkgconfig_DATA = $(wayland_eglstream_pkgconfig_files) CLEANFILES = \ $(libnvidia_egl_wayland_la_built_sources) \ $(wayland_eglstream_pkgconfig_files) $(libnvidia_egl_wayland_la_SOURCES): $(libnvidia_egl_wayland_la_built_sources) 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) < $< > $@ $(libnvidia_egl_wayland_la_built_client_headers):%-client-protocol.h : %.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ $(libnvidia_egl_wayland_la_built_server_headers):%-server-protocol.h : %.xml $(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@ egl-wayland-1.1.3/README.md000066400000000000000000000137031347064175300152150ustar00rootroot00000000000000Wayland EGL External Platform library ===================================== Overview -------- 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 families of extensions. This library implements an EGL External Platform interface to work along with EGL drivers that support the external platform mechanism. More information about EGL External platforms and the interface can be found at: https://github.com/NVIDIA/eglexternalplatform Building and Installing the library ----------------------------------- This library build-depends on: * EGL headers https://www.khronos.org/registry/EGL/ * Wayland libraries & protocols https://wayland.freedesktop.org/ * EGL External Platform interface https://github.com/NVIDIA/eglexternalplatform To build, run: ./autogen.sh make To install, run: make install You can also use meson build system to build and install: meson builddir cd builddir ninja ninja install *Notes*: The NVIDIA EGL driver uses a JSON-based loader to load all EGL External platforms available on the system. If this library is not installed as part of a NVIDIA driver installation, a JSON configuration file must be manually added in order to make the library work with the NVIDIA driver. The default EGL External platform JSON configuration directory is: `/usr/share/egl/egl_external_platform.d/` Acknowledgements ---------------- Thanks to James Jones for the original implementation of the Wayland EGL platform. ### Wayland EGL External platform library ### The Wayland EGL External platform library itself is licensed as follows: 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. ### buildconf ### The Wayland EGL External platform library uses the buildconf autotools bootstrapping script 'autogen.sh': http://freecode.com/projects/buildconf This script carries the following copyright notice: Copyright (c) 2005-2009 United States Government as represented by the U.S. Army Research Laboratory. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### MESA's wayland-egl-priv.h ### The Wayland EGL External platform library uses the wayland-egl-priv.h header file from the MESA package: https://cgit.freedesktop.org/mesa/mesa/tree/src/egl/wayland/wayland-egl/wayland-egl-priv.h This file carries the following copyright notice: 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. egl-wayland-1.1.3/autogen.sh000077500000000000000000000003071347064175300157330ustar00rootroot00000000000000#!/bin/sh test -n "$srcdir" || srcdir=`dirname "$0"` test -n "$srcdir" || srcdir=. ( cd "$srcdir" && autoreconf --force -v --install ) || exit test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" egl-wayland-1.1.3/configure.ac000066400000000000000000000066141347064175300162270ustar00rootroot00000000000000AC_PREREQ([2.64]) m4_define([wayland_eglstream_major_version], [1]) m4_define([wayland_eglstream_minor_version], [1]) m4_define([wayland_eglstream_micro_version], [3]) m4_define([wayland_eglstream_version], [wayland_eglstream_major_version.wayland_eglstream_minor_version.wayland_eglstream_micro_version]) AC_INIT([wayland-eglstream], [wayland_eglstream_version], [mvicomoya@nvidia.com]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build]) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) AC_SUBST([WAYLAND_EXTERNAL_MAJOR_VERSION], [wayland_eglstream_major_version]) AC_SUBST([WAYLAND_EXTERNAL_MINOR_VERSION], [wayland_eglstream_minor_version]) AC_SUBST([WAYLAND_EXTERNAL_MICRO_VERSION], [wayland_eglstream_micro_version]) AC_SUBST([WAYLAND_EXTERNAL_VERSION], [wayland_eglstream_version]) AC_SUBST([EGL_EXTERNAL_PLATFORM_MIN_VERSION], [${WAYLAND_EXTERNAL_MAJOR_VERSION}.${WAYLAND_EXTERNAL_MINOR_VERSION}]) AC_SUBST([EGL_EXTERNAL_PLATFORM_MAX_VERSION], [$(($WAYLAND_EXTERNAL_MAJOR_VERSION + 1))]) # Add an --enable-debug option AX_CHECK_ENABLE_DEBUG(no, DEBUG) AC_USE_SYSTEM_EXTENSIONS AM_INIT_AUTOMAKE([1.11 foreign subdir-objects]) AM_SILENT_RULES([yes]) PKG_PROG_PKG_CONFIG() # Checks for programs. AC_PROG_CC AC_PROG_CXX AM_PROG_AS AC_PROG_LIBTOOL AC_ARG_VAR([WAYLAND_SCANNER], [The wayland-scanner executable]) AC_PATH_PROG([WAYLAND_SCANNER], [wayland-scanner]) # User didn't specify wayland-scanner location manually, so find it ourselves 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]) LT_INIT # Checks for libraries. AX_PTHREAD() 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 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]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_INT32_T AC_TYPE_SIZE_T AC_TYPE_UINT32_T # Checks for library functions. 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], [COMPILER_FLAG_VISIBILITY_HIDDEN="-fvisibility=hidden"], [COMPILER_FLAG_VISIBILITY_HIDDEN=""]) AC_SUBST([COMPILER_FLAG_VISIBILITY_HIDDEN]) # See if the linker supports the --no-undefined flag. AX_CHECK_LINK_FLAG([-Xlinker --no-undefined], [LINKER_FLAG_NO_UNDEFINED="-Xlinker --no-undefined"], [LINKER_FLAG_NO_UNDEFINED=""]) AC_SUBST([LINKER_FLAG_NO_UNDEFINED]) # Default CFLAGS CFLAGS="$CFLAGS -Wall -Werror -include config.h" PKG_NOARCH_INSTALLDIR AC_CONFIG_FILES([ wayland-eglstream.pc wayland-eglstream-protocols.pc Makefile ]) AC_OUTPUT AC_MSG_RESULT([ Version ${WAYLAND_EXTERNAL_VERSION} Prefix ${prefix} ]) egl-wayland-1.1.3/include/000077500000000000000000000000001347064175300153555ustar00rootroot00000000000000egl-wayland-1.1.3/include/wayland-egldisplay.h000066400000000000000000000115301347064175300213200ustar00rootroot00000000000000/* * Copyright (c) 2014-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_EGLDISPLAY_H #define WAYLAND_EGLDISPLAY_H #include #include #include #include "wayland-external-exports.h" #include "wayland-eglhandle.h" #ifdef __cplusplus extern "C" { #endif /* This define represents the version of the wl_eglstream_controller interface when the attach_eglstream_consumer_attrib() request was first available" */ #define WL_EGLSTREAM_CONTROLLER_ATTACH_EGLSTREAM_CONSUMER_ATTRIB_SINCE 2 typedef struct WlEglDeviceDpyRec { EGLDeviceEXT eglDevice; EGLDisplay eglDisplay; unsigned int refCount; struct wl_list link; } WlEglDeviceDpy; typedef struct WlEglDisplayRec { WlEglDeviceDpy *devDpy; EGLBoolean ownNativeDpy; struct wl_display *nativeDpy; struct wl_list evtQueueList; struct wl_list dangEvtQueueList; struct wl_registry *wlRegistry; struct wl_eglstream_display *wlStreamDpy; struct wl_eglstream_controller *wlStreamCtl; unsigned int wlStreamCtlVer; struct { unsigned int stream_fd : 1; unsigned int stream_inet : 1; unsigned int stream_socket : 1; } caps; WlEglPlatformData *data; struct { unsigned int stream : 1; unsigned int stream_attrib : 1; unsigned int stream_cross_process_fd : 1; unsigned int stream_remote : 1; unsigned int stream_producer_eglsurface : 1; 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; typedef struct WlEventQueueRec { WlEglDisplay *display; struct wl_event_queue *queue; int refCount; struct wl_list dpyLink; struct wl_list dangLink; struct wl_list threadLink; } WlEventQueue; EGLBoolean wlEglIsValidNativeDisplayExport(void *data, void *nativeDpy); EGLBoolean wlEglBindDisplaysHook(void *data, EGLDisplay dpy, void *nativeDpy); EGLBoolean wlEglUnbindDisplaysHook(EGLDisplay dpy, void *nativeDpy); EGLDisplay wlEglGetPlatformDisplayExport(void *data, EGLenum platform, void *nativeDpy, const EGLAttrib *attribs); EGLBoolean wlEglInitializeHook(EGLDisplay dpy, EGLint *major, EGLint *minor); EGLBoolean wlEglTerminateHook(EGLDisplay dpy); EGLBoolean wlEglChooseConfigHook(EGLDisplay dpy, EGLint const * attribs, EGLConfig * configs, EGLint configSize, EGLint * numConfig); EGLBoolean wlEglGetConfigAttribHook(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint * value); EGLBoolean wlEglIsWaylandDisplay(void *nativeDpy); EGLBoolean wlEglIsWlEglDisplay(WlEglDisplay *display); EGLBoolean wlEglDestroyAllDisplays(WlEglPlatformData *data); const char* wlEglQueryStringExport(void *data, EGLDisplay dpy, EGLExtPlatformString name); struct wl_event_queue* wlGetEventQueue(WlEglDisplay *display); void wlUpdateQueueBusyStatus(WlEglDisplay *display, struct wl_event_queue *queue, EGLBoolean isBusy); int wlEglRoundtrip(WlEglDisplay *display, struct wl_event_queue *queue); #ifdef __cplusplus } #endif #endif egl-wayland-1.1.3/include/wayland-eglhandle.h000066400000000000000000000153361347064175300211160ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #ifndef WAYLAND_EGLHANDLE_H #define WAYLAND_EGLHANDLE_H #include #include #include "wayland-external-exports.h" #include "wayland-egl-ext.h" #include #ifdef __cplusplus extern "C" { #endif /* * Define function pointers for EGL core functions */ typedef const char* (*PWLEGLFNQUERYSTRINGCOREPROC) (EGLDisplay dpy, EGLint name); typedef EGLContext (*PWLEGLFNGETCURRENTCONTEXTCOREPROC) (void); typedef EGLSurface (*PWLEGLFNGETCURRENTSURFACECOREPROC) (EGLint readdraw); typedef EGLBoolean (*PWLEGLFNRELEASETHREADCOREPROC) (void); typedef EGLint (*PWLEGLFNGETERRORCOREPROC) (void); typedef void* (*PWLEGLFNGETPROCADDRESSCOREPROC) (const char *name); typedef EGLBoolean (*PWLEGLFNINITIALIZECOREPROC) (EGLDisplay dpy, EGLint *major, EGLint *minor); typedef EGLBoolean (*PWLEGLFNTERMINATECOREPROC) (EGLDisplay dpy); typedef EGLBoolean (*PWLEGLFNCHOOSECONFIGCOREPROC) (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); typedef EGLBoolean (*PWLEGLFNGETCONFIGATTRIBCOREPROC) (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); typedef EGLSurface (*PWLEGLFNCREATEPBUFFERSURFACECOREPROC) (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); typedef EGLBoolean (*PWLEGLFNDESTROYSURFACECOREPROC) (EGLDisplay dpy, EGLSurface surface); typedef EGLBoolean (*PWLEGLFNMAKECURRENTCOREPROC) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); typedef EGLBoolean (*PWLEGLFNSWAPBUFFERSCOREPROC) (EGLDisplay dpy, EGLSurface surface); typedef EGLBoolean (*PWLEGLFNSWAPBUFFERSWITHDAMAGEKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); typedef EGLBoolean (*PWLEGLFNSWAPINTERVALCOREPROC) (EGLDisplay dpy, EGLint interval); /* * WlEglPlatformData structure * * Keeps all EGL driver-specific methods provided by a specific EGL * implementation that are required by the Wayland external platform * implementation to manage resources associated with a specific backing * EGLDisplay. */ typedef struct WlEglPlatformDataRec { /* Application-facing callbacks fetched from the EGL driver */ struct { int major; int minor; PWLEGLFNQUERYSTRINGCOREPROC queryString; PFNEGLQUERYDEVICESEXTPROC queryDevices; PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay; PWLEGLFNINITIALIZECOREPROC initialize; PWLEGLFNTERMINATECOREPROC terminate; PWLEGLFNCHOOSECONFIGCOREPROC chooseConfig; PWLEGLFNGETCONFIGATTRIBCOREPROC getConfigAttrib; PWLEGLFNGETCURRENTCONTEXTCOREPROC getCurrentContext; PWLEGLFNGETCURRENTSURFACECOREPROC getCurrentSurface; PWLEGLFNMAKECURRENTCOREPROC makeCurrent; PFNEGLCREATESTREAMKHRPROC createStream; PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC createStreamFromFD; PFNEGLCREATESTREAMATTRIBNVPROC createStreamAttrib; PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC getStreamFileDescriptor; PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC createStreamProducerSurface; PWLEGLFNCREATEPBUFFERSURFACECOREPROC createPbufferSurface; PFNEGLDESTROYSTREAMKHRPROC destroyStream; PWLEGLFNDESTROYSURFACECOREPROC destroySurface; PWLEGLFNSWAPBUFFERSCOREPROC swapBuffers; PWLEGLFNSWAPBUFFERSWITHDAMAGEKHRPROC swapBuffersWithDamage; PWLEGLFNSWAPINTERVALCOREPROC swapInterval; PWLEGLFNGETERRORCOREPROC getError; PWLEGLFNRELEASETHREADCOREPROC releaseThread; PFNEGLQUERYDISPLAYATTRIBKHRPROC queryDisplayAttrib; /* Used for fifo_synchronous support */ PFNEGLQUERYSTREAMKHRPROC queryStream; PFNEGLQUERYSTREAMU64KHRPROC queryStreamu64; PFNEGLCREATESTREAMSYNCNVPROC createStreamSync; PFNEGLCLIENTWAITSYNCKHRPROC clientWaitSync; PFNEGLSIGNALSYNCKHRPROC signalSync; PFNEGLDESTROYSYNCKHRPROC destroySync; PFNEGLSTREAMFLUSHNVPROC streamFlush; } egl; /* Non-application-facing callbacks provided by the EGL driver */ struct { PEGLEXTFNSETERROR setError; PEGLEXTFNSTREAMSWAPINTERVAL streamSwapInterval; } callbacks; /* pthread key for TLS */ pthread_key_t tlsKey; } WlEglPlatformData; /* * wlEglCreatePlatformData() * * Creates a new platform data structure and fills it out with all the required * application-facing EGL methods provided by . * * . correspond to the EGL External Platform interface * version supported by the driver. * * Returns a pointer to the newly created structure upon success; otherwise, * returns NULL. */ WlEglPlatformData* wlEglCreatePlatformData(int apiMajor, int apiMinor, const EGLExtDriver *driver); /* * wlEglDestroyPlatformData() * * Destroys the given platform data, previously created with * wlEglCreatePlatformData(). */ void wlEglDestroyPlatformData(WlEglPlatformData *data); void* wlEglGetInternalHandleExport(EGLDisplay dpy, EGLenum type, void *handle); #ifdef __cplusplus } #endif #endif egl-wayland-1.1.3/include/wayland-eglstream-server.h000066400000000000000000000066021347064175300224560ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #ifndef WAYLAND_EGLSTREAM_SERVER_H #define WAYLAND_EGLSTREAM_SERVER_H #include #include #include #include "wayland-eglhandle.h" #ifdef __cplusplus extern "C" { #endif /* * Forward declarations */ struct wl_eglstream_display; struct wl_eglstream; /* * wl_eglstream_display_bind() * * Creates and initializes a wl_eglstream_display connection associated to the * given wl_display and EGLDisplay. */ EGLBoolean wl_eglstream_display_bind(WlEglPlatformData *data, struct wl_display *wlDisplay, EGLDisplay eglDisplay); /* * wl_eglstream_display_unbind() * * Destroys the given wl_eglstream_display connection result of a previous * wl_eglstream_display_bind() call. */ void wl_eglstream_display_unbind(struct wl_eglstream_display *wlStreamDpy); /* * wl_eglstream_display_get() * * Given an EGL display, returns its associated wl_eglstream_display connection. */ struct wl_eglstream_display* wl_eglstream_display_get(EGLDisplay eglDisplay); /* * wl_eglstream_display_get_stream() * * Given a generic wl_resource, returns its associated wl_eglstream. */ struct wl_eglstream* wl_eglstream_display_get_stream(struct wl_eglstream_display *wlStreamDpy, struct wl_resource *resource); /* wl_eglstream_display definition */ struct wl_eglstream_display { WlEglPlatformData *data; struct wl_global *global; struct wl_display *wlDisplay; EGLDisplay eglDisplay; struct { int stream_attrib : 1; int stream_cross_process_fd : 1; int stream_remote : 1; int stream_socket : 1; int stream_socket_inet : 1; int stream_socket_unix : 1; int stream_origin : 1; } exts; int caps_override : 1; int supported_caps; struct wl_buffer_interface wl_eglstream_interface; struct wl_list link; }; /* wl_eglstream definition */ struct wl_eglstream { struct wl_resource *resource; struct wl_eglstream_display *wlStreamDpy; int width, height; EGLBoolean fromFd; EGLBoolean isInet; int handle; EGLStreamKHR eglStream; }; #ifdef __cplusplus } #endif #endif egl-wayland-1.1.3/include/wayland-eglstream.h000066400000000000000000000032401347064175300211450ustar00rootroot00000000000000/* * 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. */ #ifndef WAYLAND_EGLSTREAM_H #define WAYLAND_EGLSTREAM_H #include #include #ifdef __cplusplus extern "C" { #endif /* wlEglCreateStreamAttribHook() * * Creates an EGLStream from the given external attribute list. If suceeded, * the new stream handle is returned; otherwise, EGL_NO_STREAM_KHR is returned * and the appropriate EGL error is generated. */ EGLStreamKHR wlEglCreateStreamAttribHook(EGLDisplay dpy, const EGLAttrib *attribs); #ifdef __cplusplus } #endif #endif egl-wayland-1.1.3/include/wayland-eglsurface.h000066400000000000000000000106561347064175300213130ustar00rootroot00000000000000/* * Copyright (c) 2014-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_EGLSURFACE_H #define WAYLAND_EGLSURFACE_H #include #include #include #include #include "wayland-egldisplay.h" #include "wayland-eglutils.h" #ifdef __cplusplus extern "C" { #endif typedef struct WlEglSurfaceCtxRec { EGLBoolean isOffscreen; EGLSurface eglSurface; EGLStreamKHR eglStream; void *wlStreamResource; struct wl_event_queue *wlStreamResCbQueue; EGLBoolean isAttached; int useDamageThread; pthread_t damageThreadId; EGLSyncKHR damageThreadSync; int damageThreadFlush; int damageThreadShutdown; EGLuint64KHR framesProduced; EGLuint64KHR framesFinished; EGLuint64KHR framesProcessed; struct wl_list link; } WlEglSurfaceCtx; typedef struct WlEglSurfaceRec { WlEglDisplay *wlEglDpy; EGLConfig eglConfig; EGLint *attribs; struct wl_egl_window *wlEglWin; long int wlEglWinVer; struct wl_surface *wlSurface; int width, height; int dx, dy; WlEglSurfaceCtx ctx; struct wl_list oldCtxList; EGLint swapInterval; EGLint fifoLength; struct wl_callback *throttleCallback; struct wl_event_queue *throttleCbQueue; struct wl_list link; EGLBoolean isSurfaceProducer; } WlEglSurface; extern struct wl_list wlEglSurfaceList; WL_EXPORT EGLBoolean wlEglInitializeSurfaceExport(WlEglSurface *surface); EGLSurface wlEglCreatePlatformWindowSurfaceHook(EGLDisplay dpy, EGLConfig config, void *nativeWin, const EGLAttrib *attribs); EGLSurface wlEglCreatePlatformPixmapSurfaceHook(EGLDisplay dpy, EGLConfig config, void *nativePixmap, const EGLAttrib *attribs); EGLSurface wlEglCreatePbufferSurfaceHook(EGLDisplay dpy, EGLConfig config, const EGLint *attribs); EGLSurface wlEglCreateStreamProducerSurfaceHook(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attribs); EGLBoolean wlEglDestroySurfaceHook(EGLDisplay dpy, EGLSurface eglSurface); EGLBoolean wlEglDestroyAllSurfaces(WlEglDisplay *display); EGLBoolean wlEglIsWaylandWindowValid(struct wl_egl_window *window); EGLBoolean wlEglIsWlEglSurface(WlEglSurface *wlEglSurface); EGLBoolean wlEglQueryNativeResourceHook(EGLDisplay dpy, void *nativeResource, EGLint attribute, int *value); 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); #ifdef __cplusplus } #endif #endif egl-wayland-1.1.3/include/wayland-eglswap.h000066400000000000000000000040701347064175300206260ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #ifndef WAYLAND_EGLSWAP_H #define WAYLAND_EGLSWAP_H #include #include #include "wayland-eglhandle.h" #include "wayland-eglsurface.h" #ifdef __cplusplus extern "C" { #endif EGLBoolean wlEglSwapBuffersHook(EGLDisplay dpy, EGLSurface eglSurface); EGLBoolean wlEglSwapBuffersWithDamageHook(EGLDisplay eglDisplay, EGLSurface eglSurface, EGLint *rects, EGLint n_rects); EGLBoolean wlEglSwapIntervalHook(EGLDisplay eglDisplay, EGLint interval); EGLint wlEglStreamSwapIntervalCallback(WlEglPlatformData *data, EGLStreamKHR stream, EGLint *interval); WL_EXPORT EGLBoolean wlEglPrePresentExport(WlEglSurface *surface); WL_EXPORT EGLBoolean wlEglPostPresentExport(WlEglSurface *surface); #ifdef __cplusplus } #endif #endif egl-wayland-1.1.3/include/wayland-eglutils.h000066400000000000000000000042031347064175300210120ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #ifndef WAYLAND_EGLUTILS_H #define WAYLAND_EGLUTILS_H #include #include #include "wayland-external-exports.h" #include "wayland-eglhandle.h" #ifdef NDEBUG #define wlEglSetError(data, err) \ wlEglSetErrorCallback(data, err, 0, 0) #else #define wlEglSetError(data, err) \ wlEglSetErrorCallback(data, err, __FILE__, __LINE__) #endif #ifndef WL_LIST_INIT #define WL_LIST_INIT(head) { .prev = (head), .next = (head) } #endif #if defined(__QNX__) #define HAS_MINCORE 0 #else #define HAS_MINCORE 1 #endif #ifdef __cplusplus extern "C" { #endif EGLBoolean wlEglFindExtension(const char *extension, const char *extensions); #if HAS_MINCORE EGLBoolean wlEglPointerIsDereferencable(void *p); EGLBoolean wlEglCheckInterfaceType(struct wl_object *obj, const char *ifname); #endif void wlEglSetErrorCallback(WlEglPlatformData *data, EGLint err, const char *file, int line); #ifdef __cplusplus } #endif #endif egl-wayland-1.1.3/include/wayland-external-exports.h000066400000000000000000000053431347064175300225140ustar00rootroot00000000000000/* * 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. */ #ifndef WAYLAND_EXTERNAL_EXPORTS_H #define WAYLAND_EXTERNAL_EXPORTS_H /* * .. * defines the EGL external Wayland * implementation version. * * The includer of this file can override either WAYLAND_EXTERNAL_VERSION_MAJOR * or WAYLAND_EXTERNAL_VERSION_MINOR in order to build against a certain EGL * external API version. * * * How to update this version numbers: * * - WAYLAND_EXTERNAL_VERSION_MAJOR must match the EGL external API major * number this platform implements * * - WAYLAND_EXTERNAL_VERSION_MINOR must match the EGL external API minor * number this platform implements * * - If the platform implementation is changed in any way, increase * WAYLAND_EXTERNAL_VERSION_MICRO by 1 */ #if !defined(WAYLAND_EXTERNAL_VERSION_MAJOR) #define WAYLAND_EXTERNAL_VERSION_MAJOR 1 #if !defined(WAYLAND_EXTERNAL_VERSION_MINOR) #define WAYLAND_EXTERNAL_VERSION_MINOR 1 #endif #elif !defined(WAYLAND_EXTERNAL_VERSION_MINOR) #define WAYLAND_EXTERNAL_VERSION_MINOR 0 #endif #define WAYLAND_EXTERNAL_VERSION_MICRO 3 #define EGL_EXTERNAL_PLATFORM_VERSION_MAJOR WAYLAND_EXTERNAL_VERSION_MAJOR #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); #endif egl-wayland-1.1.3/include/wayland-thread.h000066400000000000000000000053431347064175300204370ustar00rootroot00000000000000/* * 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_list evtQueueList; int processExiting; } 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 egl-wayland-1.1.3/m4/000077500000000000000000000000001347064175300142525ustar00rootroot00000000000000egl-wayland-1.1.3/m4/ax_check_enable_debug.m4000066400000000000000000000107301347064175300207360ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_enable_debug.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_ENABLE_DEBUG([enable by default=yes/info/profile/no], [ENABLE DEBUG VARIABLES ...], [DISABLE DEBUG VARIABLES NDEBUG ...], [IS-RELEASE]) # # DESCRIPTION # # Check for the presence of an --enable-debug option to configure, with # the specified default value used when the option is not present. Return # the value in the variable $ax_enable_debug. # # Specifying 'yes' adds '-g -O0' to the compilation flags for all # languages. Specifying 'info' adds '-g' to the compilation flags. # Specifying 'profile' adds '-g -pg' to the compilation flags and '-pg' to # the linking flags. Otherwise, nothing is added. # # Define the variables listed in the second argument if debug is enabled, # defaulting to no variables. Defines the variables listed in the third # argument if debug is disabled, defaulting to NDEBUG. All lists of # variables should be space-separated. # # If debug is not enabled, ensure AC_PROG_* will not add debugging flags. # Should be invoked prior to any AC_PROG_* compiler checks. # # IS-RELEASE can be used to change the default to 'no' when making a # release. Set IS-RELEASE to 'yes' or 'no' as appropriate. By default, it # uses the value of $ax_is_release, so if you are using the AX_IS_RELEASE # macro, there is no need to pass this parameter. # # AX_IS_RELEASE([git-directory]) # AX_CHECK_ENABLE_DEBUG() # # LICENSE # # Copyright (c) 2011 Rhys Ulerich # Copyright (c) 2014, 2015 Philip Withnall # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. #serial 5 AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[ AC_BEFORE([$0],[AC_PROG_CC])dnl AC_BEFORE([$0],[AC_PROG_CXX])dnl AC_BEFORE([$0],[AC_PROG_F77])dnl AC_BEFORE([$0],[AC_PROG_FC])dnl AC_MSG_CHECKING(whether to enable debugging) ax_enable_debug_default=m4_tolower(m4_normalize(ifelse([$1],,[no],[$1]))) ax_enable_debug_is_release=m4_tolower(m4_normalize(ifelse([$4],, [$ax_is_release], [$4]))) # If this is a release, override the default. AS_IF([test "$ax_enable_debug_is_release" = "yes"], [ax_enable_debug_default="no"]) m4_define(ax_enable_debug_vars,[m4_normalize(ifelse([$2],,,[$2]))]) m4_define(ax_disable_debug_vars,[m4_normalize(ifelse([$3],,[NDEBUG],[$3]))]) AC_ARG_ENABLE(debug, [AS_HELP_STRING([--enable-debug=]@<:@yes/info/profile/no@:>@,[compile with debugging])], [],enable_debug=$ax_enable_debug_default) # empty mean debug yes AS_IF([test "x$enable_debug" = "x"], [enable_debug="yes"]) # case of debug AS_CASE([$enable_debug], [yes],[ AC_MSG_RESULT(yes) CFLAGS="${CFLAGS} -g -O0" CXXFLAGS="${CXXFLAGS} -g -O0" FFLAGS="${FFLAGS} -g -O0" FCFLAGS="${FCFLAGS} -g -O0" OBJCFLAGS="${OBJCFLAGS} -g -O0" ], [info],[ AC_MSG_RESULT(info) CFLAGS="${CFLAGS} -g" CXXFLAGS="${CXXFLAGS} -g" FFLAGS="${FFLAGS} -g" FCFLAGS="${FCFLAGS} -g" OBJCFLAGS="${OBJCFLAGS} -g" ], [profile],[ AC_MSG_RESULT(profile) CFLAGS="${CFLAGS} -g -pg" CXXFLAGS="${CXXFLAGS} -g -pg" FFLAGS="${FFLAGS} -g -pg" FCFLAGS="${FCFLAGS} -g -pg" OBJCFLAGS="${OBJCFLAGS} -g -pg" LDFLAGS="${LDFLAGS} -pg" ], [ AC_MSG_RESULT(no) dnl Ensure AC_PROG_CC/CXX/F77/FC/OBJC will not enable debug flags dnl by setting any unset environment flag variables AS_IF([test "x${CFLAGS+set}" != "xset"], [CFLAGS=""]) AS_IF([test "x${CXXFLAGS+set}" != "xset"], [CXXFLAGS=""]) AS_IF([test "x${FFLAGS+set}" != "xset"], [FFLAGS=""]) AS_IF([test "x${FCFLAGS+set}" != "xset"], [FCFLAGS=""]) AS_IF([test "x${OBJCFLAGS+set}" != "xset"], [OBJCFLAGS=""]) ]) dnl Define various variables if debugging is disabled. dnl assert.h is a NOP if NDEBUG is defined, so define it by default. AS_IF([test "x$enable_debug" = "xyes"], [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is enabled])])], [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is disabled])])]) ax_enable_debug=$enable_debug ]) egl-wayland-1.1.3/m4/ax_check_link_flag.m4000066400000000000000000000057601347064175300202770ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) # # DESCRIPTION # # Check whether the given FLAG works with the linker or gives an error. # (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the linker's default flags # when the check is done. The check is thus made with the flags: "LDFLAGS # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 AC_DEFUN([AX_CHECK_LINK_FLAG], [AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $4 $1" AC_LINK_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) LDFLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_LINK_FLAGS egl-wayland-1.1.3/m4/ax_pthread.m4000066400000000000000000000312671347064175300166440ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 20 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) AC_MSG_RESULT($ax_pthread_ok) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($ax_pthread_ok) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], ax_cv_PTHREAD_PRIO_INHERIT, [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: compile with *_r variant if test "x$GCC" != xyes; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD egl-wayland-1.1.3/meson.build000066400000000000000000000041551347064175300161010ustar00rootroot00000000000000project('wayland-eglstream', 'c', version : '1.1.3', default_options : [ 'buildtype=debugoptimized', 'c_std=gnu99', 'warning_level=1', ], license : 'MIT', meson_version : '>= 0.43' ) cc = meson.get_compiler('c') wayland_eglstream_version = meson.project_version() ver_arr = wayland_eglstream_version.split('.') wayland_eglstream_major_version = ver_arr[0] wayland_eglstream_minor_version = ver_arr[1] 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) prog_scanner = find_program(wl_scanner.get_pkgconfig_variable('wayland_scanner')) inc = include_directories( 'include', 'wayland-egl', ) pkgconf = configuration_data() pkgconf.set('prefix', get_option('prefix')) pkgconf.set('exec_prefix', '${prefix}') pkgconf.set('libdir', '${exec_prefix}/@0@'.format(get_option('libdir'))) pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) pkgconf.set('datadir', '${datarootdir}') pkgconf.set('datarootdir', '${prefix}/@0@'.format(get_option('datadir'))) pkgconf.set('PACKAGE', meson.project_name()) pkgconf.set('WAYLAND_EXTERNAL_VERSION', meson.project_version()) pkgconf.set('EGL_EXTERNAL_PLATFORM_MIN_VERSION', '@0@.@1@'.format(wayland_eglstream_major_version, wayland_eglstream_minor_version)) pkgconf.set('EGL_EXTERNAL_PLATFORM_MAX_VERSION', wayland_eglstream_major_version.to_int() + 1) generated_pc = [ 'wayland-eglstream', 'wayland-eglstream-protocols' ] foreach pc : generated_pc configure_file( input : '@0@.pc.in'.format(pc), output : '@BASENAME@', configuration : pkgconf, install : true, install_dir : join_paths(get_option('datadir'), 'pkgconfig') ) endforeach subdir('wayland-eglstream') subdir('src') egl-wayland-1.1.3/src/000077500000000000000000000000001347064175300145215ustar00rootroot00000000000000egl-wayland-1.1.3/src/meson.build000066400000000000000000000023561347064175300166710ustar00rootroot00000000000000if not cc.has_function('dlsym') libdl = cc.find_library('dl') else libdl = [] endif add_project_arguments('-Wall', language : 'c') add_project_arguments('-Werror', language : 'c') add_project_arguments('-fvisibility=hidden', language : 'c') add_project_arguments('-DWL_HIDE_DEPRECATED', language : 'c') add_project_link_arguments('-Wl,-Bsymbolic', language : 'c') if cc.has_argument('-Wpedantic') add_project_arguments('-Wno-pedantic', language : 'c') endif src = [ 'wayland-thread.c', 'wayland-egldisplay.c', 'wayland-eglstream.c', 'wayland-eglstream-server.c', 'wayland-eglsurface.c', 'wayland-eglswap.c', 'wayland-eglutils.c', 'wayland-eglhandle.c', 'wayland-external-exports.c', wayland_eglstream_protocol_c, wayland_eglstream_client_protocol_h, wayland_eglstream_server_protocol_h, wayland_eglstream_controller_protocol_c, wayland_eglstream_controller_client_protocol_h, ] egl_wayland = library('nvidia-egl-wayland', src, dependencies : [ eglexternalplatform, wayland_server, wayland_client, wayland_egl_backend, threads, libdl, ], include_directories : inc, version : meson.project_version(), install : true, ) egl-wayland-1.1.3/src/wayland-egldisplay.c000066400000000000000000000741671347064175300204760ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #include "wayland-egldisplay.h" #include "wayland-eglstream-client-protocol.h" #include "wayland-eglstream-controller-client-protocol.h" #include "wayland-eglstream-server.h" #include "wayland-thread.h" #include "wayland-eglsurface.h" #include "wayland-eglhandle.h" #include "wayland-eglutils.h" #include #include #include /* TODO: Make global display lists hang off platform data */ static struct wl_list wlEglDisplayList = WL_LIST_INIT(&wlEglDisplayList); static struct wl_list wlEglDeviceDpyList = WL_LIST_INIT(&wlEglDeviceDpyList); EGLBoolean wlEglIsWaylandDisplay(void *nativeDpy) { #if HAS_MINCORE if (!wlEglPointerIsDereferencable(nativeDpy)) { return EGL_FALSE; } return wlEglCheckInterfaceType((struct wl_object *)nativeDpy, "wl_display_interface"); #else (void)nativeDpy; /* we return EGL_TRUE in order to always assume a valid wayland * display is given so that we bypass all the checks that would * prevent any of the functions in this library to work * otherwise. */ return EGL_TRUE; #endif } EGLBoolean wlEglIsValidNativeDisplayExport(void *data, void *nativeDpy) { EGLBoolean checkDpy = EGL_TRUE; char *val = getenv("EGL_PLATFORM"); (void)data; if (val && !strcasecmp(val, "wayland")) { return EGL_TRUE; } #if !HAS_MINCORE /* wlEglIsWaylandDisplay always returns true if mincore(2) * is not available, hence we cannot ascertain whether the * the nativeDpy is wayland. * Note: this effectively forces applications to use * eglGetPlatformDisplay() instead of eglGetDisplay(). */ checkDpy = EGL_FALSE; #endif return (checkDpy ? wlEglIsWaylandDisplay(nativeDpy) : EGL_FALSE); } EGLBoolean wlEglBindDisplaysHook(void *data, EGLDisplay dpy, void *nativeDpy) { EGLBoolean res = EGL_FALSE; wlExternalApiLock(); res = wl_eglstream_display_bind((WlEglPlatformData *)data, (struct wl_display *)nativeDpy, dpy); wlExternalApiUnlock(); return res; } EGLBoolean wlEglUnbindDisplaysHook(EGLDisplay dpy, void *nativeDpy) { struct wl_eglstream_display *wlStreamDpy; EGLBoolean res = EGL_FALSE; wlExternalApiLock(); wlStreamDpy = wl_eglstream_display_get(dpy); if (wlStreamDpy && (wlStreamDpy->wlDisplay == (struct wl_display *)nativeDpy)) { wl_eglstream_display_unbind(wlStreamDpy); res = EGL_TRUE; } wlExternalApiUnlock(); return res; } static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { WlEglDisplay *display = (WlEglDisplay *)data; if (strcmp(interface, "wl_eglstream_display") == 0) { display->wlStreamDpy = wl_registry_bind(registry, name, &wl_eglstream_display_interface, version); } if (strcmp(interface, "wl_eglstream_controller") == 0) { display->wlStreamCtl = wl_registry_bind(registry, name, &wl_eglstream_controller_interface, version); display->wlStreamCtlVer = version; } } static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { (void) data; (void) registry; (void) name; } static const struct wl_registry_listener registry_listener = { registry_handle_global, registry_handle_global_remove }; static void eglstream_display_handle_caps(void *data, struct wl_eglstream_display *wlStreamDpy, int32_t caps) { WlEglDisplay *dpy = (WlEglDisplay *)data; (void) wlStreamDpy; #define IS_CAP_SET(CAPS, CAP) (((CAPS)&(CAP)) != 0) dpy->caps.stream_fd = IS_CAP_SET(caps, WL_EGLSTREAM_DISPLAY_CAP_STREAM_FD); dpy->caps.stream_inet = IS_CAP_SET(caps, WL_EGLSTREAM_DISPLAY_CAP_STREAM_INET); dpy->caps.stream_socket = IS_CAP_SET(caps, WL_EGLSTREAM_DISPLAY_CAP_STREAM_SOCKET); #undef IS_CAP_SET } static void eglstream_display_handle_swapinterval_override( void *data, struct wl_eglstream_display *wlStreamDpy, int32_t swapinterval, struct wl_buffer *streamResource) { WlEglSurface *surf = NULL; (void) data; (void) wlStreamDpy; wl_list_for_each(surf, &wlEglSurfaceList, link) { if (surf->ctx.wlStreamResource == streamResource) { WlEglPlatformData *pData = surf->wlEglDpy->data; EGLDisplay dpy = surf->wlEglDpy->devDpy->eglDisplay; if (pData->egl.swapInterval(dpy, swapinterval)) { surf->swapInterval = swapinterval; } break; } } } static const struct wl_eglstream_display_listener eglstream_display_listener = { eglstream_display_handle_caps, eglstream_display_handle_swapinterval_override, }; static void sync_callback(void *data, struct wl_callback *callback, uint32_t serial) { int *done = data; (void) serial; *done = 1; wl_callback_destroy(callback); } static const struct wl_callback_listener sync_listener = { sync_callback }; struct wl_event_queue* wlGetEventQueue(WlEglDisplay *display) { WlThread *wlThread = wlGetThread(); WlEventQueue *evtQueue = NULL; WlEventQueue *iter = NULL; if (wlThread != NULL) { /* Try to find an existing queue in the thread list */ wl_list_for_each(iter, &wlThread->evtQueueList, threadLink) { if (iter->display == display) { evtQueue = iter; break; } } /* If a valid queue was found, we are done */ if ((evtQueue != NULL) && (evtQueue->queue != NULL)) { return evtQueue->queue; } if (evtQueue == NULL) { /* Create the WlEventQueue and add it to the thread list */ evtQueue = calloc(1, sizeof(*evtQueue)); if (evtQueue == NULL) { return NULL; } evtQueue->display = display; wl_list_insert(&wlThread->evtQueueList, &evtQueue->threadLink); } /* Create the wl_event_queue, and add WlEventQueue to the dpy list */ evtQueue->queue = wl_display_create_queue(display->nativeDpy); if (evtQueue->queue == NULL) { return NULL; } wl_list_insert(&display->evtQueueList, &evtQueue->dpyLink); } return (evtQueue ? evtQueue->queue : NULL); } void wlUpdateQueueBusyStatus(WlEglDisplay *display, struct wl_event_queue *queue, EGLBoolean isBusy) { WlEventQueue *evtQueue = NULL; WlEventQueue *iter = NULL; WlEventQueue *tmp = NULL; if (display != NULL) { assert(queue); /* Try to find the queue from dpy queue list */ wl_list_for_each(iter, &display->evtQueueList, dpyLink) { if (iter->queue == queue) { evtQueue = iter; break; } } if (evtQueue) { if (isBusy) { evtQueue->refCount++; } else { /* refCount should not be already 0 */ assert(evtQueue->refCount > 0); evtQueue->refCount--; } } /* If it isn't present in evtQueueList, check the * availability in dangling queue list if the isBusy flag is FALSE. * If it is present in dangling queue list and the refCnt reaches 0, * invalidate and destroy */ else if (!isBusy) { wl_list_for_each_safe(iter, tmp, &display->dangEvtQueueList, dangLink) { if (iter->queue == queue) { iter->refCount--; if (!iter->refCount) { wl_event_queue_destroy(iter->queue); iter->queue = NULL; wl_list_remove(&iter->dangLink); free(iter); } break; } } } } } int wlEglRoundtrip(WlEglDisplay *display, struct wl_event_queue *queue) { struct wl_display *wrapper; struct wl_callback *callback; int ret = 0, done = 0; 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) */ wlExternalApiUnlock(); ret = wl_display_dispatch_queue(display->nativeDpy, queue); wlExternalApiLock(); } if (!done) { wl_callback_destroy(callback); } return ret; } /* On wayland, when a wl_display backed EGLDisplay is created and then * wl_display is destroyed without terminating EGLDisplay first, some * driver allocated resources associated with wl_display could not be * destroyed properly during EGL teardown. * Per EGL spec: Termination of a display that has already been terminated, * or has not yet been initialized, is allowed, but the only effect of such * a call is to return EGL_TRUE, since there are no EGL resources associated * with the display to release. * However, in our wayland egl driver, we do allocate some resources * which are associated with wl_display even eglInitialize is not called. * If the app does not terminate EGLDisplay before closing wl_display, * it can hit assertion or hang in pthread_mutex_lock during EGL teardown. * To WAR the issue, in case wl_display has been destroyed, we skip * destroying some resources during EGL system termination, only when * terminateDisplay is called from wlEglDestroyAllDisplays. */ static EGLBoolean terminateDisplay(EGLDisplay dpy, EGLBoolean skipDestroy) { WlEglDisplay *display = (WlEglDisplay *)dpy; WlEglPlatformData *data = display->data; WlEventQueue *iter = NULL; WlEventQueue *tmp = NULL; EGLBoolean fullTerminate = EGL_FALSE; EGLBoolean res = EGL_TRUE; /* We can only get here if the EGLDisplay belongs to the Wayland platform. * However, if it is no longer a WlEglDisplay, it means we have already * removed it from the list. Terminating an already terminated display * has no effect as per the EGL specification. */ if (!wlEglIsWlEglDisplay(display)) { return EGL_TRUE; } if (display->useRefCount) { display->refCount -= 1; if (display->refCount > 0) { return EGL_TRUE; } } /* Remove display from wlEglDisplayList before calling into * wlEglDestroyAllSurfaces to avoid multiple threads trying to teminate * the same display simultaneously. When wlEglDestroyAllSurfaces was * called, wl external API lock could be released temporarily, which * would allow multiple threads get the same display, enter * terminateDisplay and lead to segmentation fault. */ wl_list_remove(&display->link); /* First, destroy any surface associated to the given display. Then * destroy the display connection itself */ wlEglDestroyAllSurfaces(display); if (skipDestroy != EGL_TRUE || display->ownNativeDpy) { if (display->wlRegistry) { wl_registry_destroy(display->wlRegistry); } if (display->wlStreamDpy) { wl_eglstream_display_destroy(display->wlStreamDpy); } /* Invalidate all event queues created for this display */ wl_list_for_each_safe(iter, tmp, &display->evtQueueList, dpyLink) { wl_event_queue_destroy(iter->queue); iter->queue = NULL; wl_list_remove(&iter->dpyLink); } /* Invalidate and destroy event queues from dangling queue list if any */ wl_list_for_each_safe(iter, tmp, &display->dangEvtQueueList, dangLink) { wl_event_queue_destroy(iter->queue); iter->queue = NULL; wl_list_remove(&iter->dangLink); free(iter); } } if (display->ownNativeDpy) { wl_display_disconnect(display->nativeDpy); } /* Unreference internal EGL display. If refCount reaches 0, mark the * internal display for termination. */ if (display->devDpy != NULL) { display->devDpy->refCount--; if (display->devDpy->refCount == 0) { /* Save the internal EGLDisplay handle, as it's needed by the actual * eglTerminate() call */ fullTerminate = EGL_TRUE; dpy = display->devDpy->eglDisplay; wl_list_remove(&display->devDpy->link); free(display->devDpy); } } /* Destroy the external display */ free(display); /* XXX: Currently, we assume an internal EGLDisplay will only be used by a * single external platform. In practice, we could create multiple * external displays from different external implementations using the * same internal EGLDisplay. This is a known issue currently tracked in * the following Khronos bug: * * https://cvs.khronos.org/bugzilla/show_bug.cgi?id=12072 */ if (fullTerminate) { wlExternalApiUnlock(); res = data->egl.terminate(dpy); wlExternalApiLock(); } return res; } EGLBoolean wlEglTerminateHook(EGLDisplay dpy) { EGLBoolean res; wlExternalApiLock(); res = terminateDisplay(dpy, EGL_FALSE); wlExternalApiUnlock(); return res; } EGLDisplay wlEglGetPlatformDisplayExport(void *data, EGLenum platform, 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; 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; if (platform != EGL_PLATFORM_WAYLAND_EXT) { wlEglSetError(data, EGL_BAD_PARAMETER); 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 * and its corresponding internal EGLDisplay. Otherwise, check for existing * associated EGLDisplay for the given Wayland display and if it doesn't * exist, create a new one */ if (!nativeDpy) { nativeDpy = wl_display_connect(NULL); if (!nativeDpy) { wlExternalApiUnlock(); return EGL_NO_DISPLAY; } ownNativeDpy = EGL_TRUE; wl_display_dispatch_pending(nativeDpy); } else { wl_list_for_each(display, &wlEglDisplayList, link) { if (display->nativeDpy == nativeDpy && display->devDpy->eglDisplay == eglDisplay) { wlExternalApiUnlock(); return (EGLDisplay)display; } } } display = calloc(1, sizeof(*display)); if (!display) { wlExternalApiUnlock(); err = EGL_BAD_ALLOC; goto fail; } display->data = pData; display->ownNativeDpy = ownNativeDpy; display->nativeDpy = nativeDpy; wl_list_init(&display->evtQueueList); wl_list_init(&display->dangEvtQueueList); queue = wlGetEventQueue(display); if (queue == NULL) { wlExternalApiUnlock(); err = EGL_BAD_ALLOC; 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->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, queue); } if (ret < 0 || !display->wlStreamDpy) { wlExternalApiUnlock(); err = EGL_BAD_ALLOC; goto fail; } /* Listen to wl_eglstream_display events and make another roundtrip so we * catch any bind-related event (e.g. server capabilities) */ ret = wl_eglstream_display_add_listener(display->wlStreamDpy, &eglstream_display_listener, display); if (ret == 0) { ret = wlEglRoundtrip(display, queue); } if (ret < 0) { wlExternalApiUnlock(); err = EGL_BAD_ALLOC; goto fail; } /* * Seek for the desired device in wlEglDeviceDpyList. If found, use it; * otherwise, create a new WlEglDeviceDpy and add it to wlEglDeviceDpyList */ wl_list_for_each(devDpy, &wlEglDeviceDpyList, link) { /* TODO: Add support for multiple devices/device selection */ if (devDpy->eglDisplay == eglDisplay) { display->devDpy = devDpy; display->devDpy->refCount++; break; } } if (!display->devDpy) { devDpy = calloc(1, sizeof(*devDpy)); if (!devDpy) { wlExternalApiUnlock(); err = EGL_BAD_ALLOC; goto fail; } devDpy->eglDevice = eglDevice; devDpy->eglDisplay = eglDisplay; } // Due to temporary unlock of wlMutex in wlEglRoundtrip, it is possible // that two or more threads enter wlEglGetPlatformDisplayExport simultaneously. // Before inserting display in wlEglDisplayList, we need to check whether // while we were unlocked, other thread already inserted the display which // has the same nativeDpy. If so, we need to free allocations and return // the already inserted display. wl_list_for_each(dpy, &wlEglDisplayList, link) { if (dpy->nativeDpy == display->nativeDpy) { // If display->devDpy is NULL, we just allocated devDpy, need to free it. if (!display->devDpy) { free(devDpy); } terminateDisplay(display, EGL_FALSE); wlExternalApiUnlock(); return (EGLDisplay)dpy; } } // If no device found in wlEglDeviceDpyList, insert the newly created // WlEglDeviceDpy into wlEglDeviceDpyList. if (!display->devDpy) { assert(devDpy); // Given that different wayland EGLDisplays may share the same devDpy, // it could happen that someone else creating a different display // already created the devDpy. We need to check it does not exist yet // before inserting, and if it does, free devDpy. wl_list_for_each(tmpDpy, &wlEglDeviceDpyList, link) { /* TODO: Add support for multiple devices/device selection */ display->devDpy = tmpDpy; free (devDpy); break; } if (!display->devDpy) { wl_list_insert(&wlEglDeviceDpyList, &devDpy->link); display->devDpy = devDpy; } display->devDpy->refCount++; } // The newly created WlEglDisplay has been set up properly, insert it // in wlEglDisplayList. wl_list_insert(&wlEglDisplayList, &display->link); wlExternalApiUnlock(); return display; fail: if (display) { wlEglTerminateHook(display); } else if (ownNativeDpy) { wl_display_disconnect(nativeDpy); } 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; EGLAttrib useRefCount = EGL_FALSE; dpy = display->devDpy->eglDisplay; res = data->egl.initialize(dpy, major, minor); if (res) { const char *exts = data->egl.queryString(dpy, EGL_EXTENSIONS); wlExternalApiLock(); #define CACHE_EXT(_PREFIX_, _NAME_) \ display->exts._NAME_ = \ !!wlEglFindExtension("EGL_" #_PREFIX_ "_" #_NAME_, exts) CACHE_EXT(KHR, stream); CACHE_EXT(NV, stream_attrib); CACHE_EXT(KHR, stream_cross_process_fd); CACHE_EXT(NV, stream_remote); CACHE_EXT(KHR, stream_producer_eglsurface); 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; } EGLBoolean wlEglIsWlEglDisplay(WlEglDisplay *display) { WlEglDisplay *dpy; wl_list_for_each(dpy, &wlEglDisplayList, link) { if (dpy == display) { return EGL_TRUE; } } return EGL_FALSE; } EGLBoolean wlEglChooseConfigHook(EGLDisplay dpy, EGLint const *attribs, EGLConfig *configs, EGLint configSize, EGLint *numConfig) { WlEglDisplay *display = (WlEglDisplay *)dpy; WlEglPlatformData *data = display->data; EGLint *attribs2 = NULL; EGLint nAttribs = 0; EGLint nTotalAttribs = 0; EGLBoolean surfType = EGL_FALSE; EGLint err = EGL_SUCCESS; EGLBoolean ret; /* Save the internal EGLDisplay handle, as it's needed by the actual * eglChooseConfig() call */ dpy = display->devDpy->eglDisplay; /* Calculate number of attributes in attribs */ if (attribs) { while (attribs[nAttribs] != EGL_NONE) { surfType = surfType || (attribs[nAttribs] == EGL_SURFACE_TYPE); nAttribs += 2; } } /* If not SURFACE_TYPE provided, we need convert the default WINDOW_BIT to a * default EGL_STREAM_BIT */ nTotalAttribs += (surfType ? nAttribs : (nAttribs + 2)); /* Make attributes list copy */ attribs2 = (EGLint *)malloc((nTotalAttribs + 1) * sizeof(*attribs2)); if (!attribs2) { err = EGL_BAD_ALLOC; goto done; } if (nAttribs > 0) { memcpy(attribs2, attribs, nAttribs * sizeof(*attribs2)); } attribs2[nTotalAttribs] = EGL_NONE; /* Replace all WINDOW_BITs by EGL_STREAM_BITs */ if (surfType) { nAttribs = 0; while (attribs2[nAttribs] != EGL_NONE) { if ((attribs2[nAttribs] == EGL_SURFACE_TYPE) && (attribs2[nAttribs + 1] != EGL_DONT_CARE) && (attribs2[nAttribs + 1] & EGL_WINDOW_BIT)) { attribs2[nAttribs + 1] &= ~EGL_WINDOW_BIT; attribs2[nAttribs + 1] |= EGL_STREAM_BIT_KHR; } nAttribs += 2; } } else { attribs2[nTotalAttribs - 2] = EGL_SURFACE_TYPE; attribs2[nTotalAttribs - 1] = EGL_STREAM_BIT_KHR; } /* Actual eglChooseConfig() call */ ret = data->egl.chooseConfig(dpy, attribs2, configs, configSize, numConfig); done: /* Cleanup */ free(attribs2); if (err != EGL_SUCCESS) { wlEglSetError(data, err); return EGL_FALSE; } return ret; } EGLBoolean wlEglGetConfigAttribHook(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { WlEglDisplay *display = (WlEglDisplay *)dpy; WlEglPlatformData *data = display->data; EGLBoolean ret = EGL_FALSE; /* Save the internal EGLDisplay handle, as it's needed by the actual * eglGetConfigAttrib() call */ dpy = display->devDpy->eglDisplay; ret = data->egl.getConfigAttrib(dpy, config, attribute, value); if (ret && (attribute == EGL_SURFACE_TYPE)) { /* We only support window configurations through EGLStreams */ if (*value & EGL_STREAM_BIT_KHR) { *value |= EGL_WINDOW_BIT; } else { *value &= ~EGL_WINDOW_BIT; } } return ret; } EGLBoolean wlEglDestroyAllDisplays(WlEglPlatformData *data) { WlEglDisplay *display, *next; EGLBoolean res = EGL_TRUE; wlExternalApiLock(); wl_list_for_each_safe(display, next, &wlEglDisplayList, link) { if (display->data == data) { res = terminateDisplay((EGLDisplay)display, EGL_TRUE) && res; } } wlExternalApiUnlock(); return res; } const char* wlEglQueryStringExport(void *data, EGLDisplay dpy, EGLExtPlatformString name) { WlEglPlatformData *pData = (WlEglPlatformData *)data; EGLBoolean isEGL15 = (pData->egl.major > 1) || ((pData->egl.major == 1) && (pData->egl.minor >= 5)); const char *res = NULL; switch (name) { case EGL_EXT_PLATFORM_PLATFORM_CLIENT_EXTENSIONS: res = isEGL15 ? "EGL_KHR_platform_wayland EGL_EXT_platform_wayland" : "EGL_EXT_platform_wayland"; break; case EGL_EXT_PLATFORM_DISPLAY_EXTENSIONS: if (dpy == EGL_NO_DISPLAY) { /* This should return all client extensions, which for now is * equivalent to EXTERNAL_PLATFORM_CLIENT_EXTENSIONS */ res = isEGL15 ? "EGL_KHR_platform_wayland EGL_EXT_platform_wayland" : "EGL_EXT_platform_wayland"; } else { /* * Check whether the given display supports EGLStream * extensions. For Wayland support over EGLStreams, at least the * following extensions must be supported by the underlying * driver: * * - EGL_KHR_stream * - EGL_KHR_stream_producer_eglsurface * - EGL_KHR_stream_cross_process_fd */ const char *exts = pData->egl.queryString(dpy, EGL_EXTENSIONS); if (wlEglFindExtension("EGL_KHR_stream", exts) && wlEglFindExtension("EGL_KHR_stream_producer_eglsurface", exts) && wlEglFindExtension("EGL_KHR_stream_cross_process_fd", exts)) { res = "EGL_WL_bind_wayland_display " "EGL_WL_wayland_eglstream"; } } break; default: break; } return res; } egl-wayland-1.1.3/src/wayland-eglhandle.c000066400000000000000000000136661347064175300202610ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #include "wayland-eglhandle.h" #include "wayland-egldisplay.h" #include "wayland-eglsurface.h" #include "wayland-thread.h" #include #include #include WlEglPlatformData* wlEglCreatePlatformData(int apiMajor, int apiMinor, const EGLExtDriver *driver) { const char *exts = NULL; WlEglPlatformData *res = NULL; assert((driver != NULL) && (driver->getProcAddress != NULL)); /* Allocate platform data and fetch EGL functions */ res = calloc(1, sizeof(WlEglPlatformData)); if (res == NULL) { return NULL; } /* Cache the EGL driver version */ #if EGL_EXTERNAL_PLATFORM_HAS(DRIVER_VERSION) if (EGL_EXTERNAL_PLATFORM_SUPPORTS(apiMajor, apiMinor, DRIVER_VERSION)) { res->egl.major = driver->major; res->egl.minor = driver->minor; } #endif /* Fetch all required driver functions */ #define GET_PROC(_FIELD_, _NAME_) \ do { \ res->egl._FIELD_ = driver->getProcAddress(#_NAME_); \ if (res->egl._FIELD_ == NULL) { \ goto fail; \ } \ } while (0) /* Core and basic stream functionality */ 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); GET_PROC(chooseConfig, eglChooseConfig); GET_PROC(getConfigAttrib, eglGetConfigAttrib); GET_PROC(getCurrentContext, eglGetCurrentContext); GET_PROC(getCurrentSurface, eglGetCurrentSurface); GET_PROC(makeCurrent, eglMakeCurrent); GET_PROC(createStream, eglCreateStreamKHR); GET_PROC(createStreamFromFD, eglCreateStreamFromFileDescriptorKHR); GET_PROC(createStreamAttrib, eglCreateStreamAttribNV); GET_PROC(getStreamFileDescriptor, eglGetStreamFileDescriptorKHR); GET_PROC(createStreamProducerSurface, eglCreateStreamProducerSurfaceKHR); GET_PROC(createPbufferSurface, eglCreatePbufferSurface); GET_PROC(destroyStream, eglDestroyStreamKHR); GET_PROC(destroySurface, eglDestroySurface); GET_PROC(swapBuffers, eglSwapBuffers); GET_PROC(swapBuffersWithDamage, eglSwapBuffersWithDamageKHR); GET_PROC(swapInterval, eglSwapInterval); GET_PROC(getError, eglGetError); GET_PROC(releaseThread, eglReleaseThread); #undef GET_PROC /* Fetch all optional driver functions */ #define GET_PROC(_FIELD_, _NAME_) \ res->egl._FIELD_ = driver->getProcAddress(#_NAME_) /* Used by damage thread */ GET_PROC(queryStream, eglQueryStreamKHR); GET_PROC(queryStreamu64, eglQueryStreamu64KHR); GET_PROC(createStreamSync, eglCreateStreamSyncNV); GET_PROC(clientWaitSync, eglClientWaitSyncKHR); GET_PROC(signalSync, eglSignalSyncKHR); GET_PROC(destroySync, eglDestroySyncKHR); /* Stream flush */ GET_PROC(streamFlush, eglStreamFlushNV); GET_PROC(queryDisplayAttrib, eglQueryDisplayAttribKHR); #undef GET_PROC /* Check for required EGL client extensions */ exts = res->egl.queryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); if (!wlEglFindExtension("EGL_EXT_platform_base", exts) || !wlEglFindExtension("EGL_EXT_platform_device", exts)) { goto fail; } /* Cache driver imports */ res->callbacks.setError = driver->setError; res->callbacks.streamSwapInterval = driver->streamSwapInterval; return res; fail: free(res); return NULL; } void wlEglDestroyPlatformData(WlEglPlatformData *data) { free(data); } void* wlEglGetInternalHandleExport(EGLDisplay dpy, EGLenum type, void *handle) { wlExternalApiLock(); if ((type == EGL_OBJECT_DISPLAY_KHR) && wlEglIsWlEglDisplay((WlEglDisplay *)handle)) { handle = (void *)(((WlEglDisplay *)handle)->devDpy->eglDisplay); } else if ((type == EGL_OBJECT_SURFACE_KHR) && wlEglIsWlEglSurface((WlEglSurface *)handle)) { WlEglSurface *surface = (WlEglSurface *)handle; if (dpy == surface->wlEglDpy) { handle = (void *)(surface->ctx.eglSurface); } else { handle = NULL; } } wlExternalApiUnlock(); return handle; } egl-wayland-1.1.3/src/wayland-eglstream-server.c000066400000000000000000000310651347064175300216160ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-eglstream-server.h" #include "wayland-eglstream-server-protocol.h" #include "wayland-eglstream.h" #include "wayland-eglswap.h" #include "wayland-eglutils.h" #define MASK(_VAL_) (1 << (_VAL_)) static struct wl_list wlStreamDpyList = WL_LIST_INIT(&wlStreamDpyList); static void destroy_wl_eglstream_resource(struct wl_resource *resource) { struct wl_eglstream *wlStream = wl_resource_get_user_data(resource); if (wlStream->handle >= 0) { close(wlStream->handle); } free(wlStream); } static void destroy_wl_eglstream(struct wl_client *client, struct wl_resource *resource) { (void) client; wl_resource_destroy(resource); } static void handle_create_stream(struct wl_client *client, struct wl_resource *resource, uint32_t id, int32_t width, int32_t height, int handle, int handle_type, struct wl_array *attribs) { struct wl_eglstream_display *wlStreamDpy = wl_resource_get_user_data(resource); struct wl_eglstream *wlStream; struct sockaddr_in sockAddr; char sockAddrStr[NI_MAXHOST]; intptr_t *attr; int mask = 0; enum wl_eglstream_error err; wlStream = calloc(1, sizeof *wlStream); if (wlStream == NULL) { err = WL_EGLSTREAM_ERROR_BAD_ALLOC; goto error_create_stream; } wlStream->wlStreamDpy = wlStreamDpy; wlStream->eglStream = EGL_NO_STREAM_KHR; wlStream->width = width; wlStream->height = height; wlStream->handle = -1; memset(&sockAddr, 0, sizeof(sockAddr)); switch (handle_type) { case WL_EGLSTREAM_HANDLE_TYPE_FD: wlStream->handle = handle; wlStream->fromFd = EGL_TRUE; break; case WL_EGLSTREAM_HANDLE_TYPE_INET: sockAddr.sin_family = AF_INET; wlStream->isInet = EGL_TRUE; /* Close the given dummy fd */ close(handle); break; case WL_EGLSTREAM_HANDLE_TYPE_SOCKET: wlStream->handle = handle; break; default: err = WL_EGLSTREAM_ERROR_BAD_HANDLE; goto error_create_stream; } wl_array_for_each(attr, attribs) { switch (attr[0]) { case WL_EGLSTREAM_ATTRIB_INET_ADDR: /* INET_ADDR should only be set once */ if (mask & MASK(WL_EGLSTREAM_ATTRIB_INET_ADDR)) { err = WL_EGLSTREAM_ERROR_BAD_ATTRIBS; goto error_create_stream; } sockAddr.sin_addr.s_addr = htonl((int)attr[1]); mask |= MASK(WL_EGLSTREAM_ATTRIB_INET_ADDR); break; case WL_EGLSTREAM_ATTRIB_INET_PORT: /* INET_PORT should only be set once */ if (mask & MASK(WL_EGLSTREAM_ATTRIB_INET_PORT)) { err = WL_EGLSTREAM_ERROR_BAD_ATTRIBS; goto error_create_stream; } sockAddr.sin_port = htons((int)attr[1]); mask |= MASK(WL_EGLSTREAM_ATTRIB_INET_PORT); break; default: assert(!"Unknown attribute"); break; } /* Attribs processed in pairs */ attr++; } if (wlStream->isInet) { /* Both address and port should have been set */ if (mask != (MASK(WL_EGLSTREAM_ATTRIB_INET_ADDR) | MASK(WL_EGLSTREAM_ATTRIB_INET_PORT))) { err = WL_EGLSTREAM_ERROR_BAD_ATTRIBS; goto error_create_stream; } wlStream->handle = socket(AF_INET, SOCK_STREAM, 0); if (wlStream->handle == -1) { err = WL_EGLSTREAM_ERROR_BAD_ALLOC; goto error_create_stream; } if (connect(wlStream->handle, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) < 0) { err = WL_EGLSTREAM_ERROR_BAD_ADDRESS; goto error_create_stream; } } wlStream->resource = wl_resource_create(client, &wl_buffer_interface, 1, id); if (!wlStream->resource) { err = WL_EGLSTREAM_ERROR_BAD_ALLOC; goto error_create_stream; } wl_resource_set_implementation( wlStream->resource, (void (**)(void))&wlStreamDpy->wl_eglstream_interface, wlStream, destroy_wl_eglstream_resource); return; error_create_stream: switch (err) { case WL_EGLSTREAM_ERROR_BAD_ALLOC: wl_resource_post_no_memory(resource); break; case WL_EGLSTREAM_ERROR_BAD_HANDLE: wl_resource_post_error(resource, err, "Invalid or unknown handle"); break; case WL_EGLSTREAM_ERROR_BAD_ATTRIBS: wl_resource_post_error(resource, err, "Malformed attributes list"); break; case WL_EGLSTREAM_ERROR_BAD_ADDRESS: wl_resource_post_error(resource, err, "Unable to connect to %s:%d.", (getnameinfo((struct sockaddr *)&sockAddr, sizeof(sockAddr), sockAddrStr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) ? "" : sockAddrStr), ntohs(sockAddr.sin_port)); break; default: assert(!"Unknown error code"); break; } if (wlStream) { if (wlStream->isInet && wlStream->handle >= 0) { close(wlStream->handle); } free(wlStream); } } static void handle_swap_interval(struct wl_client *client, struct wl_resource *displayResource, struct wl_resource *streamResource, int interval) { struct wl_eglstream_display *wlStreamDpy = wl_resource_get_user_data(displayResource); struct wl_eglstream *wlStream = wl_eglstream_display_get_stream(wlStreamDpy, streamResource); (void) client; if (wlEglStreamSwapIntervalCallback(wlStreamDpy->data, wlStream->eglStream, &interval) == EGL_BAD_MATCH) { wl_eglstream_display_send_swapinterval_override(displayResource, interval, streamResource); } } static const struct wl_eglstream_display_interface wl_eglstream_display_interface_impl = { handle_create_stream, handle_swap_interval, }; static void wl_eglstream_display_global_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wl_eglstream_display *wlStreamDpy = NULL; struct wl_resource *resource = NULL; wlStreamDpy = (struct wl_eglstream_display *)data; resource = wl_resource_create(client, &wl_eglstream_display_interface, version, id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &wl_eglstream_display_interface_impl, data, NULL); wl_eglstream_display_send_caps(resource, wlStreamDpy->supported_caps); } EGLBoolean wl_eglstream_display_bind(WlEglPlatformData *data, struct wl_display *wlDisplay, EGLDisplay eglDisplay) { 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 */ if (wl_eglstream_display_get(eglDisplay) != NULL) { return EGL_FALSE; } wlStreamDpy = malloc(sizeof(*wlStreamDpy)); if (!wlStreamDpy) { return EGL_FALSE; } wlStreamDpy->data = data; wlStreamDpy->wlDisplay = wlDisplay; wlStreamDpy->eglDisplay = eglDisplay; wlStreamDpy->caps_override = 0; exts = data->egl.queryString(eglDisplay, EGL_EXTENSIONS); #define CACHE_EXT(_PREFIX_, _NAME_) \ wlStreamDpy->exts._NAME_ = \ !!wlEglFindExtension("EGL_" #_PREFIX_ "_" #_NAME_, exts) CACHE_EXT(NV, stream_attrib); CACHE_EXT(KHR, stream_cross_process_fd); CACHE_EXT(NV, stream_remote); CACHE_EXT(NV, stream_socket); CACHE_EXT(NV, stream_socket_inet); CACHE_EXT(NV, stream_socket_unix); CACHE_EXT(NV, stream_origin); #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, wlStreamDpy, wl_eglstream_display_global_bind); wl_list_insert(&wlStreamDpyList, &wlStreamDpy->link); return EGL_TRUE; } void wl_eglstream_display_unbind(struct wl_eglstream_display *wlStreamDpy) { wl_global_destroy(wlStreamDpy->global); wl_list_remove(&wlStreamDpy->link); free(wlStreamDpy); } struct wl_eglstream_display* wl_eglstream_display_get(EGLDisplay eglDisplay) { struct wl_eglstream_display *wlDisplay; wl_list_for_each(wlDisplay, &wlStreamDpyList, link) { if (wlDisplay->eglDisplay == eglDisplay) { return wlDisplay; } } return NULL; } struct wl_eglstream* wl_eglstream_display_get_stream(struct wl_eglstream_display *wlStreamDpy, struct wl_resource *resource) { if (resource == NULL) { return NULL; } if (wl_resource_instance_of(resource, &wl_buffer_interface, &wlStreamDpy->wl_eglstream_interface)) { return wl_resource_get_user_data(resource); } else { return NULL; } } egl-wayland-1.1.3/src/wayland-eglstream.c000066400000000000000000000210421347064175300203040ustar00rootroot00000000000000/* * 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. */ #include "wayland-eglstream.h" #include "wayland-eglstream-server.h" #include "wayland-thread.h" #include "wayland-eglhandle.h" #include "wayland-egldisplay.h" #include "wayland-eglutils.h" #include "wayland-egl-ext.h" #include #include #include #define WL_EGL_CONN_WAIT_USECS 1e3 /* 1 msec */ #define WL_EGL_CONN_TIMEOUT_USECS 1e6 /* 1 sec */ EGLStreamKHR wlEglCreateStreamAttribHook(EGLDisplay dpy, const EGLAttrib *attribs) { WlEglPlatformData *data = NULL; EGLStreamKHR stream = EGL_NO_STREAM_KHR; struct wl_eglstream_display *wlStreamDpy = NULL; struct wl_resource *resource = NULL; struct wl_eglstream *wlStream = NULL; int nAttribs = 0; int idx = 0; int fd = -1; EGLint err = EGL_SUCCESS; /* Parse attribute list and count internal attributes */ if (attribs) { while (attribs[idx] != EGL_NONE) { if (attribs[idx] == EGL_WAYLAND_EGLSTREAM_WL) { if (resource != NULL) { err = EGL_BAD_MATCH; break; } resource = (struct wl_resource *)attribs[idx + 1]; if (resource == NULL) { err = EGL_BAD_ACCESS; break; } } else { /* Internal attribute */ nAttribs++; } idx += 2; } } if ((err == EGL_SUCCESS) && (resource == NULL)) { /* No EGL_WAYLAND_EGLSTREAM_WL attribute provided, which means dpy is * external. Forward this call to the underlying driver as there's * nothing to do here */ WlEglDisplay *display = (WlEglDisplay *)dpy; return display->data->egl.createStreamAttrib(display->devDpy->eglDisplay, attribs); } /* Otherwise, we must create a server-side stream */ wlExternalApiLock(); wlStreamDpy = wl_eglstream_display_get(dpy); if (wlStreamDpy == NULL) { err = EGL_BAD_ACCESS; } else { data = wlStreamDpy->data; } if (err != EGL_SUCCESS) { goto fail; } wlStream = wl_eglstream_display_get_stream(wlStreamDpy, resource); if (wlStream == NULL) { err = EGL_BAD_ACCESS; goto fail; } if (wlStream->eglStream != EGL_NO_STREAM_KHR || wlStream->handle == -1) { err = EGL_BAD_STREAM_KHR; goto fail; } if (wlStream->fromFd) { /* Check for EGL_KHR_stream_cross_process_fd support */ if (!wlStreamDpy->exts.stream_cross_process_fd) { err = EGL_BAD_ACCESS; goto fail; } /* 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. 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; } fd = wlStream->handle; stream = data->egl.createStreamFromFD(dpy, wlStream->handle); /* Clean up */ close(fd); } #if defined(EGL_NV_stream_attrib) && \ defined(EGL_NV_stream_remote) && \ defined(EGL_NV_stream_socket) else { EGLAttrib *attribs2 = NULL; /* Check for required extensions support */ if (!wlStreamDpy->exts.stream_attrib || !wlStreamDpy->exts.stream_remote || !wlStreamDpy->exts.stream_socket || (!wlStreamDpy->exts.stream_socket_inet && !wlStreamDpy->exts.stream_socket_unix)) { err = EGL_BAD_ACCESS; goto fail; } /* If not inet connection supported, wlStream should not be inet */ if (!wlStreamDpy->exts.stream_socket_inet && wlStream->isInet) { err = EGL_BAD_ACCESS; goto fail; } /* Create attributes array to pass down to the actual EGL stream * creation function */ attribs2 = (EGLAttrib *)malloc((2*(nAttribs + 5) + 1)*sizeof(*attribs2)); nAttribs = 0; attribs2[nAttribs++] = EGL_STREAM_TYPE_NV; attribs2[nAttribs++] = EGL_STREAM_CROSS_PROCESS_NV; attribs2[nAttribs++] = EGL_STREAM_PROTOCOL_NV; attribs2[nAttribs++] = EGL_STREAM_PROTOCOL_SOCKET_NV; attribs2[nAttribs++] = EGL_STREAM_ENDPOINT_NV; attribs2[nAttribs++] = EGL_STREAM_CONSUMER_NV; attribs2[nAttribs++] = EGL_SOCKET_TYPE_NV; attribs2[nAttribs++] = (wlStream->isInet ? EGL_SOCKET_TYPE_INET_NV : EGL_SOCKET_TYPE_UNIX_NV); attribs2[nAttribs++] = EGL_SOCKET_HANDLE_NV; attribs2[nAttribs++] = (EGLAttrib)wlStream->handle; /* Include internal attributes given by the application */ while (attribs && attribs[0] != EGL_NONE) { switch (attribs[0]) { /* Filter out external attributes */ case EGL_WAYLAND_EGLSTREAM_WL: break; /* EGL_NV_stream_remote attributes shouldn't be set by the * application */ case EGL_STREAM_TYPE_NV: case EGL_STREAM_PROTOCOL_NV: case EGL_STREAM_ENDPOINT_NV: case EGL_SOCKET_TYPE_NV: case EGL_SOCKET_HANDLE_NV: free(attribs2); err = EGL_BAD_ATTRIBUTE; goto fail; /* Everything else is fine and will be handled by EGL */ default: attribs2[nAttribs++] = attribs[0]; attribs2[nAttribs++] = attribs[1]; } attribs += 2; } attribs2[nAttribs] = EGL_NONE; stream = data->egl.createStreamAttrib(dpy, attribs2); /* Clean up */ free(attribs2); if (stream != EGL_NO_STREAM_KHR) { /* Wait for the stream to establish connection with the producer's * side */ uint32_t timeout = WL_EGL_CONN_TIMEOUT_USECS; EGLint state = EGL_STREAM_STATE_INITIALIZING_NV; do { usleep(WL_EGL_CONN_WAIT_USECS); timeout -= WL_EGL_CONN_WAIT_USECS; if (!data->egl.queryStream(dpy, stream, EGL_STREAM_STATE_KHR, &state)) { break; } } while ((state == EGL_STREAM_STATE_INITIALIZING_NV) && (timeout > 0)); if (state == EGL_STREAM_STATE_INITIALIZING_NV) { data->egl.destroyStream(dpy, stream); stream = EGL_NO_STREAM_KHR; } } } #endif if (stream == EGL_NO_STREAM_KHR) { err = EGL_BAD_ACCESS; goto fail; } wlStream->eglStream = stream; wlStream->handle = -1; wlExternalApiUnlock(); return stream; fail: wlExternalApiUnlock(); wlEglSetError(data, err); return EGL_NO_STREAM_KHR; } egl-wayland-1.1.3/src/wayland-eglsurface.c000066400000000000000000001452511347064175300204520ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #include "wayland-eglsurface.h" #include "wayland-eglstream-client-protocol.h" #include "wayland-eglstream-controller-client-protocol.h" #include "wayland-eglstream-server.h" #include "wayland-thread.h" #include "wayland-eglutils.h" #include "wayland-egl-ext.h" #include #include #include #include #include #include #include #include #include #include #define WL_EGL_WINDOW_DESTROY_CALLBACK_SINCE 3 struct wl_list wlEglSurfaceList = WL_LIST_INIT(&wlEglSurfaceList); EGLBoolean wlEglIsWlEglSurface(WlEglSurface *surface) { WlEglSurface *surf; wl_list_for_each(surf, &wlEglSurfaceList, link) { if (surf == surface) { return EGL_TRUE; } } return EGL_FALSE; } EGLBoolean wlEglIsWaylandWindowValid(struct wl_egl_window *window) { struct wl_surface *surface = NULL; #if HAS_MINCORE if (!window || !wlEglPointerIsDereferencable(window)) { return EGL_FALSE; } surface = (struct wl_surface *)window->version; if (!wlEglPointerIsDereferencable(surface)) { surface = window->surface; if (!wlEglPointerIsDereferencable(surface)) { return EGL_FALSE; } } return wlEglCheckInterfaceType((struct wl_object *)surface, "wl_surface_interface"); #else /* * Note that dereferencing an invalid surface pointer could mean an old * version of libwayland-egl.so is loaded, which may not support version * member in wl_egl_window struct. */ surface = window->surface; /* 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); #endif } static void wayland_throttleCallback(void *data, struct wl_callback *callback, uint32_t time) { WlEglSurface *surface = (WlEglSurface *)data; WlEglDisplay *display = NULL; (void) time; wlExternalApiLock(); /* the surface could be destroyed while the lock was suspended in * wlEglWaitFrameSync */ if (wlEglIsWlEglSurface(surface) && (surface->throttleCallback != NULL)) { display = surface->wlEglDpy; wlUpdateQueueBusyStatus(display, surface->throttleCbQueue, EGL_FALSE); surface->throttleCbQueue = NULL; wl_callback_destroy(callback); surface->throttleCallback = NULL; } wlExternalApiUnlock(); } static const struct wl_callback_listener throttle_listener = { wayland_throttleCallback }; void wlEglCreateFrameSync(WlEglSurface *surface, struct wl_event_queue *queue) { struct wl_surface *wrapper = NULL; if (surface->swapInterval > 0) { /* it is assumed that the refCount is decremented for * throttleCbQueue and it is set as NULL in the previous * throttleCallback, if not then raise the assertion */ assert(surface->throttleCbQueue == NULL); 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; } /* After a window resize, the compositor has to be * updated with the new buffer's geometry. However, we * won't have updated geometry information until the * underlying buffer is attached. A surface attach * may be deferred to a later time in some situations * (e.g. FIFO_SYNCHRONOUS + damage thread). * * Therefore, the surface_commit done from here would * use outdated geometry information if the buffer is * not attached, which would make xdg-shell fail with * error. To avoid this, skip the surface commit here * if the surface attach is not yet done. */ if (surface->ctx.isAttached) { wl_surface_commit(surface->wlSurface); } surface->throttleCbQueue = queue; wlUpdateQueueBusyStatus(surface->wlEglDpy, queue, EGL_TRUE); } } EGLint wlEglWaitFrameSync(WlEglSurface *surface, struct wl_event_queue *queue) { WlEglDisplay *display = surface->wlEglDpy; int ret = 0; while (ret != -1 && surface->throttleCallback != NULL) { wlExternalApiUnlock(); ret = wl_display_dispatch_queue(display->nativeDpy, queue); wlExternalApiLock(); /* Bail out if the surface was destroyed while the lock was suspended */ if (!wlEglIsWlEglSurface(surface)) { return EGL_BAD_SURFACE; } } if (surface->throttleCallback != NULL) { wl_callback_destroy(surface->throttleCallback); surface->throttleCallback = NULL; return EGL_BAD_ALLOC; } return EGL_SUCCESS; } EGLBoolean wlEglSendDamageEvent(WlEglSurface *surface, struct wl_event_queue *queue) { /* Attach same buffer to indicate new content for the surface is * made available by the client */ wl_surface_attach(surface->wlSurface, surface->ctx.wlStreamResource, surface->dx, surface->dy); wl_surface_damage(surface->wlSurface, 0, 0, surface->width, surface->height); wl_surface_commit(surface->wlSurface); surface->ctx.isAttached = EGL_TRUE; 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; struct wl_event_queue *queue = wlGetEventQueue(display); int ok = (queue != NULL); EGLint state; while (ok) { // Unsignal sync and check latest frame and stream state // Done if any functions fail or stream has disconnected. ok = data->egl.signalSync(display->devDpy->eglDisplay, surface->ctx.damageThreadSync, EGL_UNSIGNALED_KHR) && data->egl.queryStreamu64(display->devDpy->eglDisplay, surface->ctx.eglStream, EGL_PRODUCER_FRAME_KHR, &surface->ctx.framesFinished) && data->egl.queryStream(display->devDpy->eglDisplay, surface->ctx.eglStream, EGL_STREAM_STATE_KHR, &state) && (state != EGL_STREAM_STATE_DISCONNECTED_KHR); // If flush has been requested, trigger shutdown once // last produced frame has been processed. if (surface->ctx.damageThreadFlush) { if (surface->ctx.framesProcessed == surface->ctx.framesProduced) { surface->ctx.damageThreadShutdown = 1; } } // If shutdown has been requested, we're done if (surface->ctx.damageThreadShutdown) { 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) || (surface->isSurfaceProducer && !wlEglIsWaylandWindowValid(surface->wlEglWin))) { ok = 0; } // If not done, keep handling frames if (ok) { // If there's an unprocessed frame ready, send damage event if (surface->ctx.framesFinished != surface->ctx.framesProcessed) { if (display->exts.stream_flush) { data->egl.streamFlush(display->devDpy->eglDisplay, surface->ctx.eglStream); } /* wlEglSendDamageEvent() expects the API lock to be held */ wlExternalApiLock(); ok = wlEglSendDamageEvent(surface, queue); wlExternalApiUnlock(); surface->ctx.framesProcessed++; } // Otherwise, wait for sync to trigger else { ok = (EGL_CONDITION_SATISFIED_KHR == data->egl.clientWaitSync(display->devDpy->eglDisplay, surface->ctx.damageThreadSync, 0, EGL_FOREVER_KHR)); } } } data->egl.releaseThread(); return NULL; } static EGLint setup_wl_eglstream_damage_thread(WlEglSurface *surface) { WlEglDisplay *display = surface->wlEglDpy; WlEglPlatformData *data = display->data; int ret; surface->ctx.damageThreadFlush = 0; surface->ctx.damageThreadShutdown = 0; surface->ctx.framesProduced = 0; surface->ctx.framesFinished = 0; surface->ctx.framesProcessed = 0; surface->ctx.damageThreadSync = data->egl.createStreamSync(display->devDpy->eglDisplay, surface->ctx.eglStream, EGL_SYNC_NEW_FRAME_NV, NULL); if (surface->ctx.damageThreadSync == EGL_NO_SYNC_KHR) { return data->egl.getError(); } ret = pthread_create(&surface->ctx.damageThreadId, NULL, damage_thread, (void*)surface); if (ret != 0) { return EGL_BAD_ALLOC; } return EGL_SUCCESS; } static void finish_wl_eglstream_damage_thread(WlEglSurface *surface, WlEglSurfaceCtx *ctx, int immediate) { WlEglDisplay *display = surface->wlEglDpy; WlEglPlatformData *data = display->data; if (ctx->damageThreadSync != EGL_NO_SYNC_KHR) { if (immediate) { ctx->damageThreadShutdown = 1; } else { ctx->damageThreadFlush = 1; } data->egl.signalSync(display->devDpy->eglDisplay, ctx->damageThreadSync, EGL_SIGNALED_KHR); if (ctx->damageThreadId != (pthread_t)0) { wlExternalApiUnlock(); pthread_join(ctx->damageThreadId, NULL); wlExternalApiLock(); ctx->damageThreadId = (pthread_t)0; } data->egl.destroySync(display->devDpy->eglDisplay, ctx->damageThreadSync); ctx->damageThreadSync = EGL_NO_SYNC_KHR; } } static void destroy_surface_context(WlEglSurface *surface, WlEglSurfaceCtx *ctx) { WlEglDisplay *display = surface->wlEglDpy; WlEglPlatformData *data = display->data; EGLDisplay dpy = display->devDpy->eglDisplay; EGLSurface surf = ctx->eglSurface; EGLStreamKHR stream = ctx->eglStream; void *resource = ctx->wlStreamResource; ctx->eglSurface = EGL_NO_SURFACE; ctx->eglStream = EGL_NO_STREAM_KHR; ctx->wlStreamResource = NULL; if (surf != EGL_NO_SURFACE) { wlExternalApiUnlock(); data->egl.destroySurface(dpy, surf); wlExternalApiLock(); } if (surface->ctx.isOffscreen) { return; } /* If we are destroying the current context, * we are likely tearing down, and the latest * framesync must be destroyed too */ if ((&surface->ctx == ctx) && (surface->throttleCallback != NULL)) { wlUpdateQueueBusyStatus(display, surface->throttleCbQueue, EGL_FALSE); surface->throttleCbQueue = NULL; wl_callback_destroy(surface->throttleCallback); surface->throttleCallback = NULL; } finish_wl_eglstream_damage_thread(surface, ctx, 1); if (stream != EGL_NO_STREAM_KHR) { data->egl.destroyStream(dpy, stream); ctx->eglStream = EGL_NO_STREAM_KHR; } if (resource) { if (ctx->wlStreamResCbQueue != NULL) { wlUpdateQueueBusyStatus(display, ctx->wlStreamResCbQueue, EGL_FALSE); ctx->wlStreamResCbQueue = NULL; } wl_buffer_destroy(resource); } } 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) { WlEglSurface *surface = (WlEglSurface*)data; WlEglSurfaceCtx *ctx; struct wl_event_queue *queue; /* Look for the surface context for the given buffer and destroy it */ wlExternalApiLock(); if (wlEglIsWlEglSurface(surface)) { if (surface->ctx.wlStreamResCbQueue != NULL) { queue = surface->ctx.wlStreamResCbQueue; wlUpdateQueueBusyStatus(surface->wlEglDpy, queue, EGL_FALSE); surface->ctx.wlStreamResCbQueue = NULL; } wl_list_for_each(ctx, &surface->oldCtxList, link) { if (ctx->wlStreamResource == buffer) { destroy_surface_context(surface, ctx); wl_list_remove(&ctx->link); free(ctx); break; } } } wlExternalApiUnlock(); } static struct wl_buffer_listener wl_buffer_listener = { wl_buffer_release }; 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; } surface->ctx.wlStreamResCbQueue = queue; wlUpdateQueueBusyStatus(display, queue, EGL_TRUE); return buffer; } static EGLint create_surface_stream_fd(WlEglSurface *surface, struct wl_event_queue *queue) { WlEglDisplay *display = surface->wlEglDpy; WlEglPlatformData *data = display->data; int handle = EGL_NO_FILE_DESCRIPTOR_KHR; struct wl_array wlAttribs; EGLint eglAttribs[] = { EGL_STREAM_FIFO_LENGTH_KHR, surface->fifoLength, EGL_NONE, EGL_NONE, EGL_NONE }; EGLint err = EGL_SUCCESS; /* We don't have any mechanism to check whether the compositor is going to * use this surface for composition or not when using cross_process_fd, so * just enable FIFO_SYNCHRONOUS if the extensions are supported */ if (display->exts.stream_fifo_synchronous && display->exts.stream_sync && surface->fifoLength > 0) { eglAttribs[2] = EGL_STREAM_FIFO_SYNCHRONOUS_NV; eglAttribs[3] = EGL_TRUE; } /* First, create the EGLStream */ surface->ctx.eglStream = data->egl.createStream(display->devDpy->eglDisplay, eglAttribs); if (surface->ctx.eglStream == EGL_NO_STREAM_KHR) { err = data->egl.getError(); goto fail; } handle = data->egl.getStreamFileDescriptor(display->devDpy->eglDisplay, surface->ctx.eglStream); if (handle == EGL_NO_FILE_DESCRIPTOR_KHR) { err = data->egl.getError(); goto fail; } /* Finally, create the wl_eglstream */ wl_array_init(&wlAttribs); /* Empty attributes list */ surface->ctx.wlStreamResource = create_wl_eglstream(surface, handle, WL_EGLSTREAM_HANDLE_TYPE_FD, &wlAttribs, queue); if (!surface->ctx.wlStreamResource) { err = EGL_BAD_ALLOC; goto fail; } /* Clean-up */ close(handle); return EGL_SUCCESS; fail: destroy_surface_context(surface, &surface->ctx); if (handle >= 0) { close(handle); } return err; } #ifdef EGL_NV_stream_remote static void* acceptOneConnection(void *args) { int *socket = (int *)args; int serverSocket = *socket; /* Accept only one connection and store the client socket that will be used * to create the EGLStream */ *socket = accept(serverSocket, NULL, NULL); close(serverSocket); return NULL; } static EGLint startInetHandshake(pthread_t *thread, int *clientSocket, int *port) { struct sockaddr_in addr; unsigned int addrLen; EGLint err = EGL_SUCCESS; int ret; /* Create a server socket that will listen to all IPs and pick a random * port. Then, only one connection will be accepted. We can use clientSocket * to temporary store the server socket */ *clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (*clientSocket == -1) { err = EGL_BAD_ALLOC; goto fail; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; /* Accept connections to all IPs */ addr.sin_port = htons(0); /* Get a random port */ if (bind(*clientSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { err = EGL_BAD_ALLOC; goto fail; } if (listen(*clientSocket, 1) < 0) { err = EGL_BAD_ALLOC; goto fail; } /* Return host byte ordered port for sending through wayland protocol. * Wayland will convert back to wire format before sending. */ addrLen = sizeof(addr); ret = getsockname(*clientSocket, (struct sockaddr *)&addr, &addrLen); if (ret != 0) { err = EGL_BAD_ALLOC; goto fail; } *port = ntohs(addr.sin_port); /* Start a new thread that will accept one connection only. It will store * the new client socket in . */ ret = pthread_create(thread, NULL, acceptOneConnection, clientSocket); if (ret != 0) { err = EGL_BAD_ALLOC; goto fail; } return EGL_SUCCESS; fail: if (*clientSocket >= 0) { close(*clientSocket); *clientSocket = -1; } return err; } static EGLint finishInetHandshake(pthread_t thread, int *socket) { int ret = pthread_join(thread, NULL); if (ret != 0 || *socket == -1) { return EGL_BAD_ALLOC; } return EGL_SUCCESS; } static EGLint create_surface_stream_remote(WlEglSurface *surface, EGLBoolean useInet, struct wl_event_queue *queue) { WlEglDisplay *display = surface->wlEglDpy; WlEglPlatformData *data = display->data; struct wl_array wlAttribs; intptr_t *wlAttribsData; EGLint eglAttribs[] = { EGL_STREAM_TYPE_NV, EGL_STREAM_CROSS_PROCESS_NV, EGL_STREAM_ENDPOINT_NV, EGL_STREAM_PRODUCER_NV, EGL_STREAM_PROTOCOL_NV, EGL_STREAM_PROTOCOL_SOCKET_NV, EGL_SOCKET_TYPE_NV, EGL_DONT_CARE, EGL_SOCKET_HANDLE_NV, -1, EGL_NONE, EGL_NONE, EGL_NONE, }; pthread_t thread; int socket[2]; int port; EGLint err = EGL_SUCCESS; int ret; wl_array_init(&wlAttribs); /* Empty attributes list */ if (useInet) { /* Start inet handshaking and get the socket and selected port */ err = startInetHandshake(&thread, &socket[0], &port); if (err != EGL_SUCCESS) { goto fail; } /* Fill the wlAttribs array with the connection data. */ if (!wl_array_add(&wlAttribs, 4*sizeof(intptr_t))) { err = EGL_BAD_ALLOC; goto fail; } /* Get host byte ordered address for sending through wayland protocol. * Wayland will convert back to wire format before sending. Assume a * local INET connection until cross partition wayland support is added. */ wlAttribsData = (intptr_t *)wlAttribs.data; wlAttribsData[0] = WL_EGLSTREAM_ATTRIB_INET_ADDR; wlAttribsData[1] = (intptr_t)INADDR_LOOPBACK; wlAttribsData[2] = WL_EGLSTREAM_ATTRIB_INET_PORT; wlAttribsData[3] = (intptr_t)port; if (wlAttribsData[1] == -1) { err = EGL_BAD_ALLOC; goto fail; } /* Create a dummy fd to be feed into wayland. The fd will never be used, * but wayland will abort if an invaild fd is given. */ socket[1] = open("/dev/null", O_RDONLY); if (socket[1] == -1) { err = EGL_BAD_ALLOC; goto fail; } } else { /* Create a new socket pair for both EGLStream endpoints */ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, socket); if (ret != 0) { err = EGL_BAD_ALLOC; goto fail; } } surface->ctx.wlStreamResource = 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; } /* 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; } if (useInet) { /* Wait for the inet handshake to finish */ err = finishInetHandshake(thread, &socket[0]); if (err != EGL_SUCCESS) { goto fail; } } /* Finally, create the EGLStream * * EGL_SOCKET_TYPE_NV is in eglAttribs[6] * EGL_SOCKET_HANDLE_NV is in eglAttribs[8] */ eglAttribs[7] = (useInet ? EGL_SOCKET_TYPE_INET_NV : EGL_SOCKET_TYPE_UNIX_NV); eglAttribs[9] = socket[0]; if (!surface->isSurfaceProducer && display->wlStreamCtlVer >= WL_EGLSTREAM_CONTROLLER_ATTACH_EGLSTREAM_CONSUMER_ATTRIB_SINCE) { eglAttribs[10] = EGL_STREAM_FIFO_LENGTH_KHR; eglAttribs[11] = surface->fifoLength; } surface->ctx.eglStream = data->egl.createStream(display->devDpy->eglDisplay, eglAttribs); if (surface->ctx.eglStream == EGL_NO_STREAM_KHR) { err = data->egl.getError(); goto fail; } /* Close server socket on the client side */ if (socket[1] >= 0) { close(socket[1]); } return EGL_SUCCESS; fail: destroy_surface_context(surface, &surface->ctx); wl_array_release(&wlAttribs); if (socket[0] >= 0) { close(socket[0]); } if (!useInet && socket[1] >= 0) { close(socket[1]); } return err; } #endif static EGLint create_surface_stream(WlEglSurface *surface, struct wl_event_queue *queue) { WlEglDisplay *display = surface->wlEglDpy; EGLint err = EGL_BAD_ACCESS; /* Try all supported EGLStream creation methods until one of them succeeds. * More efficient connection schemes should be given a higher priority. If * there is more than one method giving the same efficiency, the more * versatile/configurable one would be preferred: * * 1. Cross-process unix sockets * 2. Cross-process FD * 3. Cross-process inet sockets */ #ifdef EGL_NV_stream_remote if ((err != EGL_SUCCESS) && display->caps.stream_socket && display->exts.stream_remote) { 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, 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, queue); } #endif return err; } static EGLint create_surface_context(WlEglSurface *surface) { 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; struct wl_array wlAttribs; intptr_t *wlAttribsData; assert(surface->ctx.eglSurface == EGL_NO_SURFACE); /* it is assumed that the wlStreamResCbQueue is NULL and * will be set once per surf.ctx and per wlStreamResource * if it is already set raise an assertion */ assert(surface->ctx.wlStreamResCbQueue == NULL); queue = wlGetEventQueue(display); if (!queue) { err = EGL_BAD_ALLOC; goto fail; } /* Width and height are the first and second attributes respectively */ 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); if (err != EGL_SUCCESS) { goto fail; } /* Then attach the wl_eglstream so the compositor connects a consumer to the * EGLStream */ if (display->wlStreamCtl != NULL) { if (display->wlStreamCtlVer >= WL_EGLSTREAM_CONTROLLER_ATTACH_EGLSTREAM_CONSUMER_ATTRIB_SINCE) { wl_array_init(&wlAttribs); if (!wl_array_add(&wlAttribs, 2 * sizeof(intptr_t))) { wl_array_release(&wlAttribs); err = EGL_BAD_ALLOC; goto fail; } wlAttribsData = (intptr_t *)wlAttribs.data; wlAttribsData[0] = WL_EGLSTREAM_CONTROLLER_ATTRIB_PRESENT_MODE; if (surface->isSurfaceProducer) { wlAttribsData[1] = WL_EGLSTREAM_CONTROLLER_PRESENT_MODE_DONT_CARE; } else if (surface->fifoLength > 0) { if (!wl_array_add(&wlAttribs, 2 * sizeof(intptr_t))) { wl_array_release(&wlAttribs); err = EGL_BAD_ALLOC; goto fail; } wlAttribsData = (intptr_t *)wlAttribs.data; wlAttribsData[1] = WL_EGLSTREAM_CONTROLLER_PRESENT_MODE_FIFO; wlAttribsData[2] = WL_EGLSTREAM_CONTROLLER_ATTRIB_FIFO_LENGTH; wlAttribsData[3] = surface->fifoLength; } else { wlAttribsData[1] = WL_EGLSTREAM_CONTROLLER_PRESENT_MODE_MAILBOX; } wl_eglstream_controller_attach_eglstream_consumer_attribs(display->wlStreamCtl, surface->wlSurface, surface->ctx.wlStreamResource, &wlAttribs); } else { wl_eglstream_controller_attach_eglstream_consumer(display->wlStreamCtl, surface->wlSurface, surface->ctx.wlStreamResource); } } else { wl_surface_attach(surface->wlSurface, surface->ctx.wlStreamResource, window->dx, window->dy); wl_surface_commit(surface->wlSurface); /* Since we are using the legacy method of overloading wl_surface_attach * in order to create the server-side EGLStream here, the compositor * will actually take this as a new buffer. We mark it as 'attached' * because whenever a new wl_surface_attach request is issued, the * compositor will emit back a wl_buffer_release event, and we will * destroy the context then. */ surface->ctx.isAttached = EGL_TRUE; } if (wlEglRoundtrip(display, queue) < 0) { err = EGL_BAD_ALLOC; 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); } /* Check whether we should use a damage thread */ surface->ctx.useDamageThread = display->exts.stream_fifo_synchronous && display->exts.stream_sync && data->egl.queryStream(display->devDpy->eglDisplay, surface->ctx.eglStream, EGL_STREAM_FIFO_SYNCHRONOUS_NV, &synchronous) && (synchronous == EGL_TRUE); if (surface->ctx.useDamageThread) { err = setup_wl_eglstream_damage_thread(surface); if (err != EGL_SUCCESS) { goto fail; } } /* Cache current window size and displacement for future checks */ 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; fail: destroy_surface_context(surface, &surface->ctx); return err; } EGLBoolean wlEglInitializeSurfaceExport(WlEglSurface *surface) { WlEglDisplay *display = surface->wlEglDpy; wlExternalApiLock(); wl_list_init(&surface->oldCtxList); if (create_surface_context(surface) != EGL_SUCCESS) { wlExternalApiUnlock(); return EGL_FALSE; } wl_list_insert(&wlEglSurfaceList, &surface->link); wl_eglstream_display_swap_interval(display->wlStreamDpy, surface->ctx.wlStreamResource, surface->swapInterval); 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; EGLint err = EGL_SUCCESS; if (!window || !surface) { return; } display = surface->wlEglDpy; if (!wlEglIsWaylandDisplay(display->nativeDpy) || !wlEglIsWaylandWindowValid(surface->wlEglWin)) { return; } pData = display->data; wlExternalApiLock(); /* Resize stream only if window geometry has changed */ if ((surface->width != window->width) || (surface->height != window->height) || (surface->dx != window->dx) || (surface->dy != window->dy)) { // If a damage thread is in use, wait for it to finish processing all // pending frames finish_wl_eglstream_damage_thread(surface, &surface->ctx, 0); discard_surface_context(surface); surface->ctx.wlStreamResource = NULL; surface->ctx.wlStreamResCbQueue = NULL; surface->ctx.isAttached = EGL_FALSE; surface->ctx.eglSurface = EGL_NO_SURFACE; surface->ctx.eglStream = EGL_NO_STREAM_KHR; surface->ctx.damageThreadSync = EGL_NO_SYNC_KHR; surface->ctx.damageThreadId = (pthread_t)0; err = create_surface_context(surface); if (err == EGL_SUCCESS) { /* We are handing execution control over to EGL here, passing * external objects down. Thus, it will re-enter the external * platform in order to resolve such objects to their internal * representations. * * XXX: Note that we are using external objects here. If another * thread destroys them while we are still making the surface * current, they will become invalid. This should be resolved * once we refactor our EGL API wrappers, removing the need * for resolving external objects into their internal * representations. */ wlExternalApiUnlock(); pData->egl.makeCurrent(display, surface, surface, pData->egl.getCurrentContext()); wlExternalApiLock(); /* Reset swap interval */ wl_eglstream_display_swap_interval(display->wlStreamDpy, surface->ctx.wlStreamResource, surface->swapInterval); } } wlExternalApiUnlock(); } static EGLBoolean validateSurfaceAttrib(EGLAttrib attrib, EGLAttrib value) { switch (attrib) { /* Window-only attributes will be ignored, but we still need to make sure a * valid value is given */ case EGL_RENDER_BUFFER: return (value == EGL_BACK_BUFFER) ? EGL_TRUE : EGL_FALSE; case EGL_POST_SUB_BUFFER_SUPPORTED_NV: return (value == EGL_TRUE || value == EGL_FALSE) ? EGL_TRUE : EGL_FALSE; /* EGL_WIDTH and EGL_HEIGHT shouldn't be specified */ case EGL_WIDTH: case EGL_HEIGHT: return EGL_FALSE; /* If attribute is supported/unsupported for both EGL_WINDOW_BIT and * EGL_STREAM_BIT_KHR, then that will be handled inside the actual * eglCreateStreamProducerSurfaceKHR() */ default: return EGL_TRUE; } } static EGLint assignWlEglSurfaceAttribs(WlEglSurface *surface, const EGLAttrib *attribs) { EGLint *int_attribs = NULL; unsigned int nAttribs = 2; // At least width and height int i; if (attribs) { for (i = 0; attribs[i] != EGL_NONE; i += 2) { if (!validateSurfaceAttrib(attribs[i], attribs[i + 1])) { return EGL_BAD_ATTRIBUTE; } /* Filter out window-only attributes */ if ((attribs[i] != EGL_RENDER_BUFFER) && (attribs[i] != EGL_POST_SUB_BUFFER_SUPPORTED_NV)) { nAttribs++; } } } int_attribs = (EGLint *)malloc(((nAttribs * 2) + 1) * sizeof(*int_attribs)); if (!int_attribs) { return EGL_BAD_ALLOC; } nAttribs = 0; int_attribs[nAttribs++] = EGL_WIDTH; // width at offset 0 int_attribs[nAttribs++] = 0; int_attribs[nAttribs++] = EGL_HEIGHT; // height at offset 2 int_attribs[nAttribs++] = 0; if (attribs) { for (i = 0; attribs[i] != EGL_NONE; i += 2) { if ((attribs[i] != EGL_RENDER_BUFFER) && (attribs[i] != EGL_POST_SUB_BUFFER_SUPPORTED_NV)) { int_attribs[nAttribs++] = (EGLint)attribs[i]; int_attribs[nAttribs++] = (EGLint)attribs[i + 1]; } } } int_attribs[nAttribs] = EGL_NONE; surface->attribs = int_attribs; return EGL_SUCCESS; } static EGLint destroyEglSurface(EGLDisplay dpy, EGLSurface eglSurface) { 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; } /* Remove surface from wlEglSurfaceList as early as possible to avoid * multiple threads trying to destroy the same surface simultaneously. * Inside destroy_surface_context and finish_wl_eglstream_damage_thread, * wl external API lock could be released temporarily, which would allow * multiple threads grab the same surface from wlEglSurfaceList, enter * destroyEglSurface and lead to segmentation fault. */ wl_list_remove(&surface->link); if (!surface->ctx.isOffscreen) { // Force damage thread to exit before invalidating the window objects finish_wl_eglstream_damage_thread(surface, &surface->ctx, 1); // 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))) { queue = wlGetEventQueue(display); if (queue != NULL) { wl_surface_attach(surface->wlSurface, NULL, 0, 0); wl_surface_commit(surface->wlSurface); ret = wlEglRoundtrip(display, queue); } if (surface->isSurfaceProducer) { 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; } } } wl_list_for_each_safe(ctx, next, &surface->oldCtxList, link) { destroy_surface_context(surface, ctx); wl_list_remove(&ctx->link); free(ctx); } free(surface->attribs); } destroy_surface_context(surface, &surface->ctx); free(surface); return (ret >= 0) ? EGL_SUCCESS : EGL_BAD_DISPLAY; } static void destroy_callback(void *data) { WlEglSurface *surface = (WlEglSurface*)data; if (!surface || !wlEglIsWlEglDisplay(surface->wlEglDpy)) { return; } wlExternalApiLock(); destroyEglSurface((EGLDisplay)surface->wlEglDpy, (EGLSurface)surface); wlExternalApiUnlock(); } static void getWlEglWindowVersionAndSurface(struct wl_egl_window *window, long int *version, struct wl_surface **surface) { /* * Given that wl_egl_window wasn't always a versioned struct, and that * 'window->version' replaced 'window->surface', we must check whether * 'window->version' is actually a valid pointer. If it is, we are dealing * with a wl_egl_window from an old implementation of libwayland-egl.so * Note that this will be disabled if platfrom does not have * mincore(2) to check whether a pointer is valid or not. */ *version = window->version; *surface = window->surface; #if HAS_MINCORE if (wlEglPointerIsDereferencable((void *)(window->version))) { *version = 0; *surface = (struct wl_surface *)(window->version); } #endif } EGLSurface wlEglCreatePlatformWindowSurfaceHook(EGLDisplay dpy, EGLConfig config, void *nativeWin, const EGLAttrib *attribs) { WlEglDisplay *display = (WlEglDisplay*)dpy; WlEglPlatformData *data = display->data; WlEglSurface *surface = NULL; struct wl_egl_window *window = (struct wl_egl_window *)nativeWin; EGLBoolean res = EGL_FALSE; EGLint err = EGL_SUCCESS; EGLint surfType; wlExternalApiLock(); if (!wlEglIsWaylandDisplay(display->nativeDpy)) { err = EGL_BAD_DISPLAY; goto fail; } dpy = display->devDpy->eglDisplay; if (!wlEglIsWaylandWindowValid(window)) { err = EGL_BAD_NATIVE_WINDOW; goto fail; } // Check for existing associated surface if (window->driver_private != NULL) { err = EGL_BAD_ALLOC; goto fail; } wlExternalApiUnlock(); res = data->egl.getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfType); wlExternalApiLock(); if (!res || !(surfType & EGL_STREAM_BIT_KHR)) { err = EGL_BAD_CONFIG; goto fail; } if (!display->exts.stream || (!display->exts.stream_cross_process_fd && !display->exts.stream_remote) || !display->exts.stream_producer_eglsurface) { err = EGL_BAD_ALLOC; goto fail; } surface = calloc(1, sizeof(*surface)); if (!surface) { err = EGL_BAD_ALLOC; goto fail; } surface->wlEglDpy = display; surface->eglConfig = config; surface->wlEglWin = window; surface->ctx.eglStream = EGL_NO_STREAM_KHR; surface->ctx.eglSurface = EGL_NO_SURFACE; surface->ctx.isOffscreen = EGL_FALSE; surface->isSurfaceProducer = EGL_TRUE; // FIFO_LENGTH == 1 to set FIFO mode, FIFO_LENGTH == 0 to set MAILBOX mode surface->fifoLength = (display->exts.stream_fifo_synchronous && display->exts.stream_sync) ? 1 : 0; getWlEglWindowVersionAndSurface(window, &surface->wlEglWinVer, &surface->wlSurface); wl_list_init(&surface->oldCtxList); wl_list_insert(&wlEglSurfaceList, &surface->link); err = assignWlEglSurfaceAttribs(surface, attribs); if (err != EGL_SUCCESS) { goto fail; } err = create_surface_context(surface); if (err != EGL_SUCCESS) { goto fail; } surface->swapInterval = 1; // Default swap interval is 1 // Set client's swap interval if there is an override on the compositor // side, Otherwise set to default wl_eglstream_display_swap_interval(display->wlStreamDpy, surface->ctx.wlStreamResource, surface->swapInterval); window->driver_private = surface; window->resize_callback = resize_callback; if (surface->wlEglWinVer >= WL_EGL_WINDOW_DESTROY_CALLBACK_SINCE) { window->destroy_window_callback = destroy_callback; } wlExternalApiUnlock(); return surface; fail: if (surface) { destroyEglSurface(display, surface); } wlExternalApiUnlock(); wlEglSetError(data, err); return EGL_NO_SURFACE; } EGLSurface wlEglCreatePlatformPixmapSurfaceHook(EGLDisplay dpy, EGLConfig config, void *nativePixmap, const EGLAttrib *attribs) { WlEglDisplay *display = (WlEglDisplay*)dpy; (void) config; (void) nativePixmap; (void) attribs; /* Wayland does not support pixmap types. See EGL_EXT_platform_wayland. */ wlEglSetError(display->data, EGL_BAD_PARAMETER); return EGL_NO_SURFACE; } EGLSurface wlEglCreatePbufferSurfaceHook(EGLDisplay dpy, EGLConfig config, const EGLint *attribs) { WlEglDisplay *display = (WlEglDisplay*)dpy; WlEglPlatformData *data = display->data; WlEglSurface *surface = NULL; EGLSurface surf = EGL_NO_SURFACE; EGLint err = EGL_SUCCESS; /* Nothing really special needs to be done. Just fall back to the driver's * Pbuffer surface creation function */ dpy = display->devDpy->eglDisplay; surf = data->egl.createPbufferSurface(dpy, config, attribs); if (surf == EGL_NO_SURFACE) { goto fail; } surface = calloc(1, sizeof(*surface)); if (!surface) { err = EGL_BAD_ALLOC; goto fail; } surface->wlEglDpy = display; surface->eglConfig = config; surface->ctx.eglSurface = surf; surface->ctx.isOffscreen = EGL_TRUE; wl_list_init(&surface->oldCtxList); wlExternalApiLock(); wl_list_insert(&wlEglSurfaceList, &surface->link); wlExternalApiUnlock(); return surface; fail: if (err != EGL_SUCCESS) { wlEglSetError(data, err); } return EGL_NO_SURFACE; } EGLSurface wlEglCreateStreamProducerSurfaceHook(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attribs) { WlEglDisplay *display = (WlEglDisplay*)dpy; WlEglPlatformData *data = display->data; WlEglSurface *surface = NULL; EGLSurface surf = EGL_NO_SURFACE; EGLint err = EGL_SUCCESS; /* Nothing really special needs to be done. Just fall back to the driver's * stream producer surface creation function */ dpy = display->devDpy->eglDisplay; surf = data->egl.createStreamProducerSurface(dpy, config, stream, attribs); if (surf == EGL_NO_SURFACE) { goto fail; } surface = calloc(1, sizeof(*surface)); if (!surface) { err = EGL_BAD_ALLOC; goto fail; } surface->wlEglDpy = display; surface->eglConfig = config; surface->ctx.eglSurface = surf; surface->ctx.isOffscreen = EGL_TRUE; wl_list_init(&surface->oldCtxList); wlExternalApiLock(); wl_list_insert(&wlEglSurfaceList, &surface->link); wlExternalApiUnlock(); return surface; fail: if (err != EGL_SUCCESS) { wlEglSetError(data, err); } return EGL_NO_SURFACE; } EGLBoolean wlEglDestroySurfaceHook(EGLDisplay dpy, EGLSurface eglSurface) { WlEglDisplay *display = (WlEglDisplay*)dpy; EGLBoolean err = EGL_SUCCESS; if (!wlEglIsWlEglDisplay(display)) { wlEglSetError(display->data, EGL_BAD_DISPLAY); return EGL_FALSE; } wlExternalApiLock(); err = destroyEglSurface(dpy, eglSurface); wlExternalApiUnlock(); if (err != EGL_SUCCESS) { wlEglSetError(display->data, err); return EGL_FALSE; } return EGL_TRUE; } EGLBoolean wlEglDestroyAllSurfaces(WlEglDisplay *display) { WlEglSurface *surface, *next; EGLBoolean res = EGL_TRUE; wl_list_for_each_safe(surface, next, &wlEglSurfaceList, link) { if (surface->wlEglDpy == display) { res = (destroyEglSurface(display, surface) == EGL_SUCCESS) && res; } } return res; } EGLBoolean wlEglQueryNativeResourceHook(EGLDisplay dpy, void *nativeResource, EGLint attribute, int *value) { struct wl_eglstream_display *wlStreamDpy = NULL; struct wl_eglstream *wlStream = NULL; EGLBoolean res = EGL_FALSE; EGLint originY; wlExternalApiLock(); wlStreamDpy = wl_eglstream_display_get(dpy); if (!wlStreamDpy) { goto done; } wlStream = wl_eglstream_display_get_stream( wlStreamDpy, (struct wl_resource *)nativeResource); if(!wlStream) { goto done; } switch (attribute) { case EGL_WIDTH: *value = (int)wlStream->width; res = EGL_TRUE; goto done; case EGL_HEIGHT: *value = (int)wlStream->height; res = EGL_TRUE; goto done; case EGL_WAYLAND_Y_INVERTED_WL: if (wlStreamDpy->exts.stream_origin && wlStreamDpy->data->egl.queryStream(wlStreamDpy->eglDisplay, wlStream->eglStream, EGL_STREAM_FRAME_ORIGIN_Y_NV, &originY)) { /* If we have an image with origin at the top, the wayland * compositor will consider it as y-inverted */ *value = (int)((originY == EGL_TOP_NV) ? EGL_TRUE : EGL_FALSE); } else { /* No mechanism found to query frame orientation. Assume OpenGL * orientation (image origin at the lower left corner), which * matches to what the wayland compositor would consider as * non-y-inverted */ *value = (int)EGL_FALSE; } res = EGL_TRUE; goto done; } done: wlExternalApiUnlock(); return res; } egl-wayland-1.1.3/src/wayland-eglswap.c000066400000000000000000000162611347064175300177720ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #include "wayland-eglswap.h" #include "wayland-eglstream-client-protocol.h" #include "wayland-thread.h" #include "wayland-egldisplay.h" #include "wayland-eglsurface.h" #include "wayland-eglhandle.h" #include "wayland-eglutils.h" #include EGLBoolean wlEglSwapBuffersHook(EGLDisplay eglDisplay, EGLSurface eglSurface) { return wlEglSwapBuffersWithDamageHook(eglDisplay, eglSurface, NULL, 0); } EGLBoolean wlEglSwapBuffersWithDamageHook(EGLDisplay eglDisplay, EGLSurface eglSurface, EGLint *rects, EGLint n_rects) { 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(); if (!wlEglIsWaylandDisplay(display->nativeDpy)) { err = EGL_BAD_DISPLAY; goto fail; } if (!wlEglIsWlEglSurface(surface)) { err = EGL_BAD_SURFACE; goto fail; } isOffscreen = surface->ctx.isOffscreen; if (!isOffscreen) { queue = wlGetEventQueue(display); 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; } /* Bail out if we were left with an invalid surface */ if (wlEglWaitFrameSync(surface, queue) == EGL_BAD_SURFACE) { err = EGL_BAD_SURFACE; goto fail; } } /* Save the internal EGLDisplay, EGLSurface and EGLStream handles, as * they are needed by the eglSwapBuffers() and streamFlush calls below */ eglDisplay = display->devDpy->eglDisplay; eglSurface = surface->ctx.eglSurface; eglStream = surface->ctx.eglStream; /* eglSwapBuffers() is a blocking call. We must release the lock so other * threads using the external platform are allowed to progress. */ wlExternalApiUnlock(); if (rects) { res = data->egl.swapBuffersWithDamage(eglDisplay, eglSurface, rects, n_rects); } else { res = data->egl.swapBuffers(eglDisplay, eglSurface); } if (isOffscreen) { goto done; } if (display->exts.stream_flush) { data->egl.streamFlush(eglDisplay, eglStream); } wlExternalApiLock(); /* Bail out if the surface was destroyed while the lock was suspended */ if (!wlEglIsWlEglSurface(surface)) { err = EGL_BAD_SURFACE; goto fail; } if (res) { if (surface->ctx.useDamageThread) { surface->ctx.framesProduced++; } else { res = wlEglSendDamageEvent(surface, queue); } } wlEglCreateFrameSync(surface, queue); wlExternalApiUnlock(); done: return res; fail: wlExternalApiUnlock(); wlEglSetError(data, err); return EGL_FALSE; } EGLBoolean wlEglSwapIntervalHook(EGLDisplay eglDisplay, EGLint interval) { WlEglDisplay *display = (WlEglDisplay *)eglDisplay; WlEglPlatformData *data = display->data; WlEglSurface *surface = NULL; EGLint state; /* Save the internal EGLDisplay handle, as it's needed by the actual * eglSwapInterval() call */ eglDisplay = display->devDpy->eglDisplay; if (!(data->egl.swapInterval(eglDisplay, interval))) { return EGL_FALSE; } surface = (WlEglSurface *)data->egl.getCurrentSurface(EGL_DRAW); wlExternalApiLock(); /* Check this is a valid wayland EGL surface (and stream) before sending the * swap interval value to the consumer */ if (!wlEglIsWlEglSurface(surface) || (surface->swapInterval == interval) || (surface->ctx.wlStreamResource == NULL) || (surface->ctx.eglStream == EGL_NO_STREAM_KHR) || (data->egl.queryStream(display->devDpy->eglDisplay, surface->ctx.eglStream, EGL_STREAM_STATE_KHR, &state) == EGL_FALSE) || (state == EGL_STREAM_STATE_DISCONNECTED_KHR)) { goto done; } wl_eglstream_display_swap_interval(display->wlStreamDpy, surface->ctx.wlStreamResource, interval); /* Cache interval value so we can reset it upon surface reattach */ surface->swapInterval = interval; done: wlExternalApiUnlock(); return EGL_TRUE; } EGLBoolean wlEglPrePresentExport(WlEglSurface *surface) { WlEglDisplay *display = surface->wlEglDpy; struct wl_event_queue *queue = NULL; wlExternalApiLock(); queue = wlGetEventQueue(display); if (queue == NULL) { return EGL_FALSE; } wlEglWaitFrameSync(surface, queue); wlExternalApiUnlock(); return EGL_TRUE; } EGLBoolean wlEglPostPresentExport(WlEglSurface *surface) { WlEglDisplay *display = surface->wlEglDpy; WlEglPlatformData *data = display->data; struct wl_event_queue *queue = NULL; EGLBoolean res = EGL_TRUE; if (display->exts.stream_flush) { data->egl.streamFlush((EGLDisplay) display, surface->ctx.eglStream); } wlExternalApiLock(); queue = wlGetEventQueue(display); if (queue == NULL) { return EGL_FALSE; } if (surface->ctx.useDamageThread) { surface->ctx.framesProduced++; } else { res = wlEglSendDamageEvent(surface, queue); } wlEglCreateFrameSync(surface, queue); wlExternalApiUnlock(); return res; } EGLint wlEglStreamSwapIntervalCallback(WlEglPlatformData *data, EGLStreamKHR stream, EGLint *interval) { EGLint res = EGL_SUCCESS; if (data->callbacks.streamSwapInterval) { res = data->callbacks.streamSwapInterval(stream, interval); } return res; } egl-wayland-1.1.3/src/wayland-eglutils.c000066400000000000000000000125661347064175300201640ustar00rootroot00000000000000/* * Copyright (c) 2014-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. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "wayland-eglutils.h" #include "wayland-thread.h" #include "wayland-eglhandle.h" #include #include #include #include #if HAS_MINCORE #include // Need dlsym() to load mincore() symbol dynamically. #endif EGLBoolean wlEglFindExtension(const char *extension, const char *extensions) { const char *start; const char *where, *terminator; start = extensions; for (;;) { where = strstr(start, extension); if (!where) { break; } terminator = where + strlen(extension); if (where == start || *(where - 1) == ' ') { if (*terminator == ' ' || *terminator == '\0') { return EGL_TRUE; } } start = terminator; } return EGL_FALSE; } #if HAS_MINCORE EGLBoolean wlEglPointerIsDereferencable(void *p) { /* * BSD and Solaris have slightly different prototypes for mincore, but * they should be compatible with this. BSD uses: * * (const void *, size_t, char *) * * And Solaris uses: * * (caddr_t, size_t, char*) * * Which I believe are all ABI compatible with the Linux prototype used * below for MINCOREPROC. */ typedef int (*MINCOREPROC)(void *, size_t, unsigned char *); static MINCOREPROC pMinCore = NULL; static EGLBoolean minCoreLoadAttempted = EGL_FALSE; uintptr_t addr = (uintptr_t) p; unsigned char unused; const long page_size = getpagesize(); if (minCoreLoadAttempted == EGL_FALSE) { minCoreLoadAttempted = EGL_TRUE; /* * According to its manpage, mincore was introduced in Linux 2.3.99pre1 * and glibc 2.2. The minimum glibc our driver supports is 2.0, so this * mincore can not be linked in directly. It does however seem * reasonable to assume that Wayland will not be run on glibc < 2.2. * * Attempt to load mincore from the currently available libraries. * mincore comes from libc, which the EGL driver depends on, so it * should always be loaded if our driver is running. */ pMinCore = (MINCOREPROC)dlsym(NULL, "mincore"); } /* * If the pointer can't be tested for safety, or is obviously unsafe, * assume it can't be dereferenced. */ if (p == NULL || !pMinCore) { return EGL_FALSE; } /* align addr to page_size */ addr &= ~(page_size - 1); /* * mincore() returns 0 on success, and -1 on failure. The last parameter * is a vector of bytes with one entry for each page queried. mincore * returns page residency information in the first bit of each byte in the * vector. * * Residency doesn't actually matter when determining whether a pointer is * dereferenceable, so the output vector can be ignored. What matters is * whether mincore succeeds. It will fail with ENOMEM if the range * [addr, addr + length) is not mapped into the process, so all that needs * to be checked there is whether the mincore call succeeds or not, as it * can only succeed on dereferenceable memory ranges. */ return (pMinCore((void *) addr, page_size, &unused) >= 0); } EGLBoolean wlEglCheckInterfaceType(struct wl_object *obj, const char *ifname) { Dl_info info; /* * The first member of a wl_object is a pointer to its wl_interface, * so we can check if it corresponds to the given symbol name */ if (dladdr(*(void **)obj, &info) == 0) { return EGL_FALSE; } return !strcmp(info.dli_sname, ifname); } #endif void wlEglSetErrorCallback(WlEglPlatformData *data, EGLint error, const char *file, int line) { if (data && data->callbacks.setError) { const char *defaultMsg = "Wayland external platform error"; if (file != NULL) { char msg[256]; if (snprintf(msg, 256, "%s:%d: %s", file, line, defaultMsg) > 0) { data->callbacks.setError(error, EGL_DEBUG_MSG_ERROR_KHR, msg); return; } } data->callbacks.setError(error, EGL_DEBUG_MSG_ERROR_KHR, defaultMsg); } } egl-wayland-1.1.3/src/wayland-external-exports.c000066400000000000000000000112741347064175300216530ustar00rootroot00000000000000/* * 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. */ #include #include "wayland-external-exports.h" #include "wayland-egldisplay.h" #include "wayland-eglstream.h" #include "wayland-eglsurface.h" #include "wayland-eglswap.h" #include "wayland-eglutils.h" #include "wayland-eglhandle.h" #include #include typedef struct WlEglHookRec { const char *name; void *func; } WlEglHook; static const WlEglHook wlEglHooksMap[] = { /* Keep names in ascending order */ { "eglBindWaylandDisplayWL", wlEglBindDisplaysHook }, { "eglChooseConfig", wlEglChooseConfigHook }, { "eglCreatePbufferSurface", wlEglCreatePbufferSurfaceHook }, { "eglCreatePlatformPixmapSurface", wlEglCreatePlatformPixmapSurfaceHook }, { "eglCreatePlatformWindowSurface", wlEglCreatePlatformWindowSurfaceHook }, { "eglCreateStreamAttribNV", wlEglCreateStreamAttribHook }, { "eglCreateStreamProducerSurfaceKHR", wlEglCreateStreamProducerSurfaceHook }, { "eglDestroySurface", wlEglDestroySurfaceHook }, { "eglGetConfigAttrib", wlEglGetConfigAttribHook }, { "eglInitialize", wlEglInitializeHook }, { "eglQueryWaylandBufferWL", wlEglQueryNativeResourceHook }, { "eglSwapBuffers", wlEglSwapBuffersHook }, { "eglSwapBuffersWithDamageKHR", wlEglSwapBuffersWithDamageHook }, { "eglSwapInterval", wlEglSwapIntervalHook }, { "eglTerminate", wlEglTerminateHook }, { "eglUnbindWaylandDisplayWL", wlEglUnbindDisplaysHook }, }; static int hookCmp(const void *elemA, const void *elemB) { const char *key = (const char *)elemA; const WlEglHook *hook = (const WlEglHook *)elemB; return strcmp(key, hook->name); } static void* wlEglGetHookAddressExport(void *data, const char *name) { WlEglHook *hook; (void) data; hook = (WlEglHook *)bsearch((const void *)name, (const void *)wlEglHooksMap, sizeof(wlEglHooksMap)/sizeof(WlEglHook), sizeof(WlEglHook), hookCmp); if (hook) { return hook->func; } return NULL; } static EGLBoolean wlEglUnloadPlatformExport(void *data) { EGLBoolean res; res = wlEglDestroyAllDisplays((WlEglPlatformData *)data); wlEglDestroyPlatformData((WlEglPlatformData *)data); return res; } EGLBoolean loadEGLExternalPlatform(int major, int minor, const EGLExtDriver *driver, EGLExtPlatform *platform) { if (!platform || !EGL_EXTERNAL_PLATFORM_VERSION_CHECK(major, minor)) { return EGL_FALSE; } platform->version.major = WAYLAND_EXTERNAL_VERSION_MAJOR; platform->version.minor = WAYLAND_EXTERNAL_VERSION_MINOR; platform->version.micro = WAYLAND_EXTERNAL_VERSION_MICRO; platform->platform = EGL_PLATFORM_WAYLAND_EXT; platform->data = (void *)wlEglCreatePlatformData(major, minor, driver); if (platform->data == NULL) { return EGL_FALSE; } platform->exports.unloadEGLExternalPlatform = wlEglUnloadPlatformExport; platform->exports.getHookAddress = wlEglGetHookAddressExport; platform->exports.isValidNativeDisplay = wlEglIsValidNativeDisplayExport; platform->exports.getPlatformDisplay = wlEglGetPlatformDisplayExport; platform->exports.queryString = wlEglQueryStringExport; platform->exports.getInternalHandle = wlEglGetInternalHandleExport; return EGL_TRUE; } egl-wayland-1.1.3/src/wayland-thread.c000066400000000000000000000154631347064175300176020ustar00rootroot00000000000000/* * 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 "wayland-egldisplay.h" #include #include #include #if defined(__QNX__) #define WL_EGL_ATTRIBUTE_DESTRUCTOR #define WL_EGL_ATEXIT(func) atexit(func) #else #define WL_EGL_ATTRIBUTE_DESTRUCTOR __attribute__((destructor)) #define WL_EGL_ATEXIT(func) 0 #endif 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; WlEventQueue *iter = NULL; WlEventQueue *tmp = NULL; wlExternalApiLock(); if (wlThread) { wl_list_for_each_safe(iter, tmp, &wlThread->evtQueueList, threadLink) { /* skip destroy if queue is still in use */ if (iter->refCount > 0) { wl_list_remove(&iter->threadLink); wl_list_init(&iter->threadLink); /* if terminateDisplay is called before thread exit, * queue could have been already destroyed */ if (iter->queue == NULL) { free(iter); } /* add it to the dangling queue list * of the display to destroy it later*/ else { WlEglDisplay *display = iter->display; if(display) { wl_list_remove(&iter->dpyLink); wl_list_init(&iter->dpyLink); wl_list_insert(&display->dangEvtQueueList, &iter->dangLink); } } } /* Invalidate and destroy the queue */ else { if (iter->queue != NULL) { /* wl_event_queue are associated with wl_display, If the app does * not terminate EGLDisplay before closing wl_display, calling * wl_display functions can cause assert or hang issues. * To prevent that, here we assume wl_display is disconnected * if exiting the process or unloading the library and skip * freeing wl_event_queue. */ if (!wlThread->processExiting) { wl_event_queue_destroy(iter->queue); } wl_list_remove(&iter->dpyLink); } wl_list_remove(&iter->threadLink); free(iter); } } free(wlThread); } wlExternalApiUnlock(); } static void mainThread_exit(void) WL_EGL_ATTRIBUTE_DESTRUCTOR; static void mainThread_exit(void) { if (wlTLSKeyInitialized) { WlThread *mainThread = pthread_getspecific(wlTLSKey); if (mainThread) { mainThread->processExiting = 1; destroy_tls_key(mainThread); } } } 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; } /* Thread destructor will be called only when thread exits. If main thread * exits, the destructor won't be called and valgrind will report memory leaks. * To avoid that, use atexit/library destructor to do the clean-up. */ if (WL_EGL_ATEXIT(mainThread_exit) != 0) { assert(!"failed to create process destructor"); } } 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; } wl_list_init(&wlThread->evtQueueList); wlThread->processExiting = 0; } return wlThread; } egl-wayland-1.1.3/wayland-egl/000077500000000000000000000000001347064175300161365ustar00rootroot00000000000000egl-wayland-1.1.3/wayland-egl/wayland-egl-ext.h000066400000000000000000000064101347064175300213120ustar00rootroot00000000000000/* * 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. */ #ifndef WAYLAND_EGL_EXT_H #define WAYLAND_EGL_EXT_H #ifndef EGL_WL_wayland_eglstream #define EGL_WL_wayland_eglstream 1 #define EGL_WAYLAND_EGLSTREAM_WL 0x334B #endif /* EGL_WL_wayland_eglstream */ #ifndef EGL_NV_stream_fifo_synchronous #define EGL_NV_stream_fifo_synchronous 1 #define EGL_STREAM_FIFO_SYNCHRONOUS_NV 0x3336 #endif /* EGL_NV_stream_fifo_synchronous */ #ifndef EGL_NV_stream_flush #define EGL_NV_stream_flush 1 typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMFLUSHNVPROC) (EGLDisplay dpy, EGLStreamKHR stream); #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglStreamFlushNV (EGLDisplay dpy, EGLStreamKHR stream); #endif #endif /*EGL_NV_stream_flush*/ /* Deprecated. Use EGL_KHR_stream_attrib */ #ifndef EGL_NV_stream_attrib #define EGL_NV_stream_attrib 1 #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamAttribNV(EGLDisplay dpy, const EGLAttrib *attrib_list); #endif 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 */ #ifndef EGL_NV_stream_origin #define EGL_NV_stream_origin 1 #define EGL_STREAM_FRAME_ORIGIN_X_NV 0x3366 #define EGL_STREAM_FRAME_ORIGIN_Y_NV 0x3367 #define EGL_STREAM_FRAME_MAJOR_AXIS_NV 0x3368 #define EGL_CONSUMER_AUTO_ORIENTATION_NV 0x3369 #define EGL_PRODUCER_AUTO_ORIENTATION_NV 0x336A #define EGL_LEFT_NV 0x336B #define EGL_RIGHT_NV 0x336C #define EGL_TOP_NV 0x336D #define EGL_BOTTOM_NV 0x336E #define EGL_X_AXIS_NV 0x336F #define EGL_Y_AXIS_NV 0x3370 #endif /* EGL_NV_stream_origin */ #endif egl-wayland-1.1.3/wayland-eglstream-protocols.pc.in000066400000000000000000000003111347064175300223200ustar00rootroot00000000000000prefix=@prefix@ datarootdir=@datarootdir@ pkgdatadir=@datadir@/@PACKAGE@ Name: wayland-eglstream-protocols Description: Nvidia Wayland EGLStream XML protocol files Version: @WAYLAND_EXTERNAL_VERSION@ egl-wayland-1.1.3/wayland-eglstream.pc.in000066400000000000000000000006171347064175300203070ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: wayland-eglstream Description: Nvidia Wayland EGLStream compositor helper libraries Version: @WAYLAND_EXTERNAL_VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -lnvidia-egl-wayland Requires: eglexternalplatform >= @EGL_EXTERNAL_PLATFORM_MIN_VERSION@ eglexternalplatform < @EGL_EXTERNAL_PLATFORM_MAX_VERSION@ egl-wayland-1.1.3/wayland-eglstream/000077500000000000000000000000001347064175300173525ustar00rootroot00000000000000egl-wayland-1.1.3/wayland-eglstream/.gitignore000066400000000000000000000001141347064175300213360ustar00rootroot00000000000000# All source files in this directory are autogenerated, ignore them *.c *.h egl-wayland-1.1.3/wayland-eglstream/meson.build000066400000000000000000000024311347064175300215140ustar00rootroot00000000000000generated_private_protocols = [ 'wayland-eglstream', ] generated_public_protocols = [ 'wayland-eglstream-controller', ] 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' output_file = '@0@-server-protocol.h'.format(proto) else 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 var_name = output_file.underscorify() target = custom_target( '@0@'.format(output_file), command: [prog_scanner, output_type, '@INPUT@', '@OUTPUT@'], input: '@0@.xml'.format(proto), output: output_file, ) set_variable(var_name, target) endforeach endforeach install_data( 'wayland-eglstream.xml', 'wayland-eglstream-controller.xml', install_dir : join_paths(get_option('datadir'), meson.project_name()) ) egl-wayland-1.1.3/wayland-eglstream/wayland-eglstream-controller.xml000066400000000000000000000110361347064175300256760ustar00rootroot00000000000000 Copyright (c) 2017-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. - dont_care: Using this enum will tell the server to make its own decisions regarding present mode. - fifo: Tells the server to use a fifo present mode. The decision to use fifo synchronous is left up to the server. - mailbox: Tells the server to use a mailbox present mode. - present_mode: Must be one of wl_eglstream_controller_present_mode. Tells the server the desired present mode that should be used. - fifo_length: Only valid when the present_mode attrib is provided and its value is specified as fifo. Tells the server the desired fifo length to be used when the desired present_mode is fifo. Creates the corresponding server side EGLStream from the given wl_buffer and attaches a consumer to it. Creates the corresponding server side EGLStream from the given wl_buffer and attaches a consumer to it using the given attributes. It contains key-value pairs compatible with intptr_t type. A key must be one of wl_eglstream_controller_attrib enumeration values. What a value represents is attribute-specific. egl-wayland-1.1.3/wayland-eglstream/wayland-eglstream.xml000066400000000000000000000200161347064175300235130ustar00rootroot00000000000000 Copyright (c) 2014-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. - fd: The given handle represents a file descriptor, and the EGLStream connection must be done as described in EGL_KHR_stream_cross_process_fd - inet: The EGLStream connection must be done using an inet address and port as described in EGL_NV_stream_socket. The given handle can be ignored, but both inet address and port must be given as attributes. - socket: The given handle represents a unix socket, and the EGLStream connection must be done as described in EGL_NV_stream_socket. - inet_addr: The given attribute encodes an IPv4 address of a client socket. Both IPv4 address and port must be set at the same time. - inet_port: The given attribute encodes a port of a client socket. Both IPv4 address and port must be set at the same time. This enum values should be used as bit masks. - stream_fd: The server supports EGLStream connections as described in EGL_KHR_stream_cross_process_fd - stream_inet: The server supports EGLStream inet connections as described in EGL_NV_stream_socket. - stream_socket: The server supports EGLStream unix socket connections as described in EGL_NV_stream_socket. The capabilities event is sent out at wl_eglstream_display binding time. It allows the server to advertise what features it supports so clients may know what is safe to be used. The swapinterval_override event is sent out whenever a client requests a swapinterval setting through swap_interval() and there is an override in place that will make such request to be ignored. The swapinterval_override event will provide the override value so that the client is made aware of it. Create a wl_buffer corresponding to given handle. The attributes list may be used to define additional EGLStream connection data (e.g inet address/port). The server can create its EGLStream handle using the information encoded in the wl_buffer. It contains key-value pairs compatible with intptr_t type. A key must be one of wl_eglstream_display_attrib enumeration values. What a value represents is attribute-specific. Set the swap interval for the consumer of the given EGLStream. The swap interval is silently clamped to the valid range on the server side.