From 31d3cdcdb69ef5d8f8d2aaf27e1a27203dc2c828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 19 Feb 2020 12:47:43 +0100 Subject: [PATCH] Enable embedding implementation-specific values in VertexFormat. Similarly to PixelFormat. Will be useful for Vulkan, unfortunately not so much for GL because there the format is specified by three orthogonal values and it's a terrible mess. --- src/Magnum/Test/CMakeLists.txt | 8 ++- src/Magnum/Test/VertexFormatTest.cpp | 102 +++++++++++++++++++++++++++ src/Magnum/VertexFormat.cpp | 19 +++++ src/Magnum/VertexFormat.h | 66 ++++++++++++++--- 4 files changed, 185 insertions(+), 10 deletions(-) diff --git a/src/Magnum/Test/CMakeLists.txt b/src/Magnum/Test/CMakeLists.txt index e46b1abf4..e7cd1e216 100644 --- a/src/Magnum/Test/CMakeLists.txt +++ b/src/Magnum/Test/CMakeLists.txt @@ -29,10 +29,8 @@ corrade_add_test(ImageTest ImageTest.cpp LIBRARIES MagnumTestLib) corrade_add_test(ImageViewTest ImageViewTest.cpp LIBRARIES MagnumTestLib) corrade_add_test(MeshTest MeshTest.cpp LIBRARIES MagnumTestLib) corrade_add_test(PixelFormatTest PixelFormatTest.cpp LIBRARIES MagnumTestLib) -target_compile_definitions(PixelFormatTest PRIVATE "CORRADE_GRACEFUL_ASSERT") corrade_add_test(PixelStorageTest PixelStorageTest.cpp LIBRARIES Magnum) corrade_add_test(ResourceManagerTest ResourceManagerTest.cpp LIBRARIES Magnum) -target_compile_definitions(ResourceManagerTest PRIVATE "CORRADE_GRACEFUL_ASSERT") corrade_add_test(SamplerTest SamplerTest.cpp LIBRARIES MagnumTestLib) corrade_add_test(TagsTest TagsTest.cpp LIBRARIES Magnum) corrade_add_test(VertexFormatTest VertexFormatTest.cpp LIBRARIES MagnumTestLib) @@ -49,3 +47,9 @@ set_target_properties( TagsTest VertexFormatTest PROPERTIES FOLDER "Magnum/Test") + +set_property(TARGET + PixelFormatTest + ResourceManagerTest + VertexFormatTest + APPEND PROPERTY COMPILE_DEFINITIONS "CORRADE_GRACEFUL_ASSERT") diff --git a/src/Magnum/Test/VertexFormatTest.cpp b/src/Magnum/Test/VertexFormatTest.cpp index 635225c92..cefe65519 100644 --- a/src/Magnum/Test/VertexFormatTest.cpp +++ b/src/Magnum/Test/VertexFormatTest.cpp @@ -38,21 +38,32 @@ struct VertexFormatTest: TestSuite::Tester { void mapping(); + void isImplementationSpecific(); + void wrap(); + void wrapInvalid(); + void unwrap(); + void unwrapInvalid(); void size(); void sizeInvalid(); + void sizeImplementationSpecific(); void componentCount(); void componentCountInvalid(); + void componentCountImplementationSpecific(); void componentFormat(); void componentFormatInvalid(); + void componentFormatImplementationSpecific(); void isNormalized(); void isNormalizedInvalid(); + void isNormalizedImplementationSpecific(); void assemble(); void assembleRoundtrip(); void assembleCantNormalize(); void assembleInvalidComponentCount(); + void assembleImplementationSpecific(); void debug(); + void debugImplementationSpecific(); void configuration(); }; @@ -77,14 +88,23 @@ constexpr struct { VertexFormatTest::VertexFormatTest() { addTests({&VertexFormatTest::mapping, + &VertexFormatTest::isImplementationSpecific, + &VertexFormatTest::wrap, + &VertexFormatTest::wrapInvalid, + &VertexFormatTest::unwrap, + &VertexFormatTest::unwrapInvalid, &VertexFormatTest::size, &VertexFormatTest::sizeInvalid, + &VertexFormatTest::sizeImplementationSpecific, &VertexFormatTest::componentCount, &VertexFormatTest::componentCountInvalid, + &VertexFormatTest::componentCountImplementationSpecific, &VertexFormatTest::componentFormat, &VertexFormatTest::componentFormatInvalid, + &VertexFormatTest::componentFormatImplementationSpecific, &VertexFormatTest::isNormalized, &VertexFormatTest::isNormalizedInvalid, + &VertexFormatTest::isNormalizedImplementationSpecific, &VertexFormatTest::assemble}); @@ -93,8 +113,10 @@ VertexFormatTest::VertexFormatTest() { addTests({&VertexFormatTest::assembleCantNormalize, &VertexFormatTest::assembleInvalidComponentCount, + &VertexFormatTest::assembleImplementationSpecific, &VertexFormatTest::debug, + &VertexFormatTest::debugImplementationSpecific, &VertexFormatTest::configuration}); } @@ -137,6 +159,41 @@ void VertexFormatTest::mapping() { CORRADE_COMPARE(firstUnhandled, 0xffff); } +void VertexFormatTest::isImplementationSpecific() { + constexpr bool a = isVertexFormatImplementationSpecific(VertexFormat::Vector2sNormalized); + constexpr bool b = isVertexFormatImplementationSpecific(VertexFormat(0x8000dead)); + CORRADE_VERIFY(!a); + CORRADE_VERIFY(b); +} + +void VertexFormatTest::wrap() { + constexpr VertexFormat a = Magnum::vertexFormatWrap(0xdead); + CORRADE_COMPARE(UnsignedInt(a), 0x8000dead); +} + +void VertexFormatTest::wrapInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + Magnum::vertexFormatWrap(0xdeadbeef); + + CORRADE_COMPARE(out.str(), "vertexFormatWrap(): implementation-specific value 0xdeadbeef already wrapped or too large\n"); +} + +void VertexFormatTest::unwrap() { + constexpr UnsignedInt a = Magnum::vertexFormatUnwrap(VertexFormat(0x8000dead)); + CORRADE_COMPARE(a, 0xdead); +} + +void VertexFormatTest::unwrapInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + Magnum::vertexFormatUnwrap(VertexFormat::Float); + + CORRADE_COMPARE(out.str(), "vertexFormatUnwrap(): VertexFormat::Float isn't a wrapped implementation-specific value\n"); +} + void VertexFormatTest::size() { CORRADE_COMPARE(Magnum::vertexFormatSize(VertexFormat::Vector2), sizeof(Vector2)); CORRADE_COMPARE(Magnum::vertexFormatSize(VertexFormat::Vector3), sizeof(Vector3)); @@ -155,6 +212,13 @@ void VertexFormatTest::sizeInvalid() { "vertexFormatSize(): invalid format VertexFormat(0xdead)\n"); } +void VertexFormatTest::sizeImplementationSpecific() { + std::ostringstream out; + Error redirectError{&out}; + Magnum::vertexFormatSize(Magnum::vertexFormatWrap(0xdead)); + CORRADE_COMPARE(out.str(), "vertexFormatSize(): can't determine size of an implementation-specific format 0xdead\n"); +} + void VertexFormatTest::componentCount() { CORRADE_COMPARE(Magnum::vertexFormatComponentCount(VertexFormat::UnsignedByteNormalized), 1); CORRADE_COMPARE(Magnum::vertexFormatComponentCount(VertexFormat::Vector2us), 2); @@ -174,6 +238,14 @@ void VertexFormatTest::componentCountInvalid() { "vertexFormatComponentCount(): invalid format VertexFormat(0xdead)\n"); } +void VertexFormatTest::componentCountImplementationSpecific() { + std::ostringstream out; + Error redirectError{&out}; + Magnum::vertexFormatComponentCount(Magnum::vertexFormatWrap(0xdead)); + CORRADE_COMPARE(out.str(), + "vertexFormatComponentCount(): can't determine component count of an implementation-specific format 0xdead\n"); +} + void VertexFormatTest::componentFormat() { CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector4), VertexFormat::Float); CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector3h), VertexFormat::Half); @@ -199,6 +271,14 @@ void VertexFormatTest::componentFormatInvalid() { "vertexFormatComponentType(): invalid format VertexFormat(0xdead)\n"); } +void VertexFormatTest::componentFormatImplementationSpecific() { + std::ostringstream out; + Error redirectError{&out}; + Magnum::vertexFormatComponentFormat(Magnum::vertexFormatWrap(0xdead)); + CORRADE_COMPARE(out.str(), + "vertexFormatComponentFormat(): can't determine component format of an implementation-specific format 0xdead\n"); +} + void VertexFormatTest::isNormalized() { CORRADE_VERIFY(isVertexFormatNormalized(VertexFormat::UnsignedByteNormalized)); CORRADE_VERIFY(!isVertexFormatNormalized(VertexFormat::Vector2us)); @@ -218,6 +298,14 @@ void VertexFormatTest::isNormalizedInvalid() { "isVertexFormatNormalized(): invalid format VertexFormat(0xdead)\n"); } +void VertexFormatTest::isNormalizedImplementationSpecific() { + std::ostringstream out; + Error redirectError{&out}; + isVertexFormatNormalized(Magnum::vertexFormatWrap(0xdead)); + CORRADE_COMPARE(out.str(), + "isVertexFormatNormalized(): can't determine normalization of an implementation-specific format 0xdead\n"); +} + void VertexFormatTest::assemble() { CORRADE_COMPARE(vertexFormat(VertexFormat::UnsignedShort, 3, true), VertexFormat::Vector3usNormalized); @@ -269,12 +357,26 @@ void VertexFormatTest::assembleInvalidComponentCount() { "vertexFormat(): invalid component count 5\n"); } +void VertexFormatTest::assembleImplementationSpecific() { + std::ostringstream out; + Error redirectError{&out}; + vertexFormat(Magnum::vertexFormatWrap(0xdead), 1, true); + CORRADE_COMPARE(out.str(), + "vertexFormat(): can't assemble a format out of an implementation-specific format 0xdead\n"); +} + void VertexFormatTest::debug() { std::ostringstream o; Debug(&o) << VertexFormat::Vector4 << VertexFormat(0xdead); CORRADE_COMPARE(o.str(), "VertexFormat::Vector4 VertexFormat(0xdead)\n"); } +void VertexFormatTest::debugImplementationSpecific() { + std::ostringstream o; + Debug(&o) << Magnum::vertexFormatWrap(0xdead); + CORRADE_COMPARE(o.str(), "VertexFormat::ImplementationSpecific(0xdead)\n"); +} + void VertexFormatTest::configuration() { Utility::Configuration c; diff --git a/src/Magnum/VertexFormat.cpp b/src/Magnum/VertexFormat.cpp index cfe0ac031..25789d659 100644 --- a/src/Magnum/VertexFormat.cpp +++ b/src/Magnum/VertexFormat.cpp @@ -33,6 +33,9 @@ namespace Magnum { UnsignedInt vertexFormatSize(const VertexFormat format) { + CORRADE_ASSERT(!isVertexFormatImplementationSpecific(format), + "vertexFormatSize(): can't determine size of an implementation-specific format" << reinterpret_cast(vertexFormatUnwrap(format)), {}); + switch(format) { case VertexFormat::UnsignedByte: case VertexFormat::UnsignedByteNormalized: @@ -102,6 +105,9 @@ UnsignedInt vertexFormatSize(const VertexFormat format) { } UnsignedInt vertexFormatComponentCount(const VertexFormat format) { + CORRADE_ASSERT(!isVertexFormatImplementationSpecific(format), + "vertexFormatComponentCount(): can't determine component count of an implementation-specific format" << reinterpret_cast(vertexFormatUnwrap(format)), {}); + switch(format) { case VertexFormat::Float: case VertexFormat::Half: @@ -168,6 +174,9 @@ UnsignedInt vertexFormatComponentCount(const VertexFormat format) { } VertexFormat vertexFormatComponentFormat(const VertexFormat format) { + CORRADE_ASSERT(!isVertexFormatImplementationSpecific(format), + "vertexFormatComponentFormat(): can't determine component format of an implementation-specific format" << reinterpret_cast(vertexFormatUnwrap(format)), {}); + switch(format) { case VertexFormat::Float: case VertexFormat::Vector2: @@ -244,6 +253,9 @@ VertexFormat vertexFormatComponentFormat(const VertexFormat format) { } bool isVertexFormatNormalized(const VertexFormat format) { + CORRADE_ASSERT(!isVertexFormatImplementationSpecific(format), + "isVertexFormatNormalized(): can't determine normalization of an implementation-specific format" << reinterpret_cast(vertexFormatUnwrap(format)), {}); + switch(format) { case VertexFormat::Float: case VertexFormat::Half: @@ -306,6 +318,9 @@ bool isVertexFormatNormalized(const VertexFormat format) { } VertexFormat vertexFormat(const VertexFormat format, UnsignedInt componentCount, bool normalized) { + CORRADE_ASSERT(!isVertexFormatImplementationSpecific(format), + "vertexFormat(): can't assemble a format out of an implementation-specific format" << reinterpret_cast(vertexFormatUnwrap(format)), {}); + VertexFormat componentFormat = vertexFormatComponentFormat(format); /* First turn the format into a normalized one, if requested */ @@ -360,6 +375,10 @@ constexpr const char* VertexFormatNames[] { Debug& operator<<(Debug& debug, const VertexFormat value) { debug << "VertexFormat" << Debug::nospace; + if(isVertexFormatImplementationSpecific(value)) { + return debug << "::ImplementationSpecific(" << Debug::nospace << reinterpret_cast(vertexFormatUnwrap(value)) << Debug::nospace << ")"; + } + if(UnsignedInt(value) - 1 < Containers::arraySize(VertexFormatNames)) { return debug << "::" << Debug::nospace << VertexFormatNames[UnsignedInt(value) - 1]; } diff --git a/src/Magnum/VertexFormat.h b/src/Magnum/VertexFormat.h index 6b66aa88e..149c7a60d 100644 --- a/src/Magnum/VertexFormat.h +++ b/src/Magnum/VertexFormat.h @@ -26,9 +26,10 @@ */ /** @file - * @brief Enum @ref Magnum::VertexFormat, @ref Magnum::vertexFormatSize(), @ref Magnum::vertexFormatComponentCount(), @ref Magnum::vertexFormatComponentFormat(), @ref Magnum::isVertexFormatNormalized() + * @brief Enum @ref Magnum::VertexFormat, function @ref Magnum::isVertexFormatImplementationSpecific(), @ref Magnum::vertexFormatWrap(), @ref Magnum::vertexFormatUnwrap(), @ref Magnum::vertexFormatSize(), @ref Magnum::vertexFormatComponentCount(), @ref Magnum::vertexFormatComponentFormat(), @ref Magnum::isVertexFormatNormalized() */ +#include #include #include "Magnum/Magnum.h" @@ -41,7 +42,12 @@ namespace Magnum { @m_since_latest Like @ref PixelFormat, but for mesh attributes --- including double-precision -types and matrices. +types and matrices. Can act also as a wrapper for implementation-specific mesh +attribute type values using @ref vertexFormatWrap() and +@ref vertexFormatUnwrap(). Distinction between generic and +implementation-specific types can be done using +@ref isVertexFormatImplementationSpecific(). + @see @ref Trade::MeshData, @ref Trade::MeshAttributeData, @ref Trade::MeshAttribute */ @@ -311,6 +317,56 @@ enum class VertexFormat: UnsignedInt { Vector4i }; +/** +@debugoperatorenum{VertexFormat} +@m_since_latest +*/ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, VertexFormat value); + +/** +@brief Whether a @ref VertexFormat value wraps an implementation-specific identifier +@m_since_latest + +Returns @cpp true @ce if value of @p format has its highest bit set, +@cpp false @ce otherwise. Use @ref vertexFormatWrap() and @ref vertexFormatUnwrap() +to wrap/unwrap an implementation-specific indentifier to/from +@ref VertexFormat. +*/ +constexpr bool isVertexFormatImplementationSpecific(VertexFormat format) { + return UnsignedInt(format) & (1u << 31); +} + +/** +@brief Wrap an implementation-specific vertex format identifier in @ref VertexFormat +@m_since_latest + +Sets the highest bit on @p type to mark it as implementation-specific. Expects +that @p type fits into the remaining bits. Use @ref vertexFormatUnwrap() +for the inverse operation. +@see @ref isVertexFormatImplementationSpecific() +*/ +template constexpr VertexFormat vertexFormatWrap(T implementationSpecific) { + static_assert(sizeof(T) <= 4, "types larger than 32bits are not supported"); + return CORRADE_CONSTEXPR_ASSERT(!(UnsignedInt(implementationSpecific) & (1u << 31)), + "vertexFormatWrap(): implementation-specific value" << reinterpret_cast(implementationSpecific) << "already wrapped or too large"), + VertexFormat((1u << 31)|UnsignedInt(implementationSpecific)); +} + +/** +@brief Unwrap an implementation-specific vertex format identifier from @ref VertexFormat +@m_since_latest + +Unsets the highest bit from @p type to extract the implementation-specific +value. Expects that @p type has it set. Use @ref vertexFormatWrap() for +the inverse operation. +@see @ref isVertexFormatImplementationSpecific() +*/ +template constexpr T vertexFormatUnwrap(VertexFormat format) { + return CORRADE_CONSTEXPR_ASSERT(UnsignedInt(format) & (1u << 31), + "vertexFormatUnwrap():" << format << "isn't a wrapped implementation-specific value"), + T(UnsignedInt(format) & ~(1u << 31)); +} + /** @brief Size of given vertex format @m_since_latest @@ -370,12 +426,6 @@ normalization. Expects that @p componentCount is not larger than @cpp 4 @ce and */ MAGNUM_EXPORT VertexFormat vertexFormat(VertexFormat format, UnsignedInt componentCount, bool normalized); -/** -@debugoperatorenum{VertexFormat} -@m_since_latest -*/ -MAGNUM_EXPORT Debug& operator<<(Debug& debug, VertexFormat value); - } namespace Corrade { namespace Utility {