Line data Source code
1 :
2 : /* Copyright (c) 2009-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Maxim Makhinya
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "window.h"
21 :
22 : #ifdef EQUALIZER_USE_QT5WIDGETS
23 : # include "../qt/window.h" // must be included before any header defining Bool
24 : #endif
25 :
26 : #include "eventHandler.h"
27 : #include "messagePump.h"
28 : #include "windowEvent.h"
29 :
30 : #include "../error.h"
31 : #include "../global.h"
32 :
33 : #include <co/objectOCommand.h>
34 :
35 : namespace eq
36 : {
37 : namespace glx
38 : {
39 : namespace detail
40 : {
41 : #define getIAttribute( attr ) getIAttribute( WindowSettings::attr )
42 :
43 : class Window
44 : {
45 : public:
46 0 : Window( Display* xDisplay_, const GLXEWContext* glxewContext_,
47 : MessagePump* messagePump_ )
48 : : xDisplay( xDisplay_ )
49 : , xDrawable ( 0 )
50 : , glXContext( 0 )
51 : , glXNVSwapGroup( 0 )
52 : , glXEventHandler( 0 )
53 : , glxewContext( glxewContext_ )
54 0 : , messagePump( messagePump_ )
55 0 : {}
56 :
57 : /** The display connection (maintained by GLXPipe) */
58 : Display* xDisplay;
59 : /** The X11 drawable ID of the window. */
60 : XID xDrawable;
61 : /** The glX rendering context. */
62 : GLXContext glXContext;
63 : /** The currently joined swap group. */
64 : uint32_t glXNVSwapGroup;
65 :
66 : /** The event handler. */
67 : EventHandler* glXEventHandler;
68 :
69 : /** The glX extension pointer table. */
70 : const GLXEWContext* glxewContext;
71 :
72 : MessagePump* const messagePump;
73 : };
74 : }
75 :
76 0 : Window::Window( NotifierInterface& parent, const WindowSettings& settings,
77 : Display* xDisplay, const GLXEWContext* glxewContext,
78 : MessagePump* messagePump )
79 : : WindowIF( parent, settings )
80 0 : , _impl( new detail::Window( xDisplay, glxewContext, messagePump ))
81 : {
82 0 : }
83 :
84 0 : Window::~Window()
85 : {
86 0 : delete _impl;
87 0 : }
88 :
89 : //---------------------------------------------------------------------------
90 : // GLX init
91 : //---------------------------------------------------------------------------
92 : namespace
93 : {
94 0 : static Bool WaitForNotify( Display*, XEvent *e, char *arg )
95 0 : { return (e->type == MapNotify) && (e->xmap.window == (::Window)arg); }
96 : }
97 :
98 0 : bool Window::configInit()
99 : {
100 0 : GLXFBConfig* fbConfig = chooseGLXFBConfig();
101 0 : if( !fbConfig )
102 : {
103 0 : sendError( ERROR_SYSTEMWINDOW_PIXELFORMAT_NOTFOUND );
104 0 : return false;
105 : }
106 :
107 0 : GLXContext context = createGLXContext( fbConfig );
108 0 : setGLXContext( context );
109 0 : if( !context )
110 : {
111 0 : XFree( fbConfig );
112 0 : return false;
113 : }
114 :
115 0 : bool success = configInitGLXDrawable( fbConfig );
116 0 : XFree( fbConfig );
117 :
118 0 : if( !success || !_impl->xDrawable )
119 : {
120 0 : sendError( ERROR_GLXWINDOW_NO_DRAWABLE );
121 0 : return false;
122 : }
123 :
124 0 : makeCurrent();
125 0 : initGLEW();
126 0 : _initSwapSync();
127 0 : if( getIAttribute( IATTR_HINT_DRAWABLE ) == FBO )
128 0 : success = configInitFBO();
129 :
130 0 : return success;
131 : }
132 :
133 0 : GLXFBConfig* Window::chooseGLXFBConfig()
134 : {
135 0 : if( !_impl->xDisplay )
136 : {
137 0 : sendError( ERROR_GLXWINDOW_NO_DISPLAY );
138 0 : return 0;
139 : }
140 0 : if( !GLXEW_VERSION_1_3 && !GLXEW_SGIX_fbconfig )
141 : {
142 0 : sendError( ERROR_GLXWINDOW_FBCONFIG_REQUIRED );
143 0 : return 0;
144 : }
145 :
146 : // build attribute list
147 0 : std::vector< int > attributes;
148 0 : const int32_t drawableHint = getIAttribute( IATTR_HINT_DRAWABLE );
149 0 : switch( drawableHint )
150 : {
151 : case PBUFFER:
152 0 : attributes.push_back ( GLX_DRAWABLE_TYPE );
153 0 : attributes.push_back ( GLX_PBUFFER_BIT );
154 0 : break;
155 :
156 : default:
157 0 : LBWARN << "Unknown drawable type " << drawableHint << ", using window"
158 0 : << std::endl;
159 : // no break;
160 : case UNDEFINED:
161 : case OFF: // needs fbConfig with visual for dummy window
162 : case FBO: // No typo - FBO needs fbConfig with visual for dummy window
163 : case WINDOW:
164 0 : attributes.push_back( GLX_X_RENDERABLE );
165 0 : attributes.push_back( True );
166 : }
167 :
168 0 : int colorSize = getIAttribute( IATTR_PLANES_COLOR );
169 0 : if( colorSize != OFF )
170 : {
171 0 : if( drawableHint == FBO || drawableHint == OFF )
172 0 : colorSize = 8; // Create FBO dummy window with 8bpp
173 0 : else switch( colorSize )
174 : {
175 : case RGBA16F:
176 : case RGBA32F:
177 0 : if( !GLXEW_ARB_fbconfig_float )
178 : {
179 0 : sendError( ERROR_SYSTEMWINDOW_ARB_FLOAT_FB_REQUIRED );
180 0 : return 0;
181 : }
182 0 : attributes.push_back( GLX_RENDER_TYPE );
183 0 : attributes.push_back( GLX_RGBA_FLOAT_BIT );
184 0 : colorSize = colorSize == RGBA16F ? 16 : 32;
185 0 : break;
186 :
187 : case AUTO:
188 : case ON:
189 0 : colorSize = 8;
190 0 : break;
191 : default:
192 0 : break;
193 : }
194 :
195 0 : LBASSERT( colorSize > 0 );
196 0 : attributes.push_back( GLX_RED_SIZE );
197 0 : attributes.push_back( colorSize );
198 0 : attributes.push_back( GLX_GREEN_SIZE );
199 0 : attributes.push_back( colorSize );
200 0 : attributes.push_back( GLX_BLUE_SIZE );
201 0 : attributes.push_back( colorSize );
202 :
203 0 : const int alphaSize = getIAttribute( IATTR_PLANES_ALPHA );
204 0 : switch( alphaSize )
205 : {
206 : case AUTO:
207 : case UNDEFINED:
208 : case ON:
209 0 : attributes.push_back( GLX_ALPHA_SIZE );
210 0 : attributes.push_back( colorSize );
211 0 : break;
212 :
213 : case OFF:
214 0 : break;
215 :
216 : default:
217 0 : LBASSERT( alphaSize > 0 );
218 0 : attributes.push_back( GLX_ALPHA_SIZE );
219 0 : attributes.push_back( alphaSize > 0 ? alphaSize : colorSize );
220 : }
221 : }
222 0 : const int depthSize = getIAttribute( IATTR_PLANES_DEPTH );
223 0 : if( depthSize > 0 || depthSize == AUTO )
224 : {
225 0 : attributes.push_back( GLX_DEPTH_SIZE );
226 0 : attributes.push_back( depthSize > 0 ? depthSize : 1 );
227 : }
228 0 : const int stencilSize = getIAttribute( IATTR_PLANES_STENCIL );
229 0 : if( stencilSize > 0 || stencilSize == AUTO )
230 : {
231 0 : attributes.push_back( GLX_STENCIL_SIZE );
232 0 : attributes.push_back( stencilSize>0 ? stencilSize : 1 );
233 : }
234 0 : const int accumSize = getIAttribute( IATTR_PLANES_ACCUM );
235 0 : const int accumAlpha = getIAttribute( IATTR_PLANES_ACCUM_ALPHA );
236 0 : if( accumSize >= 0 )
237 : {
238 0 : attributes.push_back( GLX_ACCUM_RED_SIZE );
239 0 : attributes.push_back( accumSize );
240 0 : attributes.push_back( GLX_ACCUM_GREEN_SIZE );
241 0 : attributes.push_back( accumSize );
242 0 : attributes.push_back( GLX_ACCUM_BLUE_SIZE );
243 0 : attributes.push_back( accumSize );
244 0 : attributes.push_back( GLX_ACCUM_ALPHA_SIZE );
245 0 : attributes.push_back( accumAlpha >= 0 ? accumAlpha : accumSize );
246 : }
247 0 : else if( accumAlpha >= 0 )
248 : {
249 0 : attributes.push_back( GLX_ACCUM_ALPHA_SIZE );
250 0 : attributes.push_back( accumAlpha );
251 : }
252 :
253 0 : const int samplesSize = getIAttribute( IATTR_PLANES_SAMPLES );
254 0 : if( samplesSize >= 0 && drawableHint != FBO )
255 : {
256 0 : attributes.push_back( GLX_SAMPLE_BUFFERS );
257 0 : attributes.push_back( 1 );
258 0 : attributes.push_back( GLX_SAMPLES );
259 0 : attributes.push_back( samplesSize );
260 : }
261 :
262 : #ifdef Darwin
263 : // WAR: glDrawBuffer( GL_BACK ) renders only to the left back buffer on a
264 : // stereo visual on Darwin which creates ugly flickering on mono configs
265 : if( getIAttribute( IATTR_HINT_STEREO ) == ON )
266 : {
267 : attributes.push_back( GLX_STEREO );
268 : attributes.push_back( true );
269 : }
270 : #else
271 0 : if( getIAttribute( IATTR_HINT_STEREO ) == ON ||
272 0 : ( getIAttribute( IATTR_HINT_STEREO ) == AUTO &&
273 0 : getIAttribute( IATTR_HINT_DRAWABLE ) == WINDOW ))
274 : {
275 0 : attributes.push_back( GLX_STEREO );
276 0 : attributes.push_back( true );
277 : }
278 : #endif
279 0 : if( getIAttribute( IATTR_HINT_DOUBLEBUFFER ) == ON ||
280 0 : ( getIAttribute( IATTR_HINT_DOUBLEBUFFER ) == AUTO &&
281 0 : getIAttribute( IATTR_HINT_DRAWABLE ) == WINDOW ))
282 : {
283 0 : attributes.push_back( GLX_DOUBLEBUFFER );
284 0 : attributes.push_back( true );
285 : }
286 0 : attributes.push_back( None );
287 :
288 : // build backoff list, least important attribute last
289 0 : std::vector<int> backoffAttributes;
290 0 : if( getIAttribute( IATTR_HINT_DRAWABLE ) == WINDOW )
291 : {
292 0 : if( getIAttribute( IATTR_HINT_DOUBLEBUFFER ) == AUTO )
293 0 : backoffAttributes.push_back( GLX_DOUBLEBUFFER );
294 :
295 : #ifndef Darwin
296 0 : if( getIAttribute( IATTR_HINT_STEREO ) == AUTO )
297 0 : backoffAttributes.push_back( GLX_STEREO );
298 : #endif
299 : }
300 :
301 0 : if( stencilSize == AUTO )
302 0 : backoffAttributes.push_back( GLX_STENCIL_SIZE );
303 :
304 0 : PFNGLXCHOOSEFBCONFIGSGIXPROC chooseFBConfig = GLXEW_VERSION_1_3 ?
305 0 : glXChooseFBConfig : glXChooseFBConfigSGIX;
306 :
307 0 : const int screen = DefaultScreen( _impl->xDisplay );
308 0 : int nConfigs = 0;
309 : GLXFBConfig* configs = chooseFBConfig( _impl->xDisplay, screen,
310 0 : &attributes[0], &nConfigs );
311 :
312 0 : while(( nConfigs == 0 || !configs ) && !backoffAttributes.empty( ))
313 : {
314 : // Gradually remove backoff attributes
315 0 : const int attribute = backoffAttributes.back();
316 0 : backoffAttributes.pop_back();
317 :
318 : std::vector<int>::iterator iter = find( attributes.begin(),
319 0 : attributes.end(), attribute );
320 0 : LBASSERT( iter != attributes.end( ));
321 0 : attributes.erase( iter, iter+2 );
322 0 : configs = chooseFBConfig( _impl->xDisplay, screen, &attributes[0],
323 0 : &nConfigs );
324 : }
325 :
326 0 : return configs;
327 : }
328 :
329 0 : GLXContext Window::createGLXContext( GLXFBConfig* fbConfig )
330 : {
331 0 : if( !_impl->xDisplay )
332 : {
333 0 : sendError( ERROR_GLXWINDOW_NO_DISPLAY );
334 0 : return 0;
335 : }
336 0 : if( !fbConfig )
337 : {
338 0 : sendError( ERROR_SYSTEMWINDOW_NO_PIXELFORMAT );
339 0 : return 0;
340 : }
341 :
342 0 : GLXContext shCtx = 0;
343 0 : const SystemWindow* shareWindow = getSharedContextWindow();
344 0 : if( shareWindow )
345 : {
346 : const WindowIF* shareGLXWindow =
347 0 : dynamic_cast< const WindowIF* >( shareWindow );
348 0 : if( shareGLXWindow )
349 0 : shCtx = shareGLXWindow->getGLXContext();
350 : #ifdef EQUALIZER_USE_QT5WIDGETS
351 0 : else if( dynamic_cast< const qt::WindowIF* >( shareWindow ))
352 : {
353 : // allows sharing with Qt window
354 0 : shareWindow->makeCurrent();
355 0 : shCtx = glXGetCurrentContext();
356 : }
357 : #endif
358 : }
359 :
360 0 : int type = GLX_RGBA_TYPE;
361 0 : if( getIAttribute( IATTR_HINT_DRAWABLE ) == PBUFFER &&
362 0 : ( getIAttribute( IATTR_PLANES_COLOR ) == RGBA16F ||
363 0 : getIAttribute( IATTR_PLANES_COLOR ) == RGBA32F ))
364 : {
365 0 : type = GLX_RGBA_FLOAT_TYPE;
366 : }
367 :
368 0 : GLXContext context = 0;
369 0 : if( glXCreateContextAttribsARB &&
370 0 : getIAttribute( IATTR_HINT_CORE_PROFILE ) == ON )
371 : {
372 : int attribList[] = {
373 : GLX_CONTEXT_MAJOR_VERSION_ARB,
374 0 : getIAttribute( IATTR_HINT_OPENGL_MAJOR ),
375 : GLX_CONTEXT_MINOR_VERSION_ARB,
376 0 : getIAttribute( IATTR_HINT_OPENGL_MINOR ),
377 : GLX_RENDER_TYPE, type,
378 : GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
379 : None
380 0 : };
381 :
382 : context = glXCreateContextAttribsARB( _impl->xDisplay, fbConfig[0],
383 0 : shCtx, True, attribList );
384 : }
385 : else
386 : {
387 0 : if( GLXEW_VERSION_1_3 )
388 : context = glXCreateNewContext( _impl->xDisplay, fbConfig[0], type,
389 0 : shCtx, True );
390 : else
391 : context = glXCreateContextWithConfigSGIX( _impl->xDisplay,
392 0 : fbConfig[0], type, shCtx, True );
393 : }
394 :
395 : #ifdef Darwin
396 : // WAR http://xquartz.macosforge.org/trac/ticket/466
397 : if( !context )
398 : {
399 : XVisualInfo* visInfo = GLXEW_VERSION_1_3 ?
400 : glXGetVisualFromFBConfig( _impl->xDisplay, fbConfig[0] ) :
401 : glXGetVisualFromFBConfigSGIX( _impl->xDisplay, fbConfig[0] );
402 : if( !visInfo )
403 : {
404 : std::vector<int> attributes;
405 : attributes.push_back( GLX_RGBA );
406 : attributes.push_back( GLX_RED_SIZE );
407 : attributes.push_back( 1 );
408 : attributes.push_back( GLX_ALPHA_SIZE );
409 : attributes.push_back( 1 );
410 : attributes.push_back( GLX_DEPTH_SIZE );
411 : attributes.push_back( 1 );
412 : attributes.push_back( GLX_DOUBLEBUFFER );
413 : attributes.push_back( None );
414 :
415 : const int screen = DefaultScreen( _impl->xDisplay );
416 : visInfo = glXChooseVisual( _impl->xDisplay, screen,
417 : &attributes.front( ));
418 : if( !visInfo )
419 : {
420 : sendError( ERROR_GLXWINDOW_NO_VISUAL );
421 : return 0;
422 : }
423 : }
424 :
425 : context = glXCreateContext( _impl->xDisplay, visInfo, shCtx, True );
426 : XFree( visInfo );
427 : }
428 : #endif
429 :
430 0 : if( !context )
431 : {
432 0 : sendError( ERROR_GLXWINDOW_CREATECONTEXT_FAILED );
433 0 : return 0;
434 : }
435 0 : return context;
436 : }
437 :
438 0 : bool Window::configInitGLXDrawable( GLXFBConfig* fbConfig )
439 : {
440 0 : switch( getIAttribute( IATTR_HINT_DRAWABLE ))
441 : {
442 : case PBUFFER:
443 0 : return configInitGLXPBuffer( fbConfig );
444 :
445 : case FBO:
446 : case OFF:
447 : {
448 0 : const PixelViewport pvp( 0, 0, 1, 1 );
449 0 : setXDrawable( _createGLXWindow( fbConfig, pvp ));
450 0 : return _impl->xDrawable != 0;
451 : }
452 :
453 : default:
454 0 : LBWARN << "Unknown drawable type "
455 0 : << getIAttribute( IATTR_HINT_DRAWABLE ) << ", using window"
456 0 : << std::endl;
457 : // no break;
458 : case UNDEFINED:
459 : case WINDOW:
460 0 : return configInitGLXWindow( fbConfig );
461 : }
462 : }
463 :
464 0 : bool Window::configInitGLXWindow( GLXFBConfig* fbConfig )
465 : {
466 0 : if( !_impl->xDisplay )
467 : {
468 0 : sendError( ERROR_GLXWINDOW_NO_DISPLAY );
469 0 : return false;
470 : }
471 :
472 0 : PixelViewport pvp = getPixelViewport();
473 0 : if( getIAttribute( IATTR_HINT_FULLSCREEN ) == ON )
474 : {
475 0 : const int screen = DefaultScreen( _impl->xDisplay );
476 0 : pvp.h = DisplayHeight( _impl->xDisplay, screen );
477 0 : pvp.w = DisplayWidth( _impl->xDisplay, screen );
478 0 : pvp.x = 0;
479 0 : pvp.y = 0;
480 :
481 0 : setPixelViewport( pvp );
482 : }
483 :
484 0 : XID drawable = _createGLXWindow( fbConfig, pvp );
485 0 : if( !drawable )
486 0 : return false;
487 :
488 : // map and wait for MapNotify event
489 0 : XMapWindow( _impl->xDisplay, drawable );
490 :
491 : XEvent event;
492 0 : XIfEvent( _impl->xDisplay, &event, WaitForNotify, (XPointer)(drawable) );
493 :
494 0 : XMoveResizeWindow( _impl->xDisplay, drawable, pvp.x, pvp.y, pvp.w, pvp.h );
495 0 : XFlush( _impl->xDisplay );
496 :
497 : // Grab keyboard focus in fullscreen mode
498 0 : if( getIAttribute( IATTR_HINT_FULLSCREEN ) == ON ||
499 0 : getIAttribute( IATTR_HINT_DECORATION ) == OFF )
500 : {
501 : XGrabKeyboard( _impl->xDisplay, drawable, True, GrabModeAsync,
502 0 : GrabModeAsync, CurrentTime );
503 : }
504 0 : setXDrawable( drawable );
505 :
506 0 : LBVERB << "Created X11 drawable " << drawable << std::endl;
507 0 : return true;
508 : }
509 :
510 0 : XID Window::_createGLXWindow( GLXFBConfig* fbConfig, const PixelViewport& pvp )
511 : {
512 0 : LBASSERT( getIAttribute( IATTR_HINT_DRAWABLE ) != PBUFFER );
513 :
514 0 : if( !_impl->xDisplay )
515 : {
516 0 : sendError( ERROR_GLXWINDOW_NO_DISPLAY );
517 0 : return 0;
518 : }
519 0 : if( !fbConfig )
520 : {
521 0 : sendError( ERROR_SYSTEMWINDOW_NO_PIXELFORMAT );
522 0 : return 0;
523 : }
524 :
525 0 : XVisualInfo* visInfo = GLXEW_VERSION_1_3 ?
526 0 : glXGetVisualFromFBConfig( _impl->xDisplay, fbConfig[0] ) :
527 0 : glXGetVisualFromFBConfigSGIX( _impl->xDisplay, fbConfig[0]);
528 0 : if( !visInfo )
529 : {
530 0 : sendError( ERROR_GLXWINDOW_NO_VISUAL );
531 0 : return 0;
532 : }
533 :
534 0 : const int screen = DefaultScreen( _impl->xDisplay );
535 0 : XID parent = RootWindow( _impl->xDisplay, screen );
536 : XSetWindowAttributes wa;
537 : wa.colormap = XCreateColormap( _impl->xDisplay, parent, visInfo->visual,
538 0 : AllocNone );
539 0 : wa.background_pixmap = None;
540 0 : wa.border_pixel = 0;
541 : wa.event_mask = StructureNotifyMask | VisibilityChangeMask | ExposureMask |
542 : KeyPressMask | KeyReleaseMask | PointerMotionMask |
543 0 : ButtonPressMask | ButtonReleaseMask;
544 :
545 0 : switch( getIAttribute( IATTR_HINT_DECORATION ))
546 : {
547 : case ON:
548 0 : wa.override_redirect = False;
549 0 : break;
550 :
551 : case OFF:
552 0 : wa.override_redirect = True;
553 0 : break;
554 :
555 : case AUTO:
556 : default:
557 : wa.override_redirect =
558 0 : getIAttribute( IATTR_HINT_FULLSCREEN ) == ON ?
559 0 : True : False;
560 0 : break;
561 : }
562 :
563 : XID drawable = XCreateWindow( _impl->xDisplay, parent,
564 : pvp.x, pvp.y, pvp.w, pvp.h,
565 : 0, visInfo->depth, InputOutput,
566 : visInfo->visual,
567 : CWBackPixmap | CWBorderPixel | CWEventMask |
568 0 : CWColormap | CWOverrideRedirect, &wa );
569 0 : XFree( visInfo );
570 0 : if( !drawable )
571 : {
572 0 : sendError( ERROR_GLXWINDOW_CREATEWINDOW_FAILED );
573 0 : return 0;
574 : }
575 :
576 0 : std::stringstream windowTitle;
577 0 : const std::string& name = getName();
578 :
579 0 : if( name.empty( ))
580 : {
581 0 : windowTitle << "Equalizer";
582 : #ifndef NDEBUG
583 0 : windowTitle << " (" << getpid() << ")";
584 : #endif
585 : }
586 : else
587 0 : windowTitle << name;
588 :
589 0 : XStoreName( _impl->xDisplay, drawable, windowTitle.str().c_str( ));
590 :
591 : // Register for close window request from the window manager
592 0 : Atom deleteAtom = XInternAtom( _impl->xDisplay, "WM_DELETE_WINDOW", False );
593 0 : XSetWMProtocols( _impl->xDisplay, drawable, &deleteAtom, 1 );
594 :
595 0 : return drawable;
596 : }
597 :
598 0 : bool Window::configInitGLXPBuffer( GLXFBConfig* fbConfig )
599 : {
600 0 : if( !_impl->xDisplay )
601 : {
602 0 : sendError( ERROR_GLXWINDOW_NO_DISPLAY );
603 0 : return false;
604 : }
605 0 : if( !fbConfig )
606 : {
607 0 : sendError( ERROR_SYSTEMWINDOW_NO_PIXELFORMAT );
608 0 : return false;
609 : }
610 0 : if( !GLXEW_VERSION_1_3 )
611 : {
612 0 : sendError( ERROR_GLXWINDOW_GLX_1_3_REQUIRED );
613 0 : return false;
614 : }
615 :
616 : // Create PBuffer
617 0 : const PixelViewport& pvp = getPixelViewport();
618 : const int attributes[] = { GLX_PBUFFER_WIDTH, pvp.w,
619 : GLX_PBUFFER_HEIGHT, pvp.h,
620 : GLX_LARGEST_PBUFFER, True,
621 : GLX_PRESERVED_CONTENTS, True,
622 0 : 0 };
623 :
624 : // TODO: Could check for GLX_SGIX_pbuffer, but the only GLX 1.2 platform at
625 : // hand is OS X, which does not support this extension.
626 :
627 0 : XID pbuffer = glXCreatePbuffer( _impl->xDisplay, fbConfig[ 0 ], attributes );
628 0 : if ( !pbuffer )
629 : {
630 0 : sendError( ERROR_GLXWINDOW_CREATEPBUFFER_FAILED );
631 0 : return false;
632 : }
633 :
634 0 : XFlush( _impl->xDisplay );
635 0 : setXDrawable( pbuffer );
636 :
637 0 : LBVERB << "Created X11 PBuffer " << pbuffer << std::endl;
638 0 : return true;
639 : }
640 :
641 0 : void Window::setXDrawable( XID drawable )
642 : {
643 0 : LBASSERT( _impl->xDisplay );
644 :
645 0 : if( _impl->xDrawable == drawable )
646 0 : return;
647 :
648 0 : if( _impl->xDrawable )
649 0 : exitEventHandler();
650 :
651 0 : _impl->xDrawable = drawable;
652 :
653 0 : if( !drawable )
654 0 : return;
655 :
656 0 : const int32_t drawableType = getIAttribute( IATTR_HINT_DRAWABLE );
657 0 : if( drawableType != OFF )
658 0 : initEventHandler();
659 :
660 : // query pixel viewport of window
661 0 : switch( drawableType )
662 : {
663 : case PBUFFER:
664 : {
665 0 : unsigned width = 0;
666 0 : unsigned height = 0;
667 0 : glXQueryDrawable( _impl->xDisplay, drawable, GLX_WIDTH, &width );
668 0 : glXQueryDrawable( _impl->xDisplay, drawable, GLX_HEIGHT, &height );
669 :
670 : setPixelViewport(
671 0 : PixelViewport( 0, 0, int32_t( width ), int32_t( height )));
672 0 : break;
673 : }
674 : case WINDOW:
675 : case AUTO:
676 : case UNDEFINED:
677 : {
678 : XWindowAttributes wa;
679 0 : XGetWindowAttributes( _impl->xDisplay, drawable, &wa );
680 :
681 : // position is relative to parent: translate to absolute coords
682 : ::Window root, parent, *children;
683 : unsigned nChildren;
684 :
685 : XQueryTree( _impl->xDisplay, drawable, &root, &parent, &children,
686 0 : &nChildren );
687 0 : if( children != 0 )
688 0 : XFree( children );
689 :
690 : int x,y;
691 : ::Window childReturn;
692 : XTranslateCoordinates( _impl->xDisplay, parent, root, wa.x, wa.y,
693 0 : &x, &y, &childReturn );
694 :
695 0 : setPixelViewport( PixelViewport( x, y, wa.width, wa.height ));
696 0 : break;
697 : }
698 : default:
699 0 : LBERROR << "Unknown drawable type " << drawableType << std::endl;
700 0 : LBUNIMPLEMENTED;
701 : case OFF:
702 : case FBO:
703 0 : LBASSERT( getPixelViewport().hasArea( ));
704 : }
705 : }
706 :
707 0 : void Window::setGLXContext( GLXContext context )
708 : {
709 0 : _impl->glXContext = context;
710 0 : }
711 :
712 0 : GLXContext Window::getGLXContext() const
713 : {
714 0 : return _impl->glXContext;
715 : }
716 :
717 0 : XID Window::getXDrawable() const
718 : {
719 0 : return _impl->xDrawable;
720 : }
721 :
722 0 : Display* Window::getXDisplay()
723 : {
724 0 : return _impl->xDisplay;
725 : }
726 :
727 0 : const GLXEWContext* Window::glxewGetContext() const
728 : {
729 0 : return _impl->glxewContext;
730 : }
731 :
732 0 : void Window::_initSwapSync()
733 : {
734 0 : if( getIAttribute( IATTR_HINT_DRAWABLE ) != WINDOW )
735 0 : return;
736 :
737 0 : const int32_t swapSync = getIAttribute(WindowSettings::IATTR_HINT_SWAPSYNC);
738 0 : if( swapSync == AUTO || swapSync == UNDEFINED ) // leave it alone
739 0 : return;
740 :
741 0 : if( GLXEW_SGI_swap_control )
742 0 : glXSwapIntervalSGI( (swapSync < 0) ? 1 : swapSync );
743 : else
744 0 : LBWARN << "GLX_SGI_swap_control not supported, ignoring window "
745 0 : << "swapsync hint " << IAttribute( swapSync ) << std::endl;
746 : }
747 :
748 0 : void Window::configExit()
749 : {
750 0 : if( !_impl->xDisplay )
751 0 : return;
752 :
753 0 : leaveNVSwapBarrier();
754 0 : configExitFBO();
755 0 : exitGLEW();
756 :
757 0 : glXMakeCurrent( _impl->xDisplay, None, 0 );
758 :
759 0 : GLXContext context = getGLXContext();
760 0 : XID drawable = getXDrawable();
761 :
762 0 : setGLXContext( 0 );
763 0 : setXDrawable( 0 );
764 :
765 : // WAR assert in glXDestroyContext/xcb_io.c:183
766 0 : XSync( _impl->xDisplay, False );
767 :
768 0 : if( context )
769 0 : glXDestroyContext( _impl->xDisplay, context );
770 :
771 0 : if( drawable )
772 : {
773 0 : if( getIAttribute( IATTR_HINT_DRAWABLE ) == PBUFFER )
774 0 : glXDestroyPbuffer( _impl->xDisplay, drawable );
775 : else
776 0 : XDestroyWindow( _impl->xDisplay, drawable );
777 : }
778 :
779 0 : LBVERB << "Destroyed GLX context and X drawable " << std::endl;
780 : }
781 :
782 0 : void Window::makeCurrent( const bool cache ) const
783 : {
784 0 : LBASSERT( _impl->xDisplay );
785 0 : if( cache && isCurrent( ))
786 0 : return;
787 :
788 0 : glXMakeCurrent( _impl->xDisplay, _impl->xDrawable, _impl->glXContext );
789 0 : WindowIF::makeCurrent();
790 0 : if( _impl->glXContext )
791 : {
792 0 : EQ_GL_ERROR( "After glXMakeCurrent" );
793 : }
794 : }
795 :
796 0 : void Window::doneCurrent() const
797 : {
798 0 : LBASSERT( _impl->xDisplay );
799 0 : if( !isCurrent( ))
800 0 : return;
801 :
802 0 : glXMakeCurrent( _impl->xDisplay, 0, 0 );
803 0 : WindowIF::doneCurrent();
804 : }
805 :
806 0 : void Window::swapBuffers()
807 : {
808 0 : LBASSERT( _impl->xDisplay );
809 0 : glXSwapBuffers( _impl->xDisplay, _impl->xDrawable );
810 0 : }
811 :
812 0 : void Window::joinNVSwapBarrier( const uint32_t group, const uint32_t barrier)
813 : {
814 0 : if( group == 0 )
815 0 : return;
816 :
817 : #if 1
818 0 : LBWARN << "Entering untested function GLXWindow::joinNVSwapBarrier"
819 0 : << std::endl;
820 :
821 0 : if ( !GLXEW_NV_swap_group )
822 : {
823 0 : LBWARN << "NV Swap group extension not supported" << std::endl;
824 0 : return;
825 : }
826 :
827 0 : const int screen = DefaultScreen( _impl->xDisplay );
828 0 : uint32_t maxBarrier = 0;
829 0 : uint32_t maxGroup = 0;
830 :
831 0 : glXQueryMaxSwapGroupsNV( _impl->xDisplay, screen, &maxGroup, &maxBarrier );
832 :
833 0 : if( group > maxGroup )
834 : {
835 0 : LBWARN << "Failed to initialize GLX_NV_swap_group: requested group "
836 0 : << group << " greater than maxGroups (" << maxGroup << ")"
837 0 : << std::endl;
838 0 : return;
839 : }
840 :
841 0 : if( barrier > maxBarrier )
842 : {
843 0 : LBWARN << "Failed to initialize GLX_NV_swap_group: requested barrier "
844 0 : << barrier << "greater than maxBarriers (" << maxBarrier << ")"
845 0 : << std::endl;
846 0 : return;
847 : }
848 :
849 0 : if( !glXJoinSwapGroupNV( _impl->xDisplay, _impl->xDrawable, group ))
850 : {
851 0 : LBWARN << "Failed to join swap group " << group << std::endl;
852 0 : return;
853 : }
854 :
855 0 : _impl->glXNVSwapGroup = group;
856 :
857 0 : if( !glXBindSwapBarrierNV( _impl->xDisplay, group, barrier ))
858 : {
859 0 : LBWARN << "Failed to bind swap barrier " << barrier << std::endl;
860 0 : return;
861 : }
862 :
863 0 : LBVERB << "Joined swap group " << group << " and barrier " << barrier
864 0 : << std::endl;
865 : #else
866 : LBUNIMPLEMENTED;
867 : #endif
868 : }
869 :
870 0 : void Window::leaveNVSwapBarrier()
871 : {
872 0 : if( _impl->glXNVSwapGroup == 0 )
873 0 : return;
874 :
875 0 : glXBindSwapBarrierNV( _impl->xDisplay, _impl->glXNVSwapGroup, 0 );
876 0 : glXJoinSwapGroupNV( _impl->xDisplay, _impl->xDrawable, 0 );
877 :
878 0 : _impl->glXNVSwapGroup = 0;
879 : }
880 :
881 0 : bool Window::processEvent( const WindowEvent& event )
882 : {
883 0 : switch( event.type )
884 : {
885 : case Event::WINDOW_POINTER_BUTTON_PRESS:
886 0 : if( getIAttribute( IATTR_HINT_GRAB_POINTER ) == ON &&
887 0 : getIAttribute( IATTR_HINT_DRAWABLE ) == WINDOW &&
888 : // If no other button was pressed already, capture the mouse
889 0 : event.pointerButtonPress.buttons == event.pointerButtonPress.button)
890 : {
891 : const unsigned int eventMask = ButtonPressMask | ButtonReleaseMask |
892 0 : ButtonMotionMask;
893 0 : const int result = XGrabPointer( getXDisplay(), getXDrawable(),
894 : False, eventMask, GrabModeAsync,
895 : GrabModeAsync, None, None,
896 0 : CurrentTime );
897 0 : if( result == GrabSuccess )
898 : {
899 0 : WindowEvent grabEvent = event;
900 0 : grabEvent.type = Event::WINDOW_POINTER_GRAB;
901 0 : processEvent( grabEvent );
902 : }
903 : else
904 : {
905 0 : LBWARN << "Failed to grab mouse: XGrabPointer returned "
906 0 : << result << std::endl;
907 : }
908 : }
909 0 : break;
910 :
911 : case Event::WINDOW_POINTER_BUTTON_RELEASE:
912 0 : if( getIAttribute( IATTR_HINT_GRAB_POINTER ) == ON &&
913 0 : getIAttribute( IATTR_HINT_DRAWABLE ) == WINDOW &&
914 : // If no button is pressed anymore, release the mouse
915 0 : event.pointerButtonRelease.buttons == PTR_BUTTON_NONE )
916 : {
917 : // Call early for consistent ordering
918 0 : const bool result = SystemWindow::processEvent( event );
919 :
920 0 : WindowEvent ungrabEvent = event;
921 0 : ungrabEvent.type = Event::WINDOW_POINTER_UNGRAB;
922 0 : processEvent( ungrabEvent );
923 0 : XUngrabPointer( getXDisplay(), CurrentTime );
924 0 : return result;
925 : }
926 0 : break;
927 : }
928 0 : return SystemWindow::processEvent( event );
929 : }
930 :
931 0 : void Window::initEventHandler()
932 : {
933 0 : LBASSERT( !_impl->glXEventHandler );
934 0 : _impl->glXEventHandler = new EventHandler( this );
935 :
936 0 : Display* display = getXDisplay();
937 0 : LBASSERT( display );
938 0 : if( _impl->messagePump )
939 0 : _impl->messagePump->register_( display );
940 : else
941 0 : LBDEBUG << "Using glx::EventHandler without glx::MessagePump, external "
942 0 : << "event dispatch assumed" << std::endl;
943 0 : }
944 :
945 0 : void Window::exitEventHandler()
946 : {
947 0 : if( _impl->messagePump )
948 : {
949 0 : Display* display = getXDisplay();
950 0 : LBASSERT( display );
951 0 : _impl->messagePump->deregister( display );
952 : }
953 :
954 0 : delete _impl->glXEventHandler;
955 0 : _impl->glXEventHandler = 0;
956 0 : }
957 :
958 : }
959 42 : }
|