Browse Source

GL: use known compressed format properties instead of querying them.

With this change, neither GL is queried for compressed block size
properties nor they're taken from CompressedPixelStorage anymore. For
image upload they're taken directly from the passed image and set to
GL's pixel pack state, for image download they're taken from known
GL::CompressedPixelFormat properties set to GL's pixel unpack
state and saved to the image.

Besides removing a bunch of checks from tests, there isn't anything new
to *add* there -- everything should work just as before, or
(assuming shitty drivers with broken format queries) better.

Also, in some cases the internal format queries were made into a
zero-initialized output variable to ensure consistent behavior with
broken drivers. That's now done in all cases, with a lengthy comment to
ensure this doesn't get "cleaned up" by accident.
pull/680/head
Vladimír Vondruš 10 months ago
parent
commit
d779e837f7
  1. 201
      src/Magnum/GL/AbstractTexture.cpp
  2. 4
      src/Magnum/GL/AbstractTexture.h
  3. 314
      src/Magnum/GL/CubeMapTexture.cpp
  4. 48
      src/Magnum/GL/CubeMapTexture.h
  5. 8
      src/Magnum/GL/CubeMapTextureArray.h
  6. 25
      src/Magnum/GL/Implementation/RendererState.cpp
  7. 23
      src/Magnum/GL/Implementation/RendererState.h
  8. 8
      src/Magnum/GL/RectangleTexture.h
  9. 6
      src/Magnum/GL/Test/AbstractTextureGLTest.cpp
  10. 6
      src/Magnum/GL/Test/CubeMapTextureArrayGLTest.cpp
  11. 6
      src/Magnum/GL/Test/CubeMapTextureGLTest.cpp
  12. 6
      src/Magnum/GL/Test/TextureArrayGLTest.cpp
  13. 12
      src/Magnum/GL/Test/TextureGLTest.cpp
  14. 53
      src/Magnum/GL/Texture.h
  15. 8
      src/Magnum/GL/TextureArray.h
  16. 6
      src/Magnum/Implementation/ImageProperties.h

201
src/Magnum/GL/AbstractTexture.cpp

@ -1794,18 +1794,23 @@ template void MAGNUM_GL_EXPORT AbstractTexture::image<3>(GLint, BufferImage<3>&,
template<UnsignedInt dimensions> void AbstractTexture::compressedImage(const GLint level, CompressedImage<dimensions>& image, const ImageFlags<dimensions> flags) {
const Math::Vector<dimensions, Int> size = DataHelper<dimensions>::imageSize(*this, level);
/* If the user-provided pixel storage doesn't tell us all properties about
the compression, we need to ask GL for it */
std::size_t dataSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize()) {
GLint textureDataSize;
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize);
dataSize = textureDataSize;
} else dataSize = Magnum::Implementation::compressedImageDataSizeFor(image, size);
/* Internal texture format */
GLint format;
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
const std::size_t dataSize = Magnum::Implementation::compressedImageDataSizeFor(image.storage(), blockSize, blockDataSize, size);
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
@ -1813,9 +1818,9 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedImage(const GLi
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image.storage(), blockSize, blockDataSize);
Context::current().state().texture.getCompressedImageImplementation(*this, level, data.size(), data);
image = CompressedImage<dimensions>{image.storage(), CompressedPixelFormat(format), size, Utility::move(data), flags};
image = CompressedImage<dimensions>{image.storage(), UnsignedInt(format), blockSize, blockDataSize, size, Utility::move(data), flags};
}
template void MAGNUM_GL_EXPORT AbstractTexture::compressedImage<1>(GLint, CompressedImage<1>&, ImageFlags1D);
@ -1831,16 +1836,21 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedImage(const GLi
CORRADE_ASSERT(image.size() == size,
"GL::AbstractTexture::compressedImage(): expected image view size" << size << "but got" << image.size(), );
/* Internal texture format */
GLint format;
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::AbstractTexture::compressedImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
/* Check that the internal texture format matches (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat).
Zero-init to avoid a non-deterministic message in the assert below if
the drivers are extra shitty and don't implement this query (Intel
Windows drivers, I'm talking about you). */
{
GLint format{};
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::AbstractTexture::compressedImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
}
#endif
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
Context::current().state().texture.getCompressedImageImplementation(*this, level, image.data().size(), image.data());
}
@ -1851,27 +1861,36 @@ template void MAGNUM_GL_EXPORT AbstractTexture::compressedImage<3>(GLint, const
template<UnsignedInt dimensions> void AbstractTexture::compressedImage(const GLint level, CompressedBufferImage<dimensions>& image, BufferUsage usage) {
const Math::Vector<dimensions, Int> size = DataHelper<dimensions>::imageSize(*this, level);
/* If the user-provided pixel storage doesn't tell us all properties about
the compression, we need to ask GL for it */
std::size_t dataSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize()) {
GLint textureDataSize;
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize);
dataSize = textureDataSize;
} else dataSize = Magnum::Implementation::compressedImageDataSizeFor(image, size);
/* Internal texture format */
GLint format;
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
const std::size_t dataSize = Magnum::Implementation::compressedImageDataSizeFor(image.storage(), blockSize, blockDataSize, size);
/* 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);
/* The setData() call above updates the block properties, so just verify
they're the same as the ones used here as the ones from the umage get
used in applyCompressedPixelStoragePack() below */
CORRADE_INTERNAL_ASSERT(blockSize == image.blockSize() && blockDataSize == image.blockDataSize());
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
Context::current().state().texture.getCompressedImageImplementation(*this, level, dataSize, nullptr);
}
@ -1943,18 +1962,6 @@ template void MAGNUM_GL_EXPORT AbstractTexture::subImage<1>(GLint, const Range1D
template void MAGNUM_GL_EXPORT AbstractTexture::subImage<2>(GLint, const Range2Di&, BufferImage<2>&, BufferUsage);
template void MAGNUM_GL_EXPORT AbstractTexture::subImage<3>(GLint, const Range3Di&, BufferImage<3>&, BufferUsage);
template<UnsignedInt dimensions> std::size_t AbstractTexture::compressedSubImageSize(TextureFormat format, const Math::Vector<dimensions, Int>& size) {
/* Amount of blocks in given range (rounded up) multiplied by block
data size. The user is responsible for proper block-aligned size. */
const Math::Vector<dimensions, Int> blockSize = DataHelper<dimensions>::compressedBlockSize(_target, format);
return ((size + blockSize - Math::Vector<dimensions, Int>{1})/blockSize).product()*
compressedBlockDataSize(_target, format);
}
template std::size_t MAGNUM_GL_EXPORT AbstractTexture::compressedSubImageSize<1>(TextureFormat format, const Math::Vector<1, Int>& size);
template std::size_t MAGNUM_GL_EXPORT AbstractTexture::compressedSubImageSize<2>(TextureFormat format, const Math::Vector<2, Int>& size);
template std::size_t MAGNUM_GL_EXPORT AbstractTexture::compressedSubImageSize<3>(TextureFormat format, const Math::Vector<3, Int>& size);
template<UnsignedInt dimensions> void AbstractTexture::compressedSubImage(const GLint level, const RangeTypeFor<dimensions, Int>& range, CompressedImage<dimensions>& image, const ImageFlags<dimensions> flags) {
/* Explicitly create if not already because the texture might have been
created w/ the DSA extension disabled but below a DSA API is used */
@ -1964,17 +1971,23 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedSubImage(const
const Vector3i paddedOffset = Vector3i::pad<dimensions>(range.min());
const Vector3i paddedSize = Vector3i::pad(size, 1);
/* Internal texture format */
GLint format;
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
/* Calculate compressed subimage size. If the user-provided pixel storage
doesn't tell us all properties about the compression, we need to ask GL
for it. That requires GL_ARB_internalformat_query2. */
std::size_t dataSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize())
dataSize = compressedSubImageSize<dimensions>(TextureFormat(format), size);
else dataSize = Magnum::Implementation::compressedImageDataSizeFor(image, size);
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
const std::size_t dataSize = Magnum::Implementation::compressedImageDataSizeFor(image.storage(), blockSize, blockDataSize, size);
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
@ -1982,7 +1995,7 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedSubImage(const
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image.storage(), blockSize, blockDataSize);
glGetCompressedTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), data.size(), data);
image = CompressedImage<dimensions>{CompressedPixelFormat(format), size, Utility::move(data), flags};
}
@ -2001,22 +2014,26 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedSubImage(const
created w/ the DSA extension disabled but below a DSA API is used */
createIfNotAlready();
const Math::Vector<dimensions, Int> size = range.size();
#ifndef CORRADE_NO_ASSERT
/* Internal texture format */
GLint format;
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
/* Check that the internal texture format matches (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat).
Zero-init to avoid a non-deterministic message in the assert below if
the drivers are extra shitty and don't implement this query (Intel
Windows drivers, I'm talking about you). */
{
GLint format{};
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::AbstractTexture::compressedSubImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::AbstractTexture::compressedSubImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
}
#endif
const Vector3i paddedOffset = Vector3i::pad<dimensions>(range.min());
const Vector3i paddedSize = Vector3i::pad(size, 1);
const Vector3i paddedSize = Vector3i::pad<dimensions>(range.size(), 1);
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
glGetCompressedTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), image.data().size(), image.data());
}
@ -2033,26 +2050,36 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedSubImage(const
const Vector3i paddedOffset = Vector3i::pad<dimensions>(range.min());
const Vector3i paddedSize = Vector3i::pad(size, 1);
/* Internal texture format */
GLint format;
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
Context::current().state().texture.getLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
/* Calculate compressed subimage size. If the user-provided pixel storage
doesn't tell us all properties about the compression, we need to ask GL
for it. That requires GL_ARB_internalformat_query2. */
std::size_t dataSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize())
dataSize = compressedSubImageSize<dimensions>(TextureFormat(format), size);
else dataSize = Magnum::Implementation::compressedImageDataSizeFor(image, size);
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
const std::size_t dataSize = Magnum::Implementation::compressedImageDataSizeFor(image.storage(), blockSize, blockDataSize, size);
/* 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);
/* The setData() call above updates the block properties, so just verify
they're the same as the ones used here as the ones from the umage get
used in applyCompressedPixelStoragePack() below */
CORRADE_INTERNAL_ASSERT(blockSize == image.blockSize() && blockDataSize == image.blockDataSize());
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
glGetCompressedTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), dataSize, nullptr);
}
@ -2149,7 +2176,7 @@ void AbstractTexture::DataHelper<1>::setImage(AbstractTexture& texture, const GL
void AbstractTexture::DataHelper<1>::setCompressedImage(AbstractTexture& texture, const GLint level, const CompressedImageView1D& image) {
Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
texture.bindInternal();
glCompressedTexImage1D(texture._target, level, GLenum(compressedPixelFormat(image.format())), image.size()[0], 0, Implementation::occupiedCompressedImageDataSize(image), image.data());
}
@ -2163,7 +2190,7 @@ void AbstractTexture::DataHelper<1>::setImage(AbstractTexture& texture, const GL
void AbstractTexture::DataHelper<1>::setCompressedImage(AbstractTexture& texture, const GLint level, CompressedBufferImage1D& image) {
image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
texture.bindInternal();
glCompressedTexImage1D(texture._target, level, GLenum(image.format()), image.size()[0], 0, Implementation::occupiedCompressedImageDataSize(image), nullptr);
}
@ -2176,7 +2203,7 @@ void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture& texture, const
void AbstractTexture::DataHelper<1>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Math::Vector<1, GLint>& offset, const CompressedImageView1D& image) {
Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
Context::current().state().texture.compressedSubImage1DImplementation(texture, level, offset, image.size(), compressedPixelFormat(image.format()), image.data(), Implementation::occupiedCompressedImageDataSize(image));
}
@ -2188,7 +2215,7 @@ void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture& texture, const
void AbstractTexture::DataHelper<1>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Math::Vector<1, GLint>& offset, CompressedBufferImage1D& image) {
image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
Context::current().state().texture.compressedSubImage1DImplementation(texture, level, offset, image.size(), image.format(), nullptr, Implementation::occupiedCompressedImageDataSize(image));
}
#endif
@ -2209,7 +2236,7 @@ void AbstractTexture::DataHelper<2>::setCompressedImage(AbstractTexture& texture
#ifndef MAGNUM_TARGET_GLES2
Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack);
#endif
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
texture.bindInternal();
glCompressedTexImage2D(target, level, GLenum(compressedPixelFormat(image.format())), image.size().x(), image.size().y(), 0, Implementation::occupiedCompressedImageDataSize(image), image.data());
}
@ -2224,7 +2251,7 @@ void AbstractTexture::DataHelper<2>::setImage(AbstractTexture& texture, const GL
void AbstractTexture::DataHelper<2>::setCompressedImage(AbstractTexture& texture, const GLenum target, const GLint level, CompressedBufferImage2D& image) {
image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
texture.bindInternal();
glCompressedTexImage2D(target, level, GLenum(image.format()), image.size().x(), image.size().y(), 0, Implementation::occupiedCompressedImageDataSize(image), nullptr);
}
@ -2246,7 +2273,7 @@ void AbstractTexture::DataHelper<2>::setCompressedSubImage(AbstractTexture& text
#ifndef MAGNUM_TARGET_GLES2
Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack);
#endif
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
Context::current().state().texture.compressedSubImage2DImplementation(texture, level, offset, image.size(), compressedPixelFormat(image.format()), image.data(), Implementation::occupiedCompressedImageDataSize(image));
}
@ -2259,7 +2286,7 @@ void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture& texture, const
void AbstractTexture::DataHelper<2>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Vector2i& offset, CompressedBufferImage2D& image) {
image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
Context::current().state().texture.compressedSubImage2DImplementation(texture, level, offset, image.size(), image.format(), nullptr, Implementation::occupiedCompressedImageDataSize(image));
}
#endif
@ -2281,7 +2308,7 @@ void AbstractTexture::DataHelper<3>::setCompressedImage(AbstractTexture& texture
#ifndef MAGNUM_TARGET_GLES2
Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack);
#endif
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
texture.bindInternal();
#ifndef MAGNUM_TARGET_GLES2
glCompressedTexImage3D(texture._target, level, GLenum(compressedPixelFormat(image.format())), image.size().x(), image.size().y(), image.size().z(), 0, Implementation::occupiedCompressedImageDataSize(image), image.data());
@ -2301,7 +2328,7 @@ void AbstractTexture::DataHelper<3>::setImage(AbstractTexture& texture, const GL
void AbstractTexture::DataHelper<3>::setCompressedImage(AbstractTexture& texture, const GLint level, CompressedBufferImage3D& image) {
image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
texture.bindInternal();
glCompressedTexImage3D(texture._target, level, GLenum(image.format()), image.size().x(), image.size().y(), image.size().z(), 0, Implementation::occupiedCompressedImageDataSize(image), nullptr);
}
@ -2324,7 +2351,7 @@ void AbstractTexture::DataHelper<3>::setCompressedSubImage(AbstractTexture& text
#ifndef MAGNUM_TARGET_GLES2
Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack);
#endif
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
Context::current().state().texture.compressedSubImage3DImplementation(texture, level, offset, image.size(), compressedPixelFormat(image.format()), image.data(), Implementation::occupiedCompressedImageDataSize(image));
}
#endif
@ -2338,7 +2365,7 @@ void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture& texture, const
void AbstractTexture::DataHelper<3>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Vector3i& offset, CompressedBufferImage3D& image) {
image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
Context::current().state().texture.compressedSubImage3DImplementation(texture, level, offset, image.size(), image.format(), nullptr, Implementation::occupiedCompressedImageDataSize(image));
}
#endif

4
src/Magnum/GL/AbstractTexture.h

@ -544,10 +544,6 @@ class MAGNUM_GL_EXPORT AbstractTexture: public AbstractObject {
static void MAGNUM_GL_LOCAL createImplementationDSA(AbstractTexture& self);
#endif
#ifndef MAGNUM_TARGET_GLES
template<UnsignedInt dimensions> std::size_t MAGNUM_GL_LOCAL compressedSubImageSize(TextureFormat format, const Math::Vector<dimensions, Int>& size);
#endif
static void MAGNUM_GL_LOCAL bindImplementationDefault(AbstractTexture& self, GLint textureUnit);
#ifndef MAGNUM_TARGET_GLES
static void MAGNUM_GL_LOCAL bindImplementationMulti(AbstractTexture& self, GLint textureUnit);

314
src/Magnum/GL/CubeMapTexture.cpp

@ -153,21 +153,30 @@ BufferImage3D CubeMapTexture::image(const Int level, BufferImage3D&& image, cons
void CubeMapTexture::compressedImage(const Int level, CompressedImage3D& image) {
const Vector3i size{imageSize(level), 6};
/* If the user-provided pixel storage doesn't tell us all properties about
the compression, we need to ask GL for it */
std::pair<std::size_t, std::size_t> dataOffsetSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize()) {
/* Unlike in AbstractTexture::compressedImage(), here we have a
separate offset and size because of the
nv-cubemap-broken-full-compressed-image-query workaround, where it
needs to go slice-by-slice, advancing the offset each time */
dataOffsetSize.first = 0;
dataOffsetSize.second = Context::current().state().texture.getCubeLevelCompressedImageSizeImplementation(*this, level)*6;
} else dataOffsetSize = Magnum::Implementation::compressedImageDataOffsetSizeFor(image, size);
/* Internal texture format */
GLint format;
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
/* Note that this has to call getCubeLevelParameterivImplementation(), not
getLevelParameterivImplementation(), to supply a concrete coordinate in
non-DSA codepaths */
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
/* Unlike in AbstractTexture::compressedImage(), here we have a separate
offset and size because of the nv-cubemap-broken-full-compressed-image-query
workaround, where it needs to go slice-by-slice, advancing the offset
each time */
const std::pair<std::size_t, std::size_t> dataOffsetSize = Magnum::Implementation::compressedImageDataOffsetSizeFor(image.storage(), blockSize, blockDataSize, size);
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
@ -175,7 +184,7 @@ void CubeMapTexture::compressedImage(const Int level, CompressedImage3D& image)
data = Containers::Array<char>{dataOffsetSize.first + dataOffsetSize.second};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image.storage(), blockSize, blockDataSize);
Context::current().state().texture.getCompressedCubeImage3DImplementation(*this, level, size.xy(), dataOffsetSize.first, dataOffsetSize.second, data);
image = CompressedImage3D{image.storage(), CompressedPixelFormat(format), size, Utility::move(data), ImageFlag3D::CubeMap};
}
@ -193,59 +202,77 @@ void CubeMapTexture::compressedImage(const Int level, const MutableCompressedIma
CORRADE_ASSERT(image.size() == size,
"GL::CubeMapTexture::compressedImage(): expected image view size" << size << "but got" << image.size(), );
/* If the user-provided pixel storage doesn't tell us all properties about
the compression, we need to ask GL for it */
std::pair<std::size_t, std::size_t> dataOffsetSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize()) {
/* Unlike in AbstractTexture::compressedImage(), here we have a
separate offset and size because of the
nv-cubemap-broken-full-compressed-image-query workaround, where it
needs to go slice-by-slice, advancing the offset each time */
dataOffsetSize.first = 0;
dataOffsetSize.second = Context::current().state().texture.getCubeLevelCompressedImageSizeImplementation(*this, level)*6;
} else dataOffsetSize = Magnum::Implementation::compressedImageDataOffsetSizeFor(image, size);
#ifndef CORRADE_NO_ASSERT
/* Internal texture format */
GLint format;
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::CubeMapTexture::compressedImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
/* Check that the internal texture format matches (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat).
Zero-init to avoid a non-deterministic message in the assert below if
the drivers are extra shitty and don't implement this query (Intel
Windows drivers, I'm talking about you). */
{
GLint format{};
/* Note that this has to call getCubeLevelParameterivImplementation(),
not getLevelParameterivImplementation(), to supply a concrete
coordinate in non-DSA codepaths */
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::CubeMapTexture::compressedImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
}
#endif
/* Unlike in AbstractTexture::compressedImage(), here we have a separate
offset and size because of the nv-cubemap-broken-full-compressed-image-query
workaround, where it needs to go slice-by-slice, advancing the offset
each time */
const CompressedPixelFormat format = compressedPixelFormat(image.format());
const Vector3i blockSize = compressedPixelFormatBlockSize(format);
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(format);
const std::pair<std::size_t, std::size_t> dataOffsetSize = Magnum::Implementation::compressedImageDataOffsetSizeFor(image.storage(), blockSize, blockDataSize, size);
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
Context::current().state().texture.getCompressedCubeImage3DImplementation(*this, level, size.xy(), dataOffsetSize.first, dataOffsetSize.second, image.data());
}
void CubeMapTexture::compressedImage(const Int level, CompressedBufferImage3D& image, const BufferUsage usage) {
const Vector3i size{imageSize(level), 6};
/* If the user-provided pixel storage doesn't tell us all properties about
the compression, we need to ask GL for it */
std::pair<std::size_t, std::size_t> dataOffsetSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize()) {
/* Unlike in AbstractTexture::compressedImage(), here we have a
separate offset and size because of the
nv-cubemap-broken-full-compressed-image-query workaround, where it
needs to go slice-by-slice, advancing the offset each time */
dataOffsetSize.first = 0;
dataOffsetSize.second = Context::current().state().texture.getCubeLevelCompressedImageSizeImplementation(*this, level)*6;
} else dataOffsetSize = Magnum::Implementation::compressedImageDataOffsetSizeFor(image, size);
/* Internal texture format */
GLint format;
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
/* Note that this has to call getCubeLevelParameterivImplementation(), not
getLevelParameterivImplementation(), to supply a concrete coordinate in
non-DSA codepaths */
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
/* Unlike in AbstractTexture::compressedImage(), here we have a separate
offset and size because of the nv-cubemap-broken-full-compressed-image-query
workaround, where it needs to go slice-by-slice, advancing the offset
each time */
const std::pair<std::size_t, std::size_t> dataOffsetSize = Magnum::Implementation::compressedImageDataOffsetSizeFor(image.storage(), blockSize, blockDataSize, size);
/* Reallocate only if needed */
if(image.dataSize() < dataOffsetSize.first + dataOffsetSize.second)
image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataOffsetSize.first + dataOffsetSize.second}, usage);
else
image.setData(image.storage(), CompressedPixelFormat(format), size, nullptr, usage);
/* The setData() call above updates the block properties, so just verify
they're the same as the ones used here as the ones from the umage get
used in applyCompressedPixelStoragePack() below */
CORRADE_INTERNAL_ASSERT(blockSize == image.blockSize() && blockDataSize == image.blockDataSize());
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
Context::current().state().texture.getCompressedCubeImage3DImplementation(*this, level, size.xy(), dataOffsetSize.first, dataOffsetSize.second, nullptr);
}
@ -309,19 +336,27 @@ BufferImage2D CubeMapTexture::image(const CubeMapCoordinate coordinate, const In
void CubeMapTexture::compressedImage(const CubeMapCoordinate coordinate, const Int level, CompressedImage2D& image) {
const Vector2i size = imageSize(level);
/* If the user-provided pixel storage doesn't tell us all properties about
the compression, we need to ask GL for it */
std::size_t dataSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize())
dataSize = Context::current().state().texture.getCubeLevelCompressedImageSizeImplementation(*this, level);
else
dataSize = Magnum::Implementation::compressedImageDataSizeFor(image, size);
/* Internal texture format. Zero-init to avoid an assert about value
already wrapped in compressedPixelFormatWrap() later if the drivers are
extra shitty (Intel Windows drivers, I'm talking about you). */
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that
case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
/* Note that this has to call getCubeLevelParameterivImplementation(), not
getLevelParameterivImplementation(), to supply a concrete coordinate in
non-DSA codepaths */
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
const std::size_t dataSize = Magnum::Implementation::compressedImageDataSizeFor(image.storage(), blockSize, blockDataSize, size);
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
@ -329,7 +364,7 @@ void CubeMapTexture::compressedImage(const CubeMapCoordinate coordinate, const I
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image.storage(), blockSize, blockDataSize);
Context::current().state().texture.getCompressedCubeImageImplementation(*this, coordinate, level, size, data.size(), data);
image = CompressedImage2D{image.storage(), CompressedPixelFormat(format), size, Utility::move(data), ImageFlags2D{}};
}
@ -348,46 +383,63 @@ void CubeMapTexture::compressedImage(const CubeMapCoordinate coordinate, const I
"GL::CubeMapTexture::compressedImage(): expected image view size" << size << "but got" << image.size(), );
#ifndef CORRADE_NO_ASSERT
/* Internal texture format. Zero-init to avoid an assert about value
already wrapped in compressedPixelFormatWrap() later if the drivers are
extra shitty (Intel Windows drivers, I'm talking about you). */
GLint format{};
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::CubeMapTexture::compressedImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
/* Check that the internal texture format matches (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat).
Zero-init to avoid a non-deterministic message in the assert below if
the drivers are extra shitty and don't implement this query (Intel
Windows drivers, I'm talking about you). */
{
GLint format{};
/* Note that this has to call getCubeLevelParameterivImplementation(),
not getLevelParameterivImplementation(), to supply a concrete
coordinate in non-DSA codepaths */
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::CubeMapTexture::compressedImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
}
#endif
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
Context::current().state().texture.getCompressedCubeImageImplementation(*this, coordinate, level, size, image.data().size(), image.data());
}
void CubeMapTexture::compressedImage(const CubeMapCoordinate coordinate, const Int level, CompressedBufferImage2D& image, const BufferUsage usage) {
const Vector2i size = imageSize(level);
/* If the user-provided pixel storage doesn't tell us all properties about
the compression, we need to ask GL for it */
std::size_t dataSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize())
dataSize = Context::current().state().texture.getCubeLevelCompressedImageSizeImplementation(*this, level);
else
dataSize = Magnum::Implementation::compressedImageDataSizeFor(image, size);
/* Internal texture format. Zero-init to avoid an assert about value
already wrapped in compressedPixelFormatWrap() later if the drivers are
extra shitty (Intel Windows drivers, I'm talking about you). */
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
/* Note that this has to call getCubeLevelParameterivImplementation(), not
getLevelParameterivImplementation(), to supply a concrete coordinate in
non-DSA codepaths */
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
const std::size_t dataSize = Magnum::Implementation::compressedImageDataSizeFor(image.storage(), blockSize, blockDataSize, size);
/* 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);
/* The setData() call above updates the block properties, so just verify
they're the same as the ones used here as the ones from the umage get
used in applyCompressedPixelStoragePack() below */
CORRADE_INTERNAL_ASSERT(blockSize == image.blockSize() && blockDataSize == image.blockDataSize());
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
Context::current().state().texture.getCompressedCubeImageImplementation(*this, coordinate, level, size, dataSize, nullptr);
}
@ -411,19 +463,26 @@ void CubeMapTexture::compressedSubImage(const Int level, const Range3Di& range,
created w/ the DSA extension disabled but below a DSA API is used */
createIfNotAlready();
/* Internal texture format. Zero-init to avoid an assert about value
already wrapped in compressedPixelFormatWrap() later if the drivers are
extra shitty (Intel Windows drivers, I'm talking about you). */
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
/* Note that this has to call getCubeLevelParameterivImplementation(), not
getLevelParameterivImplementation(), to supply a concrete coordinate in
non-DSA codepaths */
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
/* Calculate compressed subimage size. If the user-provided pixel storage
doesn't tell us all properties about the compression, we need to ask GL
for it. That requires GL_ARB_internalformat_query2. */
std::size_t dataSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize())
dataSize = compressedSubImageSize<3>(TextureFormat(format), range.size());
else dataSize = Magnum::Implementation::compressedImageDataSizeFor(image, range.size());
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
const std::size_t dataSize = Magnum::Implementation::compressedImageDataSizeFor(image.storage(), blockSize, blockDataSize, range.size());
/* Reallocate only if needed */
Containers::Array<char> data{image.release()};
@ -431,7 +490,7 @@ void CubeMapTexture::compressedSubImage(const Int level, const Range3Di& range,
data = Containers::Array<char>{dataSize};
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image.storage(), blockSize, blockDataSize);
glGetCompressedTextureSubImage(_id, level, range.min().x(), range.min().y(), range.min().z(), range.size().x(), range.size().y(), range.size().z(), data.size(), data);
/* Would be CubeMap if the whole image was queried, but then we'd have to
query the size and compare, which is extra work. So it's Array
@ -455,18 +514,24 @@ void CubeMapTexture::compressedSubImage(const Int level, const Range3Di& range,
createIfNotAlready();
#ifndef CORRADE_NO_ASSERT
/* Internal texture format. Zero-init to avoid an assert about value
already wrapped in compressedPixelFormatWrap() later if the drivers are
extra shitty (Intel Windows drivers, I'm talking about you). */
GLint format{};
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::CubeMapTexture::compressedSubImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
/* Check that the internal texture format matches (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat).
Zero-init to avoid a non-deterministic message in the assert below if
the drivers are extra shitty and don't implement this query (Intel
Windows drivers, I'm talking about you). */
{
GLint format{};
/* Note that this has to call getCubeLevelParameterivImplementation(),
not getLevelParameterivImplementation(), to supply a concrete
coordinate in non-DSA codepaths */
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
CORRADE_ASSERT(compressedPixelFormat(image.format()) == CompressedPixelFormat(format),
"GL::CubeMapTexture::compressedSubImage(): expected image view format" << CompressedPixelFormat(format) << "but got" << compressedPixelFormat(image.format()), );
}
#endif
Buffer::unbindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
glGetCompressedTextureSubImage(_id, level, range.min().x(), range.min().y(), range.min().z(), range.size().x(), range.size().y(), range.size().z(), image.data().size(), image.data());
}
@ -475,28 +540,39 @@ void CubeMapTexture::compressedSubImage(const Int level, const Range3Di& range,
created w/ the DSA extension disabled but below a DSA API is used */
createIfNotAlready();
/* Internal texture format. Zero-init to avoid an assert about value
already wrapped in compressedPixelFormatWrap() later if the drivers are
extra shitty (Intel Windows drivers, I'm talking about you). */
/* Get internal texture format, determine its properties (compressed
GL::TextureFormat values are same as GL::CompressedPixelFormat) and
calculate data size for those. Yes, if the format is unknown to Magnum,
this will blow up. But that's likely a very rare scenario that isn't
worth implementing (and is rather impossible to test), and the user can
always query into a view with block properties specified in that case.
The format is zero-init to have it deterministically assert inside
compressedPixelFormatBlockSize() if the drivers are extra shitty and
don't implement this query (Intel Windows drivers, I'm talking about
you), otherwise it could give back a value that could randomly work, or
cause OOMs, crashes and such. */
GLint format{};
/* Note that this has to call getCubeLevelParameterivImplementation(), not
getLevelParameterivImplementation(), to supply a concrete coordinate in
non-DSA codepaths */
Context::current().state().texture.getCubeLevelParameterivImplementation(*this, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
/* Calculate compressed subimage size. If the user-provided pixel storage
doesn't tell us all properties about the compression, we need to ask GL
for it. That requires GL_ARB_internalformat_query2. */
std::size_t dataSize;
if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize())
dataSize = compressedSubImageSize<3>(TextureFormat(format), range.size());
else dataSize = Magnum::Implementation::compressedImageDataSizeFor(image, range.size());
const Vector3i blockSize = compressedPixelFormatBlockSize(CompressedPixelFormat(format));
const UnsignedInt blockDataSize = compressedPixelFormatBlockDataSize(CompressedPixelFormat(format));
const std::size_t dataSize = Magnum::Implementation::compressedImageDataSizeFor(image.storage(), blockSize, blockDataSize, range.size());
/* Reallocate only if needed */
if(image.dataSize() < dataSize)
image.setData(image.storage(), CompressedPixelFormat(format), range.size(), {nullptr, dataSize}, usage);
else
image.setData(image.storage(), CompressedPixelFormat(format), range.size(), nullptr, usage);
/* The setData() call above updates the block properties, so just verify
they're the same as the ones used here as the ones from the umage get
used in applyCompressedPixelStoragePack() below */
CORRADE_INTERNAL_ASSERT(blockSize == image.blockSize() && blockDataSize == image.blockDataSize());
image.buffer().bindInternal(Buffer::TargetHint::PixelPack);
Context::current().state().renderer.applyPixelStoragePack(image.storage());
Context::current().state().renderer.applyCompressedPixelStoragePack(image);
glGetCompressedTextureSubImage(_id, level, range.min().x(), range.min().y(), range.min().z(), range.size().x(), range.size().y(), range.size().z(), dataSize, nullptr);
}
@ -535,7 +611,7 @@ CubeMapTexture& CubeMapTexture::setCompressedSubImage(const Int level, const Vec
createIfNotAlready();
Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
glCompressedTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), image.size().x(), image.size().y(), image.size().z(), GLenum(compressedPixelFormat(image.format())), Implementation::occupiedCompressedImageDataSize(image), image.data());
return *this;
}
@ -546,7 +622,7 @@ CubeMapTexture& CubeMapTexture::setCompressedSubImage(const Int level, const Vec
createIfNotAlready();
image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
glCompressedTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), image.size().x(), image.size().y(), image.size().z(), GLenum(image.format()), Implementation::occupiedCompressedImageDataSize(image), nullptr);
return *this;
}
@ -578,7 +654,7 @@ CubeMapTexture& CubeMapTexture::setCompressedSubImage(const CubeMapCoordinate co
#ifndef MAGNUM_TARGET_GLES2
Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack);
#endif
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
Context::current().state().texture.cubeCompressedSubImageImplementation(*this, coordinate, level, offset, image.size(), compressedPixelFormat(image.format()), image.data(), Implementation::occupiedCompressedImageDataSize(image));
return *this;
}
@ -586,7 +662,7 @@ CubeMapTexture& CubeMapTexture::setCompressedSubImage(const CubeMapCoordinate co
#ifndef MAGNUM_TARGET_GLES2
CubeMapTexture& CubeMapTexture::setCompressedSubImage(const CubeMapCoordinate coordinate, const Int level, const Vector2i& offset, CompressedBufferImage2D& image) {
image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack);
Context::current().state().renderer.applyPixelStorageUnpack(image.storage());
Context::current().state().renderer.applyCompressedPixelStorageUnpack(image);
Context::current().state().texture.cubeCompressedSubImageImplementation(*this, coordinate, level, offset, image.size(), image.format(), nullptr, Implementation::occupiedCompressedImageDataSize(image));
return *this;
}

48
src/Magnum/GL/CubeMapTexture.h

@ -663,15 +663,24 @@ class MAGNUM_GL_EXPORT CubeMapTexture: public AbstractTexture {
/**
* @brief Read given mip level of a compressed texture to an image
*
* Compression format and data size are taken from the texture, image
* size is taken using @ref imageSize(). Flags of @p image get reset to
* Compression format is taken from the texture, image size is taken
* using @ref imageSize(). Flags of @p image get reset to
* @ref ImageFlag3D::CubeMap. The storage is not reallocated if it is
* large enough to contain the new data --- however if you want to read
* into existing memory or *ensure* a reallocation does not happen, use
* @ref compressedImage(Int, const MutableCompressedImageView3D&)
* instead.
*
* The function assumes that the internal texture format is a known
* @ref CompressedPixelFormat in order to correctly size the output
* array using @ref compressedPixelFormatBlockSize() and
* @ref compressedPixelFormatBlockDataSize() properties queried on it.
* If it's not, use @ref compressedImage(Int, const MutableCompressedImageView3D&)
* instead and specify the format along with explicit block properties.
* You can also query the texture itself using
* @ref compressedBlockSize() and @ref compressedBlockDataSize() in
* that case, if available on given platform.
* @see @fn_gl2{GetTextureLevelParameter,GetTexLevelParameter} with
* @def_gl{TEXTURE_COMPRESSED_IMAGE_SIZE},
* @def_gl{TEXTURE_INTERNAL_FORMAT}, @def_gl{TEXTURE_WIDTH},
* @def_gl{TEXTURE_HEIGHT}, then
* @fn_gl2_keyword{GetCompressedTextureImage,GetCompressedTexImage}
@ -802,16 +811,26 @@ class MAGNUM_GL_EXPORT CubeMapTexture: public AbstractTexture {
/**
* @brief Read given compressed texture mip level and coordinate to an image
*
* Compression format and data size are taken from the texture, image
* size is taken using @ref imageSize(). Flags of @p image get cleared
* --- use @ref compressedImage(Int, CompressedImage3D&) instead if you
* want to get an image annotated with @ref ImageFlag3D::CubeMap. The
* storage is not reallocated if it is large enough to contain the new
* data --- however if you want to read into existing memory or
* *ensure* a reallocation does not happen, use
* Compression format is taken from the texture, image size is taken
* using @ref imageSize(). Flags of @p image get cleared --- use
* @ref compressedImage(Int, CompressedImage3D&) instead if you want to
* get an image annotated with @ref ImageFlag3D::CubeMap. The storage
* is not reallocated if it is large enough to contain the new data ---
* however if you want to read into existing memory or *ensure* a
* reallocation does not happen, use
* @ref compressedImage(CubeMapCoordinate, Int, const MutableCompressedImageView2D&)
* instead.
*
* The function assumes that the internal texture format is a known
* @ref CompressedPixelFormat in order to correctly size the output
* array using @ref compressedPixelFormatBlockSize() and
* @ref compressedPixelFormatBlockDataSize() properties queried on it.
* If it's not, use @ref compressedImage(CubeMapCoordinate, Int, const MutableCompressedImageView2D&)
* instead and specify the format along with explicit block properties.
* You can also query the texture itself using
* @ref compressedBlockSize() and @ref compressedBlockDataSize() in
* that case, if available on given platform.
*
* If @gl_extension{ARB,get_texture_sub_image} (part of OpenGL 4.5) is
* not available, the texture is bound before the operation (if not
* already). If either @gl_extension{ARB,get_texture_sub_image} or
@ -819,7 +838,6 @@ class MAGNUM_GL_EXPORT CubeMapTexture: public AbstractTexture {
* protected from buffer overflow.
* @see @fn_gl2{GetTextureLevelParameter,GetTexLevelParameter},
* eventually @fn_gl{GetTexLevelParameter} with
* @def_gl{TEXTURE_COMPRESSED_IMAGE_SIZE},
* @def_gl{TEXTURE_INTERNAL_FORMAT}, @def_gl{TEXTURE_WIDTH},
* @def_gl{TEXTURE_HEIGHT}, then @fn_gl{PixelStore}, then
* @fn_gl_keyword{GetCompressedTextureSubImage},
@ -956,10 +974,6 @@ class MAGNUM_GL_EXPORT CubeMapTexture: public AbstractTexture {
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() or @ref DebugTools::textureSubImage()
* for possible workarounds.
@ -995,10 +1009,6 @@ class MAGNUM_GL_EXPORT CubeMapTexture: public AbstractTexture {
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() or @ref DebugTools::textureSubImage()
* for possible workarounds.

8
src/Magnum/GL/CubeMapTextureArray.h

@ -715,10 +715,6 @@ class MAGNUM_GL_EXPORT CubeMapTextureArray: public AbstractTexture {
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
* @requires_gl Texture image queries are not available in OpenGL ES.
* See @ref Framebuffer::read() or @ref DebugTools::textureSubImage()
* for possible workarounds.
@ -761,10 +757,6 @@ class MAGNUM_GL_EXPORT CubeMapTextureArray: public AbstractTexture {
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
* @requires_gl Texture image queries are not available in OpenGL ES.
* See @ref Framebuffer::read() or @ref DebugTools::textureSubImage()
* for possible workarounds.

25
src/Magnum/GL/Implementation/RendererState.cpp

@ -359,39 +359,46 @@ void RendererState::applyPixelStorageInternal(const Magnum::PixelStorage& storag
#endif
}
void RendererState::applyPixelStorageInternal(const CompressedPixelStorage& storage, const bool isUnpack) {
void RendererState::applyCompressedPixelStorageInternal(const CompressedPixelStorage& storage, const Vector3i& blockSize, const Int blockDataSize, const bool isUnpack) {
#ifdef MAGNUM_TARGET_GLES
CORRADE_ASSERT(storage == CompressedPixelStorage{},
"GL: non-default CompressedPixelStorage parameters are not supported in OpenGL ES or WebGL", );
static_cast<void>(blockSize);
static_cast<void>(blockDataSize);
static_cast<void>(isUnpack);
#else
/* The block properties should always be non-zero, either coming from an
Image(View) constructed with a particular format or from properties for
a format that was queried from GL */
CORRADE_INTERNAL_ASSERT(blockSize != Vector3i{} && blockDataSize != 0);
applyPixelStorageInternal(static_cast<const Magnum::PixelStorage&>(storage), isUnpack);
PixelStorage& state = isUnpack ? unpackPixelStorage : packPixelStorage;
/* Compressed block width */
if(state.compressedBlockSize.x() == PixelStorage::DisengagedValue ||
state.compressedBlockSize.x() != storage.compressedBlockSize().x())
state.compressedBlockSize.x() != blockSize.x())
glPixelStorei(isUnpack ? GL_UNPACK_COMPRESSED_BLOCK_WIDTH : GL_PACK_COMPRESSED_BLOCK_WIDTH,
state.compressedBlockSize.x() = storage.compressedBlockSize().x());
state.compressedBlockSize.x() = blockSize.x());
/* Compressed block height */
if(state.compressedBlockSize.y() == PixelStorage::DisengagedValue ||
state.compressedBlockSize.y() != storage.compressedBlockSize().y())
state.compressedBlockSize.y() != blockSize.y())
glPixelStorei(isUnpack ? GL_UNPACK_COMPRESSED_BLOCK_HEIGHT : GL_PACK_COMPRESSED_BLOCK_HEIGHT,
state.compressedBlockSize.y() = storage.compressedBlockSize().y());
state.compressedBlockSize.y() = blockSize.y());
/* Compressed block depth */
if(state.compressedBlockSize.z() == PixelStorage::DisengagedValue ||
state.compressedBlockSize.z() != storage.compressedBlockSize().z())
state.compressedBlockSize.z() != blockSize.z())
glPixelStorei(isUnpack ? GL_UNPACK_COMPRESSED_BLOCK_DEPTH : GL_PACK_COMPRESSED_BLOCK_DEPTH,
state.compressedBlockSize.z() = storage.compressedBlockSize().z());
state.compressedBlockSize.z() = blockSize.z());
/* Compressed block size */
if(state.compressedBlockDataSize == PixelStorage::DisengagedValue ||
state.compressedBlockDataSize != storage.compressedBlockDataSize())
state.compressedBlockDataSize != blockDataSize)
glPixelStorei(isUnpack ? GL_UNPACK_COMPRESSED_BLOCK_SIZE : GL_PACK_COMPRESSED_BLOCK_SIZE,
state.compressedBlockDataSize = storage.compressedBlockDataSize());
state.compressedBlockDataSize = blockDataSize);
#endif
}

23
src/Magnum/GL/Implementation/RendererState.h

@ -117,17 +117,26 @@ struct RendererState {
void applyPixelStorageUnpack(const Magnum::PixelStorage& storage) {
applyPixelStorageInternal(storage, true);
}
/* Deleted to avoid accidents -- use applyCompressedPixelStorage*() */
void applyPixelStoragePack(const Magnum::CompressedPixelStorage&) = delete;
void applyPixelStorageUnpack(const Magnum::CompressedPixelStorage&) = delete;
/* Bool parameter is ugly, but this is implementation detail of internal
API so who cares */
void applyPixelStorageInternal(const CompressedPixelStorage& storage, bool unpack);
/* Used internally in *Texture::compressedImage(), *Texture::compressedSubImage(),
*Texture::setCompressedImage() and *Texture::setCompressedSubImage() */
void applyPixelStoragePack(const CompressedPixelStorage& storage) {
applyPixelStorageInternal(storage, false);
void applyCompressedPixelStorageInternal(const CompressedPixelStorage& storage, const Vector3i& blockSize, Int blockDataSize, bool unpack);
/* Used internally in *Texture::compressedImage(),
*Texture::compressedSubImage(), *Texture::setCompressedImage() and
*Texture::setCompressedSubImage(). The overload with explicit block
properties is used in APIs that take an Image& and which replace it with
am image of a new format along with its properties. */
void applyCompressedPixelStoragePack(const CompressedPixelStorage& storage, const Vector3i& blockSize, Int blockDataSize) {
applyCompressedPixelStorageInternal(storage, blockSize, blockDataSize, false);
}
void applyPixelStorageUnpack(const CompressedPixelStorage& storage) {
applyPixelStorageInternal(storage, true);
template<class T> void applyCompressedPixelStoragePack(const T& image) {
applyCompressedPixelStoragePack(image.storage(), image.blockSize(), image.blockDataSize());
}
template<class T> void applyCompressedPixelStorageUnpack(const T& image) {
applyCompressedPixelStorageInternal(image.storage(), image.blockSize(), image.blockDataSize(), true);
}
};

8
src/Magnum/GL/RectangleTexture.h

@ -545,10 +545,6 @@ class MAGNUM_GL_EXPORT RectangleTexture: public AbstractTexture {
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
*/
void compressedSubImage(const Range2Di& range, CompressedImage2D& image) {
AbstractTexture::compressedSubImage<2>(0, range, image, ImageFlags2D{});
@ -585,10 +581,6 @@ class MAGNUM_GL_EXPORT RectangleTexture: public AbstractTexture {
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
*/
void compressedSubImage(const Range2Di& range, CompressedBufferImage2D& image, BufferUsage usage) {
AbstractTexture::compressedSubImage<2>(0, range, image, usage);

6
src/Magnum/GL/Test/AbstractTextureGLTest.cpp

@ -252,8 +252,6 @@ void AbstractTextureGLTest::compressedSubImageQueryViewNullptr() {
CORRADE_SKIP(Extensions::ARB::get_texture_sub_image::string() << "is not supported.");
if(!Context::current().isExtensionSupported<Extensions::EXT::texture_compression_s3tc>())
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(!Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture2D texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{4});
@ -275,8 +273,6 @@ void AbstractTextureGLTest::compressedSubImageQueryViewBadSize() {
CORRADE_SKIP(Extensions::ARB::get_texture_sub_image::string() << "is not supported.");
if(!Context::current().isExtensionSupported<Extensions::EXT::texture_compression_s3tc>())
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(!Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture2D texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{4});
@ -299,8 +295,6 @@ void AbstractTextureGLTest::compressedSubImageQueryViewBadFormat() {
CORRADE_SKIP(Extensions::ARB::get_texture_sub_image::string() << "is not supported.");
if(!Context::current().isExtensionSupported<Extensions::EXT::texture_compression_s3tc>())
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(!Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture2D texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{4});

6
src/Magnum/GL/Test/CubeMapTextureArrayGLTest.cpp

@ -1305,8 +1305,6 @@ void CubeMapTextureArrayGLTest::compressedSubImageQuery() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
CubeMapTextureArray texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 12, 6})
@ -1338,8 +1336,6 @@ void CubeMapTextureArrayGLTest::compressedSubImageQueryView() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
CubeMapTextureArray texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 12, 6})
@ -1373,8 +1369,6 @@ void CubeMapTextureArrayGLTest::compressedSubImageQueryBuffer() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
CubeMapTextureArray texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 12, 6})

6
src/Magnum/GL/Test/CubeMapTextureGLTest.cpp

@ -1698,8 +1698,6 @@ void CubeMapTextureGLTest::compressedSubImageQuery() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
CubeMapTexture texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{12})
@ -1728,8 +1726,6 @@ void CubeMapTextureGLTest::compressedSubImageQueryView() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
CubeMapTexture texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{12})
@ -1820,8 +1816,6 @@ void CubeMapTextureGLTest::compressedSubImageQueryBuffer() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
CubeMapTexture texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{12})

6
src/Magnum/GL/Test/TextureArrayGLTest.cpp

@ -1940,8 +1940,6 @@ void TextureArrayGLTest::compressedSubImage2DQuery() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture2DArray texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4, 4})
@ -1974,8 +1972,6 @@ void TextureArrayGLTest::compressedSubImage2DQueryView() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture2DArray texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4, 4})
@ -2010,8 +2006,6 @@ void TextureArrayGLTest::compressedSubImage2DQueryBuffer() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture2DArray texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4, 4})

12
src/Magnum/GL/Test/TextureGLTest.cpp

@ -2389,8 +2389,6 @@ void TextureGLTest::compressedSubImage2DQuery() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture2D texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4})
@ -2420,8 +2418,6 @@ void TextureGLTest::compressedSubImage2DQueryView() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture2D texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4})
@ -2453,8 +2449,6 @@ void TextureGLTest::compressedSubImage2DQueryBuffer() {
CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture2D texture;
texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4})
@ -3010,8 +3004,6 @@ void TextureGLTest::compressedSubImage3DQuery() {
CORRADE_SKIP(Extensions::ARB::texture_compression_bptc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture3D texture;
texture.setStorage(1, TextureFormat::CompressedRGBABptcUnorm, {12, 4, 4})
@ -3044,8 +3036,6 @@ void TextureGLTest::compressedSubImage3DQueryView() {
CORRADE_SKIP(Extensions::ARB::texture_compression_bptc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture3D texture;
texture.setStorage(1, TextureFormat::CompressedRGBABptcUnorm, {12, 4, 4})
@ -3080,8 +3070,6 @@ void TextureGLTest::compressedSubImage3DQueryBuffer() {
CORRADE_SKIP(Extensions::ARB::texture_compression_bptc::string() << "is not supported.");
if(data.storage != CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::compressed_texture_pixel_storage>())
CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported.");
if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported<Extensions::ARB::internalformat_query2>())
CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported.");
Texture3D texture;
texture.setStorage(1, TextureFormat::CompressedRGBABptcUnorm, {12, 4, 4})

53
src/Magnum/GL/Texture.h

@ -943,14 +943,24 @@ Texture: public AbstractTexture {
* @param level Mip level
* @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(). @ref ImageFlags of @p image
* get cleared. The storage is not reallocated if it is large enough to
* contain the new data --- however if you want to read into existing
* memory or *ensure* a reallocation does not happen, use
* Compression format is taken from the texture, image size is taken
* using @ref imageSize(). @ref ImageFlags of @p image get cleared. The
* storage is not reallocated if it is large enough to contain the new
* data --- however if you want to read into existing memory or
* *ensure* a reallocation does not happen, use
* @ref compressedImage(Int, const BasicMutableCompressedImageView<dimensions>&)
* instead.
*
* The function assumes that the internal texture format is a known
* @ref CompressedPixelFormat in order to correctly size the output
* array using @ref compressedPixelFormatBlockSize() and
* @ref compressedPixelFormatBlockDataSize() properties queried on it.
* If it's not, use @ref compressedImage(Int, const BasicMutableCompressedImageView<dimensions>&)
* instead and specify the format along with explicit block properties.
* You can also query the texture itself using
* @ref compressedBlockSize() and @ref compressedBlockDataSize() in
* that case, if available on given platform.
*
* If @gl_extension{ARB,direct_state_access} (part of OpenGL 4.5) is
* not available, the texture is bound before the operation (if not
* already). If either @gl_extension{ARB,direct_state_access} or
@ -958,7 +968,6 @@ Texture: public AbstractTexture {
* protected from buffer overflow.
* @see @fn_gl2{GetTextureLevelParameter,GetTexLevelParameter},
* eventually @fn_gl{GetTexLevelParameter} with
* @def_gl{TEXTURE_COMPRESSED_IMAGE_SIZE},
* @def_gl{TEXTURE_INTERNAL_FORMAT}, @def_gl{TEXTURE_WIDTH},
* @def_gl{TEXTURE_HEIGHT}, @def_gl{TEXTURE_DEPTH}, then
* @fn_gl{PixelStore}, then
@ -1107,27 +1116,29 @@ Texture: public AbstractTexture {
* @param range Range to read
* @param image Image where to put the compressed data
*
* Compression format and data size are taken from the texture.
* @ref ImageFlags of @p image get cleared. The storage is not
* reallocated if it is large enough to contain the new data ---
* however if you want to read into existing memory or *ensure* a
* reallocation does not happen, use
* Compression format is taken from the texture. @ref ImageFlags of
* @p image get cleared. The storage is not reallocated if it is large
* enough to contain the new data --- however if you want to read into
* existing memory or *ensure* a reallocation does not happen, use
* @ref compressedSubImage(Int, const RangeTypeFor<dimensions, Int>&, const BasicMutableCompressedImageView<dimensions>&)
* instead.
*
* The function assumes that the internal texture format is a known
* @ref CompressedPixelFormat in order to correctly size the output
* array using @ref compressedPixelFormatBlockSize() and
* @ref compressedPixelFormatBlockDataSize() properties queried on it.
* If it's not, use@ref compressedSubImage(Int, const RangeTypeFor<dimensions, Int>&, const BasicMutableCompressedImageView<dimensions>&)
* instead and specify the format along with explicit block properties.
* You can also query the texture itself using
* @ref compressedBlockSize() and @ref compressedBlockDataSize() in
* that case, if available on given platform.
* @see @fn_gl2{GetTextureLevelParameter,GetTexLevelParameter},
* eventually @fn_gl{GetTexLevelParameter} with
* @def_gl{TEXTURE_INTERNAL_FORMAT}, then possibly
* @fn_gl{GetInternalformat} with @def_gl{TEXTURE_COMPRESSED_BLOCK_SIZE},
* @def_gl{TEXTURE_COMPRESSED_BLOCK_WIDTH} and
* @def_gl{TEXTURE_COMPRESSED_BLOCK_HEIGHT}, then
* @def_gl{TEXTURE_INTERNAL_FORMAT}, then
* @fn_gl_keyword{GetCompressedTextureSubImage}
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() or @ref DebugTools::textureSubImage()
* for possible workarounds.
@ -1171,10 +1182,6 @@ Texture: public AbstractTexture {
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() or @ref DebugTools::textureSubImage()
* for possible workarounds.

8
src/Magnum/GL/TextureArray.h

@ -796,10 +796,6 @@ TextureArray: public AbstractTexture {
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() or @ref DebugTools::textureSubImage()
* for possible workarounds.
@ -839,10 +835,6 @@ TextureArray: public AbstractTexture {
* @requires_gl45 Extension @gl_extension{ARB,get_texture_sub_image}
* @requires_gl42 Extension @gl_extension{ARB,compressed_texture_pixel_storage}
* for non-default @ref CompressedPixelStorage
* @requires_gl43 Extension @gl_extension{ARB,internalformat_query2} if
* @ref CompressedPixelStorage::compressedBlockSize() and
* @ref CompressedPixelStorage::compressedBlockDataSize() are not
* set to non-zero values
* @requires_gl Texture image queries are not available in OpenGL ES or
* WebGL. See @ref Framebuffer::read() or @ref DebugTools::textureSubImage()
* for possible workarounds.

6
src/Magnum/Implementation/ImageProperties.h

@ -190,6 +190,12 @@ template<std::size_t dimensions, class T> std::size_t compressedImageDataSizeFor
return r.first + r.second;
}
/* Used in image query functions */
template<std::size_t dimensions> std::size_t compressedImageDataSizeFor(const CompressedPixelStorage& storage, const Vector3i& blockSize, const UnsignedInt blockDataSize, const Math::Vector<dimensions, Int>& size) {
auto r = compressedImageDataOffsetSizeFor(storage, blockSize, blockDataSize, size);
return r.first + r.second;
}
/* Used in data size assertions */
template<class T> inline std::size_t compressedImageDataSize(const T& image) {
auto r = compressedImageDataOffsetSizeFor(image, image.size());

Loading…
Cancel
Save