LCOV - code coverage report
Current view: top level - eq/glx - window.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 260 413 63.0 %
Date: 2017-12-16 05:07:20 Functions: 27 30 90.0 %

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

Generated by: LCOV version 1.11