diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp index 079d9321f..9e7147c8e 100644 --- a/src/AbstractFramebuffer.cpp +++ b/src/AbstractFramebuffer.cpp @@ -25,6 +25,10 @@ namespace Magnum { +AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault; +AbstractFramebuffer::DrawBufferImplementation AbstractFramebuffer::drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDefault; +AbstractFramebuffer::ReadBufferImplementation AbstractFramebuffer::readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault; + #ifndef DOXYGEN_GENERATING_OUTPUT AbstractFramebuffer::Target AbstractFramebuffer::readTarget = AbstractFramebuffer::Target::ReadDraw; AbstractFramebuffer::Target AbstractFramebuffer::drawTarget = AbstractFramebuffer::Target::ReadDraw; @@ -130,9 +134,66 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) readTarget = Target::Read; drawTarget = Target::Draw; } + + if(context->isExtensionSupported()) { + Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + + drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDSA; + drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA; + readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA; + } #else static_cast(context); #endif } +void AbstractFramebuffer::drawBuffersImplementationDefault(GLsizei count, const GLenum* buffers) { + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(drawTarget); + glDrawBuffers(count, buffers); + #else + static_cast(count); + static_cast(buffers); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::drawBuffersImplementationDSA(GLsizei count, const GLenum* buffers) { + glFramebufferDrawBuffersEXT(_id, count, buffers); +} +#endif + +void AbstractFramebuffer::drawBufferImplementationDefault(GLenum buffer) { + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(drawTarget); + glDrawBuffer(buffer); + #else + static_cast(buffer); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::drawBufferImplementationDSA(GLenum buffer) { + glFramebufferDrawBufferEXT(_id, buffer); +} +#endif + +void AbstractFramebuffer::readBufferImplementationDefault(GLenum buffer) { + /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(readTarget); + glReadBuffer(buffer); + #else + static_cast(buffer); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractFramebuffer::readBufferImplementationDSA(GLenum buffer) { + glFramebufferReadBufferEXT(_id, buffer); +} +#endif + } diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h index 542e00a12..777ed7dc6 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -255,7 +255,17 @@ class MAGNUM_EXPORT AbstractFramebuffer { void MAGNUM_LOCAL bindInternal(Target target); void MAGNUM_LOCAL setViewportInternal(); - static Target readTarget, drawTarget; + static MAGNUM_LOCAL Target readTarget; + static MAGNUM_LOCAL Target drawTarget; + + typedef void(AbstractFramebuffer::*DrawBuffersImplementation)(GLsizei, const GLenum*); + static MAGNUM_LOCAL DrawBuffersImplementation drawBuffersImplementation; + + typedef void(AbstractFramebuffer::*DrawBufferImplementation)(GLenum); + static DrawBufferImplementation drawBufferImplementation; + + typedef void(AbstractFramebuffer::*ReadBufferImplementation)(GLenum); + static ReadBufferImplementation readBufferImplementation; GLuint _id; Vector2i _viewportPosition, _viewportSize; @@ -263,6 +273,21 @@ class MAGNUM_EXPORT AbstractFramebuffer { private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + + void MAGNUM_LOCAL drawBuffersImplementationDefault(GLsizei count, const GLenum* buffers); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL drawBuffersImplementationDSA(GLsizei count, const GLenum* buffers); + #endif + + void MAGNUM_LOCAL drawBufferImplementationDefault(GLenum buffer); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL drawBufferImplementationDSA(GLenum buffer); + #endif + + void MAGNUM_LOCAL readBufferImplementationDefault(GLenum buffer); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL readBufferImplementationDSA(GLenum buffer); + #endif }; inline AbstractFramebuffer::~AbstractFramebuffer() {} diff --git a/src/Context.cpp b/src/Context.cpp index 8aaaf98ed..d1ac1e884 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -28,8 +28,10 @@ #include "DebugMarker.h" #include "DefaultFramebuffer.h" #include "Extensions.h" +#include "Framebuffer.h" #include "IndexedMesh.h" #include "Mesh.h" +#include "Renderbuffer.h" #include "Implementation/State.h" @@ -304,8 +306,10 @@ Context::Context() { #endif DebugMarker::initializeContextBasedFunctionality(this); DefaultFramebuffer::initializeContextBasedFunctionality(this); + Framebuffer::initializeContextBasedFunctionality(this); IndexedMesh::initializeContextBasedFunctionality(this); Mesh::initializeContextBasedFunctionality(this); + Renderbuffer::initializeContextBasedFunctionality(this); } Context::~Context() { diff --git a/src/DefaultFramebuffer.cpp b/src/DefaultFramebuffer.cpp index 64c71c118..38081e96b 100644 --- a/src/DefaultFramebuffer.cpp +++ b/src/DefaultFramebuffer.cpp @@ -39,27 +39,11 @@ void DefaultFramebuffer::mapForDraw(std::initializer_list(attachment.second); - bindInternal(drawTarget); - glDrawBuffers(max+1, _attachments); + (this->*drawBuffersImplementation)(max+1, _attachments); delete[] _attachments; } - -void DefaultFramebuffer::mapForDraw(DrawAttachment attachment) { - bindInternal(drawTarget); - glDrawBuffer(static_cast(attachment)); -} #endif -void DefaultFramebuffer::mapForRead(ReadAttachment attachment) { - bindInternal(readTarget); - /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glReadBuffer(static_cast(attachment)); - #else - static_cast(attachment); - #endif -} - void DefaultFramebuffer::initializeContextBasedFunctionality(Context* context) { Implementation::FramebufferState* state = context->state()->framebuffer; diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h index 92a6486c7..4262fe6a4 100644 --- a/src/DefaultFramebuffer.h +++ b/src/DefaultFramebuffer.h @@ -57,6 +57,15 @@ void drawEvent() { See Framebuffer documentation for more involved usage, usage of non-default or multiple framebuffers. + +@section DefaultFramebuffer-performance-optimization Performance optimizations + +See also @ref AbstractFramebuffer-performance-optimization "relevant section in AbstractFramebuffer". + +If extension @extension{EXT,direct_state_access} is available, functions +mapForDraw() and mapForRead() use DSA to avoid unnecessary calls to +@fn_gl{BindFramebuffer}. See their respective documentation for more +information. */ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { friend class Context; @@ -208,7 +217,12 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * framebuffer.mapForDraw({{MyShader::ColorOutput, DefaultFramebuffer::DrawAttachment::BackLeft}, * {MyShader::NormalOutput, DefaultFramebuffer::DrawAttachment::None}}); * @endcode - * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} + * + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} or + * @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} * @requires_gles30 Draw attachments for default framebuffer are * available only in OpenGL ES 3.0. */ @@ -220,21 +234,34 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * * Similar to above function, can be used in cases when shader has * only one (unnamed) output. - * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} + * + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} or + * @fn_gl_extension{FramebufferDrawBuffer,EXT,direct_state_access} * @requires_gles30 Draw attachments for default framebuffer are * available only in OpenGL ES 3.0. */ - void mapForDraw(DrawAttachment attachment); + inline void mapForDraw(DrawAttachment attachment) { + (this->*drawBufferImplementation)(static_cast(attachment)); + } #endif /** * @brief Map given attachment for reading * @param attachment Buffer attachment * - * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} or + * @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ - void mapForRead(ReadAttachment attachment); + inline void mapForRead(ReadAttachment attachment) { + (this->*readBufferImplementation)(static_cast(attachment)); + } private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp index 398bd34e8..def6ea157 100644 --- a/src/Framebuffer.cpp +++ b/src/Framebuffer.cpp @@ -17,6 +17,7 @@ #include "BufferImage.h" #include "Context.h" +#include "Extensions.h" #include "Image.h" #include "Renderbuffer.h" #include "Texture.h" @@ -26,6 +27,13 @@ namespace Magnum { +Framebuffer::RenderbufferImplementation Framebuffer::renderbufferImplementation = &Framebuffer::renderbufferImplementationDefault; +#ifndef MAGNUM_TARGET_GLES +Framebuffer::Texture1DImplementation Framebuffer::texture1DImplementation = &Framebuffer::texture1DImplementationDefault; +#endif +Framebuffer::Texture2DImplementation Framebuffer::texture2DImplementation = &Framebuffer::texture2DImplementationDefault; +Framebuffer::Texture3DImplementation Framebuffer::texture3DImplementation = &Framebuffer::texture3DImplementationDefault; + Framebuffer::Framebuffer(const Vector2i& viewportPosition, const Vector2i& viewportSize) { _viewportPosition = viewportPosition; _viewportSize = viewportSize; @@ -54,103 +62,84 @@ void Framebuffer::mapForDraw(std::initializer_list*drawBuffersImplementation)(max+1, _attachments); delete[] _attachments; } -void Framebuffer::mapForDraw(std::int8_t attachment) { - bindInternal(drawTarget); - glDrawBuffer(static_cast(attachment)); +void Framebuffer::attachTexture2D(DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel) { + /** @todo Check for texture target compatibility */ + (this->*texture2DImplementation)(GLenum(depthStencilAttachment), GLenum(texture->target()), texture->id(), mipLevel); } -void Framebuffer::mapForRead(std::uint8_t colorAttachment) { - bindInternal(Target::Read); - /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachment); - #else - static_cast(colorAttachment); - #endif +void Framebuffer::attachTexture2D(std::uint8_t colorAttachment, Texture2D* texture, GLint mipLevel) { + /** @todo Check for texture target compatibility */ + (this->*texture2DImplementation)(GL_COLOR_ATTACHMENT0 + colorAttachment, GLenum(texture->target()), texture->id(), mipLevel); } -void Framebuffer::attachRenderbuffer(Target target, DepthStencilAttachment depthStencilAttachment, Renderbuffer* renderbuffer) { - bindInternal(target); - glFramebufferRenderbuffer(static_cast(target), static_cast(depthStencilAttachment), GL_RENDERBUFFER, renderbuffer->id()); +void Framebuffer::initializeContextBasedFunctionality(Context* context) { + #ifndef MAGNUM_TARGET_GLES + if(context->isExtensionSupported()) { + Debug() << "Framebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + + renderbufferImplementation = &Framebuffer::renderbufferImplementationDSA; + texture1DImplementation = &Framebuffer::texture1DImplementationDSA; + texture2DImplementation = &Framebuffer::texture2DImplementationDSA; + texture3DImplementation = &Framebuffer::texture3DImplementationDSA; + } + #else + static_cast(context); + #endif } -void Framebuffer::attachRenderbuffer(Target target, std::uint8_t colorAttachment, Renderbuffer* renderbuffer) { - bindInternal(target); - glFramebufferRenderbuffer(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, GL_RENDERBUFFER, renderbuffer->id()); +void Framebuffer::renderbufferImplementationDefault(GLenum attachment, Renderbuffer* renderbuffer) { + bindInternal(drawTarget); + glFramebufferRenderbuffer(static_cast(drawTarget), attachment, GL_RENDERBUFFER, renderbuffer->id()); } #ifndef MAGNUM_TARGET_GLES -void Framebuffer::attachTexture1D(Target target, DepthStencilAttachment depthStencilAttachment, Texture1D* texture, GLint mipLevel) { - /** @todo Check for texture target compatibility */ - bindInternal(target); - glFramebufferTexture1D(static_cast(target), static_cast(depthStencilAttachment), static_cast(texture->target()), texture->id(), mipLevel); +void Framebuffer::renderbufferImplementationDSA(GLenum attachment, Renderbuffer* renderbuffer) { + glNamedFramebufferRenderbufferEXT(_id, attachment, GL_RENDERBUFFER, renderbuffer->id()); } -void Framebuffer::attachTexture1D(Target target, std::uint8_t colorAttachment, Texture1D* texture, GLint mipLevel) { - /** @todo Check for texture target compatibility */ - bindInternal(target); - glFramebufferTexture1D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(texture->target()), texture->id(), mipLevel); -} -#endif - -void Framebuffer::attachTexture2D(Target target, DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel) { - /** @todo Check for texture target compatibility */ - bindInternal(target); - glFramebufferTexture2D(static_cast(target), static_cast(depthStencilAttachment), static_cast(texture->target()), texture->id(), mipLevel); +void Framebuffer::texture1DImplementationDefault(GLenum attachment, Texture1D* texture, GLint mipLevel) { + bindInternal(drawTarget); + glFramebufferTexture1D(static_cast(drawTarget), attachment, static_cast(texture->target()), texture->id(), mipLevel); } -void Framebuffer::attachTexture2D(Target target, std::uint8_t colorAttachment, Texture2D* texture, GLint mipLevel) { - /** @todo Check for texture target compatibility */ - bindInternal(target); - glFramebufferTexture2D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(texture->target()), texture->id(), mipLevel); +void Framebuffer::texture1DImplementationDSA(GLenum attachment, Texture1D* texture, GLint mipLevel) { + glNamedFramebufferTexture1DEXT(_id, attachment, GLenum(texture->target()), texture->id(), mipLevel); } +#endif -void Framebuffer::attachCubeMapTexture(Target target, DepthStencilAttachment depthStencilAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { - /** @todo Check for internal format compatibility */ - bindInternal(target); - glFramebufferTexture2D(static_cast(target), static_cast(depthStencilAttachment), static_cast(coordinate), texture->id(), mipLevel); +void Framebuffer::texture2DImplementationDefault(GLenum attachment, GLenum textureTarget, GLuint textureId, GLint mipLevel) { + bindInternal(drawTarget); + glFramebufferTexture2D(static_cast(drawTarget), attachment, textureTarget, textureId, mipLevel); } -void Framebuffer::attachCubeMapTexture(Target target, std::uint8_t colorAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { - /** @todo Check for internal format compatibility */ - bindInternal(target); - glFramebufferTexture2D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(coordinate), texture->id(), mipLevel); +#ifndef MAGNUM_TARGET_GLES +void Framebuffer::texture2DImplementationDSA(GLenum attachment, GLenum textureTarget, GLuint textureId, GLint mipLevel) { + glNamedFramebufferTexture2DEXT(_id, attachment, textureTarget, textureId, mipLevel); } +#endif -void Framebuffer::attachTexture3D(Target target, DepthStencilAttachment depthStencilAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { +void Framebuffer::texture3DImplementationDefault(GLenum attachment, Texture3D* texture, GLint mipLevel, GLint layer) { /** @todo Check for texture target compatibility */ - bindInternal(target); + bindInternal(drawTarget); /** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */ #ifndef MAGNUM_TARGET_GLES - glFramebufferTexture3D(static_cast(target), static_cast(depthStencilAttachment), static_cast(texture->target()), texture->id(), mipLevel, layer); + glFramebufferTexture3D(static_cast(drawTarget), attachment, static_cast(texture->target()), texture->id(), mipLevel, layer); #else - static_cast(depthStencilAttachment); + static_cast(attachment); static_cast(texture); static_cast(mipLevel); static_cast(layer); #endif } -void Framebuffer::attachTexture3D(Target target, std::uint8_t colorAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { - /** @todo Check for texture target compatibility */ - bindInternal(target); - /** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */ - #ifndef MAGNUM_TARGET_GLES - glFramebufferTexture3D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(texture->target()), texture->id(), mipLevel, layer); - #else - static_cast(colorAttachment); - static_cast(texture); - static_cast(mipLevel); - static_cast(layer); - #endif +#ifndef MAGNUM_TARGET_GLES +void Framebuffer::texture3DImplementationDSA(GLenum attachment, Texture3D* texture, GLint mipLevel, GLint layer) { + glNamedFramebufferTexture3DEXT(_id, attachment, GLenum(texture->target()), texture->id(), mipLevel, layer); } +#endif } diff --git a/src/Framebuffer.h b/src/Framebuffer.h index f755e9ef7..6bc7104a0 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -46,9 +46,9 @@ Renderbuffer depthStencil; // configure the textures and allocate texture memory... -framebuffer.attachTexture2D(Framebuffer::Target::Draw, 0, &color); -framebuffer.attachTexture2D(Framebuffer::Target::Draw, 1, &normal); -framebuffer.attachRenderbuffer(Framebuffer::Target::Draw, Framebuffer::DepthStencilAttachment::DepthStencil, &depthStencil); +framebuffer.attachTexture2D(0, &color); +framebuffer.attachTexture2D(1, &normal); +framebuffer.attachRenderbuffer(Framebuffer::DepthStencilAttachment::DepthStencil, &depthStencil); @endcode Then you need to map outputs of your shader to color attachments in the @@ -75,9 +75,21 @@ void drawEvent() { } @endcode +@section Framebuffer-performance-optimization Performance optimizations + +See also @ref AbstractFramebuffer-performance-optimization "relevant section in AbstractFramebuffer". + +If extension @extension{EXT,direct_state_access} is available, functions +mapForDraw(), mapForRead(), attachRenderbuffer(), attachTexture1D(), +attachTexture2D(), attachCubeMapTexture() and attachTexture3D() use DSA +to avoid unnecessary calls to @fn_gl{BindFramebuffer}. See their respective +documentation for more information. + @requires_gl30 %Extension @extension{EXT,framebuffer_object} */ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { + friend class Context; + public: /** * @brief Constructor @@ -106,7 +118,12 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * framebuffer.mapForDraw({{MyShader::ColorOutput, 0}, * {MyShader::NormalOutput, 1}}); * @endcode - * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} + * + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} or + * @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} */ void mapForDraw(std::initializer_list> attachments); @@ -117,19 +134,32 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { * * Similar to above function, can be used in cases when shader has * only one (unnamed) output. - * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} + * + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} or + * @fn_gl_extension{FramebufferDrawBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} */ - void mapForDraw(std::int8_t attachment); + inline void mapForDraw(std::int8_t attachment) { + (this->*drawBufferImplementation)(static_cast(GL_COLOR_ATTACHMENT0 + attachment)); + } /** * @brief Map given color attachment for reading * @param attachment Color attachment ID * - * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} or + * @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ - void mapForRead(std::uint8_t attachment); + inline void mapForRead(std::uint8_t attachment) { + (this->*readBufferImplementation)(GL_COLOR_ATTACHMENT0 + attachment); + } /** * @brief Attachment for depth/stencil part of fragment shader output @@ -155,127 +185,204 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { /** * @brief Attach renderbuffer to given framebuffer depth/stencil attachment - * @param target %Target * @param depthStencilAttachment Depth/stencil attachment * @param renderbuffer %Renderbuffer * - * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} or + * @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access} */ - void attachRenderbuffer(Target target, DepthStencilAttachment depthStencilAttachment, Renderbuffer* renderbuffer); + inline void attachRenderbuffer(DepthStencilAttachment depthStencilAttachment, Renderbuffer* renderbuffer) { + (this->*renderbufferImplementation)(GLenum(depthStencilAttachment), renderbuffer); + } /** * @brief Attach renderbuffer to given framebuffer color attachment - * @param target %Target * @param colorAttachment Color attachment ID (number between 0 and 15) * @param renderbuffer %Renderbuffer * - * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} or + * @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access} */ - void attachRenderbuffer(Target target, std::uint8_t colorAttachment, Renderbuffer* renderbuffer); + inline void attachRenderbuffer(std::uint8_t colorAttachment, Renderbuffer* renderbuffer) { + (this->*renderbufferImplementation)(GL_COLOR_ATTACHMENT0 + colorAttachment, renderbuffer); + } #ifndef MAGNUM_TARGET_GLES /** * @brief Attach 1D texture to given framebuffer depth/stencil attachment - * @param target %Target * @param depthStencilAttachment Depth/stencil attachment * @param texture 1D texture * @param mipLevel Mip level * - * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or + * @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ - void attachTexture1D(Target target, DepthStencilAttachment depthStencilAttachment, Texture1D* texture, GLint mipLevel); + inline void attachTexture1D(DepthStencilAttachment depthStencilAttachment, Texture1D* texture, GLint mipLevel) { + /** @todo Check for texture target compatibility */ + (this->*texture1DImplementation)(GLenum(depthStencilAttachment), texture, mipLevel); + } /** * @brief Attach 1D texture to given framebuffer color attachment - * @param target %Target * @param colorAttachment Color attachment ID (number between 0 and 15) * @param texture 1D texture * @param mipLevel Mip level * - * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or + * @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ - void attachTexture1D(Target target, std::uint8_t colorAttachment, Texture1D* texture, GLint mipLevel); + inline void attachTexture1D(std::uint8_t colorAttachment, Texture1D* texture, GLint mipLevel) { + /** @todo Check for texture target compatibility */ + (this->*texture1DImplementation)(GL_COLOR_ATTACHMENT0 + colorAttachment, texture, mipLevel); + } #endif /** * @brief Attach 2D texture to given framebuffer depth/stencil attachment - * @param target %Target * @param depthStencilAttachment Depth/stencil attachment * @param texture 2D texture * @param mipLevel Mip level. For rectangle textures it * should be always 0. * - * @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, - * @fn_gl{FramebufferTexture} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - void attachTexture2D(Target target, DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel); + void attachTexture2D(DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel); /** * @brief Attach 2D texture to given framebuffer color attachment - * @param target %Target * @param colorAttachment Color attachment ID (number between 0 and 15) * @param texture 2D texture * @param mipLevel Mip level. For rectangle textures it * should be always 0. * - * @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, - * @fn_gl{FramebufferTexture} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - void attachTexture2D(Target target, std::uint8_t colorAttachment, Texture2D* texture, GLint mipLevel); + void attachTexture2D(std::uint8_t colorAttachment, Texture2D* texture, GLint mipLevel); /** * @brief Attach cube map texture to given framebuffer depth/stencil attachment - * @param target %Target * @param depthStencilAttachment Depth/stencil attachment * @param texture Cube map texture * @param coordinate Cube map coordinate * @param mipLevel Mip level * - * @see attachTexture2D(), @fn_gl{BindFramebuffer}, - * @fn_gl{FramebufferTexture} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see attachTexture2D(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - void attachCubeMapTexture(Target target, DepthStencilAttachment depthStencilAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel); + inline void attachCubeMapTexture(DepthStencilAttachment depthStencilAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { + (this->*texture2DImplementation)(GLenum(depthStencilAttachment), GLenum(coordinate), texture->id(), mipLevel); + } /** * @brief Attach cube map texture to given framebuffer color attachment - * @param target %Target * @param colorAttachment Color attachment ID (number between 0 and 15) * @param texture Cube map texture * @param coordinate Cube map coordinate * @param mipLevel Mip level * - * @see attachTexture2D(), @fn_gl{BindFramebuffer}, - * @fn_gl{FramebufferTexture} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see attachTexture2D(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - void attachCubeMapTexture(Target target, std::uint8_t colorAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel); + inline void attachCubeMapTexture(std::uint8_t colorAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { + (this->*texture2DImplementation)(GL_COLOR_ATTACHMENT0 + colorAttachment, GLenum(coordinate), texture->id(), mipLevel); + } /** * @brief Attach 3D texture to given framebuffer depth/stencil attachment - * @param target %Target * @param depthStencilAttachment Depth/stencil attachment * @param texture 3D texture * @param mipLevel Mip level * @param layer Layer of 2D image within a 3D texture * - * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or + * @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access} * @requires_es_extension %Extension @es_extension{OES,texture_3D} */ - void attachTexture3D(Target target, DepthStencilAttachment depthStencilAttachment, Texture3D* texture, GLint mipLevel, GLint layer); + inline void attachTexture3D(DepthStencilAttachment depthStencilAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { + /** @todo Check for texture target compatibility */ + (this->*texture3DImplementation)(GLenum(depthStencilAttachment), texture, mipLevel, layer); + } /** * @brief Attach 3D texture to given framebuffer color attachment - * @param target %Target * @param colorAttachment Color attachment ID (number between 0 and 15) * @param texture 3D texture * @param mipLevel Mip level * @param layer Layer of 2D image within a 3D texture. * - * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or + * @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access} * @requires_es_extension %Extension @es_extension{OES,texture_3D} */ - void attachTexture3D(Target target, std::uint8_t colorAttachment, Texture3D* texture, GLint mipLevel, GLint layer); + inline void attachTexture3D(std::uint8_t colorAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { + /** @todo Check for texture target compatibility */ + (this->*texture3DImplementation)(GL_COLOR_ATTACHMENT0 + colorAttachment, texture, mipLevel, layer); + } + + private: + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + + typedef void(Framebuffer::*RenderbufferImplementation)(GLenum, Renderbuffer*); + void MAGNUM_LOCAL renderbufferImplementationDefault(GLenum attachment, Renderbuffer* renderbuffer); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL renderbufferImplementationDSA(GLenum attachment, Renderbuffer* renderbuffer); + #endif + static RenderbufferImplementation renderbufferImplementation; + + #ifndef MAGNUM_TARGET_GLES + typedef void(Framebuffer::*Texture1DImplementation)(GLenum, Texture1D*, GLint); + void MAGNUM_LOCAL texture1DImplementationDefault(GLenum attachment, Texture1D* texture, GLint mipLevel); + void MAGNUM_LOCAL texture1DImplementationDSA(GLenum attachment, Texture1D* texture, GLint mipLevel); + static Texture1DImplementation texture1DImplementation; + #endif + + typedef void(Framebuffer::*Texture2DImplementation)(GLenum, GLenum, GLuint, GLint); + void MAGNUM_LOCAL texture2DImplementationDefault(GLenum attachment, GLenum textureTarget, GLuint textureId, GLint mipLevel); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL texture2DImplementationDSA(GLenum attachment, GLenum textureTarget, GLuint textureId, GLint mipLevel); + #endif + static MAGNUM_LOCAL Texture2DImplementation texture2DImplementation; + + typedef void(Framebuffer::*Texture3DImplementation)(GLenum, Texture3D*, GLint, GLint); + void MAGNUM_LOCAL texture3DImplementationDefault(GLenum attachment, Texture3D* texture, GLint mipLevel, GLint layer); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL texture3DImplementationDSA(GLenum attachment, Texture3D* texture, GLint mipLevel, GLint layer); + #endif + static Texture3DImplementation texture3DImplementation; }; } diff --git a/src/Renderbuffer.cpp b/src/Renderbuffer.cpp index 100ac550e..afb9d1f26 100644 --- a/src/Renderbuffer.cpp +++ b/src/Renderbuffer.cpp @@ -16,12 +16,15 @@ #include "Renderbuffer.h" #include "Context.h" +#include "Extensions.h" #include "Implementation/State.h" #include "Implementation/FramebufferState.h" namespace Magnum { +Renderbuffer::StorageImplementation Renderbuffer::storageImplementation = &Renderbuffer::storageImplementationDefault; + Renderbuffer::~Renderbuffer() { /* If bound, remove itself from state */ GLuint& binding = Context::current()->state()->framebuffer->renderbufferBinding; @@ -30,11 +33,6 @@ Renderbuffer::~Renderbuffer() { glDeleteRenderbuffers(1, &_id); } -void Renderbuffer::setStorage(Renderbuffer::InternalFormat internalFormat, const Vector2i& size) { - bind(); - glRenderbufferStorage(GL_RENDERBUFFER, GLenum(internalFormat), size.x(), size.y()); -} - void Renderbuffer::bind() { GLuint& binding = Context::current()->state()->framebuffer->renderbufferBinding; @@ -44,4 +42,27 @@ void Renderbuffer::bind() { glBindRenderbuffer(GL_RENDERBUFFER, _id); } +void Renderbuffer::initializeContextBasedFunctionality(Context* context) { + #ifndef MAGNUM_TARGET_GLES + if(context->isExtensionSupported()) { + Debug() << "Renderbuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + + storageImplementation = &Renderbuffer::storageImplementationDSA; + } + #else + static_cast(context); + #endif +} + +void Renderbuffer::storageImplementationDefault(Renderbuffer::InternalFormat internalFormat, const Vector2i& size) { + bind(); + glRenderbufferStorage(GL_RENDERBUFFER, GLenum(internalFormat), size.x(), size.y()); +} + +#ifndef MAGNUM_TARGET_GLES +void Renderbuffer::storageImplementationDSA(Renderbuffer::InternalFormat internalFormat, const Vector2i& size) { + glNamedRenderbufferStorageEXT(_id, GLenum(internalFormat), size.x(), size.y()); +} +#endif + } diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index d61c260a1..266bad113 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -19,7 +19,6 @@ * @brief Class Magnum::Renderbuffer */ -#include "Math/Vector2.h" #include "Magnum.h" #include "magnumVisibility.h" @@ -37,9 +36,15 @@ for more information. The engine tracks currently bound renderbuffer to avoid unnecessary calls to @fn_gl{BindRenderbuffer} in setStorage(). +If extension @extension{EXT,direct_state_access} is available, function +setStorage() uses DSA to avoid unnecessary calls to @fn_gl{BindFramebuffer}. +See its documentation for more information. + @requires_gl30 %Extension @extension{EXT,framebuffer_object} */ class MAGNUM_EXPORT Renderbuffer { + friend class Context; + Renderbuffer(const Renderbuffer& other) = delete; Renderbuffer(Renderbuffer&& other) = delete; Renderbuffer& operator=(const Renderbuffer& other) = delete; @@ -538,11 +543,26 @@ class MAGNUM_EXPORT Renderbuffer { * @param internalFormat Internal format * @param size Renderbuffer size * - * @see @fn_gl{BindRenderbuffer}, @fn_gl{RenderbufferStorage} + * If @extension{EXT,direct_state_access} is not available and the + * framebufferbuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindRenderbuffer}, @fn_gl{RenderbufferStorage} or + * @fn_gl_extension{NamedRenderbufferStorage,EXT,direct_state_access} */ - void setStorage(InternalFormat internalFormat, const Vector2i& size); + inline void setStorage(InternalFormat internalFormat, const Vector2i& size) { + (this->*storageImplementation)(internalFormat, size); + } private: + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + + typedef void(Renderbuffer::*StorageImplementation)(InternalFormat, const Vector2i&); + void MAGNUM_LOCAL storageImplementationDefault(InternalFormat internalFormat, const Vector2i& size); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL storageImplementationDSA(InternalFormat internalFormat, const Vector2i& size); + #endif + static StorageImplementation storageImplementation; + void MAGNUM_LOCAL bind(); GLuint _id;