Merge pull request #2484 from GeorgesStavracas/feaneron/egl-wayland

EGL/Wayland (Wayland, pt 3)
This commit is contained in:
Jim 2021-02-12 01:30:05 -08:00 committed by GitHub
commit 190ab876cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 3669 additions and 1248 deletions

View File

@ -419,6 +419,7 @@ jobs:
pkg-config \
python3-dev \
qtbase5-dev \
qtbase5-private-dev \
libqt5svg5-dev \
swig \
libcmocka-dev \

View File

@ -42,6 +42,7 @@ sudo apt-get install -y \
pkg-config \
python3-dev \
qtbase5-dev \
qtbase5-private-dev \
libqt5svg5-dev \
swig \
linux-generic \

View File

@ -202,6 +202,8 @@ if(APPLE)
list(APPEND CMAKE_INSTALL_RPATH "@loader_path/" "@executable_path/")
elseif(UNIX)
option(USE_XDG "Utilize XDG Base Directory Specification" ON)
option(ENABLE_WAYLAND "Build support for Wayland" ON)
if(USE_XDG)
add_definitions(-DUSE_XDG)
endif()

View File

@ -396,6 +396,16 @@ if(WIN32)
OUTPUT_NAME "obs${_output_suffix}")
endif()
if (ENABLE_WAYLAND)
find_package(Qt5Gui REQUIRED)
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
set(obs_PLATFORM_LIBRARIES
${obs_PLATFORM_LIBRARIES}
Qt5::Gui
Qt5::GuiPrivate)
endif()
target_link_libraries(obs
libobs
Qt5::Widgets

View File

@ -58,6 +58,16 @@
#include <pthread.h>
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
#include <obs-nix-platform.h>
#include <QX11Info>
#ifdef ENABLE_WAYLAND
#include <qpa/qplatformnativeinterface.h>
#endif
#endif
#include <iostream>
#include "ui-config.h"
@ -1384,6 +1394,29 @@ bool OBSApp::OBSInit()
qRegisterMetaType<VoidFunc>();
#if !defined(_WIN32) && !defined(__APPLE__)
obs_set_nix_platform(OBS_NIX_PLATFORM_X11_GLX);
if (QApplication::platformName() == "xcb") {
if (getenv("OBS_USE_EGL")) {
blog(LOG_INFO, "Using EGL/X11");
obs_set_nix_platform(OBS_NIX_PLATFORM_X11_EGL);
}
obs_set_nix_platform_display(QX11Info::display());
}
#ifdef ENABLE_WAYLAND
if (QApplication::platformName().contains("wayland")) {
obs_set_nix_platform(OBS_NIX_PLATFORM_WAYLAND);
QPlatformNativeInterface *native =
QGuiApplication::platformNativeInterface();
obs_set_nix_platform_display(
native->nativeResourceForIntegration("display"));
blog(LOG_INFO, "Platform: Wayland");
}
#endif
#endif
if (!StartupOBS(locale.c_str(), GetProfilerNameStore()))
return false;

View File

@ -6,6 +6,62 @@
#include <QResizeEvent>
#include <QShowEvent>
#include <obs-config.h>
#ifdef ENABLE_WAYLAND
#include <obs-nix-platform.h>
class SurfaceEventFilter : public QObject {
OBSQTDisplay *display;
int mTimerId;
public:
SurfaceEventFilter(OBSQTDisplay *src) : display(src), mTimerId(0) {}
protected:
bool eventFilter(QObject *obj, QEvent *event) override
{
bool result = QObject::eventFilter(obj, event);
QPlatformSurfaceEvent *surfaceEvent;
switch (event->type()) {
case QEvent::PlatformSurface:
surfaceEvent =
static_cast<QPlatformSurfaceEvent *>(event);
if (surfaceEvent->surfaceEventType() !=
QPlatformSurfaceEvent::SurfaceCreated)
return result;
if (display->windowHandle()->isExposed())
createOBSDisplay();
else
mTimerId = startTimer(67); // Arbitrary
break;
case QEvent::Expose:
createOBSDisplay();
break;
default:
break;
}
return result;
}
void timerEvent(QTimerEvent *) { createOBSDisplay(true); }
private:
void createOBSDisplay(bool force = false)
{
display->CreateDisplay(force);
if (mTimerId > 0) {
killTimer(mTimerId);
mTimerId = 0;
}
}
};
#endif
static inline long long color_to_int(const QColor &color)
{
auto shift = [&](unsigned val, int shift) {
@ -33,8 +89,13 @@ OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
setAttribute(Qt::WA_NativeWindow);
auto windowVisible = [this](bool visible) {
if (!visible)
if (!visible) {
#ifdef ENABLE_WAYLAND
if (obs_get_nix_platform() == OBS_NIX_PLATFORM_WAYLAND)
display = nullptr;
#endif
return;
}
if (!display) {
CreateDisplay();
@ -45,7 +106,7 @@ OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
}
};
auto sizeChanged = [this](QScreen *) {
auto screenChanged = [this](QScreen *) {
CreateDisplay();
QSize size = GetPixelSize(this);
@ -53,7 +114,13 @@ OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
};
connect(windowHandle(), &QWindow::visibleChanged, windowVisible);
connect(windowHandle(), &QWindow::screenChanged, sizeChanged);
connect(windowHandle(), &QWindow::screenChanged, screenChanged);
#ifdef ENABLE_WAYLAND
if (obs_get_nix_platform() == OBS_NIX_PLATFORM_WAYLAND)
windowHandle()->installEventFilter(
new SurfaceEventFilter(this));
#endif
}
QColor OBSQTDisplay::GetDisplayBackgroundColor() const
@ -76,9 +143,12 @@ void OBSQTDisplay::UpdateDisplayBackgroundColor()
obs_display_set_background_color(display, backgroundColor);
}
void OBSQTDisplay::CreateDisplay()
void OBSQTDisplay::CreateDisplay(bool force)
{
if (display || !windowHandle()->isExposed())
if (display)
return;
if (!windowHandle()->isExposed() && !force)
return;
QSize size = GetPixelSize(this);
@ -89,7 +159,8 @@ void OBSQTDisplay::CreateDisplay()
info.format = GS_BGRA;
info.zsformat = GS_ZS_NONE;
QTToGSWindow(winId(), info.window);
if (!QTToGSWindow(windowHandle(), info.window))
return;
display = obs_display_create(&info, backgroundColor);

View File

@ -13,8 +13,6 @@ class OBSQTDisplay : public QWidget {
OBSDisplay display;
void CreateDisplay();
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override;
@ -25,6 +23,7 @@ signals:
public:
OBSQTDisplay(QWidget *parent = nullptr,
Qt::WindowFlags flags = Qt::WindowFlags());
~OBSQTDisplay() { display = nullptr; }
virtual QPaintEngine *paintEngine() const override;
@ -35,4 +34,5 @@ public:
QColor GetDisplayBackgroundColor() const;
void SetDisplayBackgroundColor(const QColor &color);
void UpdateDisplayBackgroundColor();
void CreateDisplay(bool force = false);
};

View File

@ -30,9 +30,14 @@
#include <QStandardItemModel>
#if !defined(_WIN32) && !defined(__APPLE__)
#include <obs-nix-platform.h>
#include <QX11Info>
#endif
#ifdef ENABLE_WAYLAND
#include <qpa/qplatformnativeinterface.h>
#endif
static inline void OBSErrorBoxva(QWidget *parent, const char *msg, va_list args)
{
char full_message[4096];
@ -108,16 +113,33 @@ void OBSMessageBox::critical(QWidget *parent, const QString &title,
mb.exec();
}
void QTToGSWindow(WId windowId, gs_window &gswindow)
bool QTToGSWindow(QWindow *window, gs_window &gswindow)
{
bool success = true;
#ifdef _WIN32
gswindow.hwnd = (HWND)windowId;
gswindow.hwnd = (HWND)window->winId();
#elif __APPLE__
gswindow.view = (id)windowId;
gswindow.view = (id)window->winId();
#else
gswindow.id = windowId;
gswindow.display = QX11Info::display();
switch (obs_get_nix_platform()) {
case OBS_NIX_PLATFORM_X11_GLX:
case OBS_NIX_PLATFORM_X11_EGL:
gswindow.id = window->winId();
gswindow.display = obs_get_nix_platform_display();
break;
#ifdef ENABLE_WAYLAND
case OBS_NIX_PLATFORM_WAYLAND:
QPlatformNativeInterface *native =
QGuiApplication::platformNativeInterface();
gswindow.display =
native->nativeResourceForWindow("surface", window);
success = gswindow.display != nullptr;
break;
#endif
}
#endif
return success;
}
uint32_t TranslateQtKeyboardEventModifiers(Qt::KeyboardModifiers mods)

View File

@ -20,6 +20,7 @@
#include <QApplication>
#include <QMessageBox>
#include <QWidget>
#include <QWindow>
#include <QThread>
#include <obs.hpp>
@ -56,7 +57,7 @@ public:
void OBSErrorBox(QWidget *parent, const char *msg, ...);
void QTToGSWindow(WId windowId, gs_window &gswindow);
bool QTToGSWindow(QWindow *window, gs_window &gswindow);
uint32_t TranslateQtKeyboardEventModifiers(Qt::KeyboardModifiers mods);

View File

@ -79,6 +79,10 @@
#include <json11.hpp>
#ifdef ENABLE_WAYLAND
#include <obs-nix-platform.h>
#endif
using namespace json11;
using namespace std;
@ -1865,9 +1869,22 @@ void OBSBasic::OBSInit()
bool alwaysOnTop = config_get_bool(App()->GlobalConfig(), "BasicWindow",
"AlwaysOnTop");
if (alwaysOnTop || opt_always_on_top) {
#ifdef ENABLE_WAYLAND
bool isWayland = obs_get_nix_platform() == OBS_NIX_PLATFORM_WAYLAND;
#else
bool isWayland = false;
#endif
if (!isWayland && (alwaysOnTop || opt_always_on_top)) {
SetAlwaysOnTop(this, true);
ui->actionAlwaysOnTop->setChecked(true);
} else if (isWayland) {
if (opt_always_on_top)
blog(LOG_INFO,
"Always On Top not available on Wayland, ignoring…");
ui->actionAlwaysOnTop->setEnabled(false);
ui->actionAlwaysOnTop->setVisible(false);
}
#ifndef _WIN32

View File

@ -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)

View File

@ -0,0 +1,78 @@
# Try to find Wayland on a Unix system
#
# This will define:
#
# WAYLAND_FOUND - True if Wayland is found
# WAYLAND_LIBRARIES - Link these to use Wayland
# WAYLAND_INCLUDE_DIRS - Include directory for Wayland
# WAYLAND_DEFINITIONS - Compiler flags for using Wayland
#
# In addition the following more fine grained variables will be defined:
#
# Wayland_Client_FOUND WAYLAND_CLIENT_INCLUDE_DIRS WAYLAND_CLIENT_LIBRARIES
# Wayland_Server_FOUND WAYLAND_SERVER_INCLUDE_DIRS WAYLAND_SERVER_LIBRARIES
# Wayland_EGL_FOUND WAYLAND_EGL_INCLUDE_DIRS WAYLAND_EGL_LIBRARIES
# Wayland_Cursor_FOUND WAYLAND_CURSOR_INCLUDE_DIRS WAYLAND_CURSOR_LIBRARIES
#
# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
# 2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
IF (NOT WIN32)
# Use pkg-config to get the directories and then use these values
# in the find_path() and find_library() calls
find_package(PkgConfig)
PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor)
set(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS})
find_path(WAYLAND_CLIENT_INCLUDE_DIRS NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
find_library(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
if(WAYLAND_CLIENT_INCLUDE_DIRS AND WAYLAND_CLIENT_LIBRARIES)
set(Wayland_Client_FOUND TRUE)
else()
set(Wayland_Client_FOUND FALSE)
endif()
mark_as_advanced(WAYLAND_CLIENT_INCLUDE_DIRS WAYLAND_CLIENT_LIBRARIES)
find_path(WAYLAND_CURSOR_INCLUDE_DIRS NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
find_library(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
if(WAYLAND_CURSOR_INCLUDE_DIRS AND WAYLAND_CURSOR_LIBRARIES)
set(Wayland_Cursor_FOUND TRUE)
else()
set(Wayland_Cursor_FOUND FALSE)
endif()
mark_as_advanced(WAYLAND_CURSOR_INCLUDE_DIRS WAYLAND_CURSOR_LIBRARIES)
find_path(WAYLAND_EGL_INCLUDE_DIRS NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
find_library(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
if(WAYLAND_EGL_INCLUDE_DIRS AND WAYLAND_EGL_LIBRARIES)
set(Wayland_EGL_FOUND TRUE)
else()
set(Wayland_EGL_FOUND FALSE)
endif()
mark_as_advanced(WAYLAND_EGL_INCLUDE_DIRS WAYLAND_EGL_LIBRARIES)
find_path(WAYLAND_SERVER_INCLUDE_DIRS NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
find_library(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
if(WAYLAND_SERVER_INCLUDE_DIRS AND WAYLAND_SERVER_LIBRARIES)
set(Wayland_Server_FOUND TRUE)
else()
set(Wayland_Server_FOUND FALSE)
endif()
mark_as_advanced(WAYLAND_SERVER_INCLUDE_DIRS WAYLAND_SERVER_LIBRARIES)
set(WAYLAND_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIRS} ${WAYLAND_SERVER_INCLUDE_DIRS} ${WAYLAND_EGL_INCLUDE_DIRS} ${WAYLAND_CURSOR_INCLUDE_DIRS})
set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES})
mark_as_advanced(WAYLAND_INCLUDE_DIRS WAYLAND_LIBRARIES)
list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIRS)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Wayland REQUIRED_VARS WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIRS HANDLE_COMPONENTS)
ENDIF ()

View File

@ -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

385
deps/glad/include/glad/glad_egl.h vendored Normal file
View File

@ -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 <KHR/khrplatform.h>
#include <EGL/eglplatform.h>
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

48
deps/glad/src/glad_egl.c vendored Normal file
View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glad/glad_egl.h>
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;
}

View File

@ -28,7 +28,7 @@ elseif(APPLE)
${COCOA}
${IOSURF}
${OPENGL_gl_LIBRARY})
else() #This needs to change to be more specific to get ready for Wayland
else()
find_package(XCB COMPONENTS XCB REQUIRED)
find_package(X11_XCB REQUIRED)
@ -45,7 +45,32 @@ 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)
if(ENABLE_WAYLAND)
find_package(EGL REQUIRED)
find_package(Wayland REQUIRED)
include_directories(
${WAYLAND_CLIENT_INCLUDE_DIRS}
${WAYLAND_EGL_INCLUDE_DIRS}
${EGL_INCLUDE_DIRS})
add_definitions(
${WAYLAND_DEFINITIONS})
set(libobs-opengl_PLATFORM_DEPS
${libobs-opengl_PLATFORM_DEPS}
${WAYLAND_CLIENT_LIBRARIES}
${WAYLAND_EGL_LIBRARIES}
${EGL_LIBRARIES})
set(libobs-opengl_PLATFORM_SOURCES
${libobs-opengl_PLATFORM_SOURCES}
gl-wayland-egl.c)
endif()
endif()
set(libobs-opengl_SOURCES

125
libobs-opengl/gl-nix.c Normal file
View File

@ -0,0 +1,125 @@
/******************************************************************************
Copyright (C) 2019 by Jason Francis <cycl0ps@tuta.io>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "gl-nix.h"
#include "gl-x11-glx.h"
#include "gl-x11-egl.h"
#ifdef ENABLE_WAYLAND
#include "gl-wayland-egl.h"
#endif
static const struct gl_winsys_vtable *gl_vtable = NULL;
static void init_winsys(void)
{
assert(gl_vtable == NULL);
switch (obs_get_nix_platform()) {
case OBS_NIX_PLATFORM_X11_GLX:
gl_vtable = gl_x11_glx_get_winsys_vtable();
break;
case OBS_NIX_PLATFORM_X11_EGL:
gl_vtable = gl_x11_egl_get_winsys_vtable();
break;
#ifdef ENABLE_WAYLAND
case OBS_NIX_PLATFORM_WAYLAND:
gl_vtable = gl_wayland_egl_get_winsys_vtable();
blog(LOG_INFO, "Using EGL/Wayland");
break;
#endif
}
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);
}

56
libobs-opengl/gl-nix.h Normal file
View File

@ -0,0 +1,56 @@
/******************************************************************************
Copyright (C) 2019 by Jason Francis <cycl0ps@tuta.io>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#include <obs.h>
#include <obs-nix-platform.h>
#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);
};

View File

@ -0,0 +1,342 @@
/******************************************************************************
Copyright (C) 2019 by Jason Francis <cycl0ps@tuta.io>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "gl-wayland-egl.h"
#include <wayland-client.h>
#include <wayland-egl.h>
#include <glad/glad_egl.h>
static const EGLint config_attribs[] = {EGL_SURFACE_TYPE,
EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_BIT,
EGL_STENCIL_SIZE,
0,
EGL_DEPTH_SIZE,
0,
EGL_BUFFER_SIZE,
32,
EGL_ALPHA_SIZE,
8,
EGL_NATIVE_RENDERABLE,
EGL_TRUE,
EGL_NONE};
static const EGLint 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 const EGLint khr_ctx_attribs[] = {
#ifdef _DEBUG
EGL_CONTEXT_FLAGS_KHR,
EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR,
#endif
EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
EGL_CONTEXT_MAJOR_VERSION_KHR,
3,
EGL_CONTEXT_MINOR_VERSION_KHR,
3,
EGL_NONE};
struct gl_windowinfo {
struct wl_egl_window *window;
EGLSurface egl_surface;
};
struct gl_platform {
struct wl_display *wl_display;
EGLDisplay display;
EGLConfig config;
EGLContext context;
};
struct gl_windowinfo *
gl_wayland_egl_windowinfo_create(const struct gs_init_data *info)
{
struct wl_egl_window *window =
wl_egl_window_create(info->window.display, info->cx, info->cy);
if (window == NULL) {
blog(LOG_ERROR, "wl_egl_window_create failed");
return NULL;
}
struct gl_windowinfo *wi = bmalloc(sizeof(struct gl_windowinfo));
wi->window = window;
return wi;
}
static void gl_wayland_egl_windowinfo_destroy(struct gl_windowinfo *info)
{
wl_egl_window_destroy(info->window);
bfree(info);
}
static bool egl_make_current(EGLDisplay display, EGLSurface surface,
EGLContext context)
{
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
blog(LOG_ERROR, "eglBindAPI failed");
}
if (!eglMakeCurrent(display, surface, surface, context)) {
blog(LOG_ERROR, "eglMakeCurrent failed");
return false;
}
return true;
}
static bool egl_context_create(struct gl_platform *plat, const EGLint *attribs)
{
bool success = false;
EGLint num_config;
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
blog(LOG_ERROR, "eglBindAPI failed");
}
EGLBoolean result = eglChooseConfig(plat->display, config_attribs,
&plat->config, 1, &num_config);
if (result != EGL_TRUE || num_config == 0) {
blog(LOG_ERROR, "eglChooseConfig failed");
goto error;
}
plat->context = eglCreateContext(plat->display, plat->config,
EGL_NO_CONTEXT, attribs);
if (plat->context == EGL_NO_CONTEXT) {
blog(LOG_ERROR, "eglCreateContext failed");
goto error;
}
success =
egl_make_current(plat->display, EGL_NO_SURFACE, plat->context);
error:
return success;
}
static void egl_context_destroy(struct gl_platform *plat)
{
egl_make_current(plat->display, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(plat->display, plat->context);
}
static bool extension_supported(const char *extensions, const char *search)
{
const char *result = strstr(extensions, search);
unsigned long len = strlen(search);
return result != NULL &&
(result == extensions || *(result - 1) == ' ') &&
(result[len] == ' ' || result[len] == '\0');
}
static struct gl_platform *gl_wayland_egl_platform_create(gs_device_t *device,
uint32_t adapter)
{
struct gl_platform *plat = bmalloc(sizeof(struct gl_platform));
plat->wl_display = obs_get_nix_platform_display();
device->plat = plat;
plat->display = eglGetDisplay(plat->wl_display);
if (plat->display == EGL_NO_DISPLAY) {
blog(LOG_ERROR, "eglGetDisplay failed");
goto fail_display_init;
}
EGLint major;
EGLint minor;
if (eglInitialize(plat->display, &major, &minor) == EGL_FALSE) {
blog(LOG_ERROR, "eglInitialize failed");
goto fail_display_init;
}
blog(LOG_INFO, "Initialized EGL %d.%d", major, minor);
const char *extensions = eglQueryString(plat->display, EGL_EXTENSIONS);
blog(LOG_DEBUG, "Supported EGL Extensions: %s", extensions);
const EGLint *attribs = ctx_attribs;
if (major == 1 && minor == 4) {
if (extension_supported(extensions, "EGL_KHR_create_context")) {
attribs = khr_ctx_attribs;
} else {
blog(LOG_ERROR,
"EGL_KHR_create_context extension is required to use EGL 1.4.");
goto fail_context_create;
}
} else if (major < 1 || (major == 1 && minor < 4)) {
blog(LOG_ERROR, "EGL 1.4 or higher is required.");
goto fail_context_create;
}
if (!egl_context_create(plat, attribs)) {
goto fail_context_create;
}
if (!gladLoadGL()) {
blog(LOG_ERROR, "Failed to load OpenGL entry functions.");
goto fail_load_gl;
}
goto success;
fail_load_gl:
egl_context_destroy(plat);
fail_context_create:
eglTerminate(plat->display);
fail_display_init:
bfree(plat);
plat = NULL;
success:
UNUSED_PARAMETER(adapter);
return plat;
}
static void gl_wayland_egl_platform_destroy(struct gl_platform *plat)
{
if (plat) {
egl_context_destroy(plat);
eglTerminate(plat->display);
bfree(plat);
}
}
static bool gl_wayland_egl_platform_init_swapchain(struct gs_swap_chain *swap)
{
struct gl_platform *plat = swap->device->plat;
EGLSurface egl_surface = eglCreateWindowSurface(
plat->display, plat->config, swap->wi->window, NULL);
if (egl_surface == EGL_NO_SURFACE) {
blog(LOG_ERROR, "eglCreateWindowSurface failed");
return false;
}
swap->wi->egl_surface = egl_surface;
return true;
}
static void
gl_wayland_egl_platform_cleanup_swapchain(struct gs_swap_chain *swap)
{
struct gl_platform *plat = swap->device->plat;
eglDestroySurface(plat->display, swap->wi->egl_surface);
}
static void gl_wayland_egl_device_enter_context(gs_device_t *device)
{
struct gl_platform *plat = device->plat;
EGLSurface surface = EGL_NO_SURFACE;
if (device->cur_swap != NULL)
surface = device->cur_swap->wi->egl_surface;
egl_make_current(plat->display, surface, plat->context);
}
static void gl_wayland_egl_device_leave_context(gs_device_t *device)
{
struct gl_platform *plat = device->plat;
egl_make_current(plat->display, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
static void *gl_wayland_egl_device_get_device_obj(gs_device_t *device)
{
return device->plat->context;
}
static void gl_wayland_egl_getclientsize(const struct gs_swap_chain *swap,
uint32_t *width, uint32_t *height)
{
wl_egl_window_get_attached_size(swap->wi->window, (void *)width,
(void *)height);
}
static void gl_wayland_egl_clear_context(gs_device_t *device)
{
struct gl_platform *plat = device->plat;
egl_make_current(plat->display, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
static void gl_wayland_egl_update(gs_device_t *device)
{
wl_egl_window_resize(device->cur_swap->wi->window,
device->cur_swap->info.cx,
device->cur_swap->info.cy, 0, 0);
}
static void gl_wayland_egl_device_load_swapchain(gs_device_t *device,
gs_swapchain_t *swap)
{
if (device->cur_swap == swap)
return;
device->cur_swap = swap;
struct gl_platform *plat = device->plat;
if (swap == NULL) {
egl_make_current(plat->display, EGL_NO_SURFACE, EGL_NO_CONTEXT);
} else {
egl_make_current(plat->display, swap->wi->egl_surface,
plat->context);
}
}
static void gl_wayland_egl_device_present(gs_device_t *device)
{
struct gl_platform *plat = device->plat;
struct gl_windowinfo *wi = device->cur_swap->wi;
if (eglSwapInterval(plat->display, 0) == EGL_FALSE) {
blog(LOG_ERROR, "eglSwapInterval failed");
}
if (eglSwapBuffers(plat->display, wi->egl_surface) == EGL_FALSE) {
blog(LOG_ERROR, "eglSwapBuffers failed");
}
}
static const struct gl_winsys_vtable egl_wayland_winsys_vtable = {
.windowinfo_create = gl_wayland_egl_windowinfo_create,
.windowinfo_destroy = gl_wayland_egl_windowinfo_destroy,
.platform_create = gl_wayland_egl_platform_create,
.platform_destroy = gl_wayland_egl_platform_destroy,
.platform_init_swapchain = gl_wayland_egl_platform_init_swapchain,
.platform_cleanup_swapchain = gl_wayland_egl_platform_cleanup_swapchain,
.device_enter_context = gl_wayland_egl_device_enter_context,
.device_leave_context = gl_wayland_egl_device_leave_context,
.device_get_device_obj = gl_wayland_egl_device_get_device_obj,
.getclientsize = gl_wayland_egl_getclientsize,
.clear_context = gl_wayland_egl_clear_context,
.update = gl_wayland_egl_update,
.device_load_swapchain = gl_wayland_egl_device_load_swapchain,
.device_present = gl_wayland_egl_device_present,
};
const struct gl_winsys_vtable *gl_wayland_egl_get_winsys_vtable(void)
{
return &egl_wayland_winsys_vtable;
}

View File

@ -0,0 +1,22 @@
/******************************************************************************
Copyright (C) 2019 by Jason Francis <cycl0ps@tuta.io>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#include "gl-nix.h"
const struct gl_winsys_vtable *gl_wayland_egl_get_winsys_vtable(void);

657
libobs-opengl/gl-x11-egl.c Normal file
View File

@ -0,0 +1,657 @@
/******************************************************************************
Copyright (C) 2019 by Ivan Avdeev <me@w23.ru>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
/* 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 <X11/Xlib.h>
#include <X11/Xlib-xcb.h>
#include <xcb/xcb.h>
#include <stdio.h>
#include "gl-x11-egl.h"
#include <glad/glad_egl.h>
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(Display *platform_display)
{
Display *display;
xcb_connection_t *xcb_conn;
xcb_screen_iterator_t screen_iterator;
xcb_screen_t *screen;
int screen_num;
if (platform_display)
display = platform_display;
else
display = XOpenDisplay(NULL);
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 *platform_display = obs_get_nix_platform_display();
Display *display = open_windowless_display(platform_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;
}

View File

@ -0,0 +1,22 @@
/******************************************************************************
Copyright (C) 2019 by Ivan Avdeev <me@w23.ru>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#include "gl-nix.h"
const struct gl_winsys_vtable *gl_x11_egl_get_winsys_vtable(void);

View File

@ -36,7 +36,7 @@
#include <stdio.h>
#include "gl-subsystem.h"
#include "gl-nix.h"
#include <glad/glad_glx.h>
@ -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 @@ success:
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 @@ success:
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;
}

View File

@ -0,0 +1,22 @@
/******************************************************************************
Copyright (C) 2014 by Zachary Lund <admin@computerquip.com>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#include "gl-nix.h"
const struct gl_winsys_vtable *gl_x11_glx_get_winsys_vtable(void);

View File

@ -187,12 +187,30 @@ elseif(APPLE)
elseif(UNIX)
set(libobs_PLATFORM_SOURCES
obs-nix.c
obs-nix-platform.c
obs-nix-x11.c
util/threading-posix.c
util/pipe-posix.c
util/platform-nix.c)
set(libobs_PLATFORM_HEADERS
util/threading-posix.h)
util/threading-posix.h
obs-nix-platform.h)
if(ENABLE_WAYLAND)
find_package(Wayland COMPONENTS Client REQUIRED)
set(libobs_PLATFORM_SOURCES ${libobs_PLATFORM_SOURCES}
obs-nix-wayland.c)
include_directories(
${WAYLAND_CLIENT_INCLUDE_DIR})
add_definitions(
${WAYLAND_DEFINITIONS})
set(libobs_PLATFORM_DEPS
${libobs_PLATFORM_DEPS}
${WAYLAND_CLIENT_LIBRARIES})
endif()
if(HAVE_PULSEAUDIO)
set(libobs_audio_monitoring_HEADERS

42
libobs/obs-nix-platform.c Normal file
View File

@ -0,0 +1,42 @@
/******************************************************************************
Copyright (C) 2019 by Jason Francis <cycl0ps@tuta.io>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "obs-nix-platform.h"
static enum obs_nix_platform_type obs_nix_platform = OBS_NIX_PLATFORM_X11_GLX;
static void *obs_nix_platform_display = NULL;
void obs_set_nix_platform(enum obs_nix_platform_type platform)
{
obs_nix_platform = platform;
}
enum obs_nix_platform_type obs_get_nix_platform(void)
{
return obs_nix_platform;
}
void obs_set_nix_platform_display(void *display)
{
obs_nix_platform_display = display;
}
void *obs_get_nix_platform_display(void)
{
return obs_nix_platform_display;
}

56
libobs/obs-nix-platform.h Normal file
View File

@ -0,0 +1,56 @@
/******************************************************************************
Copyright (C) 2019 by Jason Francis <cycl0ps@tuta.io>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#include "util/c99defs.h"
#ifdef __cplusplus
extern "C" {
#endif
enum obs_nix_platform_type {
OBS_NIX_PLATFORM_X11_GLX,
OBS_NIX_PLATFORM_X11_EGL,
#ifdef ENABLE_WAYLAND
OBS_NIX_PLATFORM_WAYLAND,
#endif
};
/**
* Sets the Unix platform.
* @param platform The platform to select.
*/
EXPORT void obs_set_nix_platform(enum obs_nix_platform_type platform);
/**
* Gets the host platform.
*/
EXPORT enum obs_nix_platform_type obs_get_nix_platform(void);
/**
* Sets the host platform's display connection.
* @param display The host display connection.
*/
EXPORT void obs_set_nix_platform_display(void *display);
/**
* Gets the host platform's display connection.
*/
EXPORT void *obs_get_nix_platform_display(void);
#ifdef __cplusplus
}
#endif

88
libobs/obs-nix-wayland.c Normal file
View File

@ -0,0 +1,88 @@
/******************************************************************************
Copyright (C) 2019 by Jason Francis <cycl0ps@tuta.io>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "obs-internal.h"
#include "obs-nix-platform.h"
#include "obs-nix-wayland.h"
#include <wayland-client.h>
void obs_nix_wayland_log_info(void)
{
struct wl_display *display = obs_get_nix_platform_display();
if (display == NULL) {
blog(LOG_INFO, "Unable to connect to Wayland server");
return;
}
//TODO: query some information about the wayland server if possible
blog(LOG_INFO, "Connected to Wayland server");
}
static bool
obs_nix_wayland_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
{
UNUSED_PARAMETER(hotkeys);
return true;
}
static void
obs_nix_wayland_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
{
UNUSED_PARAMETER(hotkeys);
}
static bool
obs_nix_wayland_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *context,
obs_key_t key)
{
UNUSED_PARAMETER(context);
UNUSED_PARAMETER(key);
return false;
}
static void obs_nix_wayland_key_to_str(obs_key_t key, struct dstr *dstr)
{
UNUSED_PARAMETER(key);
UNUSED_PARAMETER(dstr);
}
static obs_key_t obs_nix_wayland_key_from_virtual_key(int sym)
{
UNUSED_PARAMETER(sym);
return OBS_KEY_NONE;
}
static int obs_nix_wayland_key_to_virtual_key(obs_key_t key)
{
UNUSED_PARAMETER(key);
return 0;
}
static const struct obs_nix_hotkeys_vtable wayland_hotkeys_vtable = {
.init = obs_nix_wayland_hotkeys_platform_init,
.free = obs_nix_wayland_hotkeys_platform_free,
.is_pressed = obs_nix_wayland_hotkeys_platform_is_pressed,
.key_to_str = obs_nix_wayland_key_to_str,
.key_from_virtual_key = obs_nix_wayland_key_from_virtual_key,
.key_to_virtual_key = obs_nix_wayland_key_to_virtual_key,
};
const struct obs_nix_hotkeys_vtable *obs_nix_wayland_get_hotkeys_vtable(void)
{
return &wayland_hotkeys_vtable;
}

24
libobs/obs-nix-wayland.h Normal file
View File

@ -0,0 +1,24 @@
/******************************************************************************
Copyright (C) 2019 by Jason Francis <cycl0ps@tuta.io>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#include "obs-nix.h"
void obs_nix_wayland_log_info(void);
const struct obs_nix_hotkeys_vtable *obs_nix_wayland_get_hotkeys_vtable(void);

1271
libobs/obs-nix-x11.c Normal file

File diff suppressed because it is too large Load Diff

22
libobs/obs-nix-x11.h Normal file
View File

@ -0,0 +1,22 @@
/******************************************************************************
Copyright (C) 2019 by Jason Francis <cycl0ps@tuta.io>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#include "obs-nix.h"
void obs_nix_x11_log_info(void);
const struct obs_nix_hotkeys_vtable *obs_nix_x11_get_hotkeys_vtable(void);

File diff suppressed because it is too large Load Diff

42
libobs/obs-nix.h Normal file
View File

@ -0,0 +1,42 @@
/******************************************************************************
Copyright (C) 2020 by Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "obs-internal.h"
struct obs_nix_hotkeys_vtable {
bool (*init)(struct obs_core_hotkeys *hotkeys);
void (*free)(struct obs_core_hotkeys *hotkeys);
bool (*is_pressed)(obs_hotkeys_platform_t *context, obs_key_t key);
void (*key_to_str)(obs_key_t key, struct dstr *dstr);
obs_key_t (*key_from_virtual_key)(int sym);
int (*key_to_virtual_key)(obs_key_t key);
};
#ifdef __cplusplus
}
#endif

View File

@ -22,6 +22,8 @@
#define LIBOBS_IMAGEMAGICK_DIR_STYLE_7GE 7
#define LIBOBS_IMAGEMAGICK_DIR_STYLE @LIBOBS_IMAGEMAGICK_DIR_STYLE@
#cmakedefine ENABLE_WAYLAND
/* NOTE: Release candidate version numbers internally are always the previous
* main release number! For example, if the current public release is 21.0 and
* the build is 22.0 release candidate 1, internally the build number (defined

View File

@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <obs-module.h>
#include <obs-nix-platform.h>
OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("linux-xshm", "en-US")
@ -30,6 +31,11 @@ extern void xcomposite_unload(void);
bool obs_module_load(void)
{
if (obs_get_nix_platform() != OBS_NIX_PLATFORM_X11_GLX) {
blog(LOG_ERROR, "linux-capture cannot run on EGL platforms");
return false;
}
obs_register_source(&xshm_input);
xcomposite_load();
return true;