diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index b2bbb7566..68177a9c4 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -175,7 +175,7 @@ OpenGL function | Matching API @fn_gl2{GetBufferPointer,GetBufferPointerv}, \n `glGetNamedBufferPointer()`, \n @fn_gl_extension{GetNamedBufferPointer,EXT,direct_state_access} | not queryable, @ref Buffer::map() setter only @fn_gl{GetBufferSubData}, \n `glGetNamedBufferSubData()`, \n @fn_gl_extension{GetNamedBufferSubData,EXT,direct_state_access} | @ref Buffer::data(), \n @ref Buffer::subData() @fn_gl{GetCompressedTexImage}, \n `glGetnCompressedTexImage()`, \n @fn_gl_extension{GetnCompressedTexImage,ARB,robustness}, \n `glGetCompressedTextureImage()`, \n @fn_gl_extension{GetCompressedTextureImage,EXT,direct_state_access} | @ref Texture::compressedImage(), \n @ref TextureArray::compressedImage(), \n @ref CubeMapTexture::compressedImage(), \n @ref CubeMapTextureArray::compressedImage(), \n @ref RectangleTexture::compressedImage() -@fn_gl{GetCompressedTextureSubImage} | | +@fn_gl{GetCompressedTextureSubImage} | @ref Texture::compressedSubImage(), \n @ref TextureArray::compressedSubImage(), \n @ref CubeMapTexture::compressedImage(), \n @ref CubeMapTexture::compressedSubImage(), \n @ref CubeMapTextureArray::compressedSubImage(), \n @ref RectangleTexture::compressedSubImage() @fn_gl{GetDebugMessageLog} | | @fn_gl{GetError} | @ref Renderer::error() @fn_gl{GetFragDataIndex}, @fn_gl{GetFragDataLocation} | not queryable, @ref AbstractShaderProgram::bindFragmentDataLocation() and \n @ref AbstractShaderProgram::bindFragmentDataLocationIndexed() setters only diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 2a39b4ed4..f8ac8924b 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -222,7 +222,7 @@ GLSL 4.50 | done @extension{ARB,cull_distance} | | @extension{ARB,derivative_control} | done (shading language only) @extension{ARB,direct_state_access} | done for implemented functionality (except VAOs) -@extension{ARB,get_texture_sub_image} | missing compressed texture queries +@extension{ARB,get_texture_sub_image} | done @extension{ARB,shader_texture_image_samples} | done (shading language only) @extension{ARB,texture_barrier} | | @extension{KHR,context_flush_control} | | diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index d4fc418a5..94012890d 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -1629,6 +1629,64 @@ template void AbstractTexture::subImage(const GLint leve template void MAGNUM_EXPORT AbstractTexture::subImage<1>(GLint, const Range1Di&, BufferImage<1>&, BufferUsage); template void MAGNUM_EXPORT AbstractTexture::subImage<2>(GLint, const Range2Di&, BufferImage<2>&, BufferUsage); template void MAGNUM_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 void AbstractTexture::compressedSubImage(const GLint level, const RangeTypeFor& range, CompressedImage& image) { + createIfNotAlready(); + + const Math::Vector size = range.size(); + const Vector3i paddedOffset = Vector3i::pad(range.min()); + const Vector3i paddedSize = Vector3i::pad(size, 1); + GLint format; + (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); + const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, compressedSubImageSize(TextureFormat(format), size)); + + /* Reallocate only if needed */ + Containers::Array data{image.release()}; + if(data.size() < dataSize) + data = Containers::Array{dataSize}; + + Buffer::unbindInternal(Buffer::TargetHint::PixelPack); + image.storage().applyPack(); + glGetCompressedTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), data.size(), data); + image.setData(CompressedPixelFormat(format), size, std::move(data)); +} + +template void MAGNUM_EXPORT AbstractTexture::compressedSubImage<1>(GLint, const Range1Di&, CompressedImage<1>&); +template void MAGNUM_EXPORT AbstractTexture::compressedSubImage<2>(GLint, const Range2Di&, CompressedImage<2>&); +template void MAGNUM_EXPORT AbstractTexture::compressedSubImage<3>(GLint, const Range3Di&, CompressedImage<3>&); + +template void AbstractTexture::compressedSubImage(const GLint level, const RangeTypeFor& range, CompressedBufferImage& image, const BufferUsage usage) { + createIfNotAlready(); + + const Math::Vector size = range.size(); + const Vector3i paddedOffset = Vector3i::pad(range.min()); + const Vector3i paddedSize = Vector3i::pad(size, 1); + GLint format; + (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); + const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, compressedSubImageSize(TextureFormat(format), 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); + + image.buffer().bindInternal(Buffer::TargetHint::PixelPack); + image.storage().applyPack(); + glGetCompressedTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), dataSize, nullptr); +} + +template void MAGNUM_EXPORT AbstractTexture::compressedSubImage<1>(GLint, const Range1Di&, CompressedBufferImage<1>&, BufferUsage); +template void MAGNUM_EXPORT AbstractTexture::compressedSubImage<2>(GLint, const Range2Di&, CompressedBufferImage<2>&, BufferUsage); +template void MAGNUM_EXPORT AbstractTexture::compressedSubImage<3>(GLint, const Range3Di&, CompressedBufferImage<3>&, BufferUsage); #endif #endif diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index 2921da856..2b1657aa9 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -409,6 +409,8 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { template void compressedImage(GLint level, CompressedBufferImage& image, BufferUsage usage); template void subImage(GLint level, const RangeTypeFor& range, Image& image); template void subImage(GLint level, const RangeTypeFor& range, BufferImage& image, BufferUsage usage); + template void compressedSubImage(GLint level, const RangeTypeFor& range, CompressedImage& image); + template void compressedSubImage(GLint level, const RangeTypeFor& range, CompressedBufferImage& image, BufferUsage usage); #endif GLenum _target; @@ -431,6 +433,10 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { void MAGNUM_LOCAL createImplementationDSA(); #endif + #ifndef MAGNUM_TARGET_GLES + template std::size_t MAGNUM_LOCAL compressedSubImageSize(TextureFormat format, const Math::Vector& size); + #endif + void MAGNUM_LOCAL bindImplementationDefault(GLint textureUnit); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL bindImplementationMulti(GLint textureUnit); diff --git a/src/Magnum/CubeMapTexture.cpp b/src/Magnum/CubeMapTexture.cpp index f29e4ea51..49d2ef01a 100644 --- a/src/Magnum/CubeMapTexture.cpp +++ b/src/Magnum/CubeMapTexture.cpp @@ -257,6 +257,16 @@ BufferImage3D CubeMapTexture::subImage(const Int level, const Range3Di& range, B return std::move(image); } +CompressedImage3D CubeMapTexture::compressedSubImage(const Int level, const Range3Di& range, CompressedImage3D&& image) { + compressedSubImage(level, range, image); + return std::move(image); +} + +CompressedBufferImage3D CubeMapTexture::compressedSubImage(const Int level, const Range3Di& range, CompressedBufferImage3D&& image, const BufferUsage usage) { + compressedSubImage(level, range, image, usage); + return std::move(image); +} + CubeMapTexture& CubeMapTexture::setSubImage(const Int level, const Vector3i& offset, const ImageView3D& image) { createIfNotAlready(); diff --git a/src/Magnum/CubeMapTexture.h b/src/Magnum/CubeMapTexture.h index dda1c8861..2ee70927a 100644 --- a/src/Magnum/CubeMapTexture.h +++ b/src/Magnum/CubeMapTexture.h @@ -721,6 +721,50 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture { * @endcode */ BufferImage3D subImage(Int level, const Range3Di& range, BufferImage3D&& image, BufferUsage usage); + + /** + * @copybrief Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedImage&) + * + * See @ref Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedImage&) + * for more information. + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + * @requires_gl Texture image queries are not available in OpenGL ES or + * WebGL. See @ref Framebuffer::read() for possible workaround. + */ + void compressedSubImage(Int level, const Range3Di& range, CompressedImage3D& image) { + AbstractTexture::compressedSubImage<3>(level, range, image); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedImage3D image = texture.compressedSubImage(0, range, {}); + * @endcode + */ + CompressedImage3D compressedSubImage(Int level, const Range3Di& range, CompressedImage3D&& image); + + /** + * @copybrief Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedBufferImage&, BufferUsage) + * + * See @ref Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedBufferImage&, BufferUsage) + * for more information. + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + * @requires_gl Texture image queries are not available in OpenGL ES or + * WebGL. See @ref Framebuffer::read() for possible workaround. + */ + void compressedSubImage(Int level, const Range3Di& range, CompressedBufferImage3D& image, BufferUsage usage) { + AbstractTexture::compressedSubImage<3>(level, range, image, usage); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedBufferImage3D image = texture.compressedSubImage(0, range, {}, BufferUsage::StaticRead); + * @endcode + */ + CompressedBufferImage3D compressedSubImage(Int level, const Range3Di& range, CompressedBufferImage3D&& image, BufferUsage usage); #endif /** diff --git a/src/Magnum/CubeMapTextureArray.cpp b/src/Magnum/CubeMapTextureArray.cpp index a0a8535a0..009a6acf7 100644 --- a/src/Magnum/CubeMapTextureArray.cpp +++ b/src/Magnum/CubeMapTextureArray.cpp @@ -78,6 +78,16 @@ BufferImage3D CubeMapTextureArray::subImage(const Int level, const Range3Di& ran this->subImage(level, range, image, usage); return std::move(image); } + +CompressedImage3D CubeMapTextureArray::compressedSubImage(const Int level, const Range3Di& range, CompressedImage3D&& image) { + compressedSubImage(level, range, image); + return std::move(image); +} + +CompressedBufferImage3D CubeMapTextureArray::compressedSubImage(const Int level, const Range3Di& range, CompressedBufferImage3D&& image, const BufferUsage usage) { + compressedSubImage(level, range, image, usage); + return std::move(image); +} #endif } diff --git a/src/Magnum/CubeMapTextureArray.h b/src/Magnum/CubeMapTextureArray.h index fc9f8f9ce..a78abb21b 100644 --- a/src/Magnum/CubeMapTextureArray.h +++ b/src/Magnum/CubeMapTextureArray.h @@ -526,6 +526,50 @@ class MAGNUM_EXPORT CubeMapTextureArray: public AbstractTexture { * @endcode */ BufferImage3D subImage(Int level, const Range3Di& range, BufferImage3D&& image, BufferUsage usage); + + /** + * @copybrief Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedImage&) + * + * See @ref Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedImage&) + * for more information. + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + * @requires_gl Texture image queries are not available in OpenGL ES. + * See @ref Framebuffer::read() for possible workaround. + */ + void compressedSubImage(Int level, const Range3Di& range, CompressedImage3D& image) { + AbstractTexture::compressedSubImage<3>(level, range, image); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedImage3D image = texture.compressedSubImage(0, range, {}); + * @endcode + */ + CompressedImage3D compressedSubImage(Int level, const Range3Di& range, CompressedImage3D&& image); + + /** + * @copybrief Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedBufferImage&, BufferUsage) + * + * See @ref Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedBufferImage&, BufferUsage) + * for more information. + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + * @requires_gl Texture image queries are not available in OpenGL ES. + * See @ref Framebuffer::read() for possible workaround. + */ + void compressedSubImage(Int level, const Range3Di& range, CompressedBufferImage3D& image, BufferUsage usage) { + AbstractTexture::compressedSubImage<3>(level, range, image, usage); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedBufferImage3D image = texture.compressedSubImage(0, range, {}, BufferUsage::StaticRead); + * @endcode + */ + CompressedBufferImage3D compressedSubImage(Int level, const Range3Di& range, CompressedBufferImage3D&& image, BufferUsage usage); #endif /** diff --git a/src/Magnum/RectangleTexture.cpp b/src/Magnum/RectangleTexture.cpp index 1a7b93a2b..ef516190f 100644 --- a/src/Magnum/RectangleTexture.cpp +++ b/src/Magnum/RectangleTexture.cpp @@ -78,5 +78,15 @@ BufferImage2D RectangleTexture::subImage(const Range2Di& range, BufferImage2D&& return std::move(image); } +CompressedImage2D RectangleTexture::compressedSubImage(const Range2Di& range, CompressedImage2D&& image) { + compressedSubImage(range, image); + return std::move(image); +} + +CompressedBufferImage2D RectangleTexture::compressedSubImage(const Range2Di& range, CompressedBufferImage2D&& image, const BufferUsage usage) { + compressedSubImage(range, image, usage); + return std::move(image); +} + } #endif diff --git a/src/Magnum/RectangleTexture.h b/src/Magnum/RectangleTexture.h index 186af3f70..11db9875e 100644 --- a/src/Magnum/RectangleTexture.h +++ b/src/Magnum/RectangleTexture.h @@ -414,6 +414,46 @@ class MAGNUM_EXPORT RectangleTexture: public AbstractTexture { */ BufferImage2D subImage(const Range2Di& range, BufferImage2D&& image, BufferUsage usage); + /** + * @copybrief Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedImage&) + * + * See @ref Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedImage&) + * for more information. + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + */ + void compressedSubImage(const Range2Di& range, CompressedImage2D& image) { + AbstractTexture::compressedSubImage<2>(0, range, image); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedImage2D image = texture.compressedSubImage(range, {}); + * @endcode + */ + CompressedImage2D compressedSubImage(const Range2Di& range, CompressedImage2D&& image); + + /** + * @copybrief Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedBufferImage&, BufferUsage) + * + * See @ref Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedBufferImage&, BufferUsage) + * for more information. + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + */ + void compressedSubImage(const Range2Di& range, CompressedBufferImage2D& image, BufferUsage usage) { + AbstractTexture::compressedSubImage<2>(0, range, image, usage); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedBufferImage2D image = texture.compressedSubImage(range, {}, BufferUsage::StaticRead); + * @endcode + */ + CompressedBufferImage2D compressedSubImage(const Range2Di& range, CompressedBufferImage2D&& image, BufferUsage usage); + /** * @copybrief Texture::setImage() * @return Reference to self (for method chaining) diff --git a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp index e97073d02..984ee06ee 100644 --- a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp @@ -66,7 +66,9 @@ struct CubeMapTextureArrayGLTest: AbstractOpenGLTester { void compressedSubImageBuffer(); #ifndef MAGNUM_TARGET_GLES void subImageQuery(); + void compressedSubImageQuery(); void subImageQueryBuffer(); + void compressedSubImageQueryBuffer(); #endif void generateMipmap(); @@ -109,7 +111,9 @@ CubeMapTextureArrayGLTest::CubeMapTextureArrayGLTest() { &CubeMapTextureArrayGLTest::compressedSubImageBuffer, #ifndef MAGNUM_TARGET_GLES &CubeMapTextureArrayGLTest::subImageQuery, + &CubeMapTextureArrayGLTest::compressedSubImageQuery, &CubeMapTextureArrayGLTest::subImageQueryBuffer, + &CubeMapTextureArrayGLTest::compressedSubImageQueryBuffer, #endif &CubeMapTextureArrayGLTest::generateMipmap, @@ -840,6 +844,41 @@ void CubeMapTextureArrayGLTest::subImageQuery() { Containers::ArrayView{SubData}, TestSuite::Compare::Container); } +void CubeMapTextureArrayGLTest::compressedSubImageQuery() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_compression_s3tc::string() + std::string(" is not supported.")); + + CubeMapTextureArray texture; + texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 12, 6}) + .setCompressedSubImage(0, {}, CompressedImageView3D{CompressedPixelFormat::RGBAS3tcDxt3, {12, 12, 6}, CompressedSubDataComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + /* Test also without compressed pixel storage to ensure that both size + computations work */ + if(Context::current()->isExtensionSupported()) { + CompressedImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 4, 1}, Vector3i{4}), {}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i{4}); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}), + Containers::ArrayView{CompressedSubData}, TestSuite::Compare::Container); + } + + CompressedImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 4, 1}, Vector3i{4}), {_compressedSubDataStorage}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i{4}); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}.suffix(_compressedSubDataOffset)), + Containers::ArrayView{CompressedSubData}, TestSuite::Compare::Container); +} + void CubeMapTextureArrayGLTest::subImageQueryBuffer() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported.")); @@ -862,6 +901,39 @@ void CubeMapTextureArrayGLTest::subImageQueryBuffer() { CORRADE_COMPARE_AS(imageData.suffix(SubDataOffset), Containers::ArrayView{SubData}, TestSuite::Compare::Container); } + +void CubeMapTextureArrayGLTest::compressedSubImageQueryBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_compression_s3tc::string() + std::string(" is not supported.")); + + CubeMapTextureArray texture; + texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 12, 6}) + .setCompressedSubImage(0, {}, CompressedImageView3D{CompressedPixelFormat::RGBAS3tcDxt3, {12, 12, 6}, CompressedSubDataComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + /* Test also without compressed pixel storage to ensure that both size + computations work */ + if(Context::current()->isExtensionSupported()) { + CompressedBufferImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 4, 1}, Vector3i{4}), {}, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i{4}); + CORRADE_COMPARE_AS(imageData, Containers::ArrayView{CompressedSubData}, TestSuite::Compare::Container); + } + + CompressedBufferImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 4, 1}, Vector3i{4}), {_compressedSubDataStorage}, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i{4}); + CORRADE_COMPARE_AS(imageData.suffix(_compressedSubDataOffset), Containers::ArrayView{CompressedSubData}, TestSuite::Compare::Container); +} #endif void CubeMapTextureArrayGLTest::generateMipmap() { diff --git a/src/Magnum/Test/CubeMapTextureGLTest.cpp b/src/Magnum/Test/CubeMapTextureGLTest.cpp index 324f81a57..5e5534673 100644 --- a/src/Magnum/Test/CubeMapTextureGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureGLTest.cpp @@ -90,7 +90,9 @@ struct CubeMapTextureGLTest: AbstractOpenGLTester { #endif #ifndef MAGNUM_TARGET_GLES void subImageQuery(); + void compressedSubImageQuery(); void subImageQueryBuffer(); + void compressedSubImageQueryBuffer(); #endif void generateMipmap(); @@ -157,7 +159,9 @@ CubeMapTextureGLTest::CubeMapTextureGLTest() { #endif #ifndef MAGNUM_TARGET_GLES &CubeMapTextureGLTest::subImageQuery, + &CubeMapTextureGLTest::compressedSubImageQuery, &CubeMapTextureGLTest::subImageQueryBuffer, + &CubeMapTextureGLTest::compressedSubImageQueryBuffer, #endif &CubeMapTextureGLTest::generateMipmap, @@ -991,6 +995,44 @@ void CubeMapTextureGLTest::subImageQuery() { Containers::ArrayView{Data}, TestSuite::Compare::Container); } +void CubeMapTextureGLTest::compressedSubImageQuery() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); + /* I'm too lazy to call setSubImage() six times */ + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::direct_state_access::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_compression_s3tc::string() + std::string(" is not supported.")); + + CubeMapTexture texture; + texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{12}) + .setCompressedSubImage(0, {}, CompressedImageView3D{CompressedPixelFormat::RGBAS3tcDxt3, {12, 12, 1}, CompressedSubDataComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + /* Test also without compressed pixel storage to ensure that both size + computations work */ + if(Context::current()->isExtensionSupported()) { + CompressedImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 4, 0}, {4, 4, 1}), {}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), (Vector3i{4, 4, 1})); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}), + Containers::ArrayView{CompressedData}, TestSuite::Compare::Container); + } + + CompressedImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 4, 0}, {4, 4, 1}), {_compressedDataStorage}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), (Vector3i{4, 4, 1})); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}.suffix(_compressedDataOffset)), + Containers::ArrayView{CompressedData}, TestSuite::Compare::Container); +} + void CubeMapTextureGLTest::subImageQueryBuffer() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); @@ -1013,6 +1055,42 @@ void CubeMapTextureGLTest::subImageQueryBuffer() { CORRADE_COMPARE(image.size(), Vector3i(2, 2, 1)); CORRADE_COMPARE_AS(imageData.suffix(_dataOffset), Containers::ArrayView{Data}, TestSuite::Compare::Container); } + +void CubeMapTextureGLTest::compressedSubImageQueryBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); + /* I'm too lazy to call setSubImage() six times */ + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::direct_state_access::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_compression_s3tc::string() + std::string(" is not supported.")); + + CubeMapTexture texture; + texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, Vector2i{12}) + .setCompressedSubImage(0, {}, CompressedImageView3D{CompressedPixelFormat::RGBAS3tcDxt3, {12, 12, 1}, CompressedSubDataComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + /* Test also without compressed pixel storage to ensure that both size + computations work */ + if(Context::current()->isExtensionSupported()) { + CompressedBufferImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 4, 0}, {4, 4, 1}), {}, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), (Vector3i{4, 4, 1})); + CORRADE_COMPARE_AS(imageData, Containers::ArrayView{CompressedData}, TestSuite::Compare::Container); + } + + CompressedBufferImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 4, 0}, {4, 4, 1}), {_compressedDataStorage}, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), (Vector3i{4, 4, 1})); + CORRADE_COMPARE_AS(imageData.suffix(_compressedDataOffset), Containers::ArrayView{CompressedData}, TestSuite::Compare::Container); +} #endif void CubeMapTextureGLTest::generateMipmap() { diff --git a/src/Magnum/Test/RectangleTextureGLTest.cpp b/src/Magnum/Test/RectangleTextureGLTest.cpp index e6ea19b7a..091dee333 100644 --- a/src/Magnum/Test/RectangleTextureGLTest.cpp +++ b/src/Magnum/Test/RectangleTextureGLTest.cpp @@ -64,7 +64,9 @@ struct RectangleTextureGLTest: AbstractOpenGLTester { void subImageBuffer(); void compressedSubImageBuffer(); void subImageQuery(); + void compressedSubImageQuery(); void subImageQueryBuffer(); + void compressedSubImageQueryBuffer(); void invalidateImage(); void invalidateSubImage(); @@ -95,7 +97,9 @@ RectangleTextureGLTest::RectangleTextureGLTest() { &RectangleTextureGLTest::subImageBuffer, &RectangleTextureGLTest::compressedSubImageBuffer, &RectangleTextureGLTest::subImageQuery, + &RectangleTextureGLTest::compressedSubImageQuery, &RectangleTextureGLTest::subImageQueryBuffer, + &RectangleTextureGLTest::compressedSubImageQueryBuffer, &RectangleTextureGLTest::invalidateImage, &RectangleTextureGLTest::invalidateSubImage}); @@ -398,6 +402,10 @@ void RectangleTextureGLTest::subImageQuery() { Containers::ArrayView{Data}, TestSuite::Compare::Container); } +void RectangleTextureGLTest::compressedSubImageQuery() { + CORRADE_SKIP("No rectangle texture compression format exists."); +} + void RectangleTextureGLTest::subImageQueryBuffer() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); @@ -421,6 +429,10 @@ void RectangleTextureGLTest::subImageQueryBuffer() { Containers::ArrayView{Data}, TestSuite::Compare::Container); } +void RectangleTextureGLTest::compressedSubImageQueryBuffer() { + CORRADE_SKIP("No rectangle texture compression format exists."); +} + void RectangleTextureGLTest::invalidateImage() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); diff --git a/src/Magnum/Test/TextureArrayGLTest.cpp b/src/Magnum/Test/TextureArrayGLTest.cpp index ad79e364f..da8a88d93 100644 --- a/src/Magnum/Test/TextureArrayGLTest.cpp +++ b/src/Magnum/Test/TextureArrayGLTest.cpp @@ -117,7 +117,9 @@ struct TextureArrayGLTest: AbstractOpenGLTester { void subImage1DBuffer(); void compressedSubImage1DBuffer(); void subImage1DQuery(); + void compressedSubImage1DQuery(); void subImage1DQueryBuffer(); + void compressedSubImage1DQueryBuffer(); #endif void subImage2D(); void compressedSubImage2D(); @@ -125,7 +127,9 @@ struct TextureArrayGLTest: AbstractOpenGLTester { void compressedSubImage2DBuffer(); #ifndef MAGNUM_TARGET_GLES void subImage2DQuery(); + void compressedSubImage2DQuery(); void subImage2DQueryBuffer(); + void compressedSubImage2DQueryBuffer(); #endif #ifndef MAGNUM_TARGET_GLES @@ -225,7 +229,9 @@ TextureArrayGLTest::TextureArrayGLTest() { &TextureArrayGLTest::subImage1DBuffer, &TextureArrayGLTest::compressedSubImage1DBuffer, &TextureArrayGLTest::subImage1DQuery, + &TextureArrayGLTest::compressedSubImage1DQuery, &TextureArrayGLTest::subImage1DQueryBuffer, + &TextureArrayGLTest::compressedSubImage1DQueryBuffer, #endif &TextureArrayGLTest::subImage2D, &TextureArrayGLTest::compressedSubImage2D, @@ -233,7 +239,9 @@ TextureArrayGLTest::TextureArrayGLTest() { &TextureArrayGLTest::compressedSubImage2DBuffer, #ifndef MAGNUM_TARGET_GLES &TextureArrayGLTest::subImage2DQuery, + &TextureArrayGLTest::compressedSubImage2DQuery, &TextureArrayGLTest::subImage2DQueryBuffer, + &TextureArrayGLTest::compressedSubImage2DQueryBuffer, #endif #ifndef MAGNUM_TARGET_GLES @@ -967,6 +975,10 @@ void TextureArrayGLTest::subImage1DQuery() { (Containers::ArrayView{image.data(), image.data().size()}.suffix(DataOffset1D)), Containers::ArrayView{Data1D}, TestSuite::Compare::Container); } +void TextureArrayGLTest::compressedSubImage1DQuery() { + CORRADE_SKIP("No 1D texture compression format exists."); +} + void TextureArrayGLTest::subImage1DQueryBuffer() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); @@ -989,6 +1001,10 @@ void TextureArrayGLTest::subImage1DQueryBuffer() { CORRADE_COMPARE_AS(imageData.suffix(DataOffset1D), Containers::ArrayView{Data1D}, TestSuite::Compare::Container); } + +void TextureArrayGLTest::compressedSubImage1DQueryBuffer() { + CORRADE_SKIP("No 1D texture compression format exists."); +} #endif namespace { @@ -1252,6 +1268,44 @@ void TextureArrayGLTest::subImage2DQuery() { (Containers::ArrayView{image.data(), image.data().size()}.suffix(DataOffset2D)), Containers::ArrayView{Data2D}, TestSuite::Compare::Container); } +void TextureArrayGLTest::compressedSubImage2DQuery() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_compression_s3tc::string() + std::string(" is not supported.")); + + Texture2DArray texture; + texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4, 4}) + .setCompressedSubImage(0, {}, CompressedImageView3D{CompressedPixelFormat::RGBAS3tcDxt3, + {12, 4, 4}, CompressedSubData2DComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + /* Test also without compressed pixel storage to ensure that both size + computations work */ + if(Context::current()->isExtensionSupported()) { + CompressedImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 0, 1}, {4, 4, 2}), {}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), (Vector3i{4, 4, 2})); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}), + Containers::ArrayView{CompressedData2D}, TestSuite::Compare::Container); + } + + CompressedImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 0, 1}, {4, 4, 2}), {_compressedDataStorage2D}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), (Vector3i{4, 4, 2})); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}.suffix(_compressedDataOffset2D)), + Containers::ArrayView{CompressedData2D}, TestSuite::Compare::Container); +} + void TextureArrayGLTest::subImage2DQueryBuffer() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); @@ -1275,6 +1329,36 @@ void TextureArrayGLTest::subImage2DQueryBuffer() { Containers::ArrayView{Data2D}, TestSuite::Compare::Container); } +void TextureArrayGLTest::compressedSubImage2DQueryBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_compression_s3tc::string() + std::string(" is not supported.")); + + Texture2DArray texture; + texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4, 4}) + .setCompressedSubImage(0, {}, CompressedImageView3D{CompressedPixelFormat::RGBAS3tcDxt3, + {12, 4, 4}, CompressedSubData2DComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + CompressedBufferImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 0, 1}, {4, 4, 2}), { + #ifndef MAGNUM_TARGET_GLES + _compressedDataStorage2D + #endif + }, BufferUsage::StaticRead); + + MAGNUM_VERIFY_NO_ERROR(); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), (Vector3i{4, 4, 2})); + CORRADE_COMPARE_AS(imageData.suffix(_compressedDataOffset2D), Containers::ArrayView{CompressedData2D}, TestSuite::Compare::Container); +} + void TextureArrayGLTest::generateMipmap1D() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not supported.")); diff --git a/src/Magnum/Test/TextureGLTest.cpp b/src/Magnum/Test/TextureGLTest.cpp index a3918c200..3e33caa9a 100644 --- a/src/Magnum/Test/TextureGLTest.cpp +++ b/src/Magnum/Test/TextureGLTest.cpp @@ -139,7 +139,9 @@ struct TextureGLTest: AbstractOpenGLTester { void subImage1DBuffer(); void compressedSubImage1DBuffer(); void subImage1DQuery(); + void compressedSubImage1DQuery(); void subImage1DQueryBuffer(); + void compressedSubImage1DQueryBuffer(); #endif void subImage2D(); void compressedSubImage2D(); @@ -149,7 +151,9 @@ struct TextureGLTest: AbstractOpenGLTester { #endif #ifndef MAGNUM_TARGET_GLES void subImage2DQuery(); + void compressedSubImage2DQuery(); void subImage2DQueryBuffer(); + void compressedSubImage2DQueryBuffer(); #endif void subImage3D(); void compressedSubImage3D(); @@ -159,7 +163,9 @@ struct TextureGLTest: AbstractOpenGLTester { #endif #ifndef MAGNUM_TARGET_GLES void subImage3DQuery(); + void compressedSubImage3DQuery(); void subImage3DQueryBuffer(); + void compressedSubImage3DQueryBuffer(); #endif #ifndef MAGNUM_TARGET_GLES @@ -286,7 +292,9 @@ TextureGLTest::TextureGLTest() { &TextureGLTest::subImage1DBuffer, &TextureGLTest::compressedSubImage1DBuffer, &TextureGLTest::subImage1DQuery, + &TextureGLTest::compressedSubImage1DQuery, &TextureGLTest::subImage1DQueryBuffer, + &TextureGLTest::compressedSubImage1DQueryBuffer, #endif &TextureGLTest::subImage2D, &TextureGLTest::compressedSubImage2D, @@ -296,7 +304,9 @@ TextureGLTest::TextureGLTest() { #endif #ifndef MAGNUM_TARGET_GLES &TextureGLTest::subImage2DQuery, + &TextureGLTest::compressedSubImage2DQuery, &TextureGLTest::subImage2DQueryBuffer, + &TextureGLTest::compressedSubImage2DQueryBuffer, #endif &TextureGLTest::subImage3D, &TextureGLTest::compressedSubImage3D, @@ -306,7 +316,9 @@ TextureGLTest::TextureGLTest() { #endif #ifndef MAGNUM_TARGET_GLES &TextureGLTest::subImage3DQuery, + &TextureGLTest::compressedSubImage3DQuery, &TextureGLTest::subImage3DQueryBuffer, + &TextureGLTest::compressedSubImage3DQueryBuffer, #endif #ifndef MAGNUM_TARGET_GLES @@ -1316,6 +1328,10 @@ void TextureGLTest::subImage1DQuery() { (Containers::ArrayView{image.data(), image.data().size()}.suffix(DataOffset1D)), Containers::ArrayView{Data1D}, TestSuite::Compare::Container); } +void TextureGLTest::compressedSubImage1DQuery() { + CORRADE_SKIP("No 1D texture compression format exists."); +} + void TextureGLTest::subImage1DQueryBuffer() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); @@ -1336,6 +1352,10 @@ void TextureGLTest::subImage1DQueryBuffer() { CORRADE_COMPARE_AS(imageData.suffix(DataOffset1D), Containers::ArrayView{Data1D}, TestSuite::Compare::Container); } + +void TextureGLTest::compressedSubImage1DQueryBuffer() { + CORRADE_SKIP("No 1D texture compression format exists."); +} #endif namespace { @@ -1491,6 +1511,41 @@ void TextureGLTest::subImage2DQuery() { (Containers::ArrayView{image.data(), image.data().size()}.suffix(_dataOffset2D)), Containers::ArrayView{Data2D}, TestSuite::Compare::Container); } +void TextureGLTest::compressedSubImage2DQuery() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_compression_s3tc::string() + std::string(" is not supported.")); + + Texture2D texture; + texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4}) + .setCompressedSubImage(0, {}, CompressedImageView2D{CompressedPixelFormat::RGBAS3tcDxt3, {12, 4}, CompressedSubData2DComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + /* Test also without compressed pixel storage to ensure that both size + computations work */ + if(Context::current()->isExtensionSupported()) { + CompressedImage2D image = texture.compressedSubImage(0, Range2Di::fromSize({4, 0}, Vector2i{4}), {}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i{4}); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}), + Containers::ArrayView{CompressedData2D}, TestSuite::Compare::Container); + } + + CompressedImage2D image = texture.compressedSubImage(0, Range2Di::fromSize({4, 0}, Vector2i{4}), {_compressedDataStorage2D}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i{4}); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}.suffix(_compressedDataOffset2D)), + Containers::ArrayView{CompressedData2D}, TestSuite::Compare::Container); +} + void TextureGLTest::subImage2DQueryBuffer() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); @@ -1511,6 +1566,39 @@ void TextureGLTest::subImage2DQueryBuffer() { CORRADE_COMPARE_AS(imageData.suffix(_dataOffset2D), Containers::ArrayView{Data2D}, TestSuite::Compare::Container); } + +void TextureGLTest::compressedSubImage2DQueryBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_compression_s3tc::string() + std::string(" is not supported.")); + + Texture2D texture; + texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {12, 4}) + .setCompressedSubImage(0, {}, CompressedImageView2D{CompressedPixelFormat::RGBAS3tcDxt3, {12, 4}, CompressedSubData2DComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + /* Test also without compressed pixel storage to ensure that both size + computations work */ + if(Context::current()->isExtensionSupported()) { + CompressedBufferImage2D image = texture.compressedSubImage(0, Range2Di::fromSize({4, 0}, Vector2i{4}), {}, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i{4}); + CORRADE_COMPARE_AS(imageData, Containers::ArrayView{CompressedData2D}, TestSuite::Compare::Container); + } + + CompressedBufferImage2D image = texture.compressedSubImage(0, Range2Di::fromSize({4, 0}, Vector2i{4}), {_compressedDataStorage2D}, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i{4}); + CORRADE_COMPARE_AS(imageData.suffix(_compressedDataOffset2D), Containers::ArrayView{CompressedData2D}, TestSuite::Compare::Container); +} #endif namespace { @@ -1707,6 +1795,41 @@ void TextureGLTest::subImage3DQuery() { (Containers::ArrayView{image.data(), image.data().size()}.suffix(_dataOffset3D)), Containers::ArrayView{Data3D}, TestSuite::Compare::Container); } +void TextureGLTest::compressedSubImage3DQuery() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_compression_bptc::string() + std::string(" is not supported.")); + + Texture3D texture; + texture.setStorage(1, TextureFormat::CompressedRGBABptcUnorm, {12, 4, 4}) + .setCompressedSubImage(0, {}, CompressedImageView3D{CompressedPixelFormat::RGBABptcUnorm, {12, 4, 4}, CompressedSubData3DComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + /* Test also without compressed pixel storage to ensure that both size + computations work */ + if(Context::current()->isExtensionSupported()) { + CompressedImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 0, 0}, Vector3i{4}), {}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), (Vector3i{4})); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}), + Containers::ArrayView{CompressedData3D}, TestSuite::Compare::Container); + } + + CompressedImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 0, 0}, Vector3i{4}), {_compressedDataStorage3D}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), (Vector3i{4})); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()}.suffix(_compressedDataOffset3D)), + Containers::ArrayView{CompressedData3D}, TestSuite::Compare::Container); +} + void TextureGLTest::subImage3DQueryBuffer() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); @@ -1728,6 +1851,39 @@ void TextureGLTest::subImage3DQueryBuffer() { Containers::ArrayView{Data3D}, TestSuite::Compare::Container); } +void TextureGLTest::compressedSubImage3DQueryBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::get_texture_sub_image::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_compression_bptc::string() + std::string(" is not supported.")); + + Texture3D texture; + texture.setStorage(1, TextureFormat::CompressedRGBABptcUnorm, {12, 4, 4}) + .setCompressedSubImage(0, {}, CompressedImageView3D{CompressedPixelFormat::RGBABptcUnorm, {12, 4, 4}, CompressedSubData3DComplete}); + + MAGNUM_VERIFY_NO_ERROR(); + + /* Test also without compressed pixel storage to ensure that both size + computations work */ + if(Context::current()->isExtensionSupported()) { + CompressedBufferImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 0, 0}, Vector3i{4}), {}, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i{4}); + CORRADE_COMPARE_AS(imageData, Containers::ArrayView{CompressedData3D}, TestSuite::Compare::Container); + } + + CompressedBufferImage3D image = texture.compressedSubImage(0, Range3Di::fromSize({4, 0, 0}, Vector3i{4}), {_compressedDataStorage3D}, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i{4}); + CORRADE_COMPARE_AS(imageData.suffix(_compressedDataOffset3D), Containers::ArrayView{CompressedData3D}, TestSuite::Compare::Container); +} + void TextureGLTest::generateMipmap1D() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not supported.")); diff --git a/src/Magnum/Texture.cpp b/src/Magnum/Texture.cpp index 018d8084b..db9553812 100644 --- a/src/Magnum/Texture.cpp +++ b/src/Magnum/Texture.cpp @@ -93,6 +93,16 @@ template BufferImage Texture::su return std::move(image); } +template CompressedImage Texture::compressedSubImage(const Int level, const RangeTypeFor& range, CompressedImage&& image) { + compressedSubImage(level, range, image); + return std::move(image); +} + +template CompressedBufferImage Texture::compressedSubImage(const Int level, const RangeTypeFor& range, CompressedBufferImage&& image, const BufferUsage usage) { + compressedSubImage(level, range, image, usage); + return std::move(image); +} + template class MAGNUM_EXPORT Texture<1>; template class MAGNUM_EXPORT Texture<2>; template class MAGNUM_EXPORT Texture<3>; diff --git a/src/Magnum/Texture.h b/src/Magnum/Texture.h index 288b0189a..c99773547 100644 --- a/src/Magnum/Texture.h +++ b/src/Magnum/Texture.h @@ -860,6 +860,61 @@ template class Texture: public AbstractTexture { * @endcode */ BufferImage subImage(Int level, const RangeTypeFor& range, BufferImage&& image, BufferUsage usage); + + /** + * @brief Read range of given compressed texture mip level to image + * @param level Mip level + * @param range Range to read + * @param image Image where to put the compressed data + * + * Compression format and data size are taken from the texture. + * @see @fn_gl2{GetTextureLevelParameter,GetTexLevelParameter}, + * @fn_gl_extension{GetTextureLevelParameter,EXT,direct_state_access}, + * eventually @fn_gl{GetTexLevelParameter} with + * @def_gl{TEXTURE_COMPRESSED_IMAGE_SIZE}, @def_gl{TEXTURE_INTERNAL_FORMAT}, + * then @fn_gl{GetCompressedTextureSubImage} + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + * @requires_gl Texture image queries are not available in OpenGL ES or + * WebGL. See @ref Framebuffer::read() for possible workaround. + */ + void compressedSubImage(Int level, const RangeTypeFor& range, CompressedImage& image) { + AbstractTexture::compressedSubImage(level, range, image); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedImage2D image = texture.compressedSubImage(0, rect, {}); + * @endcode + */ + CompressedImage compressedSubImage(Int level, const RangeTypeFor& range, CompressedImage&& image); + + /** + * @brief Read range of given compressed texture mip level to buffer image + * @param level Mip level + * @param range Range to read + * @param image Buffer image where to put the compressed data + * @param usage Buffer usage + * + * See @ref compressedSubImage(Int, const RangeTypeFor&, CompressedBufferImage&, BufferUsage) + * for more information. + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + * @requires_gl Texture image queries are not available in OpenGL ES or + * WebGL. See @ref Framebuffer::read() for possible workaround. + */ + void compressedSubImage(Int level, const RangeTypeFor& range, CompressedBufferImage& image, BufferUsage usage) { + AbstractTexture::compressedSubImage(level, range, image, usage); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedBufferImage2D image = texture.compressedSubImage(0, rect, {}, BufferUsage::StaticRead); + * @endcode + */ + CompressedBufferImage compressedSubImage(Int level, const RangeTypeFor& range, CompressedBufferImage&& image, BufferUsage usage); #endif /** diff --git a/src/Magnum/TextureArray.cpp b/src/Magnum/TextureArray.cpp index de611004f..e30f6cd6a 100644 --- a/src/Magnum/TextureArray.cpp +++ b/src/Magnum/TextureArray.cpp @@ -84,6 +84,16 @@ template BufferImage TextureArraysubImage(level, range, image, usage); return std::move(image); } + +template CompressedImage TextureArray::compressedSubImage(const Int level, const RangeTypeFor& range, CompressedImage&& image) { + compressedSubImage(level, range, image); + return std::move(image); +} + +template CompressedBufferImage TextureArray::compressedSubImage(const Int level, const RangeTypeFor& range, CompressedBufferImage&& image, const BufferUsage usage) { + compressedSubImage(level, range, image, usage); + return std::move(image); +} #endif #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/TextureArray.h b/src/Magnum/TextureArray.h index a61370ed4..d0f7498f2 100644 --- a/src/Magnum/TextureArray.h +++ b/src/Magnum/TextureArray.h @@ -551,6 +551,50 @@ template class TextureArray: public AbstractTexture { * @endcode */ BufferImage subImage(Int level, const RangeTypeFor& range, BufferImage&& image, BufferUsage usage); + + /** + * @copybrief Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedImage&) + * + * See @ref Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedImage&) + * for more information. + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + * @requires_gl Texture image queries are not available in OpenGL ES or + * WebGL. See @ref Framebuffer::read() for possible workaround. + */ + void compressedSubImage(Int level, const RangeTypeFor& range, CompressedImage& image) { + AbstractTexture::compressedSubImage(level, range, image); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedImage3D image = texture.compressedSubImage(0, range, {}); + * @endcode + */ + CompressedImage compressedSubImage(Int level, const RangeTypeFor& range, CompressedImage&& image); + + /** + * @copybrief Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedBufferImage&, BufferUsage) + * + * See @ref Texture::compressedSubImage(Int, const RangeTypeFor&, CompressedBufferImage&, BufferUsage) + * for more information. + * @requires_gl45 Extension @extension{ARB,get_texture_sub_image} + * @requires_gl Texture image queries are not available in OpenGL ES or + * WebGL. See @ref Framebuffer::read() for possible workaround. + */ + void compressedSubImage(Int level, const RangeTypeFor& range, CompressedBufferImage& image, BufferUsage usage) { + AbstractTexture::compressedSubImage(level, range, image, usage); + } + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * CompressedBufferImage3D image = texture.compressedSubImage(0, range, {}, BufferUsage::StaticRead); + * @endcode + */ + CompressedBufferImage compressedSubImage(Int level, const RangeTypeFor& range, CompressedBufferImage&& image, BufferUsage usage); #endif /**