summaryrefslogtreecommitdiff
path: root/src/mbgl/gl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/gl')
-rw-r--r--src/mbgl/gl/attribute.cpp29
-rw-r--r--src/mbgl/gl/attribute.hpp177
-rw-r--r--src/mbgl/gl/color_mode.cpp44
-rw-r--r--src/mbgl/gl/color_mode.hpp95
-rw-r--r--src/mbgl/gl/context.cpp404
-rw-r--r--src/mbgl/gl/context.hpp153
-rw-r--r--src/mbgl/gl/debugging.cpp4
-rw-r--r--src/mbgl/gl/depth_mode.cpp18
-rw-r--r--src/mbgl/gl/depth_mode.hpp36
-rw-r--r--src/mbgl/gl/draw_mode.hpp76
-rw-r--r--src/mbgl/gl/extension.cpp21
-rw-r--r--src/mbgl/gl/framebuffer.hpp5
-rw-r--r--src/mbgl/gl/index_buffer.hpp39
-rw-r--r--src/mbgl/gl/primitives.hpp22
-rw-r--r--src/mbgl/gl/program.hpp70
-rw-r--r--src/mbgl/gl/renderbuffer.hpp5
-rw-r--r--src/mbgl/gl/segment.hpp39
-rw-r--r--src/mbgl/gl/shader.cpp113
-rw-r--r--src/mbgl/gl/shader.hpp45
-rw-r--r--src/mbgl/gl/stencil_mode.cpp27
-rw-r--r--src/mbgl/gl/stencil_mode.hpp66
-rw-r--r--src/mbgl/gl/texture.hpp7
-rw-r--r--src/mbgl/gl/types.hpp97
-rw-r--r--src/mbgl/gl/uniform.cpp54
-rw-r--r--src/mbgl/gl/uniform.hpp94
-rw-r--r--src/mbgl/gl/value.cpp99
-rw-r--r--src/mbgl/gl/value.hpp125
-rw-r--r--src/mbgl/gl/vao.cpp58
-rw-r--r--src/mbgl/gl/vao.hpp78
-rw-r--r--src/mbgl/gl/vertex_buffer.hpp31
30 files changed, 1453 insertions, 678 deletions
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp
new file mode 100644
index 0000000000..7432fff590
--- /dev/null
+++ b/src/mbgl/gl/attribute.cpp
@@ -0,0 +1,29 @@
+#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/gl.hpp>
+
+namespace mbgl {
+namespace gl {
+
+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) {
+ 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 8bc474e967..e45014127b 100644
--- a/src/mbgl/gl/attribute.hpp
+++ b/src/mbgl/gl/attribute.hpp
@@ -1,50 +1,171 @@
#pragma once
#include <mbgl/gl/types.hpp>
-#include <mbgl/gl/shader.hpp>
+#include <mbgl/util/ignore.hpp>
+#include <mbgl/util/indexed_tuple.hpp>
#include <cstddef>
-#include <limits>
-#include <vector>
+#include <functional>
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:
+ explicit State(AttributeLocation location_)
+ : location(location_) {}
+
+ 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(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
- 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");
- static_assert(sizeof(Vertex) <= std::numeric_limits<int32_t>::max(), "vertex type is too big");
- }
+ typename A1::Type a1;
- AttributeLocation location;
- DataType type;
- uint8_t count;
- std::size_t offset;
+ using VertexType = Vertex<A1>;
+ static const std::size_t attributeOffsets[1];
};
-#define MBGL_MAKE_ATTRIBUTE_BINDING(Vertex, shader, name) \
- ::mbgl::gl::AttributeBinding(&Vertex::name, \
- shader.name, \
- std::integral_constant<std::size_t, offsetof(Vertex, name)>())
+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 Shader, class Vertex> struct AttributeBindings;
+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)
+};
+
+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)
+};
+
+} // namespace detail
+
+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 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 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)... });
+ };
+ }
+};
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/color_mode.cpp b/src/mbgl/gl/color_mode.cpp
new file mode 100644
index 0000000000..e838c8e2ff
--- /dev/null
+++ b/src/mbgl/gl/color_mode.cpp
@@ -0,0 +1,44 @@
+#include <mbgl/gl/color_mode.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/util/traits.hpp>
+
+namespace mbgl {
+namespace gl {
+
+static_assert(underlying_type(ColorMode::BlendEquation::Add) == GL_FUNC_ADD, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::BlendEquation::Subtract) == GL_FUNC_SUBTRACT, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::BlendEquation::ReverseSubtract) == GL_FUNC_REVERSE_SUBTRACT, "OpenGL enum mismatch");
+
+static_assert(underlying_type(ColorMode::Zero) == GL_ZERO, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::One) == GL_ONE, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcAlphaSaturate) == GL_SRC_ALPHA_SATURATE, "OpenGL enum mismatch");
+
+static_assert(underlying_type(ColorMode::Zero) == GL_ZERO, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::One) == GL_ONE, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch");
+static_assert(underlying_type(ColorMode::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch");
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/color_mode.hpp b/src/mbgl/gl/color_mode.hpp
new file mode 100644
index 0000000000..e73c8737eb
--- /dev/null
+++ b/src/mbgl/gl/color_mode.hpp
@@ -0,0 +1,95 @@
+#pragma once
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/color.hpp>
+
+namespace mbgl {
+namespace gl {
+
+class ColorMode {
+public:
+ enum class BlendEquation {
+ Add = 0x8006,
+ Subtract = 0x800A,
+ ReverseSubtract = 0x800B
+ };
+
+ enum BlendFactor {
+ Zero = 0x0000,
+ One = 0x0001,
+ SrcColor = 0x0300,
+ OneMinusSrcColor = 0x0301,
+ SrcAlpha = 0x0302,
+ OneMinusSrcAlpha = 0x0303,
+ DstAlpha = 0x0304,
+ OneMinusDstAlpha = 0x0305,
+ DstColor = 0x0306,
+ OneMinusDstColor = 0x0307,
+ SrcAlphaSaturate = 0x0308,
+ ConstantColor = 0x8001,
+ OneMinusConstantColor = 0x8002,
+ ConstantAlpha = 0x8003,
+ OneMinusConstantAlpha = 0x8004
+ };
+
+ template <BlendEquation E>
+ struct ConstantBlend {
+ static constexpr BlendEquation equation = E;
+ static constexpr BlendFactor srcFactor = One;
+ static constexpr BlendFactor dstFactor = One;
+ };
+
+ template <BlendEquation E>
+ struct LinearBlend {
+ static constexpr BlendEquation equation = E;
+ BlendFactor srcFactor;
+ BlendFactor dstFactor;
+ };
+
+ struct Replace {
+ static constexpr BlendEquation equation = BlendEquation::Add;
+ static constexpr BlendFactor srcFactor = One;
+ static constexpr BlendFactor dstFactor = One;
+ };
+
+ using Add = LinearBlend<BlendEquation::Add>;
+ using Subtract = LinearBlend<BlendEquation::Subtract>;
+ using ReverseSubtract = LinearBlend<BlendEquation::ReverseSubtract>;
+
+ using BlendFunction = variant<
+ Replace,
+ Add,
+ Subtract,
+ ReverseSubtract>;
+
+ BlendFunction blendFunction;
+ Color blendColor;
+
+ struct Mask {
+ bool r;
+ bool g;
+ bool b;
+ bool a;
+ };
+
+ Mask mask;
+
+ static ColorMode disabled() {
+ return ColorMode { Replace(), {}, { false, false, false, false } };
+ }
+
+ static ColorMode unblended() {
+ return ColorMode { Replace(), {}, { true, true, true, true } };
+ }
+
+ static ColorMode alphaBlended() {
+ return ColorMode { Add { One, OneMinusSrcAlpha }, {}, { true, true, true, true } };
+ }
+};
+
+constexpr bool operator!=(const ColorMode::Mask& a, const ColorMode::Mask& b) {
+ return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a;
+}
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index 23b28a15df..5048ffcd66 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -3,10 +3,25 @@
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/vertex_array.hpp>
#include <mbgl/util/traits.hpp>
+#include <mbgl/util/std.hpp>
+#include <mbgl/util/logging.hpp>
+
+#include <cstring>
namespace mbgl {
namespace gl {
+static_assert(underlying_type(ShaderType::Vertex) == GL_VERTEX_SHADER, "OpenGL type mismatch");
+static_assert(underlying_type(ShaderType::Fragment) == GL_FRAGMENT_SHADER, "OpenGL type mismatch");
+
+static_assert(underlying_type(PrimitiveType::Points) == GL_POINTS, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::Lines) == GL_LINES, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::LineLoop) == GL_LINE_LOOP, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::LineStrip) == GL_LINE_STRIP, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::Triangles) == GL_TRIANGLES, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::TriangleStrip) == GL_TRIANGLE_STRIP, "OpenGL type mismatch");
+static_assert(underlying_type(PrimitiveType::TriangleFan) == GL_TRIANGLE_FAN, "OpenGL type mismatch");
+
static_assert(std::is_same<ProgramID, GLuint>::value, "OpenGL type mismatch");
static_assert(std::is_same<ShaderID, GLuint>::value, "OpenGL type mismatch");
static_assert(std::is_same<BufferID, GLuint>::value, "OpenGL type mismatch");
@@ -15,81 +30,66 @@ static_assert(std::is_same<VertexArrayID, GLuint>::value, "OpenGL type mismatch"
static_assert(std::is_same<FramebufferID, GLuint>::value, "OpenGL type mismatch");
static_assert(std::is_same<RenderbufferID, GLuint>::value, "OpenGL type mismatch");
-static_assert(std::is_same<StencilValue, GLint>::value, "OpenGL type mismatch");
-static_assert(std::is_same<StencilMaskValue, GLuint>::value, "OpenGL type mismatch");
-
-static_assert(underlying_type(StencilTestFunction::Never) == GL_NEVER, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::Less) == GL_LESS, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::Equal) == GL_EQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::Greater) == GL_GREATER, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestFunction::Always) == GL_ALWAYS, "OpenGL enum mismatch");
-
-static_assert(underlying_type(StencilTestOperation::Keep) == GL_KEEP, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Zero) == GL_ZERO, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Replace) == GL_REPLACE, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Increment) == GL_INCR, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::IncrementWrap) == GL_INCR_WRAP, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Decrement) == GL_DECR, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::DecrementWrap) == GL_DECR_WRAP, "OpenGL enum mismatch");
-static_assert(underlying_type(StencilTestOperation::Invert) == GL_INVERT, "OpenGL enum mismatch");
-
-static_assert(underlying_type(DepthTestFunction::Never) == GL_NEVER, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::Less) == GL_LESS, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::Equal) == GL_EQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::Greater) == GL_GREATER, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch");
-static_assert(underlying_type(DepthTestFunction::Always) == GL_ALWAYS, "OpenGL enum mismatch");
-
-static_assert(underlying_type(BlendSourceFactor::Zero) == GL_ZERO, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::One) == GL_ONE, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendSourceFactor::SrcAlphaSaturate) == GL_SRC_ALPHA_SATURATE, "OpenGL enum mismatch");
-
-static_assert(underlying_type(BlendDestinationFactor::Zero) == GL_ZERO, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::One) == GL_ONE, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch");
-static_assert(underlying_type(BlendDestinationFactor::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch");
+static_assert(std::is_same<std::underlying_type_t<TextureFormat>, GLenum>::value, "OpenGL type mismatch");
+static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch");
+static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch");
Context::~Context() {
reset();
}
-UniqueProgram Context::createProgram() {
- return UniqueProgram{ MBGL_CHECK_ERROR(glCreateProgram()), { this } };
+UniqueShader Context::createShader(ShaderType type, const std::string& source) {
+ UniqueShader result { MBGL_CHECK_ERROR(glCreateShader(static_cast<GLenum>(type))), { this } };
+
+ const GLchar* sources = source.data();
+ const GLsizei lengths = static_cast<GLsizei>(source.length());
+ MBGL_CHECK_ERROR(glShaderSource(result, 1, &sources, &lengths));
+ MBGL_CHECK_ERROR(glCompileShader(result));
+
+ GLint status = 0;
+ MBGL_CHECK_ERROR(glGetShaderiv(result, GL_COMPILE_STATUS, &status));
+ if (status != 0) {
+ return result;
+ }
+
+ GLint logLength;
+ MBGL_CHECK_ERROR(glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength));
+ if (logLength > 0) {
+ const auto log = std::make_unique<GLchar[]>(logLength);
+ MBGL_CHECK_ERROR(glGetShaderInfoLog(result, logLength, &logLength, log.get()));
+ Log::Error(Event::Shader, "Shader failed to compile: %s", log.get());
+ }
+
+ throw std::runtime_error("shader failed to compile");
}
-UniqueShader Context::createVertexShader() {
- return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)), { this } };
+UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentShader) {
+ UniqueProgram result { MBGL_CHECK_ERROR(glCreateProgram()), { this } };
+
+ MBGL_CHECK_ERROR(glAttachShader(result, vertexShader));
+ MBGL_CHECK_ERROR(glAttachShader(result, fragmentShader));
+
+ return result;
}
-UniqueShader Context::createFragmentShader() {
- return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)), { this } };
+void Context::linkProgram(ProgramID program_) {
+ MBGL_CHECK_ERROR(glLinkProgram(program_));
+
+ GLint status;
+ MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_LINK_STATUS, &status));
+ if (status == GL_TRUE) {
+ return;
+ }
+
+ GLint logLength;
+ MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_INFO_LOG_LENGTH, &logLength));
+ const auto log = std::make_unique<GLchar[]>(logLength);
+ if (logLength > 0) {
+ MBGL_CHECK_ERROR(glGetProgramInfoLog(program_, logLength, &logLength, log.get()));
+ Log::Error(Event::Shader, "Program failed to link: %s", log.get());
+ }
+
+ throw std::runtime_error("program failed to link");
}
UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size) {
@@ -105,21 +105,12 @@ UniqueBuffer Context::createIndexBuffer(const void* data, std::size_t size) {
BufferID id = 0;
MBGL_CHECK_ERROR(glGenBuffers(1, &id));
UniqueBuffer result { std::move(id), { this } };
+ vertexArrayObject = 0;
elementBuffer = result;
MBGL_CHECK_ERROR(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW));
return result;
}
-void Context::bindAttribute(const AttributeBinding& binding, std::size_t stride, const int8_t* offset) {
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(binding.location));
- MBGL_CHECK_ERROR(glVertexAttribPointer(binding.location,
- binding.count,
- static_cast<GLenum>(binding.type),
- false,
- static_cast<GLsizei>(stride),
- offset + binding.offset));
-}
-
UniqueTexture Context::createTexture() {
if (pooledTextures.empty()) {
pooledTextures.resize(TextureMax);
@@ -131,31 +122,60 @@ UniqueTexture Context::createTexture() {
return UniqueTexture{ std::move(id), { this } };
}
-UniqueVertexArray Context::createVertexArray() {
- 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));
return UniqueFramebuffer{ std::move(id), { this } };
}
-UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type,
- const uint16_t width,
- const uint16_t height) {
+UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, const Size size) {
RenderbufferID id = 0;
MBGL_CHECK_ERROR(glGenRenderbuffers(1, &id));
UniqueRenderbuffer renderbuffer{ std::move(id), { this } };
bindRenderbuffer = renderbuffer;
MBGL_CHECK_ERROR(
- glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), width, height));
+ glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), size.width, size.height));
return renderbuffer;
}
+std::unique_ptr<uint8_t[]> Context::readFramebuffer(const Size size, const TextureFormat format, const bool flip) {
+ const size_t stride = size.width * (format == TextureFormat::RGBA ? 4 : 1);
+ auto data = std::make_unique<uint8_t[]>(stride * size.height);
+
+#if not MBGL_USE_GLES2
+ // When reading data from the framebuffer, make sure that we are storing the values
+ // tightly packed into the buffer to avoid buffer overruns.
+ pixelStorePack = { 1 };
+#endif // MBGL_USE_GLES2
+
+ MBGL_CHECK_ERROR(glReadPixels(0, 0, size.width, size.height, static_cast<GLenum>(format),
+ GL_UNSIGNED_BYTE, data.get()));
+
+ if (flip) {
+ auto tmp = std::make_unique<uint8_t[]>(stride);
+ uint8_t* rgba = data.get();
+ for (int i = 0, j = size.height - 1; i < j; i++, j--) {
+ std::memcpy(tmp.get(), rgba + i * stride, stride);
+ std::memcpy(rgba + i * stride, rgba + j * stride, stride);
+ std::memcpy(rgba + j * stride, tmp.get(), stride);
+ }
+ }
+
+ return data;
+}
+
+#if not MBGL_USE_GLES2
+void Context::drawPixels(const Size size, const void* data, TextureFormat format) {
+ pixelStoreUnpack = { 1 };
+ if (format != TextureFormat::RGBA) {
+ format = static_cast<TextureFormat>(GL_LUMINANCE);
+ }
+ MBGL_CHECK_ERROR(glDrawPixels(size.width, size.height, static_cast<GLenum>(GL_LUMINANCE),
+ GL_UNSIGNED_BYTE, data));
+}
+#endif // MBGL_USE_GLES2
+
namespace {
void checkFramebuffer() {
@@ -251,35 +271,62 @@ Framebuffer Context::createFramebuffer(const Texture& color) {
}
UniqueTexture
-Context::createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit unit) {
+Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit) {
auto obj = createTexture();
- activeTexture = unit;
- texture[unit] = obj;
+ updateTexture(obj, size, data, format, unit);
+ // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures.
+ // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus.
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
- MBGL_CHECK_ERROR(
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data));
return obj;
}
+void Context::updateTexture(
+ TextureID id, const Size size, const void* data, TextureFormat format, TextureUnit unit) {
+ activeTexture = unit;
+ texture[unit] = id;
+ MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLenum>(format), size.width,
+ size.height, 0, static_cast<GLenum>(format), GL_UNSIGNED_BYTE,
+ data));
+}
+
void Context::bindTexture(Texture& obj,
TextureUnit unit,
TextureFilter filter,
- TextureMipMap mipmap) {
- if (filter != obj.filter || mipmap != obj.mipmap) {
+ TextureMipMap mipmap,
+ TextureWrap wrapX,
+ TextureWrap wrapY) {
+ if (filter != obj.filter || mipmap != obj.mipmap || wrapX != obj.wrapX || wrapY != obj.wrapY) {
activeTexture = unit;
texture[unit] = obj.texture;
- MBGL_CHECK_ERROR(glTexParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- filter == TextureFilter::Linear
- ? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)
- : (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
- filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST));
- obj.filter = filter;
- obj.mipmap = mipmap;
+
+ if (filter != obj.filter || mipmap != obj.mipmap) {
+ MBGL_CHECK_ERROR(glTexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ filter == TextureFilter::Linear
+ ? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)
+ : (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
+ MBGL_CHECK_ERROR(
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST));
+ obj.filter = filter;
+ obj.mipmap = mipmap;
+ }
+ if (wrapX != obj.wrapX) {
+
+ MBGL_CHECK_ERROR(
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ wrapX == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
+ obj.wrapX = wrapX;
+ }
+ if (wrapY != obj.wrapY) {
+ MBGL_CHECK_ERROR(
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ wrapY == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
+ obj.wrapY = wrapY;
+ }
} else if (texture[unit] != obj.texture) {
// We are checking first to avoid setting the active texture without a subsequent
// texture bind.
@@ -306,6 +353,7 @@ void Context::setDirtyState() {
depthTest.setDirty();
depthFunc.setDirty();
blend.setDirty();
+ blendEquation.setDirty();
blendFunc.setDirty();
blendColor.setDirty();
colorMask.setDirty();
@@ -316,8 +364,13 @@ void Context::setDirtyState() {
lineWidth.setDirty();
activeTexture.setDirty();
#if not MBGL_USE_GLES2
+ pointSize.setDirty();
pixelZoom.setDirty();
rasterPos.setDirty();
+ pixelStorePack.setDirty();
+ pixelStoreUnpack.setDirty();
+ pixelTransferDepth.setDirty();
+ pixelTransferStencil.setDirty();
#endif // MBGL_USE_GLES2
for (auto& tex : texture) {
tex.setDirty();
@@ -327,6 +380,153 @@ void Context::setDirtyState() {
vertexArrayObject.setDirty();
}
+void Context::clear(optional<mbgl::Color> color,
+ optional<float> depth,
+ optional<int32_t> stencil) {
+ GLbitfield mask = 0;
+
+ if (color) {
+ mask |= GL_COLOR_BUFFER_BIT;
+ clearColor = *color;
+ colorMask = { true, true, true, true };
+ }
+
+ if (depth) {
+ mask |= GL_DEPTH_BUFFER_BIT;
+ clearDepth = *depth;
+ depthMask = true;
+ }
+
+ if (stencil) {
+ mask |= GL_STENCIL_BUFFER_BIT;
+ clearStencil = *stencil;
+ stencilMask = 0xFF;
+ }
+
+ MBGL_CHECK_ERROR(glClear(mask));
+}
+
+#if not MBGL_USE_GLES2
+PrimitiveType Context::operator()(const Points& points) {
+ pointSize = points.pointSize;
+ return PrimitiveType::Points;
+}
+#else
+PrimitiveType Context::operator()(const Points&) {
+ return PrimitiveType::Points;
+}
+#endif // MBGL_USE_GLES2
+
+PrimitiveType Context::operator()(const Lines& lines) {
+ lineWidth = lines.lineWidth;
+ return PrimitiveType::Lines;
+}
+
+PrimitiveType Context::operator()(const LineStrip& lineStrip) {
+ lineWidth = lineStrip.lineWidth;
+ return PrimitiveType::LineStrip;
+}
+
+PrimitiveType Context::operator()(const Triangles&) {
+ return PrimitiveType::Triangles;
+}
+
+PrimitiveType Context::operator()(const TriangleStrip&) {
+ return PrimitiveType::TriangleStrip;
+}
+
+void Context::setDepthMode(const DepthMode& depth) {
+ if (depth.func == DepthMode::Always && !depth.mask) {
+ depthTest = false;
+ } else {
+ depthTest = true;
+ depthFunc = depth.func;
+ depthMask = depth.mask;
+ depthRange = depth.range;
+ }
+}
+
+void Context::setStencilMode(const StencilMode& stencil) {
+ if (stencil.test.is<StencilMode::Always>() && !stencil.mask) {
+ stencilTest = false;
+ } else {
+ stencilTest = true;
+ stencilMask = stencil.mask;
+ stencilOp = { stencil.fail, stencil.depthFail, stencil.pass };
+ apply_visitor([&] (const auto& test) {
+ stencilFunc = { test.func, stencil.ref, test.mask };
+ }, stencil.test);
+ }
+}
+
+void Context::setColorMode(const ColorMode& color) {
+ if (color.blendFunction.is<ColorMode::Replace>()) {
+ blend = false;
+ } else {
+ blend = true;
+ blendColor = color.blendColor;
+ apply_visitor([&] (const auto& blendFunction) {
+ blendEquation = ColorMode::BlendEquation(blendFunction.equation);
+ blendFunc = { blendFunction.srcFactor, blendFunction.dstFactor };
+ }, color.blendFunction);
+ }
+
+ 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::performCleanup() {
for (auto id : abandonedPrograms) {
if (program == id) {
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index cf8bb2658b..093afa20ed 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -8,12 +8,21 @@
#include <mbgl/gl/framebuffer.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/gl/index_buffer.hpp>
-#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/types.hpp>
+#include <mbgl/gl/draw_mode.hpp>
+#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>
+
+#include <functional>
#include <memory>
#include <vector>
#include <array>
+#include <string>
+#include <unordered_map>
namespace mbgl {
@@ -27,32 +36,31 @@ class Context : private util::noncopyable {
public:
~Context();
- UniqueProgram createProgram();
- UniqueShader createVertexShader();
- UniqueShader createFragmentShader();
+ UniqueShader createShader(ShaderType type, const std::string& source);
+ UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader);
+ void linkProgram(ProgramID);
UniqueTexture createTexture();
- UniqueVertexArray createVertexArray();
- template <class V>
- VertexBuffer<V> createVertexBuffer(std::vector<V>&& v) {
- return VertexBuffer<V> {
- v.size(),
- createVertexBuffer(v.data(), v.size() * sizeof(V))
+ template <class Vertex, class DrawMode>
+ VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v) {
+ return VertexBuffer<Vertex, DrawMode> {
+ v.vertexSize(),
+ createVertexBuffer(v.data(), v.byteSize())
};
}
- template <class P>
- IndexBuffer<P> createIndexBuffer(std::vector<P>&& v) {
- return IndexBuffer<P> {
- createIndexBuffer(v.data(), v.size() * sizeof(P))
+ template <class DrawMode>
+ IndexBuffer<DrawMode> createIndexBuffer(IndexVector<DrawMode>&& v) {
+ return IndexBuffer<DrawMode> {
+ createIndexBuffer(v.data(), v.byteSize())
};
}
template <RenderbufferType type>
- Renderbuffer<type> createRenderbuffer(const std::array<uint16_t, 2>& size) {
+ Renderbuffer<type> createRenderbuffer(const Size size) {
static_assert(type == RenderbufferType::RGBA || type == RenderbufferType::DepthStencil,
"invalid renderbuffer type");
- return { size, createRenderbuffer(type, size[0], size[1]) };
+ return { size, createRenderbuffer(type, size) };
}
Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&,
@@ -62,30 +70,73 @@ public:
const Renderbuffer<RenderbufferType::DepthStencil>&);
Framebuffer createFramebuffer(const Texture&);
+ template <typename Image,
+ TextureFormat format = Image::channels == 4 ? TextureFormat::RGBA
+ : TextureFormat::Alpha>
+ Image readFramebuffer(const Size size, bool flip = true) {
+ static_assert(Image::channels == (format == TextureFormat::RGBA ? 4 : 1),
+ "image format mismatch");
+ return { size, readFramebuffer(size, format, flip) };
+ }
+
+#if not MBGL_USE_GLES2
+ template <typename Image>
+ void drawPixels(const Image& image) {
+ auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
+ drawPixels(image.size, image.data.get(), format);
+ }
+#endif // MBGL_USE_GLES2
+
// Create a texture from an image with data.
template <typename Image>
Texture createTexture(const Image& image, TextureUnit unit = 0) {
- return { {{ image.width, image.height }},
- createTexture(image.width, image.height, image.data.get(), unit) };
+ auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
+ return { image.size, createTexture(image.size, image.data.get(), format, unit) };
+ }
+
+ template <typename Image>
+ void updateTexture(Texture& obj, const Image& image, TextureUnit unit = 0) {
+ auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
+ updateTexture(obj.texture.get(), image.size, image.data.get(), format, unit);
+ obj.size = image.size;
}
// Creates an empty texture with the specified dimensions.
- Texture createTexture(const std::array<uint16_t, 2>& size, TextureUnit unit = 0) {
- return { size, createTexture(size[0], size[1], nullptr, unit) };
+ Texture createTexture(const Size size,
+ TextureFormat format = TextureFormat::RGBA,
+ TextureUnit unit = 0) {
+ return { size, createTexture(size, nullptr, format, unit) };
}
void bindTexture(Texture&,
TextureUnit = 0,
TextureFilter = TextureFilter::Nearest,
- TextureMipMap = TextureMipMap::No);
-
- template <class Shader, class Vertex>
- void bindAttributes(const Shader& shader, const VertexBuffer<Vertex>&, const int8_t* offset) {
- static_assert(std::is_same<typename Shader::VertexType, Vertex>::value, "vertex type mismatch");
- for (const auto& binding : AttributeBindings<Shader, Vertex>()(shader)) {
- bindAttribute(binding, sizeof(Vertex), offset);
- }
- }
+ TextureMipMap = TextureMipMap::No,
+ TextureWrap wrapX = TextureWrap::Clamp,
+ TextureWrap wrapY = TextureWrap::Clamp);
+
+ void clear(optional<mbgl::Color> color,
+ 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 setDepthMode(const DepthMode&);
+ void setStencilMode(const StencilMode&);
+ void setColorMode(const ColorMode&);
// Actually remove the objects we marked as abandoned with the above methods.
// Only call this while the OpenGL context is exclusive to this thread.
@@ -107,6 +158,23 @@ public:
void setDirtyState();
+ State<value::ActiveTexture> activeTexture;
+ State<value::BindFramebuffer> bindFramebuffer;
+ State<value::Viewport> viewport;
+ std::array<State<value::BindTexture>, 2> texture;
+ State<value::BindVertexArray> vertexArrayObject;
+ State<value::Program> program;
+
+#if not MBGL_USE_GLES2
+ State<value::PixelZoom> pixelZoom;
+ State<value::RasterPos> rasterPos;
+ State<value::PixelStorePack> pixelStorePack;
+ State<value::PixelStoreUnpack> pixelStoreUnpack;
+ State<value::PixelTransferDepth> pixelTransferDepth;
+ State<value::PixelTransferStencil> pixelTransferStencil;
+#endif // MBGL_USE_GLES2
+
+private:
State<value::StencilFunc> stencilFunc;
State<value::StencilMask> stencilMask;
State<value::StencilTest> stencilTest;
@@ -116,34 +184,37 @@ public:
State<value::DepthTest> depthTest;
State<value::DepthFunc> depthFunc;
State<value::Blend> blend;
+ State<value::BlendEquation> blendEquation;
State<value::BlendFunc> blendFunc;
State<value::BlendColor> blendColor;
State<value::ColorMask> colorMask;
State<value::ClearDepth> clearDepth;
State<value::ClearColor> clearColor;
State<value::ClearStencil> clearStencil;
- State<value::Program> program;
State<value::LineWidth> lineWidth;
- State<value::ActiveTexture> activeTexture;
- State<value::BindFramebuffer> bindFramebuffer;
- State<value::Viewport> viewport;
State<value::BindRenderbuffer> bindRenderbuffer;
#if not MBGL_USE_GLES2
- State<value::PixelZoom> pixelZoom;
- State<value::RasterPos> rasterPos;
+ State<value::PointSize> pointSize;
#endif // MBGL_USE_GLES2
- std::array<State<value::BindTexture>, 2> texture;
State<value::BindVertexBuffer> vertexBuffer;
State<value::BindElementBuffer> elementBuffer;
- State<value::BindVertexArray> vertexArrayObject;
-private:
UniqueBuffer createVertexBuffer(const void* data, std::size_t size);
UniqueBuffer createIndexBuffer(const void* data, std::size_t size);
- UniqueTexture createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit);
+ UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit);
+ void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit);
UniqueFramebuffer createFramebuffer();
- UniqueRenderbuffer createRenderbuffer(RenderbufferType, uint16_t width, uint16_t height);
- void bindAttribute(const AttributeBinding&, std::size_t stride, const int8_t* offset);
+ UniqueRenderbuffer createRenderbuffer(RenderbufferType, Size size);
+ std::unique_ptr<uint8_t[]> readFramebuffer(Size, TextureFormat, bool flip);
+#if not MBGL_USE_GLES2
+ 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;
diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp
index 1d82b6afb0..8037fc5ef5 100644
--- a/src/mbgl/gl/debugging.cpp
+++ b/src/mbgl/gl/debugging.cpp
@@ -2,8 +2,8 @@
#include <mbgl/gl/debugging.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/extension.hpp>
-#include <mbgl/platform/event.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/event.hpp>
+#include <mbgl/util/logging.hpp>
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
diff --git a/src/mbgl/gl/depth_mode.cpp b/src/mbgl/gl/depth_mode.cpp
new file mode 100644
index 0000000000..21af75a391
--- /dev/null
+++ b/src/mbgl/gl/depth_mode.cpp
@@ -0,0 +1,18 @@
+#include <mbgl/gl/depth_mode.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/util/traits.hpp>
+
+namespace mbgl {
+namespace gl {
+
+static_assert(underlying_type(DepthMode::Never) == GL_NEVER, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::Less) == GL_LESS, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::Equal) == GL_EQUAL, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::Greater) == GL_GREATER, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch");
+static_assert(underlying_type(DepthMode::Always) == GL_ALWAYS, "OpenGL enum mismatch");
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/depth_mode.hpp b/src/mbgl/gl/depth_mode.hpp
new file mode 100644
index 0000000000..37617e3c34
--- /dev/null
+++ b/src/mbgl/gl/depth_mode.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <mbgl/util/range.hpp>
+
+namespace mbgl {
+namespace gl {
+
+class DepthMode {
+public:
+ enum Function {
+ Never = 0x0200,
+ Less = 0x0201,
+ Equal = 0x0202,
+ LessEqual = 0x0203,
+ Greater = 0x0204,
+ NotEqual = 0x0205,
+ GreaterEqual = 0x0206,
+ Always = 0x0207
+ };
+
+ enum Mask : bool {
+ ReadOnly = false,
+ ReadWrite = true
+ };
+
+ Function func;
+ Mask mask;
+ Range<float> range;
+
+ static DepthMode disabled() {
+ return DepthMode { Always, ReadOnly, { 0.0, 1.0 } };
+ }
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/draw_mode.hpp b/src/mbgl/gl/draw_mode.hpp
new file mode 100644
index 0000000000..ab86d5e469
--- /dev/null
+++ b/src/mbgl/gl/draw_mode.hpp
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <mbgl/gl/primitives.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+namespace gl {
+
+class Points {
+public:
+ using Primitive = Point;
+ static constexpr std::size_t bufferGroupSize = 1;
+
+ explicit Points(float pointSize_) : pointSize(pointSize_) {}
+
+ float pointSize;
+};
+
+class Lines {
+public:
+ using Primitive = Line;
+ static constexpr std::size_t bufferGroupSize = 2;
+
+ explicit Lines(float lineWidth_) : lineWidth(lineWidth_) {
+ assert(lineWidth > 0);
+ }
+
+ float lineWidth;
+};
+
+class LineStrip {
+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;
+
+ explicit LineStrip(float lineWidth_) : lineWidth(lineWidth_) {
+ assert(lineWidth > 0);
+ }
+
+ float lineWidth;
+};
+
+class Triangles {
+public:
+ using Primitive = Triangle;
+ static constexpr std::size_t bufferGroupSize = 3;
+};
+
+class TriangleStrip {
+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;
+};
+
+// Special draw mode for use with VertexVector<Indexed, Vertex>, in which
+// case the true draw mode is denoted by the IndexVector type.
+class Indexed {
+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/extension.cpp b/src/mbgl/gl/extension.cpp
index ee94e8ecfd..e6b4d9156e 100644
--- a/src/mbgl/gl/extension.cpp
+++ b/src/mbgl/gl/extension.cpp
@@ -4,6 +4,7 @@
#include <mutex>
#include <string>
#include <vector>
+#include <cstring>
namespace mbgl {
namespace gl {
@@ -26,18 +27,14 @@ static std::once_flag initializeExtensionsOnce;
void InitializeExtensions(glProc (*getProcAddress)(const char*)) {
std::call_once(initializeExtensionsOnce, [getProcAddress] {
- const char* extensionsPtr =
- reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)));
-
- if (!extensionsPtr)
- return;
-
- const std::string extensions = extensionsPtr;
- for (auto fn : detail::extensionFunctions()) {
- for (auto probe : fn.second) {
- if (extensions.find(probe.first) != std::string::npos) {
- *fn.first = getProcAddress(probe.second);
- break;
+ if (const char* extensions =
+ reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) {
+ for (auto fn : detail::extensionFunctions()) {
+ for (auto probe : fn.second) {
+ if (strstr(extensions, probe.first) != nullptr) {
+ *fn.first = getProcAddress(probe.second);
+ break;
+ }
}
}
}
diff --git a/src/mbgl/gl/framebuffer.hpp b/src/mbgl/gl/framebuffer.hpp
index 880fed159e..91ed467b40 100644
--- a/src/mbgl/gl/framebuffer.hpp
+++ b/src/mbgl/gl/framebuffer.hpp
@@ -1,15 +1,14 @@
#pragma once
#include <mbgl/gl/object.hpp>
-
-#include <array>
+#include <mbgl/util/size.hpp>
namespace mbgl {
namespace gl {
class Framebuffer {
public:
- std::array<uint16_t, 2> size;
+ Size size;
gl::UniqueFramebuffer framebuffer;
};
diff --git a/src/mbgl/gl/index_buffer.hpp b/src/mbgl/gl/index_buffer.hpp
index f38d7fd4f5..b3610f4154 100644
--- a/src/mbgl/gl/index_buffer.hpp
+++ b/src/mbgl/gl/index_buffer.hpp
@@ -1,39 +1,38 @@
#pragma once
#include <mbgl/gl/object.hpp>
+#include <mbgl/gl/draw_mode.hpp>
+#include <mbgl/util/ignore.hpp>
+
+#include <vector>
namespace mbgl {
namespace gl {
-class Line {
+template <class DrawMode>
+class IndexVector {
public:
- Line(uint16_t a_, uint16_t b_)
- : a(a_), b(b_) {}
-
- uint16_t a;
- uint16_t b;
+ static constexpr std::size_t groupSize = DrawMode::bufferGroupSize;
- static constexpr std::size_t IndexCount = 2;
-};
+ template <class... Args>
+ void emplace_back(Args&&... args) {
+ static_assert(sizeof...(args) == groupSize, "wrong buffer element count");
+ util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...});
+ }
-class Triangle {
-public:
- Triangle(uint16_t a_, uint16_t b_, uint16_t c_)
- : a(a_), b(b_), c(c_) {}
+ std::size_t indexSize() const { return v.size(); }
+ std::size_t byteSize() const { return v.size() * sizeof(uint16_t); }
- uint16_t a;
- uint16_t b;
- uint16_t c;
+ bool empty() const { return v.empty(); }
+ const uint16_t* data() const { return v.data(); }
- static constexpr std::size_t IndexCount = 3;
+private:
+ std::vector<uint16_t> v;
};
-template <class Primitive>
+template <class DrawMode>
class IndexBuffer {
public:
- static_assert(std::is_same<Primitive, Line>::value || std::is_same<Primitive, Triangle>::value,
- "primitive must be Line or Triangle");
- static constexpr std::size_t primitiveSize = sizeof(Primitive);
UniqueBuffer buffer;
};
diff --git a/src/mbgl/gl/primitives.hpp b/src/mbgl/gl/primitives.hpp
new file mode 100644
index 0000000000..fe6b1b2e5b
--- /dev/null
+++ b/src/mbgl/gl/primitives.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+namespace mbgl {
+namespace gl {
+
+class Point {
+public:
+ static constexpr std::size_t vertexCount = 1;
+};
+
+class Line {
+public:
+ static constexpr std::size_t vertexCount = 2;
+};
+
+class Triangle {
+public:
+ static constexpr std::size_t vertexCount = 3;
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp
new file mode 100644
index 0000000000..33387e9d4e
--- /dev/null
+++ b/src/mbgl/gl/program.hpp
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <mbgl/gl/types.hpp>
+#include <mbgl/gl/object.hpp>
+#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/vertex_buffer.hpp>
+#include <mbgl/gl/index_buffer.hpp>
+#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/uniform.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace gl {
+
+template <class P, class As, class Us>
+class Program {
+public:
+ using Primitive = P;
+ 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");
+
+ 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)),
+ uniformsState((context.linkProgram(program), Uniforms::state(program))) {}
+
+ template <class DrawMode>
+ void draw(Context& context,
+ DrawMode drawMode,
+ DepthMode depthMode,
+ StencilMode stencilMode,
+ ColorMode colorMode,
+ UniformValues&& uniformValues,
+ const VertexBuffer<Vertex>& vertexBuffer,
+ 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)
+ });
+ }
+
+private:
+ UniqueShader vertexShader;
+ UniqueShader fragmentShader;
+ UniqueProgram program;
+
+ typename Attributes::State attributesState;
+ typename Uniforms::State uniformsState;
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/renderbuffer.hpp b/src/mbgl/gl/renderbuffer.hpp
index 9e8993bb77..cc8ff13268 100644
--- a/src/mbgl/gl/renderbuffer.hpp
+++ b/src/mbgl/gl/renderbuffer.hpp
@@ -1,8 +1,7 @@
#pragma once
#include <mbgl/gl/object.hpp>
-
-#include <array>
+#include <mbgl/util/size.hpp>
namespace mbgl {
namespace gl {
@@ -11,7 +10,7 @@ template <RenderbufferType renderbufferType>
class Renderbuffer {
public:
using type = std::integral_constant<RenderbufferType, renderbufferType>;
- std::array<uint16_t, 2> size;
+ Size size;
gl::UniqueRenderbuffer renderbuffer;
};
diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp
new file mode 100644
index 0000000000..8f74afd237
--- /dev/null
+++ b/src/mbgl/gl/segment.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <mbgl/util/optional.hpp>
+
+#include <cstddef>
+
+namespace mbgl {
+namespace gl {
+
+class Segment {
+public:
+ Segment(std::size_t vertexOffset_,
+ std::size_t indexOffset_,
+ std::size_t vertexLength_ = 0,
+ std::size_t indexLength_ = 0)
+ : vertexOffset(vertexOffset_),
+ indexOffset(indexOffset_),
+ vertexLength(vertexLength_),
+ indexLength(indexLength_) {}
+
+ const std::size_t vertexOffset;
+ const std::size_t indexOffset;
+
+ std::size_t vertexLength;
+ std::size_t indexLength;
+
+private:
+ friend class Context;
+ mutable optional<UniqueVertexArray> vao;
+};
+
+template <class Attributes>
+class SegmentVector : public std::vector<Segment> {
+public:
+ SegmentVector() = default;
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/shader.cpp b/src/mbgl/gl/shader.cpp
deleted file mode 100644
index d8ee734567..0000000000
--- a/src/mbgl/gl/shader.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/gl/context.hpp>
-#include <mbgl/util/stopwatch.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/platform/platform.hpp>
-
-#include <cstring>
-#include <cassert>
-#include <iostream>
-#include <string>
-#include <fstream>
-#include <cstdio>
-#include <cassert>
-
-namespace mbgl {
-namespace gl {
-
-Shader::Shader(const char* name_,
- const char* vertexSource,
- const char* fragmentSource,
- Context& context,
- Defines defines)
- : name(name_),
- program(context.createProgram()),
- vertexShader(context.createVertexShader()),
- fragmentShader(context.createFragmentShader()) {
- util::stopwatch stopwatch("shader compilation", Event::Shader);
-
- if (!compileShader(vertexShader, vertexSource)) {
- Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertexSource);
- throw util::ShaderException(std::string { "Vertex shader " } + name + " failed to compile");
- }
-
- std::string fragment(fragmentSource);
- if (defines & Defines::Overdraw) {
- assert(fragment.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos);
- fragment.replace(fragment.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n");
- }
-
- if (!compileShader(fragmentShader, fragment.c_str())) {
- Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragmentSource);
- throw util::ShaderException(std::string { "Fragment shader " } + name + " failed to compile");
- }
-
- // Attach shaders
- MBGL_CHECK_ERROR(glAttachShader(program.get(), vertexShader.get()));
- MBGL_CHECK_ERROR(glAttachShader(program.get(), fragmentShader.get()));
-
- // Link program
- GLint status;
- MBGL_CHECK_ERROR(glLinkProgram(program.get()));
-
- MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_LINK_STATUS, &status));
- if (status == 0) {
- GLint logLength;
- MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &logLength));
- const auto log = std::make_unique<GLchar[]>(logLength);
- if (logLength > 0) {
- MBGL_CHECK_ERROR(glGetProgramInfoLog(program.get(), logLength, &logLength, log.get()));
- Log::Error(Event::Shader, "Program failed to link: %s", log.get());
- }
- throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get());
- }
-}
-
-bool Shader::compileShader(UniqueShader& shader, const GLchar *source) {
- GLint status = 0;
-
- const GLsizei lengths = static_cast<GLsizei>(std::strlen(source));
- MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, &source, &lengths));
-
- MBGL_CHECK_ERROR(glCompileShader(shader.get()));
-
- MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status));
- if (status == 0) {
- GLint logLength;
- MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_INFO_LOG_LENGTH, &logLength));
- if (logLength > 0) {
- const auto log = std::make_unique<GLchar[]>(logLength);
- MBGL_CHECK_ERROR(glGetShaderInfoLog(shader.get(), logLength, &logLength, log.get()));
- Log::Error(Event::Shader, "Shader failed to compile: %s", log.get());
- }
- return false;
- }
-
- MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status));
- if (status == GL_FALSE) {
- Log::Error(Event::Shader, "Shader %s failed to compile.", name);
- return false;
- }
-
- return true;
-}
-
-Shader::~Shader() {
- if (program.get()) {
- MBGL_CHECK_ERROR(glDetachShader(program.get(), vertexShader.get()));
- MBGL_CHECK_ERROR(glDetachShader(program.get(), fragmentShader.get()));
- }
-}
-
-UniformLocation Shader::getUniformLocation(const char* uniform) const {
- return MBGL_CHECK_ERROR(glGetUniformLocation(program.get(), uniform));
-}
-
-AttributeLocation Shader::getAttributeLocation(const char* attribute) const {
- return MBGL_CHECK_ERROR(glGetAttribLocation(program.get(), attribute));
-}
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/shader.hpp b/src/mbgl/gl/shader.hpp
deleted file mode 100644
index f88bd4f867..0000000000
--- a/src/mbgl/gl/shader.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/types.hpp>
-#include <mbgl/gl/object.hpp>
-#include <mbgl/util/noncopyable.hpp>
-
-namespace mbgl {
-namespace gl {
-
-class Context;
-
-class Shader : private util::noncopyable {
-public:
- ~Shader();
- const char* name;
-
- ProgramID getID() const {
- return program.get();
- }
-
- AttributeLocation getAttributeLocation(const char* uniform) const;
- UniformLocation getUniformLocation(const char* uniform) const;
-
- enum Defines : bool {
- None = false,
- Overdraw = true,
- };
-
-protected:
- Shader(const char* name_,
- const char* vertex,
- const char* fragment,
- Context&,
- Defines defines = Defines::None);
-
-private:
- bool compileShader(UniqueShader&, const char *source);
-
- UniqueProgram program;
- UniqueShader vertexShader;
- UniqueShader fragmentShader;
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/stencil_mode.cpp b/src/mbgl/gl/stencil_mode.cpp
new file mode 100644
index 0000000000..6858d6d106
--- /dev/null
+++ b/src/mbgl/gl/stencil_mode.cpp
@@ -0,0 +1,27 @@
+#include <mbgl/gl/stencil_mode.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/util/traits.hpp>
+
+namespace mbgl {
+namespace gl {
+
+static_assert(StencilMode::Never::func == GL_NEVER, "OpenGL enum mismatch");
+static_assert(StencilMode::Less::func == GL_LESS, "OpenGL enum mismatch");
+static_assert(StencilMode::Equal::func == GL_EQUAL, "OpenGL enum mismatch");
+static_assert(StencilMode::LessEqual::func == GL_LEQUAL, "OpenGL enum mismatch");
+static_assert(StencilMode::Greater::func == GL_GREATER, "OpenGL enum mismatch");
+static_assert(StencilMode::NotEqual::func == GL_NOTEQUAL, "OpenGL enum mismatch");
+static_assert(StencilMode::GreaterEqual::func == GL_GEQUAL, "OpenGL enum mismatch");
+static_assert(StencilMode::Always::func == GL_ALWAYS, "OpenGL enum mismatch");
+
+static_assert(underlying_type(StencilMode::Keep) == GL_KEEP, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Zero) == GL_ZERO, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Replace) == GL_REPLACE, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Increment) == GL_INCR, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::IncrementWrap) == GL_INCR_WRAP, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Decrement) == GL_DECR, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::DecrementWrap) == GL_DECR_WRAP, "OpenGL enum mismatch");
+static_assert(underlying_type(StencilMode::Invert) == GL_INVERT, "OpenGL enum mismatch");
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/stencil_mode.hpp b/src/mbgl/gl/stencil_mode.hpp
new file mode 100644
index 0000000000..bc959c9a73
--- /dev/null
+++ b/src/mbgl/gl/stencil_mode.hpp
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+namespace gl {
+
+class StencilMode {
+public:
+ template <uint32_t F>
+ struct SimpleTest {
+ static constexpr uint32_t func = F;
+ static constexpr uint32_t mask = 0;
+ };
+
+ template <uint32_t F>
+ struct MaskedTest {
+ static constexpr uint32_t func = F;
+ uint32_t mask;
+ };
+
+ using Never = SimpleTest<0x0200>;
+ using Less = MaskedTest<0x0201>;
+ using Equal = MaskedTest<0x0202>;
+ using LessEqual = MaskedTest<0x0203>;
+ using Greater = MaskedTest<0x0204>;
+ using NotEqual = MaskedTest<0x0205>;
+ using GreaterEqual = MaskedTest<0x0206>;
+ using Always = SimpleTest<0x0207>;
+
+ using Test = variant<
+ Never,
+ Less,
+ Equal,
+ LessEqual,
+ Greater,
+ NotEqual,
+ GreaterEqual,
+ Always>;
+
+ enum Op {
+ Zero = 0x0000,
+ Keep = 0x1E00,
+ Replace = 0x1E01,
+ Increment = 0x1E02,
+ Decrement = 0x1E03,
+ Invert = 0x150A,
+ IncrementWrap = 0x8507,
+ DecrementWrap = 0x8508
+ };
+
+ Test test;
+ int32_t ref;
+ uint32_t mask;
+
+ Op fail;
+ Op depthFail;
+ Op pass;
+
+ static StencilMode disabled() {
+ return StencilMode { Always(), 0, 0, Keep, Keep, Keep };
+ }
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/texture.hpp b/src/mbgl/gl/texture.hpp
index 49e1323095..5330689ac2 100644
--- a/src/mbgl/gl/texture.hpp
+++ b/src/mbgl/gl/texture.hpp
@@ -1,18 +1,19 @@
#pragma once
#include <mbgl/gl/object.hpp>
-
-#include <array>
+#include <mbgl/util/size.hpp>
namespace mbgl {
namespace gl {
class Texture {
public:
- std::array<uint16_t, 2> size;
+ Size size;
UniqueTexture texture;
TextureFilter filter = TextureFilter::Nearest;
TextureMipMap mipmap = TextureMipMap::No;
+ TextureWrap wrapX = TextureWrap::Clamp;
+ TextureWrap wrapY = TextureWrap::Clamp;
};
} // namespace gl
diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp
index dccc61b03a..577629d5d3 100644
--- a/src/mbgl/gl/types.hpp
+++ b/src/mbgl/gl/types.hpp
@@ -19,9 +19,10 @@ using AttributeLocation = int32_t;
using UniformLocation = int32_t;
using TextureUnit = uint8_t;
-using DepthValue = double;
-using StencilValue = int32_t;
-using StencilMaskValue = uint32_t;
+enum class ShaderType : uint32_t {
+ Vertex = 0x8B31,
+ Fragment = 0x8B30
+};
enum class DataType : uint32_t {
Byte = 0x1400,
@@ -43,11 +44,6 @@ template <> struct DataTypeOf<int32_t> : std::integral_constant<DataType, DataT
template <> struct DataTypeOf<uint32_t> : std::integral_constant<DataType, DataType::UnsignedInteger> {};
template <> struct DataTypeOf<float> : std::integral_constant<DataType, DataType::Float> {};
-enum class BufferType : uint32_t {
- Vertex = 0x8892,
- Element = 0x8893
-};
-
enum class RenderbufferType : uint32_t {
RGBA = 0x8058,
DepthStencil = 0x88F0,
@@ -55,74 +51,37 @@ enum class RenderbufferType : uint32_t {
enum class TextureMipMap : bool { No = false, Yes = true };
enum class TextureFilter : bool { Nearest = false, Linear = true };
-
-enum class StencilTestFunction : uint32_t {
- Never = 0x0200,
- Less = 0x0201,
- Equal = 0x0202,
- LessEqual = 0x0203,
- Greater = 0x0204,
- NotEqual = 0x0205,
- GreaterEqual = 0x0206,
- Always = 0x0207,
+enum class TextureWrap : bool { Clamp, Repeat };
+enum class TextureFormat : uint32_t {
+ RGBA = 0x1908,
+ Alpha = 0x1906,
+#if not MBGL_USE_GLES2
+ Stencil = 0x1901,
+ Depth = 0x1902,
+#endif // MBGL_USE_GLES2
};
-enum class StencilTestOperation : uint32_t {
- Keep = 0x1E00,
- Zero = 0x0000,
- Replace = 0x1E01,
- Increment = 0x1E02,
- IncrementWrap = 0x8507,
- Decrement = 0x1E03,
- DecrementWrap = 0x8508,
- Invert = 0x150A,
+enum class PrimitiveType {
+ Points = 0x0000,
+ Lines = 0x0001,
+ LineLoop = 0x0002,
+ LineStrip = 0x0003,
+ Triangles = 0x0004,
+ TriangleStrip = 0x0005,
+ TriangleFan = 0x0006
};
-enum class DepthTestFunction : uint32_t {
- Never = 0x0200,
- Less = 0x0201,
- Equal = 0x0202,
- LessEqual = 0x0203,
- Greater = 0x0204,
- NotEqual = 0x0205,
- GreaterEqual = 0x0206,
- Always = 0x0207,
-};
+#if not MBGL_USE_GLES2
-enum class BlendSourceFactor : uint32_t {
- Zero = 0x0000,
- One = 0x0001,
- SrcColor = 0x0300,
- OneMinusSrcColor = 0x0301,
- DstColor = 0x0306,
- OneMinusDstColor = 0x0307,
- SrcAlpha = 0x0302,
- OneMinusSrcAlpha = 0x0303,
- DstAlpha = 0x0304,
- OneMinusDstAlpha = 0x0305,
- ConstantColor = 0x8001,
- OneMinusConstantColor = 0x8002,
- ConstantAlpha = 0x8003,
- OneMinusConstantAlpha = 0x8004,
- SrcAlphaSaturate = 0x0308,
+struct PixelStorageType {
+ int32_t alignment;
};
-enum class BlendDestinationFactor : uint32_t {
- Zero = 0x0000,
- One = 0x0001,
- SrcColor = 0x0300,
- OneMinusSrcColor = 0x0301,
- DstColor = 0x0306,
- OneMinusDstColor = 0x0307,
- SrcAlpha = 0x0302,
- OneMinusSrcAlpha = 0x0303,
- DstAlpha = 0x0304,
- OneMinusDstAlpha = 0x0305,
- ConstantColor = 0x8001,
- OneMinusConstantColor = 0x8002,
- ConstantAlpha = 0x8003,
- OneMinusConstantAlpha = 0x8004,
-};
+constexpr bool operator!=(const PixelStorageType& a, const PixelStorageType& b) {
+ return a.alignment != b.alignment;
+}
+
+#endif // MBGL_USE_GLES2
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/uniform.cpp b/src/mbgl/gl/uniform.cpp
index 07a27963d9..7b674f2cde 100644
--- a/src/mbgl/gl/uniform.cpp
+++ b/src/mbgl/gl/uniform.cpp
@@ -1,54 +1,80 @@
#include <mbgl/gl/uniform.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/util/color.hpp>
+#include <mbgl/util/size.hpp>
+#include <mbgl/util/convert.hpp>
namespace mbgl {
namespace gl {
+UniformLocation uniformLocation(ProgramID id, const char* name) {
+ return MBGL_CHECK_ERROR(glGetUniformLocation(id, name));
+}
+
template <>
-void Uniform<float>::bind(const float& t) {
+void bindUniform<float>(UniformLocation location, const float& t) {
MBGL_CHECK_ERROR(glUniform1f(location, t));
}
template <>
-void Uniform<int32_t>::bind(const int32_t& t) {
+void bindUniform<int32_t>(UniformLocation location, const int32_t& t) {
MBGL_CHECK_ERROR(glUniform1i(location, t));
}
template <>
-void Uniform<std::array<float, 2>>::bind(const std::array<float, 2>& t) {
+void bindUniform<std::array<float, 2>>(UniformLocation location, const std::array<float, 2>& t) {
MBGL_CHECK_ERROR(glUniform2fv(location, 1, t.data()));
}
template <>
-void Uniform<std::array<float, 3>>::bind(const std::array<float, 3>& t) {
+void bindUniform<std::array<float, 3>>(UniformLocation location, const std::array<float, 3>& t) {
MBGL_CHECK_ERROR(glUniform3fv(location, 1, t.data()));
}
template <>
-void Uniform<std::array<float, 4>>::bind(const std::array<float, 4>& t) {
+void bindUniform<std::array<float, 4>>(UniformLocation location, const std::array<float, 4>& t) {
MBGL_CHECK_ERROR(glUniform4fv(location, 1, t.data()));
}
template <>
-void Uniform<Color>::bind(const Color& t) {
- std::array<float, 4> a = {{ t.r, t.g, t.b, t.a }};
- MBGL_CHECK_ERROR(glUniform4fv(location, 1, a.data()));
+void bindUniform<std::array<double, 4>>(UniformLocation location, const std::array<double, 4>& t) {
+ MBGL_CHECK_ERROR(glUniformMatrix2fv(location, 1, GL_FALSE, util::convert<float>(t).data()));
+}
+
+template <>
+void bindUniform<std::array<double, 9>>(UniformLocation location, const std::array<double, 9>& t) {
+ MBGL_CHECK_ERROR(glUniformMatrix3fv(location, 1, GL_FALSE, util::convert<float>(t).data()));
+}
+
+template <>
+void bindUniform<std::array<double, 16>>(UniformLocation location, const std::array<double, 16>& t) {
+ MBGL_CHECK_ERROR(glUniformMatrix4fv(location, 1, GL_FALSE, util::convert<float>(t).data()));
+}
+
+
+template <>
+void bindUniform<bool>(UniformLocation location, const bool& t) {
+ return bindUniform(location, int32_t(t));
+}
+
+template <>
+void bindUniform<uint8_t>(UniformLocation location, const uint8_t& t) {
+ bindUniform(location, int32_t(t));
}
template <>
-void UniformMatrix<2>::bind(const std::array<float, 4>& t) {
- MBGL_CHECK_ERROR(glUniformMatrix2fv(location, 1, GL_FALSE, t.data()));
+void bindUniform<Color>(UniformLocation location, const Color& t) {
+ bindUniform(location, std::array<float, 4> {{ t.r, t.g, t.b, t.a }});
}
template <>
-void UniformMatrix<3>::bind(const std::array<float, 9>& t) {
- MBGL_CHECK_ERROR(glUniformMatrix3fv(location, 1, GL_FALSE, t.data()));
+void bindUniform<Size>(UniformLocation location, const Size& t) {
+ bindUniform(location, util::convert<float>(std::array<uint32_t, 2> {{ t.width, t.height }}));
}
template <>
-void UniformMatrix<4>::bind(const std::array<float, 16>& t) {
- MBGL_CHECK_ERROR(glUniformMatrix4fv(location, 1, GL_FALSE, t.data()));
+void bindUniform<std::array<uint16_t, 2>>(UniformLocation location, const std::array<uint16_t, 2>& t) {
+ bindUniform(location, util::convert<float>(t));
}
// Add more as needed.
diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp
index 5af781043d..726cd4fe10 100644
--- a/src/mbgl/gl/uniform.hpp
+++ b/src/mbgl/gl/uniform.hpp
@@ -1,60 +1,80 @@
#pragma once
-#include <mbgl/gl/shader.hpp>
+#include <mbgl/gl/types.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/ignore.hpp>
+#include <mbgl/util/indexed_tuple.hpp>
#include <array>
+#include <functional>
namespace mbgl {
namespace gl {
-template <typename T>
+template <class T>
+void bindUniform(UniformLocation, const T&);
+
+template <class Tag, class T>
+class UniformValue {
+public:
+ explicit UniformValue(T t_) : t(std::move(t_)) {}
+ T t;
+};
+
+template <class Tag, class T>
class Uniform {
public:
- Uniform(const char* name, const Shader& shader)
- : current(), location(shader.getUniformLocation(name)) {
- }
+ using Value = UniformValue<Tag, T>;
- void operator=(const T& t) {
- if (current != t) {
- current = t;
- bind(t);
+ class State {
+ public:
+ void operator=(const Value& value) {
+ if (!current || *current != value.t) {
+ current = value.t;
+ bindUniform(location, value.t);
+ }
}
- }
-
-private:
- void bind(const T&);
- T current;
- UniformLocation location;
+ UniformLocation location;
+ optional<T> current = {};
+ };
};
-template <size_t C, size_t R = C>
-class UniformMatrix {
+template <class Tag, class T>
+using UniformScalar = Uniform<Tag, T>;
+
+template <class Tag, class T, size_t N>
+using UniformVector = Uniform<Tag, std::array<T, N>>;
+
+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_; }
+
+#define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \
+ struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static constexpr auto name = #name_; }
+
+#define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \
+ struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static constexpr auto name = #name_; }
+
+UniformLocation uniformLocation(ProgramID, const char * name);
+
+template <class... Us>
+class Uniforms {
public:
- typedef std::array<float, C*R> T;
+ using State = IndexedTuple<TypeList<Us...>, TypeList<typename Us::State...>>;
+ using Values = IndexedTuple<TypeList<Us...>, TypeList<typename Us::Value...>>;
- UniformMatrix(const char* name, const Shader& shader)
- : current(), location(shader.getUniformLocation(name)) {
+ static State state(const ProgramID& id) {
+ return State { { uniformLocation(id, Us::name) }... };
}
- void operator=(const std::array<double, C*R>& t) {
- bool dirty = false;
- for (unsigned int i = 0; i < C*R; i++) {
- if (current[i] != t[i]) {
- current[i] = t[i];
- dirty = true;
- }
- }
- if (dirty) {
- bind(current);
- }
+ 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)... });
+ };
}
-
-private:
- void bind(const T&);
-
- T current;
- UniformLocation location;
};
} // namespace gl
diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp
index 14cd03efc4..86218f3d9a 100644
--- a/src/mbgl/gl/value.cpp
+++ b/src/mbgl/gl/value.cpp
@@ -94,7 +94,7 @@ StencilFunc::Type StencilFunc::Get() {
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FUNC, &func));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_REF, &ref));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_VALUE_MASK, &mask));
- return { static_cast<StencilTestFunction>(func), ref, static_cast<StencilMaskValue>(mask) };
+ return { static_cast<uint32_t>(func), ref, static_cast<uint32_t>(mask) };
}
const constexpr StencilTest::Type StencilTest::Default;
@@ -122,17 +122,17 @@ StencilOp::Type StencilOp::Get() {
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FAIL, &sfail));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &dpfail));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &dppass));
- return { static_cast<StencilTestOperation>(sfail), static_cast<StencilTestOperation>(dpfail),
- static_cast<StencilTestOperation>(dppass) };
+ return { static_cast<StencilMode::Op>(sfail), static_cast<StencilMode::Op>(dpfail),
+ static_cast<StencilMode::Op>(dppass) };
}
const constexpr DepthRange::Type DepthRange::Default;
void DepthRange::Set(const Type& value) {
#if MBGL_USE_GLES2
- MBGL_CHECK_ERROR(glDepthRangef(value.near, value.far));
+ MBGL_CHECK_ERROR(glDepthRangef(value.min, value.max));
#else
- MBGL_CHECK_ERROR(glDepthRange(value.near, value.far));
+ MBGL_CHECK_ERROR(glDepthRange(value.min, value.max));
#endif
}
@@ -178,6 +178,18 @@ Blend::Type Blend::Get() {
return blend;
}
+const constexpr BlendEquation::Type BlendEquation::Default;
+
+void BlendEquation::Set(const Type& value) {
+ MBGL_CHECK_ERROR(glBlendEquation(static_cast<GLenum>(value)));
+}
+
+BlendEquation::Type BlendEquation::Get() {
+ GLint blend;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_EQUATION_RGB, &blend));
+ return static_cast<Type>(blend);
+}
+
const constexpr BlendFunc::Type BlendFunc::Default;
void BlendFunc::Set(const Type& value) {
@@ -189,8 +201,8 @@ BlendFunc::Type BlendFunc::Get() {
GLint sfactor, dfactor;
MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_SRC_ALPHA, &sfactor));
MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_DST_ALPHA, &dfactor));
- return { static_cast<BlendSourceFactor>(sfactor),
- static_cast<BlendDestinationFactor>(dfactor) };
+ return { static_cast<ColorMode::BlendFactor>(sfactor),
+ static_cast<ColorMode::BlendFactor>(dfactor) };
}
const constexpr BlendColor::Type BlendColor::Default;
@@ -244,14 +256,14 @@ ActiveTexture::Type ActiveTexture::Get() {
const constexpr Viewport::Type Viewport::Default;
void Viewport::Set(const Type& value) {
- MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.width, value.height));
+ MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.size.width, value.size.height));
}
Viewport::Type Viewport::Get() {
GLint viewport[4];
MBGL_CHECK_ERROR(glGetIntegerv(GL_VIEWPORT, viewport));
return { static_cast<int32_t>(viewport[0]), static_cast<int32_t>(viewport[1]),
- static_cast<uint16_t>(viewport[2]), static_cast<uint16_t>(viewport[3]) };
+ { static_cast<uint32_t>(viewport[2]), static_cast<uint32_t>(viewport[3]) } };
}
const constexpr BindFramebuffer::Type BindFramebuffer::Default;
@@ -340,6 +352,18 @@ BindVertexArray::Type BindVertexArray::Get() {
#if not MBGL_USE_GLES2
+const constexpr PointSize::Type PointSize::Default;
+
+void PointSize::Set(const Type& value) {
+ MBGL_CHECK_ERROR(glPointSize(value));
+}
+
+PointSize::Type PointSize::Get() {
+ GLfloat pointSize;
+ MBGL_CHECK_ERROR(glGetFloatv(GL_POINT_SIZE, &pointSize));
+ return pointSize;
+}
+
const constexpr PixelZoom::Type PixelZoom::Default;
void PixelZoom::Set(const Type& value) {
@@ -365,8 +389,63 @@ RasterPos::Type RasterPos::Get() {
return { pos[0], pos[1], pos[2], pos[3] };
}
-#endif // MBGL_USE_GLES2
+const constexpr PixelStorePack::Type PixelStorePack::Default;
+
+void PixelStorePack::Set(const Type& value) {
+ assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 ||
+ value.alignment == 8);
+ MBGL_CHECK_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, value.alignment));
+}
+
+PixelStorePack::Type PixelStorePack::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_PACK_ALIGNMENT, &value.alignment));
+ return value;
+}
+
+const constexpr PixelStoreUnpack::Type PixelStoreUnpack::Default;
+void PixelStoreUnpack::Set(const Type& value) {
+ assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 ||
+ value.alignment == 8);
+ MBGL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, value.alignment));
+}
+
+PixelStoreUnpack::Type PixelStoreUnpack::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_UNPACK_ALIGNMENT, &value.alignment));
+ return value;
+}
+
+const constexpr PixelTransferDepth::Type PixelTransferDepth::Default;
+
+void PixelTransferDepth::Set(const Type& value) {
+ MBGL_CHECK_ERROR(glPixelTransferf(GL_DEPTH_SCALE, value.scale));
+ MBGL_CHECK_ERROR(glPixelTransferf(GL_DEPTH_BIAS, value.bias));
+}
+
+PixelTransferDepth::Type PixelTransferDepth::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_SCALE, &value.scale));
+ MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_BIAS, &value.bias));
+ return value;
+}
+
+const constexpr PixelTransferStencil::Type PixelTransferStencil::Default;
+
+void PixelTransferStencil::Set(const Type& value) {
+ MBGL_CHECK_ERROR(glPixelTransferf(GL_INDEX_SHIFT, value.shift));
+ MBGL_CHECK_ERROR(glPixelTransferf(GL_INDEX_OFFSET, value.offset));
+}
+
+PixelTransferStencil::Type PixelTransferStencil::Get() {
+ Type value;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_INDEX_SHIFT, &value.shift));
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_INDEX_OFFSET, &value.offset));
+ return value;
+}
+
+#endif // MBGL_USE_GLES2
} // namespace value
} // namespace gl
diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp
index 866ce389a4..3586c26bda 100644
--- a/src/mbgl/gl/value.hpp
+++ b/src/mbgl/gl/value.hpp
@@ -1,7 +1,12 @@
#pragma once
#include <mbgl/gl/types.hpp>
+#include <mbgl/gl/depth_mode.hpp>
+#include <mbgl/gl/stencil_mode.hpp>
+#include <mbgl/gl/color_mode.hpp>
#include <mbgl/util/color.hpp>
+#include <mbgl/util/size.hpp>
+#include <mbgl/util/range.hpp>
namespace mbgl {
namespace gl {
@@ -22,14 +27,14 @@ struct ClearColor {
};
struct ClearStencil {
- using Type = StencilValue;
+ using Type = int32_t;
static const constexpr Type Default = 0;
static void Set(const Type&);
static Type Get();
};
struct StencilMask {
- using Type = StencilMaskValue;
+ using Type = uint32_t;
static const constexpr Type Default = ~0u;
static void Set(const Type&);
static Type Get();
@@ -43,28 +48,19 @@ struct DepthMask {
};
struct ColorMask {
- struct Type {
- bool r;
- bool g;
- bool b;
- bool a;
- };
+ using Type = ColorMode::Mask;
static const constexpr Type Default = { true, true, true, true };
static void Set(const Type&);
static Type Get();
};
-constexpr bool operator!=(const ColorMask::Type& a, const ColorMask::Type& b) {
- return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a;
-}
-
struct StencilFunc {
struct Type {
- StencilTestFunction func;
- StencilValue ref;
- StencilMaskValue mask;
+ uint32_t func;
+ int32_t ref;
+ uint32_t mask;
};
- static const constexpr Type Default = { StencilTestFunction::Always, 0, ~0u };
+ static const constexpr Type Default = { StencilMode::Always::func, 0, ~0u };
static void Set(const Type&);
static Type Get();
};
@@ -82,12 +78,11 @@ struct StencilTest {
struct StencilOp {
struct Type {
- StencilTestOperation sfail;
- StencilTestOperation dpfail;
- StencilTestOperation dppass;
+ StencilMode::Op sfail;
+ StencilMode::Op dpfail;
+ StencilMode::Op dppass;
};
- static const constexpr Type Default = { StencilTestOperation::Keep, StencilTestOperation::Keep,
- StencilTestOperation::Keep };
+ static const constexpr Type Default = { StencilMode::Keep, StencilMode::Keep, StencilMode::Keep };
static void Set(const Type&);
static Type Get();
};
@@ -97,19 +92,12 @@ constexpr bool operator!=(const StencilOp::Type& a, const StencilOp::Type& b) {
}
struct DepthRange {
- struct Type {
- float near;
- float far;
- };
+ using Type = Range<float>;
static const constexpr Type Default = { 0, 1 };
static void Set(const Type&);
static Type Get();
};
-constexpr bool operator!=(const DepthRange::Type& a, const DepthRange::Type& b) {
- return a.near != b.near || a.far != b.far;
-}
-
struct DepthTest {
using Type = bool;
static const constexpr Type Default = false;
@@ -118,8 +106,8 @@ struct DepthTest {
};
struct DepthFunc {
- using Type = DepthTestFunction;
- static const constexpr Type Default = DepthTestFunction::Less;
+ using Type = DepthMode::Function;
+ static const constexpr Type Default = DepthMode::Less;
static void Set(const Type&);
static Type Get();
};
@@ -131,12 +119,19 @@ struct Blend {
static Type Get();
};
+struct BlendEquation {
+ using Type = ColorMode::BlendEquation;
+ static const constexpr Type Default = ColorMode::BlendEquation::Add;
+ static void Set(const Type&);
+ static Type Get();
+};
+
struct BlendFunc {
struct Type {
- BlendSourceFactor sfactor;
- BlendDestinationFactor dfactor;
+ ColorMode::BlendFactor sfactor;
+ ColorMode::BlendFactor dfactor;
};
- static const constexpr Type Default = { BlendSourceFactor::One, BlendDestinationFactor::Zero };
+ static const constexpr Type Default = { ColorMode::One, ColorMode::Zero };
static void Set(const Type&);
static Type Get();
};
@@ -177,16 +172,19 @@ struct Viewport {
struct Type {
int32_t x;
int32_t y;
- uint16_t width;
- uint16_t height;
+ Size size;
};
- static const constexpr Type Default = { 0, 0, 0, 0 };
+ static const constexpr Type Default = { 0, 0, { 0, 0 } };
static void Set(const Type&);
static Type Get();
};
constexpr bool operator!=(const Viewport::Type& a, const Viewport::Type& b) {
- return a.x != b.x || a.y != b.y || a.width != b.width || a.height != b.height;
+ return a.x != b.x || a.y != b.y || a.size != b.size;
+}
+
+constexpr bool operator==(const Viewport::Type& a, const Viewport::Type& b) {
+ return !(a != b);
}
struct BindFramebuffer {
@@ -233,6 +231,13 @@ struct BindVertexArray {
#if not MBGL_USE_GLES2
+struct PointSize {
+ using Type = float;
+ static const constexpr Type Default = 1;
+ static void Set(const Type&);
+ static Type Get();
+};
+
struct PixelZoom {
struct Type {
float xfactor;
@@ -254,7 +259,7 @@ struct RasterPos {
double z;
double w;
};
- static const constexpr Type Default = { 0, 0, 0, 0 };
+ static const constexpr Type Default = { 0, 0, 0, 1 };
static void Set(const Type&);
static Type Get();
};
@@ -263,6 +268,48 @@ constexpr bool operator!=(const RasterPos::Type& a, const RasterPos::Type& b) {
return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w;
}
+struct PixelStorePack {
+ using Type = PixelStorageType;
+ static const constexpr Type Default = { 4 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
+struct PixelStoreUnpack {
+ using Type = PixelStorageType;
+ static const constexpr Type Default = { 4 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
+struct PixelTransferDepth {
+ struct Type {
+ float scale;
+ float bias;
+ };
+ static const constexpr Type Default = { 1, 0 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
+constexpr bool operator!=(const PixelTransferDepth::Type& a, const PixelTransferDepth::Type& b) {
+ return a.scale != b.scale || a.bias != b.bias;
+}
+
+struct PixelTransferStencil {
+ struct Type {
+ int32_t shift;
+ int32_t offset;
+ };
+ static const constexpr Type Default = { 0, 0 };
+ static void Set(const Type&);
+ static Type Get();
+};
+
+constexpr bool operator!=(const PixelTransferStencil::Type& a, const PixelTransferStencil::Type& b) {
+ return a.shift != b.shift || a.offset != b.offset;
+}
+
#endif // MBGL_USE_GLES2
} // namespace value
diff --git a/src/mbgl/gl/vao.cpp b/src/mbgl/gl/vao.cpp
deleted file mode 100644
index b235b0e63b..0000000000
--- a/src/mbgl/gl/vao.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <mbgl/gl/vao.hpp>
-#include <mbgl/gl/vertex_array.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/gl/gl.hpp>
-
-namespace mbgl {
-namespace gl {
-
-void VertexArrayObject::bindVertexArrayObject(Context& context) {
- if (!GenVertexArrays || !BindVertexArray) {
- static bool reported = false;
- if (!reported) {
- Log::Warning(Event::OpenGL, "Not using Vertex Array Objects");
- reported = true;
- }
- return;
- }
-
- if (!vertexArray) {
- vertexArray = context.createVertexArray();
- context.vertexBuffer.setDirty();
- context.elementBuffer.setDirty();
- }
-
- context.vertexArrayObject = *vertexArray;
-}
-
-void VertexArrayObject::verifyBinding(Shader& shader,
- BufferID vertexBuffer,
- BufferID elementsBuffer,
- int8_t* offset) {
- if (bound_shader != shader.getID()) {
- throw std::runtime_error(std::string("trying to rebind VAO to another shader from " +
- util::toString(bound_shader) + "(" + bound_shader_name + ") to " +
- util::toString(shader.getID()) + "(" + shader.name + ")" ));
- } else if (bound_offset != offset) {
- throw std::runtime_error("trying to bind VAO to another offset");
- } else if (bound_vertex_buffer != vertexBuffer) {
- throw std::runtime_error("trying to bind VAO to another vertex buffer");
- } else if (bound_elements_buffer != elementsBuffer) {
- throw std::runtime_error("trying to bind VAO to another elements buffer");
- }
-}
-
-void VertexArrayObject::storeBinding(Shader& shader,
- BufferID vertexBuffer,
- BufferID elementsBuffer,
- int8_t* offset) {
- bound_shader = shader.getID();
- bound_shader_name = shader.name;
- bound_offset = offset;
- bound_vertex_buffer = vertexBuffer;
- bound_elements_buffer = elementsBuffer;
-}
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/vao.hpp b/src/mbgl/gl/vao.hpp
deleted file mode 100644
index 826c028d32..0000000000
--- a/src/mbgl/gl/vao.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-#pragma once
-
-#include <mbgl/gl/shader.hpp>
-#include <mbgl/gl/context.hpp>
-#include <mbgl/gl/vertex_buffer.hpp>
-#include <mbgl/util/optional.hpp>
-
-#include <stdexcept>
-
-namespace mbgl {
-namespace gl {
-
-class VertexArrayObject {
-public:
- template <typename Shader, typename T>
- void bind(Shader& shader,
- const VertexBuffer<T>& vertexBuffer,
- int8_t* offset,
- Context& context) {
- bindVertexArrayObject(context);
- if (bound_shader == 0) {
- context.vertexBuffer = vertexBuffer.buffer;
- context.bindAttributes(shader, vertexBuffer, offset);
- if (vertexArray) {
- storeBinding(shader, vertexBuffer.buffer, 0, offset);
- }
- } else {
- verifyBinding(shader, vertexBuffer.buffer, 0, offset);
- }
- }
-
- template <typename Shader, typename T, typename P>
- void bind(Shader& shader,
- const VertexBuffer<T>& vertexBuffer,
- const IndexBuffer<P>& indexBuffer,
- int8_t* offset,
- Context& context) {
- bindVertexArrayObject(context);
- if (bound_shader == 0) {
- context.vertexBuffer = vertexBuffer.buffer;
- context.elementBuffer = indexBuffer.buffer;
- context.bindAttributes(shader, vertexBuffer, offset);
- if (vertexArray) {
- storeBinding(shader, vertexBuffer.buffer, indexBuffer.buffer, offset);
- }
- } else {
- verifyBinding(shader, vertexBuffer.buffer, indexBuffer.buffer, offset);
- }
- }
-
- VertexArrayID getID() const {
- return *vertexArray;
- }
-
-private:
- void bindVertexArrayObject(Context&);
- void storeBinding(Shader& shader,
- BufferID vertexBuffer,
- BufferID elementsBuffer,
- int8_t* offset);
- void verifyBinding(Shader& shader,
- BufferID vertexBuffer,
- BufferID elementsBuffer,
- int8_t* offset);
-
- optional<UniqueVertexArray> vertexArray;
-
- // For debug reasons, we're storing the bind information so that we can
- // detect errors and report
- ProgramID bound_shader = 0;
- const char* bound_shader_name = "";
- BufferID bound_vertex_buffer = 0;
- BufferID bound_elements_buffer = 0;
- int8_t *bound_offset = nullptr;
-};
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/vertex_buffer.hpp b/src/mbgl/gl/vertex_buffer.hpp
index c77a9a4213..c9bc01f3e8 100644
--- a/src/mbgl/gl/vertex_buffer.hpp
+++ b/src/mbgl/gl/vertex_buffer.hpp
@@ -1,14 +1,43 @@
#pragma once
#include <mbgl/gl/object.hpp>
+#include <mbgl/gl/primitives.hpp>
+#include <mbgl/gl/draw_mode.hpp>
+#include <mbgl/util/ignore.hpp>
+
+#include <vector>
namespace mbgl {
namespace gl {
-template <class Vertex>
+template <class V, class DrawMode = Indexed>
+class VertexVector {
+public:
+ using Vertex = V;
+ static constexpr std::size_t groupSize = DrawMode::bufferGroupSize;
+
+ template <class... Args>
+ void emplace_back(Args&&... args) {
+ static_assert(sizeof...(args) == groupSize, "wrong buffer element count");
+ util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...});
+ }
+
+ std::size_t vertexSize() const { return v.size(); }
+ std::size_t byteSize() const { return v.size() * sizeof(Vertex); }
+
+ bool empty() const { return v.empty(); }
+ const Vertex* data() const { return v.data(); }
+
+private:
+ std::vector<Vertex> v;
+};
+
+template <class V, class DrawMode = Indexed>
class VertexBuffer {
public:
+ using Vertex = V;
static constexpr std::size_t vertexSize = sizeof(Vertex);
+
std::size_t vertexCount;
UniqueBuffer buffer;
};