GHOST: Add new interface to manage offscreen contexts.
authorClément Foucault <foucault.clem@gmail.com>
Mon, 26 Feb 2018 18:10:15 +0000 (19:10 +0100)
committerClément Foucault <foucault.clem@gmail.com>
Mon, 26 Feb 2018 18:10:15 +0000 (19:10 +0100)
Offscreen contexts are not attached to a window and can only be used for rendering to frambuffer objects.

CGL implementation : Brecht Van Lommel (brecht)
GLX implementation : Clément Foucault (fclem)
WGL implementation : Germano Cavalcante (mano-wii)

Other implementation are just place holder for now.

25 files changed:
intern/ghost/CMakeLists.txt
intern/ghost/GHOST_C-api.h
intern/ghost/GHOST_IContext.h [new file with mode: 0644]
intern/ghost/GHOST_ISystem.h
intern/ghost/intern/GHOST_C-api.cpp
intern/ghost/intern/GHOST_Context.h
intern/ghost/intern/GHOST_ContextCGL.h
intern/ghost/intern/GHOST_ContextCGL.mm
intern/ghost/intern/GHOST_ContextEGL.cpp
intern/ghost/intern/GHOST_ContextEGL.h
intern/ghost/intern/GHOST_ContextGLX.cpp
intern/ghost/intern/GHOST_ContextGLX.h
intern/ghost/intern/GHOST_ContextNone.cpp
intern/ghost/intern/GHOST_ContextNone.h
intern/ghost/intern/GHOST_ContextSDL.cpp
intern/ghost/intern/GHOST_ContextSDL.h
intern/ghost/intern/GHOST_ContextWGL.cpp
intern/ghost/intern/GHOST_ContextWGL.h
intern/ghost/intern/GHOST_SystemCocoa.h
intern/ghost/intern/GHOST_SystemCocoa.mm
intern/ghost/intern/GHOST_SystemWin32.cpp
intern/ghost/intern/GHOST_SystemWin32.h
intern/ghost/intern/GHOST_SystemX11.cpp
intern/ghost/intern/GHOST_SystemX11.h
intern/ghost/intern/GHOST_WindowCocoa.mm

index 5a97da2..7771af9 100644 (file)
@@ -54,6 +54,7 @@ set(SRC
        intern/GHOST_WindowManager.cpp
 
        GHOST_C-api.h
+       GHOST_IContext.h
        GHOST_IEvent.h
        GHOST_IEventConsumer.h
        GHOST_ISystem.h
index 967d3f5..d5d8be7 100644 (file)
@@ -52,6 +52,7 @@ GHOST_DECLARE_HANDLE(GHOST_WindowHandle);
 GHOST_DECLARE_HANDLE(GHOST_EventHandle);
 GHOST_DECLARE_HANDLE(GHOST_RectangleHandle);
 GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
+GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
 
 
 /**
@@ -188,6 +189,23 @@ extern GHOST_WindowHandle GHOST_CreateWindow(
         GHOST_TDrawingContextType type,
         GHOST_GLSettings glSettings);
 
+/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \param systemhandle The handle to the system
+ * \return A handle to the new context ( == NULL if creation failed).
+ */
+extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle);
+
+/**
+ * Dispose of a context.
+ * \param systemhandle The handle to the system
+ * \param contexthandle Handle to the context to be disposed.
+ * \return Indication of success.
+ */
+extern GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
+                                                    GHOST_ContextHandle contexthandle);
+
 /**
  * Returns the window user data.
  * \param windowhandle The handle to the window
@@ -710,6 +728,20 @@ extern GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle wind
  */
 extern GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle);
 
+/**
+ * Activates the drawing context of this context.
+ * \param contexthandle The handle to the context
+ * \return A success indicator.
+ */
+extern GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle);
+
+/**
+ * Release the drawing context bound to this thread.
+ * \param contexthandle The handle to the context
+ * \return A success indicator.
+ */
+extern GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle);
+
 /**
  * Returns the status of the tablet
  * \param windowhandle The handle to the window
diff --git a/intern/ghost/GHOST_IContext.h b/intern/ghost/GHOST_IContext.h
new file mode 100644 (file)
index 0000000..5b027a6
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ghost/GHOST_IContext.h
+ *  \ingroup GHOST
+ * Declaration of GHOST_IContext interface class.
+ */
+
+#ifndef __GHOST_IContext_H__
+#define __GHOST_IContext_H__
+
+#include "STR_String.h"
+#include "GHOST_Types.h"
+
+
+/**
+ * Interface for GHOST context.
+ *
+ * You can create a offscreen context (windowless) with the system's
+ * GHOST_ISystem::createOffscreenContext method.
+ * \see GHOST_ISystem#createOffscreenContext
+ *
+ * \author  Clément Foucault
+ * \date    Feb 9, 2018
+ */
+class GHOST_IContext
+{
+public:
+       /**
+        * Destructor.
+        */
+       virtual ~GHOST_IContext()
+       {
+       }
+
+       /**
+        * Activates the drawing context.
+        * \return  A boolean success indicator.
+        */
+       virtual GHOST_TSuccess activateDrawingContext() = 0;
+
+       /**
+        * Release the drawing context of the calling thread.
+        * \return  A boolean success indicator.
+        */
+       virtual GHOST_TSuccess releaseDrawingContext() = 0;
+
+#ifdef WITH_CXX_GUARDEDALLOC
+       MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IContext")
+#endif
+};
+
+#endif // __GHOST_IContext_H__
+
index 03193d6..5c5590e 100644 (file)
@@ -36,6 +36,7 @@
 #define __GHOST_ISYSTEM_H__
 
 #include "GHOST_Types.h"
+#include "GHOST_IContext.h"
 #include "GHOST_ITimerTask.h"
 #include "GHOST_IWindow.h"
 
@@ -261,6 +262,20 @@ public:
         */
        virtual GHOST_TSuccess disposeWindow(GHOST_IWindow *window) = 0;
 
+       /**
+        * Create a new offscreen context.
+        * Never explicitly delete the context, use disposeContext() instead.
+        * \return  The new context (or 0 if creation failed).
+        */
+       virtual GHOST_IContext *createOffscreenContext() = 0;
+
+       /**
+        * Dispose of a context.
+        * \param   context Pointer to the context to be disposed.
+        * \return  Indication of success.
+        */
+       virtual GHOST_TSuccess disposeContext(GHOST_IContext *context) = 0;
+
        /**
         * Returns whether a window is valid.
         * \param   window Pointer to the window to be checked.
index ce65318..2fe9417 100644 (file)
@@ -132,6 +132,22 @@ void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
        system->getAllDisplayDimensions(*width, *height);
 }
 
+GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle)
+{
+       GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
+
+       return (GHOST_ContextHandle) system->createOffscreenContext();
+}
+
+GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
+                                             GHOST_ContextHandle contexthandle)
+{
+       GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
+       GHOST_IContext *context = (GHOST_IContext *) contexthandle;
+
+       return system->disposeContext(context);
+}
+
 GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
                                       const char *title,
                                       GHOST_TInt32 left,
@@ -713,7 +729,19 @@ GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandl
        return window->activateDrawingContext();
 }
 
+GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
+{
+       GHOST_IContext *context = (GHOST_IContext *) contexthandle;
+
+       return context->activateDrawingContext();
+}
+
+GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
+{
+       GHOST_IContext *context = (GHOST_IContext *) contexthandle;
 
+       return context->releaseDrawingContext();
+}
 
 GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle)
 {
index 8776fa4..670b86d 100644 (file)
@@ -33,6 +33,7 @@
 #ifndef __GHOST_CONTEXT_H__
 #define __GHOST_CONTEXT_H__
 
+#include "GHOST_IContext.h"
 #include "GHOST_Types.h"
 
 #include "glew-mx.h"
@@ -40,7 +41,7 @@
 #include <cstdlib> // for NULL
 
 
-class GHOST_Context
+class GHOST_Context : public GHOST_IContext
 {
 public:
        /**
@@ -71,6 +72,12 @@ public:
         */
        virtual GHOST_TSuccess activateDrawingContext() = 0;
 
+       /**
+        * Release the drawing context of the calling thread.
+        * \return  A boolean success indicator.
+        */
+       virtual GHOST_TSuccess releaseDrawingContext()= 0;
+
        /**
         * Call immediately after new to initialize.  If this fails then immediately delete the object.
         * \return Indication as to whether initialization has succeeded.
index 6dcc4da..ea6eb48 100644 (file)
@@ -82,6 +82,12 @@ public:
         */
        GHOST_TSuccess activateDrawingContext();
 
+       /**
+        * Release the drawing context of the calling thread.
+        * \return  A boolean success indicator.
+        */
+       GHOST_TSuccess releaseDrawingContext();
+
        /**
         * Call immediately after new to initialize.  If this fails then immediately delete the object.
         * \return Indication as to whether initialization has succeeded.
index 03af3cc..46993a1 100644 (file)
@@ -35,6 +35,8 @@
 
 #include <Cocoa/Cocoa.h>
 
+//#define GHOST_MULTITHREADED_OPENGL
+
 #ifdef GHOST_MULTITHREADED_OPENGL
 #include <OpenGL/OpenGL.h>
 #endif
@@ -62,8 +64,6 @@ GHOST_ContextCGL::GHOST_ContextCGL(
       m_openGLContext(nil),
       m_debug(contextFlags)
 {
-       assert(openGLView != nil);
-
        // for now be very strict about OpenGL version requested
        switch (contextMajorVersion) {
                case 2:
@@ -73,7 +73,7 @@ GHOST_ContextCGL::GHOST_ContextCGL(
                        break;
                case 3:
                        // Apple didn't implement 3.0 or 3.1
-                       assert(contextMinorVersion == 2);
+                       assert(contextMinorVersion == 3);
                        assert(contextProfileMask == GL_CONTEXT_CORE_PROFILE_BIT);
                        m_coreProfile = true;
                        break;
@@ -88,7 +88,10 @@ GHOST_ContextCGL::~GHOST_ContextCGL()
        if (m_openGLContext != nil) {
                if (m_openGLContext == [NSOpenGLContext currentContext]) {
                        [NSOpenGLContext clearCurrentContext];
-                       [m_openGLView clearGLContext];
+
+                       if(m_openGLView) {
+                               [m_openGLView clearGLContext];
+                       }
                }
 
                if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) {
@@ -167,6 +170,18 @@ GHOST_TSuccess GHOST_ContextCGL::activateDrawingContext()
        }
 }
 
+GHOST_TSuccess GHOST_ContextCGL::releaseDrawingContext()
+{
+       if (m_openGLContext != nil) {
+               NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+               [NSOpenGLContext clearCurrentContext];
+               [pool drain];
+               return GHOST_kSuccess;
+       }
+       else {
+               return GHOST_kFailure;
+       }
+}
 
 GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext()
 {
@@ -258,7 +273,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
        std::vector<NSOpenGLPixelFormatAttribute> attribs;
        attribs.reserve(40);
 
-       NSOpenGLContext *prev_openGLContext = [m_openGLView openGLContext];
+       NSOpenGLContext *prev_openGLContext = (m_openGLView) ? [m_openGLView openGLContext] : NULL;
 
 #ifdef GHOST_OPENGL_ALPHA
        static const bool needAlpha   = true;
@@ -346,8 +361,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
 
 #ifdef GHOST_MULTITHREADED_OPENGL
        //Switch openGL to multhreaded mode
-       CGLContextObj cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj];
-       if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError)
+       if (CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine) == kCGLNoError)
                if (m_debug)
                        fprintf(stderr, "\nSwitched OpenGL to multithreaded mode\n");
 #endif
@@ -362,8 +376,10 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
 
        initContextGLEW();
 
-       [m_openGLView setOpenGLContext:m_openGLContext];
-       [m_openGLContext setView:m_openGLView];
+       if (m_openGLView) {
+               [m_openGLView setOpenGLContext:m_openGLContext];
+               [m_openGLContext setView:m_openGLView];
+       }
 
        if (s_sharedCount == 0)
                s_sharedOpenGLContext = m_openGLContext;
@@ -380,7 +396,10 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
 
 error:
 
-       [m_openGLView setOpenGLContext:prev_openGLContext];
+       if (m_openGLView) {
+               [m_openGLView setOpenGLContext:prev_openGLContext];
+       }
+
        [pixelFormat release];
 
        [pool drain];
index a591d9b..56962d2 100644 (file)
@@ -312,6 +312,17 @@ GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext()
        }
 }
 
+GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext()
+{
+       if (m_display) {
+               bindAPI(m_api);
+
+               return EGL_CHK(::eglMakeCurrent(m_display, None, None, NULL)) ? GHOST_kSuccess : GHOST_kFailure;
+       }
+       else {
+               return GHOST_kFailure;
+       }
+}
 
 void GHOST_ContextEGL::initContextEGLEW()
 {
index 6dfb177..83415f6 100644 (file)
@@ -80,6 +80,12 @@ public:
         */
        GHOST_TSuccess activateDrawingContext();
 
+       /**
+        * Release the drawing context of the calling thread.
+        * \return  A boolean success indicator.
+        */
+       GHOST_TSuccess releaseDrawingContext();
+
        /**
         * Call immediately after new to initialize.  If this fails then immediately delete the object.
         * \return Indication as to whether initialization has succeeded.
index 061ac29..fb7fa4e 100644 (file)
@@ -74,7 +74,6 @@ GHOST_ContextGLX::GHOST_ContextGLX(
       m_contextResetNotificationStrategy(contextResetNotificationStrategy),
       m_context(None)
 {
-       assert(m_window  != 0);
        assert(m_display != NULL);
 }
 
@@ -119,6 +118,16 @@ GHOST_TSuccess GHOST_ContextGLX::activateDrawingContext()
        }
 }
 
+GHOST_TSuccess GHOST_ContextGLX::releaseDrawingContext()
+{
+       if (m_display) {
+               return ::glXMakeCurrent(m_display, None, NULL) ? GHOST_kSuccess : GHOST_kFailure;
+       }
+       else {
+               return GHOST_kFailure;
+       }
+}
+
 void GHOST_ContextGLX::initContextGLXEW()
 {
        initContextGLEW();
@@ -246,9 +255,22 @@ const bool GLXEW_ARB_create_context_robustness =
                }
                attribs[i++] = 0;
 
+               /* Some drivers don't like having a true offscreen context.
+                * Create a pixel buffer instead of a window to render to.
+                * even if it will never be used for drawing. */
+               int pbuffer_attribs[] = {
+                       GLX_PBUFFER_WIDTH, 1,
+                       GLX_PBUFFER_HEIGHT, 1,
+                       None
+               };
+
                /* Create a GL 3.x context */
                if (m_fbconfig) {
                        m_context = glXCreateContextAttribsARB(m_display, m_fbconfig, s_sharedContext, true, attribs);
+
+                       if (!m_window) {
+                               m_window = (Window)glXCreatePbuffer(m_display, m_fbconfig, pbuffer_attribs);
+                       }
                }
                else {
                        GLXFBConfig *framebuffer_config = NULL;
@@ -263,6 +285,11 @@ const bool GLXEW_ARB_create_context_robustness =
 
                        if (framebuffer_config) {
                                m_context = glXCreateContextAttribsARB(m_display, framebuffer_config[0], s_sharedContext, True, attribs);
+
+                               if (!m_window) {
+                                       m_window = (Window)glXCreatePbuffer(m_display, framebuffer_config[0], pbuffer_attribs);
+                               }
+
                                XFree(framebuffer_config);
                        }
                }
@@ -288,8 +315,10 @@ const bool GLXEW_ARB_create_context_robustness =
                // which means we cannot use glX extensions until after we create a context
                initContextGLXEW();
 
-               initClearGL();
-               ::glXSwapBuffers(m_display, m_window);
+               if (m_window) {
+                       initClearGL();
+                       ::glXSwapBuffers(m_display, m_window);
+               }
 
                /* re initialize to get the extensions properly */
                initContextGLXEW();
index 51fb1dd..ded1b29 100644 (file)
@@ -81,6 +81,12 @@ public:
         */
        GHOST_TSuccess activateDrawingContext();
 
+       /**
+        * Release the drawing context of the calling thread.
+        * \return  A boolean success indicator.
+        */
+       GHOST_TSuccess releaseDrawingContext();
+
        /**
         * Call immediately after new to initialize.  If this fails then immediately delete the object.
         * \return Indication as to whether initialization has succeeded.
index 380ab53..89bdf6b 100644 (file)
@@ -46,6 +46,12 @@ GHOST_TSuccess GHOST_ContextNone::activateDrawingContext()
 }
 
 
+GHOST_TSuccess GHOST_ContextNone::releaseDrawingContext()
+{
+       return GHOST_kSuccess;
+}
+
+
 GHOST_TSuccess GHOST_ContextNone::updateDrawingContext()
 {
        return GHOST_kSuccess;
index 80cce76..9f2af4a 100644 (file)
@@ -59,6 +59,12 @@ public:
         */
        GHOST_TSuccess activateDrawingContext();
 
+       /**
+        * Dummy function
+        * \return  Always succeeds
+        */
+       GHOST_TSuccess releaseDrawingContext();
+
        /**
         * Dummy function
         * \return Always succeeds
index 7a02e97..1ba591b 100644 (file)
@@ -105,6 +105,18 @@ GHOST_TSuccess GHOST_ContextSDL::activateDrawingContext()
 }
 
 
+GHOST_TSuccess GHOST_ContextSDL::releaseDrawingContext()
+{
+       if (m_context) {
+               /* Untested, may not work */
+               return SDL_GL_MakeCurrent(NULL, NULL) ? GHOST_kSuccess : GHOST_kFailure;
+       }
+       else {
+               return GHOST_kFailure;
+       }
+}
+
+
 GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
 {
 #ifdef GHOST_OPENGL_ALPHA
index 61f339c..681d24b 100644 (file)
@@ -85,6 +85,12 @@ public:
         */
        GHOST_TSuccess activateDrawingContext();
 
+       /**
+        * Release the drawing context of the calling thread.
+        * \return  A boolean success indicator.
+        */
+       GHOST_TSuccess releaseDrawingContext();
+
        /**
         * Call immediately after new to initialize.  If this fails then immediately delete the object.
         * \return Indication as to whether initialization has succeeded.
index 7b5e302..a23c0b0 100644 (file)
 HGLRC GHOST_ContextWGL::s_sharedHGLRC = NULL;
 int   GHOST_ContextWGL::s_sharedCount = 0;
 
-bool GHOST_ContextWGL::s_singleContextMode = false;
-
-
-/* Intel video-cards don't work fine with multiple contexts and
- * have to share the same context for all windows.
- * But if we just share context for all windows it could work incorrect
- * with multiple videocards configuration. Suppose, that Intel videocards
- * can't be in multiple-devices configuration. */
+/* Some third-generation Intel video-cards are constantly bring problems */
 static bool is_crappy_intel_card()
 {
        return strstr((const char *)glGetString(GL_VENDOR), "Intel") != NULL;
@@ -69,6 +62,7 @@ GHOST_ContextWGL::GHOST_ContextWGL(
         int contextFlags,
         int contextResetNotificationStrategy)
     : GHOST_Context(stereoVisual, numOfAASamples),
+      m_dummyPbuffer(NULL),
       m_hWnd(hWnd),
       m_hDC(hDC),
       m_contextProfileMask(contextProfileMask),
@@ -85,8 +79,6 @@ GHOST_ContextWGL::GHOST_ContextWGL(
       m_dummyVersion(NULL)
 #endif
 {
-       assert(m_hWnd);
-       assert(m_hDC);
 }
 
 
@@ -106,12 +98,20 @@ GHOST_ContextWGL::~GHOST_ContextWGL()
 
                        WIN32_CHK(::wglDeleteContext(m_hGLRC));
                }
+               if (m_dummyPbuffer) {
+                       if (m_hDC != NULL)
+                               WIN32_CHK(::wglReleasePbufferDCARB(m_dummyPbuffer, m_hDC));
+
+                       WIN32_CHK(::wglDestroyPbufferARB(m_dummyPbuffer));
+               }
        }
 
 #ifndef NDEBUG
-       free((void*)m_dummyRenderer);
-       free((void*)m_dummyVendor);
-       free((void*)m_dummyVersion);
+       if (m_dummyRenderer) {
+               free((void*)m_dummyRenderer);
+               free((void*)m_dummyVendor);
+               free((void*)m_dummyVersion);
+       }
 #endif
 }
 
@@ -154,6 +154,16 @@ GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext()
 }
 
 
+GHOST_TSuccess GHOST_ContextWGL::releaseDrawingContext()
+{
+       if (WIN32_CHK(::wglMakeCurrent(NULL, NULL))) {
+               return GHOST_kSuccess;
+       }
+       else {
+               return GHOST_kFailure;
+       }
+}
+
 /* Ron Fosner's code for weighting pixel formats and forcing software.
  * See http://www.opengl.org/resources/faq/technical/weight.cpp
  */
@@ -317,6 +327,8 @@ static HWND clone_window(HWND hWnd, LPVOID lpParam)
 void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
 {
        HWND  dummyHWND  = NULL;
+       HPBUFFERARB dummyhBuffer = NULL;
+
        HDC   dummyHDC   = NULL;
        HGLRC dummyHGLRC = NULL;
 
@@ -333,23 +345,29 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
        prevHGLRC = ::wglGetCurrentContext();
        WIN32_CHK(GetLastError() == NO_ERROR);
 
-       dummyHWND = clone_window(m_hWnd, NULL);
+       iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD);
 
-       if (dummyHWND == NULL)
+       if (iPixelFormat == 0)
                goto finalize;
 
-       dummyHDC = GetDC(dummyHWND);
-
-       if (!WIN32_CHK(dummyHDC != NULL))
+       PIXELFORMATDESCRIPTOR chosenPFD;
+       if (!WIN32_CHK(::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD)))
                goto finalize;
 
-       iPixelFormat = choose_pixel_format_legacy(dummyHDC, preferredPFD);
+       if (m_hWnd) {
+               dummyHWND = clone_window(m_hWnd, NULL);
 
-       if (iPixelFormat == 0)
-               goto finalize;
+               if (dummyHWND == NULL)
+                       goto finalize;
 
-       PIXELFORMATDESCRIPTOR chosenPFD;
-       if (!WIN32_CHK(::DescribePixelFormat(dummyHDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD)))
+               dummyHDC = GetDC(dummyHWND);
+       }
+       else {
+               dummyhBuffer = wglCreatePbufferARB(m_hDC, iPixelFormat, 1, 1, 0);
+               dummyHDC = wglGetPbufferDCARB(dummyhBuffer);
+       }
+
+       if (!WIN32_CHK(dummyHDC != NULL))
                goto finalize;
 
        if (!WIN32_CHK(::SetPixelFormat(dummyHDC, iPixelFormat, &chosenPFD)))
@@ -378,8 +396,6 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
        m_dummyVersion  = _strdup(reinterpret_cast<const char *>(glGetString(GL_VERSION)));
 #endif
 
-       s_singleContextMode = is_crappy_intel_card();
-
 finalize:
        WIN32_CHK(::wglMakeCurrent(prevHDC, prevHGLRC));
 
@@ -392,6 +408,12 @@ finalize:
 
                WIN32_CHK(::DestroyWindow(dummyHWND));
        }
+       else if (dummyhBuffer != NULL) {
+               if (dummyHDC != NULL)
+                       WIN32_CHK(::wglReleasePbufferDCARB(dummyhBuffer, dummyHDC));
+
+               WIN32_CHK(::wglDestroyPbufferARB(dummyhBuffer));
+       }
 }
 
 
@@ -753,7 +775,9 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
        HDC prevHDC = ::wglGetCurrentDC();
        WIN32_CHK(GetLastError() == NO_ERROR);
 
-       if (!WGLEW_ARB_create_context || ::GetPixelFormat(m_hDC) == 0) {
+       const bool create_hDC = m_hDC == NULL;
+
+       if (!WGLEW_ARB_create_context || create_hDC || ::GetPixelFormat(m_hDC) == 0) {
                const bool needAlpha = m_alphaBackground;
 
 #ifdef GHOST_OPENGL_STENCIL
@@ -770,20 +794,32 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
                int iPixelFormat;
                int lastPFD;
 
+               if (create_hDC) {
+                       /* get a handle to a device context with graphics accelerator enabled */
+                       m_hDC = wglGetCurrentDC();
+                       if (m_hDC == NULL) {
+                               m_hDC = GetDC(NULL);
+                       }
+               }
+
                PIXELFORMATDESCRIPTOR chosenPFD;
 
                iPixelFormat = choose_pixel_format(m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, sRGB);
 
                if (iPixelFormat == 0) {
-                       ::wglMakeCurrent(prevHDC, prevHGLRC);
-                       return GHOST_kFailure;
+                       goto error;
+               }
+
+               if (create_hDC) {
+                       /* create an off-screen pixel buffer (Pbuffer) */
+                       m_dummyPbuffer = wglCreatePbufferARB(m_hDC, iPixelFormat, 1, 1, 0);
+                       m_hDC = wglGetPbufferDCARB(m_dummyPbuffer);
                }
 
                lastPFD = ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD);
 
                if (!WIN32_CHK(lastPFD != 0)) {
-                       ::wglMakeCurrent(prevHDC, prevHGLRC);
-                       return GHOST_kFailure;
+                       goto error;
                }
 
                if (needAlpha && chosenPFD.cAlphaBits == 0)
@@ -793,8 +829,7 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
                        fprintf(stderr, "Warning! Unable to find a pixel format with a stencil buffer.\n");
 
                if (!WIN32_CHK(::SetPixelFormat(m_hDC, iPixelFormat, &chosenPFD))) {
-                       ::wglMakeCurrent(prevHDC, prevHGLRC);
-                       return GHOST_kFailure;
+                       goto error;
                }
        }
 
@@ -870,30 +905,24 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
 
                iAttributes.push_back(0);
 
-               if (!s_singleContextMode || s_sharedHGLRC == NULL)
-                       m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0]));
-               else
-                       m_hGLRC = s_sharedHGLRC;
+               m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0]));
        }
 
        if (!WIN32_CHK(m_hGLRC != NULL)) {
-               ::wglMakeCurrent(prevHDC, prevHGLRC);
-               return GHOST_kFailure;
+               goto error;
        }
 
-       if (s_sharedHGLRC == NULL)
-               s_sharedHGLRC = m_hGLRC;
-
        s_sharedCount++;
 
-       if (!s_singleContextMode && s_sharedHGLRC != m_hGLRC && !WIN32_CHK(::wglShareLists(s_sharedHGLRC, m_hGLRC))) {
-               ::wglMakeCurrent(prevHDC, prevHGLRC);
-               return GHOST_kFailure;
+       if (s_sharedHGLRC == NULL) {
+               s_sharedHGLRC = m_hGLRC;
+       }
+       else if (!WIN32_CHK(::wglShareLists(s_sharedHGLRC, m_hGLRC))) {
+               goto error;
        }
 
        if (!WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
-               ::wglMakeCurrent(prevHDC, prevHGLRC);
-               return GHOST_kFailure;
+               goto error;
        }
 
        initContextGLEW();
@@ -923,6 +952,16 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
 #endif
 
        return GHOST_kSuccess;
+error:
+       if (m_dummyPbuffer) {
+               if (m_hDC != NULL)
+                       WIN32_CHK(::wglReleasePbufferDCARB(m_dummyPbuffer, m_hDC));
+
+               WIN32_CHK(::wglDestroyPbufferARB(m_dummyPbuffer));
+       }
+       ::wglMakeCurrent(prevHDC, prevHGLRC);
+       return GHOST_kFailure;
+
 }
 
 
index a07cc1b..b3b66c5 100644 (file)
@@ -78,6 +78,12 @@ public:
         */
        GHOST_TSuccess activateDrawingContext();
 
+       /**
+        * Release the drawing context of the calling thread.
+        * \return  A boolean success indicator.
+        */
+       GHOST_TSuccess releaseDrawingContext();
+
        /**
         * Call immediately after new to initialize.  If this fails then immediately delete the object.
         * \return Indication as to whether initialization has succeeded.
@@ -137,6 +143,10 @@ private:
 
        void initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD);
 
+       /* offscreen buffer with size of 1x1 pixel,
+        * kept here to release the device constext when closing the program. */
+       HPBUFFERARB m_dummyPbuffer;
+
        HWND m_hWnd;
        HDC  m_hDC;
 
index 6802ad4..62d9774 100644 (file)
@@ -123,6 +123,25 @@ public:
            const GHOST_TEmbedderWindowID parentWindow = 0
            );
        
+       /**
+        * Create a new offscreen context.
+        * Never explicitly delete the context, use disposeContext() instead.
+        * \return  The new context (or 0 if creation failed).
+        */
+       GHOST_IContext *
+       createOffscreenContext(
+           );
+
+       /**
+        * Dispose of a context.
+        * \param   context Pointer to the context to be disposed.
+        * \return  Indication of success.
+        */
+       GHOST_TSuccess
+       disposeContext(
+           GHOST_IContext *context
+           );
+
        /***************************************************************************************
         * Event management functionality
         ***************************************************************************************/
index e9fffb6..011719e 100644 (file)
  * ***** END GPL LICENSE BLOCK *****
  */
 
-#import <Cocoa/Cocoa.h>
-
-/*For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible)*/
-#include <Carbon/Carbon.h>
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/sysctl.h>
-
 #include "GHOST_SystemCocoa.h"
 
 #include "GHOST_DisplayManagerCocoa.h"
 #include "GHOST_WindowManager.h"
 #include "GHOST_WindowCocoa.h"
 
+#if defined(WITH_GL_EGL)
+#  include "GHOST_ContextEGL.h"
+#else
+#  include "GHOST_ContextCGL.h"
+#endif
+
 #ifdef WITH_INPUT_NDOF
   #include "GHOST_NDOFManagerCocoa.h"
 #endif
 
 #include "AssertMacros.h"
 
+#import <Cocoa/Cocoa.h>
+
+/* For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible) */
+#include <Carbon/Carbon.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
 
 #pragma mark KeyMap, mouse converters
 
@@ -580,6 +585,53 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
        return window;
 }
 
+/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \return  The new context (or 0 if creation failed).
+ */
+GHOST_IContext *
+GHOST_SystemCocoa::
+createOffscreenContext()
+{
+       GHOST_Context *context = new GHOST_ContextCGL(
+               false,
+               0,
+               NULL,
+               NULL,
+
+#if defined(WITH_GL_PROFILE_CORE)
+               GL_CONTEXT_CORE_PROFILE_BIT,
+               3, 3,
+#else
+               0, // no profile bit
+               2, 1,
+#endif
+               GHOST_OPENGL_CGL_CONTEXT_FLAGS,
+               GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY);
+
+       if (context->initializeDrawingContext())
+               return context;
+       else
+               delete context;
+
+       return NULL;
+}
+
+/**
+ * Dispose of a context.
+ * \param   context Pointer to the context to be disposed.
+ * \return  Indication of success.
+ */
+GHOST_TSuccess
+GHOST_SystemCocoa::
+disposeContext(GHOST_IContext *context)
+{
+       delete context;
+
+       return GHOST_kSuccess;
+}
+
 /**
  * \note : returns coordinates in Cocoa screen coordinates
  */
index b0dae43..056b553 100644 (file)
 #include "GHOST_WindowManager.h"
 #include "GHOST_WindowWin32.h"
 
+#if defined(WITH_GL_EGL)
+#  include "GHOST_ContextEGL.h"
+#else
+#  include "GHOST_ContextWGL.h"
+#endif
+
 #ifdef WITH_INPUT_NDOF
   #include "GHOST_NDOFManagerWin32.h"
 #endif
@@ -299,6 +305,94 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(
 }
 
 
+/**
+ * Create a new offscreen context.
+ * Never explicitly delete the window, use disposeContext() instead.
+ * \return  The new context (or 0 if creation failed).
+ */
+GHOST_IContext *GHOST_SystemWin32::createOffscreenContext()
+{
+       bool debug_context = false; /* TODO: inform as a parameter */
+
+       GHOST_Context *context;
+
+#if defined(WITH_GL_PROFILE_CORE)
+       for (int minor = 5; minor >= 0; --minor) {
+                       context = new GHOST_ContextWGL(
+                           false, true, 0,
+                           NULL, NULL,
+                           WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+                           4, minor,
+                           (debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
+                           GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
+
+                       if (context->initializeDrawingContext()) {
+                               return context;
+                       }
+                       else {
+                               delete context;
+                       }
+               }
+
+               context = new GHOST_ContextWGL(
+                   false, true, 0,
+                   NULL, NULL,
+                   WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+                   3, 3,
+                   (debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
+                   GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
+
+               if (context->initializeDrawingContext()) {
+                       return context;
+               }
+               else {
+                       MessageBox(
+                               NULL,
+                               "Blender requires a graphics driver with at least OpenGL 3.3 support.\n\n"
+                               "The program will now close.",
+                               "Blender - Unsupported Graphics Driver!",
+                               MB_OK | MB_ICONERROR);
+                       delete context;
+                       exit();
+               }
+
+#elif defined(WITH_GL_PROFILE_COMPAT)
+               // ask for 2.1 context, driver gives any GL version >= 2.1 (hopefully the latest compatibility profile)
+               // 2.1 ignores the profile bit & is incompatible with core profile
+               context = new GHOST_ContextWGL(
+                       false, true, 0,
+                       NULL, NULL,
+                       0, // no profile bit
+                       2, 1,
+                       (debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
+                       GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
+
+               if (context->initializeDrawingContext()) {
+                       return context;
+               }
+               else {
+                       delete context;
+               }
+#else
+#  error // must specify either core or compat at build time
+#endif
+
+       return NULL;
+}
+
+/**
+ * Dispose of a context.
+ * \param   context Pointer to the context to be disposed.
+ * \return  Indication of success.
+ */
+GHOST_TSuccess GHOST_SystemWin32::disposeContext(GHOST_IContext *context)
+{
+       delete context;
+
+       return GHOST_kSuccess;
+}
+
+
 bool GHOST_SystemWin32::processEvents(bool waitForEvent)
 {
        MSG msg;
index 099d14e..6bf2c5b 100644 (file)
@@ -132,6 +132,21 @@ public:
            const bool exclusive = false,
            const GHOST_TEmbedderWindowID parentWindow = 0);
 
+
+       /**
+        * Create a new offscreen context.
+        * Never explicitly delete the window, use disposeContext() instead.
+        * \return  The new context (or 0 if creation failed).
+        */
+       GHOST_IContext *createOffscreenContext();
+
+       /**
+        * Dispose of a context.
+        * \param   context Pointer to the context to be disposed.
+        * \return  Indication of success.
+        */
+       GHOST_TSuccess disposeContext(GHOST_IContext *context);
+
        /***************************************************************************************
         ** Event management functionality
         ***************************************************************************************/
index 9b617a3..0de6e2f 100644 (file)
 
 #include "GHOST_Debug.h"
 
+#if defined(WITH_GL_EGL)
+#  include "GHOST_ContextEGL.h"
+#else
+#  include "GHOST_ContextGLX.h"
+#endif
+
 #ifdef WITH_XF86KEYSYM
 #include <X11/XF86keysym.h>
 #endif
@@ -113,6 +119,7 @@ GHOST_SystemX11(
     : GHOST_System(),
       m_start_time(0)
 {
+       XInitThreads();
        m_display = XOpenDisplay(NULL);
        
        if (!m_display) {
@@ -379,6 +386,98 @@ createWindow(const STR_String& title,
        return window;
 }
 
+
+/**
+ * Create a new offscreen context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * \return  The new context (or 0 if creation failed).
+ */
+GHOST_IContext *
+GHOST_SystemX11::
+createOffscreenContext()
+{
+       // During development:
+       //   try 4.x compatibility profile
+       //   try 3.3 compatibility profile
+       //   fall back to 3.0 if needed
+       //
+       // Final Blender 2.8:
+       //   try 4.x core profile
+       //   try 3.3 core profile
+       //   no fallbacks
+
+#if defined(WITH_GL_PROFILE_CORE)
+       {
+               const char *version_major = (char*)glewGetString(GLEW_VERSION_MAJOR);
+               if (version_major != NULL && version_major[0] == '1') {
+                       fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
+                       abort();
+               }
+       }
+#endif
+
+       const int profile_mask =
+#if defined(WITH_GL_PROFILE_CORE)
+               GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+#elif defined(WITH_GL_PROFILE_COMPAT)
+               GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+#else
+#  error // must specify either core or compat at build time
+#endif
+
+       GHOST_Context *context;
+
+       for (int minor = 5; minor >= 0; --minor) {
+               context = new GHOST_ContextGLX(
+                       false,
+                       0,
+                       (Window)NULL,
+                       m_display,
+                       (GLXFBConfig)NULL,
+                       profile_mask,
+                       4, minor,
+                       GHOST_OPENGL_GLX_CONTEXT_FLAGS | (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
+                       GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+
+               if (context->initializeDrawingContext())
+                       return context;
+               else
+                       delete context;
+       }
+
+       context = new GHOST_ContextGLX(
+               false,
+               0,
+               (Window)NULL,
+               m_display,
+               (GLXFBConfig)NULL,
+               profile_mask,
+               3, 3,
+               GHOST_OPENGL_GLX_CONTEXT_FLAGS | (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
+               GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+
+       if (context->initializeDrawingContext())
+               return context;
+       else
+               delete context;
+
+       return NULL;
+}
+
+/**
+ * Dispose of a context.
+ * \param   context Pointer to the context to be disposed.
+ * \return  Indication of success.
+ */
+GHOST_TSuccess
+GHOST_SystemX11::
+disposeContext(GHOST_IContext *context)
+{
+       delete context;
+
+       return GHOST_kSuccess;
+}
+
 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
 static void destroyIMCallback(XIM /*xim*/, XPointer ptr, XPointer /*data*/)
 {
index e60cab6..1ad8277 100644 (file)
@@ -171,6 +171,26 @@ public:
            const GHOST_TEmbedderWindowID parentWindow = 0
            );
 
+
+       /**
+        * Create a new offscreen context.
+        * Never explicitly delete the context, use disposeContext() instead.
+        * \return  The new context (or 0 if creation failed).
+        */
+       GHOST_IContext *
+       createOffscreenContext(
+           );
+
+       /**
+        * Dispose of a context.
+        * \param   context Pointer to the context to be disposed.
+        * \return  Indication of success.
+        */
+       GHOST_TSuccess
+       disposeContext(
+           GHOST_IContext *context
+           );
+
        /**
         * Retrieves events from the system and stores them in the queue.
         * \param waitForEvent Flag to wait for an event (or return immediately).
index 309c19f..2b98642 100644 (file)
@@ -1005,7 +1005,7 @@ GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType ty
 
 #if defined(WITH_GL_PROFILE_CORE)
                        GL_CONTEXT_CORE_PROFILE_BIT,
-                       3, 2,
+                       3, 3,
 #else
                        0, // no profile bit
                        2, 1,