From c1c71339e428165385efecf253d1bbf1854845f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 23 Jan 2014 01:06:12 +0100 Subject: [PATCH] Moved global data from framebuffer classes to per-context state. On the way to unify and reduce the "Using optional features" messages. --- src/Magnum/AbstractFramebuffer.cpp | 83 ++--------- src/Magnum/AbstractFramebuffer.h | 25 +--- src/Magnum/CMakeLists.txt | 1 + src/Magnum/Context.cpp | 3 - src/Magnum/DefaultFramebuffer.cpp | 16 +- src/Magnum/DefaultFramebuffer.h | 14 +- src/Magnum/Framebuffer.cpp | 57 ++++--- src/Magnum/Framebuffer.h | 47 +----- .../Implementation/FramebufferState.cpp | 141 ++++++++++++++++++ src/Magnum/Implementation/FramebufferState.h | 32 +++- src/Magnum/Implementation/State.cpp | 2 +- src/Magnum/Renderbuffer.cpp | 39 +---- src/Magnum/Renderbuffer.h | 24 +-- 13 files changed, 257 insertions(+), 227 deletions(-) create mode 100644 src/Magnum/Implementation/FramebufferState.cpp diff --git a/src/Magnum/AbstractFramebuffer.cpp b/src/Magnum/AbstractFramebuffer.cpp index 8eb210fa2..9500c4b7f 100644 --- a/src/Magnum/AbstractFramebuffer.cpp +++ b/src/Magnum/AbstractFramebuffer.cpp @@ -37,19 +37,6 @@ namespace Magnum { -AbstractFramebuffer::CheckStatusImplementation AbstractFramebuffer::checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDefault; - -AbstractFramebuffer::ReadImplementation AbstractFramebuffer::readImplementation = &AbstractFramebuffer::readImplementationDefault; - -AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault; -AbstractFramebuffer::DrawBufferImplementation AbstractFramebuffer::drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDefault; -AbstractFramebuffer::ReadBufferImplementation AbstractFramebuffer::readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault; - -#ifdef MAGNUM_TARGET_GLES2 -FramebufferTarget AbstractFramebuffer::readTarget = FramebufferTarget::ReadDraw; -FramebufferTarget AbstractFramebuffer::drawTarget = FramebufferTarget::ReadDraw; -#endif - Vector2i AbstractFramebuffer::maxViewportSize() { Vector2i& value = Context::current()->state().framebuffer->maxViewportSize; @@ -136,9 +123,9 @@ FramebufferTarget AbstractFramebuffer::bindInternal() { glBindFramebuffer(GLenum(FramebufferTarget::Read), _id); return FramebufferTarget::Read; #else - if(readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id; - glBindFramebuffer(GLenum(readTarget), _id); - return readTarget; + if(state->readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id; + glBindFramebuffer(GLenum(state->readTarget), _id); + return state->readTarget; #endif } @@ -186,20 +173,22 @@ void AbstractFramebuffer::clear(FramebufferClearMask mask) { #ifndef MAGNUM_TARGET_GLES2 bindInternal(FramebufferTarget::Draw); #else - bindInternal(drawTarget); + bindInternal(Context::current()->state().framebuffer->drawTarget); #endif glClear(GLbitfield(mask)); } void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Image2D& image) { + const Implementation::FramebufferState& state = *Context::current()->state().framebuffer; + #ifndef MAGNUM_TARGET_GLES2 bindInternal(FramebufferTarget::Read); #else - bindInternal(readTarget); + bindInternal(state.readTarget); #endif const std::size_t dataSize = image.dataSize(size); char* const data = new char[dataSize]; - readImplementation(offset, size, image.format(), image.type(), dataSize, data); + (state.readImplementation)(offset, size, image.format(), image.type(), dataSize, data); image.setData(image.format(), image.type(), size, data); } @@ -216,7 +205,7 @@ void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Buf image.setData(image.format(), image.type(), size, nullptr, usage); image.buffer().bind(Buffer::Target::PixelPack); - readImplementation(offset, size, image.format(), image.type(), image.dataSize(size), nullptr); + (Context::current()->state().framebuffer->readImplementation)(offset, size, image.format(), image.type(), image.dataSize(size), nullptr); } #endif @@ -245,60 +234,6 @@ void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attach #endif } -void AbstractFramebuffer::initializeContextBasedFunctionality(Context& context) { - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) { - Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; - - checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDSA; - drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDSA; - drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA; - readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA; - } - #endif - - #ifdef MAGNUM_TARGET_GLES2 - /* Optimistically set separate binding targets and check if one of the - extensions providing them is available */ - readTarget = FramebufferTarget::Read; - drawTarget = FramebufferTarget::Draw; - - if(context.isExtensionSupported()) - Debug() << "AbstractFramebuffer: using" << Extensions::GL::ANGLE::framebuffer_blit::string() << "features"; - - else if(context.isExtensionSupported()) - Debug() << "AbstractFramebuffer: using" << Extensions::GL::APPLE::framebuffer_multisample::string() << "features"; - - else if(context.isExtensionSupported()) - Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_blit::string() << "features"; - - /* NV_framebuffer_multisample requires NV_framebuffer_blit, which has these - enums. However, on my system only NV_framebuffer_multisample is - supported, but NV_framebuffer_blit isn't. I will hold my breath and - assume these enums are available. */ - else if(context.isExtensionSupported()) - Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_multisample::string() << "features"; - - /* If no such extension is available, reset back to unified target */ - else readTarget = drawTarget = FramebufferTarget::ReadDraw; - #endif - - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) - #else - if(context.isExtensionSupported()) - #endif - { - #ifndef MAGNUM_TARGET_GLES - Debug() << "AbstractFramebuffer: using" << Extensions::GL::ARB::robustness::string() << "features"; - #else - Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::robustness::string() << "features"; - #endif - - readImplementation = &AbstractFramebuffer::readImplementationRobustness; - } -} - GLenum AbstractFramebuffer::checkStatusImplementationDefault(const FramebufferTarget target) { bindInternal(target); return glCheckFramebufferStatus(GLenum(target)); diff --git a/src/Magnum/AbstractFramebuffer.h b/src/Magnum/AbstractFramebuffer.h index 8502203c6..8904ebb5f 100644 --- a/src/Magnum/AbstractFramebuffer.h +++ b/src/Magnum/AbstractFramebuffer.h @@ -127,6 +127,8 @@ enum class FramebufferTarget: GLenum { ReadDraw = GL_FRAMEBUFFER /**< For both reading and drawing. */ }; +namespace Implementation { struct FramebufferState; } + /** @brief Base for default and named framebuffers @@ -145,7 +147,7 @@ protected from buffer overflow. @todo @extension{ARB,viewport_array} (and `GL_MAX_VIEWPORTS`) */ class MAGNUM_EXPORT AbstractFramebuffer { - friend class Context; + friend class Implementation::FramebufferState; public: /** @todo `GL_IMPLEMENTATION_COLOR_READ_FORMAT`, `GL_IMPLEMENTATION_COLOR_READ_TYPE`, seems to be depending on currently bound FB (aargh) (@extension{ARB,ES2_compatibility}). */ @@ -311,23 +313,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { FramebufferTarget MAGNUM_LOCAL bindInternal(); void MAGNUM_LOCAL setViewportInternal(); - #ifdef MAGNUM_TARGET_GLES2 - static MAGNUM_LOCAL FramebufferTarget readTarget; - static MAGNUM_LOCAL FramebufferTarget drawTarget; - #endif - - typedef GLenum(AbstractFramebuffer::*CheckStatusImplementation)(FramebufferTarget); - static CheckStatusImplementation checkStatusImplementation; - - 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; - void MAGNUM_LOCAL invalidateImplementation(GLsizei count, GLenum* attachments); void MAGNUM_LOCAL invalidateImplementation(GLsizei count, GLenum* attachments, const Range2Di& rectangle); @@ -335,8 +320,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { Range2Di _viewport; private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - GLenum MAGNUM_LOCAL checkStatusImplementationDefault(FramebufferTarget target); #ifndef MAGNUM_TARGET_GLES GLenum MAGNUM_LOCAL checkStatusImplementationDSA(FramebufferTarget target); @@ -357,10 +340,8 @@ class MAGNUM_EXPORT AbstractFramebuffer { void MAGNUM_LOCAL readBufferImplementationDSA(GLenum buffer); #endif - typedef void(*ReadImplementation)(const Vector2i&, const Vector2i&, ColorFormat, ColorType, std::size_t, GLvoid*); static void MAGNUM_LOCAL readImplementationDefault(const Vector2i& offset, const Vector2i& size, ColorFormat format, ColorType type, std::size_t dataSize, GLvoid* data); static void MAGNUM_LOCAL readImplementationRobustness(const Vector2i& offset, const Vector2i& size, ColorFormat format, ColorType type, std::size_t dataSize, GLvoid* data); - static ReadImplementation MAGNUM_LOCAL readImplementation; }; CORRADE_ENUMSET_OPERATORS(FramebufferClearMask) diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt index b688a1f46..fd98022fe 100644 --- a/src/Magnum/CMakeLists.txt +++ b/src/Magnum/CMakeLists.txt @@ -54,6 +54,7 @@ set(Magnum_SRCS Implementation/BufferState.cpp Implementation/DebugState.cpp + Implementation/FramebufferState.cpp Implementation/State.cpp Implementation/TextureState.cpp diff --git a/src/Magnum/Context.cpp b/src/Magnum/Context.cpp index e7abb8e15..732c57e4c 100644 --- a/src/Magnum/Context.cpp +++ b/src/Magnum/Context.cpp @@ -448,7 +448,6 @@ Context::Context() { _state = new Implementation::State(*this); /* Initialize functionality based on current OpenGL version and extensions */ - AbstractFramebuffer::initializeContextBasedFunctionality(*this); AbstractShaderProgram::initializeContextBasedFunctionality(*this); AbstractTexture::initializeContextBasedFunctionality(*this); Buffer::initializeContextBasedFunctionality(*this); @@ -456,9 +455,7 @@ Context::Context() { BufferTexture::initializeContextBasedFunctionality(*this); #endif DefaultFramebuffer::initializeContextBasedFunctionality(*this); - Framebuffer::initializeContextBasedFunctionality(*this); Mesh::initializeContextBasedFunctionality(*this); - Renderbuffer::initializeContextBasedFunctionality(*this); Renderer::initializeContextBasedFunctionality(*this); } diff --git a/src/Magnum/DefaultFramebuffer.cpp b/src/Magnum/DefaultFramebuffer.cpp index b9eb7b4ab..f2990e3f5 100644 --- a/src/Magnum/DefaultFramebuffer.cpp +++ b/src/Magnum/DefaultFramebuffer.cpp @@ -38,6 +38,10 @@ DefaultFramebuffer defaultFramebuffer; DefaultFramebuffer::DefaultFramebuffer() { _id = 0; } +DefaultFramebuffer::Status DefaultFramebuffer::checkStatus(const FramebufferTarget target) { + return Status((this->*Context::current()->state().framebuffer->checkStatusImplementation)(target)); +} + #ifndef MAGNUM_TARGET_GLES2 DefaultFramebuffer& DefaultFramebuffer::mapForDraw(std::initializer_list> attachments) { /* Max attachment location */ @@ -52,11 +56,21 @@ DefaultFramebuffer& DefaultFramebuffer::mapForDraw(std::initializer_list*drawBuffersImplementation)(max+1, _attachments); + (this->*Context::current()->state().framebuffer->drawBuffersImplementation)(max+1, _attachments); + return *this; +} + +DefaultFramebuffer& DefaultFramebuffer::mapForDraw(const DrawAttachment attachment) { + (this->*Context::current()->state().framebuffer->drawBufferImplementation)(GLenum(attachment)); return *this; } #endif +DefaultFramebuffer& DefaultFramebuffer::mapForRead(const ReadAttachment attachment) { + (this->*Context::current()->state().framebuffer->readBufferImplementation)(GLenum(attachment)); + return *this; +} + void DefaultFramebuffer::invalidate(std::initializer_list attachments) { /** @todo C++14: use VLA to avoid heap allocation */ Containers::Array _attachments(attachments.size()); diff --git a/src/Magnum/DefaultFramebuffer.h b/src/Magnum/DefaultFramebuffer.h index bbd55ca0a..61276f675 100644 --- a/src/Magnum/DefaultFramebuffer.h +++ b/src/Magnum/DefaultFramebuffer.h @@ -316,9 +316,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @fn_gl_extension{CheckNamedFramebufferStatus,EXT,direct_state_access} * @requires_gl30 %Extension @extension{ARB,framebuffer_object} */ - Status checkStatus(FramebufferTarget target) { - return Status((this->*checkStatusImplementation)(target)); - } + Status checkStatus(FramebufferTarget target); #ifndef MAGNUM_TARGET_GLES2 /** @@ -362,10 +360,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @requires_gles30 Draw attachments for default framebuffer are * available only in OpenGL ES 3.0. */ - DefaultFramebuffer& mapForDraw(DrawAttachment attachment) { - (this->*drawBufferImplementation)(GLenum(attachment)); - return *this; - } + DefaultFramebuffer& mapForDraw(DrawAttachment attachment); #endif /** @@ -380,10 +375,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ - DefaultFramebuffer& mapForRead(ReadAttachment attachment) { - (this->*readBufferImplementation)(GLenum(attachment)); - return *this; - } + DefaultFramebuffer& mapForRead(ReadAttachment attachment); /** * @brief Invalidate framebuffer diff --git a/src/Magnum/Framebuffer.cpp b/src/Magnum/Framebuffer.cpp index e6b73894d..141877e8a 100644 --- a/src/Magnum/Framebuffer.cpp +++ b/src/Magnum/Framebuffer.cpp @@ -42,13 +42,6 @@ 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; - const Framebuffer::DrawAttachment Framebuffer::DrawAttachment::None = Framebuffer::DrawAttachment(GL_NONE); const Framebuffer::BufferAttachment Framebuffer::BufferAttachment::Depth = Framebuffer::BufferAttachment(GL_DEPTH_ATTACHMENT); const Framebuffer::BufferAttachment Framebuffer::BufferAttachment::Stencil = Framebuffer::BufferAttachment(GL_STENCIL_ATTACHMENT); @@ -104,6 +97,10 @@ Framebuffer& Framebuffer::setLabel(const std::string& label) { return *this; } +Framebuffer::Status Framebuffer::checkStatus(const FramebufferTarget target) { + return Status((this->*Context::current()->state().framebuffer->checkStatusImplementation)(target)); +} + Framebuffer& Framebuffer::mapForDraw(std::initializer_list> attachments) { /* Max attachment location */ std::size_t max = 0; @@ -117,7 +114,17 @@ Framebuffer& Framebuffer::mapForDraw(std::initializer_list*drawBuffersImplementation)(max+1, _attachments); + (this->*Context::current()->state().framebuffer->drawBuffersImplementation)(max+1, _attachments); + return *this; +} + +Framebuffer& Framebuffer::mapForDraw(const DrawAttachment attachment) { + (this->*Context::current()->state().framebuffer->drawBufferImplementation)(GLenum(attachment)); + return *this; +} + +Framebuffer& Framebuffer::mapForRead(const ColorAttachment attachment) { + (this->*Context::current()->state().framebuffer->readBufferImplementation)(GLenum(attachment)); return *this; } @@ -139,25 +146,33 @@ void Framebuffer::invalidate(std::initializer_list attac invalidateImplementation(attachments.size(), _attachments, rectangle); } +Framebuffer& Framebuffer::attachRenderbuffer(const BufferAttachment attachment, Renderbuffer& renderbuffer) { + (this->*Context::current()->state().framebuffer->renderbufferImplementation)(attachment, renderbuffer); + return *this; +} + +#ifndef MAGNUM_TARGET_GLES +Framebuffer& Framebuffer::attachTexture1D(const BufferAttachment attachment, Texture1D& texture, const Int level) { + (this->*Context::current()->state().framebuffer->texture1DImplementation)(attachment, texture, level); + return *this; +} +#endif + Framebuffer& Framebuffer::attachTexture2D(BufferAttachment attachment, Texture2D& texture, Int mipLevel) { /** @todo Check for texture target compatibility */ - (this->*texture2DImplementation)(attachment, GLenum(texture.target()), texture.id(), mipLevel); + (this->*Context::current()->state().framebuffer->texture2DImplementation)(attachment, GLenum(texture.target()), texture.id(), mipLevel); return *this; } -void Framebuffer::initializeContextBasedFunctionality(Context& context) { - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) { - Debug() << "Framebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; +Framebuffer& Framebuffer::attachCubeMapTexture(const BufferAttachment attachment, CubeMapTexture& texture, CubeMapTexture::Coordinate coordinate, const Int level) { + (this->*Context::current()->state().framebuffer->texture2DImplementation)(attachment, GLenum(coordinate), texture.id(), level); + return *this; +} - renderbufferImplementation = &Framebuffer::renderbufferImplementationDSA; - texture1DImplementation = &Framebuffer::texture1DImplementationDSA; - texture2DImplementation = &Framebuffer::texture2DImplementationDSA; - texture3DImplementation = &Framebuffer::texture3DImplementationDSA; - } - #else - static_cast(context); - #endif +Framebuffer& Framebuffer::attachTexture3D(Framebuffer::BufferAttachment attachment, Texture3D& texture, Int level, Int layer) { + /** @todo Check for texture target compatibility */ + (this->*Context::current()->state().framebuffer->texture3DImplementation)(attachment, texture, level, layer); + return *this; } void Framebuffer::renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer& renderbuffer) { diff --git a/src/Magnum/Framebuffer.h b/src/Magnum/Framebuffer.h index ff07280a5..ed984ab45 100644 --- a/src/Magnum/Framebuffer.h +++ b/src/Magnum/Framebuffer.h @@ -102,7 +102,7 @@ See their respective documentation for more information. @todo `MAX_COLOR_ATTACHMENTS` */ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObject { - friend class Context; + friend class Implementation::FramebufferState; public: /** @@ -364,9 +364,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @see @fn_gl{BindFramebuffer}, @fn_gl{CheckFramebufferStatus} or * @fn_gl_extension{CheckNamedFramebufferStatus,EXT,direct_state_access} */ - Status checkStatus(FramebufferTarget target) { - return Status((this->*checkStatusImplementation)(target)); - } + Status checkStatus(FramebufferTarget target); /** * @brief Map shader output to attachments @@ -409,10 +407,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @fn_gl{DrawBuffers} in OpenGL ES 3.0 * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} */ - Framebuffer& mapForDraw(DrawAttachment attachment) { - (this->*drawBufferImplementation)(GLenum(attachment)); - return *this; - } + Framebuffer& mapForDraw(DrawAttachment attachment); /** * @brief Map given color attachment for reading @@ -426,10 +421,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * or @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ - Framebuffer& mapForRead(ColorAttachment attachment) { - (this->*readBufferImplementation)(GLenum(attachment)); - return *this; - } + Framebuffer& mapForRead(ColorAttachment attachment); /** * @brief Invalidate framebuffer @@ -478,10 +470,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} or * @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access} */ - Framebuffer& attachRenderbuffer(BufferAttachment attachment, Renderbuffer& renderbuffer) { - (this->*renderbufferImplementation)(attachment, renderbuffer); - return *this; - } + Framebuffer& attachRenderbuffer(BufferAttachment attachment, Renderbuffer& renderbuffer); #ifndef MAGNUM_TARGET_GLES /** @@ -498,10 +487,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * or @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ - Framebuffer& attachTexture1D(BufferAttachment attachment, Texture1D& texture, Int level) { - (this->*texture1DImplementation)(attachment, texture, level); - return *this; - } + Framebuffer& attachTexture1D(BufferAttachment attachment, Texture1D& texture, Int level); #endif /** @@ -535,10 +521,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @fn_gl2{FramebufferTexture2D,FramebufferTexture} or * @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - Framebuffer& attachCubeMapTexture(BufferAttachment attachment, CubeMapTexture& texture, CubeMapTexture::Coordinate coordinate, Int level) { - (this->*texture2DImplementation)(attachment, GLenum(coordinate), texture.id(), level); - return *this; - } + Framebuffer& attachCubeMapTexture(BufferAttachment attachment, CubeMapTexture& texture, CubeMapTexture::Coordinate coordinate, Int level); /** * @brief Attach 3D texture to given buffer @@ -555,11 +538,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * or @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access} * @requires_es_extension %Extension @es_extension{OES,texture_3D} */ - Framebuffer& attachTexture3D(BufferAttachment attachment, Texture3D& texture, Int level, Int layer) { - /** @todo Check for texture target compatibility */ - (this->*texture3DImplementation)(attachment, texture, level, layer); - return *this; - } + Framebuffer& attachTexture3D(BufferAttachment attachment, Texture3D& texture, Int level, Int layer); /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT @@ -570,35 +549,25 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje #endif private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - - typedef void(Framebuffer::*RenderbufferImplementation)(BufferAttachment, Renderbuffer&); void MAGNUM_LOCAL renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer& renderbuffer); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL renderbufferImplementationDSA(BufferAttachment attachment, Renderbuffer& renderbuffer); #endif - static RenderbufferImplementation renderbufferImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(Framebuffer::*Texture1DImplementation)(BufferAttachment, Texture1D&, GLint); void MAGNUM_LOCAL texture1DImplementationDefault(BufferAttachment attachment, Texture1D& texture, GLint level); void MAGNUM_LOCAL texture1DImplementationDSA(BufferAttachment attachment, Texture1D& texture, GLint level); - static Texture1DImplementation texture1DImplementation; #endif - typedef void(Framebuffer::*Texture2DImplementation)(BufferAttachment, GLenum, GLuint, GLint); void MAGNUM_LOCAL texture2DImplementationDefault(BufferAttachment attachment, GLenum textureTarget, GLuint textureId, GLint level); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL texture2DImplementationDSA(BufferAttachment attachment, GLenum textureTarget, GLuint textureId, GLint level); #endif - static Texture2DImplementation texture2DImplementation; - typedef void(Framebuffer::*Texture3DImplementation)(BufferAttachment, Texture3D&, GLint, GLint); void MAGNUM_LOCAL texture3DImplementationDefault(BufferAttachment attachment, Texture3D& texture, GLint level, GLint layer); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL texture3DImplementationDSA(BufferAttachment attachment, Texture3D& texture, GLint level, GLint layer); #endif - static Texture3DImplementation texture3DImplementation; }; /** @debugoperator{DefaultFramebuffer} */ diff --git a/src/Magnum/Implementation/FramebufferState.cpp b/src/Magnum/Implementation/FramebufferState.cpp new file mode 100644 index 000000000..5ef927e74 --- /dev/null +++ b/src/Magnum/Implementation/FramebufferState.cpp @@ -0,0 +1,141 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "FramebufferState.h" + +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" +#include "Magnum/Renderbuffer.h" + +namespace Magnum { namespace Implementation { + +FramebufferState::FramebufferState(Context& context, std::vector& extensions): readBinding(0), drawBinding(0), renderbufferBinding(0), maxDrawBuffers(0), maxColorAttachments(0), maxRenderbufferSize(0), maxSamples(0) + #ifndef MAGNUM_TARGET_GLES + , maxDualSourceDrawBuffers(0) + #endif +{ + /* DSA/non-DSA implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::direct_state_access::string()); + + checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDSA; + drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDSA; + drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA; + readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA; + + renderbufferImplementation = &Framebuffer::renderbufferImplementationDSA; + texture1DImplementation = &Framebuffer::texture1DImplementationDSA; + texture2DImplementation = &Framebuffer::texture2DImplementationDSA; + texture3DImplementation = &Framebuffer::texture3DImplementationDSA; + + renderbufferStorageImplementation = &Renderbuffer::storageImplementationDSA; + } else + #endif + { + checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDefault; + drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault; + drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDefault; + readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault; + + renderbufferImplementation = &Framebuffer::renderbufferImplementationDefault; + #ifndef MAGNUM_TARGET_GLES + texture1DImplementation = &Framebuffer::texture1DImplementationDefault; + #endif + texture2DImplementation = &Framebuffer::texture2DImplementationDefault; + texture3DImplementation = &Framebuffer::texture3DImplementationDefault; + + renderbufferStorageImplementation = &Renderbuffer::storageImplementationDefault; + } + + /* Framebuffer binding on ES2 */ + #ifdef MAGNUM_TARGET_GLES2 + /* Optimistically set separate binding targets and check if one of the + extensions providing them is available */ + readTarget = FramebufferTarget::Read; + drawTarget = FramebufferTarget::Draw; + + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ANGLE::framebuffer_blit::string()); + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::APPLE::framebuffer_multisample::string()); + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::NV::framebuffer_blit::string()); + + /* NV_framebuffer_multisample requires NV_framebuffer_blit, which has these + enums. However, on my system only NV_framebuffer_multisample is + supported, but NV_framebuffer_blit isn't. I will hold my breath and + assume these enums are available. */ + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::NV::framebuffer_multisample::string()); + + /* If no such extension is available, reset back to unified target */ + } else readTarget = drawTarget = FramebufferTarget::ReadDraw; + #endif + + /* Framebuffer reading implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) + #else + if(context.isExtensionSupported()) + #endif + { + #ifndef MAGNUM_TARGET_GLES + extensions.push_back(Extensions::GL::ARB::robustness::string()); + #else + extensions.push_back(Extensions::GL::EXT::robustness::string()); + #endif + + readImplementation = &AbstractFramebuffer::readImplementationRobustness; + } else readImplementation = &AbstractFramebuffer::readImplementationDefault; + + /* Multisample renderbuffer storage implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + /* Extension added above */ + + renderbufferStorageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationDSA; + } else + #endif + { + #ifdef MAGNUM_TARGET_GLES2 + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ANGLE::framebuffer_multisample::string()); + + renderbufferStorageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationANGLE; + } else if (context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::NV::framebuffer_multisample::string()); + + renderbufferStorageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationNV; + } else renderbufferStorageMultisampleImplementation = nullptr; + #else + renderbufferStorageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationDefault; + #endif + } +} + +}} diff --git a/src/Magnum/Implementation/FramebufferState.h b/src/Magnum/Implementation/FramebufferState.h index b3556f8b0..9df8a9bb3 100644 --- a/src/Magnum/Implementation/FramebufferState.h +++ b/src/Magnum/Implementation/FramebufferState.h @@ -25,18 +25,34 @@ DEALINGS IN THE SOFTWARE. */ -#include "Magnum/Magnum.h" -#include "Magnum/OpenGL.h" -#include "Magnum/Math/Range.h" +#include +#include + +#include "Magnum/Framebuffer.h" namespace Magnum { namespace Implementation { struct FramebufferState { - constexpr FramebufferState(): readBinding(0), drawBinding(0), renderbufferBinding(0), maxDrawBuffers(0), maxColorAttachments(0), maxRenderbufferSize(0), maxSamples(0) - #ifndef MAGNUM_TARGET_GLES - , maxDualSourceDrawBuffers(0) - #endif - {} + explicit FramebufferState(Context& context, std::vector& extensions); + + GLenum(AbstractFramebuffer::*checkStatusImplementation)(FramebufferTarget); + void(AbstractFramebuffer::*drawBuffersImplementation)(GLsizei, const GLenum*); + void(AbstractFramebuffer::*drawBufferImplementation)(GLenum); + void(AbstractFramebuffer::*readBufferImplementation)(GLenum); + + void(Framebuffer::*renderbufferImplementation)(Framebuffer::BufferAttachment, Renderbuffer&); + #ifndef MAGNUM_TARGET_GLES + void(Framebuffer::*texture1DImplementation)(Framebuffer::BufferAttachment, Texture1D&, GLint); + #endif + void(Framebuffer::*texture2DImplementation)(Framebuffer::BufferAttachment, GLenum, GLuint, GLint); + void(Framebuffer::*texture3DImplementation)(Framebuffer::BufferAttachment, Texture3D&, GLint, GLint); + + void(Renderbuffer::*renderbufferStorageImplementation)(RenderbufferFormat, const Vector2i&); + void(Renderbuffer::*renderbufferStorageMultisampleImplementation)(GLsizei, RenderbufferFormat, const Vector2i&); + + void(*readImplementation)(const Vector2i&, const Vector2i&, ColorFormat, ColorType, std::size_t, GLvoid*); + + FramebufferTarget readTarget, drawTarget; GLuint readBinding, drawBinding, renderbufferBinding; GLint maxDrawBuffers, maxColorAttachments, maxRenderbufferSize, maxSamples; diff --git a/src/Magnum/Implementation/State.cpp b/src/Magnum/Implementation/State.cpp index 62ee567f1..5ff69fd5d 100644 --- a/src/Magnum/Implementation/State.cpp +++ b/src/Magnum/Implementation/State.cpp @@ -53,7 +53,7 @@ State::State(Context& context) { buffer = new BufferState; debug = new DebugState(context, extensions); - framebuffer = new FramebufferState; + framebuffer = new FramebufferState(context, extensions); mesh = new MeshState; renderer = new RendererState; shader = new ShaderState; diff --git a/src/Magnum/Renderbuffer.cpp b/src/Magnum/Renderbuffer.cpp index 12f27a53a..47a99b4bb 100644 --- a/src/Magnum/Renderbuffer.cpp +++ b/src/Magnum/Renderbuffer.cpp @@ -34,14 +34,6 @@ namespace Magnum { -Renderbuffer::StorageImplementation Renderbuffer::storageImplementation = &Renderbuffer::storageImplementationDefault; -Renderbuffer::StorageMultisampleImplementation Renderbuffer::storageMultisampleImplementation = - #ifndef MAGNUM_TARGET_GLES2 - &Renderbuffer::storageMultisampleImplementationDefault; - #else - nullptr; - #endif - Int Renderbuffer::maxSize() { GLint& value = Context::current()->state().framebuffer->maxRenderbufferSize; @@ -94,6 +86,14 @@ Renderbuffer& Renderbuffer::setLabel(const std::string& label) { return *this; } +void Renderbuffer::setStorage(const RenderbufferFormat internalFormat, const Vector2i& size) { + (this->*Context::current()->state().framebuffer->renderbufferStorageImplementation)(internalFormat, size); +} + +void Renderbuffer::setStorageMultisample(const Int samples, const RenderbufferFormat internalFormat, const Vector2i& size) { + (this->*Context::current()->state().framebuffer->renderbufferStorageMultisampleImplementation)(samples, internalFormat, size); +} + void Renderbuffer::bind() { GLuint& binding = Context::current()->state().framebuffer->renderbufferBinding; @@ -103,29 +103,6 @@ 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; - storageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationDSA; - } - #elif !defined(MAGNUM_TARGET_GLES3) - if(context.isExtensionSupported()) { - Debug() << "Renderbuffer: using" << Extensions::GL::ANGLE::framebuffer_multisample::string() << "features"; - - storageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationANGLE; - } else if (context.isExtensionSupported()) { - Debug() << "Renderbuffer: using" << Extensions::GL::NV::framebuffer_multisample::string() << "features"; - - storageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationNV; - } - #else - static_cast(context); - #endif -} - void Renderbuffer::storageImplementationDefault(RenderbufferFormat internalFormat, const Vector2i& size) { bind(); glRenderbufferStorage(GL_RENDERBUFFER, GLenum(internalFormat), size.x(), size.y()); diff --git a/src/Magnum/Renderbuffer.h b/src/Magnum/Renderbuffer.h index 36ae950b8..6bf754d1f 100644 --- a/src/Magnum/Renderbuffer.h +++ b/src/Magnum/Renderbuffer.h @@ -34,6 +34,8 @@ namespace Magnum { +namespace Implementation { struct FramebufferState; } + /** @brief %Renderbuffer @@ -54,7 +56,7 @@ See its documentation for more information. @requires_gl30 %Extension @extension{ARB,framebuffer_object} */ class MAGNUM_EXPORT Renderbuffer: public AbstractObject { - friend class Context; + friend class Implementation::FramebufferState; public: /** @@ -146,9 +148,7 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject { * @see @ref maxSize(), @fn_gl{BindRenderbuffer}, @fn_gl{RenderbufferStorage} * or @fn_gl_extension{NamedRenderbufferStorage,EXT,direct_state_access} */ - void setStorage(RenderbufferFormat internalFormat, const Vector2i& size) { - (this->*storageImplementation)(internalFormat, size); - } + void setStorage(RenderbufferFormat internalFormat, const Vector2i& size); /** * @brief Set multisample renderbuffer storage @@ -166,31 +166,23 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject { * @todo How about @es_extension{APPLE,framebuffer_multisample}? * @todo NaCl has @fn_gl_extension{RenderbufferStorageMultisample,EXT,multisampled_render_to_texture} */ - void setStorageMultisample(Int samples, RenderbufferFormat internalFormat, const Vector2i& size) { - (this->*storageMultisampleImplementation)(samples, internalFormat, size); - } + void setStorageMultisample(Int samples, RenderbufferFormat internalFormat, const Vector2i& size); private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - - typedef void(Renderbuffer::*StorageImplementation)(RenderbufferFormat, const Vector2i&); void MAGNUM_LOCAL storageImplementationDefault(RenderbufferFormat internalFormat, const Vector2i& size); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL storageImplementationDSA(RenderbufferFormat internalFormat, const Vector2i& size); #endif - static StorageImplementation storageImplementation; - typedef void(Renderbuffer::*StorageMultisampleImplementation)(GLsizei, RenderbufferFormat, const Vector2i&); #ifndef MAGNUM_TARGET_GLES2 void MAGNUM_LOCAL storageMultisampleImplementationDefault(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL storageMultisampleImplementationDSA(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); + #endif #else void MAGNUM_LOCAL storageMultisampleImplementationANGLE(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); void MAGNUM_LOCAL storageMultisampleImplementationNV(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); #endif - #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL storageMultisampleImplementationDSA(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); - #endif - static StorageMultisampleImplementation storageMultisampleImplementation; void MAGNUM_LOCAL bind();