diff --git a/src/Magnum/GL/AbstractTexture.cpp b/src/Magnum/GL/AbstractTexture.cpp index 520f4a5cf..28ef5c8d2 100644 --- a/src/Magnum/GL/AbstractTexture.cpp +++ b/src/Magnum/GL/AbstractTexture.cpp @@ -1794,18 +1794,23 @@ template void MAGNUM_GL_EXPORT AbstractTexture::image<3>(GLint, BufferImage<3>&, template void AbstractTexture::compressedImage(const GLint level, CompressedImage& image, const ImageFlags flags) { const Math::Vector size = DataHelper::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 data{image.release()}; @@ -1813,9 +1818,9 @@ template void AbstractTexture::compressedImage(const GLi data = Containers::Array{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{image.storage(), CompressedPixelFormat(format), size, Utility::move(data), flags}; + image = CompressedImage{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 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 void AbstractTexture::compressedImage(const GLint level, CompressedBufferImage& image, BufferUsage usage) { const Math::Vector size = DataHelper::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 std::size_t AbstractTexture::compressedSubImageSize(TextureFormat format, const Math::Vector& 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 blockSize = DataHelper::compressedBlockSize(_target, format); - return ((size + blockSize - Math::Vector{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 void AbstractTexture::compressedSubImage(const GLint level, const RangeTypeFor& range, CompressedImage& image, const ImageFlags 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 void AbstractTexture::compressedSubImage(const const Vector3i paddedOffset = Vector3i::pad(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(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 data{image.release()}; @@ -1982,7 +1995,7 @@ template void AbstractTexture::compressedSubImage(const data = Containers::Array{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{CompressedPixelFormat(format), size, Utility::move(data), flags}; } @@ -2001,22 +2014,26 @@ template void AbstractTexture::compressedSubImage(const created w/ the DSA extension disabled but below a DSA API is used */ createIfNotAlready(); - const Math::Vector 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(range.min()); - const Vector3i paddedSize = Vector3i::pad(size, 1); + const Vector3i paddedSize = Vector3i::pad(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 void AbstractTexture::compressedSubImage(const const Vector3i paddedOffset = Vector3i::pad(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(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 diff --git a/src/Magnum/GL/AbstractTexture.h b/src/Magnum/GL/AbstractTexture.h index 8768342af..f18c50e90 100644 --- a/src/Magnum/GL/AbstractTexture.h +++ b/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 std::size_t MAGNUM_GL_LOCAL compressedSubImageSize(TextureFormat format, const Math::Vector& 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); diff --git a/src/Magnum/GL/CubeMapTexture.cpp b/src/Magnum/GL/CubeMapTexture.cpp index 554980a8c..d9851a43d 100644 --- a/src/Magnum/GL/CubeMapTexture.cpp +++ b/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 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 dataOffsetSize = Magnum::Implementation::compressedImageDataOffsetSizeFor(image.storage(), blockSize, blockDataSize, size); /* Reallocate only if needed */ Containers::Array data{image.release()}; @@ -175,7 +184,7 @@ void CubeMapTexture::compressedImage(const Int level, CompressedImage3D& image) data = Containers::Array{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 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 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 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 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 data{image.release()}; @@ -329,7 +364,7 @@ void CubeMapTexture::compressedImage(const CubeMapCoordinate coordinate, const I data = Containers::Array{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 data{image.release()}; @@ -431,7 +490,7 @@ void CubeMapTexture::compressedSubImage(const Int level, const Range3Di& range, data = Containers::Array{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; } diff --git a/src/Magnum/GL/CubeMapTexture.h b/src/Magnum/GL/CubeMapTexture.h index ce0b97fa5..e7b221a5f 100644 --- a/src/Magnum/GL/CubeMapTexture.h +++ b/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. diff --git a/src/Magnum/GL/CubeMapTextureArray.h b/src/Magnum/GL/CubeMapTextureArray.h index 750799424..f1a7fe6fb 100644 --- a/src/Magnum/GL/CubeMapTextureArray.h +++ b/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. diff --git a/src/Magnum/GL/Implementation/RendererState.cpp b/src/Magnum/GL/Implementation/RendererState.cpp index cc6107d30..fcf90e276 100644 --- a/src/Magnum/GL/Implementation/RendererState.cpp +++ b/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(blockSize); + static_cast(blockDataSize); static_cast(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(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 } diff --git a/src/Magnum/GL/Implementation/RendererState.h b/src/Magnum/GL/Implementation/RendererState.h index 850fb2a19..ef475c1ea 100644 --- a/src/Magnum/GL/Implementation/RendererState.h +++ b/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 void applyCompressedPixelStoragePack(const T& image) { + applyCompressedPixelStoragePack(image.storage(), image.blockSize(), image.blockDataSize()); + } + template void applyCompressedPixelStorageUnpack(const T& image) { + applyCompressedPixelStorageInternal(image.storage(), image.blockSize(), image.blockDataSize(), true); } }; diff --git a/src/Magnum/GL/RectangleTexture.h b/src/Magnum/GL/RectangleTexture.h index 22c7403a9..d9d66439a 100644 --- a/src/Magnum/GL/RectangleTexture.h +++ b/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); diff --git a/src/Magnum/GL/Test/AbstractTextureGLTest.cpp b/src/Magnum/GL/Test/AbstractTextureGLTest.cpp index 1ac0c5bbf..17e2a9c18 100644 --- a/src/Magnum/GL/Test/AbstractTextureGLTest.cpp +++ b/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()) CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported."); - if(!Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported."); - if(!Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::EXT::texture_compression_s3tc::string() << "is not supported."); - if(!Context::current().isExtensionSupported()) - CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported."); Texture2D texture; texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{4}); diff --git a/src/Magnum/GL/Test/CubeMapTextureArrayGLTest.cpp b/src/Magnum/GL/Test/CubeMapTextureArrayGLTest.cpp index 4a82e662d..b4689c4fd 100644 --- a/src/Magnum/GL/Test/CubeMapTextureArrayGLTest.cpp +++ b/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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported."); CubeMapTextureArray texture; texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 12, 6}) diff --git a/src/Magnum/GL/Test/CubeMapTextureGLTest.cpp b/src/Magnum/GL/Test/CubeMapTextureGLTest.cpp index a85bf6538..005242ddb 100644 --- a/src/Magnum/GL/Test/CubeMapTextureGLTest.cpp +++ b/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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported."); CubeMapTexture texture; texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{12}) diff --git a/src/Magnum/GL/Test/TextureArrayGLTest.cpp b/src/Magnum/GL/Test/TextureArrayGLTest.cpp index d3e4d8d3f..7b56f0494 100644 --- a/src/Magnum/GL/Test/TextureArrayGLTest.cpp +++ b/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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported."); Texture2DArray texture; texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4, 4}) diff --git a/src/Magnum/GL/Test/TextureGLTest.cpp b/src/Magnum/GL/Test/TextureGLTest.cpp index 21cc05e91..f091e85a1 100644 --- a/src/Magnum/GL/Test/TextureGLTest.cpp +++ b/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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - 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()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); - if(data.storage == CompressedPixelStorage{} && !Context::current().isExtensionSupported()) - CORRADE_SKIP(Extensions::ARB::internalformat_query2::string() << "is not supported."); Texture3D texture; texture.setStorage(1, TextureFormat::CompressedRGBABptcUnorm, {12, 4, 4}) diff --git a/src/Magnum/GL/Texture.h b/src/Magnum/GL/Texture.h index 82a52be97..6d5e7d58f 100644 --- a/src/Magnum/GL/Texture.h +++ b/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&) * 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&) + * 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&, const BasicMutableCompressedImageView&) * 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&, const BasicMutableCompressedImageView&) + * 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. diff --git a/src/Magnum/GL/TextureArray.h b/src/Magnum/GL/TextureArray.h index 8219e82ca..8a19fdadc 100644 --- a/src/Magnum/GL/TextureArray.h +++ b/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. diff --git a/src/Magnum/Implementation/ImageProperties.h b/src/Magnum/Implementation/ImageProperties.h index 0a3755bf3..5ddb1f50b 100644 --- a/src/Magnum/Implementation/ImageProperties.h +++ b/src/Magnum/Implementation/ImageProperties.h @@ -190,6 +190,12 @@ template std::size_t compressedImageDataSizeFor return r.first + r.second; } +/* Used in image query functions */ +template std::size_t compressedImageDataSizeFor(const CompressedPixelStorage& storage, const Vector3i& blockSize, const UnsignedInt blockDataSize, const Math::Vector& size) { + auto r = compressedImageDataOffsetSizeFor(storage, blockSize, blockDataSize, size); + return r.first + r.second; +} + /* Used in data size assertions */ template inline std::size_t compressedImageDataSize(const T& image) { auto r = compressedImageDataOffsetSizeFor(image, image.size());