#pragma once #include #include #include #include #include #include #include #include #include #define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ struct name_ { \ using Type = ::mbgl::gfx::AttributeType; \ static constexpr auto name() { \ return #name_; \ } \ } #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 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]; }; class AttributeBinding { public: AttributeDescriptor attribute; uint8_t vertexStride; const VertexBufferResource* vertexBufferResource; uint32_t vertexOffset; friend bool operator==(const AttributeBinding& lhs, const AttributeBinding& rhs) { return lhs.attribute == rhs.attribute && lhs.vertexStride == rhs.vertexStride && lhs.vertexBufferResource == rhs.vertexBufferResource && lhs.vertexOffset == rhs.vertexOffset; } }; // 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 // any other solution that relies on chained inheritance. Manually implemented // variadic specialization looks like the only solution. Fortunately, we // only use a maximum of five attributes. namespace detail { template struct VertexType; template struct VertexType { using Type = VertexType; typename A1::Value a1; } MBGL_VERTEX_ALIGN; template struct VertexType { using Type = VertexType; typename A1::Value a1; typename A2::Value a2; } MBGL_VERTEX_ALIGN; template struct VertexType { using Type = VertexType; typename A1::Value a1; typename A2::Value a2; typename A3::Value a3; } MBGL_VERTEX_ALIGN; template struct VertexType { using Type = VertexType; typename A1::Value a1; typename A2::Value a2; typename A3::Value a3; typename A4::Value a4; } MBGL_VERTEX_ALIGN; template struct VertexType { using Type = VertexType; 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 struct Descriptor> { using Type = VertexType; 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 struct Descriptor> { using Type = VertexType; 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 struct Descriptor> { using Type = VertexType; 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 struct Descriptor> { using Type = VertexType; 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 struct Descriptor> { using Type = VertexType; 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 struct Vertex; template struct Vertex> { using Type = VertexType; }; } // namespace detail template using Vertex = typename detail::Vertex::Type; template using VertexType = typename detail::VertexType; template AttributeBinding attributeBinding(const VertexBuffer>& buffer) { using Descriptor = detail::Descriptor>; static_assert(I < Descriptor::data.count, "attribute index must be in range"); return { Descriptor::data.attributes[I], Descriptor::data.stride, &buffer.getResource(), 0, }; } optional offsetAttributeBinding(const optional& binding, std::size_t vertexOffset); template class AttributeBindings; template class AttributeBindings> final : public IndexedTuple, TypeList>...>> { using Base = IndexedTuple, TypeList>...>>; public: AttributeBindings(const VertexBuffer>>& buffer) : Base{ attributeBinding::value>(buffer)... } { } template AttributeBindings(Args&&... args) : Base(std::forward(args)...) { } AttributeBindings offset(const std::size_t vertexOffset) const { return { offsetAttributeBinding(Base::template get(), vertexOffset)... }; } uint32_t activeCount() const { uint32_t result = 0; util::ignore({ ((result += bool(Base::template get())), 0)... }); return result; } }; } // namespace gfx } // namespace mbgl