Browse Source

Pixel storage support, part 9: reallocate image data only if needed.

Makes it possible to update only some portion of an image without
breaking the rest.
pull/107/head
Vladimír Vondruš 11 years ago
parent
commit
98f979477c
  1. 16
      src/Magnum/AbstractFramebuffer.cpp
  2. 6
      src/Magnum/AbstractFramebuffer.h
  3. 40
      src/Magnum/AbstractTexture.cpp
  4. 56
      src/Magnum/CubeMapTexture.cpp
  5. 29
      src/Magnum/CubeMapTexture.h
  6. 22
      src/Magnum/Texture.h

16
src/Magnum/AbstractFramebuffer.cpp

@ -280,7 +280,13 @@ AbstractFramebuffer& AbstractFramebuffer::clear(const FramebufferClearMask mask)
void AbstractFramebuffer::read(const Range2Di& rectangle, Image2D& image) {
bindInternal(FramebufferTarget::Read);
Containers::Array<char> data{Implementation::imageDataSizeFor(image, rectangle.size())};
/* Reallocate only if needed */
const std::size_t dataSize = Implementation::imageDataSizeFor(image, rectangle.size());
Containers::Array<char> data{image.release()};
if(data.size() < dataSize)
data = Containers::Array<char>{dataSize};
#ifndef MAGNUM_TARGET_GLES2
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
#endif
@ -296,11 +302,13 @@ Image2D AbstractFramebuffer::read(const Range2Di& rectangle, Image2D&& image) {
#ifndef MAGNUM_TARGET_GLES2
void AbstractFramebuffer::read(const Range2Di& rectangle, BufferImage2D& image, BufferUsage usage) {
bindInternal(FramebufferTarget::Read);
/* If the buffer doesn't have sufficient size, resize it */
/** @todo Explicitly reset also when buffer usage changes */
/* Reallocate only if needed */
const std::size_t dataSize = Implementation::imageDataSizeFor(image, rectangle.size());
if(image.size() != rectangle.size())
if(image.dataSize() < dataSize)
image.setData(image.storage(), image.format(), image.type(), rectangle.size(), {nullptr, dataSize}, usage);
else
image.setData(image.storage(), image.format(), image.type(), rectangle.size(), nullptr, usage);
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
(Context::current()->state().framebuffer->readImplementation)(rectangle, image.format(), image.type(), dataSize, nullptr);

6
src/Magnum/AbstractFramebuffer.h

@ -314,7 +314,8 @@ class MAGNUM_EXPORT AbstractFramebuffer {
* @param image Image where to put the data
*
* Image parameters like format and type of pixel data are taken from
* given image.
* given image. The storage is not reallocated if it is large enough to
* contain the new data.
*
* If @extension{ARB,robustness} is available, the operation is
* protected from buffer overflow.
@ -350,7 +351,8 @@ class MAGNUM_EXPORT AbstractFramebuffer {
* @param usage Buffer usage
*
* See @ref read(const Vector2i&, const Vector2i&, Image2D&) for more
* information.
* information. The storage is not reallocated if it is large enough to
* contain the new data, which means that @p usage might get ignored.
* @requires_gles30 Pixel buffer objects are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Pixel buffer objects are not available in WebGL

40
src/Magnum/AbstractTexture.cpp

@ -1494,7 +1494,12 @@ void AbstractTexture::invalidateSubImageImplementationARB(GLint level, const Vec
#ifndef MAGNUM_TARGET_GLES
template<UnsignedInt dimensions> void AbstractTexture::image(GLint level, Image<dimensions>& image) {
const Math::Vector<dimensions, Int> size = DataHelper<dimensions>::imageSize(*this, level);
Containers::Array<char> data{Implementation::imageDataSizeFor(image, size)};
const std::size_t dataSize = Implementation::imageDataSizeFor(image, size);
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
if(data.size() < dataSize)
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
(this->*Context::current()->state().texture->getImageImplementation)(level, image.format(), image.type(), data.size(), data);
@ -1508,8 +1513,12 @@ template void MAGNUM_EXPORT AbstractTexture::image<3>(GLint, Image<3>&);
template<UnsignedInt dimensions> void AbstractTexture::image(GLint level, BufferImage<dimensions>& image, BufferUsage usage) {
const Math::Vector<dimensions, Int> size = DataHelper<dimensions>::imageSize(*this, level);
const std::size_t dataSize = Implementation::imageDataSizeFor(image, size);
if(image.size() != size)
/* Reallocate only if needed */
if(image.dataSize() < dataSize)
image.setData(image.storage(), image.format(), image.type(), size, {nullptr, dataSize}, usage);
else
image.setData(image.storage(), image.format(), image.type(), size, nullptr, usage);
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
(this->*Context::current()->state().texture->getImageImplementation)(level, image.format(), image.type(), dataSize, nullptr);
@ -1523,9 +1532,14 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedImage(const GLi
const Math::Vector<dimensions, Int> size = DataHelper<dimensions>::imageSize(*this, level);
GLint textureDataSize;
(this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize);
const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, textureDataSize);
GLint format;
(this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format);
Containers::Array<char> data{Implementation::compressedImageDataSizeFor(image, size, textureDataSize)};
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
if(data.size() < dataSize)
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
(this->*Context::current()->state().texture->getCompressedImageImplementation)(level, data.size(), data);
@ -1544,7 +1558,12 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedImage(const GLi
GLint format;
(this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format);
image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage);
/* Reallocate only if needed */
if(image.dataSize() < dataSize)
image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage);
else
image.setData(image.storage(), CompressedPixelFormat(format), size, nullptr, usage);
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
(this->*Context::current()->state().texture->getCompressedImageImplementation)(level, dataSize, nullptr);
}
@ -1557,9 +1576,14 @@ template<UnsignedInt dimensions> void AbstractTexture::subImage(const GLint leve
createIfNotAlready();
const Math::Vector<dimensions, Int> size = range.size();
const std::size_t dataSize = Implementation::imageDataSizeFor(image, size);
const Vector3i paddedOffset = Vector3i::pad(range.min());
const Vector3i paddedSize = Vector3i::pad(size, 1);
Containers::Array<char> data{Implementation::imageDataSizeFor(image, size)};
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
if(data.size() < dataSize)
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
glGetTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), GLenum(image.format()), GLenum(image.type()), data.size(), data);
@ -1577,8 +1601,12 @@ template<UnsignedInt dimensions> void AbstractTexture::subImage(const GLint leve
const std::size_t dataSize = Implementation::imageDataSizeFor(image, size);
const Vector3i paddedOffset = Vector3i::pad(range.min());
const Vector3i paddedSize = Vector3i::pad(size, 1);
if(image.size() != size)
/* Reallocate only if needed */
if(image.dataSize() < dataSize)
image.setData(image.storage(), image.format(), image.type(), size, {nullptr, dataSize}, usage);
else
image.setData(image.storage(), image.format(), image.type(), size, nullptr, usage);
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
glGetTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), GLenum(image.format()), GLenum(image.type()), dataSize, nullptr);

56
src/Magnum/CubeMapTexture.cpp

@ -60,7 +60,13 @@ void CubeMapTexture::image(const Int level, Image3D& image) {
createIfNotAlready();
const Vector3i size{imageSize(level), 6};
Containers::Array<char> data{Implementation::imageDataSizeFor(image, size)};
const std::size_t dataSize = Implementation::imageDataSizeFor(image, size);
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
if(data.size() < dataSize)
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
glGetTextureImage(_id, level, GLenum(image.format()), GLenum(image.type()), data.size(), data);
image.setData(image.storage(), image.format(), image.type(), size, std::move(data));
@ -76,8 +82,12 @@ void CubeMapTexture::image(const Int level, BufferImage3D& image, const BufferUs
const Vector3i size{imageSize(level), 6};
const std::size_t dataSize = Implementation::imageDataSizeFor(image, size);
if(image.size() != size)
/* Reallocate only if needed */
if(image.dataSize() < dataSize)
image.setData(image.storage(), image.format(), image.type(), size, {nullptr, dataSize}, usage);
else
image.setData(image.storage(), image.format(), image.type(), size, nullptr, usage);
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
glGetTextureImage(_id, level, GLenum(image.format()), GLenum(image.type()), dataSize, nullptr);
@ -97,10 +107,14 @@ void CubeMapTexture::compressedImage(const Int level, CompressedImage3D& image)
const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, textureDataSize);
GLint format;
(this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format);
Containers::Array<char> data{dataSize};
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
if(data.size() < dataSize)
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
glGetCompressedTextureImage(_id, level, dataSize, data);
glGetCompressedTextureImage(_id, level, data.size(), data);
image.setData(image.storage(), CompressedPixelFormat(format), size, std::move(data));
}
@ -119,8 +133,13 @@ void CubeMapTexture::compressedImage(const Int level, CompressedBufferImage3D& i
GLint format;
(this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format);
/* Reallocate only if needed */
if(image.dataSize() < dataSize)
image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage);
else
image.setData(image.storage(), CompressedPixelFormat(format), size, nullptr, usage);
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage);
glGetCompressedTextureImage(_id, level, dataSize, nullptr);
}
@ -131,7 +150,12 @@ CompressedBufferImage3D CubeMapTexture::compressedImage(const Int level, Compres
void CubeMapTexture::image(const Coordinate coordinate, const Int level, Image2D& image) {
const Vector2i size = imageSize(level);
Containers::Array<char> data{Implementation::imageDataSizeFor(image, size)};
const std::size_t dataSize = Implementation::imageDataSizeFor(image, size);
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
if(data.size() < dataSize)
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
(this->*Context::current()->state().texture->getCubeImageImplementation)(coordinate, level, size, image.format(), image.type(), data.size(), data);
@ -146,8 +170,12 @@ Image2D CubeMapTexture::image(const Coordinate coordinate, const Int level, Imag
void CubeMapTexture::image(const Coordinate coordinate, const Int level, BufferImage2D& image, const BufferUsage usage) {
const Vector2i size = imageSize(level);
const std::size_t dataSize = Implementation::imageDataSizeFor(image, size);
if(image.size() != size)
/* Reallocate only if needed */
if(image.dataSize() < dataSize)
image.setData(image.storage(), image.format(), image.type(), size, {nullptr, dataSize}, usage);
else
image.setData(image.storage(), image.format(), image.type(), size, nullptr, usage);
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
(this->*Context::current()->state().texture->getCubeImageImplementation)(coordinate, level, size, image.format(), image.type(), dataSize, nullptr);
@ -162,9 +190,14 @@ void CubeMapTexture::compressedImage(const Coordinate coordinate, const Int leve
const Vector2i size = imageSize(level);
GLint textureDataSize;
(this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize);
const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, textureDataSize);
GLint format;
(this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format);
Containers::Array<char> data{Implementation::compressedImageDataSizeFor(image, size, textureDataSize)};
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
if(data.size() < dataSize)
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
(this->*Context::current()->state().texture->getCompressedCubeImageImplementation)(coordinate, level, size, data.size(), data);
@ -184,7 +217,12 @@ void CubeMapTexture::compressedImage(const Coordinate coordinate, const Int leve
GLint format;
(this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format);
image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage);
/* Reallocate only if needed */
if(image.dataSize() < dataSize)
image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage);
else
image.setData(image.storage(), CompressedPixelFormat(format), size, nullptr, usage);
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
(this->*Context::current()->state().texture->getCompressedCubeImageImplementation)(coordinate, level, size, dataSize, nullptr);
}

29
src/Magnum/CubeMapTexture.h

@ -440,7 +440,10 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
*
* Image parameters like format and type of pixel data are taken from
* given image, image size is taken from the texture using
* @ref imageSize().
* @ref imageSize(). The storage is not reallocated if it is large
* enough to contain the new data.
*
* The operation is protected from buffer overflow.
* @see @fn_gl2{GetTextureLevelParameter,GetTexLevelParameter} with
* @def_gl{TEXTURE_WIDTH}, @def_gl{TEXTURE_HEIGHT}, then
* @fn_gl2{GetTextureImage,GetTexImage}
@ -462,7 +465,9 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
/**
* @brief Read given mip level of texture to buffer image
*
* See @ref image(Int, Image3D&) for more information.
* See @ref image(Int, Image3D&) for more information. The storage is
* not reallocated if it is large enough to contain the new data, which
* means that @p usage might get ignored.
* @requires_gl45 Extension @extension{ARB,direct_state_access}
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() for possible workaround.
@ -482,7 +487,8 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
* @brief Read given mip level of compressed texture to image
*
* Compression format and data size are taken from the texture, image
* size is taken using @ref imageSize().
* size is taken using @ref imageSize(). The storage is not reallocated
* if it is large enough to contain the new data.
* @see @fn_gl2{GetTextureLevelParameter,GetTexLevelParameter} with
* @def_gl{TEXTURE_COMPRESSED_IMAGE_SIZE},
* @def_gl{TEXTURE_INTERNAL_FORMAT}, @def_gl{TEXTURE_WIDTH},
@ -507,7 +513,8 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
* @brief Read given mip level of compressed texture to buffer image
*
* See @ref compressedImage(Int, CompressedImage3D&) for more
* information.
* information. The storage is not reallocated if it is large enough to
* contain the new data, which means that @p usage might get ignored.
* @requires_gl45 Extension @extension{ARB,direct_state_access}
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() for possible workaround.
@ -528,7 +535,8 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
*
* Image parameters like format and type of pixel data are taken from
* given image, image size is taken from the texture using
* @ref imageSize().
* @ref imageSize(). The storage is not reallocated if it is large
* enough to contain the new data.
*
* If neither @extension{ARB,get_texture_sub_image} (part of OpenGL
* 4.5) nor @extension{EXT,direct_state_access} is available, the
@ -564,7 +572,9 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
/**
* @brief Read given mip level and coordinate of texture to buffer image
*
* See @ref image(Coordinate, Int, Image2D&) for more information.
* See @ref image(Coordinate, Int, Image2D&) for more information. The
* storage is not reallocated if it is large enough to contain the new
* data, which means that @p usage might get ignored.
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() for possible workaround.
*/
@ -583,7 +593,8 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
* @brief Read given mip level and coordinate of compressed texture to image
*
* Compression format and data size are taken from the texture, image
* size is taken using @ref imageSize().
* size is taken using @ref imageSize(). The storage is not reallocated
* if it is large enough to contain the new data.
*
* If neither @extension{ARB,get_texture_sub_image} (part of OpenGL
* 4.5) nor @extension{EXT,direct_state_access} is available, the
@ -621,7 +632,9 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture {
* @brief Read given mip level and coordinate of compressed texture to buffer image
*
* See @ref compressedImage(Coordinate, Int, CompressedImage2D&) for
* more information.
* more information. The storage is not reallocated if it is large
* enough to contain the new data, which means that @p usage might get
* ignored.
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() for possible workaround.
*/

22
src/Magnum/Texture.h

@ -637,7 +637,8 @@ template<UnsignedInt dimensions> class Texture: public AbstractTexture {
*
* Image parameters like format and type of pixel data are taken from
* given image, image size is taken from the texture using
* @ref imageSize().
* @ref imageSize(). The storage is not reallocated if it is large
* enough to contain the new data.
*
* If neither @extension{ARB,direct_state_access} (part of OpenGL 4.5)
* nor @extension{EXT,direct_state_access} is available, the texture is
@ -678,7 +679,9 @@ template<UnsignedInt dimensions> class Texture: public AbstractTexture {
* @param image Buffer image where to put the data
* @param usage Buffer usage
*
* See @ref image(Int, Image&) for more information.
* See @ref image(Int, Image&) for more information. The storage is not
* reallocated if it is large enough to contain the new data, which
* means that @p usage might get ignored.
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() for possible workaround.
* @todo Make it more flexible (usable with
@ -703,7 +706,8 @@ template<UnsignedInt dimensions> class Texture: public AbstractTexture {
* @param image Image where to put the compressed data
*
* Compression format and data size are taken from the texture, image
* size is taken using @ref imageSize().
* size is taken using @ref imageSize(). The storage is not reallocated
* if it is large enough to contain the new data.
*
* If neither @extension{ARB,direct_state_access} (part of OpenGL 4.5)
* nor @extension{EXT,direct_state_access} is available, the texture is
@ -746,7 +750,8 @@ template<UnsignedInt dimensions> class Texture: public AbstractTexture {
* @param usage Buffer usage
*
* See @ref compressedImage(Int, CompressedImage&) for more
* information.
* information. The storage is not reallocated if it is large enough to
* contain the new data, which means that @p usage might get ignored.
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() for possible workaround.
* @todo Make it more flexible (usable with
@ -772,7 +777,10 @@ template<UnsignedInt dimensions> class Texture: public AbstractTexture {
* @param image Image where to put the data
*
* Image parameters like format and type of pixel data are taken from
* given image.
* given image. The storage is not reallocated if it is large enough to
* contain the new data.
*
* The operation is protected from buffer overflow.
* @see @fn_gl{GetTextureSubImage}
* @requires_gl45 Extension @extension{ARB,get_texture_sub_image}
* @requires_gl Texture image queries are not available in OpenGL ES or
@ -799,7 +807,9 @@ template<UnsignedInt dimensions> class Texture: public AbstractTexture {
* @param usage Buffer usage
*
* See @ref subImage(Int, const RangeTypeFor<dimensions, Int>&, Image&)
* for more information.
* for more information. The storage is not reallocated if it is large
* enough to contain the new data, which means that @p usage might get
* ignored.
* @requires_gl45 Extension @extension{ARB,get_texture_sub_image}
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() for possible workaround.

Loading…
Cancel
Save