From 35a918d0501919cb41f78bd0cd446055b5d61198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 12 Jan 2013 16:11:52 +0100 Subject: [PATCH] Extension-aware Buffer and *Texture data invalidation. If ARB_invalidate_subdata is not available, these functions do nothing, instead of crashing on null pointer dereference. It results in more convenient usage, enabling users to call them whenever they want, improving performance on implementations which supports that. --- src/AbstractTexture.cpp | 26 +++++++++++++++++++++++++ src/AbstractTexture.h | 40 +++++++++++++++++++++++++-------------- src/Buffer.cpp | 25 ++++++++++++++++++++++++ src/Buffer.h | 38 +++++++++++++++++++++++++++++-------- src/CubeMapTexture.h | 7 +++---- src/CubeMapTextureArray.h | 7 +++---- src/Texture.h | 6 ++---- 7 files changed, 115 insertions(+), 34 deletions(-) diff --git a/src/AbstractTexture.cpp b/src/AbstractTexture.cpp index 6f07fd02e..75530006a 100644 --- a/src/AbstractTexture.cpp +++ b/src/AbstractTexture.cpp @@ -49,6 +49,9 @@ AbstractTexture::SubImage2DImplementation AbstractTexture::subImage2DImplementat AbstractTexture::SubImage3DImplementation AbstractTexture::subImage3DImplementation = &AbstractTexture::subImageImplementationDefault; +AbstractTexture::InvalidateImplementation AbstractTexture::invalidateImplementation = &AbstractTexture::invalidateImplementationNoOp; +AbstractTexture::InvalidateSubImplementation AbstractTexture::invalidateSubImplementation = &AbstractTexture::invalidateSubImplementationNoOp; + #ifndef DOXYGEN_GENERATING_OUTPUT /* Check correctness of binary OR in setMinificationFilter(). If nobody fucks @@ -213,6 +216,13 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) { subImage2DImplementation = &AbstractTexture::subImageImplementationDSA; subImage3DImplementation = &AbstractTexture::subImageImplementationDSA; } + + if(context->isExtensionSupported()) { + Debug() << "AbstractTexture: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features"; + + invalidateImplementation = &AbstractTexture::invalidateImplementationARB; + invalidateSubImplementation = &AbstractTexture::invalidateSubImplementationARB; + } #endif } @@ -335,6 +345,22 @@ void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, cons } #endif +void AbstractTexture::invalidateImplementationNoOp(GLint) {} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::invalidateImplementationARB(GLint level) { + glInvalidateTexImage(_id, level); +} +#endif + +void AbstractTexture::invalidateSubImplementationNoOp(GLint, const Vector3i&, const Vector3i&) {} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::invalidateSubImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size) { + glInvalidateTexSubImage(_id, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z()); +} +#endif + #ifndef DOXYGEN_GENERATING_OUTPUT void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture* texture, const Array2D& wrapping) { #ifndef MAGNUM_TARGET_GLES diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index c13cc1230..d8021bf78 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -53,6 +53,12 @@ dedicated layers, not occupied by other textures. Always fully configure the texture before setting the texture data, so OpenGL can optimize the data to match your settings. +You can use functions invalidateImage() and @ref Texture::invalidateSubImage() "invalidateSubImage()" +if you don't need texture data anymore to avoid unnecessary memory operations +performed by OpenGL in order to preserve the data. If running on OpenGL ES or +extension @extension{ARB,invalidate_subdata} is not available, these functions +do nothing. + @todo Add glPixelStore encapsulation @todo Texture copying @todo Move constructor/assignment - how to avoid creation of empty texture and @@ -1111,20 +1117,18 @@ class MAGNUM_EXPORT AbstractTexture { return this; } - #ifndef MAGNUM_TARGET_GLES /** * @brief Invalidate texture image * @param level Mip level * + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * is not available, this function does nothing. * @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); + (this->*invalidateImplementation)(level); } - #endif /** * @brief Generate mipmap @@ -1230,6 +1234,20 @@ class MAGNUM_EXPORT AbstractTexture { #endif static SubImage3DImplementation subImage3DImplementation; + typedef void(AbstractTexture::*InvalidateImplementation)(GLint); + void MAGNUM_LOCAL invalidateImplementationNoOp(GLint level); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL invalidateImplementationARB(GLint level); + #endif + static InvalidateImplementation invalidateImplementation; + + typedef void(AbstractTexture::*InvalidateSubImplementation)(GLint, const Vector3i&, const Vector3i&); + void MAGNUM_LOCAL invalidateSubImplementationNoOp(GLint level, const Vector3i& offset, const Vector3i& size); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL invalidateSubImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size); + #endif + static InvalidateSubImplementation invalidateSubImplementation; + void MAGNUM_LOCAL destroy(); void MAGNUM_LOCAL move(); @@ -1257,11 +1275,9 @@ template<> struct AbstractTexture::DataHelper<1> { (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); + (texture->*invalidateSubImplementation)(level, {offset[0], 0, 0}, {size[0], 1, 1}); } - #endif }; #endif template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { @@ -1290,11 +1306,9 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { (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); + (texture->*invalidateSubImplementation)(level, {offset, 0}, {size, 1}); } - #endif }; template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { enum class Target: GLenum { @@ -1322,11 +1336,9 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { (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()); + (texture->*invalidateSubImplementation)(level, offset, size); } - #endif }; #endif diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 524a7b815..f37079450 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -29,6 +29,8 @@ Buffer::CopyImplementation Buffer::copyImplementation = &Buffer::copyImplementat #endif Buffer::SetDataImplementation Buffer::setDataImplementation = &Buffer::setDataImplementationDefault; Buffer::SetSubDataImplementation Buffer::setSubDataImplementation = &Buffer::setSubDataImplementationDefault; +Buffer::InvalidateImplementation Buffer::invalidateImplementation = &Buffer::invalidateImplementationNoOp; +Buffer::InvalidateSubImplementation Buffer::invalidateSubImplementation = &Buffer::invalidateSubImplementationNoOp; Buffer::MapImplementation Buffer::mapImplementation = &Buffer::mapImplementationDefault; Buffer::MapRangeImplementation Buffer::mapRangeImplementation = &Buffer::mapRangeImplementationDefault; Buffer::FlushMappedRangeImplementation Buffer::flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDefault; @@ -47,6 +49,13 @@ void Buffer::initializeContextBasedFunctionality(Context* context) { flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDSA; unmapImplementation = &Buffer::unmapImplementationDSA; } + + if(context->isExtensionSupported()) { + Debug() << "Buffer: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features"; + + invalidateImplementation = &Buffer::invalidateImplementationARB; + invalidateSubImplementation = &Buffer::invalidateSubImplementationARB; + } #else static_cast(context); #endif @@ -122,6 +131,22 @@ void Buffer::setSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, const } #endif +void Buffer::invalidateImplementationNoOp() {} + +#ifndef MAGNUM_TARGET_GLES +void Buffer::invalidateImplementationARB() { + glInvalidateBufferData(_id); +} +#endif + +void Buffer::invalidateSubImplementationNoOp(GLintptr, GLsizeiptr) {} + +#ifndef MAGNUM_TARGET_GLES +void Buffer::invalidateSubImplementationARB(GLintptr offset, GLsizeiptr length) { + glInvalidateBufferSubData(_id, offset, length); +} +#endif + void* Buffer::mapImplementationDefault(MapAccess access) { /** @todo Re-enable when extension wrangler is available for ES */ #ifndef MAGNUM_TARGET_GLES diff --git a/src/Buffer.h b/src/Buffer.h index 07a93271e..a02d20088 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -102,6 +102,12 @@ copy(), setData(), setSubData(), map(), flushMappedRange() and unmap() use DSA functions to avoid unnecessary calls to @fn_gl{BindBuffer}. See their respective documentation for more information. +You can use functions invalidateData() and invalidateSubData() if you don't +need buffer data anymore to avoid unnecessary memory operations performed by +OpenGL in order to preserve the data. If running on OpenGL ES or extension +@extension{ARB,invalidate_subdata} is not available, these functions do +nothing. + @todo Support for AMD's query buffer (@extension{AMD,query_buffer_object}) @todo BindBufferRange/BindBufferOffset/BindBufferBase for transform feedback (3.0, @extension{EXT,transform_feedback}) */ @@ -363,6 +369,7 @@ class MAGNUM_EXPORT Buffer { /** * Previous contents of the entire buffer may be discarded. May * not be used in combination with @ref MapFlag "MapFlag::Read". + * @see invalidateData() */ #ifndef MAGNUM_TARGET_GLES2 InvalidateBuffer = GL_MAP_INVALIDATE_BUFFER_BIT, @@ -373,6 +380,7 @@ class MAGNUM_EXPORT Buffer { /** * Previous contents of mapped range may be discarded. May not * be used in combination with @ref MapFlag "MapFlag::Read". + * @see invalidateSubData() */ #ifndef MAGNUM_TARGET_GLES2 InvalidateRange = GL_MAP_INVALIDATE_RANGE_BIT, @@ -584,12 +592,12 @@ class MAGNUM_EXPORT Buffer { /** * @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. + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * is not available, this function does nothing. + * @see @ref MapFlag "MapFlag::InvalidateBuffer", @fn_gl{InvalidateBufferData} */ inline void invalidateData() { - glInvalidateBufferData(_id); + (this->*invalidateImplementation)(); } /** @@ -597,12 +605,12 @@ class MAGNUM_EXPORT Buffer { * @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. + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * is not available, this function does nothing. + * @see @ref MapFlag "MapFlag::InvalidateRange", @fn_gl{InvalidateBufferData} */ inline void invalidateSubData(GLintptr offset, GLsizeiptr length) { - glInvalidateBufferSubData(_id, offset, length); + (this->*invalidateSubImplementation)(offset, length); } #endif @@ -714,6 +722,20 @@ class MAGNUM_EXPORT Buffer { #endif static SetSubDataImplementation setSubDataImplementation; + typedef void(Buffer::*InvalidateImplementation)(); + void MAGNUM_LOCAL invalidateImplementationNoOp(); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL invalidateImplementationARB(); + #endif + static InvalidateImplementation invalidateImplementation; + + typedef void(Buffer::*InvalidateSubImplementation)(GLintptr, GLsizeiptr); + void MAGNUM_LOCAL invalidateSubImplementationNoOp(GLintptr offset, GLsizeiptr length); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL invalidateSubImplementationARB(GLintptr offset, GLsizeiptr length); + #endif + static InvalidateSubImplementation invalidateSubImplementation; + typedef void*(Buffer::*MapImplementation)(MapAccess); void MAGNUM_LOCAL * mapImplementationDefault(MapAccess access); #ifndef MAGNUM_TARGET_GLES diff --git a/src/CubeMapTexture.h b/src/CubeMapTexture.h index b9dacaa8d..0c7270520 100644 --- a/src/CubeMapTexture.h +++ b/src/CubeMapTexture.h @@ -127,7 +127,6 @@ class CubeMapTexture: public AbstractTexture { return this; } - #ifndef MAGNUM_TARGET_GLES /** * @brief Invalidate texture subimage * @param level Mip level @@ -137,14 +136,14 @@ class CubeMapTexture: public AbstractTexture { * Z coordinate is equivalent to number of texture face, i.e. * @ref Coordinate "Coordinate::PositiveX" is `0` and so on, in the * same order as in the enum. + * + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * is not available, this function does nothing. * @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 Vector3i& offset, const Vector3i& size) { DataHelper<3>::invalidateSub(this, level, offset, size); } - #endif /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT diff --git a/src/CubeMapTextureArray.h b/src/CubeMapTextureArray.h index 80e42a171..15b95c030 100644 --- a/src/CubeMapTextureArray.h +++ b/src/CubeMapTextureArray.h @@ -151,7 +151,6 @@ class CubeMapTextureArray: public AbstractTexture { return this; } - #ifndef MAGNUM_TARGET_GLES /** * @brief Invalidate texture subimage * @param level Mip level @@ -161,14 +160,14 @@ class CubeMapTextureArray: public AbstractTexture { * Z coordinate is equivalent to layer * 6 + number of texture face, * i.e. @ref Coordinate "Coordinate::PositiveX" is `0` and so on, in * the same order as in the enum. + * + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * is not available, this function does nothing. * @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 Vector3i& offset, const Vector3i& size) { DataHelper<3>::invalidateSub(this, level, offset, size); } - #endif /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT diff --git a/src/Texture.h b/src/Texture.h index 96a6c9551..5e7000d7d 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -250,21 +250,19 @@ 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 * + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * is not available, this function does nothing. * @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