Browse Source

Add a table describing block size of all known compressed pixel formats.

Needed for a bunch of features (and feature parity in
CompressedImageView).
findsdl-include-root
Vladimír Vondruš 7 years ago
parent
commit
75bfd41baf
  1. 3
      doc/changelog.dox
  2. 116
      src/Magnum/Implementation/compressedPixelFormatMapping.hpp
  3. 48
      src/Magnum/PixelFormat.cpp
  4. 23
      src/Magnum/PixelFormat.h
  5. 2
      src/Magnum/PixelStorage.h
  6. 95
      src/Magnum/Test/PixelFormatTest.cpp

3
doc/changelog.dox

@ -58,6 +58,9 @@ See also:
@ref PixelFormat::RGB8Srgb and @ref PixelFormat::RGBA8Srgb sRGB pixel
formats as well as their conversion to corresponding GL/Vulkan formats in
@ref GL::pixelFormat() and @ref Vk::vkFormat(Magnum::PixelFormat)
- New @ref compressedBlockSize() and @ref compressedBlockDataSize() utilities
for querying parameters of @ref CompressedPixelFormat entries, similar to
what @ref pixelSize() is for @ref PixelFormat
@subsubsection changelog-latest-new-audio Audio library

116
src/Magnum/Implementation/compressedPixelFormatMapping.hpp

@ -0,0 +1,116 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019
Vladimír Vondruš <mosra@centrum.cz>
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 width, height, depth, size in bytes */
#ifdef _c
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_bc1_with_no_alpha */
_c(Bc1RGBUnorm, 4, 4, 1, 64)
_c(Bc1RGBSrgb, 4, 4, 1, 64)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_bc1_with_alpha */
_c(Bc1RGBAUnorm, 4, 4, 1, 64)
_c(Bc1RGBASrgb, 4, 4, 1, 64)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_bc2 */
_c(Bc2RGBAUnorm, 4, 4, 1, 128)
_c(Bc2RGBASrgb, 4, 4, 1, 128)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_bc3 */
_c(Bc3RGBAUnorm, 4, 4, 1, 128)
_c(Bc3RGBASrgb, 4, 4, 1, 128)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_bc4_unsigned */
_c(Bc4RUnorm, 4, 4, 1, 64)
_c(Bc4RSnorm, 4, 4, 1, 64)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_bc5_unsigned */
_c(Bc5RGUnorm, 4, 4, 1, 128)
_c(Bc5RGSnorm, 4, 4, 1, 128)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_bc6h */
_c(Bc6hRGBUfloat, 4, 4, 1, 128)
_c(Bc6hRGBSfloat, 4, 4, 1, 128)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_bc7 */
_c(Bc7RGBAUnorm, 4, 4, 1, 128)
_c(Bc7RGBASrgb, 4, 4, 1, 128)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#Section-r11eac */
_c(EacR11Unorm, 4, 4, 1, 64)
_c(EacR11Snorm, 4, 4, 1, 64)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_format_unsigned_rg11_eac */
_c(EacRG11Unorm, 4, 4, 1, 128)
_c(EacRG11Snorm, 4, 4, 1, 128)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#RGBETC2 */
_c(Etc2RGB8Unorm, 4, 4, 1, 64)
_c(Etc2RGB8Srgb, 4, 4, 1, 64)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_format_rgb_etc2_with_punchthrough_alpha */
_c(Etc2RGB8A1Unorm, 4, 4, 1, 64)
_c(Etc2RGB8A1Srgb, 4, 4, 1, 64)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_format_rgba_etc2 */
_c(Etc2RGBA8Unorm, 4, 4, 1, 128)
_c(Etc2RGBA8Srgb, 4, 4, 1, 128)
/* https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#_basic_concepts,
all blocks fit into 128 bits */
_c(Astc4x4RGBAUnorm, 4, 4, 1, 128)
_c(Astc4x4RGBASrgb, 4, 4, 1, 128)
_c(Astc5x4RGBAUnorm, 5, 4, 1, 128)
_c(Astc5x4RGBASrgb, 5, 4, 1, 128)
_c(Astc5x5RGBAUnorm, 5, 5, 1, 128)
_c(Astc5x5RGBASrgb, 5, 5, 1, 128)
_c(Astc6x5RGBAUnorm, 6, 5, 1, 128)
_c(Astc6x5RGBASrgb, 6, 5, 1, 128)
_c(Astc6x6RGBAUnorm, 6, 6, 1, 128)
_c(Astc6x6RGBASrgb, 6, 6, 1, 128)
_c(Astc8x5RGBAUnorm, 8, 5, 1, 128)
_c(Astc8x5RGBASrgb, 8, 5, 1, 128)
_c(Astc8x6RGBAUnorm, 8, 6, 1, 128)
_c(Astc8x6RGBASrgb, 8, 6, 1, 128)
_c(Astc8x8RGBAUnorm, 8, 8, 1, 128)
_c(Astc8x8RGBASrgb, 8, 8, 1, 128)
_c(Astc10x5RGBAUnorm, 10, 5, 1, 128)
_c(Astc10x5RGBASrgb, 10, 5, 1, 128)
_c(Astc10x6RGBAUnorm, 10, 6, 1, 128)
_c(Astc10x6RGBASrgb, 10, 6, 1, 128)
_c(Astc10x8RGBAUnorm, 10, 8, 1, 128)
_c(Astc10x8RGBASrgb, 10, 8, 1, 128)
_c(Astc10x10RGBAUnorm, 10, 10, 1, 128)
_c(Astc10x10RGBASrgb, 10, 10, 1, 128)
_c(Astc12x10RGBAUnorm, 12, 10, 1, 128)
_c(Astc12x10RGBASrgb, 12, 10, 1, 128)
_c(Astc12x12RGBAUnorm, 12, 12, 1, 128)
_c(Astc12x12RGBASrgb, 12, 12, 1, 128)
/* https://en.wikipedia.org/wiki/PVRTC */
_c(PvrtcRGB2bppUnorm, 8, 4, 1, 64)
_c(PvrtcRGB2bppSrgb, 8, 4, 1, 64)
_c(PvrtcRGBA2bppUnorm, 8, 4, 1, 64)
_c(PvrtcRGBA2bppSrgb, 8, 4, 1, 64)
_c(PvrtcRGB4bppUnorm, 4, 4, 1, 64)
_c(PvrtcRGB4bppSrgb, 4, 4, 1, 64)
_c(PvrtcRGBA4bppUnorm, 4, 4, 1, 64)
_c(PvrtcRGBA4bppSrgb, 4, 4, 1, 64)
#endif

48
src/Magnum/PixelFormat.cpp

@ -25,9 +25,12 @@
#include "PixelFormat.h"
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h>
#include "Magnum/Math/Vector3.h"
namespace Magnum {
UnsignedInt pixelSize(const PixelFormat format) {
@ -183,6 +186,51 @@ Debug& operator<<(Debug& debug, const PixelFormat value) {
}
#endif
namespace {
#ifndef DOXYGEN_GENERATING_OUTPUT /* It gets *really* confused */
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
is supplied in bits, so first divide by eight and then subtract 1. For
the currently ~60 supported format that makes this table to be about 128
bytes.*/
#define _c(format, width, height, depth, size) \
((width - 1) << 12) | \
((height - 1) << 8) | \
((depth - 1) << 4) | \
((size >> 3) - 1),
#include "Magnum/Implementation/compressedPixelFormatMapping.hpp"
#undef _s
#undef _c
};
#endif
}
Vector3i compressedBlockSize(const CompressedPixelFormat format) {
CORRADE_ASSERT(!(UnsignedInt(format) & (1 << 31)),
"compressedBlockSize(): can't determine size of an implementation-specific format", {});
CORRADE_ASSERT(UnsignedInt(format) - 1 < Containers::arraySize(CompressedBlockData),
"compressedBlockSize(): invalid format" << format, {});
const UnsignedInt data = CompressedBlockData[UnsignedInt(format) - 1];
return {
(Int(data >> 12) & 0xf) + 1,
(Int(data >> 8) & 0xf) + 1,
(Int(data >> 4) & 0xf) + 1,
};
}
UnsignedInt compressedBlockDataSize(const CompressedPixelFormat format) {
CORRADE_ASSERT(!(UnsignedInt(format) & (1 << 31)),
"compressedBlockDataSize(): can't determine size of an implementation-specific format", {});
CORRADE_ASSERT(UnsignedInt(format) - 1 < Containers::arraySize(CompressedBlockData),
"compressedBlockDataSize(): invalid format" << format, {});
return (CompressedBlockData[UnsignedInt(format) - 1] & 0xf) + 1;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
Debug& operator<<(Debug& debug, const CompressedPixelFormat value) {
if(isCompressedPixelFormatImplementationSpecific(value)) {

23
src/Magnum/PixelFormat.h

@ -749,7 +749,8 @@ For D3D, corresponds to @m_class{m-doc-external} [DXGI_FORMAT](https://docs.micr
and import is provided by the @ref Trade::DdsImporter "DdsImporter" plugin; for
Metal, corresponds to @m_class{m-doc-external} [MTLPixelFormat](https://developer.apple.com/documentation/metal/mtlpixelformat?language=objc).
See documentation of each value for more information about the mapping.
@see @ref PixelFormat, @ref CompressedImage, @ref CompressedImageView
@see @ref compressedBlockSize(), @ref compressedBlockDataSize(),
@ref PixelFormat, @ref CompressedImage, @ref CompressedImageView
*/
enum class CompressedPixelFormat: UnsignedInt {
/* Zero reserved for an invalid format (but not being a named value) */
@ -1591,6 +1592,26 @@ enum class CompressedPixelFormat: UnsignedInt {
Metal doesn't support it and it doesn't have a WebGL equiv either. */
};
/**
@brief Compressed block size
For 2D formats the Z dimension is always 1. Expects that the pixel format is
* *not* implementation-specific.
@see @ref compressedBlockDataSize(),
@ref isCompressedPixelFormatImplementationSpecific()
*/
MAGNUM_EXPORT Vector3i compressedBlockSize(CompressedPixelFormat format);
/**
@brief Compressed block data size
Byte size of each compressed block. Expects that the pixel format is *not*
implementation-specific.
@see @ref compressedBlockSize(),
@ref isCompressedPixelFormatImplementationSpecific()
*/
MAGNUM_EXPORT UnsignedInt compressedBlockDataSize(CompressedPixelFormat format);
/** @debugoperatorenum{CompressedPixelFormat} */
MAGNUM_EXPORT Debug& operator<<(Debug& debug, CompressedPixelFormat value);

2
src/Magnum/PixelStorage.h

@ -185,6 +185,7 @@ class MAGNUM_EXPORT CompressedPixelStorage: public PixelStorage {
* If set to @cpp 0 @ce for given dimension, size information from
* particular compressed format is used. Default is @cpp 0 @ce in all
* dimensions.
* @see @ref Magnum::compressedBlockSize()
*/
CompressedPixelStorage& setCompressedBlockSize(const Vector3i& size) {
_blockSize = size;
@ -199,6 +200,7 @@ class MAGNUM_EXPORT CompressedPixelStorage: public PixelStorage {
*
* If set to @cpp 0 @ce, size information from particular compressed
* format is used. Default is @cpp 0 @ce in all dimensions.
* @see @ref Magnum::compressedBlockDataSize()
*/
CompressedPixelStorage& setCompressedBlockDataSize(Int size) {
_blockDataSize = size;

95
src/Magnum/Test/PixelFormatTest.cpp

@ -25,9 +25,11 @@
#include <sstream>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Numeric.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/PixelFormat.h"
#include "Magnum/Math/Vector3.h"
namespace Magnum { namespace Test { namespace {
@ -38,6 +40,10 @@ struct PixelFormatTest: TestSuite::Tester {
void sizeInvalid();
void sizeImplementationSpecific();
void compressedBlockSize();
void compressedBlockSizeInvalid();
void compressedBlockSizeImplementationSpecific();
void isImplementationSpecific();
void wrap();
void wrapInvalid();
@ -62,6 +68,10 @@ PixelFormatTest::PixelFormatTest() {
&PixelFormatTest::sizeInvalid,
&PixelFormatTest::sizeImplementationSpecific,
&PixelFormatTest::compressedBlockSize,
&PixelFormatTest::compressedBlockSizeInvalid,
&PixelFormatTest::compressedBlockSizeImplementationSpecific,
&PixelFormatTest::isImplementationSpecific,
&PixelFormatTest::wrap,
&PixelFormatTest::wrapInvalid,
@ -113,6 +123,91 @@ void PixelFormatTest::sizeImplementationSpecific() {
CORRADE_COMPARE(out.str(), "pixelSize(): can't determine pixel size of an implementation-specific format\n");
}
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);
/* 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 = CompressedPixelFormat(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, width, height, depth, size) \
case CompressedPixelFormat::format: \
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \
CORRADE_COMPARE(Magnum::compressedBlockSize(CompressedPixelFormat::format), (Vector3i{width, height, depth})); \
CORRADE_COMPARE(compressedBlockDataSize(CompressedPixelFormat::format), size/8); \
CORRADE_COMPARE(size % 8, 0); \
CORRADE_COMPARE_AS(width, 16, TestSuite::Compare::LessOrEqual); \
CORRADE_COMPARE_AS(height, 16, TestSuite::Compare::LessOrEqual); \
CORRADE_COMPARE_AS(depth, 16, TestSuite::Compare::LessOrEqual); \
CORRADE_COMPARE_AS(size/8, 16, TestSuite::Compare::LessOrEqual); \
++nextHandled; \
continue;
#include "Magnum/Implementation/compressedPixelFormatMapping.hpp"
#undef _c
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
/* 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(firstUnhandled, 0xffff);
}
void PixelFormatTest::compressedBlockSizeInvalid() {
std::ostringstream out;
Error redirectError{&out};
Magnum::compressedBlockSize(CompressedPixelFormat{});
Magnum::compressedBlockSize(CompressedPixelFormat(0xdead));
compressedBlockDataSize(CompressedPixelFormat{});
compressedBlockDataSize(CompressedPixelFormat(0xdead));
CORRADE_COMPARE(out.str(),
"compressedBlockSize(): invalid format CompressedPixelFormat(0x0)\n"
"compressedBlockSize(): invalid format CompressedPixelFormat(0xdead)\n"
"compressedBlockDataSize(): invalid format CompressedPixelFormat(0x0)\n"
"compressedBlockDataSize(): invalid format CompressedPixelFormat(0xdead)\n");
}
void PixelFormatTest::compressedBlockSizeImplementationSpecific() {
std::ostringstream out;
Error redirectError{&out};
Magnum::compressedBlockSize(compressedPixelFormatWrap(0xdead));
compressedBlockDataSize(compressedPixelFormatWrap(0xdead));
CORRADE_COMPARE(out.str(),
"compressedBlockSize(): can't determine size of an implementation-specific format\n"
"compressedBlockDataSize(): can't determine size of an implementation-specific format\n");
}
void PixelFormatTest::isImplementationSpecific() {
constexpr bool a = isPixelFormatImplementationSpecific(PixelFormat::RGBA8Unorm);
constexpr bool b = isPixelFormatImplementationSpecific(PixelFormat(0x8000dead));

Loading…
Cancel
Save