diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-10-28 16:39:50 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-02-02 09:44:42 -0800 |
commit | 141e995806576364d185626176c1b993fc519291 (patch) | |
tree | ecdc41fc7699f2a1a9e9456157348451ebe99597 /src/mbgl/gl | |
parent | 6a6bddb4537004cc1bfc506e76772de74d33f3f7 (diff) | |
download | qtlocation-mapboxgl-141e995806576364d185626176c1b993fc519291.tar.gz |
[core] Add support for data-driven styling
Diffstat (limited to 'src/mbgl/gl')
-rw-r--r-- | src/mbgl/gl/attribute.cpp | 227 | ||||
-rw-r--r-- | src/mbgl/gl/attribute.hpp | 185 | ||||
-rw-r--r-- | src/mbgl/gl/context.cpp | 87 | ||||
-rw-r--r-- | src/mbgl/gl/context.hpp | 35 | ||||
-rw-r--r-- | src/mbgl/gl/draw_mode.hpp | 19 | ||||
-rw-r--r-- | src/mbgl/gl/normalization.hpp | 35 | ||||
-rw-r--r-- | src/mbgl/gl/program.hpp | 42 | ||||
-rw-r--r-- | src/mbgl/gl/segment.cpp | 7 | ||||
-rw-r--r-- | src/mbgl/gl/segment.hpp | 33 | ||||
-rw-r--r-- | src/mbgl/gl/types.hpp | 10 | ||||
-rw-r--r-- | src/mbgl/gl/uniform.hpp | 33 |
11 files changed, 528 insertions, 185 deletions
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp index 7432fff590..2c16dac3fc 100644 --- a/src/mbgl/gl/attribute.cpp +++ b/src/mbgl/gl/attribute.cpp @@ -1,29 +1,238 @@ #include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/context.hpp> #include <mbgl/gl/gl.hpp> +#include <mbgl/gl/normalization.hpp> namespace mbgl { namespace gl { +static_assert(offsetof(Normalized<uint8_t>, value) == 0, "unexpected normalized offset"); + AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) { MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name)); return location; } -void bindAttribute(AttributeLocation location, - std::size_t count, - DataType type, - std::size_t vertexSize, - std::size_t vertexOffset, - std::size_t attributeOffset) { +template <class T> DataType DataTypeOf = static_cast<DataType>(0); +template <> DataType DataTypeOf< int8_t> = DataType::Byte; +template <> DataType DataTypeOf<uint8_t> = DataType::UnsignedByte; +template <> DataType DataTypeOf< int16_t> = DataType::Short; +template <> DataType DataTypeOf<uint16_t> = DataType::UnsignedShort; +template <> DataType DataTypeOf< int32_t> = DataType::Integer; +template <> DataType DataTypeOf<uint32_t> = DataType::UnsignedInteger; +template <> DataType DataTypeOf<float> = DataType::Float; + +template <class T> bool IsNormalized = false; +template <class T> bool IsNormalized<Normalized<T>> = true; +template <class T> DataType DataTypeOf<Normalized<T>> = DataTypeOf<T>; + +template <class T, std::size_t N> +void VariableAttributeBinding<T, N>::bind(Context& context, + AttributeLocation location, + optional<VariableAttributeBinding<T, N>>& oldBinding, + std::size_t vertexOffset) const { + if (oldBinding == *this) { + return; + } + context.vertexBuffer = vertexBuffer; MBGL_CHECK_ERROR(glEnableVertexAttribArray(location)); MBGL_CHECK_ERROR(glVertexAttribPointer( location, - static_cast<GLint>(count), - static_cast<GLenum>(type), - GL_FALSE, + static_cast<GLint>(N), + static_cast<GLenum>(DataTypeOf<T>), + static_cast<GLboolean>(IsNormalized<T>), static_cast<GLsizei>(vertexSize), reinterpret_cast<GLvoid*>(attributeOffset + (vertexSize * vertexOffset)))); } +template class VariableAttributeBinding<uint8_t, 1>; +template class VariableAttributeBinding<uint8_t, 2>; +template class VariableAttributeBinding<uint8_t, 3>; +template class VariableAttributeBinding<uint8_t, 4>; + +template class VariableAttributeBinding<Normalized<uint8_t>, 1>; +template class VariableAttributeBinding<Normalized<uint8_t>, 2>; +template class VariableAttributeBinding<Normalized<uint8_t>, 3>; +template class VariableAttributeBinding<Normalized<uint8_t>, 4>; + +template class VariableAttributeBinding<uint16_t, 1>; +template class VariableAttributeBinding<uint16_t, 2>; +template class VariableAttributeBinding<uint16_t, 3>; +template class VariableAttributeBinding<uint16_t, 4>; + +template class VariableAttributeBinding<int16_t, 1>; +template class VariableAttributeBinding<int16_t, 2>; +template class VariableAttributeBinding<int16_t, 3>; +template class VariableAttributeBinding<int16_t, 4>; + +template class VariableAttributeBinding<float, 1>; +template class VariableAttributeBinding<float, 2>; +template class VariableAttributeBinding<float, 3>; +template class VariableAttributeBinding<float, 4>; + +template <> +void ConstantAttributeBinding<uint8_t, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 1>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0])); +} + +template <> +void ConstantAttributeBinding<uint8_t, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 2>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1])); +} + +template <> +void ConstantAttributeBinding<uint8_t, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 3>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2])); +} + +template <> +void ConstantAttributeBinding<uint8_t, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 4>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3])); +} + + +template <> +void ConstantAttributeBinding<Normalized<uint8_t>, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 1>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0].denormalized())); +} + +template <> +void ConstantAttributeBinding<Normalized<uint8_t>, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 2>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0].denormalized(), value[1].denormalized())); +} + +template <> +void ConstantAttributeBinding<Normalized<uint8_t>, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 3>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0].denormalized(), value[1].denormalized(), value[2].denormalized())); +} + +template <> +void ConstantAttributeBinding<Normalized<uint8_t>, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 4>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0].denormalized(), value[1].denormalized(), value[2].denormalized(), value[3].denormalized())); +} + + +template <> +void ConstantAttributeBinding<uint16_t, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 1>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0])); +} + +template <> +void ConstantAttributeBinding<uint16_t, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 2>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1])); +} + +template <> +void ConstantAttributeBinding<uint16_t, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 3>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2])); +} + +template <> +void ConstantAttributeBinding<uint16_t, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 4>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3])); +} + + +template <> +void ConstantAttributeBinding<int16_t, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 1>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0])); +} + +template <> +void ConstantAttributeBinding<int16_t, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 2>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1])); +} + +template <> +void ConstantAttributeBinding<int16_t, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 3>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2])); +} + +template <> +void ConstantAttributeBinding<int16_t, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 4>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3])); +} + + +template <> +void ConstantAttributeBinding<float, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 1>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0])); +} + +template <> +void ConstantAttributeBinding<float, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 2>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1])); +} + +template <> +void ConstantAttributeBinding<float, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 3>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2])); +} + +template <> +void ConstantAttributeBinding<float, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 4>>& oldBinding, std::size_t) const { + assert(location != 0); + oldBinding = {}; + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3])); +} + } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index e45014127b..6300ebb56b 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -1,8 +1,10 @@ #pragma once #include <mbgl/gl/types.hpp> +#include <mbgl/gl/segment.hpp> #include <mbgl/util/ignore.hpp> #include <mbgl/util/indexed_tuple.hpp> +#include <mbgl/util/variant.hpp> #include <cstddef> #include <functional> @@ -10,24 +12,79 @@ namespace mbgl { namespace gl { -template <class Tag, class T, std::size_t N> +template <class T, std::size_t N> +class VariableAttributeBinding { +public: + VariableAttributeBinding(BufferID vertexBuffer_, + std::size_t vertexSize_, + std::size_t attributeOffset_) + : vertexBuffer(vertexBuffer_), + vertexSize(vertexSize_), + attributeOffset(attributeOffset_) + {} + + void bind(Context&, AttributeLocation, optional<VariableAttributeBinding<T, N>>&, std::size_t vertexOffset) const; + + friend bool operator==(const VariableAttributeBinding& lhs, + const VariableAttributeBinding& rhs) { + return lhs.vertexBuffer == rhs.vertexBuffer + && lhs.vertexSize == rhs.vertexSize + && lhs.attributeOffset == rhs.attributeOffset; + } + +private: + BufferID vertexBuffer; + std::size_t vertexSize; + std::size_t attributeOffset; +}; + +template <class T, std::size_t N> +class ConstantAttributeBinding { +public: + ConstantAttributeBinding() { value.fill(T()); } + + explicit ConstantAttributeBinding(std::array<T, N> value_) + : value(std::move(value_)) + {} + + void bind(Context&, AttributeLocation, optional<VariableAttributeBinding<T, N>>&, std::size_t) const; + + friend bool operator==(const ConstantAttributeBinding& lhs, + const ConstantAttributeBinding& rhs) { + return lhs.value == rhs.value; + } + +private: + std::array<T, N> value; +}; + +template <class T, std::size_t N> class Attribute { public: - using Type = T[N]; + using Value = std::array<T, N>; + + using VariableBinding = VariableAttributeBinding<T, N>; + using ConstantBinding = ConstantAttributeBinding<T, N>; - class State { - public: - explicit State(AttributeLocation location_) - : location(location_) {} + using Location = AttributeLocation; - AttributeLocation location; - static constexpr std::size_t count = N; - static constexpr DataType type = DataTypeOf<T>::value; - }; + using Binding = variant< + ConstantBinding, + VariableBinding>; + + static void bind(Context& context, + const Location& location, + optional<VariableBinding>& oldBinding, + const Binding& newBinding, + std::size_t vertexOffset) { + Binding::visit(newBinding, [&] (const auto& binding) { + binding.bind(context, location, oldBinding, vertexOffset); + }); + } }; #define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ - struct name_ : ::mbgl::gl::Attribute<name_, type_, n_> { static constexpr auto name = #name_; } + struct name_ : ::mbgl::gl::Attribute<type_, n_> { static auto name() { return #name_; } } namespace detail { @@ -41,10 +98,16 @@ namespace detail { template <class... As> class Vertex; +template <> +class Vertex<> { +public: + using VertexType = Vertex<>; +}; + template <class A1> class Vertex<A1> { public: - typename A1::Type a1; + typename A1::Value a1; using VertexType = Vertex<A1>; static const std::size_t attributeOffsets[1]; @@ -53,8 +116,8 @@ public: template <class A1, class A2> class Vertex<A1, A2> { public: - typename A1::Type a1; - typename A2::Type a2; + typename A1::Value a1; + typename A2::Value a2; using VertexType = Vertex<A1, A2>; static const std::size_t attributeOffsets[2]; @@ -63,9 +126,9 @@ public: 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; + typename A1::Value a1; + typename A2::Value a2; + typename A3::Value a3; using VertexType = Vertex<A1, A2, A3>; static const std::size_t attributeOffsets[3]; @@ -74,10 +137,10 @@ public: 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; + typename A1::Value a1; + typename A2::Value a2; + typename A3::Value a3; + typename A4::Value a4; using VertexType = Vertex<A1, A2, A3, A4>; static const std::size_t attributeOffsets[4]; @@ -86,11 +149,11 @@ public: 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; + typename A1::Value a1; + typename A2::Value a2; + typename A3::Value a3; + typename A4::Value a4; + typename A5::Value a5; using VertexType = Vertex<A1, A2, A3, A4, A5>; static const std::size_t attributeOffsets[5]; @@ -135,37 +198,71 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = { AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name); -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 = IndexedTuple<TypeList<As...>, TypeList<typename As::State...>>; + using Types = TypeList<As...>; + using Locations = IndexedTuple< + TypeList<As...>, + TypeList<typename As::Location...>>; + using Bindings = IndexedTuple< + TypeList<As...>, + TypeList<typename As::Binding...>>; + using VariableBindings = IndexedTuple< + TypeList<As...>, + TypeList<optional<typename As::VariableBinding>...>>; + using Vertex = detail::Vertex<As...>; template <class A> static constexpr std::size_t Index = TypeIndex<A, As...>::value; - static State state(const ProgramID& id) { - return State { typename As::State(bindAttributeLocation(id, Index<As>, As::name))... }; + static Locations locations(const ProgramID& id) { + return Locations { bindAttributeLocation(id, Index<As>, As::name())... }; } - static std::function<void (std::size_t)> binder(const State& state) { - return [&state] (std::size_t vertexOffset) { - util::ignore({ (bindAttribute(state.template get<As>().location, - state.template get<As>().count, - state.template get<As>().type, - sizeof(Vertex), - vertexOffset, - Vertex::attributeOffsets[Index<As>]), 0)... }); + template <class DrawMode> + static Bindings allVariableBindings(const VertexBuffer<Vertex, DrawMode>& buffer) { + static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout"); + + return Bindings { + typename As::VariableBinding { + buffer.buffer, + sizeof(Vertex), + Vertex::attributeOffsets[Index<As>] + }... }; } + + static void bind(Context& context, + const Locations& locations, + VariableBindings& oldBindings, + const Bindings& newBindings, + std::size_t vertexOffset) { + util::ignore({ (As::bind(context, + locations.template get<As>(), + oldBindings.template get<As>(), + newBindings.template get<As>(), + vertexOffset), 0)... }); + } }; +namespace detail { + +template <class...> +struct ConcatenateAttributes; + +template <class... As, class... Bs> +struct ConcatenateAttributes<TypeList<As...>, TypeList<Bs...>> { + using Type = Attributes<As..., Bs...>; +}; + +} // namespace detail + +template <class A, class B> +using ConcatenateAttributes = typename detail::ConcatenateAttributes< + typename A::Types, + typename B::Types>::Type; + } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 5048ffcd66..a74e941bc6 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -122,6 +122,16 @@ UniqueTexture Context::createTexture() { return UniqueTexture{ std::move(id), { this } }; } +UniqueVertexArray Context::createVertexArray() { + if (!gl::GenVertexArrays) { + throw std::runtime_error("GL_ARB_vertex_array_object extension is required"); + } + + VertexArrayID id = 0; + MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id)); + return UniqueVertexArray(std::move(id), { this }); +} + UniqueFramebuffer Context::createFramebuffer() { FramebufferID id = 0; MBGL_CHECK_ERROR(glGenFramebuffers(1, &id)); @@ -407,32 +417,26 @@ void Context::clear(optional<mbgl::Color> color, } #if not MBGL_USE_GLES2 -PrimitiveType Context::operator()(const Points& points) { +void Context::setDrawMode(const Points& points) { pointSize = points.pointSize; - return PrimitiveType::Points; } #else -PrimitiveType Context::operator()(const Points&) { - return PrimitiveType::Points; +void Context::setDrawMode(const Points&) { } #endif // MBGL_USE_GLES2 -PrimitiveType Context::operator()(const Lines& lines) { +void Context::setDrawMode(const Lines& lines) { lineWidth = lines.lineWidth; - return PrimitiveType::Lines; } -PrimitiveType Context::operator()(const LineStrip& lineStrip) { +void Context::setDrawMode(const LineStrip& lineStrip) { lineWidth = lineStrip.lineWidth; - return PrimitiveType::LineStrip; } -PrimitiveType Context::operator()(const Triangles&) { - return PrimitiveType::Triangles; +void Context::setDrawMode(const Triangles&) { } -PrimitiveType Context::operator()(const TriangleStrip&) { - return PrimitiveType::TriangleStrip; +void Context::setDrawMode(const TriangleStrip&) { } void Context::setDepthMode(const DepthMode& depth) { @@ -474,57 +478,14 @@ void Context::setColorMode(const ColorMode& color) { colorMask = color.mask; } -void Context::draw(const Drawable& drawable) { - if (drawable.segments.empty()) { - return; - } - - PrimitiveType primitiveType = apply_visitor([&] (auto m) { return (*this)(m); }, drawable.drawMode); - - setDepthMode(drawable.depthMode); - setStencilMode(drawable.stencilMode); - setColorMode(drawable.colorMode); - - program = drawable.program; - - drawable.bindUniforms(); - - for (const auto& segment : drawable.segments) { - auto needAttributeBindings = [&] () { - if (!gl::GenVertexArrays || !gl::BindVertexArray) { - return true; - } - - if (segment.vao) { - vertexArrayObject = *segment.vao; - return false; - } - - VertexArrayID id = 0; - MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id)); - vertexArrayObject = id; - segment.vao = UniqueVertexArray(std::move(id), { this }); - - // If we are initializing a new VAO, we need to force the buffers - // to be rebound. VAOs don't inherit the existing buffer bindings. - vertexBuffer.setDirty(); - elementBuffer.setDirty(); - - return true; - }; - - if (needAttributeBindings()) { - vertexBuffer = drawable.vertexBuffer; - elementBuffer = drawable.indexBuffer; - drawable.bindAttributes(segment.vertexOffset); - } - - MBGL_CHECK_ERROR(glDrawElements( - static_cast<GLenum>(primitiveType), - static_cast<GLsizei>(segment.indexLength), - GL_UNSIGNED_SHORT, - reinterpret_cast<GLvoid*>(sizeof(uint16_t) * segment.indexOffset))); - } +void Context::draw(PrimitiveType primitiveType, + std::size_t indexOffset, + std::size_t indexLength) { + MBGL_CHECK_ERROR(glDrawElements( + static_cast<GLenum>(primitiveType), + static_cast<GLsizei>(indexLength), + GL_UNSIGNED_SHORT, + reinterpret_cast<GLvoid*>(sizeof(uint16_t) * indexOffset))); } void Context::performCleanup() { diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 093afa20ed..636dfc9eac 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -13,7 +13,6 @@ #include <mbgl/gl/depth_mode.hpp> #include <mbgl/gl/stencil_mode.hpp> #include <mbgl/gl/color_mode.hpp> -#include <mbgl/gl/segment.hpp> #include <mbgl/util/noncopyable.hpp> @@ -40,6 +39,7 @@ public: UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader); void linkProgram(ProgramID); UniqueTexture createTexture(); + UniqueVertexArray createVertexArray(); template <class Vertex, class DrawMode> VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v) { @@ -119,25 +119,20 @@ public: optional<float> depth, optional<int32_t> stencil); - struct Drawable { - DrawMode drawMode; - DepthMode depthMode; - StencilMode stencilMode; - ColorMode colorMode; - gl::ProgramID program; - gl::BufferID vertexBuffer; - gl::BufferID indexBuffer; - const std::vector<Segment>& segments; - std::function<void ()> bindUniforms; - std::function<void (std::size_t)> bindAttributes; - }; - - void draw(const Drawable&); + void setDrawMode(const Points&); + void setDrawMode(const Lines&); + void setDrawMode(const LineStrip&); + void setDrawMode(const Triangles&); + void setDrawMode(const TriangleStrip&); void setDepthMode(const DepthMode&); void setStencilMode(const StencilMode&); void setColorMode(const ColorMode&); + void draw(PrimitiveType, + std::size_t indexOffset, + std::size_t indexLength); + // Actually remove the objects we marked as abandoned with the above methods. // Only call this while the OpenGL context is exclusive to this thread. void performCleanup(); @@ -164,6 +159,8 @@ public: std::array<State<value::BindTexture>, 2> texture; State<value::BindVertexArray> vertexArrayObject; State<value::Program> program; + State<value::BindVertexBuffer> vertexBuffer; + State<value::BindElementBuffer> elementBuffer; #if not MBGL_USE_GLES2 State<value::PixelZoom> pixelZoom; @@ -196,8 +193,6 @@ private: #if not MBGL_USE_GLES2 State<value::PointSize> pointSize; #endif // MBGL_USE_GLES2 - State<value::BindVertexBuffer> vertexBuffer; - State<value::BindElementBuffer> elementBuffer; UniqueBuffer createVertexBuffer(const void* data, std::size_t size); UniqueBuffer createIndexBuffer(const void* data, std::size_t size); @@ -210,12 +205,6 @@ private: void drawPixels(Size size, const void* data, TextureFormat); #endif // MBGL_USE_GLES2 - PrimitiveType operator()(const Points&); - PrimitiveType operator()(const Lines&); - PrimitiveType operator()(const LineStrip&); - PrimitiveType operator()(const Triangles&); - PrimitiveType operator()(const TriangleStrip&); - friend detail::ProgramDeleter; friend detail::ShaderDeleter; friend detail::BufferDeleter; diff --git a/src/mbgl/gl/draw_mode.hpp b/src/mbgl/gl/draw_mode.hpp index ab86d5e469..275eb25b89 100644 --- a/src/mbgl/gl/draw_mode.hpp +++ b/src/mbgl/gl/draw_mode.hpp @@ -1,7 +1,7 @@ #pragma once +#include <mbgl/gl/types.hpp> #include <mbgl/gl/primitives.hpp> -#include <mbgl/util/variant.hpp> #include <cassert> @@ -11,7 +11,9 @@ namespace gl { class Points { public: using Primitive = Point; + static constexpr std::size_t bufferGroupSize = 1; + static constexpr PrimitiveType primitiveType = PrimitiveType::Points; explicit Points(float pointSize_) : pointSize(pointSize_) {} @@ -21,7 +23,9 @@ public: class Lines { public: using Primitive = Line; + static constexpr std::size_t bufferGroupSize = 2; + static constexpr PrimitiveType primitiveType = PrimitiveType::Lines; explicit Lines(float lineWidth_) : lineWidth(lineWidth_) { assert(lineWidth > 0); @@ -35,7 +39,9 @@ public: // LineStrip is a form of "Line" rendering, but the element buffer // cannot be grouped into logical elements beyond a single Point. using Primitive = Line; + static constexpr std::size_t bufferGroupSize = 1; + static constexpr PrimitiveType primitiveType = PrimitiveType::LineStrip; explicit LineStrip(float lineWidth_) : lineWidth(lineWidth_) { assert(lineWidth > 0); @@ -47,7 +53,9 @@ public: class Triangles { public: using Primitive = Triangle; + static constexpr std::size_t bufferGroupSize = 3; + static constexpr PrimitiveType primitiveType = PrimitiveType::Triangles; }; class TriangleStrip { @@ -55,7 +63,9 @@ public: // TriangleStrip is a form of "Triangle" rendering, but the element buffer // cannot be grouped into logical elements beyond a single Point. using Primitive = Triangle; + static constexpr std::size_t bufferGroupSize = 1; + static constexpr PrimitiveType primitiveType = PrimitiveType::TriangleStrip; }; // Special draw mode for use with VertexVector<Indexed, Vertex>, in which @@ -65,12 +75,5 @@ public: static constexpr std::size_t bufferGroupSize = 1; }; -using DrawMode = variant< - Points, - Lines, - LineStrip, - Triangles, - TriangleStrip>; - } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/normalization.hpp b/src/mbgl/gl/normalization.hpp new file mode 100644 index 0000000000..83fa67a3ec --- /dev/null +++ b/src/mbgl/gl/normalization.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include <mbgl/math/clamp.hpp> + +#include <cassert> +#include <limits> + +namespace mbgl { +namespace gl { + +template <class T> +class Normalized { +public: + T value; + + Normalized() : value(0) {} + + explicit Normalized(float f) + : value(static_cast<T>(std::numeric_limits<T>::max() * util::clamp(f, 0.0f, 1.0f))) { + assert(f >= 0.0f); + assert(f <= 1.0f); + } + + float denormalized() const { + return float(value) / std::numeric_limits<T>::max(); + } +}; + +template <class T> +bool operator==(const Normalized<T>& lhs, const Normalized<T>& rhs) { + return lhs.value == rhs.value; +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index 33387e9d4e..fa0470796e 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -20,16 +20,14 @@ public: using Attributes = As; using Uniforms = Us; - using Vertex = typename Attributes::Vertex; using UniformValues = typename Uniforms::Values; - - static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout"); + using AttributeBindings = typename Attributes::Bindings; Program(Context& context, const std::string& vertexSource, const std::string& fragmentSource) : vertexShader(context.createShader(ShaderType::Vertex, vertexSource)), fragmentShader(context.createShader(ShaderType::Fragment, fragmentSource)), program(context.createProgram(vertexShader, fragmentShader)), - attributesState(Attributes::state(program)), + attributeLocations(Attributes::locations(program)), uniformsState((context.linkProgram(program), Uniforms::state(program))) {} template <class DrawMode> @@ -39,22 +37,30 @@ public: StencilMode stencilMode, ColorMode colorMode, UniformValues&& uniformValues, - const VertexBuffer<Vertex>& vertexBuffer, + AttributeBindings&& attributeBindings, const IndexBuffer<DrawMode>& indexBuffer, const SegmentVector<Attributes>& segments) { static_assert(std::is_same<Primitive, typename DrawMode::Primitive>::value, "incompatible draw mode"); - context.draw({ - std::move(drawMode), - std::move(depthMode), - std::move(stencilMode), - std::move(colorMode), - program, - vertexBuffer.buffer, - indexBuffer.buffer, - segments, - Uniforms::binder(uniformsState, std::move(uniformValues)), - Attributes::binder(attributesState) - }); + + context.setDrawMode(drawMode); + context.setDepthMode(depthMode); + context.setStencilMode(stencilMode); + context.setColorMode(colorMode); + + context.program = program; + + Uniforms::bind(uniformsState, std::move(uniformValues)); + + for (const auto& segment : segments) { + segment.bind(context, + indexBuffer.buffer, + attributeLocations, + attributeBindings); + + context.draw(drawMode.primitiveType, + segment.indexOffset, + segment.indexLength); + } } private: @@ -62,7 +68,7 @@ private: UniqueShader fragmentShader; UniqueProgram program; - typename Attributes::State attributesState; + typename Attributes::Locations attributeLocations; typename Uniforms::State uniformsState; }; diff --git a/src/mbgl/gl/segment.cpp b/src/mbgl/gl/segment.cpp new file mode 100644 index 0000000000..aabdc83cd4 --- /dev/null +++ b/src/mbgl/gl/segment.cpp @@ -0,0 +1,7 @@ +#include <mbgl/gl/segment.hpp> + +namespace mbgl { +namespace gl { + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp index 8f74afd237..bb9f2f1ee8 100644 --- a/src/mbgl/gl/segment.hpp +++ b/src/mbgl/gl/segment.hpp @@ -1,12 +1,16 @@ #pragma once +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/vertex_buffer.hpp> #include <mbgl/util/optional.hpp> #include <cstddef> +#include <vector> namespace mbgl { namespace gl { +template <class Attributes> class Segment { public: Segment(std::size_t vertexOffset_, @@ -24,13 +28,38 @@ public: std::size_t vertexLength; std::size_t indexLength; + void bind(Context& context, + BufferID indexBuffer_, + const typename Attributes::Locations& attributeLocations, + const typename Attributes::Bindings& attributeBindings_) const { + if (!vao) { + vao = context.createVertexArray(); + context.vertexBuffer.setDirty(); + } + + context.vertexArrayObject = *vao; + + if (indexBuffer != indexBuffer_) { + indexBuffer = indexBuffer_; + context.elementBuffer.setDirty(); + context.elementBuffer = indexBuffer_; + } + + Attributes::bind(context, + attributeLocations, + variableBindings, + attributeBindings_, + vertexOffset); + } + private: - friend class Context; mutable optional<UniqueVertexArray> vao; + mutable optional<BufferID> indexBuffer; + mutable typename Attributes::VariableBindings variableBindings; }; template <class Attributes> -class SegmentVector : public std::vector<Segment> { +class SegmentVector : public std::vector<Segment<Attributes>> { public: SegmentVector() = default; }; diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 577629d5d3..565ca5754f 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -34,16 +34,6 @@ enum class DataType : uint32_t { Float = 0x1406 }; -template <typename T> struct DataTypeOf; - -template <> struct DataTypeOf<int8_t> : std::integral_constant<DataType, DataType::Byte> {}; -template <> struct DataTypeOf<uint8_t> : std::integral_constant<DataType, DataType::UnsignedByte> {}; -template <> struct DataTypeOf<int16_t> : std::integral_constant<DataType, DataType::Short> {}; -template <> struct DataTypeOf<uint16_t> : std::integral_constant<DataType, DataType::UnsignedShort> {}; -template <> struct DataTypeOf<int32_t> : std::integral_constant<DataType, DataType::Integer> {}; -template <> struct DataTypeOf<uint32_t> : std::integral_constant<DataType, DataType::UnsignedInteger> {}; -template <> struct DataTypeOf<float> : std::integral_constant<DataType, DataType::Float> {}; - enum class RenderbufferType : uint32_t { RGBA = 0x8058, DepthStencil = 0x88F0, diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp index 726cd4fe10..92136b61c2 100644 --- a/src/mbgl/gl/uniform.hpp +++ b/src/mbgl/gl/uniform.hpp @@ -50,32 +50,49 @@ template <class Tag, class T, size_t N> using UniformMatrix = Uniform<Tag, std::array<T, N*N>>; #define MBGL_DEFINE_UNIFORM_SCALAR(type_, name_) \ - struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static constexpr auto name = #name_; } + struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static auto name() { return #name_; } } #define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \ - struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static constexpr auto name = #name_; } + struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static auto name() { return #name_; } } #define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \ - struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static constexpr auto name = #name_; } + struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static auto name() { return #name_; } } UniformLocation uniformLocation(ProgramID, const char * name); template <class... Us> class Uniforms { public: + using Types = TypeList<Us...>; using State = IndexedTuple<TypeList<Us...>, TypeList<typename Us::State...>>; using Values = IndexedTuple<TypeList<Us...>, TypeList<typename Us::Value...>>; static State state(const ProgramID& id) { - return State { { uniformLocation(id, Us::name) }... }; + return State { { uniformLocation(id, Us::name()) }... }; } - static std::function<void ()> binder(State& state, Values&& values_) { - return [&state, values = std::move(values_)] () mutable { - util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... }); - }; + static void bind(State& state, Values&& values) { + util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... }); } }; + +namespace detail { + +template <class...> +struct ConcatenateUniforms; + +template <class... As, class... Bs> +struct ConcatenateUniforms<TypeList<As...>, TypeList<Bs...>> { + using Type = Uniforms<As..., Bs...>; +}; + +} // namespace detail + +template <class A, class B> +using ConcatenateUniforms = typename detail::ConcatenateUniforms< + typename A::Types, + typename B::Types>::Type; + } // namespace gl } // namespace mbgl |