Browse Source

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.
pull/7/head
Vladimír Vondruš 14 years ago
parent
commit
35a918d050
  1. 26
      src/AbstractTexture.cpp
  2. 40
      src/AbstractTexture.h
  3. 25
      src/Buffer.cpp
  4. 38
      src/Buffer.h
  5. 7
      src/CubeMapTexture.h
  6. 7
      src/CubeMapTextureArray.h
  7. 6
      src/Texture.h

26
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<Extensions::GL::ARB::invalidate_subdata>()) {
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>& wrapping) {
#ifndef MAGNUM_TARGET_GLES

40
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

25
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<Extensions::GL::ARB::invalidate_subdata>()) {
Debug() << "Buffer: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features";
invalidateImplementation = &Buffer::invalidateImplementationARB;
invalidateSubImplementation = &Buffer::invalidateSubImplementationARB;
}
#else
static_cast<void>(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

38
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

7
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

7
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

6
src/Texture.h

@ -250,21 +250,19 @@ template<std::uint8_t dimensions> 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<Dimensions, GLint>::VectorType& offset, const typename DimensionTraits<Dimensions, GLint>::VectorType& size) {
DataHelper<dimensions>::invalidateSub(this, level, offset, size);
}
#endif
/* Overloads to remove WTF-factor from method chaining order */
#ifndef DOXYGEN_GENERATING_OUTPUT

Loading…
Cancel
Save