/* This file is part of Magnum. Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025 Vladimír Vondruš Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include "Magnum/Image.h" #include "Magnum/ImageView.h" #include "Magnum/PixelFormat.h" #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" #include "Magnum/GL/Framebuffer.h" #include "Magnum/GL/OpenGLTester.h" #include "Magnum/GL/PixelFormat.h" #include "Magnum/GL/Texture.h" #ifndef MAGNUM_TARGET_GLES2 #include "Magnum/GL/TextureArray.h" #endif #include "Magnum/GL/TextureFormat.h" #ifdef MAGNUM_TARGET_GLES #include "Magnum/GL/Framebuffer.h" #endif namespace Magnum { namespace GL { namespace Test { namespace { struct PixelStorageGLTest: OpenGLTester { explicit PixelStorageGLTest(); void alignmentUnpack2D(); void alignmentPack2D(); #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void alignmentRowLengthSkipXYUnpack2D(); void alignmentRowLengthSkipXYPack2D(); #ifndef MAGNUM_TARGET_GLES2 void alignmentImageHeightRowLengthSkipXYZUnpack3D(); #endif #ifndef MAGNUM_TARGET_GLES void alignmentImageHeightRowLengthSkipXYZPack3D(); #endif #endif #if defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2) void rowLengthNotSupported(); #endif #ifdef MAGNUM_TARGET_GLES2 void imageHeightNotSupported(); #elif defined(MAGNUM_TARGET_GLES) void imageHeightSkipZPackNotSupported(); #endif #ifndef MAGNUM_TARGET_GLES void compressedUnpack2D(); void compressedPack2D(); void compressedUnpack3D(); void compressedPack3D(); #endif #ifdef MAGNUM_TARGET_GLES void compressedNotSupported(); #endif }; PixelStorageGLTest::PixelStorageGLTest() { addTests({&PixelStorageGLTest::alignmentUnpack2D, &PixelStorageGLTest::alignmentPack2D, #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) &PixelStorageGLTest::alignmentRowLengthSkipXYUnpack2D, &PixelStorageGLTest::alignmentRowLengthSkipXYPack2D, #ifndef MAGNUM_TARGET_GLES2 &PixelStorageGLTest::alignmentImageHeightRowLengthSkipXYZUnpack3D, #endif #ifndef MAGNUM_TARGET_GLES &PixelStorageGLTest::alignmentImageHeightRowLengthSkipXYZPack3D, #endif #endif #if defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2) &PixelStorageGLTest::rowLengthNotSupported, #endif #ifdef MAGNUM_TARGET_GLES2 &PixelStorageGLTest::imageHeightNotSupported, #elif defined(MAGNUM_TARGET_GLES) &PixelStorageGLTest::imageHeightSkipZPackNotSupported, #endif #ifndef MAGNUM_TARGET_GLES &PixelStorageGLTest::compressedUnpack2D, &PixelStorageGLTest::compressedPack2D, &PixelStorageGLTest::compressedUnpack3D, &PixelStorageGLTest::compressedPack3D #endif #ifdef MAGNUM_TARGET_GLES &PixelStorageGLTest::compressedNotSupported, #endif }); } constexpr char AlignmentData2D[]{ /* Data -----------------------------------------------------------. */ /* Alignment */ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x00', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x00', }; void PixelStorageGLTest::alignmentUnpack2D() { ImageView2D image{ PixelStorage{} .setAlignment(2), Magnum::PixelFormat::RGB8Unorm, {3, 2}, AlignmentData2D}; Texture2D texture; texture.setImage(0, textureFormat(image.format()), image); MAGNUM_VERIFY_NO_GL_ERROR(); /* Read into a format that's guaranteed to be supported even on WebGL 1, i.e. a four-component one. With a three-component format both Chrome and Firefox produce a stupid error about "buffer not large enough", while the problem is the format not being supported. WebGL 2 works with RGB completely fine, tho. Strangely enough, reading to RGB (with a two-pixel alignment, tho) in alignmentPack2D() below works all fine. I smell some shitty ANGLE bug. */ Image2D actual{PixelFormat::RGBA, PixelType::UnsignedByte, {}, Containers::Array{ValueInit, 24}}; #ifndef MAGNUM_TARGET_GLES texture.image(0, actual); #else Framebuffer framebuffer{{{}, {3, 2}}}; framebuffer .attachTexture(Framebuffer::ColorAttachment{0}, texture, 0) .read(framebuffer.viewport(), actual); #endif MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_AS(actual.data(), Containers::arrayView({ '\x00', '\x01', '\x02', '\xff', '\x03', '\x04', '\x05', '\xff', '\x06', '\x07', '\x08', '\xff', '\x0a', '\x0b', '\x0c', '\xff', '\x0d', '\x0e', '\x0f', '\xff', '\x10', '\x11', '\x12', '\xff', }), TestSuite::Compare::Container); } void PixelStorageGLTest::alignmentPack2D() { const char data[]{ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x00', '\x00', '\x00', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x00', '\x00', '\x00', }; ImageView2D actual{Magnum::PixelFormat::RGB8Unorm, {3, 2}, data}; Texture2D texture; texture.setImage(0, textureFormat(actual.format()), actual); MAGNUM_VERIFY_NO_GL_ERROR(); /* Pre-allocate and zero out the data array so we can conveniently compare */ Image2D image{PixelStorage{} .setAlignment(2), PixelFormat::RGB, PixelType::UnsignedByte, {}, Containers::Array{ValueInit, sizeof(AlignmentData2D)}}; #ifndef MAGNUM_TARGET_GLES texture.image(0, image); #else Framebuffer framebuffer{{{}, {3, 2}}}; framebuffer.attachTexture(Framebuffer::ColorAttachment{0}, texture, 0); /* We *need* to read as RGB in this case because otherwise the alignment cannot be properly tested, as it'll be always a multiple of four */ CORRADE_EXPECT_FAIL_IF(framebuffer.implementationColorReadFormat() != PixelFormat::RGB, "Implementation-defined framebuffer read format is not RGB, reading will fail."); framebuffer.read(framebuffer.viewport(), image); #endif MAGNUM_VERIFY_NO_GL_ERROR(); #ifdef MAGNUM_TARGET_GLES /* SwiftShader (on Android, at least) seems to write even to the padding bytes, yay. Clear those before comparison. */ if(Context::current().detectedDriver() & Context::DetectedDriver::SwiftShader) { CORRADE_COMPARE(image.data().size(), Containers::arraySize(AlignmentData2D)); for(std::size_t i: {9, 19}) { CORRADE_ITERATION(i); if(image.data()[i] != '\0') { CORRADE_WARN("Padding byte at offset 9 isn't zero but" << image.data()[i]); image.data()[i] = '\0'; } } } #endif CORRADE_COMPARE_AS(image.data(), Containers::arrayView(AlignmentData2D), TestSuite::Compare::Container); } #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) constexpr char AlignmentRowLengthSkipXYData2D[]{ /* Row length ------------------------------------------------------ */ /* Alignment */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', /* ------------ Skip */ /* Data ------------------------------------ */ /* Alignment */ '\x00', '\x00', '\x00', '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x00', '\x00', '\x00', '\x00', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x00', '\x00', '\x00', '\x00', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x00', }; constexpr const char ActualData[] = { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x00', '\x00', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x00', '\x00', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x00', '\x00' }; void PixelStorageGLTest::alignmentRowLengthSkipXYUnpack2D() { #ifdef MAGNUM_TARGET_GLES2 if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::EXT::unpack_subimage::string() << "is not supported."); #endif ImageView2D image{PixelStorage{} .setAlignment(2) .setRowLength(3) .setSkip({1, 3, 0}), PixelFormat::RGB, PixelType::UnsignedByte, {2, 3}, AlignmentRowLengthSkipXYData2D}; Texture2D texture; texture.setStorage(1, TextureFormat::RGB8, {2, 3}) .setSubImage(0, {}, image); MAGNUM_VERIFY_NO_GL_ERROR(); /* Read into zero-initialized array to avoid comparing random memory in padding bytes (confirmed on NVidia 355.11, AMD 15.300.1025.0) */ Image2D actual{PixelFormat::RGB, PixelType::UnsignedByte, {}, Containers::Array{ValueInit, sizeof(ActualData)}}; #ifndef MAGNUM_TARGET_GLES texture.image(0, actual); #else Framebuffer fb{{{}, {2, 3}}}; fb.attachTexture(Framebuffer::ColorAttachment{0}, texture, 0); CORRADE_EXPECT_FAIL_IF(fb.implementationColorReadFormat() != PixelFormat::RGB, "Implementation-defined framebuffer read format is not RGB, reading will fail."); fb.read(fb.viewport(), actual); #endif MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_AS(actual.data(), Containers::arrayView(ActualData), TestSuite::Compare::Container); } void PixelStorageGLTest::alignmentRowLengthSkipXYPack2D() { #ifdef MAGNUM_TARGET_GLES2 if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::NV::pack_subimage::string() << "is not supported."); #endif ImageView2D actual{PixelFormat::RGB, PixelType::UnsignedByte, {2, 3}, ActualData}; Texture2D texture; texture.setStorage(1, TextureFormat::RGB8, {2, 3}) .setSubImage(0, {}, actual); MAGNUM_VERIFY_NO_GL_ERROR(); /* Pre-allocate and zero out the data array so we can conveniently compare */ Image2D image{PixelStorage{} .setAlignment(2) .setRowLength(3) .setSkip({1, 3, 0}), PixelFormat::RGB, PixelType::UnsignedByte, {}, Containers::Array{ValueInit, sizeof(AlignmentRowLengthSkipXYData2D)}}; #ifndef MAGNUM_TARGET_GLES texture.image(0, image); #else Framebuffer fb{{{}, {2, 3}}}; fb.attachTexture(Framebuffer::ColorAttachment{0}, texture, 0); CORRADE_EXPECT_FAIL_IF(fb.implementationColorReadFormat() != PixelFormat::RGB, "Implementation-defined framebuffer read format is not RGB, reading will fail."); fb.read(fb.viewport(), image); #endif MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_AS(image.data(), Containers::arrayView(AlignmentRowLengthSkipXYData2D), TestSuite::Compare::Container); } #endif #ifndef MAGNUM_TARGET_GLES2 constexpr const char Data3D[] = { /* Row length ------------------------------------------------------ */ /* Alignment */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', /* Row length ------------------------------------------------------ */ /* Alignment */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', /* ------------ Skip */ /* Data ------------------------------------ */ /* Alignment */ '\x00', '\x00', '\x00', '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x00', '\x00', '\x00', '\x00', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x00', '\x00', '\x00', '\x00', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x00', /* Filling to image height not needed */ }; void PixelStorageGLTest::alignmentImageHeightRowLengthSkipXYZUnpack3D() { PixelStorage storage; storage.setAlignment(2) .setRowLength(3) .setImageHeight(5) .setSkip({1, 2, 1}); ImageView3D image{storage, PixelFormat::RGB, PixelType::UnsignedByte, {2, 3, 1}, Data3D}; Texture3D texture; texture.setStorage(1, TextureFormat::RGB8, {2, 3, 1}) .setSubImage(0, {}, image); MAGNUM_VERIFY_NO_GL_ERROR(); /* Testing mainly image height here, which is not available as pack parameter in ES */ #ifndef MAGNUM_TARGET_GLES /* Read into zero-initialized array to avoid comparing random memory in padding bytes (confirmed on AMD 15.300.1025.0) */ Image3D actual{PixelFormat::RGB, PixelType::UnsignedByte, {}, Containers::Array{ValueInit, sizeof(ActualData)}}; texture.image(0, actual); MAGNUM_VERIFY_NO_GL_ERROR(); /* Clear padding in the last row (the driver might leave them untouched, confirmed on NVidia 358.16) */ CORRADE_VERIFY(actual.data().size() == Containers::arrayView(ActualData).size()); *(actual.data().end() - 1) = *(actual.data().end() - 2) = 0; CORRADE_COMPARE_AS(actual.data(), Containers::arrayView(ActualData), TestSuite::Compare::Container); #endif } #endif /* Testing mainly image height here, which is not available as pack parameter in ES */ #ifndef MAGNUM_TARGET_GLES void PixelStorageGLTest::alignmentImageHeightRowLengthSkipXYZPack3D() { ImageView3D actual{PixelFormat::RGB, PixelType::UnsignedByte, {2, 3, 1}, ActualData}; Texture3D texture; texture.setStorage(1, TextureFormat::RGB8, {2, 3, 1}) .setSubImage(0, {}, actual); MAGNUM_VERIFY_NO_GL_ERROR(); Image3D image{PixelStorage{} .setAlignment(2) .setRowLength(3) .setImageHeight(5) .setSkip({1, 2, 1}), PixelFormat::RGB, PixelType::UnsignedByte, {}, Containers::Array{ValueInit, sizeof(Data3D)}}; texture.image(0, image); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_AS(image.data(), Containers::arrayView(Data3D), TestSuite::Compare::Container); } #endif #if defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2) void PixelStorageGLTest::rowLengthNotSupported() { CORRADE_SKIP_IF_NO_ASSERT(); char data[4*4*4]{}; MutableImageView2D image{ PixelStorage{} .setRowLength(4), Magnum::PixelFormat::RGBA8Unorm, {4, 4}, data}; Texture2D texture; /* Just to reset all pixel storage parameters potentially set by any of the above tests to default. The (graceful) assertions would do an early return somewhere in the middle, leading to some params being left at their earlier state. */ texture.setImage(0, textureFormat(image.format()), ImageView2D{image.format(), image.size(), image.data()}); Framebuffer framebuffer{{}}; framebuffer.attachTexture(Framebuffer::ColorAttachment{0}, texture, 0); /* ... and similarly to reset unpack parameters */ framebuffer.read({{}, image.size()}, MutableImageView2D{image.format(), image.size(), data}); MAGNUM_VERIFY_NO_GL_ERROR(); Containers::String out; Error redirectError{&out}; texture.setImage(0, textureFormat(image.format()), image); framebuffer.read({{}, image.size()}, image); CORRADE_COMPARE_AS(out, "GL: non-default PixelStorage::rowLength() is not supported in WebGL 1.0\n" "GL: non-default PixelStorage::rowLength() is not supported in WebGL 1.0\n", TestSuite::Compare::String); MAGNUM_VERIFY_NO_GL_ERROR(); /* And again to reset these for any tests that might run after */ texture.setImage(0, textureFormat(image.format()), ImageView2D{image.format(), image.size(), image.data()}); framebuffer.read({{}, image.size()}, MutableImageView2D{image.format(), image.size(), data}); MAGNUM_VERIFY_NO_GL_ERROR(); } #endif #ifdef MAGNUM_TARGET_GLES2 void PixelStorageGLTest::imageHeightNotSupported() { CORRADE_SKIP_IF_NO_ASSERT(); char data[4*4*4]{}; MutableImageView2D image{ PixelStorage{} .setImageHeight(4), Magnum::PixelFormat::RGBA8Unorm, {4, 4}, data}; Texture2D texture; /* Just to reset all pixel storage parameters potentially set by any of the above tests to default. The (graceful) assertions would do an early return somewhere in the middle, leading to some params being left at their earlier state. */ texture.setImage(0, textureFormat(image.format()), ImageView2D{image.format(), image.size(), data}); Framebuffer framebuffer{{}}; framebuffer.attachTexture(Framebuffer::ColorAttachment{0}, texture, 0); /* ... and similarly to reset unpack parameters */ framebuffer.read({{}, image.size()}, MutableImageView2D{image.format(), image.size(), data}); MAGNUM_VERIFY_NO_GL_ERROR(); Containers::String out; Error redirectError{&out}; texture.setImage(0, textureFormat(image.format()), image); framebuffer.read({{}, image.size()}, image); CORRADE_COMPARE_AS(out, "GL: non-default PixelStorage::imageHeight() is not supported in OpenGL ES 2\n" "GL: non-default PixelStorage::imageHeight() is not supported in OpenGL ES 2\n", TestSuite::Compare::String); MAGNUM_VERIFY_NO_GL_ERROR(); /* And again to reset these for any tests that might run after */ texture.setImage(0, textureFormat(image.format()), ImageView2D{image.format(), image.size(), data}); framebuffer.read({{}, image.size()}, MutableImageView2D{image.format(), image.size(), data}); MAGNUM_VERIFY_NO_GL_ERROR(); } #elif defined(MAGNUM_TARGET_GLES) void PixelStorageGLTest::imageHeightSkipZPackNotSupported() { CORRADE_SKIP_IF_NO_ASSERT(); GL::Context::current().resetState(GL::Context::State::PixelStorage); char data[4*4*4*2]{}; /* twice for skip Z */ Texture2D texture; /* Just so the texure can be correctly read from */ texture.setImage(0, TextureFormat::RGBA8, ImageView2D{Magnum::PixelFormat::RGBA8Unorm, {4, 4}, data}); Framebuffer framebuffer{{}}; framebuffer.attachTexture(Framebuffer::ColorAttachment{0}, texture, 0); /* Just to reset all pixel storage parameters potentially set by any of the above tests to default. The (graceful) assertions would do an early return somewhere in the middle, leading to some params being left at their earlier state. */ framebuffer.read({{}, {4, 4}}, MutableImageView2D{Magnum::PixelFormat::RGBA8Unorm, {4, 4}, data}); MutableImageView2D imageImageHeight{ PixelStorage{} .setImageHeight(4), Magnum::PixelFormat::RGBA8Unorm, {4, 4}, data}; MutableImageView2D imageSkipZ{ PixelStorage{} .setSkip({0, 0, 1}), Magnum::PixelFormat::RGBA8Unorm, {4, 4}, data}; MAGNUM_VERIFY_NO_GL_ERROR(); Containers::String out; Error redirectError{&out}; framebuffer.read({{}, imageImageHeight.size()}, imageImageHeight); framebuffer.read({{}, imageSkipZ.size()}, imageSkipZ); CORRADE_COMPARE_AS(out, "GL: non-default PixelStorage::imageHeight() for pack is not supported in OpenGL ES\n" "GL: non-default PixelStorage::skip().z() for pack is not supported in OpenGL ES\n", TestSuite::Compare::String); MAGNUM_VERIFY_NO_GL_ERROR(); /* And again to reset these for any tests that might run after */ framebuffer.read({{}, {4, 4}}, MutableImageView2D{Magnum::PixelFormat::RGBA8Unorm, {4, 4}, data}); MAGNUM_VERIFY_NO_GL_ERROR(); } #endif #ifndef MAGNUM_TARGET_GLES constexpr const UnsignedByte CompressedData2D[] = { /* Skip */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 34, 34, 51, 51, 67, 232, 57, 0, 0, 213, 255, 170, 2 }; /* Just 4x4 0x00 - 0x3f compressed using RGBA DXT3 by the driver */ constexpr const UnsignedByte ActualCompressedData[] = { 0, 17, 17, 34, 34, 51, 51, 67, 232, 57, 0, 0, 213, 255, 170, 2, }; void PixelStorageGLTest::compressedUnpack2D() { if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); CompressedPixelStorage storage; storage.setCompressedBlockSize({4, 4, 1}) .setCompressedBlockDataSize(16) .setRowLength(12) .setSkip({4, 4, 0}); CompressedImageView2D image{storage, CompressedPixelFormat::RGBAS3tcDxt3, {4, 4}, CompressedData2D}; Texture2D texture; texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {4, 4}) .setCompressedSubImage(0, {}, image); MAGNUM_VERIFY_NO_GL_ERROR(); CompressedImage2D actual = texture.compressedImage(0, {}); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_AS(Containers::arrayCast(actual.data()), Containers::arrayView(ActualCompressedData), TestSuite::Compare::Container); } void PixelStorageGLTest::compressedPack2D() { if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); CompressedImageView2D actual{CompressedPixelFormat::RGBAS3tcDxt3, {4, 4}, ActualCompressedData}; Texture2D texture; texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {4, 4}) .setCompressedSubImage(0, {}, actual); MAGNUM_VERIFY_NO_GL_ERROR(); /* Pre-allocate and zero out the data array so we can conveniently compare */ CompressedImage2D image{CompressedPixelStorage{} .setCompressedBlockSize({4, 4, 1}) .setCompressedBlockDataSize(16) .setRowLength(12) .setSkip({4, 4, 0}), CompressedPixelFormat::RGBAS3tcDxt3, {}, Containers::Array{ValueInit, sizeof(CompressedData2D)}}; texture.compressedImage(0, image); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_AS(Containers::arrayCast(image.data()), Containers::arrayView(CompressedData2D), TestSuite::Compare::Container); } constexpr const UnsignedByte CompressedData3D[] = { /* Skip image */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Skip rows and pixels */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 34, 34, 51, 51, 67, 232, 57, 0, 0, 213, 255, 170, 2 }; void PixelStorageGLTest::compressedUnpack3D() { if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); CompressedPixelStorage storage; storage.setCompressedBlockSize({4, 4, 1}) .setCompressedBlockDataSize(16) .setRowLength(8) .setImageHeight(8) .setSkip({4, 4, 4}); CompressedImageView3D image{storage, CompressedPixelFormat::RGBAS3tcDxt3, {4, 4, 1}, CompressedData3D}; Texture2DArray texture; texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {4, 4, 1}) .setCompressedSubImage(0, {}, image); MAGNUM_VERIFY_NO_GL_ERROR(); CompressedImage3D actual = texture.compressedImage(0, {}); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_AS(Containers::arrayCast(actual.data()), Containers::arrayView(ActualCompressedData), TestSuite::Compare::Container); } void PixelStorageGLTest::compressedPack3D() { if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::compressed_texture_pixel_storage::string() << "is not supported."); CompressedImageView3D actual{CompressedPixelFormat::RGBAS3tcDxt3, {4, 4, 1}, ActualCompressedData}; Texture2DArray texture; texture.setStorage(1, TextureFormat::CompressedRGBAS3tcDxt3, {4, 4, 1}) .setCompressedSubImage(0, {}, actual); MAGNUM_VERIFY_NO_GL_ERROR(); /* Pre-allocate and zero out the data array so we can conveniently compare */ CompressedImage3D image{CompressedPixelStorage{} .setCompressedBlockSize({4, 4, 1}) .setCompressedBlockDataSize(16) .setRowLength(8) .setImageHeight(8) .setSkip({4, 4, 4}), CompressedPixelFormat::RGBAS3tcDxt3, {}, Containers::Array{ValueInit, sizeof(CompressedData3D)}}; texture.compressedImage(0, image); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_AS(Containers::arrayCast(image.data()), Containers::arrayView(CompressedData3D), TestSuite::Compare::Container); } #endif #ifdef MAGNUM_TARGET_GLES void PixelStorageGLTest::compressedNotSupported() { CORRADE_SKIP_IF_NO_ASSERT(); /* Pick a 64-bit 4x4 format. Zero data are uploaded so it doesn't matter which it is. */ Magnum::CompressedPixelFormat format; #ifndef MAGNUM_TARGET_WEBGL if(Context::current().isExtensionSupported() || Context::current().isExtensionSupported() || Context::current().isExtensionSupported()) #else if(Context::current().isExtensionSupported()) #endif { format = Magnum::CompressedPixelFormat::Bc1RGBUnorm; } else #ifdef MAGNUM_TARGET_WEBGL if(Context::current().isExtensionSupported()) #elif defined(MAGNUM_TARGET_GLES2) if(Context::current().isExtensionSupported()) #else /* On ES3 ETC textures are available always */ #endif { format = Magnum::CompressedPixelFormat::Etc2RGB8Unorm; } #if defined(MAGNUM_TARGET_WEBGL) || defined(MAGNUM_TARGET_GLES2) else { #ifdef MAGNUM_TARGET_WEBGL CORRADE_SKIP(Extensions::WEBGL::compressed_texture_s3tc::string() << "not supported, can't test"); #else CORRADE_SKIP("None of" << Extensions::EXT::texture_compression_s3tc::string() << Debug::nospace << "," << Extensions::EXT::texture_compression_dxt1::string() << Debug::nospace << "," << Extensions::ANGLE::texture_compression_dxt1::string() << "or" << Extensions::ANGLE::compressed_texture_etc::string() << "extensions are supported, can't test"); #endif } #endif char data[8]{}; MutableCompressedImageView2D image{ /* Just set any random property to make it different from the default-constructed instance to trigger the assert */ CompressedPixelStorage{} .setRowLength(4), format, {4, 4}, data}; Texture2D texture; /* Just to reset all pixel storage parameters potentially set by any of the above tests to default. The (graceful) assertions would do an early return somewhere in the middle, leading to some params being left at their earlier state. */ texture.setCompressedImage(0, CompressedImageView2D{image.format(), image.size(), data}); MAGNUM_VERIFY_NO_GL_ERROR(); Containers::String out; Error redirectError{&out}; texture.setCompressedImage(0, image); /* There isn't any way to use CompressedPixelStorage for pixel pack on GLES */ CORRADE_COMPARE_AS(out, "GL: non-default CompressedPixelStorage parameters are not supported in OpenGL ES or WebGL\n", TestSuite::Compare::String); MAGNUM_VERIFY_NO_GL_ERROR(); /* And again to reset these for any tests that might run after */ texture.setCompressedImage(0, CompressedImageView2D{image.format(), image.size(), data}); MAGNUM_VERIFY_NO_GL_ERROR(); } #endif }}}} CORRADE_TEST_MAIN(Magnum::GL::Test::PixelStorageGLTest)