summaryrefslogtreecommitdiff
path: root/src/mbgl/gl
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-10-29 14:51:07 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-11-08 08:09:28 -0800
commit36210fe4e9c68a52dedc90548d90e77cf39a2228 (patch)
treebe6f8e5c84f98094a372fc7518a5384fd37563bc /src/mbgl/gl
parent687ee1e1c92275f65469412591ff262b46e7ccd9 (diff)
downloadqtlocation-mapboxgl-36210fe4e9c68a52dedc90548d90e77cf39a2228.tar.gz
[core] Make attribute binding more similar to uniform binding
Diffstat (limited to 'src/mbgl/gl')
-rw-r--r--src/mbgl/gl/attribute.cpp24
-rw-r--r--src/mbgl/gl/attribute.hpp176
-rw-r--r--src/mbgl/gl/context.cpp12
-rw-r--r--src/mbgl/gl/drawable.hpp6
4 files changed, 181 insertions, 37 deletions
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 <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/gl.hpp>
+
+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<GLint>(count),
+ static_cast<GLenum>(type),
+ GL_FALSE,
+ static_cast<GLsizei>(vertexSize),
+ reinterpret_cast<GLvoid*>(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 <mbgl/gl/shader.hpp>
#include <cstddef>
+#include <functional>
+#include <tuple>
+#include <utility>
namespace mbgl {
namespace gl {
-template <typename T, std::size_t N>
+template <class Tag, class T, std::size_t N>
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<T>::value;
+ };
};
-class AttributeBinding {
+#define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \
+ struct name_ : ::mbgl::gl::Attribute<name_, type_, n_> { 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... As>
+class Vertex;
+
+template <class A1>
+class Vertex<A1> {
public:
- template <class Vertex, class T, std::size_t N, std::size_t O>
- AttributeBinding(const T (Vertex::*)[N], const Attribute<T, N>& attribute, std::integral_constant<std::size_t, O>)
- : location(attribute.location),
- type(DataTypeOf<T>::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<A1>;
+ static const std::size_t attributeOffsets[1];
+};
+
+template <class A1, class A2>
+class Vertex<A1, A2> {
+public:
+ typename A1::Type a1;
+ typename A2::Type a2;
+
+ using VertexType = Vertex<A1, A2>;
+ static const std::size_t attributeOffsets[2];
+};
+
+template <class A1, class A2, class A3>
+class Vertex<A1, A2, A3> {
+public:
+ typename A1::Type a1;
+ typename A2::Type a2;
+ typename A3::Type a3;
+
+ using VertexType = Vertex<A1, A2, A3>;
+ static const std::size_t attributeOffsets[3];
+};
+
+template <class A1, class A2, class A3, class A4>
+class Vertex<A1, A2, A3, A4> {
+public:
+ typename A1::Type a1;
+ typename A2::Type a2;
+ typename A3::Type a3;
+ typename A4::Type a4;
+
+ using VertexType = Vertex<A1, A2, A3, A4>;
+ static const std::size_t attributeOffsets[4];
+};
+
+template <class A1, class A2, class A3, class A4, class A5>
+class Vertex<A1, A2, A3, A4, A5> {
+public:
+ typename A1::Type a1;
+ typename A2::Type a2;
+ typename A3::Type a3;
+ typename A4::Type a4;
+ typename A5::Type a5;
+
+ using VertexType = Vertex<A1, A2, A3, A4, A5>;
+ static const std::size_t attributeOffsets[5];
+};
+
+template <class A1>
+const std::size_t Vertex<A1>::attributeOffsets[1] = {
+ offsetof(VertexType, a1)
+};
+
+template <class A1, class A2>
+const std::size_t Vertex<A1, A2>::attributeOffsets[2] = {
+ offsetof(VertexType, a1),
+ offsetof(VertexType, a2)
+};
+
+template <class A1, class A2, class A3>
+const std::size_t Vertex<A1, A2, A3>::attributeOffsets[3] = {
+ offsetof(VertexType, a1),
+ offsetof(VertexType, a2),
+ offsetof(VertexType, a3)
+};
+
+template <class A1, class A2, class A3, class A4>
+const std::size_t Vertex<A1, A2, A3, A4>::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 <class A1, class A2, class A3, class A4, class A5>
+const std::size_t Vertex<A1, A2, A3, A4, A5>::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<std::size_t, offsetof(Vertex, name)>())
+} // namespace detail
-template <class Shader, class Vertex> 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... As>
+class Attributes {
+public:
+ using State = std::tuple<typename As::State...>;
+ using Vertex = detail::Vertex<As...>;
+
+ static State state(const Shader& shader) {
+ return State { { As::name, shader }... };
+ }
+
+ static std::function<void (std::size_t)> binder(const State& state) {
+ return binder(state, std::index_sequence_for<As...>());
+ }
+
+private:
+ template <std::size_t... Is>
+ static std::function<void (std::size_t)> binder(const State& state, std::index_sequence<Is...>) {
+ return [&state] (std::size_t vertexOffset) {
+ noop((bindAttribute(std::get<Is>(state).location,
+ std::get<Is>(state).count,
+ std::get<Is>(state).type,
+ sizeof(Vertex),
+ vertexOffset,
+ Vertex::attributeOffsets[Is]), 0)...);
+ };
+ }
+
+ // This exists only to provide a varags context for unpacking the assignments in `binder`.
+ template <int...> 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<GLenum>(binding.type),
- GL_FALSE,
- static_cast<GLsizei>(drawable.vertexSize),
- reinterpret_cast<GLvoid*>(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, typename Subject::VertexType>()(shader))
+ bindAttributes(Shader::AttributesType::binder(shader.attributesState))
{
static_assert(std::is_standard_layout<typename Subject::VertexType>::value, "vertex type must use standard layout");
- static_assert(std::is_same<typename Shader::VertexType, typename Subject::VertexType>::value, "vertex type mismatch");
+ static_assert(std::is_same<typename Shader::AttributesType::Vertex, typename Subject::VertexType>::value, "vertex type mismatch");
}
DrawMode drawMode;
@@ -117,7 +117,7 @@ public:
std::size_t primitiveSize;
const std::vector<Segment>& segments;
std::function<void ()> bindUniforms;
- std::vector<AttributeBinding> attributeBindings;
+ std::function<void (std::size_t)> bindAttributes;
};
} // namespace gl