LCOV - code coverage report
Current view: top level - eq/glx - pipe.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 103 157 65.6 %
Date: 2017-12-16 05:07:20 Functions: 15 16 93.8 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2017, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          Maxim Makhinya
       4             :  *                          Daniel Nachbaur <danielnachbaur@gmail.com>
       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 "pipe.h"
      21             : 
      22             : #include "../gl.h"
      23             : #include "../global.h"
      24             : #include "../log.h"
      25             : #include "../pipe.h"
      26             : 
      27             : #include <boost/lexical_cast.hpp>
      28             : #include <eq/fabric/gpuInfo.h>
      29             : #include <lunchbox/os.h>
      30             : 
      31             : using boost::lexical_cast;
      32             : 
      33             : namespace eq
      34             : {
      35             : namespace glx
      36             : {
      37             : #ifndef NDEBUG
      38             : static int XErrorHandler(Display* display, XErrorEvent* event);
      39             : #endif
      40             : 
      41             : namespace detail
      42             : {
      43             : class Pipe
      44             : {
      45             : public:
      46           2 :     Pipe()
      47           2 :         : xDisplay(0)
      48             :     {
      49           2 :         lunchbox::setZero(&glxewContext, sizeof(GLXEWContext));
      50           2 :     }
      51             : 
      52           2 :     ~Pipe()
      53           2 :     {
      54             : #ifndef NDEBUG
      55           2 :         lunchbox::setZero(&glxewContext, sizeof(GLXEWContext));
      56             : #endif
      57           2 :     }
      58             : 
      59             :     /** Window-system specific display information. */
      60             :     Display* xDisplay;
      61             : 
      62             :     /** Extended GLX function entries. */
      63             :     GLXEWContext glxewContext;
      64             : };
      65             : }
      66             : 
      67           2 : Pipe::Pipe(eq::Pipe* parent)
      68             :     : SystemPipe(parent)
      69           2 :     , _impl(new detail::Pipe)
      70             : {
      71           2 : }
      72             : 
      73           6 : Pipe::~Pipe()
      74             : {
      75           2 :     delete _impl;
      76           4 : }
      77             : 
      78           5 : Display* Pipe::getXDisplay() const
      79             : {
      80           5 :     return _impl->xDisplay;
      81             : }
      82             : 
      83           5 : GLXEWContext* Pipe::glxewGetContext()
      84             : {
      85           5 :     return &_impl->glxewContext;
      86             : }
      87             : 
      88             : //---------------------------------------------------------------------------
      89             : // GLX init
      90             : //---------------------------------------------------------------------------
      91           2 : bool Pipe::configInit()
      92             : {
      93           4 :     const std::string displayName = getXDisplayString();
      94           2 :     Display* xDisplay = XOpenDisplay(displayName.c_str());
      95             : 
      96           2 :     if (!xDisplay)
      97             :     {
      98           0 :         sendError(ERROR_GLXPIPE_DEVICE_NOTFOUND) << displayName
      99           0 :                                                  << lunchbox::sysError();
     100           0 :         return false;
     101             :     }
     102             : 
     103             :     int major, event, error;
     104           2 :     if (!XQueryExtension(xDisplay, "GLX", &major, &event, &error))
     105             :     {
     106           0 :         sendError(ERROR_GLXPIPE_GLX_NOTFOUND);
     107           0 :         XCloseDisplay(xDisplay);
     108           0 :         return false;
     109             :     }
     110             : 
     111           2 :     setXDisplay(xDisplay);
     112           2 :     LBVERB << "Opened X display " << displayName << " @" << xDisplay
     113           2 :            << ", device " << getPipe()->getDevice() << std::endl;
     114             : 
     115           2 :     return _configInitGLXEW();
     116             : }
     117             : 
     118           2 : void Pipe::configExit()
     119             : {
     120           2 :     Display* xDisplay = getXDisplay();
     121           2 :     if (!xDisplay)
     122           0 :         return;
     123             : 
     124           2 :     setXDisplay(0);
     125           2 :     XCloseDisplay(xDisplay);
     126           2 :     LBVERB << "Closed X display " << xDisplay << std::endl;
     127             : }
     128             : 
     129           2 : std::string Pipe::getXDisplayString()
     130             : {
     131           4 :     std::ostringstream stringStream;
     132             : 
     133           2 :     const uint32_t port = getPipe()->getPort();
     134           2 :     const uint32_t device = getPipe()->getDevice();
     135             : 
     136           2 :     if (port != LB_UNDEFINED_UINT32)
     137             :     {
     138           2 :         if (device == LB_UNDEFINED_UINT32)
     139           0 :             stringStream << ":" << port;
     140             :         else
     141           2 :             stringStream << ":" << port << "." << device;
     142             :     }
     143           0 :     else if (device != LB_UNDEFINED_UINT32)
     144           0 :         stringStream << ":0." << device;
     145             : 
     146           4 :     const std::string name(XDisplayName(stringStream.str().c_str()));
     147           4 :     return name.empty() ? ":0" : name;
     148             : }
     149             : 
     150           4 : void Pipe::setXDisplay(Display* display)
     151             : {
     152           4 :     if (_impl->xDisplay == display)
     153           0 :         return;
     154             : 
     155           4 :     _impl->xDisplay = display;
     156           4 :     XSetCurrentDisplay(display);
     157             : 
     158           8 :     GPUInfo info;
     159           4 :     if (getGPUInfo(display, info))
     160             :     {
     161             : #ifndef NDEBUG
     162             :         // somewhat reduntant since it is a global handler
     163           2 :         XSetErrorHandler(XErrorHandler);
     164             : #endif
     165           2 :         const uint32_t port = getPipe()->getPort();
     166           2 :         const uint32_t device = getPipe()->getDevice();
     167             : 
     168           2 :         if (port != LB_UNDEFINED_UINT32 && info.port != port)
     169           0 :             LBWARN << "Display mismatch: provided display connection uses"
     170           0 :                    << " display " << info.port << ", but pipe has port " << port
     171           0 :                    << std::endl;
     172             : 
     173           2 :         if (device != LB_UNDEFINED_UINT32 && info.device != device)
     174           0 :             LBWARN << "Screen mismatch: provided display connection uses "
     175           0 :                    << "default screen " << info.device
     176           0 :                    << ", but pipe has screen " << device << std::endl;
     177             :     }
     178             : 
     179           4 :     const PixelViewport& pvp = getPipe()->getPixelViewport();
     180           4 :     if (!pvp.isValid())
     181           0 :         getPipe()->setPixelViewport(info.pvp);
     182             : }
     183             : 
     184           4 : bool Pipe::getGPUInfo(Display* display, GPUInfo& info)
     185             : {
     186           4 :     if (!display)
     187           2 :         return false;
     188             : 
     189           4 :     std::string displayString = DisplayString(display);
     190           2 :     const size_t colonPos = displayString.find(':');
     191           2 :     if (colonPos != std::string::npos)
     192             :     {
     193           4 :         const std::string displayNumber = displayString.substr(colonPos + 1);
     194           2 :         info.port = atoi(displayNumber.c_str());
     195           2 :         info.device = DefaultScreen(display);
     196             :     }
     197             : 
     198           2 :     info.pvp.x = 0;
     199           2 :     info.pvp.y = 0;
     200           2 :     info.pvp.w = DisplayWidth(display, DefaultScreen(display));
     201           2 :     info.pvp.h = DisplayHeight(display, DefaultScreen(display));
     202             : 
     203           2 :     return true;
     204             : }
     205             : 
     206           2 : bool Pipe::_configInitGLXEW()
     207             : {
     208           2 :     LBASSERT(_impl->xDisplay);
     209             : 
     210             :     //----- Create and make current a temporary GL context to initialize GLXEW
     211             :     // visual
     212           4 :     std::vector<int> attributes;
     213           2 :     attributes.push_back(GLX_RGBA);
     214           2 :     attributes.push_back(None);
     215             : 
     216           1 :     const int screen = DefaultScreen(_impl->xDisplay);
     217             :     XVisualInfo* visualInfo =
     218           1 :         glXChooseVisual(_impl->xDisplay, screen, &attributes.front());
     219           2 :     if (!visualInfo)
     220             :     {
     221           0 :         sendError(ERROR_SYSTEMPIPE_PIXELFORMAT_NOTFOUND);
     222           0 :         return false;
     223             :     }
     224             : 
     225             :     // context
     226           2 :     GLXContext context = glXCreateContext(_impl->xDisplay, visualInfo, 0, True);
     227           2 :     if (!context)
     228             :     {
     229           0 :         sendError(ERROR_SYSTEMPIPE_CREATECONTEXT_FAILED);
     230           0 :         return false;
     231             :     }
     232             : 
     233             :     // window
     234           2 :     const XID parent = RootWindow(_impl->xDisplay, screen);
     235             :     XSetWindowAttributes wa;
     236           2 :     wa.colormap =
     237           2 :         XCreateColormap(_impl->xDisplay, parent, visualInfo->visual, AllocNone);
     238           2 :     wa.background_pixmap = None;
     239           2 :     wa.border_pixel = 0;
     240             :     XID drawable =
     241           2 :         XCreateWindow(_impl->xDisplay, parent, 0, 0, 16, 16, 0,
     242             :                       visualInfo->depth, InputOutput, visualInfo->visual,
     243           2 :                       CWBackPixmap | CWBorderPixel | CWColormap, &wa);
     244           2 :     if (!drawable)
     245             :     {
     246           0 :         sendError(ERROR_SYSTEMPIPE_CREATEWINDOW_FAILED);
     247           0 :         return false;
     248             :     }
     249             : 
     250           2 :     XFree(visualInfo);
     251           2 :     XSync(_impl->xDisplay, False);
     252             : 
     253           2 :     glXMakeCurrent(_impl->xDisplay, drawable, context);
     254             : 
     255           2 :     const GLenum result = glxewInit();
     256           2 :     bool success = result == GLEW_OK;
     257           2 :     if (success)
     258             :     {
     259           2 :         LBVERB << "Pipe GLXEW initialization successful" << std::endl;
     260           2 :         success = configInitGL();
     261             : 
     262           2 :         const char* glVersion = (const char*)glGetString(GL_VERSION);
     263           2 :         if (success && glVersion)
     264           2 :             _maxOpenGLVersion = static_cast<float>(atof(glVersion));
     265             :     }
     266             :     else
     267           0 :         sendError(ERROR_GLXPIPE_GLXEWINIT_FAILED)
     268           0 :             << lexical_cast<std::string>(result);
     269             : 
     270           2 :     XSync(_impl->xDisplay, False);
     271           2 :     glXDestroyContext(_impl->xDisplay, context);
     272           2 :     XDestroyWindow(_impl->xDisplay, drawable);
     273             : 
     274           2 :     return success;
     275             : }
     276             : 
     277             : #ifndef NDEBUG
     278           0 : int XErrorHandler(Display* display, XErrorEvent* event)
     279             : {
     280           0 :     LBWARN << lunchbox::disableFlush;
     281           0 :     LBWARN << "X Error occured: " << lunchbox::disableHeader
     282           0 :            << lunchbox::indent;
     283             : 
     284             :     char buffer[256];
     285           0 :     XGetErrorText(display, event->error_code, buffer, 256);
     286             : 
     287           0 :     LBWARN << buffer << std::endl;
     288           0 :     LBWARN << "Major opcode: " << (int)event->request_code << std::endl;
     289           0 :     LBWARN << "Minor opcode: " << (int)event->minor_code << std::endl;
     290           0 :     LBWARN << "Error code: " << (int)event->error_code << std::endl;
     291           0 :     LBWARN << "Request serial: " << event->serial << std::endl;
     292           0 :     LBWARN << "Current serial: " << NextRequest(display) - 1 << std::endl;
     293             : 
     294           0 :     switch (event->error_code)
     295             :     {
     296             :     case BadValue:
     297           0 :         LBWARN << "  Value: " << event->resourceid << std::endl;
     298           0 :         break;
     299             : 
     300             :     case BadAtom:
     301           0 :         LBWARN << "  AtomID: " << event->resourceid << std::endl;
     302           0 :         break;
     303             : 
     304             :     default:
     305           0 :         LBWARN << "  ResourceID: " << event->resourceid << std::endl;
     306           0 :         break;
     307             :     }
     308             : 
     309           0 :     if (event->request_code == 154 && event->minor_code == 3)
     310           0 :         LBWARN << "Likely glxCreateContext failed because it is run on a remote"
     311           0 :                << "X Server (which has indirect GLX disabled)" << std::endl;
     312             : 
     313           0 :     LBWARN << lunchbox::enableFlush << lunchbox::exdent
     314           0 :            << lunchbox::enableHeader;
     315             : 
     316             : #ifndef NDEBUG
     317           0 :     if (getenv("EQ_ABORT_WAIT"))
     318             :     {
     319           0 :         LBWARN << "Caught X Error, entering infinite loop for debugging"
     320           0 :                << std::endl;
     321           0 :         while (true)
     322             :             ;
     323             :     }
     324             : #endif
     325             : 
     326           0 :     return 0;
     327             : }
     328             : #endif // !NDEBUG
     329             : }
     330          30 : }

Generated by: LCOV version 1.11