From d59297aeeb667ded0e7a81ef13777aef58b85658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 12 Jan 2013 13:42:38 +0100 Subject: [PATCH] Implemented ARB_invalidate_subdata GL 4.3 extension. Framebuffer invalidation is also available in OpenGL ES 3.0 and ES 2.0 using EXT_discard_framebuffer extension. --- src/AbstractFramebuffer.cpp | 21 +++++++++++ src/AbstractFramebuffer.h | 7 ++++ src/AbstractTexture.h | 33 +++++++++++++++++ src/Buffer.h | 26 ++++++++++++++ src/CubeMapTexture.h | 5 +++ src/CubeMapTextureArray.h | 7 ++++ src/DefaultFramebuffer.cpp | 20 +++++++++++ src/DefaultFramebuffer.h | 71 +++++++++++++++++++++++++++++++++++++ src/Framebuffer.cpp | 22 ++++++++++++ src/Framebuffer.h | 55 ++++++++++++++++++++++++++++ src/Texture.h | 26 +++++++++++--- 11 files changed, 288 insertions(+), 5 deletions(-) diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp index 06b86d8e8..3fa25606f 100644 --- a/src/AbstractFramebuffer.cpp +++ b/src/AbstractFramebuffer.cpp @@ -141,6 +141,27 @@ void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Abs } #endif +#ifndef DOXYGEN_GENERATING_OUTPUT +void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attachments) { + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + glInvalidateFramebuffer(GLenum(bindInternal()), count, attachments); + #else + //glDiscardFramebufferEXT(GLenum(bindInternal()), count, attachments); + #endif +} + +void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attachments, const Rectanglei& rectangle) { + /** @todo Re-enable when extension wrangler is available for ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + glInvalidateSubFramebuffer(GLenum(bindInternal()), count, attachments, rectangle.left(), rectangle.bottom(), rectangle.width(), rectangle.height()); + #else + //glDiscardSubFramebufferEXT(GLenum(bindInternal()), count, attachments, rectangle.left(), rectangle.bottom(), rectangle.width(), rectangle.height()); + static_cast(rectangle); + #endif +} +#endif + void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) { #ifndef MAGNUM_TARGET_GLES if(context->isExtensionSupported()) { diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h index f2efec6b1..443d5982b 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -207,6 +207,10 @@ class MAGNUM_EXPORT AbstractFramebuffer { * @brief Clear specified buffers in framebuffer * @param mask Which buffers to clear * + * To improve performance you can also use + * DefaultFramebuffer::invalidate() / Framebuffer::invalidate() instead + * of clearing given buffer if you will not use it anymore or fully + * overwrite it later. * @see Renderer::setClearColor(), Renderer::setClearDepth(), * Renderer::setClearStencil(), @fn_gl{BindFramebuffer}, * @fn_gl{Clear} @@ -261,6 +265,9 @@ class MAGNUM_EXPORT AbstractFramebuffer { 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 Rectanglei& rectangle); + GLuint _id; Rectanglei _viewport; #endif diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index 7c2b96cc8..b4eeb267e 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -1111,6 +1111,21 @@ class MAGNUM_EXPORT AbstractTexture { return this; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Invalidate texture image + * @param level Mip level + * + * @see @ref Texture::invalidateSubImage() "invalidateSubImage()", + * @fn_gl{InvalidateTexImage} + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gl Texture image invalidation is not available in OpenGL ES. + */ + inline void invalidateImage(GLint level) { + glInvalidateTexImage(_id, level); + } + #endif + /** * @brief Generate mipmap * @return Pointer to self (for method chaining) @@ -1233,6 +1248,12 @@ template<> struct AbstractTexture::DataHelper<1> { template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint level, const Math::Vector<1, GLint>& offset, Image* image) { (texture->*subImage1DImplementation)(target, level, offset, image->size(), image->format(), image->type(), image->data()); } + + #ifndef MAGNUM_TARGET_GLES + inline static void invalidateSub(AbstractTexture* texture, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLint>& size) { + glInvalidateTexSubImage(texture->_id, level, offset[0], 0, 0, size[0], 1, 1); + } + #endif }; #endif template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { @@ -1260,6 +1281,12 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint level, const Vector2i& offset, Image* image) { (texture->*subImage2DImplementation)(target, level, offset, Vector2i(image->size(), 1), image->format(), image->type(), image->data()); } + + #ifndef MAGNUM_TARGET_GLES + inline static void invalidateSub(AbstractTexture* texture, GLint level, const Vector2i& offset, const Vector2i& size) { + glInvalidateTexSubImage(texture->_id, level, offset.x(), offset.y(), 0, size.x(), size.y(), 1); + } + #endif }; template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { enum class Target: GLenum { @@ -1286,6 +1313,12 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint level, const Vector3i& offset, Image* image) { (texture->*subImage3DImplementation)(target, level, offset, Vector3i(image->size(), 1), image->format(), image->type(), image->data()); } + + #ifndef MAGNUM_TARGET_GLES + inline static void invalidateSub(AbstractTexture* texture, GLint level, const Vector3i& offset, const Vector3i& size) { + glInvalidateTexSubImage(texture->_id, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z()); + } + #endif }; #endif diff --git a/src/Buffer.h b/src/Buffer.h index 215bea7b2..07a93271e 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -580,6 +580,32 @@ class MAGNUM_EXPORT Buffer { setSubData(offset, data.size()*sizeof(T), data.data()); } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Invalidate buffer data + * + * @see @fn_gl{InvalidateBufferData} + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gl Buffer data invalidation is not available in OpenGL ES. + */ + inline void invalidateData() { + glInvalidateBufferData(_id); + } + + /** + * @brief Invalidate buffer subdata + * @param offset Offset into the buffer + * @param length Length of the invalidated range + * + * @see @fn_gl{InvalidateBufferData} + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gl Buffer data invalidation is not available in OpenGL ES. + */ + inline void invalidateSubData(GLintptr offset, GLsizeiptr length) { + glInvalidateBufferSubData(_id, offset, length); + } + #endif + /** * @brief Map buffer to client memory * @param access Access diff --git a/src/CubeMapTexture.h b/src/CubeMapTexture.h index f2e9e60ee..ae3d7a51b 100644 --- a/src/CubeMapTexture.h +++ b/src/CubeMapTexture.h @@ -127,6 +127,11 @@ class CubeMapTexture: public AbstractTexture { return this; } + /** @copydoc Texture::invalidateSubImage() */ + inline void invalidateSubImage(GLint level, const Vector2i& offset, const Vector2i& size) { + DataHelper<2>::invalidateSub(this, level, offset, size); + } + /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT inline CubeMapTexture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel) { diff --git a/src/CubeMapTextureArray.h b/src/CubeMapTextureArray.h index 9c8270233..480b3dbd1 100644 --- a/src/CubeMapTextureArray.h +++ b/src/CubeMapTextureArray.h @@ -151,6 +151,13 @@ class CubeMapTextureArray: public AbstractTexture { return this; } + #ifndef MAGNUM_TARGET_GLES + /** @copydoc Texture::invalidateSubImage() */ + inline void invalidateSubImage(GLint level, const Vector2i& offset, const Vector2i& size) { + DataHelper<2>::invalidateSub(this, level, offset, size); + } + #endif + /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT inline CubeMapTextureArray* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel) { diff --git a/src/DefaultFramebuffer.cpp b/src/DefaultFramebuffer.cpp index a8b0649c4..b8a940a33 100644 --- a/src/DefaultFramebuffer.cpp +++ b/src/DefaultFramebuffer.cpp @@ -44,6 +44,26 @@ void DefaultFramebuffer::mapForDraw(std::initializer_list attachments) { + GLenum* _attachments = new GLenum[attachments.size()]; + for(std::size_t i = 0; i != attachments.size(); ++i) + _attachments[i] = GLenum(*(attachments.begin()+i)); + + invalidateImplementation(attachments.size(), _attachments); + + delete _attachments; +} + +void DefaultFramebuffer::invalidate(std::initializer_list attachments, const Rectanglei& rectangle) { + GLenum* _attachments = new GLenum[attachments.size()]; + for(std::size_t i = 0; i != attachments.size(); ++i) + _attachments[i] = GLenum(*(attachments.begin()+i)); + + invalidateImplementation(attachments.size(), _attachments, rectangle); + + delete _attachments; +} + void DefaultFramebuffer::initializeContextBasedFunctionality(Context* context) { Implementation::FramebufferState* state = context->state()->framebuffer; diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h index 912eb73dc..d2df00bf6 100644 --- a/src/DefaultFramebuffer.h +++ b/src/DefaultFramebuffer.h @@ -203,6 +203,50 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { #endif }; + /** + * @brief Invalidation attachment + * + * @see invalidate() + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + */ + enum class InvalidationAttachment: GLenum { + #ifndef MAGNUM_TARGET_GLES + /** + * Invalidate front left buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontLeft = GL_FRONT_LEFT, + + /** + * Invalidate front right buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontRight = GL_FRONT_RIGHT, + + /** + * Invalidate back left buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackLeft = GL_BACK_LEFT, + + /** + * Invalidate back right buffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackRight = GL_BACK_RIGHT, + #endif + + /** Invalidate color buffer. */ + Color = GL_COLOR, + + /** Invalidate depth bufer. */ + Depth = GL_DEPTH, + + /** Invalidate stencil buffer. */ + Stencil = GL_STENCIL + }; + explicit MAGNUM_LOCAL DefaultFramebuffer(); #ifndef MAGNUM_TARGET_GLES2 @@ -263,6 +307,33 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { (this->*readBufferImplementation)(static_cast(attachment)); } + /** + * @brief Invalidate framebuffer + * @param attachments Attachments to invalidate + * + * The framebuffer is bound to some target before the operation, if + * not already. + * @see @fn_gl{InvalidateFramebuffer} or @fn_gles_extension{DiscardFramebuffer,EXT,discard_framebuffer} + * on OpenGL ES 2.0 + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + */ + void invalidate(std::initializer_list attachments); + + /** + * @brief Invalidate framebuffer rectangle + * @param attachments Attachments to invalidate + * @param rectangle %Rectangle to invalidate + * + * The framebuffer is bound to some target before the operation, if + * not already. + * @see @fn_gl{InvalidateSubFramebuffer} or @fn_gles_extension{DiscardSubFramebuffer,EXT,discard_framebuffer} + * on OpenGL ES 2.0 + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + */ + void invalidate(std::initializer_list attachments, const Rectanglei& rectangle); + private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); }; diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp index 36508570f..056a08cd9 100644 --- a/src/Framebuffer.cpp +++ b/src/Framebuffer.cpp @@ -40,6 +40,8 @@ const Framebuffer::BufferAttachment Framebuffer::BufferAttachment::Stencil = Fra #ifndef MAGNUM_TARGET_GLES2 const Framebuffer::BufferAttachment Framebuffer::BufferAttachment::DepthStencil = Framebuffer::BufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT); #endif +const Framebuffer::InvalidationAttachment Framebuffer::InvalidationAttachment::Depth = Framebuffer::InvalidationAttachment(GL_DEPTH_ATTACHMENT); +const Framebuffer::InvalidationAttachment Framebuffer::InvalidationAttachment::Stencil = Framebuffer::InvalidationAttachment(GL_STENCIL_ATTACHMENT); Framebuffer::Framebuffer(const Rectanglei& viewport) { _viewport = viewport; @@ -72,6 +74,26 @@ void Framebuffer::mapForDraw(std::initializer_list attachments) { + GLenum* _attachments = new GLenum[attachments.size()]; + for(std::size_t i = 0; i != attachments.size(); ++i) + _attachments[i] = GLenum(*(attachments.begin()+i)); + + invalidateImplementation(attachments.size(), _attachments); + + delete _attachments; +} + +void Framebuffer::invalidate(std::initializer_list attachments, const Rectanglei& rectangle) { + GLenum* _attachments = new GLenum[attachments.size()]; + for(std::size_t i = 0; i != attachments.size(); ++i) + _attachments[i] = GLenum(*(attachments.begin()+i)); + + invalidateImplementation(attachments.size(), _attachments, rectangle); + + delete _attachments; +} + void Framebuffer::attachTexture2D(BufferAttachment attachment, Texture2D* texture, GLint mipLevel) { /** @todo Check for texture target compatibility */ (this->*texture2DImplementation)(attachment, GLenum(texture->target()), texture->id(), mipLevel); diff --git a/src/Framebuffer.h b/src/Framebuffer.h index 4cdb162d2..2bb2548ef 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -175,6 +175,34 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { GLenum attachment; }; + /** + * @brief Invalidation attachment + * + * @see invalidate() + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + */ + class InvalidationAttachment { + public: + /** @brief Invalidate depth buffer */ + static const InvalidationAttachment Depth; + + /** @brief Invalidate stencil buffer */ + static const InvalidationAttachment Stencil; + + /** @brief Invalidate color buffer */ + inline constexpr /*implicit*/ InvalidationAttachment(Framebuffer::ColorAttachment attachment): attachment(GLenum(attachment)) {} + + #ifndef DOXYGEN_GENERATING_OUTPUT + inline constexpr explicit operator GLenum() const { return attachment; } + #endif + + private: + inline constexpr explicit InvalidationAttachment(GLenum attachment): attachment(attachment) {} + + GLenum attachment; + }; + /** * @brief Constructor * @@ -230,6 +258,33 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { (this->*drawBufferImplementation)(GLenum(attachment)); } + /** + * @brief Invalidate framebuffer + * @param attachments Attachments to invalidate + * + * The framebuffer is bound to some target before the operation, if + * not already. + * @see @fn_gl{InvalidateFramebuffer} or @fn_gles_extension{DiscardFramebuffer,EXT,discard_framebuffer} + * on OpenGL ES 2.0 + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + */ + void invalidate(std::initializer_list attachments); + + /** + * @brief Invalidate framebuffer rectangle + * @param attachments Attachments to invalidate + * @param rectangle %Rectangle to invalidate + * + * The framebuffer is bound to some target before the operation, if + * not already. + * @see @fn_gl{InvalidateSubFramebuffer} or @fn_gles_extension{DiscardSubFramebuffer,EXT,discard_framebuffer} + * on OpenGL ES 2.0 + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + */ + void invalidate(std::initializer_list attachments, const Rectanglei& rectangle); + /** * @brief Map given color attachment for reading * @param attachment Color attachment diff --git a/src/Texture.h b/src/Texture.h index e6013c716..96a6c9551 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -209,8 +209,8 @@ template class Texture: public AbstractTexture { * * If @extension{EXT,direct_state_access} is not available, the * texture is bound to some layer before the operation. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexImage1D}/ - * @fn_gl{TexImage2D}/@fn_gl{TexImage3D} or + * @see setSubImage(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{TexImage1D}/@fn_gl{TexImage2D}/@fn_gl{TexImage3D} or * @fn_gl_extension{TextureImage1D,EXT,direct_state_access}/ * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureImage3D,EXT,direct_state_access} @@ -239,9 +239,9 @@ template class Texture: public AbstractTexture { * * If @extension{EXT,direct_state_access} is not available, the * texture is bound to some layer before the operation. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexSubImage1D}/ - * @fn_gl{TexSubImage2D}/@fn_gl{TexSubImage3D} or - * @fn_gl_extension{TextureSubImage1D,EXT,direct_state_access}/ + * @see setImage(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{TexSubImage1D}/@fn_gl{TexSubImage2D}/@fn_gl{TexSubImage3D} + * or @fn_gl_extension{TextureSubImage1D,EXT,direct_state_access}/ * @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureSubImage3D,EXT,direct_state_access} */ @@ -250,6 +250,22 @@ template class Texture: public AbstractTexture { return this; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Invalidate texture subimage + * @param level Mip level + * @param offset Offset into the texture + * @param size Size of invalidated data + * + * @see invalidateImage(), @fn_gl{InvalidateTexSubImage} + * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} + * @requires_gl Texture image invalidation is not available in OpenGL ES. + */ + inline void invalidateSubImage(GLint level, const typename DimensionTraits::VectorType& offset, const typename DimensionTraits::VectorType& size) { + DataHelper::invalidateSub(this, level, offset, size); + } + #endif + /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT inline Texture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel) {