LCOV - code coverage report
Current view: top level - eq - glWindow.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 132 182 72.5 %
Date: 2017-12-16 05:07:20 Functions: 24 27 88.9 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2016, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *                          Makhinya Maxim
       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 "glWindow.h"
      21             : 
      22             : #include "error.h"
      23             : #include "gl.h"
      24             : #include "global.h"
      25             : #include "pipe.h"
      26             : 
      27             : #include <eq/fabric/drawableConfig.h>
      28             : #include <eq/util/frameBufferObject.h>
      29             : #include <lunchbox/os.h>
      30             : #include <lunchbox/perThread.h>
      31             : 
      32             : template void lunchbox::perThreadNoDelete<const eq::GLWindow>(
      33             :     const eq::GLWindow*);
      34             : 
      35             : namespace eq
      36             : {
      37             : namespace
      38             : {
      39          10 : lunchbox::PerThread<const GLWindow, lunchbox::perThreadNoDelete> _current;
      40             : }
      41             : namespace detail
      42             : {
      43             : class GLWindow
      44             : {
      45             : public:
      46           3 :     GLWindow()
      47           3 :         : glewContext(nullptr)
      48             :         , fbo(nullptr)
      49           3 :         , fboMultiSample(nullptr)
      50             :     {
      51           3 :     }
      52             : 
      53           3 :     ~GLWindow() { delete glewContext; }
      54             :     /** Extended OpenGL function entries when window has a context. */
      55             :     GLEWContext* glewContext;
      56             : 
      57             :     /** Frame buffer object for FBO drawables. */
      58             :     util::FrameBufferObject* fbo;
      59             : 
      60             :     util::FrameBufferObject* fboMultiSample;
      61             : };
      62             : }
      63             : 
      64           3 : GLWindow::GLWindow(NotifierInterface& parent, const WindowSettings& settings)
      65             :     : SystemWindow(parent, settings)
      66           3 :     , _impl(new detail::GLWindow)
      67             : {
      68           3 : }
      69             : 
      70           6 : GLWindow::~GLWindow()
      71             : {
      72           3 :     if (_current == this)
      73           3 :         _current = 0;
      74           3 :     delete _impl;
      75           3 : }
      76             : 
      77           0 : void GLWindow::resize(const PixelViewport& pvp)
      78             : {
      79           0 :     if (_impl->fbo)
      80             :     {
      81           0 :         _impl->fbo->bind();
      82           0 :         _impl->fbo->resize(pvp.w, pvp.h);
      83           0 :         _impl->fbo->unbind();
      84           0 :         if (_impl->fboMultiSample)
      85             :         {
      86           0 :             _impl->fboMultiSample->bind(GL_DRAW_FRAMEBUFFER_EXT);
      87           0 :             _impl->fboMultiSample->resize(pvp.w, pvp.h);
      88           0 :             _impl->fboMultiSample->unbind(GL_DRAW_FRAMEBUFFER_EXT);
      89             :         }
      90             :     }
      91             :     else
      92           0 :         _resize(pvp);
      93           0 : }
      94             : 
      95           5 : void GLWindow::makeCurrent(const bool useCache) const
      96             : {
      97           5 :     if (useCache && _current == this)
      98           0 :         return;
      99             : 
     100           5 :     bindFrameBuffer();
     101           5 :     _current = this;
     102             : }
     103             : 
     104           1 : void GLWindow::doneCurrent() const
     105             : {
     106           1 :     if (!_current)
     107           0 :         return;
     108             : 
     109           1 :     if (_impl->fbo)
     110           0 :         _impl->fbo->unbind();
     111           1 :     _current = 0;
     112             : }
     113             : 
     114          16 : bool GLWindow::isCurrent() const
     115             : {
     116          16 :     return _current == this;
     117             : }
     118             : 
     119           3 : void GLWindow::initGLEW()
     120             : {
     121           3 :     if (_impl->glewContext)
     122           0 :         return;
     123             : 
     124           3 :     _impl->glewContext = new GLEWContext;
     125             : 
     126             : #ifdef __linux__
     127             :     // http://sourceforge.net/p/glew/patches/40/
     128           3 :     glewExperimental = true;
     129             : #endif
     130             : 
     131           3 :     const GLenum result = glewInit();
     132           3 :     glGetError(); // eat GL errors from buggy glew implementation
     133           3 :     if (result == GLEW_OK)
     134           3 :         return;
     135             : 
     136           0 :     LBWARN << "GLEW initialization failed: " << result << std::endl;
     137           0 :     delete _impl->glewContext;
     138           0 :     _impl->glewContext = nullptr;
     139             : }
     140             : 
     141           3 : void GLWindow::exitGLEW()
     142             : {
     143           3 :     delete _impl->glewContext;
     144           3 :     _impl->glewContext = nullptr;
     145           3 : }
     146             : 
     147           5 : const util::FrameBufferObject* GLWindow::getFrameBufferObject() const
     148             : {
     149           5 :     return _impl->fbo;
     150             : }
     151             : 
     152           0 : util::FrameBufferObject* GLWindow::getFrameBufferObject()
     153             : {
     154           0 :     return _impl->fbo;
     155             : }
     156             : 
     157          26 : const GLEWContext* GLWindow::glewGetContext() const
     158             : {
     159          26 :     return _impl->glewContext;
     160             : }
     161             : 
     162          34 : GLEWContext* GLWindow::glewGetContext()
     163             : {
     164          34 :     return _impl->glewContext;
     165             : }
     166             : 
     167           1 : bool GLWindow::configInitFBO()
     168             : {
     169           1 :     if (!_impl->glewContext || !GLEW_EXT_framebuffer_object)
     170             :     {
     171           0 :         sendError(ERROR_FBO_UNSUPPORTED);
     172           0 :         return false;
     173             :     }
     174             : 
     175           1 :     if (!_createFBO(_impl->fbo, 0))
     176           0 :         return false;
     177             : 
     178           1 :     const int samplesSize = getIAttribute(WindowSettings::IATTR_PLANES_SAMPLES);
     179           1 :     if (samplesSize <= 0)
     180           1 :         return true;
     181             : 
     182           0 :     return _createFBO(_impl->fboMultiSample, samplesSize);
     183             : }
     184             : 
     185           3 : void GLWindow::configExitFBO()
     186             : {
     187           3 :     _destroyFBO(_impl->fboMultiSample);
     188           3 :     _destroyFBO(_impl->fbo);
     189           3 : }
     190             : 
     191           1 : bool GLWindow::_createFBO(util::FrameBufferObject*& fbo, const int samplesSize)
     192             : {
     193           1 :     const PixelViewport& pvp = getPixelViewport();
     194           1 :     const GLuint colorFormat = getColorFormat();
     195             : 
     196           1 :     int depthSize = getIAttribute(WindowSettings::IATTR_PLANES_DEPTH);
     197           1 :     if (depthSize == AUTO)
     198           1 :         depthSize = 24;
     199             : 
     200           1 :     int stencilSize = getIAttribute(WindowSettings::IATTR_PLANES_STENCIL);
     201           1 :     if (stencilSize == AUTO)
     202           1 :         stencilSize = 1;
     203             : 
     204           2 :     fbo = new util::FrameBufferObject(_impl->glewContext,
     205             :                                       samplesSize ? GL_TEXTURE_2D_MULTISAMPLE
     206           2 :                                                   : GL_TEXTURE_RECTANGLE_ARB);
     207           1 :     Error error = fbo->init(pvp.w, pvp.h, colorFormat, depthSize, stencilSize,
     208           1 :                             samplesSize);
     209           1 :     if (!error)
     210           1 :         return true;
     211             : 
     212           0 :     if (getIAttribute(WindowSettings::IATTR_PLANES_STENCIL) == AUTO)
     213           0 :         error = fbo->init(pvp.w, pvp.h, colorFormat, depthSize, 0, samplesSize);
     214             : 
     215           0 :     if (!error)
     216           0 :         return true;
     217             : 
     218           0 :     sendError(error.getCode());
     219           0 :     delete fbo;
     220           0 :     fbo = 0;
     221           0 :     return false;
     222             : }
     223             : 
     224           6 : void GLWindow::_destroyFBO(util::FrameBufferObject*& fbo)
     225             : {
     226           6 :     if (!fbo)
     227           5 :         return;
     228             : 
     229           1 :     fbo->exit();
     230           1 :     delete fbo;
     231           1 :     fbo = 0;
     232             : }
     233             : 
     234          16 : void GLWindow::bindFrameBuffer() const
     235             : {
     236          16 :     if (!_impl->glewContext)
     237           3 :         return;
     238             : 
     239          13 :     if (_impl->fbo)
     240           6 :         _impl->fbo->bind();
     241           7 :     else if (GLEW_EXT_framebuffer_object)
     242           7 :         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
     243             : }
     244             : 
     245           5 : void GLWindow::bindDrawFrameBuffer() const
     246             : {
     247           5 :     if (!_impl->glewContext)
     248           0 :         return;
     249             : 
     250           5 :     if (_impl->fboMultiSample)
     251           0 :         _impl->fboMultiSample->bind(GL_DRAW_FRAMEBUFFER_EXT);
     252           5 :     else if (_impl->fbo)
     253           2 :         _impl->fbo->bind(GL_DRAW_FRAMEBUFFER_EXT);
     254           3 :     else if (GLEW_EXT_framebuffer_object)
     255           3 :         glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
     256             : }
     257             : 
     258           5 : void GLWindow::updateFrameBuffer() const
     259             : {
     260           5 :     if (!_impl->glewContext || !_impl->fboMultiSample)
     261           5 :         return;
     262             : 
     263           0 :     _impl->fboMultiSample->bind(GL_READ_FRAMEBUFFER_EXT);
     264           0 :     _impl->fbo->bind(GL_DRAW_FRAMEBUFFER_EXT);
     265           0 :     const PixelViewport& pvp = getPixelViewport();
     266           0 :     EQ_GL_CALL(glBlitFramebuffer(0, 0, pvp.w, pvp.h, 0, 0, pvp.w, pvp.h,
     267             :                                  GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
     268             :                                      GL_STENCIL_BUFFER_BIT,
     269             :                                  GL_NEAREST));
     270             : }
     271             : 
     272           2 : void GLWindow::flush()
     273             : {
     274           2 :     glFlush();
     275           2 : }
     276             : 
     277          25 : void GLWindow::finish()
     278             : {
     279          25 :     glFinish();
     280          25 : }
     281             : 
     282             : #define TEST_GLEW_VERSION(MAJOR, MINOR) \
     283             :     if (GLEW_VERSION_##MAJOR##_##MINOR) \
     284             :         dc.glewGLVersion = MAJOR##.##MINOR##f;
     285             : 
     286           2 : void GLWindow::queryDrawableConfig(DrawableConfig& dc)
     287             : {
     288           2 :     dc = DrawableConfig();
     289             : 
     290             :     // GL version
     291           2 :     const char* glVersion = (const char*)glGetString(GL_VERSION);
     292           2 :     if (!glVersion) // most likely no context
     293             :     {
     294           0 :         LBWARN << "glGetString(GL_VERSION) returned 0, assuming GL version 1.1"
     295           0 :                << std::endl;
     296           0 :         dc.glVersion = 1.1f;
     297             :     }
     298             :     else
     299           2 :         dc.glVersion = static_cast<float>(std::atof(glVersion));
     300             : 
     301           2 :     if (dc.glVersion >= 3.2f)
     302             :     {
     303             :         GLint mask;
     304           2 :         EQ_GL_CALL(glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask));
     305           2 :         dc.coreProfile = mask & GL_CONTEXT_CORE_PROFILE_BIT;
     306             :     }
     307             : 
     308           2 :     TEST_GLEW_VERSION(1, 1);
     309           2 :     TEST_GLEW_VERSION(1, 2);
     310           2 :     TEST_GLEW_VERSION(1, 3);
     311           2 :     TEST_GLEW_VERSION(1, 4);
     312           2 :     TEST_GLEW_VERSION(1, 5);
     313           2 :     TEST_GLEW_VERSION(2, 0);
     314           2 :     TEST_GLEW_VERSION(2, 1);
     315           2 :     TEST_GLEW_VERSION(3, 0);
     316           2 :     TEST_GLEW_VERSION(3, 1);
     317           2 :     TEST_GLEW_VERSION(3, 2);
     318           2 :     TEST_GLEW_VERSION(3, 3);
     319           2 :     TEST_GLEW_VERSION(4, 0);
     320           2 :     TEST_GLEW_VERSION(4, 1);
     321           2 :     TEST_GLEW_VERSION(4, 2);
     322           2 :     TEST_GLEW_VERSION(4, 3);
     323             : #ifdef GLEW_VERSION_4_5
     324             :     TEST_GLEW_VERSION(4, 4);
     325             :     TEST_GLEW_VERSION(4, 5);
     326             : #endif
     327             : 
     328             :     // Framebuffer capabilities
     329             :     GLboolean result;
     330           2 :     EQ_GL_CALL(glGetBooleanv(GL_STEREO, &result));
     331           2 :     dc.stereo = result;
     332             : 
     333           2 :     EQ_GL_CALL(glGetBooleanv(GL_DOUBLEBUFFER, &result));
     334           2 :     dc.doublebuffered = result;
     335             : 
     336           2 :     if (dc.coreProfile)
     337             :     {
     338           0 :         if (getFrameBufferObject())
     339             :         {
     340           0 :             glGetFramebufferAttachmentParameteriv(
     341             :                 GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
     342           0 :                 GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &dc.stencilBits);
     343             :             // eat GL error if no stencil attachment; should return '0' bits
     344             :             // according to spec, but gives GL_INVALID_OPERATION
     345           0 :             glGetError();
     346           0 :             EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
     347             :                 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
     348             :                 GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &dc.colorBits));
     349           0 :             EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
     350             :                 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
     351             :                 GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, &dc.alphaBits));
     352             :         }
     353             :         else
     354             :         {
     355           0 :             EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
     356             :                 GL_FRAMEBUFFER, GL_FRONT_LEFT,
     357             :                 GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &dc.stencilBits));
     358           0 :             EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
     359             :                 GL_FRAMEBUFFER, GL_FRONT_LEFT,
     360             :                 GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &dc.colorBits));
     361           0 :             EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
     362             :                 GL_FRAMEBUFFER, GL_FRONT_LEFT,
     363             :                 GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, &dc.alphaBits));
     364             :         }
     365             :     }
     366             :     else
     367             :     {
     368           2 :         EQ_GL_CALL(glGetIntegerv(GL_STENCIL_BITS, &dc.stencilBits));
     369           2 :         EQ_GL_CALL(glGetIntegerv(GL_RED_BITS, &dc.colorBits));
     370           2 :         EQ_GL_CALL(glGetIntegerv(GL_ALPHA_BITS, &dc.alphaBits));
     371           2 :         EQ_GL_CALL(glGetIntegerv(GL_ACCUM_RED_BITS, &dc.accumBits));
     372             :     }
     373             : 
     374           2 :     dc.accumBits *= 4;
     375           2 :     LBDEBUG << "Window drawable config: " << dc << std::endl;
     376           2 : }
     377          30 : }

Generated by: LCOV version 1.11