diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt index b0ff71ed5..e6476374f 100644 --- a/src/Magnum/CMakeLists.txt +++ b/src/Magnum/CMakeLists.txt @@ -68,7 +68,8 @@ set(Magnum_PRIVATE_HEADERS Implementation/meshIndexTypeMapping.hpp Implementation/meshPrimitiveMapping.hpp - Implementation/compressedPixelFormatMapping.hpp) + Implementation/compressedPixelFormatMapping.hpp + Implementation/pixelFormatMapping.hpp) # Functionality specific to static Windows builds if(CORRADE_TARGET_WINDOWS AND NOT CORRADE_TARGET_WINDOWS_RT AND MAGNUM_BUILD_STATIC) diff --git a/src/Magnum/Implementation/pixelFormatMapping.hpp b/src/Magnum/Implementation/pixelFormatMapping.hpp new file mode 100644 index 000000000..db18c6977 --- /dev/null +++ b/src/Magnum/Implementation/pixelFormatMapping.hpp @@ -0,0 +1,80 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 + 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. +*/ + +/* Each entry is just the name, for debug output and configuration to string */ +#ifdef _c +_c(R8Unorm) +_c(RG8Unorm) +_c(RGB8Unorm) +_c(RGBA8Unorm) +_c(R8Snorm) +_c(RG8Snorm) +_c(RGB8Snorm) +_c(RGBA8Snorm) +_c(R8Srgb) +_c(RG8Srgb) +_c(RGB8Srgb) +_c(RGBA8Srgb) +_c(R8UI) +_c(RG8UI) +_c(RGB8UI) +_c(RGBA8UI) +_c(R8I) +_c(RG8I) +_c(RGB8I) +_c(RGBA8I) +_c(R16Unorm) +_c(RG16Unorm) +_c(RGB16Unorm) +_c(RGBA16Unorm) +_c(R16Snorm) +_c(RG16Snorm) +_c(RGB16Snorm) +_c(RGBA16Snorm) +_c(R16UI) +_c(RG16UI) +_c(RGB16UI) +_c(RGBA16UI) +_c(R16I) +_c(RG16I) +_c(RGB16I) +_c(RGBA16I) +_c(R32UI) +_c(RG32UI) +_c(RGB32UI) +_c(RGBA32UI) +_c(R32I) +_c(RG32I) +_c(RGB32I) +_c(RGBA32I) +_c(R16F) +_c(RG16F) +_c(RGB16F) +_c(RGBA16F) +_c(R32F) +_c(RG32F) +_c(RGB32F) +_c(RGBA32F) +#endif diff --git a/src/Magnum/PixelFormat.cpp b/src/Magnum/PixelFormat.cpp index 2b9e45238..b0b2fd4ec 100644 --- a/src/Magnum/PixelFormat.cpp +++ b/src/Magnum/PixelFormat.cpp @@ -110,85 +110,43 @@ UnsignedInt pixelSize(const PixelFormat format) { CORRADE_ASSERT(false, "pixelSize(): invalid format" << format, {}); } +namespace { + +#ifndef DOXYGEN_GENERATING_OUTPUT /* It gets *really* confused */ +constexpr const char* PixelFormatNames[] { + #define _c(format) #format, + #include "Magnum/Implementation/pixelFormatMapping.hpp" + #undef _c +}; +#endif + +} + #ifndef DOXYGEN_GENERATING_OUTPUT Debug& operator<<(Debug& debug, const PixelFormat value) { + debug << "PixelFormat" << Debug::nospace; + if(isPixelFormatImplementationSpecific(value)) { - return debug << "PixelFormat::ImplementationSpecific(" << Debug::nospace << reinterpret_cast(pixelFormatUnwrap(value)) << Debug::nospace << ")"; + return debug << "::ImplementationSpecific(" << Debug::nospace << reinterpret_cast(pixelFormatUnwrap(value)) << Debug::nospace << ")"; } - #ifdef __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic error "-Wswitch" - #endif - switch(value) { - /* LCOV_EXCL_START */ - #define _c(value) case PixelFormat::value: return debug << "PixelFormat::" #value; - _c(R8Unorm) - _c(RG8Unorm) - _c(RGB8Unorm) - _c(RGBA8Unorm) - _c(R8Snorm) - _c(RG8Snorm) - _c(RGB8Snorm) - _c(RGBA8Snorm) - _c(R8Srgb) - _c(RG8Srgb) - _c(RGB8Srgb) - _c(RGBA8Srgb) - _c(R8UI) - _c(RG8UI) - _c(RGB8UI) - _c(RGBA8UI) - _c(R8I) - _c(RG8I) - _c(RGB8I) - _c(RGBA8I) - _c(R16Unorm) - _c(RG16Unorm) - _c(RGB16Unorm) - _c(RGBA16Unorm) - _c(R16Snorm) - _c(RG16Snorm) - _c(RGB16Snorm) - _c(RGBA16Snorm) - _c(R16UI) - _c(RG16UI) - _c(RGB16UI) - _c(RGBA16UI) - _c(R16I) - _c(RG16I) - _c(RGB16I) - _c(RGBA16I) - _c(R32UI) - _c(RG32UI) - _c(RGB32UI) - _c(RGBA32UI) - _c(R32I) - _c(RG32I) - _c(RGB32I) - _c(RGBA32I) - _c(R16F) - _c(RG16F) - _c(RGB16F) - _c(RGBA16F) - _c(R32F) - _c(RG32F) - _c(RGB32F) - _c(RGBA32F) - #undef _c - /* LCOV_EXCL_STOP */ + if(UnsignedInt(value) - 1 < Containers::arraySize(PixelFormatNames)) { + return debug << "::" << Debug::nospace << PixelFormatNames[UnsignedInt(value) - 1]; } - #ifdef __GNUC__ - #pragma GCC diagnostic pop - #endif - return debug << "PixelFormat(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; + return debug << "(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; } #endif namespace { #ifndef DOXYGEN_GENERATING_OUTPUT /* It gets *really* confused */ +constexpr const char* CompressedPixelFormatNames[] { + #define _c(format, width, height, depth, size) #format, + #include "Magnum/Implementation/compressedPixelFormatMapping.hpp" + #undef _c +}; + constexpr UnsignedShort CompressedBlockData[] { /* Assuming w/h/d/s is never larger than 16 (and never zero), each number has 1 subtracted and packed into four bits, 16 bits in total. The size @@ -233,131 +191,17 @@ UnsignedInt compressedBlockDataSize(const CompressedPixelFormat format) { #ifndef DOXYGEN_GENERATING_OUTPUT Debug& operator<<(Debug& debug, const CompressedPixelFormat value) { + debug << "CompressedPixelFormat" << Debug::nospace; + if(isCompressedPixelFormatImplementationSpecific(value)) { - return debug << "CompressedPixelFormat::ImplementationSpecific(" << Debug::nospace << reinterpret_cast(compressedPixelFormatUnwrap(value)) << Debug::nospace << ")"; + return debug << "::ImplementationSpecific(" << Debug::nospace << reinterpret_cast(compressedPixelFormatUnwrap(value)) << Debug::nospace << ")"; } - #ifdef __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic error "-Wswitch" - #endif - switch(value) { - /* LCOV_EXCL_START */ - #define _c(value) case CompressedPixelFormat::value: return debug << "CompressedPixelFormat::" #value; - _c(Bc1RGBUnorm) - _c(Bc1RGBSrgb) - _c(Bc1RGBAUnorm) - _c(Bc1RGBASrgb) - _c(Bc2RGBAUnorm) - _c(Bc2RGBASrgb) - _c(Bc3RGBAUnorm) - _c(Bc3RGBASrgb) - _c(Bc4RUnorm) - _c(Bc4RSnorm) - _c(Bc5RGUnorm) - _c(Bc5RGSnorm) - _c(Bc6hRGBUfloat) - _c(Bc6hRGBSfloat) - _c(Bc7RGBAUnorm) - _c(Bc7RGBASrgb) - _c(EacR11Unorm) - _c(EacR11Snorm) - _c(EacRG11Unorm) - _c(EacRG11Snorm) - _c(Etc2RGB8Unorm) - _c(Etc2RGB8Srgb) - _c(Etc2RGB8A1Unorm) - _c(Etc2RGB8A1Srgb) - _c(Etc2RGBA8Unorm) - _c(Etc2RGBA8Srgb) - _c(Astc4x4RGBAUnorm) - _c(Astc4x4RGBASrgb) - _c(Astc4x4RGBAF) - _c(Astc5x4RGBAUnorm) - _c(Astc5x4RGBASrgb) - _c(Astc5x4RGBAF) - _c(Astc5x5RGBAUnorm) - _c(Astc5x5RGBASrgb) - _c(Astc5x5RGBAF) - _c(Astc6x5RGBAUnorm) - _c(Astc6x5RGBASrgb) - _c(Astc6x5RGBAF) - _c(Astc6x6RGBAUnorm) - _c(Astc6x6RGBASrgb) - _c(Astc6x6RGBAF) - _c(Astc8x5RGBAUnorm) - _c(Astc8x5RGBASrgb) - _c(Astc8x5RGBAF) - _c(Astc8x6RGBAUnorm) - _c(Astc8x6RGBASrgb) - _c(Astc8x6RGBAF) - _c(Astc8x8RGBAUnorm) - _c(Astc8x8RGBASrgb) - _c(Astc8x8RGBAF) - _c(Astc10x5RGBAUnorm) - _c(Astc10x5RGBASrgb) - _c(Astc10x5RGBAF) - _c(Astc10x6RGBAUnorm) - _c(Astc10x6RGBASrgb) - _c(Astc10x6RGBAF) - _c(Astc10x8RGBAUnorm) - _c(Astc10x8RGBASrgb) - _c(Astc10x8RGBAF) - _c(Astc10x10RGBAUnorm) - _c(Astc10x10RGBASrgb) - _c(Astc10x10RGBAF) - _c(Astc12x10RGBAUnorm) - _c(Astc12x10RGBASrgb) - _c(Astc12x10RGBAF) - _c(Astc12x12RGBAUnorm) - _c(Astc12x12RGBASrgb) - _c(Astc12x12RGBAF) - _c(Astc3x3x3RGBAUnorm) - _c(Astc3x3x3RGBASrgb) - _c(Astc3x3x3RGBAF) - _c(Astc4x3x3RGBAUnorm) - _c(Astc4x3x3RGBASrgb) - _c(Astc4x3x3RGBAF) - _c(Astc4x4x3RGBAUnorm) - _c(Astc4x4x3RGBASrgb) - _c(Astc4x4x3RGBAF) - _c(Astc4x4x4RGBAUnorm) - _c(Astc4x4x4RGBASrgb) - _c(Astc4x4x4RGBAF) - _c(Astc5x4x4RGBAUnorm) - _c(Astc5x4x4RGBASrgb) - _c(Astc5x4x4RGBAF) - _c(Astc5x5x4RGBAUnorm) - _c(Astc5x5x4RGBASrgb) - _c(Astc5x5x4RGBAF) - _c(Astc5x5x5RGBAUnorm) - _c(Astc5x5x5RGBASrgb) - _c(Astc5x5x5RGBAF) - _c(Astc6x5x5RGBAUnorm) - _c(Astc6x5x5RGBASrgb) - _c(Astc6x5x5RGBAF) - _c(Astc6x6x5RGBAUnorm) - _c(Astc6x6x5RGBASrgb) - _c(Astc6x6x5RGBAF) - _c(Astc6x6x6RGBAUnorm) - _c(Astc6x6x6RGBASrgb) - _c(Astc6x6x6RGBAF) - _c(PvrtcRGB2bppUnorm) - _c(PvrtcRGB2bppSrgb) - _c(PvrtcRGBA2bppUnorm) - _c(PvrtcRGBA2bppSrgb) - _c(PvrtcRGB4bppUnorm) - _c(PvrtcRGB4bppSrgb) - _c(PvrtcRGBA4bppUnorm) - _c(PvrtcRGBA4bppSrgb) - #undef _c - /* LCOV_EXCL_STOP */ + if(UnsignedInt(value) - 1 < Containers::arraySize(CompressedPixelFormatNames)) { + return debug << "::" << Debug::nospace << CompressedPixelFormatNames[UnsignedInt(value) - 1]; } - #ifdef __GNUC__ - #pragma GCC diagnostic pop - #endif - return debug << "CompressedPixelFormat(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; + return debug << "(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; } #endif diff --git a/src/Magnum/Test/PixelFormatTest.cpp b/src/Magnum/Test/PixelFormatTest.cpp index 3ed4ec4ea..53dc7f4c1 100644 --- a/src/Magnum/Test/PixelFormatTest.cpp +++ b/src/Magnum/Test/PixelFormatTest.cpp @@ -36,6 +36,9 @@ namespace Magnum { namespace Test { namespace { struct PixelFormatTest: TestSuite::Tester { explicit PixelFormatTest(); + void mapping(); + void compressedMapping(); + void size(); void sizeInvalid(); void sizeImplementationSpecific(); @@ -64,7 +67,10 @@ struct PixelFormatTest: TestSuite::Tester { }; PixelFormatTest::PixelFormatTest() { - addTests({&PixelFormatTest::size, + addTests({&PixelFormatTest::mapping, + &PixelFormatTest::compressedMapping, + + &PixelFormatTest::size, &PixelFormatTest::sizeInvalid, &PixelFormatTest::sizeImplementationSpecific, @@ -91,49 +97,47 @@ PixelFormatTest::PixelFormatTest() { &PixelFormatTest::compressedDebugImplementationSpecific}); } -void PixelFormatTest::size() { - CORRADE_COMPARE(pixelSize(PixelFormat::R8I), 1); - CORRADE_COMPARE(pixelSize(PixelFormat::R16UI), 2); - CORRADE_COMPARE(pixelSize(PixelFormat::RGB8Unorm), 3); - CORRADE_COMPARE(pixelSize(PixelFormat::RGBA8Snorm), 4); - CORRADE_COMPARE(pixelSize(PixelFormat::RGB16I), 6); - CORRADE_COMPARE(pixelSize(PixelFormat::RGBA16F), 8); - CORRADE_COMPARE(pixelSize(PixelFormat::RGB32UI), 12); - CORRADE_COMPARE(pixelSize(PixelFormat::RGBA32F), 16); -} - -void PixelFormatTest::sizeInvalid() { - std::ostringstream out; - Error redirectError{&out}; - - pixelSize(PixelFormat{}); - pixelSize(PixelFormat(0xdead)); - - CORRADE_COMPARE(out.str(), - "pixelSize(): invalid format PixelFormat(0x0)\n" - "pixelSize(): invalid format PixelFormat(0xdead)\n"); -} - -void PixelFormatTest::sizeImplementationSpecific() { - std::ostringstream out; - Error redirectError{&out}; +void PixelFormatTest::mapping() { + /* This goes through the first 16 bits, which should be enough. Going + through 32 bits takes 8 seconds, too much. */ + UnsignedInt firstUnhandled = 0xffff; + UnsignedInt nextHandled = 1; /* 0 is an invalid format */ + for(UnsignedInt i = 1; i <= 0xffff; ++i) { + const auto format = PixelFormat(i); + /* Each case verifies: + - that the cases are ordered by number (so insertion here is done in + proper place) + - that there was no gap (unhandled value inside the range) + - that a particular pixel format maps to a particular GL format + - that a particular pixel type maps to a particular GL type */ + #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic error "-Wswitch" + #endif + switch(format) { + #define _c(format) \ + case PixelFormat::format: \ + CORRADE_COMPARE(nextHandled, i); \ + CORRADE_COMPARE(firstUnhandled, 0xffff); \ + ++nextHandled; \ + continue; + #include "Magnum/Implementation/pixelFormatMapping.hpp" + #undef _c + } + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #endif - pixelSize(pixelFormatWrap(0xdead)); + /* Not handled by any value, remember -- we might either be at the end + of the enum range (which is okay) or some value might be unhandled + here */ + firstUnhandled = i; + } - CORRADE_COMPARE(out.str(), "pixelSize(): can't determine size of an implementation-specific format\n"); + CORRADE_COMPARE(firstUnhandled, 0xffff); } -void PixelFormatTest::compressedBlockSize() { - /* Touchstone verification */ - CORRADE_COMPARE(Magnum::compressedBlockSize(CompressedPixelFormat::Etc2RGB8A1Srgb), (Vector3i{4, 4, 1})); - CORRADE_COMPARE(compressedBlockDataSize(CompressedPixelFormat::Etc2RGB8A1Srgb), 8); - CORRADE_COMPARE(Magnum::compressedBlockSize(CompressedPixelFormat::Astc5x4RGBAUnorm), (Vector3i{5, 4, 1})); - CORRADE_COMPARE(compressedBlockDataSize(CompressedPixelFormat::Astc5x4RGBAUnorm), 16); - CORRADE_COMPARE(Magnum::compressedBlockSize(CompressedPixelFormat::Astc12x10RGBAUnorm), (Vector3i{12, 10, 1})); - CORRADE_COMPARE(compressedBlockDataSize(CompressedPixelFormat::Astc12x10RGBAUnorm), 16); - CORRADE_COMPARE(Magnum::compressedBlockSize(CompressedPixelFormat::PvrtcRGBA2bppUnorm), (Vector3i{8, 4, 1})); - CORRADE_COMPARE(compressedBlockDataSize(CompressedPixelFormat::PvrtcRGBA2bppUnorm), 8); - +void PixelFormatTest::compressedMapping() { /* This goes through the first 16 bits, which should be enough. Going through 32 bits takes 8 seconds, too much. */ UnsignedInt firstUnhandled = 0xffff; @@ -180,6 +184,51 @@ void PixelFormatTest::compressedBlockSize() { CORRADE_COMPARE(firstUnhandled, 0xffff); } +void PixelFormatTest::size() { + CORRADE_COMPARE(pixelSize(PixelFormat::R8I), 1); + CORRADE_COMPARE(pixelSize(PixelFormat::R16UI), 2); + CORRADE_COMPARE(pixelSize(PixelFormat::RGB8Unorm), 3); + CORRADE_COMPARE(pixelSize(PixelFormat::RGBA8Snorm), 4); + CORRADE_COMPARE(pixelSize(PixelFormat::RGB16I), 6); + CORRADE_COMPARE(pixelSize(PixelFormat::RGBA16F), 8); + CORRADE_COMPARE(pixelSize(PixelFormat::RGB32UI), 12); + CORRADE_COMPARE(pixelSize(PixelFormat::RGBA32F), 16); +} + +void PixelFormatTest::sizeInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + pixelSize(PixelFormat{}); + pixelSize(PixelFormat(0xdead)); + + CORRADE_COMPARE(out.str(), + "pixelSize(): invalid format PixelFormat(0x0)\n" + "pixelSize(): invalid format PixelFormat(0xdead)\n"); +} + +void PixelFormatTest::sizeImplementationSpecific() { + std::ostringstream out; + Error redirectError{&out}; + + pixelSize(pixelFormatWrap(0xdead)); + + CORRADE_COMPARE(out.str(), "pixelSize(): can't determine size of an implementation-specific format\n"); +} + +void PixelFormatTest::compressedBlockSize() { + CORRADE_COMPARE(Magnum::compressedBlockSize(CompressedPixelFormat::Etc2RGB8A1Srgb), (Vector3i{4, 4, 1})); + CORRADE_COMPARE(compressedBlockDataSize(CompressedPixelFormat::Etc2RGB8A1Srgb), 8); + CORRADE_COMPARE(Magnum::compressedBlockSize(CompressedPixelFormat::Astc5x4RGBAUnorm), (Vector3i{5, 4, 1})); + CORRADE_COMPARE(compressedBlockDataSize(CompressedPixelFormat::Astc5x4RGBAUnorm), 16); + CORRADE_COMPARE(Magnum::compressedBlockSize(CompressedPixelFormat::Astc12x10RGBAUnorm), (Vector3i{12, 10, 1})); + CORRADE_COMPARE(compressedBlockDataSize(CompressedPixelFormat::Astc12x10RGBAUnorm), 16); + CORRADE_COMPARE(Magnum::compressedBlockSize(CompressedPixelFormat::PvrtcRGBA2bppUnorm), (Vector3i{8, 4, 1})); + CORRADE_COMPARE(compressedBlockDataSize(CompressedPixelFormat::PvrtcRGBA2bppUnorm), 8); + + /* The rest tested in compressedMapping() */ +} + void PixelFormatTest::compressedBlockSizeInvalid() { std::ostringstream out; Error redirectError{&out};