1 #pragma once 2 3 #include <mbgl/gl/types.hpp> 4 #include <mbgl/gl/vertex_buffer.hpp> 5 #include <mbgl/util/ignore.hpp> 6 #include <mbgl/util/indexed_tuple.hpp> 7 #include <mbgl/util/optional.hpp> 8 9 #include <cstddef> 10 #include <vector> 11 #include <set> 12 #include <functional> 13 #include <string> 14 #include <array> 15 #include <limits> 16 17 namespace mbgl { 18 namespace gl { 19 20 template <class> struct DataTypeOf; 21 template <> struct DataTypeOf< int8_t> : std::integral_constant<DataType, DataType::Byte> {}; 22 template <> struct DataTypeOf<uint8_t> : std::integral_constant<DataType, DataType::UnsignedByte> {}; 23 template <> struct DataTypeOf< int16_t> : std::integral_constant<DataType, DataType::Short> {}; 24 template <> struct DataTypeOf<uint16_t> : std::integral_constant<DataType, DataType::UnsignedShort> {}; 25 template <> struct DataTypeOf< int32_t> : std::integral_constant<DataType, DataType::Integer> {}; 26 template <> struct DataTypeOf<uint32_t> : std::integral_constant<DataType, DataType::UnsignedInteger> {}; 27 template <> struct DataTypeOf<float> : std::integral_constant<DataType, DataType::Float> {}; 28 29 class AttributeBinding { 30 public: 31 DataType attributeType; 32 uint8_t attributeSize; 33 uint32_t attributeOffset; 34 35 BufferID vertexBuffer; 36 uint32_t vertexSize; 37 uint32_t vertexOffset; 38 operator ==(const AttributeBinding & lhs,const AttributeBinding & rhs)39 friend bool operator==(const AttributeBinding& lhs, 40 const AttributeBinding& rhs) { 41 return std::tie(lhs.attributeType, lhs.attributeSize, lhs.attributeOffset, lhs.vertexBuffer, lhs.vertexSize, lhs.vertexOffset) 42 == std::tie(rhs.attributeType, rhs.attributeSize, rhs.attributeOffset, rhs.vertexBuffer, rhs.vertexSize, rhs.vertexOffset); 43 } 44 }; 45 46 using AttributeBindingArray = std::vector<optional<AttributeBinding>>; 47 48 /* 49 gl::Attribute<T,N> manages the binding of a vertex buffer to a GL program attribute. 50 - T is the underlying primitive type (exposed as Attribute<T,N>::ValueType) 51 - N is the number of components in the attribute declared in the shader (exposed as Attribute<T,N>::Dimensions) 52 */ 53 template <class T, std::size_t N> 54 class Attribute { 55 public: 56 using ValueType = T; 57 static constexpr size_t Dimensions = N; 58 using Value = std::array<T, N>; 59 60 using Location = AttributeLocation; 61 using Binding = AttributeBinding; 62 63 /* 64 Create a binding for this attribute. The `attributeSize` parameter may be used to 65 override the number of components available in the buffer for each vertex. Thus, 66 a buffer with only one float for each vertex can be bound to a `vec2` attribute 67 */ 68 template <class Vertex, class DrawMode> binding(const VertexBuffer<Vertex,DrawMode> & buffer,std::size_t attributeIndex,std::size_t attributeSize=N)69 static Binding binding(const VertexBuffer<Vertex, DrawMode>& buffer, 70 std::size_t attributeIndex, 71 std::size_t attributeSize = N) { 72 static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout"); 73 assert(attributeSize >= 1); 74 assert(attributeSize <= 4); 75 assert(Vertex::attributeOffsets[attributeIndex] <= std::numeric_limits<uint32_t>::max()); 76 static_assert(sizeof(Vertex) <= std::numeric_limits<uint32_t>::max(), "vertex too large"); 77 return AttributeBinding { 78 DataTypeOf<T>::value, 79 static_cast<uint8_t>(attributeSize), 80 static_cast<uint32_t>(Vertex::attributeOffsets[attributeIndex]), 81 buffer.buffer, 82 static_cast<uint32_t>(sizeof(Vertex)), 83 0, 84 }; 85 } 86 offsetBinding(const optional<Binding> & binding,std::size_t vertexOffset)87 static optional<Binding> offsetBinding(const optional<Binding>& binding, std::size_t vertexOffset) { 88 assert(vertexOffset <= std::numeric_limits<uint32_t>::max()); 89 if (binding) { 90 AttributeBinding result = *binding; 91 result.vertexOffset = static_cast<uint32_t>(vertexOffset); 92 return result; 93 } else { 94 return binding; 95 } 96 } 97 }; 98 99 #define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ 100 struct name_ { \ 101 static auto name() { return #name_; } \ 102 using Type = ::mbgl::gl::Attribute<type_, n_>; \ 103 } 104 105 namespace detail { 106 107 // Attribute binding requires member offsets. The only standard way to 108 // obtain an offset is the offsetof macro. The offsetof macro has defined 109 // behavior only for standard layout types. That rules out std::tuple and 110 // any other solution that relies on chained inheritance. Manually implemented 111 // variadic specialization looks like the only solution. Fortunately, we 112 // only use a maximum of five attributes. 113 114 template <class... As> 115 class Vertex; 116 117 template <> 118 class Vertex<> { 119 public: 120 using VertexType = Vertex<>; 121 }; 122 123 template <class A1> 124 class Vertex<A1> { 125 public: 126 typename A1::Value a1; 127 128 using VertexType = Vertex<A1>; 129 static const std::size_t attributeOffsets[1]; 130 }; 131 132 template <class A1, class A2> 133 class Vertex<A1, A2> { 134 public: 135 typename A1::Value a1; 136 typename A2::Value a2; 137 138 using VertexType = Vertex<A1, A2>; 139 static const std::size_t attributeOffsets[2]; 140 }; 141 142 template <class A1, class A2, class A3> 143 class Vertex<A1, A2, A3> { 144 public: 145 typename A1::Value a1; 146 typename A2::Value a2; 147 typename A3::Value a3; 148 149 using VertexType = Vertex<A1, A2, A3>; 150 static const std::size_t attributeOffsets[3]; 151 }; 152 153 template <class A1, class A2, class A3, class A4> 154 class Vertex<A1, A2, A3, A4> { 155 public: 156 typename A1::Value a1; 157 typename A2::Value a2; 158 typename A3::Value a3; 159 typename A4::Value a4; 160 161 using VertexType = Vertex<A1, A2, A3, A4>; 162 static const std::size_t attributeOffsets[4]; 163 }; 164 165 template <class A1, class A2, class A3, class A4, class A5> 166 class Vertex<A1, A2, A3, A4, A5> { 167 public: 168 typename A1::Value a1; 169 typename A2::Value a2; 170 typename A3::Value a3; 171 typename A4::Value a4; 172 typename A5::Value a5; 173 174 using VertexType = Vertex<A1, A2, A3, A4, A5>; 175 static const std::size_t attributeOffsets[5]; 176 }; 177 178 template <class A1> 179 const std::size_t Vertex<A1>::attributeOffsets[1] = { 180 offsetof(VertexType, a1) 181 }; 182 183 template <class A1, class A2> 184 const std::size_t Vertex<A1, A2>::attributeOffsets[2] = { 185 offsetof(VertexType, a1), 186 offsetof(VertexType, a2) 187 }; 188 189 template <class A1, class A2, class A3> 190 const std::size_t Vertex<A1, A2, A3>::attributeOffsets[3] = { 191 offsetof(VertexType, a1), 192 offsetof(VertexType, a2), 193 offsetof(VertexType, a3) 194 }; 195 196 template <class A1, class A2, class A3, class A4> 197 const std::size_t Vertex<A1, A2, A3, A4>::attributeOffsets[4] = { 198 offsetof(VertexType, a1), 199 offsetof(VertexType, a2), 200 offsetof(VertexType, a3), 201 offsetof(VertexType, a4) 202 }; 203 204 template <class A1, class A2, class A3, class A4, class A5> 205 const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = { 206 offsetof(VertexType, a1), 207 offsetof(VertexType, a2), 208 offsetof(VertexType, a3), 209 offsetof(VertexType, a4), 210 offsetof(VertexType, a5) 211 }; 212 213 } // namespace detail 214 215 class Context; 216 void bindAttributeLocation(Context&, ProgramID, AttributeLocation, const char * name); 217 std::set<std::string> getActiveAttributes(ProgramID); 218 219 template <class... As> 220 class Attributes { 221 public: 222 using Types = TypeList<As...>; 223 using Locations = IndexedTuple< 224 TypeList<As...>, 225 TypeList<optional<typename As::Type::Location>...>>; 226 using Bindings = IndexedTuple< 227 TypeList<As...>, 228 TypeList<optional<typename As::Type::Binding>...>>; 229 using NamedLocations = std::vector<std::pair<const std::string, AttributeLocation>>; 230 231 using Vertex = detail::Vertex<typename As::Type...>; 232 bindLocations(Context & context,const ProgramID & id)233 static Locations bindLocations(Context& context, const ProgramID& id) { 234 std::set<std::string> activeAttributes = getActiveAttributes(id); 235 236 AttributeLocation location = 0; 237 auto maybeBindLocation = [&](const char* name) -> optional<AttributeLocation> { 238 if (activeAttributes.count(name)) { 239 bindAttributeLocation(context, id, location, name); 240 return location++; 241 } else { 242 return {}; 243 } 244 }; 245 246 return Locations { maybeBindLocation(As::name())... }; 247 } 248 249 template <class Program> loadNamedLocations(const Program & program)250 static Locations loadNamedLocations(const Program& program) { 251 return Locations{ program.attributeLocation(As::name())... }; 252 } 253 getNamedLocations(const Locations & locations)254 static NamedLocations getNamedLocations(const Locations& locations) { 255 NamedLocations result; 256 257 auto maybeAddLocation = [&] (const std::string& name, const optional<AttributeLocation>& location) { 258 if (location) { 259 result.emplace_back(name, *location); 260 } 261 }; 262 263 util::ignore({ (maybeAddLocation(As::name(), locations.template get<As>()), 0)... }); 264 265 return result; 266 } 267 268 template <class DrawMode> bindings(const VertexBuffer<Vertex,DrawMode> & buffer)269 static Bindings bindings(const VertexBuffer<Vertex, DrawMode>& buffer) { 270 return Bindings { As::Type::binding(buffer, TypeIndex<As, As...>::value)... }; 271 } 272 offsetBindings(const Bindings & bindings,std::size_t vertexOffset)273 static Bindings offsetBindings(const Bindings& bindings, std::size_t vertexOffset) { 274 return Bindings { As::Type::offsetBinding(bindings.template get<As>(), vertexOffset)... }; 275 } 276 toBindingArray(const Locations & locations,const Bindings & bindings)277 static AttributeBindingArray toBindingArray(const Locations& locations, const Bindings& bindings) { 278 AttributeBindingArray result; 279 result.resize(sizeof...(As)); 280 281 auto maybeAddBinding = [&] (const optional<AttributeLocation>& location, 282 const optional<AttributeBinding>& binding) { 283 if (location) { 284 result.at(*location) = binding; 285 } 286 }; 287 288 util::ignore({ (maybeAddBinding(locations.template get<As>(), bindings.template get<As>()), 0)... }); 289 290 return result; 291 } 292 activeBindingCount(const Bindings & bindings)293 static uint32_t activeBindingCount(const Bindings& bindings) { 294 uint32_t result = 0; 295 util::ignore({ ((result += bool(bindings.template get<As>())), 0)... }); 296 return result; 297 } 298 }; 299 300 namespace detail { 301 302 template <class...> 303 struct ConcatenateAttributes; 304 305 template <class... As, class... Bs> 306 struct ConcatenateAttributes<TypeList<As...>, TypeList<Bs...>> { 307 using Type = Attributes<As..., Bs...>; 308 }; 309 310 } // namespace detail 311 312 template <class A, class B> 313 using ConcatenateAttributes = typename detail::ConcatenateAttributes< 314 typename A::Types, 315 typename B::Types>::Type; 316 317 } // namespace gl 318 } // namespace mbgl 319