LCOV - code coverage report
Current view: top level - ezlibs/ezGL - fbo.hpp (source / functions) Coverage Total Hit
Test: Coverage (llvm-cov → lcov → genhtml) Lines: 0.0 % 240 0
Test Date: 2025-09-16 22:55:37 Functions: 0.0 % 29 0
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : #pragma once
       2                 :             : 
       3                 :             : /*
       4                 :             : MIT License
       5                 :             : 
       6                 :             : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
       7                 :             : 
       8                 :             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9                 :             : of this software and associated documentation files (the "Software"), to deal
      10                 :             : in the Software without restriction, including without limitation the rights
      11                 :             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12                 :             : copies of the Software, and to permit persons to whom the Software is
      13                 :             : furnished to do so, subject to the following conditions:
      14                 :             : 
      15                 :             : The above copyright notice and this permission notice shall be included in all
      16                 :             : copies or substantial portions of the Software.
      17                 :             : 
      18                 :             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19                 :             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20                 :             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21                 :             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22                 :             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23                 :             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24                 :             : SOFTWARE.
      25                 :             : */
      26                 :             : 
      27                 :             : // ezGL is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
      28                 :             : 
      29                 :             : 
      30                 :             : #include "ezGL.hpp"
      31                 :             : #include <array>
      32                 :             : #include <vector>
      33                 :             : #include <memory>
      34                 :             : 
      35                 :             : namespace ez {
      36                 :             : namespace gl {
      37                 :             : 
      38                 :             : class FBO;
      39                 :             : typedef std::shared_ptr<FBO> FBOPtr;
      40                 :             : typedef std::weak_ptr<FBO> FBOWeak;
      41                 :             : 
      42                 :             : class FBO {
      43                 :             : private:
      44                 :             :     FBOWeak m_This;
      45                 :             :     GLuint m_FBOId = 0U;
      46                 :             :     GLsizei m_SizeX = 0;
      47                 :             :     GLsizei m_SizeY = 0;
      48                 :             :     GLuint m_CountBuffers = 0U;
      49                 :             :     bool m_UseMipMapping = false;
      50                 :             :     std::vector<TexturePtr> m_Textures;
      51                 :             :     GLenum* m_ColorDrawBuffers = nullptr;
      52                 :             : 
      53                 :             : public:
      54                 :           0 :     static FBOPtr create(const GLsizei& vSX, const GLsizei& vSY, const GLuint vCountBuffers, const bool vUseMipMapping) {
      55                 :           0 :         auto res = std::make_shared<FBO>();
      56                 :           0 :         res->m_This = res;
      57                 :           0 :         if (!res->init(vSX, vSY, vCountBuffers, vUseMipMapping)) {
      58                 :           0 :             res.reset();
      59                 :           0 :         }
      60                 :           0 :         return res;
      61                 :           0 :     }
      62                 :             : 
      63                 :             : public:
      64                 :             :     FBO() = default;
      65                 :           0 :     virtual ~FBO() { unit(); }
      66                 :             : 
      67                 :           0 :     bool init(const GLsizei& vSX, const GLsizei& vSY, const GLuint vCountBuffers, const bool vUseMipMapping) {
      68                 :           0 :         bool res = false;
      69                 :           0 :         m_SizeX = vSX;
      70                 :           0 :         m_SizeY = vSY;
      71                 :           0 :         m_CountBuffers = vCountBuffers;
      72                 :           0 :         m_UseMipMapping = vUseMipMapping;
      73                 :           0 :         if (m_CountBuffers > 0U) {
      74                 :           0 :             glGenFramebuffers(1, &m_FBOId);
      75                 :           0 :             CheckGLErrors;
      76                 :           0 :             glBindFramebuffer(GL_FRAMEBUFFER, m_FBOId);
      77                 :           0 :             CheckGLErrors;
      78                 :           0 :             m_Textures.resize(m_CountBuffers);
      79                 :           0 :             m_ColorDrawBuffers = new GLenum[m_CountBuffers];
      80                 :           0 :             for (GLuint idx = 0U; idx < vCountBuffers; ++idx) {
      81                 :           0 :                 m_Textures[idx] = Texture::createEmpty(vSX, vSY, "clamp", "nearest", vUseMipMapping);
      82                 :           0 :                 if (m_Textures[idx] != nullptr) {
      83                 :           0 :                     m_ColorDrawBuffers[idx] = GL_COLOR_ATTACHMENT0 + (GLenum)idx;
      84                 :           0 :                     glFramebufferTexture2D(GL_FRAMEBUFFER, m_ColorDrawBuffers[idx], GL_TEXTURE_2D, m_Textures[idx]->getTexId(), 0);
      85                 :           0 :                     CheckGLErrors;
      86                 :           0 :                 }
      87                 :           0 :             }
      88                 :           0 :             glFinish();
      89                 :           0 :             res = check();
      90                 :           0 :             glBindFramebuffer(GL_FRAMEBUFFER, 0);
      91                 :           0 :             CheckGLErrors;
      92                 :           0 :         }
      93                 :           0 :         return res;
      94                 :           0 :     }
      95                 :             : 
      96                 :           0 :     bool bind() {
      97                 :           0 : #ifdef PROFILER_SCOPED
      98                 :           0 :         PROFILER_SCOPED("FBO", "bind");
      99                 :           0 : #endif
     100                 :           0 :         if (m_FBOId > 0) {
     101                 :           0 :             glBindFramebuffer(GL_FRAMEBUFFER, m_FBOId);
     102                 :           0 :             CheckGLErrors;
     103                 :           0 :             return true;
     104                 :           0 :         }
     105                 :           0 :         return false;
     106                 :           0 :     }
     107                 :             : 
     108                 :           0 :     void clearBuffer(const std::array<float, 4U>& vColor) {
     109                 :           0 : #ifdef PROFILER_SCOPED
     110                 :           0 :         PROFILER_SCOPED("FBO", "clearBuffer");
     111                 :           0 : #endif
     112                 :           0 :         if (bind()) {
     113                 :           0 :             {
     114                 :           0 : #ifdef PROFILER_SCOPED
     115                 :           0 :                 PROFILER_SCOPED("FBO", "clearColor");
     116                 :           0 : #endif
     117                 :           0 :                 glClearColor(vColor[0], vColor[1], vColor[2], vColor[3]);
     118                 :           0 :                 glClear(GL_COLOR_BUFFER_BIT);
     119                 :           0 :             }
     120                 :           0 :             unbind();
     121                 :           0 :         }
     122                 :           0 :     }
     123                 :             : 
     124                 :           0 :     void updateMipMaping() {
     125                 :           0 :         if (m_UseMipMapping) {
     126                 :           0 : #ifdef PROFILER_SCOPED
     127                 :           0 :             PROFILER_SCOPED("FBO", "updateMipMaping %u", m_FBOId);
     128                 :           0 : #endif
     129                 :           0 :             for (auto& tex_ptr : m_Textures) {
     130                 :           0 :                 if (tex_ptr != nullptr) {
     131                 :           0 :                     tex_ptr->updateMipMaping();
     132                 :           0 :                 }
     133                 :           0 :             }
     134                 :           0 :         }
     135                 :           0 :     }
     136                 :             : 
     137                 :           0 :     void selectBuffers() {
     138                 :           0 : #ifdef PROFILER_SCOPED
     139                 :           0 :         PROFILER_SCOPED("FBO", "glDrawBuffers");
     140                 :           0 : #endif
     141                 :           0 :         glDrawBuffers(m_CountBuffers, m_ColorDrawBuffers);
     142                 :           0 :         CheckGLErrors;
     143                 :           0 :     }
     144                 :             : 
     145                 :           0 :     void unbind() {
     146                 :           0 : #ifdef PROFILER_SCOPED
     147                 :           0 :         PROFILER_SCOPED("FBO", "unbind");
     148                 :           0 : #endif
     149                 :           0 :         glBindFramebuffer(GL_FRAMEBUFFER, 0);
     150                 :           0 :         CheckGLErrors;
     151                 :           0 :         glBindTexture(GL_TEXTURE_2D, 0);
     152                 :           0 :         CheckGLErrors;
     153                 :           0 :     }
     154                 :             : 
     155                 :           0 :     GLuint getBuffersCount() const { return m_CountBuffers; }
     156                 :             : 
     157                 :           0 :     GLuint getTextureId(const size_t& vBufferIdx = 0U) const {
     158                 :           0 :         if (m_Textures.size() > vBufferIdx) {
     159                 :           0 :             return m_Textures[vBufferIdx]->getTexId();
     160                 :           0 :         }
     161                 :           0 :         return 0U;
     162                 :           0 :     }
     163                 :             : 
     164                 :           0 :     bool resize(const GLsizei& vNewSx, const GLsizei& vNewSy) {
     165                 :           0 :         bool res = false;
     166                 :           0 :         if (m_FBOId > 0) {
     167                 :           0 :             m_SizeX = vNewSx;
     168                 :           0 :             m_SizeY = vNewSy;
     169                 :           0 :             glBindFramebuffer(GL_FRAMEBUFFER, m_FBOId);
     170                 :           0 :             CheckGLErrors;
     171                 :           0 :             for (GLuint idx = 0U; idx < m_CountBuffers; ++idx) {
     172                 :           0 :                 if (m_Textures[idx] != nullptr) {
     173                 :           0 :                     // m_Textures[idx] = Texture::createEmpty(vNewSx, vNewSy, m_UseMipMapping);
     174                 :           0 :                     if (m_Textures[idx]->resize(vNewSx, vNewSy)) {
     175                 :           0 :                         if (m_Textures[idx] != nullptr) {
     176                 :           0 :                             m_ColorDrawBuffers[idx] = GL_COLOR_ATTACHMENT0 + (GLenum)idx;
     177                 :           0 :                             glFramebufferTexture2D(GL_FRAMEBUFFER, m_ColorDrawBuffers[idx], GL_TEXTURE_2D, m_Textures[idx]->getTexId(), 0);
     178                 :           0 :                             CheckGLErrors;
     179                 :           0 :                         }
     180                 :           0 :                     }
     181                 :           0 :                 }
     182                 :           0 :             }
     183                 :           0 :             glFinish();
     184                 :           0 :             res = check();
     185                 :           0 :             glBindFramebuffer(GL_FRAMEBUFFER, 0);
     186                 :           0 :             CheckGLErrors;
     187                 :           0 :         }
     188                 :           0 :         return res;
     189                 :           0 :     }
     190                 :             : 
     191                 :           0 :     bool check() {
     192                 :           0 :         if (GL_TRUE == glIsFramebuffer(m_FBOId)) {
     193                 :           0 :             CheckGLErrors;
     194                 :           0 :             if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
     195                 :           0 :                 CheckGLErrors;
     196                 :           0 :                 return true;
     197                 :           0 :             }
     198                 :           0 :         }
     199                 :           0 :         return false;
     200                 :           0 :     }
     201                 :             : 
     202                 :           0 :     void unit() {
     203                 :           0 :         glDeleteFramebuffers(1, &m_FBOId);
     204                 :           0 :         CheckGLErrors;
     205                 :           0 :     }
     206                 :             : 
     207                 :           0 :     void blitOnScreen(const GLint vX, const GLint vY, const GLint vW, const GLint vH, const GLint vAttachementID, GLbitfield vMask, GLenum vFilter) {
     208                 :           0 :         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
     209                 :           0 :         CheckGLErrors;
     210                 :           0 : 
     211                 :           0 :         glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBOId);
     212                 :           0 :         CheckGLErrors;
     213                 :           0 : 
     214                 :           0 :         glReadBuffer(GL_COLOR_ATTACHMENT0 + vAttachementID);
     215                 :           0 :         CheckGLErrors;
     216                 :           0 : 
     217                 :           0 :         glDrawBuffer(GL_BACK);
     218                 :           0 :         CheckGLErrors;
     219                 :           0 : 
     220                 :           0 :         glBlitFramebuffer(0, 0, m_SizeX, m_SizeY, vX, vY, vX + vW, vY + vH, vMask, vFilter);
     221                 :           0 :         CheckGLErrors;
     222                 :           0 :     }
     223                 :             : };
     224                 :             : 
     225                 :             : /*
     226                 :             :  * add front and back FBO
     227                 :             :  * and switch between front and back after rendering
     228                 :             :  */
     229                 :             : 
     230                 :             : class FBOPipeLine;
     231                 :             : typedef std::shared_ptr<FBOPipeLine> FBOPipeLinePtr;
     232                 :             : typedef std::weak_ptr<FBOPipeLine> FBOPipeLineWeak;
     233                 :             : class FBOPipeLine {
     234                 :             : private:
     235                 :             :     FBOPipeLineWeak m_This;
     236                 :             :     FBOPtr m_FrontFBOPtr = nullptr;
     237                 :             :     FBOPtr m_BackFBOPtr = nullptr;
     238                 :             :     bool m_MultiPass = false;
     239                 :             : 
     240                 :             : public:
     241                 :           0 :     static FBOPipeLinePtr create(const GLsizei& vSX, const GLsizei& vSY, const GLuint vCountBuffers, const bool vUseMipMapping, const bool vMultiPass) {
     242                 :           0 :         auto res = std::make_shared<FBOPipeLine>();
     243                 :           0 :         res->m_This = res;
     244                 :           0 :         if (!res->init(vSX, vSY, vCountBuffers, vUseMipMapping, vMultiPass)) {
     245                 :           0 :             res.reset();
     246                 :           0 :         }
     247                 :           0 :         return res;
     248                 :           0 :     }
     249                 :             : 
     250                 :             : public:
     251                 :             :     FBOPipeLine() = default;
     252                 :           0 :     virtual ~FBOPipeLine() { unit(); }
     253                 :           0 :     bool init(const GLsizei& vSX, const GLsizei& vSY, const GLuint vCountBuffers, const bool vUseMipMapping, const bool vMultiPass) {
     254                 :           0 :         bool res = true;
     255                 :           0 :         m_MultiPass = vMultiPass;
     256                 :           0 :         m_FrontFBOPtr = FBO::create(vSX, vSY, vCountBuffers, vUseMipMapping);
     257                 :           0 :         if (m_FrontFBOPtr != nullptr) {
     258                 :           0 :             if (m_MultiPass) {
     259                 :           0 :                 m_BackFBOPtr = FBO::create(vSX, vSY, vCountBuffers, vUseMipMapping);
     260                 :           0 :                 if (m_BackFBOPtr != nullptr) {
     261                 :           0 :                     res = true;
     262                 :           0 :                 }
     263                 :           0 :             } else {
     264                 :           0 :                 res = true;
     265                 :           0 :             }
     266                 :           0 :         }
     267                 :           0 :         return res;
     268                 :           0 :     }
     269                 :           0 :     bool resize(const GLsizei& vNewSx, const GLsizei& vNewSy) {
     270                 :           0 :         bool res = false;
     271                 :           0 :         assert(m_FrontFBOPtr != nullptr);
     272                 :           0 :         res = m_FrontFBOPtr->resize(vNewSx, vNewSy);
     273                 :           0 :         if (m_MultiPass) {
     274                 :           0 :             assert(m_BackFBOPtr != nullptr);
     275                 :           0 :             res &= m_BackFBOPtr->resize(vNewSx, vNewSy);
     276                 :           0 :         }
     277                 :           0 :         return res;
     278                 :           0 :     }
     279                 :           0 :     void unit() {
     280                 :           0 :         m_FrontFBOPtr.reset();
     281                 :           0 :         m_BackFBOPtr.reset();
     282                 :           0 :     }
     283                 :           0 :     bool bind() {
     284                 :           0 :         assert(m_FrontFBOPtr != nullptr);
     285                 :           0 :         return m_FrontFBOPtr->bind();
     286                 :           0 :     }
     287                 :           0 :     void clearBuffer(const std::array<float, 4U>& vColor) {
     288                 :           0 :         assert(m_FrontFBOPtr != nullptr);
     289                 :           0 :         m_FrontFBOPtr->clearBuffer(vColor);
     290                 :           0 :         if (m_MultiPass) {
     291                 :           0 :             assert(m_BackFBOPtr != nullptr);
     292                 :           0 :             m_BackFBOPtr->clearBuffer(vColor);
     293                 :           0 :         }
     294                 :           0 :     }
     295                 :           0 :     void updateMipMaping() {
     296                 :           0 :         assert(m_FrontFBOPtr != nullptr);
     297                 :           0 :         m_FrontFBOPtr->updateMipMaping();
     298                 :           0 :     }
     299                 :           0 :     void selectBuffers() {
     300                 :           0 :         assert(m_FrontFBOPtr != nullptr);
     301                 :           0 :         m_FrontFBOPtr->selectBuffers();
     302                 :           0 :     }
     303                 :           0 :     void unbind() {
     304                 :           0 :         assert(m_FrontFBOPtr != nullptr);
     305                 :           0 :         m_FrontFBOPtr->unbind();
     306                 :           0 :         if (m_MultiPass) {
     307                 :           0 :             swapFBOs();
     308                 :           0 :         }
     309                 :           0 :     }
     310                 :           0 :     GLuint getFrontTextureId(const size_t& vBufferIdx = 0U) const {
     311                 :           0 :         assert(m_FrontFBOPtr != nullptr);
     312                 :           0 :         return m_FrontFBOPtr->getTextureId(vBufferIdx);
     313                 :           0 :     }
     314                 :           0 :     GLuint getBackTextureId(const size_t& vBufferIdx = 0U) const {
     315                 :           0 :         assert(m_MultiPass);
     316                 :           0 :         assert(m_BackFBOPtr != nullptr);
     317                 :           0 :         return m_BackFBOPtr->getTextureId(vBufferIdx);
     318                 :           0 :     }
     319                 :           0 :     FBOWeak getFrontFBO() const { return m_FrontFBOPtr; }
     320                 :           0 :     FBOWeak getBackFBO() const {
     321                 :           0 :         assert(m_MultiPass);
     322                 :           0 :         return m_BackFBOPtr;
     323                 :           0 :     }
     324                 :           0 :     void swapFBOs() {
     325                 :           0 :         assert(m_MultiPass);
     326                 :           0 :         FBOPtr tmp = m_BackFBOPtr;
     327                 :           0 :         m_BackFBOPtr = m_FrontFBOPtr;
     328                 :           0 :         m_FrontFBOPtr = tmp;
     329                 :           0 :     }
     330                 :             : };
     331                 :             : 
     332                 :             : }  // namespace gl
     333                 :             : }  // namespace ez
        

Generated by: LCOV version 2.0-1