From 2f646af255bf05bd50070deb83bb89e48509afc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 4 Mar 2019 13:09:51 +0100 Subject: [core] make vertex descriptors constexpr --- src/mbgl/gfx/attribute.hpp | 232 +++++++++++++++++++--------- src/mbgl/gfx/types.hpp | 39 +++++ src/mbgl/gl/attribute.hpp | 42 ++--- src/mbgl/gl/context.cpp | 8 - src/mbgl/gl/types.hpp | 10 -- src/mbgl/gl/value.cpp | 93 ++++++++++- src/mbgl/gl/vertex_buffer.hpp | 5 - src/mbgl/programs/collision_box_program.cpp | 2 +- src/mbgl/renderer/paint_property_binder.hpp | 31 ++-- 9 files changed, 310 insertions(+), 152 deletions(-) diff --git a/src/mbgl/gfx/attribute.hpp b/src/mbgl/gfx/attribute.hpp index 66bbf1ec5e..0dce6b2a06 100644 --- a/src/mbgl/gfx/attribute.hpp +++ b/src/mbgl/gfx/attribute.hpp @@ -1,9 +1,11 @@ #pragma once +#include #include #include #include +#include #include #define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ @@ -14,17 +16,69 @@ } \ } +#define MBGL_VERTEX_ALIGN __attribute__((aligned(4))) + namespace mbgl { namespace gfx { +namespace { + +template struct AttributeDataTypeOf; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; + +} // namespace + template class AttributeType { public: - using ValueType = T; + using ElementType = T; + static constexpr AttributeDataType DataType = AttributeDataTypeOf::value; static constexpr size_t Dimensions = N; using Value = std::array; }; +struct AttributeDescriptor { + AttributeDataType dataType; + uint8_t offset; +}; + +inline bool operator==(const AttributeDescriptor& lhs, const AttributeDescriptor& rhs) { + return lhs.dataType == rhs.dataType && lhs.offset == rhs.offset; +} + +struct VertexDescriptor { + uint8_t stride; + uint8_t count; + AttributeDescriptor attributes[5]; +}; + // Attribute binding requires member offsets. The only standard way to // obtain an offset is the offsetof macro. The offsetof macro has defined // behavior only for standard layout types. That rules out std::tuple and @@ -35,114 +89,138 @@ public: namespace detail { template -class Vertex; - -template <> -class Vertex<> { -public: - using VertexType = Vertex<>; -}; +struct Vertex; template -class Vertex { -public: - A1 a1; - - using VertexType = Vertex; - static const std::size_t attributeOffsets[1]; -}; +struct Vertex { + using Type = Vertex; + typename A1::Value a1; +} MBGL_VERTEX_ALIGN; template -class Vertex { -public: - A1 a1; - A2 a2; - - using VertexType = Vertex; - static const std::size_t attributeOffsets[2]; -}; +struct Vertex { + using Type = Vertex; + typename A1::Value a1; + typename A2::Value a2; +} MBGL_VERTEX_ALIGN; template -class Vertex { -public: - A1 a1; - A2 a2; - A3 a3; - - using VertexType = Vertex; - static const std::size_t attributeOffsets[3]; -}; +struct Vertex { + using Type = Vertex; + typename A1::Value a1; + typename A2::Value a2; + typename A3::Value a3; +} MBGL_VERTEX_ALIGN; template -class Vertex { -public: - A1 a1; - A2 a2; - A3 a3; - A4 a4; - - using VertexType = Vertex; - static const std::size_t attributeOffsets[4]; -}; +struct Vertex { + using Type = Vertex; + typename A1::Value a1; + typename A2::Value a2; + typename A3::Value a3; + typename A4::Value a4; +} MBGL_VERTEX_ALIGN; template -class Vertex { -public: - A1 a1; - A2 a2; - A3 a3; - A4 a4; - A5 a5; - - using VertexType = Vertex; - static const std::size_t attributeOffsets[5]; -}; +struct Vertex { + using Type = Vertex; + typename A1::Value a1; + typename A2::Value a2; + typename A3::Value a3; + typename A4::Value a4; + typename A5::Value a5; +} MBGL_VERTEX_ALIGN; + +template +struct Descriptor; template -const std::size_t Vertex::attributeOffsets[1] = { - offsetof(VertexType, a1) +struct Descriptor> { + using Type = Vertex; + static_assert(sizeof(Type) < 256, "vertex type must be smaller than 256 bytes"); + static_assert(std::is_standard_layout::value, "vertex type must use standard layout"); + static constexpr const VertexDescriptor data = { sizeof(Type), 1, { + { A1::DataType, offsetof(Type, a1) }, + }}; }; +template +constexpr const VertexDescriptor Descriptor>::data; + template -const std::size_t Vertex::attributeOffsets[2] = { - offsetof(VertexType, a1), - offsetof(VertexType, a2) +struct Descriptor> { + using Type = Vertex; + static_assert(sizeof(Type) < 256, "vertex type must be smaller than 256 bytes"); + static_assert(std::is_standard_layout::value, "vertex type must use standard layout"); + static constexpr const VertexDescriptor data = { sizeof(Type), 2, { + { A1::DataType, offsetof(Type, a1) }, + { A2::DataType, offsetof(Type, a2) }, + }}; }; +template +constexpr const VertexDescriptor Descriptor>::data; + template -const std::size_t Vertex::attributeOffsets[3] = { - offsetof(VertexType, a1), - offsetof(VertexType, a2), - offsetof(VertexType, a3) +struct Descriptor> { + using Type = Vertex; + static_assert(sizeof(Type) < 256, "vertex type must be smaller than 256 bytes"); + static_assert(std::is_standard_layout::value, "vertex type must use standard layout"); + static constexpr const VertexDescriptor data = { sizeof(Type), 3, { + { A1::DataType, offsetof(Type, a1) }, + { A2::DataType, offsetof(Type, a2) }, + { A3::DataType, offsetof(Type, a3) }, + }}; }; +template +constexpr const VertexDescriptor Descriptor>::data; + template -const std::size_t Vertex::attributeOffsets[4] = { - offsetof(VertexType, a1), - offsetof(VertexType, a2), - offsetof(VertexType, a3), - offsetof(VertexType, a4) +struct Descriptor> { + using Type = Vertex; + static_assert(sizeof(Type) < 256, "vertex type must be smaller than 256 bytes"); + static_assert(std::is_standard_layout::value, "vertex type must use standard layout"); + static constexpr const VertexDescriptor data = { sizeof(Type), 4, { + { A1::DataType, offsetof(Type, a1) }, + { A2::DataType, offsetof(Type, a2) }, + { A3::DataType, offsetof(Type, a3) }, + { A4::DataType, offsetof(Type, a4) }, + }}; }; +template +constexpr const VertexDescriptor Descriptor>::data; + template -const std::size_t Vertex::attributeOffsets[5] = { - offsetof(VertexType, a1), - offsetof(VertexType, a2), - offsetof(VertexType, a3), - offsetof(VertexType, a4), - offsetof(VertexType, a5) +struct Descriptor> { + using Type = Vertex; + static_assert(sizeof(Type) < 256, "vertex type must be smaller than 256 bytes"); + static_assert(std::is_standard_layout::value, "vertex type must use standard layout"); + static constexpr const VertexDescriptor data = { sizeof(Type), 5, { + { A1::DataType, offsetof(Type, a1) }, + { A2::DataType, offsetof(Type, a2) }, + { A3::DataType, offsetof(Type, a3) }, + { A4::DataType, offsetof(Type, a4) }, + { A5::DataType, offsetof(Type, a5) }, + }}; }; +template +constexpr const VertexDescriptor Descriptor>::data; + template -class Vertex> { -public: - using VertexType = Vertex; +struct Vertex> { + using Type = Vertex; }; } // namespace detail template -using Vertex = typename detail::Vertex::VertexType; +using Vertex = typename detail::Vertex::Type; + +template +using VertexDescriptorOf = detail::Descriptor; } // namespace gfx } // namespace mbgl diff --git a/src/mbgl/gfx/types.hpp b/src/mbgl/gfx/types.hpp index d1421dddb7..a9cb4e1ece 100644 --- a/src/mbgl/gfx/types.hpp +++ b/src/mbgl/gfx/types.hpp @@ -15,6 +15,45 @@ enum class PrimitiveType : uint8_t { TriangleFan, }; +enum class AttributeDataType : uint8_t { + Byte, + Byte2, + Byte3, + Byte4, + + UByte, + UByte2, + UByte3, + UByte4, + + Short, + Short2, + Short3, + Short4, + + UShort, + UShort2, + UShort3, + UShort4, + + Int, + Int2, + Int3, + Int4, + + UInt, + UInt2, + UInt3, + UInt4, + + Float, + Float2, + Float3, + Float4, + + Invalid = 255, +}; + enum class ColorBlendEquationType : uint8_t { Add, Subtract, diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index 95a9942381..53ba71a89f 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -18,29 +18,17 @@ namespace mbgl { namespace gl { -template struct DataTypeOf; -template <> struct DataTypeOf< int8_t> : std::integral_constant {}; -template <> struct DataTypeOf : std::integral_constant {}; -template <> struct DataTypeOf< int16_t> : std::integral_constant {}; -template <> struct DataTypeOf : std::integral_constant {}; -template <> struct DataTypeOf< int32_t> : std::integral_constant {}; -template <> struct DataTypeOf : std::integral_constant {}; -template <> struct DataTypeOf : std::integral_constant {}; - class AttributeBinding { public: - DataType attributeType; - uint8_t attributeSize; - uint32_t attributeOffset; - + gfx::AttributeDescriptor attribute; + uint8_t vertexStride; BufferID vertexBuffer; - uint32_t vertexSize; uint32_t vertexOffset; friend bool operator==(const AttributeBinding& lhs, const AttributeBinding& rhs) { - return std::tie(lhs.attributeType, lhs.attributeSize, lhs.attributeOffset, lhs.vertexBuffer, lhs.vertexSize, lhs.vertexOffset) - == std::tie(rhs.attributeType, rhs.attributeSize, rhs.attributeOffset, rhs.vertexBuffer, rhs.vertexSize, rhs.vertexOffset); + return std::tie(lhs.attribute, lhs.vertexStride, lhs.vertexBuffer, lhs.vertexOffset) + == std::tie(rhs.attribute, rhs.vertexStride, rhs.vertexBuffer, rhs.vertexOffset); } }; @@ -51,21 +39,13 @@ using AttributeBindingArray = std::vector>; override the number of components available in the buffer for each vertex. Thus, a buffer with only one float for each vertex can be bound to a `vec2` attribute */ -template -AttributeBinding attributeBinding(const VertexBuffer& buffer, - std::size_t attributeIndex, - std::size_t attributeSize = AttributeType::Dimensions) { - static_assert(std::is_standard_layout::value, "vertex type must use standard layout"); - assert(attributeSize >= 1); - assert(attributeSize <= 4); - assert(Vertex::attributeOffsets[attributeIndex] <= std::numeric_limits::max()); - static_assert(sizeof(Vertex) <= std::numeric_limits::max(), "vertex too large"); - return AttributeBinding { - DataTypeOf::value, - static_cast(attributeSize), - static_cast(Vertex::attributeOffsets[attributeIndex]), +template +AttributeBinding attributeBinding(const VertexBuffer& buffer) { + static_assert(I < gfx::VertexDescriptorOf::data.count, "vertex attribute index out of range"); + return { + gfx::VertexDescriptorOf::data.attributes[I], + gfx::VertexDescriptorOf::data.stride, buffer.buffer, - static_cast(sizeof(Vertex)), 0, }; } @@ -127,7 +107,7 @@ public: } static Bindings bindings(const VertexBuffer>& buffer) { - return Bindings { attributeBinding(buffer, TypeIndex::value)... }; + return Bindings { attributeBinding::value>(buffer)... }; } static Bindings offsetBindings(const Bindings& bindings, std::size_t vertexOffset) { diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index bcbb3ab66c..72d59737f3 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -17,14 +17,6 @@ using namespace platform; static_assert(underlying_type(ShaderType::Vertex) == GL_VERTEX_SHADER, "OpenGL type mismatch"); static_assert(underlying_type(ShaderType::Fragment) == GL_FRAGMENT_SHADER, "OpenGL type mismatch"); -static_assert(underlying_type(DataType::Byte) == GL_BYTE, "OpenGL type mismatch"); -static_assert(underlying_type(DataType::UnsignedByte) == GL_UNSIGNED_BYTE, "OpenGL type mismatch"); -static_assert(underlying_type(DataType::Short) == GL_SHORT, "OpenGL type mismatch"); -static_assert(underlying_type(DataType::UnsignedShort) == GL_UNSIGNED_SHORT, "OpenGL type mismatch"); -static_assert(underlying_type(DataType::Integer) == GL_INT, "OpenGL type mismatch"); -static_assert(underlying_type(DataType::UnsignedInteger) == GL_UNSIGNED_INT, "OpenGL type mismatch"); -static_assert(underlying_type(DataType::Float) == GL_FLOAT, "OpenGL type mismatch"); - #if not MBGL_USE_GLES2 static_assert(underlying_type(RenderbufferType::RGBA) == GL_RGBA8, "OpenGL type mismatch"); #else diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 4c3033454f..22b7098100 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -32,16 +32,6 @@ enum class ShaderType : uint32_t { Fragment = 0x8B30 }; -enum class DataType : uint16_t { - Byte = 0x1400, - UnsignedByte = 0x1401, - Short = 0x1402, - UnsignedShort = 0x1403, - Integer = 0x1404, - UnsignedInteger = 0x1405, - Float = 0x1406 -}; - enum class RenderbufferType : uint32_t { RGBA = 0x8058, DepthStencil = 0x88F0, diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp index 4e56686103..b290cde50c 100644 --- a/src/mbgl/gl/value.cpp +++ b/src/mbgl/gl/value.cpp @@ -398,17 +398,102 @@ BindVertexArray::Type BindVertexArray::Get(const Context& context) { const optional VertexAttribute::Default {}; +namespace { + +GLenum vertexType(const gfx::AttributeDataType type) { + switch (type) { + case gfx::AttributeDataType::Byte: + case gfx::AttributeDataType::Byte2: + case gfx::AttributeDataType::Byte3: + case gfx::AttributeDataType::Byte4: + return GL_BYTE; + case gfx::AttributeDataType::UByte: + case gfx::AttributeDataType::UByte2: + case gfx::AttributeDataType::UByte3: + case gfx::AttributeDataType::UByte4: + return GL_UNSIGNED_BYTE; + case gfx::AttributeDataType::Short: + case gfx::AttributeDataType::Short2: + case gfx::AttributeDataType::Short3: + case gfx::AttributeDataType::Short4: + return GL_SHORT; + case gfx::AttributeDataType::UShort: + case gfx::AttributeDataType::UShort2: + case gfx::AttributeDataType::UShort3: + case gfx::AttributeDataType::UShort4: + return GL_UNSIGNED_SHORT; + case gfx::AttributeDataType::Int: + case gfx::AttributeDataType::Int2: + case gfx::AttributeDataType::Int3: + case gfx::AttributeDataType::Int4: + return GL_INT; + case gfx::AttributeDataType::UInt: + case gfx::AttributeDataType::UInt2: + case gfx::AttributeDataType::UInt3: + case gfx::AttributeDataType::UInt4: + return GL_UNSIGNED_INT; + case gfx::AttributeDataType::Float: + case gfx::AttributeDataType::Float2: + case gfx::AttributeDataType::Float3: + case gfx::AttributeDataType::Float4: + return GL_FLOAT; + default: + return GL_FLOAT; + } +} + +GLint components(const gfx::AttributeDataType type) { + switch (type) { + case gfx::AttributeDataType::Byte: + case gfx::AttributeDataType::UByte: + case gfx::AttributeDataType::Short: + case gfx::AttributeDataType::UShort: + case gfx::AttributeDataType::Int: + case gfx::AttributeDataType::UInt: + case gfx::AttributeDataType::Float: + return 1; + case gfx::AttributeDataType::Byte2: + case gfx::AttributeDataType::UByte2: + case gfx::AttributeDataType::Short2: + case gfx::AttributeDataType::UShort2: + case gfx::AttributeDataType::Int2: + case gfx::AttributeDataType::UInt2: + case gfx::AttributeDataType::Float2: + return 2; + case gfx::AttributeDataType::Byte3: + case gfx::AttributeDataType::UByte3: + case gfx::AttributeDataType::Short3: + case gfx::AttributeDataType::UShort3: + case gfx::AttributeDataType::Int3: + case gfx::AttributeDataType::UInt3: + case gfx::AttributeDataType::Float3: + return 3; + case gfx::AttributeDataType::Byte4: + case gfx::AttributeDataType::UByte4: + case gfx::AttributeDataType::Short4: + case gfx::AttributeDataType::UShort4: + case gfx::AttributeDataType::Int4: + case gfx::AttributeDataType::UInt4: + case gfx::AttributeDataType::Float4: + return 4; + default: + return 0; + } +} + +} // namespace + void VertexAttribute::Set(const optional& binding, Context& context, AttributeLocation location) { if (binding) { context.vertexBuffer = binding->vertexBuffer; MBGL_CHECK_ERROR(glEnableVertexAttribArray(location)); MBGL_CHECK_ERROR(glVertexAttribPointer( location, - static_cast(binding->attributeSize), - static_cast(binding->attributeType), + components(binding->attribute.dataType), + vertexType(binding->attribute.dataType), static_cast(false), - static_cast(binding->vertexSize), - reinterpret_cast(binding->attributeOffset + (binding->vertexSize * binding->vertexOffset)))); + static_cast(binding->vertexStride), + reinterpret_cast(binding->attribute.offset + (binding->vertexStride * binding->vertexOffset)))); } else { MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); } diff --git a/src/mbgl/gl/vertex_buffer.hpp b/src/mbgl/gl/vertex_buffer.hpp index 0b62b86c12..b65e7f9a01 100644 --- a/src/mbgl/gl/vertex_buffer.hpp +++ b/src/mbgl/gl/vertex_buffer.hpp @@ -2,17 +2,12 @@ #include -#include - namespace mbgl { namespace gl { template class VertexBuffer { public: - using Vertex = V; - static constexpr std::size_t vertexSize = sizeof(Vertex); - std::size_t vertexCount; UniqueBuffer buffer; }; diff --git a/src/mbgl/programs/collision_box_program.cpp b/src/mbgl/programs/collision_box_program.cpp index 57107db75d..869f4be61f 100644 --- a/src/mbgl/programs/collision_box_program.cpp +++ b/src/mbgl/programs/collision_box_program.cpp @@ -2,6 +2,6 @@ namespace mbgl { -static_assert(sizeof(CollisionBoxProgram::LayoutVertex) == 14, "expected CollisionBoxVertex size"); +static_assert(sizeof(CollisionBoxProgram::LayoutVertex) == 16, "expected CollisionBoxVertex size"); } // namespace mbgl diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 874fab5add..cbf60ea679 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -25,7 +25,7 @@ namespace mbgl { being zoomed. */ template -using ZoomInterpolatedAttributeType = gfx::AttributeType; +using ZoomInterpolatedAttributeType = gfx::AttributeType; inline std::array attributeValue(float v) { return {{ v }}; @@ -174,8 +174,7 @@ template class SourceFunctionPaintPropertyBinder : public PaintPropertyBinder, A> { public: using BaseAttributeType = A; - using BaseAttributeValue = typename A::Value; - using BaseVertex = gfx::Vertex; + using BaseVertex = gfx::Vertex; using AttributeType = ZoomInterpolatedAttributeType; @@ -201,7 +200,9 @@ public: if (currentValue.isConstant()) { return {}; } else { - return std::tuple> { gl::attributeBinding(*vertexBuffer, 0, BaseAttributeType::Dimensions) }; + return std::tuple>{ + gl::attributeBinding<0>(*vertexBuffer) + }; } } @@ -231,7 +232,7 @@ public: using AttributeType = ZoomInterpolatedAttributeType; using AttributeValue = typename AttributeType::Value; - using Vertex = gfx::Vertex; + using Vertex = gfx::Vertex; CompositeFunctionPaintPropertyBinder(style::PropertyExpression expression_, float zoom, T defaultValue_) : expression(std::move(expression_)), @@ -259,7 +260,9 @@ public: if (currentValue.isConstant()) { return {}; } else { - return std::tuple> { gl::attributeBinding(*vertexBuffer, 0) }; + return std::tuple>{ + gl::attributeBinding<0>(*vertexBuffer) + }; } } @@ -295,13 +298,10 @@ public: using AttributeType2 = ZoomInterpolatedAttributeType; using BaseAttributeType = A1; - using BaseAttributeValue = typename BaseAttributeType::Value; - using BaseAttributeType2 = A2; - using BaseAttributeValue2 = typename BaseAttributeType2::Value; - using Vertex = gfx::Vertex; - using Vertex2 = gfx::Vertex; + using Vertex = gfx::Vertex; + using Vertex2 = gfx::Vertex; CompositeCrossFadedPaintPropertyBinder(style::PropertyExpression expression_, float zoom, T defaultValue_) : expression(std::move(expression_)), @@ -354,11 +354,10 @@ public: if (currentValue.isConstant()) { return {}; } else { - return std::tuple, optional> { - gl::attributeBinding(*patternToVertexBuffer, 0, BaseAttributeType::Dimensions), - gl::attributeBinding( - crossfade.fromScale == 2 ? *zoomInVertexBuffer : *zoomOutVertexBuffer, - 0, BaseAttributeType2::Dimensions) }; + return std::tuple, optional>{ + gl::attributeBinding<0>(*patternToVertexBuffer), + gl::attributeBinding<0>(crossfade.fromScale == 2 ? *zoomInVertexBuffer : *zoomOutVertexBuffer) + }; } } -- cgit v1.2.1