2014-03-14 18:51:06 +01:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*/
2015-06-18 10:15:28 +02:00
# include <config_opengl.h>
2014-04-15 00:43:50 +02:00
# include <vcl/opengl/OpenGLContext.hxx>
2014-04-27 20:25:52 +02:00
# include <vcl/opengl/OpenGLHelper.hxx>
2014-03-17 05:06:00 +01:00
# include <vcl/syschild.hxx>
# include <vcl/sysdata.hxx>
2014-03-14 18:51:06 +01:00
2014-04-08 02:16:08 +02:00
# include <vcl/pngwrite.hxx>
# include <vcl/bmpacc.hxx>
# include <vcl/graph.hxx>
2015-11-13 12:00:59 +00:00
# include <osl/thread.hxx>
2014-09-01 23:10:54 +02:00
# if defined(MACOSX)
2014-09-01 00:36:15 +02:00
# include <premac.h>
2015-12-08 13:58:27 +02:00
# include <AppKit/NSOpenGLView.h>
# include <AppKit/NSOpenGL.h>
2014-09-01 00:36:15 +02:00
# include <postmac.h>
2014-09-01 23:10:54 +02:00
# endif
2014-09-01 00:36:15 +02:00
2014-11-17 12:29:56 +01:00
# if defined( WNT )
# include <win/saldata.hxx>
# endif
2014-11-22 07:58:38 -05:00
# include "svdata.hxx"
2016-01-05 16:17:41 +00:00
# include "salgdi.hxx"
2014-11-22 07:58:38 -05:00
2014-11-26 09:22:25 -05:00
# include <opengl/framebuffer.hxx>
2014-11-28 14:56:08 -05:00
# include <opengl/program.hxx>
2014-11-26 09:22:25 -05:00
# include <opengl/texture.hxx>
2015-08-20 17:03:30 +01:00
# include <opengl/zone.hxx>
2014-11-26 09:22:25 -05:00
2014-03-14 18:51:06 +01:00
using namespace com : : sun : : star ;
2014-12-04 22:25:56 -05:00
# define MAX_FRAMEBUFFER_COUNT 30
2014-11-18 11:45:40 +01:00
// TODO use rtl::Static instead of 'static'
2014-12-22 19:10:59 +01:00
# if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
2014-11-26 15:59:28 +01:00
static std : : vector < GLXContext > g_vShareList ;
2014-11-18 11:45:40 +01:00
# elif defined(WNT)
2014-11-26 15:59:28 +01:00
static std : : vector < HGLRC > g_vShareList ;
2014-11-06 05:18:48 +01:00
# endif
2014-11-04 17:32:48 -05:00
2014-05-23 02:11:23 +02:00
GLWindow : : ~ GLWindow ( )
{
2014-12-22 19:10:59 +01:00
# if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
2014-05-23 02:11:23 +02:00
XFree ( vi ) ;
# endif
}
2014-04-02 03:31:01 +02:00
OpenGLContext : : OpenGLContext ( ) :
2015-11-10 10:28:29 +01:00
mpWindow ( nullptr ) ,
m_pChildWindow ( nullptr ) ,
2014-08-16 05:36:30 +02:00
mbInitialized ( false ) ,
2015-09-07 22:21:15 +01:00
mnRefCount ( 0 ) ,
2014-10-31 19:19:47 +01:00
mbRequestLegacyContext ( false ) ,
2014-11-04 01:15:30 +01:00
mbUseDoubleBufferedRendering ( true ) ,
2015-12-11 18:18:50 +00:00
mbVCLOnly ( false ) ,
2014-12-04 22:25:56 -05:00
mnFramebufferCount ( 0 ) ,
2015-11-10 10:28:29 +01:00
mpCurrentFramebuffer ( nullptr ) ,
mpFirstFramebuffer ( nullptr ) ,
mpLastFramebuffer ( nullptr ) ,
mpCurrentProgram ( nullptr ) ,
2014-11-22 08:04:23 -05:00
mnPainting ( 0 ) ,
2015-11-10 10:28:29 +01:00
mpPrevContext ( nullptr ) ,
mpNextContext ( nullptr )
2014-03-15 07:07:08 +01:00
{
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " new context: " < < this ) ;
2015-08-20 17:03:30 +01:00
2014-11-22 07:58:38 -05:00
ImplSVData * pSVData = ImplGetSVData ( ) ;
if ( pSVData - > maGDIData . mpLastContext )
{
pSVData - > maGDIData . mpLastContext - > mpNextContext = this ;
mpPrevContext = pSVData - > maGDIData . mpLastContext ;
}
else
pSVData - > maGDIData . mpFirstContext = this ;
pSVData - > maGDIData . mpLastContext = this ;
2015-01-06 16:09:09 +00:00
// FIXME: better hope we call 'makeCurrent' soon to preserve
// the invariant that the last item is the current context.
2014-03-15 07:07:08 +01:00
}
OpenGLContext : : ~ OpenGLContext ( )
{
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " delete context: " < < this ) ;
2015-09-07 22:21:15 +01:00
assert ( mnRefCount = = 0 ) ;
mnRefCount = 1 ; // guard the shutdown paths.
2014-12-04 22:17:58 -05:00
reset ( ) ;
2014-11-26 09:22:25 -05:00
ImplSVData * pSVData = ImplGetSVData ( ) ;
if ( mpPrevContext )
mpPrevContext - > mpNextContext = mpNextContext ;
else
pSVData - > maGDIData . mpFirstContext = mpNextContext ;
if ( mpNextContext )
mpNextContext - > mpPrevContext = mpPrevContext ;
else
pSVData - > maGDIData . mpLastContext = mpPrevContext ;
2015-04-10 14:08:12 +01:00
m_pChildWindow . disposeAndClear ( ) ;
2015-09-07 22:21:15 +01:00
assert ( mnRefCount = = 1 ) ;
2014-03-15 07:07:08 +01:00
}
2015-09-08 15:57:55 +01:00
// release associated child-window if we have one
void OpenGLContext : : dispose ( )
{
reset ( ) ;
m_pChildWindow . disposeAndClear ( ) ;
}
2015-09-07 22:21:15 +01:00
rtl : : Reference < OpenGLContext > OpenGLContext : : Create ( )
2015-01-20 04:12:18 +01:00
{
2015-09-07 22:21:15 +01:00
return rtl : : Reference < OpenGLContext > ( new OpenGLContext ) ;
2015-01-20 04:12:18 +01:00
}
2014-12-02 21:51:50 +01:00
2014-08-16 05:36:30 +02:00
void OpenGLContext : : requestLegacyContext ( )
{
mbRequestLegacyContext = true ;
}
2014-10-31 19:19:47 +01:00
void OpenGLContext : : requestSingleBufferedRendering ( )
{
mbUseDoubleBufferedRendering = false ;
}
2014-03-17 05:13:12 +01:00
# if defined( _WIN32 )
static LRESULT CALLBACK WndProc ( HWND hwnd , UINT message , WPARAM wParam , LPARAM lParam )
{
switch ( message )
{
case WM_CREATE :
return 0 ;
case WM_CLOSE :
PostQuitMessage ( 0 ) ;
return 0 ;
case WM_DESTROY :
return 0 ;
case WM_KEYDOWN :
switch ( wParam )
{
case VK_ESCAPE :
PostQuitMessage ( 0 ) ;
return 0 ;
case VK_SPACE :
break ;
}
default :
return DefWindowProc ( hwnd , message , wParam , lParam ) ;
}
}
2015-03-19 15:56:12 +01:00
int InitTempWindow ( HWND * hwnd , int width , int height , const PIXELFORMATDESCRIPTOR & inPfd , GLWindow & glWin )
2014-03-17 05:13:12 +01:00
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-03-17 05:13:12 +01:00
PIXELFORMATDESCRIPTOR pfd = inPfd ;
int pfmt ;
int ret ;
WNDCLASS wc ;
wc . style = 0 ;
wc . lpfnWndProc = WndProc ;
wc . cbClsExtra = wc . cbWndExtra = 0 ;
wc . hInstance = NULL ;
wc . hIcon = NULL ;
wc . hCursor = NULL ;
wc . hbrBackground = NULL ;
wc . lpszMenuName = NULL ;
wc . lpszClassName = ( LPCSTR ) " GLRenderer " ;
RegisterClass ( & wc ) ;
* hwnd = CreateWindow ( wc . lpszClassName , NULL , WS_DISABLED , 0 , 0 , width , height , NULL , NULL , wc . hInstance , NULL ) ;
glWin . hDC = GetDC ( * hwnd ) ;
pfmt = ChoosePixelFormat ( glWin . hDC , & pfd ) ;
if ( ! pfmt )
{
return - 1 ;
}
ret = SetPixelFormat ( glWin . hDC , pfmt , & pfd ) ;
if ( ! ret )
{
return - 1 ;
}
glWin . hRC = wglCreateContext ( glWin . hDC ) ;
if ( ! ( glWin . hRC ) )
{
return - 1 ;
}
ret = wglMakeCurrent ( glWin . hDC , glWin . hRC ) ;
if ( ! ret )
{
return - 1 ;
}
2014-11-14 15:43:44 +01:00
2014-03-17 05:13:12 +01:00
return 0 ;
}
bool WGLisExtensionSupported ( const char * extension )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-03-17 05:13:12 +01:00
const size_t extlen = strlen ( extension ) ;
const char * supported = NULL ;
2015-07-06 17:31:41 +03:00
// Try to use wglGetExtensionStringARB on current DC, if possible
2014-03-17 05:13:12 +01:00
PROC wglGetExtString = wglGetProcAddress ( " wglGetExtensionsStringARB " ) ;
if ( wglGetExtString )
supported = ( ( char * ( __stdcall * ) ( HDC ) ) wglGetExtString ) ( wglGetCurrentDC ( ) ) ;
2015-07-06 17:31:41 +03:00
// If that failed, try standard OpenGL extensions string
2014-03-17 05:13:12 +01:00
if ( supported = = NULL )
supported = ( char * ) glGetString ( GL_EXTENSIONS ) ;
2015-07-06 17:31:41 +03:00
// If that failed too, must be no extensions supported
2014-03-17 05:13:12 +01:00
if ( supported = = NULL )
2014-11-02 02:49:22 +01:00
return false ;
2014-03-17 05:13:12 +01:00
2015-07-06 17:31:41 +03:00
// Begin examination at start of string, increment by 1 on false match
2014-03-17 05:13:12 +01:00
for ( const char * p = supported ; ; p + + )
{
2015-07-06 17:31:41 +03:00
// Advance p up to the next possible match
2014-03-17 05:13:12 +01:00
p = strstr ( p , extension ) ;
if ( p = = NULL )
return 0 ; // No Match
2015-07-06 17:31:41 +03:00
// Make sure that match is at the start of the string or that
// the previous char is a space, or else we could accidentally
// match "wglFunkywglExtension" with "wglExtension"
2014-03-17 05:13:12 +01:00
2015-07-06 17:31:41 +03:00
// Also, make sure that the following character is space or null
// or else "wglExtensionTwo" might match "wglExtension"
2014-03-17 05:13:12 +01:00
if ( ( p = = supported | | p [ - 1 ] = = ' ' ) & & ( p [ extlen ] = = ' \0 ' | | p [ extlen ] = = ' ' ) )
return 1 ; // Match
}
}
2015-03-04 09:28:31 +00:00
bool InitMultisample ( const PIXELFORMATDESCRIPTOR & pfd , int & rPixelFormat ,
2014-11-04 01:15:30 +01:00
bool bUseDoubleBufferedRendering , bool bRequestVirtualDevice )
2014-03-17 05:13:12 +01:00
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-03-17 05:13:12 +01:00
HWND hWnd = NULL ;
2014-03-17 08:11:38 +01:00
GLWindow glWin ;
2015-07-06 17:31:41 +03:00
// Create a temp window to check whether support multi-sample, if support, get the format
2014-03-17 08:11:38 +01:00
if ( InitTempWindow ( & hWnd , 1 , 1 , pfd , glWin ) < 0 )
2014-03-17 05:13:12 +01:00
{
SAL_WARN ( " vcl.opengl " , " Can't create temp window to test " ) ;
return false ;
}
2015-07-06 17:31:41 +03:00
// See if the string exists in WGL
2014-03-17 05:13:12 +01:00
if ( ! WGLisExtensionSupported ( " WGL_ARB_multisample " ) )
{
2015-07-06 17:31:41 +03:00
SAL_WARN ( " vcl.opengl " , " Device doesn't support multisample " ) ;
2014-03-17 05:13:12 +01:00
return false ;
}
2015-07-06 17:31:41 +03:00
// Get our pixel format
2014-03-17 05:13:12 +01:00
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = ( PFNWGLCHOOSEPIXELFORMATARBPROC ) wglGetProcAddress ( " wglChoosePixelFormatARB " ) ;
if ( ! wglChoosePixelFormatARB )
{
return false ;
}
2015-07-06 17:31:41 +03:00
// Get our current device context
2014-03-17 05:13:12 +01:00
HDC hDC = GetDC ( hWnd ) ;
int pixelFormat ;
int valid ;
UINT numFormats ;
float fAttributes [ ] = { 0 , 0 } ;
2015-07-06 17:31:41 +03:00
// These attributes are the bits we want to test for in our sample.
// Everything is pretty standard, the only one we want to
// really focus on is the WGL_SAMPLE_BUFFERS_ARB and WGL_SAMPLES_ARB.
// These two are going to do the main testing for whether or not
// we support multisampling on this hardware.
2014-03-17 05:13:12 +01:00
int iAttributes [ ] =
{
2014-10-31 19:19:47 +01:00
WGL_DOUBLE_BUFFER_ARB , GL_TRUE ,
2014-03-17 05:13:12 +01:00
WGL_DRAW_TO_WINDOW_ARB , GL_TRUE ,
WGL_SUPPORT_OPENGL_ARB , GL_TRUE ,
WGL_ACCELERATION_ARB , WGL_FULL_ACCELERATION_ARB ,
WGL_COLOR_BITS_ARB , 24 ,
WGL_ALPHA_BITS_ARB , 8 ,
2014-06-09 23:46:03 -07:00
WGL_DEPTH_BITS_ARB , 24 ,
2014-03-17 05:13:12 +01:00
WGL_STENCIL_BITS_ARB , 0 ,
WGL_SAMPLE_BUFFERS_ARB , GL_TRUE ,
WGL_SAMPLES_ARB , 8 ,
0 , 0
} ;
2014-03-17 08:11:38 +01:00
2014-11-02 02:13:16 +01:00
if ( ! bUseDoubleBufferedRendering )
2015-11-10 10:56:57 +02:00
{
// Use asserts to make sure the iAttributes array is not changed without changing these ugly
// hardcode indexes into it.
assert ( iAttributes [ 0 ] = = WGL_DOUBLE_BUFFER_ARB ) ;
2014-10-31 19:19:47 +01:00
iAttributes [ 1 ] = GL_FALSE ;
2015-11-10 10:56:57 +02:00
}
2014-10-31 19:19:47 +01:00
2014-11-04 01:15:30 +01:00
if ( bRequestVirtualDevice )
{
2015-11-10 10:56:57 +02:00
assert ( iAttributes [ 2 ] = = WGL_DRAW_TO_WINDOW_ARB ) ;
2014-11-04 01:15:30 +01:00
iAttributes [ 2 ] = WGL_DRAW_TO_BITMAP_ARB ;
}
2015-12-15 19:23:35 +02:00
bool bArbMultisampleSupported = false ;
2014-03-17 08:11:38 +01:00
2015-11-10 10:56:57 +02:00
// First we check to see if we can get a pixel format for 8 samples
2014-03-17 05:13:12 +01:00
valid = wglChoosePixelFormatARB ( hDC , iAttributes , fAttributes , 1 , & pixelFormat , & numFormats ) ;
2015-07-06 17:31:41 +03:00
// If we returned true, and our format count is greater than 1
2014-03-17 05:13:12 +01:00
if ( valid & & numFormats > = 1 )
{
2014-03-17 08:11:38 +01:00
bArbMultisampleSupported = true ;
rPixelFormat = pixelFormat ;
2014-03-17 05:13:12 +01:00
wglMakeCurrent ( NULL , NULL ) ;
wglDeleteContext ( glWin . hRC ) ;
ReleaseDC ( hWnd , glWin . hDC ) ;
DestroyWindow ( hWnd ) ;
2014-03-17 08:11:38 +01:00
return bArbMultisampleSupported ;
2014-03-17 05:13:12 +01:00
}
2015-11-10 10:56:57 +02:00
// Our pixel format with 8 samples failed, test for 2 samples
assert ( iAttributes [ 18 ] = = WGL_SAMPLES_ARB ) ;
2014-03-17 05:13:12 +01:00
iAttributes [ 19 ] = 2 ;
valid = wglChoosePixelFormatARB ( hDC , iAttributes , fAttributes , 1 , & pixelFormat , & numFormats ) ;
if ( valid & & numFormats > = 1 )
{
2014-03-17 08:11:38 +01:00
bArbMultisampleSupported = true ;
rPixelFormat = pixelFormat ;
2014-03-17 05:13:12 +01:00
wglMakeCurrent ( NULL , NULL ) ;
wglDeleteContext ( glWin . hRC ) ;
ReleaseDC ( hWnd , glWin . hDC ) ;
DestroyWindow ( hWnd ) ;
2014-03-17 08:11:38 +01:00
return bArbMultisampleSupported ;
2014-03-17 05:13:12 +01:00
}
2015-07-06 17:31:41 +03:00
// Return the valid format
2014-03-17 05:13:12 +01:00
wglMakeCurrent ( NULL , NULL ) ;
wglDeleteContext ( glWin . hRC ) ;
ReleaseDC ( hWnd , glWin . hDC ) ;
DestroyWindow ( hWnd ) ;
2014-03-17 08:11:38 +01:00
2014-11-14 19:12:11 +01:00
return bArbMultisampleSupported ;
2014-03-17 05:13:12 +01:00
}
# endif
2014-03-14 18:51:06 +01:00
# ifdef DBG_UTIL
namespace {
const char * getSeverityString ( GLenum severity )
{
switch ( severity )
{
case GL_DEBUG_SEVERITY_LOW :
return " low " ;
case GL_DEBUG_SEVERITY_MEDIUM :
return " medium " ;
case GL_DEBUG_SEVERITY_HIGH :
return " high " ;
default :
;
}
return " unknown " ;
}
const char * getSourceString ( GLenum source )
{
switch ( source )
{
case GL_DEBUG_SOURCE_API :
return " API " ;
case GL_DEBUG_SOURCE_SHADER_COMPILER :
return " shader compiler " ;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM :
return " window system " ;
case GL_DEBUG_SOURCE_THIRD_PARTY :
return " third party " ;
case GL_DEBUG_SOURCE_APPLICATION :
return " Libreoffice " ;
case GL_DEBUG_SOURCE_OTHER :
return " unknown " ;
default :
;
}
return " unknown " ;
}
const char * getTypeString ( GLenum type )
{
switch ( type )
{
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR :
return " deprecated behavior " ;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR :
return " undefined behavior " ;
case GL_DEBUG_TYPE_PERFORMANCE :
return " performance " ;
case GL_DEBUG_TYPE_PORTABILITY :
return " portability " ;
case GL_DEBUG_TYPE_MARKER :
return " marker " ;
case GL_DEBUG_TYPE_PUSH_GROUP :
return " push group " ;
case GL_DEBUG_TYPE_POP_GROUP :
return " pop group " ;
case GL_DEBUG_TYPE_OTHER :
return " other " ;
2014-05-17 07:39:46 +02:00
case GL_DEBUG_TYPE_ERROR :
return " error " ;
2014-03-14 18:51:06 +01:00
default :
;
}
2014-11-10 15:05:25 +01:00
return " unknown " ;
2014-03-14 18:51:06 +01:00
}
extern " C " void
# if defined _WIN32
APIENTRY
# endif
debug_callback ( GLenum source , GLenum type , GLuint id ,
2015-06-18 10:15:28 +02:00
GLenum severity , GLsizei , const GLchar * message ,
2015-06-18 14:42:03 +02:00
# if HAVE_GLEW_1_12
2015-06-18 10:15:28 +02:00
const GLvoid *
# else
GLvoid *
# endif
)
2014-03-14 18:51:06 +01:00
{
2014-08-28 21:00:42 +02:00
// ignore Nvidia's : "Program/shader state performance warning: Fragment Shader is going to be recompiled because the shader key based on GL state mismatches."
// the GLSL compiler is a bit too aggressive in optimizing the state based on the current OpenGL state
if ( id = = 131218 )
return ;
2014-03-14 18:51:06 +01:00
SAL_WARN ( " vcl.opengl " , " OpenGL debug message: source: " < < getSourceString ( source ) < < " , type: "
2015-11-19 10:47:29 +02:00
< < getTypeString ( type ) < < " , id: " < < id < < " , severity: " < < getSeverityString ( severity ) < < " , with message: " < < message ) ;
2014-03-14 18:51:06 +01:00
}
}
# endif
2014-12-22 19:10:59 +01:00
# if defined UNX && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
2014-03-14 22:11:29 +01:00
namespace {
2015-01-23 15:33:48 +01:00
# ifdef DBG_UTIL
2015-01-19 22:57:32 +01:00
int unxErrorHandler ( Display * dpy , XErrorEvent * event )
{
2015-01-20 02:04:52 +01:00
char err [ 256 ] ;
char req [ 256 ] ;
char minor [ 256 ] ;
XGetErrorText ( dpy , event - > error_code , err , 256 ) ;
XGetErrorText ( dpy , event - > request_code , req , 256 ) ;
XGetErrorText ( dpy , event - > minor_code , minor , 256 ) ;
SAL_WARN ( " vcl.opengl " , " Error: " < < err < < " , Req: " < < req < < " , Minor: " < < minor ) ;
2015-01-19 22:57:32 +01:00
return 0 ;
}
2015-01-23 15:33:48 +01:00
# endif
2015-01-19 22:57:32 +01:00
typedef int ( * errorHandler ) ( Display * /*dpy*/ , XErrorEvent * /*evnt*/ ) ;
class TempErrorHandler
{
private :
errorHandler oldErrorHandler ;
Display * mdpy ;
public :
2015-09-10 21:10:10 +01:00
TempErrorHandler ( Display * dpy , errorHandler newErrorHandler )
2015-11-10 10:28:29 +01:00
: oldErrorHandler ( nullptr )
2015-09-10 21:10:10 +01:00
, mdpy ( dpy )
2015-01-19 22:57:32 +01:00
{
2015-09-07 22:33:22 +02:00
if ( mdpy )
{
XLockDisplay ( dpy ) ;
XSync ( dpy , false ) ;
oldErrorHandler = XSetErrorHandler ( newErrorHandler ) ;
}
2015-01-19 22:57:32 +01:00
}
~ TempErrorHandler ( )
{
2015-09-07 22:33:22 +02:00
if ( mdpy )
{
// sync so that we possibly get an XError
glXWaitGL ( ) ;
XSync ( mdpy , false ) ;
XSetErrorHandler ( oldErrorHandler ) ;
XUnlockDisplay ( mdpy ) ;
}
2015-01-19 22:57:32 +01:00
}
} ;
2014-03-14 18:51:06 +01:00
static bool errorTriggered ;
int oglErrorHandler ( Display * /*dpy*/ , XErrorEvent * /*evnt*/ )
{
errorTriggered = true ;
return 0 ;
}
2014-11-20 12:07:10 +01:00
GLXFBConfig * getFBConfig ( Display * dpy , Window win , int & nBestFBC , bool bUseDoubleBufferedRendering , bool bWithSameVisualID )
2014-09-03 14:21:19 +02:00
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-11-10 10:28:29 +01:00
if ( dpy = = nullptr | | ! glXQueryExtension ( dpy , nullptr , nullptr ) )
return nullptr ;
2014-09-03 14:21:19 +02:00
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " window: " < < win ) ;
2014-09-03 14:21:19 +02:00
XWindowAttributes xattr ;
2014-11-17 21:07:27 +00:00
if ( ! XGetWindowAttributes ( dpy , win , & xattr ) )
{
SAL_WARN ( " vcl.opengl " , " Failed to get window attributes for fbconfig " < < win ) ;
2015-11-10 10:28:29 +01:00
xattr . screen = nullptr ;
xattr . visual = nullptr ;
2014-11-17 21:07:27 +00:00
}
2014-09-03 14:21:19 +02:00
int screen = XScreenNumberOfScreen ( xattr . screen ) ;
2014-10-29 13:20:52 +01:00
// TODO: moggi: Select colour channel depth based on visual attributes, not hardcoded */
2014-09-03 14:21:19 +02:00
static int visual_attribs [ ] =
{
GLX_DOUBLEBUFFER , True ,
GLX_X_RENDERABLE , True ,
GLX_RED_SIZE , 8 ,
GLX_GREEN_SIZE , 8 ,
GLX_BLUE_SIZE , 8 ,
GLX_ALPHA_SIZE , 8 ,
GLX_DEPTH_SIZE , 24 ,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR ,
None
} ;
2014-10-31 19:19:47 +01:00
if ( ! bUseDoubleBufferedRendering )
visual_attribs [ 1 ] = False ;
2014-09-03 14:21:19 +02:00
int fbCount = 0 ;
GLXFBConfig * pFBC = glXChooseFBConfig ( dpy ,
screen ,
visual_attribs , & fbCount ) ;
if ( ! pFBC )
{
SAL_WARN ( " vcl.opengl " , " no suitable fb format found " ) ;
2015-11-10 10:28:29 +01:00
return nullptr ;
2014-09-03 14:21:19 +02:00
}
int best_num_samp = - 1 ;
for ( int i = 0 ; i < fbCount ; + + i )
{
XVisualInfo * pVi = glXGetVisualFromFBConfig ( dpy , pFBC [ i ] ) ;
2014-11-24 09:28:40 +00:00
if ( pVi & & ( ! bWithSameVisualID | | ( xattr . visual & & pVi - > visualid = = xattr . visual - > visualid ) ) )
2014-09-03 14:21:19 +02:00
{
// pick the one with the most samples per pixel
int nSampleBuf = 0 ;
int nSamples = 0 ;
glXGetFBConfigAttrib ( dpy , pFBC [ i ] , GLX_SAMPLE_BUFFERS , & nSampleBuf ) ;
glXGetFBConfigAttrib ( dpy , pFBC [ i ] , GLX_SAMPLES , & nSamples ) ;
if ( nBestFBC < 0 | | ( nSampleBuf & & ( nSamples > best_num_samp ) ) )
{
nBestFBC = i ;
best_num_samp = nSamples ;
}
}
XFree ( pVi ) ;
}
return pFBC ;
}
2014-10-24 17:03:39 +02:00
// we need them before glew can initialize them
// glew needs an OpenGL context so we need to get the address manually
void initOpenGLFunctionPointers ( )
{
2015-01-19 15:10:10 +01:00
glXChooseFBConfig = reinterpret_cast < GLXFBConfig * ( * ) ( Display * dpy , int screen , const int * attrib_list , int * nelements ) > ( glXGetProcAddressARB ( reinterpret_cast < GLubyte const * > ( " glXChooseFBConfig " ) ) ) ;
glXGetVisualFromFBConfig = reinterpret_cast < XVisualInfo * ( * ) ( Display * dpy , GLXFBConfig config ) > ( glXGetProcAddressARB ( reinterpret_cast < GLubyte const * > ( " glXGetVisualFromFBConfig " ) ) ) ; // try to find a visual for the current set of attributes
glXGetFBConfigAttrib = reinterpret_cast < int ( * ) ( Display * dpy , GLXFBConfig config , int attribute , int * value ) > ( glXGetProcAddressARB ( reinterpret_cast < GLubyte const * > ( " glXGetFBConfigAttrib " ) ) ) ;
glXCreateContextAttribsARB = reinterpret_cast < GLXContext ( * ) ( Display * , GLXFBConfig , GLXContext , Bool , const int * ) > ( glXGetProcAddressARB ( reinterpret_cast < const GLubyte * > ( " glXCreateContextAttribsARB " ) ) ) ;
glXCreatePixmap = reinterpret_cast < GLXPixmap ( * ) ( Display * , GLXFBConfig , Pixmap , const int * ) > ( glXGetProcAddressARB ( reinterpret_cast < const GLubyte * > ( " glXCreatePixmap " ) ) ) ;
2014-10-24 17:03:39 +02:00
}
2014-10-29 13:20:52 +01:00
Visual * getVisual ( Display * dpy , Window win )
2014-10-24 17:03:39 +02:00
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-10-24 17:03:39 +02:00
initOpenGLFunctionPointers ( ) ;
2014-10-29 13:20:52 +01:00
XWindowAttributes xattr ;
2014-11-17 21:07:27 +00:00
if ( ! XGetWindowAttributes ( dpy , win , & xattr ) )
{
SAL_WARN ( " vcl.opengl " , " Failed to get window attributes for getVisual " < < win ) ;
2015-11-10 10:28:29 +01:00
xattr . visual = nullptr ;
2014-11-17 21:07:27 +00:00
}
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " using VisualID " < < xattr . visual ) ;
2014-10-29 13:20:52 +01:00
return xattr . visual ;
2014-10-24 17:03:39 +02:00
}
2014-03-14 18:51:06 +01:00
}
2014-03-17 05:06:00 +01:00
2014-03-14 18:51:06 +01:00
# endif
2014-09-23 11:20:40 +02:00
bool OpenGLContext : : init ( vcl : : Window * pParent )
2014-03-14 18:51:06 +01:00
{
2014-04-02 03:31:01 +02:00
if ( mbInitialized )
return true ;
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-04-20 15:35:54 +01:00
m_xWindow . reset ( pParent ? nullptr : VclPtr < vcl : : Window > : : Create ( nullptr , WB_NOBORDER | WB_NODIALOGCONTROL ) ) ;
2015-02-15 20:41:33 +00:00
mpWindow = pParent ? pParent : m_xWindow . get ( ) ;
if ( m_xWindow )
m_xWindow - > setPosSizePixel ( 0 , 0 , 0 , 0 ) ;
2015-11-10 10:28:29 +01:00
m_pChildWindow = nullptr ;
2014-03-14 18:51:06 +01:00
initWindow ( ) ;
2014-04-27 12:20:13 +02:00
return ImplInit ( ) ;
}
bool OpenGLContext : : init ( SystemChildWindow * pChildWindow )
{
if ( mbInitialized )
return true ;
if ( ! pChildWindow )
return false ;
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-04-27 12:20:13 +02:00
mpWindow = pChildWindow - > GetParent ( ) ;
m_pChildWindow = pChildWindow ;
initWindow ( ) ;
return ImplInit ( ) ;
}
2014-12-22 19:10:59 +01:00
# if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
2014-10-24 17:03:39 +02:00
bool OpenGLContext : : init ( Display * dpy , Window win , int screen )
{
if ( mbInitialized )
return true ;
if ( ! dpy )
return false ;
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-10-24 17:03:39 +02:00
m_aGLWin . dpy = dpy ;
m_aGLWin . win = win ;
m_aGLWin . screen = screen ;
2014-10-29 13:20:52 +01:00
Visual * pVisual = getVisual ( dpy , win ) ;
2014-10-24 17:03:39 +02:00
initGLWindow ( pVisual ) ;
return ImplInit ( ) ;
}
2015-11-11 18:06:29 +02:00
// Copy of gluCheckExtension(), from the Apache-licensed
// https://code.google.com/p/glues/source/browse/trunk/glues/source/glues_registry.c
static GLboolean checkExtension ( const GLubyte * extName , const GLubyte * extString )
{
GLboolean flag = GL_FALSE ;
char * word ;
char * lookHere ;
char * deleteThis ;
if ( extString = = nullptr )
{
return GL_FALSE ;
}
deleteThis = lookHere = static_cast < char * > ( malloc ( strlen ( reinterpret_cast < const char * > ( extString ) ) + 1 ) ) ;
if ( lookHere = = nullptr )
{
return GL_FALSE ;
}
/* strtok() will modify string, so copy it somewhere */
strcpy ( lookHere , reinterpret_cast < const char * > ( extString ) ) ;
while ( ( word = strtok ( lookHere , " " ) ) ! = nullptr )
{
if ( strcmp ( word , reinterpret_cast < const char * > ( extName ) ) = = 0 )
{
flag = GL_TRUE ;
break ;
}
lookHere = nullptr ; /* get next token */
}
free ( static_cast < void * > ( deleteThis ) ) ;
return flag ;
}
2014-11-07 07:32:00 +01:00
2015-11-11 18:06:29 +02:00
bool GLWindow : : HasGLXExtension ( const char * name ) const
{
return checkExtension ( reinterpret_cast < const GLubyte * > ( name ) , reinterpret_cast < const GLubyte * > ( GLXExtensions ) ) ;
}
2014-11-07 07:32:00 +01:00
2014-04-27 12:20:13 +02:00
bool OpenGLContext : : ImplInit ( )
{
2015-01-20 12:34:48 +01:00
if ( ! m_aGLWin . dpy )
return false ;
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-11-10 10:28:29 +01:00
GLXContext pSharedCtx ( nullptr ) ;
2015-01-20 02:07:06 +01:00
# ifdef DBG_UTIL
2015-01-20 02:04:52 +01:00
TempErrorHandler aErrorHandler ( m_aGLWin . dpy , unxErrorHandler ) ;
2015-01-20 02:07:06 +01:00
# endif
2014-11-10 17:13:55 -05:00
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " OpenGLContext::ImplInit----start " ) ;
2014-11-10 17:13:55 -05:00
2014-11-26 15:59:28 +01:00
if ( ! g_vShareList . empty ( ) )
pSharedCtx = g_vShareList . front ( ) ;
2014-11-10 17:13:55 -05:00
2015-11-16 14:51:28 +00:00
if ( glXCreateContextAttribsARB & & ! mbRequestLegacyContext )
2014-09-03 14:21:19 +02:00
{
2014-09-03 14:25:57 +02:00
int best_fbc = - 1 ;
2015-11-16 18:18:36 +00:00
GLXFBConfig * pFBC = getFBConfig ( m_aGLWin . dpy , m_aGLWin . win , best_fbc , mbUseDoubleBufferedRendering , false ) ;
2014-09-07 19:33:18 +02:00
if ( ! pFBC )
return false ;
2014-11-05 18:29:40 +01:00
if ( best_fbc ! = - 1 )
2014-09-03 14:25:57 +02:00
{
2014-11-18 11:45:40 +01:00
int pContextAttribs [ ] =
2014-11-05 18:29:40 +01:00
{
2015-11-16 18:18:36 +00:00
#if 0 // defined(DBG_UTIL)
2014-11-05 18:29:40 +01:00
GLX_CONTEXT_MAJOR_VERSION_ARB , 3 ,
GLX_CONTEXT_MINOR_VERSION_ARB , 2 ,
2015-11-16 18:18:36 +00:00
# endif
2014-11-05 18:29:40 +01:00
None
2015-11-16 18:18:36 +00:00
2014-11-05 18:29:40 +01:00
} ;
2015-11-16 14:16:32 +00:00
m_aGLWin . ctx = glXCreateContextAttribsARB ( m_aGLWin . dpy , pFBC [ best_fbc ] , pSharedCtx , /* direct, not via X */ GL_TRUE , pContextAttribs ) ;
2014-11-05 18:29:40 +01:00
SAL_INFO_IF ( m_aGLWin . ctx , " vcl.opengl " , " created a 3.2 core context " ) ;
}
else
SAL_WARN ( " vcl.opengl " , " unable to find correct FBC " ) ;
2014-09-03 14:25:57 +02:00
}
2014-11-07 07:32:00 +01:00
2014-09-03 14:21:19 +02:00
if ( ! m_aGLWin . ctx )
{
2015-01-20 12:34:48 +01:00
if ( ! m_aGLWin . vi )
2014-09-07 19:33:18 +02:00
return false ;
2015-11-16 18:18:36 +00:00
SAL_WARN ( " vcl.opengl " , " attempting to create a non-double-buffered "
" visual matching the context " ) ;
2015-01-20 12:34:48 +01:00
m_aGLWin . ctx = glXCreateContext ( m_aGLWin . dpy ,
2014-09-03 14:21:19 +02:00
m_aGLWin . vi ,
2014-11-04 17:32:48 -05:00
pSharedCtx ,
2015-11-16 14:16:32 +00:00
GL_TRUE /* direct, not via X server */ ) ;
2014-09-03 14:21:19 +02:00
}
2014-11-07 07:32:00 +01:00
2014-11-10 17:13:55 -05:00
if ( m_aGLWin . ctx )
{
2014-11-26 15:59:28 +01:00
g_vShareList . push_back ( m_aGLWin . ctx ) ;
2014-11-10 17:13:55 -05:00
}
else
2014-03-14 18:51:06 +01:00
{
2014-09-03 14:20:36 +02:00
SAL_WARN ( " vcl.opengl " , " unable to create GLX context " ) ;
2014-03-14 18:51:06 +01:00
return false ;
}
2015-11-16 14:51:28 +00:00
if ( ! glXMakeCurrent ( m_aGLWin . dpy , m_aGLWin . win , m_aGLWin . ctx ) )
2014-11-07 06:13:05 +01:00
{
SAL_WARN ( " vcl.opengl " , " unable to select current GLX context " ) ;
return false ;
}
int glxMinor , glxMajor ;
double nGLXVersion = 0 ;
if ( glXQueryVersion ( m_aGLWin . dpy , & glxMajor , & glxMinor ) )
nGLXVersion = glxMajor + 0.1 * glxMinor ;
SAL_INFO ( " vcl.opengl " , " available GLX version: " < < nGLXVersion ) ;
m_aGLWin . GLExtensions = glGetString ( GL_EXTENSIONS ) ;
SAL_INFO ( " vcl.opengl " , " available GL extensions: " < < m_aGLWin . GLExtensions ) ;
XWindowAttributes xWinAttr ;
2015-11-16 14:51:28 +00:00
if ( ! XGetWindowAttributes ( m_aGLWin . dpy , m_aGLWin . win , & xWinAttr ) )
2014-11-17 21:07:27 +00:00
{
SAL_WARN ( " vcl.opengl " , " Failed to get window attributes on " < < m_aGLWin . win ) ;
m_aGLWin . Width = 0 ;
m_aGLWin . Height = 0 ;
}
else
{
m_aGLWin . Width = xWinAttr . width ;
m_aGLWin . Height = xWinAttr . height ;
}
2014-11-07 06:13:05 +01:00
if ( m_aGLWin . HasGLXExtension ( " GLX_SGI_swap_control " ) )
{
// enable vsync
typedef GLint ( * glXSwapIntervalProc ) ( GLint ) ;
2015-01-19 15:10:10 +01:00
glXSwapIntervalProc glXSwapInterval = reinterpret_cast < glXSwapIntervalProc > ( glXGetProcAddress ( reinterpret_cast < const GLubyte * > ( " glXSwapIntervalSGI " ) ) ) ;
2014-11-07 06:13:05 +01:00
if ( glXSwapInterval )
{
2015-01-20 02:04:52 +01:00
TempErrorHandler aLocalErrorHandler ( m_aGLWin . dpy , oglErrorHandler ) ;
2014-11-07 06:13:05 +01:00
errorTriggered = false ;
glXSwapInterval ( 1 ) ;
if ( errorTriggered )
SAL_WARN ( " vcl.opengl " , " error when trying to set swap interval, NVIDIA or Mesa bug? " ) ;
else
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " set swap interval to 1 (enable vsync) " ) ;
2014-11-07 06:13:05 +01:00
}
}
2015-01-19 22:57:32 +01:00
2015-08-14 09:57:53 +02:00
bool bRet = InitGLEW ( ) ;
InitGLEWDebugging ( ) ;
2015-08-27 20:39:19 +01:00
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ;
windows opengl: make sure mpLastContext is indeed the current context
There were two problems here:
1) The OpenGLContext ctor registered the instance on the list of
contexts, but platform-specific call (e.g. wglMakeCurrent()) was only
made later. Add a registerAsCurrent() member function that helps
ensuring that the last item in the context list is indeed the current
context.
2) OpenGLContext::prepareForYield() is called without the solar mutex
being locked, but it still assumes that the last context in the context
list is the thread's current context, which may not be true. The result
is that during JunitTest_sd_unoapi, we end up in a situation like:
debug:4640:5240: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA65F8
debug:4640:7944: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 000D0003, pSVData->maGDIData.mpLastContext is 00FA6C70
debug:4640:5240: OpenGLContext::prepareForYield: start, wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA6C70
I.e. one thread registers as current, an other registers as current, too (while
the other thread has the solar mutex), then once the original thread wants to
release the solar mutex, the real current context and the last item in the
context list won't match, so the assert at the end of prepareForYield() will
fail.
Fix this by releasing the GL context in WinSalInstance::DestroyFrame().
With this, JunitTest_sd_unoapi passes on Windows with GL enabled.
Change-Id: Icfb9c65c871586b5df69b5a2ab3aa91843dfc799
Reviewed-on: https://gerrit.libreoffice.org/18473
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
Tested-by: Michael Meeks <michael.meeks@collabora.com>
2015-09-10 17:25:27 +02:00
registerAsCurrent ( ) ;
2015-08-14 09:57:53 +02:00
return bRet ;
2014-11-07 06:13:05 +01:00
}
# elif defined( _WIN32 )
bool OpenGLContext : : init ( HDC hDC , HWND hWnd )
{
if ( mbInitialized )
return false ;
m_aGLWin . hDC = hDC ;
m_aGLWin . hWnd = hWnd ;
return ImplInit ( ) ;
}
bool OpenGLContext : : ImplInit ( )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " OpenGLContext::ImplInit----start " ) ;
2014-11-17 12:29:56 +01:00
// PixelFormat tells Windows how we want things to be
PIXELFORMATDESCRIPTOR PixelFormatFront =
2014-03-14 18:51:06 +01:00
{
sizeof ( PIXELFORMATDESCRIPTOR ) ,
1 , // Version Number
2014-11-04 01:15:30 +01:00
PFD_SUPPORT_OPENGL ,
2014-03-14 18:51:06 +01:00
PFD_TYPE_RGBA , // Request An RGBA Format
( BYTE ) 32 , // Select Our Color Depth
0 , 0 , 0 , 0 , 0 , 0 , // Color Bits Ignored
0 , // No Alpha Buffer
0 , // Shift Bit Ignored
0 , // No Accumulation Buffer
0 , 0 , 0 , 0 , // Accumulation Bits Ignored
2015-11-10 11:05:00 +02:00
24 , // 24 bit z-buffer
2014-12-02 00:47:10 +01:00
8 , // stencil buffer
2014-03-14 18:51:06 +01:00
0 , // No Auxiliary Buffer
0 , // now ignored
0 , // Reserved
0 , 0 , 0 // Layer Masks Ignored
} ;
2015-09-01 09:39:29 +02:00
if ( mbUseDoubleBufferedRendering )
PixelFormatFront . dwFlags | = PFD_DOUBLEBUFFER ;
2014-11-04 01:15:30 +01:00
2015-07-07 13:58:41 +02:00
PixelFormatFront . dwFlags | = PFD_DRAW_TO_WINDOW ;
2014-11-04 01:15:30 +01:00
2014-03-14 18:51:06 +01:00
// we must check whether can set the MSAA
2014-05-06 02:27:08 +02:00
int WindowPix = 0 ;
2014-11-04 01:15:30 +01:00
bool bMultiSampleSupport = InitMultisample ( PixelFormatFront , WindowPix ,
2015-07-07 13:58:41 +02:00
mbUseDoubleBufferedRendering , false ) ;
2014-05-06 02:27:08 +02:00
if ( bMultiSampleSupport & & WindowPix ! = 0 )
2014-03-14 18:51:06 +01:00
{
2014-03-17 08:24:14 +01:00
m_aGLWin . bMultiSampleSupported = true ;
2014-03-14 18:51:06 +01:00
}
else
{
2014-05-06 02:27:08 +02:00
WindowPix = ChoosePixelFormat ( m_aGLWin . hDC , & PixelFormatFront ) ;
2014-12-02 03:05:27 +01:00
# if OSL_DEBUG_LEVEL > 0
PIXELFORMATDESCRIPTOR pfd ;
DescribePixelFormat ( m_aGLWin . hDC , WindowPix , sizeof ( PIXELFORMATDESCRIPTOR ) , & pfd ) ;
SAL_WARN ( " vcl.opengl " , " Render Target: Window: " < < ( int ) ( ( pfd . dwFlags & PFD_DRAW_TO_WINDOW ) ! = 0 ) < < " , Bitmap: " < < ( int ) ( ( pfd . dwFlags & PFD_DRAW_TO_BITMAP ) ! = 0 ) ) ;
SAL_WARN ( " vcl.opengl " , " Supports OpenGL: " < < ( int ) ( ( pfd . dwFlags & PFD_SUPPORT_OPENGL ) ! = 0 ) ) ;
# endif
2014-03-14 18:51:06 +01:00
}
2014-05-05 16:46:59 +02:00
2014-05-06 02:27:08 +02:00
if ( WindowPix = = 0 )
2014-05-05 16:46:59 +02:00
{
2014-05-06 02:27:08 +02:00
SAL_WARN ( " vcl.opengl " , " Invalid pixelformat " ) ;
return false ;
}
2014-11-17 12:29:56 +01:00
if ( ! SetPixelFormat ( m_aGLWin . hDC , WindowPix , & PixelFormatFront ) )
{
ImplWriteLastError ( GetLastError ( ) , " SetPixelFormat in OpenGLContext::ImplInit " ) ;
SAL_WARN ( " vcl.opengl " , " SetPixelFormat failed " ) ;
return false ;
}
2014-11-18 11:45:40 +01:00
HGLRC hTempRC = wglCreateContext ( m_aGLWin . hDC ) ;
2014-11-26 09:22:25 -05:00
if ( hTempRC = = NULL )
2014-05-06 02:27:08 +02:00
{
2014-11-17 12:29:56 +01:00
ImplWriteLastError ( GetLastError ( ) , " wglCreateContext in OpenGLContext::ImplInit " ) ;
2014-05-06 02:27:08 +02:00
SAL_WARN ( " vcl.opengl " , " wglCreateContext failed " ) ;
return false ;
}
2014-11-18 11:45:40 +01:00
if ( ! wglMakeCurrent ( m_aGLWin . hDC , hTempRC ) )
2014-05-06 02:27:08 +02:00
{
2014-11-17 12:29:56 +01:00
ImplWriteLastError ( GetLastError ( ) , " wglMakeCurrent in OpenGLContext::ImplInit " ) ;
SAL_WARN ( " vcl.opengl " , " wglMakeCurrent failed " ) ;
2014-05-05 16:46:59 +02:00
return false ;
}
2014-03-14 18:51:06 +01:00
2014-11-18 11:45:40 +01:00
if ( ! InitGLEW ( ) )
2015-09-30 18:25:45 +02:00
{
wglMakeCurrent ( NULL , NULL ) ;
wglDeleteContext ( hTempRC ) ;
2014-11-18 11:45:40 +01:00
return false ;
2015-09-30 18:25:45 +02:00
}
2014-11-18 11:45:40 +01:00
HGLRC hSharedCtx = 0 ;
2014-11-26 15:59:28 +01:00
if ( ! g_vShareList . empty ( ) )
hSharedCtx = g_vShareList . front ( ) ;
2014-11-18 11:45:40 +01:00
2014-12-05 03:32:41 +01:00
if ( ! wglCreateContextAttribsARB )
2015-09-30 18:25:45 +02:00
{
wglMakeCurrent ( NULL , NULL ) ;
wglDeleteContext ( hTempRC ) ;
2014-12-05 03:32:41 +01:00
return false ;
2015-09-30 18:25:45 +02:00
}
2014-12-05 03:32:41 +01:00
2014-11-18 11:45:40 +01:00
// now setup the shared context; this needs a temporary context already
// set up in order to work
2015-08-14 09:57:53 +02:00
int attribs [ ] =
{
# ifdef DBG_UTIL
WGL_CONTEXT_FLAGS_ARB , WGL_CONTEXT_DEBUG_BIT_ARB ,
# endif
0
} ;
m_aGLWin . hRC = wglCreateContextAttribsARB ( m_aGLWin . hDC , hSharedCtx , attribs ) ;
2014-11-18 11:45:40 +01:00
if ( m_aGLWin . hRC = = 0 )
{
ImplWriteLastError ( GetLastError ( ) , " wglCreateContextAttribsARB in OpenGLContext::ImplInit " ) ;
SAL_WARN ( " vcl.opengl " , " wglCreateContextAttribsARB failed " ) ;
2015-09-30 18:25:45 +02:00
wglMakeCurrent ( NULL , NULL ) ;
wglDeleteContext ( hTempRC ) ;
2014-11-18 11:45:40 +01:00
return false ;
}
wglMakeCurrent ( NULL , NULL ) ;
wglDeleteContext ( hTempRC ) ;
if ( ! wglMakeCurrent ( m_aGLWin . hDC , m_aGLWin . hRC ) )
{
ImplWriteLastError ( GetLastError ( ) , " wglMakeCurrent (with shared context) in OpenGLContext::ImplInit " ) ;
SAL_WARN ( " vcl.opengl " , " wglMakeCurrent failed " ) ;
return false ;
}
2015-09-01 14:46:32 +02:00
InitGLEWDebugging ( ) ;
2014-11-26 15:59:28 +01:00
g_vShareList . push_back ( m_aGLWin . hRC ) ;
2014-11-18 11:45:40 +01:00
2014-11-09 08:43:44 +01:00
RECT clientRect ;
GetClientRect ( WindowFromDC ( m_aGLWin . hDC ) , & clientRect ) ;
2014-11-07 17:56:35 +01:00
m_aGLWin . Width = clientRect . right - clientRect . left ;
m_aGLWin . Height = clientRect . bottom - clientRect . top ;
2015-08-27 20:39:19 +01:00
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ;
windows opengl: make sure mpLastContext is indeed the current context
There were two problems here:
1) The OpenGLContext ctor registered the instance on the list of
contexts, but platform-specific call (e.g. wglMakeCurrent()) was only
made later. Add a registerAsCurrent() member function that helps
ensuring that the last item in the context list is indeed the current
context.
2) OpenGLContext::prepareForYield() is called without the solar mutex
being locked, but it still assumes that the last context in the context
list is the thread's current context, which may not be true. The result
is that during JunitTest_sd_unoapi, we end up in a situation like:
debug:4640:5240: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA65F8
debug:4640:7944: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 000D0003, pSVData->maGDIData.mpLastContext is 00FA6C70
debug:4640:5240: OpenGLContext::prepareForYield: start, wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA6C70
I.e. one thread registers as current, an other registers as current, too (while
the other thread has the solar mutex), then once the original thread wants to
release the solar mutex, the real current context and the last item in the
context list won't match, so the assert at the end of prepareForYield() will
fail.
Fix this by releasing the GL context in WinSalInstance::DestroyFrame().
With this, JunitTest_sd_unoapi passes on Windows with GL enabled.
Change-Id: Icfb9c65c871586b5df69b5a2ab3aa91843dfc799
Reviewed-on: https://gerrit.libreoffice.org/18473
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
Tested-by: Michael Meeks <michael.meeks@collabora.com>
2015-09-10 17:25:27 +02:00
registerAsCurrent ( ) ;
2014-11-18 11:45:40 +01:00
return true ;
2014-11-07 06:13:05 +01:00
}
2014-03-14 18:51:06 +01:00
# elif defined( MACOSX )
2014-11-07 06:13:05 +01:00
bool OpenGLContext : : ImplInit ( )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " OpenGLContext::ImplInit----start " ) ;
2014-09-01 01:59:57 +02:00
NSOpenGLView * pView = getOpenGLView ( ) ;
2015-12-08 13:58:27 +02:00
[ [ pView openGLContext ] makeCurrentContext ] ;
2014-07-16 08:02:32 +02:00
2015-08-14 09:57:53 +02:00
bool bRet = InitGLEW ( ) ;
InitGLEWDebugging ( ) ;
return bRet ;
2014-11-07 06:13:05 +01:00
}
2014-03-14 18:51:06 +01:00
2014-11-07 06:13:05 +01:00
# else
2014-03-14 18:51:06 +01:00
2014-11-07 06:13:05 +01:00
bool OpenGLContext : : ImplInit ( )
{
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " OpenGLContext not implemented for this platform " ) ;
2014-11-07 06:13:05 +01:00
return false ;
}
2014-03-14 18:51:06 +01:00
# endif
2014-11-07 06:13:05 +01:00
bool OpenGLContext : : InitGLEW ( )
{
2014-04-08 00:34:29 +02:00
static bool bGlewInit = false ;
if ( ! bGlewInit )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-04-08 00:34:29 +02:00
glewExperimental = GL_TRUE ;
2014-05-05 16:46:59 +02:00
GLenum err = glewInit ( ) ;
if ( err ! = GLEW_OK )
2014-04-08 00:34:29 +02:00
{
2014-05-05 16:46:59 +02:00
SAL_WARN ( " vcl.opengl " , " Failed to initialize GLEW: " < < glewGetErrorString ( err ) ) ;
2014-04-08 00:34:29 +02:00
return false ;
}
else
bGlewInit = true ;
}
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " OpenGLContext::ImplInit----end " ) ;
2015-08-14 09:57:53 +02:00
mbInitialized = true ;
return true ;
}
void OpenGLContext : : InitGLEWDebugging ( )
{
2014-05-09 05:23:12 +02:00
# ifdef DBG_UTIL
// only enable debug output in dbgutil build
2014-11-15 10:16:02 +01:00
if ( GLEW_ARB_debug_output )
2014-05-09 05:23:12 +02:00
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-11-15 10:16:02 +01:00
if ( glDebugMessageCallbackARB )
{
2014-11-16 12:33:55 +01:00
glEnable ( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB ) ;
2015-11-10 10:28:29 +01:00
glDebugMessageCallbackARB ( & debug_callback , nullptr ) ;
2015-12-21 21:25:31 +00:00
2016-01-05 16:17:54 +02:00
# ifdef GL_DEBUG_SEVERITY_NOTIFICATION_ARB
2015-12-21 21:25:31 +00:00
// Ignore i965’ s shader compiler notification flood.
glDebugMessageControlARB ( GL_DEBUG_SOURCE_SHADER_COMPILER_ARB , GL_DEBUG_TYPE_OTHER_ARB , GL_DEBUG_SEVERITY_NOTIFICATION_ARB , 0 , nullptr , true ) ;
2016-01-05 16:17:54 +02:00
# endif
2014-11-15 10:16:02 +01:00
}
else if ( glDebugMessageCallback )
{
glEnable ( GL_DEBUG_OUTPUT ) ;
2015-11-10 10:28:29 +01:00
glDebugMessageCallback ( & debug_callback , nullptr ) ;
2015-12-21 21:25:31 +00:00
// Ignore i965’ s shader compiler notification flood.
glDebugMessageControl ( GL_DEBUG_SOURCE_SHADER_COMPILER , GL_DEBUG_TYPE_OTHER , GL_DEBUG_SEVERITY_NOTIFICATION , 0 , nullptr , true ) ;
2014-11-15 10:16:02 +01:00
}
2014-05-09 05:23:12 +02:00
}
2015-08-28 11:28:13 +01:00
// Test hooks for inserting tracing messages into the stream
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " LibreOffice GLContext initialized: " < < this ) ;
2014-05-09 05:23:12 +02:00
# endif
2014-03-14 18:51:06 +01:00
}
2014-05-19 19:21:29 +02:00
void OpenGLContext : : setWinPosAndSize ( const Point & rPos , const Size & rSize )
{
2015-02-15 20:41:33 +00:00
if ( m_xWindow )
m_xWindow - > SetPosSizePixel ( rPos , rSize ) ;
2014-05-19 19:21:29 +02:00
if ( m_pChildWindow )
m_pChildWindow - > SetPosSizePixel ( rPos , rSize ) ;
m_aGLWin . Width = rSize . Width ( ) ;
m_aGLWin . Height = rSize . Height ( ) ;
}
2014-03-14 18:51:06 +01:00
void OpenGLContext : : setWinSize ( const Size & rSize )
{
2015-02-15 20:41:33 +00:00
if ( m_xWindow )
m_xWindow - > SetSizePixel ( rSize ) ;
2014-04-27 12:20:13 +02:00
if ( m_pChildWindow )
m_pChildWindow - > SetSizePixel ( rSize ) ;
2014-04-08 02:16:08 +02:00
m_aGLWin . Width = rSize . Width ( ) ;
m_aGLWin . Height = rSize . Height ( ) ;
2014-03-14 18:51:06 +01:00
}
2015-07-07 13:58:41 +02:00
2014-04-08 02:16:08 +02:00
2014-03-14 18:51:06 +01:00
# if defined( WNT )
bool OpenGLContext : : initWindow ( )
{
2014-04-27 12:20:13 +02:00
if ( ! m_pChildWindow )
{
2014-09-01 23:59:24 +02:00
SystemWindowData winData = generateWinData ( mpWindow , false ) ;
2015-04-20 15:35:54 +01:00
m_pChildWindow = VclPtr < SystemChildWindow > : : Create ( mpWindow , 0 , & winData , false ) ;
2014-04-27 12:20:13 +02:00
}
2014-03-14 18:51:06 +01:00
if ( m_pChildWindow )
{
2014-05-06 03:41:01 +02:00
m_pChildWindow - > SetMouseTransparent ( true ) ;
2015-05-27 16:09:43 +02:00
m_pChildWindow - > SetParentClipMode ( ParentClipMode : : Clip ) ;
2014-05-06 03:41:01 +02:00
m_pChildWindow - > EnableEraseBackground ( false ) ;
2014-03-14 18:51:06 +01:00
m_pChildWindow - > SetControlForeground ( ) ;
m_pChildWindow - > SetControlBackground ( ) ;
2014-05-19 15:36:06 +02:00
//m_pChildWindow->EnablePaint(false);
2014-05-06 02:22:57 +02:00
const SystemEnvData * sysData ( m_pChildWindow - > GetSystemData ( ) ) ;
2014-03-14 18:51:06 +01:00
m_aGLWin . hWnd = sysData - > hWnd ;
}
2014-11-02 04:12:59 +01:00
m_aGLWin . hDC = GetDC ( m_aGLWin . hWnd ) ;
2014-03-14 18:51:06 +01:00
return true ;
}
2014-07-16 08:02:32 +02:00
# elif defined( MACOSX )
bool OpenGLContext : : initWindow ( )
{
if ( ! m_pChildWindow )
{
2014-09-01 23:59:24 +02:00
SystemWindowData winData = generateWinData ( mpWindow , mbRequestLegacyContext ) ;
2015-04-20 15:35:54 +01:00
m_pChildWindow = VclPtr < SystemChildWindow > : : Create ( mpWindow , 0 , & winData , false ) ;
2014-07-16 08:02:32 +02:00
}
if ( m_pChildWindow )
{
m_pChildWindow - > SetMouseTransparent ( true ) ;
2015-05-27 16:09:43 +02:00
m_pChildWindow - > SetParentClipMode ( ParentClipMode : : Clip ) ;
2014-07-16 08:02:32 +02:00
m_pChildWindow - > EnableEraseBackground ( false ) ;
m_pChildWindow - > SetControlForeground ( ) ;
m_pChildWindow - > SetControlBackground ( ) ;
//m_pChildWindow->EnablePaint(false);
}
return true ;
}
2014-12-22 19:10:59 +01:00
# elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
2014-03-14 18:51:06 +01:00
bool OpenGLContext : : initWindow ( )
{
return false ;
}
# elif defined( UNX )
bool OpenGLContext : : initWindow ( )
{
2015-11-10 10:28:29 +01:00
const SystemEnvData * pChildSysData = nullptr ;
2014-09-01 23:59:24 +02:00
SystemWindowData winData = generateWinData ( mpWindow , false ) ;
2014-04-25 14:41:24 +02:00
if ( winData . pVisual )
2014-03-14 18:51:06 +01:00
{
2014-04-27 12:20:13 +02:00
if ( ! m_pChildWindow )
{
2015-04-13 21:46:06 +01:00
m_pChildWindow = VclPtr < SystemChildWindow > : : Create ( mpWindow , 0 , & winData , false ) ;
2014-04-27 12:20:13 +02:00
}
2014-03-14 18:51:06 +01:00
pChildSysData = m_pChildWindow - > GetSystemData ( ) ;
}
if ( ! m_pChildWindow | | ! pChildSysData )
return false ;
m_pChildWindow - > SetMouseTransparent ( true ) ;
2015-05-27 16:09:43 +02:00
m_pChildWindow - > SetParentClipMode ( ParentClipMode : : NoClip ) ;
2014-03-14 18:51:06 +01:00
m_pChildWindow - > EnableEraseBackground ( false ) ;
m_pChildWindow - > SetControlForeground ( ) ;
m_pChildWindow - > SetControlBackground ( ) ;
2015-03-31 13:17:42 +02:00
m_aGLWin . dpy = static_cast < Display * > ( pChildSysData - > pDisplay ) ;
2014-03-14 18:51:06 +01:00
m_aGLWin . win = pChildSysData - > aWindow ;
2014-04-25 14:41:24 +02:00
m_aGLWin . screen = pChildSysData - > nScreen ;
2015-03-28 19:08:26 +01:00
Visual * pVisual = static_cast < Visual * > ( pChildSysData - > pVisual ) ;
2014-10-24 16:50:05 +02:00
initGLWindow ( pVisual ) ;
return true ;
}
void OpenGLContext : : initGLWindow ( Visual * pVisual )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-04-25 14:41:24 +02:00
// Get visual info
{
XVisualInfo aTemplate ;
2014-05-26 19:41:16 +02:00
aTemplate . visualid = XVisualIDFromVisual ( pVisual ) ;
2014-04-25 14:41:24 +02:00
int nVisuals = 0 ;
XVisualInfo * pInfos = XGetVisualInfo ( m_aGLWin . dpy , VisualIDMask , & aTemplate , & nVisuals ) ;
if ( nVisuals ! = 1 )
SAL_WARN ( " vcl.opengl " , " match count for visual id is not 1 " ) ;
m_aGLWin . vi = pInfos ;
}
2015-07-06 17:31:41 +03:00
// Check multisample support
2014-10-29 13:20:52 +01:00
/* TODO: moggi: This is not necessarily correct in the DBG_UTIL path, as it picks
* an FBConfig instead . . . */
2014-04-25 14:41:24 +02:00
int nSamples = 0 ;
glXGetConfig ( m_aGLWin . dpy , m_aGLWin . vi , GLX_SAMPLES , & nSamples ) ;
if ( nSamples > 0 )
m_aGLWin . bMultiSampleSupported = true ;
2014-03-14 18:51:06 +01:00
m_aGLWin . GLXExtensions = glXQueryExtensionsString ( m_aGLWin . dpy , m_aGLWin . screen ) ;
2014-04-02 03:31:38 +02:00
SAL_INFO ( " vcl.opengl " , " available GLX extensions: " < < m_aGLWin . GLXExtensions ) ;
2014-03-14 18:51:06 +01:00
}
# endif
2014-12-04 22:17:58 -05:00
void OpenGLContext : : reset ( )
{
if ( ! mbInitialized )
return ;
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-09-01 15:09:25 +01:00
// don't reset a context in the middle of stack frames rendering to it
assert ( mnPainting = = 0 ) ;
2014-12-04 22:17:58 -05:00
// reset the clip region
maClipRegion . SetEmpty ( ) ;
// destroy all framebuffers
if ( mpLastFramebuffer )
{
OpenGLFramebuffer * pFramebuffer = mpLastFramebuffer ;
makeCurrent ( ) ;
while ( pFramebuffer )
{
OpenGLFramebuffer * pPrevFramebuffer = pFramebuffer - > mpPrevFramebuffer ;
delete pFramebuffer ;
pFramebuffer = pPrevFramebuffer ;
}
2015-11-10 10:28:29 +01:00
mpFirstFramebuffer = nullptr ;
mpLastFramebuffer = nullptr ;
2014-12-04 22:17:58 -05:00
}
// destroy all programs
if ( ! maPrograms . empty ( ) )
{
makeCurrent ( ) ;
maPrograms . clear ( ) ;
}
if ( isCurrent ( ) )
resetCurrent ( ) ;
mbInitialized = false ;
// destroy the context itself
# if defined( WNT )
if ( m_aGLWin . hRC )
{
std : : vector < HGLRC > : : iterator itr = std : : remove ( g_vShareList . begin ( ) , g_vShareList . end ( ) , m_aGLWin . hRC ) ;
if ( itr ! = g_vShareList . end ( ) )
g_vShareList . erase ( itr ) ;
2015-09-02 11:37:17 +02:00
if ( wglGetCurrentContext ( ) ! = NULL )
wglMakeCurrent ( NULL , NULL ) ;
2014-12-04 22:17:58 -05:00
wglDeleteContext ( m_aGLWin . hRC ) ;
ReleaseDC ( m_aGLWin . hWnd , m_aGLWin . hDC ) ;
2015-09-08 15:57:55 +01:00
m_aGLWin . hRC = 0 ;
2014-12-04 22:17:58 -05:00
}
# elif defined( MACOSX )
2015-12-08 13:58:27 +02:00
[ NSOpenGLContext clearCurrentContext ] ;
2014-12-22 19:10:59 +01:00
# elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
2014-12-04 22:17:58 -05:00
// nothing
# elif defined( UNX )
if ( m_aGLWin . ctx )
{
std : : vector < GLXContext > : : iterator itr = std : : remove ( g_vShareList . begin ( ) , g_vShareList . end ( ) , m_aGLWin . ctx ) ;
if ( itr ! = g_vShareList . end ( ) )
g_vShareList . erase ( itr ) ;
2015-11-10 10:28:29 +01:00
glXMakeCurrent ( m_aGLWin . dpy , None , nullptr ) ;
2014-12-04 22:17:58 -05:00
if ( glGetError ( ) ! = GL_NO_ERROR )
{
2015-03-02 20:22:42 +01:00
SAL_WARN ( " vcl.opengl " , " glError: " < < glGetError ( ) ) ;
2014-12-04 22:17:58 -05:00
}
glXDestroyContext ( m_aGLWin . dpy , m_aGLWin . ctx ) ;
2015-11-10 10:28:29 +01:00
m_aGLWin . ctx = nullptr ;
2014-12-04 22:17:58 -05:00
}
# endif
}
2014-04-27 12:47:52 +02:00
# if defined( WNT ) || defined( MACOSX ) || defined( IOS ) || defined( ANDROID )
2014-04-27 12:09:20 +02:00
2014-09-23 11:20:40 +02:00
SystemWindowData OpenGLContext : : generateWinData ( vcl : : Window * /*pParent*/ , bool bRequestLegacyContext )
2014-04-27 12:09:20 +02:00
{
2014-09-01 23:59:24 +02:00
( void ) bRequestLegacyContext ;
2014-04-27 12:09:20 +02:00
SystemWindowData aWinData ;
2014-09-01 01:18:09 +02:00
# if defined(MACOSX)
aWinData . bOpenGL = true ;
2014-09-01 23:59:24 +02:00
aWinData . bLegacy = bRequestLegacyContext ;
2014-09-01 01:18:09 +02:00
# endif
2014-04-27 12:09:20 +02:00
aWinData . nSize = sizeof ( aWinData ) ;
return aWinData ;
}
# elif defined( UNX )
2014-09-23 11:20:40 +02:00
SystemWindowData OpenGLContext : : generateWinData ( vcl : : Window * pParent , bool )
2014-04-27 12:09:20 +02:00
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-04-27 12:09:20 +02:00
SystemWindowData aWinData ;
aWinData . nSize = sizeof ( aWinData ) ;
2015-11-10 10:28:29 +01:00
aWinData . pVisual = nullptr ;
2014-04-27 12:09:20 +02:00
2014-12-22 19:10:59 +01:00
# if !defined(LIBO_HEADLESS)
2014-04-27 12:09:20 +02:00
const SystemEnvData * sysData ( pParent - > GetSystemData ( ) ) ;
2015-03-31 13:17:42 +02:00
Display * dpy = static_cast < Display * > ( sysData - > pDisplay ) ;
2014-10-24 16:35:32 +02:00
Window win = sysData - > aWindow ;
2014-04-27 12:09:20 +02:00
2015-11-10 10:28:29 +01:00
if ( dpy = = nullptr | | ! glXQueryExtension ( dpy , nullptr , nullptr ) )
2014-04-27 12:09:20 +02:00
return aWinData ;
2014-11-20 12:07:10 +01:00
initOpenGLFunctionPointers ( ) ;
int best_fbc = - 1 ;
GLXFBConfig * pFBC = getFBConfig ( dpy , win , best_fbc , true , false ) ;
if ( ! pFBC )
return aWinData ;
2015-11-10 10:28:29 +01:00
XVisualInfo * vi = nullptr ;
2014-11-20 12:07:10 +01:00
if ( best_fbc ! = - 1 )
vi = glXGetVisualFromFBConfig ( dpy , pFBC [ best_fbc ] ) ;
XFree ( pFBC ) ;
if ( vi )
{
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " using VisualID " < < vi - > visualid ) ;
2015-06-08 16:29:41 +02:00
aWinData . pVisual = static_cast < void * > ( vi - > visual ) ;
2014-11-20 12:07:10 +01:00
}
2014-12-22 19:10:59 +01:00
# endif
2014-04-27 12:09:20 +02:00
return aWinData ;
}
# endif
2014-12-04 22:17:58 -05:00
bool OpenGLContext : : isCurrent ( )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-12-04 22:17:58 -05:00
# if defined( WNT )
2015-11-16 14:51:28 +00:00
return wglGetCurrentContext ( ) = = m_aGLWin . hRC & &
wglGetCurrentDC ( ) = = m_aGLWin . hDC ;
2014-12-04 22:17:58 -05:00
# elif defined( MACOSX )
2015-05-08 23:46:54 +02:00
( void ) this ; // loplugin:staticmethods
2014-12-04 22:17:58 -05:00
return false ;
2014-12-22 19:10:59 +01:00
# elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
2014-12-04 22:17:58 -05:00
return false ;
# elif defined( UNX )
2015-11-16 14:51:28 +00:00
return m_aGLWin . ctx & & glXGetCurrentContext ( ) = = m_aGLWin . ctx & &
glXGetCurrentDrawable ( ) = = m_aGLWin . win ;
2014-12-04 22:17:58 -05:00
# endif
}
2014-12-04 22:25:56 -05:00
2015-09-02 17:28:39 +01:00
bool OpenGLContext : : hasCurrent ( )
{
# if defined( WNT )
return wglGetCurrentContext ( ) ! = NULL ;
# elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
return false ;
# elif defined( UNX )
return glXGetCurrentContext ( ) ! = None ;
# endif
}
2014-12-04 22:25:56 -05:00
void OpenGLContext : : clearCurrent ( )
{
ImplSVData * pSVData = ImplGetSVData ( ) ;
// release all framebuffers from the old context so we can re-attach the
// texture in the new context
2015-09-07 22:21:15 +01:00
rtl : : Reference < OpenGLContext > pCurrentCtx = pSVData - > maGDIData . mpLastContext ;
if ( pCurrentCtx . is ( ) & & pCurrentCtx - > isCurrent ( ) )
2014-12-04 22:25:56 -05:00
pCurrentCtx - > ReleaseFramebuffers ( ) ;
}
2015-09-02 22:14:10 +01:00
void OpenGLContext : : prepareForYield ( )
{
ImplSVData * pSVData = ImplGetSVData ( ) ;
// release all framebuffers from the old context so we can re-attach the
// texture in the new context
2015-09-07 22:21:15 +01:00
rtl : : Reference < OpenGLContext > pCurrentCtx = pSVData - > maGDIData . mpLastContext ;
2015-09-04 16:44:25 +03:00
2015-09-07 22:21:15 +01:00
if ( ! pCurrentCtx . is ( ) )
2015-09-04 16:44:25 +03:00
return ; // Not using OpenGL
SAL_INFO ( " vcl.opengl " , " Unbinding contexts in preparation for yield " ) ;
if ( pCurrentCtx - > isCurrent ( ) )
2015-09-02 22:14:10 +01:00
pCurrentCtx - > resetCurrent ( ) ;
assert ( ! hasCurrent ( ) ) ;
}
2014-04-28 09:57:29 +02:00
void OpenGLContext : : makeCurrent ( )
{
2014-12-04 22:17:58 -05:00
if ( isCurrent ( ) )
return ;
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-12-04 22:25:56 -05:00
clearCurrent ( ) ;
2014-04-28 09:57:29 +02:00
# if defined( WNT )
2014-12-04 22:17:58 -05:00
if ( ! wglMakeCurrent ( m_aGLWin . hDC , m_aGLWin . hRC ) )
2014-05-06 02:27:08 +02:00
{
SAL_WARN ( " vcl.opengl " , " OpenGLContext::makeCurrent(): wglMakeCurrent failed: " < < GetLastError ( ) ) ;
2014-12-04 22:17:58 -05:00
return ;
2014-05-06 02:27:08 +02:00
}
2014-07-16 08:02:32 +02:00
# elif defined( MACOSX )
2014-09-01 01:59:57 +02:00
NSOpenGLView * pView = getOpenGLView ( ) ;
2015-12-08 13:58:27 +02:00
[ [ pView openGLContext ] makeCurrentContext ] ;
2014-12-22 19:10:59 +01:00
# elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
2014-04-28 09:57:29 +02:00
// nothing
# elif defined( UNX )
2015-01-20 02:07:06 +01:00
# ifdef DBG_UTIL
2015-01-20 02:04:52 +01:00
TempErrorHandler aErrorHandler ( m_aGLWin . dpy , unxErrorHandler ) ;
2015-01-20 02:07:06 +01:00
# endif
2015-01-19 22:57:32 +01:00
2015-09-08 11:46:13 +01:00
if ( m_aGLWin . dpy )
2014-11-17 21:51:50 +00:00
{
2015-11-16 14:51:28 +00:00
if ( ! glXMakeCurrent ( m_aGLWin . dpy , m_aGLWin . win , m_aGLWin . ctx ) )
2015-09-08 11:46:13 +01:00
{
2015-11-16 14:51:28 +00:00
SAL_WARN ( " vcl.opengl " , " OpenGLContext::makeCurrent failed "
" on drawable " < < m_aGLWin . win ) ;
2015-09-08 11:46:13 +01:00
return ;
}
2014-12-04 22:17:58 -05:00
}
# endif
windows opengl: make sure mpLastContext is indeed the current context
There were two problems here:
1) The OpenGLContext ctor registered the instance on the list of
contexts, but platform-specific call (e.g. wglMakeCurrent()) was only
made later. Add a registerAsCurrent() member function that helps
ensuring that the last item in the context list is indeed the current
context.
2) OpenGLContext::prepareForYield() is called without the solar mutex
being locked, but it still assumes that the last context in the context
list is the thread's current context, which may not be true. The result
is that during JunitTest_sd_unoapi, we end up in a situation like:
debug:4640:5240: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA65F8
debug:4640:7944: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 000D0003, pSVData->maGDIData.mpLastContext is 00FA6C70
debug:4640:5240: OpenGLContext::prepareForYield: start, wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA6C70
I.e. one thread registers as current, an other registers as current, too (while
the other thread has the solar mutex), then once the original thread wants to
release the solar mutex, the real current context and the last item in the
context list won't match, so the assert at the end of prepareForYield() will
fail.
Fix this by releasing the GL context in WinSalInstance::DestroyFrame().
With this, JunitTest_sd_unoapi passes on Windows with GL enabled.
Change-Id: Icfb9c65c871586b5df69b5a2ab3aa91843dfc799
Reviewed-on: https://gerrit.libreoffice.org/18473
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
Tested-by: Michael Meeks <michael.meeks@collabora.com>
2015-09-10 17:25:27 +02:00
registerAsCurrent ( ) ;
}
2016-01-05 16:17:41 +00:00
rtl : : Reference < OpenGLContext > OpenGLContext : : getVCLContext ( bool bMakeIfNecessary )
{
ImplSVData * pSVData = ImplGetSVData ( ) ;
OpenGLContext * pContext = pSVData - > maGDIData . mpLastContext ;
while ( pContext )
{
// check if this context is usable
if ( pContext - > isInitialized ( ) & & pContext - > isVCLOnly ( ) )
break ;
pContext = pContext - > mpPrevContext ;
}
rtl : : Reference < OpenGLContext > xContext ;
if ( ! pContext & & bMakeIfNecessary )
{
// create our magic fallback window context.
xContext = ImplGetDefaultContextWindow ( ) - > GetGraphics ( ) - > GetOpenGLContext ( ) ;
assert ( xContext . is ( ) ) ;
}
else
xContext = pContext ;
if ( xContext . is ( ) )
xContext - > makeCurrent ( ) ;
return xContext ;
}
/*
* We don ' t care what context we have , but we want one that is live ,
* ie . not reset underneath us , and is setup for VCL usage - ideally
* not swapping context at all .
*/
void OpenGLContext : : makeVCLCurrent ( )
{
getVCLContext ( true ) ;
}
windows opengl: make sure mpLastContext is indeed the current context
There were two problems here:
1) The OpenGLContext ctor registered the instance on the list of
contexts, but platform-specific call (e.g. wglMakeCurrent()) was only
made later. Add a registerAsCurrent() member function that helps
ensuring that the last item in the context list is indeed the current
context.
2) OpenGLContext::prepareForYield() is called without the solar mutex
being locked, but it still assumes that the last context in the context
list is the thread's current context, which may not be true. The result
is that during JunitTest_sd_unoapi, we end up in a situation like:
debug:4640:5240: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA65F8
debug:4640:7944: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 000D0003, pSVData->maGDIData.mpLastContext is 00FA6C70
debug:4640:5240: OpenGLContext::prepareForYield: start, wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA6C70
I.e. one thread registers as current, an other registers as current, too (while
the other thread has the solar mutex), then once the original thread wants to
release the solar mutex, the real current context and the last item in the
context list won't match, so the assert at the end of prepareForYield() will
fail.
Fix this by releasing the GL context in WinSalInstance::DestroyFrame().
With this, JunitTest_sd_unoapi passes on Windows with GL enabled.
Change-Id: Icfb9c65c871586b5df69b5a2ab3aa91843dfc799
Reviewed-on: https://gerrit.libreoffice.org/18473
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
Tested-by: Michael Meeks <michael.meeks@collabora.com>
2015-09-10 17:25:27 +02:00
void OpenGLContext : : registerAsCurrent ( )
{
ImplSVData * pSVData = ImplGetSVData ( ) ;
2015-01-06 16:09:09 +00:00
// move the context to the end of the contexts list
2014-12-04 22:17:58 -05:00
static int nSwitch = 0 ;
2015-11-20 10:14:49 +01:00
VCL_GL_INFO ( " ******* CONTEXT SWITCH " < < + + nSwitch < < " ********* " ) ;
2014-12-04 22:17:58 -05:00
if ( mpNextContext )
2014-11-26 09:22:25 -05:00
{
2014-12-04 22:17:58 -05:00
if ( mpPrevContext )
mpPrevContext - > mpNextContext = mpNextContext ;
else
pSVData - > maGDIData . mpFirstContext = mpNextContext ;
mpNextContext - > mpPrevContext = mpPrevContext ;
2014-11-26 09:22:25 -05:00
2014-12-04 22:17:58 -05:00
mpPrevContext = pSVData - > maGDIData . mpLastContext ;
2015-11-10 10:28:29 +01:00
mpNextContext = nullptr ;
2014-12-04 22:17:58 -05:00
pSVData - > maGDIData . mpLastContext - > mpNextContext = this ;
pSVData - > maGDIData . mpLastContext = this ;
2014-11-26 09:22:25 -05:00
}
2014-04-28 09:57:29 +02:00
}
2014-07-13 07:52:51 +02:00
void OpenGLContext : : resetCurrent ( )
{
2014-12-04 22:25:56 -05:00
clearCurrent ( ) ;
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-07-13 07:52:51 +02:00
# if defined( WNT )
2015-09-01 18:38:27 +02:00
wglMakeCurrent ( NULL , NULL ) ;
2014-07-16 08:02:32 +02:00
# elif defined( MACOSX )
2015-05-08 23:46:54 +02:00
( void ) this ; // loplugin:staticmethods
2015-12-08 13:58:27 +02:00
[ NSOpenGLContext clearCurrentContext ] ;
2014-12-22 19:10:59 +01:00
# elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
2014-07-13 07:52:51 +02:00
// nothing
# elif defined( UNX )
2015-09-07 16:39:04 +02:00
if ( m_aGLWin . dpy )
2015-11-10 10:28:29 +01:00
glXMakeCurrent ( m_aGLWin . dpy , None , nullptr ) ;
2014-07-13 07:52:51 +02:00
# endif
}
2014-04-27 12:20:13 +02:00
void OpenGLContext : : swapBuffers ( )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-04-27 12:47:52 +02:00
# if defined( WNT )
2014-04-27 12:20:13 +02:00
SwapBuffers ( m_aGLWin . hDC ) ;
2014-07-16 08:02:32 +02:00
# elif defined( MACOSX )
2014-09-01 01:59:57 +02:00
NSOpenGLView * pView = getOpenGLView ( ) ;
2015-12-08 13:58:27 +02:00
[ [ pView openGLContext ] flushBuffer ] ;
2014-12-22 19:10:59 +01:00
# elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
2014-04-27 12:47:52 +02:00
// nothing
2014-04-27 12:20:13 +02:00
# elif defined( UNX )
2015-11-16 14:51:28 +00:00
glXSwapBuffers ( m_aGLWin . dpy , m_aGLWin . win ) ;
2014-04-27 12:20:13 +02:00
# endif
2015-11-13 12:00:59 +00:00
static bool bSleep = getenv ( " SAL_GL_SLEEP_ON_SWAP " ) ;
if ( bSleep )
{
// half a second.
TimeValue aSleep ( 0 , 500 * 1000 * 1000 ) ;
osl : : Thread : : wait ( aSleep ) ;
}
2014-04-27 12:20:13 +02:00
}
2014-05-19 19:21:29 +02:00
void OpenGLContext : : sync ( )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-05-19 19:21:29 +02:00
# if defined( WNT )
// nothing
2014-12-22 19:10:59 +01:00
# elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
2015-05-08 23:46:54 +02:00
( void ) this ; // loplugin:staticmethods
2014-05-19 19:21:29 +02:00
// nothing
# elif defined( UNX )
glXWaitGL ( ) ;
XSync ( m_aGLWin . dpy , false ) ;
# endif
}
void OpenGLContext : : show ( )
{
if ( m_pChildWindow )
m_pChildWindow - > Show ( ) ;
2015-02-15 20:41:33 +00:00
else if ( m_xWindow )
m_xWindow - > Show ( ) ;
2014-05-19 19:21:29 +02:00
}
2014-08-08 01:55:33 +02:00
SystemChildWindow * OpenGLContext : : getChildWindow ( )
{
return m_pChildWindow ;
}
const SystemChildWindow * OpenGLContext : : getChildWindow ( ) const
{
return m_pChildWindow ;
}
2014-08-29 11:55:23 +02:00
bool OpenGLContext : : supportMultiSampling ( ) const
{
return m_aGLWin . bMultiSampleSupported ;
}
2014-09-01 01:59:57 +02:00
# if defined(MACOSX)
NSOpenGLView * OpenGLContext : : getOpenGLView ( )
{
return reinterpret_cast < NSOpenGLView * > ( m_pChildWindow - > GetSystemData ( ) - > mpNSView ) ;
}
# endif
2014-08-29 11:55:23 +02:00
2014-12-04 22:25:56 -05:00
bool OpenGLContext : : BindFramebuffer ( OpenGLFramebuffer * pFramebuffer )
2014-11-26 09:22:25 -05:00
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2014-11-26 09:22:25 -05:00
if ( pFramebuffer ! = mpCurrentFramebuffer )
{
if ( pFramebuffer )
pFramebuffer - > Bind ( ) ;
else
2015-04-01 08:33:09 +02:00
OpenGLFramebuffer : : Unbind ( ) ;
2014-11-26 09:22:25 -05:00
mpCurrentFramebuffer = pFramebuffer ;
}
return true ;
}
bool OpenGLContext : : AcquireDefaultFramebuffer ( )
{
2015-11-10 10:28:29 +01:00
return BindFramebuffer ( nullptr ) ;
2014-11-26 09:22:25 -05:00
}
OpenGLFramebuffer * OpenGLContext : : AcquireFramebuffer ( const OpenGLTexture & rTexture )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-11-10 10:28:29 +01:00
OpenGLFramebuffer * pFramebuffer = nullptr ;
OpenGLFramebuffer * pFreeFbo = nullptr ;
OpenGLFramebuffer * pSameSizeFbo = nullptr ;
2014-11-26 09:22:25 -05:00
// check if there is already a framebuffer attached to that texture
pFramebuffer = mpLastFramebuffer ;
while ( pFramebuffer )
{
if ( pFramebuffer - > IsAttached ( rTexture ) )
break ;
2014-12-04 22:25:56 -05:00
if ( ! pFreeFbo & & pFramebuffer - > IsFree ( ) )
pFreeFbo = pFramebuffer ;
if ( ! pSameSizeFbo & &
pFramebuffer - > GetWidth ( ) = = rTexture . GetWidth ( ) & &
pFramebuffer - > GetHeight ( ) = = rTexture . GetHeight ( ) )
pSameSizeFbo = pFramebuffer ;
2014-11-26 09:22:25 -05:00
pFramebuffer = pFramebuffer - > mpPrevFramebuffer ;
}
2014-12-04 22:25:56 -05:00
// else use any framebuffer having the same size
if ( ! pFramebuffer & & pSameSizeFbo )
pFramebuffer = pSameSizeFbo ;
2014-11-26 09:22:25 -05:00
// else use the first free framebuffer
2014-12-04 22:25:56 -05:00
if ( ! pFramebuffer & & pFreeFbo )
pFramebuffer = pFreeFbo ;
2014-11-26 09:22:25 -05:00
2014-12-04 22:25:56 -05:00
// if there isn't any free one, create a new one if the limit isn't reached
if ( ! pFramebuffer & & mnFramebufferCount < MAX_FRAMEBUFFER_COUNT )
2014-11-26 09:22:25 -05:00
{
2014-12-04 22:25:56 -05:00
mnFramebufferCount + + ;
2014-11-26 09:22:25 -05:00
pFramebuffer = new OpenGLFramebuffer ( ) ;
if ( mpLastFramebuffer )
{
pFramebuffer - > mpPrevFramebuffer = mpLastFramebuffer ;
mpLastFramebuffer - > mpNextFramebuffer = pFramebuffer ;
mpLastFramebuffer = pFramebuffer ;
}
else
{
mpFirstFramebuffer = pFramebuffer ;
mpLastFramebuffer = pFramebuffer ;
}
}
2014-12-04 22:25:56 -05:00
// last try, use any framebuffer
// TODO order the list of framebuffers as a LRU
if ( ! pFramebuffer )
pFramebuffer = mpFirstFramebuffer ;
assert ( pFramebuffer ) ;
BindFramebuffer ( pFramebuffer ) ;
pFramebuffer - > AttachTexture ( rTexture ) ;
2014-11-26 09:22:25 -05:00
glViewport ( 0 , 0 , rTexture . GetWidth ( ) , rTexture . GetHeight ( ) ) ;
2015-11-17 09:20:25 +02:00
CHECK_GL_ERROR ( ) ;
2014-11-26 09:22:25 -05:00
return pFramebuffer ;
}
2015-08-31 12:11:50 +01:00
// FIXME: this method is rather grim from a perf. perspective.
// We should instead (eventually) use pointers to associate the
// framebuffer and texture cleanly.
void OpenGLContext : : UnbindTextureFromFramebuffers ( GLuint nTexture )
{
OpenGLFramebuffer * pFramebuffer ;
// see if there is a framebuffer attached to that texture
pFramebuffer = mpLastFramebuffer ;
while ( pFramebuffer )
{
if ( pFramebuffer - > IsAttached ( nTexture ) )
{
BindFramebuffer ( pFramebuffer ) ;
pFramebuffer - > DetachTexture ( ) ;
}
pFramebuffer = pFramebuffer - > mpPrevFramebuffer ;
}
2015-12-31 22:12:59 +00:00
// Lets just check that no other context has a framebuffer
// with this texture - that would be bad ...
assert ( ! IsTextureAttachedAnywhere ( nTexture ) ) ;
}
/// Method for debugging; check texture is not already attached.
bool OpenGLContext : : IsTextureAttachedAnywhere ( GLuint nTexture )
{
ImplSVData * pSVData = ImplGetSVData ( ) ;
for ( auto * pCheck = pSVData - > maGDIData . mpLastContext ; pCheck ;
pCheck = pCheck - > mpPrevContext )
{
for ( auto pBuffer = pCheck - > mpLastFramebuffer ; pBuffer ;
pBuffer = pBuffer - > mpPrevFramebuffer )
{
if ( pBuffer - > IsAttached ( nTexture ) )
return true ;
}
}
return false ;
2015-08-31 12:11:50 +01:00
}
2014-11-26 09:22:25 -05:00
void OpenGLContext : : ReleaseFramebuffer ( OpenGLFramebuffer * pFramebuffer )
{
if ( pFramebuffer )
pFramebuffer - > DetachTexture ( ) ;
}
2014-12-04 22:25:56 -05:00
void OpenGLContext : : ReleaseFramebuffer ( const OpenGLTexture & rTexture )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-08-29 23:15:54 +01:00
2015-09-15 14:07:27 +01:00
if ( ! rTexture ) // no texture to release.
return ;
2014-12-04 22:25:56 -05:00
OpenGLFramebuffer * pFramebuffer = mpLastFramebuffer ;
while ( pFramebuffer )
{
if ( pFramebuffer - > IsAttached ( rTexture ) )
{
BindFramebuffer ( pFramebuffer ) ;
pFramebuffer - > DetachTexture ( ) ;
2015-08-29 23:15:54 +01:00
if ( mpCurrentFramebuffer = = pFramebuffer )
2015-11-10 10:28:29 +01:00
BindFramebuffer ( nullptr ) ;
2014-12-04 22:25:56 -05:00
}
pFramebuffer = pFramebuffer - > mpPrevFramebuffer ;
}
}
void OpenGLContext : : ReleaseFramebuffers ( )
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-08-29 23:15:54 +01:00
2014-12-04 22:25:56 -05:00
OpenGLFramebuffer * pFramebuffer = mpLastFramebuffer ;
while ( pFramebuffer )
{
2015-06-12 02:45:54 +02:00
if ( ! pFramebuffer - > IsFree ( ) )
{
BindFramebuffer ( pFramebuffer ) ;
pFramebuffer - > DetachTexture ( ) ;
}
2014-12-04 22:25:56 -05:00
pFramebuffer = pFramebuffer - > mpPrevFramebuffer ;
}
2015-11-10 10:28:29 +01:00
BindFramebuffer ( nullptr ) ;
2014-12-04 22:25:56 -05:00
}
2015-09-13 12:15:13 +02:00
OpenGLProgram * OpenGLContext : : GetProgram ( const OUString & rVertexShader , const OUString & rFragmentShader , const rtl : : OString & preamble )
2014-11-28 14:56:08 -05:00
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-10-19 09:55:57 +03:00
// We cache the shader programs in a per-process run-time cache
// based on only the names and the preamble. We don't expect
// shader source files to change during the lifetime of a
// LibreOffice process.
rtl : : OString aNameBasedKey = OUStringToOString ( rVertexShader + " + " + rFragmentShader , RTL_TEXTENCODING_UTF8 ) + " + " + preamble ;
if ( ! aNameBasedKey . isEmpty ( ) )
{
ProgramCollection : : iterator it = maPrograms . find ( aNameBasedKey ) ;
2015-09-13 12:15:13 +02:00
if ( it ! = maPrograms . end ( ) )
return it - > second . get ( ) ;
}
2014-11-28 14:56:08 -05:00
2015-10-19 09:55:57 +03:00
// Binary shader programs are cached persistently (between
// LibreOffice process instances) based on a hash of their source
// code, as the source code can and will change between
// LibreOffice versions even if the shader names don't change.
rtl : : OString aPersistentKey = OpenGLHelper : : GetDigest ( rVertexShader , rFragmentShader , preamble ) ;
2015-09-12 12:21:12 +01:00
std : : shared_ptr < OpenGLProgram > pProgram = std : : make_shared < OpenGLProgram > ( ) ;
2015-10-19 09:55:57 +03:00
if ( ! pProgram - > Load ( rVertexShader , rFragmentShader , preamble , aPersistentKey ) )
2015-11-10 10:28:29 +01:00
return nullptr ;
2014-11-28 14:56:08 -05:00
2015-10-19 09:55:57 +03:00
maPrograms . insert ( std : : make_pair ( aNameBasedKey , pProgram ) ) ;
2015-04-23 13:47:02 +01:00
return pProgram . get ( ) ;
2014-11-28 14:56:08 -05:00
}
2015-01-20 14:48:48 +01:00
OpenGLProgram * OpenGLContext : : UseProgram ( const OUString & rVertexShader , const OUString & rFragmentShader , const OString & preamble )
2014-11-28 14:56:08 -05:00
{
2015-08-20 17:03:30 +01:00
OpenGLZone aZone ;
2015-01-20 14:48:48 +01:00
OpenGLProgram * pProgram = GetProgram ( rVertexShader , rFragmentShader , preamble ) ;
2014-11-28 14:56:08 -05:00
if ( pProgram = = mpCurrentProgram )
return pProgram ;
mpCurrentProgram = pProgram ;
2015-09-10 11:39:44 +02:00
if ( ! mpCurrentProgram )
{
SAL_WARN ( " vcl.opengl " , " OpenGLContext::UseProgram: mpCurrentProgram is 0 " ) ;
2015-11-10 10:28:29 +01:00
return nullptr ;
2015-09-10 11:39:44 +02:00
}
2014-11-28 14:56:08 -05:00
mpCurrentProgram - > Use ( ) ;
return mpCurrentProgram ;
}
2015-11-16 20:31:58 +02:00
void OpenGLContext : : UseNoProgram ( )
{
2015-11-19 14:15:35 +01:00
if ( mpCurrentProgram = = nullptr )
2015-11-16 20:31:58 +02:00
return ;
2015-11-19 14:15:35 +01:00
mpCurrentProgram = nullptr ;
2015-11-16 20:31:58 +02:00
glUseProgram ( 0 ) ;
CHECK_GL_ERROR ( ) ;
}
2014-03-14 18:51:06 +01:00
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */