diff --git a/doc/changelog.dox b/doc/changelog.dox index 70605d02a..af5d8a353 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -251,6 +251,8 @@ See also: [mosra/magnum#403](https://github.com/mosra/magnum/pull/403)) - Added an ability to remove a buffer from a @ref GL::BufferTexture using @ref GL::BufferTexture::resetBuffer() "resetBuffer()" +- Matrix @ref GL::Attribute instances can now specify custom stride between + column vectors in order to control alignment in packed 8- and 16-bit types @subsubsection changelog-latest-changes-math Math library @@ -422,6 +424,8 @@ See also: @ref GL::Attribute::DataType::Half, @ref GL::DynamicAttribute::DataType::Half and @ref GL::PixelType::Half that are consistent with the @ref Half type used elsewhere. +- @cpp GL::Attribute::vectorSize() @ce is deprecated as the name is + misleading now, use @ref GL::Attribute::vectorStride() instead - @cpp Trade::AbstractImporter::mesh2D() @ce, @cpp Trade::MeshData2D @ce, @cpp Trade::MeshData3D @ce, @cpp Trade::AbstractImporter::mesh2D() @ce, diff --git a/src/Magnum/GL/Attribute.h b/src/Magnum/GL/Attribute.h index dc1a71430..262ccfd4b 100644 --- a/src/Magnum/GL/Attribute.h +++ b/src/Magnum/GL/Attribute.h @@ -286,25 +286,56 @@ template class Attribute { /** * @brief Constructor - * @param components Component count * @param dataType Type of passed data. Default is the same as * type used in shader (e.g. @ref DataType::Int for * @ref Magnum::Vector4i "Vector4i"). * @param dataOptions Data options. Default is no options. + * + * Component count is set to the same value as in type used in shader + * (e.g. @ref Components::Three for @ref Magnum::Vector3 "Vector3"). */ - constexpr Attribute(Components components, DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _components(components), _dataType(dataType), _dataOptions(dataOptions) {} + constexpr Attribute(DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): Attribute{Implementation::Attribute::DefaultComponents, dataType, dataOptions} {} /** * @brief Constructor + * @param components Component count * @param dataType Type of passed data. Default is the same as * type used in shader (e.g. @ref DataType::Int for * @ref Magnum::Vector4i "Vector4i"). * @param dataOptions Data options. Default is no options. * + * Vector stride is set to the size of the vector type (e.g. 9 for a + * @ref Magnum::Matrix3 "Matrix3"). + */ + constexpr Attribute(Components components, DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): Attribute{components, Implementation::Attribute::size(GLint(components), dataType), dataType, dataOptions} {} + + /** + * @brief Construct with a custom vector stride + * @param vectorStride Stride between consecutive matrix column + * vectors + * @param dataType Type of passed data. Default is the same as + * type used in shader (e.g. @ref DataType::Int for + * @ref Magnum::Vector4i "Vector4i"). + * @param dataOptions Data options. Default is no options. + * @m_since_latest + * * Component count is set to the same value as in type used in shader * (e.g. @ref Components::Three for @ref Magnum::Vector3 "Vector3"). */ - constexpr Attribute(DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _components(Implementation::Attribute::DefaultComponents), _dataType(dataType), _dataOptions(dataOptions) {} + constexpr Attribute(UnsignedInt vectorStride, DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): Attribute{Implementation::Attribute::DefaultComponents, vectorStride, dataType, dataOptions} {} + + /** + * @brief Construct with a custom vector stride + * @param components Component count + * @param vectorStride Stride between consecutive matrix column + * vectors + * @param dataType Type of passed data. Default is the same as + * type used in shader (e.g. @ref DataType::Int for + * @ref Magnum::Vector4i "Vector4i"). + * @param dataOptions Data options. Default is no options. + * @m_since_latest + */ + constexpr Attribute(Components components, UnsignedInt vectorStride, DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _components{components}, _vectorStride{vectorStride}, _dataType{dataType}, _dataOptions{dataOptions} {} /** @brief Component count of passed data */ constexpr Components components() const { return _components; } @@ -312,20 +343,36 @@ template class Attribute { /** @brief Type of passed data */ constexpr DataType dataType() const { return _dataType; } + /** + * @brief Stride between consecutive vector elements + * @m_since_latest + * + * Used for describing matrix attributes. Implicitly the same as size + * of given vector type (e.g. @cpp 9 @ce for a + * @ref Magnum::Matrix3 "Matrix3"), but can be overriden for example to + * ensure four-byte column alignment with 1- and 2-byte data types. + * @see @ref Vectors + */ + constexpr UnsignedInt vectorStride() const { return _vectorStride; } + + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Size of each vector in passed data + * @m_deprecated_since_latest Use @ref vectorStride() instead. * * @see @ref VectorCount */ - UnsignedInt vectorSize() const { - return Implementation::Attribute::size(GLint(_components), _dataType); + constexpr CORRADE_DEPRECATED("use vectorStride() instead") UnsignedInt vectorSize() const { + return vectorStride(); } + #endif /** @brief Data options */ constexpr DataOptions dataOptions() const { return _dataOptions; } private: Components _components; + UnsignedInt _vectorStride; DataType _dataType; DataOptions _dataOptions; }; diff --git a/src/Magnum/GL/Mesh.h b/src/Magnum/GL/Mesh.h index b97e794d1..150f5c8b3 100644 --- a/src/Magnum/GL/Mesh.h +++ b/src/Magnum/GL/Mesh.h @@ -1002,7 +1002,7 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { /* Computing stride of interleaved vertex attributes */ template static GLsizei strideOfInterleaved(const Attribute& attribute, const U&... attributes) { - return attribute.vectorSize()*Attribute::VectorCount + strideOfInterleaved(attributes...); + return attribute.vectorStride()*Attribute::VectorCount + strideOfInterleaved(attributes...); } template static GLsizei strideOfInterleaved(GLintptr gap, const T&... attributes) { return gap + strideOfInterleaved(attributes...); @@ -1014,7 +1014,7 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { addVertexAttribute(buffer, attribute, offset, stride, divisor); /* Add size of this attribute to offset for next attribute */ - addVertexBufferInternal(buffer, offset+attribute.vectorSize()*Attribute::VectorCount, stride, divisor, attributes...); + addVertexBufferInternal(buffer, offset+attribute.vectorStride()*Attribute::VectorCount, stride, divisor, attributes...); } template void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLuint divisor, GLintptr gap, const T&... attributes) { /* Add the gap to offset for next attribute */ @@ -1029,7 +1029,7 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { GLint(attribute.components()), GLenum(attribute.dataType()), Implementation::kindFor(attribute.dataOptions()), - GLintptr(offset+i*attribute.vectorSize()), + GLintptr(offset+i*attribute.vectorStride()), stride, divisor); } @@ -1054,7 +1054,7 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { GLint(attribute.components()), GLenum(attribute.dataType()), Implementation::kindFor(attribute.dataOptions()), - GLintptr(offset+i*attribute.vectorSize()), + GLintptr(offset+i*attribute.vectorStride()), stride, divisor); } diff --git a/src/Magnum/GL/Test/AttributeTest.cpp b/src/Magnum/GL/Test/AttributeTest.cpp index 255bdbc8d..2b8bd9976 100644 --- a/src/Magnum/GL/Test/AttributeTest.cpp +++ b/src/Magnum/GL/Test/AttributeTest.cpp @@ -51,6 +51,7 @@ struct AttributeTest: TestSuite::Tester { #ifndef MAGNUM_TARGET_GLES2 void attributeMatrixMxN(); #endif + void attributeMatrixNxNCustomStride(); void attributeMatrixNxNd(); void attributeMatrixMxNd(); @@ -116,6 +117,7 @@ AttributeTest::AttributeTest() { #ifndef MAGNUM_TARGET_GLES2 &AttributeTest::attributeMatrixMxN, #endif + &AttributeTest::attributeMatrixNxNCustomStride, &AttributeTest::attributeMatrixNxNd, &AttributeTest::attributeMatrixMxNd, @@ -174,7 +176,7 @@ void AttributeTest::attributeScalar() { Attribute a; CORRADE_COMPARE(a.components(), Attribute::Components::One); CORRADE_VERIFY(!a.dataOptions()); - CORRADE_COMPARE(a.vectorSize(), 4); + CORRADE_COMPARE(a.vectorStride(), 4); CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); DynamicAttribute da{a}; @@ -185,7 +187,7 @@ void AttributeTest::attributeScalar() { /* Options */ Attribute b(Attribute::DataType::UnsignedShort, Attribute::DataOption::Normalized); - CORRADE_COMPARE(b.vectorSize(), 2); + CORRADE_COMPARE(b.vectorStride(), 2); CORRADE_VERIFY(b.dataOptions() <= Attribute::DataOption::Normalized); DynamicAttribute db{b}; @@ -203,7 +205,7 @@ void AttributeTest::attributeScalarInt() { /* Default constructor */ Attribute a; - CORRADE_COMPARE(a.vectorSize(), 4); + CORRADE_COMPARE(a.vectorStride(), 4); DynamicAttribute da{a}; CORRADE_COMPARE(da.kind(), DynamicAttribute::Kind::Integral); @@ -213,7 +215,7 @@ void AttributeTest::attributeScalarInt() { /* Options */ Attribute b(Attribute::DataType::Short); - CORRADE_COMPARE(b.vectorSize(), 2); + CORRADE_COMPARE(b.vectorStride(), 2); DynamicAttribute db{b}; CORRADE_COMPARE(db.kind(), DynamicAttribute::Kind::Integral); @@ -233,7 +235,7 @@ void AttributeTest::attributeScalarUnsignedInt() { /* Default constructor */ Attribute a; - CORRADE_COMPARE(a.vectorSize(), 4); + CORRADE_COMPARE(a.vectorStride(), 4); DynamicAttribute da{a}; CORRADE_COMPARE(da.kind(), DynamicAttribute::Kind::Integral); @@ -243,7 +245,7 @@ void AttributeTest::attributeScalarUnsignedInt() { /* Options */ Attribute b(Attribute::DataType::UnsignedByte); - CORRADE_COMPARE(b.vectorSize(), 1); + CORRADE_COMPARE(b.vectorStride(), 1); DynamicAttribute db{b}; CORRADE_COMPARE(db.kind(), DynamicAttribute::Kind::Integral); @@ -263,7 +265,7 @@ void AttributeTest::attributeScalarDouble() { /* Default constructor */ Attribute a; - CORRADE_COMPARE(a.vectorSize(), 8); + CORRADE_COMPARE(a.vectorStride(), 8); DynamicAttribute da{a}; CORRADE_COMPARE(da.kind(), DynamicAttribute::Kind::Long); @@ -283,7 +285,7 @@ void AttributeTest::attributeVector() { /* Default constructor */ Attribute a; CORRADE_COMPARE(a.components(), Attribute::Components::Three); - CORRADE_COMPARE(a.vectorSize(), 3*4); + CORRADE_COMPARE(a.vectorStride(), 3*4); CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); DynamicAttribute da{a}; @@ -296,7 +298,7 @@ void AttributeTest::attributeVector() { #ifndef MAGNUM_TARGET_GLES Attribute b(Attribute::Components::Two, Attribute::DataType::Double); CORRADE_COMPARE(b.components(), Attribute::Components::Two); - CORRADE_COMPARE(b.vectorSize(), 2*8); + CORRADE_COMPARE(b.vectorStride(), 2*8); DynamicAttribute db{b}; CORRADE_COMPARE(db.kind(), DynamicAttribute::Kind::Generic); @@ -306,7 +308,7 @@ void AttributeTest::attributeVector() { #else Attribute b(Attribute::Components::Two, Attribute::DataType::Float); CORRADE_COMPARE(b.components(), Attribute::Components::Two); - CORRADE_COMPARE(b.vectorSize(), 2*4); + CORRADE_COMPARE(b.vectorStride(), 2*4); DynamicAttribute db{b}; CORRADE_COMPARE(db.kind(), DynamicAttribute::Kind::Generic); @@ -325,7 +327,7 @@ void AttributeTest::attributeVectorInt() { /* Default constructor */ Attribute a; CORRADE_COMPARE(a.components(), Attribute::Components::Two); - CORRADE_COMPARE(a.vectorSize(), 2*4); + CORRADE_COMPARE(a.vectorStride(), 2*4); CORRADE_COMPARE(a.dataType(), Attribute::DataType::Int); DynamicAttribute da{a}; @@ -336,7 +338,7 @@ void AttributeTest::attributeVectorInt() { /* Options */ Attribute b(Attribute::Components::One, Attribute::DataType::Int); - CORRADE_COMPARE(b.vectorSize(), 4); + CORRADE_COMPARE(b.vectorStride(), 4); DynamicAttribute db{b}; CORRADE_COMPARE(db.kind(), DynamicAttribute::Kind::Integral); @@ -357,7 +359,7 @@ void AttributeTest::attributeVectorUnsignedInt() { /* Default constructor */ Attribute a; CORRADE_COMPARE(a.components(), Attribute::Components::Four); - CORRADE_COMPARE(a.vectorSize(), 4*4); + CORRADE_COMPARE(a.vectorStride(), 4*4); CORRADE_COMPARE(a.dataType(), Attribute::DataType::UnsignedInt); DynamicAttribute da{a}; @@ -368,7 +370,7 @@ void AttributeTest::attributeVectorUnsignedInt() { /* Options */ Attribute b(Attribute::Components::Three, Attribute::DataType::UnsignedShort); - CORRADE_COMPARE(b.vectorSize(), 3*2); + CORRADE_COMPARE(b.vectorStride(), 3*2); DynamicAttribute db{b}; CORRADE_COMPARE(db.kind(), DynamicAttribute::Kind::Integral); @@ -389,7 +391,7 @@ void AttributeTest::attributeVectorDouble() { /* Default constructor */ Attribute a; CORRADE_COMPARE(a.components(), Attribute::Components::Two); - CORRADE_COMPARE(a.vectorSize(), 2*8); + CORRADE_COMPARE(a.vectorStride(), 2*8); CORRADE_COMPARE(a.dataType(), Attribute::DataType::Double); DynamicAttribute da{a}; @@ -400,7 +402,7 @@ void AttributeTest::attributeVectorDouble() { /* Options */ Attribute b(Attribute::Components::One); - CORRADE_COMPARE(b.vectorSize(), 8); + CORRADE_COMPARE(b.vectorStride(), 8); DynamicAttribute db{b}; CORRADE_COMPARE(db.kind(), DynamicAttribute::Kind::Long); @@ -420,7 +422,7 @@ void AttributeTest::attributeVector4() { /* Custom type */ #ifndef MAGNUM_TARGET_GLES Attribute a(Attribute::DataType::UnsignedInt2101010Rev); - CORRADE_COMPARE(a.vectorSize(), 4); + CORRADE_COMPARE(a.vectorStride(), 4); DynamicAttribute da{a}; CORRADE_COMPARE(da.kind(), DynamicAttribute::Kind::Generic); @@ -429,7 +431,7 @@ void AttributeTest::attributeVector4() { CORRADE_COMPARE(da.dataType(), DynamicAttribute::DataType::UnsignedInt2101010Rev); #elif !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) Attribute a(Attribute::DataType::Half); - CORRADE_COMPARE(a.vectorSize(), 8); + CORRADE_COMPARE(a.vectorStride(), 8); DynamicAttribute da{a}; CORRADE_COMPARE(da.kind(), DynamicAttribute::Kind::Generic); @@ -438,7 +440,7 @@ void AttributeTest::attributeVector4() { CORRADE_COMPARE(da.dataType(), DynamicAttribute::DataType::Half); #else Attribute a(Attribute::DataType::Float); - CORRADE_COMPARE(a.vectorSize(), 16); + CORRADE_COMPARE(a.vectorStride(), 16); DynamicAttribute da{a}; CORRADE_COMPARE(da.kind(), DynamicAttribute::Kind::Generic); @@ -456,7 +458,7 @@ void AttributeTest::attributeVectorBGRA() { /* BGRA */ Attribute a(Attribute::Components::BGRA); - CORRADE_COMPARE(a.vectorSize(), 4*4); + CORRADE_COMPARE(a.vectorStride(), 4*4); DynamicAttribute da{a}; CORRADE_COMPARE(da.kind(), DynamicAttribute::Kind::Generic); @@ -476,7 +478,7 @@ void AttributeTest::attributeMatrixNxN() { /* Default constructor */ Attribute a; CORRADE_COMPARE(a.components(), Attribute::Components::Three); - CORRADE_COMPARE(a.vectorSize(), 3*4); + CORRADE_COMPARE(a.vectorStride(), 3*4); CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); DynamicAttribute da{a}; @@ -486,6 +488,36 @@ void AttributeTest::attributeMatrixNxN() { CORRADE_COMPARE(da.dataType(), DynamicAttribute::DataType::Float); } +void AttributeTest::attributeMatrixNxNCustomStride() { + typedef Attribute<3, Matrix3> Attribute; + CORRADE_VERIFY((std::is_same{})); + CORRADE_COMPARE(Attribute::VectorCount, 3); + + /* Default stride */ + Attribute a{Attribute::DataType::Short}; + CORRADE_COMPARE(a.components(), Attribute::Components::Three); + CORRADE_COMPARE(a.vectorStride(), 6); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Short); + + DynamicAttribute da{a}; + CORRADE_COMPARE(da.kind(), DynamicAttribute::Kind::Generic); + CORRADE_COMPARE(da.location(), 3); + CORRADE_COMPARE(da.components(), DynamicAttribute::Components::Three); + CORRADE_COMPARE(da.dataType(), DynamicAttribute::DataType::Short); + + /* Custom stride */ + Attribute b{8, Attribute::DataType::Short}; + CORRADE_COMPARE(b.components(), Attribute::Components::Three); + CORRADE_COMPARE(b.vectorStride(), 8); + CORRADE_COMPARE(b.dataType(), Attribute::DataType::Short); + + DynamicAttribute db{b}; + CORRADE_COMPARE(db.kind(), DynamicAttribute::Kind::Generic); + CORRADE_COMPARE(db.location(), 3); + CORRADE_COMPARE(db.components(), DynamicAttribute::Components::Three); + CORRADE_COMPARE(db.dataType(), DynamicAttribute::DataType::Short); +} + #ifndef MAGNUM_TARGET_GLES2 void AttributeTest::attributeMatrixMxN() { typedef Attribute<3, Matrix3x4> Attribute; @@ -495,7 +527,7 @@ void AttributeTest::attributeMatrixMxN() { /* Default constructor */ Attribute a; CORRADE_COMPARE(a.components(), Attribute::Components::Four); - CORRADE_COMPARE(a.vectorSize(), 4*4); + CORRADE_COMPARE(a.vectorStride(), 4*4); CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); DynamicAttribute da{a}; @@ -515,7 +547,7 @@ void AttributeTest::attributeMatrixNxNd() { /* Default constructor */ Attribute a; CORRADE_COMPARE(a.components(), Attribute::Components::Four); - CORRADE_COMPARE(a.vectorSize(), 4*8); + CORRADE_COMPARE(a.vectorStride(), 4*8); CORRADE_COMPARE(a.dataType(), Attribute::DataType::Double); DynamicAttribute da{a}; @@ -537,7 +569,7 @@ void AttributeTest::attributeMatrixMxNd() { /* Default constructor */ Attribute a; CORRADE_COMPARE(a.components(), Attribute::Components::Two); - CORRADE_COMPARE(a.vectorSize(), 2*8); + CORRADE_COMPARE(a.vectorStride(), 2*8); CORRADE_COMPARE(a.dataType(), Attribute::DataType::Double); DynamicAttribute da{a};