Browse Source

Trade: allow array attributes to have implementation-specific formats.

I'm not sure why this restriction was there as nothing was preventing
them from being used. The attribute is only accessible through the
typeless attribute(), which gives back
`Containers::StridedArrayView2D<const char>` with second dimension size
being set to the full stride. And there it doesn't matter if the format
is an array or not.

This will be useful for joint IDs and weights, for example doing crazy
things like packing the IDs into an array of 8 4-bit numbers, saving
half the memory compared to the smallest builtin representation using
UnsignedByte[8].
pull/582/merge
Vladimír Vondruš 4 years ago
parent
commit
a67effb57a
  1. 3
      doc/changelog.dox
  2. 6
      src/Magnum/Trade/MeshData.h
  3. 30
      src/Magnum/Trade/Test/MeshDataTest.cpp

3
doc/changelog.dox

@ -627,6 +627,9 @@ See also:
attribute strides for better data layout flexibility. This is however not attribute strides for better data layout flexibility. This is however not
commonly supported by GPU APIs and tools like @ref MeshTools::compile() commonly supported by GPU APIs and tools like @ref MeshTools::compile()
assert in that case. assert in that case.
- @ref Trade::MeshData now allows array attributes to have
implementation-specific vertex formats as well. The restriction didn't make
sense, as there was nothing in the design preventing them from being used.
- Added @ref Trade::MeshData::findAttributeId() for an ability to check that - Added @ref Trade::MeshData::findAttributeId() for an ability to check that
an attribute exists and retrieve its ID in a single step, avoiding a double an attribute exists and retrieve its ID in a single step, avoiding a double
lookup compared to @relativeref{Trade::MeshData,hasAttribute()} + lookup compared to @relativeref{Trade::MeshData,hasAttribute()} +

6
src/Magnum/Trade/MeshData.h

@ -2287,8 +2287,7 @@ namespace Implementation {
} }
constexpr MeshAttributeData::MeshAttributeData(std::nullptr_t, const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView1D<const void>& data, const UnsignedShort arraySize) noexcept: constexpr MeshAttributeData::MeshAttributeData(std::nullptr_t, const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView1D<const void>& data, const UnsignedShort arraySize) noexcept:
_format{(CORRADE_CONSTEXPR_ASSERT(!arraySize || !isVertexFormatImplementationSpecific(format), _format{format},
"Trade::MeshAttributeData: array attributes can't have an implementation-specific format"), format)},
_name{(CORRADE_CONSTEXPR_ASSERT(Implementation::isVertexFormatCompatibleWithAttribute(name, format), _name{(CORRADE_CONSTEXPR_ASSERT(Implementation::isVertexFormatCompatibleWithAttribute(name, format),
"Trade::MeshAttributeData:" << format << "is not a valid format for" << name), name)}, "Trade::MeshAttributeData:" << format << "is not a valid format for" << name), name)},
_isOffsetOnly{false}, _vertexCount{UnsignedInt(data.size())}, _isOffsetOnly{false}, _vertexCount{UnsignedInt(data.size())},
@ -2300,8 +2299,7 @@ constexpr MeshAttributeData::MeshAttributeData(std::nullptr_t, const MeshAttribu
_data{data.data()} {} _data{data.data()} {}
constexpr MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const std::size_t offset, const UnsignedInt vertexCount, const std::ptrdiff_t stride, UnsignedShort arraySize) noexcept: constexpr MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const std::size_t offset, const UnsignedInt vertexCount, const std::ptrdiff_t stride, UnsignedShort arraySize) noexcept:
_format{(CORRADE_CONSTEXPR_ASSERT(!arraySize || !isVertexFormatImplementationSpecific(format), _format{format},
"Trade::MeshAttributeData: array attributes can't have an implementation-specific format"), format)},
_name{(CORRADE_CONSTEXPR_ASSERT(Implementation::isVertexFormatCompatibleWithAttribute(name, format), _name{(CORRADE_CONSTEXPR_ASSERT(Implementation::isVertexFormatCompatibleWithAttribute(name, format),
"Trade::MeshAttributeData:" << format << "is not a valid format for" << name), name)}, "Trade::MeshAttributeData:" << format << "is not a valid format for" << name), name)},
_isOffsetOnly{true}, _vertexCount{vertexCount}, _isOffsetOnly{true}, _vertexCount{vertexCount},

30
src/Magnum/Trade/Test/MeshDataTest.cpp

@ -85,6 +85,7 @@ struct MeshDataTest: TestSuite::Tester {
void constructArrayAttributeTypeErased(); void constructArrayAttributeTypeErased();
void constructArrayAttributeNullptr(); void constructArrayAttributeNullptr();
void constructArrayAttributeOffsetOnly(); void constructArrayAttributeOffsetOnly();
void constructArrayAttributeImplementationSpecificFormat();
void constructArrayAttributeNotAllowed(); void constructArrayAttributeNotAllowed();
void construct(); void construct();
@ -258,6 +259,7 @@ MeshDataTest::MeshDataTest() {
&MeshDataTest::constructArrayAttributeTypeErased, &MeshDataTest::constructArrayAttributeTypeErased,
&MeshDataTest::constructArrayAttributeNullptr, &MeshDataTest::constructArrayAttributeNullptr,
&MeshDataTest::constructArrayAttributeOffsetOnly, &MeshDataTest::constructArrayAttributeOffsetOnly,
&MeshDataTest::constructArrayAttributeImplementationSpecificFormat,
&MeshDataTest::constructArrayAttributeNotAllowed}); &MeshDataTest::constructArrayAttributeNotAllowed});
addInstancedTests({&MeshDataTest::construct}, addInstancedTests({&MeshDataTest::construct},
@ -1129,6 +1131,19 @@ void MeshDataTest::constructArrayAttributeOffsetOnly() {
CORRADE_COMPARE(cdata.arraySize(), 4); CORRADE_COMPARE(cdata.arraySize(), 4);
} }
void MeshDataTest::constructArrayAttributeImplementationSpecificFormat() {
Vector2 positions[]{{1.0f, 0.3f}, {0.5f, 0.7f}};
/* This should not fire any asserts */
MeshAttributeData a{meshAttributeCustom(35), vertexFormatWrap(0x3a), positions, 2};
CORRADE_COMPARE(a.name(), meshAttributeCustom(35));
CORRADE_COMPARE(a.format(), vertexFormatWrap(0x3a));
CORRADE_COMPARE(a.arraySize(), 2);
CORRADE_COMPARE_AS(Containers::arrayCast<const Vector2>(a.data()),
Containers::arrayView<Vector2>({{1.0f, 0.3f}, {0.5f, 0.7f}}),
TestSuite::Compare::Container);
}
void MeshDataTest::constructArrayAttributeNotAllowed() { void MeshDataTest::constructArrayAttributeNotAllowed() {
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
@ -1144,23 +1159,21 @@ void MeshDataTest::constructArrayAttributeNotAllowed() {
MeshAttributeData{meshAttributeCustom(35), positions2D}; MeshAttributeData{meshAttributeCustom(35), positions2D};
MeshAttributeData{meshAttributeCustom(35), VertexFormat::Vector2, positions2Dchar, 3}; MeshAttributeData{meshAttributeCustom(35), VertexFormat::Vector2, positions2Dchar, 3};
MeshAttributeData{meshAttributeCustom(35), VertexFormat::Vector2, 0, 3, 6*sizeof(Vector2), 3}; MeshAttributeData{meshAttributeCustom(35), VertexFormat::Vector2, 0, 3, 6*sizeof(Vector2), 3};
MeshAttributeData{meshAttributeCustom(35), vertexFormatWrap(0xdead), positions, 3};
MeshAttributeData{meshAttributeCustom(35), vertexFormatWrap(0xdead), 0, 3, 6*sizeof(Vector2), 3};
/* This is not */ /* This is not */
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector2b, positions, 3}; MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector2b, positions, 3};
MeshAttributeData{meshAttributeCustom(35), vertexFormatWrap(0xdead), positions, 3};
MeshAttributeData{MeshAttribute::Position, positions2D}; MeshAttributeData{MeshAttribute::Position, positions2D};
MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector2, positions2Dchar, 3}; MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector2, positions2Dchar, 3};
MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector2, 0, 3, 6*sizeof(Vector2), 3}; MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector2, 0, 3, 6*sizeof(Vector2), 3};
MeshAttributeData{meshAttributeCustom(35), vertexFormatWrap(0xdead), 0, 3, 6*sizeof(Vector2), 3};
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Trade::MeshAttributeData: Trade::MeshAttribute::Position can't be an array attribute\n"
"Trade::MeshAttributeData: array attributes can't have an implementation-specific format\n"
"Trade::MeshAttributeData: Trade::MeshAttribute::Position can't be an array attribute\n" "Trade::MeshAttributeData: Trade::MeshAttribute::Position can't be an array attribute\n"
"Trade::MeshAttributeData: Trade::MeshAttribute::Position can't be an array attribute\n" "Trade::MeshAttributeData: Trade::MeshAttribute::Position can't be an array attribute\n"
"Trade::MeshAttributeData: Trade::MeshAttribute::Position can't be an array attribute\n" "Trade::MeshAttributeData: Trade::MeshAttribute::Position can't be an array attribute\n"
"Trade::MeshAttributeData: array attributes can't have an implementation-specific format\n"); "Trade::MeshAttributeData: Trade::MeshAttribute::Position can't be an array attribute\n");
} }
void MeshDataTest::construct() { void MeshDataTest::construct() {
@ -1895,14 +1908,17 @@ void MeshDataTest::constructImplementationSpecificVertexFormat() {
MeshAttributeData{MeshAttribute::TextureCoordinates, MeshAttributeData{MeshAttribute::TextureCoordinates,
vertexFormatWrap(0xdead3), attribute}, vertexFormatWrap(0xdead3), attribute},
MeshAttributeData{MeshAttribute::Color, MeshAttributeData{MeshAttribute::Color,
vertexFormatWrap(0xdead4), attribute}}}; vertexFormatWrap(0xdead4), attribute},
MeshAttributeData{meshAttributeCustom(35),
vertexFormatWrap(0xdead5), attribute, 27}}};
/* Getting typeless attribute should work also */ /* Getting typeless attribute should work also */
UnsignedInt format = 0xdead1; UnsignedInt format = 0xdead1;
for(MeshAttribute name: {MeshAttribute::Position, for(MeshAttribute name: {MeshAttribute::Position,
MeshAttribute::Normal, MeshAttribute::Normal,
MeshAttribute::TextureCoordinates, MeshAttribute::TextureCoordinates,
MeshAttribute::Color}) { MeshAttribute::Color,
meshAttributeCustom(35)}) {
CORRADE_ITERATION(name); CORRADE_ITERATION(name);
CORRADE_COMPARE(data.attributeFormat(name), vertexFormatWrap(format++)); CORRADE_COMPARE(data.attributeFormat(name), vertexFormatWrap(format++));

Loading…
Cancel
Save