Browse Source

GL,Vk: inverse mapping of {Texture,Pixel}Format to generic PixelFormat.

An ad-hoc solution was already done in DebugTools::screenshot(), now I
need it in another place. While not as fast as the O(1) mapping from
the generic format to the API-specific ones due to the potentially
linear lookup, it definitely could be useful in general.
pull/168/head
Vladimír Vondruš 3 years ago
parent
commit
7060a83ca9
  1. 5
      doc/changelog.dox
  2. 15
      src/Magnum/DebugTools/Screenshot.cpp
  3. 4
      src/Magnum/DebugTools/Test/ScreenshotGLTest.cpp
  4. 54
      src/Magnum/GL/Implementation/compressedPixelFormatMapping.hpp
  5. 28
      src/Magnum/GL/Implementation/pixelFormatMapping.hpp
  6. 106
      src/Magnum/GL/PixelFormat.cpp
  7. 60
      src/Magnum/GL/PixelFormat.h
  8. 94
      src/Magnum/GL/Test/PixelFormatTest.cpp
  9. 8
      src/Magnum/GL/TextureFormat.cpp
  10. 51
      src/Magnum/GL/TextureFormat.h
  11. 44
      src/Magnum/PixelFormat.h
  12. 14
      src/Magnum/Vk/Implementation/compressedPixelFormatMapping.hpp
  13. 49
      src/Magnum/Vk/PixelFormat.cpp
  14. 50
      src/Magnum/Vk/PixelFormat.h
  15. 43
      src/Magnum/Vk/Test/PixelFormatTest.cpp

5
doc/changelog.dox

@ -606,6 +606,11 @@ See also:
in @ref GL::Extensions for compatibility with older browsers.
- Re-enabled @fn_gl{DrawRangeElements} for WebGL 2, this time hopefully for
the last time (see [mosra/magnum#97](https://github.com/mosra/magnum/issues/97))
- Added @ref GL::genericPixelFormat() and
@ref GL::genericCompressedPixelFormat() helpers for convenient mapping of
@ref GL::PixelFormat, @ref GL::PixelType, @ref GL::CompressedPixelFormat
and @ref GL::TextureFormat values back to the generic @ref PixelFormat and
@ref CompressedPixelFormat
@subsubsection changelog-latest-changes-math Math library

15
src/Magnum/DebugTools/Screenshot.cpp

@ -47,20 +47,9 @@ bool screenshot(PluginManager::Manager<Trade::AbstractImageConverter>& manager,
/* Get the implementation-specific color read format for given framebuffer */
const GL::PixelFormat format = framebuffer.implementationColorReadFormat();
const GL::PixelType type = framebuffer.implementationColorReadType();
auto genericFormat = [](GL::PixelFormat format, GL::PixelType type) -> Containers::Optional<PixelFormat> {
#ifndef DOXYGEN_GENERATING_OUTPUT /* It gets *really* confused */
#define _c(generic, glFormat, glType, glTextureFormat) if(format == GL::PixelFormat::glFormat && type == GL::PixelType::glType) return PixelFormat::generic;
#define _n(generic, glFormat, glType) if(format == GL::PixelFormat::glFormat && type == GL::PixelType::glType) return PixelFormat::generic;
#define _s(generic) return {};
#include "Magnum/GL/Implementation/pixelFormatMapping.hpp"
#undef _c
#undef _n
#undef _s
#endif
return {};
}(format, type);
const Containers::Optional<PixelFormat> genericFormat = GL::genericPixelFormat(format, type);
if(!genericFormat) {
Error{} << "DebugTools::screenshot(): can't map (" << Debug::nospace << format << Debug::nospace << "," << type << Debug::nospace << ") to a generic pixel format";
Error{} << "DebugTools::screenshot(): can't map {" << Debug::nospace << format << Debug::nospace << "," << type << Debug::nospace << "} to a generic pixel format";
return false;
}

4
src/Magnum/DebugTools/Test/ScreenshotGLTest.cpp

@ -244,9 +244,9 @@ void ScreenshotGLTest::unknownFormat() {
CORRADE_VERIFY(!succeeded);
if(framebuffer.implementationColorReadFormat() == GL::PixelFormat::RGBA)
CORRADE_COMPARE(out.str(), "DebugTools::screenshot(): can't map (GL::PixelFormat::RGBA, GL::PixelType::UnsignedShort565) to a generic pixel format\n");
CORRADE_COMPARE(out.str(), "DebugTools::screenshot(): can't map {GL::PixelFormat::RGBA, GL::PixelType::UnsignedShort565} to a generic pixel format\n");
else
CORRADE_COMPARE(out.str(), "DebugTools::screenshot(): can't map (GL::PixelFormat::RGB, GL::PixelType::UnsignedShort565) to a generic pixel format\n");
CORRADE_COMPARE(out.str(), "DebugTools::screenshot(): can't map {GL::PixelFormat::RGB, GL::PixelType::UnsignedShort565} to a generic pixel format\n");
}
void ScreenshotGLTest::pluginLoadFailed() {

54
src/Magnum/GL/Implementation/compressedPixelFormatMapping.hpp

@ -23,7 +23,11 @@
DEALINGS IN THE SOFTWARE.
*/
/* See Magnum/GL/PixelFormat.cpp and Magnum/GL/Test/PixelFormatTest.cpp */
/* See Magnum/GL/PixelFormat.cpp and Magnum/GL/Test/PixelFormatTest.cpp. _c()
is a mapping with the second element being both a CompressedPixelFormat and
a (compressed) TextureFormat as they share the same values. _s() denotes a
skipped value (so the enum numbering is preserved), _d() denotes a duplicate
_c() value, i.e. a N:1 mapping from a generic format. */
#ifdef _c
_c(Bc1RGBUnorm, RGBS3tcDxt1)
_c(Bc1RGBSrgb, SRGBS3tcDxt1)
@ -62,77 +66,77 @@ _c(Etc2RGB8A1Unorm, RGB8PunchthroughAlpha1Etc2)
_c(Etc2RGB8A1Srgb, SRGB8PunchthroughAlpha1Etc2)
_c(Etc2RGBA8Unorm, RGBA8Etc2Eac)
_c(Etc2RGBA8Srgb, SRGB8Alpha8Etc2Eac)
_c(Astc4x4RGBAUnorm, RGBAAstc4x4)
_d(Astc4x4RGBAUnorm, RGBAAstc4x4)
_c(Astc4x4RGBASrgb, SRGB8Alpha8Astc4x4)
_c(Astc4x4RGBAF, RGBAAstc4x4)
_c(Astc5x4RGBAUnorm, RGBAAstc5x4)
_d(Astc5x4RGBAUnorm, RGBAAstc5x4)
_c(Astc5x4RGBASrgb, SRGB8Alpha8Astc5x4)
_c(Astc5x4RGBAF, RGBAAstc5x4)
_c(Astc5x5RGBAUnorm, RGBAAstc5x5)
_d(Astc5x5RGBAUnorm, RGBAAstc5x5)
_c(Astc5x5RGBASrgb, SRGB8Alpha8Astc5x5)
_c(Astc5x5RGBAF, RGBAAstc5x5)
_c(Astc6x5RGBAUnorm, RGBAAstc6x5)
_d(Astc6x5RGBAUnorm, RGBAAstc6x5)
_c(Astc6x5RGBASrgb, SRGB8Alpha8Astc6x5)
_c(Astc6x5RGBAF, RGBAAstc6x5)
_c(Astc6x6RGBAUnorm, RGBAAstc6x6)
_d(Astc6x6RGBAUnorm, RGBAAstc6x6)
_c(Astc6x6RGBASrgb, SRGB8Alpha8Astc6x6)
_c(Astc6x6RGBAF, RGBAAstc6x6)
_c(Astc8x5RGBAUnorm, RGBAAstc8x5)
_d(Astc8x5RGBAUnorm, RGBAAstc8x5)
_c(Astc8x5RGBASrgb, SRGB8Alpha8Astc8x5)
_c(Astc8x5RGBAF, RGBAAstc8x5)
_c(Astc8x6RGBAUnorm, RGBAAstc8x6)
_d(Astc8x6RGBAUnorm, RGBAAstc8x6)
_c(Astc8x6RGBASrgb, SRGB8Alpha8Astc8x6)
_c(Astc8x6RGBAF, RGBAAstc8x6)
_c(Astc8x8RGBAUnorm, RGBAAstc8x8)
_d(Astc8x8RGBAUnorm, RGBAAstc8x8)
_c(Astc8x8RGBASrgb, SRGB8Alpha8Astc8x8)
_c(Astc8x8RGBAF, RGBAAstc8x8)
_c(Astc10x5RGBAUnorm, RGBAAstc10x5)
_d(Astc10x5RGBAUnorm, RGBAAstc10x5)
_c(Astc10x5RGBASrgb, SRGB8Alpha8Astc10x5)
_c(Astc10x5RGBAF, RGBAAstc10x5)
_c(Astc10x6RGBAUnorm, RGBAAstc10x6)
_d(Astc10x6RGBAUnorm, RGBAAstc10x6)
_c(Astc10x6RGBASrgb, SRGB8Alpha8Astc10x6)
_c(Astc10x6RGBAF, RGBAAstc10x6)
_c(Astc10x8RGBAUnorm, RGBAAstc10x8)
_d(Astc10x8RGBAUnorm, RGBAAstc10x8)
_c(Astc10x8RGBASrgb, SRGB8Alpha8Astc10x8)
_c(Astc10x8RGBAF, RGBAAstc10x8)
_c(Astc10x10RGBAUnorm, RGBAAstc10x10)
_d(Astc10x10RGBAUnorm, RGBAAstc10x10)
_c(Astc10x10RGBASrgb, SRGB8Alpha8Astc10x10)
_c(Astc10x10RGBAF, RGBAAstc10x10)
_c(Astc12x10RGBAUnorm, RGBAAstc12x10)
_d(Astc12x10RGBAUnorm, RGBAAstc12x10)
_c(Astc12x10RGBASrgb, SRGB8Alpha8Astc12x10)
_c(Astc12x10RGBAF, RGBAAstc12x10)
_c(Astc12x12RGBAUnorm, RGBAAstc12x12)
_d(Astc12x12RGBAUnorm, RGBAAstc12x12)
_c(Astc12x12RGBASrgb, SRGB8Alpha8Astc12x12)
_c(Astc12x12RGBAF, RGBAAstc12x12)
#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
_c(Astc3x3x3RGBAUnorm, RGBAAstc3x3x3)
_d(Astc3x3x3RGBAUnorm, RGBAAstc3x3x3)
_c(Astc3x3x3RGBASrgb, SRGB8Alpha8Astc3x3x3)
_c(Astc3x3x3RGBAF, RGBAAstc3x3x3)
_c(Astc4x3x3RGBAUnorm, RGBAAstc4x3x3)
_d(Astc4x3x3RGBAUnorm, RGBAAstc4x3x3)
_c(Astc4x3x3RGBASrgb, SRGB8Alpha8Astc4x3x3)
_c(Astc4x3x3RGBAF, RGBAAstc4x3x3)
_c(Astc4x4x3RGBAUnorm, RGBAAstc4x4x3)
_d(Astc4x4x3RGBAUnorm, RGBAAstc4x4x3)
_c(Astc4x4x3RGBASrgb, SRGB8Alpha8Astc4x4x3)
_c(Astc4x4x3RGBAF, RGBAAstc4x4x3)
_c(Astc4x4x4RGBAUnorm, RGBAAstc4x4x4)
_d(Astc4x4x4RGBAUnorm, RGBAAstc4x4x4)
_c(Astc4x4x4RGBASrgb, SRGB8Alpha8Astc4x4x4)
_c(Astc4x4x4RGBAF, RGBAAstc4x4x4)
_c(Astc5x4x4RGBAUnorm, RGBAAstc5x4x4)
_d(Astc5x4x4RGBAUnorm, RGBAAstc5x4x4)
_c(Astc5x4x4RGBASrgb, SRGB8Alpha8Astc5x4x4)
_c(Astc5x4x4RGBAF, RGBAAstc5x4x4)
_c(Astc5x5x4RGBAUnorm, RGBAAstc5x5x4)
_d(Astc5x5x4RGBAUnorm, RGBAAstc5x5x4)
_c(Astc5x5x4RGBASrgb, SRGB8Alpha8Astc5x5x4)
_c(Astc5x5x4RGBAF, RGBAAstc5x5x4)
_c(Astc5x5x5RGBAUnorm, RGBAAstc5x5x5)
_d(Astc5x5x5RGBAUnorm, RGBAAstc5x5x5)
_c(Astc5x5x5RGBASrgb, SRGB8Alpha8Astc5x5x5)
_c(Astc5x5x5RGBAF, RGBAAstc5x5x5)
_c(Astc6x5x5RGBAUnorm, RGBAAstc6x5x5)
_d(Astc6x5x5RGBAUnorm, RGBAAstc6x5x5)
_c(Astc6x5x5RGBASrgb, SRGB8Alpha8Astc6x5x5)
_c(Astc6x5x5RGBAF, RGBAAstc6x5x5)
_c(Astc6x6x5RGBAUnorm, RGBAAstc6x6x5)
_d(Astc6x6x5RGBAUnorm, RGBAAstc6x6x5)
_c(Astc6x6x5RGBASrgb, SRGB8Alpha8Astc6x6x5)
_c(Astc6x6x5RGBAF, RGBAAstc6x6x5)
_c(Astc6x6x6RGBAUnorm, RGBAAstc6x6x6)
_d(Astc6x6x6RGBAUnorm, RGBAAstc6x6x6)
_c(Astc6x6x6RGBASrgb, SRGB8Alpha8Astc6x6x6)
_c(Astc6x6x6RGBAF, RGBAAstc6x6x6)
#else

28
src/Magnum/GL/Implementation/pixelFormatMapping.hpp

@ -26,7 +26,10 @@
/* See Magnum/GL/PixelFormat.cpp, Magnum/GL/Test/PixelFormatTest.cpp and
DebugTools/Screenshot.cpp. _c() is a mapping, _s() denotes a skipped value
(so the enum numbering is preserved), _n() denotes a value where pixel
format mapping is defined, but texture format is not */
format mapping is defined, but texture format is not; _d() denotes a
_c() value with duplicated format/type combination, i.e. a N:1 mapping from
a generic format, _dn() then a _n() value with duplicated format/type
combination. */
#ifdef _c
#ifndef MAGNUM_TARGET_GLES2
_c(R8Unorm, Red, UnsignedByte, R8)
@ -58,23 +61,26 @@ _s(RGBA8Snorm)
texture format tho. */
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
_c(R8Srgb, Red, UnsignedByte, SR8)
_c(RG8Srgb, RG, UnsignedByte, SRG8)
_d(R8Srgb, Red, UnsignedByte, SR8)
_d(RG8Srgb, RG, UnsignedByte, SRG8)
#else
_n(R8Srgb, Red, UnsignedByte)
_n(RG8Srgb, RG, UnsignedByte)
_dn(R8Srgb, Red, UnsignedByte)
_dn(RG8Srgb, RG, UnsignedByte)
#endif
#else
/* SLUMINANCE / SLUMINANCE_ALPHA texture formats not exposed */
_n(R8Srgb, Luminance, UnsignedByte)
_n(RG8Srgb, LuminanceAlpha, UnsignedByte)
_dn(R8Srgb, Luminance, UnsignedByte)
_dn(RG8Srgb, LuminanceAlpha, UnsignedByte)
#endif
/* Again, GL's pixel format doesn't distinguish between linear and sRGB, so
mapping is the same as in case of the Unorm types. It's encoded in the
texture format tho. */
#ifndef MAGNUM_TARGET_GLES2
_c(RGB8Srgb, RGB, UnsignedByte, SRGB8)
_c(RGBA8Srgb, RGBA, UnsignedByte, SRGB8Alpha8)
_d(RGB8Srgb, RGB, UnsignedByte, SRGB8)
_d(RGBA8Srgb, RGBA, UnsignedByte, SRGB8Alpha8)
#else
_n(RGB8Srgb, RGB, UnsignedByte)
_n(RGBA8Srgb, RGBA, UnsignedByte)
_dn(RGB8Srgb, RGB, UnsignedByte)
_dn(RGBA8Srgb, RGBA, UnsignedByte)
#endif
#ifndef MAGNUM_TARGET_GLES2
_c(R8UI, RedInteger, UnsignedByte, R8UI)

106
src/Magnum/GL/PixelFormat.cpp

@ -25,8 +25,9 @@
#include "PixelFormat.h"
#include <Corrade/Utility/Assert.h>
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h>
#include "Magnum/PixelFormat.h"
@ -41,24 +42,32 @@ constexpr struct {
PixelFormat format;
PixelType type;
} FormatMapping[] {
#define _c(input, format, type, textureFormat) {PixelFormat::format, PixelType::type},
/* GCC 4.8 doesn't like just a {} for default enum values */
#define _n(input, format, type) {PixelFormat::format, PixelType::type},
#define _dn _n
#define _c(input, format, type, textureFormat) _n(input, format, type)
#define _d _c
/* GCC 4.8 doesn't like just a {} for default enum values */
#define _s(input) {PixelFormat{}, PixelType{}},
#include "Magnum/GL/Implementation/pixelFormatMapping.hpp"
#undef _s
#undef _n
#undef _d
#undef _c
#undef _nd
#undef _n
};
constexpr TextureFormat TextureFormatMapping[] {
#define _c(input, format, type, textureFormat) TextureFormat::textureFormat,
#define _d _c
/* GCC 4.8 doesn't like just a {} for default enum values */
#define _n(input, format, type) TextureFormat{},
#define _s(input) TextureFormat{},
#define _n(input, format, type) _s(input)
#define _dn _n
#include "Magnum/GL/Implementation/pixelFormatMapping.hpp"
#undef _s
#undef _dn
#undef _n
#undef _s
#undef _d
#undef _c
};
#endif
@ -261,6 +270,57 @@ UnsignedInt pixelFormatSize(const PixelFormat format, const PixelType type) {
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
Containers::Optional<Magnum::PixelFormat> genericPixelFormat(const PixelFormat format, PixelType type) {
/* Assuming a switch will get better optimized to some LUT than an if
cascade */
switch((UnsignedLong(format) << 32)|UnsignedLong(type)) {
#define _n(input, format, type) \
case (UnsignedLong(PixelFormat::format) << 32)| \
UnsignedLong(PixelType::type): \
return Magnum::PixelFormat::input;
#define _c(input, format, type, textureFormat) _n(input, format, type)
#define _d(input, format, type, textureFormat)
#define _dn(input, format, type)
#define _s(input)
#include "Magnum/GL/Implementation/pixelFormatMapping.hpp"
#undef _s
#undef _dn
#undef _n
#undef _d
#undef _c
}
return {};
}
Containers::Optional<Magnum::PixelFormat> genericPixelFormat(const TextureFormat format) {
switch(format) {
#define _c(input, format, type, textureFormat) \
case TextureFormat::textureFormat: return Magnum::PixelFormat::input;
#define _d _c
#define _n(input, format, type)
#define _dn(input, format, type)
#define _s(input)
#include "Magnum/GL/Implementation/pixelFormatMapping.hpp"
#undef _s
#undef _dn
#undef _n
#undef _d
#undef _c
/* For compressed formats it returns NullOpt too instead of asserting,
as -- compared to the generic-to-GL translation, which is O(1) --
the inverse mapping is potentially a linear lookup and forcing the
user to check some isTextureFormatCompressed() first (which would do
another linear lookup) makes no sense from a perf PoV. Plus for
unknown formats it's unknown whether it's a compressed format or
not, and the function suddenly starting to assert when a format
becomes known isn't good for backwards compatibility. */
default:
return {};
}
}
#ifndef DOXYGEN_GENERATING_OUTPUT
Debug& operator<<(Debug& debug, const PixelFormat value) {
debug << "GL::PixelFormat" << Debug::nospace;
@ -402,9 +462,11 @@ namespace {
having just a single table for both */
constexpr CompressedPixelFormat CompressedFormatMapping[] {
#define _c(input, format) CompressedPixelFormat::format,
#define _d _c
#define _s(input) CompressedPixelFormat{},
#include "Magnum/GL/Implementation/compressedPixelFormatMapping.hpp"
#undef _s
#undef _d
#undef _c
};
#endif
@ -455,6 +517,38 @@ TextureFormat textureFormat(const Magnum::CompressedPixelFormat format) {
return out;
}
Containers::Optional<Magnum::CompressedPixelFormat> genericCompressedPixelFormat(const CompressedPixelFormat format) {
switch(format) {
#define _c(input, format) \
case CompressedPixelFormat::format: \
return Magnum::CompressedPixelFormat::input;
#define _d(input, format)
#define _s(input)
#include "Magnum/GL/Implementation/compressedPixelFormatMapping.hpp"
#undef _s
#undef _d
#undef _c
default:
return {};
}
}
Containers::Optional<Magnum::CompressedPixelFormat> genericCompressedPixelFormat(const TextureFormat format) {
/* Enum values are the same between CompressedPixelFormat and
TextureFormat, so just casting and delegating.
For uncompressed formats it returns NullOpt too instead of asserting, as
-- compared to the generic-to-GL translation, which is O(1) -- the
inverse mapping is potentially a linear lookup and forcing the user to
check some isTextureFormatCompressed() first (which would do another
linear lookup) makes no sense from a perf PoV. Plus for unknown formats
it's unknown whether it's a compressed format or not, and the function
suddenly starting to assert when a format becomes known isn't good for
backwards compatibility. */
return genericCompressedPixelFormat(CompressedPixelFormat(UnsignedInt(format)));
}
Debug& operator<<(Debug& debug, const CompressedPixelFormat value) {
debug << "GL::CompressedPixelFormat" << Debug::nospace;

60
src/Magnum/GL/PixelFormat.h

@ -26,7 +26,7 @@
*/
/** @file
* @brief Enum @ref Magnum::GL::PixelFormat, @ref Magnum::GL::PixelType, @ref Magnum::GL::CompressedPixelFormat, function @ref Magnum::GL::hasPixelFormat(), @ref Magnum::GL::pixelFormat(), @ref Magnum::GL::pixelType(), @ref Magnum::GL::pixelFormatSize(), @ref Magnum::GL::hasCompressedPixelFormat(), @ref Magnum::GL::compressedPixelFormat()
* @brief Enum @ref Magnum::GL::PixelFormat, @ref Magnum::GL::PixelType, @ref Magnum::GL::CompressedPixelFormat, function @ref Magnum::GL::hasPixelFormat(), @ref Magnum::GL::pixelFormat(), @ref Magnum::GL::pixelType(), @ref Magnum::GL::pixelFormatSize(), @ref Magnum::GL::genericPixelFormat(), @ref Magnum::GL::hasCompressedPixelFormat(), @ref Magnum::GL::compressedPixelFormat(), @ref Magnum::GL::genericCompressedPixelFormat()
*/
#include <Corrade/Utility/Assert.h>
@ -648,6 +648,7 @@ value is expected to be valid.
extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format.
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref pixelFormat(), @ref pixelType(), @ref hasCompressedPixelFormat()
*/
MAGNUM_GL_EXPORT bool hasPixelFormat(Magnum::PixelFormat format);
@ -671,7 +672,9 @@ to query availability of given format.
@gl_extension{EXT,texture_rg} being present or not. If you wish to use @ref PixelFormat::Red and @ref PixelFormat::RG instead, specify the GL-specific
pixel format directly instead of using the generic enum.
@see @ref pixelType(), @ref compressedPixelFormat()
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref pixelType(), @ref compressedPixelFormat(),
@ref genericPixelFormat(PixelFormat, PixelType)
*/
MAGNUM_GL_EXPORT PixelFormat pixelFormat(Magnum::PixelFormat format);
@ -687,7 +690,10 @@ In case @ref isPixelFormatImplementationSpecific() returns @cpp false @ce for
Not all generic pixel formats may be available on all targets and this function
expects that given format is available on the target. Use @ref hasPixelFormat()
to query availability of given format.
@see @ref pixelFormat(), @ref compressedPixelFormat()
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref pixelFormat(), @ref compressedPixelFormat(),
@ref genericPixelFormat(PixelFormat, PixelType)
*/
MAGNUM_GL_EXPORT PixelType pixelType(Magnum::PixelFormat format, UnsignedInt extra = 0);
@ -708,6 +714,27 @@ CORRADE_DEPRECATED("use pixelFormatSize() instead") inline UnsignedInt pixelSize
}
#endif
/**
@brief Convert OpenGL pixel format and type combination to a generic pixel format
@m_since_latest
Returns @ref Containers::NullOpt if given combination doesn't match any generic
pixel format. Otherwise the returned value will result in the same @p format
and @p type when passed back to @ref pixelFormat(Magnum::PixelFormat) and
@ref pixelType(Magnum::PixelFormat, UnsignedInt).
An exception is sRGB formats --- those map to the same OpenGL format + type
combination, e.g. @ref Magnum::PixelFormat::RGBA8Unorm and
@relativeref{Magnum::PixelFormat,RGBA8Srgb} both result in
@ref GL::PixelFormat::RGBA + @ref GL::PixelType::UnsignedByte. This function
always maps the OpenGL format + type combination to the linear type, not sRGB.
Unlike mapping *from* a generic pixel format, the inverse operation is done
with an @f$ \mathcal{O}(n) @f$ complexity.
@see @ref genericCompressedPixelFormat(CompressedPixelFormat)
*/
MAGNUM_GL_EXPORT Containers::Optional<Magnum::PixelFormat> genericPixelFormat(PixelFormat format, PixelType type);
/** @debugoperatorenum{PixelFormat} */
MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, PixelFormat value);
@ -2103,6 +2130,7 @@ expected to be valid.
extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format.
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref compressedPixelFormat(), @ref hasPixelFormat(),
@ref hasTextureFormat()
*/
@ -2120,10 +2148,34 @@ returns @ref compressedPixelFormatUnwrap() cast to @ref GL::CompressedPixelForma
Not all generic pixel formats may be available on all targets and this function
expects that given format is available on the target. Use
@ref hasCompressedPixelFormat() to query availability of given format.
@see @ref pixelFormat(), @ref textureFormat()
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref pixelFormat(), @ref textureFormat(),
@ref genericCompressedPixelFormat(CompressedPixelFormat)
*/
MAGNUM_GL_EXPORT CompressedPixelFormat compressedPixelFormat(Magnum::CompressedPixelFormat format);
/**
@brief Convert OpenGL compressed pixel format to a generic compressed pixel format
@m_since_latest
Returns @ref Containers::NullOpt if given format doesn't match any generic
pixel format. Otherwise the returned value will result in the same @p format
when passed back to @ref compressedPixelFormat(Magnum::CompressedPixelFormat).
An exception is ASTC float and normalized formats --- those map to the same
OpenGL format, e.g. @ref Magnum::CompressedPixelFormat::Astc4x4RGBAUnorm and
@relativeref{Magnum::CompressedPixelFormat,Astc4x4RGBAF} both result in
@ref GL::CompressedPixelFormat::RGBAAstc4x4. To avoid potential information
loss, this function always maps the OpenGL ASTC format back to the float
variant.
Unlike mapping *from* a generic pixel format, the inverse operation is done
with an @f$ \mathcal{O}(n) @f$ complexity.
@see @ref genericPixelFormat(PixelFormat, PixelType)
*/
MAGNUM_GL_EXPORT Containers::Optional<Magnum::CompressedPixelFormat> genericCompressedPixelFormat(CompressedPixelFormat format);
/** @debugoperatorenum{CompressedPixelFormat} */
MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, CompressedPixelFormat value);

94
src/Magnum/GL/Test/PixelFormatTest.cpp

@ -24,6 +24,7 @@
*/
#include <sstream>
#include <Corrade/Containers/Optional.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
@ -50,6 +51,7 @@ struct PixelFormatTest: TestSuite::Tester {
void mapTextureFormatImplementationSpecific();
void mapTextureFormatUnsupported();
void mapTextureFormatInvalid();
void mapGenericFormatUnsupported();
void size();
void sizeInvalid();
@ -61,6 +63,7 @@ struct PixelFormatTest: TestSuite::Tester {
void mapCompressedTextureFormatImplementationSpecific();
void mapCompressedTextureFormatUnsupported();
void mapCompressedTextureFormatInvalid();
void mapGenericCompressedFormatUnsupported();
void debugPixelFormat();
void debugPixelType();
@ -80,6 +83,7 @@ PixelFormatTest::PixelFormatTest() {
&PixelFormatTest::mapTextureFormatImplementationSpecific,
&PixelFormatTest::mapTextureFormatUnsupported,
&PixelFormatTest::mapTextureFormatInvalid,
&PixelFormatTest::mapGenericFormatUnsupported,
&PixelFormatTest::size,
&PixelFormatTest::sizeInvalid,
@ -91,6 +95,7 @@ PixelFormatTest::PixelFormatTest() {
&PixelFormatTest::mapCompressedTextureFormatImplementationSpecific,
&PixelFormatTest::mapCompressedTextureFormatUnsupported,
&PixelFormatTest::mapCompressedTextureFormatInvalid,
&PixelFormatTest::mapGenericCompressedFormatUnsupported,
&PixelFormatTest::debugPixelFormat,
&PixelFormatTest::debugPixelType,
@ -103,12 +108,18 @@ void PixelFormatTest::mapFormatTypeTextureFormat() {
CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::RGBA8Unorm));
CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::RGBA8Unorm), PixelFormat::RGBA);
CORRADE_COMPARE(pixelType(Magnum::PixelFormat::RGBA8Unorm), PixelType::UnsignedByte);
CORRADE_COMPARE(genericPixelFormat(PixelFormat::RGB, PixelType::UnsignedByte), Magnum::PixelFormat::RGB8Unorm);
#ifndef MAGNUM_TARGET_GLES2
CORRADE_VERIFY(hasTextureFormat(Magnum::PixelFormat::RGBA8Unorm));
CORRADE_COMPARE(textureFormat(Magnum::PixelFormat::RGBA8Unorm), TextureFormat::RGBA8);
CORRADE_COMPARE(genericPixelFormat(TextureFormat::RGB8), Magnum::PixelFormat::RGB8Unorm);
#else
CORRADE_VERIFY(!hasTextureFormat(Magnum::PixelFormat::RGBA8Unorm));
CORRADE_COMPARE(genericPixelFormat(TextureFormat::RGB), Containers::NullOpt);
#endif
/* sRGB formats have N:1 mapping, conversion back is losing the sRGB bit */
CORRADE_COMPARE(genericPixelFormat(pixelFormat(Magnum::PixelFormat::R8Srgb), pixelType(Magnum::PixelFormat::R8Srgb)), Magnum::PixelFormat::R8Unorm);
CORRADE_COMPARE(genericPixelFormat(pixelFormat(Magnum::PixelFormat::RGBA8Srgb), pixelType(Magnum::PixelFormat::RGBA8Srgb)), Magnum::PixelFormat::RGBA8Unorm);
/* This goes through the first 16 bits, which should be enough. Going
through 32 bits takes 8 seconds, too much. */
@ -134,11 +145,51 @@ void PixelFormatTest::mapFormatTypeTextureFormat() {
CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::format)); \
CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::format), Magnum::GL::PixelFormat::expectedFormat); \
CORRADE_COMPARE(pixelType(Magnum::PixelFormat::format), Magnum::GL::PixelType::expectedType); \
CORRADE_COMPARE(genericPixelFormat(Magnum::GL::PixelFormat::expectedFormat, Magnum::GL::PixelType::expectedType), Magnum::PixelFormat::format); \
CORRADE_VERIFY(hasTextureFormat(Magnum::PixelFormat::format)); \
CORRADE_COMPARE(textureFormat(Magnum::PixelFormat::format), Magnum::GL::TextureFormat::expectedTextureFormat); \
CORRADE_COMPARE(genericPixelFormat(Magnum::GL::TextureFormat::expectedTextureFormat), Magnum::PixelFormat::format); \
++nextHandled; \
continue;
/* For duplicate format/type mappings compared to _c() it only
checks the forward mapping and genericPixelFormat() from a
TextureFormat. The duplicate mapping is tested in the touchstone
verification above. */
#define _d(format, expectedFormat, expectedType, expectedTextureFormat) \
case Magnum::PixelFormat::format: \
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \
CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::format)); \
CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::format), Magnum::GL::PixelFormat::expectedFormat); \
CORRADE_COMPARE(pixelType(Magnum::PixelFormat::format), Magnum::GL::PixelType::expectedType); \
CORRADE_VERIFY(hasTextureFormat(Magnum::PixelFormat::format)); \
CORRADE_COMPARE(textureFormat(Magnum::PixelFormat::format), Magnum::GL::TextureFormat::expectedTextureFormat); \
CORRADE_COMPARE(genericPixelFormat(Magnum::GL::TextureFormat::expectedTextureFormat), Magnum::PixelFormat::format); \
++nextHandled; \
continue;
#define _n(format, expectedFormat, expectedType) \
case Magnum::PixelFormat::format: { \
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \
CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::format)); \
CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::format), Magnum::GL::PixelFormat::expectedFormat); \
CORRADE_COMPARE(pixelType(Magnum::PixelFormat::format), Magnum::GL::PixelType::expectedType); \
CORRADE_COMPARE(genericPixelFormat(Magnum::GL::PixelFormat::expectedFormat, Magnum::GL::PixelType::expectedType), Magnum::PixelFormat::format); \
CORRADE_VERIFY(!hasTextureFormat(Magnum::PixelFormat::format)); \
std::ostringstream out; \
{ /* Redirected otherwise graceful assert would abort */ \
Error redirectError{&out}; \
textureFormat(Magnum::PixelFormat::format); \
} \
Debug{Debug::Flag::NoNewlineAtTheEnd} << out.str(); \
++nextHandled; \
continue; \
}
/* For duplicate format/type mappings compared to _n() it only
checks the forward mapping and genericPixelFormat() from a
TextureFormat. The duplicate mapping is tested in the touchstone
verification above. */
#define _dn(format, expectedFormat, expectedType) \
case Magnum::PixelFormat::format: { \
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \
@ -175,6 +226,7 @@ void PixelFormatTest::mapFormatTypeTextureFormat() {
#include "Magnum/GL/Implementation/pixelFormatMapping.hpp"
#undef _s
#undef _n
#undef _d
#undef _c
}
#ifdef CORRADE_TARGET_GCC
@ -319,6 +371,18 @@ void PixelFormatTest::mapTextureFormatInvalid() {
"GL::textureFormat(): invalid format PixelFormat(0x123)\n");
}
void PixelFormatTest::mapGenericFormatUnsupported() {
/* These don't have any generic equivalent yet */
#ifndef MAGNUM_TARGET_WEBGL
CORRADE_COMPARE(genericPixelFormat(PixelFormat::BGRA, PixelType::UnsignedByte), Containers::NullOpt);
#endif
CORRADE_COMPARE(genericPixelFormat(PixelFormat::RGBA, PixelType::UnsignedShort565), Containers::NullOpt);
CORRADE_COMPARE(genericPixelFormat(TextureFormat::RGB565), Containers::NullOpt);
/* For compressed texture formats it returns NullOpt too, instead of
asserting. See comment in the source for reasons. */
CORRADE_COMPARE(genericPixelFormat(TextureFormat::CompressedR11Eac), Containers::NullOpt);
}
void PixelFormatTest::size() {
#ifndef MAGNUM_TARGET_GLES
CORRADE_COMPARE(pixelFormatSize(PixelFormat::RGB, PixelType::UnsignedByte332), 1);
@ -350,6 +414,9 @@ void PixelFormatTest::mapCompressedFormatTextureFormat() {
CORRADE_COMPARE(compressedPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm), CompressedPixelFormat::RGBAS3tcDxt1);
CORRADE_VERIFY(hasTextureFormat(Magnum::CompressedPixelFormat::Astc8x8RGBASrgb));
CORRADE_COMPARE(textureFormat(Magnum::CompressedPixelFormat::Astc8x8RGBASrgb), TextureFormat::CompressedSRGB8Alpha8Astc8x8);
/* ASTC Unorm formats have N:1 mapping, conversion back is losing the
Unorm/F distinction */
CORRADE_COMPARE(genericCompressedPixelFormat(compressedPixelFormat(Magnum::CompressedPixelFormat::Astc4x4RGBAUnorm)), Magnum::CompressedPixelFormat::Astc4x4RGBAF);
/* This goes through the first 16 bits, which should be enough. Going
through 32 bits takes 8 seconds, too much. */
@ -369,6 +436,21 @@ void PixelFormatTest::mapCompressedFormatTextureFormat() {
#endif
switch(format) {
#define _c(format, expectedFormat) \
case Magnum::CompressedPixelFormat::format: \
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \
CORRADE_VERIFY(hasCompressedPixelFormat(Magnum::CompressedPixelFormat::format)); \
CORRADE_COMPARE(genericCompressedPixelFormat(Magnum::GL::CompressedPixelFormat::expectedFormat), Magnum::CompressedPixelFormat::format); \
CORRADE_VERIFY(hasTextureFormat(Magnum::CompressedPixelFormat::format)); \
CORRADE_COMPARE(compressedPixelFormat(Magnum::CompressedPixelFormat::format), Magnum::GL::CompressedPixelFormat::expectedFormat); \
CORRADE_COMPARE(textureFormat(Magnum::CompressedPixelFormat::format), Magnum::GL::TextureFormat::Compressed ## expectedFormat); \
CORRADE_COMPARE(genericCompressedPixelFormat(Magnum::GL::TextureFormat::Compressed ## expectedFormat), Magnum::CompressedPixelFormat::format); \
++nextHandled; \
continue;
/* For duplicate mappings compared to _c() it only checks the
forward mapping. The duplicate mapping is tested in the
touchstone verification above */
#define _d(format, expectedFormat) \
case Magnum::CompressedPixelFormat::format: \
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \
@ -396,6 +478,7 @@ void PixelFormatTest::mapCompressedFormatTextureFormat() {
}
#include "Magnum/GL/Implementation/compressedPixelFormatMapping.hpp"
#undef _s
#undef _d
#undef _c
}
#ifdef CORRADE_TARGET_GCC
@ -501,6 +584,17 @@ void PixelFormatTest::mapCompressedTextureFormatInvalid() {
"GL::textureFormat(): invalid format CompressedPixelFormat(0x123)\n");
}
void PixelFormatTest::mapGenericCompressedFormatUnsupported() {
/* Generic formats don't have any generic equivalent yet (heh) */
#ifndef MAGNUM_TARGET_GLES
CORRADE_COMPARE(genericCompressedPixelFormat(CompressedPixelFormat::Red), Containers::NullOpt);
CORRADE_COMPARE(genericCompressedPixelFormat(TextureFormat::CompressedRed), Containers::NullOpt);
#endif
/* For uncompressed texture formats it returns NullOpt too, instead of
asserting. See comment in the source for reasons. */
CORRADE_COMPARE(genericCompressedPixelFormat(TextureFormat::RGB), Containers::NullOpt);
}
void PixelFormatTest::debugPixelFormat() {
std::ostringstream out;

8
src/Magnum/GL/TextureFormat.cpp

@ -34,9 +34,11 @@
namespace Magnum { namespace GL {
/* the textureFormat() and hasTextureFormat() utilities share mapping tables
with pixelFormat() / hasPixelFormat() so are defined in PixelFormat.cpp
instead (and tested there too) */
/* compressed textureFormat(), hasTextureFormat() and
genericCompressedPixelFormat(TextureFormat) utilities share mapping tables
with compressedPixelFormat(), hasCompressedPixelFormat() and
genericCompressedPixelFormat(CompressedPixelFormat) so are defined in
PixelFormat.cpp instead (and tested there too) */
#ifndef DOXYGEN_GENERATING_OUTPUT
Debug& operator<<(Debug& debug, const TextureFormat value) {

51
src/Magnum/GL/TextureFormat.h

@ -2625,6 +2625,7 @@ and other format-specific extensions are supported.
extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format.
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref textureFormat(), @ref hasPixelFormat(),
@ref hasCompressedPixelFormat()
*/
@ -2647,7 +2648,9 @@ manually based on whether @ref Texture::setImage() or
@ref Texture::setStorage() is used and whether @gl_extension{EXT,texture_storage}
and other format-specific extensions are supported.
@see @ref pixelType(), @ref compressedPixelFormat()
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref pixelType(), @ref compressedPixelFormat(),
@ref genericPixelFormat(TextureFormat)
*/
MAGNUM_GL_EXPORT TextureFormat textureFormat(Magnum::PixelFormat format);
@ -2669,6 +2672,7 @@ performed.
extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format.
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref textureFormat(), @ref hasCompressedPixelFormat(),
@ref hasPixelFormat()
*/
@ -2688,12 +2692,51 @@ an implementation-specific pixel format to an OpenGL texture format can't be
performed.
Not all generic pixel formats may be available on all targets and this function
expects that given format is available on the target. Use @ref hasTextureFormat()
to query availability of given format.
@see @ref compressedPixelFormat(), @ref pixelFormat()
expects that given format is available on the target. Use
@ref hasTextureFormat() to query availability of given format.
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref compressedPixelFormat(), @ref pixelFormat(),
@ref genericCompressedPixelFormat(TextureFormat)
*/
MAGNUM_GL_EXPORT TextureFormat textureFormat(Magnum::CompressedPixelFormat format);
/**
@brief Convert OpenGL texture format to a generic pixel format
@m_since_latest
Returns @ref Containers::NullOpt if given format is compressed or if it doesn't
match any generic pixel format. Otherwise the returned value will result in the
same @p format when passed back to @ref textureFormat(Magnum::PixelFormat).
Unlike mapping *from* a generic pixel format, the inverse operation is done
with an @f$ \mathcal{O}(n) @f$ complexity.
@see @ref genericCompressedPixelFormat(TextureFormat)
*/
MAGNUM_GL_EXPORT Containers::Optional<Magnum::PixelFormat> genericPixelFormat(TextureFormat format);
/**
@brief Convert OpenGL compressed texture format to a generic compressed pixel format
@m_since_latest
Returns @ref Containers::NullOpt if given format is not compressed or if it
doesn't match any generic compressed pixel format. Otherwise the returned value
will result in the same @p format when passed back to
@ref textureFormat(Magnum::CompressedPixelFormat).
An exception is ASTC float and normalized formats --- those map to the same
OpenGL format, e.g. @ref Magnum::CompressedPixelFormat::Astc4x4RGBAUnorm and
@relativeref{Magnum::CompressedPixelFormat,Astc4x4RGBAF} both result in
@ref GL::TextureFormat::CompressedRGBAAstc4x4. To avoid potential information
loss, this function always maps the OpenGL ASTC format back to the float
variant.
Unlike mapping *from* a generic pixel format, the inverse operation is done
with an @f$ \mathcal{O}(n) @f$ complexity.
@see @ref genericPixelFormat(TextureFormat)
*/
MAGNUM_GL_EXPORT Containers::Optional<Magnum::CompressedPixelFormat> genericCompressedPixelFormat(TextureFormat format);
/**
@debugoperatorenum{TextureFormat}
@m_since{2019,10}

44
src/Magnum/PixelFormat.h

@ -48,17 +48,20 @@ Can act also as a wrapper for implementation-specific pixel format values using
generic and implementation-specific formats can be done using
@ref isPixelFormatImplementationSpecific().
In case of OpenGL, corresponds to @ref GL::PixelFormat and @ref GL::PixelType
and is convertible to them using @ref GL::pixelFormat() and
@ref GL::pixelType(). See documentation of each value for more information
about the mapping. Note that not every format is available on all targets, use
@ref GL::hasPixelFormat() to check for its presence.
In case of Vulkan, corresponds to @ref Vk::PixelFormat and is convertible
to it using @ref Vk::pixelFormat(Magnum::PixelFormat). See documentation of
each value for more information about the mapping. Note that not every format
may be available, use @ref Vk::hasPixelFormat(Magnum::PixelFormat) to check for
its presence.
In case of OpenGL, corresponds to @ref GL::PixelFormat, @ref GL::PixelType
and uncompressed @ref GL::TextureFormat values, is convertible to them using
@ref GL::pixelFormat(), @ref GL::pixelType() and @ref GL::textureFormat(), and
an inverse mapping can be done via @ref GL::genericPixelFormat(PixelFormat, PixelType)
and @ref GL::genericPixelFormat(TextureFormat). See documentation of each value
for more information about the mapping. Note that not every format is available
on all targets, use @ref GL::hasPixelFormat() to check for its presence.
In case of Vulkan, corresponds to uncompressed @ref Vk::PixelFormat values, is
convertible to it using @ref Vk::pixelFormat(Magnum::PixelFormat), and an
inverse mapping can be done via @ref Vk::genericPixelFormat(). See
documentation of each value for more information about the mapping. Note that
not every format may be available, use
@ref Vk::hasPixelFormat(Magnum::PixelFormat) to check for its presence.
For D3D, corresponds to @m_class{m-doc-external} [DXGI_FORMAT](https://docs.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format)
and import is provided by the @ref Trade::DdsImporter "DdsImporter" plugin; for
@ -982,17 +985,22 @@ Can act also as a wrapper for implementation-specific pixel format values using
Distinction between generic and implementation-specific formats can be done
using @ref isCompressedPixelFormatImplementationSpecific().
In case of OpenGL, corresponds to @ref GL::CompressedPixelFormat and is
convertible to it using @ref GL::compressedPixelFormat(). See documentation of
In case of OpenGL, corresponds to @ref GL::CompressedPixelFormat and compressed
@ref GL::TextureFormat values, is convertible to them using
@ref GL::compressedPixelFormat() and @ref GL::textureFormat(), and an inverse
mapping can be done via @ref GL::genericCompressedPixelFormat(CompressedPixelFormat)
and @ref GL::genericCompressedPixelFormat(TextureFormat). See documentation of
each value for more information about the mapping. Note that not every format
is available on all targets, use @ref GL::hasCompressedPixelFormat() to check
for its presence.
In case of Vulkan, corresponds to @ref Vk::PixelFormat and is convertible to it
using @ref Vk::pixelFormat(Magnum::CompressedPixelFormat). See documentation
of each value for more information about the mapping. Note that not every
format may be available, use @ref Vk::hasPixelFormat(Magnum::CompressedPixelFormat)
to check for its presence.
In case of Vulkan, corresponds to compressed @ref Vk::PixelFormat values, is
convertible to it using @ref Vk::pixelFormat(Magnum::CompressedPixelFormat),
and an inverse mapping can be done via @ref Vk::genericCompressedPixelFormat().
See documentation of each value for more information about the mapping. Note
that not every format may be available, use
@ref Vk::hasPixelFormat(Magnum::CompressedPixelFormat) to check for its
presence.
For D3D, corresponds to @m_class{m-doc-external} [DXGI_FORMAT](https://docs.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format)
and import is provided by the @ref Trade::DdsImporter "DdsImporter" plugin; for

14
src/Magnum/Vk/Implementation/compressedPixelFormatMapping.hpp

@ -23,7 +23,11 @@
DEALINGS IN THE SOFTWARE.
*/
/* See Magnum/Vk/Enums.cpp and Magnum/Vk/Test/EnumsTest.cpp */
/* See Magnum/Vk/Enums.cpp and Magnum/Vk/Test/EnumsTest.cpp. _c() is a mapping,
_s() denotes a skipped value (so the enum numbering is preserved), _d()
denotes a _c() value with duplicated result, i.e. a N:1 mapping from a
generic format. The _c2() is just a shortand for the input and output name
being the same. */
#ifdef _c
#define _c2(input) _c(input, input)
_c2(Bc1RGBUnorm)
@ -128,12 +132,12 @@ _s(Astc6x6x6RGBASrgb) //, ASTC_6x6x6_SRGB_BLOCK)
_s(Astc6x6x6RGBAF) //, ASTC_6x6x6_SFLOAT_BLOCK_EXT)
/* https://github.com/KhronosGroup/Vulkan-Docs/issues/512 */
_c(PvrtcRGB2bppUnorm, PvrtcRGBA2bppUnorm)
_c(PvrtcRGB2bppSrgb, PvrtcRGBA2bppSrgb)
_d(PvrtcRGB2bppUnorm, PvrtcRGBA2bppUnorm)
_d(PvrtcRGB2bppSrgb, PvrtcRGBA2bppSrgb)
_c2(PvrtcRGBA2bppUnorm)
_c2(PvrtcRGBA2bppSrgb)
_c(PvrtcRGB4bppUnorm, PvrtcRGBA4bppUnorm)
_c(PvrtcRGB4bppSrgb, PvrtcRGBA4bppSrgb)
_d(PvrtcRGB4bppUnorm, PvrtcRGBA4bppUnorm)
_d(PvrtcRGB4bppSrgb, PvrtcRGBA4bppSrgb)
_c2(PvrtcRGBA4bppUnorm)
_c2(PvrtcRGBA4bppSrgb)
#undef _c2

49
src/Magnum/Vk/PixelFormat.cpp

@ -26,6 +26,7 @@
#include "PixelFormat.h"
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Utility/Debug.h>
#include "Magnum/PixelFormat.h"
@ -46,9 +47,11 @@ constexpr PixelFormat PixelFormatMapping[] {
constexpr PixelFormat CompressedPixelFormatMapping[] {
/* GCC 4.8 doesn't like just a {} for default enum values */
#define _c(input, format) PixelFormat::Compressed ## format,
#define _d _c
#define _s(input) PixelFormat{},
#include "Magnum/Vk/Implementation/compressedPixelFormatMapping.hpp"
#undef _s
#undef _d
#undef _c
};
@ -245,4 +248,50 @@ PixelFormat pixelFormat(const Magnum::CompressedPixelFormat format) {
return out;
}
Containers::Optional<Magnum::PixelFormat> genericPixelFormat(const PixelFormat format) {
switch(format) {
#define _c(format) \
case PixelFormat::format: \
return Magnum::PixelFormat::format;
#include "Magnum/Vk/Implementation/pixelFormatMapping.hpp"
#undef _c
/* For compressed formats it returns NullOpt too instead of asserting,
as -- compared to the generic-to-Vk translation, which is O(1) --
the inverse mapping is potentially a linear lookup and forcing the
user to check some isPixelFormatCompressed() first (which would do
another linear lookup) makes no sense from a perf PoV. Plus for
unknown formats it's unknown whether it's a compressed format or
not, and the function suddenly starting to assert when a format
becomes known isn't good for backwards compatibility. */
default:
return {};
}
}
Containers::Optional<Magnum::CompressedPixelFormat> genericCompressedPixelFormat(const PixelFormat format) {
switch(format) {
#define _c(input, format) \
case PixelFormat::Compressed ## format: \
return Magnum::CompressedPixelFormat::input;
#define _d(input, format)
#define _s(input)
#include "Magnum/Vk/Implementation/compressedPixelFormatMapping.hpp"
#undef _s
#undef _d
#undef _c
/* For uncompressed formats it returns NullOpt too instead of asserting,
as -- compared to the generic-to-GL translation, which is O(1) -- the
inverse mapping is potentially a linear lookup and forcing the user
to check some isTextureFormatCompressed() first (which would do
another linear lookup) makes no sense from a perf PoV. Plus for
unknown formats it's unknown whether it's a compressed format or not,
and the function suddenly starting to assert when a format becomes
known isn't good for backwards compatibility. */
default:
return {};
}
}
}}

50
src/Magnum/Vk/PixelFormat.h

@ -30,7 +30,7 @@
#include "Magnum/Vk/visibility.h"
/** @file
* @brief Enum @ref Magnum::Vk::PixelFormat, function @ref Magnum::Vk::hasPixelFormat(), @ref Magnum::Vk::pixelFormat()
* @brief Enum @ref Magnum::Vk::PixelFormat, function @ref Magnum::Vk::hasPixelFormat(), @ref Magnum::Vk::pixelFormat(), @ref Magnum::Vk::genericPixelFormat(), @ref Magnum::Vk::genericCompressedPixelFormat()
* @m_since_latest
*/
@ -1413,6 +1413,7 @@ be valid.
extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format.
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref pixelFormat(Magnum::PixelFormat)
*/
MAGNUM_VK_EXPORT bool hasPixelFormat(Magnum::PixelFormat format);
@ -1430,6 +1431,7 @@ expected to be valid.
extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format.
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref pixelFormat(Magnum::CompressedPixelFormat)
*/
MAGNUM_VK_EXPORT bool hasPixelFormat(Magnum::CompressedPixelFormat format);
@ -1447,6 +1449,9 @@ cast to @ref PixelFormat.
Not all generic pixel formats have a Vulkan equivalent and this function
expects that given format is available. Use
@ref hasPixelFormat(Magnum::PixelFormat) to query availability of given format.
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref genericPixelFormat(PixelFormat)
*/
MAGNUM_VK_EXPORT PixelFormat pixelFormat(Magnum::PixelFormat format);
@ -1462,11 +1467,50 @@ assumes @p format stores a Vulkan-specific format and returns
Not all generic pixel formats have a Vulkan equivalent and this function
expects that given format is available. Use
@ref hasPixelFormat(Magnum::CompressedPixelFormat) to query availability of given
format.
@ref hasPixelFormat(Magnum::CompressedPixelFormat) to query availability of
given format.
The mapping operation is done with an @f$ \mathcal{O}(1) @f$ complexity.
@see @ref genericCompressedPixelFormat(PixelFormat)
*/
MAGNUM_VK_EXPORT PixelFormat pixelFormat(Magnum::CompressedPixelFormat format);
/**
@brief Convert Vulkan pixel format to a generic pixel format
@m_since_latest
Returns @ref Containers::NullOpt if given format is compressed or if it doesn't
match any generic pixel format. Otherwise the returned value will result in the
same @p format when passed back to @ref pixelFormat(Magnum::PixelFormat).
Unlike mapping *from* a generic pixel format, the inverse operation is done
with an @f$ \mathcal{O}(n) @f$ complexity.
@see @ref genericCompressedPixelFormat(PixelFormat)
*/
MAGNUM_VK_EXPORT Containers::Optional<Magnum::PixelFormat> genericPixelFormat(PixelFormat format);
/**
@brief Convert Vulkan compressed pixel format to a generic compressed pixel format
@m_since_latest
Returns @ref Containers::NullOpt if given format is not compressed or if it
doesn't match any generic compressed pixel format. Otherwise the returned value
will result in the same @p format when passed back to
@ref pixelFormat(Magnum::CompressedPixelFormat).
An exception is PVRTC formats --- the RGB and RGBA variants map to the same
Vulkan format, e.g. @ref Magnum::CompressedPixelFormat::PvrtcRGB2bppSrgb and
@relativeref{Magnum::CompressedPixelFormat,PvrtcRGBA2bppSrgb} both result in
@ref Vk::PixelFormat::CompressedPvrtcRGBA2bppSrgb. To avoid potential
information loss, this function always maps the Vulkan PVRTC formats back to
the RGBA variants.
Unlike mapping *from* a generic pixel format, the inverse operation is done
with an @f$ \mathcal{O}(n) @f$ complexity.
@see @ref genericPixelFormat(PixelFormat)
*/
MAGNUM_VK_EXPORT Containers::Optional<Magnum::CompressedPixelFormat> genericCompressedPixelFormat(PixelFormat format);
}}
#endif

43
src/Magnum/Vk/Test/PixelFormatTest.cpp

@ -24,6 +24,7 @@
*/
#include <sstream>
#include <Corrade/Containers/Optional.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
@ -39,11 +40,13 @@ struct PixelFormatTest: TestSuite::Tester {
void mapImplementationSpecific();
void mapUnsupported();
void mapInvalid();
void mapGenericUnsupported();
void mapCompressed();
void mapCompressedImplementationSpecific();
void mapCompressedUnsupported();
void mapCompressedInvalid();
void mapGenericCompressedUnsupported();
void debug();
};
@ -53,11 +56,13 @@ PixelFormatTest::PixelFormatTest() {
&PixelFormatTest::mapImplementationSpecific,
&PixelFormatTest::mapUnsupported,
&PixelFormatTest::mapInvalid,
&PixelFormatTest::mapGenericUnsupported,
&PixelFormatTest::mapCompressed,
&PixelFormatTest::mapCompressedImplementationSpecific,
&PixelFormatTest::mapCompressedUnsupported,
&PixelFormatTest::mapCompressedInvalid,
&PixelFormatTest::mapGenericCompressedUnsupported,
&PixelFormatTest::debug});
}
@ -90,6 +95,7 @@ void PixelFormatTest::map() {
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \
CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::format)); \
CORRADE_COMPARE(genericPixelFormat(PixelFormat::format), Magnum::PixelFormat::format); \
CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::format), PixelFormat::format); \
{ \
std::ostringstream out; \
@ -166,11 +172,23 @@ void PixelFormatTest::mapInvalid() {
"Vk::pixelFormat(): invalid format PixelFormat(0x123)\n");
}
void PixelFormatTest::mapGenericUnsupported() {
/* This one doesn't have any generic equivalent yet, and isn't in the
enum either */
CORRADE_COMPARE(genericPixelFormat(PixelFormat(VK_FORMAT_R5G6B5_UNORM_PACK16)), Containers::NullOpt);
/* For compressed texture formats it returns NullOpt too, instead of
asserting. See comment in the source for reasons. */
CORRADE_COMPARE(genericPixelFormat(PixelFormat::CompressedAstc4x4RGBAF), Containers::NullOpt);
}
void PixelFormatTest::mapCompressed() {
/* Touchstone verification. Using Vulkan enums directly to sidestep
potential problems in enum mapping as well. */
CORRADE_VERIFY(hasPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm));
CORRADE_COMPARE(pixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm), PixelFormat(VK_FORMAT_BC1_RGBA_UNORM_BLOCK));
/* PVRTC RGB and RGBA formats have N:1 mapping, conversion back makes them
always RGBA */
CORRADE_COMPARE(genericCompressedPixelFormat(pixelFormat(Magnum::CompressedPixelFormat::PvrtcRGB4bppSrgb)), Magnum::CompressedPixelFormat::PvrtcRGBA4bppSrgb);
/* This goes through the first 16 bits, which should be enough. Going
through 32 bits takes 8 seconds, too much. */
@ -190,6 +208,23 @@ void PixelFormatTest::mapCompressed() {
#endif
switch(format) {
#define _c(format, expectedFormat) \
case Magnum::CompressedPixelFormat::format: \
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \
CORRADE_VERIFY(hasPixelFormat(Magnum::CompressedPixelFormat::format)); \
CORRADE_COMPARE(genericCompressedPixelFormat(PixelFormat::Compressed ## expectedFormat), Magnum::CompressedPixelFormat::format); \
CORRADE_COMPARE(pixelFormat(Magnum::CompressedPixelFormat::format), PixelFormat::Compressed ## expectedFormat); \
{ \
std::ostringstream out; \
Debug{&out} << pixelFormat(Magnum::CompressedPixelFormat::format); \
CORRADE_COMPARE(out.str(), "Vk::PixelFormat::Compressed" #expectedFormat "\n"); \
} \
++nextHandled; \
continue;
/* For duplicate mappings compared to _c() it only checks the
forward mapping. The duplicate mapping is tested in the
touchstone verification above */
#define _d(format, expectedFormat) \
case Magnum::CompressedPixelFormat::format: \
CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \
@ -267,6 +302,14 @@ void PixelFormatTest::mapCompressedInvalid() {
"Vk::pixelFormat(): invalid format CompressedPixelFormat(0x123)\n");
}
void PixelFormatTest::mapGenericCompressedUnsupported() {
/* PVRTC2 doesn't have any generic equivalent yet */
CORRADE_COMPARE(genericPixelFormat(PixelFormat::CompressedPvrtc2RGBA2bppUnorm), Containers::NullOpt);
/* For uncompressed texture formats it returns NullOpt too, instead of
asserting. See comment in the source for reasons. */
CORRADE_COMPARE(genericCompressedPixelFormat(PixelFormat::RGB8Unorm), Containers::NullOpt);
}
void PixelFormatTest::debug() {
std::ostringstream out;
Debug{&out} << PixelFormat::RGB16UI << PixelFormat(-10007655);

Loading…
Cancel
Save