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. in @ref GL::Extensions for compatibility with older browsers.
- Re-enabled @fn_gl{DrawRangeElements} for WebGL 2, this time hopefully for - 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)) 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 @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 */ /* Get the implementation-specific color read format for given framebuffer */
const GL::PixelFormat format = framebuffer.implementationColorReadFormat(); const GL::PixelFormat format = framebuffer.implementationColorReadFormat();
const GL::PixelType type = framebuffer.implementationColorReadType(); const GL::PixelType type = framebuffer.implementationColorReadType();
auto genericFormat = [](GL::PixelFormat format, GL::PixelType type) -> Containers::Optional<PixelFormat> { const Containers::Optional<PixelFormat> genericFormat = GL::genericPixelFormat(format, type);
#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);
if(!genericFormat) { 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; return false;
} }

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

@ -244,9 +244,9 @@ void ScreenshotGLTest::unknownFormat() {
CORRADE_VERIFY(!succeeded); CORRADE_VERIFY(!succeeded);
if(framebuffer.implementationColorReadFormat() == GL::PixelFormat::RGBA) 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 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() { void ScreenshotGLTest::pluginLoadFailed() {

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

@ -23,7 +23,11 @@
DEALINGS IN THE SOFTWARE. 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 #ifdef _c
_c(Bc1RGBUnorm, RGBS3tcDxt1) _c(Bc1RGBUnorm, RGBS3tcDxt1)
_c(Bc1RGBSrgb, SRGBS3tcDxt1) _c(Bc1RGBSrgb, SRGBS3tcDxt1)
@ -62,77 +66,77 @@ _c(Etc2RGB8A1Unorm, RGB8PunchthroughAlpha1Etc2)
_c(Etc2RGB8A1Srgb, SRGB8PunchthroughAlpha1Etc2) _c(Etc2RGB8A1Srgb, SRGB8PunchthroughAlpha1Etc2)
_c(Etc2RGBA8Unorm, RGBA8Etc2Eac) _c(Etc2RGBA8Unorm, RGBA8Etc2Eac)
_c(Etc2RGBA8Srgb, SRGB8Alpha8Etc2Eac) _c(Etc2RGBA8Srgb, SRGB8Alpha8Etc2Eac)
_c(Astc4x4RGBAUnorm, RGBAAstc4x4) _d(Astc4x4RGBAUnorm, RGBAAstc4x4)
_c(Astc4x4RGBASrgb, SRGB8Alpha8Astc4x4) _c(Astc4x4RGBASrgb, SRGB8Alpha8Astc4x4)
_c(Astc4x4RGBAF, RGBAAstc4x4) _c(Astc4x4RGBAF, RGBAAstc4x4)
_c(Astc5x4RGBAUnorm, RGBAAstc5x4) _d(Astc5x4RGBAUnorm, RGBAAstc5x4)
_c(Astc5x4RGBASrgb, SRGB8Alpha8Astc5x4) _c(Astc5x4RGBASrgb, SRGB8Alpha8Astc5x4)
_c(Astc5x4RGBAF, RGBAAstc5x4) _c(Astc5x4RGBAF, RGBAAstc5x4)
_c(Astc5x5RGBAUnorm, RGBAAstc5x5) _d(Astc5x5RGBAUnorm, RGBAAstc5x5)
_c(Astc5x5RGBASrgb, SRGB8Alpha8Astc5x5) _c(Astc5x5RGBASrgb, SRGB8Alpha8Astc5x5)
_c(Astc5x5RGBAF, RGBAAstc5x5) _c(Astc5x5RGBAF, RGBAAstc5x5)
_c(Astc6x5RGBAUnorm, RGBAAstc6x5) _d(Astc6x5RGBAUnorm, RGBAAstc6x5)
_c(Astc6x5RGBASrgb, SRGB8Alpha8Astc6x5) _c(Astc6x5RGBASrgb, SRGB8Alpha8Astc6x5)
_c(Astc6x5RGBAF, RGBAAstc6x5) _c(Astc6x5RGBAF, RGBAAstc6x5)
_c(Astc6x6RGBAUnorm, RGBAAstc6x6) _d(Astc6x6RGBAUnorm, RGBAAstc6x6)
_c(Astc6x6RGBASrgb, SRGB8Alpha8Astc6x6) _c(Astc6x6RGBASrgb, SRGB8Alpha8Astc6x6)
_c(Astc6x6RGBAF, RGBAAstc6x6) _c(Astc6x6RGBAF, RGBAAstc6x6)
_c(Astc8x5RGBAUnorm, RGBAAstc8x5) _d(Astc8x5RGBAUnorm, RGBAAstc8x5)
_c(Astc8x5RGBASrgb, SRGB8Alpha8Astc8x5) _c(Astc8x5RGBASrgb, SRGB8Alpha8Astc8x5)
_c(Astc8x5RGBAF, RGBAAstc8x5) _c(Astc8x5RGBAF, RGBAAstc8x5)
_c(Astc8x6RGBAUnorm, RGBAAstc8x6) _d(Astc8x6RGBAUnorm, RGBAAstc8x6)
_c(Astc8x6RGBASrgb, SRGB8Alpha8Astc8x6) _c(Astc8x6RGBASrgb, SRGB8Alpha8Astc8x6)
_c(Astc8x6RGBAF, RGBAAstc8x6) _c(Astc8x6RGBAF, RGBAAstc8x6)
_c(Astc8x8RGBAUnorm, RGBAAstc8x8) _d(Astc8x8RGBAUnorm, RGBAAstc8x8)
_c(Astc8x8RGBASrgb, SRGB8Alpha8Astc8x8) _c(Astc8x8RGBASrgb, SRGB8Alpha8Astc8x8)
_c(Astc8x8RGBAF, RGBAAstc8x8) _c(Astc8x8RGBAF, RGBAAstc8x8)
_c(Astc10x5RGBAUnorm, RGBAAstc10x5) _d(Astc10x5RGBAUnorm, RGBAAstc10x5)
_c(Astc10x5RGBASrgb, SRGB8Alpha8Astc10x5) _c(Astc10x5RGBASrgb, SRGB8Alpha8Astc10x5)
_c(Astc10x5RGBAF, RGBAAstc10x5) _c(Astc10x5RGBAF, RGBAAstc10x5)
_c(Astc10x6RGBAUnorm, RGBAAstc10x6) _d(Astc10x6RGBAUnorm, RGBAAstc10x6)
_c(Astc10x6RGBASrgb, SRGB8Alpha8Astc10x6) _c(Astc10x6RGBASrgb, SRGB8Alpha8Astc10x6)
_c(Astc10x6RGBAF, RGBAAstc10x6) _c(Astc10x6RGBAF, RGBAAstc10x6)
_c(Astc10x8RGBAUnorm, RGBAAstc10x8) _d(Astc10x8RGBAUnorm, RGBAAstc10x8)
_c(Astc10x8RGBASrgb, SRGB8Alpha8Astc10x8) _c(Astc10x8RGBASrgb, SRGB8Alpha8Astc10x8)
_c(Astc10x8RGBAF, RGBAAstc10x8) _c(Astc10x8RGBAF, RGBAAstc10x8)
_c(Astc10x10RGBAUnorm, RGBAAstc10x10) _d(Astc10x10RGBAUnorm, RGBAAstc10x10)
_c(Astc10x10RGBASrgb, SRGB8Alpha8Astc10x10) _c(Astc10x10RGBASrgb, SRGB8Alpha8Astc10x10)
_c(Astc10x10RGBAF, RGBAAstc10x10) _c(Astc10x10RGBAF, RGBAAstc10x10)
_c(Astc12x10RGBAUnorm, RGBAAstc12x10) _d(Astc12x10RGBAUnorm, RGBAAstc12x10)
_c(Astc12x10RGBASrgb, SRGB8Alpha8Astc12x10) _c(Astc12x10RGBASrgb, SRGB8Alpha8Astc12x10)
_c(Astc12x10RGBAF, RGBAAstc12x10) _c(Astc12x10RGBAF, RGBAAstc12x10)
_c(Astc12x12RGBAUnorm, RGBAAstc12x12) _d(Astc12x12RGBAUnorm, RGBAAstc12x12)
_c(Astc12x12RGBASrgb, SRGB8Alpha8Astc12x12) _c(Astc12x12RGBASrgb, SRGB8Alpha8Astc12x12)
_c(Astc12x12RGBAF, RGBAAstc12x12) _c(Astc12x12RGBAF, RGBAAstc12x12)
#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
_c(Astc3x3x3RGBAUnorm, RGBAAstc3x3x3) _d(Astc3x3x3RGBAUnorm, RGBAAstc3x3x3)
_c(Astc3x3x3RGBASrgb, SRGB8Alpha8Astc3x3x3) _c(Astc3x3x3RGBASrgb, SRGB8Alpha8Astc3x3x3)
_c(Astc3x3x3RGBAF, RGBAAstc3x3x3) _c(Astc3x3x3RGBAF, RGBAAstc3x3x3)
_c(Astc4x3x3RGBAUnorm, RGBAAstc4x3x3) _d(Astc4x3x3RGBAUnorm, RGBAAstc4x3x3)
_c(Astc4x3x3RGBASrgb, SRGB8Alpha8Astc4x3x3) _c(Astc4x3x3RGBASrgb, SRGB8Alpha8Astc4x3x3)
_c(Astc4x3x3RGBAF, RGBAAstc4x3x3) _c(Astc4x3x3RGBAF, RGBAAstc4x3x3)
_c(Astc4x4x3RGBAUnorm, RGBAAstc4x4x3) _d(Astc4x4x3RGBAUnorm, RGBAAstc4x4x3)
_c(Astc4x4x3RGBASrgb, SRGB8Alpha8Astc4x4x3) _c(Astc4x4x3RGBASrgb, SRGB8Alpha8Astc4x4x3)
_c(Astc4x4x3RGBAF, RGBAAstc4x4x3) _c(Astc4x4x3RGBAF, RGBAAstc4x4x3)
_c(Astc4x4x4RGBAUnorm, RGBAAstc4x4x4) _d(Astc4x4x4RGBAUnorm, RGBAAstc4x4x4)
_c(Astc4x4x4RGBASrgb, SRGB8Alpha8Astc4x4x4) _c(Astc4x4x4RGBASrgb, SRGB8Alpha8Astc4x4x4)
_c(Astc4x4x4RGBAF, RGBAAstc4x4x4) _c(Astc4x4x4RGBAF, RGBAAstc4x4x4)
_c(Astc5x4x4RGBAUnorm, RGBAAstc5x4x4) _d(Astc5x4x4RGBAUnorm, RGBAAstc5x4x4)
_c(Astc5x4x4RGBASrgb, SRGB8Alpha8Astc5x4x4) _c(Astc5x4x4RGBASrgb, SRGB8Alpha8Astc5x4x4)
_c(Astc5x4x4RGBAF, RGBAAstc5x4x4) _c(Astc5x4x4RGBAF, RGBAAstc5x4x4)
_c(Astc5x5x4RGBAUnorm, RGBAAstc5x5x4) _d(Astc5x5x4RGBAUnorm, RGBAAstc5x5x4)
_c(Astc5x5x4RGBASrgb, SRGB8Alpha8Astc5x5x4) _c(Astc5x5x4RGBASrgb, SRGB8Alpha8Astc5x5x4)
_c(Astc5x5x4RGBAF, RGBAAstc5x5x4) _c(Astc5x5x4RGBAF, RGBAAstc5x5x4)
_c(Astc5x5x5RGBAUnorm, RGBAAstc5x5x5) _d(Astc5x5x5RGBAUnorm, RGBAAstc5x5x5)
_c(Astc5x5x5RGBASrgb, SRGB8Alpha8Astc5x5x5) _c(Astc5x5x5RGBASrgb, SRGB8Alpha8Astc5x5x5)
_c(Astc5x5x5RGBAF, RGBAAstc5x5x5) _c(Astc5x5x5RGBAF, RGBAAstc5x5x5)
_c(Astc6x5x5RGBAUnorm, RGBAAstc6x5x5) _d(Astc6x5x5RGBAUnorm, RGBAAstc6x5x5)
_c(Astc6x5x5RGBASrgb, SRGB8Alpha8Astc6x5x5) _c(Astc6x5x5RGBASrgb, SRGB8Alpha8Astc6x5x5)
_c(Astc6x5x5RGBAF, RGBAAstc6x5x5) _c(Astc6x5x5RGBAF, RGBAAstc6x5x5)
_c(Astc6x6x5RGBAUnorm, RGBAAstc6x6x5) _d(Astc6x6x5RGBAUnorm, RGBAAstc6x6x5)
_c(Astc6x6x5RGBASrgb, SRGB8Alpha8Astc6x6x5) _c(Astc6x6x5RGBASrgb, SRGB8Alpha8Astc6x6x5)
_c(Astc6x6x5RGBAF, RGBAAstc6x6x5) _c(Astc6x6x5RGBAF, RGBAAstc6x6x5)
_c(Astc6x6x6RGBAUnorm, RGBAAstc6x6x6) _d(Astc6x6x6RGBAUnorm, RGBAAstc6x6x6)
_c(Astc6x6x6RGBASrgb, SRGB8Alpha8Astc6x6x6) _c(Astc6x6x6RGBASrgb, SRGB8Alpha8Astc6x6x6)
_c(Astc6x6x6RGBAF, RGBAAstc6x6x6) _c(Astc6x6x6RGBAF, RGBAAstc6x6x6)
#else #else

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

@ -26,7 +26,10 @@
/* See Magnum/GL/PixelFormat.cpp, Magnum/GL/Test/PixelFormatTest.cpp and /* See Magnum/GL/PixelFormat.cpp, Magnum/GL/Test/PixelFormatTest.cpp and
DebugTools/Screenshot.cpp. _c() is a mapping, _s() denotes a skipped value DebugTools/Screenshot.cpp. _c() is a mapping, _s() denotes a skipped value
(so the enum numbering is preserved), _n() denotes a value where pixel (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 #ifdef _c
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(R8Unorm, Red, UnsignedByte, R8) _c(R8Unorm, Red, UnsignedByte, R8)
@ -58,23 +61,26 @@ _s(RGBA8Snorm)
texture format tho. */ texture format tho. */
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
_c(R8Srgb, Red, UnsignedByte, SR8) _d(R8Srgb, Red, UnsignedByte, SR8)
_c(RG8Srgb, RG, UnsignedByte, SRG8) _d(RG8Srgb, RG, UnsignedByte, SRG8)
#else #else
_n(R8Srgb, Red, UnsignedByte) _dn(R8Srgb, Red, UnsignedByte)
_n(RG8Srgb, RG, UnsignedByte) _dn(RG8Srgb, RG, UnsignedByte)
#endif #endif
#else #else
/* SLUMINANCE / SLUMINANCE_ALPHA texture formats not exposed */ /* SLUMINANCE / SLUMINANCE_ALPHA texture formats not exposed */
_n(R8Srgb, Luminance, UnsignedByte) _dn(R8Srgb, Luminance, UnsignedByte)
_n(RG8Srgb, LuminanceAlpha, UnsignedByte) _dn(RG8Srgb, LuminanceAlpha, UnsignedByte)
#endif #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 #ifndef MAGNUM_TARGET_GLES2
_c(RGB8Srgb, RGB, UnsignedByte, SRGB8) _d(RGB8Srgb, RGB, UnsignedByte, SRGB8)
_c(RGBA8Srgb, RGBA, UnsignedByte, SRGB8Alpha8) _d(RGBA8Srgb, RGBA, UnsignedByte, SRGB8Alpha8)
#else #else
_n(RGB8Srgb, RGB, UnsignedByte) _dn(RGB8Srgb, RGB, UnsignedByte)
_n(RGBA8Srgb, RGBA, UnsignedByte) _dn(RGBA8Srgb, RGBA, UnsignedByte)
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(R8UI, RedInteger, UnsignedByte, R8UI) _c(R8UI, RedInteger, UnsignedByte, R8UI)

106
src/Magnum/GL/PixelFormat.cpp

@ -25,8 +25,9 @@
#include "PixelFormat.h" #include "PixelFormat.h"
#include <Corrade/Utility/Assert.h>
#include <Corrade/Containers/ArrayView.h> #include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h> #include <Corrade/Utility/Debug.h>
#include "Magnum/PixelFormat.h" #include "Magnum/PixelFormat.h"
@ -41,24 +42,32 @@ constexpr struct {
PixelFormat format; PixelFormat format;
PixelType type; PixelType type;
} FormatMapping[] { } 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 _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{}}, #define _s(input) {PixelFormat{}, PixelType{}},
#include "Magnum/GL/Implementation/pixelFormatMapping.hpp" #include "Magnum/GL/Implementation/pixelFormatMapping.hpp"
#undef _s #undef _s
#undef _n #undef _d
#undef _c #undef _c
#undef _nd
#undef _n
}; };
constexpr TextureFormat TextureFormatMapping[] { constexpr TextureFormat TextureFormatMapping[] {
#define _c(input, format, type, textureFormat) TextureFormat::textureFormat, #define _c(input, format, type, textureFormat) TextureFormat::textureFormat,
#define _d _c
/* GCC 4.8 doesn't like just a {} for default enum values */ /* GCC 4.8 doesn't like just a {} for default enum values */
#define _n(input, format, type) TextureFormat{},
#define _s(input) TextureFormat{}, #define _s(input) TextureFormat{},
#define _n(input, format, type) _s(input)
#define _dn _n
#include "Magnum/GL/Implementation/pixelFormatMapping.hpp" #include "Magnum/GL/Implementation/pixelFormatMapping.hpp"
#undef _s #undef _dn
#undef _n #undef _n
#undef _s
#undef _d
#undef _c #undef _c
}; };
#endif #endif
@ -261,6 +270,57 @@ UnsignedInt pixelFormatSize(const PixelFormat format, const PixelType type) {
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ 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 #ifndef DOXYGEN_GENERATING_OUTPUT
Debug& operator<<(Debug& debug, const PixelFormat value) { Debug& operator<<(Debug& debug, const PixelFormat value) {
debug << "GL::PixelFormat" << Debug::nospace; debug << "GL::PixelFormat" << Debug::nospace;
@ -402,9 +462,11 @@ namespace {
having just a single table for both */ having just a single table for both */
constexpr CompressedPixelFormat CompressedFormatMapping[] { constexpr CompressedPixelFormat CompressedFormatMapping[] {
#define _c(input, format) CompressedPixelFormat::format, #define _c(input, format) CompressedPixelFormat::format,
#define _d _c
#define _s(input) CompressedPixelFormat{}, #define _s(input) CompressedPixelFormat{},
#include "Magnum/GL/Implementation/compressedPixelFormatMapping.hpp" #include "Magnum/GL/Implementation/compressedPixelFormatMapping.hpp"
#undef _s #undef _s
#undef _d
#undef _c #undef _c
}; };
#endif #endif
@ -455,6 +517,38 @@ TextureFormat textureFormat(const Magnum::CompressedPixelFormat format) {
return out; 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& operator<<(Debug& debug, const CompressedPixelFormat value) {
debug << "GL::CompressedPixelFormat" << Debug::nospace; debug << "GL::CompressedPixelFormat" << Debug::nospace;

60
src/Magnum/GL/PixelFormat.h

@ -26,7 +26,7 @@
*/ */
/** @file /** @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> #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 extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format. 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() @see @ref pixelFormat(), @ref pixelType(), @ref hasCompressedPixelFormat()
*/ */
MAGNUM_GL_EXPORT bool hasPixelFormat(Magnum::PixelFormat format); 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 @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. 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); 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 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() expects that given format is available on the target. Use @ref hasPixelFormat()
to query availability of given format. 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); MAGNUM_GL_EXPORT PixelType pixelType(Magnum::PixelFormat format, UnsignedInt extra = 0);
@ -708,6 +714,27 @@ CORRADE_DEPRECATED("use pixelFormatSize() instead") inline UnsignedInt pixelSize
} }
#endif #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} */ /** @debugoperatorenum{PixelFormat} */
MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, PixelFormat value); 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 extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format. 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(), @see @ref compressedPixelFormat(), @ref hasPixelFormat(),
@ref hasTextureFormat() @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 Not all generic pixel formats may be available on all targets and this function
expects that given format is available on the target. Use expects that given format is available on the target. Use
@ref hasCompressedPixelFormat() to query availability of given format. @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); 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} */ /** @debugoperatorenum{CompressedPixelFormat} */
MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, CompressedPixelFormat value); MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, CompressedPixelFormat value);

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

@ -24,6 +24,7 @@
*/ */
#include <sstream> #include <sstream>
#include <Corrade/Containers/Optional.h>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
@ -50,6 +51,7 @@ struct PixelFormatTest: TestSuite::Tester {
void mapTextureFormatImplementationSpecific(); void mapTextureFormatImplementationSpecific();
void mapTextureFormatUnsupported(); void mapTextureFormatUnsupported();
void mapTextureFormatInvalid(); void mapTextureFormatInvalid();
void mapGenericFormatUnsupported();
void size(); void size();
void sizeInvalid(); void sizeInvalid();
@ -61,6 +63,7 @@ struct PixelFormatTest: TestSuite::Tester {
void mapCompressedTextureFormatImplementationSpecific(); void mapCompressedTextureFormatImplementationSpecific();
void mapCompressedTextureFormatUnsupported(); void mapCompressedTextureFormatUnsupported();
void mapCompressedTextureFormatInvalid(); void mapCompressedTextureFormatInvalid();
void mapGenericCompressedFormatUnsupported();
void debugPixelFormat(); void debugPixelFormat();
void debugPixelType(); void debugPixelType();
@ -80,6 +83,7 @@ PixelFormatTest::PixelFormatTest() {
&PixelFormatTest::mapTextureFormatImplementationSpecific, &PixelFormatTest::mapTextureFormatImplementationSpecific,
&PixelFormatTest::mapTextureFormatUnsupported, &PixelFormatTest::mapTextureFormatUnsupported,
&PixelFormatTest::mapTextureFormatInvalid, &PixelFormatTest::mapTextureFormatInvalid,
&PixelFormatTest::mapGenericFormatUnsupported,
&PixelFormatTest::size, &PixelFormatTest::size,
&PixelFormatTest::sizeInvalid, &PixelFormatTest::sizeInvalid,
@ -91,6 +95,7 @@ PixelFormatTest::PixelFormatTest() {
&PixelFormatTest::mapCompressedTextureFormatImplementationSpecific, &PixelFormatTest::mapCompressedTextureFormatImplementationSpecific,
&PixelFormatTest::mapCompressedTextureFormatUnsupported, &PixelFormatTest::mapCompressedTextureFormatUnsupported,
&PixelFormatTest::mapCompressedTextureFormatInvalid, &PixelFormatTest::mapCompressedTextureFormatInvalid,
&PixelFormatTest::mapGenericCompressedFormatUnsupported,
&PixelFormatTest::debugPixelFormat, &PixelFormatTest::debugPixelFormat,
&PixelFormatTest::debugPixelType, &PixelFormatTest::debugPixelType,
@ -103,12 +108,18 @@ void PixelFormatTest::mapFormatTypeTextureFormat() {
CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::RGBA8Unorm)); CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::RGBA8Unorm));
CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::RGBA8Unorm), PixelFormat::RGBA); CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::RGBA8Unorm), PixelFormat::RGBA);
CORRADE_COMPARE(pixelType(Magnum::PixelFormat::RGBA8Unorm), PixelType::UnsignedByte); CORRADE_COMPARE(pixelType(Magnum::PixelFormat::RGBA8Unorm), PixelType::UnsignedByte);
CORRADE_COMPARE(genericPixelFormat(PixelFormat::RGB, PixelType::UnsignedByte), Magnum::PixelFormat::RGB8Unorm);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
CORRADE_VERIFY(hasTextureFormat(Magnum::PixelFormat::RGBA8Unorm)); CORRADE_VERIFY(hasTextureFormat(Magnum::PixelFormat::RGBA8Unorm));
CORRADE_COMPARE(textureFormat(Magnum::PixelFormat::RGBA8Unorm), TextureFormat::RGBA8); CORRADE_COMPARE(textureFormat(Magnum::PixelFormat::RGBA8Unorm), TextureFormat::RGBA8);
CORRADE_COMPARE(genericPixelFormat(TextureFormat::RGB8), Magnum::PixelFormat::RGB8Unorm);
#else #else
CORRADE_VERIFY(!hasTextureFormat(Magnum::PixelFormat::RGBA8Unorm)); CORRADE_VERIFY(!hasTextureFormat(Magnum::PixelFormat::RGBA8Unorm));
CORRADE_COMPARE(genericPixelFormat(TextureFormat::RGB), Containers::NullOpt);
#endif #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 /* This goes through the first 16 bits, which should be enough. Going
through 32 bits takes 8 seconds, too much. */ through 32 bits takes 8 seconds, too much. */
@ -134,11 +145,51 @@ void PixelFormatTest::mapFormatTypeTextureFormat() {
CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::format)); \ CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::format)); \
CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::format), Magnum::GL::PixelFormat::expectedFormat); \ CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::format), Magnum::GL::PixelFormat::expectedFormat); \
CORRADE_COMPARE(pixelType(Magnum::PixelFormat::format), Magnum::GL::PixelType::expectedType); \ 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_VERIFY(hasTextureFormat(Magnum::PixelFormat::format)); \
CORRADE_COMPARE(textureFormat(Magnum::PixelFormat::format), Magnum::GL::TextureFormat::expectedTextureFormat); \ 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; \ ++nextHandled; \
continue; continue;
#define _n(format, expectedFormat, expectedType) \ #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: { \ case Magnum::PixelFormat::format: { \
CORRADE_COMPARE(nextHandled, i); \ CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \ CORRADE_COMPARE(firstUnhandled, 0xffff); \
@ -175,6 +226,7 @@ void PixelFormatTest::mapFormatTypeTextureFormat() {
#include "Magnum/GL/Implementation/pixelFormatMapping.hpp" #include "Magnum/GL/Implementation/pixelFormatMapping.hpp"
#undef _s #undef _s
#undef _n #undef _n
#undef _d
#undef _c #undef _c
} }
#ifdef CORRADE_TARGET_GCC #ifdef CORRADE_TARGET_GCC
@ -319,6 +371,18 @@ void PixelFormatTest::mapTextureFormatInvalid() {
"GL::textureFormat(): invalid format PixelFormat(0x123)\n"); "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() { void PixelFormatTest::size() {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
CORRADE_COMPARE(pixelFormatSize(PixelFormat::RGB, PixelType::UnsignedByte332), 1); CORRADE_COMPARE(pixelFormatSize(PixelFormat::RGB, PixelType::UnsignedByte332), 1);
@ -350,6 +414,9 @@ void PixelFormatTest::mapCompressedFormatTextureFormat() {
CORRADE_COMPARE(compressedPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(compressedPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm), CompressedPixelFormat::RGBAS3tcDxt1);
CORRADE_VERIFY(hasTextureFormat(Magnum::CompressedPixelFormat::Astc8x8RGBASrgb)); CORRADE_VERIFY(hasTextureFormat(Magnum::CompressedPixelFormat::Astc8x8RGBASrgb));
CORRADE_COMPARE(textureFormat(Magnum::CompressedPixelFormat::Astc8x8RGBASrgb), TextureFormat::CompressedSRGB8Alpha8Astc8x8); 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 /* This goes through the first 16 bits, which should be enough. Going
through 32 bits takes 8 seconds, too much. */ through 32 bits takes 8 seconds, too much. */
@ -369,6 +436,21 @@ void PixelFormatTest::mapCompressedFormatTextureFormat() {
#endif #endif
switch(format) { switch(format) {
#define _c(format, expectedFormat) \ #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: \ case Magnum::CompressedPixelFormat::format: \
CORRADE_COMPARE(nextHandled, i); \ CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \ CORRADE_COMPARE(firstUnhandled, 0xffff); \
@ -396,6 +478,7 @@ void PixelFormatTest::mapCompressedFormatTextureFormat() {
} }
#include "Magnum/GL/Implementation/compressedPixelFormatMapping.hpp" #include "Magnum/GL/Implementation/compressedPixelFormatMapping.hpp"
#undef _s #undef _s
#undef _d
#undef _c #undef _c
} }
#ifdef CORRADE_TARGET_GCC #ifdef CORRADE_TARGET_GCC
@ -501,6 +584,17 @@ void PixelFormatTest::mapCompressedTextureFormatInvalid() {
"GL::textureFormat(): invalid format CompressedPixelFormat(0x123)\n"); "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() { void PixelFormatTest::debugPixelFormat() {
std::ostringstream out; std::ostringstream out;

8
src/Magnum/GL/TextureFormat.cpp

@ -34,9 +34,11 @@
namespace Magnum { namespace GL { namespace Magnum { namespace GL {
/* the textureFormat() and hasTextureFormat() utilities share mapping tables /* compressed textureFormat(), hasTextureFormat() and
with pixelFormat() / hasPixelFormat() so are defined in PixelFormat.cpp genericCompressedPixelFormat(TextureFormat) utilities share mapping tables
instead (and tested there too) */ with compressedPixelFormat(), hasCompressedPixelFormat() and
genericCompressedPixelFormat(CompressedPixelFormat) so are defined in
PixelFormat.cpp instead (and tested there too) */
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
Debug& operator<<(Debug& debug, const TextureFormat value) { 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 extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format. 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(), @see @ref textureFormat(), @ref hasPixelFormat(),
@ref hasCompressedPixelFormat() @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} @ref Texture::setStorage() is used and whether @gl_extension{EXT,texture_storage}
and other format-specific extensions are supported. 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); 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 extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format. 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(), @see @ref textureFormat(), @ref hasCompressedPixelFormat(),
@ref hasPixelFormat() @ref hasPixelFormat()
*/ */
@ -2688,12 +2692,51 @@ an implementation-specific pixel format to an OpenGL texture format can't be
performed. performed.
Not all generic pixel formats may be available on all targets and this function 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() expects that given format is available on the target. Use
to query availability of given format. @ref hasTextureFormat() to query availability of given format.
@see @ref compressedPixelFormat(), @ref pixelFormat()
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); 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} @debugoperatorenum{TextureFormat}
@m_since{2019,10} @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 generic and implementation-specific formats can be done using
@ref isPixelFormatImplementationSpecific(). @ref isPixelFormatImplementationSpecific().
In case of OpenGL, corresponds to @ref GL::PixelFormat and @ref GL::PixelType In case of OpenGL, corresponds to @ref GL::PixelFormat, @ref GL::PixelType
and is convertible to them using @ref GL::pixelFormat() and and uncompressed @ref GL::TextureFormat values, is convertible to them using
@ref GL::pixelType(). See documentation of each value for more information @ref GL::pixelFormat(), @ref GL::pixelType() and @ref GL::textureFormat(), and
about the mapping. Note that not every format is available on all targets, use an inverse mapping can be done via @ref GL::genericPixelFormat(PixelFormat, PixelType)
@ref GL::hasPixelFormat() to check for its presence. and @ref GL::genericPixelFormat(TextureFormat). See documentation of each value
for more information about the mapping. Note that not every format is available
In case of Vulkan, corresponds to @ref Vk::PixelFormat and is convertible on all targets, use @ref GL::hasPixelFormat() to check for its presence.
to it using @ref Vk::pixelFormat(Magnum::PixelFormat). See documentation of
each value for more information about the mapping. Note that not every format In case of Vulkan, corresponds to uncompressed @ref Vk::PixelFormat values, is
may be available, use @ref Vk::hasPixelFormat(Magnum::PixelFormat) to check for convertible to it using @ref Vk::pixelFormat(Magnum::PixelFormat), and an
its presence. 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) 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 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 Distinction between generic and implementation-specific formats can be done
using @ref isCompressedPixelFormatImplementationSpecific(). using @ref isCompressedPixelFormatImplementationSpecific().
In case of OpenGL, corresponds to @ref GL::CompressedPixelFormat and is In case of OpenGL, corresponds to @ref GL::CompressedPixelFormat and compressed
convertible to it using @ref GL::compressedPixelFormat(). See documentation of @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 each value for more information about the mapping. Note that not every format
is available on all targets, use @ref GL::hasCompressedPixelFormat() to check is available on all targets, use @ref GL::hasCompressedPixelFormat() to check
for its presence. for its presence.
In case of Vulkan, corresponds to @ref Vk::PixelFormat and is convertible to it In case of Vulkan, corresponds to compressed @ref Vk::PixelFormat values, is
using @ref Vk::pixelFormat(Magnum::CompressedPixelFormat). See documentation convertible to it using @ref Vk::pixelFormat(Magnum::CompressedPixelFormat),
of each value for more information about the mapping. Note that not every and an inverse mapping can be done via @ref Vk::genericCompressedPixelFormat().
format may be available, use @ref Vk::hasPixelFormat(Magnum::CompressedPixelFormat) See documentation of each value for more information about the mapping. Note
to check for its presence. 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) 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 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. 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 #ifdef _c
#define _c2(input) _c(input, input) #define _c2(input) _c(input, input)
_c2(Bc1RGBUnorm) _c2(Bc1RGBUnorm)
@ -128,12 +132,12 @@ _s(Astc6x6x6RGBASrgb) //, ASTC_6x6x6_SRGB_BLOCK)
_s(Astc6x6x6RGBAF) //, ASTC_6x6x6_SFLOAT_BLOCK_EXT) _s(Astc6x6x6RGBAF) //, ASTC_6x6x6_SFLOAT_BLOCK_EXT)
/* https://github.com/KhronosGroup/Vulkan-Docs/issues/512 */ /* https://github.com/KhronosGroup/Vulkan-Docs/issues/512 */
_c(PvrtcRGB2bppUnorm, PvrtcRGBA2bppUnorm) _d(PvrtcRGB2bppUnorm, PvrtcRGBA2bppUnorm)
_c(PvrtcRGB2bppSrgb, PvrtcRGBA2bppSrgb) _d(PvrtcRGB2bppSrgb, PvrtcRGBA2bppSrgb)
_c2(PvrtcRGBA2bppUnorm) _c2(PvrtcRGBA2bppUnorm)
_c2(PvrtcRGBA2bppSrgb) _c2(PvrtcRGBA2bppSrgb)
_c(PvrtcRGB4bppUnorm, PvrtcRGBA4bppUnorm) _d(PvrtcRGB4bppUnorm, PvrtcRGBA4bppUnorm)
_c(PvrtcRGB4bppSrgb, PvrtcRGBA4bppSrgb) _d(PvrtcRGB4bppSrgb, PvrtcRGBA4bppSrgb)
_c2(PvrtcRGBA4bppUnorm) _c2(PvrtcRGBA4bppUnorm)
_c2(PvrtcRGBA4bppSrgb) _c2(PvrtcRGBA4bppSrgb)
#undef _c2 #undef _c2

49
src/Magnum/Vk/PixelFormat.cpp

@ -26,6 +26,7 @@
#include "PixelFormat.h" #include "PixelFormat.h"
#include <Corrade/Containers/ArrayView.h> #include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Utility/Debug.h> #include <Corrade/Utility/Debug.h>
#include "Magnum/PixelFormat.h" #include "Magnum/PixelFormat.h"
@ -46,9 +47,11 @@ constexpr PixelFormat PixelFormatMapping[] {
constexpr PixelFormat CompressedPixelFormatMapping[] { constexpr PixelFormat CompressedPixelFormatMapping[] {
/* GCC 4.8 doesn't like just a {} for default enum values */ /* GCC 4.8 doesn't like just a {} for default enum values */
#define _c(input, format) PixelFormat::Compressed ## format, #define _c(input, format) PixelFormat::Compressed ## format,
#define _d _c
#define _s(input) PixelFormat{}, #define _s(input) PixelFormat{},
#include "Magnum/Vk/Implementation/compressedPixelFormatMapping.hpp" #include "Magnum/Vk/Implementation/compressedPixelFormatMapping.hpp"
#undef _s #undef _s
#undef _d
#undef _c #undef _c
}; };
@ -245,4 +248,50 @@ PixelFormat pixelFormat(const Magnum::CompressedPixelFormat format) {
return out; 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" #include "Magnum/Vk/visibility.h"
/** @file /** @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 * @m_since_latest
*/ */
@ -1413,6 +1413,7 @@ be valid.
extension. Such check is outside of the scope of this function and you are extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format. 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) @see @ref pixelFormat(Magnum::PixelFormat)
*/ */
MAGNUM_VK_EXPORT bool hasPixelFormat(Magnum::PixelFormat format); 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 extension. Such check is outside of the scope of this function and you are
expected to verify extension availability before using such format. 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) @see @ref pixelFormat(Magnum::CompressedPixelFormat)
*/ */
MAGNUM_VK_EXPORT bool hasPixelFormat(Magnum::CompressedPixelFormat format); 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 Not all generic pixel formats have a Vulkan equivalent and this function
expects that given format is available. Use expects that given format is available. Use
@ref hasPixelFormat(Magnum::PixelFormat) to query availability of given format. @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); 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 Not all generic pixel formats have a Vulkan equivalent and this function
expects that given format is available. Use expects that given format is available. Use
@ref hasPixelFormat(Magnum::CompressedPixelFormat) to query availability of given @ref hasPixelFormat(Magnum::CompressedPixelFormat) to query availability of
format. 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); 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 #endif

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

@ -24,6 +24,7 @@
*/ */
#include <sstream> #include <sstream>
#include <Corrade/Containers/Optional.h>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
@ -39,11 +40,13 @@ struct PixelFormatTest: TestSuite::Tester {
void mapImplementationSpecific(); void mapImplementationSpecific();
void mapUnsupported(); void mapUnsupported();
void mapInvalid(); void mapInvalid();
void mapGenericUnsupported();
void mapCompressed(); void mapCompressed();
void mapCompressedImplementationSpecific(); void mapCompressedImplementationSpecific();
void mapCompressedUnsupported(); void mapCompressedUnsupported();
void mapCompressedInvalid(); void mapCompressedInvalid();
void mapGenericCompressedUnsupported();
void debug(); void debug();
}; };
@ -53,11 +56,13 @@ PixelFormatTest::PixelFormatTest() {
&PixelFormatTest::mapImplementationSpecific, &PixelFormatTest::mapImplementationSpecific,
&PixelFormatTest::mapUnsupported, &PixelFormatTest::mapUnsupported,
&PixelFormatTest::mapInvalid, &PixelFormatTest::mapInvalid,
&PixelFormatTest::mapGenericUnsupported,
&PixelFormatTest::mapCompressed, &PixelFormatTest::mapCompressed,
&PixelFormatTest::mapCompressedImplementationSpecific, &PixelFormatTest::mapCompressedImplementationSpecific,
&PixelFormatTest::mapCompressedUnsupported, &PixelFormatTest::mapCompressedUnsupported,
&PixelFormatTest::mapCompressedInvalid, &PixelFormatTest::mapCompressedInvalid,
&PixelFormatTest::mapGenericCompressedUnsupported,
&PixelFormatTest::debug}); &PixelFormatTest::debug});
} }
@ -90,6 +95,7 @@ void PixelFormatTest::map() {
CORRADE_COMPARE(nextHandled, i); \ CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \ CORRADE_COMPARE(firstUnhandled, 0xffff); \
CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::format)); \ CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::format)); \
CORRADE_COMPARE(genericPixelFormat(PixelFormat::format), Magnum::PixelFormat::format); \
CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::format), PixelFormat::format); \ CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::format), PixelFormat::format); \
{ \ { \
std::ostringstream out; \ std::ostringstream out; \
@ -166,11 +172,23 @@ void PixelFormatTest::mapInvalid() {
"Vk::pixelFormat(): invalid format PixelFormat(0x123)\n"); "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() { void PixelFormatTest::mapCompressed() {
/* Touchstone verification. Using Vulkan enums directly to sidestep /* Touchstone verification. Using Vulkan enums directly to sidestep
potential problems in enum mapping as well. */ potential problems in enum mapping as well. */
CORRADE_VERIFY(hasPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm)); CORRADE_VERIFY(hasPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm));
CORRADE_COMPARE(pixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm), PixelFormat(VK_FORMAT_BC1_RGBA_UNORM_BLOCK)); 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 /* This goes through the first 16 bits, which should be enough. Going
through 32 bits takes 8 seconds, too much. */ through 32 bits takes 8 seconds, too much. */
@ -190,6 +208,23 @@ void PixelFormatTest::mapCompressed() {
#endif #endif
switch(format) { switch(format) {
#define _c(format, expectedFormat) \ #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: \ case Magnum::CompressedPixelFormat::format: \
CORRADE_COMPARE(nextHandled, i); \ CORRADE_COMPARE(nextHandled, i); \
CORRADE_COMPARE(firstUnhandled, 0xffff); \ CORRADE_COMPARE(firstUnhandled, 0xffff); \
@ -267,6 +302,14 @@ void PixelFormatTest::mapCompressedInvalid() {
"Vk::pixelFormat(): invalid format CompressedPixelFormat(0x123)\n"); "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() { void PixelFormatTest::debug() {
std::ostringstream out; std::ostringstream out;
Debug{&out} << PixelFormat::RGB16UI << PixelFormat(-10007655); Debug{&out} << PixelFormat::RGB16UI << PixelFormat(-10007655);

Loading…
Cancel
Save