Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : */
9 :
10 : #include <vcl/opengl/OpenGLContext.hxx>
11 : #include <vcl/opengl/OpenGLHelper.hxx>
12 : #include <vcl/syschild.hxx>
13 : #include <vcl/sysdata.hxx>
14 :
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>
20 :
21 : #if defined(MACOSX)
22 : #include <premac.h>
23 : #include "OpenGLWrapper.hxx"
24 : #include <postmac.h>
25 : #endif
26 :
27 : #if defined( WNT )
28 : #include <win/saldata.hxx>
29 : #endif
30 :
31 : #include "svdata.hxx"
32 :
33 : #include <opengl/framebuffer.hxx>
34 : #include <opengl/program.hxx>
35 : #include <opengl/texture.hxx>
36 :
37 : using namespace com::sun::star;
38 :
39 : #define MAX_FRAMEBUFFER_COUNT 30
40 :
41 : // TODO use rtl::Static instead of 'static'
42 : #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
43 267 : static std::vector<GLXContext> g_vShareList;
44 : #elif defined(WNT)
45 : static std::vector<HGLRC> g_vShareList;
46 : #endif
47 :
48 18 : GLWindow::~GLWindow()
49 : {
50 : #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
51 18 : XFree(vi);
52 : #endif
53 18 : }
54 :
55 18 : OpenGLContext::OpenGLContext():
56 : mpWindow(NULL),
57 : m_pChildWindow(NULL),
58 : mbInitialized(false),
59 : mnRefCount(1),
60 : mbRequestLegacyContext(false),
61 : mbUseDoubleBufferedRendering(true),
62 : mbRequestVirtualDevice(false),
63 : mnFramebufferCount(0),
64 : mpCurrentFramebuffer(NULL),
65 : mpFirstFramebuffer(NULL),
66 : mpLastFramebuffer(NULL),
67 : mpCurrentProgram(NULL),
68 : mnPainting(0),
69 : mpPrevContext(NULL),
70 18 : mpNextContext(NULL)
71 : {
72 : SAL_INFO("vcl.opengl", "new context: " << this);
73 : #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
74 18 : mbPixmap = false;
75 : #endif
76 :
77 18 : ImplSVData* pSVData = ImplGetSVData();
78 18 : if( pSVData->maGDIData.mpLastContext )
79 : {
80 14 : pSVData->maGDIData.mpLastContext->mpNextContext = this;
81 14 : mpPrevContext = pSVData->maGDIData.mpLastContext;
82 : }
83 : else
84 4 : pSVData->maGDIData.mpFirstContext = this;
85 18 : pSVData->maGDIData.mpLastContext = this;
86 :
87 : // FIXME: better hope we call 'makeCurrent' soon to preserve
88 : // the invariant that the last item is the current context.
89 18 : }
90 :
91 36 : OpenGLContext::~OpenGLContext()
92 : {
93 : SAL_INFO("vcl.opengl", "delete context: " << this);
94 18 : reset();
95 :
96 18 : ImplSVData* pSVData = ImplGetSVData();
97 18 : if( mpPrevContext )
98 13 : mpPrevContext->mpNextContext = mpNextContext;
99 : else
100 5 : pSVData->maGDIData.mpFirstContext = mpNextContext;
101 18 : if( mpNextContext )
102 1 : mpNextContext->mpPrevContext = mpPrevContext;
103 : else
104 17 : pSVData->maGDIData.mpLastContext = mpPrevContext;
105 :
106 18 : m_pChildWindow.disposeAndClear();
107 18 : }
108 :
109 : #ifdef DBG_UTIL
110 : void OpenGLContext::AddRef(SalGraphicsImpl* pImpl)
111 : {
112 : assert(mnRefCount > 0);
113 : mnRefCount++;
114 :
115 : maParents.insert(pImpl);
116 : }
117 :
118 : void OpenGLContext::DeRef(SalGraphicsImpl* pImpl)
119 : {
120 :
121 : auto it = maParents.find(pImpl);
122 : if(it != maParents.end())
123 : maParents.erase(it);
124 :
125 : assert(mnRefCount > 0);
126 : if( --mnRefCount == 0 )
127 : delete this;
128 : }
129 : #else
130 0 : void OpenGLContext::AddRef()
131 : {
132 : assert(mnRefCount > 0);
133 0 : mnRefCount++;
134 0 : }
135 :
136 0 : void OpenGLContext::DeRef()
137 : {
138 : assert(mnRefCount > 0);
139 0 : if( --mnRefCount == 0 )
140 0 : delete this;
141 0 : }
142 : #endif
143 :
144 0 : void OpenGLContext::requestLegacyContext()
145 : {
146 0 : mbRequestLegacyContext = true;
147 0 : }
148 :
149 0 : void OpenGLContext::requestSingleBufferedRendering()
150 : {
151 0 : mbUseDoubleBufferedRendering = false;
152 0 : }
153 :
154 0 : void OpenGLContext::requestVirtualDevice()
155 : {
156 0 : mbRequestVirtualDevice = true;
157 0 : }
158 :
159 : #if defined( _WIN32 )
160 : static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
161 : {
162 : switch (message)
163 : {
164 : case WM_CREATE:
165 : return 0;
166 : case WM_CLOSE:
167 : PostQuitMessage(0);
168 : return 0;
169 : case WM_DESTROY:
170 : return 0;
171 : case WM_KEYDOWN:
172 : switch(wParam)
173 : {
174 : case VK_ESCAPE:
175 : PostQuitMessage(0);
176 : return 0;
177 :
178 : case VK_SPACE:
179 : break;
180 : }
181 : default:
182 : return DefWindowProc(hwnd, message, wParam, lParam);
183 : }
184 : }
185 :
186 : int InitTempWindow(HWND *hwnd, int width, int height, const PIXELFORMATDESCRIPTOR& inPfd, GLWindow& glWin)
187 : {
188 : PIXELFORMATDESCRIPTOR pfd = inPfd;
189 : int pfmt;
190 : int ret;
191 : WNDCLASS wc;
192 : wc.style = 0;
193 : wc.lpfnWndProc = WndProc;
194 : wc.cbClsExtra = wc.cbWndExtra = 0;
195 : wc.hInstance = NULL;
196 : wc.hIcon = NULL;
197 : wc.hCursor = NULL;
198 : wc.hbrBackground = NULL;
199 : wc.lpszMenuName = NULL;
200 : wc.lpszClassName = (LPCSTR)"GLRenderer";
201 : RegisterClass(&wc);
202 : *hwnd = CreateWindow(wc.lpszClassName, NULL, WS_DISABLED, 0, 0, width, height, NULL, NULL, wc.hInstance, NULL);
203 : glWin.hDC = GetDC(*hwnd);
204 : pfmt = ChoosePixelFormat(glWin.hDC, &pfd);
205 : if (!pfmt)
206 : {
207 : return -1;
208 : }
209 : ret = SetPixelFormat(glWin.hDC, pfmt, &pfd);
210 : if(!ret)
211 : {
212 : return -1;
213 : }
214 : glWin.hRC = wglCreateContext(glWin.hDC);
215 : if(!(glWin.hRC))
216 : {
217 : return -1;
218 : }
219 : ret = wglMakeCurrent(glWin.hDC, glWin.hRC);
220 : if(!ret)
221 : {
222 : return -1;
223 : }
224 :
225 : CHECK_GL_ERROR();
226 : return 0;
227 : }
228 :
229 : bool WGLisExtensionSupported(const char *extension)
230 : {
231 : const size_t extlen = strlen(extension);
232 : const char *supported = NULL;
233 :
234 : // Try To Use wglGetExtensionStringARB On Current DC, If Possible
235 : PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");
236 :
237 : if (wglGetExtString)
238 : supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC());
239 : // If That Failed, Try Standard Opengl Extensions String
240 : if (supported == NULL)
241 : supported = (char*)glGetString(GL_EXTENSIONS);
242 : // If That Failed Too, Must Be No Extensions Supported
243 : if (supported == NULL)
244 : return false;
245 :
246 : // Begin Examination At Start Of String, Increment By 1 On False Match
247 : for (const char* p = supported; ; p++)
248 : {
249 : // Advance p Up To The Next Possible Match
250 : p = strstr(p, extension);
251 :
252 : if (p == NULL)
253 : return 0; // No Match
254 :
255 : // Make Sure That Match Is At The Start Of The String Or That
256 : // The Previous Char Is A Space, Or Else We Could Accidentally
257 : // Match "wglFunkywglExtension" With "wglExtension"
258 :
259 : // Also, Make Sure That The Following Character Is Space Or NULL
260 : // Or Else "wglExtensionTwo" Might Match "wglExtension"
261 : if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))
262 : return 1; // Match
263 : }
264 : }
265 :
266 : bool InitMultisample(const PIXELFORMATDESCRIPTOR& pfd, int& rPixelFormat,
267 : bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice)
268 : {
269 : HWND hWnd = NULL;
270 : GLWindow glWin;
271 : //create a temp windwo to check whether support multi-sample, if support, get the format
272 : if (InitTempWindow(&hWnd, 1, 1, pfd, glWin) < 0)
273 : {
274 : SAL_WARN("vcl.opengl", "Can't create temp window to test");
275 : return false;
276 : }
277 :
278 : // See If The String Exists In WGL!
279 : if (!WGLisExtensionSupported("WGL_ARB_multisample"))
280 : {
281 : SAL_WARN("vcl.opengl", "Device doesn't support multi sample");
282 : return false;
283 : }
284 : // Get Our Pixel Format
285 : PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
286 : if (!wglChoosePixelFormatARB)
287 : {
288 : return false;
289 : }
290 : // Get Our Current Device Context
291 : HDC hDC = GetDC(hWnd);
292 :
293 : int pixelFormat;
294 : int valid;
295 : UINT numFormats;
296 : float fAttributes[] = {0,0};
297 : // These Attributes Are The Bits We Want To Test For In Our Sample
298 : // Everything Is Pretty Standard, The Only One We Want To
299 : // Really Focus On Is The SAMPLE BUFFERS ARB And WGL SAMPLES
300 : // These Two Are Going To Do The Main Testing For Whether Or Not
301 : // We Support Multisampling On This Hardware.
302 : int iAttributes[] =
303 : {
304 : WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
305 : WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
306 : WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
307 : WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
308 : WGL_COLOR_BITS_ARB,24,
309 : WGL_ALPHA_BITS_ARB,8,
310 : WGL_DEPTH_BITS_ARB,24,
311 : WGL_STENCIL_BITS_ARB,0,
312 : WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
313 : WGL_SAMPLES_ARB,8,
314 : 0,0
315 : };
316 :
317 : if (!bUseDoubleBufferedRendering)
318 : iAttributes[1] = GL_FALSE;
319 :
320 : if (bRequestVirtualDevice)
321 : {
322 : iAttributes[2] = WGL_DRAW_TO_BITMAP_ARB;
323 : }
324 :
325 : bool bArbMultisampleSupported = true;
326 :
327 : // First We Check To See If We Can Get A Pixel Format For 4 Samples
328 : valid = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
329 : // If We Returned True, And Our Format Count Is Greater Than 1
330 : if (valid && numFormats >= 1)
331 : {
332 : bArbMultisampleSupported = true;
333 : rPixelFormat = pixelFormat;
334 : wglMakeCurrent(NULL, NULL);
335 : wglDeleteContext(glWin.hRC);
336 : ReleaseDC(hWnd, glWin.hDC);
337 : DestroyWindow(hWnd);
338 : return bArbMultisampleSupported;
339 : }
340 : // Our Pixel Format With 4 Samples Failed, Test For 2 Samples
341 : iAttributes[19] = 2;
342 : valid = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
343 : if (valid && numFormats >= 1)
344 : {
345 : bArbMultisampleSupported = true;
346 : rPixelFormat = pixelFormat;
347 : wglMakeCurrent(NULL, NULL);
348 : wglDeleteContext(glWin.hRC);
349 : ReleaseDC(hWnd, glWin.hDC);
350 : DestroyWindow(hWnd);
351 : return bArbMultisampleSupported;
352 : }
353 : // Return The Valid Format
354 : wglMakeCurrent(NULL, NULL);
355 : wglDeleteContext(glWin.hRC);
356 : ReleaseDC(hWnd, glWin.hDC);
357 : DestroyWindow(hWnd);
358 :
359 : return bArbMultisampleSupported;
360 : }
361 : #endif
362 :
363 : #ifdef DBG_UTIL
364 :
365 : namespace {
366 :
367 : const char* getSeverityString(GLenum severity)
368 : {
369 : switch(severity)
370 : {
371 : case GL_DEBUG_SEVERITY_LOW:
372 : return "low";
373 : case GL_DEBUG_SEVERITY_MEDIUM:
374 : return "medium";
375 : case GL_DEBUG_SEVERITY_HIGH:
376 : return "high";
377 : default:
378 : ;
379 : }
380 :
381 : return "unknown";
382 : }
383 :
384 : const char* getSourceString(GLenum source)
385 : {
386 : switch(source)
387 : {
388 : case GL_DEBUG_SOURCE_API:
389 : return "API";
390 : case GL_DEBUG_SOURCE_SHADER_COMPILER:
391 : return "shader compiler";
392 : case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
393 : return "window system";
394 : case GL_DEBUG_SOURCE_THIRD_PARTY:
395 : return "third party";
396 : case GL_DEBUG_SOURCE_APPLICATION:
397 : return "Libreoffice";
398 : case GL_DEBUG_SOURCE_OTHER:
399 : return "unknown";
400 : default:
401 : ;
402 : }
403 :
404 : return "unknown";
405 : }
406 :
407 : const char* getTypeString(GLenum type)
408 : {
409 : switch(type)
410 : {
411 : case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
412 : return "deprecated behavior";
413 : case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
414 : return "undefined behavior";
415 : case GL_DEBUG_TYPE_PERFORMANCE:
416 : return "performance";
417 : case GL_DEBUG_TYPE_PORTABILITY:
418 : return "portability";
419 : case GL_DEBUG_TYPE_MARKER:
420 : return "marker";
421 : case GL_DEBUG_TYPE_PUSH_GROUP:
422 : return "push group";
423 : case GL_DEBUG_TYPE_POP_GROUP:
424 : return "pop group";
425 : case GL_DEBUG_TYPE_OTHER:
426 : return "other";
427 : case GL_DEBUG_TYPE_ERROR:
428 : return "error";
429 : default:
430 : ;
431 : }
432 :
433 : return "unknown";
434 : }
435 :
436 : extern "C" void
437 : #if defined _WIN32
438 : APIENTRY
439 : #endif
440 : debug_callback(GLenum source, GLenum type, GLuint id,
441 : GLenum severity, GLsizei , const GLchar* message, GLvoid* )
442 : {
443 : // ignore Nvidia's : "Program/shader state performance warning: Fragment Shader is going to be recompiled because the shader key based on GL state mismatches."
444 : // the GLSL compiler is a bit too aggressive in optimizing the state based on the current OpenGL state
445 : if (id == 131218)
446 : return;
447 :
448 : SAL_WARN("vcl.opengl", "OpenGL debug message: source: " << getSourceString(source) << ", type: "
449 : << getTypeString(type) << ", id: " << id << ", severity: " << getSeverityString(severity) << " with message: " << message);
450 : }
451 :
452 : }
453 :
454 : #endif
455 :
456 : #if defined UNX && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
457 :
458 : namespace {
459 :
460 : #ifdef DBG_UTIL
461 : int unxErrorHandler(Display* dpy, XErrorEvent* event)
462 : {
463 : char err[256];
464 : char req[256];
465 : char minor[256];
466 : XGetErrorText(dpy, event->error_code, err, 256);
467 : XGetErrorText(dpy, event->request_code, req, 256);
468 : XGetErrorText(dpy, event->minor_code, minor, 256);
469 : SAL_WARN("vcl.opengl", "Error: " << err << ", Req: " << req << ", Minor: " << minor);
470 : return 0;
471 : }
472 : #endif
473 :
474 : typedef int (*errorHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/);
475 :
476 : class TempErrorHandler
477 : {
478 : private:
479 : errorHandler oldErrorHandler;
480 : Display* mdpy;
481 :
482 : public:
483 0 : TempErrorHandler(Display* dpy, errorHandler newErrorHandler):
484 0 : mdpy(dpy)
485 : {
486 0 : XLockDisplay(dpy);
487 0 : XSync(dpy, false);
488 0 : oldErrorHandler = XSetErrorHandler(newErrorHandler);
489 0 : }
490 :
491 0 : ~TempErrorHandler()
492 : {
493 : // sync so that we possibly get an XError
494 0 : glXWaitGL();
495 0 : XSync(mdpy, false);
496 0 : XSetErrorHandler(oldErrorHandler);
497 0 : XUnlockDisplay(mdpy);
498 0 : }
499 : };
500 :
501 : static bool errorTriggered;
502 0 : int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ )
503 : {
504 0 : errorTriggered = true;
505 :
506 0 : return 0;
507 : }
508 :
509 0 : GLXFBConfig* getFBConfigForPixmap(Display* dpy, int& nBestFBC, bool bUseDoubleBufferedRendering, int screen)
510 : {
511 : static int visual_attribs[] =
512 : {
513 : GLX_DOUBLEBUFFER, False,
514 : GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
515 : GLX_X_RENDERABLE, True,
516 : GLX_RED_SIZE, 8,
517 : GLX_GREEN_SIZE, 8,
518 : GLX_BLUE_SIZE, 8,
519 : GLX_ALPHA_SIZE, 8,
520 : GLX_DEPTH_SIZE, 24,
521 : GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
522 : None
523 : };
524 :
525 0 : if (bUseDoubleBufferedRendering)
526 0 : visual_attribs[1] = True;
527 :
528 0 : int fbCount = 0;
529 : GLXFBConfig* pFBC = glXChooseFBConfig( dpy,
530 : screen,
531 0 : visual_attribs, &fbCount );
532 :
533 0 : if(!pFBC)
534 : {
535 : SAL_WARN("vcl.opengl", "no suitable fb format found");
536 0 : return NULL;
537 : }
538 :
539 0 : int best_num_samp = -1;
540 0 : for(int i = 0; i < fbCount; ++i)
541 : {
542 : // pick the one with the most samples per pixel
543 0 : int nSampleBuf = 0;
544 0 : int nSamples = 0;
545 0 : glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf );
546 0 : glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLES , &nSamples );
547 :
548 0 : if ( nBestFBC < 0 || (nSampleBuf && ( nSamples > best_num_samp )) )
549 : {
550 0 : nBestFBC = i;
551 0 : best_num_samp = nSamples;
552 : }
553 : }
554 :
555 0 : CHECK_GL_ERROR();
556 0 : return pFBC;
557 : }
558 :
559 0 : GLXFBConfig* getFBConfig(Display* dpy, Window win, int& nBestFBC, bool bUseDoubleBufferedRendering, bool bWithSameVisualID)
560 : {
561 0 : if( dpy == 0 || !glXQueryExtension( dpy, NULL, NULL ) )
562 0 : return NULL;
563 :
564 : SAL_INFO("vcl.opengl", "window: " << win);
565 :
566 : XWindowAttributes xattr;
567 0 : if( !XGetWindowAttributes( dpy, win, &xattr ) )
568 : {
569 : SAL_WARN("vcl.opengl", "Failed to get window attributes for fbconfig " << win);
570 0 : xattr.screen = 0;
571 0 : xattr.visual = NULL;
572 : }
573 :
574 0 : int screen = XScreenNumberOfScreen( xattr.screen );
575 :
576 : // TODO: moggi: Select colour channel depth based on visual attributes, not hardcoded */
577 : static int visual_attribs[] =
578 : {
579 : GLX_DOUBLEBUFFER, True,
580 : GLX_X_RENDERABLE, True,
581 : GLX_RED_SIZE, 8,
582 : GLX_GREEN_SIZE, 8,
583 : GLX_BLUE_SIZE, 8,
584 : GLX_ALPHA_SIZE, 8,
585 : GLX_DEPTH_SIZE, 24,
586 : GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
587 : None
588 : };
589 :
590 0 : if (!bUseDoubleBufferedRendering)
591 0 : visual_attribs[1] = False;
592 :
593 0 : int fbCount = 0;
594 : GLXFBConfig* pFBC = glXChooseFBConfig( dpy,
595 : screen,
596 0 : visual_attribs, &fbCount );
597 :
598 0 : if(!pFBC)
599 : {
600 : SAL_WARN("vcl.opengl", "no suitable fb format found");
601 0 : return NULL;
602 : }
603 :
604 0 : int best_num_samp = -1;
605 0 : for(int i = 0; i < fbCount; ++i)
606 : {
607 0 : XVisualInfo* pVi = glXGetVisualFromFBConfig( dpy, pFBC[i] );
608 0 : if(pVi && (!bWithSameVisualID || (xattr.visual && pVi->visualid == xattr.visual->visualid)) )
609 : {
610 : // pick the one with the most samples per pixel
611 0 : int nSampleBuf = 0;
612 0 : int nSamples = 0;
613 0 : glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf );
614 0 : glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLES , &nSamples );
615 :
616 0 : if ( nBestFBC < 0 || (nSampleBuf && ( nSamples > best_num_samp )) )
617 : {
618 0 : nBestFBC = i;
619 0 : best_num_samp = nSamples;
620 : }
621 : }
622 0 : XFree( pVi );
623 : }
624 :
625 0 : return pFBC;
626 : }
627 :
628 : // we need them before glew can initialize them
629 : // glew needs an OpenGL context so we need to get the address manually
630 0 : void initOpenGLFunctionPointers()
631 : {
632 0 : glXChooseFBConfig = reinterpret_cast<GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements)>(glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXChooseFBConfig")));
633 0 : 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
634 0 : glXGetFBConfigAttrib = reinterpret_cast<int(*)(Display *dpy, GLXFBConfig config, int attribute, int* value)>(glXGetProcAddressARB(reinterpret_cast<GLubyte const *>("glXGetFBConfigAttrib")));
635 0 : glXCreateContextAttribsARB = reinterpret_cast<GLXContext(*)(Display*, GLXFBConfig, GLXContext, Bool, const int*)>(glXGetProcAddressARB(reinterpret_cast<const GLubyte *>("glXCreateContextAttribsARB")));
636 0 : glXCreatePixmap = reinterpret_cast<GLXPixmap(*)(Display*, GLXFBConfig, Pixmap, const int*)>(glXGetProcAddressARB(reinterpret_cast<const GLubyte *>("glXCreatePixmap")));
637 0 : }
638 :
639 0 : Visual* getVisual(Display* dpy, Window win)
640 : {
641 0 : initOpenGLFunctionPointers();
642 :
643 : XWindowAttributes xattr;
644 0 : if( !XGetWindowAttributes( dpy, win, &xattr ) )
645 : {
646 : SAL_WARN("vcl.opengl", "Failed to get window attributes for getVisual " << win);
647 0 : xattr.visual = NULL;
648 : }
649 : SAL_INFO("vcl.opengl", "using VisualID " << xattr.visual);
650 0 : return xattr.visual;
651 : }
652 :
653 : }
654 :
655 : #endif
656 :
657 1 : bool OpenGLContext::init( vcl::Window* pParent )
658 : {
659 1 : if(mbInitialized)
660 0 : return true;
661 :
662 1 : m_xWindow.reset(pParent ? nullptr : VclPtr<vcl::Window>::Create(nullptr, WB_NOBORDER|WB_NODIALOGCONTROL));
663 1 : mpWindow = pParent ? pParent : m_xWindow.get();
664 1 : if(m_xWindow)
665 1 : m_xWindow->setPosSizePixel(0,0,0,0);
666 1 : m_pChildWindow = 0;
667 1 : initWindow();
668 1 : return ImplInit();
669 : }
670 :
671 17 : bool OpenGLContext::init(SystemChildWindow* pChildWindow)
672 : {
673 17 : if(mbInitialized)
674 0 : return true;
675 :
676 17 : if( !pChildWindow )
677 0 : return false;
678 :
679 17 : mpWindow = pChildWindow->GetParent();
680 17 : m_pChildWindow = pChildWindow;
681 17 : initWindow();
682 17 : return ImplInit();
683 : }
684 :
685 : #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID && !defined(LIBO_HEADLESS)
686 0 : bool OpenGLContext::init(Display* dpy, Window win, int screen)
687 : {
688 0 : if(mbInitialized)
689 0 : return true;
690 :
691 0 : if (!dpy)
692 0 : return false;
693 :
694 0 : m_aGLWin.dpy = dpy;
695 0 : m_aGLWin.win = win;
696 0 : m_aGLWin.screen = screen;
697 :
698 0 : Visual* pVisual = getVisual(dpy, win);
699 :
700 0 : initGLWindow(pVisual);
701 :
702 0 : return ImplInit();
703 : }
704 :
705 0 : bool OpenGLContext::init(Display* dpy, Pixmap pix, unsigned int width, unsigned int height, int nScreen)
706 : {
707 0 : if(mbInitialized)
708 0 : return true;
709 :
710 0 : if (!dpy)
711 0 : return false;
712 :
713 0 : initOpenGLFunctionPointers();
714 :
715 : SAL_INFO("vcl.opengl", "init with pixmap");
716 0 : m_aGLWin.dpy = dpy;
717 0 : m_aGLWin.Width = width;
718 0 : m_aGLWin.Height = height;
719 0 : m_aGLWin.pix = pix;
720 : const int attrib_list[] = { GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
721 : GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
722 0 : None};
723 0 : int best_fbc = -1;
724 0 : GLXFBConfig* config = getFBConfigForPixmap(dpy, best_fbc, mbUseDoubleBufferedRendering, nScreen);
725 0 : if (best_fbc == -1)
726 0 : return false;
727 :
728 0 : m_aGLWin.vi = glXGetVisualFromFBConfig( dpy, config[best_fbc] );
729 0 : m_aGLWin.glPix = glXCreatePixmap(dpy, config[best_fbc], pix, attrib_list);
730 :
731 0 : mbPixmap = true;
732 :
733 0 : return ImplInit();
734 : }
735 :
736 18 : bool OpenGLContext::ImplInit()
737 : {
738 18 : if (!m_aGLWin.dpy)
739 : {
740 18 : return false;
741 : }
742 :
743 0 : GLXContext pSharedCtx( NULL );
744 : #ifdef DBG_UTIL
745 : TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler);
746 : #endif
747 :
748 : SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start");
749 :
750 0 : if (!g_vShareList.empty())
751 0 : pSharedCtx = g_vShareList.front();
752 :
753 : #ifdef DBG_UTIL
754 : if (!mbPixmap && glXCreateContextAttribsARB && !mbRequestLegacyContext)
755 : {
756 : int best_fbc = -1;
757 : GLXFBConfig* pFBC = getFBConfig(m_aGLWin.dpy, m_aGLWin.win, best_fbc, mbUseDoubleBufferedRendering, true);
758 : if (!pFBC)
759 : return false;
760 :
761 : if (best_fbc != -1)
762 : {
763 : int pContextAttribs[] =
764 : {
765 : GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
766 : GLX_CONTEXT_MINOR_VERSION_ARB, 2,
767 : None
768 : };
769 : m_aGLWin.ctx = glXCreateContextAttribsARB(m_aGLWin.dpy, pFBC[best_fbc], pSharedCtx, GL_TRUE, pContextAttribs);
770 : SAL_INFO_IF(m_aGLWin.ctx, "vcl.opengl", "created a 3.2 core context");
771 : }
772 : else
773 : SAL_WARN("vcl.opengl", "unable to find correct FBC");
774 :
775 : }
776 : #endif
777 :
778 0 : if (!m_aGLWin.ctx)
779 : {
780 0 : if (!m_aGLWin.vi)
781 0 : return false;
782 :
783 : m_aGLWin.ctx = glXCreateContext(m_aGLWin.dpy,
784 : m_aGLWin.vi,
785 : pSharedCtx,
786 0 : GL_TRUE);
787 : }
788 :
789 0 : if( m_aGLWin.ctx )
790 : {
791 0 : g_vShareList.push_back( m_aGLWin.ctx );
792 : }
793 : else
794 : {
795 : SAL_WARN("vcl.opengl", "unable to create GLX context");
796 0 : return false;
797 : }
798 :
799 0 : if( !glXMakeCurrent( m_aGLWin.dpy, mbPixmap ? m_aGLWin.glPix : m_aGLWin.win, m_aGLWin.ctx ) )
800 : {
801 : SAL_WARN("vcl.opengl", "unable to select current GLX context");
802 0 : return false;
803 : }
804 :
805 : int glxMinor, glxMajor;
806 0 : double nGLXVersion = 0;
807 0 : if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) )
808 0 : nGLXVersion = glxMajor + 0.1*glxMinor;
809 : SAL_INFO("vcl.opengl", "available GLX version: " << nGLXVersion);
810 :
811 0 : m_aGLWin.GLExtensions = glGetString( GL_EXTENSIONS );
812 : SAL_INFO("vcl.opengl", "available GL extensions: " << m_aGLWin.GLExtensions);
813 :
814 : XWindowAttributes xWinAttr;
815 0 : if( mbPixmap )
816 : {
817 0 : m_aGLWin.Width = 0; // FIXME: correct ?
818 0 : m_aGLWin.Height = 0;
819 : }
820 0 : else if( !XGetWindowAttributes( m_aGLWin.dpy, m_aGLWin.win, &xWinAttr ) )
821 : {
822 : SAL_WARN("vcl.opengl", "Failed to get window attributes on " << m_aGLWin.win);
823 0 : m_aGLWin.Width = 0;
824 0 : m_aGLWin.Height = 0;
825 : }
826 : else
827 : {
828 0 : m_aGLWin.Width = xWinAttr.width;
829 0 : m_aGLWin.Height = xWinAttr.height;
830 : }
831 :
832 0 : if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) )
833 : {
834 : // enable vsync
835 : typedef GLint (*glXSwapIntervalProc)(GLint);
836 0 : glXSwapIntervalProc glXSwapInterval = reinterpret_cast<glXSwapIntervalProc>(glXGetProcAddress( reinterpret_cast<const GLubyte*>("glXSwapIntervalSGI") ));
837 0 : if( glXSwapInterval )
838 : {
839 0 : TempErrorHandler aLocalErrorHandler(m_aGLWin.dpy, oglErrorHandler);
840 :
841 0 : errorTriggered = false;
842 :
843 0 : glXSwapInterval( 1 );
844 :
845 0 : if( errorTriggered )
846 : SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?");
847 : else
848 0 : SAL_INFO("vcl.opengl", "set swap interval to 1 (enable vsync)");
849 : }
850 : }
851 :
852 0 : return InitGLEW();
853 : }
854 :
855 : #elif defined( _WIN32 )
856 :
857 : bool OpenGLContext::init(HDC hDC, HWND hWnd)
858 : {
859 : if (mbInitialized)
860 : return false;
861 :
862 : m_aGLWin.hDC = hDC;
863 : m_aGLWin.hWnd = hWnd;
864 : return ImplInit();
865 : }
866 :
867 : bool OpenGLContext::ImplInit()
868 : {
869 : SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start");
870 : // PixelFormat tells Windows how we want things to be
871 : PIXELFORMATDESCRIPTOR PixelFormatFront =
872 : {
873 : sizeof(PIXELFORMATDESCRIPTOR),
874 : 1, // Version Number
875 : PFD_SUPPORT_OPENGL,
876 : PFD_TYPE_RGBA, // Request An RGBA Format
877 : (BYTE)32, // Select Our Color Depth
878 : 0, 0, 0, 0, 0, 0, // Color Bits Ignored
879 : 0, // No Alpha Buffer
880 : 0, // Shift Bit Ignored
881 : 0, // No Accumulation Buffer
882 : 0, 0, 0, 0, // Accumulation Bits Ignored
883 : 64, // 32 bit Z-BUFFER
884 : 8, // stencil buffer
885 : 0, // No Auxiliary Buffer
886 : 0, // now ignored
887 : 0, // Reserved
888 : 0, 0, 0 // Layer Masks Ignored
889 : };
890 :
891 : // interestingly we need this flag being set even if we use single buffer
892 : // rendering - otherwise we get errors with virtual devices
893 : PixelFormatFront.dwFlags |= PFD_DOUBLEBUFFER;
894 :
895 : if (mbRequestVirtualDevice)
896 : PixelFormatFront.dwFlags |= PFD_DRAW_TO_BITMAP;
897 : else
898 : PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW;
899 :
900 : // we must check whether can set the MSAA
901 : int WindowPix = 0;
902 : bool bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix,
903 : mbUseDoubleBufferedRendering, mbRequestVirtualDevice);
904 : if (bMultiSampleSupport && WindowPix != 0)
905 : {
906 : m_aGLWin.bMultiSampleSupported = true;
907 : }
908 : else
909 : {
910 : WindowPix = ChoosePixelFormat(m_aGLWin.hDC, &PixelFormatFront);
911 : #if OSL_DEBUG_LEVEL > 0
912 : PIXELFORMATDESCRIPTOR pfd;
913 : DescribePixelFormat(m_aGLWin.hDC, WindowPix, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
914 : SAL_WARN("vcl.opengl", "Render Target: Window: " << (int) ((pfd.dwFlags & PFD_DRAW_TO_WINDOW) != 0) << ", Bitmap: " << (int) ((pfd.dwFlags & PFD_DRAW_TO_BITMAP) != 0));
915 : SAL_WARN("vcl.opengl", "Supports OpenGL: " << (int) ((pfd.dwFlags & PFD_SUPPORT_OPENGL) != 0));
916 : #endif
917 : }
918 :
919 : if (WindowPix == 0)
920 : {
921 : SAL_WARN("vcl.opengl", "Invalid pixelformat");
922 : return false;
923 : }
924 :
925 : if (!SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront))
926 : {
927 : ImplWriteLastError(GetLastError(), "SetPixelFormat in OpenGLContext::ImplInit");
928 : SAL_WARN("vcl.opengl", "SetPixelFormat failed");
929 : return false;
930 : }
931 :
932 : HGLRC hTempRC = wglCreateContext(m_aGLWin.hDC);
933 : if (hTempRC == NULL)
934 : {
935 : ImplWriteLastError(GetLastError(), "wglCreateContext in OpenGLContext::ImplInit");
936 : SAL_WARN("vcl.opengl", "wglCreateContext failed");
937 : return false;
938 : }
939 :
940 : if (!wglMakeCurrent(m_aGLWin.hDC, hTempRC))
941 : {
942 : ImplWriteLastError(GetLastError(), "wglMakeCurrent in OpenGLContext::ImplInit");
943 : SAL_WARN("vcl.opengl", "wglMakeCurrent failed");
944 : return false;
945 : }
946 :
947 : if (!InitGLEW())
948 : return false;
949 :
950 : HGLRC hSharedCtx = 0;
951 : if (!g_vShareList.empty())
952 : hSharedCtx = g_vShareList.front();
953 :
954 : if (!wglCreateContextAttribsARB)
955 : return false;
956 :
957 : // now setup the shared context; this needs a temporary context already
958 : // set up in order to work
959 : m_aGLWin.hRC = wglCreateContextAttribsARB(m_aGLWin.hDC, hSharedCtx, NULL);
960 : if (m_aGLWin.hRC == 0)
961 : {
962 : ImplWriteLastError(GetLastError(), "wglCreateContextAttribsARB in OpenGLContext::ImplInit");
963 : SAL_WARN("vcl.opengl", "wglCreateContextAttribsARB failed");
964 : return false;
965 : }
966 :
967 : wglMakeCurrent(NULL, NULL);
968 : wglDeleteContext(hTempRC);
969 :
970 : if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
971 : {
972 : ImplWriteLastError(GetLastError(), "wglMakeCurrent (with shared context) in OpenGLContext::ImplInit");
973 : SAL_WARN("vcl.opengl", "wglMakeCurrent failed");
974 : return false;
975 : }
976 :
977 : g_vShareList.push_back(m_aGLWin.hRC);
978 :
979 : RECT clientRect;
980 : GetClientRect(WindowFromDC(m_aGLWin.hDC), &clientRect);
981 : m_aGLWin.Width = clientRect.right - clientRect.left;
982 : m_aGLWin.Height = clientRect.bottom - clientRect.top;
983 :
984 : return true;
985 : }
986 :
987 : #elif defined( MACOSX )
988 :
989 : bool OpenGLContext::ImplInit()
990 : {
991 : SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start");
992 : NSOpenGLView* pView = getOpenGLView();
993 : OpenGLWrapper::makeCurrent(pView);
994 :
995 : return InitGLEW();
996 : }
997 :
998 : #else
999 :
1000 : bool OpenGLContext::ImplInit()
1001 : {
1002 : SAL_INFO("vcl.opengl", "OpenGLContext not implemented for this platform");
1003 : return false;
1004 : }
1005 :
1006 : #endif
1007 :
1008 0 : bool OpenGLContext::InitGLEW()
1009 : {
1010 : static bool bGlewInit = false;
1011 0 : if(!bGlewInit)
1012 : {
1013 0 : glewExperimental = GL_TRUE;
1014 0 : GLenum err = glewInit();
1015 0 : if (err != GLEW_OK)
1016 : {
1017 : SAL_WARN("vcl.opengl", "Failed to initialize GLEW: " << glewGetErrorString(err));
1018 0 : return false;
1019 : }
1020 : else
1021 0 : bGlewInit = true;
1022 : }
1023 :
1024 : #ifdef DBG_UTIL
1025 : // only enable debug output in dbgutil build
1026 : if( GLEW_ARB_debug_output)
1027 : {
1028 : if (glDebugMessageCallbackARB)
1029 : {
1030 : glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
1031 : glDebugMessageCallbackARB(&debug_callback, NULL);
1032 : }
1033 : else if ( glDebugMessageCallback )
1034 : {
1035 : glEnable(GL_DEBUG_OUTPUT);
1036 : glDebugMessageCallback(&debug_callback, NULL);
1037 : }
1038 : }
1039 :
1040 : #endif
1041 :
1042 : SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----end");
1043 0 : mbInitialized = true;
1044 0 : return true;
1045 : }
1046 :
1047 0 : void OpenGLContext::setWinPosAndSize(const Point &rPos, const Size& rSize)
1048 : {
1049 0 : if(m_xWindow)
1050 0 : m_xWindow->SetPosSizePixel(rPos, rSize);
1051 0 : if( m_pChildWindow )
1052 0 : m_pChildWindow->SetPosSizePixel(rPos, rSize);
1053 :
1054 0 : m_aGLWin.Width = rSize.Width();
1055 0 : m_aGLWin.Height = rSize.Height();
1056 0 : }
1057 :
1058 0 : void OpenGLContext::setWinSize(const Size& rSize)
1059 : {
1060 0 : if(m_xWindow)
1061 0 : m_xWindow->SetSizePixel(rSize);
1062 0 : if( m_pChildWindow )
1063 0 : m_pChildWindow->SetSizePixel(rSize);
1064 :
1065 0 : m_aGLWin.Width = rSize.Width();
1066 0 : m_aGLWin.Height = rSize.Height();
1067 0 : }
1068 :
1069 0 : void OpenGLContext::renderToFile()
1070 : {
1071 0 : int iWidth = m_aGLWin.Width;
1072 0 : int iHeight = m_aGLWin.Height;
1073 : static int nIdx = 0;
1074 0 : OUString aName = "file:///home/moggi/Documents/work/output" + OUString::number( nIdx++ ) + ".png";
1075 0 : OpenGLHelper::renderToFile(iWidth, iHeight, aName);
1076 0 : }
1077 :
1078 : #if defined( WNT )
1079 :
1080 : bool OpenGLContext::initWindow()
1081 : {
1082 : if( !m_pChildWindow )
1083 : {
1084 : SystemWindowData winData = generateWinData(mpWindow, false);
1085 : m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false);
1086 : }
1087 :
1088 : if( m_pChildWindow )
1089 : {
1090 : m_pChildWindow->SetMouseTransparent( true );
1091 : m_pChildWindow->SetParentClipMode(ParentClipMode::Clip);
1092 : m_pChildWindow->EnableEraseBackground( false );
1093 : m_pChildWindow->SetControlForeground();
1094 : m_pChildWindow->SetControlBackground();
1095 : //m_pChildWindow->EnablePaint(false);
1096 :
1097 : const SystemEnvData* sysData(m_pChildWindow->GetSystemData());
1098 : m_aGLWin.hWnd = sysData->hWnd;
1099 : }
1100 :
1101 : m_aGLWin.hDC = GetDC(m_aGLWin.hWnd);
1102 : return true;
1103 : }
1104 :
1105 : #elif defined( MACOSX )
1106 :
1107 : bool OpenGLContext::initWindow()
1108 : {
1109 : if( !m_pChildWindow )
1110 : {
1111 : SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext);
1112 : m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false);
1113 : }
1114 :
1115 : if( m_pChildWindow )
1116 : {
1117 : m_pChildWindow->SetMouseTransparent( true );
1118 : m_pChildWindow->SetParentClipMode(ParentClipMode::Clip);
1119 : m_pChildWindow->EnableEraseBackground( false );
1120 : m_pChildWindow->SetControlForeground();
1121 : m_pChildWindow->SetControlBackground();
1122 : //m_pChildWindow->EnablePaint(false);
1123 :
1124 : }
1125 :
1126 : return true;
1127 : }
1128 :
1129 : #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1130 :
1131 : bool OpenGLContext::initWindow()
1132 : {
1133 : return false;
1134 : }
1135 :
1136 : #elif defined( UNX )
1137 :
1138 18 : bool OpenGLContext::initWindow()
1139 : {
1140 18 : const SystemEnvData* pChildSysData = 0;
1141 18 : SystemWindowData winData = generateWinData(mpWindow, false);
1142 18 : if( winData.pVisual )
1143 : {
1144 0 : if( !m_pChildWindow )
1145 : {
1146 0 : m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false);
1147 : }
1148 0 : pChildSysData = m_pChildWindow->GetSystemData();
1149 : }
1150 :
1151 18 : if (!m_pChildWindow || !pChildSysData)
1152 18 : return false;
1153 :
1154 0 : m_pChildWindow->SetMouseTransparent( true );
1155 0 : m_pChildWindow->SetParentClipMode( ParentClipMode::NoClip );
1156 0 : m_pChildWindow->EnableEraseBackground( false );
1157 0 : m_pChildWindow->SetControlForeground();
1158 0 : m_pChildWindow->SetControlBackground();
1159 :
1160 0 : m_aGLWin.dpy = static_cast<Display*>(pChildSysData->pDisplay);
1161 0 : m_aGLWin.win = pChildSysData->aWindow;
1162 0 : m_aGLWin.screen = pChildSysData->nScreen;
1163 :
1164 0 : Visual* pVisual = static_cast<Visual*>(pChildSysData->pVisual);
1165 0 : initGLWindow(pVisual);
1166 :
1167 0 : return true;
1168 : }
1169 :
1170 0 : void OpenGLContext::initGLWindow(Visual* pVisual)
1171 : {
1172 : // Get visual info
1173 : {
1174 : XVisualInfo aTemplate;
1175 0 : aTemplate.visualid = XVisualIDFromVisual( pVisual );
1176 0 : int nVisuals = 0;
1177 0 : XVisualInfo* pInfos = XGetVisualInfo( m_aGLWin.dpy, VisualIDMask, &aTemplate, &nVisuals );
1178 0 : if( nVisuals != 1 )
1179 : SAL_WARN( "vcl.opengl", "match count for visual id is not 1" );
1180 0 : m_aGLWin.vi = pInfos;
1181 : }
1182 :
1183 : // Check multi sample support
1184 : /* TODO: moggi: This is not necessarily correct in the DBG_UTIL path, as it picks
1185 : * an FBConfig instead ... */
1186 0 : int nSamples = 0;
1187 0 : glXGetConfig(m_aGLWin.dpy, m_aGLWin.vi, GLX_SAMPLES, &nSamples);
1188 0 : if( nSamples > 0 )
1189 0 : m_aGLWin.bMultiSampleSupported = true;
1190 :
1191 0 : m_aGLWin.GLXExtensions = glXQueryExtensionsString( m_aGLWin.dpy, m_aGLWin.screen );
1192 : SAL_INFO("vcl.opengl", "available GLX extensions: " << m_aGLWin.GLXExtensions);
1193 0 : }
1194 :
1195 : #endif
1196 :
1197 18 : void OpenGLContext::reset()
1198 : {
1199 18 : if( !mbInitialized )
1200 36 : return;
1201 :
1202 : // reset the clip region
1203 0 : maClipRegion.SetEmpty();
1204 :
1205 : // destroy all framebuffers
1206 0 : if( mpLastFramebuffer )
1207 : {
1208 0 : OpenGLFramebuffer* pFramebuffer = mpLastFramebuffer;
1209 :
1210 0 : makeCurrent();
1211 0 : while( pFramebuffer )
1212 : {
1213 0 : OpenGLFramebuffer* pPrevFramebuffer = pFramebuffer->mpPrevFramebuffer;
1214 0 : delete pFramebuffer;
1215 0 : pFramebuffer = pPrevFramebuffer;
1216 : }
1217 0 : mpFirstFramebuffer = NULL;
1218 0 : mpLastFramebuffer = NULL;
1219 : }
1220 :
1221 : // destroy all programs
1222 0 : if( !maPrograms.empty() )
1223 : {
1224 :
1225 0 : makeCurrent();
1226 0 : maPrograms.clear();
1227 : }
1228 :
1229 0 : if( isCurrent() )
1230 0 : resetCurrent();
1231 :
1232 0 : mbInitialized = false;
1233 :
1234 : // destroy the context itself
1235 : #if defined( WNT )
1236 : if (m_aGLWin.hRC)
1237 : {
1238 : std::vector<HGLRC>::iterator itr = std::remove(g_vShareList.begin(), g_vShareList.end(), m_aGLWin.hRC);
1239 : if (itr != g_vShareList.end())
1240 : g_vShareList.erase(itr);
1241 :
1242 : wglMakeCurrent( m_aGLWin.hDC, 0 );
1243 : wglDeleteContext( m_aGLWin.hRC );
1244 : ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC );
1245 : }
1246 : #elif defined( MACOSX )
1247 : OpenGLWrapper::resetCurrent();
1248 : #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1249 : // nothing
1250 : #elif defined( UNX )
1251 0 : if(m_aGLWin.ctx)
1252 : {
1253 0 : std::vector<GLXContext>::iterator itr = std::remove( g_vShareList.begin(), g_vShareList.end(), m_aGLWin.ctx );
1254 0 : if (itr != g_vShareList.end())
1255 0 : g_vShareList.erase(itr);
1256 :
1257 0 : glXMakeCurrent(m_aGLWin.dpy, None, NULL);
1258 0 : if( glGetError() != GL_NO_ERROR )
1259 : {
1260 : SAL_WARN("vcl.opengl", "glError: " << glGetError());
1261 : }
1262 0 : glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx);
1263 :
1264 0 : if (mbPixmap && m_aGLWin.glPix != None)
1265 0 : glXDestroyPixmap(m_aGLWin.dpy, m_aGLWin.glPix);
1266 : }
1267 : #endif
1268 : }
1269 :
1270 : #if defined( WNT ) || defined( MACOSX ) || defined( IOS ) || defined( ANDROID )
1271 :
1272 : SystemWindowData OpenGLContext::generateWinData(vcl::Window* /*pParent*/, bool bRequestLegacyContext)
1273 : {
1274 : (void) bRequestLegacyContext;
1275 : SystemWindowData aWinData;
1276 : #if defined(MACOSX)
1277 : aWinData.bOpenGL = true;
1278 : aWinData.bLegacy = bRequestLegacyContext;
1279 : #endif
1280 : aWinData.nSize = sizeof(aWinData);
1281 : return aWinData;
1282 : }
1283 :
1284 : #elif defined( UNX )
1285 :
1286 35 : SystemWindowData OpenGLContext::generateWinData(vcl::Window* pParent, bool)
1287 : {
1288 : SystemWindowData aWinData;
1289 35 : aWinData.nSize = sizeof(aWinData);
1290 35 : aWinData.pVisual = NULL;
1291 :
1292 : #if !defined(LIBO_HEADLESS)
1293 35 : const SystemEnvData* sysData(pParent->GetSystemData());
1294 :
1295 35 : Display *dpy = static_cast<Display*>(sysData->pDisplay);
1296 35 : Window win = sysData->aWindow;
1297 :
1298 35 : if( dpy == 0 || !glXQueryExtension( dpy, NULL, NULL ) )
1299 35 : return aWinData;
1300 :
1301 0 : initOpenGLFunctionPointers();
1302 :
1303 0 : int best_fbc = -1;
1304 0 : GLXFBConfig* pFBC = getFBConfig(dpy, win, best_fbc, true, false);
1305 :
1306 0 : if (!pFBC)
1307 0 : return aWinData;
1308 :
1309 0 : XVisualInfo* vi = 0;
1310 0 : if( best_fbc != -1 )
1311 0 : vi = glXGetVisualFromFBConfig( dpy, pFBC[best_fbc] );
1312 :
1313 0 : XFree(pFBC);
1314 :
1315 0 : if( vi )
1316 : {
1317 : SAL_INFO("vcl.opengl", "using VisualID " << vi->visualid);
1318 0 : aWinData.pVisual = static_cast<void*>(vi->visual);
1319 : }
1320 : #endif
1321 :
1322 0 : return aWinData;
1323 : }
1324 :
1325 : #endif
1326 :
1327 45332 : bool OpenGLContext::isCurrent()
1328 : {
1329 : #if defined( WNT )
1330 : return (wglGetCurrentContext() == m_aGLWin.hRC &&
1331 : wglGetCurrentDC() == m_aGLWin.hDC);
1332 : #elif defined( MACOSX )
1333 : (void) this; // loplugin:staticmethods
1334 : return false;
1335 : #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1336 : return false;
1337 : #elif defined( UNX )
1338 45332 : GLXDrawable nDrawable = mbPixmap ? m_aGLWin.glPix : m_aGLWin.win;
1339 90664 : return (glXGetCurrentContext() == m_aGLWin.ctx &&
1340 90664 : glXGetCurrentDrawable() == nDrawable);
1341 : #endif
1342 : }
1343 :
1344 13794207 : void OpenGLContext::clearCurrent()
1345 : {
1346 13794207 : ImplSVData* pSVData = ImplGetSVData();
1347 :
1348 : // release all framebuffers from the old context so we can re-attach the
1349 : // texture in the new context
1350 13794207 : OpenGLContext* pCurrentCtx = pSVData->maGDIData.mpLastContext;
1351 13794207 : if( pCurrentCtx && pCurrentCtx->isCurrent() )
1352 45331 : pCurrentCtx->ReleaseFramebuffers();
1353 13794207 : }
1354 :
1355 1 : void OpenGLContext::makeCurrent()
1356 : {
1357 1 : ImplSVData* pSVData = ImplGetSVData();
1358 :
1359 1 : if (isCurrent())
1360 2 : return;
1361 :
1362 0 : clearCurrent();
1363 :
1364 : #if defined( WNT )
1365 : if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
1366 : {
1367 : SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent(): wglMakeCurrent failed: " << GetLastError());
1368 : return;
1369 : }
1370 : #elif defined( MACOSX )
1371 : NSOpenGLView* pView = getOpenGLView();
1372 : OpenGLWrapper::makeCurrent(pView);
1373 : #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1374 : // nothing
1375 : #elif defined( UNX )
1376 : #ifdef DBG_UTIL
1377 : TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler);
1378 : #endif
1379 :
1380 0 : GLXDrawable nDrawable = mbPixmap ? m_aGLWin.glPix : m_aGLWin.win;
1381 0 : if (!glXMakeCurrent( m_aGLWin.dpy, nDrawable, m_aGLWin.ctx ))
1382 : {
1383 : SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent failed on drawable " << nDrawable << " pixmap? " << mbPixmap);
1384 0 : return;
1385 : }
1386 : #endif
1387 :
1388 : // move the context to the end of the contexts list
1389 : static int nSwitch = 0;
1390 : SAL_INFO("vcl.opengl", "******* CONTEXT SWITCH " << ++nSwitch << " *********");
1391 0 : if( mpNextContext )
1392 : {
1393 0 : if( mpPrevContext )
1394 0 : mpPrevContext->mpNextContext = mpNextContext;
1395 : else
1396 0 : pSVData->maGDIData.mpFirstContext = mpNextContext;
1397 0 : mpNextContext->mpPrevContext = mpPrevContext;
1398 :
1399 0 : mpPrevContext = pSVData->maGDIData.mpLastContext;
1400 0 : mpNextContext = NULL;
1401 0 : pSVData->maGDIData.mpLastContext->mpNextContext = this;
1402 0 : pSVData->maGDIData.mpLastContext = this;
1403 : }
1404 : }
1405 :
1406 0 : void OpenGLContext::resetCurrent()
1407 : {
1408 0 : clearCurrent();
1409 :
1410 : #if defined( WNT )
1411 : wglMakeCurrent( m_aGLWin.hDC, 0 );
1412 : #elif defined( MACOSX )
1413 : (void) this; // loplugin:staticmethods
1414 : OpenGLWrapper::resetCurrent();
1415 : #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1416 : // nothing
1417 : #elif defined( UNX )
1418 0 : glXMakeCurrent(m_aGLWin.dpy, None, NULL);
1419 : #endif
1420 0 : }
1421 :
1422 0 : void OpenGLContext::swapBuffers()
1423 : {
1424 : #if defined( WNT )
1425 : SwapBuffers(m_aGLWin.hDC);
1426 : #elif defined( MACOSX )
1427 : NSOpenGLView* pView = getOpenGLView();
1428 : OpenGLWrapper::swapBuffers(pView);
1429 : #elif defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1430 : // nothing
1431 : #elif defined( UNX )
1432 0 : glXSwapBuffers(m_aGLWin.dpy, mbPixmap ? m_aGLWin.glPix : m_aGLWin.win);
1433 : #endif
1434 0 : }
1435 :
1436 0 : void OpenGLContext::sync()
1437 : {
1438 : #if defined( WNT )
1439 : // nothing
1440 : #elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) || defined(LIBO_HEADLESS)
1441 : (void) this; // loplugin:staticmethods
1442 : // nothing
1443 : #elif defined( UNX )
1444 0 : glXWaitGL();
1445 0 : XSync(m_aGLWin.dpy, false);
1446 : #endif
1447 0 : }
1448 :
1449 0 : void OpenGLContext::show()
1450 : {
1451 0 : if (m_pChildWindow)
1452 0 : m_pChildWindow->Show();
1453 0 : else if (m_xWindow)
1454 0 : m_xWindow->Show();
1455 0 : }
1456 :
1457 0 : SystemChildWindow* OpenGLContext::getChildWindow()
1458 : {
1459 0 : return m_pChildWindow;
1460 : }
1461 :
1462 0 : const SystemChildWindow* OpenGLContext::getChildWindow() const
1463 : {
1464 0 : return m_pChildWindow;
1465 : }
1466 :
1467 0 : bool OpenGLContext::supportMultiSampling() const
1468 : {
1469 0 : return m_aGLWin.bMultiSampleSupported;
1470 : }
1471 :
1472 : #if defined(MACOSX)
1473 : NSOpenGLView* OpenGLContext::getOpenGLView()
1474 : {
1475 : return reinterpret_cast<NSOpenGLView*>(m_pChildWindow->GetSystemData()->mpNSView);
1476 : }
1477 : #endif
1478 :
1479 0 : bool OpenGLContext::BindFramebuffer( OpenGLFramebuffer* pFramebuffer )
1480 : {
1481 0 : if( pFramebuffer != mpCurrentFramebuffer )
1482 : {
1483 0 : if( pFramebuffer )
1484 0 : pFramebuffer->Bind();
1485 : else
1486 0 : OpenGLFramebuffer::Unbind();
1487 0 : mpCurrentFramebuffer = pFramebuffer;
1488 : }
1489 :
1490 0 : return true;
1491 : }
1492 :
1493 0 : bool OpenGLContext::AcquireDefaultFramebuffer()
1494 : {
1495 0 : return BindFramebuffer( NULL );
1496 : }
1497 :
1498 0 : OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rTexture )
1499 : {
1500 0 : OpenGLFramebuffer* pFramebuffer = NULL;
1501 0 : OpenGLFramebuffer* pFreeFbo = NULL;
1502 0 : OpenGLFramebuffer* pSameSizeFbo = NULL;
1503 :
1504 : // check if there is already a framebuffer attached to that texture
1505 0 : pFramebuffer = mpLastFramebuffer;
1506 0 : while( pFramebuffer )
1507 : {
1508 0 : if( pFramebuffer->IsAttached( rTexture ) )
1509 0 : break;
1510 0 : if( !pFreeFbo && pFramebuffer->IsFree() )
1511 0 : pFreeFbo = pFramebuffer;
1512 0 : if( !pSameSizeFbo &&
1513 0 : pFramebuffer->GetWidth() == rTexture.GetWidth() &&
1514 0 : pFramebuffer->GetHeight() == rTexture.GetHeight() )
1515 0 : pSameSizeFbo = pFramebuffer;
1516 0 : pFramebuffer = pFramebuffer->mpPrevFramebuffer;
1517 : }
1518 :
1519 : // else use any framebuffer having the same size
1520 0 : if( !pFramebuffer && pSameSizeFbo )
1521 0 : pFramebuffer = pSameSizeFbo;
1522 :
1523 : // else use the first free framebuffer
1524 0 : if( !pFramebuffer && pFreeFbo )
1525 0 : pFramebuffer = pFreeFbo;
1526 :
1527 : // if there isn't any free one, create a new one if the limit isn't reached
1528 0 : if( !pFramebuffer && mnFramebufferCount < MAX_FRAMEBUFFER_COUNT )
1529 : {
1530 0 : mnFramebufferCount++;
1531 0 : pFramebuffer = new OpenGLFramebuffer();
1532 0 : if( mpLastFramebuffer )
1533 : {
1534 0 : pFramebuffer->mpPrevFramebuffer = mpLastFramebuffer;
1535 0 : mpLastFramebuffer->mpNextFramebuffer = pFramebuffer;
1536 0 : mpLastFramebuffer = pFramebuffer;
1537 : }
1538 : else
1539 : {
1540 0 : mpFirstFramebuffer = pFramebuffer;
1541 0 : mpLastFramebuffer = pFramebuffer;
1542 : }
1543 : }
1544 :
1545 : // last try, use any framebuffer
1546 : // TODO order the list of framebuffers as a LRU
1547 0 : if( !pFramebuffer )
1548 0 : pFramebuffer = mpFirstFramebuffer;
1549 :
1550 : assert( pFramebuffer );
1551 0 : BindFramebuffer( pFramebuffer );
1552 0 : pFramebuffer->AttachTexture( rTexture );
1553 0 : glViewport( 0, 0, rTexture.GetWidth(), rTexture.GetHeight() );
1554 :
1555 0 : return pFramebuffer;
1556 : }
1557 :
1558 0 : void OpenGLContext::ReleaseFramebuffer( OpenGLFramebuffer* pFramebuffer )
1559 : {
1560 0 : if( pFramebuffer )
1561 0 : pFramebuffer->DetachTexture();
1562 0 : }
1563 :
1564 0 : void OpenGLContext::ReleaseFramebuffer( const OpenGLTexture& rTexture )
1565 : {
1566 0 : OpenGLFramebuffer* pFramebuffer = mpLastFramebuffer;
1567 :
1568 0 : while( pFramebuffer )
1569 : {
1570 0 : if( pFramebuffer->IsAttached( rTexture ) )
1571 : {
1572 0 : BindFramebuffer( pFramebuffer );
1573 0 : pFramebuffer->DetachTexture();
1574 : }
1575 0 : pFramebuffer = pFramebuffer->mpPrevFramebuffer;
1576 : }
1577 0 : }
1578 :
1579 45331 : void OpenGLContext::ReleaseFramebuffers()
1580 : {
1581 45331 : OpenGLFramebuffer* pFramebuffer = mpLastFramebuffer;
1582 90662 : while( pFramebuffer )
1583 : {
1584 0 : BindFramebuffer( pFramebuffer );
1585 0 : pFramebuffer->DetachTexture();
1586 0 : pFramebuffer = pFramebuffer->mpPrevFramebuffer;
1587 : }
1588 45331 : }
1589 :
1590 0 : OpenGLProgram* OpenGLContext::GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble )
1591 : {
1592 0 : ProgramKey aKey( rVertexShader, rFragmentShader, preamble );
1593 :
1594 : std::map< ProgramKey, boost::shared_ptr<OpenGLProgram> >::iterator
1595 0 : it = maPrograms.find( aKey );
1596 0 : if( it != maPrograms.end() )
1597 0 : return it->second.get();
1598 :
1599 0 : boost::shared_ptr<OpenGLProgram> pProgram = boost::make_shared<OpenGLProgram>();
1600 0 : if( !pProgram->Load( rVertexShader, rFragmentShader, preamble ) )
1601 0 : return NULL;
1602 :
1603 0 : maPrograms.insert(std::pair<ProgramKey, boost::shared_ptr<OpenGLProgram> >(aKey, pProgram));
1604 0 : return pProgram.get();
1605 : }
1606 :
1607 0 : OpenGLProgram* OpenGLContext::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble )
1608 : {
1609 0 : OpenGLProgram* pProgram = GetProgram( rVertexShader, rFragmentShader, preamble );
1610 :
1611 0 : if( pProgram == mpCurrentProgram )
1612 0 : return pProgram;
1613 :
1614 0 : mpCurrentProgram = pProgram;
1615 0 : mpCurrentProgram->Use();
1616 :
1617 0 : return mpCurrentProgram;
1618 : }
1619 :
1620 : inline
1621 0 : OpenGLContext::ProgramKey::ProgramKey( const OUString& v, const OUString& f, const OString& p )
1622 0 : : vertexShader( v ), fragmentShader( f ), preamble( p )
1623 : {
1624 0 : }
1625 :
1626 : inline
1627 0 : bool OpenGLContext::ProgramKey::operator< ( const ProgramKey& other ) const
1628 : {
1629 0 : if( vertexShader != other.vertexShader )
1630 0 : return vertexShader < other.vertexShader;
1631 0 : if( fragmentShader != other.fragmentShader )
1632 0 : return fragmentShader < other.fragmentShader;
1633 0 : return preamble < other.preamble;
1634 801 : }
1635 :
1636 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|