diff options
25 files changed, 686 insertions, 70 deletions
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 5a97da28d17..7771af93d4f 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -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 diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 967d3f58143..d5d8be7db8e 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -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); /** @@ -189,6 +190,23 @@ extern GHOST_WindowHandle GHOST_CreateWindow( 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 * \return The window user data. @@ -711,6 +729,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 * \return Status of tablet diff --git a/intern/ghost/GHOST_IContext.h b/intern/ghost/GHOST_IContext.h new file mode 100644 index 00000000000..5b027a614ab --- /dev/null +++ b/intern/ghost/GHOST_IContext.h @@ -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__ + diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 03193d6e1da..5c5590ef069 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -36,6 +36,7 @@ #define __GHOST_ISYSTEM_H__ #include "GHOST_Types.h" +#include "GHOST_IContext.h" #include "GHOST_ITimerTask.h" #include "GHOST_IWindow.h" @@ -262,6 +263,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. * \return Indication of validity. diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index ce653188760..2fe94171cf8 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -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) { diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h index 8776fa4764f..670b86d456f 100644 --- a/intern/ghost/intern/GHOST_Context.h +++ b/intern/ghost/intern/GHOST_Context.h @@ -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: /** @@ -72,6 +73,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. */ diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h index 6dcc4da0f0a..ea6eb485ce2 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.h +++ b/intern/ghost/intern/GHOST_ContextCGL.h @@ -83,6 +83,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. */ diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm index 03af3cc497e..46993a1cd1d 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.mm +++ b/intern/ghost/intern/GHOST_ContextCGL.mm @@ -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]; diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp index a591d9b7583..56962d24939 100644 --- a/intern/ghost/intern/GHOST_ContextEGL.cpp +++ b/intern/ghost/intern/GHOST_ContextEGL.cpp @@ -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() { diff --git a/intern/ghost/intern/GHOST_ContextEGL.h b/intern/ghost/intern/GHOST_ContextEGL.h index 6dfb177f26d..83415f6be54 100644 --- a/intern/ghost/intern/GHOST_ContextEGL.h +++ b/intern/ghost/intern/GHOST_ContextEGL.h @@ -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. */ diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index 061ac29945b..fb7fa4ee762 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -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(); diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h index 51fb1dd57dc..ded1b293659 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.h +++ b/intern/ghost/intern/GHOST_ContextGLX.h @@ -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. */ diff --git a/intern/ghost/intern/GHOST_ContextNone.cpp b/intern/ghost/intern/GHOST_ContextNone.cpp index 380ab532f7a..89bdf6b89fa 100644 --- a/intern/ghost/intern/GHOST_ContextNone.cpp +++ b/intern/ghost/intern/GHOST_ContextNone.cpp @@ -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; diff --git a/intern/ghost/intern/GHOST_ContextNone.h b/intern/ghost/intern/GHOST_ContextNone.h index 80cce76190d..9f2af4ae235 100644 --- a/intern/ghost/intern/GHOST_ContextNone.h +++ b/intern/ghost/intern/GHOST_ContextNone.h @@ -61,6 +61,12 @@ public: /** * Dummy function + * \return Always succeeds + */ + GHOST_TSuccess releaseDrawingContext(); + + /** + * Dummy function * \return Always succeeds */ GHOST_TSuccess updateDrawingContext(); diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp index 7a02e9743c3..1ba591bd0b2 100644 --- a/intern/ghost/intern/GHOST_ContextSDL.cpp +++ b/intern/ghost/intern/GHOST_ContextSDL.cpp @@ -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 diff --git a/intern/ghost/intern/GHOST_ContextSDL.h b/intern/ghost/intern/GHOST_ContextSDL.h index 61f339c1bc2..681d24bb7c6 100644 --- a/intern/ghost/intern/GHOST_ContextSDL.h +++ b/intern/ghost/intern/GHOST_ContextSDL.h @@ -86,6 +86,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. */ diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index 7b5e30247a8..a23c0b0b26c 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -43,14 +43,7 @@ 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; + } diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h index a07cc1b6301..b3b66c5f6e2 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.h +++ b/intern/ghost/intern/GHOST_ContextWGL.h @@ -79,6 +79,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; diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index 6802ad42c7b..62d9774d81d 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -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 ***************************************************************************************/ diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index e9fffb6f60b..011719ea946 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -27,15 +27,6 @@ * ***** 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" @@ -51,12 +42,26 @@ #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 @@ -581,6 +586,53 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow( } /** + * 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 */ GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index b0dae432643..056b5536ab0 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -56,6 +56,12 @@ #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; diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 099d14e68ae..6bf2c5b8d6f 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -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 ***************************************************************************************/ diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 9b617a34e1a..0de6e2f7d4a 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -57,6 +57,12 @@ #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*/) { diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index e60cab6a194..1ad8277a431 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -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). diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 309c19f92af..2b986428fd3 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -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, |