pax_global_header00006660000000000000000000000064141157754540014527gustar00rootroot0000000000000052 comment=cd0d19aa2742b1318527cabbcf279fb651c45d30 egl-wayland-1.1.9/000077500000000000000000000000001411577545400137435ustar00rootroot00000000000000egl-wayland-1.1.9/.gitignore000066400000000000000000000013651411577545400157400ustar00rootroot00000000000000# 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.9/COPYING000066400000000000000000000021761411577545400150040ustar00rootroot00000000000000 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.9/Makefile.am000066400000000000000000000120451411577545400160010ustar00rootroot00000000000000 # 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 \ -I$(top_builddir)/wayland-drm # 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 \ $(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-egldevice.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-drm.c \ src/wayland-external-exports.c libnvidia_egl_wayland_la_built_public_protocols = \ wayland-eglstream/wayland-eglstream-controller-protocol.c \ wayland-drm/wayland-drm-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 \ wayland-drm/wayland-drm-server-protocol.h libnvidia_egl_wayland_la_dmabuf_built_client_headers = \ linux-dmabuf-unstable-v1-client-protocol.h libnvidia_egl_wayland_la_dmabuf_built_private_protocols = \ linux-dmabuf-unstable-v1-protocol.c 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) \ $(libnvidia_egl_wayland_la_dmabuf_built_client_headers) \ $(libnvidia_egl_wayland_la_dmabuf_built_private_protocols) 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-drm/wayland-drm.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_dmabuf_built_private_protocols):%-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/%.xml $(AM_V_GEN)$(WAYLAND_SCANNER) $(WAYLAND_PRIVATE_CODEGEN) < $< > $@ $(libnvidia_egl_wayland_la_dmabuf_built_client_headers):%-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/%.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ $(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.9/README.md000066400000000000000000000110331411577545400152200ustar00rootroot00000000000000Wayland 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. egl-wayland-1.1.9/autogen.sh000077500000000000000000000003071411577545400157440ustar00rootroot00000000000000#!/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.9/configure.ac000066400000000000000000000067071411577545400162430ustar00rootroot00000000000000AC_PREREQ([2.64]) m4_define([wayland_eglstream_major_version], [1]) m4_define([wayland_eglstream_minor_version], [1]) m4_define([wayland_eglstream_micro_version], [9]) 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"`]) # Check for protocols. PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.8]) AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, `$PKG_CONFIG --variable=pkgdatadir wayland-protocols`) # Initialize libtool LT_PREREQ([2.2]) LT_INIT # Checks for libraries. AX_PTHREAD() 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.9/include/000077500000000000000000000000001411577545400153665ustar00rootroot00000000000000egl-wayland-1.1.9/include/wayland-drm.h000066400000000000000000000026231411577545400177610ustar00rootroot00000000000000/* * Copyright (c) 2021, 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_DRM_H #define WAYLAND_DRM_H extern EGLBoolean wl_drm_display_bind(struct wl_display *display, struct wl_eglstream_display *wlStreamDpy); extern void wl_drm_display_unbind(struct wl_eglstream_display *wlStreamDpy); #endif /* WAYLAND_DRM_H */ egl-wayland-1.1.9/include/wayland-egldevice.h000066400000000000000000000057361411577545400211360ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, 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_EGLDEVICE_H #define WAYLAND_EGLDEVICE_H #include #include #include #include "wayland-external-exports.h" #include "wayland-eglhandle.h" #ifdef __cplusplus extern "C" { #endif /** * Keeps track of an internal display. * * Since the same internal display can be shared by multiple external displays, * the internal displays are always created with the EGL_TRACK_REFERENCES_KHR * flag set. If the driver doesn't support that extension, then we keep track * of an initialization count to produce the same behavior. */ typedef struct WlEglDeviceDpyRec { EGLDeviceEXT eglDevice; EGLDisplay eglDisplay; WlEglPlatformData *data; unsigned int initCount; EGLint major; EGLint minor; 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 stream_consumer_eglimage : 1; unsigned int image_dma_buf_export : 1; } exts; struct wl_list link; } WlEglDeviceDpy; /** * Returns the WlEglDeviceDpy structure for a given device. * Note that the same device will always return the same WlEglDeviceDpy. */ WlEglDeviceDpy *wlGetInternalDisplay(WlEglPlatformData *data, EGLDeviceEXT device); /** * Frees all of the WlEglDeviceDpy structures. */ void wlFreeAllInternalDisplays(WlEglPlatformData *data); EGLBoolean wlInternalInitialize(WlEglDeviceDpy *devDpy); EGLBoolean wlInternalTerminate(WlEglDeviceDpy *devDpy); #ifdef __cplusplus } #endif #endif // WAYLAND_EGLDEVICE_H egl-wayland-1.1.9/include/wayland-egldisplay.h000066400000000000000000000116771411577545400213450ustar00rootroot00000000000000/* * 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 #include "wayland-external-exports.h" #include "wayland-eglhandle.h" #include "wayland-egldevice.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 WlEglDmaBufFormatRec { uint32_t format; uint32_t numModifiers; uint64_t *modifiers; } WlEglDmaBufFormat; typedef struct WlEglDisplayRec { WlEglDeviceDpy *devDpy; EGLBoolean ownNativeDpy; struct wl_display *nativeDpy; struct wl_registry *wlRegistry; struct wl_eglstream_display *wlStreamDpy; struct wl_eglstream_controller *wlStreamCtl; struct zwp_linux_dmabuf_v1 *wlDmaBuf; unsigned int wlStreamCtlVer; struct wl_event_queue *wlEventQueue; struct { unsigned int stream_fd : 1; unsigned int stream_inet : 1; unsigned int stream_socket : 1; } caps; WlEglPlatformData *data; EGLBoolean useInitRefCount; /** * The number of times that eglTerminate has to be called before the * display is termianted. * * If \c useInitRefCount is true, then this is incremented each time * eglInitialize is called, and decremented each time eglTerminate is * called. * * If \c useInitRefCount is false, then this value is capped at 1. * * In all cases, the display is initialized if (initCount > 0). */ unsigned int initCount; pthread_mutex_t mutex; int refCount; struct wl_list wlEglSurfaceList; struct wl_list link; WlEglDmaBufFormat *dmaBufFormats; uint32_t numFormats; } 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); WlEglDisplay *wlEglAcquireDisplay(EGLDisplay dpy); void wlEglReleaseDisplay(WlEglDisplay *display); EGLBoolean wlEglChooseConfigHook(EGLDisplay dpy, EGLint const * attribs, EGLConfig * configs, EGLint configSize, EGLint * numConfig); EGLBoolean wlEglGetConfigAttribHook(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint * value); EGLBoolean wlEglQueryDisplayAttribHook(EGLDisplay dpy, EGLint name, EGLAttrib *value); EGLBoolean wlEglIsWaylandDisplay(void *nativeDpy); EGLBoolean wlEglIsWlEglDisplay(WlEglDisplay *display); EGLBoolean wlEglDestroyAllDisplays(WlEglPlatformData *data); const char* wlEglQueryStringExport(void *data, EGLDisplay dpy, EGLExtPlatformString name); #ifdef __cplusplus } #endif #endif egl-wayland-1.1.9/include/wayland-eglhandle.h000066400000000000000000000171411411577545400211230ustar00rootroot00000000000000/* * 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; PFNEGLQUERYDISPLAYATTRIBEXTPROC queryDisplayAttrib; PFNEGLQUERYDEVICESTRINGEXTPROC queryDeviceString; /* Used for fifo_synchronous support */ PFNEGLQUERYSTREAMKHRPROC queryStream; PFNEGLQUERYSTREAMU64KHRPROC queryStreamu64; PFNEGLCREATESTREAMSYNCNVPROC createStreamSync; PFNEGLCLIENTWAITSYNCKHRPROC clientWaitSync; PFNEGLSIGNALSYNCKHRPROC signalSync; PFNEGLDESTROYSYNCKHRPROC destroySync; PFNEGLSTREAMFLUSHNVPROC streamFlush; /* Used for dma-buf surfaces */ PFNEGLSTREAMIMAGECONSUMERCONNECTNVPROC streamImageConsumerConnect; PFNEGLSTREAMACQUIREIMAGENVPROC streamAcquireImage; PFNEGLSTREAMRELEASEIMAGENVPROC streamReleaseImage; PFNEGLQUERYSTREAMCONSUMEREVENTNVPROC queryStreamConsumerEvent; PFNEGLEXPORTDMABUFIMAGEMESAPROC exportDMABUFImage; PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC exportDMABUFImageQuery; PFNEGLCREATEIMAGEKHRPROC createImage; PFNEGLDESTROYIMAGEKHRPROC destroyImage; } egl; /* Non-application-facing callbacks provided by the EGL driver */ struct { PEGLEXTFNSETERROR setError; PEGLEXTFNSTREAMSWAPINTERVAL streamSwapInterval; } callbacks; /* True if the driver supports the EGL_KHR_display_reference extension. */ EGLBoolean supportsDisplayReference; /* A linked list of WlEglDeviceDpy structs. */ struct wl_list deviceDpyList; /* 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.9/include/wayland-eglstream-server.h000066400000000000000000000101261411577545400224630ustar00rootroot00000000000000/* * 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, const char *exts); /* * 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; struct { const char *device_name; struct wl_global *global; } *drm; 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; /* * The following attribute encodes the default value for a * stream's image inversion relative to wayland protocol * convention. Vulkan apps will be set to 'true', while * OpenGL apps will be set to 'false'. * NOTE: EGL_NV_stream_origin is the authorative source of * truth regarding a stream's frame orientation and should be * queried for an accurate value. The following attribute is a * 'best guess' fallback mechanism which should only be used * when a query to EGL_NV_stream_origin fails. */ EGLBoolean yInverted; }; #ifdef __cplusplus } #endif #endif egl-wayland-1.1.9/include/wayland-eglstream.h000066400000000000000000000032401411577545400211560ustar00rootroot00000000000000/* * 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.9/include/wayland-eglsurface.h000066400000000000000000000145741411577545400213270ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, 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 WlEglStreamImageRec { /* Pointer back to the parent surface for use in Wayland callbacks */ struct WlEglSurfaceRec *surface; /* * Use an individual mutex to guard access to each image's data. This avoids * sharing the surface lock between the app and buffer release event * threads, resulting in simplified lock management and smaller critical * sections. */ pthread_mutex_t mutex; EGLImageKHR eglImage; struct wl_buffer *buffer; EGLBoolean attached; struct wl_list acquiredLink; } WlEglStreamImage; typedef struct WlEglSurfaceCtxRec { EGLBoolean isOffscreen; EGLSurface eglSurface; EGLStreamKHR eglStream; void *wlStreamResource; EGLBoolean isAttached; int useDamageThread; pthread_t damageThreadId; EGLSyncKHR damageThreadSync; int damageThreadFlush; int damageThreadShutdown; EGLuint64KHR framesProduced; EGLuint64KHR framesFinished; EGLuint64KHR framesProcessed; /* * The double pointer is because of the need to allocate the data for each * image slot separately to avoid clobbering the acquiredLink member * whenever the streamImages arrary is resized with realloc(). */ WlEglStreamImage **streamImages; struct wl_list acquiredImages; struct wl_buffer *currentBuffer; uint32_t numStreamImages; struct wl_list link; } WlEglSurfaceCtx; typedef struct WlEglSurfaceRec { WlEglDisplay *wlEglDpy; EGLConfig eglConfig; EGLint *attribs; EGLBoolean pendingSwapIntervalUpdate; 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 *wlEventQueue; /* Asynchronous wl_buffer.release event processing */ struct { struct wl_event_queue *wlBufferEventQueue; pthread_t bufferReleaseThreadId; int bufferReleaseThreadPipe[2]; }; struct wl_list link; EGLBoolean isSurfaceProducer; /* The refCount is initialized to 1 during EGLSurface creation, * gets incremented/decrementsd in wlEglSurfaceRef()/wlEglSurfaceUnref(), * when we enter/exit from eglSwapBuffers(). */ unsigned int refCount; /* * Set to EGL_TRUE before destroying the EGLSurface in eglDestroySurface(). */ EGLBoolean isDestroyed; /* The lock is used to serialize eglSwapBuffers()/eglDestroySurface(), * Using wlExternalApiLock() for this requires that we release lock * before dispatching frame sync events in wlEglWaitFrameSync(). */ pthread_mutex_t mutexLock; } WlEglSurface; 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 wlEglIsWlEglSurfaceForDisplay(WlEglDisplay *display, 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); EGLint wlEglWaitFrameSync(WlEglSurface *surface); EGLBoolean wlEglSurfaceRef(WlEglDisplay *display, WlEglSurface *surface); void wlEglSurfaceUnref(WlEglSurface *surface); EGLint wlEglHandleImageStreamEvents(WlEglSurface *surface); #ifdef __cplusplus } #endif #endif egl-wayland-1.1.9/include/wayland-eglswap.h000066400000000000000000000040701411577545400206370ustar00rootroot00000000000000/* * 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.9/include/wayland-eglutils.h000066400000000000000000000043211411577545400210240ustar00rootroot00000000000000/* * 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_INITIALIZER #define WL_LIST_INITIALIZER(head) { .prev = (head), .next = (head) } #endif #ifndef WL_LIST_INIT #define WL_LIST_INIT(head) \ do { (head)->prev = (head)->next = (head); } while (0); #endif #ifdef __cplusplus extern "C" { #endif EGLBoolean wlEglFindExtension(const char *extension, const char *extensions); EGLBoolean wlEglMemoryIsReadable(const void *p, size_t len); EGLBoolean wlEglCheckInterfaceType(struct wl_object *obj, const char *ifname); void wlEglSetErrorCallback(WlEglPlatformData *data, EGLint err, const char *file, int line); #ifdef __cplusplus } #endif #endif egl-wayland-1.1.9/include/wayland-external-exports.h000066400000000000000000000053431411577545400225250ustar00rootroot00000000000000/* * 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 9 #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.9/include/wayland-thread.h000066400000000000000000000046731411577545400204550ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, 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 #include #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); /* * wlEglInitializeMutex(pthread_mutex_t *mutex) * * Initialises the pthread mutex referenced by mutex. */ bool wlEglInitializeMutex(pthread_mutex_t *mutex); /* * wlEglMutexDestroy(pthread_mutex_t *mutex) * * Destroys the pthread mutex referenced by mutex. */ void wlEglMutexDestroy(pthread_mutex_t *mutex); #endif egl-wayland-1.1.9/m4/000077500000000000000000000000001411577545400142635ustar00rootroot00000000000000egl-wayland-1.1.9/m4/ax_check_compile_flag.m4000066400000000000000000000040701411577545400207740ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # 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 current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # 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. This file is offered as-is, without any # warranty. #serial 6 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS egl-wayland-1.1.9/m4/ax_check_enable_debug.m4000066400000000000000000000107301411577545400207470ustar00rootroot00000000000000# =========================================================================== # 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.9/m4/ax_check_link_flag.m4000066400000000000000000000057601411577545400203100ustar00rootroot00000000000000# =========================================================================== # 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.9/m4/ax_pthread.m4000066400000000000000000000312671411577545400166550ustar00rootroot00000000000000# =========================================================================== # 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.9/meson.build000066400000000000000000000043061411577545400161100ustar00rootroot00000000000000project('wayland-eglstream', 'c', version : '1.1.9', default_options : [ 'buildtype=debugoptimized', 'c_std=gnu99', 'warning_level=1', ], license : 'MIT', meson_version : '>= 0.50' ) 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) configure_file( input : 'wayland-eglstream.pc.in', output : '@BASENAME@', configuration : pkgconf, install : true, install_dir : join_paths(get_option('libdir'), 'pkgconfig') ) configure_file( input : 'wayland-eglstream-protocols.pc.in', output : '@BASENAME@', configuration : pkgconf, install : true, install_dir : join_paths(get_option('datadir'), 'pkgconfig') ) subdir('wayland-eglstream') subdir('wayland-drm') subdir('src') egl-wayland-1.1.9/src/000077500000000000000000000000001411577545400145325ustar00rootroot00000000000000egl-wayland-1.1.9/src/meson.build000066400000000000000000000036531411577545400167030ustar00rootroot00000000000000add_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 wl_protos = dependency('wayland-protocols', version: '>= 1.8') wl_protos_dir = wl_protos.get_pkgconfig_variable('pkgdatadir') wl_dmabuf_xml = join_paths(wl_protos_dir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml') client_header = generator(prog_scanner, output : '@BASENAME@-client-protocol.h', arguments : ['client-header', '@INPUT@', '@OUTPUT@'] ) if wl_scanner.version().version_compare('>= 1.14.91') code_arg = 'private-code' else code_arg = 'code' endif code = generator(prog_scanner, output : '@BASENAME@-protocol.c', arguments : [code_arg, '@INPUT@', '@OUTPUT@'] ) src = [ 'wayland-thread.c', 'wayland-egldevice.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-drm.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, wayland_drm_protocol_c, wayland_drm_server_protocol_h, ] src += client_header.process(wl_dmabuf_xml) src += code.process(wl_dmabuf_xml) egl_wayland = library('nvidia-egl-wayland', src, dependencies : [ eglexternalplatform, wayland_server, wayland_client, wayland_egl_backend, threads, ], include_directories : inc, version : meson.project_version(), install : true, ) egl-wayland-1.1.9/src/wayland-drm.c000066400000000000000000000144431411577545400171230ustar00rootroot00000000000000/* * Copyright (c) 2021, 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 "wayland-eglstream-server.h" #include "wayland-drm.h" #include "wayland-eglutils.h" #include "wayland-drm-server-protocol.h" static void authenticate(struct wl_client *client, struct wl_resource *resource, uint32_t id) { (void)client; (void)id; /* * This implementation will only ever report render node files, and * authentication is not supported nor required for render node devices. */ wl_resource_post_error(resource, WL_DRM_ERROR_AUTHENTICATE_FAIL, "authenticate failed"); } static void create_buffer(struct wl_client *client, struct wl_resource *resource, uint32_t id, uint32_t name, int32_t width, int32_t height, uint32_t stride, uint32_t format) { (void)client; (void)id; (void)name; (void)width; (void)height; (void)stride; (void)format; wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_FORMAT, "invalid format"); } static void create_planar_buffer(struct wl_client *client, struct wl_resource *resource, uint32_t id, uint32_t name, int32_t width, int32_t height, uint32_t format, int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1, int32_t offset2, int32_t stride2) { (void)client; (void)id; (void)name; (void)width; (void)height; (void)format; (void)offset0; (void)stride0; (void)offset1; (void)stride1; (void)offset2; (void)stride2; wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_FORMAT, "invalid format"); } static void create_prime_buffer(struct wl_client *client, struct wl_resource *resource, uint32_t id, int fd, int32_t width, int32_t height, uint32_t format, int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1, int32_t offset2, int32_t stride2) { (void)client; (void)id; (void)fd; (void)width; (void)height; (void)format; (void)offset0; (void)stride0; (void)offset1; (void)stride1; (void)offset2; (void)stride2; wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_FORMAT, "invalid format"); close(fd); } static const struct wl_drm_interface interface = { authenticate, create_buffer, create_planar_buffer, create_prime_buffer, }; static void bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wl_eglstream_display *wlStreamDpy = data; struct wl_resource *resource = wl_resource_create(client, &wl_drm_interface, version > 2 ? 2 : version, id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &interface, data, NULL); wl_resource_post_event(resource, WL_DRM_DEVICE, wlStreamDpy->drm->device_name); /* * Don't send any format events. This implementation doesn't support * creating Wayland buffers of any format. */ /* * Don't report any capabilities beyond the baseline, as currently all * capabilities are only relevant when buffer creation is supported. */ if (version >= 2) wl_resource_post_event(resource, WL_DRM_CAPABILITIES, 0); } EGLBoolean wl_drm_display_bind(struct wl_display *display, struct wl_eglstream_display *wlStreamDpy) { EGLDisplay dpy = wlStreamDpy->eglDisplay; EGLDeviceEXT egl_dev; const char *dev_exts; const char *dev_name; if (!wlStreamDpy->data->egl.queryDisplayAttrib(dpy, EGL_DEVICE_EXT, (EGLAttribKHR*)&egl_dev)) { return EGL_FALSE; } dev_exts = wlStreamDpy->data->egl.queryDeviceString(egl_dev, EGL_EXTENSIONS); if (!dev_exts) { return EGL_FALSE; } if (!wlEglFindExtension("EGL_EXT_device_drm_render_node", dev_exts)) { return EGL_FALSE; } dev_name = wlStreamDpy->data->egl.queryDeviceString(egl_dev, EGL_DRM_RENDER_NODE_FILE_EXT); if (!dev_name) { return EGL_FALSE; } wlStreamDpy->drm = calloc(1, sizeof *wlStreamDpy->drm); if (!wlStreamDpy->drm) { return EGL_FALSE; } wlStreamDpy->drm->device_name = dev_name; wlStreamDpy->drm->global = wl_global_create(display, &wl_drm_interface, 2, wlStreamDpy, bind); return EGL_TRUE; } void wl_drm_display_unbind(struct wl_eglstream_display *wlStreamDpy) { if (wlStreamDpy->drm) { wl_global_destroy(wlStreamDpy->drm->global); free(wlStreamDpy->drm); wlStreamDpy->drm = NULL; } } egl-wayland-1.1.9/src/wayland-egldevice.c000066400000000000000000000107741411577545400202730ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, 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-egldevice.h" #include #include #include #include "wayland-eglhandle.h" #include "wayland-eglutils.h" WlEglDeviceDpy *wlGetInternalDisplay(WlEglPlatformData *data, EGLDeviceEXT device) { static const EGLint TRACK_REFS_ATTRIBS[] = { EGL_TRACK_REFERENCES_KHR, EGL_TRUE, EGL_NONE }; WlEglDeviceDpy *devDpy = NULL; const EGLint *attribs = NULL; // First, see if we've already created an EGLDisplay for this device. wl_list_for_each(devDpy, &data->deviceDpyList, link) { if (devDpy->data == data && devDpy->eglDevice == device) { return devDpy; } } // We didn't find a matching display, so create one. if (data->supportsDisplayReference) { // Always use EGL_KHR_display_reference if the driver supports it. // We'll do our own refcounting so that we can work without it, but // setting EGL_TRACK_REFERENCES_KHR means that it's less likely that // something else might grab the same EGLDevice-based display and // call eglTerminate on it. attribs = TRACK_REFS_ATTRIBS; } devDpy = calloc(1, sizeof(WlEglDeviceDpy)); if (devDpy == NULL) { return NULL; } devDpy->eglDevice = device; devDpy->data = data; devDpy->eglDisplay = data->egl.getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, device, attribs); if (devDpy->eglDisplay == EGL_NO_DISPLAY) { free(devDpy); return NULL; } wl_list_insert(&data->deviceDpyList, &devDpy->link); return devDpy; } static void wlFreeInternalDisplay(WlEglDeviceDpy *devDpy) { if (devDpy->initCount > 0) { devDpy->data->egl.terminate(devDpy->eglDisplay); } wl_list_remove(&devDpy->link); free(devDpy); } void wlFreeAllInternalDisplays(WlEglPlatformData *data) { WlEglDeviceDpy *devDpy, *devNext; wl_list_for_each_safe(devDpy, devNext, &data->deviceDpyList, link) { assert (devDpy->data == data); wlFreeInternalDisplay(devDpy); } } EGLBoolean wlInternalInitialize(WlEglDeviceDpy *devDpy) { if (devDpy->initCount == 0) { const char *exts; if (!devDpy->data->egl.initialize(devDpy->eglDisplay, &devDpy->major, &devDpy->minor)) { return EGL_FALSE; } exts = devDpy->data->egl.queryString(devDpy->eglDisplay, EGL_EXTENSIONS); #define CACHE_EXT(_PREFIX_, _NAME_) \ devDpy->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(NV, stream_consumer_eglimage); CACHE_EXT(MESA, image_dma_buf_export); #undef CACHE_EXT } devDpy->initCount++; return EGL_TRUE; } EGLBoolean wlInternalTerminate(WlEglDeviceDpy *devDpy) { if (devDpy->initCount > 0) { if (devDpy->initCount == 1) { if (!devDpy->data->egl.terminate(devDpy->eglDisplay)) { return EGL_FALSE; } } devDpy->initCount--; } return EGL_TRUE; } egl-wayland-1.1.9/src/wayland-egldisplay.c000066400000000000000000000730651411577545400205030ustar00rootroot00000000000000/* * 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 "linux-dmabuf-unstable-v1-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 typedef struct WlServerProtocolsRec { EGLBoolean hasEglStream; EGLBoolean hasDmaBuf; } WlServerProtocols; /* TODO: Make global display lists hang off platform data */ static struct wl_list wlEglDisplayList = WL_LIST_INITIALIZER(&wlEglDisplayList); EGLBoolean wlEglIsWaylandDisplay(void *nativeDpy) { if (!wlEglMemoryIsReadable(nativeDpy, sizeof (void *))) { return EGL_FALSE; } return wlEglCheckInterfaceType(nativeDpy, "wl_display"); } EGLBoolean wlEglIsValidNativeDisplayExport(void *data, void *nativeDpy) { char *val = getenv("EGL_PLATFORM"); (void)data; if (val && !strcasecmp(val, "wayland")) { return EGL_TRUE; } return wlEglIsWaylandDisplay(nativeDpy); } EGLBoolean wlEglBindDisplaysHook(void *data, EGLDisplay dpy, void *nativeDpy) { /* Retrieve extension string before taking external API lock */ const char *exts = ((WlEglPlatformData *)data)->egl.queryString(dpy, EGL_EXTENSIONS); EGLBoolean res = EGL_FALSE; wlExternalApiLock(); res = wl_eglstream_display_bind((WlEglPlatformData *)data, (struct wl_display *)nativeDpy, dpy, exts); 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 dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, uint32_t format) { (void)data; (void)dmabuf; (void)format; /* Only use formats that include an associated modifier */ } static void dmabuf_add_format_modifier(WlEglDmaBufFormat *format, const uint64_t modifier) { uint64_t *newModifiers; uint32_t m; for (m = 0; m < format->numModifiers; m++) { if (format->modifiers[m] == modifier) { return; } } newModifiers = realloc(format->modifiers, sizeof(format->modifiers[0]) * (format->numModifiers + 1)); if (!newModifiers) { return; } newModifiers[format->numModifiers] = modifier; format->modifiers = newModifiers; format->numModifiers++; } static void dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, uint32_t format, uint32_t mod_hi, uint32_t mod_lo) { WlEglDisplay *display = data; WlEglDmaBufFormat *newFormats; const uint64_t modifier = ((uint64_t)mod_hi << 32ULL) | (uint64_t)mod_lo; uint32_t f; (void)dmabuf; for (f = 0; f < display->numFormats; f++) { if (display->dmaBufFormats[f].format == format) { dmabuf_add_format_modifier(&display->dmaBufFormats[f], modifier); return; } } newFormats = realloc(display->dmaBufFormats, sizeof(display->dmaBufFormats[0]) * (display->numFormats + 1)); if (!newFormats) { return; } newFormats[display->numFormats].format = format; newFormats[display->numFormats].numModifiers = 0; newFormats[display->numFormats].modifiers = NULL; dmabuf_add_format_modifier(&newFormats[display->numFormats], modifier); display->dmaBufFormats = newFormats; display->numFormats++; } static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { .format = dmabuf_handle_format, .modifier = dmabuf_handle_modifier, }; static void dmabuf_set_interface(WlEglDisplay *display, struct wl_registry *registry, uint32_t name, uint32_t version) { if (version < 3) { /* * Version 3 added format modifier support, which the dmabuf * support in this library relies on. */ return; } display->wlDmaBuf = wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, 3); zwp_linux_dmabuf_v1_add_listener(display->wlDmaBuf, &dmabuf_listener, display); } 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); } else if (strcmp(interface, "wl_eglstream_controller") == 0) { display->wlStreamCtl = wl_registry_bind(registry, name, &wl_eglstream_controller_interface, version); display->wlStreamCtlVer = version; } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) { dmabuf_set_interface(display, registry, name, 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 registry_handle_global_check_protocols( void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { WlServerProtocols *protocols = (WlServerProtocols *)data; (void) registry; (void) name; (void) version; if (strcmp(interface, "wl_eglstream_display") == 0) { protocols->hasEglStream = EGL_TRUE; } if ((strcmp(interface, "zwp_linux_dmabuf_v1") == 0) && (version >= 3)) { protocols->hasDmaBuf = EGL_TRUE; } } 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) { WlEglDisplay *dpy = (WlEglDisplay *)data; WlEglSurface *surf = NULL; (void) wlStreamDpy; wl_list_for_each(surf, &dpy->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, }; /* 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(WlEglDisplay *display, EGLBoolean globalTeardown) { if (display->initCount == 0) { return EGL_TRUE; } /* If globalTeardown is true, then ignore the refcount and terminate the display. That's used when the library is unloaded. */ if (display->initCount > 1 && !globalTeardown) { display->initCount--; return EGL_TRUE; } if (!wlInternalTerminate(display->devDpy)) { if (!globalTeardown) { return EGL_FALSE; } } display->initCount = 0; /* First, destroy any surface associated to the given display. Then * destroy the display connection itself */ wlEglDestroyAllSurfaces(display); if (!globalTeardown || display->ownNativeDpy) { if (display->wlRegistry) { wl_registry_destroy(display->wlRegistry); display->wlRegistry = NULL; } if (display->wlStreamDpy) { wl_eglstream_display_destroy(display->wlStreamDpy); display->wlStreamDpy = NULL; } if (display->wlEventQueue) { wl_event_queue_destroy(display->wlEventQueue); display->wlEventQueue = NULL; } } return EGL_TRUE; } EGLBoolean wlEglTerminateHook(EGLDisplay dpy) { WlEglDisplay *display = wlEglAcquireDisplay(dpy); EGLBoolean res; if (!display) { return EGL_FALSE; } pthread_mutex_lock(&display->mutex); res = terminateDisplay(display, EGL_FALSE); pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return res; } static void checkServerProtocols(struct wl_display *nativeDpy, WlServerProtocols *protocols) { struct wl_display *wrapper = NULL; struct wl_registry *wlRegistry = NULL; struct wl_event_queue *queue = wl_display_create_queue(nativeDpy); int ret = 0; const struct wl_registry_listener registryListener = { registry_handle_global_check_protocols, registry_handle_global_remove }; if (queue == NULL) { return; } 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. */ wlRegistry = wl_display_get_registry(wrapper); wl_proxy_wrapper_destroy(wrapper); /* Done with wrapper */ ret = wl_registry_add_listener(wlRegistry, ®istryListener, protocols); if (ret == 0) { wl_display_roundtrip_queue(nativeDpy, queue); } if (queue) { wl_event_queue_destroy(queue); } if (wlRegistry) { wl_registry_destroy(wlRegistry); } } EGLDisplay wlEglGetPlatformDisplayExport(void *data, EGLenum platform, void *nativeDpy, const EGLAttrib *attribs) { WlEglPlatformData *pData = (WlEglPlatformData *)data; WlEglDisplay *display = NULL; WlServerProtocols protocols; EGLint numDevices = 0; int i = 0; EGLDeviceEXT eglDevice = NULL; EGLint err = EGL_SUCCESS; EGLBoolean useInitRefCount = EGL_FALSE; if (platform != EGL_PLATFORM_WAYLAND_EXT) { wlEglSetError(data, EGL_BAD_PARAMETER); return EGL_NO_DISPLAY; } /* Check the attribute list. Any attributes are likely to require some * special handling, so reject anything we don't recognize. */ if (attribs) { for (i = 0; attribs[i] != EGL_NONE; i += 2) { if (attribs[i] == EGL_TRACK_REFERENCES_KHR) { if (attribs[i + 1] == EGL_TRUE || attribs[i + 1] == EGL_FALSE) { useInitRefCount = (EGLBoolean) attribs[i + 1]; } else { wlEglSetError(data, EGL_BAD_ATTRIBUTE); return EGL_NO_DISPLAY; } } else { wlEglSetError(data, EGL_BAD_ATTRIBUTE); return EGL_NO_DISPLAY; } } } wlExternalApiLock(); /* First, check if we've got an existing display that matches. */ wl_list_for_each(display, &wlEglDisplayList, link) { if ((display->nativeDpy == nativeDpy || (!nativeDpy && display->ownNativeDpy)) && display->useInitRefCount == useInitRefCount) { wlExternalApiUnlock(); return (EGLDisplay)display; } } display = calloc(1, sizeof(*display)); if (!display) { wlExternalApiUnlock(); err = EGL_BAD_ALLOC; goto fail; } display->data = pData; display->nativeDpy = nativeDpy; display->useInitRefCount = useInitRefCount; /* 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 (!display->nativeDpy) { display->nativeDpy = wl_display_connect(NULL); if (!display->nativeDpy) { wlExternalApiUnlock(); err = EGL_BAD_ALLOC; goto fail; } display->ownNativeDpy = EGL_TRUE; wl_display_dispatch_pending(display->nativeDpy); } memset(&protocols, 0, sizeof(protocols)); checkServerProtocols(display->nativeDpy, &protocols); if (!protocols.hasEglStream && !protocols.hasDmaBuf) { wlExternalApiUnlock(); goto fail; } if (!pData->egl.queryDevices(1, &eglDevice, &numDevices) || numDevices == 0) { wlExternalApiUnlock(); goto fail; } display->devDpy = wlGetInternalDisplay(pData, eglDevice); if (display->devDpy == NULL) { wlExternalApiUnlock(); goto fail; } if (!wlEglInitializeMutex(&display->mutex)) { wlExternalApiUnlock(); goto fail; } display->refCount = 1; WL_LIST_INIT(&display->wlEglSurfaceList); // 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->ownNativeDpy) { wl_display_disconnect(display->nativeDpy); } free(display); if (err != EGL_SUCCESS) { wlEglSetError(data, err); } return EGL_NO_DISPLAY; } EGLBoolean wlEglInitializeHook(EGLDisplay dpy, EGLint *major, EGLint *minor) { WlEglDisplay *display = wlEglAcquireDisplay(dpy); WlEglPlatformData *data = NULL; struct wl_display *wrapper = NULL; EGLint err = EGL_SUCCESS; int ret = 0; if (!display) { return EGL_FALSE; } pthread_mutex_lock(&display->mutex); data = display->data; if (display->initCount > 0) { // This display has already been initialized. if (major) { *major = display->devDpy->major; } if (minor) { *minor = display->devDpy->minor; } if (display->useInitRefCount) { display->initCount++; } pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return EGL_TRUE; } if (!wlInternalInitialize(display->devDpy)) { pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return EGL_FALSE; } // Set the initCount to 1. If something goes wrong, then terminateDisplay // will clean up and set it back to zero. display->initCount = 1; display->wlEventQueue = wl_display_create_queue(display->nativeDpy);; if (display->wlEventQueue == NULL) { err = EGL_BAD_ALLOC; goto fail; } wrapper = wl_proxy_create_wrapper(display->nativeDpy); wl_proxy_set_queue((struct wl_proxy *)wrapper, display->wlEventQueue); /* Listen to wl_registry events and make a roundtrip in order to find the * wl_eglstream_display and/or zwp_linux_dmabuf_v1 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 = wl_display_roundtrip_queue(display->nativeDpy, display->wlEventQueue); } if (ret < 0) { err = EGL_BAD_ALLOC; goto fail; } if (display->wlStreamDpy) { /* 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 = wl_display_roundtrip_queue(display->nativeDpy, display->wlEventQueue); } if (ret < 0) { err = EGL_BAD_ALLOC; goto fail; } } else if (!display->wlDmaBuf) { /* This library requires either the EGLStream or dma-buf protocols to * present content to the Wayland compositor. */ err = EGL_BAD_ALLOC; goto fail; } if (major != NULL) { *major = display->devDpy->major; } if (minor != NULL) { *minor = display->devDpy->minor; } pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return EGL_TRUE; fail: terminateDisplay(display, EGL_FALSE); if (err != EGL_SUCCESS) { wlEglSetError(data, err); } pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return EGL_FALSE; } EGLBoolean wlEglIsWlEglDisplay(WlEglDisplay *display) { WlEglDisplay *dpy; wl_list_for_each(dpy, &wlEglDisplayList, link) { if (dpy == display) { return EGL_TRUE; } } return EGL_FALSE; } WlEglDisplay *wlEglAcquireDisplay(EGLDisplay dpy) { WlEglDisplay *display = (WlEglDisplay *)dpy; wlExternalApiLock(); if (wlEglIsWlEglDisplay(display)) { ++display->refCount; } else { display = NULL; } wlExternalApiUnlock(); return display; } static void wlEglUnrefDisplay(WlEglDisplay *display) { if (--display->refCount == 0) { wlEglMutexDestroy(&display->mutex); free(display); } } void wlEglReleaseDisplay(WlEglDisplay *display) { wlExternalApiLock(); wlEglUnrefDisplay(display); wlExternalApiUnlock(); } 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 wlEglQueryDisplayAttribHook(EGLDisplay dpy, EGLint name, EGLAttrib *value) { WlEglDisplay *display = wlEglAcquireDisplay(dpy); WlEglPlatformData *data = NULL; EGLBoolean ret = EGL_TRUE; if (!display) { return EGL_FALSE; } pthread_mutex_lock(&display->mutex); data = display->data; if (value == NULL) { wlEglSetError(data, EGL_BAD_PARAMETER); pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return EGL_FALSE; } if (display->initCount == 0) { wlEglSetError(data, EGL_NOT_INITIALIZED); pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return EGL_FALSE; } switch (name) { case EGL_DEVICE_EXT: *value = (EGLAttrib) display->devDpy->eglDevice; break; case EGL_TRACK_REFERENCES_KHR: *value = (EGLAttrib) display->useInitRefCount; break; default: ret = data->egl.queryDisplayAttrib(display->devDpy->eglDisplay, name, value); break; } pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); 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) { pthread_mutex_lock(&display->mutex); res = terminateDisplay(display, EGL_TRUE) && res; if (display->ownNativeDpy) { wl_display_disconnect(display->nativeDpy); } display->devDpy = NULL; pthread_mutex_unlock(&display->mutex); wl_list_remove(&display->link); /* Unref the external display */ wlEglUnrefDisplay(display); } } wlFreeAllInternalDisplays(data); 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 * * For Wayland support via dma-buf, at least the following * extensions must be supported by the underlying driver: * * - EGL_KHR_stream * - EGL_KHR_stream_producer_eglsurface * - EGL_NV_stream_consumer_eglimage * - EGL_MESA_image_dma_buf_export */ const char *exts = pData->egl.queryString(dpy, EGL_EXTENSIONS); if (wlEglFindExtension("EGL_KHR_stream", exts) && wlEglFindExtension("EGL_KHR_stream_producer_eglsurface", exts)) { if (wlEglFindExtension("EGL_KHR_stream_cross_process_fd", exts)) { res = "EGL_WL_bind_wayland_display " "EGL_WL_wayland_eglstream"; } else if (wlEglFindExtension("EGL_NV_stream_consumer_eglimage", exts) && wlEglFindExtension("EGL_MESA_image_dma_buf_export", exts)) { res = "EGL_WL_bind_wayland_display"; } } } break; default: break; } return res; } egl-wayland-1.1.9/src/wayland-eglhandle.c000066400000000000000000000164251411577545400202660ustar00rootroot00000000000000/* * 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; } wl_list_init(&res->deviceDpyList); /* 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); /* From EGL_EXT_device_query, used by the wayland-drm implementation */ GET_PROC(queryDisplayAttrib, eglQueryDisplayAttribEXT); GET_PROC(queryDeviceString, eglQueryDeviceStringEXT); #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); /* EGLImage Stream consumer and dependencies */ GET_PROC(streamImageConsumerConnect, eglStreamImageConsumerConnectNV); GET_PROC(streamAcquireImage, eglStreamAcquireImageNV); GET_PROC(streamReleaseImage, eglStreamReleaseImageNV); GET_PROC(queryStreamConsumerEvent, eglQueryStreamConsumerEventNV); GET_PROC(exportDMABUFImage, eglExportDMABUFImageMESA); GET_PROC(exportDMABUFImageQuery, eglExportDMABUFImageQueryMESA); GET_PROC(createImage, eglCreateImageKHR); GET_PROC(destroyImage, eglDestroyImageKHR); #undef GET_PROC /* Check for required EGL client extensions */ exts = res->egl.queryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); if (exts == NULL) { goto fail; } /* * Note EGL_EXT_platform_device implies support for EGL_EXT_device_base, * which is equivalent to the combination of EGL_EXT_device_query and * EGL_EXT_device_enumeration. The wayland-drm implementation assumes * EGL_EXT_device_query is supported based on this check. */ if (!wlEglFindExtension("EGL_EXT_platform_base", exts) || !wlEglFindExtension("EGL_EXT_platform_device", exts)) { goto fail; } res->supportsDisplayReference = wlEglFindExtension("EGL_KHR_display_reference", exts); /* 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) { WlEglDisplay *display; if (type == EGL_OBJECT_DISPLAY_KHR) { display = wlEglAcquireDisplay(handle); if (display) { handle = (void *)display->devDpy->eglDisplay; wlEglReleaseDisplay(display); } } else if (type == EGL_OBJECT_SURFACE_KHR) { display = wlEglAcquireDisplay(dpy); if (display) { pthread_mutex_lock(&display->mutex); if (wlEglIsWlEglSurfaceForDisplay(display, (WlEglSurface *)handle)) { handle = (void *)(((WlEglSurface *)handle)->ctx.eglSurface); } pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(dpy); } } return handle; } egl-wayland-1.1.9/src/wayland-eglstream-server.c000066400000000000000000000322021411577545400216210ustar00rootroot00000000000000/* * 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-drm.h" #include "wayland-eglswap.h" #include "wayland-eglutils.h" #include "wayland-thread.h" #define MASK(_VAL_) (1 << (_VAL_)) static struct wl_list wlStreamDpyList = WL_LIST_INITIALIZER(&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; wlStream->yInverted = EGL_FALSE; 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; case WL_EGLSTREAM_ATTRIB_Y_INVERTED: /* Y_INVERTED should only be set once */ if (mask & MASK(WL_EGLSTREAM_ATTRIB_Y_INVERTED)) { err = WL_EGLSTREAM_ERROR_BAD_ATTRIBS; goto error_create_stream; } wlStream->yInverted = (EGLBoolean)attr[1]; mask |= MASK(WL_EGLSTREAM_ATTRIB_Y_INVERTED); 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, const char *exts) { struct wl_eglstream_display *wlStreamDpy = 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 = calloc(1, sizeof(*wlStreamDpy)); if (!wlStreamDpy) { return EGL_FALSE; } wlStreamDpy->data = data; wlStreamDpy->wlDisplay = wlDisplay; wlStreamDpy->eglDisplay = eglDisplay; wlStreamDpy->caps_override = 0; #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); /* Failure is not fatal */ wl_drm_display_bind(wlDisplay, wlStreamDpy); wl_list_insert(&wlStreamDpyList, &wlStreamDpy->link); return EGL_TRUE; } void wl_eglstream_display_unbind(struct wl_eglstream_display *wlStreamDpy) { wl_drm_display_unbind(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.9/src/wayland-eglstream.c000066400000000000000000000211011411577545400203110ustar00rootroot00000000000000/* * 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); wlStream->handle = -1; } #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.9/src/wayland-eglsurface.c000066400000000000000000002140301411577545400204530ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, 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 "linux-dmabuf-unstable-v1-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 #include #include #define WL_EGL_WINDOW_DESTROY_CALLBACK_SINCE 3 enum BufferReleaseThreadEvents { BUFFER_RELEASE_THREAD_EVENT_TERMINATE, }; enum BufferReleasePipeEndpoints { BUFFER_RELEASE_PIPE_READ = 0, BUFFER_RELEASE_PIPE_WRITE = 1 }; static WlEglStreamImage * pop_acquired_image(WlEglSurface *surface); static void remove_surface_image(WlEglDisplay *display, WlEglSurface *surface, EGLImageKHR eglImage); EGLBoolean wlEglIsWlEglSurfaceForDisplay(WlEglDisplay *display, WlEglSurface *surface) { WlEglSurface *surf; wl_list_for_each(surf, &display->wlEglSurfaceList, link) { if (surf == surface) { return EGL_TRUE; } } return EGL_FALSE; } EGLBoolean wlEglIsWaylandWindowValid(struct wl_egl_window *window) { struct wl_surface *surface = NULL; if (!window || !wlEglMemoryIsReadable(window, sizeof (*window))) { return EGL_FALSE; } surface = (struct wl_surface *)window->version; if (!wlEglMemoryIsReadable(surface, sizeof (void *))) { surface = window->surface; if (!wlEglMemoryIsReadable(surface, sizeof (void *))) { return EGL_FALSE; } } return wlEglCheckInterfaceType((struct wl_object *)surface, "wl_surface"); } static void wayland_throttleCallback(void *data, struct wl_callback *callback, uint32_t time) { WlEglSurface *surface = (WlEglSurface *)data; (void) time; if (surface->throttleCallback != NULL) { wl_callback_destroy(callback); surface->throttleCallback = NULL; } } static const struct wl_callback_listener throttle_listener = { wayland_throttleCallback }; void wlEglCreateFrameSync(WlEglSurface *surface) { struct wl_surface *wrapper = NULL; assert(surface->wlEventQueue); if (surface->swapInterval > 0) { wrapper = wl_proxy_create_wrapper(surface->wlSurface); wl_proxy_set_queue((struct wl_proxy *)wrapper, surface->wlEventQueue); 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); } } } EGLint wlEglWaitFrameSync(WlEglSurface *surface) { WlEglDisplay *display = surface->wlEglDpy; struct wl_event_queue *queue = surface->wlEventQueue; int ret = 0; assert(queue || surface->throttleCallback == NULL); while (ret != -1 && surface->throttleCallback != NULL) { ret = wl_display_dispatch_queue(display->nativeDpy, queue); } return EGL_SUCCESS; } EGLBoolean wlEglSendDamageEvent(WlEglSurface *surface, struct wl_event_queue *queue) { struct wl_display *wlDpy = surface->wlEglDpy->nativeDpy; if (surface->ctx.wlStreamResource) { /* 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); } else { WlEglStreamImage *image; if (wlEglHandleImageStreamEvents(surface) != EGL_SUCCESS) { return EGL_FALSE; } image = pop_acquired_image(surface); if (image) { surface->ctx.currentBuffer = image->buffer; image->attached = EGL_TRUE; } wl_surface_attach(surface->wlSurface, surface->ctx.currentBuffer, 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 (wl_display_roundtrip_queue(wlDpy, 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 = wl_display_create_queue( display->nativeDpy); 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->devDpy->exts.stream_flush) { data->egl.streamFlush(display->devDpy->eglDisplay, surface->ctx.eglStream); } ok = wlEglSendDamageEvent(surface, queue); 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)); } } } wl_event_queue_destroy(queue); 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) { pthread_join(ctx->damageThreadId, NULL); ctx->damageThreadId = (pthread_t)0; } data->egl.destroySync(display->devDpy->eglDisplay, ctx->damageThreadSync); ctx->damageThreadSync = EGL_NO_SYNC_KHR; } } static void* buffer_release_thread(void *args) { WlEglSurface *surface = (WlEglSurface*)args; WlEglDisplay *display = surface->wlEglDpy; struct wl_display *wlDpy = display->nativeDpy; struct wl_event_queue *queue = surface->wlBufferEventQueue; struct pollfd pfds[2]; const int fd = wl_display_get_fd(wlDpy); int res; uint8_t cmd; while (1) { /* First clear out any previously-read events on the queue */ wl_display_dispatch_queue_pending(wlDpy, queue); /* * Now block until more events are present on the wire, then * read them. Also, watch for messages from the app thread. */ if ((wl_display_prepare_read_queue(wlDpy, queue) < 0)) { if (errno == EAGAIN) { continue; } else { return NULL; } } memset(&pfds, 0, sizeof(pfds)); pfds[0].fd = fd; pfds[0].events = POLLIN; pfds[1].fd = surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_READ]; pfds[1].events = POLLIN; res = poll(&pfds[0], sizeof(pfds) / sizeof(pfds[0]), 1000); if (res <= 0) { wl_display_cancel_read(wlDpy); continue; } if (pfds[1].revents & POLLIN) { if (read(pfds[1].fd, &cmd, sizeof(cmd) != sizeof(cmd))) { /* Reading an event from the app side failed. Bail. */ wl_display_cancel_read(wlDpy); return NULL; } switch (cmd) { default: /* * Unknown command from the app side. Treat it like a * termination request. * * fall through. */ case BUFFER_RELEASE_THREAD_EVENT_TERMINATE: wl_display_cancel_read(wlDpy); return NULL; } } if (pfds[0].revents & POLLIN) { if (wl_display_read_events(wlDpy) < 0) { return NULL; } } else { wl_display_cancel_read(wlDpy); } } return NULL; } static EGLint setup_wl_buffer_release_thread(WlEglSurface *surface) { int ret; if (pipe(surface->bufferReleaseThreadPipe)) { return EGL_BAD_ALLOC; } surface->wlBufferEventQueue = wl_display_create_queue(surface->wlEglDpy->nativeDpy); ret = pthread_create(&surface->bufferReleaseThreadId, NULL, buffer_release_thread, (void*)surface); if (ret != 0) { close(surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_WRITE]); surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_WRITE] = -1; close(surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_READ]); surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_READ] = -1; wl_event_queue_destroy(surface->wlBufferEventQueue); surface->wlBufferEventQueue = NULL; return EGL_BAD_ALLOC; } return EGL_SUCCESS; } static void finish_wl_buffer_release_thread(WlEglSurface *surface) { uint8_t cmd = BUFFER_RELEASE_THREAD_EVENT_TERMINATE; if (surface->wlBufferEventQueue) { if (write(surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_WRITE], &cmd, sizeof(cmd)) != sizeof(cmd)) { /* The thread is not going to terminate gracefully. */ pthread_cancel(surface->bufferReleaseThreadId); } pthread_join(surface->bufferReleaseThreadId, NULL); surface->bufferReleaseThreadId = (pthread_t)0; close(surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_WRITE]); surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_WRITE] = -1; close(surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_READ]); surface->bufferReleaseThreadPipe[BUFFER_RELEASE_PIPE_READ] = -1; wl_event_queue_destroy(surface->wlBufferEventQueue); } } static void destroy_stream_image(WlEglDisplay *display, WlEglSurface *surface, WlEglStreamImage *image) { WlEglPlatformData *data = display->data; EGLDisplay dpy = display->devDpy->eglDisplay; /* Must be called with image->mutex already locked */ assert(image->eglImage != EGL_NO_IMAGE_KHR); data->egl.destroyImage(dpy, image->eglImage); image->eglImage = EGL_NO_IMAGE_KHR; if (surface->ctx.currentBuffer == image->buffer) { surface->ctx.currentBuffer = NULL; } if (image->buffer && !image->attached) { wl_buffer_destroy(image->buffer); image->buffer = NULL; } if (!wl_list_empty(&image->acquiredLink)) { wl_list_remove(&image->acquiredLink); wl_list_init(&image->acquiredLink); } } 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; uint32_t i; finish_wl_eglstream_damage_thread(surface, ctx, 1); ctx->eglSurface = EGL_NO_SURFACE; ctx->eglStream = EGL_NO_STREAM_KHR; ctx->wlStreamResource = NULL; for (i = 0; i < ctx->numStreamImages; i++) { WlEglStreamImage *image = surface->ctx.streamImages[i]; pthread_mutex_lock(&image->mutex); if (image->eglImage != EGL_NO_IMAGE_KHR) { destroy_stream_image(display, surface, image); } pthread_mutex_unlock(&image->mutex); } if (surf != EGL_NO_SURFACE) { data->egl.destroySurface(dpy, surf); } if (surface->ctx.isOffscreen) { return; } if (stream != EGL_NO_STREAM_KHR) { data->egl.destroyStream(dpy, stream); ctx->eglStream = EGL_NO_STREAM_KHR; } if (resource) { 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 && surface->ctx.wlStreamResource) { 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; /* Look for the surface context for the given buffer and destroy it */ 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; } } } 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) { 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 (!display->wlStreamDpy) { return NULL; } 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, surface->wlEventQueue); buffer = wl_eglstream_display_create_stream(wrapper, width, height, handle, type, attribs); wl_proxy_wrapper_destroy(wrapper); /* Done with wrapper */ if (!buffer) { return NULL; } if (wl_buffer_add_listener(buffer, &wl_buffer_listener, surface) == -1) { wl_buffer_destroy(buffer); return NULL; } return buffer; } static EGLint create_surface_stream_fd(WlEglSurface *surface) { 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->devDpy->exts.stream_fifo_synchronous && display->devDpy->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); 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) { 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 (!(wlAttribsData = (intptr_t *)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[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; } } if (!(wlAttribsData = (intptr_t *)wl_array_add(&wlAttribs, 2*sizeof(intptr_t)))) { err = EGL_BAD_ALLOC; goto fail; } /* If Vulkan, default Y_INVERTED to 'true'. Otherwise, assume OpenGL * orientation (image origin at the lower left corner), which aligns with * what a wayland compositor would consider 'non-y-inverted' */ wlAttribsData[0] = WL_EGLSTREAM_ATTRIB_Y_INVERTED; wlAttribsData[1] = (intptr_t)(surface->isSurfaceProducer ? EGL_FALSE : EGL_TRUE); surface->ctx.wlStreamResource = create_wl_eglstream(surface, socket[1], (useInet ? WL_EGLSTREAM_HANDLE_TYPE_INET : WL_EGLSTREAM_HANDLE_TYPE_SOCKET), &wlAttribs); 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 (wl_display_roundtrip_queue(display->nativeDpy, surface->wlEventQueue) < 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]); } wl_array_release(&wlAttribs); 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 void stream_local_buffer_release_callback(void *ptr, struct wl_buffer *buffer) { WlEglStreamImage *image = (WlEglStreamImage*)ptr; /* Safe: image->surface pointer value is const once image is initialized */ WlEglSurface *surface = image->surface; WlEglDisplay *display = surface->wlEglDpy; WlEglPlatformData *data = display->data; (void)buffer; /* In case assert() compiles to nothing */ assert(image->buffer == NULL || image->buffer == buffer); pthread_mutex_lock(&image->mutex); image->attached = EGL_FALSE; if (image->eglImage != EGL_NO_IMAGE_KHR) { data->egl.streamReleaseImage(display->devDpy->eglDisplay, surface->ctx.eglStream, image->eglImage, EGL_NO_SYNC_KHR); } else if (image->buffer) { /* * If the image has been destroyed while the buffer was attached * the buffer destruction was deferred. Clean it up now. */ wl_buffer_destroy(image->buffer); image->buffer = NULL; } pthread_mutex_unlock(&image->mutex); } static const struct wl_buffer_listener stream_local_buffer_listener = { stream_local_buffer_release_callback, }; static EGLint acquire_surface_image(WlEglDisplay *display, WlEglSurface *surface) { WlEglPlatformData *data = display->data; EGLDisplay dpy = display->devDpy->eglDisplay; EGLImageKHR eglImage; WlEglStreamImage *image = NULL; struct zwp_linux_dmabuf_v1 *wrapper = NULL; struct zwp_linux_buffer_params_v1 *params; EGLuint64KHR modifier; int format; int planes; EGLint stride; EGLint offset; uint32_t i; int fd; if (!data->egl.streamAcquireImage(dpy, surface->ctx.eglStream, &eglImage, EGL_NO_SYNC_KHR)) { return EGL_BAD_SURFACE; } for (i = 0; i < surface->ctx.numStreamImages; i++) { if (surface->ctx.streamImages[i]->eglImage == eglImage) { image = surface->ctx.streamImages[i]; break; } } if (!image) { goto fail_release; } pthread_mutex_lock(&image->mutex); if (!image->buffer) { if (!data->egl.exportDMABUFImageQuery(dpy, eglImage, &format, &planes, &modifier)) { goto fail_release; } assert(planes == 1); /* XXX support planar formats */ if (!data->egl.exportDMABUFImage(dpy, eglImage, &fd, &stride, &offset)) { goto fail_release; } wrapper = wl_proxy_create_wrapper(display->wlDmaBuf); wl_proxy_set_queue((struct wl_proxy *)wrapper, surface->wlBufferEventQueue); params = zwp_linux_dmabuf_v1_create_params(wrapper); zwp_linux_buffer_params_v1_add(params, fd, 0, /* XXX support planar formats */ offset, stride, modifier >> 32, modifier & 0xffffffff); image->buffer = zwp_linux_buffer_params_v1_create_immed(params, surface->width, surface->height, format, 0); zwp_linux_buffer_params_v1_destroy(params); wl_proxy_wrapper_destroy(wrapper); /* Done with wrapper */ close(fd); if (!image->buffer) { goto fail_release; } if (wl_buffer_add_listener(image->buffer, &stream_local_buffer_listener, image) == -1) { wl_buffer_destroy(image->buffer); image->buffer = NULL; goto fail_release; } } /* Add image to the end of the acquired images list */ wl_list_insert(surface->ctx.acquiredImages.prev, &image->acquiredLink); pthread_mutex_unlock(&image->mutex); return EGL_SUCCESS; fail_release: /* Release the image back to the stream */ data->egl.streamReleaseImage(dpy, surface->ctx.eglStream, eglImage, EGL_NO_SYNC_KHR); if (image) { /* Release the image lock */ pthread_mutex_unlock(&image->mutex); } return EGL_BAD_SURFACE; } static void remove_surface_image(WlEglDisplay *display, WlEglSurface *surface, EGLImageKHR eglImage) { WlEglStreamImage *image; uint32_t i; EGLBoolean found = EGL_FALSE; for (i = 0; i < surface->ctx.numStreamImages && found == EGL_FALSE; i++) { image = surface->ctx.streamImages[i]; pthread_mutex_lock(&image->mutex); if (image->eglImage == eglImage) { found = EGL_TRUE; destroy_stream_image(display, surface, image); } pthread_mutex_unlock(&image->mutex); } } static WlEglStreamImage * pop_acquired_image(WlEglSurface *surface) { WlEglStreamImage *image; wl_list_for_each(image, &surface->ctx.acquiredImages, acquiredLink) { /* Safe only because the iteration is aborted by returning */ wl_list_remove(&image->acquiredLink); wl_list_init(&image->acquiredLink); return image; } /* List is empty. Return NULL. */ return NULL; } static EGLint add_surface_image(WlEglDisplay *display, WlEglSurface *surface) { WlEglPlatformData *data = display->data; EGLDisplay dpy = display->devDpy->eglDisplay; WlEglStreamImage **newImages; WlEglStreamImage *image; EGLImageKHR eglImage; uint32_t i; for (i = 0; i < surface->ctx.numStreamImages; i++) { image = surface->ctx.streamImages[i]; pthread_mutex_lock(&image->mutex); if ((image->eglImage == EGL_NO_IMAGE_KHR) && !image->buffer) { eglImage = image->eglImage = data->egl.createImage(dpy, EGL_NO_CONTEXT, EGL_STREAM_CONSUMER_IMAGE_NV, (EGLClientBuffer)surface->ctx.eglStream, NULL); pthread_mutex_unlock(&image->mutex); if (eglImage != EGL_NO_IMAGE_KHR) { return EGL_SUCCESS; } else { return EGL_BAD_ALLOC; } } pthread_mutex_unlock(&image->mutex); } newImages = realloc(surface->ctx.streamImages, sizeof(newImages[0]) * (surface->ctx.numStreamImages + 1)); if (!newImages) { return EGL_BAD_ALLOC; } surface->ctx.streamImages = newImages; newImages[i] = calloc(1, sizeof(*newImages[i])); if (!surface->ctx.streamImages[i]) { goto free_image; } newImages[i]->surface = surface; /* * No need to lock the mutex after allocating because numStreamImages is not * incremented until after the image itself is initialized. Also, because * numStreamImages is not incremented until initialization is complete, the * image must be freed if initialization fails beyond this point to avoid * leaks. */ if (!wlEglInitializeMutex(&newImages[i]->mutex)) { goto free_image; } wl_list_init(&newImages[i]->acquiredLink); newImages[i]->eglImage = data->egl.createImage(dpy, EGL_NO_CONTEXT, EGL_STREAM_CONSUMER_IMAGE_NV, (EGLClientBuffer)surface->ctx.eglStream, NULL); if (newImages[i]->eglImage == EGL_NO_IMAGE_KHR) { wlEglMutexDestroy(&newImages[i]->mutex); goto free_image; } surface->ctx.numStreamImages++; return EGL_SUCCESS; free_image: free(newImages[i]); newImages[i] = NULL; return EGL_BAD_ALLOC; } EGLint wlEglHandleImageStreamEvents(WlEglSurface *surface) { WlEglDisplay *display = surface->wlEglDpy; EGLDisplay dpy = display->devDpy->eglDisplay; WlEglPlatformData *data = display->data; EGLAttrib aux; EGLenum event; EGLint err = EGL_SUCCESS; if (surface->ctx.wlStreamResource) { /* Not a local stream */ return err; } while (1) { err = data->egl.queryStreamConsumerEvent(dpy, surface->ctx.eglStream, 0, &event, &aux); if (err == EGL_TRUE) { err = EGL_SUCCESS; } else if (err == EGL_TIMEOUT_EXPIRED) { err = EGL_SUCCESS; break; } else if (err == EGL_FALSE) { /* XXX Pick the right error code */ err = EGL_BAD_SURFACE; break; } else { break; } switch (event) { case EGL_STREAM_IMAGE_AVAILABLE_NV: err = acquire_surface_image(display, surface); break; case EGL_STREAM_IMAGE_ADD_NV: err = add_surface_image(display, surface); break; case EGL_STREAM_IMAGE_REMOVE_NV: remove_surface_image(display, surface, (EGLImageKHR)aux); break; default: assert(!"Unhandled EGLImage stream consumer event"); } } return err; } static EGLint create_surface_stream_local(WlEglSurface *surface) { WlEglDisplay *display = surface->wlEglDpy; WlEglPlatformData *data = display->data; EGLDisplay dpy = display->devDpy->eglDisplay; 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 local streams, so * just enable FIFO_SYNCHRONOUS if the extensions are supported. * Note the use of this mechanism makes the optional sync parameter * passed to eglStreamAcquireImageNV() redundant, so that mechanism is not * used in this library. */ if (display->devDpy->exts.stream_fifo_synchronous && display->devDpy->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(dpy, eglAttribs); if (surface->ctx.eglStream == EGL_NO_STREAM_KHR) { err = data->egl.getError(); goto fail; } /* Now create the local EGLImage consumer */ if (!data->egl.streamImageConsumerConnect(dpy, surface->ctx.eglStream, 0, /* XXX modifier count */ NULL, /* XXX modifier list */ NULL)) { err = data->egl.getError(); goto fail; } wl_list_init(&surface->ctx.acquiredImages); if (!surface->wlBufferEventQueue) { /* * Local stream contexts need a private wayland queue used by a separate * thread that can process buffer release events even the application * thread is blocking in the EGL library for stream frame acquisition * while swapping the producer surface. The thread and queue are owned * by the surface because they need to outlive the context when resizing * the surface while a buffer is still attached, but they are * initialized lazily here to avoid incuring the cost of an extra unused * thread and two pipe file descriptors per surface when they are not * needed. */ if (EGL_SUCCESS != setup_wl_buffer_release_thread(surface)) { goto fail; } } return EGL_SUCCESS; fail: destroy_surface_context(surface, &surface->ctx); return err; } static EGLint create_surface_stream(WlEglSurface *surface) { 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. Local stream + dma-buf * 2. Cross-process unix sockets * 3. Cross-process FD * 4. Cross-process inet sockets */ #ifdef EGL_NV_stream_consumer_eglimage if ((err != EGL_SUCCESS) && display->devDpy->exts.stream_consumer_eglimage && display->devDpy->exts.image_dma_buf_export && display->wlDmaBuf) { err = create_surface_stream_local(surface); } #endif #ifdef EGL_NV_stream_remote if ((err != EGL_SUCCESS) && display->caps.stream_socket && display->devDpy->exts.stream_remote) { err = create_surface_stream_remote(surface, EGL_FALSE); } #endif if ((err != EGL_SUCCESS) && display->caps.stream_fd && display->devDpy->exts.stream_cross_process_fd) { err = create_surface_stream_fd(surface); } #ifdef EGL_NV_stream_remote if ((err != EGL_SUCCESS) && display->caps.stream_inet && display->devDpy->exts.stream_remote) { err = create_surface_stream_remote(surface, EGL_TRUE); } #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; int winWidth = 0; int winHeight = 0; int winDx = 0; int winDy = 0; EGLint synchronous = EGL_FALSE; EGLint err = EGL_SUCCESS; struct wl_array wlAttribs; intptr_t *wlAttribsData; assert(surface->ctx.eglSurface == EGL_NO_SURFACE); if (surface->isSurfaceProducer) { winWidth = window->width; winHeight = window->height; winDx = window->dx; winDy = window->dy; /* Width and height are the first and second attributes respectively */ surface->attribs[1] = winWidth; surface->attribs[3] = winHeight; } else { winWidth = surface->width; winHeight = surface->height; winDx = surface->dx; winDy = surface->dy; } /* First, create the underlying wl_eglstream and EGLStream */ err = create_surface_stream(surface); if (err != EGL_SUCCESS) { goto fail; } /* If the stream has a server component, attach the wl_eglstream so the * compositor connects a consumer to the EGLStream */ if (surface->ctx.wlStreamResource) { 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); wl_array_release(&wlAttribs); } else { wl_eglstream_controller_attach_eglstream_consumer(display->wlStreamCtl, surface->wlSurface, surface->ctx.wlStreamResource); } } else { wl_surface_attach(surface->wlSurface, surface->ctx.wlStreamResource, winDx, winDy); 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 (wl_display_roundtrip_queue(display->nativeDpy, surface->wlEventQueue) < 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->devDpy->exts.stream_fifo_synchronous && display->devDpy->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 = winWidth; surface->height = winHeight; surface->dx = winDx; surface->dy = winDy; window->attached_width = winWidth; window->attached_height = winHeight; } return EGL_SUCCESS; fail: destroy_surface_context(surface, &surface->ctx); return err; } EGLBoolean wlEglInitializeSurfaceExport(WlEglSurface *surface) { WlEglDisplay *display = wlEglAcquireDisplay((WlEglDisplay *)surface->wlEglDpy); if (!display) { return EGL_FALSE; } pthread_mutex_lock(&display->mutex); // Create per surface wayland queue surface->wlEventQueue = wl_display_create_queue(display->nativeDpy); surface->refCount = 1; if (!wlEglInitializeMutex(&surface->mutexLock)) { pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return EGL_FALSE; } if (create_surface_context(surface) != EGL_SUCCESS) { wl_event_queue_destroy(surface->wlEventQueue); pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return EGL_FALSE; } wl_list_insert(&display->wlEglSurfaceList, &surface->link); wl_list_init(&surface->oldCtxList); if (surface->ctx.wlStreamResource) { /* Set client's pendingSwapIntervalUpdate for updating client's * swapinterval */ surface->pendingSwapIntervalUpdate = EGL_TRUE; } pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); 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; pthread_mutex_lock(&surface->mutexLock); /* 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.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) { pData->egl.makeCurrent(display, surface, surface, pData->egl.getCurrentContext()); if (surface->ctx.wlStreamResource) { /* Set client's pendingSwapIntervalUpdate for updating client's * swapinterval */ surface->pendingSwapIntervalUpdate = EGL_TRUE; } } } pthread_mutex_unlock(&surface->mutexLock); } 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; } EGLBoolean wlEglSurfaceRef(WlEglDisplay *display, WlEglSurface *surface) { if (!wlEglIsWlEglSurfaceForDisplay(display, surface) || surface->wlEglDpy->initCount == 0) { return EGL_FALSE; } surface->refCount++; return EGL_TRUE; } void wlEglSurfaceUnref(WlEglSurface *surface) { uint32_t i; surface->refCount--; if (surface->refCount > 0) { return; } wlEglMutexDestroy(&surface->mutexLock); for (i = 0; i < surface->ctx.numStreamImages; i++) { wlEglMutexDestroy(&surface->ctx.streamImages[i]->mutex); free(surface->ctx.streamImages[i]); } free(surface->ctx.streamImages); free(surface); return; } static EGLBoolean wlEglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface) { WlEglDisplay *display = (WlEglDisplay*)dpy; WlEglSurface *surface = (WlEglSurface*)eglSurface; WlEglSurfaceCtx *ctx = NULL; WlEglSurfaceCtx *next = NULL; WlEglStreamImage *image; uint32_t i; if (!wlEglIsWlEglSurfaceForDisplay(display, surface) || display != surface->wlEglDpy) { return EGL_FALSE; } wl_list_remove(&surface->link); surface->isDestroyed = EGL_TRUE; // Acquire WlEglSurface lock. pthread_mutex_lock(&surface->mutexLock); destroy_surface_context(surface, &surface->ctx); if (!surface->ctx.isOffscreen) { // 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->wlEglWin->driver_private = NULL; surface->wlEglWin->resize_callback = NULL; if (surface->wlEglWinVer >= WL_EGL_WINDOW_DESTROY_CALLBACK_SINCE) { surface->wlEglWin->destroy_window_callback = NULL; } } } if (surface->throttleCallback != NULL) { wl_callback_destroy(surface->throttleCallback); surface->throttleCallback = NULL; } if (surface->wlEventQueue != NULL) { wl_event_queue_destroy(surface->wlEventQueue); surface->wlEventQueue = NULL; } if (!surface->ctx.isOffscreen) { 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); } for (i = 0; i < surface->ctx.numStreamImages; i++) { image = surface->ctx.streamImages[i]; pthread_mutex_lock(&image->mutex); /* * Destroy any attached buffers to ensure no further buffer release * events are delivered after the buffer release queue and thread are * torn down. */ if (image->buffer) { assert(image->attached); wl_buffer_destroy(image->buffer); image->buffer = NULL; image->attached = EGL_FALSE; } pthread_mutex_unlock(&image->mutex); } finish_wl_buffer_release_thread(surface); // Release WlEglSurface lock. pthread_mutex_unlock(&surface->mutexLock); wlEglSurfaceUnref(eglSurface); return EGL_TRUE; } static void destroy_callback(void *data) { WlEglSurface *surface = (WlEglSurface*)data; WlEglDisplay *display = surface->wlEglDpy; pthread_mutex_lock(&display->mutex); if (!surface || surface->wlEglDpy->initCount == 0) { pthread_mutex_unlock(&display->mutex); return; } wlEglDestroySurface((EGLDisplay)surface->wlEglDpy, (EGLSurface)surface); pthread_mutex_unlock(&display->mutex); } 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 */ *version = window->version; *surface = window->surface; if (wlEglMemoryIsReadable((void *)window->version, sizeof (void *))) { *version = 0; *surface = (struct wl_surface *)(window->version); } } EGLSurface wlEglCreatePlatformWindowSurfaceHook(EGLDisplay dpy, EGLConfig config, void *nativeWin, const EGLAttrib *attribs) { WlEglDisplay *display = wlEglAcquireDisplay(dpy); WlEglPlatformData *data = NULL; WlEglSurface *surface = NULL; struct wl_egl_window *window = (struct wl_egl_window *)nativeWin; EGLBoolean res = EGL_FALSE; EGLint err = EGL_SUCCESS; EGLint surfType; if (!display) { return EGL_NO_SURFACE; } pthread_mutex_lock(&display->mutex); data = display->data; if (display->initCount == 0) { err = EGL_NOT_INITIALIZED; 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; } res = data->egl.getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfType); if (!res || !(surfType & EGL_STREAM_BIT_KHR)) { err = EGL_BAD_CONFIG; goto fail; } if (!display->devDpy->exts.stream || (!display->devDpy->exts.stream_cross_process_fd && !display->devDpy->exts.stream_remote) || !display->devDpy->exts.stream_producer_eglsurface) { err = EGL_BAD_ALLOC; goto fail; } surface = calloc(1, sizeof(*surface)); if (!surface) { err = EGL_BAD_ALLOC; goto fail; } if (!wlEglInitializeMutex(&surface->mutexLock)) { 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; surface->refCount = 1; surface->isDestroyed = EGL_FALSE; // FIFO_LENGTH == 1 to set FIFO mode, FIFO_LENGTH == 0 to set MAILBOX mode surface->fifoLength = (display->devDpy->exts.stream_fifo_synchronous && display->devDpy->exts.stream_sync) ? 1 : 0; // Create per surface wayland queue surface->wlEventQueue = wl_display_create_queue(display->nativeDpy); getWlEglWindowVersionAndSurface(window, &surface->wlEglWinVer, &surface->wlSurface); wl_list_init(&surface->oldCtxList); 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 if (surface->ctx.wlStreamResource) { /* Set client's pendingSwapIntervalUpdate for updating client's * swapinterval */ surface->pendingSwapIntervalUpdate = EGL_TRUE; } window->driver_private = surface; window->resize_callback = resize_callback; if (surface->wlEglWinVer >= WL_EGL_WINDOW_DESTROY_CALLBACK_SINCE) { window->destroy_window_callback = destroy_callback; } wl_list_insert(&display->wlEglSurfaceList, &surface->link); pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return surface; fail: if (surface) { wlEglDestroySurface(display, surface); } pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); 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 = wlEglAcquireDisplay(dpy); WlEglPlatformData *data = NULL; WlEglSurface *surface = NULL; EGLSurface surf = EGL_NO_SURFACE; EGLint err = EGL_SUCCESS; if (!display) { return EGL_NO_SURFACE; } pthread_mutex_lock(&display->mutex); data = display->data; /* 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; } if (!wlEglInitializeMutex(&surface->mutexLock)) { err = EGL_BAD_ALLOC; goto fail; } surface->wlEglDpy = display; surface->eglConfig = config; surface->ctx.eglSurface = surf; surface->ctx.isOffscreen = EGL_TRUE; surface->refCount = 1; surface->isDestroyed = EGL_FALSE; wl_list_init(&surface->oldCtxList); wl_list_insert(&display->wlEglSurfaceList, &surface->link); pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return surface; fail: pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); if (err != EGL_SUCCESS) { wlEglSetError(data, err); } return EGL_NO_SURFACE; } EGLSurface wlEglCreateStreamProducerSurfaceHook(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attribs) { WlEglDisplay *display = wlEglAcquireDisplay(dpy); WlEglPlatformData *data = NULL; WlEglSurface *surface = NULL; EGLSurface surf = EGL_NO_SURFACE; EGLint err = EGL_SUCCESS; if (!display) { return EGL_NO_SURFACE; } pthread_mutex_lock(&display->mutex); data = display->data; /* 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; } if (!wlEglInitializeMutex(&surface->mutexLock)) { err = EGL_BAD_ALLOC; goto fail; } surface->wlEglDpy = display; surface->eglConfig = config; surface->ctx.eglSurface = surf; surface->ctx.isOffscreen = EGL_TRUE; surface->refCount = 1; surface->isDestroyed = EGL_FALSE; wl_list_init(&surface->oldCtxList); wl_list_insert(&display->wlEglSurfaceList, &surface->link); pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return surface; fail: pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); if (err != EGL_SUCCESS) { wlEglSetError(data, err); } return EGL_NO_SURFACE; } EGLBoolean wlEglDestroySurfaceHook(EGLDisplay dpy, EGLSurface eglSurface) { WlEglDisplay *display = wlEglAcquireDisplay(dpy); EGLint ret = EGL_FALSE; if (!display) { return EGL_FALSE; } pthread_mutex_lock(&display->mutex); if (display->initCount == 0) { wlEglSetError(display->data, EGL_NOT_INITIALIZED); goto done; } ret = wlEglDestroySurface(dpy, eglSurface); if (!ret) { wlEglSetError(display->data, EGL_BAD_SURFACE); } done: pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return ret; } EGLBoolean wlEglDestroyAllSurfaces(WlEglDisplay *display) { WlEglSurface *surface, *next; EGLBoolean res = EGL_TRUE; wl_list_for_each_safe(surface, next, &display->wlEglSurfaceList, link) { if (surface->wlEglDpy == display) { res = wlEglDestroySurface(display, surface) && 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. Set to * stream's default value.*/ *value = (int)wlStream->yInverted; } res = EGL_TRUE; goto done; } done: wlExternalApiUnlock(); return res; } egl-wayland-1.1.9/src/wayland-eglswap.c000066400000000000000000000232151411577545400200000ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, 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 #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 = wlEglAcquireDisplay(eglDisplay); WlEglPlatformData *data = NULL; WlEglSurface *surface = NULL; EGLStreamKHR eglStream = EGL_NO_STREAM_KHR; EGLBoolean isOffscreen = EGL_FALSE; EGLBoolean res; EGLint err; if (!display) { return EGL_FALSE; } pthread_mutex_lock(&display->mutex); data = display->data; if (display->initCount == 0) { err = EGL_NOT_INITIALIZED; goto fail; } if (!wlEglSurfaceRef(display, eglSurface)) { err = EGL_BAD_SURFACE; goto fail; } surface = eglSurface; if (surface->pendingSwapIntervalUpdate == EGL_TRUE) { /* Send request from client to override swapinterval value based on * server's swapinterval for overlay compositing */ wl_eglstream_display_swap_interval(display->wlStreamDpy, surface->ctx.wlStreamResource, surface->swapInterval); /* For receiving any event in case of override */ if (wl_display_roundtrip_queue(display->nativeDpy, display->wlEventQueue) < 0) { err = EGL_BAD_ALLOC; goto fail; } surface->pendingSwapIntervalUpdate = EGL_FALSE; } pthread_mutex_unlock(&display->mutex); // Acquire wlEglSurface lock. pthread_mutex_lock(&surface->mutexLock); if (surface->isDestroyed) { err = EGL_BAD_SURFACE; goto fail_locked; } isOffscreen = surface->ctx.isOffscreen; if (!isOffscreen) { if (!wlEglIsWaylandWindowValid(surface->wlEglWin)) { err = EGL_BAD_NATIVE_WINDOW; goto fail_locked; } wlEglWaitFrameSync(surface); } /* 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. */ if (rects) { res = data->egl.swapBuffersWithDamage(eglDisplay, eglSurface, rects, n_rects); } else { res = data->egl.swapBuffers(eglDisplay, eglSurface); } if (isOffscreen) { goto done; } if (display->devDpy->exts.stream_flush) { data->egl.streamFlush(eglDisplay, eglStream); } if (res) { if (surface->ctx.useDamageThread) { surface->ctx.framesProduced++; } else { res = wlEglSendDamageEvent(surface, surface->wlEventQueue); } } wlEglCreateFrameSync(surface); done: // Release wlEglSurface lock. pthread_mutex_unlock(&surface->mutexLock); /* reacquire display lock */ pthread_mutex_lock(&display->mutex); wlEglSurfaceUnref(surface); pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return res; fail_locked: pthread_mutex_unlock(&surface->mutexLock); /* reacquire display lock */ pthread_mutex_lock(&display->mutex); fail: if (surface != NULL) { wlEglSurfaceUnref(surface); } pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); wlEglSetError(data, err); return EGL_FALSE; } EGLBoolean wlEglSwapIntervalHook(EGLDisplay eglDisplay, EGLint interval) { WlEglDisplay *display = wlEglAcquireDisplay(eglDisplay); WlEglPlatformData *data = NULL; WlEglSurface *surface = NULL; EGLBoolean ret = EGL_TRUE; EGLint state; if (!display) { return EGL_FALSE; } pthread_mutex_lock(&display->mutex); data = display->data; if (display->initCount == 0) { wlEglSetError(data, EGL_NOT_INITIALIZED); ret = EGL_FALSE; goto done; } /* Save the internal EGLDisplay handle, as it's needed by the actual * eglSwapInterval() call */ eglDisplay = display->devDpy->eglDisplay; pthread_mutex_unlock(&display->mutex); if (!(data->egl.swapInterval(eglDisplay, interval))) { wlEglReleaseDisplay(display); return EGL_FALSE; } surface = (WlEglSurface *)data->egl.getCurrentSurface(EGL_DRAW); pthread_mutex_lock(&display->mutex); /* Check this is a valid wayland EGL surface with a server-side stream * resource before sending the swap interval value to the consumer */ if (display->initCount == 0 || !wlEglIsWlEglSurfaceForDisplay(display, 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; } /* Cache interval value so we can reset it upon surface reattach */ surface->swapInterval = interval; /* Set client's pendingSwapIntervalUpdate for updating client's * swapinterval */ surface->pendingSwapIntervalUpdate = EGL_TRUE; done: pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return ret; } EGLBoolean wlEglPrePresentExport(WlEglSurface *surface) { WlEglDisplay *display = wlEglAcquireDisplay((WlEglDisplay *)surface->wlEglDpy); if (!display) { return EGL_FALSE; } pthread_mutex_lock(&display->mutex); if (surface->pendingSwapIntervalUpdate == EGL_TRUE) { /* Send request from client to override swapinterval value based on * server's swapinterval for overlay compositing */ wl_eglstream_display_swap_interval(display->wlStreamDpy, surface->ctx.wlStreamResource, surface->swapInterval); /* For receiving any event in case of override */ if (wl_display_roundtrip_queue(display->nativeDpy, display->wlEventQueue) < 0) { pthread_mutex_unlock(&display->mutex); wlEglReleaseDisplay(display); return EGL_FALSE; } surface->pendingSwapIntervalUpdate = EGL_FALSE; } pthread_mutex_unlock(&display->mutex); // Acquire wlEglSurface lock. pthread_mutex_lock(&surface->mutexLock); wlEglWaitFrameSync(surface); // Release wlEglSurface lock. pthread_mutex_unlock(&surface->mutexLock); wlEglReleaseDisplay(display); return EGL_TRUE; } EGLBoolean wlEglPostPresentExport(WlEglSurface *surface) { WlEglDisplay *display = wlEglAcquireDisplay((WlEglDisplay *)surface->wlEglDpy); WlEglPlatformData *data = NULL; EGLBoolean res = EGL_TRUE; if (!display) { return EGL_FALSE; } data = display->data; // Acquire wlEglSurface lock. pthread_mutex_lock(&surface->mutexLock); if (display->devDpy->exts.stream_flush) { data->egl.streamFlush((EGLDisplay) display, surface->ctx.eglStream); } if (surface->ctx.useDamageThread) { surface->ctx.framesProduced++; } else { res = wlEglSendDamageEvent(surface, surface->wlEventQueue); } wlEglCreateFrameSync(surface); // Release wlEglSurface lock. pthread_mutex_unlock(&surface->mutexLock); wlEglReleaseDisplay(display); 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.9/src/wayland-eglutils.c000066400000000000000000000071161411577545400201700ustar00rootroot00000000000000/* * 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 #include #include #include 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; } EGLBoolean wlEglMemoryIsReadable(const void *p, size_t len) { int fds[2], result = -1; if (pipe(fds) == -1) { return EGL_FALSE; } if (fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1) { goto done; } /* write will fail with EFAULT if the provided buffer is outside * our accessible address space. */ result = write(fds[1], p, len); assert(result != -1 || errno == EFAULT); done: close(fds[0]); close(fds[1]); return result != -1; } EGLBoolean wlEglCheckInterfaceType(struct wl_object *obj, const char *ifname) { /* The first member of a wl_object is a pointer to its wl_interface, */ struct wl_interface *interface = *(void **)obj; /* Check if the memory for the wl_interface struct, and the * interface name, are safe to read. */ int len = strlen(ifname); if (!wlEglMemoryIsReadable(interface, sizeof (*interface)) || !wlEglMemoryIsReadable(interface->name, len + 1)) { return EGL_FALSE; } return !strcmp(interface->name, ifname); } 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.9/src/wayland-external-exports.c000066400000000000000000000115201411577545400216560ustar00rootroot00000000000000/* * 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 }, { "eglQueryDisplayAttribEXT", wlEglQueryDisplayAttribHook }, { "eglQueryDisplayAttribKHR", wlEglQueryDisplayAttribHook }, { "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.9/src/wayland-thread.c000066400000000000000000000067431411577545400176140ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, 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 #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 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; } bool wlEglInitializeMutex(pthread_mutex_t *mutex) { pthread_mutexattr_t attr; bool ret = true; if (pthread_mutexattr_init(&attr)) { return false; } if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) { ret = false; goto done; } if (pthread_mutex_init(mutex, &attr)) { ret = false; goto done; } done: pthread_mutexattr_destroy(&attr); return ret; } void wlEglMutexDestroy(pthread_mutex_t *mutex) { pthread_mutex_destroy(mutex); } egl-wayland-1.1.9/wayland-drm/000077500000000000000000000000001411577545400161625ustar00rootroot00000000000000egl-wayland-1.1.9/wayland-drm/meson.build000066400000000000000000000015061411577545400203260ustar00rootroot00000000000000foreach output_type: ['server-header', 'public-code'] if output_type == 'server-header' output_file = 'wayland-drm-server-protocol.h' else output_file = 'wayland-drm-protocol.c' 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: 'wayland-drm.xml', output: output_file, ) set_variable(var_name, target) endforeach install_data( 'wayland-drm.xml', install_dir : join_paths(get_option('datadir'), meson.project_name()) ) egl-wayland-1.1.9/wayland-drm/wayland-drm.xml000066400000000000000000000174471411577545400211400ustar00rootroot00000000000000 Copyright © 2008-2011 Kristian Høgsberg Copyright © 2010-2011 Intel Corporation Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that\n the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the copyright holders not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. The copyright holders make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Bitmask of capabilities. egl-wayland-1.1.9/wayland-egl/000077500000000000000000000000001411577545400161475ustar00rootroot00000000000000egl-wayland-1.1.9/wayland-egl/wayland-egl-ext.h000066400000000000000000000112471411577545400213270ustar00rootroot00000000000000/* * 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_bind_wayland_display #define EGL_WL_bind_wayland_display 1 #define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC #define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC #define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC struct wl_display; struct wl_resource; #define EGL_WAYLAND_BUFFER_WL 0x31D5 #define EGL_WAYLAND_PLANE_WL 0x31D6 #define EGL_TEXTURE_Y_U_V_WL 0x31D7 #define EGL_TEXTURE_Y_UV_WL 0x31D8 #define EGL_TEXTURE_Y_XUXV_WL 0x31D9 #define EGL_TEXTURE_EXTERNAL_WL 0x31DA #define EGL_WAYLAND_Y_INVERTED_WL 0x31DB typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWLPROC) (EGLDisplay dpy, struct wl_display *display); typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWLPROC) (EGLDisplay dpy, struct wl_display *display); typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWLPROC) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value); #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL (EGLDisplay dpy, struct wl_display *display); EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL (EGLDisplay dpy, struct wl_display *display); EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value); #endif #endif /* EGL_WL_bind_wayland_display */ #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.9/wayland-eglstream-protocols.pc.in000066400000000000000000000003111411577545400223310ustar00rootroot00000000000000prefix=@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.9/wayland-eglstream.pc.in000066400000000000000000000006171411577545400203200ustar00rootroot00000000000000prefix=@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.9/wayland-eglstream/000077500000000000000000000000001411577545400173635ustar00rootroot00000000000000egl-wayland-1.1.9/wayland-eglstream/.gitignore000066400000000000000000000001141411577545400213470ustar00rootroot00000000000000# All source files in this directory are autogenerated, ignore them *.c *.h egl-wayland-1.1.9/wayland-eglstream/meson.build000066400000000000000000000024311411577545400215250ustar00rootroot00000000000000generated_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.9/wayland-eglstream/wayland-eglstream-controller.xml000066400000000000000000000110361411577545400257070ustar00rootroot00000000000000 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.9/wayland-eglstream/wayland-eglstream.xml000066400000000000000000000213711411577545400235310ustar00rootroot00000000000000 Copyright (c) 2014-2019, 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. - y_inverted: The given attribute encodes the default value for a stream's image inversion relative to wayland protocol convention. Vulkan apps will be set to 'true', while OpenGL apps will be set to 'false'. NOTE: EGL_NV_stream_origin is the authorative source of truth regarding a stream's frame orientation and should be queried for an accurate value. The given attribute is a 'best guess' fallback mechanism which should only be used when a query to EGL_NV_stream_origin fails. 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.