LCOV - code coverage report
Current view: top level - eq/util - texture.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 73 234 31.2 %
Date: 2017-12-16 05:07:20 Functions: 14 37 37.8 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2009-2017, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          Cedric Stalder <cedric.stalder@gmail.com>
       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 "texture.h"
      21             : 
      22             : #include <eq/fabric/pixelViewport.h>
      23             : 
      24             : #include <eq/gl.h>
      25             : #include <eq/image.h>
      26             : #include <pression/plugins/compressor.h>
      27             : 
      28             : namespace eq
      29             : {
      30             : namespace util
      31             : {
      32             : namespace detail
      33             : {
      34             : class Texture
      35             : {
      36             : public:
      37          22 :     Texture(const GLenum tgt, const GLEWContext* const gl)
      38          22 :         : name(0)
      39             :         , target(tgt)
      40             :         , internalFormat(0)
      41             :         , format(0)
      42             :         , type(0)
      43             :         , width(0)
      44             :         , height(0)
      45             :         , defined(false)
      46          22 :         , glewContext(gl)
      47             :     {
      48          22 :     }
      49             : 
      50          22 :     ~Texture()
      51          22 :     {
      52          22 :         if (name != 0)
      53           0 :             LBWARN << "OpenGL texture " << name << " not freed" << std::endl;
      54             : 
      55          22 :         name = 0;
      56          22 :         defined = false;
      57          22 :     }
      58             : 
      59             :     GLuint name;
      60             :     const GLenum target;
      61             :     GLuint internalFormat;
      62             :     GLuint format;
      63             :     GLuint type;
      64             :     int32_t width;
      65             :     int32_t height;
      66             :     bool defined;
      67             :     const GLEWContext* glewContext;
      68             : };
      69             : }
      70             : 
      71          22 : Texture::Texture(const unsigned target, const GLEWContext* const glewContext)
      72          22 :     : _impl(new detail::Texture(target, glewContext))
      73             : {
      74          22 : }
      75             : 
      76          45 : Texture::~Texture()
      77             : {
      78          22 :     delete _impl;
      79          23 : }
      80           0 : bool Texture::isValid() const
      81             : {
      82           0 :     return (_impl->name != 0 && _impl->defined);
      83             : }
      84             : 
      85           8 : void Texture::flush()
      86             : {
      87           8 :     if (_impl->name == 0)
      88           6 :         return;
      89             : 
      90           2 :     LB_TS_THREAD(_thread);
      91           2 :     EQ_GL_CALL(glDeleteTextures(1, &_impl->name));
      92           2 :     _impl->name = 0;
      93           2 :     _impl->defined = false;
      94             : }
      95             : 
      96           0 : void Texture::flushNoDelete()
      97             : {
      98           0 :     LB_TS_THREAD(_thread);
      99           0 :     _impl->name = 0;
     100           0 :     _impl->defined = false;
     101           0 : }
     102             : 
     103           0 : uint32_t Texture::getCompressorTarget() const
     104             : {
     105           0 :     switch (_impl->target)
     106             :     {
     107             :     case GL_TEXTURE_RECTANGLE_ARB:
     108           0 :         return EQ_COMPRESSOR_USE_TEXTURE_RECT;
     109             : 
     110             :     default:
     111           0 :         LBUNIMPLEMENTED;
     112             :     case GL_TEXTURE_2D:
     113           0 :         return EQ_COMPRESSOR_USE_TEXTURE_2D;
     114             :     }
     115             : }
     116             : 
     117           2 : void Texture::_setInternalFormat(const GLuint internalFormat)
     118             : {
     119           2 :     if (_impl->internalFormat == internalFormat)
     120           0 :         return;
     121             : 
     122           2 :     _impl->defined = false;
     123           2 :     _impl->internalFormat = internalFormat;
     124             : 
     125           2 :     switch (internalFormat)
     126             :     {
     127             :     // depth format
     128             :     case GL_DEPTH_COMPONENT:
     129           0 :         setExternalFormat(GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
     130           0 :         break;
     131             :     case GL_RGB10_A2:
     132           0 :         setExternalFormat(GL_RGBA, GL_UNSIGNED_INT_10_10_10_2);
     133           0 :         break;
     134             :     case GL_RGBA:
     135             :     case GL_RGBA8:
     136           1 :         setExternalFormat(GL_RGBA, GL_UNSIGNED_BYTE);
     137           1 :         break;
     138             :     case GL_RGBA16F:
     139           0 :         setExternalFormat(GL_RGBA, GL_HALF_FLOAT);
     140           0 :         break;
     141             :     case GL_RGBA32F:
     142           0 :         setExternalFormat(GL_RGBA, GL_FLOAT);
     143           0 :         break;
     144             :     case GL_RGB:
     145             :     case GL_RGB8:
     146           0 :         setExternalFormat(GL_RGB, GL_UNSIGNED_BYTE);
     147           0 :         break;
     148             :     case GL_RGB16F:
     149           0 :         setExternalFormat(GL_RGB, GL_HALF_FLOAT);
     150           0 :         break;
     151             :     case GL_RGB32F:
     152           0 :         setExternalFormat(GL_RGB, GL_FLOAT);
     153           0 :         break;
     154             :     case GL_ALPHA32F_ARB:
     155           0 :         setExternalFormat(GL_ALPHA, GL_FLOAT);
     156           0 :         break;
     157             :     case GL_DEPTH24_STENCIL8:
     158           1 :         setExternalFormat(GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
     159           1 :         break;
     160             :     case GL_RGBA32UI:
     161           0 :         LBASSERT(_impl->glewContext);
     162           0 :         if (GLEW_EXT_texture_integer)
     163           0 :             setExternalFormat(GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT);
     164             :         else
     165           0 :             LBUNIMPLEMENTED;
     166           0 :         break;
     167             : 
     168             :     default:
     169           0 :         LBUNIMPLEMENTED;
     170           0 :         setExternalFormat(internalFormat, GL_UNSIGNED_BYTE);
     171             :     }
     172             : }
     173             : 
     174           2 : void Texture::setExternalFormat(const uint32_t format, const uint32_t type)
     175             : {
     176           2 :     _impl->format = format;
     177           2 :     _impl->type = type;
     178           2 : }
     179             : 
     180           4 : void Texture::_generate()
     181             : {
     182           4 :     LB_TS_THREAD(_thread);
     183           4 :     if (_impl->name != 0)
     184           2 :         return;
     185             : 
     186           2 :     _impl->defined = false;
     187           2 :     EQ_GL_CALL(glGenTextures(1, &_impl->name));
     188             : }
     189             : 
     190           2 : void Texture::init(const GLuint format, const int32_t width,
     191             :                    const int32_t height)
     192             : {
     193           2 :     _generate();
     194           2 :     _setInternalFormat(format);
     195           2 :     resize(width, height);
     196           2 : }
     197             : 
     198           0 : void Texture::setGLData(const GLuint id, const GLuint internalFormat,
     199             :                         const int32_t width, const int32_t height)
     200             : {
     201           0 :     flush();
     202           0 :     _setInternalFormat(internalFormat);
     203           0 :     _impl->name = id;
     204           0 :     _impl->width = width;
     205           0 :     _impl->height = height;
     206           0 :     _impl->defined = true;
     207           0 : }
     208             : 
     209             : namespace
     210             : {
     211             : /* Check if the texture dimensions are power of two. */
     212           0 : static bool _isPOT(const uint32_t width, const uint32_t height)
     213             : {
     214           0 :     return (width > 0 && height > 0 && (width & (width - 1)) == 0 &&
     215           0 :             (height & (height - 1)) == 0);
     216             : }
     217             : }
     218             : 
     219           0 : void Texture::_grow(const int32_t width, const int32_t height)
     220             : {
     221           0 :     if (_impl->width < width)
     222             :     {
     223           0 :         _impl->width = width;
     224           0 :         _impl->defined = false;
     225             :     }
     226             : 
     227           0 :     if (_impl->height < height)
     228             :     {
     229           0 :         _impl->height = height;
     230           0 :         _impl->defined = false;
     231             :     }
     232           0 : }
     233             : 
     234           0 : void Texture::applyZoomFilter(const ZoomFilter zoomFilter) const
     235             : {
     236           0 :     EQ_GL_CALL(
     237             :         glTexParameteri(_impl->target, GL_TEXTURE_MAG_FILTER, zoomFilter));
     238           0 :     EQ_GL_CALL(
     239             :         glTexParameteri(_impl->target, GL_TEXTURE_MIN_FILTER, zoomFilter));
     240           0 : }
     241             : 
     242           0 : void Texture::applyWrap() const
     243             : {
     244           0 :     EQ_GL_CALL(
     245             :         glTexParameteri(_impl->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
     246           0 :     EQ_GL_CALL(
     247             :         glTexParameteri(_impl->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
     248           0 : }
     249             : 
     250           0 : void Texture::copyFromFrameBuffer(const GLuint internalFormat,
     251             :                                   const fabric::PixelViewport& pvp)
     252             : {
     253           0 :     EQ_GL_ERROR("before Texture::copyFromFrameBuffer");
     254           0 :     LB_TS_THREAD(_thread);
     255             : 
     256           0 :     _generate();
     257           0 :     _setInternalFormat(internalFormat);
     258           0 :     _grow(pvp.w, pvp.h);
     259             : 
     260           0 :     if (_impl->defined)
     261           0 :         glBindTexture(_impl->target, _impl->name);
     262             :     else
     263           0 :         resize(_impl->width, _impl->height);
     264             : 
     265           0 :     EQ_GL_CALL(glCopyTexSubImage2D(_impl->target, 0, 0, 0, pvp.x, pvp.y, pvp.w,
     266             :                                    pvp.h));
     267           0 :     EQ_GL_ERROR("after Texture::copyFromFrameBuffer");
     268           0 : }
     269             : 
     270           0 : void Texture::upload(const int32_t width, const int32_t height, const void* ptr)
     271             : {
     272           0 :     _generate();
     273           0 :     _grow(width, height);
     274             : 
     275           0 :     if (_impl->defined)
     276           0 :         glBindTexture(_impl->target, _impl->name);
     277             :     else
     278           0 :         resize(_impl->width, _impl->height);
     279             : 
     280           0 :     EQ_GL_CALL(glTexSubImage2D(_impl->target, 0, 0, 0, width, height,
     281             :                                _impl->format, _impl->type, ptr));
     282           0 : }
     283             : 
     284           0 : void Texture::download(void* buffer) const
     285             : {
     286           0 :     LBASSERT(isValid());
     287           0 :     EQ_GL_CALL(glBindTexture(_impl->target, _impl->name));
     288           0 :     EQ_GL_CALL(
     289             :         glGetTexImage(_impl->target, 0, _impl->format, _impl->type, buffer));
     290           0 : }
     291             : 
     292           0 : void Texture::bind() const
     293             : {
     294           0 :     LBASSERT(_impl->name);
     295           0 :     EQ_GL_CALL(glBindTexture(_impl->target, _impl->name));
     296           0 : }
     297             : 
     298           2 : void Texture::bindToFBO(const GLenum target, const int32_t width,
     299             :                         const int32_t height, const int32_t samples)
     300             : {
     301           2 :     LB_TS_THREAD(_thread);
     302           2 :     LBASSERT(_impl->internalFormat);
     303           2 :     LBASSERT(_impl->glewContext);
     304             : 
     305           2 :     _generate();
     306             : 
     307           2 :     EQ_GL_CALL(glBindTexture(_impl->target, _impl->name));
     308           2 :     EQ_GL_CALL(glTexImage2D(_impl->target, 0, _impl->internalFormat, width,
     309             :                             height, 0, _impl->format, _impl->type, 0));
     310           2 :     EQ_GL_CALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER, target, _impl->target,
     311             :                                          _impl->name, 0));
     312             : 
     313           2 :     if (samples > 1)
     314             :     {
     315           0 :         EQ_GL_CALL(glTexImage2DMultisample(_impl->target, samples,
     316             :                                            _impl->internalFormat, width, height,
     317             :                                            false));
     318             :     }
     319             : 
     320           2 :     _impl->width = width;
     321           2 :     _impl->height = height;
     322           2 :     _impl->defined = true;
     323           2 : }
     324             : 
     325           2 : void Texture::resize(const int32_t width, const int32_t height)
     326             : {
     327           2 :     LB_TS_THREAD(_thread);
     328           2 :     LBASSERT(_impl->name);
     329           2 :     LBASSERT(_impl->internalFormat);
     330           2 :     LBASSERT(width > 0 && height > 0);
     331             : 
     332           2 :     if (_impl->width == width && _impl->height == height && _impl->defined)
     333           0 :         return;
     334             : 
     335           2 :     if (_impl->target == GL_TEXTURE_2D && !_isPOT(width, height))
     336             :     {
     337           0 :         LBASSERT(_impl->glewContext);
     338           0 :         LBASSERT(GLEW_ARB_texture_non_power_of_two);
     339             :     }
     340             : 
     341           2 :     EQ_GL_CALL(glBindTexture(_impl->target, _impl->name));
     342           2 :     EQ_GL_CALL(glTexImage2D(_impl->target, 0, _impl->internalFormat, width,
     343             :                             height, 0, _impl->format, _impl->type, 0));
     344           2 :     _impl->width = width;
     345           2 :     _impl->height = height;
     346           2 :     _impl->defined = true;
     347             : }
     348             : 
     349           0 : void Texture::writeRGB(const std::string& filename) const
     350             : {
     351           0 :     LBASSERT(_impl->defined);
     352           0 :     if (!_impl->defined)
     353           0 :         return;
     354             : 
     355           0 :     eq::Image image;
     356             : 
     357           0 :     switch (_impl->internalFormat)
     358             :     {
     359             :     case GL_DEPTH_COMPONENT:
     360           0 :         image.allocDownloader(
     361             :             Frame::Buffer::color,
     362             :             EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
     363           0 :             _impl->glewContext);
     364           0 :         break;
     365             :     case GL_RGB10_A2:
     366           0 :         image.allocDownloader(Frame::Buffer::color,
     367             :                               EQ_COMPRESSOR_TRANSFER_RGB10_A2_TO_BGR10_A2,
     368           0 :                               _impl->glewContext);
     369           0 :         break;
     370             :     case GL_RGBA:
     371             :     case GL_RGBA8:
     372           0 :         image.allocDownloader(Frame::Buffer::color,
     373             :                               EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA,
     374           0 :                               _impl->glewContext);
     375           0 :         break;
     376             :     case GL_RGBA16F:
     377           0 :         image.allocDownloader(Frame::Buffer::color,
     378             :                               EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGRA16F,
     379           0 :                               _impl->glewContext);
     380           0 :         break;
     381             :     case GL_RGBA32F:
     382           0 :         image.allocDownloader(Frame::Buffer::color,
     383             :                               EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGRA32F,
     384           0 :                               _impl->glewContext);
     385           0 :         break;
     386             :     case GL_RGB:
     387             :     case GL_RGB8:
     388           0 :         image.allocDownloader(Frame::Buffer::color,
     389             :                               EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGR,
     390           0 :                               _impl->glewContext);
     391           0 :         break;
     392             :     case GL_RGB16F:
     393           0 :         image.allocDownloader(Frame::Buffer::color,
     394             :                               EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGR16F,
     395           0 :                               _impl->glewContext);
     396           0 :         break;
     397             :     case GL_RGB32F:
     398           0 :         image.allocDownloader(Frame::Buffer::color,
     399             :                               EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGR32F,
     400           0 :                               _impl->glewContext);
     401           0 :         break;
     402             :     case GL_DEPTH24_STENCIL8:
     403           0 :         image.allocDownloader(
     404             :             Frame::Buffer::color,
     405             :             EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
     406           0 :             _impl->glewContext);
     407           0 :         break;
     408             : 
     409             :     default:
     410           0 :         LBUNIMPLEMENTED;
     411           0 :         return;
     412             :     }
     413             : 
     414             :     image.setPixelViewport(
     415           0 :         eq::PixelViewport(0, 0, _impl->width, _impl->height));
     416           0 :     if (image.startReadback(Frame::Buffer::color, this, _impl->glewContext))
     417           0 :         image.finishReadback(_impl->glewContext);
     418           0 :     image.writeImage(filename + ".rgb", Frame::Buffer::color);
     419           0 :     image.resetPlugins();
     420             : }
     421             : 
     422           0 : GLenum Texture::getTarget() const
     423             : {
     424           0 :     return _impl->target;
     425             : }
     426           0 : GLuint Texture::getInternalFormat() const
     427             : {
     428           0 :     return _impl->internalFormat;
     429             : }
     430           0 : GLuint Texture::getFormat() const
     431             : {
     432           0 :     return _impl->format;
     433             : }
     434           0 : GLuint Texture::getType() const
     435             : {
     436           0 :     return _impl->type;
     437             : }
     438           0 : GLuint Texture::getName() const
     439             : {
     440           0 :     return _impl->name;
     441             : }
     442           0 : int32_t Texture::getWidth() const
     443             : {
     444           0 :     return _impl->width;
     445             : }
     446           0 : int32_t Texture::getHeight() const
     447             : {
     448           0 :     return _impl->height;
     449             : }
     450           0 : const GLEWContext* Texture::glewGetContext() const
     451             : {
     452           0 :     return _impl->glewContext;
     453             : }
     454             : 
     455           0 : void Texture::setGLEWContext(const GLEWContext* context)
     456             : {
     457           0 :     _impl->glewContext = context;
     458           0 : }
     459             : 
     460           0 : std::ostream& operator<<(std::ostream& os, const Texture& texture)
     461             : {
     462           0 :     return os << "Texture " << texture.getWidth() << "x" << texture.getHeight()
     463           0 :               << " id " << texture.getName() << std::hex << " format "
     464           0 :               << texture.getFormat() << " type " << texture.getType()
     465           0 :               << std::dec << (texture.isValid() ? "" : " invalid");
     466             : }
     467             : }
     468          30 : }

Generated by: LCOV version 1.11