From 36210fe4e9c68a52dedc90548d90e77cf39a2228 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Sat, 29 Oct 2016 14:51:07 -0700 Subject: [core] Make attribute binding more similar to uniform binding --- src/mbgl/gl/attribute.cpp | 24 +++++++ src/mbgl/gl/attribute.hpp | 176 ++++++++++++++++++++++++++++++++++++++++------ src/mbgl/gl/context.cpp | 12 +--- src/mbgl/gl/drawable.hpp | 6 +- 4 files changed, 181 insertions(+), 37 deletions(-) create mode 100644 src/mbgl/gl/attribute.cpp (limited to 'src/mbgl/gl') diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp new file mode 100644 index 0000000000..81ab6ac2a5 --- /dev/null +++ b/src/mbgl/gl/attribute.cpp @@ -0,0 +1,24 @@ +#include +#include + +namespace mbgl { +namespace gl { + +void bindAttribute(AttributeLocation location, + std::size_t count, + DataType type, + std::size_t vertexSize, + std::size_t vertexOffset, + std::size_t attributeOffset) { + MBGL_CHECK_ERROR(glEnableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttribPointer( + location, + static_cast(count), + static_cast(type), + GL_FALSE, + static_cast(vertexSize), + reinterpret_cast(attributeOffset + (vertexSize * vertexOffset)))); +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index f270a250bb..e6ef5c7f89 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -4,43 +4,173 @@ #include #include +#include +#include +#include namespace mbgl { namespace gl { -template +template class Attribute { public: - Attribute(const char* name, const Shader& shader) - : location(shader.getAttributeLocation(name)) {} + using Type = T[N]; - AttributeLocation location; + class State { + public: + State(const char* name, const Shader& shader) + : location(shader.getAttributeLocation(name)) {} + + AttributeLocation location; + static constexpr std::size_t count = N; + static constexpr DataType type = DataTypeOf::value; + }; }; -class AttributeBinding { +#define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ + struct name_ : ::mbgl::gl::Attribute { static constexpr auto name = #name_; } + +namespace detail { + +// 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. + +template +class Vertex; + +template +class Vertex { public: - template - AttributeBinding(const T (Vertex::*)[N], const Attribute& attribute, std::integral_constant) - : location(attribute.location), - type(DataTypeOf::value), - count(N), - offset(O) { - static_assert(O % 4 == 0, "vertex attribute must be optimally aligned"); - static_assert(1 <= N && N <= 4, "count must be 1, 2, 3, or 4"); - } + typename A1::Type a1; + + using VertexType = Vertex; + static const std::size_t attributeOffsets[1]; +}; + +template +class Vertex { +public: + typename A1::Type a1; + typename A2::Type a2; + + using VertexType = Vertex; + static const std::size_t attributeOffsets[2]; +}; + +template +class Vertex { +public: + typename A1::Type a1; + typename A2::Type a2; + typename A3::Type a3; + + using VertexType = Vertex; + static const std::size_t attributeOffsets[3]; +}; + +template +class Vertex { +public: + typename A1::Type a1; + typename A2::Type a2; + typename A3::Type a3; + typename A4::Type a4; + + using VertexType = Vertex; + static const std::size_t attributeOffsets[4]; +}; + +template +class Vertex { +public: + typename A1::Type a1; + typename A2::Type a2; + typename A3::Type a3; + typename A4::Type a4; + typename A5::Type a5; + + using VertexType = Vertex; + static const std::size_t attributeOffsets[5]; +}; + +template +const std::size_t Vertex::attributeOffsets[1] = { + offsetof(VertexType, a1) +}; + +template +const std::size_t Vertex::attributeOffsets[2] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2) +}; + +template +const std::size_t Vertex::attributeOffsets[3] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2), + offsetof(VertexType, a3) +}; + +template +const std::size_t Vertex::attributeOffsets[4] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2), + offsetof(VertexType, a3), + offsetof(VertexType, a4) +}; - AttributeLocation location; - DataType type; - uint8_t count; - std::size_t offset; +template +const std::size_t Vertex::attributeOffsets[5] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2), + offsetof(VertexType, a3), + offsetof(VertexType, a4), + offsetof(VertexType, a5) }; -#define MBGL_MAKE_ATTRIBUTE_BINDING(Vertex, shader, name) \ - ::mbgl::gl::AttributeBinding(&Vertex::name, \ - shader.name, \ - std::integral_constant()) +} // namespace detail -template struct AttributeBindings; +void bindAttribute(AttributeLocation location, + std::size_t count, + DataType type, + std::size_t vertexSize, + std::size_t vertexOffset, + std::size_t attributeOffset); + +template +class Attributes { +public: + using State = std::tuple; + using Vertex = detail::Vertex; + + static State state(const Shader& shader) { + return State { { As::name, shader }... }; + } + + static std::function binder(const State& state) { + return binder(state, std::index_sequence_for()); + } + +private: + template + static std::function binder(const State& state, std::index_sequence) { + return [&state] (std::size_t vertexOffset) { + noop((bindAttribute(std::get(state).location, + std::get(state).count, + std::get(state).type, + sizeof(Vertex), + vertexOffset, + Vertex::attributeOffsets[Is]), 0)...); + }; + } + + // This exists only to provide a varags context for unpacking the assignments in `binder`. + template static void noop(int...) {} +}; } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index c63819bc03..f23dfe3dbe 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -486,17 +486,7 @@ void Context::draw(const Drawable& drawable) { if (needAttributeBindings()) { vertexBuffer = drawable.vertexBuffer; elementBuffer = drawable.indexBuffer; - - for (const auto& binding : drawable.attributeBindings) { - MBGL_CHECK_ERROR(glEnableVertexAttribArray(binding.location)); - MBGL_CHECK_ERROR(glVertexAttribPointer( - binding.location, - binding.count, - static_cast(binding.type), - GL_FALSE, - static_cast(drawable.vertexSize), - reinterpret_cast(binding.offset + (drawable.vertexSize * segment.vertexOffset)))); - } + drawable.bindAttributes(segment.vertexOffset); } if (drawable.indexBuffer) { diff --git a/src/mbgl/gl/drawable.hpp b/src/mbgl/gl/drawable.hpp index 4f2f11e2f1..be6b27bb83 100644 --- a/src/mbgl/gl/drawable.hpp +++ b/src/mbgl/gl/drawable.hpp @@ -100,10 +100,10 @@ public: primitiveSize(subject.primitiveSize), segments(subject.segments), bindUniforms(Shader::UniformsType::binder(shader.uniformsState, std::move(uniformValues))), - attributeBindings(AttributeBindings()(shader)) + bindAttributes(Shader::AttributesType::binder(shader.attributesState)) { static_assert(std::is_standard_layout::value, "vertex type must use standard layout"); - static_assert(std::is_same::value, "vertex type mismatch"); + static_assert(std::is_same::value, "vertex type mismatch"); } DrawMode drawMode; @@ -117,7 +117,7 @@ public: std::size_t primitiveSize; const std::vector& segments; std::function bindUniforms; - std::vector attributeBindings; + std::function bindAttributes; }; } // namespace gl -- cgit v1.2.1