1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <vcl/opengl/OpenGLContext.hxx>
11 #include <vcl/opengl/OpenGLHelper.hxx>
12 #include <vcl/syschild.hxx>
13 #include <vcl/sysdata.hxx>
15 #include <boost/scoped_array.hpp>
16 #include <boost/make_shared.hpp>
17 #include <vcl/pngwrite.hxx>
18 #include <vcl/bmpacc.hxx>
19 #include <vcl/graph.hxx>
23 #include "OpenGLWrapper.hxx"
28 #include <win/saldata.hxx>
33 #include <opengl/framebuffer.hxx>
34 #include <opengl/program.hxx>
35 #include <opengl/texture.hxx>
36 #include <opengl/zone.hxx>
38 using namespace com::sun::star
;
40 #define MAX_FRAMEBUFFER_COUNT 30
42 // TODO use rtl::Static instead of 'static'
43 #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
44 static std::vector
<GLXContext
> g_vShareList
;
46 static std::vector
<HGLRC
> g_vShareList
;
51 #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
56 OpenGLContext::OpenGLContext():
61 mbRequestLegacyContext(false),
62 mbUseDoubleBufferedRendering(true),
63 mbRequestVirtualDevice(false),
64 mnFramebufferCount(0),
65 mpCurrentFramebuffer(NULL
),
66 mpFirstFramebuffer(NULL
),
67 mpLastFramebuffer(NULL
),
68 mpCurrentProgram(NULL
),
73 VCL_GL_INFO("vcl.opengl", "new context: " << this);
75 #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
79 ImplSVData
* pSVData
= ImplGetSVData();
80 if( pSVData
->maGDIData
.mpLastContext
)
82 pSVData
->maGDIData
.mpLastContext
->mpNextContext
= this;
83 mpPrevContext
= pSVData
->maGDIData
.mpLastContext
;
86 pSVData
->maGDIData
.mpFirstContext
= this;
87 pSVData
->maGDIData
.mpLastContext
= this;
89 // FIXME: better hope we call 'makeCurrent' soon to preserve
90 // the invariant that the last item is the current context.
93 OpenGLContext::~OpenGLContext()
95 VCL_GL_INFO("vcl.opengl", "delete context: " << this);
96 assert (mnRefCount
== 0);
98 mnRefCount
= 1; // guard the shutdown paths.
101 ImplSVData
* pSVData
= ImplGetSVData();
103 mpPrevContext
->mpNextContext
= mpNextContext
;
105 pSVData
->maGDIData
.mpFirstContext
= mpNextContext
;
107 mpNextContext
->mpPrevContext
= mpPrevContext
;
109 pSVData
->maGDIData
.mpLastContext
= mpPrevContext
;
111 m_pChildWindow
.disposeAndClear();
112 assert (mnRefCount
== 1);
115 // release associated child-window if we have one
116 void OpenGLContext::dispose()
119 m_pChildWindow
.disposeAndClear();
122 rtl::Reference
<OpenGLContext
> OpenGLContext::Create()
124 return rtl::Reference
<OpenGLContext
>(new OpenGLContext
);
127 void OpenGLContext::requestLegacyContext()
129 mbRequestLegacyContext
= true;
132 void OpenGLContext::requestSingleBufferedRendering()
134 mbUseDoubleBufferedRendering
= false;
137 void OpenGLContext::requestVirtualDevice()
139 mbRequestVirtualDevice
= true;
142 #if defined( _WIN32 )
143 static LRESULT CALLBACK
WndProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
165 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
169 int InitTempWindow(HWND
*hwnd
, int width
, int height
, const PIXELFORMATDESCRIPTOR
& inPfd
, GLWindow
& glWin
)
173 PIXELFORMATDESCRIPTOR pfd
= inPfd
;
178 wc
.lpfnWndProc
= WndProc
;
179 wc
.cbClsExtra
= wc
.cbWndExtra
= 0;
183 wc
.hbrBackground
= NULL
;
184 wc
.lpszMenuName
= NULL
;
185 wc
.lpszClassName
= (LPCSTR
)"GLRenderer";
187 *hwnd
= CreateWindow(wc
.lpszClassName
, NULL
, WS_DISABLED
, 0, 0, width
, height
, NULL
, NULL
, wc
.hInstance
, NULL
);
188 glWin
.hDC
= GetDC(*hwnd
);
189 pfmt
= ChoosePixelFormat(glWin
.hDC
, &pfd
);
194 ret
= SetPixelFormat(glWin
.hDC
, pfmt
, &pfd
);
199 glWin
.hRC
= wglCreateContext(glWin
.hDC
);
204 ret
= wglMakeCurrent(glWin
.hDC
, glWin
.hRC
);
214 bool WGLisExtensionSupported(const char *extension
)
218 const size_t extlen
= strlen(extension
);
219 const char *supported
= NULL
;
221 // Try To Use wglGetExtensionStringARB On Current DC, If Possible
222 PROC wglGetExtString
= wglGetProcAddress("wglGetExtensionsStringARB");
225 supported
= ((char*(__stdcall
*)(HDC
))wglGetExtString
)(wglGetCurrentDC());
226 // If That Failed, Try Standard Opengl Extensions String
227 if (supported
== NULL
)
228 supported
= (char*)glGetString(GL_EXTENSIONS
);
229 // If That Failed Too, Must Be No Extensions Supported
230 if (supported
== NULL
)
233 // Begin Examination At Start Of String, Increment By 1 On False Match
234 for (const char* p
= supported
; ; p
++)
236 // Advance p Up To The Next Possible Match
237 p
= strstr(p
, extension
);
240 return 0; // No Match
242 // Make Sure That Match Is At The Start Of The String Or That
243 // The Previous Char Is A Space, Or Else We Could Accidentally
244 // Match "wglFunkywglExtension" With "wglExtension"
246 // Also, Make Sure That The Following Character Is Space Or NULL
247 // Or Else "wglExtensionTwo" Might Match "wglExtension"
248 if ((p
==supported
|| p
[-1]==' ') && (p
[extlen
]=='\0' || p
[extlen
]==' '))
253 bool InitMultisample(const PIXELFORMATDESCRIPTOR
& pfd
, int& rPixelFormat
,
254 bool bUseDoubleBufferedRendering
, bool bRequestVirtualDevice
)
260 //create a temp windwo to check whether support multi-sample, if support, get the format
261 if (InitTempWindow(&hWnd
, 1, 1, pfd
, glWin
) < 0)
263 SAL_WARN("vcl.opengl", "Can't create temp window to test");
267 // See If The String Exists In WGL!
268 if (!WGLisExtensionSupported("WGL_ARB_multisample"))
270 SAL_WARN("vcl.opengl", "Device doesn't support multi sample");
273 // Get Our Pixel Format
274 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB
= (PFNWGLCHOOSEPIXELFORMATARBPROC
)wglGetProcAddress("wglChoosePixelFormatARB");
275 if (!wglChoosePixelFormatARB
)
279 // Get Our Current Device Context
280 HDC hDC
= GetDC(hWnd
);
285 float fAttributes
[] = {0,0};
286 // These Attributes Are The Bits We Want To Test For In Our Sample
287 // Everything Is Pretty Standard, The Only One We Want To
288 // Really Focus On Is The SAMPLE BUFFERS ARB And WGL SAMPLES
289 // These Two Are Going To Do The Main Testing For Whether Or Not
290 // We Support Multisampling On This Hardware.
293 WGL_DOUBLE_BUFFER_ARB
,GL_TRUE
,
294 WGL_DRAW_TO_WINDOW_ARB
,GL_TRUE
,
295 WGL_SUPPORT_OPENGL_ARB
,GL_TRUE
,
296 WGL_ACCELERATION_ARB
,WGL_FULL_ACCELERATION_ARB
,
297 WGL_COLOR_BITS_ARB
,24,
298 WGL_ALPHA_BITS_ARB
,8,
299 WGL_DEPTH_BITS_ARB
,24,
300 WGL_STENCIL_BITS_ARB
,0,
301 WGL_SAMPLE_BUFFERS_ARB
,GL_TRUE
,
306 if (!bUseDoubleBufferedRendering
)
307 iAttributes
[1] = GL_FALSE
;
309 if (bRequestVirtualDevice
)
311 iAttributes
[2] = WGL_DRAW_TO_BITMAP_ARB
;
314 bool bArbMultisampleSupported
= true;
316 // First We Check To See If We Can Get A Pixel Format For 4 Samples
317 valid
= wglChoosePixelFormatARB(hDC
, iAttributes
, fAttributes
, 1, &pixelFormat
, &numFormats
);
318 // If We Returned True, And Our Format Count Is Greater Than 1
319 if (valid
&& numFormats
>= 1)
321 bArbMultisampleSupported
= true;
322 rPixelFormat
= pixelFormat
;
323 wglMakeCurrent(NULL
, NULL
);
324 wglDeleteContext(glWin
.hRC
);
325 ReleaseDC(hWnd
, glWin
.hDC
);
327 return bArbMultisampleSupported
;
329 // Our Pixel Format With 4 Samples Failed, Test For 2 Samples
331 valid
= wglChoosePixelFormatARB(hDC
, iAttributes
, fAttributes
, 1, &pixelFormat
, &numFormats
);
332 if (valid
&& numFormats
>= 1)
334 bArbMultisampleSupported
= true;
335 rPixelFormat
= pixelFormat
;
336 wglMakeCurrent(NULL
, NULL
);
337 wglDeleteContext(glWin
.hRC
);
338 ReleaseDC(hWnd
, glWin
.hDC
);
340 return bArbMultisampleSupported
;
342 // Return The Valid Format
343 wglMakeCurrent(NULL
, NULL
);
344 wglDeleteContext(glWin
.hRC
);
345 ReleaseDC(hWnd
, glWin
.hDC
);
348 return bArbMultisampleSupported
;
356 const char* getSeverityString(GLenum severity
)
360 case GL_DEBUG_SEVERITY_LOW
:
362 case GL_DEBUG_SEVERITY_MEDIUM
:
364 case GL_DEBUG_SEVERITY_HIGH
:
373 const char* getSourceString(GLenum source
)
377 case GL_DEBUG_SOURCE_API
:
379 case GL_DEBUG_SOURCE_SHADER_COMPILER
:
380 return "shader compiler";
381 case GL_DEBUG_SOURCE_WINDOW_SYSTEM
:
382 return "window system";
383 case GL_DEBUG_SOURCE_THIRD_PARTY
:
384 return "third party";
385 case GL_DEBUG_SOURCE_APPLICATION
:
386 return "Libreoffice";
387 case GL_DEBUG_SOURCE_OTHER
:
396 const char* getTypeString(GLenum type
)
400 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR
:
401 return "deprecated behavior";
402 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR
:
403 return "undefined behavior";
404 case GL_DEBUG_TYPE_PERFORMANCE
:
405 return "performance";
406 case GL_DEBUG_TYPE_PORTABILITY
:
407 return "portability";
408 case GL_DEBUG_TYPE_MARKER
:
410 case GL_DEBUG_TYPE_PUSH_GROUP
:
412 case GL_DEBUG_TYPE_POP_GROUP
:
414 case GL_DEBUG_TYPE_OTHER
:
416 case GL_DEBUG_TYPE_ERROR
:
429 debug_callback(GLenum source
, GLenum type
, GLuint id
,
430 GLenum severity
, GLsizei
, const GLchar
* message
, GLvoid
* )
432 // ignore Nvidia's : "Program/shader state performance warning: Fragment Shader is going to be recompiled because the shader key based on GL state mismatches."
433 // the GLSL compiler is a bit too aggressive in optimizing the state based on the current OpenGL state
437 SAL_WARN("vcl.opengl", "OpenGL debug message: source: " << getSourceString(source
) << ", type: "
438 << getTypeString(type
) << ", id: " << id
<< ", severity: " << getSeverityString(severity
) << " with message: " << message
);
445 #if defined UNX && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
450 int unxErrorHandler(Display
* dpy
, XErrorEvent
* event
)
455 XGetErrorText(dpy
, event
->error_code
, err
, 256);
456 XGetErrorText(dpy
, event
->request_code
, req
, 256);
457 XGetErrorText(dpy
, event
->minor_code
, minor
, 256);
458 SAL_WARN("vcl.opengl", "Error: " << err
<< ", Req: " << req
<< ", Minor: " << minor
);
463 typedef int (*errorHandler
)(Display
* /*dpy*/, XErrorEvent
* /*evnt*/);
465 class TempErrorHandler
468 errorHandler oldErrorHandler
;
472 TempErrorHandler(Display
* dpy
, errorHandler newErrorHandler
):
479 oldErrorHandler
= XSetErrorHandler(newErrorHandler
);
487 // sync so that we possibly get an XError
490 XSetErrorHandler(oldErrorHandler
);
491 XUnlockDisplay(mdpy
);
496 static bool errorTriggered
;
497 int oglErrorHandler( Display
* /*dpy*/, XErrorEvent
* /*evnt*/ )
499 errorTriggered
= true;
504 GLXFBConfig
* getFBConfigForPixmap(Display
* dpy
, int& nBestFBC
, bool bUseDoubleBufferedRendering
, int screen
)
506 static int visual_attribs
[] =
508 GLX_DOUBLEBUFFER
, False
,
509 GLX_DRAWABLE_TYPE
, GLX_PIXMAP_BIT
,
510 GLX_X_RENDERABLE
, True
,
516 GLX_X_VISUAL_TYPE
, GLX_TRUE_COLOR
,
520 if (bUseDoubleBufferedRendering
)
521 visual_attribs
[1] = True
;
524 GLXFBConfig
* pFBC
= glXChooseFBConfig( dpy
,
526 visual_attribs
, &fbCount
);
530 SAL_WARN("vcl.opengl", "no suitable fb format found");
534 int best_num_samp
= -1;
535 for(int i
= 0; i
< fbCount
; ++i
)
537 // pick the one with the most samples per pixel
540 glXGetFBConfigAttrib( dpy
, pFBC
[i
], GLX_SAMPLE_BUFFERS
, &nSampleBuf
);
541 glXGetFBConfigAttrib( dpy
, pFBC
[i
], GLX_SAMPLES
, &nSamples
);
543 if ( nBestFBC
< 0 || (nSampleBuf
&& ( nSamples
> best_num_samp
)) )
546 best_num_samp
= nSamples
;
554 GLXFBConfig
* getFBConfig(Display
* dpy
, Window win
, int& nBestFBC
, bool bUseDoubleBufferedRendering
, bool bWithSameVisualID
)
558 if( dpy
== 0 || !glXQueryExtension( dpy
, NULL
, NULL
) )
561 VCL_GL_INFO("vcl.opengl", "window: " << win
);
563 XWindowAttributes xattr
;
564 if( !XGetWindowAttributes( dpy
, win
, &xattr
) )
566 SAL_WARN("vcl.opengl", "Failed to get window attributes for fbconfig " << win
);
571 int screen
= XScreenNumberOfScreen( xattr
.screen
);
573 // TODO: moggi: Select colour channel depth based on visual attributes, not hardcoded */
574 static int visual_attribs
[] =
576 GLX_DOUBLEBUFFER
, True
,
577 GLX_X_RENDERABLE
, True
,
583 GLX_X_VISUAL_TYPE
, GLX_TRUE_COLOR
,
587 if (!bUseDoubleBufferedRendering
)
588 visual_attribs
[1] = False
;
591 GLXFBConfig
* pFBC
= glXChooseFBConfig( dpy
,
593 visual_attribs
, &fbCount
);
597 SAL_WARN("vcl.opengl", "no suitable fb format found");
601 int best_num_samp
= -1;
602 for(int i
= 0; i
< fbCount
; ++i
)
604 XVisualInfo
* pVi
= glXGetVisualFromFBConfig( dpy
, pFBC
[i
] );
605 if(pVi
&& (!bWithSameVisualID
|| (xattr
.visual
&& pVi
->visualid
== xattr
.visual
->visualid
)) )
607 // pick the one with the most samples per pixel
610 glXGetFBConfigAttrib( dpy
, pFBC
[i
], GLX_SAMPLE_BUFFERS
, &nSampleBuf
);
611 glXGetFBConfigAttrib( dpy
, pFBC
[i
], GLX_SAMPLES
, &nSamples
);
613 if ( nBestFBC
< 0 || (nSampleBuf
&& ( nSamples
> best_num_samp
)) )
616 best_num_samp
= nSamples
;
625 // we need them before glew can initialize them
626 // glew needs an OpenGL context so we need to get the address manually
627 void initOpenGLFunctionPointers()
629 glXChooseFBConfig
= reinterpret_cast<GLXFBConfig
*(*)(Display
*dpy
, int screen
, const int *attrib_list
, int *nelements
)>(glXGetProcAddressARB(reinterpret_cast<GLubyte
const *>("glXChooseFBConfig")));
630 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
631 glXGetFBConfigAttrib
= reinterpret_cast<int(*)(Display
*dpy
, GLXFBConfig config
, int attribute
, int* value
)>(glXGetProcAddressARB(reinterpret_cast<GLubyte
const *>("glXGetFBConfigAttrib")));
632 glXCreateContextAttribsARB
= reinterpret_cast<GLXContext(*)(Display
*, GLXFBConfig
, GLXContext
, Bool
, const int*)>(glXGetProcAddressARB(reinterpret_cast<const GLubyte
*>("glXCreateContextAttribsARB")));
633 glXCreatePixmap
= reinterpret_cast<GLXPixmap(*)(Display
*, GLXFBConfig
, Pixmap
, const int*)>(glXGetProcAddressARB(reinterpret_cast<const GLubyte
*>("glXCreatePixmap")));
636 Visual
* getVisual(Display
* dpy
, Window win
)
640 initOpenGLFunctionPointers();
642 XWindowAttributes xattr
;
643 if( !XGetWindowAttributes( dpy
, win
, &xattr
) )
645 SAL_WARN("vcl.opengl", "Failed to get window attributes for getVisual " << win
);
648 VCL_GL_INFO("vcl.opengl", "using VisualID " << xattr
.visual
);
656 bool OpenGLContext::init( vcl::Window
* pParent
)
663 m_xWindow
.reset(pParent
? nullptr : VclPtr
<vcl::Window
>::Create(nullptr, WB_NOBORDER
|WB_NODIALOGCONTROL
));
664 mpWindow
= pParent
? pParent
: m_xWindow
.get();
666 m_xWindow
->setPosSizePixel(0,0,0,0);
672 bool OpenGLContext::init(SystemChildWindow
* pChildWindow
)
682 mpWindow
= pChildWindow
->GetParent();
683 m_pChildWindow
= pChildWindow
;
688 #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
689 bool OpenGLContext::init(Display
* dpy
, Window win
, int screen
)
701 m_aGLWin
.screen
= screen
;
703 Visual
* pVisual
= getVisual(dpy
, win
);
705 initGLWindow(pVisual
);
710 bool OpenGLContext::init(Display
* dpy
, Pixmap pix
, unsigned int width
, unsigned int height
, int nScreen
)
718 initOpenGLFunctionPointers();
720 SAL_INFO("vcl.opengl", "init with pixmap");
722 m_aGLWin
.Width
= width
;
723 m_aGLWin
.Height
= height
;
725 const int attrib_list
[] = { GLX_TEXTURE_FORMAT_EXT
, GLX_TEXTURE_FORMAT_RGB_EXT
,
726 GLX_TEXTURE_TARGET_EXT
, GLX_TEXTURE_2D_EXT
,
729 GLXFBConfig
* config
= getFBConfigForPixmap(dpy
, best_fbc
, mbUseDoubleBufferedRendering
, nScreen
);
733 m_aGLWin
.vi
= glXGetVisualFromFBConfig( dpy
, config
[best_fbc
] );
734 m_aGLWin
.glPix
= glXCreatePixmap(dpy
, config
[best_fbc
], pix
, attrib_list
);
741 bool OpenGLContext::ImplInit()
750 GLXContext
pSharedCtx( NULL
);
752 TempErrorHandler
aErrorHandler(m_aGLWin
.dpy
, unxErrorHandler
);
755 VCL_GL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start");
757 if (!g_vShareList
.empty())
758 pSharedCtx
= g_vShareList
.front();
761 if (!mbPixmap
&& glXCreateContextAttribsARB
&& !mbRequestLegacyContext
)
764 GLXFBConfig
* pFBC
= getFBConfig(m_aGLWin
.dpy
, m_aGLWin
.win
, best_fbc
, mbUseDoubleBufferedRendering
, true);
770 int pContextAttribs
[] =
772 GLX_CONTEXT_MAJOR_VERSION_ARB
, 3,
773 GLX_CONTEXT_MINOR_VERSION_ARB
, 2,
776 m_aGLWin
.ctx
= glXCreateContextAttribsARB(m_aGLWin
.dpy
, pFBC
[best_fbc
], pSharedCtx
, GL_TRUE
, pContextAttribs
);
777 SAL_INFO_IF(m_aGLWin
.ctx
, "vcl.opengl", "created a 3.2 core context");
780 SAL_WARN("vcl.opengl", "unable to find correct FBC");
790 m_aGLWin
.ctx
= glXCreateContext(m_aGLWin
.dpy
,
798 g_vShareList
.push_back( m_aGLWin
.ctx
);
802 SAL_WARN("vcl.opengl", "unable to create GLX context");
806 if( !glXMakeCurrent( m_aGLWin
.dpy
, mbPixmap
? m_aGLWin
.glPix
: m_aGLWin
.win
, m_aGLWin
.ctx
) )
808 SAL_WARN("vcl.opengl", "unable to select current GLX context");
812 int glxMinor
, glxMajor
;
813 double nGLXVersion
= 0;
814 if( glXQueryVersion( m_aGLWin
.dpy
, &glxMajor
, &glxMinor
) )
815 nGLXVersion
= glxMajor
+ 0.1*glxMinor
;
816 SAL_INFO("vcl.opengl", "available GLX version: " << nGLXVersion
);
818 m_aGLWin
.GLExtensions
= glGetString( GL_EXTENSIONS
);
819 SAL_INFO("vcl.opengl", "available GL extensions: " << m_aGLWin
.GLExtensions
);
821 XWindowAttributes xWinAttr
;
824 m_aGLWin
.Width
= 0; // FIXME: correct ?
827 else if( !XGetWindowAttributes( m_aGLWin
.dpy
, m_aGLWin
.win
, &xWinAttr
) )
829 SAL_WARN("vcl.opengl", "Failed to get window attributes on " << m_aGLWin
.win
);
835 m_aGLWin
.Width
= xWinAttr
.width
;
836 m_aGLWin
.Height
= xWinAttr
.height
;
839 if( m_aGLWin
.HasGLXExtension("GLX_SGI_swap_control" ) )
842 typedef GLint (*glXSwapIntervalProc
)(GLint
);
843 glXSwapIntervalProc glXSwapInterval
= reinterpret_cast<glXSwapIntervalProc
>(glXGetProcAddress( reinterpret_cast<const GLubyte
*>("glXSwapIntervalSGI") ));
844 if( glXSwapInterval
)
846 TempErrorHandler
aLocalErrorHandler(m_aGLWin
.dpy
, oglErrorHandler
);
848 errorTriggered
= false;
850 glXSwapInterval( 1 );
853 SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?");
855 VCL_GL_INFO("vcl.opengl", "set swap interval to 1 (enable vsync)");
859 bool bRet
= InitGLEW();
862 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
869 #elif defined( _WIN32 )
871 bool OpenGLContext::init(HDC hDC
, HWND hWnd
)
877 m_aGLWin
.hWnd
= hWnd
;
881 bool OpenGLContext::ImplInit()
885 VCL_GL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start");
886 // PixelFormat tells Windows how we want things to be
887 PIXELFORMATDESCRIPTOR PixelFormatFront
=
889 sizeof(PIXELFORMATDESCRIPTOR
),
892 PFD_TYPE_RGBA
, // Request An RGBA Format
893 (BYTE
)32, // Select Our Color Depth
894 0, 0, 0, 0, 0, 0, // Color Bits Ignored
895 0, // No Alpha Buffer
896 0, // Shift Bit Ignored
897 0, // No Accumulation Buffer
898 0, 0, 0, 0, // Accumulation Bits Ignored
899 64, // 32 bit Z-BUFFER
901 0, // No Auxiliary Buffer
904 0, 0, 0 // Layer Masks Ignored
907 if (mbUseDoubleBufferedRendering
)
908 PixelFormatFront
.dwFlags
|= PFD_DOUBLEBUFFER
;
910 if (mbRequestVirtualDevice
)
911 PixelFormatFront
.dwFlags
|= PFD_DRAW_TO_BITMAP
;
913 PixelFormatFront
.dwFlags
|= PFD_DRAW_TO_WINDOW
;
915 // we must check whether can set the MSAA
917 bool bMultiSampleSupport
= InitMultisample(PixelFormatFront
, WindowPix
,
918 mbUseDoubleBufferedRendering
, mbRequestVirtualDevice
);
919 if (bMultiSampleSupport
&& WindowPix
!= 0)
921 m_aGLWin
.bMultiSampleSupported
= true;
925 WindowPix
= ChoosePixelFormat(m_aGLWin
.hDC
, &PixelFormatFront
);
926 #if OSL_DEBUG_LEVEL > 0
927 PIXELFORMATDESCRIPTOR pfd
;
928 DescribePixelFormat(m_aGLWin
.hDC
, WindowPix
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
929 SAL_WARN("vcl.opengl", "Render Target: Window: " << (int) ((pfd
.dwFlags
& PFD_DRAW_TO_WINDOW
) != 0) << ", Bitmap: " << (int) ((pfd
.dwFlags
& PFD_DRAW_TO_BITMAP
) != 0));
930 SAL_WARN("vcl.opengl", "Supports OpenGL: " << (int) ((pfd
.dwFlags
& PFD_SUPPORT_OPENGL
) != 0));
936 SAL_WARN("vcl.opengl", "Invalid pixelformat");
940 if (!SetPixelFormat(m_aGLWin
.hDC
, WindowPix
, &PixelFormatFront
))
942 ImplWriteLastError(GetLastError(), "SetPixelFormat in OpenGLContext::ImplInit");
943 SAL_WARN("vcl.opengl", "SetPixelFormat failed");
947 HGLRC hTempRC
= wglCreateContext(m_aGLWin
.hDC
);
950 ImplWriteLastError(GetLastError(), "wglCreateContext in OpenGLContext::ImplInit");
951 SAL_WARN("vcl.opengl", "wglCreateContext failed");
955 if (!wglMakeCurrent(m_aGLWin
.hDC
, hTempRC
))
957 ImplWriteLastError(GetLastError(), "wglMakeCurrent in OpenGLContext::ImplInit");
958 SAL_WARN("vcl.opengl", "wglMakeCurrent failed");
964 wglMakeCurrent(NULL
, NULL
);
965 wglDeleteContext(hTempRC
);
969 HGLRC hSharedCtx
= 0;
970 if (!g_vShareList
.empty())
971 hSharedCtx
= g_vShareList
.front();
973 if (!wglCreateContextAttribsARB
)
975 wglMakeCurrent(NULL
, NULL
);
976 wglDeleteContext(hTempRC
);
980 // now setup the shared context; this needs a temporary context already
981 // set up in order to work
985 WGL_CONTEXT_FLAGS_ARB
, WGL_CONTEXT_DEBUG_BIT_ARB
,
989 m_aGLWin
.hRC
= wglCreateContextAttribsARB(m_aGLWin
.hDC
, hSharedCtx
, attribs
);
990 if (m_aGLWin
.hRC
== 0)
992 ImplWriteLastError(GetLastError(), "wglCreateContextAttribsARB in OpenGLContext::ImplInit");
993 SAL_WARN("vcl.opengl", "wglCreateContextAttribsARB failed");
994 wglMakeCurrent(NULL
, NULL
);
995 wglDeleteContext(hTempRC
);
999 wglMakeCurrent(NULL
, NULL
);
1000 wglDeleteContext(hTempRC
);
1002 if (!wglMakeCurrent(m_aGLWin
.hDC
, m_aGLWin
.hRC
))
1004 ImplWriteLastError(GetLastError(), "wglMakeCurrent (with shared context) in OpenGLContext::ImplInit");
1005 SAL_WARN("vcl.opengl", "wglMakeCurrent failed");
1009 InitGLEWDebugging();
1011 g_vShareList
.push_back(m_aGLWin
.hRC
);
1014 GetClientRect(WindowFromDC(m_aGLWin
.hDC
), &clientRect
);
1015 m_aGLWin
.Width
= clientRect
.right
- clientRect
.left
;
1016 m_aGLWin
.Height
= clientRect
.bottom
- clientRect
.top
;
1018 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
1020 registerAsCurrent();
1025 #elif defined( MACOSX )
1027 bool OpenGLContext::ImplInit()
1031 VCL_GL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start");
1032 NSOpenGLView
* pView
= getOpenGLView();
1033 OpenGLWrapper::makeCurrent(pView
);
1035 bool bRet
= InitGLEW();
1036 InitGLEWDebugging();
1042 bool OpenGLContext::ImplInit()
1044 VCL_GL_INFO("vcl.opengl", "OpenGLContext not implemented for this platform");
1050 bool OpenGLContext::InitGLEW()
1052 static bool bGlewInit
= false;
1057 glewExperimental
= GL_TRUE
;
1058 GLenum err
= glewInit();
1061 SAL_WARN("vcl.opengl", "Failed to initialize GLEW: " << glewGetErrorString(err
));
1068 VCL_GL_INFO("vcl.opengl", "OpenGLContext::ImplInit----end");
1069 mbInitialized
= true;
1073 void OpenGLContext::InitGLEWDebugging()
1076 // only enable debug output in dbgutil build
1077 if( GLEW_ARB_debug_output
)
1081 if (glDebugMessageCallbackARB
)
1083 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB
);
1084 glDebugMessageCallbackARB(&debug_callback
, NULL
);
1086 else if ( glDebugMessageCallback
)
1088 glEnable(GL_DEBUG_OUTPUT
);
1089 glDebugMessageCallback(&debug_callback
, NULL
);
1093 // Test hooks for inserting tracing messages into the stream
1094 VCL_GL_INFO("vcl.opengl", "LibreOffice GLContext initialized: " << this);
1098 void OpenGLContext::setWinPosAndSize(const Point
&rPos
, const Size
& rSize
)
1101 m_xWindow
->SetPosSizePixel(rPos
, rSize
);
1102 if( m_pChildWindow
)
1103 m_pChildWindow
->SetPosSizePixel(rPos
, rSize
);
1105 m_aGLWin
.Width
= rSize
.Width();
1106 m_aGLWin
.Height
= rSize
.Height();
1109 void OpenGLContext::setWinSize(const Size
& rSize
)
1112 m_xWindow
->SetSizePixel(rSize
);
1113 if( m_pChildWindow
)
1114 m_pChildWindow
->SetSizePixel(rSize
);
1116 m_aGLWin
.Width
= rSize
.Width();
1117 m_aGLWin
.Height
= rSize
.Height();
1120 void OpenGLContext::renderToFile()
1122 int iWidth
= m_aGLWin
.Width
;
1123 int iHeight
= m_aGLWin
.Height
;
1124 static int nIdx
= 0;
1125 OUString aName
= "file:///home/moggi/Documents/work/output" + OUString::number( nIdx
++ ) + ".png";
1126 OpenGLHelper::renderToFile(iWidth
, iHeight
, aName
);
1131 bool OpenGLContext::initWindow()
1133 if( !m_pChildWindow
)
1135 SystemWindowData winData
= generateWinData(mpWindow
, false);
1136 m_pChildWindow
= VclPtr
<SystemChildWindow
>::Create(mpWindow
, 0, &winData
, false);
1139 if( m_pChildWindow
)
1141 m_pChildWindow
->SetMouseTransparent( true );
1142 m_pChildWindow
->SetParentClipMode(PARENTCLIPMODE_CLIP
);
1143 m_pChildWindow
->EnableEraseBackground( false );
1144 m_pChildWindow
->SetControlForeground();
1145 m_pChildWindow
->SetControlBackground();
1146 //m_pChildWindow->EnablePaint(false);
1148 const SystemEnvData
* sysData(m_pChildWindow
->GetSystemData());
1149 m_aGLWin
.hWnd
= sysData
->hWnd
;
1152 m_aGLWin
.hDC
= GetDC(m_aGLWin
.hWnd
);
1156 #elif defined( MACOSX )
1158 bool OpenGLContext::initWindow()
1160 if( !m_pChildWindow
)
1162 SystemWindowData winData
= generateWinData(mpWindow
, mbRequestLegacyContext
);
1163 m_pChildWindow
= VclPtr
<SystemChildWindow
>::Create(mpWindow
, 0, &winData
, false);
1166 if( m_pChildWindow
)
1168 m_pChildWindow
->SetMouseTransparent( true );
1169 m_pChildWindow
->SetParentClipMode(PARENTCLIPMODE_CLIP
);
1170 m_pChildWindow
->EnableEraseBackground( false );
1171 m_pChildWindow
->SetControlForeground();
1172 m_pChildWindow
->SetControlBackground();
1173 //m_pChildWindow->EnablePaint(false);
1180 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1182 bool OpenGLContext::initWindow()
1187 #elif defined( UNX )
1189 bool OpenGLContext::initWindow()
1191 const SystemEnvData
* pChildSysData
= 0;
1192 SystemWindowData winData
= generateWinData(mpWindow
, false);
1193 if( winData
.pVisual
)
1195 if( !m_pChildWindow
)
1197 m_pChildWindow
= VclPtr
<SystemChildWindow
>::Create(mpWindow
, 0, &winData
, false);
1199 pChildSysData
= m_pChildWindow
->GetSystemData();
1202 if (!m_pChildWindow
|| !pChildSysData
)
1205 m_pChildWindow
->SetMouseTransparent( true );
1206 m_pChildWindow
->SetParentClipMode( PARENTCLIPMODE_NOCLIP
);
1207 m_pChildWindow
->EnableEraseBackground( false );
1208 m_pChildWindow
->SetControlForeground();
1209 m_pChildWindow
->SetControlBackground();
1211 m_aGLWin
.dpy
= static_cast<Display
*>(pChildSysData
->pDisplay
);
1212 m_aGLWin
.win
= pChildSysData
->aWindow
;
1213 m_aGLWin
.screen
= pChildSysData
->nScreen
;
1215 Visual
* pVisual
= static_cast<Visual
*>(pChildSysData
->pVisual
);
1216 initGLWindow(pVisual
);
1221 void OpenGLContext::initGLWindow(Visual
* pVisual
)
1227 XVisualInfo aTemplate
;
1228 aTemplate
.visualid
= XVisualIDFromVisual( pVisual
);
1230 XVisualInfo
* pInfos
= XGetVisualInfo( m_aGLWin
.dpy
, VisualIDMask
, &aTemplate
, &nVisuals
);
1232 SAL_WARN( "vcl.opengl", "match count for visual id is not 1" );
1233 m_aGLWin
.vi
= pInfos
;
1236 // Check multi sample support
1237 /* TODO: moggi: This is not necessarily correct in the DBG_UTIL path, as it picks
1238 * an FBConfig instead ... */
1240 glXGetConfig(m_aGLWin
.dpy
, m_aGLWin
.vi
, GLX_SAMPLES
, &nSamples
);
1242 m_aGLWin
.bMultiSampleSupported
= true;
1244 m_aGLWin
.GLXExtensions
= glXQueryExtensionsString( m_aGLWin
.dpy
, m_aGLWin
.screen
);
1245 SAL_INFO("vcl.opengl", "available GLX extensions: " << m_aGLWin
.GLXExtensions
);
1250 void OpenGLContext::reset()
1252 if( !mbInitialized
)
1257 // don't reset a context in the middle of stack frames rendering to it
1258 assert( mnPainting
== 0 );
1260 // reset the clip region
1261 maClipRegion
.SetEmpty();
1263 // destroy all framebuffers
1264 if( mpLastFramebuffer
)
1266 OpenGLFramebuffer
* pFramebuffer
= mpLastFramebuffer
;
1269 while( pFramebuffer
)
1271 OpenGLFramebuffer
* pPrevFramebuffer
= pFramebuffer
->mpPrevFramebuffer
;
1272 delete pFramebuffer
;
1273 pFramebuffer
= pPrevFramebuffer
;
1275 mpFirstFramebuffer
= NULL
;
1276 mpLastFramebuffer
= NULL
;
1279 // destroy all programs
1280 if( !maPrograms
.empty() )
1289 mbInitialized
= false;
1291 // destroy the context itself
1295 std::vector
<HGLRC
>::iterator itr
= std::remove(g_vShareList
.begin(), g_vShareList
.end(), m_aGLWin
.hRC
);
1296 if (itr
!= g_vShareList
.end())
1297 g_vShareList
.erase(itr
);
1299 if (wglGetCurrentContext() != NULL
)
1300 wglMakeCurrent(NULL
, NULL
);
1301 wglDeleteContext( m_aGLWin
.hRC
);
1302 ReleaseDC( m_aGLWin
.hWnd
, m_aGLWin
.hDC
);
1305 #elif defined( MACOSX )
1306 OpenGLWrapper::resetCurrent();
1307 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1309 #elif defined( UNX )
1312 std::vector
<GLXContext
>::iterator itr
= std::remove( g_vShareList
.begin(), g_vShareList
.end(), m_aGLWin
.ctx
);
1313 if (itr
!= g_vShareList
.end())
1314 g_vShareList
.erase(itr
);
1316 glXMakeCurrent(m_aGLWin
.dpy
, None
, NULL
);
1317 if( glGetError() != GL_NO_ERROR
)
1319 SAL_WARN("vcl.opengl", "glError: " << glGetError());
1321 glXDestroyContext(m_aGLWin
.dpy
, m_aGLWin
.ctx
);
1323 if (mbPixmap
&& m_aGLWin
.glPix
!= None
)
1324 glXDestroyPixmap(m_aGLWin
.dpy
, m_aGLWin
.glPix
);
1330 #if defined( WNT ) || defined( MACOSX ) || defined( IOS ) || defined( ANDROID )
1332 SystemWindowData
OpenGLContext::generateWinData(vcl::Window
* /*pParent*/, bool bRequestLegacyContext
)
1334 (void) bRequestLegacyContext
;
1335 SystemWindowData aWinData
;
1337 aWinData
.bOpenGL
= true;
1338 aWinData
.bLegacy
= bRequestLegacyContext
;
1340 aWinData
.nSize
= sizeof(aWinData
);
1344 #elif defined( UNX )
1346 SystemWindowData
OpenGLContext::generateWinData(vcl::Window
* pParent
, bool)
1350 SystemWindowData aWinData
;
1351 aWinData
.nSize
= sizeof(aWinData
);
1352 aWinData
.pVisual
= NULL
;
1354 #if !defined(LIBO_HEADLESS)
1355 const SystemEnvData
* sysData(pParent
->GetSystemData());
1357 Display
*dpy
= static_cast<Display
*>(sysData
->pDisplay
);
1358 Window win
= sysData
->aWindow
;
1360 if( dpy
== 0 || !glXQueryExtension( dpy
, NULL
, NULL
) )
1363 initOpenGLFunctionPointers();
1366 GLXFBConfig
* pFBC
= getFBConfig(dpy
, win
, best_fbc
, true, false);
1371 XVisualInfo
* vi
= 0;
1372 if( best_fbc
!= -1 )
1373 vi
= glXGetVisualFromFBConfig( dpy
, pFBC
[best_fbc
] );
1379 VCL_GL_INFO("vcl.opengl", "using VisualID " << vi
->visualid
);
1380 aWinData
.pVisual
= (void*)(vi
->visual
);
1389 bool OpenGLContext::isCurrent()
1394 return (wglGetCurrentContext() == m_aGLWin
.hRC
&&
1395 wglGetCurrentDC() == m_aGLWin
.hDC
);
1396 #elif defined( MACOSX )
1397 (void) this; // loplugin:staticmethods
1399 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1401 #elif defined( UNX )
1402 GLXDrawable nDrawable
= mbPixmap
? m_aGLWin
.glPix
: m_aGLWin
.win
;
1403 return (m_aGLWin
.ctx
&& glXGetCurrentContext() == m_aGLWin
.ctx
&&
1404 glXGetCurrentDrawable() == nDrawable
);
1408 bool OpenGLContext::hasCurrent()
1411 return wglGetCurrentContext() != NULL
;
1412 #elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1414 #elif defined( UNX )
1415 return glXGetCurrentContext() != None
;
1419 void OpenGLContext::clearCurrent()
1421 ImplSVData
* pSVData
= ImplGetSVData();
1423 // release all framebuffers from the old context so we can re-attach the
1424 // texture in the new context
1425 rtl::Reference
<OpenGLContext
> pCurrentCtx
= pSVData
->maGDIData
.mpLastContext
;
1426 if( pCurrentCtx
.is() && pCurrentCtx
->isCurrent() )
1427 pCurrentCtx
->ReleaseFramebuffers();
1430 void OpenGLContext::prepareForYield()
1432 ImplSVData
* pSVData
= ImplGetSVData();
1434 // release all framebuffers from the old context so we can re-attach the
1435 // texture in the new context
1436 rtl::Reference
<OpenGLContext
> pCurrentCtx
= pSVData
->maGDIData
.mpLastContext
;
1438 if ( !pCurrentCtx
.is() )
1439 return; // Not using OpenGL
1441 SAL_INFO("vcl.opengl", "Unbinding contexts in preparation for yield");
1443 if( pCurrentCtx
->isCurrent() )
1444 pCurrentCtx
->resetCurrent();
1446 assert (!hasCurrent());
1449 void OpenGLContext::makeCurrent()
1459 if (!wglMakeCurrent(m_aGLWin
.hDC
, m_aGLWin
.hRC
))
1461 SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent(): wglMakeCurrent failed: " << GetLastError());
1464 #elif defined( MACOSX )
1465 NSOpenGLView
* pView
= getOpenGLView();
1466 OpenGLWrapper::makeCurrent(pView
);
1467 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1469 #elif defined( UNX )
1471 TempErrorHandler
aErrorHandler(m_aGLWin
.dpy
, unxErrorHandler
);
1476 GLXDrawable nDrawable
= mbPixmap
? m_aGLWin
.glPix
: m_aGLWin
.win
;
1477 if (!glXMakeCurrent( m_aGLWin
.dpy
, nDrawable
, m_aGLWin
.ctx
))
1479 SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent failed on drawable " << nDrawable
<< " pixmap? " << mbPixmap
);
1485 registerAsCurrent();
1488 void OpenGLContext::registerAsCurrent()
1490 ImplSVData
* pSVData
= ImplGetSVData();
1492 // move the context to the end of the contexts list
1493 static int nSwitch
= 0;
1494 VCL_GL_INFO("vcl.opengl", "******* CONTEXT SWITCH " << ++nSwitch
<< " *********");
1498 mpPrevContext
->mpNextContext
= mpNextContext
;
1500 pSVData
->maGDIData
.mpFirstContext
= mpNextContext
;
1501 mpNextContext
->mpPrevContext
= mpPrevContext
;
1503 mpPrevContext
= pSVData
->maGDIData
.mpLastContext
;
1504 mpNextContext
= NULL
;
1505 pSVData
->maGDIData
.mpLastContext
->mpNextContext
= this;
1506 pSVData
->maGDIData
.mpLastContext
= this;
1510 void OpenGLContext::resetCurrent()
1517 wglMakeCurrent(NULL
, NULL
);
1518 #elif defined( MACOSX )
1519 (void) this; // loplugin:staticmethods
1520 OpenGLWrapper::resetCurrent();
1521 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1523 #elif defined( UNX )
1525 glXMakeCurrent(m_aGLWin
.dpy
, None
, NULL
);
1529 void OpenGLContext::swapBuffers()
1534 SwapBuffers(m_aGLWin
.hDC
);
1535 #elif defined( MACOSX )
1536 NSOpenGLView
* pView
= getOpenGLView();
1537 OpenGLWrapper::swapBuffers(pView
);
1538 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1540 #elif defined( UNX )
1541 glXSwapBuffers(m_aGLWin
.dpy
, mbPixmap
? m_aGLWin
.glPix
: m_aGLWin
.win
);
1545 void OpenGLContext::sync()
1551 #elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1552 (void) this; // loplugin:staticmethods
1554 #elif defined( UNX )
1556 XSync(m_aGLWin
.dpy
, false);
1560 void OpenGLContext::show()
1563 m_pChildWindow
->Show();
1568 SystemChildWindow
* OpenGLContext::getChildWindow()
1570 return m_pChildWindow
;
1573 const SystemChildWindow
* OpenGLContext::getChildWindow() const
1575 return m_pChildWindow
;
1578 bool OpenGLContext::supportMultiSampling() const
1580 return m_aGLWin
.bMultiSampleSupported
;
1584 NSOpenGLView
* OpenGLContext::getOpenGLView()
1586 return reinterpret_cast<NSOpenGLView
*>(m_pChildWindow
->GetSystemData()->mpNSView
);
1590 bool OpenGLContext::BindFramebuffer( OpenGLFramebuffer
* pFramebuffer
)
1594 if( pFramebuffer
!= mpCurrentFramebuffer
)
1597 pFramebuffer
->Bind();
1599 OpenGLFramebuffer::Unbind();
1600 mpCurrentFramebuffer
= pFramebuffer
;
1606 bool OpenGLContext::AcquireDefaultFramebuffer()
1608 return BindFramebuffer( NULL
);
1611 OpenGLFramebuffer
* OpenGLContext::AcquireFramebuffer( const OpenGLTexture
& rTexture
)
1615 OpenGLFramebuffer
* pFramebuffer
= NULL
;
1616 OpenGLFramebuffer
* pFreeFbo
= NULL
;
1617 OpenGLFramebuffer
* pSameSizeFbo
= NULL
;
1619 // check if there is already a framebuffer attached to that texture
1620 pFramebuffer
= mpLastFramebuffer
;
1621 while( pFramebuffer
)
1623 if( pFramebuffer
->IsAttached( rTexture
) )
1625 if( !pFreeFbo
&& pFramebuffer
->IsFree() )
1626 pFreeFbo
= pFramebuffer
;
1627 if( !pSameSizeFbo
&&
1628 pFramebuffer
->GetWidth() == rTexture
.GetWidth() &&
1629 pFramebuffer
->GetHeight() == rTexture
.GetHeight() )
1630 pSameSizeFbo
= pFramebuffer
;
1631 pFramebuffer
= pFramebuffer
->mpPrevFramebuffer
;
1634 // else use any framebuffer having the same size
1635 if( !pFramebuffer
&& pSameSizeFbo
)
1636 pFramebuffer
= pSameSizeFbo
;
1638 // else use the first free framebuffer
1639 if( !pFramebuffer
&& pFreeFbo
)
1640 pFramebuffer
= pFreeFbo
;
1642 // if there isn't any free one, create a new one if the limit isn't reached
1643 if( !pFramebuffer
&& mnFramebufferCount
< MAX_FRAMEBUFFER_COUNT
)
1645 mnFramebufferCount
++;
1646 pFramebuffer
= new OpenGLFramebuffer();
1647 if( mpLastFramebuffer
)
1649 pFramebuffer
->mpPrevFramebuffer
= mpLastFramebuffer
;
1650 mpLastFramebuffer
->mpNextFramebuffer
= pFramebuffer
;
1651 mpLastFramebuffer
= pFramebuffer
;
1655 mpFirstFramebuffer
= pFramebuffer
;
1656 mpLastFramebuffer
= pFramebuffer
;
1660 // last try, use any framebuffer
1661 // TODO order the list of framebuffers as a LRU
1663 pFramebuffer
= mpFirstFramebuffer
;
1665 assert( pFramebuffer
);
1666 BindFramebuffer( pFramebuffer
);
1667 pFramebuffer
->AttachTexture( rTexture
);
1668 glViewport( 0, 0, rTexture
.GetWidth(), rTexture
.GetHeight() );
1670 return pFramebuffer
;
1673 // FIXME: this method is rather grim from a perf. perspective.
1674 // We should instead (eventually) use pointers to associate the
1675 // framebuffer and texture cleanly.
1676 void OpenGLContext::UnbindTextureFromFramebuffers( GLuint nTexture
)
1678 OpenGLFramebuffer
* pFramebuffer
;
1680 // see if there is a framebuffer attached to that texture
1681 pFramebuffer
= mpLastFramebuffer
;
1682 while( pFramebuffer
)
1684 if (pFramebuffer
->IsAttached(nTexture
))
1686 BindFramebuffer(pFramebuffer
);
1687 pFramebuffer
->DetachTexture();
1689 pFramebuffer
= pFramebuffer
->mpPrevFramebuffer
;
1693 void OpenGLContext::ReleaseFramebuffer( OpenGLFramebuffer
* pFramebuffer
)
1696 pFramebuffer
->DetachTexture();
1699 void OpenGLContext::ReleaseFramebuffer( const OpenGLTexture
& rTexture
)
1703 if (!rTexture
) // no texture to release.
1706 OpenGLFramebuffer
* pFramebuffer
= mpLastFramebuffer
;
1708 while( pFramebuffer
)
1710 if( pFramebuffer
->IsAttached( rTexture
) )
1712 BindFramebuffer( pFramebuffer
);
1713 pFramebuffer
->DetachTexture();
1714 if (mpCurrentFramebuffer
== pFramebuffer
)
1715 BindFramebuffer( NULL
);
1717 pFramebuffer
= pFramebuffer
->mpPrevFramebuffer
;
1721 void OpenGLContext::ReleaseFramebuffers()
1725 OpenGLFramebuffer
* pFramebuffer
= mpLastFramebuffer
;
1726 while( pFramebuffer
)
1728 if (!pFramebuffer
->IsFree())
1730 BindFramebuffer( pFramebuffer
);
1731 pFramebuffer
->DetachTexture();
1733 pFramebuffer
= pFramebuffer
->mpPrevFramebuffer
;
1735 BindFramebuffer( NULL
);
1738 OpenGLProgram
* OpenGLContext::GetProgram( const OUString
& rVertexShader
, const OUString
& rFragmentShader
, const rtl::OString
& preamble
)
1742 rtl::OString aKey
= OpenGLHelper::GetDigest( rVertexShader
, rFragmentShader
, preamble
);
1744 if( !aKey
.isEmpty() )
1746 ProgramCollection::iterator it
= maPrograms
.find( aKey
);
1747 if( it
!= maPrograms
.end() )
1748 return it
->second
.get();
1751 std::shared_ptr
<OpenGLProgram
> pProgram
= std::make_shared
<OpenGLProgram
>();
1752 if( !pProgram
->Load( rVertexShader
, rFragmentShader
, preamble
, aKey
) )
1755 maPrograms
.insert(std::make_pair(aKey
, pProgram
));
1757 return pProgram
.get();
1760 OpenGLProgram
* OpenGLContext::UseProgram( const OUString
& rVertexShader
, const OUString
& rFragmentShader
, const OString
& preamble
)
1764 OpenGLProgram
* pProgram
= GetProgram( rVertexShader
, rFragmentShader
, preamble
);
1766 if( pProgram
== mpCurrentProgram
)
1769 mpCurrentProgram
= pProgram
;
1771 if (!mpCurrentProgram
)
1773 SAL_WARN("vcl.opengl", "OpenGLContext::UseProgram: mpCurrentProgram is 0");
1777 mpCurrentProgram
->Use();
1779 return mpCurrentProgram
;
1782 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */