diff --git a/cmake/Modules/FindEGL.cmake b/cmake/Modules/FindEGL.cmake new file mode 100644 index 00000000000000..ee27cc906b6d0f --- /dev/null +++ b/cmake/Modules/FindEGL.cmake @@ -0,0 +1,53 @@ +# - Try to Find EGL +# Once done, this will define +# +# EGL_FOUND - system has EGL installed. +# EGL_INCLUDE_DIRS - directories which contain the EGL headers. +# EGL_LIBRARIES - libraries required to link against EGL. +# EGL_DEFINITIONS - Compiler switches required for using EGL. +# +# Copyright (C) 2012 Intel Corporation. All rights reserved. +# 2020 Georges Basile Stavracas Neto +# +# 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. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``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 COPYRIGHT HOLDER OR ITS +# CONTRIBUTORS 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. + + +find_package(PkgConfig) + +pkg_check_modules(PC_EGL egl) + +if (PC_EGL_FOUND) + set(EGL_DEFINITIONS ${PC_EGL_CFLAGS_OTHER}) +endif () + +find_path(EGL_INCLUDE_DIRS NAMES EGL/egl.h + HINTS ${PC_EGL_INCLUDE_DIR} ${PC_EGL_INCLUDE_DIRS} +) + +find_library(EGL_LIBRARIES NAMES egl EGL + HINTS ${PC_EGL_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(EGL DEFAULT_MSG EGL_INCLUDE_DIRS EGL_LIBRARIES) + +mark_as_advanced(EGL_INCLUDE_DIRS EGL_LIBRARIES) diff --git a/deps/glad/CMakeLists.txt b/deps/glad/CMakeLists.txt index 17ccb9a987425e..83f4efac554a2f 100644 --- a/deps/glad/CMakeLists.txt +++ b/deps/glad/CMakeLists.txt @@ -3,7 +3,8 @@ project(glad) find_package(OpenGL) if(NOT WIN32 AND NOT APPLE) - find_package(X11) + find_package(X11 REQUIRED) + find_package(EGL REQUIRED) endif() set(glad_SOURCES @@ -19,7 +20,9 @@ if(WIN32) obsglad.rc) elseif(NOT APPLE) set(glad_PLATFORM_SOURCES + src/glad_egl.c src/glad_glx.c + include/glad/glad_egl.h include/glad/glad_glx.h) endif() @@ -28,7 +31,9 @@ set(glad_include_dirs if (UNIX AND NOT APPLE) list (APPEND glad_include_dirs - PRIVATE ${X11_X11_INCLUDE_PATH}) + PRIVATE + ${X11_X11_INCLUDE_PATH} + ${EGL_INCLUDE_DIRS}) endif() add_library(glad SHARED @@ -53,7 +58,9 @@ endif() if(NOT WIN32 AND NOT APPLE) set(glad_PLATFORM_DEPS - ${X11_X11_LIB}) + ${X11_X11_LIB} + ${EGL_LIBRARIES}) + # only link to libdl on linux if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(glad_PLATFORM_DEPS diff --git a/deps/glad/include/glad/glad_egl.h b/deps/glad/include/glad/glad_egl.h new file mode 100644 index 00000000000000..ac07814e51486a --- /dev/null +++ b/deps/glad/include/glad/glad_egl.h @@ -0,0 +1,385 @@ +/* + + EGL loader generated by glad 0.1.33 on Thu Aug 27 19:18:06 2020. + + Language/Generator: C/C++ + Specification: egl + APIs: egl=1.5 + Profile: - + Extensions: + EGL_EXT_platform_wayland, + EGL_EXT_platform_x11, + EGL_KHR_create_context, + EGL_KHR_create_context_no_error, + EGL_KHR_platform_wayland, + EGL_KHR_platform_x11 + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --api="egl=1.5" --generator="c" --spec="egl" --extensions="EGL_EXT_platform_wayland,EGL_EXT_platform_x11,EGL_KHR_create_context,EGL_KHR_create_context_no_error,EGL_KHR_platform_wayland,EGL_KHR_platform_x11" + Online: + https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5&extensions=EGL_EXT_platform_wayland&extensions=EGL_EXT_platform_x11&extensions=EGL_KHR_create_context&extensions=EGL_KHR_create_context_no_error&extensions=EGL_KHR_platform_wayland&extensions=EGL_KHR_platform_x11 +*/ + + +#ifndef __glad_egl_h_ + +#ifdef __egl_h_ +#error EGL header already included, remove this include, glad already provides it +#endif + +#define __glad_egl_h_ +#define __egl_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define APIENTRY __stdcall +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (* GLADloadproc)(const char *name); + +#define GLAD_GLAPI_EXPORT + +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif + +GLAPI int gladLoadEGL(void); +GLAPI int gladLoadEGLLoader(GLADloadproc); + +#include +#include +struct AHardwareBuffer; +struct wl_buffer; +struct wl_display; +struct wl_resource; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef intptr_t EGLAttribKHR; +typedef intptr_t EGLAttrib; +typedef void *EGLClientBuffer; +typedef void *EGLConfig; +typedef void *EGLContext; +typedef void *EGLDeviceEXT; +typedef void *EGLDisplay; +typedef void *EGLImage; +typedef void *EGLImageKHR; +typedef void *EGLLabelKHR; +typedef void *EGLObjectKHR; +typedef void *EGLOutputLayerEXT; +typedef void *EGLOutputPortEXT; +typedef void *EGLStreamKHR; +typedef void *EGLSurface; +typedef void *EGLSync; +typedef void *EGLSyncKHR; +typedef void *EGLSyncNV; +typedef void (*__eglMustCastToProperFunctionPointerType)(void); +typedef khronos_utime_nanoseconds_t EGLTimeKHR; +typedef khronos_utime_nanoseconds_t EGLTime; +typedef khronos_utime_nanoseconds_t EGLTimeNV; +typedef khronos_utime_nanoseconds_t EGLuint64NV; +typedef khronos_uint64_t EGLuint64KHR; +typedef khronos_stime_nanoseconds_t EGLnsecsANDROID; +typedef int EGLNativeFileDescriptorKHR; +typedef khronos_ssize_t EGLsizeiANDROID; +typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize); +typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize); +struct EGLClientPixmapHI { + void *pData; + EGLint iWidth; + EGLint iHeight; + EGLint iStride; +}; +typedef void (APIENTRY *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message); +#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC +#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC +#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC +#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300A +#define EGL_BAD_NATIVE_WINDOW 0x300B +#define EGL_BAD_PARAMETER 0x300C +#define EGL_BAD_SURFACE 0x300D +#define EGL_BLUE_SIZE 0x3022 +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_CONFIG_CAVEAT 0x3027 +#define EGL_CONFIG_ID 0x3028 +#define EGL_CORE_NATIVE_ENGINE 0x305B +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_DONT_CARE EGL_CAST(EGLint,-1) +#define EGL_DRAW 0x3059 +#define EGL_EXTENSIONS 0x3055 +#define EGL_FALSE 0 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_HEIGHT 0x3056 +#define EGL_LARGEST_PBUFFER 0x3058 +#define EGL_LEVEL 0x3029 +#define EGL_MAX_PBUFFER_HEIGHT 0x302A +#define EGL_MAX_PBUFFER_PIXELS 0x302B +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_NATIVE_RENDERABLE 0x302D +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NATIVE_VISUAL_TYPE 0x302F +#define EGL_NONE 0x3038 +#define EGL_NON_CONFORMANT_CONFIG 0x3051 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0) +#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0) +#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0) +#define EGL_PBUFFER_BIT 0x0001 +#define EGL_PIXMAP_BIT 0x0002 +#define EGL_READ 0x305A +#define EGL_RED_SIZE 0x3024 +#define EGL_SAMPLES 0x3031 +#define EGL_SAMPLE_BUFFERS 0x3032 +#define EGL_SLOW_CONFIG 0x3050 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_SUCCESS 0x3000 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define EGL_TRANSPARENT_RED_VALUE 0x3037 +#define EGL_TRANSPARENT_RGB 0x3052 +#define EGL_TRANSPARENT_TYPE 0x3034 +#define EGL_TRUE 1 +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_WIDTH 0x3057 +#define EGL_WINDOW_BIT 0x0004 +#define EGL_BACK_BUFFER 0x3084 +#define EGL_BIND_TO_TEXTURE_RGB 0x3039 +#define EGL_BIND_TO_TEXTURE_RGBA 0x303A +#define EGL_CONTEXT_LOST 0x300E +#define EGL_MIN_SWAP_INTERVAL 0x303B +#define EGL_MAX_SWAP_INTERVAL 0x303C +#define EGL_MIPMAP_TEXTURE 0x3082 +#define EGL_MIPMAP_LEVEL 0x3083 +#define EGL_NO_TEXTURE 0x305C +#define EGL_TEXTURE_2D 0x305F +#define EGL_TEXTURE_FORMAT 0x3080 +#define EGL_TEXTURE_RGB 0x305D +#define EGL_TEXTURE_RGBA 0x305E +#define EGL_TEXTURE_TARGET 0x3081 +#define EGL_ALPHA_FORMAT 0x3088 +#define EGL_ALPHA_FORMAT_NONPRE 0x308B +#define EGL_ALPHA_FORMAT_PRE 0x308C +#define EGL_ALPHA_MASK_SIZE 0x303E +#define EGL_BUFFER_PRESERVED 0x3094 +#define EGL_BUFFER_DESTROYED 0x3095 +#define EGL_CLIENT_APIS 0x308D +#define EGL_COLORSPACE 0x3087 +#define EGL_COLORSPACE_sRGB 0x3089 +#define EGL_COLORSPACE_LINEAR 0x308A +#define EGL_COLOR_BUFFER_TYPE 0x303F +#define EGL_CONTEXT_CLIENT_TYPE 0x3097 +#define EGL_DISPLAY_SCALING 10000 +#define EGL_HORIZONTAL_RESOLUTION 0x3090 +#define EGL_LUMINANCE_BUFFER 0x308F +#define EGL_LUMINANCE_SIZE 0x303D +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENVG_BIT 0x0002 +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_OPENVG_API 0x30A1 +#define EGL_OPENVG_IMAGE 0x3096 +#define EGL_PIXEL_ASPECT_RATIO 0x3092 +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_RENDER_BUFFER 0x3086 +#define EGL_RGB_BUFFER 0x308E +#define EGL_SINGLE_BUFFER 0x3085 +#define EGL_SWAP_BEHAVIOR 0x3093 +#define EGL_UNKNOWN EGL_CAST(EGLint,-1) +#define EGL_VERTICAL_RESOLUTION 0x3091 +#define EGL_CONFORMANT 0x3042 +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 +#define EGL_MATCH_NATIVE_PIXMAP 0x3041 +#define EGL_OPENGL_ES2_BIT 0x0004 +#define EGL_VG_ALPHA_FORMAT 0x3088 +#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B +#define EGL_VG_ALPHA_FORMAT_PRE 0x308C +#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 +#define EGL_VG_COLORSPACE 0x3087 +#define EGL_VG_COLORSPACE_sRGB 0x3089 +#define EGL_VG_COLORSPACE_LINEAR 0x308A +#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 +#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0) +#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 +#define EGL_MULTISAMPLE_RESOLVE 0x3099 +#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A +#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B +#define EGL_OPENGL_API 0x30A2 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 +#define EGL_CONTEXT_MAJOR_VERSION 0x3098 +#define EGL_CONTEXT_MINOR_VERSION 0x30FB +#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD +#define EGL_NO_RESET_NOTIFICATION 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0 +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2 +#define EGL_OPENGL_ES3_BIT 0x00000040 +#define EGL_CL_EVENT_HANDLE 0x309C +#define EGL_SYNC_CL_EVENT 0x30FE +#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0 +#define EGL_SYNC_TYPE 0x30F7 +#define EGL_SYNC_STATUS 0x30F1 +#define EGL_SYNC_CONDITION 0x30F8 +#define EGL_SIGNALED 0x30F2 +#define EGL_UNSIGNALED 0x30F3 +#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001 +#define EGL_FOREVER 0xFFFFFFFFFFFFFFFF +#define EGL_TIMEOUT_EXPIRED 0x30F5 +#define EGL_CONDITION_SATISFIED 0x30F6 +#define EGL_NO_SYNC EGL_CAST(EGLSync,0) +#define EGL_SYNC_FENCE 0x30F9 +#define EGL_GL_COLORSPACE 0x309D +#define EGL_GL_COLORSPACE_SRGB 0x3089 +#define EGL_GL_COLORSPACE_LINEAR 0x308A +#define EGL_GL_RENDERBUFFER 0x30B9 +#define EGL_GL_TEXTURE_2D 0x30B1 +#define EGL_GL_TEXTURE_LEVEL 0x30BC +#define EGL_GL_TEXTURE_3D 0x30B2 +#define EGL_GL_TEXTURE_ZOFFSET 0x30BD +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8 +#define EGL_IMAGE_PRESERVED 0x30D2 +#define EGL_NO_IMAGE EGL_CAST(EGLImage,0) +EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); +EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); +EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); +EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); +EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list); +EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); +EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx); +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface); +EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); +EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); +EGLDisplay eglGetCurrentDisplay(void); +EGLSurface eglGetCurrentSurface(EGLint readdraw); +EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id); +EGLint eglGetError(void); +__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname); +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); +const char *eglQueryString(EGLDisplay dpy, EGLint name); +EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); +EGLBoolean eglTerminate(EGLDisplay dpy); +EGLBoolean eglWaitGL(void); +EGLBoolean eglWaitNative(EGLint engine); +EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); +EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval); +EGLBoolean eglBindAPI(EGLenum api); +EGLenum eglQueryAPI(void); +EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list); +EGLBoolean eglReleaseThread(void); +EGLBoolean eglWaitClient(void); +EGLContext eglGetCurrentContext(void); +EGLSync eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list); +EGLBoolean eglDestroySync(EGLDisplay dpy, EGLSync sync); +EGLint eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); +EGLBoolean eglGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value); +EGLImage eglCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list); +EGLBoolean eglDestroyImage(EGLDisplay dpy, EGLImage image); +EGLDisplay eglGetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list); +EGLSurface eglCreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list); +EGLSurface eglCreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list); +EGLBoolean eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags); +#define EGL_PLATFORM_WAYLAND_EXT 0x31D8 +#define EGL_PLATFORM_X11_EXT 0x31D5 +#define EGL_PLATFORM_X11_SCREEN_EXT 0x31D6 +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#define EGL_CONTEXT_FLAGS_KHR 0x30FC +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#define EGL_OPENGL_ES3_BIT_KHR 0x00000040 +#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3 +#define EGL_PLATFORM_WAYLAND_KHR 0x31D8 +#define EGL_PLATFORM_X11_KHR 0x31D5 +#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6 +#ifndef EGL_EXT_platform_wayland +#define EGL_EXT_platform_wayland 1 +#endif +#ifndef EGL_EXT_platform_x11 +#define EGL_EXT_platform_x11 1 +#endif +#ifndef EGL_KHR_create_context +#define EGL_KHR_create_context 1 +#endif +#ifndef EGL_KHR_create_context_no_error +#define EGL_KHR_create_context_no_error 1 +#endif +#ifndef EGL_KHR_platform_wayland +#define EGL_KHR_platform_wayland 1 +#endif +#ifndef EGL_KHR_platform_x11 +#define EGL_KHR_platform_x11 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/glad/src/glad_egl.c b/deps/glad/src/glad_egl.c new file mode 100644 index 00000000000000..e3cd1fc2948b70 --- /dev/null +++ b/deps/glad/src/glad_egl.c @@ -0,0 +1,48 @@ +/* + + EGL loader generated by glad 0.1.33 on Mon Mar 9 17:01:26 2020. + + Language/Generator: C/C++ + Specification: egl + APIs: egl=1.5 + Profile: - + Extensions: + EGL_EXT_platform_wayland, + EGL_EXT_platform_x11, + EGL_KHR_platform_wayland, + EGL_KHR_platform_x11 + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --api="egl=1.5" --generator="c" --spec="egl" --extensions="EGL_EXT_platform_wayland,EGL_EXT_platform_x11,EGL_KHR_platform_wayland,EGL_KHR_platform_x11" + Online: + https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5&extensions=EGL_EXT_platform_wayland&extensions=EGL_EXT_platform_x11&extensions=EGL_KHR_platform_wayland&extensions=EGL_KHR_platform_x11 +*/ + +#include +#include +#include +#include + +int gladLoadEGL(void) { + return gladLoadEGLLoader((GLADloadproc)eglGetProcAddress); +} + +static int find_extensionsEGL(void) { + return 1; +} + +static void find_coreEGL(void) { +} + +int gladLoadEGLLoader(GLADloadproc load) { + (void) load; + find_coreEGL(); + + if (!find_extensionsEGL()) return 0; + return 1; +} + diff --git a/libobs-opengl/CMakeLists.txt b/libobs-opengl/CMakeLists.txt index aa25d74ff50375..b710b6088d8c30 100644 --- a/libobs-opengl/CMakeLists.txt +++ b/libobs-opengl/CMakeLists.txt @@ -45,7 +45,9 @@ else() #This needs to change to be more specific to get ready for Wayland ${X11_XCB_LIBRARIES}) set(libobs-opengl_PLATFORM_SOURCES - gl-x11.c) + gl-nix.c + gl-x11-egl.c + gl-x11-glx.c) endif() set(libobs-opengl_SOURCES diff --git a/libobs-opengl/gl-nix.c b/libobs-opengl/gl-nix.c new file mode 100644 index 00000000000000..4b616ef1b5e6e5 --- /dev/null +++ b/libobs-opengl/gl-nix.c @@ -0,0 +1,113 @@ +/****************************************************************************** + Copyright (C) 2019 by Jason Francis + + 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 2 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 . +******************************************************************************/ + +#include "gl-nix.h" +#include "gl-x11-glx.h" +#include "gl-x11-egl.h" + +static const struct gl_winsys_vtable *gl_vtable = NULL; + +static void init_winsys(void) +{ + assert(gl_vtable == NULL); + + if (getenv("OBS_USE_EGL")) { + gl_vtable = gl_x11_egl_get_winsys_vtable(); + blog(LOG_INFO, "Using EGL/X11"); + } else { + gl_vtable = gl_x11_glx_get_winsys_vtable(); + } + + assert(gl_vtable != NULL); +} + +extern struct gl_windowinfo * +gl_windowinfo_create(const struct gs_init_data *info) +{ + return gl_vtable->windowinfo_create(info); +} + +extern void gl_windowinfo_destroy(struct gl_windowinfo *info) +{ + gl_vtable->windowinfo_destroy(info); +} + +extern struct gl_platform *gl_platform_create(gs_device_t *device, + uint32_t adapter) +{ + init_winsys(); + + return gl_vtable->platform_create(device, adapter); +} + +extern void gl_platform_destroy(struct gl_platform *plat) +{ + gl_vtable->platform_destroy(plat); + + gl_vtable = NULL; +} + +extern bool gl_platform_init_swapchain(struct gs_swap_chain *swap) +{ + return gl_vtable->platform_init_swapchain(swap); +} + +extern void gl_platform_cleanup_swapchain(struct gs_swap_chain *swap) +{ + gl_vtable->platform_cleanup_swapchain(swap); +} + +extern void device_enter_context(gs_device_t *device) +{ + gl_vtable->device_enter_context(device); +} + +extern void device_leave_context(gs_device_t *device) +{ + gl_vtable->device_leave_context(device); +} + +extern void *device_get_device_obj(gs_device_t *device) +{ + return gl_vtable->device_get_device_obj(device); +} + +extern void gl_getclientsize(const struct gs_swap_chain *swap, uint32_t *width, + uint32_t *height) +{ + gl_vtable->getclientsize(swap, width, height); +} + +extern void gl_clear_context(gs_device_t *device) +{ + gl_vtable->clear_context(device); +} + +extern void gl_update(gs_device_t *device) +{ + gl_vtable->update(device); +} + +extern void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap) +{ + gl_vtable->device_load_swapchain(device, swap); +} + +extern void device_present(gs_device_t *device) +{ + gl_vtable->device_present(device); +} diff --git a/libobs-opengl/gl-nix.h b/libobs-opengl/gl-nix.h new file mode 100644 index 00000000000000..209cc3081daa92 --- /dev/null +++ b/libobs-opengl/gl-nix.h @@ -0,0 +1,53 @@ +/****************************************************************************** + Copyright (C) 2019 by Jason Francis + + 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 2 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 . +******************************************************************************/ + +#pragma once + +#include "gl-subsystem.h" + +struct gl_winsys_vtable { + struct gl_windowinfo *(*windowinfo_create)( + const struct gs_init_data *info); + void (*windowinfo_destroy)(struct gl_windowinfo *info); + + struct gl_platform *(*platform_create)(gs_device_t *device, + uint32_t adapter); + + void (*platform_destroy)(struct gl_platform *plat); + + bool (*platform_init_swapchain)(struct gs_swap_chain *swap); + + void (*platform_cleanup_swapchain)(struct gs_swap_chain *swap); + + void (*device_enter_context)(gs_device_t *device); + + void (*device_leave_context)(gs_device_t *device); + + void *(*device_get_device_obj)(gs_device_t *device); + + void (*getclientsize)(const struct gs_swap_chain *swap, uint32_t *width, + uint32_t *height); + + void (*clear_context)(gs_device_t *device); + + void (*update)(gs_device_t *device); + + void (*device_load_swapchain)(gs_device_t *device, + gs_swapchain_t *swap); + + void (*device_present)(gs_device_t *device); +}; diff --git a/libobs-opengl/gl-x11-egl.c b/libobs-opengl/gl-x11-egl.c new file mode 100644 index 00000000000000..5b413995337540 --- /dev/null +++ b/libobs-opengl/gl-x11-egl.c @@ -0,0 +1,651 @@ +/****************************************************************************** + Copyright (C) 2019 by Ivan Avdeev + + 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 2 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 . +******************************************************************************/ + +/* GL context initialization using EGL instead of GLX + * Which is essential for improved and more performant screen grabbing and + * VA-API feeding techniques. + * + * Note: most of x11-related functionality was taken from gl-x11.c + */ + +#include +#include + +#include + +#include + +#include "gl-x11-egl.h" + +#include + +typedef EGLDisplay(EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC)( + EGLenum platform, void *native_display, const EGLint *attrib_list); + +static const int ctx_attribs[] = { +#ifdef _DEBUG + EGL_CONTEXT_OPENGL_DEBUG, + EGL_TRUE, +#endif + EGL_CONTEXT_OPENGL_PROFILE_MASK, + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + EGL_CONTEXT_MAJOR_VERSION, + 3, + EGL_CONTEXT_MINOR_VERSION, + 3, + EGL_NONE, +}; + +static int ctx_pbuffer_attribs[] = {EGL_WIDTH, 2, EGL_HEIGHT, 2, EGL_NONE}; + +static const EGLint ctx_config_attribs[] = {EGL_STENCIL_SIZE, + 0, + EGL_DEPTH_SIZE, + 0, + EGL_BUFFER_SIZE, + 32, + EGL_ALPHA_SIZE, + 8, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_BIT, + EGL_SURFACE_TYPE, + EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_NONE}; + +struct gl_windowinfo { + EGLConfig config; + + /* Windows in X11 are defined with integers (XID). + * xcb_window_t is a define for this... they are + * compatible with Xlib as well. + */ + xcb_window_t window; + EGLSurface surface; + + /* We can't fetch screen without a request so we cache it. */ + int screen; +}; + +struct gl_platform { + Display *xdisplay; + EGLDisplay edisplay; + EGLConfig config; + EGLContext context; + EGLSurface pbuffer; +}; + +/* The following utility functions are copied verbatim from GLX code. */ + +/* + * Since we cannot take advantage of the asynchronous nature of xcb, + * all of the helper functions are synchronous but thread-safe. + * + * They check for errors and will return 0 on problems + * with the exception of when 0 is a valid return value... in which case + * read the specific function comments. + */ + +/* Returns -1 on invalid screen. */ +static int get_screen_num_from_xcb_screen(xcb_connection_t *xcb_conn, + xcb_screen_t *screen) +{ + xcb_screen_iterator_t iter = + xcb_setup_roots_iterator(xcb_get_setup(xcb_conn)); + int screen_num = 0; + + for (; iter.rem; xcb_screen_next(&iter), ++screen_num) + if (iter.data == screen) + return screen_num; + + return -1; +} + +static xcb_screen_t *get_screen_from_root(xcb_connection_t *xcb_conn, + xcb_window_t root) +{ + xcb_screen_iterator_t iter = + xcb_setup_roots_iterator(xcb_get_setup(xcb_conn)); + + while (iter.rem) { + if (iter.data->root == root) + return iter.data; + + xcb_screen_next(&iter); + } + + return 0; +} + +static inline int get_screen_num_from_root(xcb_connection_t *xcb_conn, + xcb_window_t root) +{ + xcb_screen_t *screen = get_screen_from_root(xcb_conn, root); + + if (!screen) + return -1; + + return get_screen_num_from_xcb_screen(xcb_conn, screen); +} + +static xcb_get_geometry_reply_t *get_window_geometry(xcb_connection_t *xcb_conn, + xcb_drawable_t drawable) +{ + xcb_get_geometry_cookie_t cookie; + xcb_generic_error_t *error; + xcb_get_geometry_reply_t *reply; + + cookie = xcb_get_geometry(xcb_conn, drawable); + reply = xcb_get_geometry_reply(xcb_conn, cookie, &error); + + if (error) { + blog(LOG_ERROR, "Failed to fetch parent window geometry!"); + free(error); + free(reply); + return 0; + } + + free(error); + return reply; +} + +static const char *get_egl_error_string2(const EGLint error) +{ + switch (error) { +#define OBS_EGL_CASE_ERROR(e) \ + case e: \ + return #e; + OBS_EGL_CASE_ERROR(EGL_SUCCESS) + OBS_EGL_CASE_ERROR(EGL_NOT_INITIALIZED) + OBS_EGL_CASE_ERROR(EGL_BAD_ACCESS) + OBS_EGL_CASE_ERROR(EGL_BAD_ALLOC) + OBS_EGL_CASE_ERROR(EGL_BAD_ATTRIBUTE) + OBS_EGL_CASE_ERROR(EGL_BAD_CONTEXT) + OBS_EGL_CASE_ERROR(EGL_BAD_CONFIG) + OBS_EGL_CASE_ERROR(EGL_BAD_CURRENT_SURFACE) + OBS_EGL_CASE_ERROR(EGL_BAD_DISPLAY) + OBS_EGL_CASE_ERROR(EGL_BAD_SURFACE) + OBS_EGL_CASE_ERROR(EGL_BAD_MATCH) + OBS_EGL_CASE_ERROR(EGL_BAD_PARAMETER) + OBS_EGL_CASE_ERROR(EGL_BAD_NATIVE_PIXMAP) + OBS_EGL_CASE_ERROR(EGL_BAD_NATIVE_WINDOW) + OBS_EGL_CASE_ERROR(EGL_CONTEXT_LOST) +#undef OBS_EGL_CASE_ERROR + default: + return "Unknown"; + } +} +static const char *get_egl_error_string() +{ + return get_egl_error_string2(eglGetError()); +} + +static EGLDisplay get_egl_display(struct gl_platform *plat) +{ + Display *display = plat->xdisplay; + EGLDisplay edisplay = EGL_NO_DISPLAY; + const char *egl_client_extensions = NULL; + + egl_client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = + (PFNEGLGETPLATFORMDISPLAYEXTPROC)( + strstr(egl_client_extensions, "EGL_EXT_platform_base") + ? eglGetProcAddress("eglGetPlatformDisplayEXT") + : NULL); + + if (eglGetPlatformDisplayEXT) { + edisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, + display, NULL); + if (EGL_NO_DISPLAY == edisplay) + blog(LOG_ERROR, "Failed to get EGL/X11 display"); + } + + if (EGL_NO_DISPLAY == edisplay) + edisplay = eglGetDisplay(display); + + return edisplay; +} + +static bool gl_context_create(struct gl_platform *plat) +{ + Display *display = plat->xdisplay; + int frame_buf_config_count = 0; + EGLDisplay edisplay = EGL_NO_DISPLAY; + EGLConfig config = NULL; + EGLContext context = EGL_NO_CONTEXT; + int egl_min = 0, egl_maj = 0; + bool success = false; + + eglBindAPI(EGL_OPENGL_API); + + edisplay = get_egl_display(plat); + + if (EGL_NO_DISPLAY == edisplay) { + blog(LOG_ERROR, + "Failed to get EGL display using eglGetDisplay"); + return false; + } + + if (!eglInitialize(edisplay, &egl_maj, &egl_min)) { + blog(LOG_ERROR, "Failed to initialize EGL: %s", + get_egl_error_string()); + return false; + } + + if (!eglChooseConfig(edisplay, ctx_config_attribs, &config, 1, + &frame_buf_config_count)) { + blog(LOG_ERROR, "Unable to find suitable EGL config: %s", + get_egl_error_string()); + goto error; + } + + context = + eglCreateContext(edisplay, config, EGL_NO_CONTEXT, ctx_attribs); +#ifdef _DEBUG + if (EGL_NO_CONTEXT == context) { + const EGLint error = eglGetError(); + if (error == EGL_BAD_ATTRIBUTE) { + /* Sometimes creation fails because debug gl is not supported */ + blog(LOG_ERROR, + "Unable to create EGL context with DEBUG attrib, trying without"); + context = eglCreateContext(edisplay, config, + EGL_NO_CONTEXT, + ctx_attribs + 2); + } else { + blog(LOG_ERROR, "Unable to create EGL context: %s", + get_egl_error_string2(error)); + goto error; + } + } +#endif + if (EGL_NO_CONTEXT == context) { + blog(LOG_ERROR, "Unable to create EGL context: %s", + get_egl_error_string()); + goto error; + } + + plat->pbuffer = + eglCreatePbufferSurface(edisplay, config, ctx_pbuffer_attribs); + if (EGL_NO_SURFACE == plat->pbuffer) { + blog(LOG_ERROR, "Failed to create OpenGL pbuffer: %s", + get_egl_error_string()); + goto error; + } + + plat->edisplay = edisplay; + plat->config = config; + plat->context = context; + + success = true; + blog(LOG_DEBUG, "Created EGLDisplay %p", plat->edisplay); + +error: + if (!success) { + if (EGL_NO_CONTEXT != context) + eglDestroyContext(edisplay, context); + eglTerminate(edisplay); + } + + XSync(display, false); + return success; +} + +static void gl_context_destroy(struct gl_platform *plat) +{ + eglMakeCurrent(plat->edisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + eglDestroyContext(plat->edisplay, plat->context); +} + +static struct gl_windowinfo * +gl_x11_egl_windowinfo_create(const struct gs_init_data *info) +{ + UNUSED_PARAMETER(info); + return bmalloc(sizeof(struct gl_windowinfo)); +} + +static void gl_x11_egl_windowinfo_destroy(struct gl_windowinfo *info) +{ + UNUSED_PARAMETER(info); + bfree(info); +} + +static Display *open_windowless_display(void) +{ + Display *display = XOpenDisplay(NULL); + xcb_connection_t *xcb_conn; + xcb_screen_iterator_t screen_iterator; + xcb_screen_t *screen; + int screen_num; + + if (!display) { + blog(LOG_ERROR, "Unable to open new X connection!"); + return NULL; + } + + xcb_conn = XGetXCBConnection(display); + if (!xcb_conn) { + blog(LOG_ERROR, "Unable to get XCB connection to main display"); + goto error; + } + + screen_iterator = xcb_setup_roots_iterator(xcb_get_setup(xcb_conn)); + screen = screen_iterator.data; + if (!screen) { + blog(LOG_ERROR, "Unable to get screen root"); + goto error; + } + + screen_num = get_screen_num_from_root(xcb_conn, screen->root); + if (screen_num == -1) { + blog(LOG_ERROR, "Unable to get screen number from root"); + goto error; + } + + if (!gladLoadEGL()) { + blog(LOG_ERROR, "Unable to load EGL entry functions."); + goto error; + } + + return display; + +error: + if (display) + XCloseDisplay(display); + return NULL; +} + +static int x_error_handler(Display *display, XErrorEvent *error) +{ + char str1[512]; + char str2[512]; + char str3[512]; + XGetErrorText(display, error->error_code, str1, sizeof(str1)); + XGetErrorText(display, error->request_code, str2, sizeof(str2)); + XGetErrorText(display, error->minor_code, str3, sizeof(str3)); + + blog(LOG_ERROR, + "X Error: %s, Major opcode: %s, " + "Minor opcode: %s, Serial: %lu", + str1, str2, str3, error->serial); + return 0; +} + +static struct gl_platform *gl_x11_egl_platform_create(gs_device_t *device, + uint32_t adapter) +{ + /* There's some trickery here... we're mixing libX11, xcb, and EGL + For an explanation see here: http://xcb.freedesktop.org/MixingCalls/ + Essentially, EGL requires Xlib. Everything else we use xcb. */ + struct gl_platform *plat = bmalloc(sizeof(struct gl_platform)); + Display *display = open_windowless_display(); + + if (!display) { + goto fail_display_open; + } + + XSetEventQueueOwner(display, XCBOwnsEventQueue); + XSetErrorHandler(x_error_handler); + + /* We assume later that cur_swap is already set. */ + device->plat = plat; + + plat->xdisplay = display; + + if (!gl_context_create(plat)) { + blog(LOG_ERROR, "Failed to create context!"); + goto fail_context_create; + } + + if (!eglMakeCurrent(plat->edisplay, plat->pbuffer, plat->pbuffer, + plat->context)) { + blog(LOG_ERROR, "Failed to make context current: %s", + get_egl_error_string()); + goto fail_make_current; + } + + if (!gladLoadGL()) { + blog(LOG_ERROR, "Failed to load OpenGL entry functions."); + goto fail_load_gl; + } + + goto success; + +fail_make_current: + gl_context_destroy(plat); +fail_context_create: +fail_load_gl: + XCloseDisplay(display); +fail_display_open: + bfree(plat); + plat = NULL; +success: + UNUSED_PARAMETER(adapter); + return plat; +} + +static void gl_x11_egl_platform_destroy(struct gl_platform *plat) +{ + if (!plat) + return; + + gl_context_destroy(plat); + eglTerminate(plat->edisplay); + bfree(plat); +} + +static bool gl_x11_egl_platform_init_swapchain(struct gs_swap_chain *swap) +{ + const struct gl_platform *plat = swap->device->plat; + Display *display = plat->xdisplay; + xcb_connection_t *xcb_conn = XGetXCBConnection(display); + xcb_window_t wid = xcb_generate_id(xcb_conn); + xcb_window_t parent = swap->info.window.id; + xcb_get_geometry_reply_t *geometry = + get_window_geometry(xcb_conn, parent); + bool status = false; + + int screen_num; + int visual; + + if (!geometry) + goto fail_geometry_request; + + screen_num = get_screen_num_from_root(xcb_conn, geometry->root); + if (screen_num == -1) { + goto fail_screen; + } + + { + if (!eglGetConfigAttrib(plat->edisplay, plat->config, + EGL_NATIVE_VISUAL_ID, + (EGLint *)&visual)) { + blog(LOG_ERROR, + "Cannot get visual id for EGL context: %s", + get_egl_error_string()); + goto fail_visual_id; + } + } + + xcb_colormap_t colormap = xcb_generate_id(xcb_conn); + uint32_t mask = XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP; + uint32_t mask_values[] = {0, colormap, 0}; + + xcb_create_colormap(xcb_conn, XCB_COLORMAP_ALLOC_NONE, colormap, parent, + visual); + + xcb_create_window(xcb_conn, 24 /* Hardcoded? */, wid, parent, 0, 0, + geometry->width, geometry->height, 0, 0, visual, mask, + mask_values); + + const EGLSurface surface = + eglCreateWindowSurface(plat->edisplay, plat->config, wid, 0); + if (EGL_NO_SURFACE == surface) { + blog(LOG_ERROR, "Cannot get window EGL surface: %s", + get_egl_error_string()); + goto fail_window_surface; + } + + swap->wi->config = plat->config; + swap->wi->window = wid; + swap->wi->surface = surface; + swap->wi->screen = screen_num; + + xcb_map_window(xcb_conn, wid); + + status = true; + goto success; + +fail_window_surface: +fail_visual_id: +fail_screen: +fail_geometry_request: +success: + free(geometry); + return status; +} + +static void gl_x11_egl_platform_cleanup_swapchain(struct gs_swap_chain *swap) +{ + UNUSED_PARAMETER(swap); + /* Really nothing to clean up? */ +} + +static void gl_x11_egl_device_enter_context(gs_device_t *device) +{ + const EGLContext context = device->plat->context; + const EGLDisplay display = device->plat->edisplay; + const EGLSurface surface = (device->cur_swap) + ? device->cur_swap->wi->surface + : device->plat->pbuffer; + + if (!eglMakeCurrent(display, surface, surface, context)) + blog(LOG_ERROR, "Failed to make context current: %s", + get_egl_error_string()); +} + +static void gl_x11_egl_device_leave_context(gs_device_t *device) +{ + const EGLDisplay display = device->plat->edisplay; + + if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT)) { + blog(LOG_ERROR, "Failed to reset current context: %s", + get_egl_error_string()); + } +} + +static void *gl_x11_egl_device_get_device_obj(gs_device_t *device) +{ + return device->plat->context; +} + +static void gl_x11_egl_getclientsize(const struct gs_swap_chain *swap, + uint32_t *width, uint32_t *height) +{ + xcb_connection_t *xcb_conn = + XGetXCBConnection(swap->device->plat->xdisplay); + xcb_window_t window = swap->wi->window; + + xcb_get_geometry_reply_t *geometry = + get_window_geometry(xcb_conn, window); + if (geometry) { + *width = geometry->width; + *height = geometry->height; + } + + free(geometry); +} + +static void gl_x11_egl_update(gs_device_t *device) +{ + Display *display = device->plat->xdisplay; + xcb_window_t window = device->cur_swap->wi->window; + + uint32_t values[] = {device->cur_swap->info.cx, + device->cur_swap->info.cy}; + + xcb_configure_window(XGetXCBConnection(display), window, + XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, + values); +} + +static void gl_x11_egl_clear_context(gs_device_t *device) +{ + Display *display = device->plat->edisplay; + + if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT)) { + blog(LOG_ERROR, "Failed to reset current context."); + } +} + +static void gl_x11_egl_device_load_swapchain(gs_device_t *device, + gs_swapchain_t *swap) +{ + if (device->cur_swap == swap) + return; + + device->cur_swap = swap; + + device_enter_context(device); +} + +enum swap_type { + SWAP_TYPE_NORMAL, + SWAP_TYPE_EXT, + SWAP_TYPE_MESA, + SWAP_TYPE_SGI, +}; + +static void gl_x11_egl_device_present(gs_device_t *device) +{ + Display *display = device->plat->xdisplay; + + xcb_connection_t *xcb_conn = XGetXCBConnection(display); + xcb_generic_event_t *xcb_event; + while ((xcb_event = xcb_poll_for_event(xcb_conn))) { + free(xcb_event); + } + + if (!eglSwapBuffers(device->plat->edisplay, + device->cur_swap->wi->surface)) + blog(LOG_ERROR, "Cannot swap EGL buffers: %s", + get_egl_error_string()); +} + +static const struct gl_winsys_vtable egl_x11_winsys_vtable = { + .windowinfo_create = gl_x11_egl_windowinfo_create, + .windowinfo_destroy = gl_x11_egl_windowinfo_destroy, + .platform_create = gl_x11_egl_platform_create, + .platform_destroy = gl_x11_egl_platform_destroy, + .platform_init_swapchain = gl_x11_egl_platform_init_swapchain, + .platform_cleanup_swapchain = gl_x11_egl_platform_cleanup_swapchain, + .device_enter_context = gl_x11_egl_device_enter_context, + .device_leave_context = gl_x11_egl_device_leave_context, + .device_get_device_obj = gl_x11_egl_device_get_device_obj, + .getclientsize = gl_x11_egl_getclientsize, + .clear_context = gl_x11_egl_clear_context, + .update = gl_x11_egl_update, + .device_load_swapchain = gl_x11_egl_device_load_swapchain, + .device_present = gl_x11_egl_device_present, +}; + +const struct gl_winsys_vtable *gl_x11_egl_get_winsys_vtable(void) +{ + return &egl_x11_winsys_vtable; +} diff --git a/libobs-opengl/gl-x11-egl.h b/libobs-opengl/gl-x11-egl.h new file mode 100644 index 00000000000000..44ab3111609717 --- /dev/null +++ b/libobs-opengl/gl-x11-egl.h @@ -0,0 +1,22 @@ +/****************************************************************************** + Copyright (C) 2019 by Ivan Avdeev + + 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 2 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 . +******************************************************************************/ + +#pragma once + +#include "gl-nix.h" + +const struct gl_winsys_vtable *gl_x11_egl_get_winsys_vtable(void); diff --git a/libobs-opengl/gl-x11.c b/libobs-opengl/gl-x11-glx.c similarity index 86% rename from libobs-opengl/gl-x11.c rename to libobs-opengl/gl-x11-glx.c index d04115b04c4de5..a562b564987a89 100644 --- a/libobs-opengl/gl-x11.c +++ b/libobs-opengl/gl-x11-glx.c @@ -36,7 +36,7 @@ #include -#include "gl-subsystem.h" +#include "gl-nix.h" #include @@ -221,14 +221,14 @@ static void gl_context_destroy(struct gl_platform *plat) bfree(plat); } -extern struct gl_windowinfo * -gl_windowinfo_create(const struct gs_init_data *info) +static struct gl_windowinfo * +gl_x11_glx_windowinfo_create(const struct gs_init_data *info) { UNUSED_PARAMETER(info); return bmalloc(sizeof(struct gl_windowinfo)); } -extern void gl_windowinfo_destroy(struct gl_windowinfo *info) +static void gl_x11_glx_windowinfo_destroy(struct gl_windowinfo *info) { bfree(info); } @@ -294,8 +294,8 @@ static int x_error_handler(Display *display, XErrorEvent *error) return 0; } -extern struct gl_platform *gl_platform_create(gs_device_t *device, - uint32_t adapter) +static struct gl_platform *gl_x11_glx_platform_create(gs_device_t *device, + uint32_t adapter) { /* There's some trickery here... we're mixing libX11, xcb, and GLX For an explanation see here: http://xcb.freedesktop.org/MixingCalls/ @@ -346,7 +346,7 @@ extern struct gl_platform *gl_platform_create(gs_device_t *device, return plat; } -extern void gl_platform_destroy(struct gl_platform *plat) +static void gl_x11_glx_platform_destroy(struct gl_platform *plat) { if (!plat) /* In what case would platform be invalid here? */ return; @@ -354,7 +354,7 @@ extern void gl_platform_destroy(struct gl_platform *plat) gl_context_destroy(plat); } -extern bool gl_platform_init_swapchain(struct gs_swap_chain *swap) +static bool gl_x11_glx_platform_init_swapchain(struct gs_swap_chain *swap) { Display *display = swap->device->plat->display; xcb_connection_t *xcb_conn = XGetXCBConnection(display); @@ -429,13 +429,13 @@ extern bool gl_platform_init_swapchain(struct gs_swap_chain *swap) return status; } -extern void gl_platform_cleanup_swapchain(struct gs_swap_chain *swap) +static void gl_x11_glx_platform_cleanup_swapchain(struct gs_swap_chain *swap) { UNUSED_PARAMETER(swap); /* Really nothing to clean up? */ } -extern void device_enter_context(gs_device_t *device) +static void gl_x11_glx_device_enter_context(gs_device_t *device) { GLXContext context = device->plat->context; Display *display = device->plat->display; @@ -453,7 +453,7 @@ extern void device_enter_context(gs_device_t *device) } } -extern void device_leave_context(gs_device_t *device) +static void gl_x11_glx_device_leave_context(gs_device_t *device) { Display *display = device->plat->display; @@ -462,13 +462,13 @@ extern void device_leave_context(gs_device_t *device) } } -void *device_get_device_obj(gs_device_t *device) +static void *gl_x11_glx_device_get_device_obj(gs_device_t *device) { return device->plat->context; } -extern void gl_getclientsize(const struct gs_swap_chain *swap, uint32_t *width, - uint32_t *height) +static void gl_x11_glx_getclientsize(const struct gs_swap_chain *swap, + uint32_t *width, uint32_t *height) { xcb_connection_t *xcb_conn = XGetXCBConnection(swap->device->plat->display); @@ -484,7 +484,7 @@ extern void gl_getclientsize(const struct gs_swap_chain *swap, uint32_t *width, free(geometry); } -extern void gl_clear_context(gs_device_t *device) +static void gl_x11_glx_clear_context(gs_device_t *device) { Display *display = device->plat->display; @@ -493,7 +493,7 @@ extern void gl_clear_context(gs_device_t *device) } } -extern void gl_update(gs_device_t *device) +static void gl_x11_glx_update(gs_device_t *device) { Display *display = device->plat->display; xcb_window_t window = device->cur_swap->wi->window; @@ -506,7 +506,8 @@ extern void gl_update(gs_device_t *device) values); } -extern void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap) +static void gl_x11_glx_device_load_swapchain(gs_device_t *device, + gs_swapchain_t *swap) { if (device->cur_swap == swap) return; @@ -536,7 +537,7 @@ enum swap_type { SWAP_TYPE_SGI, }; -extern void device_present(gs_device_t *device) +static void gl_x11_glx_device_present(gs_device_t *device) { static bool initialized = false; static enum swap_type swap_type = SWAP_TYPE_NORMAL; @@ -577,3 +578,25 @@ extern void device_present(gs_device_t *device) glXSwapBuffers(display, window); } + +static const struct gl_winsys_vtable glx_winsys_vtable = { + .windowinfo_create = gl_x11_glx_windowinfo_create, + .windowinfo_destroy = gl_x11_glx_windowinfo_destroy, + .platform_create = gl_x11_glx_platform_create, + .platform_destroy = gl_x11_glx_platform_destroy, + .platform_init_swapchain = gl_x11_glx_platform_init_swapchain, + .platform_cleanup_swapchain = gl_x11_glx_platform_cleanup_swapchain, + .device_enter_context = gl_x11_glx_device_enter_context, + .device_leave_context = gl_x11_glx_device_leave_context, + .device_get_device_obj = gl_x11_glx_device_get_device_obj, + .getclientsize = gl_x11_glx_getclientsize, + .clear_context = gl_x11_glx_clear_context, + .update = gl_x11_glx_update, + .device_load_swapchain = gl_x11_glx_device_load_swapchain, + .device_present = gl_x11_glx_device_present, +}; + +const struct gl_winsys_vtable *gl_x11_glx_get_winsys_vtable(void) +{ + return &glx_winsys_vtable; +} diff --git a/libobs-opengl/gl-x11-glx.h b/libobs-opengl/gl-x11-glx.h new file mode 100644 index 00000000000000..bdedf55c56dcdc --- /dev/null +++ b/libobs-opengl/gl-x11-glx.h @@ -0,0 +1,22 @@ +/****************************************************************************** + Copyright (C) 2014 by Zachary Lund + + 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 2 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 . +******************************************************************************/ + +#pragma once + +#include "gl-nix.h" + +const struct gl_winsys_vtable *gl_x11_glx_get_winsys_vtable(void);