diff --git a/irr/include/SExposedVideoData.h b/irr/include/SExposedVideoData.h index 9befcb15bdf0..346bd037c408 100644 --- a/irr/include/SExposedVideoData.h +++ b/irr/include/SExposedVideoData.h @@ -63,6 +63,12 @@ struct SExposedVideoData void *Window; }; + struct SOpenGLFB + { + //! The EGLNativeWindowType object. + void *Window; + }; + struct SOGLESAndroid { //! The ANativeWindow object. @@ -74,6 +80,7 @@ struct SExposedVideoData SOpenGLWin32 OpenGLWin32; SOpenGLLinux OpenGLLinux; SOpenGLOSX OpenGLOSX; + SOpenGLFB OpenGLFB; SOGLESAndroid OGLESAndroid; }; }; diff --git a/irr/src/CEGLManager.cpp b/irr/src/CEGLManager.cpp index 2f2a412ee209..daaa64fdf536 100644 --- a/irr/src/CEGLManager.cpp +++ b/irr/src/CEGLManager.cpp @@ -40,26 +40,32 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters ¶ms, const SE if (EglWindow != 0 && EglDisplay != EGL_NO_DISPLAY) return true; - // Window is depend on platform. - setWindow(Data); + // Window is depend on platform. #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) + EglWindow = (NativeWindowType)Data.OpenGLWin32.HWnd; + Data.OpenGLWin32.HDc = GetDC((HWND)EglWindow); EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLWin32.HDc); #elif defined(_IRR_EMSCRIPTEN_PLATFORM_) + EglWindow = 0; EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); #elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) + EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window; EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display); +#elif defined(_IRR_COMPILE_WITH_FB_DEVICE_) + EglWindow = (NativeWindowType)Data.OpenGLFB.Window; + EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); #endif // We must check if EGL display is valid. if (EglDisplay == EGL_NO_DISPLAY) { - os::Printer::log("Could not get EGL display.", ELL_ERROR); + os::Printer::log("Could not get EGL display."); terminate(); return false; } // Initialize EGL here. if (!eglInitialize(EglDisplay, &MajorVersion, &MinorVersion)) { - os::Printer::log("Could not initialize EGL display.", ELL_ERROR); + os::Printer::log("Could not initialize EGL display."); EglDisplay = EGL_NO_DISPLAY; terminate(); @@ -70,22 +76,6 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters ¶ms, const SE return true; } -void CEGLManager::setWindow(const SExposedVideoData &inData) -{ -#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) - Data.OpenGLWin32.HWnd = inData.OpenGLWin32.HWnd; - if (Data.OpenGLWin32.HWnd) { - EglWindow = (NativeWindowType)Data.OpenGLWin32.HWnd; - Data.OpenGLWin32.HDc = GetDC((HWND)EglWindow); - } -#elif defined(_IRR_EMSCRIPTEN_PLATFORM_) - EglWindow = 0; -#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) - Data.OpenGLLinux.X11Window = inData.OpenGLLinux.X11Window; - EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window; -#endif -} - void CEGLManager::terminate() { if (EglWindow == 0 && EglDisplay == EGL_NO_DISPLAY) @@ -118,16 +108,20 @@ bool CEGLManager::generateSurface() if (EglSurface != EGL_NO_SURFACE) return true; - if (!EglConfig) { + // We should assign new WindowID on platforms, where WindowID may change at runtime, + // at this time only Android support this feature. + // this needs an update method instead! + #if defined(_IRR_EMSCRIPTEN_PLATFORM_) - EglConfig = chooseConfig(ECS_IRR_CHOOSE); + // eglChooseConfig is currently only implemented as stub in emscripten (version 1.37.22 at point of writing) + // But the other solution would also be fine as it also only generates a single context so there is not much to choose from. + EglConfig = chooseConfig(ECS_IRR_CHOOSE); #else - EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS); + EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS); #endif - } - if (!EglConfig) { - os::Printer::log("Could not choose EGL config.", ELL_ERROR); + if (EglConfig == 0) { + os::Printer::log("Could not get config for EGL display."); return false; } @@ -138,26 +132,11 @@ bool CEGLManager::generateSurface() EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, 0, 0); if (EGL_NO_SURFACE == EglSurface) - os::Printer::log("Could not create EGL surface.", ELL_ERROR); + os::Printer::log("Could not create EGL surface."); #ifdef EGL_VERSION_1_2 - if (MinorVersion > 1) { - EGLBoolean ok = 0; - switch (Params.DriverType) { - case EDT_OGLES2: - case EDT_WEBGL1: - ok = eglBindAPI(EGL_OPENGL_ES_API); - break; - case EDT_OPENGL: - ok = eglBindAPI(EGL_OPENGL_API); - default: - break; - } - if (!ok) { - os::Printer::log("Could not bind EGL API.", ELL_ERROR); - return false; - } - } + if (MinorVersion > 1) + eglBindAPI(EGL_OPENGL_ES_API); #endif if (Params.Vsync) @@ -166,26 +145,6 @@ bool CEGLManager::generateSurface() return true; } -EGLint CEGLManager::getNativeVisualID() -{ - if (!EglConfig) { -#if defined(_IRR_EMSCRIPTEN_PLATFORM_) - EglConfig = chooseConfig(ECS_IRR_CHOOSE); -#else - EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS); -#endif - } - - if (!EglConfig) { - os::Printer::log("Could not choose EGL config.", ELL_WARNING); - return 0; - } - - EGLint ret = 0; - eglGetConfigAttrib(EglDisplay, EglConfig, EGL_NATIVE_VISUAL_ID, &ret); - return ret; -} - EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle) { EGLConfig configResult = 0; @@ -197,8 +156,6 @@ EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle) case EDT_WEBGL1: eglOpenGLBIT = EGL_OPENGL_ES2_BIT; break; - case EDT_OPENGL: - eglOpenGLBIT = EGL_OPENGL_BIT; default: break; } @@ -339,8 +296,6 @@ EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle) } delete[] configs; - } else { - _IRR_DEBUG_BREAK_IF(1) } return configResult; @@ -498,36 +453,33 @@ bool CEGLManager::generateContext() if (EglContext != EGL_NO_CONTEXT) return true; - std::vector ContextAttrib; + EGLint OpenGLESVersion = 0; switch (Params.DriverType) { case EDT_OGLES2: case EDT_WEBGL1: -#ifdef EGL_VERSION_1_3 - ContextAttrib.push_back(EGL_CONTEXT_CLIENT_VERSION); - ContextAttrib.push_back(2); -#endif - break; - case EDT_OPENGL: -#ifdef EGL_VERSION_1_5 - ContextAttrib.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK); - ContextAttrib.push_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); -#endif + OpenGLESVersion = 2; break; default: break; } - ContextAttrib.push_back(EGL_NONE); - ContextAttrib.push_back(0); + EGLint ContextAttrib[] = { +#ifdef EGL_VERSION_1_3 + EGL_CONTEXT_CLIENT_VERSION, OpenGLESVersion, +#endif + EGL_NONE, 0, + }; - EglContext = eglCreateContext(EglDisplay, EglConfig, EGL_NO_CONTEXT, ContextAttrib.data()); + EglContext = eglCreateContext(EglDisplay, EglConfig, EGL_NO_CONTEXT, ContextAttrib); if (testEGLError()) { os::Printer::log("Could not create EGL context.", ELL_ERROR); return false; } + os::Printer::log("EGL context created with OpenGLESVersion: ", core::stringc((int)OpenGLESVersion), ELL_DEBUG); + return true; } diff --git a/irr/src/CEGLManager.h b/irr/src/CEGLManager.h index 2a1338b9def0..49371e469d96 100644 --- a/irr/src/CEGLManager.h +++ b/irr/src/CEGLManager.h @@ -31,10 +31,6 @@ class CEGLManager : public IContextManager aren't create. */ bool initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &data) override; - // Set EGL window. - // Call this if window is not known at time of initialize() - void setWindow(const SExposedVideoData &data); - // Terminate EGL. /* Terminate EGL context. This method break both existed surface and context. */ void terminate() override; @@ -70,9 +66,6 @@ class CEGLManager : public IContextManager // Swap buffers. bool swapBuffers() override; - // Returns native visual ID. Will choose config if not already done. - EGLint getNativeVisualID(); - protected: enum EConfigStyle { diff --git a/irr/src/CGLXManager.cpp b/irr/src/CGLXManager.cpp new file mode 100644 index 000000000000..8593621b76e3 --- /dev/null +++ b/irr/src/CGLXManager.cpp @@ -0,0 +1,401 @@ +// Copyright (C) 2013 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "CGLXManager.h" + +#ifdef _IRR_COMPILE_WITH_GLX_MANAGER_ + +#include "os.h" + +#define GL_GLEXT_LEGACY 1 +#define GLX_GLXEXT_LEGACY 1 +#include +#include +#include +#include + +namespace irr +{ +namespace video +{ + +CGLXManager::CGLXManager(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata, int screennr) : + Params(params), PrimaryContext(videodata), VisualInfo(0), glxFBConfig(0), GlxWin(0) +{ +#ifdef _DEBUG + setDebugName("CGLXManager"); +#endif + + CurrentContext.OpenGLLinux.X11Display = PrimaryContext.OpenGLLinux.X11Display; + + int major, minor; + Display *display = (Display *)PrimaryContext.OpenGLLinux.X11Display; + const bool isAvailableGLX = glXQueryExtension(display, &major, &minor); + + if (isAvailableGLX && glXQueryVersion(display, &major, &minor)) { +#if defined(GLX_VERSION_1_3) + typedef GLXFBConfig *(*PFNGLXCHOOSEFBCONFIGPROC)(Display *dpy, int screen, const int *attrib_list, int *nelements); + + PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddress(reinterpret_cast("glXChooseFBConfig")); + if (major == 1 && minor > 2 && glxChooseFBConfig) { + os::Printer::log("GLX >= 1.3", ELL_DEBUG); + // attribute array for the draw buffer + int visualAttrBuffer[] = { + GLX_RENDER_TYPE, + GLX_RGBA_BIT, + GLX_RED_SIZE, + 4, + GLX_GREEN_SIZE, + 4, + GLX_BLUE_SIZE, + 4, + GLX_ALPHA_SIZE, + Params.WithAlphaChannel ? 1 : 0, + GLX_DEPTH_SIZE, + Params.ZBufferBits, // 10,11 + GLX_DOUBLEBUFFER, + Params.Doublebuffer ? True : False, + GLX_STENCIL_SIZE, + Params.Stencilbuffer ? 1 : 0, +#if defined(GLX_VERSION_1_4) && defined(GLX_SAMPLE_BUFFERS) // we need to check the extension string! + GLX_SAMPLE_BUFFERS, + 1, + GLX_SAMPLES, + Params.AntiAlias, // 18,19 +#elif defined(GLX_ARB_multisample) + GLX_SAMPLE_BUFFERS_ARB, + 1, + GLX_SAMPLES_ARB, + Params.AntiAlias, // 18,19 +#elif defined(GLX_SGIS_multisample) + GLX_SAMPLE_BUFFERS_SGIS, + 1, + GLX_SAMPLES_SGIS, + Params.AntiAlias, // 18,19 +#endif + GLX_STEREO, + Params.Stereobuffer ? True : False, + None, + }; + + GLXFBConfig *configList = 0; + int nitems = 0; + if (Params.AntiAlias < 2) { + visualAttrBuffer[17] = 0; + visualAttrBuffer[19] = 0; + } + // first round with unchanged values + { + configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); + if (!configList && Params.AntiAlias) { + while (!configList && (visualAttrBuffer[19] > 1)) { + visualAttrBuffer[19] -= 1; + configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); + } + if (!configList) { + visualAttrBuffer[17] = 0; + visualAttrBuffer[19] = 0; + configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); + if (configList) { + os::Printer::log("No FSAA available.", ELL_WARNING); + Params.AntiAlias = 0; + } else { + // reenable multisampling + visualAttrBuffer[17] = 1; + visualAttrBuffer[19] = Params.AntiAlias; + } + } + } + } + // Next try with flipped stencil buffer value + // If the first round was with stencil flag it's now without + // Other way round also makes sense because some configs + // only have depth buffer combined with stencil buffer + if (!configList) { + if (Params.Stencilbuffer) + os::Printer::log("No stencilbuffer available, disabling stencil shadows.", ELL_WARNING); + Params.Stencilbuffer = !Params.Stencilbuffer; + visualAttrBuffer[15] = Params.Stencilbuffer ? 1 : 0; + + configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); + if (!configList && Params.AntiAlias) { + while (!configList && (visualAttrBuffer[19] > 1)) { + visualAttrBuffer[19] -= 1; + configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); + } + if (!configList) { + visualAttrBuffer[17] = 0; + visualAttrBuffer[19] = 0; + configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); + if (configList) { + os::Printer::log("No FSAA available.", ELL_WARNING); + Params.AntiAlias = 0; + } else { + // reenable multisampling + visualAttrBuffer[17] = 1; + visualAttrBuffer[19] = Params.AntiAlias; + } + } + } + } + // Next try without double buffer + if (!configList && Params.Doublebuffer) { + os::Printer::log("No doublebuffering available.", ELL_WARNING); + Params.Doublebuffer = false; + visualAttrBuffer[13] = GLX_DONT_CARE; + Params.Stencilbuffer = false; + visualAttrBuffer[15] = 0; + configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); + if (!configList && Params.AntiAlias) { + while (!configList && (visualAttrBuffer[19] > 1)) { + visualAttrBuffer[19] -= 1; + configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); + } + if (!configList) { + visualAttrBuffer[17] = 0; + visualAttrBuffer[19] = 0; + configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); + if (configList) { + os::Printer::log("No FSAA available.", ELL_WARNING); + Params.AntiAlias = 0; + } else { + // reenable multisampling + visualAttrBuffer[17] = 1; + visualAttrBuffer[19] = Params.AntiAlias; + } + } + } + } + if (configList) { + glxFBConfig = configList[0]; + XFree(configList); + typedef XVisualInfo *(*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display *dpy, GLXFBConfig config); + PFNGLXGETVISUALFROMFBCONFIGPROC glxGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddress(reinterpret_cast("glXGetVisualFromFBConfig")); + if (glxGetVisualFromFBConfig) + VisualInfo = glxGetVisualFromFBConfig(display, (GLXFBConfig)glxFBConfig); + } + } else +#endif + { + // attribute array for the draw buffer + int visualAttrBuffer[] = { + GLX_RGBA, GLX_USE_GL, + GLX_RED_SIZE, 4, + GLX_GREEN_SIZE, 4, + GLX_BLUE_SIZE, 4, + GLX_ALPHA_SIZE, Params.WithAlphaChannel ? 1 : 0, + GLX_DEPTH_SIZE, Params.ZBufferBits, + GLX_STENCIL_SIZE, Params.Stencilbuffer ? 1 : 0, // 12,13 + // The following attributes have no flags, but are + // either present or not. As a no-op we use + // GLX_USE_GL, which is silently ignored by glXChooseVisual + Params.Doublebuffer ? GLX_DOUBLEBUFFER : GLX_USE_GL, // 14 + Params.Stereobuffer ? GLX_STEREO : GLX_USE_GL, // 15 + None, + }; + + VisualInfo = glXChooseVisual(display, screennr, visualAttrBuffer); + if (!VisualInfo) { + if (Params.Stencilbuffer) + os::Printer::log("No stencilbuffer available, disabling.", ELL_WARNING); + Params.Stencilbuffer = !Params.Stencilbuffer; + visualAttrBuffer[13] = Params.Stencilbuffer ? 1 : 0; + + VisualInfo = glXChooseVisual(display, screennr, visualAttrBuffer); + if (!VisualInfo && Params.Doublebuffer) { + os::Printer::log("No doublebuffering available.", ELL_WARNING); + Params.Doublebuffer = false; + visualAttrBuffer[14] = GLX_USE_GL; + VisualInfo = glXChooseVisual(display, screennr, visualAttrBuffer); + } + } + } + } else + os::Printer::log("No GLX support available. OpenGL driver will not work.", ELL_WARNING); +} + +CGLXManager::~CGLXManager() +{ +} + +bool CGLXManager::initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata) +{ + // store params + Params = params; + + // set display + CurrentContext.OpenGLLinux.X11Display = videodata.OpenGLLinux.X11Display; + + // now get new window + CurrentContext.OpenGLLinux.X11Window = videodata.OpenGLLinux.X11Window; + if (!PrimaryContext.OpenGLLinux.X11Window) { + PrimaryContext.OpenGLLinux.X11Window = CurrentContext.OpenGLLinux.X11Window; + } + + return true; +} + +void CGLXManager::terminate() +{ + memset((void *)&CurrentContext, 0, sizeof(CurrentContext)); +} + +bool CGLXManager::generateSurface() +{ + if (glxFBConfig) { + GlxWin = glXCreateWindow((Display *)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, CurrentContext.OpenGLLinux.X11Window, NULL); + if (!GlxWin) { + os::Printer::log("Could not create GLX window.", ELL_WARNING); + return false; + } + + CurrentContext.OpenGLLinux.GLXWindow = GlxWin; + } else { + CurrentContext.OpenGLLinux.GLXWindow = CurrentContext.OpenGLLinux.X11Window; + } + return true; +} + +void CGLXManager::destroySurface() +{ + if (GlxWin) + glXDestroyWindow((Display *)CurrentContext.OpenGLLinux.X11Display, GlxWin); +} + +#if defined(GLX_ARB_create_context) +static int IrrIgnoreError(Display *display, XErrorEvent *event) +{ + char msg[256]; + XGetErrorText(display, event->error_code, msg, 256); + os::Printer::log("Ignoring an X error", msg, ELL_DEBUG); + return 0; +} +#endif + +bool CGLXManager::generateContext() +{ + GLXContext context = 0; + + if (glxFBConfig) { + if (GlxWin) { +#if defined(GLX_ARB_create_context) + + PFNGLXCREATECONTEXTATTRIBSARBPROC glxCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress(reinterpret_cast("glXCreateContextAttribsARB")); + + if (glxCreateContextAttribsARB) { + os::Printer::log("GLX with GLX_ARB_create_context", ELL_DEBUG); + int contextAttrBuffer[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 0, + // GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None}; + XErrorHandler old = XSetErrorHandler(IrrIgnoreError); + context = glxCreateContextAttribsARB((Display *)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, NULL, True, contextAttrBuffer); + XSetErrorHandler(old); + // transparently fall back to legacy call + } + if (!context) +#endif + { + // create glx context + context = glXCreateNewContext((Display *)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, GLX_RGBA_TYPE, NULL, True); + if (!context) { + os::Printer::log("Could not create GLX rendering context.", ELL_WARNING); + return false; + } + } + } else { + os::Printer::log("GLX window was not properly created.", ELL_WARNING); + return false; + } + } else { + context = glXCreateContext((Display *)CurrentContext.OpenGLLinux.X11Display, VisualInfo, NULL, True); + if (!context) { + os::Printer::log("Could not create GLX rendering context.", ELL_WARNING); + return false; + } + } + CurrentContext.OpenGLLinux.X11Context = context; + return true; +} + +const SExposedVideoData &CGLXManager::getContext() const +{ + return CurrentContext; +} + +bool CGLXManager::activateContext(const SExposedVideoData &videoData, bool restorePrimaryOnZero) +{ + // TODO: handle restorePrimaryOnZero + + if (videoData.OpenGLLinux.X11Window) { + if (videoData.OpenGLLinux.X11Display && videoData.OpenGLLinux.X11Context) { + if (!glXMakeCurrent((Display *)videoData.OpenGLLinux.X11Display, videoData.OpenGLLinux.GLXWindow, (GLXContext)videoData.OpenGLLinux.X11Context)) { + os::Printer::log("Context activation failed."); + return false; + } else { + CurrentContext.OpenGLLinux.GLXWindow = videoData.OpenGLLinux.GLXWindow; + CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window; + CurrentContext.OpenGLLinux.X11Display = videoData.OpenGLLinux.X11Display; + } + } else { + // in case we only got a window ID, try with the existing values for display and context + if (!glXMakeCurrent((Display *)PrimaryContext.OpenGLLinux.X11Display, videoData.OpenGLLinux.GLXWindow, (GLXContext)PrimaryContext.OpenGLLinux.X11Context)) { + os::Printer::log("Context activation failed."); + return false; + } else { + CurrentContext.OpenGLLinux.GLXWindow = videoData.OpenGLLinux.GLXWindow; + CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window; + CurrentContext.OpenGLLinux.X11Display = PrimaryContext.OpenGLLinux.X11Display; + } + } + } else if (!restorePrimaryOnZero && !videoData.OpenGLLinux.X11Window && !videoData.OpenGLLinux.X11Display) { + if (!glXMakeCurrent((Display *)PrimaryContext.OpenGLLinux.X11Display, None, NULL)) { + os::Printer::log("Render Context reset failed."); + return false; + } + CurrentContext.OpenGLLinux.X11Window = 0; + CurrentContext.OpenGLLinux.X11Display = 0; + } + // set back to main context + else if (CurrentContext.OpenGLLinux.X11Display != PrimaryContext.OpenGLLinux.X11Display) { + if (!glXMakeCurrent((Display *)PrimaryContext.OpenGLLinux.X11Display, PrimaryContext.OpenGLLinux.X11Window, (GLXContext)PrimaryContext.OpenGLLinux.X11Context)) { + os::Printer::log("Context activation failed."); + return false; + } else { + CurrentContext = PrimaryContext; + } + } + return true; +} + +void CGLXManager::destroyContext() +{ + if (CurrentContext.OpenGLLinux.X11Context) { + if (GlxWin) { + if (!glXMakeContextCurrent((Display *)CurrentContext.OpenGLLinux.X11Display, None, None, NULL)) + os::Printer::log("Could not release glx context.", ELL_WARNING); + } else { + if (!glXMakeCurrent((Display *)CurrentContext.OpenGLLinux.X11Display, None, NULL)) + os::Printer::log("Could not release glx context.", ELL_WARNING); + } + glXDestroyContext((Display *)CurrentContext.OpenGLLinux.X11Display, (GLXContext)CurrentContext.OpenGLLinux.X11Context); + } +} + +void *CGLXManager::getProcAddress(const std::string &procName) +{ + return (void *)glXGetProcAddressARB(reinterpret_cast(procName.c_str())); +} + +bool CGLXManager::swapBuffers() +{ + glXSwapBuffers((Display *)CurrentContext.OpenGLLinux.X11Display, CurrentContext.OpenGLLinux.GLXWindow); + return true; +} + +} +} + +#endif diff --git a/irr/src/CGLXManager.h b/irr/src/CGLXManager.h new file mode 100644 index 000000000000..f940d4316134 --- /dev/null +++ b/irr/src/CGLXManager.h @@ -0,0 +1,76 @@ +// Copyright (C) 2013 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#pragma once + +#ifdef _IRR_COMPILE_WITH_GLX_MANAGER_ + +#include "SIrrCreationParameters.h" +#include "SExposedVideoData.h" +#include "IContextManager.h" +#include "SColor.h" +#include +#include + +// we can't include glx.h here, because gl.h has incompatible types with ogl es headers and it +// cause redefinition errors, thats why we use ugly trick with void* types and casts. + +namespace irr +{ +namespace video +{ +// GLX manager. +class CGLXManager : public IContextManager +{ +public: + //! Constructor. + CGLXManager(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata, int screennr); + + //! Destructor + ~CGLXManager(); + + // Initialize + bool initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &data) override; + + // Terminate + void terminate() override; + + // Create surface. + bool generateSurface() override; + + // Destroy surface. + void destroySurface() override; + + // Create context. + bool generateContext() override; + + // Destroy context. + void destroyContext() override; + + //! Get current context + const SExposedVideoData &getContext() const override; + + //! Change render context, disable old and activate new defined by videoData + bool activateContext(const SExposedVideoData &videoData, bool restorePrimaryOnZero) override; + + // Get procedure address. + void *getProcAddress(const std::string &procName) override; + + // Swap buffers. + bool swapBuffers() override; + + XVisualInfo *getVisual() const { return VisualInfo; } // return XVisualInfo + +private: + SIrrlichtCreationParameters Params; + SExposedVideoData PrimaryContext; + SExposedVideoData CurrentContext; + XVisualInfo *VisualInfo; + void *glxFBConfig; // GLXFBConfig + XID GlxWin; // GLXWindow +}; +} +} + +#endif diff --git a/irr/src/CIrrDeviceLinux.cpp b/irr/src/CIrrDeviceLinux.cpp index bb6968f031e7..c00f523807a9 100644 --- a/irr/src/CIrrDeviceLinux.cpp +++ b/irr/src/CIrrDeviceLinux.cpp @@ -34,10 +34,14 @@ #include #endif -#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES2_) +#if defined(_IRR_COMPILE_WITH_OGLES2_) #include "CEGLManager.h" #endif +#if defined(_IRR_COMPILE_WITH_OPENGL_) +#include "CGLXManager.h" +#endif + #ifdef _IRR_LINUX_XCURSOR_ #include #endif @@ -148,20 +152,8 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters ¶m) : // without it, multi-threaded GL drivers may crash XInitThreads(); + // create window if (CreationParams.DriverType != video::EDT_NULL) { - // initialize EGL so it can choose a config -#ifdef _IRR_COMPILE_WITH_X11_ -#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES2_) - video::SExposedVideoData data; - data.OpenGLLinux.X11Window = 0; // not created yet, but that's ok - data.OpenGLLinux.X11Display = XDisplay; - - ContextManager = new video::CEGLManager(); - if (!ContextManager->initialize(CreationParams, data)) - return; -#endif -#endif - // create the window, only if we do not use the null device if (!createWindow()) return; @@ -405,14 +397,14 @@ bool CIrrDeviceLinux::createWindow() if (WMCheck != None) HasNetWM = true; -#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES2_) - if (ContextManager) { - auto *c = static_cast(ContextManager); - os::Printer::log("Using X visual from EGL"); - XVisualInfo templ; - int n; - templ.visualid = static_cast(c->getNativeVisualID()); - VisualInfo = XGetVisualInfo(XDisplay, VisualIDMask, &templ, &n); +#if defined(_IRR_COMPILE_WITH_OPENGL_) + // don't use the XVisual with OpenGL, because it ignores all requested + // properties of the CreationParams + if (CreationParams.DriverType == video::EDT_OPENGL) { + video::SExposedVideoData data; + data.OpenGLLinux.X11Display = XDisplay; + ContextManager = new video::CGLXManager(CreationParams, data, Screennr); + VisualInfo = ((video::CGLXManager *)ContextManager)->getVisual(); } #endif @@ -551,7 +543,9 @@ void CIrrDeviceLinux::createDriver() { video::SExposedVideoData data; data.OpenGLLinux.X11Window = XWindow; - static_cast(ContextManager)->setWindow(data); + data.OpenGLLinux.X11Display = XDisplay; + + ContextManager->initialize(CreationParams, data); VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); } @@ -564,7 +558,10 @@ void CIrrDeviceLinux::createDriver() { video::SExposedVideoData data; data.OpenGLLinux.X11Window = XWindow; - static_cast(ContextManager)->setWindow(data); + data.OpenGLLinux.X11Display = XDisplay; + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); } @@ -577,7 +574,10 @@ void CIrrDeviceLinux::createDriver() { video::SExposedVideoData data; data.OpenGLLinux.X11Window = XWindow; - static_cast(ContextManager)->setWindow(data); + data.OpenGLLinux.X11Display = XDisplay; + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager); } diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index a31f0790da52..768ee8d37c76 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -158,7 +158,7 @@ if(ENABLE_OPENGL) if(DEVICE STREQUAL "WINDOWS") add_definitions(-D_IRR_COMPILE_WITH_WGL_MANAGER_) elseif(DEVICE STREQUAL "X11") - add_definitions(-D_IRR_COMPILE_WITH_EGL_MANAGER_) + add_definitions(-D_IRR_COMPILE_WITH_GLX_MANAGER_) elseif(DEVICE STREQUAL "OSX") add_definitions(-D_IRR_COMPILE_WITH_NSOGL_MANAGER_) endif() @@ -213,15 +213,7 @@ if(ENABLE_GLES2) find_package(OpenGLES2 REQUIRED) endif() if(ENABLE_OPENGL) - if(DEVICE STREQUAL "X11") - # use components so we can grab EGL - find_package(OpenGL REQUIRED COMPONENTS EGL OpenGL) - set(OPENGL_LIBRARIES OpenGL::GL) - set(EGL_INCLUDE_DIR OpenGL::EGL) - set(EGL_LIBRARY OpenGL::EGL) - else() - find_package(OpenGL REQUIRED) - endif() + find_package(OpenGL REQUIRED) endif() if(USE_SDL2) if(NOT ANDROID) @@ -338,6 +330,7 @@ target_link_libraries(IRROBJ PRIVATE IRRMESHOBJ) set(IRRDRVROBJ CNullDriver.cpp + CGLXManager.cpp CWGLManager.cpp CEGLManager.cpp CSDLManager.cpp diff --git a/irr/src/COpenGLDriver.cpp b/irr/src/COpenGLDriver.cpp index ee63fc84583b..e5f070f8e86e 100644 --- a/irr/src/COpenGLDriver.cpp +++ b/irr/src/COpenGLDriver.cpp @@ -40,10 +40,8 @@ COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters ¶ms, io::IFil bool COpenGLDriver::initDriver() { - if (!ContextManager->generateSurface()) - return false; - if (!ContextManager->generateContext()) - return false; + ContextManager->generateSurface(); + ContextManager->generateContext(); ExposedData = ContextManager->getContext(); ContextManager->activateContext(ExposedData, false); GL.LoadAllProcedures(ContextManager);