diff options
author | Jason Wilkins <Jason.A.Wilkins@gmail.com> | 2014-10-08 00:46:19 +0400 |
---|---|---|
committer | Jason Wilkins <Jason.A.Wilkins@gmail.com> | 2014-10-08 00:47:32 +0400 |
commit | 8d084e8c8f48dd2f07d4a3fbd4a941a7bcc0dcfb (patch) | |
tree | 5bf15f4f74f3e5a307cfa3f734b2cd086dca69bd /intern/ghost | |
parent | a8705e99ee8ec9de2f25c3bac1e9895c2f98c224 (diff) |
Ghost Context Refactor
https://developer.blender.org/D643
Separates graphics context creation from window code in Ghost so that they can vary separately.
Diffstat (limited to 'intern/ghost')
35 files changed, 4432 insertions, 1565 deletions
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index cfa2f54f53e..6f30cecab61 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -25,6 +25,7 @@ set(INC . + ../glew-mx ../string ../../source/blender/imbuf ../../source/blender/makesdna @@ -38,6 +39,8 @@ set(SRC intern/GHOST_Buttons.cpp intern/GHOST_C-api.cpp intern/GHOST_CallbackEventConsumer.cpp + intern/GHOST_Context.cpp + intern/GHOST_ContextNone.cpp intern/GHOST_DisplayManager.cpp intern/GHOST_EventManager.cpp intern/GHOST_ISystem.cpp @@ -63,6 +66,8 @@ set(SRC intern/GHOST_Buttons.h intern/GHOST_CallbackEventConsumer.h + intern/GHOST_Context.h + intern/GHOST_ContextNone.h intern/GHOST_Debug.h intern/GHOST_DisplayManager.h intern/GHOST_Event.h @@ -120,68 +125,48 @@ if(WITH_HEADLESS OR WITH_GHOST_SDL) intern/GHOST_DisplayManagerSDL.cpp intern/GHOST_SystemSDL.cpp intern/GHOST_WindowSDL.cpp + intern/GHOST_ContextSDL.cpp intern/GHOST_DisplayManagerSDL.h intern/GHOST_SystemSDL.h intern/GHOST_WindowSDL.h + intern/GHOST_ContextSDL.h ) add_definitions(-DWITH_GHOST_SDL) endif() - - # ack, this is still system dependent - if(APPLE) - list(APPEND SRC - intern/GHOST_SystemPathsCocoa.mm - intern/GHOST_SystemPathsCocoa.h - ) - - elseif(UNIX) - list(APPEND SRC - intern/GHOST_SystemPathsX11.cpp - intern/GHOST_SystemPathsX11.h - ) - - if(NOT WITH_INSTALL_PORTABLE) - add_definitions(-DPREFIX="${CMAKE_INSTALL_PREFIX}") - endif() - - elseif(WIN32) - list(APPEND SRC - intern/GHOST_SystemPathsWin32.cpp - - intern/GHOST_SystemPathsWin32.h - ) - - list(APPEND INC - ../utfconv - ) - endif() - if(NOT WITH_HEADLESS) list(APPEND INC_SYS ${SDL_INCLUDE_DIR} ) endif() -elseif(APPLE) +elseif(APPLE AND NOT WITH_X11) list(APPEND SRC intern/GHOST_DisplayManagerCocoa.mm intern/GHOST_SystemCocoa.mm - intern/GHOST_SystemPathsCocoa.mm intern/GHOST_WindowCocoa.mm intern/GHOST_DisplayManagerCocoa.h intern/GHOST_SystemCocoa.h - intern/GHOST_SystemPathsCocoa.h intern/GHOST_WindowCocoa.h ) + if (NOT WITH_GL_EGL) + list(APPEND SRC + intern/GHOST_ContextCGL.mm + + intern/GHOST_ContextCGL.h + ) + endif() + if(WITH_INPUT_NDOF) list(APPEND SRC intern/GHOST_NDOFManagerCocoa.mm + intern/GHOST_NDOFManagerCocoa.h ) + list(APPEND SRC_NDOF3DCONNEXION intern/GHOST_NDOFManager3Dconnexion.c intern/GHOST_NDOFManager3Dconnexion.h @@ -192,8 +177,7 @@ elseif(APPLE) add_definitions(-DWITH_QUICKTIME) endif() -elseif(UNIX) - +elseif(WITH_X11) list(APPEND INC_SYS ${X11_X11_INCLUDE_PATH} ) @@ -201,15 +185,21 @@ elseif(UNIX) list(APPEND SRC intern/GHOST_DisplayManagerX11.cpp intern/GHOST_SystemX11.cpp - intern/GHOST_SystemPathsX11.cpp intern/GHOST_WindowX11.cpp intern/GHOST_DisplayManagerX11.h intern/GHOST_SystemX11.h - intern/GHOST_SystemPathsX11.h intern/GHOST_WindowX11.h ) + if (NOT WITH_GL_EGL) + list(APPEND SRC + intern/GHOST_ContextGLX.cpp + + intern/GHOST_ContextGLX.h + ) + endif() + if(WITH_GHOST_XDND) add_definitions(-DWITH_XDND) @@ -257,6 +247,8 @@ elseif(UNIX) ) endif() + add_definitions(-DWITH_X11) + elseif(WIN32) ## Warnings as errors, this is too strict! #if(MSVC) @@ -267,25 +259,27 @@ elseif(WIN32) ${WINTAB_INC} ) - list(APPEND INC - ../utfconv - ) - list(APPEND SRC intern/GHOST_DisplayManagerWin32.cpp intern/GHOST_SystemWin32.cpp - intern/GHOST_SystemPathsWin32.cpp intern/GHOST_WindowWin32.cpp intern/GHOST_DropTargetWin32.cpp intern/GHOST_DisplayManagerWin32.h intern/GHOST_DropTargetWin32.h intern/GHOST_SystemWin32.h - intern/GHOST_SystemPathsWin32.h intern/GHOST_WindowWin32.h intern/GHOST_TaskbarWin32.h ) + if (NOT WITH_GL_EGL) + list(APPEND SRC + intern/GHOST_ContextWGL.cpp + + intern/GHOST_ContextWGL.h + ) + endif() + if(WITH_INPUT_NDOF) list(APPEND SRC intern/GHOST_NDOFManagerWin32.cpp @@ -294,9 +288,45 @@ elseif(WIN32) ) endif() + list(APPEND INC + ../utfconv + ) + +endif() + +if(WITH_GL_EGL AND NOT (WITH_HEADLESS OR WITH_GHOST_SDL)) + list(APPEND SRC + intern/GHOST_ContextEGL.cpp + + intern/GHOST_ContextEGL.h + ) +endif() + +if(APPLE) + list(APPEND SRC + intern/GHOST_SystemPathsCocoa.mm + intern/GHOST_SystemPathsCocoa.h + ) + +elseif(UNIX) + list(APPEND SRC + intern/GHOST_SystemPathsX11.cpp + intern/GHOST_SystemPathsX11.h + ) + + if(NOT WITH_INSTALL_PORTABLE) + add_definitions(-DPREFIX="${CMAKE_INSTALL_PREFIX}") + endif() + +elseif(WIN32) + list(APPEND SRC + intern/GHOST_SystemPathsWin32.cpp + intern/GHOST_SystemPathsWin32.h + ) + endif() -add_definitions(-DGLEW_STATIC) +add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_intern_ghost "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index c877a3b8fad..7b47f0526a2 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -674,9 +674,17 @@ extern GHOST_TSuccess GHOST_SetSwapInterval(GHOST_WindowHandle windowhandle, int /** * Gets the current swap interval for swapBuffers. - * \return An integer. + * \param windowhandle The handle to the window + * \param intervalOut pointer to location to return swap interval (left untouched if there is an error) + * \return A boolean success indicator of if swap interval was successfully read. + */ +extern GHOST_TSuccess GHOST_GetSwapInterval(GHOST_WindowHandle windowhandle, int* intervalOut); + +/** + * Gets the current swap interval for swapBuffers. + * \return Number of AA Samples (0 if there is no multisample buffer) */ -extern int GHOST_GetSwapInterval(GHOST_WindowHandle windowhandle); +extern GHOST_TUns16 GHOST_GetNumOfAASamples(GHOST_WindowHandle windowhandle); /** * Activates the drawing context of this window. diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index c6befff6871..71dc193a81b 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -212,9 +212,17 @@ public: /** * Gets the current swap interval for swapBuffers. - * \return An integer. + * \param windowhandle The handle to the window + * \param intervalOut pointer to location to return swap interval (left untouched if there is an error) + * \return A boolean success indicator of if swap interval was successfully read. */ - virtual int getSwapInterval() = 0; + virtual GHOST_TSuccess getSwapInterval(int& intervalOut) = 0; + + /** + * Gets the current swap interval for swapBuffers. + * \return Number of AA Samples (0 if there is no multisample buffer) + */ + virtual GHOST_TUns16 getNumOfAASamples() = 0; /** * Activates the drawing context of this window. diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript index 80756472edb..5a4572c164d 100644 --- a/intern/ghost/SConscript +++ b/intern/ghost/SConscript @@ -36,22 +36,33 @@ sources = env.Glob('intern/*.cpp') sources2 = env.Glob('intern/GHOST_NDOFManager3Dconnexion.c') if window_system == 'darwin': sources += env.Glob('intern/*.mm') + #remove, will be readded below if needed. + sources.remove('intern' + os.sep + 'GHOST_ContextCGL.mm') +if not env['WITH_BF_GL_EGL']: + sources.remove('intern' + os.sep + 'GHOST_ContextEGL.cpp') -pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_SystemPaths', 'GHOST_Window', 'GHOST_DropTarget', 'GHOST_NDOFManager'] -defs=['_USE_MATH_DEFINES', 'GLEW_STATIC'] +# seems cleaner to remove these now then add back the one that is needed +sources.remove('intern' + os.sep + 'GHOST_ContextGLX.cpp') +sources.remove('intern' + os.sep + 'GHOST_ContextWGL.cpp') + +pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_SystemPaths', 'GHOST_Window', 'GHOST_DropTarget', 'GHOST_NDOFManager', 'GHOST_Context'] + +defs = env['BF_GL_DEFINITIONS'] + +if env['WITH_BF_GL_EGL']: + defs.append('WITH_EGL') incs = [ '.', - '#extern/glew/include', + env['BF_GLEW_INC'], + '../glew-mx', '#source/blender/imbuf', '#source/blender/makesdna', '../string', ] incs = ' '.join(incs) -incs += ' ' + env['BF_OPENGL_INC'] - if env['WITH_GHOST_SDL']: for f in pf: try: @@ -65,9 +76,16 @@ elif window_system in ('linux', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'f for f in pf: try: sources.remove('intern' + os.sep + f + 'Win32.cpp') + except ValueError: + pass + + try: sources.remove('intern' + os.sep + f + 'SDL.cpp') except ValueError: pass + + defs += ['WITH_X11'] + ## removing because scons does not support system installation ## if this is used for blender.org builds it means our distrobution ## will find any locally installed blender and double up its script path. @@ -88,23 +106,45 @@ elif window_system in ('linux', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'f else: sources.remove('intern' + os.sep + 'GHOST_DropTargetX11.cpp') + if not env['WITH_BF_GL_EGL']: + sources.append('intern' + os.sep + 'GHOST_ContextGLX.cpp') + elif window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc', 'win64-mingw'): for f in pf: try: sources.remove('intern' + os.sep + f + 'X11.cpp') + except ValueError: + pass + + try: sources.remove('intern' + os.sep + f + 'SDL.cpp') except ValueError: pass + + if not env['WITH_BF_GL_EGL']: + sources.append('intern' + os.sep + 'GHOST_ContextWGL.cpp') + elif window_system == 'darwin': - if env['WITH_BF_QUICKTIME']: - defs.append('WITH_QUICKTIME') - for f in pf: - try: - sources.remove('intern' + os.sep + f + 'Win32.cpp') - sources.remove('intern' + os.sep + f + 'X11.cpp') - sources.remove('intern' + os.sep + f + 'SDL.cpp') - except ValueError: - pass + if env['WITH_BF_QUICKTIME']: + defs.append('WITH_QUICKTIME') + for f in pf: + try: + sources.remove('intern' + os.sep + f + 'Win32.cpp') + except ValueError: + pass + + try: + sources.remove('intern' + os.sep + f + 'X11.cpp') + except ValueError: + pass + try: + sources.remove('intern' + os.sep + f + 'SDL.cpp') + except ValueError: + pass + + if not env['WITH_BF_GL_EGL']: + sources.append('intern' + os.sep + 'GHOST_ContextCGL.mm') + else: print "Unknown window system specified." Exit() diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index eaa59f096aa..5a2e638f01a 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -144,15 +144,9 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, const GHOST_TUns16 numOfAASamples) { GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; - bool bstereoVisual; - - if (stereoVisual) - bstereoVisual = true; - else - bstereoVisual = false; return (GHOST_WindowHandle) system->createWindow(title, left, top, width, height, - state, type, bstereoVisual, false, + state, type, stereoVisual != 0, false, numOfAASamples); } @@ -698,14 +692,21 @@ GHOST_TSuccess GHOST_SetSwapInterval(GHOST_WindowHandle windowhandle, int interv return window->setSwapInterval(interval); } -int GHOST_GetSwapInterval(GHOST_WindowHandle windowhandle) +GHOST_TSuccess GHOST_GetSwapInterval(GHOST_WindowHandle windowhandle, int* intervalOut) { GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; - return window->getSwapInterval(); + return window->getSwapInterval(*intervalOut); } +GHOST_TUns16 GHOST_GetNumOfAASamples(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; + + return window->getNumOfAASamples(); +} + GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle) { GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; diff --git a/intern/ghost/intern/GHOST_Context.cpp b/intern/ghost/intern/GHOST_Context.cpp new file mode 100644 index 00000000000..1b0e8d76321 --- /dev/null +++ b/intern/ghost/intern/GHOST_Context.cpp @@ -0,0 +1,155 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Context.cpp + * \ingroup GHOST + * + * Definition of GHOST_Context class. + */ + +#include "GHOST_Context.h" + +#ifdef _WIN32 +# include <GL/wglew.h> // only for symbolic constants, do not use API functions +# include <tchar.h> +#endif + +#include <cstdio> +#include <cstring> + + +#ifdef _WIN32 + +bool win32_chk(bool result, const char *file, int line, const char *text) +{ + if (!result) { + LPTSTR formattedMsg = NULL; + + DWORD error = GetLastError(); + + const char *msg; + + DWORD count = 0; + + switch (error) { + case ERROR_INVALID_VERSION_ARB: + msg = "The specified OpenGL version and feature set are either invalid or not supported.\n"; + break; + + case ERROR_INVALID_PROFILE_ARB: + msg = "The specified OpenGL profile and feature set are either invalid or not supported.\n"; + break; + + case ERROR_INVALID_PIXEL_TYPE_ARB: + msg = "The specified pixel type is invalid.\n"; + break; + + case ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB: + msg = ("The device contexts specified are not compatible. " + "This can occur if the device contexts are managed by " + "different drivers or possibly on different graphics adapters.\n"); + break; + +#ifdef WITH_GLEW_ES + case ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV: + msg = "The device context(s) and rendering context have non-matching affinity masks.\n"; + break; + + case ERROR_MISSING_AFFINITY_MASK_NV: + msg = "The rendering context does not have an affinity mask set.\n"; + break; +#endif + + case ERROR_PROFILE_DOES_NOT_MATCH_DEVICE: + msg = ("The specified profile is intended for a device of a " + "different type than the specified device.\n"); + break; + + default: + { + count = + FormatMessage( + (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS), + NULL, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)(&formattedMsg), + 0, + NULL); + + msg = count > 0 ? formattedMsg : "<no system message>\n"; + break; + } + } + +#ifndef NDEBUG + _ftprintf( + stderr, + "%s(%d):[%s] -> Win32 Error# (%d): %s", + file, + line, + text, + error, + msg); +#else + _ftprintf( + stderr, + "Win32 Error# (%d): %s", + error, + msg); +#endif + + SetLastError(NO_ERROR); + + if (count != 0) + LocalFree(formattedMsg); + } + + return result; +} + +#endif // _WIN32 + + +void GHOST_Context::initContextGLEW() +{ + mxDestroyContext(m_mxContext); // no-op if m_mxContext is NULL + + mxMakeCurrentContext(mxCreateContext()); + + m_mxContext = mxGetCurrentContext(); +} + + +void GHOST_Context::initClearGL() +{ + glClearColor(0.447, 0.447, 0.447, 0.000); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(0.000, 0.000, 0.000, 0.000); +} diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h new file mode 100644 index 00000000000..0dfea867703 --- /dev/null +++ b/intern/ghost/intern/GHOST_Context.h @@ -0,0 +1,161 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_Context.h + * \ingroup GHOST + * Declaration of GHOST_Context class. + */ + +#ifndef __GHOST_CONTEXT_H__ +#define __GHOST_CONTEXT_H__ + +#include "GHOST_Types.h" + +#include "glew-mx.h" + +#include <cstdlib> // for NULL + + +class GHOST_Context +{ +public: + /** + * Constructor. + * \param stereoVisual Stereo visual for quad buffered stereo. + * \param numOfAASamples Number of samples used for AA (zero if no AA) + */ + GHOST_Context(bool stereoVisual, GHOST_TUns16 numOfAASamples) + : m_stereoVisual(stereoVisual), + m_numOfAASamples(numOfAASamples), + m_mxContext(NULL) + {} + + /** + * Destructor. + */ + virtual ~GHOST_Context() { + mxDestroyContext(m_mxContext); + } + + /** + * Swaps front and back buffers of a window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers() = 0; + + /** + * Activates the drawing context of this window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext() = 0; + + /** + * Call immediately after new to initialize. If this fails then immediately delete the object. + * \return Indication as to whether initialization has succeeded. + */ + virtual GHOST_TSuccess initializeDrawingContext() = 0; + + /** + * Updates the drawing context of this window. Needed + * whenever the window is changed. + * \return Indication of success. + */ + virtual GHOST_TSuccess updateDrawingContext() { + return GHOST_kFailure; + } + + /** + * Checks if it is OK for a remove the native display + * \return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess releaseNativeHandles() = 0; + + /** + * Sets the swap interval for swapBuffers. + * \param interval The swap interval to use. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess setSwapInterval(int interval) { + return GHOST_kFailure; + } + + /** + * Gets the current swap interval for swapBuffers. + * \param intervalOut Variable to store the swap interval if it can be read. + * \return Whether the swap interval can be read. + */ + virtual GHOST_TSuccess getSwapInterval(int&) { + return GHOST_kFailure; + } + + /** Stereo visual created. Only necessary for 'real' stereo support, + * ie quad buffered stereo. This is not always possible, depends on + * the graphics h/w + */ + inline bool isStereoVisual() const { + return m_stereoVisual; + } + + /** Number of samples used in anti-aliasing, set to 0 if no AA **/ + inline GHOST_TUns16 getNumOfAASamples() const { + return m_numOfAASamples; + } + +protected: + void initContextGLEW(); + + inline void activateGLEW() const { + mxMakeCurrentContext(m_mxContext); + } + + bool m_stereoVisual; + + GHOST_TUns16 m_numOfAASamples; + + static void initClearGL(); + +private: + MXContext *m_mxContext; + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_Context") +#endif +}; + + +#ifdef _WIN32 +bool win32_chk(bool result, const char *file = NULL, int line = 0, const char *text = NULL); + +# ifndef NDEBUG +# define WIN32_CHK(x) win32_chk((x), __FILE__, __LINE__, #x) +# else +# define WIN32_CHK(x) win32_chk(x) +# endif +#endif /* _WIN32 */ + + +#endif // __GHOST_CONTEXT_H__ diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h new file mode 100644 index 00000000000..99d995bcbb1 --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextCGL.h @@ -0,0 +1,153 @@ +/* + * ***** 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) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextCGL.h + * \ingroup GHOST + */ + +#ifndef __GHOST_CONTEXTCGL_H__ +#define __GHOST_CONTEXTCGL_H__ + +#include "GHOST_Context.h" + +//#define cglewGetContext() cglewContext +//#include <GL/cglew.h> +//extern "C" CGLEWContext *cglewContext; + +#ifndef GHOST_OPENGL_CGL_CONTEXT_FLAGS +#define GHOST_OPENGL_CGL_CONTEXT_FLAGS 0 +#endif + +#ifndef GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY +#define GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY 0 +#endif + + +@class NSWindow; +@class NSOpenGLView; +@class NSOpenGLContext; + + +class GHOST_ContextCGL : public GHOST_Context +{ +public: + /** + * Constructor. + */ + GHOST_ContextCGL( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + NSWindow *window, + NSOpenGLView *openGLView, + int contextProfileMask, + int contextMajorVersion, + int contextMinorVersion, + int contextFlags, + int contextResetNotificationStrategy); + + /** + * Destructor. + */ + virtual ~GHOST_ContextCGL(); + + /** + * Swaps front and back buffers of a window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Activates the drawing context of this window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Call immediately after new to initialize. If this fails then immediately delete the object. + * \return Indication as to whether initialization has succeeded. + */ + virtual GHOST_TSuccess initializeDrawingContext(); + + /** + * Removes references to native handles from this context and then returns + * \return GHOST_kSuccess if it is OK for the parent to release the handles and + * GHOST_kFailure if releasing the handles will interfere with sharing + */ + virtual GHOST_TSuccess releaseNativeHandles(); + + /** + * Sets the swap interval for swapBuffers. + * \param interval The swap interval to use. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess setSwapInterval(int interval); + + /** + * Gets the current swap interval for swapBuffers. + * \param intervalOut Variable to store the swap interval if it can be read. + * \return Whether the swap interval can be read. + */ + virtual GHOST_TSuccess getSwapInterval(int&); + + /** + * Updates the drawing context of this window. + * Needed whenever the window is changed. + * \return Indication of success. + */ + virtual GHOST_TSuccess updateDrawingContext(); + +//protected: +// inline void activateCGLEW() const { +// cglewContext = m_cglewContext; +// } + +private: + //void initContextCGLEW() + + /** The window containing the OpenGL view */ + NSWindow *m_window; + + /** The openGL view */ + NSOpenGLView *m_openGLView; + + const int m_contextProfileMask; + const int m_contextMajorVersion; + const int m_contextMinorVersion; + const int m_contextFlags; + const int m_contextResetNotificationStrategy; + + /** The opgnGL drawing context */ + NSOpenGLContext *m_openGLContext; + + //static CGLEWContext *s_cglewContext; + + /** The first created OpenGL context (for sharing display lists) */ + static NSOpenGLContext *s_sharedOpenGLContext; + static int s_sharedCount; +}; + +#endif // __GHOST_CONTEXTCGL_H__ diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm new file mode 100644 index 00000000000..b96a1dc93de --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextCGL.mm @@ -0,0 +1,351 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextCGL.mm + * \ingroup GHOST + * + * Definition of GHOST_ContextCGL class. + */ + +#include "GHOST_ContextCGL.h" + +#include <Cocoa/Cocoa.h> + +#ifdef GHOST_MULTITHREADED_OPENGL +#include <OpenGL/OpenGL.h> +#endif + +#include <vector> +#include <cassert> + + +NSOpenGLContext *GHOST_ContextCGL::s_sharedOpenGLContext = nil; +int GHOST_ContextCGL::s_sharedCount = 0; + + +GHOST_ContextCGL::GHOST_ContextCGL( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + NSWindow *window, + NSOpenGLView *openGLView, + int contextProfileMask, + int contextMajorVersion, + int contextMinorVersion, + int contextFlags, + int contextResetNotificationStrategy) + : GHOST_Context(stereoVisual, numOfAASamples), + m_window(window), + m_openGLView(openGLView), + m_contextProfileMask(contextProfileMask), + m_contextMajorVersion(contextMajorVersion), + m_contextMinorVersion(contextMinorVersion), + m_contextFlags(contextFlags), + m_contextResetNotificationStrategy(contextResetNotificationStrategy), + m_openGLContext(nil) +{ + assert(window != nil); + assert(openGLView != nil); +} + + +GHOST_ContextCGL::~GHOST_ContextCGL() +{ + if (m_openGLContext != nil) { + if (m_openGLContext == [NSOpenGLContext currentContext]) + [NSOpenGLContext clearCurrentContext]; + [m_openGLView clearGLContext]; + + if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) { + assert(s_sharedCount > 0); + + s_sharedCount--; + + if (s_sharedCount == 0) + s_sharedOpenGLContext = nil; + + [m_openGLContext release]; + } + } +} + + +GHOST_TSuccess GHOST_ContextCGL::swapBuffers() +{ + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext flushBuffer]; + [pool drain]; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_ContextCGL::setSwapInterval(int interval) +{ + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext setValues:&interval forParameter:NSOpenGLCPSwapInterval]; + [pool drain]; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_ContextCGL::getSwapInterval(int &intervalOut) +{ + if (m_openGLContext != nil) { + GLint interval; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [m_openGLContext setValues:&interval forParameter:NSOpenGLCPSwapInterval]; + + [pool drain]; + + intervalOut = static_cast<int>(interval); + + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_ContextCGL::activateDrawingContext() +{ + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext makeCurrentContext]; + + activateGLEW(); + + [pool drain]; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext() +{ + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext update]; + [pool drain]; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + + +static void makeAttribList( + std::vector<NSOpenGLPixelFormatAttribute>& attribs, + bool stereoVisual, + int numOfAASamples, + bool needAlpha, + bool needStencil) +{ + // Pixel Format Attributes for the windowed NSOpenGLContext + attribs.push_back(NSOpenGLPFADoubleBuffer); + + // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object's flushBuffer + // needed for 'Draw Overlap' drawing method + attribs.push_back(NSOpenGLPFABackingStore); + + // Force software OpenGL, for debugging + /* XXX jwilkins: fixed this to work on Intel macs? useful feature for Windows and Linux too? + * Maybe a command line flag is better... */ + if (getenv("BLENDER_SOFTWAREGL")) { + attribs.push_back(NSOpenGLPFARendererID); +#if defined(__ppc__) || defined(__ppc64__) + attribs.push_back(kCGLRendererAppleSWID); +#else + attribs.push_back(kCGLRendererGenericFloatID); +#endif + } + else { + attribs.push_back(NSOpenGLPFAAccelerated); + } + + /* Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway */ + //attribs.push_back(NSOpenGLPFAAllowOfflineRenderers); + + attribs.push_back(NSOpenGLPFADepthSize); + attribs.push_back((NSOpenGLPixelFormatAttribute) 32); + + if (stereoVisual) + attribs.push_back(NSOpenGLPFAStereo); + + if (needAlpha) { + attribs.push_back(NSOpenGLPFAAlphaSize); + attribs.push_back((NSOpenGLPixelFormatAttribute) 8); + } + + if (needStencil) { + attribs.push_back(NSOpenGLPFAStencilSize); + attribs.push_back((NSOpenGLPixelFormatAttribute) 8); + } + + if (numOfAASamples > 0) { + // Multisample anti-aliasing + attribs.push_back(NSOpenGLPFAMultisample); + + attribs.push_back(NSOpenGLPFASampleBuffers); + attribs.push_back((NSOpenGLPixelFormatAttribute) 1); + + attribs.push_back(NSOpenGLPFASamples); + attribs.push_back((NSOpenGLPixelFormatAttribute) numOfAASamples); + + attribs.push_back(NSOpenGLPFANoRecovery); + } + + attribs.push_back((NSOpenGLPixelFormatAttribute) 0); +} + + +GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + std::vector<NSOpenGLPixelFormatAttribute> attribs; + attribs.reserve(40); + + NSOpenGLContext *prev_openGLContext = [m_openGLView openGLContext]; + +#ifdef GHOST_OPENGL_ALPHA + static const bool needAlpha = true; +#else + static const bool needAlpha = false; +#endif + +#ifdef GHOST_OPENGL_STENCIL + static const bool needStencil = true; +#else + static const bool needStencil = false; +#endif + + makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil); + + NSOpenGLPixelFormat *pixelFormat; + + pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; + + // Fall back to no multisampling if Antialiasing init failed + if (m_numOfAASamples > 0 && pixelFormat == nil) { + // XXX jwilkins: Does CGL only succeed when it makes an exact match on the number of samples? + // Does this need to explicitly try for a lesser match before giving up? + // (Now that I think about it, does WGL really require the code that it has for finding a lesser match?) + + attribs.clear(); + makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil); + pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; + } + + if (pixelFormat == nil) + goto error; + + if (m_numOfAASamples > 0) { //Set m_numOfAASamples to the actual value + GLint actualSamples; + [pixelFormat getValues:&actualSamples forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; + + if (m_numOfAASamples != (GHOST_TUns16)actualSamples) { + fprintf(stderr, + "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " + "Substituting one that uses %d samples.\n", + m_numOfAASamples, actualSamples); + + m_numOfAASamples = (GHOST_TUns16)actualSamples; + } + } + + [m_openGLView setPixelFormat:pixelFormat]; + + m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext]; + + if (m_openGLContext == nil) + goto error; + + if (s_sharedCount == 0) + s_sharedOpenGLContext = m_openGLContext; + + s_sharedCount++; + +#ifdef GHOST_MULTITHREADED_OPENGL + //Switch openGL to multhreaded mode + CGLContextObj cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj]; + if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError) + printf("\nSwitched openGL to multithreaded mode\n"); +#endif + +#ifdef GHOST_WAIT_FOR_VSYNC + { + GLint swapInt = 1; + /* wait for vsync, to avoid tearing artifacts */ + [m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; + } +#endif + + [m_openGLView setOpenGLContext:m_openGLContext]; + [m_openGLContext setView:m_openGLView]; + + initContextGLEW(); + + initClearGL(); + [m_openGLContext flushBuffer]; + + [pool drain]; + + return GHOST_kSuccess; + +error: + + [m_openGLView setOpenGLContext:prev_openGLContext]; + + [pool drain]; + + return GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles() +{ + m_openGLContext = NULL; + m_openGLView = NULL; + + return GHOST_kSuccess; +} diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp new file mode 100644 index 00000000000..6a9231835c5 --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextEGL.cpp @@ -0,0 +1,638 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextEGL.cpp + * \ingroup GHOST + * + * Definition of GHOST_ContextEGL class. + */ + +#include "GHOST_ContextEGL.h" + +#include <set> +#include <sstream> +#include <vector> + +#include <cassert> +#include <cstdio> +#include <cstring> + + +#ifdef WITH_GLEW_MX +EGLEWContext *eglewContext = NULL; +#endif + + +#define CASE_CODE_RETURN_STR(code) case code: return #code; + +static const char *get_egl_error_enum_string(EGLenum error) +{ + switch (error) { + CASE_CODE_RETURN_STR(EGL_SUCCESS) + CASE_CODE_RETURN_STR(EGL_NOT_INITIALIZED) + CASE_CODE_RETURN_STR(EGL_BAD_ACCESS) + CASE_CODE_RETURN_STR(EGL_BAD_ALLOC) + CASE_CODE_RETURN_STR(EGL_BAD_ATTRIBUTE) + CASE_CODE_RETURN_STR(EGL_BAD_CONTEXT) + CASE_CODE_RETURN_STR(EGL_BAD_CONFIG) + CASE_CODE_RETURN_STR(EGL_BAD_CURRENT_SURFACE) + CASE_CODE_RETURN_STR(EGL_BAD_DISPLAY) + CASE_CODE_RETURN_STR(EGL_BAD_SURFACE) + CASE_CODE_RETURN_STR(EGL_BAD_MATCH) + CASE_CODE_RETURN_STR(EGL_BAD_PARAMETER) + CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_PIXMAP) + CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_WINDOW) + CASE_CODE_RETURN_STR(EGL_CONTEXT_LOST) + default: + return NULL; + } +} + +static const char *get_egl_error_message_string(EGLenum error) +{ + switch (error) { + case EGL_SUCCESS: + return "The last function succeeded without error."; + + case EGL_NOT_INITIALIZED: + return ("EGL is not initialized, or could not be initialized, " + "for the specified EGL display connection."); + + case EGL_BAD_ACCESS: + return ("EGL cannot access a requested resource " + "(for example a context is bound in another thread)."); + + case EGL_BAD_ALLOC: + return "EGL failed to allocate resources for the requested operation."; + + case EGL_BAD_ATTRIBUTE: + return "An unrecognized attribute or attribute value was passed in the attribute list."; + + case EGL_BAD_CONTEXT: + return "An EGLContext argument does not name a valid EGL rendering context."; + + case EGL_BAD_CONFIG: + return "An EGLConfig argument does not name a valid EGL frame buffer configuration."; + + case EGL_BAD_CURRENT_SURFACE: + return ("The current surface of the calling thread is a window, " + "pixel buffer or pixmap that is no longer valid."); + + case EGL_BAD_DISPLAY: + return "An EGLDisplay argument does not name a valid EGL display connection."; + + case EGL_BAD_SURFACE: + return ("An EGLSurface argument does not name a valid surface " + "(window, pixel buffer or pixmap) configured for GL rendering."); + + case EGL_BAD_MATCH: + return ("Arguments are inconsistent " + "(for example, a valid context requires buffers not supplied by a valid surface)."); + + case EGL_BAD_PARAMETER: + return "One or more argument values are invalid."; + + case EGL_BAD_NATIVE_PIXMAP: + return "A NativePixmapType argument does not refer to a valid native pixmap."; + + case EGL_BAD_NATIVE_WINDOW: + return "A NativeWindowType argument does not refer to a valid native window."; + + case EGL_CONTEXT_LOST: + return ("A power management event has occurred. " + "The application must destroy all contexts and reinitialise OpenGL ES state " + "and objects to continue rendering."); + + default: + return NULL; + } +} + + +static bool egl_chk(bool result, const char *file = NULL, int line = 0, const char *text = NULL) +{ + if (!result) { + EGLenum error = eglGetError(); + + const char *code = get_egl_error_enum_string(error); + const char *msg = get_egl_error_message_string(error); + +#ifndef NDEBUG + fprintf(stderr, + "%s(%d):[%s] -> EGL Error (0x%04X): %s: %s\n", + file, line, text, error, + code ? code : "<Unknown>", + msg ? msg : "<Unknown>"); +#else + fprintf(stderr, + "EGL Error (0x%04X): %s: %s\n", + error, + code ? code : "<Unknown>", + msg ? msg : "<Unknown>"); +#endif + } + + return result; +} + +#ifndef NDEBUG +#define EGL_CHK(x) egl_chk((x), __FILE__, __LINE__, #x) +#else +#define EGL_CHK(x) egl_chk(x) +#endif + + +static inline bool bindAPI(EGLenum api) +{ +#ifdef WITH_GLEW_MX + if (eglewContext != NULL) +#endif + { + if (EGLEW_VERSION_1_2) { + return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE); + } + } + + return false; +} + + +#ifdef WITH_GL_ANGLE +HMODULE GHOST_ContextEGL::s_d3dcompiler = NULL; +#endif + + +EGLContext GHOST_ContextEGL::s_gl_sharedContext = EGL_NO_CONTEXT; +EGLint GHOST_ContextEGL::s_gl_sharedCount = 0; + +EGLContext GHOST_ContextEGL::s_gles_sharedContext = EGL_NO_CONTEXT; +EGLint GHOST_ContextEGL::s_gles_sharedCount = 0; + +EGLContext GHOST_ContextEGL::s_vg_sharedContext = EGL_NO_CONTEXT; +EGLint GHOST_ContextEGL::s_vg_sharedCount = 0; + + +#pragma warning(disable : 4715) + +template <typename T> +T &choose_api(EGLenum api, T &a, T &b, T &c) +{ + switch (api) { + case EGL_OPENGL_API: + return a; + case EGL_OPENGL_ES_API: + return b; + case EGL_OPENVG_API: + return c; + default: + abort(); + } +} + + +GHOST_ContextEGL::GHOST_ContextEGL( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + EGLNativeWindowType nativeWindow, + EGLNativeDisplayType nativeDisplay, + EGLint contextProfileMask, + EGLint contextMajorVersion, + EGLint contextMinorVersion, + EGLint contextFlags, + EGLint contextResetNotificationStrategy, + EGLenum api) + : GHOST_Context(stereoVisual, numOfAASamples), + m_nativeDisplay(nativeDisplay), + m_nativeWindow (nativeWindow), + m_contextProfileMask(contextProfileMask), + m_contextMajorVersion(contextMajorVersion), + m_contextMinorVersion(contextMinorVersion), + m_contextFlags(contextFlags), + m_contextResetNotificationStrategy(contextResetNotificationStrategy), + m_api(api), + m_context(EGL_NO_CONTEXT), + m_surface(EGL_NO_SURFACE), + m_display(EGL_NO_DISPLAY), + m_swap_interval(1), +#ifdef WITH_GLEW_MX + m_eglewContext(NULL), +#endif + m_sharedContext(choose_api(api, s_gl_sharedContext, s_gles_sharedContext, s_vg_sharedContext)), + m_sharedCount (choose_api(api, s_gl_sharedCount, s_gles_sharedCount, s_vg_sharedCount)) +{ + assert(m_nativeWindow != 0); + assert(m_nativeDisplay != NULL); +} + + +GHOST_ContextEGL::~GHOST_ContextEGL() +{ + if (m_display != EGL_NO_DISPLAY) { + activateEGLEW(); + + bindAPI(m_api); + + if (m_context != EGL_NO_CONTEXT) { + if (m_context == ::eglGetCurrentContext()) + EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); + + if (m_context != m_sharedContext || m_sharedCount == 1) { + assert(m_sharedCount > 0); + + m_sharedCount--; + + if (m_sharedCount == 0) + m_sharedContext = EGL_NO_CONTEXT; + + EGL_CHK(::eglDestroyContext(m_display, m_context)); + } + } + + if (m_surface != EGL_NO_SURFACE) + EGL_CHK(::eglDestroySurface(m_display, m_surface)); + + EGL_CHK(::eglTerminate(m_display)); + +#ifdef WITH_GLEW_MX + delete m_eglewContext; +#endif + } +} + + +GHOST_TSuccess GHOST_ContextEGL::swapBuffers() +{ + return EGL_CHK(::eglSwapBuffers(m_display, m_surface)) ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_ContextEGL::setSwapInterval(int interval) +{ + if (EGLEW_VERSION_1_1) { + if (EGL_CHK(::eglSwapInterval(m_display, interval))) { + m_swap_interval = interval; + + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } + } + else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_ContextEGL::getSwapInterval(int &intervalOut) +{ + intervalOut = m_swap_interval; // XXX jwilkins: make sure there is no way to query this? + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext() +{ + if (m_display) { + activateEGLEW(); + activateGLEW(); + + bindAPI(m_api); + + return EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context)) ? GHOST_kSuccess : GHOST_kFailure; + } + else { + return GHOST_kFailure; + } +} + + +void GHOST_ContextEGL::initContextEGLEW() +{ +#ifdef WITH_GLEW_MX + eglewContext = new EGLEWContext; + memset(eglewContext, 0, sizeof(EGLEWContext)); + + delete m_eglewContext; + m_eglewContext = eglewContext; +#endif + + if (GLEW_CHK(eglewInit(m_display)) != GLEW_OK) + fprintf(stderr, "Warning! EGLEW failed to initialize properly.\n"); +} + + +static const std::string &api_string(EGLenum api) +{ + static const std::string a("OpenGL"); + static const std::string b("OpenGL ES"); + static const std::string c("OpenVG"); + + return choose_api(api, a, b, c); +} + +GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() +{ + // objects have to be declared here due to the use of goto + std::vector<EGLint> attrib_list; + EGLint num_config = 0; + + if (m_stereoVisual) + fprintf(stderr, "Warning! Stereo OpenGL ES contexts are not supported.\n"); + + m_stereoVisual = false; // It doesn't matter what the Window wants. + +#ifdef WITH_GL_ANGLE + // d3dcompiler_XX.dll needs to be loaded before ANGLE will work + if (s_d3dcompiler == NULL) { + s_d3dcompiler = LoadLibrary(D3DCOMPILER); + + WIN32_CHK(s_d3dcompiler != NULL); + + if (s_d3dcompiler == NULL) { + fprintf(stderr, "LoadLibrary(\"" D3DCOMPILER "\") failed!\n"); + return GHOST_kFailure; + } + } +#endif + + EGLDisplay prev_display = eglGetCurrentDisplay(); + EGLSurface prev_draw = eglGetCurrentSurface(EGL_DRAW); + EGLSurface prev_read = eglGetCurrentSurface(EGL_READ); + EGLContext prev_context = eglGetCurrentContext(); + + m_display = ::eglGetDisplay(m_nativeDisplay); + + if (!EGL_CHK(m_display != EGL_NO_DISPLAY)) + return GHOST_kFailure; + + EGLint egl_major, egl_minor; + + if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) + goto error; + + fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor); + + if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))) + goto error; + + initContextEGLEW(); + + if (!bindAPI(m_api)) + goto error; + + + // build attribute list + + attrib_list.reserve(20); + + if (m_api == EGL_OPENGL_ES_API && EGLEW_VERSION_1_2) { + // According to the spec it seems that you are required to set EGL_RENDERABLE_TYPE, + // but some implementations (ANGLE) do not seem to care. + + if (m_contextMajorVersion == 1) { + attrib_list.push_back(EGL_RENDERABLE_TYPE); + attrib_list.push_back(EGL_OPENGL_ES_BIT); + } + else if (m_contextMajorVersion == 2) { + attrib_list.push_back(EGL_RENDERABLE_TYPE); + attrib_list.push_back(EGL_OPENGL_ES2_BIT); + } + else if (m_contextMajorVersion == 3) { + attrib_list.push_back(EGL_RENDERABLE_TYPE); + attrib_list.push_back(EGL_OPENGL_ES3_BIT_KHR); + } + else { + fprintf(stderr, + "Warning! Unable to request an ES context of version %d.%d\n", + m_contextMajorVersion, m_contextMinorVersion); + } + + if (!((m_contextMajorVersion == 1) || + (m_contextMajorVersion == 2 && EGLEW_VERSION_1_3) || + (m_contextMajorVersion == 3 && /*EGLEW_VERSION_1_4 &&*/ EGLEW_KHR_create_context) || + (m_contextMajorVersion == 3 && EGLEW_VERSION_1_5))) + { + fprintf(stderr, + "Warning! May not be able to create a version %d.%d ES context with version %d.%d of EGL\n", + m_contextMajorVersion, m_contextMinorVersion, egl_major, egl_minor); + } + } + + attrib_list.push_back(EGL_RED_SIZE); + attrib_list.push_back(8); + + attrib_list.push_back(EGL_GREEN_SIZE); + attrib_list.push_back(8); + + attrib_list.push_back(EGL_BLUE_SIZE); + attrib_list.push_back(8); + +#ifdef GHOST_OPENGL_ALPHA + attrib_list.push_back(EGL_ALPHA_SIZE); + attrib_list.push_back(8); +#endif + + attrib_list.push_back(EGL_DEPTH_SIZE); + attrib_list.push_back(24); + +#ifdef GHOST_OPENGL_STENCIL + attrib_list.push_back(EGL_STENCIL_SIZE); + attrib_list.push_back(8); +#endif + + if (m_numOfAASamples > 0) { + attrib_list.push_back(EGL_SAMPLE_BUFFERS); + attrib_list.push_back(1); + + attrib_list.push_back(EGL_SAMPLES); + attrib_list.push_back(m_numOfAASamples); + } + + attrib_list.push_back(EGL_NONE); + + EGLConfig config; + + if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &config, 1, &num_config))) + goto error; + + // A common error is to assume that ChooseConfig worked because it returned EGL_TRUE + if (num_config != 1) // num_config should be exactly 1 + goto error; + + if (m_numOfAASamples > 0) { + EGLint actualSamples; + + if (!EGL_CHK(::eglGetConfigAttrib(m_display, config, EGL_SAMPLE_BUFFERS, &actualSamples))) + goto error; + + if (m_numOfAASamples != actualSamples) { + fprintf(stderr, + "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " + "Substituting one that uses %d samples.\n", + m_numOfAASamples, + actualSamples); + + m_numOfAASamples = (GHOST_TUns16)actualSamples; + } + } + + m_surface = ::eglCreateWindowSurface(m_display, config, m_nativeWindow, NULL); + + if (!EGL_CHK(m_surface != EGL_NO_SURFACE)) + goto error; + + attrib_list.clear(); + + if (EGLEW_VERSION_1_5 || EGLEW_KHR_create_context) { + if (m_api == EGL_OPENGL_API || m_api == EGL_OPENGL_ES_API) { + if (m_contextMajorVersion != 0) { + attrib_list.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); + attrib_list.push_back(m_contextMajorVersion); + } + + if (m_contextMinorVersion != 0) { + attrib_list.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); + attrib_list.push_back(m_contextMinorVersion); + } + + if (m_contextFlags != 0) { + attrib_list.push_back(EGL_CONTEXT_FLAGS_KHR); + attrib_list.push_back(m_contextFlags); + } + } + else { + if (m_contextMajorVersion != 0 || m_contextMinorVersion != 0) { + fprintf(stderr, + "Warning! Cannot request specific versions of %s contexts.", + api_string(m_api).c_str()); + } + + if (m_contextFlags != 0) { + fprintf(stderr, + "Warning! Flags cannot be set on %s contexts.", + api_string(m_api).c_str()); + } + } + + if (m_api == EGL_OPENGL_API) { + if (m_contextProfileMask != 0) { + attrib_list.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); + attrib_list.push_back(m_contextProfileMask); + } + } + else { + if (m_contextProfileMask != 0) + fprintf(stderr, + "Warning! Cannot select profile for %s contexts.", + api_string(m_api).c_str()); + } + + if (m_api == EGL_OPENGL_API || EGLEW_VERSION_1_5) { + if (m_contextResetNotificationStrategy != 0) { + attrib_list.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR); + attrib_list.push_back(m_contextResetNotificationStrategy); + } + } + else { + if (m_contextResetNotificationStrategy != 0) { + fprintf(stderr, + "Warning! EGL %d.%d cannot set the reset notification strategy on %s contexts.", + egl_major, egl_minor, api_string(m_api).c_str()); + } + } + } + else { + if (m_api == EGL_OPENGL_ES_API) { + if (m_contextMajorVersion != 0) { + attrib_list.push_back(EGL_CONTEXT_CLIENT_VERSION); + attrib_list.push_back(m_contextMajorVersion); + } + } + else { + if (m_contextMajorVersion != 0 || m_contextMinorVersion != 0) { + fprintf(stderr, + "Warning! EGL %d.%d is unable to select between versions of %s.", + egl_major, egl_minor, api_string(m_api).c_str()); + } + } + + if (m_contextFlags != 0) { + fprintf(stderr, + "Warning! EGL %d.%d is unable to set context flags.", + egl_major, egl_minor); + } + if (m_contextProfileMask != 0) { + fprintf(stderr, + "Warning! EGL %d.%d is unable to select between profiles.", + egl_major, egl_minor); + } + if (m_contextResetNotificationStrategy != 0) { + fprintf(stderr, + "Warning! EGL %d.%d is unable to set the reset notification strategies.", + egl_major, egl_minor); + } + } + + attrib_list.push_back(EGL_NONE); + + m_context = ::eglCreateContext(m_display, config, m_sharedContext, &(attrib_list[0])); + + if (!EGL_CHK(m_context != EGL_NO_CONTEXT)) + goto error; + + if (m_sharedContext == EGL_NO_CONTEXT) + m_sharedContext = m_context; + + m_sharedCount++; + + if (!EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context))) + goto error; + + initContextGLEW(); + + initClearGL(); + ::eglSwapBuffers(m_display, m_surface); + + return GHOST_kSuccess; + +error: + if (prev_display != EGL_NO_DISPLAY) + EGL_CHK(eglMakeCurrent(prev_display, prev_draw, prev_read, prev_context)); + + return GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_ContextEGL::releaseNativeHandles() +{ + m_nativeWindow = 0; + m_nativeDisplay = NULL; + + return GHOST_kSuccess; +} diff --git a/intern/ghost/intern/GHOST_ContextEGL.h b/intern/ghost/intern/GHOST_ContextEGL.h new file mode 100644 index 00000000000..5e458139ade --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextEGL.h @@ -0,0 +1,167 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextEGL.h + * \ingroup GHOST + */ + +#ifndef __GHOST_CONTEXTEGL_H__ +#define __GHOST_CONTEXTEGL_H__ + +#include "GHOST_Context.h" + +#ifdef WITH_GLEW_MX +# define eglewGetContext() eglewContext +#endif + +#include <GL/eglew.h> + +#ifdef WITH_GLEW_MX +extern "C" EGLEWContext *eglewContext; +#endif + + +#ifndef GHOST_OPENGL_EGL_CONTEXT_FLAGS +#define GHOST_OPENGL_EGL_CONTEXT_FLAGS 0 +#endif + +#ifndef GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY +#define GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY 0 +#endif + + +class GHOST_ContextEGL : public GHOST_Context +{ +public: + /** + * Constructor. + */ + GHOST_ContextEGL( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + EGLNativeWindowType nativeWindow, + EGLNativeDisplayType nativeDisplay, + EGLint contextProfileMask, + EGLint contextMajorVersion, + EGLint contextMinorVersion, + EGLint contextFlags, + EGLint contextResetNotificationStrategy, + EGLenum api); + + /** + * Destructor. + */ + virtual ~GHOST_ContextEGL(); + + /** + * Swaps front and back buffers of a window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Activates the drawing context of this window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Call immediately after new to initialize. If this fails then immediately delete the object. + * \return Indication as to whether initialization has succeeded. + */ + virtual GHOST_TSuccess initializeDrawingContext(); + + /** + * Removes references to native handles from this context and then returns + * \return GHOST_kSuccess if it is OK for the parent to release the handles and + * GHOST_kFailure if releasing the handles will interfere with sharing + */ + virtual GHOST_TSuccess releaseNativeHandles(); + + /** + * Sets the swap interval for swapBuffers. + * \param interval The swap interval to use. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess setSwapInterval(int interval); + + /** + * Gets the current swap interval for swapBuffers. + * \param intervalOut Variable to store the swap interval if it can be read. + * \return Whether the swap interval can be read. + */ + GHOST_TSuccess getSwapInterval(int &intervalOut); + +protected: + inline void activateEGLEW() const { +#ifdef WITH_GLEW_MX + eglewContext = m_eglewContext; +#endif + } + +private: + void initContextEGLEW(); + + EGLNativeDisplayType m_nativeDisplay; + EGLNativeWindowType m_nativeWindow; + + const EGLint m_contextProfileMask; + const EGLint m_contextMajorVersion; + const EGLint m_contextMinorVersion; + const EGLint m_contextFlags; + const EGLint m_contextResetNotificationStrategy; + + const EGLenum m_api; + + EGLContext m_context; + EGLSurface m_surface; + EGLDisplay m_display; + + EGLint m_swap_interval; + +#ifdef WITH_GLEW_MX + EGLEWContext *m_eglewContext; +#endif + + EGLContext &m_sharedContext; + EGLint &m_sharedCount; + + static EGLContext s_gl_sharedContext; + static EGLint s_gl_sharedCount; + + static EGLContext s_gles_sharedContext; + static EGLint s_gles_sharedCount; + + static EGLContext s_vg_sharedContext; + static EGLint s_vg_sharedCount; + +#ifdef WITH_GL_ANGLE + static HMODULE s_d3dcompiler; +#endif +}; + +#endif // __GHOST_CONTEXTEGL_H__ diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp new file mode 100644 index 00000000000..726614c48b1 --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -0,0 +1,341 @@ +/* + * ***** 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) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextGLX.cpp + * \ingroup GHOST + * + * Definition of GHOST_ContextGLX class. + */ + +#include "GHOST_ContextGLX.h" +#include "GHOST_SystemX11.h" + +#include <vector> + +#include <cassert> +#include <cstdio> +#include <cstring> + + +#ifdef WITH_GLEW_MX +GLXEWContext *glxewContext = NULL; +#endif + +GLXContext GHOST_ContextGLX::s_sharedContext = None; +int GHOST_ContextGLX::s_sharedCount = 0; + + +GHOST_ContextGLX::GHOST_ContextGLX( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + Window window, + Display *display, + int contextProfileMask, + int contextMajorVersion, + int contextMinorVersion, + int contextFlags, + int contextResetNotificationStrategy) + : GHOST_Context(stereoVisual, numOfAASamples), + m_display(display), + m_window(window), + m_contextProfileMask(contextProfileMask), + m_contextMajorVersion(contextMajorVersion), + m_contextMinorVersion(contextMinorVersion), + m_contextFlags(contextFlags), + m_contextResetNotificationStrategy(contextResetNotificationStrategy), + m_visualInfo(NULL), + m_context(None) +#ifdef WITH_GLEW_MX + , + m_glxewContext(NULL) +#endif +{ + assert(m_window != 0); + assert(m_display != NULL); +} + + +GHOST_ContextGLX::~GHOST_ContextGLX() +{ + if (m_display != NULL) { + activateGLXEW(); + + if (m_context != None) { + if (m_window != 0 && m_context == ::glXGetCurrentContext()) + ::glXMakeCurrent(m_display, m_window, NULL); + + if (m_context != s_sharedContext || s_sharedCount == 1) { + assert(s_sharedCount > 0); + + s_sharedCount--; + + if (s_sharedCount == 0) + s_sharedContext = NULL; + + ::glXDestroyContext(m_display, m_context); + } + } + +#ifdef WITH_GLEW_MX + delete m_glxewContext; +#endif + } + + XFree(m_visualInfo); +} + + +GHOST_TSuccess GHOST_ContextGLX::swapBuffers() +{ + ::glXSwapBuffers(m_display, m_window); + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextGLX::activateDrawingContext() +{ + if (m_display) { + activateGLXEW(); + activateGLEW(); + + return ::glXMakeCurrent(m_display, m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure; + } + else { + return GHOST_kFailure; + } +} + +void GHOST_ContextGLX::initContextGLXEW() +{ +#ifdef WITH_GLEW_MX + glxewContext = new GLXEWContext; + memset(glxewContext, 0, sizeof(GLXEWContext)); + + delete m_glxewContext; + m_glxewContext = glxewContext; +#endif + + initContextGLEW(); +} + +GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext() +{ + /* Set up the minimum attributes that we require and see if + * X can find us a visual matching those requirements. */ + + std::vector<int> attribs; + attribs.reserve(40); + + int glx_major, glx_minor; /* GLX version: major.minor */ + + if (!glXQueryVersion(m_display, &glx_major, &glx_minor)) { + fprintf(stderr, + "%s:%d: X11 glXQueryVersion() failed, " + "verify working openGL system!\n", + __FILE__, __LINE__); + + /* exit if this is the first window */ + if (s_sharedContext == NULL) { + fprintf(stderr, "initial window could not find the GLX extension, exit!\n"); + exit(EXIT_FAILURE); + } + + return GHOST_kFailure; + } + +#ifdef GHOST_OPENGL_ALPHA + const bool needAlpha = true; +#else + const bool needAlpha = false; +#endif + +#ifdef GHOST_OPENGL_STENCIL + const bool needStencil = true; +#else + const bool needStencil = false; +#endif + + /* Find the display with highest samples, starting at level requested */ + int actualSamples = m_numOfAASamples; + for (;;) { + attribs.clear(); + + if (m_stereoVisual) + attribs.push_back(GLX_STEREO); + + attribs.push_back(GLX_RGBA); + + attribs.push_back(GLX_DOUBLEBUFFER); + + attribs.push_back(GLX_RED_SIZE); + attribs.push_back(1); + + attribs.push_back(GLX_BLUE_SIZE); + attribs.push_back(1); + + attribs.push_back(GLX_GREEN_SIZE); + attribs.push_back(1); + + attribs.push_back(GLX_DEPTH_SIZE); + attribs.push_back(1); + + if (needAlpha) { + attribs.push_back(GLX_ALPHA_SIZE); + attribs.push_back(1); + } + + if (needStencil) { + attribs.push_back(GLX_STENCIL_SIZE); + attribs.push_back(1); + } + + /* GLX >= 1.4 required for multi-sample */ + if (actualSamples > 0 && ((glx_major > 1) || (glx_major == 1 && glx_minor >= 4))) { + attribs.push_back(GLX_SAMPLE_BUFFERS); + attribs.push_back(1); + + attribs.push_back(GLX_SAMPLES); + attribs.push_back(actualSamples); + } + + attribs.push_back(None); + + m_visualInfo = glXChooseVisual(m_display, DefaultScreen(m_display), &attribs[0]); + + /* Any sample level or even zero, which means oversampling disabled, is good + * but we need a valid visual to continue */ + if (m_visualInfo != NULL) { + if (actualSamples < m_numOfAASamples) { + fprintf(stderr, + "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " + "Substituting one that uses %d samples.\n", + m_numOfAASamples, actualSamples); + } + break; + } + + if (actualSamples == 0) { + /* All options exhausted, cannot continue */ + fprintf(stderr, + "%s:%d: X11 glXChooseVisual() failed, " + "verify working openGL system!\n", + __FILE__, __LINE__); + + if (s_sharedContext == None) { + fprintf(stderr, "initial window could not find the GLX extension, exit!\n"); + exit(1); + } + + return GHOST_kFailure; + } + else { + --actualSamples; + } + } + + m_numOfAASamples = actualSamples; + +#ifdef WITH_X11_XINPUT + /* use our own event handlers to avoid exiting blender, + * this would happen for eg: + * if you open blender, unplug a tablet, then open a new window. */ + XErrorHandler old_handler = XSetErrorHandler (GHOST_X11_ApplicationErrorHandler ); + XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler); +#endif + + m_context = glXCreateContext(m_display, m_visualInfo, s_sharedContext, True); + + GHOST_TSuccess success; + + if (m_context != NULL) { + if (!s_sharedContext) + s_sharedContext = m_context; + + s_sharedCount++; + + glXMakeCurrent(m_display, m_window, m_context); + + // Seems that this has to be called after MakeCurrent, + // which means we cannot use glX extensions until after we create a context + initContextGLXEW(); + + initClearGL(); + ::glXSwapBuffers(m_display, m_window); + + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + +#ifdef WITH_X11_XINPUT + /* Restore handler */ + XSetErrorHandler (old_handler); + XSetIOErrorHandler(old_handler_io); +#endif + + return success; +} + + +GHOST_TSuccess GHOST_ContextGLX::releaseNativeHandles() +{ + m_window = 0; + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextGLX::setSwapInterval(int interval) +{ + if (GLXEW_EXT_swap_control) { + ::glXSwapIntervalEXT(m_display, m_window, interval); + + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut) +{ + if (GLXEW_EXT_swap_control) { + unsigned int interval = 0; + + ::glXQueryDrawable(m_display, m_window, GLX_SWAP_INTERVAL_EXT, &interval); + + intervalOut = static_cast<int>(interval); + + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h new file mode 100644 index 00000000000..d32adf3338d --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextGLX.h @@ -0,0 +1,150 @@ +/* + * ***** 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) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextGLX.h + * \ingroup GHOST + */ + +#ifndef __GHOST_CONTEXTGLX_H__ +#define __GHOST_CONTEXTGLX_H__ + +#include "GHOST_Context.h" + +#ifdef WITH_GLEW_MX +# define glxewGetContext() glxewContext +#endif + +#include <GL/glxew.h> + +#ifdef WITH_GLEW_MX +extern "C" GLXEWContext *glxewContext; +#endif + + +#ifndef GHOST_OPENGL_GLX_CONTEXT_FLAGS +#define GHOST_OPENGL_GLX_CONTEXT_FLAGS 0 +#endif + +#ifndef GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY +#define GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY 0 +#endif + + +class GHOST_ContextGLX : public GHOST_Context +{ +public: + /** + * Constructor. + */ + GHOST_ContextGLX( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + Window window, + Display *display, + int contextProfileMask, + int contextMajorVersion, + int contextMinorVersion, + int contextFlags, + int contextResetNotificationStrategy); + + /** + * Destructor. + */ + virtual ~GHOST_ContextGLX(); + + /** + * Swaps front and back buffers of a window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Activates the drawing context of this window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Call immediately after new to initialize. If this fails then immediately delete the object. + * \return Indication as to whether initialization has succeeded. + */ + virtual GHOST_TSuccess initializeDrawingContext(); + + /** + * Removes references to native handles from this context and then returns + * \return GHOST_kSuccess if it is OK for the parent to release the handles and + * GHOST_kFailure if releasing the handles will interfere with sharing + */ + virtual GHOST_TSuccess releaseNativeHandles(); + + /** + * Sets the swap interval for swapBuffers. + * \param interval The swap interval to use. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess setSwapInterval(int interval); + + /** + * Gets the current swap interval for swapBuffers. + * \param intervalOut Variable to store the swap interval if it can be read. + * \return Whether the swap interval can be read. + */ + virtual GHOST_TSuccess getSwapInterval(int &intervalOut); + +protected: + inline void activateGLXEW() const { +#ifdef WITH_GLEW_MX + glxewContext = m_glxewContext; +#endif + } + +private: + void initContextGLXEW(); + + Display *m_display; + Window m_window; + + const int m_contextProfileMask; + const int m_contextMajorVersion; + const int m_contextMinorVersion; + const int m_contextFlags; + const int m_contextResetNotificationStrategy; + + XVisualInfo *m_visualInfo; + + GLXContext m_context; + +#ifdef WITH_GLEW_MX + GLXEWContext *m_glxewContext; +#endif + + /** The first created OpenGL context (for sharing display lists) */ + static GLXContext s_sharedContext; + static int s_sharedCount; +}; + +#endif // __GHOST_CONTEXTGLX_H__ diff --git a/intern/ghost/intern/GHOST_ContextNone.cpp b/intern/ghost/intern/GHOST_ContextNone.cpp new file mode 100644 index 00000000000..380ab532f7a --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextNone.cpp @@ -0,0 +1,79 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextNone.cpp + * \ingroup GHOST + * + * Definition of GHOST_ContextNone class. + */ + +#include "GHOST_ContextNone.h" + + +GHOST_TSuccess GHOST_ContextNone::swapBuffers() +{ + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextNone::activateDrawingContext() +{ + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextNone::updateDrawingContext() +{ + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextNone::initializeDrawingContext() +{ + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextNone::releaseNativeHandles() +{ + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextNone::setSwapInterval(int interval) +{ + m_swapInterval = interval; + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextNone::getSwapInterval(int &intervalOut) +{ + intervalOut = m_swapInterval; + return GHOST_kSuccess; +} diff --git a/intern/ghost/intern/GHOST_ContextNone.h b/intern/ghost/intern/GHOST_ContextNone.h new file mode 100644 index 00000000000..c36873c039f --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextNone.h @@ -0,0 +1,97 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextNone.h + * \ingroup GHOST + * + * Declaration of GHOST_Context class. + */ + +#ifndef __GHOST_CONTEXTNONE_H__ +#define __GHOST_CONTEXTNONE_H__ + +#include "GHOST_Context.h" + +class GHOST_ContextNone : public GHOST_Context +{ +public: + + GHOST_ContextNone( + bool stereoVisual, + GHOST_TUns16 numOfAASamples) + : GHOST_Context(stereoVisual, numOfAASamples), + m_swapInterval(1) + {} + + /** + * Dummy function + * \return Always succeeds + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Dummy function + * \return Always succeeds + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Dummy function + * \return Always succeeds + */ + virtual GHOST_TSuccess updateDrawingContext(); + + /** + * Dummy function + * \return Always succeeds + */ + virtual GHOST_TSuccess initializeDrawingContext(); + + /** + * Dummy function + * \return Always succeeds + */ + virtual GHOST_TSuccess releaseNativeHandles(); + + /** + * Dummy function + * \return Always succeeds + */ + virtual GHOST_TSuccess setSwapInterval(int interval); + + /** + * Dummy function + * \param intervalOut Gets whatever was set by setSwapInterval + * \return Always succeeds + */ + virtual GHOST_TSuccess getSwapInterval(int &intervalOut); + +private: + int m_swapInterval; +}; + +#endif // __GHOST_CONTEXTNONE_H__ diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp new file mode 100644 index 00000000000..d80a638818c --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextSDL.cpp @@ -0,0 +1,204 @@ +/* + * ***** 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) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextSDL.cpp + * \ingroup GHOST + * + * Definition of GHOST_ContextSDL class. + */ + +#include "GHOST_ContextSDL.h" + +#include <vector> + +#include <cassert> +#include <cstdio> +#include <cstring> + + +SDL_GLContext GHOST_ContextSDL::s_sharedContext = NULL; +int GHOST_ContextSDL::s_sharedCount = 0; + + +GHOST_ContextSDL::GHOST_ContextSDL( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + SDL_Window *window, + int contextProfileMask, + int contextMajorVersion, + int contextMinorVersion, + int contextFlags, + int contextResetNotificationStrategy) + : GHOST_Context(stereoVisual, numOfAASamples), + m_window(window), + m_contextProfileMask(contextProfileMask), + m_contextMajorVersion(contextMajorVersion), + m_contextMinorVersion(contextMinorVersion), + m_contextFlags(contextFlags), + m_contextResetNotificationStrategy(contextResetNotificationStrategy), + m_context(NULL) +{ + assert(m_window != NULL); +} + + +GHOST_ContextSDL::~GHOST_ContextSDL() +{ + if (m_context != NULL) { + if (m_window != 0 && m_context == SDL_GL_GetCurrentContext()) + SDL_GL_MakeCurrent(m_window, m_context); + + if (m_context != s_sharedContext || s_sharedCount == 1) { + assert(s_sharedCount > 0); + + s_sharedCount--; + + if (s_sharedCount == 0) + s_sharedContext = NULL; + + SDL_GL_DeleteContext(m_context); + } + } +} + + +GHOST_TSuccess GHOST_ContextSDL::swapBuffers() +{ + SDL_GL_SwapWindow(m_window); + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextSDL::activateDrawingContext() +{ + if (m_context) { + activateGLEW(); + + return SDL_GL_MakeCurrent(m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure; + } + else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext() +{ +#ifdef GHOST_OPENGL_ALPHA + const bool needAlpha = true; +#else + const bool needAlpha = false; +#endif + +#ifdef GHOST_OPENGL_STENCIL + const bool needStencil = true; +#else + const bool needStencil = false; +#endif + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, m_contextProfileMask); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, m_contextMajorVersion); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, m_contextMinorVersion); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, m_contextFlags); + + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + + if (needAlpha) { + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + } + + if (needStencil) { + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); + } + + if (m_stereoVisual) { + SDL_GL_SetAttribute(SDL_GL_STEREO, 1); + } + + if (m_numOfAASamples) { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, m_numOfAASamples); + } + + m_context = SDL_GL_CreateContext(m_window); + + GHOST_TSuccess success; + + if (m_context != NULL) { + if (!s_sharedContext) + s_sharedContext = m_context; + + s_sharedCount++; + + success = (SDL_GL_MakeCurrent(m_window, m_context) < 0) ? + GHOST_kFailure : GHOST_kSuccess; + + initContextGLEW(); + + initClearGL(); + SDL_GL_SwapWindow(m_window); + + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + + return success; +} + + +GHOST_TSuccess GHOST_ContextSDL::releaseNativeHandles() +{ + m_window = NULL; + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_ContextSDL::setSwapInterval(int interval) +{ + if (SDL_GL_SetSwapInterval(interval) != -1) { + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_ContextSDL::getSwapInterval(int &intervalOut) +{ + intervalOut = SDL_GL_GetSwapInterval(); + return GHOST_kSuccess; +} diff --git a/intern/ghost/intern/GHOST_ContextSDL.h b/intern/ghost/intern/GHOST_ContextSDL.h new file mode 100644 index 00000000000..5edf1a0aee8 --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextSDL.h @@ -0,0 +1,127 @@ +/* + * ***** 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) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextSDL.h + * \ingroup GHOST + */ + +#ifndef __GHOST_CONTEXTSDL_H__ +#define __GHOST_CONTEXTSDL_H__ + +#include "GHOST_Context.h" + +extern "C" { + #include "SDL.h" +} + + +#ifndef GHOST_OPENGL_SDL_CONTEXT_FLAGS +#define GHOST_OPENGL_SDL_CONTEXT_FLAGS 0 +#endif + +#ifndef GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY +#define GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY 0 +#endif + + +class GHOST_ContextSDL : public GHOST_Context +{ +public: + /** + * Constructor. + */ + GHOST_ContextSDL( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + SDL_Window *window, + int contextProfileMask, + int contextMajorVersion, + int contextMinorVersion, + int contextFlags, + int contextResetNotificationStrategy); + + /** + * Destructor. + */ + virtual ~GHOST_ContextSDL(); + + /** + * Swaps front and back buffers of a window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Activates the drawing context of this window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Call immediately after new to initialize. If this fails then immediately delete the object. + * \return Indication as to whether initialization has succeeded. + */ + virtual GHOST_TSuccess initializeDrawingContext(); + + /** + * Removes references to native handles from this context and then returns + * \return GHOST_kSuccess if it is OK for the parent to release the handles and + * GHOST_kFailure if releasing the handles will interfere with sharing + */ + virtual GHOST_TSuccess releaseNativeHandles(); + + /** + * Sets the swap interval for swapBuffers. + * \param interval The swap interval to use. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess setSwapInterval(int interval); + + /** + * Gets the current swap interval for swapBuffers. + * \param intervalOut Variable to store the swap interval if it can be read. + * \return Whether the swap interval can be read. + */ + virtual GHOST_TSuccess getSwapInterval(int &intervalOut); + +private: + SDL_Window *m_window; + + const int m_contextProfileMask; + const int m_contextMajorVersion; + const int m_contextMinorVersion; + const int m_contextFlags; + const int m_contextResetNotificationStrategy; + + SDL_GLContext m_context; /* m_sdl_glcontext */ + + /** The first created OpenGL context (for sharing display lists) */ + static SDL_GLContext s_sharedContext; + static int s_sharedCount; +}; + +#endif // __GHOST_CONTEXTSDL_H__ diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp new file mode 100644 index 00000000000..de7a7f5deee --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -0,0 +1,876 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextWGL.cpp + * \ingroup GHOST + * + * Definition of GHOST_ContextWGL class. + */ + +#include "GHOST_ContextWGL.h" + +#include <tchar.h> + +#include <cstdio> +#include <cassert> +#include <vector> + + +#ifdef WITH_GLEW_MX +WGLEWContext *wglewContext = NULL; +#endif + +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. */ +static bool is_crappy_intel_card() +{ + return strstr((const char *)glGetString(GL_VENDOR), "Intel") != NULL; +} + + +GHOST_ContextWGL::GHOST_ContextWGL( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + HWND hWnd, + HDC hDC, + int contextProfileMask, + int contextMajorVersion, + int contextMinorVersion, + int contextFlags, + int contextResetNotificationStrategy) + : GHOST_Context(stereoVisual, numOfAASamples), + m_hWnd(hWnd), + m_hDC(hDC), + m_contextProfileMask(contextProfileMask), + m_contextMajorVersion(contextMajorVersion), + m_contextMinorVersion(contextMinorVersion), + m_contextFlags(contextFlags), + m_contextResetNotificationStrategy(contextResetNotificationStrategy), + m_hGLRC(NULL) +#ifdef WITH_GLEW_MX + , + m_wglewContext(NULL) +#endif +#ifndef NDEBUG + , + m_dummyVendor(NULL), + m_dummyRenderer(NULL), + m_dummyVersion(NULL) +#endif +{ + assert(m_hWnd); + assert(m_hDC); +} + + +GHOST_ContextWGL::~GHOST_ContextWGL() +{ + if (m_hGLRC != NULL) { + if (m_hGLRC == ::wglGetCurrentContext()) + WIN32_CHK(::wglMakeCurrent(NULL, NULL)); + + if (m_hGLRC != s_sharedHGLRC || s_sharedCount == 1) { + assert(s_sharedCount > 0); + + s_sharedCount--; + + if (s_sharedCount == 0) + s_sharedHGLRC = NULL; + + WIN32_CHK(::wglDeleteContext(m_hGLRC)); + } + } + +#ifdef WITH_GLEW_MX + delete m_wglewContext; +#endif + +#ifndef NDEBUG + delete m_dummyRenderer; + delete m_dummyVendor; + delete m_dummyVersion; +#endif +} + + +GHOST_TSuccess GHOST_ContextWGL::swapBuffers() +{ + return WIN32_CHK(::SwapBuffers(m_hDC)) ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_ContextWGL::setSwapInterval(int interval) +{ + if (WGLEW_EXT_swap_control) + return WIN32_CHK(::wglSwapIntervalEXT(interval)) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + else + return GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_ContextWGL::getSwapInterval(int &intervalOut) +{ + if (WGLEW_EXT_swap_control) { + intervalOut = ::wglGetSwapIntervalEXT(); + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext() +{ + if (WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) { + activateGLEW(); + 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 + */ +static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd) +{ + int weight = 0; + + /* assume desktop color depth is 32 bits per pixel */ + + /* cull unusable pixel formats */ + /* if no formats can be found, can we determine why it was rejected? */ + if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) || + !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || + !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */ + !(pfd.iPixelType == PFD_TYPE_RGBA) || + (pfd.cDepthBits < 16) || + (pfd.dwFlags & PFD_GENERIC_FORMAT)) /* no software renderers */ + { + return 0; + } + + weight = 1; /* it's usable */ + + /* the bigger the depth buffer the better */ + /* give no weight to a 16-bit depth buffer, because those are crap */ + weight += pfd.cDepthBits - 16; + + weight += pfd.cColorBits - 8; + +#ifdef GHOST_OPENGL_ALPHA + if (pfd.cAlphaBits > 0) + weight++; +#endif + +#ifdef GHOST_OPENGL_STENCIL + if (pfd.cStencilBits >= 8) + weight++; +#endif + + /* want swap copy capability -- it matters a lot */ + if (pfd.dwFlags & PFD_SWAP_COPY) + weight += 16; + + return weight; +} + + +/* + * A modification of Ron Fosner's replacement for ChoosePixelFormat + * returns 0 on error, else returns the pixel format number to be used + */ +static int choose_pixel_format_legacy(HDC hDC, PIXELFORMATDESCRIPTOR &preferredPFD) +{ + int iPixelFormat = 0; + int weight = 0; + + int iStereoPixelFormat = 0; + int stereoWeight = 0; + + /* choose a pixel format using the useless Windows function in case we come up empty handed */ + int iLastResortPixelFormat = ::ChoosePixelFormat(hDC, &preferredPFD); + + WIN32_CHK(iLastResortPixelFormat != 0); + + int lastPFD = ::DescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), NULL); + + WIN32_CHK(lastPFD != 0); + + for (int i = 1; i <= lastPFD; i++) { + PIXELFORMATDESCRIPTOR pfd; + int check = ::DescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + WIN32_CHK(check == lastPFD); + + int w = weight_pixel_format(pfd); + + if (w > weight) { + weight = w; + iPixelFormat = i; + } + + if (w > stereoWeight && (preferredPFD.dwFlags & pfd.dwFlags & PFD_STEREO)) { + stereoWeight = w; + iStereoPixelFormat = i; + } + } + + /* choose any available stereo format over a non-stereo format */ + if (iStereoPixelFormat != 0) + iPixelFormat = iStereoPixelFormat; + + if (iPixelFormat == 0) { + fprintf(stderr, "Warning! Using result of ChoosePixelFormat.\n"); + iPixelFormat = iLastResortPixelFormat; + } + + return iPixelFormat; +} + + +/* + * Clone a window for the purpose of creating a temporary context to initialize WGL extensions. + * There is no generic way to clone the lpParam parameter, so the caller is responsible for cloning it themselves. + */ + +static HWND clone_window(HWND hWnd, LPVOID lpParam) +{ + int count; + + SetLastError(NO_ERROR); + + DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE); + WIN32_CHK(GetLastError() == NO_ERROR); + + WCHAR lpClassName[100] = L""; + count = GetClassNameW(hWnd, lpClassName, sizeof(lpClassName)); + WIN32_CHK(count != 0); + + WCHAR lpWindowName[100] = L""; + count = GetWindowTextW(hWnd, lpWindowName, sizeof(lpWindowName)); + WIN32_CHK(count != 0); + + DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE); + WIN32_CHK(GetLastError() == NO_ERROR); + + RECT rect; + GetWindowRect(hWnd, &rect); + WIN32_CHK(GetLastError() == NO_ERROR); + + HWND hWndParent = (HWND)GetWindowLongPtr(hWnd, GWLP_HWNDPARENT); + WIN32_CHK(GetLastError() == NO_ERROR); + + HMENU hMenu = GetMenu(hWnd); + WIN32_CHK(GetLastError() == NO_ERROR); + + HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE); + WIN32_CHK(GetLastError() == NO_ERROR); + + HWND hwndCloned = CreateWindowExW( + dwExStyle, + lpClassName, + lpWindowName, + dwStyle, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + hWndParent, + hMenu, + hInstance, + lpParam); + + WIN32_CHK(hwndCloned != NULL); + + return hwndCloned; +} + + +void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD) +{ +#ifdef WITH_GLEW_MX + wglewContext = new WGLEWContext; + memset(wglewContext, 0, sizeof(WGLEWContext)); + + delete m_wglewContext; + m_wglewContext = wglewContext; +#endif + + HWND dummyHWND = NULL; + HDC dummyHDC = NULL; + HGLRC dummyHGLRC = NULL; + + SetLastError(NO_ERROR); + + HDC prevHDC = ::wglGetCurrentDC(); + WIN32_CHK(GetLastError() == NO_ERROR); + + HGLRC prevHGLRC = ::wglGetCurrentContext(); + WIN32_CHK(GetLastError() == NO_ERROR); + + dummyHWND = clone_window(m_hWnd, NULL); + + if (dummyHWND == NULL) + goto finalize; + + dummyHDC = GetDC(dummyHWND); + + if (!WIN32_CHK(dummyHDC != NULL)) + goto finalize; + + int iPixelFormat = choose_pixel_format_legacy(dummyHDC, preferredPFD); + + if (iPixelFormat == 0) + goto finalize; + + PIXELFORMATDESCRIPTOR chosenPFD; + if (!WIN32_CHK(::DescribePixelFormat(dummyHDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD))) + goto finalize; + + if (!WIN32_CHK(::SetPixelFormat(dummyHDC, iPixelFormat, &chosenPFD))) + goto finalize; + + dummyHGLRC = ::wglCreateContext(dummyHDC); + + if (!WIN32_CHK(dummyHGLRC != NULL)) + goto finalize; + + if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC))) + goto finalize; + +#ifdef WITH_GLEW_MX + if (GLEW_CHK(wglewInit()) != GLEW_OK) + fprintf(stderr, "Warning! WGLEW failed to initialize properly.\n"); +#else + if (GLEW_CHK(glewInit()) != GLEW_OK) + fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n"); +#endif + + // the following are not technially WGLEW, but they also require a context to work + +#ifndef NDEBUG + delete m_dummyRenderer; + delete m_dummyVendor; + delete m_dummyVersion; + + m_dummyRenderer = _strdup(reinterpret_cast<const char *>(glGetString(GL_RENDERER))); + m_dummyVendor = _strdup(reinterpret_cast<const char *>(glGetString(GL_VENDOR))); + m_dummyVersion = _strdup(reinterpret_cast<const char *>(glGetString(GL_VERSION))); +#endif + + s_singleContextMode = is_crappy_intel_card(); + +finalize: + WIN32_CHK(::wglMakeCurrent(prevHDC, prevHGLRC)); + + if (dummyHGLRC != NULL) + WIN32_CHK(::wglDeleteContext(dummyHGLRC)); + + if (dummyHWND != NULL) { + if (dummyHDC != NULL) + WIN32_CHK(::ReleaseDC(dummyHWND, dummyHDC)); + + WIN32_CHK(::DestroyWindow(dummyHWND)); + } +} + + +static void makeAttribList( + std::vector<int>& out, + bool stereoVisual, + int numOfAASamples, + int swapMethod, + bool needAlpha, + bool needStencil, + bool sRGB) +{ + out.clear(); + out.reserve(30); + + out.push_back(WGL_SUPPORT_OPENGL_ARB); + out.push_back(GL_TRUE); + + out.push_back(WGL_DRAW_TO_WINDOW_ARB); + out.push_back(GL_TRUE); + + out.push_back(WGL_DOUBLE_BUFFER_ARB); + out.push_back(GL_TRUE); + + out.push_back(WGL_ACCELERATION_ARB); + out.push_back(WGL_FULL_ACCELERATION_ARB); + + out.push_back(WGL_SWAP_METHOD_ARB); + out.push_back(swapMethod); + + if (stereoVisual) { + out.push_back(WGL_STEREO_ARB); + out.push_back(GL_TRUE); + } + + out.push_back(WGL_PIXEL_TYPE_ARB); + out.push_back(WGL_TYPE_RGBA_ARB); + + out.push_back(WGL_COLOR_BITS_ARB); + out.push_back(24); + + out.push_back(WGL_DEPTH_BITS_ARB); + out.push_back(24); + + if (needAlpha) { + out.push_back(WGL_ALPHA_BITS_ARB); + out.push_back(8); + } + + if (needStencil) { + out.push_back(WGL_STENCIL_BITS_ARB); + out.push_back(8); + } + + if (numOfAASamples > 0) { + out.push_back(WGL_SAMPLES_ARB); + out.push_back(numOfAASamples); + + out.push_back(WGL_SAMPLE_BUFFERS_ARB); + out.push_back(1); + } + + if (sRGB) { + out.push_back(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); + out.push_back(GL_TRUE); + } + + out.push_back(0); +} + + +int GHOST_ContextWGL::_choose_pixel_format_arb_2( + bool stereoVisual, + int numOfAASamples, + bool needAlpha, + bool needStencil, + bool sRGB, + int swapMethod) +{ + std::vector<int> iAttributes; + + int iPixelFormat = 0; + + int samples; + + // guard against some insanely high number of samples + if (numOfAASamples > 64) { + fprintf(stderr, "Warning! Clamping number of samples to 64.\n"); + samples = 64; + } + else { + samples = numOfAASamples; + } + + // request a format with as many samples as possible, but not more than requested + while (samples >= 0) { + makeAttribList( + iAttributes, + stereoVisual, + samples, + swapMethod, + needAlpha, + needStencil, + sRGB); + + UINT nNumFormats; + WIN32_CHK(wglChoosePixelFormatARB(m_hDC, &(iAttributes[0]), NULL, 1, &iPixelFormat, &nNumFormats)); + + /* total number of formats that match (regardless of size of iPixelFormat array) + * see: WGL_ARB_pixel_format extension spec */ + if (nNumFormats > 0) + break; + + /* if not reset, then the state of iPixelFormat is undefined after call to wglChoosePixelFormatARB + * see: WGL_ARB_pixel_format extension spec */ + iPixelFormat = 0; + + samples--; + } + + // check how many samples were actually gotten + if (iPixelFormat != 0) { + int iQuery[] = { WGL_SAMPLES_ARB }; + int actualSamples; + wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &actualSamples); + + if (actualSamples != numOfAASamples) { + fprintf(stderr, + "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " + "Substituting one that uses %d samples.\n", + numOfAASamples, actualSamples); + + m_numOfAASamples = actualSamples; // set context property to actual value + } + } + + return iPixelFormat; +} + + +int GHOST_ContextWGL::_choose_pixel_format_arb_1( + bool stereoVisual, + int numOfAASamples, + bool needAlpha, + bool needStencil, + bool sRGB, + int &swapMethodOut) +{ + int iPixelFormat; + + swapMethodOut = WGL_SWAP_COPY_ARB; + iPixelFormat = _choose_pixel_format_arb_2( + stereoVisual, numOfAASamples, needAlpha, needStencil, sRGB, swapMethodOut); + + if (iPixelFormat == 0) { + swapMethodOut = WGL_SWAP_UNDEFINED_ARB; + iPixelFormat = _choose_pixel_format_arb_2( + stereoVisual, numOfAASamples, needAlpha, needStencil, sRGB, swapMethodOut); + } + + if (iPixelFormat == 0) { + swapMethodOut = WGL_SWAP_EXCHANGE_ARB; + iPixelFormat = _choose_pixel_format_arb_2( + stereoVisual, numOfAASamples, needAlpha, needStencil, sRGB, swapMethodOut); + } + + return iPixelFormat; +} + + +int GHOST_ContextWGL::choose_pixel_format_arb( + bool stereoVisual, + int numOfAASamples, + bool needAlpha, + bool needStencil, + bool sRGB) +{ + int iPixelFormat; + int swapMethodOut; + + iPixelFormat = _choose_pixel_format_arb_1( + stereoVisual, + numOfAASamples, + needAlpha, + needStencil, + sRGB, + swapMethodOut); + + if (iPixelFormat == 0 && stereoVisual) { + fprintf(stderr, "Warning! Unable to find a stereo pixel format.\n"); + + iPixelFormat = _choose_pixel_format_arb_1( + false, + numOfAASamples, + needAlpha, + needStencil, + sRGB, + swapMethodOut); + + m_stereoVisual = false; // set context property to actual value + } + + if (swapMethodOut != WGL_SWAP_COPY_ARB) { + fprintf(stderr, + "Warning! Unable to find a pixel format that supports WGL_SWAP_COPY_ARB. " + "Substituting one that uses %s.\n", + swapMethodOut == WGL_SWAP_UNDEFINED_ARB ? "WGL_SWAP_UNDEFINED_ARB" : "WGL_SWAP_EXCHANGE_ARB"); + } + + return iPixelFormat; +} + + +int GHOST_ContextWGL::choose_pixel_format( + bool stereoVisual, + int numOfAASamples, + bool needAlpha, + bool needStencil, + bool sRGB) +{ + PIXELFORMATDESCRIPTOR preferredPFD = { + sizeof(PIXELFORMATDESCRIPTOR), /* size */ + 1, /* version */ + PFD_SUPPORT_OPENGL | + PFD_DRAW_TO_WINDOW | + PFD_SWAP_COPY | /* support swap copy */ + PFD_DOUBLEBUFFER | /* support double-buffering */ + (stereoVisual ? PFD_STEREO : 0), /* support stereo */ + PFD_TYPE_RGBA, /* color type */ + 24, /* preferred color depth */ + 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ + needAlpha ? 8 : 0, /* alpha buffer */ + 0, /* alpha shift (ignored) */ + 0, /* no accumulation buffer */ + 0, 0, 0, 0, /* accum bits (ignored) */ + 24, /* depth buffer */ + needStencil ? 8 : 0, /* stencil buffer */ + 0, /* no auxiliary buffers */ + PFD_MAIN_PLANE, /* main layer */ + 0, /* reserved */ + 0, 0, 0 /* layer, visible, and damage masks (ignored) */ + }; + + initContextWGLEW(preferredPFD); + + if (numOfAASamples > 0 && !WGLEW_ARB_multisample) { + fprintf(stderr, "Warning! Unable to request a multisample framebuffer.\n"); + numOfAASamples = 0; + } + + if (sRGB && !(WGLEW_ARB_framebuffer_sRGB || WGLEW_EXT_framebuffer_sRGB)) { + fprintf(stderr, "Warning! Unable to request an sRGB framebuffer.\n"); + sRGB = false; + } + + int iPixelFormat = 0; + + if (WGLEW_ARB_pixel_format) + iPixelFormat = choose_pixel_format_arb(stereoVisual, numOfAASamples, needAlpha, needStencil, sRGB); + + if (iPixelFormat == 0) + iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD); + + return iPixelFormat; +} + + +#ifndef NDEBUG +static void reportContextString(const char *name, const char *dummy, const char *context) +{ + fprintf(stderr, "%s: %s\n", name, context); + + if (strcmp(dummy, context) != 0) + fprintf(stderr, "Warning! Dummy %s: %s\n", name, dummy); +} +#endif + + +GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() +{ + SetLastError(NO_ERROR); + + HGLRC prevHGLRC = ::wglGetCurrentContext(); + WIN32_CHK(GetLastError() == NO_ERROR); + + HDC prevHDC = ::wglGetCurrentDC(); + WIN32_CHK(GetLastError() == NO_ERROR); + +#ifdef GHOST_OPENGL_ALPHA + const bool needAlpha = true; +#else + const bool needAlpha = false; +#endif + +#ifdef GHOST_OPENGL_STENCIL + const bool needStencil = true; +#else + const bool needStencil = false; +#endif + +#ifdef GHOST_OPENGL_SRGB + static const bool sRGB = true; +#else + static const bool sRGB = false; +#endif + + int iPixelFormat = choose_pixel_format(m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, sRGB); + + if (iPixelFormat == 0) + goto error; + + PIXELFORMATDESCRIPTOR chosenPFD; + + int lastPFD = ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD); + + if (!WIN32_CHK(lastPFD != 0)) + goto error; + + if (needAlpha && chosenPFD.cAlphaBits == 0) + fprintf(stderr, "Warning! Unable to find a pixel format with an alpha channel.\n"); + + if (needStencil && chosenPFD.cStencilBits == 0) + fprintf(stderr, "Warning! Unable to find a pixel format with a stencil buffer.\n"); + + if (!WIN32_CHK(::SetPixelFormat(m_hDC, iPixelFormat, &chosenPFD))) + goto error; + + activateWGLEW(); + + if (WGLEW_ARB_create_context) { + int profileBitCore = m_contextProfileMask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + int profileBitCompat = m_contextProfileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + +#ifdef WITH_GLEW_ES + int profileBitES = m_contextProfileMask & WGL_CONTEXT_ES_PROFILE_BIT_EXT; +#endif + + if (!WGLEW_ARB_create_context_profile && profileBitCore) + fprintf(stderr, "Warning! OpenGL core profile not available.\n"); + + if (!WGLEW_ARB_create_context_profile && profileBitCompat) + fprintf(stderr, "Warning! OpenGL compatibility profile not available.\n"); + +#ifdef WITH_GLEW_ES + if (!WGLEW_EXT_create_context_es_profile && profileBitES && m_contextMajorVersion == 1) + fprintf(stderr, "Warning! OpenGL ES profile not available.\n"); + + if (!WGLEW_EXT_create_context_es2_profile && profileBitES && m_contextMajorVersion == 2) + fprintf(stderr, "Warning! OpenGL ES2 profile not available.\n"); +#endif + + int profileMask = 0; + + if (WGLEW_ARB_create_context_profile && profileBitCore) + profileMask |= profileBitCore; + + if (WGLEW_ARB_create_context_profile && profileBitCompat) + profileMask |= profileBitCompat; + +#ifdef WITH_GLEW_ES + if (WGLEW_EXT_create_context_es_profile && profileBitES) + profileMask |= profileBitES; +#endif + + if (profileMask != m_contextProfileMask) + fprintf(stderr, "Warning! Ignoring untested OpenGL context profile mask bits."); + + std::vector<int> iAttributes; + + if (profileMask) { + iAttributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB); + iAttributes.push_back(profileMask); + } + + if (m_contextMajorVersion != 0) { + iAttributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB); + iAttributes.push_back(m_contextMajorVersion); + } + + if (m_contextMinorVersion != 0) { + iAttributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB); + iAttributes.push_back(m_contextMinorVersion); + } + + if (m_contextFlags != 0) { + iAttributes.push_back(WGL_CONTEXT_FLAGS_ARB); + iAttributes.push_back(m_contextFlags); + } + + if (m_contextResetNotificationStrategy != 0) { + if (WGLEW_ARB_create_context_robustness) { + iAttributes.push_back(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + iAttributes.push_back(m_contextResetNotificationStrategy); + } + else { + fprintf(stderr, "Warning! Cannot set the reset notification strategy."); + } + } + + iAttributes.push_back(0); + + if (!s_singleContextMode || s_sharedHGLRC == NULL) + m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0])); + else + m_hGLRC = s_sharedHGLRC; + } + else { + if (m_contextProfileMask != 0) + fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL profiles."); + + if (m_contextMajorVersion != 0 || m_contextMinorVersion != 0) + fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL versions."); + + if (m_contextFlags != 0) + fprintf(stderr, "Warning! Legacy WGL is unable to set context flags."); + + if (!s_singleContextMode || s_sharedHGLRC == NULL) + m_hGLRC = ::wglCreateContext(m_hDC); + else + m_hGLRC = s_sharedHGLRC; + } + + if (!WIN32_CHK(m_hGLRC != NULL)) + 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))) + goto error; + + if (!WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) + goto error; + + initContextGLEW(); + + initClearGL(); + ::SwapBuffers(m_hDC); + +#ifndef NDEBUG + reportContextString("Vendor", m_dummyVendor, reinterpret_cast<const char*>(glGetString(GL_VENDOR))); + reportContextString("Renderer", m_dummyRenderer, reinterpret_cast<const char*>(glGetString(GL_RENDERER))); + reportContextString("Version", m_dummyVersion, reinterpret_cast<const char*>(glGetString(GL_VERSION))); +#endif + + return GHOST_kSuccess; + +error: + ::wglMakeCurrent(prevHDC, prevHGLRC); + + return GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_ContextWGL::releaseNativeHandles() +{ + GHOST_TSuccess success = m_hGLRC != s_sharedHGLRC || s_sharedCount == 1 ? GHOST_kSuccess : GHOST_kFailure; + + m_hWnd = NULL; + m_hDC = NULL; + + return success; +} diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h new file mode 100644 index 00000000000..f2a5171c579 --- /dev/null +++ b/intern/ghost/intern/GHOST_ContextWGL.h @@ -0,0 +1,184 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_ContextWGL.h + * \ingroup GHOST + */ + +#ifndef __GHOST_CONTEXTWGL_H__ +#define __GHOST_CONTEXTWGL_H__ + +#include "GHOST_Context.h" + +#ifdef WITH_GLEW_MX +#define wglewGetContext() wglewContext +#endif + +#include <GL/wglew.h> + +#ifdef WITH_GLEW_MX +extern "C" WGLEWContext *wglewContext; +#endif + +#ifndef GHOST_OPENGL_WGL_CONTEXT_FLAGS +#define GHOST_OPENGL_WGL_CONTEXT_FLAGS 0 +#endif + +#ifndef GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY +#define GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY 0 +#endif + + +class GHOST_ContextWGL : public GHOST_Context +{ +public: + /** + * Constructor. + */ + GHOST_ContextWGL( + bool stereoVisual, + GHOST_TUns16 numOfAASamples, + HWND hWnd, + HDC hDC, + int contextProfileMask, + int contextMajorVersion, + int contextMinorVersion, + int contextFlags, + int contextResetNotificationStrategy); + + /** + * Destructor. + */ + virtual ~GHOST_ContextWGL(); + + /** + * Swaps front and back buffers of a window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Activates the drawing context of this window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Call immediately after new to initialize. If this fails then immediately delete the object. + * \return Indication as to whether initialization has succeeded. + */ + virtual GHOST_TSuccess initializeDrawingContext(); + + /** + * Removes references to native handles from this context and then returns + * \return GHOST_kSuccess if it is OK for the parent to release the handles and + * GHOST_kFailure if releasing the handles will interfere with sharing + */ + virtual GHOST_TSuccess releaseNativeHandles(); + + /** + * Sets the swap interval for swapBuffers. + * \param interval The swap interval to use. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess setSwapInterval(int interval); + + /** + * Gets the current swap interval for swapBuffers. + * \param intervalOut Variable to store the swap interval if it can be read. + * \return Whether the swap interval can be read. + */ + virtual GHOST_TSuccess getSwapInterval(int &intervalOut); + +protected: + inline void activateWGLEW() const { +#ifdef WITH_GLEW_MX + wglewContext = m_wglewContext; +#endif + } + +private: + int choose_pixel_format( + bool stereoVisual, + int numOfAASamples, + bool needAlpha, + bool needStencil, + bool sRGB); + + int choose_pixel_format_arb( + bool stereoVisual, + int numOfAASamples, + bool needAlpha, + bool needStencil, + bool sRGB); + + int _choose_pixel_format_arb_1( + bool stereoVisual, + int numOfAASamples, + bool needAlpha, + bool needStencil, + bool sRGB, + int &swapMethodOut); + + int _choose_pixel_format_arb_2( + bool stereoVisual, + int numOfAASamples, + bool needAlpha, + bool needStencil, + bool sRGB, + int swapMethod); + + void initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD); + + HDC m_hDC; + HWND m_hWnd; + + const int m_contextProfileMask; + const int m_contextMajorVersion; + const int m_contextMinorVersion; + const int m_contextFlags; + const int m_contextResetNotificationStrategy; + + HGLRC m_hGLRC; + +#ifdef WITH_GLEW_MX + WGLEWContext *m_wglewContext; +#endif + +#ifndef NDEBUG + const char *m_dummyVendor; + const char *m_dummyRenderer; + const char *m_dummyVersion; +#endif + + static HGLRC s_sharedHGLRC; + static int s_sharedCount; + + static bool s_singleContextMode; +}; + +#endif // __GHOST_CONTEXTWGL_H__ diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 009753cb29e..d7dd2b1cde1 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -38,21 +38,22 @@ #include "GHOST_ISystem.h" -#ifdef WITH_HEADLESS -# include "GHOST_SystemNULL.h" -#elif defined(WITH_GHOST_SDL) -# include "GHOST_SystemSDL.h" -#elif defined(WIN32) -# include "GHOST_SystemWin32.h" +#ifdef WITH_X11 +# include "GHOST_SystemX11.h" #else -# ifdef __APPLE__ -# include "GHOST_SystemCocoa.h" +# ifdef WITH_HEADLESS +# include "GHOST_SystemNULL.h" +# elif defined(WITH_GHOST_SDL) +# include "GHOST_SystemSDL.h" +# elif defined(WIN32) +# include "GHOST_SystemWin32.h" # else -# include "GHOST_SystemX11.h" +# ifdef __APPLE__ +# include "GHOST_SystemCocoa.h" +# endif # endif #endif - GHOST_ISystem *GHOST_ISystem::m_system = 0; @@ -60,19 +61,21 @@ GHOST_TSuccess GHOST_ISystem::createSystem() { GHOST_TSuccess success; if (!m_system) { -#ifdef WITH_HEADLESS +#ifdef WITH_X11 + m_system = new GHOST_SystemX11(); +#else +# ifdef WITH_HEADLESS m_system = new GHOST_SystemNULL(); -#elif defined(WITH_GHOST_SDL) +# elif defined(WITH_GHOST_SDL) m_system = new GHOST_SystemSDL(); -#elif defined(WIN32) +# elif defined(WIN32) m_system = new GHOST_SystemWin32(); -#else -# ifdef __APPLE__ - m_system = new GHOST_SystemCocoa(); # else - m_system = new GHOST_SystemX11(); +# ifdef __APPLE__ + m_system = new GHOST_SystemCocoa(); +# endif # endif -#endif +#endif success = m_system != 0 ? GHOST_kSuccess : GHOST_kFailure; } else { diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index ccbac91f0b4..236002e9744 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -254,27 +254,6 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction) } -#pragma mark defines for 10.6 api not documented in 10.5 - -#pragma mark Utility functions - -#define FIRSTFILEBUFLG 512 -static bool g_hasFirstFile = false; -static char g_firstFileBuf[512]; - -//TODO:Need to investigate this. Function called too early in creator.c to have g_hasFirstFile == true -extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) -{ - if (g_hasFirstFile) { - strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1); - buf[FIRSTFILEBUFLG - 1] = '\0'; - return 1; - } - else { - return 0; - } -} - #pragma mark Cocoa objects /** @@ -338,8 +317,6 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) #pragma mark initialization/finalization -char GHOST_user_locale[128]; // Global current user locale - GHOST_SystemCocoa::GHOST_SystemCocoa() { int mib[2]; @@ -377,15 +354,6 @@ GHOST_SystemCocoa::GHOST_SystemCocoa() rstring = NULL; m_ignoreWindowSizedMessages = false; - - //Get current locale - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - CFLocaleRef myCFLocale = CFLocaleCopyCurrent(); - NSLocale * myNSLocale = (NSLocale *) myCFLocale; - [myNSLocale autorelease]; - NSString *nsIdentifier = [myNSLocale localeIdentifier]; - strncpy(GHOST_user_locale, [nsIdentifier UTF8String], sizeof(GHOST_user_locale) - 1); - [pool drain]; } GHOST_SystemCocoa::~GHOST_SystemCocoa() @@ -567,25 +535,21 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow( window = new GHOST_WindowCocoa (this, title, left, bottom, width, height, state, type, stereoVisual, numOfAASamples); - if (window) { - if (window->getValid()) { - // Store the pointer to the window - GHOST_ASSERT(m_windowManager, "m_windowManager not initialized"); - m_windowManager->addWindow(window); - m_windowManager->setActiveWindow(window); - //Need to tell window manager the new window is the active one (Cocoa does not send the event activate upon window creation) - pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window)); - pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); - } - else { - GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n"); - delete window; - window = 0; - } + if (window->getValid()) { + // Store the pointer to the window + GHOST_ASSERT(m_windowManager, "m_windowManager not initialized"); + m_windowManager->addWindow(window); + m_windowManager->setActiveWindow(window); + //Need to tell window manager the new window is the active one (Cocoa does not send the event activate upon window creation) + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window)); + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); } else { - GHOST_PRINT("GHOST_SystemCocoa::createWindow(): could not create window\n"); + GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n"); + delete window; + window = 0; } + [pool drain]; return window; } diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 3b95373f800..0767ad5a8f9 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -231,44 +231,36 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow( GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, GHOST_TDrawingContextType type, - bool stereoVisual, + bool wantStereoVisual, const bool exclusive, - const GHOST_TUns16 numOfAASamples, + const GHOST_TUns16 wantNumOfAASamples, const GHOST_TEmbedderWindowID parentWindow) { - GHOST_Window *window = 0; - window = new GHOST_WindowWin32(this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples, parentWindow); - if (window) { - if (window->getValid()) { - // Store the pointer to the window -// if (state != GHOST_kWindowStateFullScreen) { - m_windowManager->addWindow(window); - m_windowManager->setActiveWindow(window); -// } - } - else { - - // Invalid parent window hwnd - if (((GHOST_WindowWin32 *)window)->getNextWindow() == NULL) { - delete window; - window = 0; - return window; - } - - // An invalid window could be one that was used to test for AA - window = ((GHOST_WindowWin32 *)window)->getNextWindow(); - - // If another window is found, let the wm know about that one, but not the old one - if (window->getValid()) { - m_windowManager->addWindow(window); - } - else { - delete window; - window = 0; - } - - } + GHOST_Window *window = + new GHOST_WindowWin32( + this, + title, + left, + top, + width, + height, + state, + type, + wantStereoVisual, + wantNumOfAASamples, + parentWindow); + + if (window->getValid()) { + // Store the pointer to the window + m_windowManager->addWindow(window); + m_windowManager->setActiveWindow(window); } + else { + GHOST_PRINT("GHOST_SystemWin32::createWindow(): window invalid\n"); + delete window; + window = 0; + } + return window; } diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index f797d8074e1..75a9223d6a3 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -55,6 +55,7 @@ #include <X11/Xatom.h> #include <X11/keysym.h> #include <X11/XKBlib.h> /* allow detectable autorepeate */ +#include <X11/Xutil.h> #ifdef WITH_XF86KEYSYM #include <X11/XF86keysym.h> diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index a21300e36f0..be149cbb773 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -34,7 +34,6 @@ #define __GHOST_SYSTEMX11_H__ #include <X11/Xlib.h> -#include <GL/glx.h> #include "GHOST_System.h" #include "../GHOST_Types.h" diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp index 3673831c7b1..dd6154a42bb 100644 --- a/intern/ghost/intern/GHOST_Window.cpp +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -38,21 +38,23 @@ #include "GHOST_Window.h" +#include "GHOST_ContextNone.h" + #include <assert.h> GHOST_Window::GHOST_Window( GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, - const bool stereoVisual, + const bool wantStereoVisual, const bool exclusive, - const GHOST_TUns16 numOfAASamples) - : m_drawingContextType(type), + const GHOST_TUns16 wantNumOfAASamples) + : m_drawingContextType(GHOST_kDrawingContextTypeNone), m_cursorVisible(true), m_cursorGrab(GHOST_kGrabDisable), m_cursorShape(GHOST_kStandardCursorDefault), - m_stereoVisual(stereoVisual), - m_numOfAASamples(numOfAASamples) + m_wantStereoVisual(wantStereoVisual), + m_wantNumOfAASamples(wantNumOfAASamples), + m_context(new GHOST_ContextNone(false, 0)) { m_isUnsavedChanges = false; m_canAcceptDragOperation = false; @@ -74,6 +76,7 @@ GHOST_Window::GHOST_Window( GHOST_Window::~GHOST_Window() { + delete m_context; } void *GHOST_Window::getOSWindow() const @@ -83,18 +86,61 @@ void *GHOST_Window::getOSWindow() const GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType type) { - GHOST_TSuccess success = GHOST_kSuccess; if (type != m_drawingContextType) { - success = removeDrawingContext(); - if (success) { - success = installDrawingContext(type); + delete m_context; + m_context = NULL; + + if (type != GHOST_kDrawingContextTypeNone) + m_context = newDrawingContext(type); + + if (m_context != NULL) { m_drawingContextType = type; } else { + m_context = new GHOST_ContextNone(m_wantStereoVisual, m_wantNumOfAASamples); m_drawingContextType = GHOST_kDrawingContextTypeNone; } + + return (type == m_drawingContextType) ? GHOST_kSuccess : GHOST_kFailure; + } + else { + return GHOST_kSuccess; } - return success; +} + +GHOST_TSuccess GHOST_Window::swapBuffers() +{ + return m_context->swapBuffers(); +} + +GHOST_TSuccess GHOST_Window::setSwapInterval(int interval) +{ + return m_context->setSwapInterval(interval); +} + +GHOST_TSuccess GHOST_Window::getSwapInterval(int& intervalOut) +{ + return m_context->getSwapInterval(intervalOut); +} + +GHOST_TUns16 GHOST_Window::getNumOfAASamples() +{ + return m_context->getNumOfAASamples(); +} + +GHOST_TSuccess GHOST_Window::activateDrawingContext() +{ + return m_context->activateDrawingContext(); +} + +GHOST_TSuccess GHOST_Window::updateDrawingContext() +{ + return m_context->updateDrawingContext(); +} + +GHOST_TSuccess GHOST_Window::releaseNativeHandles() +{ + return m_context->releaseNativeHandles(); } GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible) diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 77ee4db8543..e470e40d43a 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -36,6 +36,7 @@ #include "GHOST_IWindow.h" class STR_String; +class GHOST_Context; /** * Platform independent implementation of GHOST_IWindow. @@ -49,29 +50,6 @@ class STR_String; class GHOST_Window : public GHOST_IWindow { public: - /** - * \section Interface inherited from GHOST_IWindow left for derived class - * implementation. - * virtual bool getValid() const = 0; - * virtual void setTitle(const STR_String& title) = 0; - * virtual void getTitle(STR_String& title) const = 0; - * virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; - * virtual void getClientBounds(GHOST_Rect& bounds) const = 0; - * virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; - * virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; - * virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; - * virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; - * virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; - * virtual GHOST_TWindowState getState() const = 0; - * virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; - * virtual GHOST_TWindowOrder getOrder(void) = 0; - * virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; - * virtual GHOST_TSuccess swapBuffers() = 0; - * virtual GHOST_TSuccess setSwapInterval() = 0; - * virtual int getSwapInterval() = 0; - * virtual GHOST_TSuccess activateDrawingContext() = 0; - * virtual GHOST_TSuccess invalidate() = 0; - */ /** * Constructor. @@ -90,10 +68,9 @@ public: GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, - GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, - const bool stereoVisual = false, + const bool wantStereoVisual = false, const bool exclusive = false, - const GHOST_TUns16 numOfAASamples = 0); + const GHOST_TUns16 wantNumOfAASamples = 0); /** * \section Interface inherited from GHOST_IWindow left for derived class @@ -113,7 +90,7 @@ public: * virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; * virtual GHOST_TSuccess swapBuffers() = 0; * virtual GHOST_TSuccess setSwapInterval() = 0; - * virtual int getSwapInterval() = 0; + * virtual GHOST_TSuccess getSwapInterval(int& intervalOut) = 0; * virtual GHOST_TSuccess activateDrawingContext() = 0; * virtual GHOST_TSuccess invalidate() = 0; */ @@ -125,6 +102,14 @@ public: virtual ~GHOST_Window(); /** + * Returns indication as to whether the window is valid. + * \return The validity of the window. + */ + virtual bool getValid() const { + return m_context != 0; + } + + /** * Returns the associated OS object/handle * \return The associated OS object/handle */ @@ -213,18 +198,20 @@ public: * \param interval The swap interval to use. * \return A boolean success indicator. */ - virtual GHOST_TSuccess setSwapInterval(int interval) { - return GHOST_kFailure; - } - + virtual GHOST_TSuccess setSwapInterval(int interval); + /** * Gets the current swap interval for swapBuffers. * \return An integer. */ - virtual int getSwapInterval() { - return 0; - } - + virtual GHOST_TSuccess getSwapInterval(int& intervalOut); + + /** + * Gets the current swap interval for swapBuffers. + * \return Number of AA Samples (0 if there is no multisample buffer) + */ + virtual GHOST_TUns16 getNumOfAASamples(); + /** * Tells if the ongoing drag'n'drop object can be accepted upon mouse drop */ @@ -257,14 +244,33 @@ public: /** * Tries to install a rendering context in this window. - * Child classes do not need to overload this method. - * They should overload the installDrawingContext and removeDrawingContext instead. + * Child classes do not need to overload this method, + * They should overload newDrawingContext instead. * \param type The type of rendering context installed. * \return Indication as to whether installation has succeeded. */ virtual GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type); /** + * Swaps front and back buffers of a window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Activates the drawing context of this window. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Updates the drawing context of this window. Needed + * whenever the window is changed. + * \return Indication of success. + */ + virtual GHOST_TSuccess updateDrawingContext(); + + /** * Returns the window user data. * \return The window user data. */ @@ -295,13 +301,7 @@ protected: * \param type The type of rendering context installed. * \return Indication as to whether installation has succeeded. */ - virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type) = 0; - - /** - * Removes the current drawing context. - * \return Indication as to whether removal has succeeded. - */ - virtual GHOST_TSuccess removeDrawingContext() = 0; + virtual GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type) = 0; /** * Sets the cursor visibility on the window using @@ -333,6 +333,9 @@ protected: virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, int szx, int szy, int hotX, int hotY, int fg, int bg) = 0; + + GHOST_TSuccess releaseNativeHandles(); + /** The the of drawing context installed in this window. */ GHOST_TDrawingContextType m_drawingContextType; @@ -369,14 +372,11 @@ protected: /** Stores whether this is a full screen window. */ bool m_fullScreen; - /** Stereo visual created. Only necessary for 'real' stereo support, - * ie quad buffered stereo. This is not always possible, depends on - * the graphics h/w - */ - bool m_stereoVisual; - - /** Number of samples used in anti-aliasing, set to 0 if no AA **/ - GHOST_TUns16 m_numOfAASamples; + /** Whether to attempt to initialize a context with a stereo framebuffer. */ + bool m_wantStereoVisual; + + /** Attempt to initialize a context with this many samples. */ + GHOST_TUns16 m_wantNumOfAASamples; /** Full-screen width */ GHOST_TUns32 m_fullScreenWidth; @@ -385,6 +385,9 @@ protected: /* OSX only, retina screens */ float m_nativePixelSize; + +private: + GHOST_Context *m_context; }; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index b30f6a340ad..1b6e8e63178 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -42,6 +42,8 @@ @class CocoaWindow; @class CocoaOpenGLView; +@class NSCursor; +@class NSScreen; class GHOST_SystemCocoa; @@ -53,6 +55,7 @@ class GHOST_SystemCocoa; * which is called the gutter. * When OpenGL contexts are active, GHOST will use AGL_BUFFER_RECT to prevent * OpenGL drawing outside the reduced client rectangle. + * XXX jwilkins: This comment seems out of date since we neither use Carbon nor AGL * \author Maarten Gribnau * \date May 23, 2001 */ @@ -220,28 +223,8 @@ public: */ virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order); - /** - * Swaps front and back buffers of a window. - * \return A boolean success indicator. - */ - virtual GHOST_TSuccess swapBuffers(); - - /** - * Updates the drawing context of this window. Needed - * whenever the window is changed. - * \return Indication of success. - */ - GHOST_TSuccess updateDrawingContext(); - - /** - * Activates the drawing context of this window. - * \return A boolean success indicator. - */ - virtual GHOST_TSuccess activateDrawingContext(); - virtual void loadCursor(bool visible, GHOST_TStandardCursor cursor) const; - const GHOST_TabletData *GetTabletData() { return &m_tablet; @@ -278,19 +261,13 @@ public: bool getImmediateDraw(void) const { return m_immediateDraw; } protected: - /** - * Tries to install a rendering context in this window. - * \param type The type of rendering context installed. - * \return Indication as to whether installation has succeeded. - */ - virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); /** - * Removes the current drawing context. - * \return Indication as to whether removal has succeeded. + * \param type The type of rendering context create. + * \return Indication of success. */ - virtual GHOST_TSuccess removeDrawingContext(); - + virtual GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type); + /** * Invalidates the contents of this window. * \return Indication of success. @@ -330,15 +307,9 @@ protected: /** The openGL view */ CocoaOpenGLView *m_openGLView; - /** The opgnGL drawing context */ - NSOpenGLContext *m_openGLContext; - /** The mother SystemCocoa class to send events */ GHOST_SystemCocoa *m_systemCocoa; - - /** The first created OpenGL context (for sharing display lists) */ - static NSOpenGLContext *s_firstOpenGLcontext; - + NSCursor *m_customCursor; GHOST_TabletData m_tablet; @@ -349,4 +320,3 @@ protected: }; #endif // __GHOST_WINDOWCOCOA_H__ - diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index f9b8899fbe5..52436d38e5c 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -20,30 +20,33 @@ * * The Original Code is: all of this file. * - * Contributor(s): Maarten Gribnau 05/2001 - Damien Plisson 10/2009 + * Contributor(s): Maarten Gribnau 05/2001 + * Damien Plisson 10/2009 + * Jason Wilkins 02/2014 * * ***** END GPL LICENSE BLOCK ***** */ +#include "GHOST_WindowCocoa.h" +#include "GHOST_SystemCocoa.h" +#include "GHOST_ContextNone.h" +#include "GHOST_Debug.h" + +#if defined(WITH_GL_EGL) +# include "GHOST_ContextEGL.h" +#else +# include "GHOST_ContextCGL.h" +#endif + #include <Cocoa/Cocoa.h> #if MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 -//Use of the SetSystemUIMode function (64bit compatible) -#include <Carbon/Carbon.h> + //Use of the SetSystemUIMode function (64bit compatible) +# include <Carbon/Carbon.h> #endif -#include <OpenGL/gl.h> -#include <OpenGL/CGLRenderers.h> -/***** Multithreaded opengl code : uncomment for enabling -#include <OpenGL/OpenGL.h> -*/ -#include "GHOST_WindowCocoa.h" -#include "GHOST_SystemCocoa.h" -#include "GHOST_Debug.h" - #include <sys/sysctl.h> #if MAC_OS_X_VERSION_MAX_ALLOWED < 1070 @@ -535,8 +538,6 @@ enum { @end #endif -NSOpenGLContext* GHOST_WindowCocoa::s_firstOpenGLcontext = nil; - GHOST_WindowCocoa::GHOST_WindowCocoa( GHOST_SystemCocoa *systemCocoa, const STR_String& title, @@ -548,13 +549,9 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( GHOST_TDrawingContextType type, const bool stereoVisual, const GHOST_TUns16 numOfAASamples ) : - GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, false, numOfAASamples), + GHOST_Window(width, height, state, stereoVisual, false, numOfAASamples), m_customCursor(0) { - NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40]; - NSOpenGLPixelFormat *pixelFormat = nil; - int i; - m_systemCocoa = systemCocoa; m_fullScreen = false; m_immediateDraw = false; @@ -586,104 +583,10 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( minSize.height = 240; [m_window setContentMinSize:minSize]; - setTitle(title); - - - // Pixel Format Attributes for the windowed NSOpenGLContext - i=0; - pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer; - - // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object's flushBuffer - // needed for 'Draw Overlap' drawing method - pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; - - // Force software OpenGL, for debugging - if (getenv("BLENDER_SOFTWAREGL")) { - pixelFormatAttrsWindow[i++] = NSOpenGLPFARendererID; - pixelFormatAttrsWindow[i++] = kCGLRendererAppleSWID; - } - else - pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated; - - //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway - - pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize; - pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; - - pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccumSize; - pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; - - if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo; - - if (numOfAASamples > 0) { - // Multisample anti-aliasing - pixelFormatAttrsWindow[i++] = NSOpenGLPFAMultisample; - - pixelFormatAttrsWindow[i++] = NSOpenGLPFASampleBuffers; - pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 1; - - pixelFormatAttrsWindow[i++] = NSOpenGLPFASamples; - pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) numOfAASamples; - - pixelFormatAttrsWindow[i++] = NSOpenGLPFANoRecovery; - } - - pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0; - - pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow]; - - - //Fall back to no multisampling if Antialiasing init failed - if (pixelFormat == nil) { - i=0; - pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer; - - // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object's flushBuffer - // needed for 'Draw Overlap' drawing method - pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; - - // Force software OpenGL, for debugging - if (getenv("BLENDER_SOFTWAREGL")) { - pixelFormatAttrsWindow[i++] = NSOpenGLPFARendererID; - pixelFormatAttrsWindow[i++] = kCGLRendererAppleSWID; - } - else - pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated; - - //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway - - pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize; - pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; - - pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccumSize; - pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; - - if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo; - - pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0; - - pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow]; - - } - - if (numOfAASamples > 0) { //Set m_numOfAASamples to the actual value - GLint gli; - [pixelFormat getValues:&gli forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; - if (m_numOfAASamples != (GHOST_TUns16)gli) { - m_numOfAASamples = (GHOST_TUns16)gli; - printf("GHOST_Window could be created with anti-aliasing of only %i samples\n",m_numOfAASamples); - } - } - //Creates the OpenGL View inside the window - m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect - pixelFormat:pixelFormat]; - - [m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; - - [pixelFormat release]; + m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect]; - m_openGLContext = [m_openGLView openGLContext]; //This context will be replaced by the proper one just after + [m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; [m_window setContentView:m_openGLView]; [m_window setInitialFirstResponder:m_openGLView]; @@ -694,6 +597,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( updateDrawingContext(); activateDrawingContext(); + // XXX jwilkins: This seems like it belongs in GHOST_ContextCGL, but probably not GHOST_ContextEGL if (m_systemCocoa->m_nativePixel) { if ([m_openGLView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) { [m_openGLView setWantsBestResolutionOpenGLSurface:YES]; @@ -703,6 +607,8 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( } } + setTitle(title); + m_tablet.Active = GHOST_kTabletModeNone; CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init]; @@ -750,6 +656,8 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa() m_customCursor = nil; } + releaseNativeHandles(); + [m_openGLView release]; if (m_window) { @@ -774,7 +682,7 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa() bool GHOST_WindowCocoa::getValid() const { - return (m_window != 0); + return GHOST_Window::getValid() && m_window != 0 && m_openGLView != 0; } void* GHOST_WindowCocoa::getOSWindow() const @@ -1266,131 +1174,95 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) #pragma mark Drawing context -/*#define WAIT_FOR_VSYNC 1*/ - -GHOST_TSuccess GHOST_WindowCocoa::swapBuffers() -{ - if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { - if (m_openGLContext != nil) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [m_openGLContext flushBuffer]; - [pool drain]; - return GHOST_kSuccess; - } - } - return GHOST_kFailure; -} - -GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext() -{ - if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { - if (m_openGLContext != nil) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [m_openGLContext update]; - [pool drain]; - return GHOST_kSuccess; - } - } - return GHOST_kFailure; -} +GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type) +{ + if (type == GHOST_kDrawingContextTypeOpenGL) { +#if !defined(WITH_GL_EGL) + +#if defined(WITH_GL_PROFILE_CORE) + GHOST_Context *context = new GHOST_ContextCGL( + m_initStereoVisual, + m_initNumOfAASamples, + m_window, + m_openGLView, + CGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 3, 2, + GHOST_OPENGL_CGL_CONTEXT_FLAGS, + GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); +#elif defined(WITH_GL_PROFILE_ES20) + GHOST_Context *context = new GHOST_ContextCGL( + m_initStereoVisual, + m_initNumOfAASamples, + m_window, + m_openGLView, + CGL_CONTEXT_ES2_PROFILE_BIT_EXT, + 2, 0, + GHOST_OPENGL_CGL_CONTEXT_FLAGS, + GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); +#elif defined(WITH_GL_PROFILE_COMPAT) + GHOST_Context *context = new GHOST_ContextCGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_openGLView, + 0, // profile bit + 0, 0, + GHOST_OPENGL_CGL_CONTEXT_FLAGS, + GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); +#else +# error +#endif -GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext() -{ - if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { - if (m_openGLContext != nil) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [m_openGLContext makeCurrentContext]; - - // Disable AA by default - if (m_numOfAASamples > 0) glDisable(GL_MULTISAMPLE_ARB); - [pool drain]; - return GHOST_kSuccess; - } - } - return GHOST_kFailure; -} +#else +#if defined(WITH_GL_PROFILE_CORE) + GHOST_Context *context = new GHOST_ContextEGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_openGLView, + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 3, 2, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); +#elif defined(WITH_GL_PROFILE_ES20) + GHOST_Context *context = new GHOST_ContextEGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_openGLView, + 0, // profile bit + 2, 0, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_ES_API); +#elif defined(WITH_GL_PROFILE_COMPAT) + GHOST_Context *context = new GHOST_ContextEGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_openGLView, + 0, // profile bit + 0, 0, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); +#else +# error +#endif -GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type) -{ - GHOST_TSuccess success = GHOST_kFailure; - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSOpenGLPixelFormat *pixelFormat; - NSOpenGLContext *tmpOpenGLContext; - - /***** Multithreaded opengl code : uncomment for enabling - CGLContextObj cglCtx; - */ - - switch (type) { - case GHOST_kDrawingContextTypeOpenGL: - if (!getValid()) break; - - pixelFormat = [m_openGLView pixelFormat]; - tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat - shareContext:s_firstOpenGLcontext]; - if (tmpOpenGLContext == nil) { - success = GHOST_kFailure; - break; - } - - //Switch openGL to multhreaded mode - /******* Multithreaded opengl code : uncomment for enabling - cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj]; - if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError) - printf("\nSwitched openGL to multithreaded mode\n"); - */ - - if (!s_firstOpenGLcontext) s_firstOpenGLcontext = tmpOpenGLContext; -#ifdef WAIT_FOR_VSYNC - { - GLint swapInt = 1; - /* wait for vsync, to avoid tearing artifacts */ - [tmpOpenGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; - } #endif - [m_openGLView setOpenGLContext:tmpOpenGLContext]; - [tmpOpenGLContext setView:m_openGLView]; - - m_openGLContext = tmpOpenGLContext; - break; - - case GHOST_kDrawingContextTypeNone: - success = GHOST_kSuccess; - break; - - default: - break; + if (context->initializeDrawingContext()) + return context; + else + delete context; } - [pool drain]; - return success; -} - -GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext() -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - switch (m_drawingContextType) { - case GHOST_kDrawingContextTypeOpenGL: - if (m_openGLContext) { - [m_openGLView clearGLContext]; - if (s_firstOpenGLcontext == m_openGLContext) s_firstOpenGLcontext = nil; - m_openGLContext = nil; - } - [pool drain]; - return GHOST_kSuccess; - case GHOST_kDrawingContextTypeNone: - [pool drain]; - return GHOST_kSuccess; - break; - default: - [pool drain]; - return GHOST_kFailure; - } + return NULL; } +#pragma mark invalidate GHOST_TSuccess GHOST_WindowCocoa::invalidate() { diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp index 4a1086144f4..1335c38d977 100644 --- a/intern/ghost/intern/GHOST_WindowSDL.cpp +++ b/intern/ghost/intern/GHOST_WindowSDL.cpp @@ -26,10 +26,11 @@ #include "GHOST_WindowSDL.h" #include "SDL_mouse.h" -#include <GL/glew.h> -#include <assert.h> +#include "glew-mx.h" + +#include "GHOST_ContextSDL.h" -static SDL_GLContext s_firstContext = NULL; +#include <assert.h> GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system, const STR_String& title, @@ -44,39 +45,29 @@ GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system, const bool exclusive, const GHOST_TUns16 numOfAASamples ) - : - GHOST_Window(width, height, state, type, stereoVisual, exclusive, numOfAASamples), - m_system(system), - m_invalid_window(false), - m_sdl_custom_cursor(NULL) + : GHOST_Window(width, height, state, stereoVisual, exclusive, numOfAASamples), + m_system(system), + m_valid_setup(false), + m_invalid_window(false), + m_sdl_custom_cursor(NULL) { - SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - - if (numOfAASamples) { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, numOfAASamples); - } /* creating the window _must_ come after setting attributes */ - m_sdl_win = SDL_CreateWindow(title, - left, - top, - width, - height, - SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); - - - - m_sdl_glcontext = SDL_GL_CreateContext(m_sdl_win); + m_sdl_win = SDL_CreateWindow( + title, + left, top, + width, height, + SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); + + /* now set up the rendering context. */ + if (setDrawingContextType(type) == GHOST_kSuccess) { + m_valid_setup = true; + GHOST_PRINT("Created window\n"); + } - //fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n", - // theEvent->error_code, theEvent->request_code); + if (exclusive) { + SDL_RaiseWindow(m_sdl_win); + } setTitle(title); } @@ -87,64 +78,38 @@ GHOST_WindowSDL::~GHOST_WindowSDL() SDL_FreeCursor(m_sdl_custom_cursor); } - if (m_sdl_glcontext != s_firstContext) { - SDL_GL_DeleteContext(m_sdl_glcontext); - } + releaseNativeHandles(); SDL_DestroyWindow(m_sdl_win); } -GHOST_TSuccess -GHOST_WindowSDL::installDrawingContext(GHOST_TDrawingContextType type) +GHOST_Context * +GHOST_WindowSDL::newDrawingContext(GHOST_TDrawingContextType type) { - // only support openGL for now. - GHOST_TSuccess success; - switch (type) { - case GHOST_kDrawingContextTypeOpenGL: - m_sdl_glcontext = SDL_GL_CreateContext(m_sdl_win); - - if (m_sdl_glcontext != NULL) { - if (!s_firstContext) { - s_firstContext = m_sdl_glcontext; - } - - success = (SDL_GL_MakeCurrent(m_sdl_win, m_sdl_glcontext) < 0) ? - GHOST_kFailure : GHOST_kSuccess; - } - else { - success = GHOST_kFailure; - } - - break; - - case GHOST_kDrawingContextTypeNone: - success = GHOST_kSuccess; - break; - - default: - success = GHOST_kFailure; + if (type == GHOST_kDrawingContextTypeOpenGL) { + GHOST_Context *context = new GHOST_ContextSDL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_sdl_win, + 0, // profile bit + 0, 0, + GHOST_OPENGL_SDL_CONTEXT_FLAGS, + GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY); + + if (context->initializeDrawingContext()) + return context; + else + delete context; } - return success; + + return NULL; } GHOST_TSuccess GHOST_WindowSDL::invalidate(void) { - // So the idea of this function is to generate an expose event - // for the window. - // Unfortunately X does not handle expose events for you and - // it is the client's job to refresh the dirty part of the window. - // We need to queue up invalidate calls and generate GHOST events - // for them in the system. - - // We implement this by setting a boolean in this class to concatenate - // all such calls into a single event for this window. - - // At the same time we queue the dirty windows in the system class - // and generate events for them at the next processEvents call. - if (m_invalid_window == false) { m_system->addDirtyWindow(this); m_invalid_window = true; @@ -153,52 +118,6 @@ GHOST_WindowSDL::invalidate(void) return GHOST_kSuccess; } - -GHOST_TSuccess -GHOST_WindowSDL::swapBuffers() -{ - if (getDrawingContextType() == GHOST_kDrawingContextTypeOpenGL) { - SDL_GL_SwapWindow(m_sdl_win); - return GHOST_kSuccess; - } - else { - return GHOST_kFailure; - } -} - - -GHOST_TSuccess -GHOST_WindowSDL::activateDrawingContext() -{ - if (m_sdl_glcontext != NULL) { - int status = SDL_GL_MakeCurrent(m_sdl_win, m_sdl_glcontext); - (void)status; - /* Disable AA by default */ - if (m_numOfAASamples > 0) { - glDisable(GL_MULTISAMPLE_ARB); - } - return GHOST_kSuccess; - } - return GHOST_kFailure; -} - - -GHOST_TSuccess -GHOST_WindowSDL::removeDrawingContext() -{ - GHOST_TSuccess success; - - if (m_sdl_glcontext != NULL) { - SDL_GL_DeleteContext(m_sdl_glcontext); - success = GHOST_kSuccess; - } - else { - success = GHOST_kFailure; - } - return success; -} - - GHOST_TSuccess GHOST_WindowSDL::setState(GHOST_TWindowState state) { @@ -236,6 +155,12 @@ GHOST_WindowSDL::getState() const return GHOST_kWindowStateNormal; } +bool +GHOST_WindowSDL:: +getValid() const +{ + return GHOST_Window::getValid() && m_valid_setup; +} void GHOST_WindowSDL::setTitle(const STR_String& title) @@ -638,16 +563,3 @@ GHOST_WindowSDL::setWindowCursorVisibility(bool visible) SDL_ShowCursor(visible); return GHOST_kSuccess; } - -GHOST_TSuccess -GHOST_WindowSDL::setSwapInterval(int interval) -{ - SDL_GL_SetSwapInterval(interval); - return GHOST_kSuccess; -} - -int -GHOST_WindowSDL::getSwapInterval() -{ - return SDL_GL_GetSwapInterval(); -} diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h index 0c11ce19b50..d446c220c2e 100644 --- a/intern/ghost/intern/GHOST_WindowSDL.h +++ b/intern/ghost/intern/GHOST_WindowSDL.h @@ -30,6 +30,7 @@ #include "GHOST_Window.h" #include "GHOST_SystemSDL.h" + #include <map> extern "C" { @@ -47,10 +48,10 @@ class GHOST_WindowSDL : public GHOST_Window { private: GHOST_SystemSDL *m_system; + bool m_valid_setup; bool m_invalid_window; SDL_Window *m_sdl_win; - SDL_GLContext m_sdl_glcontext; SDL_Cursor *m_sdl_custom_cursor; public: @@ -93,17 +94,18 @@ public: m_invalid_window = false; } - bool getValid() const - { - return (m_sdl_win != NULL); - } + bool getValid() const; void getWindowBounds(GHOST_Rect& bounds) const; void getClientBounds(GHOST_Rect& bounds) const; protected: - GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); - GHOST_TSuccess removeDrawingContext(); + + /** + * \param type The type of rendering context create. + * \return Indication of success. + */ + virtual GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type); GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode); @@ -151,12 +153,6 @@ protected: GHOST_TInt32& outX, GHOST_TInt32& outY) const; GHOST_TSuccess - swapBuffers(); - - GHOST_TSuccess - activateDrawingContext(); - - GHOST_TSuccess setState(GHOST_TWindowState state); GHOST_TWindowState @@ -172,9 +168,6 @@ protected: GHOST_TSuccess beginFullScreen() const { return GHOST_kFailure; } GHOST_TSuccess endFullScreen() const { return GHOST_kFailure; } - - GHOST_TSuccess setSwapInterval(int interval); - int getSwapInterval(); }; diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 8e7e824186c..64ea7192616 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -29,82 +29,33 @@ * \ingroup GHOST */ -#include <string.h> +#define _USE_MATH_DEFINES + #include "GHOST_WindowWin32.h" #include "GHOST_SystemWin32.h" #include "GHOST_DropTargetWin32.h" +#include "GHOST_ContextNone.h" #include "utfconv.h" #include "utf_winfunc.h" -// Need glew for some defines -#include <GL/glew.h> -#include <GL/wglew.h> +#if defined(WITH_GL_EGL) +# include "GHOST_ContextEGL.h" +#else +# include "GHOST_ContextWGL.h" +#endif + + #include <math.h> +#include <string.h> +#include <assert.h> -// MSVC6 still doesn't define M_PI -#ifndef M_PI -# define M_PI 3.1415926536 -#endif -// Some more multisample defines -#define WGL_SAMPLE_BUFFERS_ARB 0x2041 -#define WGL_SAMPLES_ARB 0x2042 const wchar_t *GHOST_WindowWin32::s_windowClassName = L"GHOST_WindowClass"; const int GHOST_WindowWin32::s_maxTitleLength = 128; -HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL; -HDC GHOST_WindowWin32::s_firstHDC = NULL; - -static int WeightPixelFormat(PIXELFORMATDESCRIPTOR &pfd); -static int EnumPixelFormats(HDC hdc); -/* - * Color and depth bit values are not to be trusted. - * For instance, on TNT2: - * When the screen color depth is set to 16 bit, we get 5 color bits - * and 16 depth bits. - * When the screen color depth is set to 32 bit, we get 8 color bits - * and 24 depth bits. - * Just to be safe, we request high quality settings. - */ -static PIXELFORMATDESCRIPTOR sPreferredFormat = { - sizeof(PIXELFORMATDESCRIPTOR), /* size */ - 1, /* version */ - PFD_SUPPORT_OPENGL | - PFD_DRAW_TO_WINDOW | - PFD_SWAP_COPY | /* support swap copy */ - PFD_DOUBLEBUFFER, /* support double-buffering */ - PFD_TYPE_RGBA, /* color type */ - 32, /* prefered color depth */ - 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ - 0, /* no alpha buffer */ - 0, /* alpha bits (ignored) */ - 0, /* no accumulation buffer */ - 0, 0, 0, 0, /* accum bits (ignored) */ - 32, /* depth buffer */ - 0, /* no stencil buffer */ - 0, /* no auxiliary buffers */ - PFD_MAIN_PLANE, /* main layer */ - 0, /* reserved */ - 0, 0, 0 /* no layer, visible, damage masks */ -}; - -/* Intel videocards 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. */ -static int is_crappy_intel_card(void) -{ - static short is_crappy = -1; - if (is_crappy == -1) { - const char *vendor = (const char *)glGetString(GL_VENDOR); - is_crappy = (strstr(vendor, "Intel") != NULL); - } - return is_crappy; -} /* force NVidia Optimus to used dedicated graphics */ extern "C" { @@ -120,17 +71,14 @@ GHOST_WindowWin32::GHOST_WindowWin32( GHOST_TUns32 height, GHOST_TWindowState state, GHOST_TDrawingContextType type, - const bool stereoVisual, - const GHOST_TUns16 numOfAASamples, - GHOST_TEmbedderWindowID parentwindowhwnd, - GHOST_TSuccess msEnabled, - int msPixelFormat) - : GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, - stereoVisual, false, numOfAASamples), + bool wantStereoVisual, + GHOST_TUns16 wantNumOfAASamples, + GHOST_TEmbedderWindowID parentwindowhwnd) + : GHOST_Window(width, height, state, + wantStereoVisual, false, wantNumOfAASamples), m_inLiveResize(false), m_system(system), m_hDC(0), - m_hGlRc(0), m_hasMouseCaptured(false), m_hasGrabMouse(false), m_nPressedButtons(0), @@ -139,18 +87,7 @@ GHOST_WindowWin32::GHOST_WindowWin32( m_tabletData(NULL), m_tablet(0), m_maxPressure(0), - m_multisample(numOfAASamples), - m_multisampleEnabled(msEnabled), - m_msPixelFormat(msPixelFormat), - //For recreation - m_title(title), - m_left(left), - m_top(top), - m_width(width), - m_height(height), m_normal_state(GHOST_kWindowStateNormal), - m_stereo(stereoVisual), - m_nextWindow(NULL), m_parentWindowHwnd(parentwindowhwnd) { OSVERSIONINFOEX versionInfo; @@ -286,35 +223,32 @@ GHOST_WindowWin32::GHOST_WindowWin32( // Store the device context m_hDC = ::GetDC(m_hWnd); - if (!s_firstHDC) { - s_firstHDC = m_hDC; - } - - // Show the window - int nCmdShow; - switch (state) { - case GHOST_kWindowStateMaximized: - nCmdShow = SW_SHOWMAXIMIZED; - break; - case GHOST_kWindowStateMinimized: - nCmdShow = SW_SHOWMINIMIZED; - break; - case GHOST_kWindowStateNormal: - default: - nCmdShow = SW_SHOWNORMAL; - break; - } - GHOST_TSuccess success; - success = setDrawingContextType(type); + GHOST_TSuccess success = setDrawingContextType(type); if (success) { + // Show the window + int nCmdShow; + switch (state) { + case GHOST_kWindowStateMaximized: + nCmdShow = SW_SHOWMAXIMIZED; + break; + case GHOST_kWindowStateMinimized: + nCmdShow = SW_SHOWMINIMIZED; + break; + case GHOST_kWindowStateNormal: + default: + nCmdShow = SW_SHOWNORMAL; + break; + } + ::ShowWindow(m_hWnd, nCmdShow); // Force an initial paint of the window ::UpdateWindow(m_hWnd); } else { //invalidate the window - m_hWnd = 0; + ::DestroyWindow(m_hWnd); + m_hWnd = NULL; } } @@ -415,14 +349,8 @@ GHOST_WindowWin32::~GHOST_WindowWin32() m_customCursor = NULL; } - ::wglMakeCurrent(NULL, NULL); - m_multisampleEnabled = GHOST_kFailure; - m_multisample = 0; - setDrawingContextType(GHOST_kDrawingContextTypeNone); - - if (m_hDC && m_hDC != s_firstHDC) { + if (m_hWnd != NULL && m_hDC != NULL && releaseNativeHandles()) { ::ReleaseDC(m_hWnd, m_hDC); - m_hDC = 0; } if (m_hWnd) { @@ -438,14 +366,9 @@ GHOST_WindowWin32::~GHOST_WindowWin32() } } -GHOST_Window *GHOST_WindowWin32::getNextWindow() -{ - return m_nextWindow; -} - bool GHOST_WindowWin32::getValid() const { - return m_hWnd != 0; + return GHOST_Window::getValid() && m_hWnd != 0 && m_hDC != 0; } HWND GHOST_WindowWin32::getHWND() const @@ -678,49 +601,6 @@ GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order) } -GHOST_TSuccess GHOST_WindowWin32::swapBuffers() -{ - HDC hDC = m_hDC; - - if (is_crappy_intel_card()) - hDC = ::wglGetCurrentDC(); - - return ::SwapBuffers(hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure; -} - -GHOST_TSuccess GHOST_WindowWin32::setSwapInterval(int interval) -{ - if (!WGL_EXT_swap_control) - return GHOST_kFailure; - return wglSwapIntervalEXT(interval) == TRUE ? GHOST_kSuccess : GHOST_kFailure; -} - -int GHOST_WindowWin32::getSwapInterval() -{ - if (WGL_EXT_swap_control) - return wglGetSwapIntervalEXT(); - - return 0; -} - -GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext() -{ - GHOST_TSuccess success; - if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { - if (m_hDC && m_hGlRc) { - success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; - } - else { - success = GHOST_kFailure; - } - } - else { - success = GHOST_kSuccess; - } - return success; -} - - GHOST_TSuccess GHOST_WindowWin32::invalidate() { GHOST_TSuccess success; @@ -733,257 +613,93 @@ GHOST_TSuccess GHOST_WindowWin32::invalidate() return success; } -GHOST_TSuccess GHOST_WindowWin32::initMultisample(PIXELFORMATDESCRIPTOR pfd) -{ - int pixelFormat; - bool success = FALSE; - UINT numFormats; - HDC hDC = GetDC(getHWND()); - float fAttributes[] = {0, 0}; - UINT nMaxFormats = 1; - - // The attributes to look for - int iAttributes[] = { - WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, - WGL_SUPPORT_OPENGL_ARB, GL_TRUE, - WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, - WGL_COLOR_BITS_ARB, pfd.cColorBits, - WGL_DEPTH_BITS_ARB, pfd.cDepthBits, -#ifdef GHOST_OPENGL_ALPHA - WGL_ALPHA_BITS_ARB, pfd.cAlphaBits, -#endif - WGL_STENCIL_BITS_ARB, pfd.cStencilBits, - WGL_DOUBLE_BUFFER_ARB, GL_TRUE, - WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, - WGL_SAMPLES_ARB, m_multisample, - 0, 0 - }; - - // Get the function - PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); - - if (!wglChoosePixelFormatARB) { - m_multisampleEnabled = GHOST_kFailure; - return GHOST_kFailure; - } - // iAttributes[17] is the initial multisample. If not valid try to use the closest valid value under it. - while (iAttributes[17] > 0) { - // See if the format is valid - success = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, nMaxFormats, &pixelFormat, &numFormats); - GHOST_PRINTF("WGL_SAMPLES_ARB = %i --> success = %i, %i formats\n", iAttributes[17], success, numFormats); - - if (success && numFormats >= 1 && m_multisampleEnabled == GHOST_kFailure) { - GHOST_PRINTF("valid pixel format with %i multisamples\n", iAttributes[17]); - m_multisampleEnabled = GHOST_kSuccess; - m_msPixelFormat = pixelFormat; - } - iAttributes[17] -= 1; - success = GHOST_kFailure; - } - if (m_multisampleEnabled == GHOST_kSuccess) { - return GHOST_kSuccess; - } - GHOST_PRINT("no available pixel format\n"); - return GHOST_kFailure; -} - -GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type) +GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType type) { - GHOST_TSuccess success; - switch (type) { - case GHOST_kDrawingContextTypeOpenGL: - { - // If this window has multisample enabled, use the supplied format - if (m_multisampleEnabled) - { - if (SetPixelFormat(m_hDC, m_msPixelFormat, &sPreferredFormat) == FALSE) - { - success = GHOST_kFailure; - break; - } - - // Create the context - m_hGlRc = ::wglCreateContext(m_hDC); - if (m_hGlRc) { - if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) { - if (s_firsthGLRc) { - if (is_crappy_intel_card()) { - if (::wglMakeCurrent(NULL, NULL) == TRUE) { - ::wglDeleteContext(m_hGlRc); - m_hGlRc = s_firsthGLRc; - } - else { - ::wglDeleteContext(m_hGlRc); - m_hGlRc = NULL; - } - } - else { - ::wglCopyContext(s_firsthGLRc, m_hGlRc, GL_ALL_ATTRIB_BITS); - ::wglShareLists(s_firsthGLRc, m_hGlRc); - } - } - else { - s_firsthGLRc = m_hGlRc; - } - - if (m_hGlRc) { - success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; - } - else { - success = GHOST_kFailure; - } - } - else { - success = GHOST_kFailure; - } - } - else { - success = GHOST_kFailure; - } - - if (success == GHOST_kFailure) { - printf("Failed to get a context....\n"); - } - } - else { - if (m_stereoVisual) - sPreferredFormat.dwFlags |= PFD_STEREO; - - // Attempt to match device context pixel format to the preferred format - int iPixelFormat = EnumPixelFormats(m_hDC); - if (iPixelFormat == 0) { - success = GHOST_kFailure; - break; - } - if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) { - success = GHOST_kFailure; - break; - } - // For debugging only: retrieve the pixel format chosen - PIXELFORMATDESCRIPTOR preferredFormat; - ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat); - - // Create the context - m_hGlRc = ::wglCreateContext(m_hDC); - if (m_hGlRc) { - if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) { - if (s_firsthGLRc) { - if (is_crappy_intel_card()) { - if (::wglMakeCurrent(NULL, NULL) == TRUE) { - ::wglDeleteContext(m_hGlRc); - m_hGlRc = s_firsthGLRc; - } - else { - ::wglDeleteContext(m_hGlRc); - m_hGlRc = NULL; - } - } - else { - ::wglShareLists(s_firsthGLRc, m_hGlRc); - } - } - else { - s_firsthGLRc = m_hGlRc; - } - - if (m_hGlRc) { - success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; - } - else { - success = GHOST_kFailure; - } - } - else { - success = GHOST_kFailure; - } - } - else { - success = GHOST_kFailure; - } - - if (success == GHOST_kFailure) { - printf("Failed to get a context....\n"); - } - - // Attempt to enable multisample - if (m_multisample && WGL_ARB_multisample && !m_multisampleEnabled && !is_crappy_intel_card()) - { - success = initMultisample(preferredFormat); - - if (success) - { - - // Make sure we don't screw up the context - if (m_hGlRc == s_firsthGLRc) - s_firsthGLRc = NULL; - m_drawingContextType = GHOST_kDrawingContextTypeOpenGL; - removeDrawingContext(); - - // Create a new window - GHOST_TWindowState new_state = getState(); - - m_nextWindow = new GHOST_WindowWin32((GHOST_SystemWin32 *)GHOST_ISystem::getSystem(), - m_title, - m_left, - m_top, - m_width, - m_height, - new_state, - type, - m_stereo, - m_multisample, - m_parentWindowHwnd, - m_multisampleEnabled, - m_msPixelFormat); - - // Return failure so we can trash this window. - success = GHOST_kFailure; - break; - } - else { - m_multisampleEnabled = GHOST_kSuccess; - printf("Multisample failed to initialize\n"); - success = GHOST_kSuccess; - } - } - } + if (type == GHOST_kDrawingContextTypeOpenGL) { +#if !defined(WITH_GL_EGL) + +#if defined(WITH_GL_PROFILE_CORE) + GHOST_Context *context = new GHOST_ContextWGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_hWnd, + m_hDC, + WGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 3, 2, + GHOST_OPENGL_WGL_CONTEXT_FLAGS, + GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); +#elif defined(WITH_GL_PROFILE_ES20) + GHOST_Context *context = new GHOST_ContextWGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_hWnd, + m_hDC, + WGL_CONTEXT_ES2_PROFILE_BIT_EXT, + 2, 0, + GHOST_OPENGL_WGL_CONTEXT_FLAGS, + GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); +#elif defined(WITH_GL_PROFILE_COMPAT) + GHOST_Context *context = new GHOST_ContextWGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_hWnd, + m_hDC, + 0, // profile bit + 0, 0, + GHOST_OPENGL_WGL_CONTEXT_FLAGS, + GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); +#else +# error +#endif - } - break; +#else - case GHOST_kDrawingContextTypeNone: - success = GHOST_kSuccess; - break; +#if defined(WITH_GL_PROFILE_CORE) + GHOST_Context *context = new GHOST_ContextEGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_hWnd, + m_hDC, + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 3, 2, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); +#elif defined(WITH_GL_PROFILE_ES20) + GHOST_Context *context = new GHOST_ContextEGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_hWnd, + m_hDC, + 0, // profile bit + 2, 0, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_ES_API); +#elif defined(WITH_GL_PROFILE_COMPAT) + GHOST_Context *context = new GHOST_ContextEGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_hWnd, + m_hDC, + 0, // profile bit + 0, 0, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); +#else +# error +#endif - default: - success = GHOST_kFailure; +#endif + if (context->initializeDrawingContext()) + return context; + else + delete context; } - return success; -} -GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext() -{ - GHOST_TSuccess success; - switch (m_drawingContextType) { - case GHOST_kDrawingContextTypeOpenGL: - // we shouldn't remove the drawing context if it's the first OpenGL context - // If we do, we get corrupted drawing. See #19997 - if (m_hGlRc && m_hGlRc != s_firsthGLRc) { - success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; - m_hGlRc = 0; - } - else { - success = GHOST_kFailure; - } - break; - case GHOST_kDrawingContextTypeNone: - success = GHOST_kSuccess; - break; - default: - success = GHOST_kFailure; - } - return success; + return NULL; } void GHOST_WindowWin32::lostMouseCapture() @@ -1334,93 +1050,3 @@ GHOST_TSuccess GHOST_WindowWin32::endProgressBar() return GHOST_kFailure; } -/* Ron Fosner's code for weighting pixel formats and forcing software. - * See http://www.opengl.org/resources/faq/technical/weight.cpp */ - -static int WeightPixelFormat(PIXELFORMATDESCRIPTOR &pfd) -{ - int weight = 0; - - /* assume desktop color depth is 32 bits per pixel */ - - /* cull unusable pixel formats */ - /* if no formats can be found, can we determine why it was rejected? */ - if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) || - !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || - !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */ - (pfd.cDepthBits <= 8) || - !(pfd.iPixelType == PFD_TYPE_RGBA)) - { - return 0; - } - - weight = 1; /* it's usable */ - - /* the bigger the depth buffer the better */ - /* give no weight to a 16-bit depth buffer, because those are crap */ - weight += pfd.cDepthBits - 16; - - weight += pfd.cColorBits - 8; - -#ifdef GHOST_OPENGL_ALPHA - if (pfd.cAlphaBits > 0) - weight ++; -#endif - - /* want swap copy capability -- it matters a lot */ - if (pfd.dwFlags & PFD_SWAP_COPY) weight += 16; - - /* but if it's a generic (not accelerated) view, it's really bad */ - if (pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10; - - return weight; -} - -/* A modification of Ron Fosner's replacement for ChoosePixelFormat */ -/* returns 0 on error, else returns the pixel format number to be used */ -static int EnumPixelFormats(HDC hdc) -{ - int iPixelFormat; - int i, n, w, weight = 0; - PIXELFORMATDESCRIPTOR pfd; - - /* we need a device context to do anything */ - if (!hdc) return 0; - - iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */ - - /* obtain detailed information about - * the device context's first pixel format */ - n = 1 + ::DescribePixelFormat(hdc, iPixelFormat, - sizeof(PIXELFORMATDESCRIPTOR), &pfd); - - /* choose a pixel format using the useless Windows function in case - * we come up empty handed */ - iPixelFormat = ::ChoosePixelFormat(hdc, &sPreferredFormat); - - if (!iPixelFormat) return 0; /* couldn't find one to use */ - - for (i = 1; i <= n; i++) { /* not the idiom, but it's right */ - ::DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd); - w = WeightPixelFormat(pfd); - // be strict on stereo - if (!((sPreferredFormat.dwFlags ^ pfd.dwFlags) & PFD_STEREO)) { - if (w > weight) { - weight = w; - iPixelFormat = i; - } - } - } - if (weight == 0) { - // we could find the correct stereo setting, just find any suitable format - for (i = 1; i <= n; i++) { /* not the idiom, but it's right */ - ::DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd); - w = WeightPixelFormat(pfd); - if (w > weight) { - weight = w; - iPixelFormat = i; - } - } - } - return iPixelFormat; -} diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index cb6c09b335c..7b12d8c583e 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -40,13 +40,6 @@ #include "GHOST_Window.h" #include "GHOST_TaskbarWin32.h" -#ifndef __MINGW64__ -#define _WIN32_WINNT 0x501 // require Windows XP or newer -#endif -#define WIN32_LEAN_AND_MEAN -#include <windows.h> - - #include <wintab.h> #define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR) #define PACKETMODE PK_BUTTONS @@ -80,8 +73,9 @@ public: * \param height The height the window. * \param state The state the window is initially opened with. * \param type The type of drawing context installed in this window. - * \param stereoVisual Stereo visual for quad buffered stereo. - * \param numOfAASamples Number of samples used for AA (zero if no AA) + * \param wantStereoVisual Stereo visual for quad buffered stereo. + * \param wantNumOfAASamples Number of samples used for AA (zero if no AA) + * \param parentWindowHwnd */ GHOST_WindowWin32( GHOST_SystemWin32 *system, @@ -92,11 +86,9 @@ public: GHOST_TUns32 height, GHOST_TWindowState state, GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, - const bool stereoVisual = false, - const GHOST_TUns16 numOfAASamples = 0, - GHOST_TEmbedderWindowID parentWindowHwnd = 0, - GHOST_TSuccess msEnabled = GHOST_kFailure, - int msPixelFormat = 0 + bool wantStereoVisual = false, + GHOST_TUns16 wantNumOfAASamples = 0, + GHOST_TEmbedderWindowID parentWindowHwnd = 0 ); /** @@ -106,13 +98,6 @@ public: virtual ~GHOST_WindowWin32(); /** - * Returns the window to replace this one if it's getting replaced - * \return The window replacing this one. - */ - - GHOST_Window *getNextWindow(); - - /** * Returns indication as to whether the window is valid. * \return The validity of the window. */ @@ -208,29 +193,6 @@ public: virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order); /** - * Swaps front and back buffers of a window. - * \return Indication of success. - */ - virtual GHOST_TSuccess swapBuffers(); - - /** - * Sets the swap interval for swapBuffers. - * \param interval The swap interval to use. - * \return A boolean success indicator. - */ - virtual GHOST_TSuccess setSwapInterval(int interval); - - /** - * Gets the current swap interval for swapBuffers. - * \return An integer. - */ - virtual int getSwapInterval(); - - /** - * Activates the drawing context of this window. - * \return Indication of success. - */ - virtual GHOST_TSuccess activateDrawingContext(); /** * Invalidates the contents of this window. @@ -248,13 +210,6 @@ public: */ virtual GHOST_TSuccess endProgressBar(); - /** - * Returns the name of the window class. - * \return The name of the window class. - */ - static const wchar_t *getWindowClassName() { - return s_windowClassName; - } /** * Register a mouse click event (should be called @@ -298,21 +253,13 @@ public: /** if the window currently resizing */ bool m_inLiveResize; -protected: - GHOST_TSuccess initMultisample(PIXELFORMATDESCRIPTOR pfd); +private: /** - * Tries to install a rendering context in this window. - * \param type The type of rendering context installed. + * \param type The type of rendering context create. * \return Indication of success. */ - virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); - - /** - * Removes the current drawing context. - * \return Indication of success. - */ - virtual GHOST_TSuccess removeDrawingContext(); + virtual GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type); /** * Sets the cursor visibility on the window using @@ -360,12 +307,7 @@ protected: HWND m_hWnd; /** Device context handle. */ HDC m_hDC; - /** OpenGL rendering context. */ - HGLRC m_hGlRc; - /** The first created OpenGL context (for sharing display lists) */ - static HGLRC s_firsthGLRc; - /** The first created device context handle. */ - static HDC s_firstHDC; + /** Flag for if window has captured the mouse */ bool m_hasMouseCaptured; /** Flag if an operator grabs the mouse with WM_cursor_grab_enable/ungrab() @@ -393,26 +335,7 @@ protected: LONG m_maxPressure; LONG m_maxAzimuth, m_maxAltitude; - /** Preferred number of samples */ - GHOST_TUns16 m_multisample; - - /** Check if multisample is supported */ - GHOST_TSuccess m_multisampleEnabled; - - /** The pixelFormat to use for multisample */ - int m_msPixelFormat; - - /** We need to following to recreate the window */ - const STR_String& m_title; - GHOST_TInt32 m_left; - GHOST_TInt32 m_top; - GHOST_TUns32 m_width; - GHOST_TUns32 m_height; GHOST_TWindowState m_normal_state; - bool m_stereo; - - /** The GHOST_System passes this to wm if this window is being replaced */ - GHOST_Window *m_nextWindow; /** Hwnd to parent window */ GHOST_TEmbedderWindowID m_parentWindowHwnd; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 86c940b7396..97f8ae73d2d 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -30,23 +30,28 @@ */ -#include <GL/glxew.h> - #include "GHOST_WindowX11.h" #include "GHOST_SystemX11.h" #include "STR_String.h" #include "GHOST_Debug.h" #ifdef WITH_XDND -#include "GHOST_DropTargetX11.h" +# include "GHOST_DropTargetX11.h" +#endif + +#if defined(WITH_GL_EGL) +# include "GHOST_ContextEGL.h" +#else +# include "GHOST_ContextGLX.h" #endif + /* For standard X11 cursors */ #include <X11/cursorfont.h> #include <X11/Xatom.h> #if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX) -#include <strings.h> +# include <strings.h> #endif #include <cstring> @@ -65,14 +70,6 @@ typedef struct { long input_mode; } MotifWmHints; -// Workaround for MESA bug #54080 -// https://bugs.freedesktop.org/show_bug.cgi?id=54080() -#define SWAP_INTERVALS_WORKAROUND - -#ifdef SWAP_INTERVALS_WORKAROUND -static bool g_swap_interval_disabled = false; -#endif // SWAP_INTERVALS_WORKAROUND - #define MWM_HINTS_DECORATIONS (1L << 1) @@ -157,13 +154,12 @@ static long BLENDER_ICON_48x48x32[] = { }; -GLXContext GHOST_WindowX11::s_firstContext = NULL; GHOST_WindowX11:: GHOST_WindowX11( GHOST_SystemX11 *system, Display *display, - const STR_String& title, + const STR_String &title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, @@ -174,8 +170,7 @@ GHOST_WindowX11( const bool stereoVisual, const bool exclusive, const GHOST_TUns16 numOfAASamples) - : GHOST_Window(width, height, state, type, stereoVisual, exclusive, numOfAASamples), - m_context(NULL), + : GHOST_Window(width, height, state, stereoVisual, exclusive, numOfAASamples), m_display(display), m_normal_state(GHOST_kWindowStateNormal), m_system(system), @@ -185,97 +180,19 @@ GHOST_WindowX11( m_custom_cursor(None), m_visible_cursor(None) { - - /* Set up the minimum attributes that we require and see if - * X can find us a visual matching those requirements. */ - - int attributes[40], i, samples; int natom; - int glxVersionMajor, glxVersionMinor; /* As in GLX major.minor */ - - m_visual = NULL; - - if (!glXQueryVersion(m_display, &glxVersionMajor, &glxVersionMinor)) { - printf("%s:%d: X11 glXQueryVersion() failed, verify working openGL system!\n", __FILE__, __LINE__); - - /* exit if this is the first window */ - if (s_firstContext == NULL) { - printf("initial window could not find the GLX extension, exit!\n"); - exit(1); - } - - return; - } - - /* Find the display with highest samples, starting at level requested */ - for (samples = m_numOfAASamples; samples >= 0; samples--) { - i = 0; /* Reusing attributes array, so reset counter */ - - if (m_stereoVisual) - attributes[i++] = GLX_STEREO; - - attributes[i++] = GLX_RGBA; - attributes[i++] = GLX_DOUBLEBUFFER; - attributes[i++] = GLX_RED_SIZE; attributes[i++] = 1; - attributes[i++] = GLX_BLUE_SIZE; attributes[i++] = 1; - attributes[i++] = GLX_GREEN_SIZE; attributes[i++] = 1; - attributes[i++] = GLX_DEPTH_SIZE; attributes[i++] = 1; -#ifdef GHOST_OPENGL_ALPHA - attributes[i++] = GLX_ALPHA_SIZE; attributes[i++] = 1; -#endif - /* GLX >= 1.4 required for multi-sample */ - if (samples && (glxVersionMajor >= 1) && (glxVersionMinor >= 4)) { - attributes[i++] = GLX_SAMPLE_BUFFERS; attributes[i++] = 1; - attributes[i++] = GLX_SAMPLES; attributes[i++] = samples; - } - attributes[i] = None; - - m_visual = glXChooseVisual(m_display, DefaultScreen(m_display), attributes); - - /* Any sample level or even zero, which means oversampling disabled, is good - * but we need a valid visual to continue */ - if (m_visual == NULL) { - if (samples == 0) { - /* All options exhausted, cannot continue */ - printf("%s:%d: X11 glXChooseVisual() failed, verify working openGL system!\n", __FILE__, __LINE__); - - if (s_firstContext == NULL) { - printf("initial window could not find the GLX extension, exit!\n"); - exit(1); - } - - return; - } - } - else { - if (m_numOfAASamples && (m_numOfAASamples > samples)) { - printf("%s:%d: oversampling requested %i but using %i samples\n", - __FILE__, __LINE__, m_numOfAASamples, samples); - } - break; - } - } - - /* Create a bunch of attributes needed to create an X window. */ - - /* First create a colormap for the window and visual. - * This seems pretty much a legacy feature as we are in rgba mode anyway. */ + unsigned int xattributes_valuemask = 0; XSetWindowAttributes xattributes; - unsigned int xattributes_valuemask = (CWBorderPixel | CWColormap | CWEventMask); memset(&xattributes, 0, sizeof(xattributes)); - xattributes.colormap = XCreateColormap(m_display, - RootWindow(m_display, m_visual->screen), - m_visual->visual, - AllocNone - ); - + xattributes_valuemask |= CWBorderPixel; xattributes.border_pixel = 0; /* Specify which events we are interested in hearing. */ + xattributes_valuemask |= CWEventMask; xattributes.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | @@ -292,15 +209,15 @@ GHOST_WindowX11( /* create the window! */ if (parentWindow == 0) { m_window = XCreateWindow(m_display, - RootWindow(m_display, m_visual->screen), + RootWindow(m_display, DefaultScreen(m_display)), left, top, width, height, - 0, /* no border. */ - m_visual->depth, + 0, /* no border. */ + CopyFromParent, InputOutput, - m_visual->visual, + CopyFromParent, xattributes_valuemask, &xattributes ); @@ -321,15 +238,15 @@ GHOST_WindowX11( m_window = XCreateWindow(m_display, - parentWindow, /* reparent against embedder */ + parentWindow, /* reparent against embedder */ left, top, width, height, - 0, /* no border. */ - m_visual->depth, + 0, /* no border. */ + CopyFromParent, InputOutput, - m_visual->visual, + CopyFromParent, xattributes_valuemask, &xattributes ); @@ -451,8 +368,6 @@ GHOST_WindowX11( BLENDER_ICON_48x48x32[0] * BLENDER_ICON_48x48x32[1] + 2); /* done setting the icon */ - setTitle(title); - #ifdef WITH_X11_XINPUT initXInputDevices(); @@ -460,11 +375,13 @@ GHOST_WindowX11( #endif /* now set up the rendering context. */ - if (installDrawingContext(type) == GHOST_kSuccess) { + if (setDrawingContextType(type) == GHOST_kSuccess) { m_valid_setup = true; GHOST_PRINT("Created window\n"); } + setTitle(title); + if (exclusive) { XMapRaised(m_display, m_window); } @@ -564,7 +481,7 @@ bool GHOST_WindowX11:: getValid() const { - return m_valid_setup; + return GHOST_Window::getValid() && m_valid_setup; } void @@ -685,7 +602,7 @@ screenToClient( Window temp; XTranslateCoordinates(m_display, - RootWindow(m_display, m_visual->screen), + RootWindow(m_display, DefaultScreen(m_display)), m_window, inX, inY, &ax, &ay, @@ -708,7 +625,7 @@ clientToScreen( XTranslateCoordinates( m_display, m_window, - RootWindow(m_display, m_visual->screen), + RootWindow(m_display, DefaultScreen(m_display)), inX, inY, &ax, &ay, &temp); @@ -1052,7 +969,7 @@ setOrder( xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - root = RootWindow(m_display, m_visual->screen), + root = RootWindow(m_display, DefaultScreen(m_display)), eventmask = SubstructureRedirectMask | SubstructureNotifyMask; XSendEvent(m_display, root, False, eventmask, &xev); @@ -1079,34 +996,6 @@ setOrder( GHOST_TSuccess GHOST_WindowX11:: -swapBuffers() -{ - if (getDrawingContextType() == GHOST_kDrawingContextTypeOpenGL) { - glXSwapBuffers(m_display, m_window); - return GHOST_kSuccess; - } - else { - return GHOST_kFailure; - } -} - -GHOST_TSuccess -GHOST_WindowX11:: -activateDrawingContext() -{ - if (m_context != NULL) { - glXMakeCurrent(m_display, m_window, m_context); - /* Disable AA by default */ - if (m_numOfAASamples > 0) { - glDisable(GL_MULTISAMPLE_ARB); - } - return GHOST_kSuccess; - } - return GHOST_kFailure; -} - -GHOST_TSuccess -GHOST_WindowX11:: invalidate() { /* So the idea of this function is to generate an expose event @@ -1172,10 +1061,6 @@ GHOST_WindowX11:: XFreeCursor(m_display, m_custom_cursor); } - if (m_context != s_firstContext) { - glXDestroyContext(m_display, m_context); - } - if (p_owner == m_window) { XSetSelectionOwner(m_display, Primary_atom, None, CurrentTime); } @@ -1193,88 +1078,98 @@ GHOST_WindowX11:: delete m_dropTarget; #endif + releaseNativeHandles(); + XDestroyWindow(m_display, m_window); - XFree(m_visual); } - - -/** - * Tries to install a rendering context in this window. - * \param type The type of rendering context installed. - * \return Indication as to whether installation has succeeded. - */ -GHOST_TSuccess -GHOST_WindowX11:: -installDrawingContext( - GHOST_TDrawingContextType type) +GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type) { - /* only support openGL for now. */ - GHOST_TSuccess success; - switch (type) { - case GHOST_kDrawingContextTypeOpenGL: - { -#ifdef WITH_X11_XINPUT - /* use our own event handlers to avoid exiting blender, - * this would happen for eg: - * if you open blender, unplug a tablet, then open a new window. */ - XErrorHandler old_handler = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler); - XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler); + if (type == GHOST_kDrawingContextTypeOpenGL) { +#if !defined(WITH_GL_EGL) + +#if defined(WITH_GL_PROFILE_CORE) + GHOST_Context *context = new GHOST_ContextGLX( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_display, + GLX_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 3, 2, + GHOST_OPENGL_GLX_CONTEXT_FLAGS, + GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); +#elif defined(WITH_GL_PROFILE_ES20) + GHOST_Context *context = new GHOST_ContextGLX( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_display, + GLX_CONTEXT_ES2_PROFILE_BIT_EXT, + 2, 0, + GHOST_OPENGL_GLX_CONTEXT_FLAGS, + GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); +#elif defined(WITH_GL_PROFILE_COMPAT) + GHOST_Context *context = new GHOST_ContextGLX( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_display, + 0, // profile bit + 0, 0, + GHOST_OPENGL_GLX_CONTEXT_FLAGS, + GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); +#else +# error #endif - m_context = glXCreateContext(m_display, m_visual, s_firstContext, True); - if (m_context != NULL) { - if (!s_firstContext) { - s_firstContext = m_context; - } - glXMakeCurrent(m_display, m_window, m_context); - glClearColor(0.447, 0.447, 0.447, 0); - glClear(GL_COLOR_BUFFER_BIT); - success = GHOST_kSuccess; - } - else { - success = GHOST_kFailure; - } +#else + +#if defined(WITH_GL_PROFILE_CORE) + GHOST_Context *context = new GHOST_ContextEGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_display, + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 3, 2, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); +#elif defined(WITH_GL_PROFILE_ES20) + GHOST_Context *context = new GHOST_ContextEGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_display, + 0, // profile bit + 2, 0, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_ES_API); +#elif defined(WITH_GL_PROFILE_COMPAT) + GHOST_Context *context = new GHOST_ContextEGL( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_display, + 0, // profile bit + 0, 0, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); +#else +# error +#endif -#ifdef WITH_X11_XINPUT - /* Restore handler */ - (void) XSetErrorHandler(old_handler); - (void) XSetIOErrorHandler(old_handler_io); #endif - break; - } - case GHOST_kDrawingContextTypeNone: - { - success = GHOST_kSuccess; - break; - } - default: - success = GHOST_kFailure; + if (context->initializeDrawingContext()) + return context; + else + delete context; } - return success; -} - - -/** - * Removes the current drawing context. - * \return Indication as to whether removal has succeeded. - */ -GHOST_TSuccess -GHOST_WindowX11:: -removeDrawingContext() -{ - GHOST_TSuccess success; - - if (m_context != NULL) { - glXDestroyContext(m_display, m_context); - success = GHOST_kSuccess; - } - else { - success = GHOST_kFailure; - } - return success; + return NULL; } @@ -1530,72 +1425,3 @@ endFullScreen() const return GHOST_kSuccess; } - -GHOST_TSuccess -GHOST_WindowX11:: -setSwapInterval(int interval) { - if (!GLX_EXT_swap_control || !glXSwapIntervalEXT -#ifdef SWAP_INTERVALS_WORKAROUND - || g_swap_interval_disabled -#endif // SWAP_INTERVALS_WORKAROUND - ) - { - return GHOST_kFailure; - } - glXSwapIntervalEXT(m_display, m_window, interval); - return GHOST_kSuccess; -} - -#ifdef SWAP_INTERVALS_WORKAROUND -static int QueryDrawable_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent) -{ - fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n", - theEvent->error_code, theEvent->request_code); - if (!g_swap_interval_disabled) { - fprintf(stderr, "Disabling SWAP INTERVALS extension\n"); - g_swap_interval_disabled = true; - } - return 0; -} - -static int QueryDrawable_ApplicationIOErrorHandler(Display *display) -{ - fprintf(stderr, "Ignoring Xlib error: error IO\n"); - if (!g_swap_interval_disabled) { - fprintf(stderr, "Disabling SWAP INTERVALS extension\n"); - g_swap_interval_disabled = true; - } - return 0; -} -#endif // SWAP_INTERVALS_WORKAROUND - -int -GHOST_WindowX11:: -getSwapInterval() { - if (GLX_EXT_swap_control) { -#ifdef SWAP_INTERVALS_WORKAROUND - /* XXX: Current MESA driver will give GLXBadDrawable for all - * the glXQueryDrawable requests with direct contexts. - * - * To prevent crashes and unexpected behaviors, we will - * disable swap intervals extension if query fails here. - * (because if we will override interval without having - * old value we couldn't restore it properly). - */ - XErrorHandler old_handler = XSetErrorHandler(QueryDrawable_ApplicationErrorHandler); - XIOErrorHandler old_handler_io = XSetIOErrorHandler(QueryDrawable_ApplicationIOErrorHandler); -#endif // SWAP_INTERVALS_WORKAROUND - - unsigned int value = 0; - glXQueryDrawable(m_display, m_window, GLX_SWAP_INTERVAL_EXT, &value); - -#ifdef SWAP_INTERVALS_WORKAROUND - /* Restore handler */ - (void) XSetErrorHandler(old_handler); - (void) XSetIOErrorHandler(old_handler_io); -#endif // SWAP_INTERVALS_WORKAROUND - - return (int)value; - } - return 0; -} diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index faaa05efe82..3255751be93 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -35,7 +35,6 @@ #include "GHOST_Window.h" #include <X11/Xlib.h> -#include <GL/glx.h> // For tablets #ifdef WITH_X11_XINPUT # include <X11/extensions/XInput.h> @@ -160,13 +159,6 @@ public: ); GHOST_TSuccess - swapBuffers( - ); - - GHOST_TSuccess - activateDrawingContext( - ); - GHOST_TSuccess invalidate( ); @@ -235,37 +227,12 @@ public: GHOST_TSuccess endFullScreen() const; - /** - * Sets the swap interval for swapBuffers. - * \param interval The swap interval to use. - * \return A boolean success indicator. - */ - virtual GHOST_TSuccess setSwapInterval(int interval); - - /** - * Gets the current swap interval for swapBuffers. - * \return An integer. - */ - virtual int getSwapInterval(); - protected: /** - * Tries to install a rendering context in this window. - * \param type The type of rendering context installed. - * \return Indication as to whether installation has succeeded. - */ - GHOST_TSuccess - installDrawingContext( - GHOST_TDrawingContextType type - ); - - /** - * Removes the current drawing context. - * \return Indication as to whether removal has succeeded. + * \param type The type of rendering context create. + * \return Indication of success. */ - GHOST_TSuccess - removeDrawingContext( - ); + virtual GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type); /** * Sets the cursor visibility on the window using @@ -350,17 +317,11 @@ private: void initXInputDevices(); #endif - GLXContext m_context; Window m_window; - Display *m_display; - XVisualInfo *m_visual; + Display *m_display; GHOST_TWindowState m_normal_state; - /** The first created OpenGL context (for sharing display lists) */ - static GLXContext s_firstContext; - - /// A pointer to the typed system class. - + /** A pointer to the typed system class. */ GHOST_SystemX11 *m_system; bool m_valid_setup; diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt index 84b6f663ff2..165f5b414b6 100644 --- a/intern/ghost/test/CMakeLists.txt +++ b/intern/ghost/test/CMakeLists.txt @@ -74,6 +74,12 @@ endif() # ----------------------------------------------------------------------------- # Libraries +if(UNIX AND NOT APPLE) + set(WITH_X11 ON) +endif() +# for now... default to this +add_definitions(-DWITH_GL_PROFILE_COMPAT) + # ghost include(${CMAKE_SOURCE_DIR}/../CMakeLists.txt) suffix_relpaths(INC_NEW "${INC}" "../") |