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