From b5a6036d48ba96f9c0fc895ea34bfbcf88b89405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 11 Jun 2013 17:50:20 +0200 Subject: [PATCH] Use proper ARB_framebuffer_object extension. Separated EXT_framebuffer_object, EXT_framebuffer_blit, EXT_framebuffer_multisample and EXT_packed_depth_stencil don't have the same functionality as ARB_framebuffer_object (e.g. missing GL_FRAMEBUFFER_UNDEFINED in glCheckFramebufferStatus()) and separated read/draw binding is only in EXT_framebuffer_blit, which complicates the internals. Checked with Mesa 8/9 and OpenGL 2.1, current one has ARB_framebuffer_object and also all these four, Mesa 7.7 didn't have EXT_framebuffer_multisample, but that's a long time ago, so not supporting these separate extensions shouldn't be an issue. The problem with unavailable separate binding points remains on OpenGL ES 2.0, there are three different extensions bringing that functionality, thus the code managing the available binding points remains there. --- src/AbstractFramebuffer.cpp | 66 +++++++++++++++++++++++++++++----- src/AbstractFramebuffer.h | 71 +++++++++++++++++++------------------ src/AbstractTexture.h | 2 +- src/Context.cpp | 9 +---- src/Extensions.h | 7 ++-- src/Framebuffer.h | 2 +- src/ImageFormat.h | 4 +-- src/Renderbuffer.h | 3 +- src/RenderbufferFormat.h | 2 +- src/Renderer.h | 2 +- src/TextureFormat.h | 2 +- 11 files changed, 106 insertions(+), 64 deletions(-) diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp index bc9b20eb5..73de50537 100644 --- a/src/AbstractFramebuffer.cpp +++ b/src/AbstractFramebuffer.cpp @@ -40,8 +40,10 @@ AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersI 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 AbstractFramebuffer::~AbstractFramebuffer() {} @@ -81,10 +83,15 @@ FramebufferTarget AbstractFramebuffer::bindInternal() { /* Or bind it, if not already */ state->readBinding = _id; - if(readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id; + #ifndef MAGNUM_TARGET_GLES2 + glBindFramebuffer(GLenum(FramebufferTarget::Read), _id); + return FramebufferTarget::Read; + #else + if(readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id; glBindFramebuffer(GLenum(readTarget), _id); return readTarget; + #endif } void AbstractFramebuffer::blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& sourceRectangle, const Rectanglei& destinationRectangle, FramebufferBlitMask mask, FramebufferBlitFilter filter) { @@ -126,12 +133,20 @@ void AbstractFramebuffer::setViewportInternal() { } void AbstractFramebuffer::clear(FramebufferClearMask mask) { + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Draw); + #else bindInternal(drawTarget); + #endif glClear(static_cast(mask)); } void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Image2D* image) { + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Read); + #else bindInternal(readTarget); + #endif const std::size_t dataSize = image->pixelSize()*size.product(); char* const data = new char[dataSize]; readImplementation(offset, size, image->format(), image->type(), dataSize, data); @@ -140,7 +155,11 @@ void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Ima #ifndef MAGNUM_TARGET_GLES2 void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, BufferImage2D* image, Buffer::Usage usage) { + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Read); + #else bindInternal(readTarget); + #endif /* If the buffer doesn't have sufficient size, resize it */ /** @todo Explicitly reset also when buffer usage changes */ if(image->size() != size) @@ -177,13 +196,6 @@ void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attach void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) { #ifndef MAGNUM_TARGET_GLES - if(context->isExtensionSupported()) { - Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::framebuffer_blit::string() << "features"; - - readTarget = FramebufferTarget::Read; - drawTarget = FramebufferTarget::Draw; - } - if(context->isExtensionSupported()) { Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; @@ -193,6 +205,32 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) } #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_GLES3 #ifndef MAGNUM_TARGET_GLES if(context->isExtensionSupported()) @@ -219,7 +257,11 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) void AbstractFramebuffer::drawBuffersImplementationDefault(GLsizei count, const GLenum* buffers) { /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Draw); + #else bindInternal(drawTarget); + #endif glDrawBuffers(count, buffers); #else static_cast(count); @@ -236,7 +278,11 @@ void AbstractFramebuffer::drawBuffersImplementationDSA(GLsizei count, const GLen void AbstractFramebuffer::drawBufferImplementationDefault(GLenum buffer) { /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Draw); + #else bindInternal(drawTarget); + #endif #ifndef MAGNUM_TARGET_GLES3 glDrawBuffer(buffer); #else @@ -256,7 +302,11 @@ void AbstractFramebuffer::drawBufferImplementationDSA(GLenum buffer) { void AbstractFramebuffer::readBufferImplementationDefault(GLenum buffer) { /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Read); + #else bindInternal(readTarget); + #endif glReadBuffer(buffer); #else static_cast(buffer); diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h index 3e7916dda..cfa47d6be 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -36,10 +36,10 @@ namespace Magnum { /** - * @brief Mask for framebuffer clearing - * - * @see AbstractFramebuffer, FramebufferClearMask - */ +@brief Mask for framebuffer clearing + +@see AbstractFramebuffer, FramebufferClearMask +*/ enum class FramebufferClear: GLbitfield { Color = GL_COLOR_BUFFER_BIT, /**< Color */ Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */ @@ -47,21 +47,21 @@ enum class FramebufferClear: GLbitfield { }; /** - * @brief Mask for clearing - * - * @see AbstractFramebuffer::clear() - */ +@brief Mask for clearing + +@see AbstractFramebuffer::clear() +*/ typedef Containers::EnumSet FramebufferClearMask; /** - * @brief Mask for framebuffer blitting - * - * @see AbstractFramebuffer, FramebufferBlitMask - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or - * @es_extension{NV,framebuffer_blit} - */ +@brief Mask for framebuffer blitting + +@see AbstractFramebuffer, FramebufferBlitMask +@requires_gl30 %Extension @extension{ARB,framebuffer_object} +@requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or + @es_extension{NV,framebuffer_blit} +*/ enum class FramebufferBlit: GLbitfield { ColorBuffer = GL_COLOR_BUFFER_BIT, /**< Color buffer */ DepthBuffer = GL_DEPTH_BUFFER_BIT, /**< Depth buffer */ @@ -69,36 +69,38 @@ enum class FramebufferBlit: GLbitfield { }; /** - * @brief Mask for framebuffer blitting - * - * @see AbstractFramebuffer::blit() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or - * @es_extension{NV,framebuffer_blit} - */ +@brief Mask for framebuffer blitting + +@see AbstractFramebuffer::blit() +@requires_gl30 %Extension @extension{ARB,framebuffer_object} +@requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or + @es_extension{NV,framebuffer_blit} +*/ typedef Containers::EnumSet FramebufferBlitMask; /** - * @brief %Framebuffer blit filtering - * - * @see AbstractFramebuffer::blit() - */ +@brief %Framebuffer blit filtering + +@see AbstractFramebuffer::blit() +@requires_gl30 %Extension @extension{ARB,framebuffer_object} +@requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or + @es_extension{NV,framebuffer_blit} +*/ enum class FramebufferBlitFilter: GLenum { Nearest = GL_NEAREST, /**< Nearest neighbor filtering */ Linear = GL_LINEAR /**< Linear interpolation filtering */ }; /** - * @brief Target for binding framebuffer - * - * @see DefaultFramebuffer::bind(), Framebuffer::bind() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - */ +@brief Target for binding framebuffer + +@see DefaultFramebuffer::bind(), Framebuffer::bind() +@requires_gl30 %Extension @extension{ARB,framebuffer_object} +*/ enum class FramebufferTarget: GLenum { /** * For reading only. - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}, * @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit} */ @@ -110,7 +112,6 @@ enum class FramebufferTarget: GLenum { /** * For drawing only. - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}, * @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit} */ @@ -163,7 +164,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { * Framebuffer::mapForDraw() for specifying particular buffers for * blitting operation. * @see @fn_gl{BlitFramebuffer} - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or * @es_extension{NV,framebuffer_blit} */ @@ -182,7 +182,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { * @ref FramebufferBlitFilter "FramebufferBlitFilter::Nearest" * filtering is used by default. * @see @fn_gl{BlitFramebuffer} - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or * @es_extension{NV,framebuffer_blit} */ @@ -272,8 +271,10 @@ 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 void(AbstractFramebuffer::*DrawBuffersImplementation)(GLsizei, const GLenum*); static MAGNUM_LOCAL DrawBuffersImplementation drawBuffersImplementation; diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index b447d1f6f..87179e638 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -253,7 +253,7 @@ class MAGNUM_EXPORT AbstractTexture { * @see setMinificationFilter(), @fn_gl{ActiveTexture}, * @fn_gl{BindTexture} and @fn_gl{GenerateMipmap} or * @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access} - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} */ AbstractTexture* generateMipmap(); diff --git a/src/Context.cpp b/src/Context.cpp index 327b6ea22..2c1596aa3 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -97,14 +97,7 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,ARB,texture_float), // done _extension(GL,ARB,depth_buffer_float), // done _extension(GL,ARB,texture_rg), // done - /** - * @todo Remove as it doesn't have the same functionality present in - * GL 3.0 and replace with ARB_framebuffer_object? - */ - _extension(GL,EXT,framebuffer_object), - _extension(GL,EXT,packed_depth_stencil), // done - _extension(GL,EXT,framebuffer_blit), // done - _extension(GL,EXT,framebuffer_multisample), + _extension(GL,ARB,framebuffer_object), _extension(GL,EXT,gpu_shader4), _extension(GL,EXT,packed_float), // done _extension(GL,EXT,texture_array), diff --git a/src/Extensions.h b/src/Extensions.h index a7980afc0..309c7b080 100644 --- a/src/Extensions.h +++ b/src/Extensions.h @@ -76,6 +76,7 @@ namespace GL { _extension(GL,ARB,texture_float, GL210, GL300) // #41 _extension(GL,ARB,depth_buffer_float, GL210, GL300) // #43 _extension(GL,ARB,draw_instanced, GL210, GL310) // #44 + _extension(GL,ARB,framebuffer_object, GL210, GL300) // #45 _extension(GL,ARB,geometry_shader4, GL210, GL320) // #47 _extension(GL,ARB,instanced_arrays, GL210, GL330) // #49 _extension(GL,ARB,map_buffer_range, GL210, GL300) // #50 @@ -154,10 +155,8 @@ namespace GL { _extension(GL,ARB,texture_storage_multisample, GL210, GL430) // #141 } namespace EXT { _extension(GL,EXT,texture_filter_anisotropic, GL210, None) // #187 - _extension(GL,EXT,framebuffer_object, GL210, GL300) // #310 - _extension(GL,EXT,packed_depth_stencil, GL210, GL300) // #312 - _extension(GL,EXT,framebuffer_blit, GL210, GL300) // #316 - _extension(GL,EXT,framebuffer_multisample, GL210, GL300) // #317 + /* EXT_framebuffer_object, EXT_packed_depth_stencil, EXT_framebuffer_blit, + EXT_framebuffer_multisample replaced with ARB_framebuffer_object */ _extension(GL,EXT,gpu_shader4, GL210, GL300) // #326 _extension(GL,EXT,packed_float, GL210, GL300) // #328 _extension(GL,EXT,texture_array, GL210, GL300) // #329 diff --git a/src/Framebuffer.h b/src/Framebuffer.h index e839d7488..975f96b14 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -94,7 +94,7 @@ 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} +@requires_gl30 %Extension @extension{ARB,framebuffer_object} */ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { friend class Context; diff --git a/src/ImageFormat.h b/src/ImageFormat.h index 9219dcc0a..2a358eca7 100644 --- a/src/ImageFormat.h +++ b/src/ImageFormat.h @@ -236,7 +236,7 @@ enum class ImageFormat: GLenum { /** * Depth and stencil. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}. * @requires_es_extension For framebuffer reading only, extension * @es_extension2{NV,read_depth_stencil,GL_NV_read_depth_stencil}. @@ -446,7 +446,7 @@ enum class ImageType: GLenum { /** * Unsigned int, depth component 24bit, stencil index 8bit. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}. */ #ifndef MAGNUM_TARGET_GLES2 diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index f35ac0bac..b4b425386 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -49,7 +49,7 @@ 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} +@requires_gl30 %Extension @extension{ARB,framebuffer_object} */ class MAGNUM_EXPORT Renderbuffer { friend class Context; @@ -105,7 +105,6 @@ class MAGNUM_EXPORT Renderbuffer { * operation. * @see @fn_gl{BindRenderbuffer}, @fn_gl{RenderbufferStorage} or * @fn_gl_extension{NamedRenderbufferStorage,EXT,direct_state_access} - * @requires_gl30 %Extension @extension{EXT,framebuffer_multisample} * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_multisample} * or @es_extension{NV,framebuffer_multisample} * @todo How about @es_extension{APPLE,framebuffer_multisample}? diff --git a/src/RenderbufferFormat.h b/src/RenderbufferFormat.h index f0d3de92f..fdb935ba1 100644 --- a/src/RenderbufferFormat.h +++ b/src/RenderbufferFormat.h @@ -36,6 +36,7 @@ namespace Magnum { @brief Internal renderbuffer format @see Renderbuffer +@requires_gl30 %Extension @extension{ARB,framebuffer_object} @todo RGB, RGB8 ES only (ES3 + @es_extension{OES,rgb8_rgba8}) */ enum class RenderbufferFormat: GLenum { @@ -481,7 +482,6 @@ enum class RenderbufferFormat: GLenum { /** * 24bit depth and 8bit stencil component. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} */ #ifdef MAGNUM_TARGET_GLES2 diff --git a/src/Renderer.h b/src/Renderer.h index 0053c78a3..e66e8311b 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -892,7 +892,7 @@ class MAGNUM_EXPORT Renderer { /** * The framebuffer object is not complete. * @see AbstractFramebuffer::checkStatus() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} */ InvalidFramebufferOperation = GL_INVALID_FRAMEBUFFER_OPERATION, diff --git a/src/TextureFormat.h b/src/TextureFormat.h index 2344cd7d7..86d68f36e 100644 --- a/src/TextureFormat.h +++ b/src/TextureFormat.h @@ -823,7 +823,7 @@ enum class TextureFormat: GLenum { /** * 24bit depth and 8bit stencil component. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} and * (@es_extension{OES,required_internalformat} or * (@es_extension{EXT,texture_storage} and @es_extension{ANGLE,depth_texture}))