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 <vcl/pngwrite.hxx>
17 : #include <vcl/bmpacc.hxx>
18 : #include <vcl/graph.hxx>
19 :
20 : #if defined(MACOSX)
21 : #include <premac.h>
22 : #include "OpenGLWrapper.hxx"
23 : #include <postmac.h>
24 : #endif
25 :
26 : using namespace com::sun::star;
27 :
28 34 : GLWindow::~GLWindow()
29 : {
30 : #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
31 34 : XFree(vi);
32 : #endif
33 34 : }
34 :
35 34 : OpenGLContext::OpenGLContext():
36 : mpWindow(NULL),
37 : m_pChildWindow(NULL),
38 : mbInitialized(false),
39 34 : mbRequestLegacyContext(false)
40 : {
41 34 : }
42 :
43 68 : OpenGLContext::~OpenGLContext()
44 : {
45 : #if defined( WNT )
46 : if (m_aGLWin.hRC)
47 : {
48 : wglMakeCurrent( m_aGLWin.hDC, 0 );
49 : wglDeleteContext( m_aGLWin.hRC );
50 : ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC );
51 : }
52 : #elif defined( MACOSX )
53 : OpenGLWrapper::resetCurrent();
54 : #elif defined( IOS ) || defined( ANDROID )
55 : // nothing
56 : #elif defined( UNX )
57 34 : if(m_aGLWin.ctx)
58 : {
59 0 : glXMakeCurrent(m_aGLWin.dpy, None, NULL);
60 0 : if( glGetError() != GL_NO_ERROR )
61 : {
62 : SAL_WARN("vcl.opengl", "glError: " << (char *)gluErrorString(glGetError()));
63 : }
64 0 : glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx);
65 : }
66 : #endif
67 34 : }
68 :
69 0 : void OpenGLContext::requestLegacyContext()
70 : {
71 0 : mbRequestLegacyContext = true;
72 0 : }
73 :
74 : #if defined( _WIN32 )
75 : static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
76 : {
77 : switch (message)
78 : {
79 : case WM_CREATE:
80 : return 0;
81 : case WM_CLOSE:
82 : PostQuitMessage(0);
83 : return 0;
84 : case WM_DESTROY:
85 : return 0;
86 : case WM_KEYDOWN:
87 : switch(wParam)
88 : {
89 : case VK_ESCAPE:
90 : PostQuitMessage(0);
91 : return 0;
92 :
93 : case VK_SPACE:
94 : break;
95 : }
96 : default:
97 : return DefWindowProc(hwnd, message, wParam, lParam);
98 : }
99 : }
100 :
101 : int InitTempWindow(HWND *hwnd, int width, int height, PIXELFORMATDESCRIPTOR inPfd, GLWindow glWin)
102 : {
103 : PIXELFORMATDESCRIPTOR pfd = inPfd;
104 : int pfmt;
105 : int ret;
106 : WNDCLASS wc;
107 : wc.style = 0;
108 : wc.lpfnWndProc = WndProc;
109 : wc.cbClsExtra = wc.cbWndExtra = 0;
110 : wc.hInstance = NULL;
111 : wc.hIcon = NULL;
112 : wc.hCursor = NULL;
113 : wc.hbrBackground = NULL;
114 : wc.lpszMenuName = NULL;
115 : wc.lpszClassName = (LPCSTR)"GLRenderer";
116 : RegisterClass(&wc);
117 : *hwnd = CreateWindow(wc.lpszClassName, NULL, WS_DISABLED, 0, 0, width, height, NULL, NULL, wc.hInstance, NULL);
118 : glWin.hDC = GetDC(*hwnd);
119 : pfmt = ChoosePixelFormat(glWin.hDC, &pfd);
120 : if (!pfmt)
121 : {
122 : return -1;
123 : }
124 : ret = SetPixelFormat(glWin.hDC, pfmt, &pfd);
125 : if(!ret)
126 : {
127 : return -1;
128 : }
129 : glWin.hRC = wglCreateContext(glWin.hDC);
130 : if(!(glWin.hRC))
131 : {
132 : return -1;
133 : }
134 : ret = wglMakeCurrent(glWin.hDC, glWin.hRC);
135 : if(!ret)
136 : {
137 : return -1;
138 : }
139 : return 0;
140 : }
141 :
142 : bool WGLisExtensionSupported(const char *extension)
143 : {
144 : const size_t extlen = strlen(extension);
145 : const char *supported = NULL;
146 :
147 : // Try To Use wglGetExtensionStringARB On Current DC, If Possible
148 : PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");
149 :
150 : if (wglGetExtString)
151 : supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC());
152 : // If That Failed, Try Standard Opengl Extensions String
153 : if (supported == NULL)
154 : supported = (char*)glGetString(GL_EXTENSIONS);
155 : // If That Failed Too, Must Be No Extensions Supported
156 : if (supported == NULL)
157 : return 0;
158 :
159 : // Begin Examination At Start Of String, Increment By 1 On False Match
160 : for (const char* p = supported; ; p++)
161 : {
162 : // Advance p Up To The Next Possible Match
163 : p = strstr(p, extension);
164 :
165 : if (p == NULL)
166 : return 0; // No Match
167 :
168 : // Make Sure That Match Is At The Start Of The String Or That
169 : // The Previous Char Is A Space, Or Else We Could Accidentally
170 : // Match "wglFunkywglExtension" With "wglExtension"
171 :
172 : // Also, Make Sure That The Following Character Is Space Or NULL
173 : // Or Else "wglExtensionTwo" Might Match "wglExtension"
174 : if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))
175 : return 1; // Match
176 : }
177 : }
178 :
179 : bool InitMultisample(PIXELFORMATDESCRIPTOR pfd, int& rPixelFormat)
180 : {
181 : HWND hWnd = NULL;
182 : GLWindow glWin;
183 : //create a temp windwo to check whether support multi-sample, if support, get the format
184 : if (InitTempWindow(&hWnd, 1, 1, pfd, glWin) < 0)
185 : {
186 : SAL_WARN("vcl.opengl", "Can't create temp window to test");
187 : return false;
188 : }
189 :
190 : // See If The String Exists In WGL!
191 : if (!WGLisExtensionSupported("WGL_ARB_multisample"))
192 : {
193 : SAL_WARN("vcl.opengl", "Device doesn't support multi sample");
194 : return false;
195 : }
196 : // Get Our Pixel Format
197 : PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
198 : if (!wglChoosePixelFormatARB)
199 : {
200 : return false;
201 : }
202 : // Get Our Current Device Context
203 : HDC hDC = GetDC(hWnd);
204 :
205 : int pixelFormat;
206 : int valid;
207 : UINT numFormats;
208 : float fAttributes[] = {0,0};
209 : // These Attributes Are The Bits We Want To Test For In Our Sample
210 : // Everything Is Pretty Standard, The Only One We Want To
211 : // Really Focus On Is The SAMPLE BUFFERS ARB And WGL SAMPLES
212 : // These Two Are Going To Do The Main Testing For Whether Or Not
213 : // We Support Multisampling On This Hardware.
214 : int iAttributes[] =
215 : {
216 : WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
217 : WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
218 : WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
219 : WGL_COLOR_BITS_ARB,24,
220 : WGL_ALPHA_BITS_ARB,8,
221 : WGL_DEPTH_BITS_ARB,24,
222 : WGL_STENCIL_BITS_ARB,0,
223 : WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
224 : WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
225 : WGL_SAMPLES_ARB,8,
226 : 0,0
227 : };
228 :
229 : bool bArbMultisampleSupported = true;
230 :
231 : // First We Check To See If We Can Get A Pixel Format For 4 Samples
232 : valid = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
233 : // If We Returned True, And Our Format Count Is Greater Than 1
234 : if (valid && numFormats >= 1)
235 : {
236 : bArbMultisampleSupported = true;
237 : rPixelFormat = pixelFormat;
238 : wglMakeCurrent(NULL, NULL);
239 : wglDeleteContext(glWin.hRC);
240 : ReleaseDC(hWnd, glWin.hDC);
241 : DestroyWindow(hWnd);
242 : return bArbMultisampleSupported;
243 : }
244 : // Our Pixel Format With 4 Samples Failed, Test For 2 Samples
245 : iAttributes[19] = 2;
246 : valid = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
247 : if (valid && numFormats >= 1)
248 : {
249 : bArbMultisampleSupported = true;
250 : rPixelFormat = pixelFormat;
251 : wglMakeCurrent(NULL, NULL);
252 : wglDeleteContext(glWin.hRC);
253 : ReleaseDC(hWnd, glWin.hDC);
254 : DestroyWindow(hWnd);
255 : return bArbMultisampleSupported;
256 : }
257 : // Return The Valid Format
258 : wglMakeCurrent(NULL, NULL);
259 : wglDeleteContext(glWin.hRC);
260 : ReleaseDC(hWnd, glWin.hDC);
261 : DestroyWindow(hWnd);
262 :
263 : return bArbMultisampleSupported;
264 : }
265 : #endif
266 :
267 : #ifdef DBG_UTIL
268 :
269 : namespace {
270 :
271 : const char* getSeverityString(GLenum severity)
272 : {
273 : switch(severity)
274 : {
275 : case GL_DEBUG_SEVERITY_LOW:
276 : return "low";
277 : case GL_DEBUG_SEVERITY_MEDIUM:
278 : return "medium";
279 : case GL_DEBUG_SEVERITY_HIGH:
280 : return "high";
281 : default:
282 : ;
283 : }
284 :
285 : return "unknown";
286 : }
287 :
288 : const char* getSourceString(GLenum source)
289 : {
290 : switch(source)
291 : {
292 : case GL_DEBUG_SOURCE_API:
293 : return "API";
294 : case GL_DEBUG_SOURCE_SHADER_COMPILER:
295 : return "shader compiler";
296 : case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
297 : return "window system";
298 : case GL_DEBUG_SOURCE_THIRD_PARTY:
299 : return "third party";
300 : case GL_DEBUG_SOURCE_APPLICATION:
301 : return "Libreoffice";
302 : case GL_DEBUG_SOURCE_OTHER:
303 : return "unknown";
304 : default:
305 : ;
306 : }
307 :
308 : return "unknown";
309 : }
310 :
311 : const char* getTypeString(GLenum type)
312 : {
313 : switch(type)
314 : {
315 : case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
316 : return "deprecated behavior";
317 : case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
318 : return "undefined behavior";
319 : case GL_DEBUG_TYPE_PERFORMANCE:
320 : return "performance";
321 : case GL_DEBUG_TYPE_PORTABILITY:
322 : return "portability";
323 : case GL_DEBUG_TYPE_MARKER:
324 : return "marker";
325 : case GL_DEBUG_TYPE_PUSH_GROUP:
326 : return "push group";
327 : case GL_DEBUG_TYPE_POP_GROUP:
328 : return "pop group";
329 : case GL_DEBUG_TYPE_OTHER:
330 : return "other";
331 : case GL_DEBUG_TYPE_ERROR:
332 : return "error";
333 : default:
334 : ;
335 : }
336 :
337 : return "unkown";
338 : }
339 :
340 : extern "C" void
341 : #if defined _WIN32
342 : APIENTRY
343 : #endif
344 : debug_callback(GLenum source, GLenum type, GLuint id,
345 : GLenum severity, GLsizei , const GLchar* message, GLvoid* )
346 : {
347 : // ignore Nvidia's : "Program/shader state performance warning: Fragment Shader is going to be recompiled because the shader key based on GL state mismatches."
348 : // the GLSL compiler is a bit too aggressive in optimizing the state based on the current OpenGL state
349 : if (id == 131218)
350 : return;
351 :
352 : SAL_WARN("vcl.opengl", "OpenGL debug message: source: " << getSourceString(source) << ", type: "
353 : << getTypeString(type) << ", id: " << id << ", severity: " << getSeverityString(severity) << " with message: " << message);
354 : }
355 :
356 : }
357 :
358 : #endif
359 :
360 : #if defined UNX && !defined MACOSX && !defined IOS && !defined ANDROID
361 :
362 : namespace {
363 :
364 : static bool errorTriggered;
365 0 : int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ )
366 : {
367 0 : errorTriggered = true;
368 :
369 0 : return 0;
370 : }
371 :
372 0 : GLXFBConfig* getFBConfig(const SystemEnvData* sysData, int& nBestFBC)
373 : {
374 0 : Display *dpy = reinterpret_cast<Display*>(sysData->pDisplay);
375 :
376 0 : if( dpy == 0 || !glXQueryExtension( dpy, NULL, NULL ) )
377 0 : return NULL;
378 :
379 0 : Window win = sysData->aWindow;
380 :
381 : SAL_INFO("vcl.opengl", "parent window: " << win);
382 :
383 : XWindowAttributes xattr;
384 0 : XGetWindowAttributes( dpy, win, &xattr );
385 :
386 0 : int screen = XScreenNumberOfScreen( xattr.screen );
387 :
388 : static int visual_attribs[] =
389 : {
390 : GLX_DOUBLEBUFFER, True,
391 : GLX_X_RENDERABLE, True,
392 : GLX_RED_SIZE, 8,
393 : GLX_GREEN_SIZE, 8,
394 : GLX_BLUE_SIZE, 8,
395 : GLX_ALPHA_SIZE, 8,
396 : GLX_DEPTH_SIZE, 24,
397 : GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
398 : None
399 : };
400 0 : int fbCount = 0;
401 : GLXFBConfig* pFBC = glXChooseFBConfig( dpy,
402 : screen,
403 0 : visual_attribs, &fbCount );
404 :
405 0 : if(!pFBC)
406 : {
407 : SAL_WARN("vcl.opengl", "no suitable fb format found");
408 0 : return NULL;
409 : }
410 :
411 0 : int best_num_samp = -1;
412 0 : for(int i = 0; i < fbCount; ++i)
413 : {
414 0 : XVisualInfo* pVi = glXGetVisualFromFBConfig( dpy, pFBC[i] );
415 0 : if(pVi)
416 : {
417 : // pick the one with the most samples per pixel
418 0 : int nSampleBuf = 0;
419 0 : int nSamples = 0;
420 0 : glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf );
421 0 : glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLES , &nSamples );
422 :
423 0 : if ( nBestFBC < 0 || (nSampleBuf && ( nSamples > best_num_samp )) )
424 : {
425 0 : nBestFBC = i;
426 0 : best_num_samp = nSamples;
427 : }
428 : }
429 0 : XFree( pVi );
430 : }
431 :
432 0 : return pFBC;
433 : }
434 :
435 : }
436 :
437 : #endif
438 :
439 0 : bool OpenGLContext::init( vcl::Window* pParent )
440 : {
441 0 : if(mbInitialized)
442 0 : return true;
443 :
444 0 : m_pWindow.reset(pParent ? NULL : new vcl::Window(0, WB_NOBORDER|WB_NODIALOGCONTROL));
445 0 : mpWindow = pParent ? pParent : m_pWindow.get();
446 0 : m_pChildWindow = 0;
447 0 : initWindow();
448 0 : return ImplInit();
449 : }
450 :
451 34 : bool OpenGLContext::init(SystemChildWindow* pChildWindow)
452 : {
453 34 : if(mbInitialized)
454 0 : return true;
455 :
456 34 : if( !pChildWindow )
457 0 : return false;
458 :
459 34 : mpWindow = pChildWindow->GetParent();
460 34 : m_pChildWindow = pChildWindow;
461 34 : initWindow();
462 34 : return ImplInit();
463 : }
464 :
465 34 : bool OpenGLContext::ImplInit()
466 : {
467 : SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start");
468 34 : if(m_pWindow)
469 0 : m_pWindow->setPosSizePixel(0,0,0,0);
470 34 : m_aGLWin.Width = 0;
471 34 : m_aGLWin.Height = 0;
472 :
473 : #if defined( WNT )
474 : m_aGLWin.hDC = GetDC(m_aGLWin.hWnd);
475 : #elif defined( MACOSX )
476 :
477 : #elif defined( IOS )
478 :
479 : SAL_INFO("vcl.opengl", "OpenGLContext not implemented yet for iOS");
480 : return false;
481 :
482 : #elif defined( ANDROID )
483 :
484 : SAL_INFO("vcl.opengl", "OpenGLContext not implemented yet for Android");
485 : return false;
486 :
487 : #elif defined( UNX )
488 : #ifdef DBG_UTIL
489 :
490 : if (glXCreateContextAttribsARB && !mbRequestLegacyContext)
491 : {
492 : int best_fbc = -1;
493 : const SystemEnvData* sysData(m_pChildWindow->GetSystemData());
494 : GLXFBConfig* pFBC = getFBConfig(sysData, best_fbc);
495 : if (!pFBC)
496 : return false;
497 :
498 : int nContextAttribs[] =
499 : {
500 : GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
501 : GLX_CONTEXT_MINOR_VERSION_ARB, 2,
502 : None
503 : };
504 : m_aGLWin.ctx = glXCreateContextAttribsARB(m_aGLWin.dpy, pFBC[best_fbc], 0, GL_TRUE, nContextAttribs);
505 :
506 : }
507 : #endif
508 34 : if (!m_aGLWin.ctx)
509 : {
510 34 : if (!m_aGLWin.dpy || !m_aGLWin.vi)
511 34 : return false;
512 :
513 0 : m_aGLWin.ctx = m_aGLWin.dpy == 0 ? 0 : glXCreateContext(m_aGLWin.dpy,
514 : m_aGLWin.vi,
515 : 0,
516 0 : GL_TRUE);
517 : }
518 0 : if( m_aGLWin.ctx == NULL )
519 : {
520 : SAL_WARN("vcl.opengl", "unable to create GLX context");
521 0 : return false;
522 : }
523 : #endif
524 :
525 : #if defined( WNT )
526 : PIXELFORMATDESCRIPTOR PixelFormatFront = // PixelFormat Tells Windows How We Want Things To Be
527 : {
528 : sizeof(PIXELFORMATDESCRIPTOR),
529 : 1, // Version Number
530 : PFD_DRAW_TO_WINDOW |
531 : PFD_SUPPORT_OPENGL |
532 : PFD_DOUBLEBUFFER,
533 : PFD_TYPE_RGBA, // Request An RGBA Format
534 : (BYTE)32, // Select Our Color Depth
535 : 0, 0, 0, 0, 0, 0, // Color Bits Ignored
536 : 0, // No Alpha Buffer
537 : 0, // Shift Bit Ignored
538 : 0, // No Accumulation Buffer
539 : 0, 0, 0, 0, // Accumulation Bits Ignored
540 : 64, // 32 bit Z-BUFFER
541 : 0, // 0 bit stencil buffer
542 : 0, // No Auxiliary Buffer
543 : 0, // now ignored
544 : 0, // Reserved
545 : 0, 0, 0 // Layer Masks Ignored
546 : };
547 :
548 : // we must check whether can set the MSAA
549 : int WindowPix = 0;
550 : bool bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix);
551 : if (bMultiSampleSupport && WindowPix != 0)
552 : {
553 : m_aGLWin.bMultiSampleSupported = true;
554 : }
555 : else
556 : {
557 : WindowPix = ChoosePixelFormat(m_aGLWin.hDC, &PixelFormatFront);
558 : }
559 :
560 : if (WindowPix == 0)
561 : {
562 : SAL_WARN("vcl.opengl", "Invalid pixelformat");
563 : return false;
564 : }
565 :
566 : SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront);
567 : m_aGLWin.hRC = wglCreateContext(m_aGLWin.hDC);
568 : if (m_aGLWin.hRC == NULL)
569 : {
570 : SAL_WARN("vcl.opengl", "wglCreateContext failed");
571 : return false;
572 : }
573 :
574 : if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
575 : {
576 : SAL_WARN("vcl.opengl", "wglMakeCurrent failed: " << GetLastError());
577 : return false;
578 : }
579 :
580 : #elif defined( MACOSX )
581 :
582 : NSOpenGLView* pView = getOpenGLView();
583 : OpenGLWrapper::makeCurrent(pView);
584 :
585 : #elif defined( IOS )
586 :
587 : #elif defined( ANDROID )
588 :
589 : #elif defined( UNX )
590 0 : if( !glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ) )
591 : {
592 : SAL_INFO("vcl.opengl", "unable to select current GLX context");
593 0 : return false;
594 : }
595 :
596 : int glxMinor, glxMajor;
597 0 : double nGLXVersion = 0;
598 0 : if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) )
599 0 : nGLXVersion = glxMajor + 0.1*glxMinor;
600 : SAL_INFO("vcl.opengl", "available GLX version: " << nGLXVersion);
601 :
602 0 : m_aGLWin.GLExtensions = glGetString( GL_EXTENSIONS );
603 : SAL_INFO("vcl.opengl", "available GL extensions: " << m_aGLWin.GLExtensions);
604 :
605 0 : if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) )
606 : {
607 : // enable vsync
608 : typedef GLint (*glXSwapIntervalProc)(GLint);
609 0 : glXSwapIntervalProc glXSwapInterval = (glXSwapIntervalProc) glXGetProcAddress( (const GLubyte*) "glXSwapIntervalSGI" );
610 0 : if( glXSwapInterval ) {
611 : int (*oldHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/);
612 :
613 : // replace error handler temporarily
614 0 : oldHandler = XSetErrorHandler( oglErrorHandler );
615 :
616 0 : errorTriggered = false;
617 :
618 0 : glXSwapInterval( 1 );
619 :
620 : // sync so that we possibly get an XError
621 0 : glXWaitGL();
622 0 : XSync(m_aGLWin.dpy, false);
623 :
624 0 : if( errorTriggered )
625 : SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?");
626 : else
627 : SAL_INFO("vcl.opengl", "set swap interval to 1 (enable vsync)");
628 :
629 : // restore the error handler
630 0 : XSetErrorHandler( oldHandler );
631 : }
632 : }
633 :
634 : #endif
635 :
636 : //rGLRender.InitOpenGL(m_aGLWin);
637 :
638 : static bool bGlewInit = false;
639 0 : if(!bGlewInit)
640 : {
641 0 : glewExperimental = GL_TRUE;
642 0 : GLenum err = glewInit();
643 0 : if (err != GLEW_OK)
644 : {
645 : SAL_WARN("vcl.opengl", "Failed to initialize GLEW: " << glewGetErrorString(err));
646 0 : return false;
647 : }
648 : else
649 0 : bGlewInit = true;
650 : }
651 :
652 : #ifdef DBG_UTIL
653 : // only enable debug output in dbgutil build
654 : // somehow there are implementations where the feature is present and the function
655 : // pointer is still NULL
656 : if( GLEW_ARB_debug_output && glDebugMessageCallback )
657 : {
658 : glEnable(GL_DEBUG_OUTPUT);
659 : glDebugMessageCallback(&debug_callback, NULL);
660 : }
661 :
662 : #endif
663 :
664 : SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----end");
665 0 : mbInitialized = true;
666 0 : return true;
667 : }
668 :
669 0 : void OpenGLContext::setWinPosAndSize(const Point &rPos, const Size& rSize)
670 : {
671 0 : if(m_pWindow)
672 0 : m_pWindow->SetPosSizePixel(rPos, rSize);
673 0 : if( m_pChildWindow )
674 0 : m_pChildWindow->SetPosSizePixel(rPos, rSize);
675 :
676 0 : m_aGLWin.Width = rSize.Width();
677 0 : m_aGLWin.Height = rSize.Height();
678 0 : }
679 :
680 0 : void OpenGLContext::setWinSize(const Size& rSize)
681 : {
682 0 : if(m_pWindow)
683 0 : m_pWindow->SetSizePixel(rSize);
684 0 : if( m_pChildWindow )
685 0 : m_pChildWindow->SetSizePixel(rSize);
686 :
687 0 : m_aGLWin.Width = rSize.Width();
688 0 : m_aGLWin.Height = rSize.Height();
689 0 : }
690 :
691 :
692 0 : void OpenGLContext::renderToFile()
693 : {
694 0 : int iWidth = m_aGLWin.Width;
695 0 : int iHeight = m_aGLWin.Height;
696 : static int nIdx = 0;
697 0 : OUString aName = OUString( "file:///home/moggi/Documents/work/output" ) + OUString::number( nIdx++ ) + ".png";
698 0 : OpenGLHelper::renderToFile(iWidth, iHeight, aName);
699 0 : }
700 :
701 : #if defined( WNT )
702 :
703 : bool OpenGLContext::initWindow()
704 : {
705 : if( !m_pChildWindow )
706 : {
707 : SystemWindowData winData = generateWinData(mpWindow, false);
708 : m_pChildWindow = new SystemChildWindow(mpWindow, 0, &winData, false);
709 : m_pChildWindowGC.reset(m_pChildWindow);
710 : }
711 :
712 : if( m_pChildWindow )
713 : {
714 : m_pChildWindow->SetMouseTransparent( true );
715 : m_pChildWindow->SetParentClipMode(PARENTCLIPMODE_CLIP);
716 : m_pChildWindow->EnableEraseBackground( false );
717 : m_pChildWindow->SetControlForeground();
718 : m_pChildWindow->SetControlBackground();
719 : //m_pChildWindow->EnablePaint(false);
720 :
721 : const SystemEnvData* sysData(m_pChildWindow->GetSystemData());
722 : m_aGLWin.hWnd = sysData->hWnd;
723 : }
724 :
725 : return true;
726 : }
727 :
728 : #elif defined( MACOSX )
729 :
730 : bool OpenGLContext::initWindow()
731 : {
732 : if( !m_pChildWindow )
733 : {
734 : SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext);
735 : m_pChildWindow = new SystemChildWindow(mpWindow, 0, &winData, false);
736 : m_pChildWindowGC.reset(m_pChildWindow);
737 : }
738 :
739 : if( m_pChildWindow )
740 : {
741 : m_pChildWindow->SetMouseTransparent( true );
742 : m_pChildWindow->SetParentClipMode(PARENTCLIPMODE_CLIP);
743 : m_pChildWindow->EnableEraseBackground( false );
744 : m_pChildWindow->SetControlForeground();
745 : m_pChildWindow->SetControlBackground();
746 : //m_pChildWindow->EnablePaint(false);
747 :
748 : }
749 :
750 : return true;
751 : }
752 :
753 : #elif defined( IOS ) || defined( ANDROID )
754 :
755 : bool OpenGLContext::initWindow()
756 : {
757 : return false;
758 : }
759 :
760 : #elif defined( UNX )
761 :
762 34 : bool OpenGLContext::initWindow()
763 : {
764 34 : const SystemEnvData* pChildSysData = 0;
765 34 : SystemWindowData winData = generateWinData(mpWindow, false);
766 34 : if( winData.pVisual )
767 : {
768 0 : if( !m_pChildWindow )
769 : {
770 0 : m_pChildWindow = new SystemChildWindow(mpWindow, 0, &winData, false);
771 0 : m_pChildWindowGC.reset(m_pChildWindow);
772 : }
773 0 : pChildSysData = m_pChildWindow->GetSystemData();
774 : }
775 :
776 34 : if (!m_pChildWindow || !pChildSysData)
777 34 : return false;
778 :
779 0 : m_pChildWindow->SetMouseTransparent( true );
780 0 : m_pChildWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
781 0 : m_pChildWindow->EnableEraseBackground( false );
782 0 : m_pChildWindow->SetControlForeground();
783 0 : m_pChildWindow->SetControlBackground();
784 :
785 0 : m_aGLWin.dpy = reinterpret_cast<Display*>(pChildSysData->pDisplay);
786 0 : m_aGLWin.win = pChildSysData->aWindow;
787 0 : m_aGLWin.screen = pChildSysData->nScreen;
788 :
789 : // Get visual info
790 : {
791 0 : Visual* pVisual = (Visual*)pChildSysData->pVisual;
792 : XVisualInfo aTemplate;
793 0 : aTemplate.visualid = XVisualIDFromVisual( pVisual );
794 0 : int nVisuals = 0;
795 0 : XVisualInfo* pInfos = XGetVisualInfo( m_aGLWin.dpy, VisualIDMask, &aTemplate, &nVisuals );
796 0 : if( nVisuals != 1 )
797 : SAL_WARN( "vcl.opengl", "match count for visual id is not 1" );
798 0 : m_aGLWin.vi = pInfos;
799 : }
800 :
801 : // Check multi sample support
802 0 : int nSamples = 0;
803 0 : glXGetConfig(m_aGLWin.dpy, m_aGLWin.vi, GLX_SAMPLES, &nSamples);
804 0 : if( nSamples > 0 )
805 0 : m_aGLWin.bMultiSampleSupported = true;
806 :
807 0 : m_aGLWin.GLXExtensions = glXQueryExtensionsString( m_aGLWin.dpy, m_aGLWin.screen );
808 : SAL_INFO("vcl.opengl", "available GLX extensions: " << m_aGLWin.GLXExtensions);
809 :
810 0 : return true;
811 : }
812 :
813 : #endif
814 :
815 : #if defined( WNT ) || defined( MACOSX ) || defined( IOS ) || defined( ANDROID )
816 :
817 : SystemWindowData OpenGLContext::generateWinData(vcl::Window* /*pParent*/, bool bRequestLegacyContext)
818 : {
819 : (void) bRequestLegacyContext;
820 : SystemWindowData aWinData;
821 : #if defined(MACOSX)
822 : aWinData.bOpenGL = true;
823 : aWinData.bLegacy = bRequestLegacyContext;
824 : #endif
825 : aWinData.nSize = sizeof(aWinData);
826 : return aWinData;
827 : }
828 :
829 : #elif defined( UNX )
830 :
831 : namespace {
832 :
833 : // we need them before glew can initialize them
834 : // glew needs an OpenGL context so we need to get the address manually
835 0 : void initOpenGLFunctionPointers()
836 : {
837 0 : glXChooseFBConfig = (GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements))glXGetProcAddressARB((GLubyte*)"glXChooseFBConfig");
838 0 : glXGetVisualFromFBConfig = (XVisualInfo*(*)(Display *dpy, GLXFBConfig config))glXGetProcAddressARB((GLubyte*)"glXGetVisualFromFBConfig"); // try to find a visual for the current set of attributes
839 0 : glXGetFBConfigAttrib = (int(*)(Display *dpy, GLXFBConfig config, int attribute, int* value))glXGetProcAddressARB((GLubyte*)"glXGetFBConfigAttrib");
840 0 : glXCreateContextAttribsARB = (GLXContext(*) (Display*, GLXFBConfig, GLXContext, Bool, const int*)) glXGetProcAddressARB((const GLubyte *) "glXCreateContextAttribsARB");;
841 0 : }
842 :
843 : }
844 :
845 68 : SystemWindowData OpenGLContext::generateWinData(vcl::Window* pParent, bool)
846 : {
847 : SystemWindowData aWinData;
848 68 : aWinData.nSize = sizeof(aWinData);
849 68 : aWinData.pVisual = NULL;
850 :
851 68 : const SystemEnvData* sysData(pParent->GetSystemData());
852 :
853 68 : Display *dpy = reinterpret_cast<Display*>(sysData->pDisplay);
854 :
855 68 : if( dpy == 0 || !glXQueryExtension( dpy, NULL, NULL ) )
856 68 : return aWinData;
857 :
858 0 : initOpenGLFunctionPointers();
859 :
860 0 : int best_fbc = -1;
861 0 : GLXFBConfig* pFBC = getFBConfig(sysData, best_fbc);
862 :
863 0 : XVisualInfo* vi = glXGetVisualFromFBConfig( dpy, pFBC[best_fbc] );
864 0 : if( vi )
865 : {
866 : SAL_INFO("vcl.opengl", "using VisualID " << vi->visualid);
867 0 : aWinData.pVisual = (void*)(vi->visual);
868 : }
869 :
870 0 : XFree(pFBC);
871 :
872 0 : return aWinData;
873 : }
874 :
875 : #endif
876 :
877 0 : void OpenGLContext::makeCurrent()
878 : {
879 : #if defined( WNT )
880 : if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
881 : {
882 : SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent(): wglMakeCurrent failed: " << GetLastError());
883 : }
884 : #elif defined( MACOSX )
885 : NSOpenGLView* pView = getOpenGLView();
886 : OpenGLWrapper::makeCurrent(pView);
887 : #elif defined( IOS ) || defined( ANDROID )
888 : // nothing
889 : #elif defined( UNX )
890 0 : glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx );
891 : #endif
892 0 : }
893 :
894 0 : void OpenGLContext::resetCurrent()
895 : {
896 : #if defined( WNT )
897 : wglMakeCurrent( m_aGLWin.hDC, 0 );
898 : #elif defined( MACOSX )
899 : OpenGLWrapper::resetCurrent();
900 : #elif defined( IOS ) || defined( ANDROID )
901 : // nothing
902 : #elif defined( UNX )
903 0 : glXMakeCurrent(m_aGLWin.dpy, None, NULL);
904 : #endif
905 0 : }
906 :
907 0 : void OpenGLContext::swapBuffers()
908 : {
909 : #if defined( WNT )
910 : SwapBuffers(m_aGLWin.hDC);
911 : #elif defined( MACOSX )
912 : NSOpenGLView* pView = getOpenGLView();
913 : OpenGLWrapper::swapBuffers(pView);
914 : #elif defined( IOS ) || defined( ANDROID )
915 : // nothing
916 : #elif defined( UNX )
917 0 : glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win);
918 : #endif
919 0 : }
920 :
921 0 : void OpenGLContext::sync()
922 : {
923 : #if defined( WNT )
924 : // nothing
925 : #elif defined( MACOSX ) || defined( IOS ) || defined( ANDROID )
926 : // nothing
927 : #elif defined( UNX )
928 0 : glXWaitGL();
929 0 : XSync(m_aGLWin.dpy, false);
930 : #endif
931 0 : }
932 :
933 0 : void OpenGLContext::show()
934 : {
935 0 : if (m_pChildWindow)
936 0 : m_pChildWindow->Show();
937 0 : else if (m_pWindow)
938 0 : m_pWindow->Show();
939 0 : }
940 :
941 0 : SystemChildWindow* OpenGLContext::getChildWindow()
942 : {
943 0 : return m_pChildWindow;
944 : }
945 :
946 0 : const SystemChildWindow* OpenGLContext::getChildWindow() const
947 : {
948 0 : return m_pChildWindow;
949 : }
950 :
951 0 : bool OpenGLContext::supportMultiSampling() const
952 : {
953 0 : return m_aGLWin.bMultiSampleSupported;
954 651 : }
955 :
956 : #if defined(MACOSX)
957 : NSOpenGLView* OpenGLContext::getOpenGLView()
958 : {
959 : return reinterpret_cast<NSOpenGLView*>(m_pChildWindow->GetSystemData()->mpNSView);
960 : }
961 : #endif
962 :
963 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|