diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp index ee78c5395..9f2f1904b 100644 --- a/src/AbstractFramebuffer.cpp +++ b/src/AbstractFramebuffer.cpp @@ -20,6 +20,9 @@ #include "Extensions.h" #include "Image.h" +#include "Implementation/FramebufferState.h" +#include "Implementation/State.h" + namespace Magnum { #ifndef DOXYGEN_GENERATING_OUTPUT @@ -27,6 +30,24 @@ AbstractFramebuffer::Target AbstractFramebuffer::readTarget = AbstractFramebuffe AbstractFramebuffer::Target AbstractFramebuffer::drawTarget = AbstractFramebuffer::Target::ReadDraw; #endif +void AbstractFramebuffer::bind(Target target) { + Implementation::FramebufferState* state = Context::current()->state()->framebuffer; + + /* If already bound, done, otherwise update tracked state */ + if(target == Target::Read) { + if(state->readBinding == _id) return; + state->readBinding = _id; + } else if(target == Target::Draw) { + if(state->drawBinding == _id) return; + state->drawBinding = _id; + } else if(target == Target::ReadDraw) { + if(state->readBinding == _id && state->drawBinding == _id) return; + state->readBinding = state->drawBinding = _id; + } else CORRADE_INTERNAL_ASSERT(false); + + glBindFramebuffer(static_cast(target), _id); +} + void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image) { bind(readTarget); char* data = new char[AbstractImage::pixelSize(format, type)*size.product()]; diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h index e751c08e1..28a8d307c 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -31,6 +31,12 @@ namespace Magnum { @brief Base for default and named framebuffers See DefaultFramebuffer and Framebuffer for more information. + +@section AbstractFramebuffer-performance-optimization Performance optimizations + +The engine tracks currently bound framebuffer to avoid unnecessary calls to +@fn_gl{BindFramebuffer}. + @todo @extension{ARB,viewport_array} */ class MAGNUM_EXPORT AbstractFramebuffer { @@ -199,15 +205,13 @@ class MAGNUM_EXPORT AbstractFramebuffer { * DefaultFramebuffer::mapForDraw(), Framebuffer::mapForDraw(), * @fn_gl{BindFramebuffer} */ - inline void bind(Target target) { - glBindFramebuffer(static_cast(target), _id); - } + void bind(Target target); /** * @brief Set viewport size * * Call when window size changes. - * @see @fn_gl{Viewport} + * @see @fn_gl{BindFramebuffer}, @fn_gl{Viewport} */ inline void setViewport(const Vector2i& position, const Vector2i& size) { bind(drawTarget); @@ -219,7 +223,8 @@ class MAGNUM_EXPORT AbstractFramebuffer { * @param mask Which buffers to clear * * @see Renderer::setClearColor(), Renderer::setClearDepth(), - * Renderer::setClearStencil(), @fn_gl{Clear} + * Renderer::setClearStencil(), @fn_gl{BindFramebuffer}, + * @fn_gl{Clear} */ inline void clear(ClearMask mask) { bind(drawTarget); @@ -234,7 +239,7 @@ class MAGNUM_EXPORT AbstractFramebuffer { * @param type Data type of pixel data * @param image %Image where to put the data * - * @see @fn_gl{ReadPixels} + * @see @fn_gl{BindFramebuffer}, @fn_gl{ReadPixels} */ void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image); @@ -248,7 +253,7 @@ class MAGNUM_EXPORT AbstractFramebuffer { * @param image %Buffer image where to put the data * @param usage %Buffer usage * - * @see Buffer::bind(Target), @fn_gl{ReadPixels} + * @see @fn_gl{BindFramebuffer}, @fn_gl{ReadPixels} * @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. */ void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, BufferImage2D* image, Buffer::Usage usage); diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h index 6acebc3ae..6e5b478d4 100644 --- a/src/DefaultFramebuffer.h +++ b/src/DefaultFramebuffer.h @@ -171,7 +171,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @ref DrawAttachment "Attachment::None", given output is not * used. * - * @see mapForRead(), bind(), @fn_gl{DrawBuffers} + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} * @requires_gles30 Draw attachments for default framebuffer are * available only in OpenGL ES 3.0. */ @@ -182,7 +182,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @brief Map given attachment for reading * @param attachment Attachment * - * @see mapForDraw(), bind(), @fn_gl{ReadBuffer} + * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ inline void mapForRead(ReadAttachment attachment) { diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp index d37dbe064..2aff2474a 100644 --- a/src/Framebuffer.cpp +++ b/src/Framebuffer.cpp @@ -16,10 +16,23 @@ #include "Framebuffer.h" #include "BufferImage.h" +#include "Context.h" #include "Image.h" +#include "Implementation/State.h" +#include "Implementation/FramebufferState.h" + namespace Magnum { +Framebuffer::~Framebuffer() { + /* If bound, remove itself from state */ + Implementation::FramebufferState* state = Context::current()->state()->framebuffer; + if(state->readBinding == _id) state->readBinding = 0; + if(state->drawBinding == _id) state->drawBinding = 0; + + glDeleteFramebuffers(1, &_id); +} + void Framebuffer::mapForDraw(std::initializer_list colorAttachments) { GLenum* attachments = new GLenum[colorAttachments.size()]; for(auto it = colorAttachments.begin(); it != colorAttachments.end(); ++it) diff --git a/src/Framebuffer.h b/src/Framebuffer.h index 54167b9ee..781596363 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -48,14 +48,14 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * Deletes associated OpenGL framebuffer. * @see @fn_gl{DeleteFramebuffers} */ - inline ~Framebuffer() { glDeleteFramebuffers(1, &_id); } + ~Framebuffer(); /** * @brief Map given color attachments of current framebuffer for drawing * @param colorAttachments Color attachment IDs. If any value is -1, * given output is not used. * - * @see mapForRead(), bind(), @fn_gl{DrawBuffers} + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} */ void mapForDraw(std::initializer_list colorAttachments); @@ -64,7 +64,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @brief Map given color attachment of current framebuffer for reading * @param colorAttachment Color attachment ID * - * @see mapForDraw(), bind(), @fn_gl{ReadBuffer} + * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ inline void mapForRead(std::uint8_t colorAttachment) { @@ -105,7 +105,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param depthStencilAttachment Depth/stencil attachment * @param renderbuffer %Renderbuffer * - * @see bind(), @fn_gl{FramebufferRenderbuffer} + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} */ inline void attachRenderbuffer(Target target, DepthStencilAttachment depthStencilAttachment, Renderbuffer* renderbuffer) { bind(target); @@ -118,7 +118,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param colorAttachment Color attachment ID (number between 0 and 15) * @param renderbuffer %Renderbuffer * - * @see bind(), @fn_gl{FramebufferRenderbuffer} + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} */ inline void attachRenderbuffer(Target target, std::uint8_t colorAttachment, Renderbuffer* renderbuffer) { bind(target); @@ -133,7 +133,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param texture 1D texture * @param mipLevel Mip level * - * @see bind(), @fn_gl{FramebufferTexture} + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ inline void attachTexture1D(Target target, DepthStencilAttachment depthStencilAttachment, Texture1D* texture, GLint mipLevel) { @@ -149,7 +149,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param texture 1D texture * @param mipLevel Mip level * - * @see bind(), @fn_gl{FramebufferTexture} + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ inline void attachTexture1D(Target target, std::uint8_t colorAttachment, Texture1D* texture, GLint mipLevel) { @@ -167,7 +167,8 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param mipLevel Mip level. For rectangle textures it * should be always 0. * - * @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture} + * @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, + * @fn_gl{FramebufferTexture} */ inline void attachTexture2D(Target target, DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel) { /** @todo Check for texture target compatibility */ @@ -183,7 +184,8 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param mipLevel Mip level. For rectangle textures it * should be always 0. * - * @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture} + * @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, + * @fn_gl{FramebufferTexture} */ inline void attachTexture2D(Target target, std::uint8_t colorAttachment, Texture2D* texture, GLint mipLevel) { /** @todo Check for texture target compatibility */ @@ -199,7 +201,8 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param coordinate Cube map coordinate * @param mipLevel Mip level * - * @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture} + * @see attachTexture2D(), @fn_gl{BindFramebuffer}, + * @fn_gl{FramebufferTexture} */ inline void attachCubeMapTexture(Target target, DepthStencilAttachment depthStencilAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { /** @todo Check for internal format compatibility */ @@ -215,7 +218,8 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param coordinate Cube map coordinate * @param mipLevel Mip level * - * @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture} + * @see attachTexture2D(), @fn_gl{BindFramebuffer}, + * @fn_gl{FramebufferTexture} */ inline void attachCubeMapTexture(Target target, std::uint8_t colorAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { /** @todo Check for internal format compatibility */ @@ -231,7 +235,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param mipLevel Mip level * @param layer Layer of 2D image within a 3D texture * - * @see bind(), @fn_gl{FramebufferTexture} + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} * @requires_es_extension %Extension @es_extension{OES,texture_3D} */ inline void attachTexture3D(Target target, DepthStencilAttachment depthStencilAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { @@ -256,7 +260,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * @param mipLevel Mip level * @param layer Layer of 2D image within a 3D texture. * - * @see bind(), @fn_gl{FramebufferTexture} + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} * @requires_es_extension %Extension @es_extension{OES,texture_3D} */ inline void attachTexture3D(Target target, std::uint8_t colorAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { diff --git a/src/Implementation/FramebufferState.h b/src/Implementation/FramebufferState.h new file mode 100644 index 000000000..43e496040 --- /dev/null +++ b/src/Implementation/FramebufferState.h @@ -0,0 +1,30 @@ +#ifndef Magnum_Implementation_FramebufferState_h +#define Magnum_Implementation_FramebufferState_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "Magnum.h" + +namespace Magnum { namespace Implementation { + +struct FramebufferState { + inline FramebufferState(): readBinding(0), drawBinding(0) {} + + GLuint readBinding, drawBinding; +}; + +}} + +#endif diff --git a/src/Implementation/State.cpp b/src/Implementation/State.cpp index 062a98a8c..152e02450 100644 --- a/src/Implementation/State.cpp +++ b/src/Implementation/State.cpp @@ -16,18 +16,25 @@ #include "State.h" #include "BufferState.h" +#include "FramebufferState.h" #include "MeshState.h" #include "ShaderProgramState.h" #include "TextureState.h" namespace Magnum { namespace Implementation { -State::State(): buffer(new BufferState), mesh(new MeshState), shaderProgram(new ShaderProgramState), texture(new TextureState) {} +State::State(): + buffer(new BufferState), + framebuffer(new FramebufferState), + mesh(new MeshState), + shaderProgram(new ShaderProgramState), + texture(new TextureState) {} State::~State() { delete texture; delete shaderProgram; delete mesh; + delete framebuffer; delete buffer; } diff --git a/src/Implementation/State.h b/src/Implementation/State.h index a264247d7..dd02d6823 100644 --- a/src/Implementation/State.h +++ b/src/Implementation/State.h @@ -20,6 +20,7 @@ namespace Magnum { namespace Implementation { struct BufferState; +struct FramebufferState; struct MeshState; struct ShaderProgramState; struct TextureState; @@ -29,6 +30,7 @@ struct State { ~State(); BufferState* const buffer; + FramebufferState* const framebuffer; MeshState* const mesh; ShaderProgramState* const shaderProgram; TextureState* const texture;