From 7d6b7a4b6bc20d26c86b52c5d8f1ba0aa653ca69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 17 Dec 2012 12:41:54 +0100 Subject: [PATCH] Using EXT_direct_state_access in framebuffers. Framebuffer::attach*() doesn't need the target at all (meaning the attachment will be used for both reading and drawing), another misunderstanding on my side. Now the extension is used on all places where it can be used (except for unimplemented features). --- src/AbstractFramebuffer.cpp | 61 ++++++++++++ src/AbstractFramebuffer.h | 27 ++++- src/Context.cpp | 4 + src/DefaultFramebuffer.cpp | 18 +--- src/DefaultFramebuffer.h | 37 ++++++- src/Framebuffer.cpp | 119 ++++++++++------------ src/Framebuffer.h | 191 ++++++++++++++++++++++++++++-------- src/Renderbuffer.cpp | 31 +++++- src/Renderbuffer.h | 26 ++++- 9 files changed, 376 insertions(+), 138 deletions(-) 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;