diff options
author | Caolán McNamara <caolanm@redhat.com> | 2016-05-20 09:41:18 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2016-05-21 10:04:15 +0100 |
commit | b8d163f4334424e78290eae49713e6ba2405b30f (patch) | |
tree | 55e78506accb6fe4dbbc1ecb918e4ccc2f510254 | |
parent | da03b62bb4d44ad1410a4dff15f97bacd55fb99b (diff) |
Split OpenGLContext up into SalInstance specific classes
which, at least theoretically, allows there to be vclplug
specific ones. i.e. a gtk3 specific one which doesn't
assume gtk3 is running under X
Change-Id: I6c007a87abbd3049b6fffc70d349e3b7ac445eec
-rw-r--r-- | avmedia/source/viewer/mediawindow_impl.cxx | 2 | ||||
-rw-r--r-- | include/vcl/opengl/OpenGLContext.hxx | 50 | ||||
-rw-r--r-- | slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionerImpl.cxx | 28 | ||||
-rw-r--r-- | slideshow/source/engine/shapes/viewmediashape.cxx | 2 | ||||
-rw-r--r-- | vcl/headless/svpinst.cxx | 11 | ||||
-rw-r--r-- | vcl/inc/headless/svpinst.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/opengl/zone.hxx | 6 | ||||
-rw-r--r-- | vcl/inc/osx/salinst.h | 1 | ||||
-rw-r--r-- | vcl/inc/salinst.hxx | 3 | ||||
-rw-r--r-- | vcl/inc/unx/salinst.h | 1 | ||||
-rw-r--r-- | vcl/inc/win/salinst.h | 1 | ||||
-rw-r--r-- | vcl/opengl/win/gdiimpl.cxx | 479 | ||||
-rw-r--r-- | vcl/opengl/x11/gdiimpl.cxx | 556 | ||||
-rw-r--r-- | vcl/osx/salobj.cxx | 109 | ||||
-rw-r--r-- | vcl/source/opengl/OpenGLContext.cxx | 1074 | ||||
-rw-r--r-- | vcl/source/window/openglwin.cxx | 2 |
16 files changed, 1230 insertions, 1097 deletions
diff --git a/avmedia/source/viewer/mediawindow_impl.cxx b/avmedia/source/viewer/mediawindow_impl.cxx index 87080ba0d6e6..1bd55af8659b 100644 --- a/avmedia/source/viewer/mediawindow_impl.cxx +++ b/avmedia/source/viewer/mediawindow_impl.cxx @@ -489,7 +489,7 @@ void MediaWindowImpl::onURLChanged() #if HAVE_FEATURE_GLTF else if (m_sMimeType == AVMEDIA_MIMETYPE_JSON) { - SystemWindowData aWinData = OpenGLContext::generateWinData(this, false); + SystemWindowData aWinData = OpenGLContext::Create()->generateWinData(this, false); mpChildWindow.disposeAndClear(); mpChildWindow.reset(VclPtr<MediaChildWindow>::Create(this,&aWinData)); mbEventTransparent = false; diff --git a/include/vcl/opengl/OpenGLContext.hxx b/include/vcl/opengl/OpenGLContext.hxx index 1ca86c7acb61..00368495a332 100644 --- a/include/vcl/opengl/OpenGLContext.hxx +++ b/include/vcl/opengl/OpenGLContext.hxx @@ -65,7 +65,7 @@ class OpenGLTests; class RenderState; /// Holds the information of our new child window -struct GLWindow +struct VCL_DLLPUBLIC GLWindow { #if defined( _WIN32 ) HWND hWnd; @@ -121,16 +121,19 @@ struct GLWindow { } + bool Synchronize(bool bOnoff) const; + ~GLWindow(); }; class VCL_DLLPUBLIC OpenGLContext { friend class OpenGLTests; +protected: OpenGLContext(); public: static rtl::Reference<OpenGLContext> Create(); - ~OpenGLContext(); + virtual ~OpenGLContext(); void acquire() { mnRefCount++; } void release() { if ( --mnRefCount == 0 ) delete this; } void dispose(); @@ -141,13 +144,6 @@ public: bool init(vcl::Window* pParent = nullptr); bool init(SystemChildWindow* pChildWindow); -// these methods are for the deep platform layer, don't use them in normal code -// only in vcl's platform code -#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS) - bool init(Display* dpy, Window win, int screen); -#elif defined( _WIN32 ) - bool init( HDC hDC, HWND hWnd ); -#endif void reset(); // use these methods right after setting a context to make sure drawing happens @@ -173,7 +169,9 @@ public: } /// Is this GL context the current context ? - bool isCurrent(); + virtual bool isCurrent(); + /// Is any GL context the current context ? + virtual bool isAnyCurrent(); /// release bound resources from the current context static void clearCurrent(); /// release contexts etc. before (potentially) allowing another thread run. @@ -186,13 +184,13 @@ public: /// fetch any VCL context, creating one if bMakeIfNecessary is set. static rtl::Reference<OpenGLContext> getVCLContext(bool bMakeIfNecessary = true); /// make this GL context current - so it is implicit in subsequent GL calls - void makeCurrent(); + virtual void makeCurrent(); /// Put this GL context to the end of the context list. void registerAsCurrent(); /// reset the GL context so this context is not implicit in subsequent GL calls. - void resetCurrent(); - void swapBuffers(); - void sync(); + virtual void resetCurrent(); + virtual void swapBuffers(); + virtual void sync(); void show(); void setWinPosAndSize(const Point &rPos, const Size& rSize); @@ -213,23 +211,20 @@ public: bool supportMultiSampling() const; - static SystemWindowData generateWinData(vcl::Window* pParent, bool bRequestLegacyContext); + virtual SystemWindowData generateWinData(vcl::Window* pParent, bool bRequestLegacyContext); private: - SAL_DLLPRIVATE bool InitGLEW(); - SAL_DLLPRIVATE void InitGLEWDebugging(); - SAL_DLLPRIVATE bool initWindow(); - SAL_DLLPRIVATE bool ImplInit(); - SAL_DLLPRIVATE void InitChildWindow(SystemChildWindow *pChildWindow); -#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS) - SAL_DLLPRIVATE void initGLWindow(Visual* pVisual); -#endif - -#if defined(MACOSX) - NSOpenGLView* getOpenGLView(); -#endif + virtual bool initWindow(); + virtual void destroyCurrentContext(); +protected: GLWindow m_aGLWin; + bool InitGLEW(); + void InitGLEWDebugging(); + void InitChildWindow(SystemChildWindow *pChildWindow); + void BuffersSwapped(); + virtual bool ImplInit(); + VclPtr<vcl::Window> m_xWindow; VclPtr<vcl::Window> mpWindow; //points to m_pWindow or the parent window, don't delete it VclPtr<SystemChildWindow> m_pChildWindow; @@ -244,6 +239,7 @@ private: OpenGLFramebuffer* mpFirstFramebuffer; OpenGLFramebuffer* mpLastFramebuffer; +private: struct ProgramHash { size_t operator()( const rtl::OString& aDigest ) const diff --git a/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionerImpl.cxx b/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionerImpl.cxx index 5ba940fa1c90..fa4df10f6a80 100644 --- a/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionerImpl.cxx +++ b/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionerImpl.cxx @@ -67,11 +67,6 @@ #include "OGLTrans_TransitionImpl.hxx" -#if defined( UNX ) && !defined( MACOSX ) - #include <X11/keysym.h> - #include <X11/X.h> -#endif - #include <vcl/sysdata.hxx> #if OSL_DEBUG_LEVEL > 0 @@ -257,9 +252,7 @@ private: bool mbFreeLeavingPixmap; bool mbFreeEnteringPixmap; #endif -#if defined( UNX ) && !defined( MACOSX ) bool mbRestoreSync; -#endif bool mbUseLeavingPixmap; bool mbUseEnteringPixmap; @@ -437,10 +430,9 @@ void OGLTransitionerImpl::impl_prepareSlides() mbUseLeavingPixmap = false; mbUseEnteringPixmap = false; -#if defined( GLX_EXT_texture_from_pixmap ) - const GLWindow& rGLWindow(mpContext->getOpenGLWindow()); +#if defined( GLX_EXT_texture_from_pixmap ) if( GLXEW_EXT_texture_from_pixmap && xLeavingSet.is() && xEnteringSet.is() && mbHasTFPVisual ) { Sequence< Any > leaveArgs; Sequence< Any > enterArgs; @@ -509,8 +501,8 @@ void OGLTransitionerImpl::impl_prepareSlides() XSetErrorHandler( oldHandler ); } } - #endif + if( !mbUseLeavingPixmap ) maLeavingBytes = mxLeavingBitmap->getData(maSlideBitmapLayout, aSlideRect); if( !mbUseEnteringPixmap ) @@ -524,13 +516,11 @@ void OGLTransitionerImpl::impl_prepareSlides() mpContext->sync(); CHECK_GL_ERROR(); -#if defined( UNX ) && !defined( MACOSX ) + // synchronized X still gives us much smoother play // I suspect some issues in above code in slideshow // synchronize whole transition for now - XSynchronize( rGLWindow.dpy, true ); - mbRestoreSync = true; -#endif + mbRestoreSync = rGLWindow.Synchronize(true); } bool OGLTransitionerImpl::impl_prepareTransition() @@ -1326,13 +1316,11 @@ void OGLTransitionerImpl::disposing() } #endif -#if defined( UNX ) && !defined( MACOSX ) - if( mbRestoreSync && bool(mpContext.is()) ) { + if (mbRestoreSync && bool(mpContext.is())) { // try to reestablish synchronize state - char* sal_synchronize = getenv("SAL_SYNCHRONIZE"); - XSynchronize( mpContext->getOpenGLWindow().dpy, sal_synchronize && *sal_synchronize == '1' ); + const char* sal_synchronize = getenv("SAL_SYNCHRONIZE"); + mpContext->getOpenGLWindow().Synchronize(sal_synchronize && *sal_synchronize == '1' ); } -#endif impl_dispose(); @@ -1359,9 +1347,7 @@ OGLTransitionerImpl::OGLTransitionerImpl() , mbFreeLeavingPixmap(false) , mbFreeEnteringPixmap(false) #endif -#if defined( UNX ) && !defined( MACOSX ) , mbRestoreSync(false) -#endif , mbUseLeavingPixmap(false) , mbUseEnteringPixmap(false) , maSlideBitmapLayout() diff --git a/slideshow/source/engine/shapes/viewmediashape.cxx b/slideshow/source/engine/shapes/viewmediashape.cxx index e0c30a27b139..0db3ea64f91d 100644 --- a/slideshow/source/engine/shapes/viewmediashape.cxx +++ b/slideshow/source/engine/shapes/viewmediashape.cxx @@ -463,7 +463,7 @@ namespace slideshow Size( aAWTRect.Width, aAWTRect.Height ) ); mpEventHandlerParent->EnablePaint(false); mpEventHandlerParent->Show(); - SystemWindowData aWinData = OpenGLContext::generateWinData(mpEventHandlerParent.get(), false); + SystemWindowData aWinData = OpenGLContext::Create()->generateWinData(mpEventHandlerParent.get(), false); mpMediaWindow = VclPtr<SystemChildWindow>::Create(mpEventHandlerParent.get(), 0, &aWinData); mpMediaWindow->SetPosSizePixel( Point( 0, 0 ), Size( aAWTRect.Width, aAWTRect.Height ) ); diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx index 0bd50fe4e59a..2665bb509d70 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -27,6 +27,7 @@ #include <sal/types.h> #include <vcl/inputtypes.hxx> +#include <vcl/opengl/OpenGLContext.hxx> #include <headless/svpinst.hxx> #include <headless/svpframe.hxx> @@ -443,6 +444,16 @@ void SvpSalInstance::AddToRecentDocumentList(const OUString&, const OUString&, c { } +//obviously doesn't actually do anything, its just a nonfunctional stub +class SvpOpenGLContext : public OpenGLContext +{ +}; + +OpenGLContext* SvpSalInstance::CreateOpenGLContext() +{ + return new SvpOpenGLContext; +} + SvpSalTimer::~SvpSalTimer() { } diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx index ae23d71fa6ba..932e928fdbfe 100644 --- a/vcl/inc/headless/svpinst.hxx +++ b/vcl/inc/headless/svpinst.hxx @@ -163,6 +163,8 @@ public: // may return NULL to disable session management virtual SalSession* CreateSalSession() override; + virtual OpenGLContext* CreateOpenGLContext() override; + virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) override; virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService) override; diff --git a/vcl/inc/opengl/zone.hxx b/vcl/inc/opengl/zone.hxx index c6ba0ccc7487..11f6ed00ec3c 100644 --- a/vcl/inc/opengl/zone.hxx +++ b/vcl/inc/opengl/zone.hxx @@ -21,7 +21,7 @@ class OpenGLWatchdogThread; * We want to be able to detect if a given crash came * from the OpenGL code, so use this helper to track that. */ -class OpenGLZone { +class VCL_DLLPUBLIC OpenGLZone { friend class OpenGLZoneTest; friend class OpenGLWatchdogThread; friend class OpenGLSalGraphicsImpl; @@ -31,8 +31,8 @@ class OpenGLZone { /// how many times have we left a new GL zone static volatile sal_uInt64 gnLeaveCount; - static VCL_DLLPUBLIC void enter(); - static VCL_DLLPUBLIC void leave(); + static void enter(); + static void leave(); public: OpenGLZone() { gnEnterCount++; } ~OpenGLZone() { gnLeaveCount++; } diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index 20f3e3e314d5..61448259c1b9 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -117,6 +117,7 @@ public: virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData ) override; virtual void DestroyMenuItem( SalMenuItem* ) override; virtual SalSession* CreateSalSession() override; + virtual OpenGLContext* CreateOpenGLContext() override; virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) override; virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx index 6502679d426a..21f7be27711f 100644 --- a/vcl/inc/salinst.hxx +++ b/vcl/inc/salinst.hxx @@ -36,6 +36,7 @@ namespace comphelper { class SolarMutex; } struct SystemParentData; struct SalPrinterQueueInfo; struct ImplJobSetup; +class OpenGLContext; class SalGraphics; class SalFrame; class SalObject; @@ -145,6 +146,8 @@ public: // may return NULL to disable session management virtual SalSession* CreateSalSession() = 0; + virtual OpenGLContext* CreateOpenGLContext() = 0; + // methods for XDisplayConnection void SetEventCallback( rtl::Reference< vcl::DisplayConnectionDispatch > const & pInstance ) diff --git a/vcl/inc/unx/salinst.h b/vcl/inc/unx/salinst.h index cc0e086e5d77..8cb1014fb743 100644 --- a/vcl/inc/unx/salinst.h +++ b/vcl/inc/unx/salinst.h @@ -69,6 +69,7 @@ public: virtual SalSystem* CreateSalSystem() override; virtual SalBitmap* CreateSalBitmap() override; virtual SalSession* CreateSalSession() override; + virtual OpenGLContext* CreateOpenGLContext() override; virtual SalYieldResult DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override; virtual bool AnyInput( VclInputFlags nType ) override; diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h index 43c0313efa7d..23c0de7c9568 100644 --- a/vcl/inc/win/salinst.h +++ b/vcl/inc/win/salinst.h @@ -71,6 +71,7 @@ public: virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData ) override; virtual void DestroyMenuItem( SalMenuItem* ) override; virtual SalSession* CreateSalSession() override; + virtual OpenGLContext* CreateOpenGLContext() override; virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) override; virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService) override; diff --git a/vcl/opengl/win/gdiimpl.cxx b/vcl/opengl/win/gdiimpl.cxx index 7fbf8f787639..50fb3928600e 100644 --- a/vcl/opengl/win/gdiimpl.cxx +++ b/vcl/opengl/win/gdiimpl.cxx @@ -12,6 +12,477 @@ #include <win/wincomp.hxx> #include <win/saldata.hxx> #include <win/salframe.h> +#include <win/salinst.h> + +static std::vector<HGLRC> g_vShareList; + +class WinOpenGLContext : public OpenGLContext +{ +public: + bool init( HDC hDC, HWND hWnd ); + virtual bool initWindow() override; +private: + virtual bool ImplInit() override; + virtual void makeCurrent() override; + virtual void destroyCurrentContext() override; + virtual bool isCurrent() override; + virtual bool isAnyCurrent() override; + virtual void resetCurrent() override; + virtual void swapBuffers() override; +}; + +void WinOpenGLContext::swapBuffers() +{ + OpenGLZone aZone; + + SwapBuffers(m_aGLWin.hDC); + + BuffersSwapped(); +} + +void WinOpenGLContext::resetCurrent() +{ + clearCurrent(); + + OpenGLZone aZone; + + wglMakeCurrent(NULL, NULL); +} + +bool WinOpenGLContext::isCurrent() +{ + OpenGLZone aZone; + return wglGetCurrentContext() == m_aGLWin.hRC && + wglGetCurrentDC() == m_aGLWin.hDC; +} + +bool WinOpenGLContext::isAnyCurrent() +{ + return wglGetCurrentContext() != NULL; +} + +void WinOpenGLContext::makeCurrent() +{ + if (isCurrent()) + return; + + OpenGLZone aZone; + + clearCurrent(); + + if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) + { + SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent(): wglMakeCurrent failed: " << GetLastError()); + return; + } + + registerAsCurrent(); +} + +bool WinOpenGLContext::init(HDC hDC, HWND hWnd) +{ + if (isInitialized()) + return false; + + m_aGLWin.hDC = hDC; + m_aGLWin.hWnd = hWnd; + return ImplInit(); +} + +bool WinOpenGLContext::initWindow() +{ + if( !m_pChildWindow ) + { + SystemWindowData winData = generateWinData(mpWindow, false); + m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false); + } + + if (m_pChildWindow) + { + InitChildWindow(m_pChildWindow.get()); + const SystemEnvData* sysData(m_pChildWindow->GetSystemData()); + m_aGLWin.hWnd = sysData->hWnd; + } + + m_aGLWin.hDC = GetDC(m_aGLWin.hWnd); + return true; +} + +void WinOpenGLContext::destroyCurrentContext() +{ + if (m_aGLWin.hRC) + { + std::vector<HGLRC>::iterator itr = std::remove(g_vShareList.begin(), g_vShareList.end(), m_aGLWin.hRC); + if (itr != g_vShareList.end()) + g_vShareList.erase(itr); + + if (wglGetCurrentContext() != NULL) + wglMakeCurrent(NULL, NULL); + wglDeleteContext( m_aGLWin.hRC ); + ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC ); + m_aGLWin.hRC = 0; + } +} + +static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_CREATE: + return 0; + case WM_CLOSE: + PostQuitMessage(0); + return 0; + case WM_DESTROY: + return 0; + case WM_KEYDOWN: + switch(wParam) + { + case VK_ESCAPE: + PostQuitMessage(0); + return 0; + + case VK_SPACE: + break; + } + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } +} + +int InitTempWindow(HWND *hwnd, int width, int height, const PIXELFORMATDESCRIPTOR& inPfd, GLWindow& glWin) +{ + OpenGLZone aZone; + + PIXELFORMATDESCRIPTOR pfd = inPfd; + int pfmt; + int ret; + WNDCLASS wc; + wc.style = 0; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = wc.cbWndExtra = 0; + wc.hInstance = NULL; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = (LPCSTR)"GLRenderer"; + RegisterClass(&wc); + *hwnd = CreateWindow(wc.lpszClassName, NULL, WS_DISABLED, 0, 0, width, height, NULL, NULL, wc.hInstance, NULL); + glWin.hDC = GetDC(*hwnd); + pfmt = ChoosePixelFormat(glWin.hDC, &pfd); + if (!pfmt) + { + return -1; + } + ret = SetPixelFormat(glWin.hDC, pfmt, &pfd); + if(!ret) + { + return -1; + } + glWin.hRC = wglCreateContext(glWin.hDC); + if(!(glWin.hRC)) + { + return -1; + } + ret = wglMakeCurrent(glWin.hDC, glWin.hRC); + if(!ret) + { + return -1; + } + + return 0; +} + +bool WGLisExtensionSupported(const char *extension) +{ + OpenGLZone aZone; + + const size_t extlen = strlen(extension); + const char *supported = NULL; + + // Try to use wglGetExtensionStringARB on current DC, if possible + PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB"); + + if (wglGetExtString) + supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC()); + // If that failed, try standard OpenGL extensions string + if (supported == NULL) + supported = (char*)glGetString(GL_EXTENSIONS); + // If that failed too, must be no extensions supported + if (supported == NULL) + return false; + + // Begin examination at start of string, increment by 1 on false match + for (const char* p = supported; ; p++) + { + // Advance p up to the next possible match + p = strstr(p, extension); + + if (p == NULL) + return 0; // No Match + + // Make sure that match is at the start of the string or that + // the previous char is a space, or else we could accidentally + // match "wglFunkywglExtension" with "wglExtension" + + // Also, make sure that the following character is space or null + // or else "wglExtensionTwo" might match "wglExtension" + if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' ')) + return 1; // Match + } +} + +bool InitMultisample(const PIXELFORMATDESCRIPTOR& pfd, int& rPixelFormat, + bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice) +{ + OpenGLZone aZone; + + HWND hWnd = NULL; + GLWindow glWin; + // Create a temp window to check whether support multi-sample, if support, get the format + if (InitTempWindow(&hWnd, 1, 1, pfd, glWin) < 0) + { + SAL_WARN("vcl.opengl", "Can't create temp window to test"); + return false; + } + + // See if the string exists in WGL + if (!WGLisExtensionSupported("WGL_ARB_multisample")) + { + SAL_WARN("vcl.opengl", "Device doesn't support multisample"); + return false; + } + // Get our pixel format + PFNWGLCHOOSEPIXELFORMATARBPROC fn_wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); + if (!fn_wglChoosePixelFormatARB) + { + return false; + } + // Get our current device context + HDC hDC = GetDC(hWnd); + + int pixelFormat; + int valid; + UINT numFormats; + float fAttributes[] = {0,0}; + // These attributes are the bits we want to test for in our sample. + // Everything is pretty standard, the only one we want to + // really focus on is the WGL_SAMPLE_BUFFERS_ARB and WGL_SAMPLES_ARB. + // These two are going to do the main testing for whether or not + // we support multisampling on this hardware. + int iAttributes[] = + { + WGL_DOUBLE_BUFFER_ARB,GL_TRUE, + WGL_DRAW_TO_WINDOW_ARB,GL_TRUE, + WGL_SUPPORT_OPENGL_ARB,GL_TRUE, + WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB, + WGL_COLOR_BITS_ARB,24, + WGL_ALPHA_BITS_ARB,8, + WGL_DEPTH_BITS_ARB,24, + WGL_STENCIL_BITS_ARB,0, + WGL_SAMPLE_BUFFERS_ARB,GL_TRUE, + WGL_SAMPLES_ARB,8, + 0,0 + }; + + if (!bUseDoubleBufferedRendering) + { + // Use asserts to make sure the iAttributes array is not changed without changing these ugly + // hardcode indexes into it. + assert(iAttributes[0] == WGL_DOUBLE_BUFFER_ARB); + iAttributes[1] = GL_FALSE; + } + + if (bRequestVirtualDevice) + { + assert(iAttributes[2] == WGL_DRAW_TO_WINDOW_ARB); + iAttributes[2] = WGL_DRAW_TO_BITMAP_ARB; + } + + bool bArbMultisampleSupported = false; + + // First we check to see if we can get a pixel format for 8 samples + valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats); + // If we returned true, and our format count is greater than 1 + if (valid && numFormats >= 1) + { + bArbMultisampleSupported = true; + rPixelFormat = pixelFormat; + wglMakeCurrent(NULL, NULL); + wglDeleteContext(glWin.hRC); + ReleaseDC(hWnd, glWin.hDC); + DestroyWindow(hWnd); + return bArbMultisampleSupported; + } + // Our pixel format with 8 samples failed, test for 2 samples + assert(iAttributes[18] == WGL_SAMPLES_ARB); + iAttributes[19] = 2; + valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats); + if (valid && numFormats >= 1) + { + bArbMultisampleSupported = true; + rPixelFormat = pixelFormat; + wglMakeCurrent(NULL, NULL); + wglDeleteContext(glWin.hRC); + ReleaseDC(hWnd, glWin.hDC); + DestroyWindow(hWnd); + return bArbMultisampleSupported; + } + // Return the valid format + wglMakeCurrent(NULL, NULL); + wglDeleteContext(glWin.hRC); + ReleaseDC(hWnd, glWin.hDC); + DestroyWindow(hWnd); + + return bArbMultisampleSupported; +} + +bool WinOpenGLContext::ImplInit() +{ + OpenGLZone aZone; + + VCL_GL_INFO("OpenGLContext::ImplInit----start"); + // PixelFormat tells Windows how we want things to be + PIXELFORMATDESCRIPTOR PixelFormatFront = + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, // Version Number + PFD_SUPPORT_OPENGL, + PFD_TYPE_RGBA, // Request An RGBA Format + (BYTE)32, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 24, // 24 bit z-buffer + 8, // stencil buffer + 0, // No Auxiliary Buffer + 0, // now ignored + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + if (mbUseDoubleBufferedRendering) + PixelFormatFront.dwFlags |= PFD_DOUBLEBUFFER; + + PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW; + + // we must check whether can set the MSAA + int WindowPix = 0; + bool bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix, + mbUseDoubleBufferedRendering, false); + if (bMultiSampleSupport && WindowPix != 0) + { + m_aGLWin.bMultiSampleSupported = true; + } + else + { + WindowPix = ChoosePixelFormat(m_aGLWin.hDC, &PixelFormatFront); +#if OSL_DEBUG_LEVEL > 0 + PIXELFORMATDESCRIPTOR pfd; + DescribePixelFormat(m_aGLWin.hDC, WindowPix, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + SAL_WARN("vcl.opengl", "Render Target: Window: " << (int) ((pfd.dwFlags & PFD_DRAW_TO_WINDOW) != 0) << ", Bitmap: " << (int) ((pfd.dwFlags & PFD_DRAW_TO_BITMAP) != 0)); + SAL_WARN("vcl.opengl", "Supports OpenGL: " << (int) ((pfd.dwFlags & PFD_SUPPORT_OPENGL) != 0)); +#endif + } + + if (WindowPix == 0) + { + SAL_WARN("vcl.opengl", "Invalid pixelformat"); + return false; + } + + if (!SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront)) + { + ImplWriteLastError(GetLastError(), "SetPixelFormat in OpenGLContext::ImplInit"); + SAL_WARN("vcl.opengl", "SetPixelFormat failed"); + return false; + } + + HGLRC hTempRC = wglCreateContext(m_aGLWin.hDC); + if (hTempRC == NULL) + { + ImplWriteLastError(GetLastError(), "wglCreateContext in OpenGLContext::ImplInit"); + SAL_WARN("vcl.opengl", "wglCreateContext failed"); + return false; + } + + if (!wglMakeCurrent(m_aGLWin.hDC, hTempRC)) + { + ImplWriteLastError(GetLastError(), "wglMakeCurrent in OpenGLContext::ImplInit"); + SAL_WARN("vcl.opengl", "wglMakeCurrent failed"); + return false; + } + + if (!InitGLEW()) + { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hTempRC); + return false; + } + + HGLRC hSharedCtx = 0; + if (!g_vShareList.empty()) + hSharedCtx = g_vShareList.front(); + + if (!wglCreateContextAttribsARB) + { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hTempRC); + return false; + } + + // now setup the shared context; this needs a temporary context already + // set up in order to work + int attribs [] = + { +#ifdef DBG_UTIL + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, +#endif + 0 + }; + m_aGLWin.hRC = wglCreateContextAttribsARB(m_aGLWin.hDC, hSharedCtx, attribs); + if (m_aGLWin.hRC == 0) + { + ImplWriteLastError(GetLastError(), "wglCreateContextAttribsARB in OpenGLContext::ImplInit"); + SAL_WARN("vcl.opengl", "wglCreateContextAttribsARB failed"); + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hTempRC); + return false; + } + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hTempRC); + + if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) + { + ImplWriteLastError(GetLastError(), "wglMakeCurrent (with shared context) in OpenGLContext::ImplInit"); + SAL_WARN("vcl.opengl", "wglMakeCurrent failed"); + return false; + } + + InitGLEWDebugging(); + + g_vShareList.push_back(m_aGLWin.hRC); + + RECT clientRect; + GetClientRect(WindowFromDC(m_aGLWin.hDC), &clientRect); + m_aGLWin.Width = clientRect.right - clientRect.left; + m_aGLWin.Height = clientRect.bottom - clientRect.top; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + registerAsCurrent(); + + return true; +} + +OpenGLContext* WinSalInstance::CreateOpenGLContext() +{ + return new WinOpenGLContext; +} WinOpenGLSalGraphicsImpl::WinOpenGLSalGraphicsImpl(WinSalGraphics& rGraphics, SalGeometryProvider *mpProvider): @@ -28,10 +499,10 @@ void WinOpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* rtl::Reference<OpenGLContext> WinOpenGLSalGraphicsImpl::CreateWinContext() { - rtl::Reference<OpenGLContext> pContext = OpenGLContext::Create(); - pContext->setVCLOnly(); - pContext->init( mrParent.mhLocalDC, mrParent.mhWnd ); - return pContext; + rtl::Reference<WinOpenGLContext> xContext(new WinOpenGLContext); + xContext->setVCLOnly(); + xContext->init(mrParent.mhLocalDC, mrParent.mhWnd); + return rtl::Reference<OpenGLContext>(xContext.get()); } void WinOpenGLSalGraphicsImpl::Init() diff --git a/vcl/opengl/x11/gdiimpl.cxx b/vcl/opengl/x11/gdiimpl.cxx index 61dba9b78db3..1137a3a170c4 100644 --- a/vcl/opengl/x11/gdiimpl.cxx +++ b/vcl/opengl/x11/gdiimpl.cxx @@ -16,19 +16,565 @@ #include <unx/saldisp.hxx> #include <unx/salframe.h> #include <unx/salgdi.h> +#include <unx/salinst.h> #include <unx/salvd.h> #include <unx/x11/xlimits.hxx> #include <opengl/texture.hxx> +#include <opengl/zone.hxx> +#include <opengl/RenderState.hxx> #include <opengl/x11/gdiimpl.hxx> #include <opengl/x11/salvd.hxx> -#include "opengl/RenderState.hxx" #include <vcl/opengl/OpenGLContext.hxx> #include <vcl/opengl/OpenGLHelper.hxx> #include <o3tl/lru_map.hxx> +static std::vector<GLXContext> g_vShareList; + +class X11OpenGLContext : public OpenGLContext +{ +public: + bool init(Display* dpy, Window win, int screen); + virtual bool initWindow() override; +private: + virtual bool ImplInit() override; + void initGLWindow(Visual* pVisual); + virtual SystemWindowData generateWinData(vcl::Window* pParent, bool bRequestLegacyContext) override; + virtual void makeCurrent() override; + virtual void destroyCurrentContext() override; + virtual bool isCurrent() override; + virtual bool isAnyCurrent() override; + virtual void sync() override; + virtual void resetCurrent() override; + virtual void swapBuffers() override; +}; + +namespace +{ + +#ifdef DBG_UTIL + int unxErrorHandler(Display* dpy, XErrorEvent* event) + { + char err[256]; + char req[256]; + char minor[256]; + XGetErrorText(dpy, event->error_code, err, 256); + XGetErrorText(dpy, event->request_code, req, 256); + XGetErrorText(dpy, event->minor_code, minor, 256); + SAL_WARN("vcl.opengl", "Error: " << err << ", Req: " << req << ", Minor: " << minor); + return 0; + } +#endif + + typedef int (*errorHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/); + + class TempErrorHandler + { + private: + errorHandler oldErrorHandler; + Display* mdpy; + + public: + TempErrorHandler(Display* dpy, errorHandler newErrorHandler) + : oldErrorHandler(nullptr) + , mdpy(dpy) + { + if (mdpy) + { + XLockDisplay(dpy); + XSync(dpy, false); + oldErrorHandler = XSetErrorHandler(newErrorHandler); + } + } + + ~TempErrorHandler() + { + if (mdpy) + { + // sync so that we possibly get an XError + glXWaitGL(); + XSync(mdpy, false); + XSetErrorHandler(oldErrorHandler); + XUnlockDisplay(mdpy); + } + } + }; + + static bool errorTriggered; + int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ ) + { + errorTriggered = true; + + return 0; + } + + GLXFBConfig* getFBConfig(Display* dpy, Window win, int& nBestFBC, bool bUseDoubleBufferedRendering, bool bWithSameVisualID) + { + OpenGLZone aZone; + + if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) ) + return nullptr; + + VCL_GL_INFO("window: " << win); + + XWindowAttributes xattr; + if( !XGetWindowAttributes( dpy, win, &xattr ) ) + { + SAL_WARN("vcl.opengl", "Failed to get window attributes for fbconfig " << win); + xattr.screen = nullptr; + xattr.visual = nullptr; + } + + int screen = XScreenNumberOfScreen( xattr.screen ); + + // TODO: moggi: Select colour channel depth based on visual attributes, not hardcoded */ + static int visual_attribs[] = + { + GLX_DOUBLEBUFFER, True, + GLX_X_RENDERABLE, True, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + None + }; + + if (!bUseDoubleBufferedRendering) + visual_attribs[1] = False; + + int fbCount = 0; + GLXFBConfig* pFBC = glXChooseFBConfig( dpy, + screen, + visual_attribs, &fbCount ); + + if(!pFBC) + { + SAL_WARN("vcl.opengl", "no suitable fb format found"); + return nullptr; + } + + int best_num_samp = -1; + for(int i = 0; i < fbCount; ++i) + { + XVisualInfo* pVi = glXGetVisualFromFBConfig( dpy, pFBC[i] ); + if(pVi && (!bWithSameVisualID || (xattr.visual && pVi->visualid == xattr.visual->visualid)) ) + { + // pick the one with the most samples per pixel + int nSampleBuf = 0; + int nSamples = 0; + glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf ); + glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLES , &nSamples ); + + if ( nBestFBC < 0 || (nSampleBuf && ( nSamples > best_num_samp )) ) + { + nBestFBC = i; + best_num_samp = nSamples; + } + } + XFree( pVi ); + } + + return pFBC; + } + + // we need them before glew can initialize them + // glew needs an OpenGL context so we need to get the address manually + void initOpenGLFunctionPointers() + { + glXChooseFBConfig = reinterpret_cast<GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements)>(glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXChooseFBConfig"))); + glXGetVisualFromFBConfig = reinterpret_cast<XVisualInfo*(*)(Display *dpy, GLXFBConfig config)>(glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXGetVisualFromFBConfig"))); // try to find a visual for the current set of attributes + glXGetFBConfigAttrib = reinterpret_cast<int(*)(Display *dpy, GLXFBConfig config, int attribute, int* value)>(glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXGetFBConfigAttrib"))); + glXCreateContextAttribsARB = reinterpret_cast<GLXContext(*)(Display*, GLXFBConfig, GLXContext, Bool, const int*)>(glXGetProcAddressARB(reinterpret_cast<const GLubyte *>("glXCreateContextAttribsARB"))); + glXCreatePixmap = reinterpret_cast<GLXPixmap(*)(Display*, GLXFBConfig, Pixmap, const int*)>(glXGetProcAddressARB(reinterpret_cast<const GLubyte *>("glXCreatePixmap"))); + } + + Visual* getVisual(Display* dpy, Window win) + { + OpenGLZone aZone; + + initOpenGLFunctionPointers(); + + XWindowAttributes xattr; + if( !XGetWindowAttributes( dpy, win, &xattr ) ) + { + SAL_WARN("vcl.opengl", "Failed to get window attributes for getVisual " << win); + xattr.visual = nullptr; + } + VCL_GL_INFO("using VisualID " << xattr.visual); + return xattr.visual; + } +} + +void X11OpenGLContext::sync() +{ + OpenGLZone aZone; + glXWaitGL(); + XSync(m_aGLWin.dpy, false); +} + +void X11OpenGLContext::swapBuffers() +{ + OpenGLZone aZone; + + glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win); + + BuffersSwapped(); +} + +void X11OpenGLContext::resetCurrent() +{ + clearCurrent(); + + OpenGLZone aZone; + + if (m_aGLWin.dpy) + glXMakeCurrent(m_aGLWin.dpy, None, nullptr); +} + +bool X11OpenGLContext::isCurrent() +{ + OpenGLZone aZone; + return m_aGLWin.ctx && glXGetCurrentContext() == m_aGLWin.ctx && + glXGetCurrentDrawable() == m_aGLWin.win; +} + +bool X11OpenGLContext::isAnyCurrent() +{ + return glXGetCurrentContext() != None; +} + +SystemWindowData X11OpenGLContext::generateWinData(vcl::Window* pParent, bool /*bRequestLegacyContext*/) +{ + OpenGLZone aZone; + + SystemWindowData aWinData; + aWinData.nSize = sizeof(aWinData); + aWinData.pVisual = nullptr; + + const SystemEnvData* sysData(pParent->GetSystemData()); + + Display *dpy = static_cast<Display*>(sysData->pDisplay); + Window win = sysData->aWindow; + + if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) ) + return aWinData; + + initOpenGLFunctionPointers(); + + int best_fbc = -1; + GLXFBConfig* pFBC = getFBConfig(dpy, win, best_fbc, true, false); + + if (!pFBC) + return aWinData; + + XVisualInfo* vi = nullptr; + if( best_fbc != -1 ) + vi = glXGetVisualFromFBConfig( dpy, pFBC[best_fbc] ); + + XFree(pFBC); + + if( vi ) + { + VCL_GL_INFO("using VisualID " << vi->visualid); + aWinData.pVisual = static_cast<void*>(vi->visual); + } + + return aWinData; +} + +bool X11OpenGLContext::ImplInit() +{ + if (!m_aGLWin.dpy) + return false; + + OpenGLZone aZone; + + GLXContext pSharedCtx( nullptr ); +#ifdef DBG_UTIL + TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler); +#endif + + VCL_GL_INFO("OpenGLContext::ImplInit----start"); + + if (!g_vShareList.empty()) + pSharedCtx = g_vShareList.front(); + + if (glXCreateContextAttribsARB && !mbRequestLegacyContext) + { + int best_fbc = -1; + GLXFBConfig* pFBC = getFBConfig(m_aGLWin.dpy, m_aGLWin.win, best_fbc, mbUseDoubleBufferedRendering, false); + + if (pFBC && best_fbc != -1) + { + int pContextAttribs[] = + { +#if 0 // defined(DBG_UTIL) + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, +#endif + None + + }; + m_aGLWin.ctx = glXCreateContextAttribsARB(m_aGLWin.dpy, pFBC[best_fbc], pSharedCtx, /* direct, not via X */ GL_TRUE, pContextAttribs); + SAL_INFO_IF(m_aGLWin.ctx, "vcl.opengl", "created a 3.2 core context"); + } + else + SAL_WARN("vcl.opengl", "unable to find correct FBC"); + } + + if (!m_aGLWin.ctx) + { + if (!m_aGLWin.vi) + return false; + + SAL_WARN("vcl.opengl", "attempting to create a non-double-buffered " + "visual matching the context"); + + m_aGLWin.ctx = glXCreateContext(m_aGLWin.dpy, + m_aGLWin.vi, + pSharedCtx, + GL_TRUE /* direct, not via X server */); + } + + if( m_aGLWin.ctx ) + { + g_vShareList.push_back( m_aGLWin.ctx ); + } + else + { + SAL_WARN("vcl.opengl", "unable to create GLX context"); + return false; + } + + if( !glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ) ) + { + SAL_WARN("vcl.opengl", "unable to select current GLX context"); + return false; + } + + int glxMinor, glxMajor; + double nGLXVersion = 0; + if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) ) + nGLXVersion = glxMajor + 0.1*glxMinor; + SAL_INFO("vcl.opengl", "available GLX version: " << nGLXVersion); + + m_aGLWin.GLExtensions = glGetString( GL_EXTENSIONS ); + SAL_INFO("vcl.opengl", "available GL extensions: " << m_aGLWin.GLExtensions); + + XWindowAttributes aWinAttr; + if( !XGetWindowAttributes( m_aGLWin.dpy, m_aGLWin.win, &aWinAttr ) ) + { + SAL_WARN("vcl.opengl", "Failed to get window attributes on " << m_aGLWin.win); + m_aGLWin.Width = 0; + m_aGLWin.Height = 0; + } + else + { + m_aGLWin.Width = aWinAttr.width; + m_aGLWin.Height = aWinAttr.height; + } + + if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) ) + { + // enable vsync + typedef GLint (*glXSwapIntervalProc)(GLint); + glXSwapIntervalProc glXSwapInterval = reinterpret_cast<glXSwapIntervalProc>(glXGetProcAddress( reinterpret_cast<const GLubyte*>("glXSwapIntervalSGI") )); + if( glXSwapInterval ) + { + TempErrorHandler aLocalErrorHandler(m_aGLWin.dpy, oglErrorHandler); + + errorTriggered = false; + + glXSwapInterval( 1 ); + + if( errorTriggered ) + SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?"); + else + VCL_GL_INFO("set swap interval to 1 (enable vsync)"); + } + } + + bool bRet = InitGLEW(); + InitGLEWDebugging(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + registerAsCurrent(); + + return bRet; +} + +void X11OpenGLContext::makeCurrent() +{ + if (isCurrent()) + return; + + OpenGLZone aZone; + + clearCurrent(); + +#ifdef DBG_UTIL + TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler); +#endif + + if (m_aGLWin.dpy) + { + if (!glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx )) + { + SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent failed " + "on drawable " << m_aGLWin.win); + return; + } + } + + registerAsCurrent(); +} + +void X11OpenGLContext::destroyCurrentContext() +{ + if(m_aGLWin.ctx) + { + std::vector<GLXContext>::iterator itr = std::remove( g_vShareList.begin(), g_vShareList.end(), m_aGLWin.ctx ); + if (itr != g_vShareList.end()) + g_vShareList.erase(itr); + + glXMakeCurrent(m_aGLWin.dpy, None, nullptr); + if( glGetError() != GL_NO_ERROR ) + { + SAL_WARN("vcl.opengl", "glError: " << glGetError()); + } + glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx); + m_aGLWin.ctx = nullptr; + } +} + +bool X11OpenGLContext::init(Display* dpy, Window win, int screen) +{ + if (isInitialized()) + return true; + + if (!dpy) + return false; + + OpenGLZone aZone; + + m_aGLWin.dpy = dpy; + m_aGLWin.win = win; + m_aGLWin.screen = screen; + + Visual* pVisual = getVisual(dpy, win); + + initGLWindow(pVisual); + + return ImplInit(); +} + +void X11OpenGLContext::initGLWindow(Visual* pVisual) +{ + OpenGLZone aZone; + + // Get visual info + { + XVisualInfo aTemplate; + aTemplate.visualid = XVisualIDFromVisual( pVisual ); + int nVisuals = 0; + XVisualInfo* pInfo = XGetVisualInfo( m_aGLWin.dpy, VisualIDMask, &aTemplate, &nVisuals ); + if( nVisuals != 1 ) + SAL_WARN( "vcl.opengl", "match count for visual id is not 1" ); + m_aGLWin.vi = pInfo; + } + + // Check multisample support + /* TODO: moggi: This is not necessarily correct in the DBG_UTIL path, as it picks + * an FBConfig instead ... */ + int nSamples = 0; + glXGetConfig(m_aGLWin.dpy, m_aGLWin.vi, GLX_SAMPLES, &nSamples); + if( nSamples > 0 ) + m_aGLWin.bMultiSampleSupported = true; + + m_aGLWin.GLXExtensions = glXQueryExtensionsString( m_aGLWin.dpy, m_aGLWin.screen ); + SAL_INFO("vcl.opengl", "available GLX extensions: " << m_aGLWin.GLXExtensions); +} + +bool X11OpenGLContext::initWindow() +{ + const SystemEnvData* pChildSysData = nullptr; + SystemWindowData winData = generateWinData(mpWindow, false); + if( winData.pVisual ) + { + if( !m_pChildWindow ) + { + m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false); + } + pChildSysData = m_pChildWindow->GetSystemData(); + } + + if (!m_pChildWindow || !pChildSysData) + return false; + + InitChildWindow(m_pChildWindow.get()); + + m_aGLWin.dpy = static_cast<Display*>(pChildSysData->pDisplay); + m_aGLWin.win = pChildSysData->aWindow; + m_aGLWin.screen = pChildSysData->nScreen; + + Visual* pVisual = static_cast<Visual*>(pChildSysData->pVisual); + initGLWindow(pVisual); + + return true; +} + +// Copy of gluCheckExtension(), from the Apache-licensed +// https://code.google.com/p/glues/source/browse/trunk/glues/source/glues_registry.c +static GLboolean checkExtension(const GLubyte* extName, const GLubyte* extString) +{ + GLboolean flag=GL_FALSE; + char* word; + char* lookHere; + char* deleteThis; + + if (extString==nullptr) + { + return GL_FALSE; + } + + deleteThis=lookHere=static_cast<char*>(malloc(strlen(reinterpret_cast<const char*>(extString))+1)); + if (lookHere==nullptr) + { + return GL_FALSE; + } + + /* strtok() will modify string, so copy it somewhere */ + strcpy(lookHere, reinterpret_cast<const char*>(extString)); + + while ((word=strtok(lookHere, " "))!=nullptr) + { + if (strcmp(word, reinterpret_cast<const char*>(extName))==0) + { + flag=GL_TRUE; + break; + } + lookHere=nullptr; /* get next token */ + } + free(static_cast<void*>(deleteThis)); + + return flag; +} + +bool GLWindow::HasGLXExtension( const char* name ) const +{ + return checkExtension( reinterpret_cast<const GLubyte*>(name), reinterpret_cast<const GLubyte*>(GLXExtensions) ); +} + +OpenGLContext* X11SalInstance::CreateOpenGLContext() +{ + return new X11OpenGLContext; +} + X11OpenGLSalGraphicsImpl::X11OpenGLSalGraphicsImpl( X11SalGraphics& rParent ): OpenGLSalGraphicsImpl(rParent,rParent.GetGeometryProvider()), mrParent(rParent) @@ -54,11 +600,11 @@ rtl::Reference<OpenGLContext> X11OpenGLSalGraphicsImpl::CreateWinContext() return nullptr; sal_uIntPtr aWin = pProvider->GetNativeWindowHandle(); - rtl::Reference<OpenGLContext> pContext = OpenGLContext::Create(); - pContext->setVCLOnly(); - pContext->init( mrParent.GetXDisplay(), aWin, + rtl::Reference<X11OpenGLContext> xContext = new X11OpenGLContext; + xContext->setVCLOnly(); + xContext->init( mrParent.GetXDisplay(), aWin, mrParent.m_nXScreen.getXScreen() ); - return pContext; + return rtl::Reference<OpenGLContext>(xContext.get()); } void X11OpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) diff --git a/vcl/osx/salobj.cxx b/vcl/osx/salobj.cxx index 87edbfa9a1ed..6bbb43aa51a8 100644 --- a/vcl/osx/salobj.cxx +++ b/vcl/osx/salobj.cxx @@ -18,10 +18,15 @@ */ #include <string.h> +#include <vcl/opengl/OpenGLContext.hxx> +#include <vcl/opengl/OpenGLHelper.hxx> +#include <opengl/zone.hxx> #include "osx/saldata.hxx" -#include "osx/salobj.h" #include "osx/salframe.h" +#include "osx/salinst.h" +#include "osx/salobj.h" + #include <AppKit/NSOpenGLView.h> AquaSalObject::AquaSalObject( AquaSalFrame* pFrame, SystemWindowData* pWindowData ) : @@ -226,4 +231,106 @@ const SystemEnvData* AquaSalObject::GetSystemData() const return &maSysData; } +class AquaOpenGLContext : public OpenGLContext +{ +public: + virtual bool initWindow() override; +private: + NSOpenGLView* getOpenGLView(); + virtual bool ImplInit() override; + virtual SystemWindowData generateWinData(vcl::Window* pParent, bool bRequestLegacyContext) override; + virtual void makeCurrent() override; + virtual void destroyCurrentContext() override; + virtual void resetCurrent() override; + virtual void swapBuffers() override; +}; + +void AquaOpenGLContext::resetCurrent() +{ + clearCurrent(); + + OpenGLZone aZone; + + (void) this; // loplugin:staticmethods + [NSOpenGLContext clearCurrentContext]; +} + +void AquaOpenGLContext::makeCurrent() +{ + if (isCurrent()) + return; + + OpenGLZone aZone; + + clearCurrent(); + + NSOpenGLView* pView = getOpenGLView(); + [[pView openGLContext] makeCurrentContext]; + + registerAsCurrent(); +} + +void AquaOpenGLContext::swapBuffers() +{ + OpenGLZone aZone; + + NSOpenGLView* pView = getOpenGLView(); + [[pView openGLContext] flushBuffer]; + + BuffersSwapped(); +} + +SystemWindowData AquaOpenGLContext::generateWinData(vcl::Window* /*pParent*/, bool bRequestLegacyContext) +{ + SystemWindowData aWinData; + aWinData.bOpenGL = true; + aWinData.bLegacy = bRequestLegacyContext; + aWinData.nSize = sizeof(aWinData); + return aWinData; +} + +void AquaOpenGLContext::destroyCurrentContext() +{ + [NSOpenGLContext clearCurrentContext]; +} + +bool AquaOpenGLContext::initWindow() +{ + if( !m_pChildWindow ) + { + SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext); + m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false); + } + + if (m_pChildWindow) + { + InitChildWindow(m_pChildWindow.get()); + } + + return true; +} + +bool AquaOpenGLContext::ImplInit() +{ + OpenGLZone aZone; + + VCL_GL_INFO("OpenGLContext::ImplInit----start"); + NSOpenGLView* pView = getOpenGLView(); + [[pView openGLContext] makeCurrentContext]; + + bool bRet = InitGLEW(); + InitGLEWDebugging(); + return bRet; +} + +NSOpenGLView* AquaOpenGLContext::getOpenGLView() +{ + return reinterpret_cast<NSOpenGLView*>(m_pChildWindow->GetSystemData()->mpNSView); +} + +OpenGLContext* AquaSalInstance::CreateOpenGLContext() +{ + return new AquaOpenGLContext; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx index f254974727c9..89ce97019be9 100644 --- a/vcl/source/opengl/OpenGLContext.cxx +++ b/vcl/source/opengl/OpenGLContext.cxx @@ -22,19 +22,9 @@ #include <osl/thread.hxx> -#if defined(MACOSX) -#include <premac.h> -#include <AppKit/NSOpenGLView.h> -#include <AppKit/NSOpenGL.h> -#include <postmac.h> -#endif - -#if defined(_WIN32) -#include <win/saldata.hxx> -#endif - #include "svdata.hxx" #include "salgdi.hxx" +#include "salinst.hxx" #include <opengl/framebuffer.hxx> #include <opengl/program.hxx> @@ -47,13 +37,6 @@ using namespace com::sun::star; #define MAX_FRAMEBUFFER_COUNT 30 -// TODO use rtl::Static instead of 'static' -#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS) -static std::vector<GLXContext> g_vShareList; -#elif defined(WNT) -static std::vector<HGLRC> g_vShareList; -#endif - static sal_Int64 nBufferSwapCounter = 0; GLWindow::~GLWindow() @@ -63,6 +46,17 @@ GLWindow::~GLWindow() #endif } +bool GLWindow::Synchronize(bool bOnoff) const +{ +#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS) + XSynchronize(dpy, bOnoff); + return true; +#else + (void)bOnoff; + return false; +#endif +} + OpenGLContext::OpenGLContext(): mpWindow(nullptr), m_pChildWindow(nullptr), @@ -128,7 +122,7 @@ void OpenGLContext::dispose() rtl::Reference<OpenGLContext> OpenGLContext::Create() { - return rtl::Reference<OpenGLContext>(new OpenGLContext); + return rtl::Reference<OpenGLContext>(ImplGetSVData()->mpDefInst->CreateOpenGLContext()); } void OpenGLContext::requestLegacyContext() @@ -141,222 +135,6 @@ void OpenGLContext::requestSingleBufferedRendering() mbUseDoubleBufferedRendering = false; } -#if defined( _WIN32 ) -static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_CREATE: - return 0; - case WM_CLOSE: - PostQuitMessage(0); - return 0; - case WM_DESTROY: - return 0; - case WM_KEYDOWN: - switch(wParam) - { - case VK_ESCAPE: - PostQuitMessage(0); - return 0; - - case VK_SPACE: - break; - } - default: - return DefWindowProc(hwnd, message, wParam, lParam); - } -} - -int InitTempWindow(HWND *hwnd, int width, int height, const PIXELFORMATDESCRIPTOR& inPfd, GLWindow& glWin) -{ - OpenGLZone aZone; - - PIXELFORMATDESCRIPTOR pfd = inPfd; - int pfmt; - int ret; - WNDCLASS wc; - wc.style = 0; - wc.lpfnWndProc = WndProc; - wc.cbClsExtra = wc.cbWndExtra = 0; - wc.hInstance = NULL; - wc.hIcon = NULL; - wc.hCursor = NULL; - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - wc.lpszClassName = (LPCSTR)"GLRenderer"; - RegisterClass(&wc); - *hwnd = CreateWindow(wc.lpszClassName, NULL, WS_DISABLED, 0, 0, width, height, NULL, NULL, wc.hInstance, NULL); - glWin.hDC = GetDC(*hwnd); - pfmt = ChoosePixelFormat(glWin.hDC, &pfd); - if (!pfmt) - { - return -1; - } - ret = SetPixelFormat(glWin.hDC, pfmt, &pfd); - if(!ret) - { - return -1; - } - glWin.hRC = wglCreateContext(glWin.hDC); - if(!(glWin.hRC)) - { - return -1; - } - ret = wglMakeCurrent(glWin.hDC, glWin.hRC); - if(!ret) - { - return -1; - } - - return 0; -} - -bool WGLisExtensionSupported(const char *extension) -{ - OpenGLZone aZone; - - const size_t extlen = strlen(extension); - const char *supported = NULL; - - // Try to use wglGetExtensionStringARB on current DC, if possible - PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB"); - - if (wglGetExtString) - supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC()); - // If that failed, try standard OpenGL extensions string - if (supported == NULL) - supported = (char*)glGetString(GL_EXTENSIONS); - // If that failed too, must be no extensions supported - if (supported == NULL) - return false; - - // Begin examination at start of string, increment by 1 on false match - for (const char* p = supported; ; p++) - { - // Advance p up to the next possible match - p = strstr(p, extension); - - if (p == NULL) - return 0; // No Match - - // Make sure that match is at the start of the string or that - // the previous char is a space, or else we could accidentally - // match "wglFunkywglExtension" with "wglExtension" - - // Also, make sure that the following character is space or null - // or else "wglExtensionTwo" might match "wglExtension" - if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' ')) - return 1; // Match - } -} - -bool InitMultisample(const PIXELFORMATDESCRIPTOR& pfd, int& rPixelFormat, - bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice) -{ - OpenGLZone aZone; - - HWND hWnd = NULL; - GLWindow glWin; - // Create a temp window to check whether support multi-sample, if support, get the format - if (InitTempWindow(&hWnd, 1, 1, pfd, glWin) < 0) - { - SAL_WARN("vcl.opengl", "Can't create temp window to test"); - return false; - } - - // See if the string exists in WGL - if (!WGLisExtensionSupported("WGL_ARB_multisample")) - { - SAL_WARN("vcl.opengl", "Device doesn't support multisample"); - return false; - } - // Get our pixel format - PFNWGLCHOOSEPIXELFORMATARBPROC fn_wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); - if (!fn_wglChoosePixelFormatARB) - { - return false; - } - // Get our current device context - HDC hDC = GetDC(hWnd); - - int pixelFormat; - int valid; - UINT numFormats; - float fAttributes[] = {0,0}; - // These attributes are the bits we want to test for in our sample. - // Everything is pretty standard, the only one we want to - // really focus on is the WGL_SAMPLE_BUFFERS_ARB and WGL_SAMPLES_ARB. - // These two are going to do the main testing for whether or not - // we support multisampling on this hardware. - int iAttributes[] = - { - WGL_DOUBLE_BUFFER_ARB,GL_TRUE, - WGL_DRAW_TO_WINDOW_ARB,GL_TRUE, - WGL_SUPPORT_OPENGL_ARB,GL_TRUE, - WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB, - WGL_COLOR_BITS_ARB,24, - WGL_ALPHA_BITS_ARB,8, - WGL_DEPTH_BITS_ARB,24, - WGL_STENCIL_BITS_ARB,0, - WGL_SAMPLE_BUFFERS_ARB,GL_TRUE, - WGL_SAMPLES_ARB,8, - 0,0 - }; - - if (!bUseDoubleBufferedRendering) - { - // Use asserts to make sure the iAttributes array is not changed without changing these ugly - // hardcode indexes into it. - assert(iAttributes[0] == WGL_DOUBLE_BUFFER_ARB); - iAttributes[1] = GL_FALSE; - } - - if (bRequestVirtualDevice) - { - assert(iAttributes[2] == WGL_DRAW_TO_WINDOW_ARB); - iAttributes[2] = WGL_DRAW_TO_BITMAP_ARB; - } - - bool bArbMultisampleSupported = false; - - // First we check to see if we can get a pixel format for 8 samples - valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats); - // If we returned true, and our format count is greater than 1 - if (valid && numFormats >= 1) - { - bArbMultisampleSupported = true; - rPixelFormat = pixelFormat; - wglMakeCurrent(NULL, NULL); - wglDeleteContext(glWin.hRC); - ReleaseDC(hWnd, glWin.hDC); - DestroyWindow(hWnd); - return bArbMultisampleSupported; - } - // Our pixel format with 8 samples failed, test for 2 samples - assert(iAttributes[18] == WGL_SAMPLES_ARB); - iAttributes[19] = 2; - valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats); - if (valid && numFormats >= 1) - { - bArbMultisampleSupported = true; - rPixelFormat = pixelFormat; - wglMakeCurrent(NULL, NULL); - wglDeleteContext(glWin.hRC); - ReleaseDC(hWnd, glWin.hDC); - DestroyWindow(hWnd); - return bArbMultisampleSupported; - } - // Return the valid format - wglMakeCurrent(NULL, NULL); - wglDeleteContext(glWin.hRC); - ReleaseDC(hWnd, glWin.hDC); - DestroyWindow(hWnd); - - return bArbMultisampleSupported; -} -#endif - #ifdef DBG_UTIL namespace { @@ -456,168 +234,6 @@ debug_callback(GLenum source, GLenum type, GLuint id, #endif -#if defined UNX && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS) - -namespace { - -#ifdef DBG_UTIL -int unxErrorHandler(Display* dpy, XErrorEvent* event) -{ - char err[256]; - char req[256]; - char minor[256]; - XGetErrorText(dpy, event->error_code, err, 256); - XGetErrorText(dpy, event->request_code, req, 256); - XGetErrorText(dpy, event->minor_code, minor, 256); - SAL_WARN("vcl.opengl", "Error: " << err << ", Req: " << req << ", Minor: " << minor); - return 0; -} -#endif - -typedef int (*errorHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/); - -class TempErrorHandler -{ -private: - errorHandler oldErrorHandler; - Display* mdpy; - -public: - TempErrorHandler(Display* dpy, errorHandler newErrorHandler) - : oldErrorHandler(nullptr) - , mdpy(dpy) - { - if (mdpy) - { - XLockDisplay(dpy); - XSync(dpy, false); - oldErrorHandler = XSetErrorHandler(newErrorHandler); - } - } - - ~TempErrorHandler() - { - if (mdpy) - { - // sync so that we possibly get an XError - glXWaitGL(); - XSync(mdpy, false); - XSetErrorHandler(oldErrorHandler); - XUnlockDisplay(mdpy); - } - } -}; - -static bool errorTriggered; -int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ ) -{ - errorTriggered = true; - - return 0; -} - -GLXFBConfig* getFBConfig(Display* dpy, Window win, int& nBestFBC, bool bUseDoubleBufferedRendering, bool bWithSameVisualID) -{ - OpenGLZone aZone; - - if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) ) - return nullptr; - - VCL_GL_INFO("window: " << win); - - XWindowAttributes xattr; - if( !XGetWindowAttributes( dpy, win, &xattr ) ) - { - SAL_WARN("vcl.opengl", "Failed to get window attributes for fbconfig " << win); - xattr.screen = nullptr; - xattr.visual = nullptr; - } - - int screen = XScreenNumberOfScreen( xattr.screen ); - - // TODO: moggi: Select colour channel depth based on visual attributes, not hardcoded */ - static int visual_attribs[] = - { - GLX_DOUBLEBUFFER, True, - GLX_X_RENDERABLE, True, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 8, - GLX_DEPTH_SIZE, 24, - GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, - None - }; - - if (!bUseDoubleBufferedRendering) - visual_attribs[1] = False; - - int fbCount = 0; - GLXFBConfig* pFBC = glXChooseFBConfig( dpy, - screen, - visual_attribs, &fbCount ); - - if(!pFBC) - { - SAL_WARN("vcl.opengl", "no suitable fb format found"); - return nullptr; - } - - int best_num_samp = -1; - for(int i = 0; i < fbCount; ++i) - { - XVisualInfo* pVi = glXGetVisualFromFBConfig( dpy, pFBC[i] ); - if(pVi && (!bWithSameVisualID || (xattr.visual && pVi->visualid == xattr.visual->visualid)) ) - { - // pick the one with the most samples per pixel - int nSampleBuf = 0; - int nSamples = 0; - glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf ); - glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLES , &nSamples ); - - if ( nBestFBC < 0 || (nSampleBuf && ( nSamples > best_num_samp )) ) - { - nBestFBC = i; - best_num_samp = nSamples; - } - } - XFree( pVi ); - } - - return pFBC; -} - -// we need them before glew can initialize them -// glew needs an OpenGL context so we need to get the address manually -void initOpenGLFunctionPointers() -{ - glXChooseFBConfig = reinterpret_cast<GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements)>(glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXChooseFBConfig"))); - glXGetVisualFromFBConfig = reinterpret_cast<XVisualInfo*(*)(Display *dpy, GLXFBConfig config)>(glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXGetVisualFromFBConfig"))); // try to find a visual for the current set of attributes - glXGetFBConfigAttrib = reinterpret_cast<int(*)(Display *dpy, GLXFBConfig config, int attribute, int* value)>(glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXGetFBConfigAttrib"))); - glXCreateContextAttribsARB = reinterpret_cast<GLXContext(*)(Display*, GLXFBConfig, GLXContext, Bool, const int*)>(glXGetProcAddressARB(reinterpret_cast<const GLubyte *>("glXCreateContextAttribsARB"))); - glXCreatePixmap = reinterpret_cast<GLXPixmap(*)(Display*, GLXFBConfig, Pixmap, const int*)>(glXGetProcAddressARB(reinterpret_cast<const GLubyte *>("glXCreatePixmap"))); -} - -Visual* getVisual(Display* dpy, Window win) -{ - OpenGLZone aZone; - - initOpenGLFunctionPointers(); - - XWindowAttributes xattr; - if( !XGetWindowAttributes( dpy, win, &xattr ) ) - { - SAL_WARN("vcl.opengl", "Failed to get window attributes for getVisual " << win); - xattr.visual = nullptr; - } - VCL_GL_INFO("using VisualID " << xattr.visual); - return xattr.visual; -} - -} - -#endif - bool OpenGLContext::init( vcl::Window* pParent ) { if(mbInitialized) @@ -650,370 +266,12 @@ bool OpenGLContext::init(SystemChildWindow* pChildWindow) return ImplInit(); } -#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS) -bool OpenGLContext::init(Display* dpy, Window win, int screen) -{ - if(mbInitialized) - return true; - - if (!dpy) - return false; - - OpenGLZone aZone; - - m_aGLWin.dpy = dpy; - m_aGLWin.win = win; - m_aGLWin.screen = screen; - - Visual* pVisual = getVisual(dpy, win); - - initGLWindow(pVisual); - - return ImplInit(); -} - -// Copy of gluCheckExtension(), from the Apache-licensed -// https://code.google.com/p/glues/source/browse/trunk/glues/source/glues_registry.c -static GLboolean checkExtension(const GLubyte* extName, const GLubyte* extString) -{ - GLboolean flag=GL_FALSE; - char* word; - char* lookHere; - char* deleteThis; - - if (extString==nullptr) - { - return GL_FALSE; - } - - deleteThis=lookHere=static_cast<char*>(malloc(strlen(reinterpret_cast<const char*>(extString))+1)); - if (lookHere==nullptr) - { - return GL_FALSE; - } - - /* strtok() will modify string, so copy it somewhere */ - strcpy(lookHere, reinterpret_cast<const char*>(extString)); - - while ((word=strtok(lookHere, " "))!=nullptr) - { - if (strcmp(word, reinterpret_cast<const char*>(extName))==0) - { - flag=GL_TRUE; - break; - } - lookHere=nullptr; /* get next token */ - } - free(static_cast<void*>(deleteThis)); - - return flag; -} - -bool GLWindow::HasGLXExtension( const char* name ) const -{ - return checkExtension( reinterpret_cast<const GLubyte*>(name), reinterpret_cast<const GLubyte*>(GLXExtensions) ); -} - -bool OpenGLContext::ImplInit() -{ - if (!m_aGLWin.dpy) - return false; - - OpenGLZone aZone; - - GLXContext pSharedCtx( nullptr ); -#ifdef DBG_UTIL - TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler); -#endif - - VCL_GL_INFO("OpenGLContext::ImplInit----start"); - - if (!g_vShareList.empty()) - pSharedCtx = g_vShareList.front(); - - if (glXCreateContextAttribsARB && !mbRequestLegacyContext) - { - int best_fbc = -1; - GLXFBConfig* pFBC = getFBConfig(m_aGLWin.dpy, m_aGLWin.win, best_fbc, mbUseDoubleBufferedRendering, false); - - if (pFBC && best_fbc != -1) - { - int pContextAttribs[] = - { -#if 0 // defined(DBG_UTIL) - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 2, -#endif - None - - }; - m_aGLWin.ctx = glXCreateContextAttribsARB(m_aGLWin.dpy, pFBC[best_fbc], pSharedCtx, /* direct, not via X */ GL_TRUE, pContextAttribs); - SAL_INFO_IF(m_aGLWin.ctx, "vcl.opengl", "created a 3.2 core context"); - } - else - SAL_WARN("vcl.opengl", "unable to find correct FBC"); - } - - if (!m_aGLWin.ctx) - { - if (!m_aGLWin.vi) - return false; - - SAL_WARN("vcl.opengl", "attempting to create a non-double-buffered " - "visual matching the context"); - - m_aGLWin.ctx = glXCreateContext(m_aGLWin.dpy, - m_aGLWin.vi, - pSharedCtx, - GL_TRUE /* direct, not via X server */); - } - - if( m_aGLWin.ctx ) - { - g_vShareList.push_back( m_aGLWin.ctx ); - } - else - { - SAL_WARN("vcl.opengl", "unable to create GLX context"); - return false; - } - - if( !glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ) ) - { - SAL_WARN("vcl.opengl", "unable to select current GLX context"); - return false; - } - - int glxMinor, glxMajor; - double nGLXVersion = 0; - if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) ) - nGLXVersion = glxMajor + 0.1*glxMinor; - SAL_INFO("vcl.opengl", "available GLX version: " << nGLXVersion); - - m_aGLWin.GLExtensions = glGetString( GL_EXTENSIONS ); - SAL_INFO("vcl.opengl", "available GL extensions: " << m_aGLWin.GLExtensions); - - XWindowAttributes aWinAttr; - if( !XGetWindowAttributes( m_aGLWin.dpy, m_aGLWin.win, &aWinAttr ) ) - { - SAL_WARN("vcl.opengl", "Failed to get window attributes on " << m_aGLWin.win); - m_aGLWin.Width = 0; - m_aGLWin.Height = 0; - } - else - { - m_aGLWin.Width = aWinAttr.width; - m_aGLWin.Height = aWinAttr.height; - } - - if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) ) - { - // enable vsync - typedef GLint (*glXSwapIntervalProc)(GLint); - glXSwapIntervalProc glXSwapInterval = reinterpret_cast<glXSwapIntervalProc>(glXGetProcAddress( reinterpret_cast<const GLubyte*>("glXSwapIntervalSGI") )); - if( glXSwapInterval ) - { - TempErrorHandler aLocalErrorHandler(m_aGLWin.dpy, oglErrorHandler); - - errorTriggered = false; - - glXSwapInterval( 1 ); - - if( errorTriggered ) - SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?"); - else - VCL_GL_INFO("set swap interval to 1 (enable vsync)"); - } - } - - bool bRet = InitGLEW(); - InitGLEWDebugging(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - registerAsCurrent(); - - return bRet; -} - -#elif defined( _WIN32 ) - -bool OpenGLContext::init(HDC hDC, HWND hWnd) -{ - if (mbInitialized) - return false; - - m_aGLWin.hDC = hDC; - m_aGLWin.hWnd = hWnd; - return ImplInit(); -} - -bool OpenGLContext::ImplInit() -{ - OpenGLZone aZone; - - VCL_GL_INFO("OpenGLContext::ImplInit----start"); - // PixelFormat tells Windows how we want things to be - PIXELFORMATDESCRIPTOR PixelFormatFront = - { - sizeof(PIXELFORMATDESCRIPTOR), - 1, // Version Number - PFD_SUPPORT_OPENGL, - PFD_TYPE_RGBA, // Request An RGBA Format - (BYTE)32, // Select Our Color Depth - 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // No Alpha Buffer - 0, // Shift Bit Ignored - 0, // No Accumulation Buffer - 0, 0, 0, 0, // Accumulation Bits Ignored - 24, // 24 bit z-buffer - 8, // stencil buffer - 0, // No Auxiliary Buffer - 0, // now ignored - 0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; - - if (mbUseDoubleBufferedRendering) - PixelFormatFront.dwFlags |= PFD_DOUBLEBUFFER; - - PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW; - - // we must check whether can set the MSAA - int WindowPix = 0; - bool bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix, - mbUseDoubleBufferedRendering, false); - if (bMultiSampleSupport && WindowPix != 0) - { - m_aGLWin.bMultiSampleSupported = true; - } - else - { - WindowPix = ChoosePixelFormat(m_aGLWin.hDC, &PixelFormatFront); -#if OSL_DEBUG_LEVEL > 0 - PIXELFORMATDESCRIPTOR pfd; - DescribePixelFormat(m_aGLWin.hDC, WindowPix, sizeof(PIXELFORMATDESCRIPTOR), &pfd); - SAL_WARN("vcl.opengl", "Render Target: Window: " << (int) ((pfd.dwFlags & PFD_DRAW_TO_WINDOW) != 0) << ", Bitmap: " << (int) ((pfd.dwFlags & PFD_DRAW_TO_BITMAP) != 0)); - SAL_WARN("vcl.opengl", "Supports OpenGL: " << (int) ((pfd.dwFlags & PFD_SUPPORT_OPENGL) != 0)); -#endif - } - - if (WindowPix == 0) - { - SAL_WARN("vcl.opengl", "Invalid pixelformat"); - return false; - } - - if (!SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront)) - { - ImplWriteLastError(GetLastError(), "SetPixelFormat in OpenGLContext::ImplInit"); - SAL_WARN("vcl.opengl", "SetPixelFormat failed"); - return false; - } - - HGLRC hTempRC = wglCreateContext(m_aGLWin.hDC); - if (hTempRC == NULL) - { - ImplWriteLastError(GetLastError(), "wglCreateContext in OpenGLContext::ImplInit"); - SAL_WARN("vcl.opengl", "wglCreateContext failed"); - return false; - } - - if (!wglMakeCurrent(m_aGLWin.hDC, hTempRC)) - { - ImplWriteLastError(GetLastError(), "wglMakeCurrent in OpenGLContext::ImplInit"); - SAL_WARN("vcl.opengl", "wglMakeCurrent failed"); - return false; - } - - if (!InitGLEW()) - { - wglMakeCurrent(NULL, NULL); - wglDeleteContext(hTempRC); - return false; - } - - HGLRC hSharedCtx = 0; - if (!g_vShareList.empty()) - hSharedCtx = g_vShareList.front(); - - if (!wglCreateContextAttribsARB) - { - wglMakeCurrent(NULL, NULL); - wglDeleteContext(hTempRC); - return false; - } - - // now setup the shared context; this needs a temporary context already - // set up in order to work - int attribs [] = - { -#ifdef DBG_UTIL - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, -#endif - 0 - }; - m_aGLWin.hRC = wglCreateContextAttribsARB(m_aGLWin.hDC, hSharedCtx, attribs); - if (m_aGLWin.hRC == 0) - { - ImplWriteLastError(GetLastError(), "wglCreateContextAttribsARB in OpenGLContext::ImplInit"); - SAL_WARN("vcl.opengl", "wglCreateContextAttribsARB failed"); - wglMakeCurrent(NULL, NULL); - wglDeleteContext(hTempRC); - return false; - } - - wglMakeCurrent(NULL, NULL); - wglDeleteContext(hTempRC); - - if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) - { - ImplWriteLastError(GetLastError(), "wglMakeCurrent (with shared context) in OpenGLContext::ImplInit"); - SAL_WARN("vcl.opengl", "wglMakeCurrent failed"); - return false; - } - - InitGLEWDebugging(); - - g_vShareList.push_back(m_aGLWin.hRC); - - RECT clientRect; - GetClientRect(WindowFromDC(m_aGLWin.hDC), &clientRect); - m_aGLWin.Width = clientRect.right - clientRect.left; - m_aGLWin.Height = clientRect.bottom - clientRect.top; - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - registerAsCurrent(); - - return true; -} - -#elif defined( MACOSX ) - -bool OpenGLContext::ImplInit() -{ - OpenGLZone aZone; - - VCL_GL_INFO("OpenGLContext::ImplInit----start"); - NSOpenGLView* pView = getOpenGLView(); - [[pView openGLContext] makeCurrentContext]; - - bool bRet = InitGLEW(); - InitGLEWDebugging(); - return bRet; -} - -#else - bool OpenGLContext::ImplInit() { VCL_GL_INFO("OpenGLContext not implemented for this platform"); return false; } -#endif - bool OpenGLContext::InitGLEW() { static bool bGlewInit = false; @@ -1101,111 +359,16 @@ void OpenGLContext::InitChildWindow(SystemChildWindow *pChildWindow) pChildWindow->SetControlBackground(); } -#if defined(_WIN32) - -bool OpenGLContext::initWindow() -{ - if( !m_pChildWindow ) - { - SystemWindowData winData = generateWinData(mpWindow, false); - m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false); - } - - if (m_pChildWindow) - { - InitChildWindow(m_pChildWindow.get()); - const SystemEnvData* sysData(m_pChildWindow->GetSystemData()); - m_aGLWin.hWnd = sysData->hWnd; - } - - m_aGLWin.hDC = GetDC(m_aGLWin.hWnd); - return true; -} - -#elif defined( MACOSX ) - -bool OpenGLContext::initWindow() -{ - if( !m_pChildWindow ) - { - SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext); - m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false); - } - - if (m_pChildWindow) - { - InitChildWindow(m_pChildWindow.get()); - } - - return true; -} - -#elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS) - bool OpenGLContext::initWindow() { return false; } -#elif defined( UNX ) - -bool OpenGLContext::initWindow() +void OpenGLContext::destroyCurrentContext() { - const SystemEnvData* pChildSysData = nullptr; - SystemWindowData winData = generateWinData(mpWindow, false); - if( winData.pVisual ) - { - if( !m_pChildWindow ) - { - m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false); - } - pChildSysData = m_pChildWindow->GetSystemData(); - } - - if (!m_pChildWindow || !pChildSysData) - return false; - - InitChildWindow(m_pChildWindow.get()); - - m_aGLWin.dpy = static_cast<Display*>(pChildSysData->pDisplay); - m_aGLWin.win = pChildSysData->aWindow; - m_aGLWin.screen = pChildSysData->nScreen; - - Visual* pVisual = static_cast<Visual*>(pChildSysData->pVisual); - initGLWindow(pVisual); - - return true; -} - -void OpenGLContext::initGLWindow(Visual* pVisual) -{ - OpenGLZone aZone; - - // Get visual info - { - XVisualInfo aTemplate; - aTemplate.visualid = XVisualIDFromVisual( pVisual ); - int nVisuals = 0; - XVisualInfo* pInfo = XGetVisualInfo( m_aGLWin.dpy, VisualIDMask, &aTemplate, &nVisuals ); - if( nVisuals != 1 ) - SAL_WARN( "vcl.opengl", "match count for visual id is not 1" ); - m_aGLWin.vi = pInfo; - } - - // Check multisample support - /* TODO: moggi: This is not necessarily correct in the DBG_UTIL path, as it picks - * an FBConfig instead ... */ - int nSamples = 0; - glXGetConfig(m_aGLWin.dpy, m_aGLWin.vi, GLX_SAMPLES, &nSamples); - if( nSamples > 0 ) - m_aGLWin.bMultiSampleSupported = true; - - m_aGLWin.GLXExtensions = glXQueryExtensionsString( m_aGLWin.dpy, m_aGLWin.screen ); - SAL_INFO("vcl.opengl", "available GLX extensions: " << m_aGLWin.GLXExtensions); + //nothing by default } -#endif - void OpenGLContext::reset() { if( !mbInitialized ) @@ -1249,127 +412,46 @@ void OpenGLContext::reset() mbInitialized = false; // destroy the context itself -#if defined(_WIN32) - if (m_aGLWin.hRC) - { - std::vector<HGLRC>::iterator itr = std::remove(g_vShareList.begin(), g_vShareList.end(), m_aGLWin.hRC); - if (itr != g_vShareList.end()) - g_vShareList.erase(itr); - - if (wglGetCurrentContext() != NULL) - wglMakeCurrent(NULL, NULL); - wglDeleteContext( m_aGLWin.hRC ); - ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC ); - m_aGLWin.hRC = 0; - } -#elif defined( MACOSX ) - [NSOpenGLContext clearCurrentContext]; -#elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS) - // nothing -#elif defined( UNX ) - if(m_aGLWin.ctx) - { - std::vector<GLXContext>::iterator itr = std::remove( g_vShareList.begin(), g_vShareList.end(), m_aGLWin.ctx ); - if (itr != g_vShareList.end()) - g_vShareList.erase(itr); - - glXMakeCurrent(m_aGLWin.dpy, None, nullptr); - if( glGetError() != GL_NO_ERROR ) - { - SAL_WARN("vcl.opengl", "glError: " << glGetError()); - } - glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx); - m_aGLWin.ctx = nullptr; - } -#endif + destroyCurrentContext(); } -#if defined(_WIN32) || defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) - -SystemWindowData OpenGLContext::generateWinData(vcl::Window* /*pParent*/, bool bRequestLegacyContext) +SystemWindowData OpenGLContext::generateWinData(vcl::Window* /*pParent*/, bool /*bRequestLegacyContext*/) { - (void) bRequestLegacyContext; SystemWindowData aWinData; -#if defined(MACOSX) - aWinData.bOpenGL = true; - aWinData.bLegacy = bRequestLegacyContext; -#endif aWinData.nSize = sizeof(aWinData); return aWinData; } -#elif defined( UNX ) - -SystemWindowData OpenGLContext::generateWinData(vcl::Window* pParent, bool) +bool OpenGLContext::isCurrent() { - OpenGLZone aZone; - - SystemWindowData aWinData; - aWinData.nSize = sizeof(aWinData); - aWinData.pVisual = nullptr; - -#if !defined(LIBO_HEADLESS) - const SystemEnvData* sysData(pParent->GetSystemData()); - - Display *dpy = static_cast<Display*>(sysData->pDisplay); - Window win = sysData->aWindow; - - if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) ) - return aWinData; - - initOpenGLFunctionPointers(); - - int best_fbc = -1; - GLXFBConfig* pFBC = getFBConfig(dpy, win, best_fbc, true, false); + (void) this; // loplugin:staticmethods + return false; +} - if (!pFBC) - return aWinData; +void OpenGLContext::makeCurrent() +{ + if (isCurrent()) + return; - XVisualInfo* vi = nullptr; - if( best_fbc != -1 ) - vi = glXGetVisualFromFBConfig( dpy, pFBC[best_fbc] ); + OpenGLZone aZone; - XFree(pFBC); + clearCurrent(); - if( vi ) - { - VCL_GL_INFO("using VisualID " << vi->visualid); - aWinData.pVisual = static_cast<void*>(vi->visual); - } -#endif + // by default nothing else to do - return aWinData; + registerAsCurrent(); } -#endif - -bool OpenGLContext::isCurrent() +bool OpenGLContext::isAnyCurrent() { - OpenGLZone aZone; - -#if defined(_WIN32) - return wglGetCurrentContext() == m_aGLWin.hRC && - wglGetCurrentDC() == m_aGLWin.hDC; -#elif defined( MACOSX ) - (void) this; // loplugin:staticmethods - return false; -#elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS) return false; -#elif defined( UNX ) - return m_aGLWin.ctx && glXGetCurrentContext() == m_aGLWin.ctx && - glXGetCurrentDrawable() == m_aGLWin.win; -#endif } bool OpenGLContext::hasCurrent() { -#if defined(_WIN32) - return wglGetCurrentContext() != NULL; -#elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS) - return false; -#elif defined( UNX ) - return glXGetCurrentContext() != None; -#endif + ImplSVData* pSVData = ImplGetSVData(); + rtl::Reference<OpenGLContext> pCurrentCtx = pSVData->maGDIData.mpLastContext; + return pCurrentCtx.is() && pCurrentCtx->isAnyCurrent(); } void OpenGLContext::clearCurrent() @@ -1402,45 +484,6 @@ void OpenGLContext::prepareForYield() assert (!hasCurrent()); } -void OpenGLContext::makeCurrent() -{ - if (isCurrent()) - return; - - OpenGLZone aZone; - - clearCurrent(); - -#if defined(_WIN32) - if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) - { - SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent(): wglMakeCurrent failed: " << GetLastError()); - return; - } -#elif defined( MACOSX ) - NSOpenGLView* pView = getOpenGLView(); - [[pView openGLContext] makeCurrentContext]; -#elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS) - // nothing -#elif defined( UNX ) -#ifdef DBG_UTIL - TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler); -#endif - - if (m_aGLWin.dpy) - { - if (!glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx )) - { - SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent failed " - "on drawable " << m_aGLWin.win); - return; - } - } -#endif - - registerAsCurrent(); -} - rtl::Reference<OpenGLContext> OpenGLContext::getVCLContext(bool bMakeIfNecessary) { ImplSVData* pSVData = ImplGetSVData(); @@ -1503,37 +546,17 @@ void OpenGLContext::registerAsCurrent() void OpenGLContext::resetCurrent() { clearCurrent(); - - OpenGLZone aZone; - -#if defined(_WIN32) - wglMakeCurrent(NULL, NULL); -#elif defined( MACOSX ) - (void) this; // loplugin:staticmethods - [NSOpenGLContext clearCurrentContext]; -#elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS) - // nothing -#elif defined( UNX ) - if (m_aGLWin.dpy) - glXMakeCurrent(m_aGLWin.dpy, None, nullptr); -#endif + // by default nothing else to do } void OpenGLContext::swapBuffers() { - OpenGLZone aZone; - -#if defined(_WIN32) - SwapBuffers(m_aGLWin.hDC); -#elif defined( MACOSX ) - NSOpenGLView* pView = getOpenGLView(); - [[pView openGLContext] flushBuffer]; -#elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS) - // nothing -#elif defined( UNX ) - glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win); -#endif + // by default nothing else to do + BuffersSwapped(); +} +void OpenGLContext::BuffersSwapped() +{ nBufferSwapCounter++; static bool bSleep = getenv("SAL_GL_SLEEP_ON_SWAP"); @@ -1544,6 +567,7 @@ void OpenGLContext::swapBuffers() } } + sal_Int64 OpenGLWrapper::getBufferSwapCounter() { return nBufferSwapCounter; @@ -1551,17 +575,8 @@ sal_Int64 OpenGLWrapper::getBufferSwapCounter() void OpenGLContext::sync() { - OpenGLZone aZone; - -#if defined(_WIN32) - // nothing -#elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS) + // default is nothing (void) this; // loplugin:staticmethods - // nothing -#elif defined( UNX ) - glXWaitGL(); - XSync(m_aGLWin.dpy, false); -#endif } void OpenGLContext::show() @@ -1587,13 +602,6 @@ bool OpenGLContext::supportMultiSampling() const return m_aGLWin.bMultiSampleSupported; } -#if defined(MACOSX) -NSOpenGLView* OpenGLContext::getOpenGLView() -{ - return reinterpret_cast<NSOpenGLView*>(m_pChildWindow->GetSystemData()->mpNSView); -} -#endif - bool OpenGLContext::BindFramebuffer( OpenGLFramebuffer* pFramebuffer ) { OpenGLZone aZone; diff --git a/vcl/source/window/openglwin.cxx b/vcl/source/window/openglwin.cxx index 3f95894181d1..442d1daa6483 100644 --- a/vcl/source/window/openglwin.cxx +++ b/vcl/source/window/openglwin.cxx @@ -26,7 +26,7 @@ private: OpenGLWindowImpl::OpenGLWindowImpl(vcl::Window* pWindow) : mxContext(OpenGLContext::Create()) { - SystemWindowData aData = OpenGLContext::generateWinData(pWindow, false); + SystemWindowData aData = mxContext->generateWinData(pWindow, false); mxChildWindow.reset(VclPtr<SystemChildWindow>::Create(pWindow, 0, &aData)); mxChildWindow->Show(); mxContext->init(mxChildWindow.get()); |