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