From ef33d297e28c51d4a3b8ff39b967a5d7b06b13ec Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 24 Feb 2016 19:49:31 -0800 Subject: [PATCH] Fix framebuffer behavior when changing attachments --- libraries/gpu/src/gpu/Framebuffer.cpp | 5 + libraries/gpu/src/gpu/Framebuffer.h | 7 +- libraries/gpu/src/gpu/GLBackend.h | 3 + libraries/gpu/src/gpu/GLBackendOutput.cpp | 177 ++++++++++++---------- 4 files changed, 110 insertions(+), 82 deletions(-) diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index 779d70cc88..abaa0f9ef1 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -21,6 +21,7 @@ Framebuffer::~Framebuffer() { Framebuffer* Framebuffer::create() { auto framebuffer = new Framebuffer(); framebuffer->_renderBuffers.resize(MAX_NUM_RENDER_BUFFERS); + framebuffer->_colorStamps.resize(MAX_NUM_RENDER_BUFFERS, 0); return framebuffer; } @@ -174,6 +175,8 @@ int Framebuffer::setRenderBuffer(uint32 slot, const TexturePointer& texture, uin } } + ++_colorStamps[slot]; + updateSize(texture); // assign the new one @@ -190,6 +193,7 @@ int Framebuffer::setRenderBuffer(uint32 slot, const TexturePointer& texture, uin } void Framebuffer::removeRenderBuffers() { + if (isSwapchain()) { return; } @@ -230,6 +234,7 @@ uint32 Framebuffer::getRenderBufferSubresource(uint32 slot) const { } bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) { + ++_depthStamp; if (isSwapchain()) { return false; } diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index e986e4a481..5d016645fe 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -135,10 +135,15 @@ public: static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } const GPUObjectPointer gpuObject {}; - + + Stamp getDepthStamp() const { return _depthStamp; } + const std::vector& getColorStamps() const { return _colorStamps; } + protected: SwapchainPointer _swapchain; + Stamp _depthStamp { 0 }; + std::vector _colorStamps; TextureViews _renderBuffers; TextureView _depthStencilBuffer; diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 7f37a73c57..15338d7587 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -173,6 +173,9 @@ public: public: GLuint _fbo = 0; std::vector _colorBuffers; + Stamp _depthStamp { 0 }; + std::vector _colorStamps; + GLFramebuffer(); ~GLFramebuffer(); diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 5f226141a8..37a10e670b 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -27,8 +27,15 @@ GLBackend::GLFramebuffer::~GLFramebuffer() { GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffer) { GLFramebuffer* object = Backend::getGPUObject(framebuffer); + bool needsUpate { false }; + if (!object || + framebuffer.getDepthStamp() != object->_depthStamp || + framebuffer.getColorStamps() != object->_colorStamps) { + needsUpate = true; + } + // If GPU object already created and in sync - if (object) { + if (!needsUpate) { return object; } else if (framebuffer.isEmpty()) { // NO framebuffer definition yet so let's avoid thinking @@ -37,94 +44,112 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe // need to have a gpu object? if (!object) { - GLint currentFBO; + // All is green, assign the gpuobject to the Framebuffer + object = new GLFramebuffer(); + Backend::setGPUObject(framebuffer, object); + glGenFramebuffers(1, &object->_fbo); + (void)CHECK_GL_ERROR(); + } + + if (needsUpate) { + GLint currentFBO = -1; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO); - - GLuint fbo; - glGenFramebuffers(1, &fbo); - (void) CHECK_GL_ERROR(); + glBindFramebuffer(GL_FRAMEBUFFER, object->_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); + GLTexture* gltexture = nullptr; + TexturePointer surface; + if (framebuffer.getColorStamps() != object->_colorStamps) { + if (framebuffer.hasColor()) { + object->_colorBuffers.clear(); + static const GLenum colorAttachments[] = { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, + GL_COLOR_ATTACHMENT8, + GL_COLOR_ATTACHMENT9, + GL_COLOR_ATTACHMENT10, + GL_COLOR_ATTACHMENT11, + GL_COLOR_ATTACHMENT12, + GL_COLOR_ATTACHMENT13, + GL_COLOR_ATTACHMENT14, + GL_COLOR_ATTACHMENT15 }; - std::vector colorBuffers; - if (framebuffer.hasColor()) { - static const GLenum colorAttachments[] = { - GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, - GL_COLOR_ATTACHMENT2, - GL_COLOR_ATTACHMENT3, - GL_COLOR_ATTACHMENT4, - GL_COLOR_ATTACHMENT5, - GL_COLOR_ATTACHMENT6, - GL_COLOR_ATTACHMENT7, - GL_COLOR_ATTACHMENT8, - GL_COLOR_ATTACHMENT9, - GL_COLOR_ATTACHMENT10, - GL_COLOR_ATTACHMENT11, - GL_COLOR_ATTACHMENT12, - GL_COLOR_ATTACHMENT13, - GL_COLOR_ATTACHMENT14, - GL_COLOR_ATTACHMENT15 }; + int unit = 0; + for (auto& b : framebuffer.getRenderBuffers()) { + surface = b._texture; + if (surface) { + gltexture = GLBackend::syncGPUObject(*surface); + } else { + gltexture = nullptr; + } - int unit = 0; - for (auto& b : framebuffer.getRenderBuffers()) { - auto surface = b._texture; - if (surface) { - auto gltexture = GLBackend::syncGPUObject(*surface); if (gltexture) { glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, gltexture->_texture, 0); + object->_colorBuffers.push_back(colorAttachments[unit]); + } else { + glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[unit], GL_TEXTURE_2D, 0, 0); } - colorBuffers.push_back(colorAttachments[unit]); unit++; } } - } -#if (GPU_FEATURE_PROFILE == GPU_LEGACY) - // for reasons that i don't understand yet, it seems that on mac gl, a fbo must have a color buffer... - else { - GLuint renderBuffer = 0; - glGenRenderbuffers(1, &renderBuffer); - glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, framebuffer.getWidth(), framebuffer.getHeight()); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer); - (void) CHECK_GL_ERROR(); - } - - // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); -#endif - - - if (framebuffer.hasDepthStencil()) { - auto surface = framebuffer.getDepthStencilBuffer(); - if (surface) { - auto gltexture = GLBackend::syncGPUObject(*surface); - if (gltexture) { - GLenum attachement = GL_DEPTH_STENCIL_ATTACHMENT; - if (!framebuffer.hasStencil()) { - attachement = GL_DEPTH_ATTACHMENT; - glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); - } else if (!framebuffer.hasDepth()) { - attachement = GL_STENCIL_ATTACHMENT; - glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); - } else { - attachement = GL_DEPTH_STENCIL_ATTACHMENT; - glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); - } - (void) CHECK_GL_ERROR(); - } + #if (GPU_FEATURE_PROFILE == GPU_LEGACY) + // for reasons that i don't understand yet, it seems that on mac gl, a fbo must have a color buffer... + else { + GLuint renderBuffer = 0; + glGenRenderbuffers(1, &renderBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, framebuffer.getWidth(), framebuffer.getHeight()); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer); + (void) CHECK_GL_ERROR(); } + // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + #endif + object->_colorStamps = framebuffer.getColorStamps(); } + GLenum attachement = GL_DEPTH_STENCIL_ATTACHMENT; + if (!framebuffer.hasStencil()) { + attachement = GL_DEPTH_ATTACHMENT; + } else if (!framebuffer.hasDepth()) { + attachement = GL_STENCIL_ATTACHMENT; + } + + if (framebuffer.getDepthStamp() != object->_depthStamp) { + auto surface = framebuffer.getDepthStencilBuffer(); + if (framebuffer.hasDepthStencil() && surface) { + gltexture = GLBackend::syncGPUObject(*surface); + } + + if (gltexture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0); + } else { + glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, 0, 0); + } + object->_depthStamp = framebuffer.getDepthStamp(); + } + + // Last but not least, define where we draw - if (!colorBuffers.empty()) { - glDrawBuffers((GLsizei)colorBuffers.size(), colorBuffers.data()); + if (!object->_colorBuffers.empty()) { + glDrawBuffers((GLsizei)object->_colorBuffers.size(), object->_colorBuffers.data()); } else { glDrawBuffer( GL_NONE ); } // Now check for completness GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + // restore the current framebuffer + if (currentFBO != -1) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO); + } + bool result = false; switch (status) { case GL_FRAMEBUFFER_COMPLETE : @@ -147,20 +172,10 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED."; break; } - if (!result && fbo) { - glDeleteFramebuffers( 1, &fbo ); + if (!result && object->_fbo) { + glDeleteFramebuffers(1, &object->_fbo); return nullptr; } - - - // All is green, assign the gpuobject to the Framebuffer - object = new GLFramebuffer(); - object->_fbo = fbo; - object->_colorBuffers = colorBuffers; - Backend::setGPUObject(framebuffer, object); - - // restore the current framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO); } return object;