Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / source / opengl / OpenGLContext.cxx
blobca53bc00c86ee0b6a9cbc8cda97458ddc19bbcee
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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>
21 #if defined(MACOSX)
22 #include <premac.h>
23 #include "OpenGLWrapper.hxx"
24 #include <postmac.h>
25 #endif
27 #if defined( WNT )
28 #include <win/saldata.hxx>
29 #endif
31 #include "svdata.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;
45 #elif defined(WNT)
46 static std::vector<HGLRC> g_vShareList;
47 #endif
49 GLWindow::~GLWindow()
51 #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
52 XFree(vi);
53 #endif
56 OpenGLContext::OpenGLContext():
57 mpWindow(NULL),
58 m_pChildWindow(NULL),
59 mbInitialized(false),
60 mnRefCount(0),
61 mbRequestLegacyContext(false),
62 mbUseDoubleBufferedRendering(true),
63 mbRequestVirtualDevice(false),
64 mnFramebufferCount(0),
65 mpCurrentFramebuffer(NULL),
66 mpFirstFramebuffer(NULL),
67 mpLastFramebuffer(NULL),
68 mpCurrentProgram(NULL),
69 mnPainting(0),
70 mpPrevContext(NULL),
71 mpNextContext(NULL)
73 VCL_GL_INFO("vcl.opengl", "new context: " << this);
75 #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
76 mbPixmap = false;
77 #endif
79 ImplSVData* pSVData = ImplGetSVData();
80 if( pSVData->maGDIData.mpLastContext )
82 pSVData->maGDIData.mpLastContext->mpNextContext = this;
83 mpPrevContext = pSVData->maGDIData.mpLastContext;
85 else
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.
99 reset();
101 ImplSVData* pSVData = ImplGetSVData();
102 if( mpPrevContext )
103 mpPrevContext->mpNextContext = mpNextContext;
104 else
105 pSVData->maGDIData.mpFirstContext = mpNextContext;
106 if( mpNextContext )
107 mpNextContext->mpPrevContext = mpPrevContext;
108 else
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()
118 reset();
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)
145 switch (message)
147 case WM_CREATE:
148 return 0;
149 case WM_CLOSE:
150 PostQuitMessage(0);
151 return 0;
152 case WM_DESTROY:
153 return 0;
154 case WM_KEYDOWN:
155 switch(wParam)
157 case VK_ESCAPE:
158 PostQuitMessage(0);
159 return 0;
161 case VK_SPACE:
162 break;
164 default:
165 return DefWindowProc(hwnd, message, wParam, lParam);
169 int InitTempWindow(HWND *hwnd, int width, int height, const PIXELFORMATDESCRIPTOR& inPfd, GLWindow& glWin)
171 OpenGLZone aZone;
173 PIXELFORMATDESCRIPTOR pfd = inPfd;
174 int pfmt;
175 int ret;
176 WNDCLASS wc;
177 wc.style = 0;
178 wc.lpfnWndProc = WndProc;
179 wc.cbClsExtra = wc.cbWndExtra = 0;
180 wc.hInstance = NULL;
181 wc.hIcon = NULL;
182 wc.hCursor = NULL;
183 wc.hbrBackground = NULL;
184 wc.lpszMenuName = NULL;
185 wc.lpszClassName = (LPCSTR)"GLRenderer";
186 RegisterClass(&wc);
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);
190 if (!pfmt)
192 return -1;
194 ret = SetPixelFormat(glWin.hDC, pfmt, &pfd);
195 if(!ret)
197 return -1;
199 glWin.hRC = wglCreateContext(glWin.hDC);
200 if(!(glWin.hRC))
202 return -1;
204 ret = wglMakeCurrent(glWin.hDC, glWin.hRC);
205 if(!ret)
207 return -1;
210 CHECK_GL_ERROR();
211 return 0;
214 bool WGLisExtensionSupported(const char *extension)
216 OpenGLZone aZone;
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");
224 if (wglGetExtString)
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)
231 return false;
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);
239 if (p == NULL)
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]==' '))
249 return 1; // Match
253 bool InitMultisample(const PIXELFORMATDESCRIPTOR& pfd, int& rPixelFormat,
254 bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice)
256 OpenGLZone aZone;
258 HWND hWnd = NULL;
259 GLWindow glWin;
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");
264 return false;
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");
271 return false;
273 // Get Our Pixel Format
274 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
275 if (!wglChoosePixelFormatARB)
277 return false;
279 // Get Our Current Device Context
280 HDC hDC = GetDC(hWnd);
282 int pixelFormat;
283 int valid;
284 UINT numFormats;
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.
291 int iAttributes[] =
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,
302 WGL_SAMPLES_ARB,8,
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);
326 DestroyWindow(hWnd);
327 return bArbMultisampleSupported;
329 // Our Pixel Format With 4 Samples Failed, Test For 2 Samples
330 iAttributes[19] = 2;
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);
339 DestroyWindow(hWnd);
340 return bArbMultisampleSupported;
342 // Return The Valid Format
343 wglMakeCurrent(NULL, NULL);
344 wglDeleteContext(glWin.hRC);
345 ReleaseDC(hWnd, glWin.hDC);
346 DestroyWindow(hWnd);
348 return bArbMultisampleSupported;
350 #endif
352 #ifdef DBG_UTIL
354 namespace {
356 const char* getSeverityString(GLenum severity)
358 switch(severity)
360 case GL_DEBUG_SEVERITY_LOW:
361 return "low";
362 case GL_DEBUG_SEVERITY_MEDIUM:
363 return "medium";
364 case GL_DEBUG_SEVERITY_HIGH:
365 return "high";
366 default:
370 return "unknown";
373 const char* getSourceString(GLenum source)
375 switch(source)
377 case GL_DEBUG_SOURCE_API:
378 return "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:
388 return "unknown";
389 default:
393 return "unknown";
396 const char* getTypeString(GLenum type)
398 switch(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:
409 return "marker";
410 case GL_DEBUG_TYPE_PUSH_GROUP:
411 return "push group";
412 case GL_DEBUG_TYPE_POP_GROUP:
413 return "pop group";
414 case GL_DEBUG_TYPE_OTHER:
415 return "other";
416 case GL_DEBUG_TYPE_ERROR:
417 return "error";
418 default:
422 return "unknown";
425 extern "C" void
426 #if defined _WIN32
427 APIENTRY
428 #endif
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
434 if (id == 131218)
435 return;
437 SAL_WARN("vcl.opengl", "OpenGL debug message: source: " << getSourceString(source) << ", type: "
438 << getTypeString(type) << ", id: " << id << ", severity: " << getSeverityString(severity) << " with message: " << message);
443 #endif
445 #if defined UNX && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
447 namespace {
449 #ifdef DBG_UTIL
450 int unxErrorHandler(Display* dpy, XErrorEvent* event)
452 char err[256];
453 char req[256];
454 char minor[256];
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);
459 return 0;
461 #endif
463 typedef int (*errorHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/);
465 class TempErrorHandler
467 private:
468 errorHandler oldErrorHandler;
469 Display* mdpy;
471 public:
472 TempErrorHandler(Display* dpy, errorHandler newErrorHandler):
473 mdpy(dpy)
475 if (mdpy)
477 XLockDisplay(dpy);
478 XSync(dpy, false);
479 oldErrorHandler = XSetErrorHandler(newErrorHandler);
483 ~TempErrorHandler()
485 if (mdpy)
487 // sync so that we possibly get an XError
488 glXWaitGL();
489 XSync(mdpy, false);
490 XSetErrorHandler(oldErrorHandler);
491 XUnlockDisplay(mdpy);
496 static bool errorTriggered;
497 int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ )
499 errorTriggered = true;
501 return 0;
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,
511 GLX_RED_SIZE, 8,
512 GLX_GREEN_SIZE, 8,
513 GLX_BLUE_SIZE, 8,
514 GLX_ALPHA_SIZE, 8,
515 GLX_DEPTH_SIZE, 24,
516 GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
517 None
520 if (bUseDoubleBufferedRendering)
521 visual_attribs[1] = True;
523 int fbCount = 0;
524 GLXFBConfig* pFBC = glXChooseFBConfig( dpy,
525 screen,
526 visual_attribs, &fbCount );
528 if(!pFBC)
530 SAL_WARN("vcl.opengl", "no suitable fb format found");
531 return NULL;
534 int best_num_samp = -1;
535 for(int i = 0; i < fbCount; ++i)
537 // pick the one with the most samples per pixel
538 int nSampleBuf = 0;
539 int nSamples = 0;
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 )) )
545 nBestFBC = i;
546 best_num_samp = nSamples;
550 CHECK_GL_ERROR();
551 return pFBC;
554 GLXFBConfig* getFBConfig(Display* dpy, Window win, int& nBestFBC, bool bUseDoubleBufferedRendering, bool bWithSameVisualID)
556 OpenGLZone aZone;
558 if( dpy == 0 || !glXQueryExtension( dpy, NULL, NULL ) )
559 return 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);
567 xattr.screen = 0;
568 xattr.visual = NULL;
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,
578 GLX_RED_SIZE, 8,
579 GLX_GREEN_SIZE, 8,
580 GLX_BLUE_SIZE, 8,
581 GLX_ALPHA_SIZE, 8,
582 GLX_DEPTH_SIZE, 24,
583 GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
584 None
587 if (!bUseDoubleBufferedRendering)
588 visual_attribs[1] = False;
590 int fbCount = 0;
591 GLXFBConfig* pFBC = glXChooseFBConfig( dpy,
592 screen,
593 visual_attribs, &fbCount );
595 if(!pFBC)
597 SAL_WARN("vcl.opengl", "no suitable fb format found");
598 return NULL;
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
608 int nSampleBuf = 0;
609 int nSamples = 0;
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 )) )
615 nBestFBC = i;
616 best_num_samp = nSamples;
619 XFree( pVi );
622 return pFBC;
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)
638 OpenGLZone aZone;
640 initOpenGLFunctionPointers();
642 XWindowAttributes xattr;
643 if( !XGetWindowAttributes( dpy, win, &xattr ) )
645 SAL_WARN("vcl.opengl", "Failed to get window attributes for getVisual " << win);
646 xattr.visual = NULL;
648 VCL_GL_INFO("vcl.opengl", "using VisualID " << xattr.visual);
649 return xattr.visual;
654 #endif
656 bool OpenGLContext::init( vcl::Window* pParent )
658 if(mbInitialized)
659 return true;
661 OpenGLZone aZone;
663 m_xWindow.reset(pParent ? nullptr : VclPtr<vcl::Window>::Create(nullptr, WB_NOBORDER|WB_NODIALOGCONTROL));
664 mpWindow = pParent ? pParent : m_xWindow.get();
665 if(m_xWindow)
666 m_xWindow->setPosSizePixel(0,0,0,0);
667 m_pChildWindow = 0;
668 initWindow();
669 return ImplInit();
672 bool OpenGLContext::init(SystemChildWindow* pChildWindow)
674 if(mbInitialized)
675 return true;
677 if( !pChildWindow )
678 return false;
680 OpenGLZone aZone;
682 mpWindow = pChildWindow->GetParent();
683 m_pChildWindow = pChildWindow;
684 initWindow();
685 return ImplInit();
688 #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
689 bool OpenGLContext::init(Display* dpy, Window win, int screen)
691 if(mbInitialized)
692 return true;
694 if (!dpy)
695 return false;
697 OpenGLZone aZone;
699 m_aGLWin.dpy = dpy;
700 m_aGLWin.win = win;
701 m_aGLWin.screen = screen;
703 Visual* pVisual = getVisual(dpy, win);
705 initGLWindow(pVisual);
707 return ImplInit();
710 bool OpenGLContext::init(Display* dpy, Pixmap pix, unsigned int width, unsigned int height, int nScreen)
712 if(mbInitialized)
713 return true;
715 if (!dpy)
716 return false;
718 initOpenGLFunctionPointers();
720 SAL_INFO("vcl.opengl", "init with pixmap");
721 m_aGLWin.dpy = dpy;
722 m_aGLWin.Width = width;
723 m_aGLWin.Height = height;
724 m_aGLWin.pix = pix;
725 const int attrib_list[] = { GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
726 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
727 None};
728 int best_fbc = -1;
729 GLXFBConfig* config = getFBConfigForPixmap(dpy, best_fbc, mbUseDoubleBufferedRendering, nScreen);
730 if (best_fbc == -1)
731 return false;
733 m_aGLWin.vi = glXGetVisualFromFBConfig( dpy, config[best_fbc] );
734 m_aGLWin.glPix = glXCreatePixmap(dpy, config[best_fbc], pix, attrib_list);
736 mbPixmap = true;
738 return ImplInit();
741 bool OpenGLContext::ImplInit()
743 if (!m_aGLWin.dpy)
745 return false;
748 OpenGLZone aZone;
750 GLXContext pSharedCtx( NULL );
751 #ifdef DBG_UTIL
752 TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler);
753 #endif
755 VCL_GL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start");
757 if (!g_vShareList.empty())
758 pSharedCtx = g_vShareList.front();
760 #ifdef DBG_UTIL
761 if (!mbPixmap && glXCreateContextAttribsARB && !mbRequestLegacyContext)
763 int best_fbc = -1;
764 GLXFBConfig* pFBC = getFBConfig(m_aGLWin.dpy, m_aGLWin.win, best_fbc, mbUseDoubleBufferedRendering, true);
765 if (!pFBC)
766 return false;
768 if (best_fbc != -1)
770 int pContextAttribs[] =
772 GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
773 GLX_CONTEXT_MINOR_VERSION_ARB, 2,
774 None
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");
779 else
780 SAL_WARN("vcl.opengl", "unable to find correct FBC");
783 #endif
785 if (!m_aGLWin.ctx)
787 if (!m_aGLWin.vi)
788 return false;
790 m_aGLWin.ctx = glXCreateContext(m_aGLWin.dpy,
791 m_aGLWin.vi,
792 pSharedCtx,
793 GL_TRUE);
796 if( m_aGLWin.ctx )
798 g_vShareList.push_back( m_aGLWin.ctx );
800 else
802 SAL_WARN("vcl.opengl", "unable to create GLX context");
803 return false;
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");
809 return false;
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;
822 if( mbPixmap )
824 m_aGLWin.Width = 0; // FIXME: correct ?
825 m_aGLWin.Height = 0;
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);
830 m_aGLWin.Width = 0;
831 m_aGLWin.Height = 0;
833 else
835 m_aGLWin.Width = xWinAttr.width;
836 m_aGLWin.Height = xWinAttr.height;
839 if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) )
841 // enable vsync
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 );
852 if( errorTriggered )
853 SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?");
854 else
855 VCL_GL_INFO("vcl.opengl", "set swap interval to 1 (enable vsync)");
859 bool bRet = InitGLEW();
860 InitGLEWDebugging();
862 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
864 registerAsCurrent();
866 return bRet;
869 #elif defined( _WIN32 )
871 bool OpenGLContext::init(HDC hDC, HWND hWnd)
873 if (mbInitialized)
874 return false;
876 m_aGLWin.hDC = hDC;
877 m_aGLWin.hWnd = hWnd;
878 return ImplInit();
881 bool OpenGLContext::ImplInit()
883 OpenGLZone aZone;
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),
890 1, // Version Number
891 PFD_SUPPORT_OPENGL,
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
900 8, // stencil buffer
901 0, // No Auxiliary Buffer
902 0, // now ignored
903 0, // Reserved
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;
912 else
913 PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW;
915 // we must check whether can set the MSAA
916 int WindowPix = 0;
917 bool bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix,
918 mbUseDoubleBufferedRendering, mbRequestVirtualDevice);
919 if (bMultiSampleSupport && WindowPix != 0)
921 m_aGLWin.bMultiSampleSupported = true;
923 else
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));
931 #endif
934 if (WindowPix == 0)
936 SAL_WARN("vcl.opengl", "Invalid pixelformat");
937 return false;
940 if (!SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront))
942 ImplWriteLastError(GetLastError(), "SetPixelFormat in OpenGLContext::ImplInit");
943 SAL_WARN("vcl.opengl", "SetPixelFormat failed");
944 return false;
947 HGLRC hTempRC = wglCreateContext(m_aGLWin.hDC);
948 if (hTempRC == NULL)
950 ImplWriteLastError(GetLastError(), "wglCreateContext in OpenGLContext::ImplInit");
951 SAL_WARN("vcl.opengl", "wglCreateContext failed");
952 return false;
955 if (!wglMakeCurrent(m_aGLWin.hDC, hTempRC))
957 ImplWriteLastError(GetLastError(), "wglMakeCurrent in OpenGLContext::ImplInit");
958 SAL_WARN("vcl.opengl", "wglMakeCurrent failed");
959 return false;
962 if (!InitGLEW())
964 wglMakeCurrent(NULL, NULL);
965 wglDeleteContext(hTempRC);
966 return false;
969 HGLRC hSharedCtx = 0;
970 if (!g_vShareList.empty())
971 hSharedCtx = g_vShareList.front();
973 if (!wglCreateContextAttribsARB)
975 wglMakeCurrent(NULL, NULL);
976 wglDeleteContext(hTempRC);
977 return false;
980 // now setup the shared context; this needs a temporary context already
981 // set up in order to work
982 int attribs [] =
984 #ifdef DBG_UTIL
985 WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
986 #endif
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);
996 return false;
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");
1006 return false;
1009 InitGLEWDebugging();
1011 g_vShareList.push_back(m_aGLWin.hRC);
1013 RECT clientRect;
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();
1022 return true;
1025 #elif defined( MACOSX )
1027 bool OpenGLContext::ImplInit()
1029 OpenGLZone aZone;
1031 VCL_GL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start");
1032 NSOpenGLView* pView = getOpenGLView();
1033 OpenGLWrapper::makeCurrent(pView);
1035 bool bRet = InitGLEW();
1036 InitGLEWDebugging();
1037 return bRet;
1040 #else
1042 bool OpenGLContext::ImplInit()
1044 VCL_GL_INFO("vcl.opengl", "OpenGLContext not implemented for this platform");
1045 return false;
1048 #endif
1050 bool OpenGLContext::InitGLEW()
1052 static bool bGlewInit = false;
1053 if(!bGlewInit)
1055 OpenGLZone aZone;
1057 glewExperimental = GL_TRUE;
1058 GLenum err = glewInit();
1059 if (err != GLEW_OK)
1061 SAL_WARN("vcl.opengl", "Failed to initialize GLEW: " << glewGetErrorString(err));
1062 return false;
1064 else
1065 bGlewInit = true;
1068 VCL_GL_INFO("vcl.opengl", "OpenGLContext::ImplInit----end");
1069 mbInitialized = true;
1070 return true;
1073 void OpenGLContext::InitGLEWDebugging()
1075 #ifdef DBG_UTIL
1076 // only enable debug output in dbgutil build
1077 if( GLEW_ARB_debug_output)
1079 OpenGLZone aZone;
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);
1095 #endif
1098 void OpenGLContext::setWinPosAndSize(const Point &rPos, const Size& rSize)
1100 if(m_xWindow)
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)
1111 if(m_xWindow)
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);
1129 #if defined( WNT )
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);
1153 return true;
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);
1177 return true;
1180 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1182 bool OpenGLContext::initWindow()
1184 return false;
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)
1203 return false;
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);
1218 return true;
1221 void OpenGLContext::initGLWindow(Visual* pVisual)
1223 OpenGLZone aZone;
1225 // Get visual info
1227 XVisualInfo aTemplate;
1228 aTemplate.visualid = XVisualIDFromVisual( pVisual );
1229 int nVisuals = 0;
1230 XVisualInfo* pInfos = XGetVisualInfo( m_aGLWin.dpy, VisualIDMask, &aTemplate, &nVisuals );
1231 if( nVisuals != 1 )
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 ... */
1239 int nSamples = 0;
1240 glXGetConfig(m_aGLWin.dpy, m_aGLWin.vi, GLX_SAMPLES, &nSamples);
1241 if( nSamples > 0 )
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);
1248 #endif
1250 void OpenGLContext::reset()
1252 if( !mbInitialized )
1253 return;
1255 OpenGLZone aZone;
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;
1268 makeCurrent();
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() )
1282 makeCurrent();
1283 maPrograms.clear();
1286 if( isCurrent() )
1287 resetCurrent();
1289 mbInitialized = false;
1291 // destroy the context itself
1292 #if defined( WNT )
1293 if (m_aGLWin.hRC)
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 );
1303 m_aGLWin.hRC = 0;
1305 #elif defined( MACOSX )
1306 OpenGLWrapper::resetCurrent();
1307 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1308 // nothing
1309 #elif defined( UNX )
1310 if(m_aGLWin.ctx)
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);
1325 m_aGLWin.ctx = 0;
1327 #endif
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;
1336 #if defined(MACOSX)
1337 aWinData.bOpenGL = true;
1338 aWinData.bLegacy = bRequestLegacyContext;
1339 #endif
1340 aWinData.nSize = sizeof(aWinData);
1341 return aWinData;
1344 #elif defined( UNX )
1346 SystemWindowData OpenGLContext::generateWinData(vcl::Window* pParent, bool)
1348 OpenGLZone aZone;
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 ) )
1361 return aWinData;
1363 initOpenGLFunctionPointers();
1365 int best_fbc = -1;
1366 GLXFBConfig* pFBC = getFBConfig(dpy, win, best_fbc, true, false);
1368 if (!pFBC)
1369 return aWinData;
1371 XVisualInfo* vi = 0;
1372 if( best_fbc != -1 )
1373 vi = glXGetVisualFromFBConfig( dpy, pFBC[best_fbc] );
1375 XFree(pFBC);
1377 if( vi )
1379 VCL_GL_INFO("vcl.opengl", "using VisualID " << vi->visualid);
1380 aWinData.pVisual = (void*)(vi->visual);
1382 #endif
1384 return aWinData;
1387 #endif
1389 bool OpenGLContext::isCurrent()
1391 OpenGLZone aZone;
1393 #if defined( WNT )
1394 return (wglGetCurrentContext() == m_aGLWin.hRC &&
1395 wglGetCurrentDC() == m_aGLWin.hDC);
1396 #elif defined( MACOSX )
1397 (void) this; // loplugin:staticmethods
1398 return false;
1399 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1400 return false;
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);
1405 #endif
1408 bool OpenGLContext::hasCurrent()
1410 #if defined( WNT )
1411 return wglGetCurrentContext() != NULL;
1412 #elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1413 return false;
1414 #elif defined( UNX )
1415 return glXGetCurrentContext() != None;
1416 #endif
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()
1451 if (isCurrent())
1452 return;
1454 OpenGLZone aZone;
1456 clearCurrent();
1458 #if defined( WNT )
1459 if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
1461 SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent(): wglMakeCurrent failed: " << GetLastError());
1462 return;
1464 #elif defined( MACOSX )
1465 NSOpenGLView* pView = getOpenGLView();
1466 OpenGLWrapper::makeCurrent(pView);
1467 #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1468 // nothing
1469 #elif defined( UNX )
1470 #ifdef DBG_UTIL
1471 TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler);
1472 #endif
1474 if (m_aGLWin.dpy)
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);
1480 return;
1483 #endif
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 << " *********");
1495 if( mpNextContext )
1497 if( mpPrevContext )
1498 mpPrevContext->mpNextContext = mpNextContext;
1499 else
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()
1512 clearCurrent();
1514 OpenGLZone aZone;
1516 #if defined( WNT )
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)
1522 // nothing
1523 #elif defined( UNX )
1524 if (m_aGLWin.dpy)
1525 glXMakeCurrent(m_aGLWin.dpy, None, NULL);
1526 #endif
1529 void OpenGLContext::swapBuffers()
1531 OpenGLZone aZone;
1533 #if defined( WNT )
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)
1539 // nothing
1540 #elif defined( UNX )
1541 glXSwapBuffers(m_aGLWin.dpy, mbPixmap ? m_aGLWin.glPix : m_aGLWin.win);
1542 #endif
1545 void OpenGLContext::sync()
1547 OpenGLZone aZone;
1549 #if defined( WNT )
1550 // nothing
1551 #elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1552 (void) this; // loplugin:staticmethods
1553 // nothing
1554 #elif defined( UNX )
1555 glXWaitGL();
1556 XSync(m_aGLWin.dpy, false);
1557 #endif
1560 void OpenGLContext::show()
1562 if (m_pChildWindow)
1563 m_pChildWindow->Show();
1564 else if (m_xWindow)
1565 m_xWindow->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;
1583 #if defined(MACOSX)
1584 NSOpenGLView* OpenGLContext::getOpenGLView()
1586 return reinterpret_cast<NSOpenGLView*>(m_pChildWindow->GetSystemData()->mpNSView);
1588 #endif
1590 bool OpenGLContext::BindFramebuffer( OpenGLFramebuffer* pFramebuffer )
1592 OpenGLZone aZone;
1594 if( pFramebuffer != mpCurrentFramebuffer )
1596 if( pFramebuffer )
1597 pFramebuffer->Bind();
1598 else
1599 OpenGLFramebuffer::Unbind();
1600 mpCurrentFramebuffer = pFramebuffer;
1603 return true;
1606 bool OpenGLContext::AcquireDefaultFramebuffer()
1608 return BindFramebuffer( NULL );
1611 OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rTexture )
1613 OpenGLZone aZone;
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 ) )
1624 break;
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;
1653 else
1655 mpFirstFramebuffer = pFramebuffer;
1656 mpLastFramebuffer = pFramebuffer;
1660 // last try, use any framebuffer
1661 // TODO order the list of framebuffers as a LRU
1662 if( !pFramebuffer )
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 )
1695 if( pFramebuffer )
1696 pFramebuffer->DetachTexture();
1699 void OpenGLContext::ReleaseFramebuffer( const OpenGLTexture& rTexture )
1701 OpenGLZone aZone;
1703 if (!rTexture) // no texture to release.
1704 return;
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()
1723 OpenGLZone aZone;
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 )
1740 OpenGLZone aZone;
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 ) )
1753 return NULL;
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 )
1762 OpenGLZone aZone;
1764 OpenGLProgram* pProgram = GetProgram( rVertexShader, rFragmentShader, preamble );
1766 if( pProgram == mpCurrentProgram )
1767 return pProgram;
1769 mpCurrentProgram = pProgram;
1771 if (!mpCurrentProgram)
1773 SAL_WARN("vcl.opengl", "OpenGLContext::UseProgram: mpCurrentProgram is 0");
1774 return 0;
1777 mpCurrentProgram->Use();
1779 return mpCurrentProgram;
1782 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */