summaryrefslogtreecommitdiff
path: root/src/mbgl/gl
diff options
context:
space:
mode:
authorThiago Marcos P. Santos <tmpsantos@gmail.com>2017-08-07 19:19:32 +0300
committerThiago Marcos P. Santos <tmpsantos@gmail.com>2017-08-09 18:02:46 +0300
commitc53896caefc96a8c18ab746026330ddc4fc0338e (patch)
tree8f562b0c416d6c99f7b565e58b758701f6081677 /src/mbgl/gl
parent9ecbe3642fb4a53b558598239b59bf1d0224c25b (diff)
downloadqtlocation-mapboxgl-c53896caefc96a8c18ab746026330ddc4fc0338e.tar.gz
Bump Mapbox GL Nativeqt-v1.1.0
mapbox-gl-native @ edd7948893fcd40a24d96b790e21d3dd028cecbe
Diffstat (limited to 'src/mbgl/gl')
-rw-r--r--src/mbgl/gl/attribute.cpp42
-rw-r--r--src/mbgl/gl/attribute.hpp240
-rw-r--r--src/mbgl/gl/context.cpp329
-rw-r--r--src/mbgl/gl/context.hpp114
-rw-r--r--src/mbgl/gl/debugging.cpp194
-rw-r--r--src/mbgl/gl/debugging.hpp24
-rw-r--r--src/mbgl/gl/debugging_extension.cpp55
-rw-r--r--src/mbgl/gl/debugging_extension.hpp120
-rw-r--r--src/mbgl/gl/draw_mode.hpp19
-rw-r--r--src/mbgl/gl/extension.cpp45
-rw-r--r--src/mbgl/gl/extension.hpp23
-rw-r--r--src/mbgl/gl/features.hpp7
-rw-r--r--src/mbgl/gl/gl.hpp50
-rw-r--r--src/mbgl/gl/index_buffer.hpp2
-rw-r--r--src/mbgl/gl/object.cpp4
-rw-r--r--src/mbgl/gl/program.hpp132
-rw-r--r--src/mbgl/gl/program_binary_extension.hpp44
-rw-r--r--src/mbgl/gl/segment.hpp39
-rw-r--r--src/mbgl/gl/state.hpp29
-rw-r--r--src/mbgl/gl/texture.hpp22
-rw-r--r--src/mbgl/gl/types.hpp57
-rw-r--r--src/mbgl/gl/uniform.cpp93
-rw-r--r--src/mbgl/gl/uniform.hpp79
-rw-r--r--src/mbgl/gl/value.cpp101
-rw-r--r--src/mbgl/gl/value.hpp45
-rw-r--r--src/mbgl/gl/vertex_array.cpp22
-rw-r--r--src/mbgl/gl/vertex_array.hpp71
-rw-r--r--src/mbgl/gl/vertex_array_extension.hpp37
-rw-r--r--src/mbgl/gl/vertex_buffer.hpp2
29 files changed, 1421 insertions, 620 deletions
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp
index 7432fff590..bb5b2ddc34 100644
--- a/src/mbgl/gl/attribute.cpp
+++ b/src/mbgl/gl/attribute.cpp
@@ -4,25 +4,35 @@
namespace mbgl {
namespace gl {
-AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) {
+void bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) {
+ if (location >= MAX_ATTRIBUTES) {
+ throw gl::Error("too many vertex attributes");
+ }
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))));
+std::set<std::string> getActiveAttributes(ProgramID id) {
+ std::set<std::string> activeAttributes;
+
+ GLint attributeCount;
+ MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTES, &attributeCount));
+
+ GLint maxAttributeLength;
+ MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeLength));
+
+ std::string attributeName;
+ attributeName.resize(maxAttributeLength);
+
+ GLsizei actualLength;
+ GLint size;
+ GLenum type;
+
+ for (int32_t i = 0; i < attributeCount; i++) {
+ MBGL_CHECK_ERROR(glGetActiveAttrib(id, i, maxAttributeLength, &actualLength, &size, &type, &attributeName[0]));
+ activeAttributes.emplace(std::string(attributeName, 0, actualLength));
+ }
+
+ return activeAttributes;
}
} // namespace gl
diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp
index 95945bca64..fa6c2ddeab 100644
--- a/src/mbgl/gl/attribute.hpp
+++ b/src/mbgl/gl/attribute.hpp
@@ -1,33 +1,108 @@
#pragma once
#include <mbgl/gl/types.hpp>
+#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/util/ignore.hpp>
#include <mbgl/util/indexed_tuple.hpp>
+#include <mbgl/util/optional.hpp>
#include <cstddef>
+#include <vector>
+#include <set>
#include <functional>
+#include <string>
+#include <array>
+#include <limits>
namespace mbgl {
namespace gl {
-template <class Tag, class T, std::size_t N>
-class Attribute {
+static constexpr std::size_t MAX_ATTRIBUTES = 8;
+
+template <class> 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> {};
+
+class AttributeBinding {
public:
- using Type = T[N];
+ DataType attributeType;
+ uint8_t attributeSize;
+ uint32_t attributeOffset;
+
+ BufferID vertexBuffer;
+ uint32_t vertexSize;
+ uint32_t vertexOffset;
+
+ friend bool operator==(const AttributeBinding& lhs,
+ const AttributeBinding& rhs) {
+ return std::tie(lhs.attributeType, lhs.attributeSize, lhs.attributeOffset, lhs.vertexBuffer, lhs.vertexSize, lhs.vertexOffset)
+ == std::tie(rhs.attributeType, rhs.attributeSize, rhs.attributeOffset, rhs.vertexBuffer, rhs.vertexSize, rhs.vertexOffset);
+ }
+};
- class State {
- public:
- explicit State(AttributeLocation location_)
- : location(location_) {}
+using AttributeBindingArray = std::array<optional<AttributeBinding>, MAX_ATTRIBUTES>;
+
+/*
+ gl::Attribute<T,N> manages the binding of a vertex buffer to a GL program attribute.
+ - T is the underlying primitive type (exposed as Attribute<T,N>::ValueType)
+ - N is the number of components in the attribute declared in the shader (exposed as Attribute<T,N>::Dimensions)
+*/
+template <class T, std::size_t N>
+class Attribute {
+public:
+ using ValueType = T;
+ static constexpr size_t Dimensions = N;
+ using Value = std::array<T, N>;
+
+ using Location = AttributeLocation;
+ using Binding = AttributeBinding;
+
+ /*
+ Create a binding for this attribute. The `attributeSize` parameter may be used to
+ override the number of components available in the buffer for each vertex. Thus,
+ a buffer with only one float for each vertex can be bound to a `vec2` attribute
+ */
+ template <class Vertex, class DrawMode>
+ static Binding binding(const VertexBuffer<Vertex, DrawMode>& buffer,
+ std::size_t attributeIndex,
+ std::size_t attributeSize = N) {
+ static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
+ assert(attributeSize >= 1);
+ assert(attributeSize <= 4);
+ assert(Vertex::attributeOffsets[attributeIndex] <= std::numeric_limits<uint32_t>::max());
+ static_assert(sizeof(Vertex) <= std::numeric_limits<uint32_t>::max(), "vertex too large");
+ return AttributeBinding {
+ DataTypeOf<T>::value,
+ static_cast<uint8_t>(attributeSize),
+ static_cast<uint32_t>(Vertex::attributeOffsets[attributeIndex]),
+ buffer.buffer,
+ static_cast<uint32_t>(sizeof(Vertex)),
+ 0,
+ };
+ }
- AttributeLocation location;
- static constexpr std::size_t count = N;
- static constexpr DataType type = DataTypeOf<T>::value;
- };
+ static optional<Binding> offsetBinding(const optional<Binding>& binding, std::size_t vertexOffset) {
+ assert(vertexOffset <= std::numeric_limits<uint32_t>::max());
+ if (binding) {
+ AttributeBinding result = *binding;
+ result.vertexOffset = static_cast<uint32_t>(vertexOffset);
+ return result;
+ } else {
+ return binding;
+ }
+ }
};
-#define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \
- struct name_ : ::mbgl::gl::Attribute<name_, type_, n_> { static constexpr auto name = #name_; }
+#define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \
+ struct name_ { \
+ static auto name() { return #name_; } \
+ using Type = ::mbgl::gl::Attribute<type_, n_>; \
+ }
namespace detail {
@@ -41,10 +116,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 +134,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 +144,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 +155,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 +167,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];
@@ -133,36 +214,99 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = {
} // 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);
+void bindAttributeLocation(ProgramID, AttributeLocation, const char * name);
+std::set<std::string> getActiveAttributes(ProgramID);
template <class... As>
class Attributes {
public:
- using State = IndexedTuple<TypeList<As...>, TypeList<typename As::State...>>;
- using Vertex = detail::Vertex<As...>;
+ using Types = TypeList<As...>;
+ using Locations = IndexedTuple<
+ TypeList<As...>,
+ TypeList<optional<typename As::Type::Location>...>>;
+ using Bindings = IndexedTuple<
+ TypeList<As...>,
+ TypeList<optional<typename As::Type::Binding>...>>;
+ using NamedLocations = std::vector<std::pair<const std::string, AttributeLocation>>;
+
+ using Vertex = detail::Vertex<typename As::Type...>;
+
+ static Locations bindLocations(const ProgramID& id) {
+ std::set<std::string> activeAttributes = getActiveAttributes(id);
+
+ AttributeLocation location = 0;
+ auto maybeBindLocation = [&](const char* name) -> optional<AttributeLocation> {
+ if (activeAttributes.count(name)) {
+ bindAttributeLocation(id, location, name);
+ return location++;
+ } else {
+ return {};
+ }
+ };
+
+ return Locations { maybeBindLocation(As::name())... };
+ }
+
+ template <class Program>
+ static Locations loadNamedLocations(const Program& program) {
+ return Locations{ program.attributeLocation(As::name())... };
+ }
+
+ static NamedLocations getNamedLocations(const Locations& locations) {
+ NamedLocations result;
+
+ auto maybeAddLocation = [&] (const std::string& name, const optional<AttributeLocation>& location) {
+ if (location) {
+ result.emplace_back(name, *location);
+ }
+ };
+
+ util::ignore({ (maybeAddLocation(As::name(), locations.template get<As>()), 0)... });
- static State state(const ProgramID& id) {
- return State { typename As::State(bindAttributeLocation(id, TypeIndex<As, As...>::value, As::name))... };
+ return result;
}
- 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[TypeIndex<As, As...>::value]), 0)... });
+ template <class DrawMode>
+ static Bindings bindings(const VertexBuffer<Vertex, DrawMode>& buffer) {
+ return Bindings { As::Type::binding(buffer, TypeIndex<As, As...>::value)... };
+ }
+
+ static Bindings offsetBindings(const Bindings& bindings, std::size_t vertexOffset) {
+ return Bindings { As::Type::offsetBinding(bindings.template get<As>(), vertexOffset)... };
+ }
+
+ static AttributeBindingArray toBindingArray(const Locations& locations, const Bindings& bindings) {
+ AttributeBindingArray result;
+
+ auto maybeAddBinding = [&] (const optional<AttributeLocation>& location,
+ const optional<AttributeBinding>& binding) {
+ if (location) {
+ result.at(*location) = binding;
+ }
};
+
+ util::ignore({ (maybeAddBinding(locations.template get<As>(), bindings.template get<As>()), 0)... });
+
+ return result;
}
};
+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..e18f1e0bcf 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -1,7 +1,8 @@
-#include <mbgl/map/view.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/gl.hpp>
-#include <mbgl/gl/vertex_array.hpp>
+#include <mbgl/gl/debugging_extension.hpp>
+#include <mbgl/gl/vertex_array_extension.hpp>
+#include <mbgl/gl/program_binary_extension.hpp>
#include <mbgl/util/traits.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/logging.hpp>
@@ -14,6 +15,31 @@ 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(DataType::Byte) == GL_BYTE, "OpenGL type mismatch");
+static_assert(underlying_type(DataType::UnsignedByte) == GL_UNSIGNED_BYTE, "OpenGL type mismatch");
+static_assert(underlying_type(DataType::Short) == GL_SHORT, "OpenGL type mismatch");
+static_assert(underlying_type(DataType::UnsignedShort) == GL_UNSIGNED_SHORT, "OpenGL type mismatch");
+static_assert(underlying_type(DataType::Integer) == GL_INT, "OpenGL type mismatch");
+static_assert(underlying_type(DataType::UnsignedInteger) == GL_UNSIGNED_INT, "OpenGL type mismatch");
+static_assert(underlying_type(DataType::Float) == GL_FLOAT, "OpenGL type mismatch");
+
+#if not MBGL_USE_GLES2
+static_assert(underlying_type(RenderbufferType::RGBA) == GL_RGBA8, "OpenGL type mismatch");
+#else
+static_assert(underlying_type(RenderbufferType::RGBA) == GL_RGBA8_OES, "OpenGL type mismatch");
+#endif // MBGL_USE_GLES2
+#if not MBGL_USE_GLES2
+static_assert(underlying_type(RenderbufferType::DepthStencil) == GL_DEPTH24_STENCIL8, "OpenGL type mismatch");
+#else
+static_assert(underlying_type(RenderbufferType::DepthStencil) == GL_DEPTH24_STENCIL8_OES, "OpenGL type mismatch");
+#endif // MBGL_USE_GLES2
+#if not MBGL_USE_GLES2
+static_assert(underlying_type(RenderbufferType::DepthComponent) == GL_DEPTH_COMPONENT, "OpenGL type mismatch");
+#else
+static_assert(underlying_type(RenderbufferType::DepthComponent) == GL_DEPTH_COMPONENT16, "OpenGL type mismatch");
+#endif // MBGL_USE_GLES2
+
+
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");
@@ -34,15 +60,87 @@ static_assert(std::is_same<std::underlying_type_t<TextureFormat>, GLenum>::value
static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch");
static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::Float) == GL_FLOAT, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::FloatVec2) == GL_FLOAT_VEC2, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::FloatVec3) == GL_FLOAT_VEC3, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::FloatVec4) == GL_FLOAT_VEC4, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::Int) == GL_INT, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::IntVec2) == GL_INT_VEC2, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::IntVec3) == GL_INT_VEC3, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::IntVec4) == GL_INT_VEC4, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::Bool) == GL_BOOL, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::BoolVec2) == GL_BOOL_VEC2, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::BoolVec3) == GL_BOOL_VEC3, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::BoolVec4) == GL_BOOL_VEC4, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::FloatMat2) == GL_FLOAT_MAT2, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::FloatMat3) == GL_FLOAT_MAT3, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::FloatMat4) == GL_FLOAT_MAT4, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::Sampler2D) == GL_SAMPLER_2D, "OpenGL type mismatch");
+static_assert(underlying_type(UniformDataType::SamplerCube) == GL_SAMPLER_CUBE, "OpenGL type mismatch");
+
+static_assert(underlying_type(BufferUsage::StreamDraw) == GL_STREAM_DRAW, "OpenGL type mismatch");
+static_assert(underlying_type(BufferUsage::StaticDraw) == GL_STATIC_DRAW, "OpenGL type mismatch");
+static_assert(underlying_type(BufferUsage::DynamicDraw) == GL_DYNAMIC_DRAW, "OpenGL type mismatch");
+
+static_assert(std::is_same<BinaryProgramFormat, GLenum>::value, "OpenGL type mismatch");
+
+Context::Context() = default;
+
Context::~Context() {
reset();
}
+void Context::initializeExtensions(const std::function<gl::ProcAddress(const char*)>& getProcAddress) {
+ if (const auto* extensions =
+ reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) {
+
+ auto fn = [&](
+ std::initializer_list<std::pair<const char*, const char*>> probes) -> ProcAddress {
+ for (auto probe : probes) {
+ if (strstr(extensions, probe.first) != nullptr) {
+ if (ProcAddress ptr = getProcAddress(probe.second)) {
+ return ptr;
+ }
+ }
+ }
+ return nullptr;
+ };
+
+ debugging = std::make_unique<extension::Debugging>(fn);
+ if (!disableVAOExtension) {
+ vertexArray = std::make_unique<extension::VertexArray>(fn);
+ }
+#if MBGL_HAS_BINARY_PROGRAMS
+ programBinary = std::make_unique<extension::ProgramBinary>(fn);
+#endif
+
+ if (!supportsVertexArrays()) {
+ Log::Warning(Event::OpenGL, "Not using Vertex Array Objects");
+ }
+ }
+}
+
+void Context::enableDebugging() {
+ if (!debugging || !debugging->debugMessageControl || !debugging->debugMessageCallback) {
+ return;
+ }
+
+ // This will enable all messages including performance hints
+ // MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE));
+
+ // This will only enable high and medium severity messages
+ MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE));
+ MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE));
+ MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE));
+
+ MBGL_CHECK_ERROR(debugging->debugMessageCallback(extension::Debugging::DebugCallback, nullptr));
+}
+
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());
+ const auto lengths = static_cast<GLsizei>(source.length());
MBGL_CHECK_ERROR(glShaderSource(result, 1, &sources, &lengths));
MBGL_CHECK_ERROR(glCompileShader(result));
@@ -72,9 +170,29 @@ UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentSha
return result;
}
+#if MBGL_HAS_BINARY_PROGRAMS
+UniqueProgram Context::createProgram(BinaryProgramFormat binaryFormat,
+ const std::string& binaryProgram) {
+ assert(supportsProgramBinaries());
+ UniqueProgram result{ MBGL_CHECK_ERROR(glCreateProgram()), { this } };
+ MBGL_CHECK_ERROR(programBinary->programBinary(result, static_cast<GLenum>(binaryFormat),
+ binaryProgram.data(),
+ static_cast<GLint>(binaryProgram.size())));
+ verifyProgramLinkage(result);
+ return result;
+}
+#else
+UniqueProgram Context::createProgram(BinaryProgramFormat, const std::string&) {
+ throw std::runtime_error("binary programs are not supported");
+}
+#endif
+
void Context::linkProgram(ProgramID program_) {
MBGL_CHECK_ERROR(glLinkProgram(program_));
+ verifyProgramLinkage(program_);
+}
+void Context::verifyProgramLinkage(ProgramID program_) {
GLint status;
MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_LINK_STATUS, &status));
if (status == GL_TRUE) {
@@ -92,21 +210,26 @@ void Context::linkProgram(ProgramID program_) {
throw std::runtime_error("program failed to link");
}
-UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size) {
+UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size, const BufferUsage usage) {
BufferID id = 0;
MBGL_CHECK_ERROR(glGenBuffers(1, &id));
UniqueBuffer result { std::move(id), { this } };
vertexBuffer = result;
- MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW));
+ MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, size, data, static_cast<GLenum>(usage)));
return result;
}
+void Context::updateVertexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size) {
+ vertexBuffer = buffer;
+ MBGL_CHECK_ERROR(glBufferSubData(GL_ARRAY_BUFFER, 0, size, data));
+}
+
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;
+ bindVertexArray = 0;
+ globalVertexArrayState.indexBuffer = result;
MBGL_CHECK_ERROR(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW));
return result;
}
@@ -122,6 +245,68 @@ UniqueTexture Context::createTexture() {
return UniqueTexture{ std::move(id), { this } };
}
+bool Context::supportsVertexArrays() const {
+ return vertexArray &&
+ vertexArray->genVertexArrays &&
+ vertexArray->bindVertexArray &&
+ vertexArray->deleteVertexArrays;
+}
+
+#if MBGL_HAS_BINARY_PROGRAMS
+bool Context::supportsProgramBinaries() const {
+ if (!programBinary || !programBinary->programBinary || !programBinary->getProgramBinary) {
+ return false;
+ }
+
+ // Blacklist Adreno 3xx, 4xx, and 5xx GPUs due to known bugs:
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=510637
+ // https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_driver_bug_list.json#2316
+ const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
+ if (renderer.find("Adreno (TM) 3") != std::string::npos
+ || renderer.find("Adreno (TM) 4") != std::string::npos
+ || renderer.find("Adreno (TM) 5") != std::string::npos) {
+ return false;
+ }
+
+ return true;
+}
+
+optional<std::pair<BinaryProgramFormat, std::string>>
+Context::getBinaryProgram(ProgramID program_) const {
+ if (!supportsProgramBinaries()) {
+ return {};
+ }
+ GLint binaryLength;
+ MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_PROGRAM_BINARY_LENGTH, &binaryLength));
+ std::string binary;
+ binary.resize(binaryLength);
+ GLenum binaryFormat;
+ MBGL_CHECK_ERROR(programBinary->getProgramBinary(
+ program_, binaryLength, &binaryLength, &binaryFormat, const_cast<char*>(binary.data())));
+ if (size_t(binaryLength) != binary.size()) {
+ return {};
+ }
+ return { { binaryFormat, std::move(binary) } };
+}
+#else
+optional<std::pair<BinaryProgramFormat, std::string>> Context::getBinaryProgram(ProgramID) const {
+ return {};
+}
+#endif
+
+VertexArray Context::createVertexArray() {
+ if (supportsVertexArrays()) {
+ VertexArrayID id = 0;
+ MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id));
+ UniqueVertexArray vao(std::move(id), { this });
+ return { UniqueVertexArrayState(new VertexArrayState(std::move(vao), *this), VertexArrayStateDeleter { true })};
+ } else {
+ // On GL implementations which do not support vertex arrays, attribute bindings are global state.
+ // So return a VertexArray which shares our global state tracking and whose deleter is a no-op.
+ return { UniqueVertexArrayState(&globalVertexArrayState, VertexArrayStateDeleter { false }) };
+ }
+}
+
UniqueFramebuffer Context::createFramebuffer() {
FramebufferID id = 0;
MBGL_CHECK_ERROR(glGenFramebuffers(1, &id));
@@ -136,6 +321,7 @@ UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, cons
bindRenderbuffer = renderbuffer;
MBGL_CHECK_ERROR(
glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), size.width, size.height));
+ bindRenderbuffer = 0;
return renderbuffer;
}
@@ -143,11 +329,9 @@ std::unique_ptr<uint8_t[]> Context::readFramebuffer(const Size size, const Textu
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()));
@@ -171,7 +355,7 @@ void Context::drawPixels(const Size size, const void* data, TextureFormat format
if (format != TextureFormat::RGBA) {
format = static_cast<TextureFormat>(GL_LUMINANCE);
}
- MBGL_CHECK_ERROR(glDrawPixels(size.width, size.height, static_cast<GLenum>(GL_LUMINANCE),
+ MBGL_CHECK_ERROR(glDrawPixels(size.width, size.height, static_cast<GLenum>(format),
GL_UNSIGNED_BYTE, data));
}
#endif // MBGL_USE_GLES2
@@ -226,7 +410,7 @@ Framebuffer
Context::createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>& color,
const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
if (color.size != depthStencil.size) {
- throw new std::runtime_error("Renderbuffer size mismatch");
+ throw std::runtime_error("Renderbuffer size mismatch");
}
auto fbo = createFramebuffer();
bindFramebuffer = fbo;
@@ -250,7 +434,7 @@ Framebuffer
Context::createFramebuffer(const Texture& color,
const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
if (color.size != depthStencil.size) {
- throw new std::runtime_error("Renderbuffer size mismatch");
+ throw std::runtime_error("Renderbuffer size mismatch");
}
auto fbo = createFramebuffer();
bindFramebuffer = fbo;
@@ -270,9 +454,21 @@ Framebuffer Context::createFramebuffer(const Texture& color) {
return { color.size, std::move(fbo) };
}
+Framebuffer
+Context::createFramebuffer(const Texture& color,
+ const Renderbuffer<RenderbufferType::DepthComponent>& depthTarget) {
+ auto fbo = createFramebuffer();
+ bindFramebuffer = fbo;
+ MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color.texture, 0));
+ MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthTarget.renderbuffer));
+ checkFramebuffer();
+ return { depthTarget.size, std::move(fbo) };
+}
+
UniqueTexture
Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit) {
auto obj = createTexture();
+ pixelStoreUnpack = { 1 };
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.
@@ -342,8 +538,8 @@ void Context::reset() {
}
void Context::setDirtyState() {
- // Note: does not set viewport/bindFramebuffer to dirty since they are handled separately in
- // the view object.
+ // Note: does not set viewport/scissorTest/bindFramebuffer to dirty
+ // since they are handled separately in the view object.
stencilFunc.setDirty();
stencilMask.setDirty();
stencilTest.setDirty();
@@ -363,12 +559,12 @@ void Context::setDirtyState() {
program.setDirty();
lineWidth.setDirty();
activeTexture.setDirty();
+ pixelStorePack.setDirty();
+ pixelStoreUnpack.setDirty();
#if not MBGL_USE_GLES2
pointSize.setDirty();
pixelZoom.setDirty();
rasterPos.setDirty();
- pixelStorePack.setDirty();
- pixelStoreUnpack.setDirty();
pixelTransferDepth.setDirty();
pixelTransferStencil.setDirty();
#endif // MBGL_USE_GLES2
@@ -376,8 +572,8 @@ void Context::setDirtyState() {
tex.setDirty();
}
vertexBuffer.setDirty();
- elementBuffer.setDirty();
- vertexArrayObject.setDirty();
+ bindVertexArray.setDirty();
+ globalVertexArrayState.setDirty();
}
void Context::clear(optional<mbgl::Color> color,
@@ -407,37 +603,38 @@ 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) {
if (depth.func == DepthMode::Always && !depth.mask) {
depthTest = false;
+
+ // Workaround for rendering errors on Adreno 2xx GPUs. Depth-related state should
+ // not matter when the depth test is disabled, but on these GPUs it apparently does.
+ // https://github.com/mapbox/mapbox-gl-native/issues/9164
+ depthFunc = depth.func;
+ depthMask = depth.mask;
+ depthRange = depth.range;
} else {
depthTest = true;
depthFunc = depth.func;
@@ -474,57 +671,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() {
@@ -545,8 +699,8 @@ void Context::performCleanup() {
for (const auto id : abandonedBuffers) {
if (vertexBuffer == id) {
vertexBuffer.setDirty();
- } else if (elementBuffer == id) {
- elementBuffer.setDirty();
+ } else if (globalVertexArrayState.indexBuffer == id) {
+ globalVertexArrayState.indexBuffer.setDirty();
}
}
MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data()));
@@ -564,13 +718,14 @@ void Context::performCleanup() {
}
if (!abandonedVertexArrays.empty()) {
+ assert(supportsVertexArrays());
for (const auto id : abandonedVertexArrays) {
- if (vertexArrayObject == id) {
- vertexArrayObject.setDirty();
+ if (bindVertexArray == id) {
+ bindVertexArray.setDirty();
}
}
- MBGL_CHECK_ERROR(gl::DeleteVertexArrays(int(abandonedVertexArrays.size()),
- abandonedVertexArrays.data()));
+ MBGL_CHECK_ERROR(vertexArray->deleteVertexArrays(int(abandonedVertexArrays.size()),
+ abandonedVertexArrays.data()));
abandonedVertexArrays.clear();
}
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index 056c262c0f..9923567276 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <mbgl/gl/features.hpp>
#include <mbgl/gl/object.hpp>
#include <mbgl/gl/state.hpp>
#include <mbgl/gl/value.hpp>
@@ -8,12 +9,12 @@
#include <mbgl/gl/framebuffer.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/gl/index_buffer.hpp>
+#include <mbgl/gl/vertex_array.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>
@@ -22,33 +23,57 @@
#include <vector>
#include <array>
#include <string>
-#include <unordered_map>
namespace mbgl {
-
-class View;
-
namespace gl {
constexpr size_t TextureMax = 64;
+using ProcAddress = void (*)();
+
+namespace extension {
+class VertexArray;
+class Debugging;
+class ProgramBinary;
+} // namespace extension
class Context : private util::noncopyable {
public:
+ Context();
~Context();
+ void initializeExtensions(const std::function<gl::ProcAddress(const char*)>&);
+
+ void enableDebugging();
+
UniqueShader createShader(ShaderType type, const std::string& source);
UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader);
+ UniqueProgram createProgram(BinaryProgramFormat binaryFormat, const std::string& binaryProgram);
+ void verifyProgramLinkage(ProgramID);
void linkProgram(ProgramID);
UniqueTexture createTexture();
+ VertexArray createVertexArray();
+
+#if MBGL_HAS_BINARY_PROGRAMS
+ bool supportsProgramBinaries() const;
+#else
+ constexpr bool supportsProgramBinaries() const { return false; }
+#endif
+ optional<std::pair<BinaryProgramFormat, std::string>> getBinaryProgram(ProgramID) const;
template <class Vertex, class DrawMode>
- VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v) {
+ VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v, const BufferUsage usage=BufferUsage::StaticDraw) {
return VertexBuffer<Vertex, DrawMode> {
v.vertexSize(),
- createVertexBuffer(v.data(), v.byteSize())
+ createVertexBuffer(v.data(), v.byteSize(), usage)
};
}
+ template <class Vertex, class DrawMode>
+ void updateVertexBuffer(VertexBuffer<Vertex, DrawMode>& buffer, VertexVector<Vertex, DrawMode>&& v) {
+ assert(v.vertexSize() == buffer.vertexCount);
+ updateVertexBuffer(buffer.buffer, v.data(), v.byteSize());
+ }
+
template <class DrawMode>
IndexBuffer<DrawMode> createIndexBuffer(IndexVector<DrawMode>&& v) {
return IndexBuffer<DrawMode> {
@@ -58,7 +83,9 @@ public:
template <RenderbufferType type>
Renderbuffer<type> createRenderbuffer(const Size size) {
- static_assert(type == RenderbufferType::RGBA || type == RenderbufferType::DepthStencil,
+ static_assert(type == RenderbufferType::RGBA ||
+ type == RenderbufferType::DepthStencil ||
+ type == RenderbufferType::DepthComponent,
"invalid renderbuffer type");
return { size, createRenderbuffer(type, size) };
}
@@ -69,6 +96,8 @@ public:
Framebuffer createFramebuffer(const Texture&,
const Renderbuffer<RenderbufferType::DepthStencil>&);
Framebuffer createFramebuffer(const Texture&);
+ Framebuffer createFramebuffer(const Texture&,
+ const Renderbuffer<RenderbufferType::DepthComponent>&);
template <typename Image,
TextureFormat format = Image::channels == 4 ? TextureFormat::RGBA
@@ -91,7 +120,7 @@ public:
template <typename Image>
Texture createTexture(const Image& image, TextureUnit unit = 0) {
auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
- return Texture(image.size, [&] { return createTexture(image.size, image.data.get(), format, unit); });
+ return { image.size, createTexture(image.size, image.data.get(), format, unit) };
}
template <typename Image>
@@ -105,7 +134,7 @@ public:
Texture createTexture(const Size size,
TextureFormat format = TextureFormat::RGBA,
TextureUnit unit = 0) {
- return Texture(size, [&] { return createTexture(size, nullptr, format, unit); });
+ return { size, createTexture(size, nullptr, format, unit) };
}
void bindTexture(Texture&,
@@ -119,25 +148,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();
@@ -158,18 +182,39 @@ public:
void setDirtyState();
+ extension::Debugging* getDebuggingExtension() const {
+ return debugging.get();
+ }
+
+ extension::VertexArray* getVertexArrayExtension() const {
+ return vertexArray.get();
+ }
+
+private:
+ std::unique_ptr<extension::Debugging> debugging;
+ std::unique_ptr<extension::VertexArray> vertexArray;
+#if MBGL_HAS_BINARY_PROGRAMS
+ std::unique_ptr<extension::ProgramBinary> programBinary;
+#endif
+
+public:
State<value::ActiveTexture> activeTexture;
State<value::BindFramebuffer> bindFramebuffer;
State<value::Viewport> viewport;
+ State<value::ScissorTest> scissorTest;
std::array<State<value::BindTexture>, 2> texture;
- State<value::BindVertexArray> vertexArrayObject;
State<value::Program> program;
+ State<value::BindVertexBuffer> vertexBuffer;
+
+ State<value::BindVertexArray, const Context&> bindVertexArray { *this };
+ VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }), *this };
+
+ State<value::PixelStorePack> pixelStorePack;
+ State<value::PixelStoreUnpack> pixelStoreUnpack;
#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
@@ -196,10 +241,9 @@ 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 createVertexBuffer(const void* data, std::size_t size, const BufferUsage usage);
+ void updateVertexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size);
UniqueBuffer createIndexBuffer(const void* data, std::size_t size);
UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit);
void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit);
@@ -210,11 +254,7 @@ 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&);
+ bool supportsVertexArrays() const;
friend detail::ProgramDeleter;
friend detail::ShaderDeleter;
@@ -233,6 +273,10 @@ private:
std::vector<VertexArrayID> abandonedVertexArrays;
std::vector<FramebufferID> abandonedFramebuffers;
std::vector<RenderbufferID> abandonedRenderbuffers;
+
+public:
+ // For testing
+ bool disableVAOExtension = false;
};
} // namespace gl
diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp
index f99308de7e..366b4d63c7 100644
--- a/src/mbgl/gl/debugging.cpp
+++ b/src/mbgl/gl/debugging.cpp
@@ -1,193 +1,33 @@
#include <mbgl/gl/debugging.hpp>
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/gl/extension.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
-#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
-#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
-#define GL_DEBUG_SOURCE_API 0x8246
-#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
-#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
-#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
-#define GL_DEBUG_SOURCE_APPLICATION 0x824A
-#define GL_DEBUG_SOURCE_OTHER 0x824B
-#define GL_DEBUG_TYPE_ERROR 0x824C
-#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
-#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
-#define GL_DEBUG_TYPE_PORTABILITY 0x824F
-#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
-#define GL_DEBUG_TYPE_OTHER 0x8251
-#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
-#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
-#define GL_DEBUG_LOGGED_MESSAGES 0x9145
-#define GL_DEBUG_SEVERITY_HIGH 0x9146
-#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
-#define GL_DEBUG_SEVERITY_LOW 0x9148
-#define GL_DEBUG_TYPE_MARKER 0x8268
-#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
-#define GL_DEBUG_TYPE_POP_GROUP 0x826A
-#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
-#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
-#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
-#define GL_BUFFER 0x82E0
-#define GL_SHADER 0x82E1
-#define GL_PROGRAM 0x82E2
-#define GL_QUERY 0x82E3
-#define GL_PROGRAM_PIPELINE 0x82E4
-#define GL_SAMPLER 0x82E6
-#define GL_MAX_LABEL_LENGTH 0x82E8
-#define GL_DEBUG_OUTPUT 0x92E0
-#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
-#define GL_DISPLAY_LIST 0x82E7
-#define GL_VERTEX_ARRAY 0x8074
-#define GL_TRANSFORM_FEEDBACK 0x8E22
-#define GL_TEXTURE 0x1702
-#define GL_RENDERBUFFER 0x8D41
-#define GL_FRAMEBUFFER 0x8D40
+#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/debugging_extension.hpp>
namespace mbgl {
namespace gl {
-namespace debugging {
-
-typedef void (*GLDEBUGPROC)(GLenum source,
- GLenum type,
- GLuint id,
- GLenum severity,
- GLsizei length,
- const GLchar *message,
- const void *userParam);
-
-static ExtensionFunction<
- void (GLenum source,
- GLenum type,
- GLenum severity,
- GLsizei count,
- const GLuint *ids,
- GLboolean enabled)>
- DebugMessageControl({
- {"GL_KHR_debug", "glDebugMessageControl"},
- {"GL_ARB_debug_output", "glDebugMessageControlARB"}
- });
-
-static ExtensionFunction<
- void (GLDEBUGPROC callback,
- const void *userParam)>
- DebugMessageCallback({
- {"GL_KHR_debug", "glDebugMessageCallback"},
- {"GL_ARB_debug_output", "glDebugMessageCallbackARB"}
- });
-
-void debugCallback(GLenum source,
- GLenum type,
- GLuint id,
- GLenum severity,
- GLsizei /*length*/,
- const GLchar* message,
- const void* /*userParam*/)
-{
- std::string strSource;
- switch (source) {
- case GL_DEBUG_SOURCE_API: strSource = "DEBUG_SOURCE_API"; break;
- case GL_DEBUG_SOURCE_WINDOW_SYSTEM: strSource = "DEBUG_SOURCE_WINDOW_SYSTEM"; break;
- case GL_DEBUG_SOURCE_SHADER_COMPILER: strSource = "DEBUG_SOURCE_SHADER_COMPILER"; break;
- case GL_DEBUG_SOURCE_THIRD_PARTY: strSource = "DEBUG_SOURCE_THIRD_PARTY"; break;
- case GL_DEBUG_SOURCE_APPLICATION: strSource = "DEBUG_SOURCE_APPLICATION"; break;
- case GL_DEBUG_SOURCE_OTHER: strSource = "DEBUG_SOURCE_OTHER"; break;
- default: strSource = "(unknown)"; break;
- }
-
- std::string strType;
- switch (type) {
- case GL_DEBUG_TYPE_ERROR: strType = "DEBUG_TYPE_ERROR"; break;
- case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: strType = "DEBUG_TYPE_DEPRECATED_BEHAVIOR"; break;
- case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: strType = "DEBUG_TYPE_UNDEFINED_BEHAVIOR"; break;
- case GL_DEBUG_TYPE_PERFORMANCE: strType = "DEBUG_TYPE_PERFORMANCE"; break;
- case GL_DEBUG_TYPE_PORTABILITY: strType = "DEBUG_TYPE_PORTABILITY"; break;
- case GL_DEBUG_TYPE_OTHER: strType = "DEBUG_TYPE_OTHER"; break;
- case GL_DEBUG_TYPE_MARKER: strType = "DEBUG_TYPE_MARKER"; break;
- case GL_DEBUG_TYPE_PUSH_GROUP: strType = "DEBUG_TYPE_OTHER"; break;
- case GL_DEBUG_TYPE_POP_GROUP: strType = "DEBUG_TYPE_POP_GROUP"; break;
- default: strSource = "(unknown)"; break;
- }
-
- std::string strSeverity;
- mbgl::EventSeverity evtSeverity;
- switch (severity) {
- case GL_DEBUG_SEVERITY_HIGH: strSeverity = "DEBUG_SEVERITY_HIGH"; evtSeverity = mbgl::EventSeverity::Error; break;
- case GL_DEBUG_SEVERITY_MEDIUM: strSeverity = "DEBUG_SEVERITY_MEDIUM"; evtSeverity = mbgl::EventSeverity::Warning; break;
- case GL_DEBUG_SEVERITY_LOW: strSeverity = "DEBUG_SEVERITY_LOW"; evtSeverity = mbgl::EventSeverity::Info; break;
- case GL_DEBUG_SEVERITY_NOTIFICATION: strSeverity = "DEBUG_SEVERITY_NOTIFICATION"; evtSeverity = mbgl::EventSeverity::Debug; break;
- default: strSource = "(unknown)"; evtSeverity = mbgl::EventSeverity::Debug; break;
- }
-
- mbgl::Log::Record(evtSeverity, mbgl::Event::OpenGL, "GL_%s GL_%s %u GL_%s - %s", strSource.c_str(), strType.c_str(), id, strSeverity.c_str(), message);
-}
-
-void enable() {
- if (!DebugMessageControl || !DebugMessageCallback) {
- return;
- }
-
- // This will enable all messages including performance hints
- //MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE));
-
- // This will only enable high and medium severity messages
- MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE));
- MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE));
- MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE));
-
- MBGL_CHECK_ERROR(DebugMessageCallback(debugCallback, nullptr));
-}
#ifndef NDEBUG
-static ExtensionFunction<
- void (GLenum source,
- GLuint id,
- GLsizei length,
- const GLchar *message)>
- PushDebugGroup({
- {"GL_KHR_debug", "glPushDebugGroup"}
- });
-
-static ExtensionFunction<
- void ()>
- PopDebugGroup({
- {"GL_KHR_debug", "glPopDebugGroup"}
- });
-
-static ExtensionFunction<
- void (GLsizei length,
- const GLchar *marker)>
- PushGroupMarkerEXT({
- {"GL_EXT_debug_marker", "glPushGroupMarkerEXT"}
- });
-static ExtensionFunction<
- void ()>
- PopGroupMarkerEXT({
- {"GL_EXT_debug_marker", "glPopGroupMarkerEXT"}
- });
-
-group::group(const std::string& str) {
- if (PushDebugGroup) {
- PushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, GLsizei(str.size()), str.c_str());
- } else if (PushGroupMarkerEXT) {
- PushGroupMarkerEXT(GLsizei(str.size() + 1), str.c_str());
+DebugGroup::DebugGroup(const Context& context_, const std::string& name) : context(context_) {
+ if (auto debugging = context.getDebuggingExtension()) {
+ if (debugging->pushDebugGroup) {
+ MBGL_CHECK_ERROR(debugging->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, GLsizei(name.size()), name.c_str()));
+ } else if (debugging->pushGroupMarkerEXT) {
+ MBGL_CHECK_ERROR(debugging->pushGroupMarkerEXT(GLsizei(name.size() + 1), name.c_str()));
+ }
}
}
-group::~group() {
- if (PopDebugGroup) {
- PopDebugGroup();
- } else if (PopGroupMarkerEXT) {
- PopGroupMarkerEXT();
+DebugGroup::~DebugGroup() {
+ if (auto debugging = context.getDebuggingExtension()) {
+ if (debugging->popDebugGroup) {
+ MBGL_CHECK_ERROR(debugging->popDebugGroup());
+ } else if (debugging->popGroupMarkerEXT) {
+ MBGL_CHECK_ERROR(debugging->popGroupMarkerEXT());
+ }
}
}
+
#endif
-} // namespace debugging
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/debugging.hpp b/src/mbgl/gl/debugging.hpp
index fe363701ad..d24b727295 100644
--- a/src/mbgl/gl/debugging.hpp
+++ b/src/mbgl/gl/debugging.hpp
@@ -1,26 +1,34 @@
#pragma once
+#include <mbgl/util/noncopyable.hpp>
+
#include <string>
namespace mbgl {
namespace gl {
-namespace debugging {
-void enable();
+class Context;
#ifndef NDEBUG
-struct group {
- group(const std::string&);
- ~group();
+
+class DebugGroup : private util::noncopyable {
+public:
+ DebugGroup(const Context&, const std::string&);
+ ~DebugGroup();
+
+private:
+ const Context& context;
};
#define __MBGL_DEBUG_GROUP_NAME2(counter) __MBGL_DEBUG_GROUP_##counter
#define __MBGL_DEBUG_GROUP_NAME(counter) __MBGL_DEBUG_GROUP_NAME2(counter)
-#define MBGL_DEBUG_GROUP(string) ::mbgl::gl::debugging::group __MBGL_DEBUG_GROUP_NAME(__LINE__)(string);
+#define MBGL_DEBUG_GROUP(context, name) const ::mbgl::gl::DebugGroup __MBGL_DEBUG_GROUP_NAME(__LINE__)(context, name);
+
#else
-#define MBGL_DEBUG_GROUP(string)
+
+#define MBGL_DEBUG_GROUP(context, name)
+
#endif
-} // namespace debugging
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/debugging_extension.cpp b/src/mbgl/gl/debugging_extension.cpp
new file mode 100644
index 0000000000..5afa4f50fc
--- /dev/null
+++ b/src/mbgl/gl/debugging_extension.cpp
@@ -0,0 +1,55 @@
+#include <mbgl/gl/debugging_extension.hpp>
+#include <mbgl/util/logging.hpp>
+
+namespace mbgl {
+namespace gl {
+namespace extension {
+
+void Debugging::DebugCallback(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei /* length */,
+ const GLchar* message,
+ const void* /* userParam */) {
+ std::string strSource;
+ switch (source) {
+ case GL_DEBUG_SOURCE_API: strSource = "DEBUG_SOURCE_API"; break;
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM: strSource = "DEBUG_SOURCE_WINDOW_SYSTEM"; break;
+ case GL_DEBUG_SOURCE_SHADER_COMPILER: strSource = "DEBUG_SOURCE_SHADER_COMPILER"; break;
+ case GL_DEBUG_SOURCE_THIRD_PARTY: strSource = "DEBUG_SOURCE_THIRD_PARTY"; break;
+ case GL_DEBUG_SOURCE_APPLICATION: strSource = "DEBUG_SOURCE_APPLICATION"; break;
+ case GL_DEBUG_SOURCE_OTHER: strSource = "DEBUG_SOURCE_OTHER"; break;
+ default: strSource = "(unknown)"; break;
+ }
+
+ std::string strType;
+ switch (type) {
+ case GL_DEBUG_TYPE_ERROR: strType = "DEBUG_TYPE_ERROR"; break;
+ case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: strType = "DEBUG_TYPE_DEPRECATED_BEHAVIOR"; break;
+ case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: strType = "DEBUG_TYPE_UNDEFINED_BEHAVIOR"; break;
+ case GL_DEBUG_TYPE_PERFORMANCE: strType = "DEBUG_TYPE_PERFORMANCE"; break;
+ case GL_DEBUG_TYPE_PORTABILITY: strType = "DEBUG_TYPE_PORTABILITY"; break;
+ case GL_DEBUG_TYPE_OTHER: strType = "DEBUG_TYPE_OTHER"; break;
+ case GL_DEBUG_TYPE_MARKER: strType = "DEBUG_TYPE_MARKER"; break;
+ case GL_DEBUG_TYPE_PUSH_GROUP: strType = "DEBUG_TYPE_OTHER"; break;
+ case GL_DEBUG_TYPE_POP_GROUP: strType = "DEBUG_TYPE_POP_GROUP"; break;
+ default: strSource = "(unknown)"; break;
+ }
+
+ std::string strSeverity;
+ mbgl::EventSeverity evtSeverity;
+ switch (severity) {
+ case GL_DEBUG_SEVERITY_HIGH: strSeverity = "DEBUG_SEVERITY_HIGH"; evtSeverity = mbgl::EventSeverity::Error; break;
+ case GL_DEBUG_SEVERITY_MEDIUM: strSeverity = "DEBUG_SEVERITY_MEDIUM"; evtSeverity = mbgl::EventSeverity::Warning; break;
+ case GL_DEBUG_SEVERITY_LOW: strSeverity = "DEBUG_SEVERITY_LOW"; evtSeverity = mbgl::EventSeverity::Info; break;
+ case GL_DEBUG_SEVERITY_NOTIFICATION: strSeverity = "DEBUG_SEVERITY_NOTIFICATION"; evtSeverity = mbgl::EventSeverity::Debug; break;
+ default: strSource = "(unknown)"; evtSeverity = mbgl::EventSeverity::Debug; break;
+ }
+
+ mbgl::Log::Record(evtSeverity, mbgl::Event::OpenGL, "GL_%s GL_%s %u GL_%s - %s", strSource.c_str(), strType.c_str(), id, strSeverity.c_str(), message);
+}
+
+} // namespace extension
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/debugging_extension.hpp b/src/mbgl/gl/debugging_extension.hpp
new file mode 100644
index 0000000000..5657bbde88
--- /dev/null
+++ b/src/mbgl/gl/debugging_extension.hpp
@@ -0,0 +1,120 @@
+#pragma once
+
+#include <mbgl/gl/extension.hpp>
+#include <mbgl/gl/gl.hpp>
+
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
+#define GL_DEBUG_SOURCE_API 0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
+#define GL_DEBUG_SOURCE_APPLICATION 0x824A
+#define GL_DEBUG_SOURCE_OTHER 0x824B
+#define GL_DEBUG_TYPE_ERROR 0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
+#define GL_DEBUG_TYPE_PORTABILITY 0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
+#define GL_DEBUG_TYPE_OTHER 0x8251
+#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
+#define GL_DEBUG_LOGGED_MESSAGES 0x9145
+#define GL_DEBUG_SEVERITY_HIGH 0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
+#define GL_DEBUG_SEVERITY_LOW 0x9148
+#define GL_DEBUG_TYPE_MARKER 0x8268
+#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
+#define GL_DEBUG_TYPE_POP_GROUP 0x826A
+#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
+#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
+#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
+#define GL_BUFFER 0x82E0
+#define GL_SHADER 0x82E1
+#define GL_PROGRAM 0x82E2
+#define GL_QUERY 0x82E3
+#define GL_PROGRAM_PIPELINE 0x82E4
+#define GL_SAMPLER 0x82E6
+#define GL_MAX_LABEL_LENGTH 0x82E8
+#define GL_DEBUG_OUTPUT 0x92E0
+#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
+#define GL_DISPLAY_LIST 0x82E7
+#define GL_VERTEX_ARRAY 0x8074
+#define GL_TRANSFORM_FEEDBACK 0x8E22
+#define GL_TEXTURE 0x1702
+#define GL_RENDERBUFFER 0x8D41
+#define GL_FRAMEBUFFER 0x8D40
+
+namespace mbgl {
+namespace gl {
+namespace extension {
+
+class Debugging {
+public:
+ using Callback = void (*)(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar* message,
+ const void* userParam);
+
+ static void DebugCallback(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei /* length */,
+ const GLchar* message,
+ const void* /* userParam */);
+
+ template <typename Fn>
+ Debugging(const Fn& loadExtension)
+ :
+#ifndef NDEBUG
+ pushDebugGroup(
+ loadExtension({ { "GL_KHR_debug", "glPushDebugGroup" } })),
+ popDebugGroup(
+ loadExtension({ { "GL_KHR_debug", "glPopDebugGroup" } })),
+ pushGroupMarkerEXT(
+ loadExtension({ { "GL_EXT_debug_marker", "glPushGroupMarkerEXT" } })),
+ popGroupMarkerEXT(
+ loadExtension({ { "GL_EXT_debug_marker", "glPopGroupMarkerEXT" } })),
+#endif
+ debugMessageControl(
+ loadExtension({ { "GL_KHR_debug", "glDebugMessageControl" },
+ { "GL_ARB_debug_output", "glDebugMessageControlARB" } })),
+ debugMessageCallback(
+ loadExtension({ { "GL_KHR_debug", "glDebugMessageCallback" },
+ { "GL_ARB_debug_output", "glDebugMessageCallbackARB" } })) {
+ }
+
+#ifndef NDEBUG
+ const ExtensionFunction<void(GLenum source,
+ GLuint id,
+ GLsizei length,
+ const GLchar* message)> pushDebugGroup;
+
+ const ExtensionFunction<void()> popDebugGroup;
+
+ const ExtensionFunction<void(GLsizei length,
+ const GLchar* marker)> pushGroupMarkerEXT;
+
+ const ExtensionFunction<void()> popGroupMarkerEXT;
+#endif
+
+ const ExtensionFunction<void(GLenum source,
+ GLenum type,
+ GLenum severity,
+ GLsizei count,
+ const GLuint* ids,
+ GLboolean enabled)> debugMessageControl;
+
+ const ExtensionFunction<void(Callback callback,
+ const void* userParam)> debugMessageCallback;
+};
+
+} // namespace extension
+} // namespace gl
+} // namespace mbgl
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/extension.cpp b/src/mbgl/gl/extension.cpp
deleted file mode 100644
index e6b4d9156e..0000000000
--- a/src/mbgl/gl/extension.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <mbgl/gl/extension.hpp>
-#include <mbgl/gl/gl.hpp>
-
-#include <mutex>
-#include <string>
-#include <vector>
-#include <cstring>
-
-namespace mbgl {
-namespace gl {
-namespace detail {
-
-using Probes = std::vector<ExtensionFunctionBase::Probe>;
-using ExtensionFunctions = std::vector<std::pair<glProc*, Probes>>;
-ExtensionFunctions& extensionFunctions() {
- static ExtensionFunctions functions;
- return functions;
-}
-
-ExtensionFunctionBase::ExtensionFunctionBase(std::initializer_list<Probe> probes) {
- extensionFunctions().emplace_back(&ptr, probes);
-}
-
-} // namespace detail
-
-static std::once_flag initializeExtensionsOnce;
-
-void InitializeExtensions(glProc (*getProcAddress)(const char*)) {
- std::call_once(initializeExtensionsOnce, [getProcAddress] {
- 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;
- }
- }
- }
- }
- });
-}
-
-} // namespace gl
-} // namespace mbgl
diff --git a/src/mbgl/gl/extension.hpp b/src/mbgl/gl/extension.hpp
index ea5a1ae5f5..8710314ef2 100644
--- a/src/mbgl/gl/extension.hpp
+++ b/src/mbgl/gl/extension.hpp
@@ -2,31 +2,21 @@
#include <initializer_list>
#include <utility>
+#include <functional>
namespace mbgl {
namespace gl {
-using glProc = void (*)();
-void InitializeExtensions(glProc (*getProcAddress)(const char*));
-
-namespace detail {
-
-class ExtensionFunctionBase {
-public:
- using Probe = std::pair<const char*, const char*>;
- ExtensionFunctionBase(std::initializer_list<Probe>);
- glProc ptr;
-};
-
-} // namespace detail
+using ProcAddress = void (*)();
template <class>
class ExtensionFunction;
template <class R, class... Args>
-class ExtensionFunction<R(Args...)> : protected detail::ExtensionFunctionBase {
+class ExtensionFunction<R(Args...)> {
public:
- using detail::ExtensionFunctionBase::ExtensionFunctionBase;
+ ExtensionFunction(const ProcAddress ptr_) : ptr(ptr_) {
+ }
explicit operator bool() const {
return ptr;
@@ -35,6 +25,9 @@ public:
R operator()(Args... args) const {
return (*reinterpret_cast<R (*)(Args...)>(ptr))(std::forward<Args>(args)...);
}
+
+private:
+ const ProcAddress ptr;
};
} // namespace gl
diff --git a/src/mbgl/gl/features.hpp b/src/mbgl/gl/features.hpp
new file mode 100644
index 0000000000..1757093967
--- /dev/null
+++ b/src/mbgl/gl/features.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#if __APPLE__
+ #define MBGL_HAS_BINARY_PROGRAMS 0
+#else
+ #define MBGL_HAS_BINARY_PROGRAMS 1
+#endif
diff --git a/src/mbgl/gl/gl.hpp b/src/mbgl/gl/gl.hpp
new file mode 100644
index 0000000000..3e21731330
--- /dev/null
+++ b/src/mbgl/gl/gl.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <stdexcept>
+#include <limits>
+
+#if __APPLE__
+ #include "TargetConditionals.h"
+ #if TARGET_OS_IPHONE
+ #include <OpenGLES/ES2/gl.h>
+ #include <OpenGLES/ES2/glext.h>
+ #elif TARGET_IPHONE_SIMULATOR
+ #include <OpenGLES/ES2/gl.h>
+ #include <OpenGLES/ES2/glext.h>
+ #elif TARGET_OS_MAC
+ #include <OpenGL/OpenGL.h>
+ #include <OpenGL/gl.h>
+ #include <OpenGL/glext.h>
+ #else
+ #error Unsupported Apple platform
+ #endif
+#elif __ANDROID__ || MBGL_USE_GLES2
+ #define GL_GLEXT_PROTOTYPES
+ #include <GLES2/gl2.h>
+ #include <GLES2/gl2ext.h>
+#elif __QT__ && QT_VERSION >= 0x050000
+ #define GL_GLEXT_PROTOTYPES
+ #include <QtGui/qopengl.h>
+#else
+ #define GL_GLEXT_PROTOTYPES
+ #include <GL/gl.h>
+ #include <GL/glext.h>
+#endif
+
+namespace mbgl {
+namespace gl {
+
+struct Error : std::runtime_error {
+ using std::runtime_error::runtime_error;
+};
+
+void checkError(const char *cmd, const char *file, int line);
+
+#ifndef NDEBUG
+#define MBGL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() noexcept(false) { ::mbgl::gl::checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }())
+#else
+#define MBGL_CHECK_ERROR(cmd) (cmd)
+#endif
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/index_buffer.hpp b/src/mbgl/gl/index_buffer.hpp
index b3610f4154..01b6396e00 100644
--- a/src/mbgl/gl/index_buffer.hpp
+++ b/src/mbgl/gl/index_buffer.hpp
@@ -24,7 +24,9 @@ public:
std::size_t byteSize() const { return v.size() * sizeof(uint16_t); }
bool empty() const { return v.empty(); }
+ void clear() { v.clear(); }
const uint16_t* data() const { return v.data(); }
+ const std::vector<uint16_t>& vector() const { return v; }
private:
std::vector<uint16_t> v;
diff --git a/src/mbgl/gl/object.cpp b/src/mbgl/gl/object.cpp
index e2d476e0c0..2c5f1bca1f 100644
--- a/src/mbgl/gl/object.cpp
+++ b/src/mbgl/gl/object.cpp
@@ -33,7 +33,9 @@ void TextureDeleter::operator()(TextureID id) const {
void VertexArrayDeleter::operator()(VertexArrayID id) const {
assert(context);
- context->abandonedVertexArrays.push_back(id);
+ if (id != 0) {
+ context->abandonedVertexArrays.push_back(id);
+ }
}
void FramebufferDeleter::operator()(FramebufferID id) const {
diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp
index 33387e9d4e..3b54ec194a 100644
--- a/src/mbgl/gl/program.hpp
+++ b/src/mbgl/gl/program.hpp
@@ -5,9 +5,16 @@
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/gl/index_buffer.hpp>
+#include <mbgl/gl/vertex_array.hpp>
#include <mbgl/gl/attribute.hpp>
#include <mbgl/gl/uniform.hpp>
+#include <mbgl/util/io.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/programs/binary_program.hpp>
+#include <mbgl/programs/program_parameters.hpp>
+#include <mbgl/shaders/shaders.hpp>
+
#include <string>
namespace mbgl {
@@ -20,17 +27,85 @@ 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)),
- uniformsState((context.linkProgram(program), Uniforms::state(program))) {}
+ : program(
+ context.createProgram(context.createShader(ShaderType::Vertex, vertexSource),
+ context.createShader(ShaderType::Fragment, fragmentSource))),
+ uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))),
+ attributeLocations(Attributes::bindLocations(program)) {
+ // Re-link program after manually binding only active attributes in Attributes::bindLocations
+ context.linkProgram(program);
+ }
+
+ template <class BinaryProgram>
+ Program(Context& context, const BinaryProgram& binaryProgram)
+ : program(context.createProgram(binaryProgram.format(), binaryProgram.code())),
+ uniformsState(Uniforms::loadNamedLocations(binaryProgram)),
+ attributeLocations(Attributes::loadNamedLocations(binaryProgram)) {
+ }
+
+ static Program createProgram(gl::Context& context,
+ const ProgramParameters& programParameters,
+ const char* name,
+ const char* vertexSource_,
+ const char* fragmentSource_) {
+ const std::string vertexSource = shaders::vertexSource(programParameters, vertexSource_);
+ const std::string fragmentSource = shaders::fragmentSource(programParameters, fragmentSource_);
+
+#if MBGL_HAS_BINARY_PROGRAMS
+ optional<std::string> cachePath = programParameters.cachePath(name);
+ if (cachePath && context.supportsProgramBinaries()) {
+ const std::string identifier = shaders::programIdentifier(vertexSource, fragmentSource);
+
+ try {
+ if (auto cachedBinaryProgram = util::readFile(*cachePath)) {
+ const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram));
+ if (binaryProgram.identifier() == identifier) {
+ return Program { context, binaryProgram };
+ } else {
+ Log::Warning(Event::OpenGL,
+ "Cached program %s changed. Recompilation required.",
+ name);
+ }
+ }
+ } catch (std::runtime_error& error) {
+ Log::Warning(Event::OpenGL, "Could not load cached program: %s",
+ error.what());
+ }
+
+ // Compile the shader
+ Program result{ context, vertexSource, fragmentSource };
+
+ try {
+ if (const auto binaryProgram =
+ result.template get<BinaryProgram>(context, identifier)) {
+ util::write_file(*cachePath, binaryProgram->serialize());
+ Log::Warning(Event::OpenGL, "Caching program in: %s", (*cachePath).c_str());
+ }
+ } catch (std::runtime_error& error) {
+ Log::Warning(Event::OpenGL, "Failed to cache program: %s", error.what());
+ }
+
+ return std::move(result);
+ }
+#endif
+
+ (void)name;
+ return Program { context, vertexSource, fragmentSource };
+ }
+
+ template <class BinaryProgram>
+ optional<BinaryProgram> get(Context& context, const std::string& identifier) const {
+ if (auto binaryProgram = context.getBinaryProgram(program)) {
+ return BinaryProgram{ binaryProgram->first, std::move(binaryProgram->second),
+ identifier, Attributes::getNamedLocations(attributeLocations),
+ Uniforms::getNamedLocations(uniformsState) };
+ }
+ return {};
+ }
template <class DrawMode>
void draw(Context& context,
@@ -38,32 +113,37 @@ public:
DepthMode depthMode,
StencilMode stencilMode,
ColorMode colorMode,
- UniformValues&& uniformValues,
- const VertexBuffer<Vertex>& vertexBuffer,
+ const UniformValues& uniformValues,
+ VertexArray& vertexArray,
+ const AttributeBindings& attributeBindings,
const IndexBuffer<DrawMode>& indexBuffer,
- const SegmentVector<Attributes>& segments) {
+ std::size_t indexOffset,
+ std::size_t indexLength) {
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, uniformValues);
+
+ vertexArray.bind(context,
+ indexBuffer.buffer,
+ Attributes::toBindingArray(attributeLocations, attributeBindings));
+
+ context.draw(drawMode.primitiveType,
+ indexOffset,
+ indexLength);
}
private:
- UniqueShader vertexShader;
- UniqueShader fragmentShader;
UniqueProgram program;
- typename Attributes::State attributesState;
typename Uniforms::State uniformsState;
+ typename Attributes::Locations attributeLocations;
};
} // namespace gl
diff --git a/src/mbgl/gl/program_binary_extension.hpp b/src/mbgl/gl/program_binary_extension.hpp
new file mode 100644
index 0000000000..a4aa1eeefc
--- /dev/null
+++ b/src/mbgl/gl/program_binary_extension.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <mbgl/gl/features.hpp>
+#include <mbgl/gl/extension.hpp>
+#include <mbgl/gl/gl.hpp>
+
+#if MBGL_HAS_BINARY_PROGRAMS
+
+#define GL_PROGRAM_BINARY_LENGTH 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS 0x87FF
+
+namespace mbgl {
+namespace gl {
+namespace extension {
+
+class ProgramBinary {
+public:
+ template <typename Fn>
+ ProgramBinary(const Fn& loadExtension)
+ : getProgramBinary(loadExtension({
+ { "GL_OES_get_program_binary", "glGetProgramBinaryOES" },
+ { "GL_ARB_get_program_binary", "glGetProgramBinary" },
+ })),
+ programBinary(loadExtension({
+ { "GL_OES_get_program_binary", "glProgramBinaryOES" },
+ { "GL_ARB_get_program_binary", "glProgramBinary" },
+ })) {
+ }
+
+ const ExtensionFunction<void(
+ GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary)>
+ getProgramBinary;
+
+ const ExtensionFunction<void(
+ GLuint program, GLenum binaryFormat, const GLvoid* binary, GLint length)>
+ programBinary;
+};
+
+} // namespace extension
+} // namespace gl
+} // namespace mbgl
+
+#endif
diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp
deleted file mode 100644
index 8f74afd237..0000000000
--- a/src/mbgl/gl/segment.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#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/state.hpp b/src/mbgl/gl/state.hpp
index efe869e5b9..17503cc043 100644
--- a/src/mbgl/gl/state.hpp
+++ b/src/mbgl/gl/state.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <tuple>
+
namespace mbgl {
namespace gl {
@@ -12,13 +14,16 @@ namespace gl {
// static void Set(const Type& value);
// static Type Get();
// };
-template <typename T>
+template <typename T, typename... Args>
class State {
public:
+ State(Args&&... args) : params(std::forward_as_tuple(::std::forward<Args>(args)...)) {
+ }
+
void operator=(const typename T::Type& value) {
if (*this != value) {
setCurrentValue(value);
- T::Set(currentValue);
+ set(std::index_sequence_for<Args...>{});
}
}
@@ -50,23 +55,15 @@ public:
}
private:
- typename T::Type currentValue = T::Default;
- bool dirty = true;
-};
-
-// Helper struct that stores the current state and restores it upon destruction. You should not use
-// this code normally, except for debugging purposes.
-template <typename T>
-class PreserveState {
-public:
- PreserveState() : value(T::Get()) {
- }
- ~PreserveState() {
- T::Set(value);
+ template <std::size_t... I>
+ void set(std::index_sequence<I...>) {
+ T::Set(currentValue, std::get<I>(params)...);
}
private:
- const typename T::Type value;
+ typename T::Type currentValue = T::Default;
+ bool dirty = true;
+ const std::tuple<Args...> params;
};
} // namespace gl
diff --git a/src/mbgl/gl/texture.hpp b/src/mbgl/gl/texture.hpp
index ffa08ec80a..625e69233a 100644
--- a/src/mbgl/gl/texture.hpp
+++ b/src/mbgl/gl/texture.hpp
@@ -3,21 +3,29 @@
#include <mbgl/gl/object.hpp>
#include <mbgl/util/size.hpp>
-#include <functional>
-
namespace mbgl {
namespace gl {
class Texture {
public:
- Texture(Size size_, std::function<UniqueTexture()> getTexture) : size(size_), texture(getTexture()) {}
+ Texture(Size size_, UniqueTexture texture_,
+ TextureFilter filter_ = TextureFilter::Nearest,
+ TextureMipMap mipmap_ = TextureMipMap::No,
+ TextureWrap wrapX_ = TextureWrap::Clamp,
+ TextureWrap wrapY_ = TextureWrap::Clamp)
+ : size(std::move(size_)),
+ texture(std::move(texture_)),
+ filter(filter_),
+ mipmap(mipmap_),
+ wrapX(wrapX_),
+ wrapY(wrapY_) {}
Size size;
UniqueTexture texture;
- TextureFilter filter = TextureFilter::Nearest;
- TextureMipMap mipmap = TextureMipMap::No;
- TextureWrap wrapX = TextureWrap::Clamp;
- TextureWrap wrapY = TextureWrap::Clamp;
+ TextureFilter filter;
+ TextureMipMap mipmap;
+ TextureWrap wrapX;
+ TextureWrap wrapY;
};
} // namespace gl
diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp
index 577629d5d3..da08195e58 100644
--- a/src/mbgl/gl/types.hpp
+++ b/src/mbgl/gl/types.hpp
@@ -15,8 +15,16 @@ using VertexArrayID = uint32_t;
using FramebufferID = uint32_t;
using RenderbufferID = uint32_t;
-using AttributeLocation = int32_t;
+// OpenGL does not formally define a type for attribute locations, but most APIs use
+// GLuint. The exception is glGetAttribLocation, which returns GLint so that -1 can
+// be used as an error indicator.
+using AttributeLocation = uint32_t;
+
+// OpenGL does not formally define a type for uniform locations, but all APIs use GLint.
+// The value -1 is special, typically used as a placeholder for an unused uniform and
+// "silently ignored".
using UniformLocation = int32_t;
+
using TextureUnit = uint8_t;
enum class ShaderType : uint32_t {
@@ -24,7 +32,7 @@ enum class ShaderType : uint32_t {
Fragment = 0x8B30
};
-enum class DataType : uint32_t {
+enum class DataType : uint16_t {
Byte = 0x1400,
UnsignedByte = 0x1401,
Short = 0x1402,
@@ -34,19 +42,14 @@ 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,
+#if not MBGL_USE_GLES2
+ DepthComponent = 0x1902, // GL_DEPTH_COMPONENT
+#else
+ DepthComponent = 0x81A5, // GL_DEPTH_COMPONENT16
+#endif // MBGL_USE_GLES2
};
enum class TextureMipMap : bool { No = false, Yes = true };
@@ -71,8 +74,6 @@ enum class PrimitiveType {
TriangleFan = 0x0006
};
-#if not MBGL_USE_GLES2
-
struct PixelStorageType {
int32_t alignment;
};
@@ -81,7 +82,33 @@ constexpr bool operator!=(const PixelStorageType& a, const PixelStorageType& b)
return a.alignment != b.alignment;
}
-#endif // MBGL_USE_GLES2
+using BinaryProgramFormat = uint32_t;
+
+enum class UniformDataType : uint32_t {
+ Float = 0x1406,
+ FloatVec2 = 0x8B50,
+ FloatVec3 = 0x8B51,
+ FloatVec4 = 0x8B52,
+ Int = 0x1404,
+ IntVec2 = 0x8B53,
+ IntVec3 = 0x8B54,
+ IntVec4 = 0x8B55,
+ Bool = 0x8B56,
+ BoolVec2 = 0x8B57,
+ BoolVec3 = 0x8B58,
+ BoolVec4 = 0x8B59,
+ FloatMat2 = 0x8B5A,
+ FloatMat3 = 0x8B5B,
+ FloatMat4 = 0x8B5C,
+ Sampler2D = 0x8B5E,
+ SamplerCube = 0x8B60,
+};
+
+enum class BufferUsage : uint32_t {
+ StreamDraw = 0x88E0,
+ StaticDraw = 0x88E4,
+ DynamicDraw = 0x88E8,
+};
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/uniform.cpp b/src/mbgl/gl/uniform.cpp
index 7b674f2cde..2946980c19 100644
--- a/src/mbgl/gl/uniform.cpp
+++ b/src/mbgl/gl/uniform.cpp
@@ -4,6 +4,8 @@
#include <mbgl/util/size.hpp>
#include <mbgl/util/convert.hpp>
+#include <memory>
+
namespace mbgl {
namespace gl {
@@ -79,5 +81,96 @@ void bindUniform<std::array<uint16_t, 2>>(UniformLocation location, const std::a
// Add more as needed.
+#ifndef NDEBUG
+
+ActiveUniforms activeUniforms(ProgramID id) {
+ ActiveUniforms active;
+
+ GLint count;
+ GLint maxLength;
+ MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &count));
+ MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength));
+
+ auto name = std::make_unique<GLchar[]>(maxLength);
+ GLsizei length;
+ GLint size;
+ GLenum type;
+ for (GLint index = 0; index < count; index++) {
+ MBGL_CHECK_ERROR(
+ glGetActiveUniform(id, index, maxLength, &length, &size, &type, name.get()));
+ active.emplace(
+ std::string{ name.get(), static_cast<size_t>(length) },
+ ActiveUniform{ static_cast<size_t>(size), static_cast<UniformDataType>(type) });
+ }
+
+ return active;
+}
+
+template <>
+bool verifyUniform<float>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::Float);
+ return true;
+}
+
+template <>
+bool verifyUniform<std::array<float, 2>>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec2);
+ return true;
+}
+
+template <>
+bool verifyUniform<std::array<float, 3>>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec3);
+ return true;
+}
+
+template <>
+bool verifyUniform<std::array<double, 16>>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatMat4);
+ return true;
+}
+
+template <>
+bool verifyUniform<bool>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 &&
+ (uniform.type == UniformDataType::Bool ||
+ uniform.type == UniformDataType::Int ||
+ uniform.type == UniformDataType::Float));
+ return true;
+}
+
+template <>
+bool verifyUniform<uint8_t>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 &&
+ (uniform.type == UniformDataType::Int ||
+ uniform.type == UniformDataType::Float ||
+ uniform.type == UniformDataType::Sampler2D));
+ return true;
+}
+
+template <>
+bool verifyUniform<Color>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec4);
+ return true;
+}
+
+template <>
+bool verifyUniform<Size>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec2);
+ return true;
+}
+
+template <>
+bool verifyUniform<std::array<uint16_t, 2>>(const ActiveUniform& uniform) {
+ assert(uniform.size == 1 &&
+ (uniform.type == UniformDataType::IntVec2 ||
+ uniform.type == UniformDataType::FloatVec2));
+ return true;
+}
+
+// Add more as needed.
+
+#endif
+
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp
index 5c0980baf0..5a78068fc8 100644
--- a/src/mbgl/gl/uniform.hpp
+++ b/src/mbgl/gl/uniform.hpp
@@ -6,6 +6,8 @@
#include <mbgl/util/indexed_tuple.hpp>
#include <array>
+#include <vector>
+#include <map>
#include <functional>
namespace mbgl {
@@ -21,17 +23,35 @@ public:
T t;
};
+class ActiveUniform {
+public:
+ std::size_t size;
+ UniformDataType type;
+};
+
+#ifndef NDEBUG
+
+template <class T>
+bool verifyUniform(const ActiveUniform&);
+
+using ActiveUniforms = std::map<std::string, ActiveUniform>;
+ActiveUniforms activeUniforms(ProgramID);
+
+#endif
+
template <class Tag, class T>
class Uniform {
public:
using Value = UniformValue<Tag, T>;
+ using Type = T;
+
class State {
public:
State(UniformLocation location_) : location(std::move(location_)) {}
void operator=(const Value& value) {
- if (!current || *current != value.t) {
+ if (location >= 0 && (!current || *current != value.t)) {
current = value.t;
bindUniform(location, value.t);
}
@@ -52,32 +72,71 @@ 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...>>;
+ using NamedLocations = std::vector<std::pair<const std::string, UniformLocation>>;
+
+ static State bindLocations(const ProgramID& id) {
+#ifndef NDEBUG
+ // Verify active uniform types match the enum
+ const auto active = activeUniforms(id);
+
+ util::ignore(
+ { // Some shader programs have uniforms declared, but not used, so they're not active.
+ // Therefore, we'll only verify them when they are indeed active.
+ (active.find(Us::name()) != active.end()
+ ? verifyUniform<typename Us::Type>(active.at(Us::name()))
+ : false)... });
+#endif
+
+ return State { { uniformLocation(id, Us::name()) }... };
+ }
- static State state(const ProgramID& id) {
- return State(typename Us::State(uniformLocation(id, Us::name))...);
+ template <class Program>
+ static State loadNamedLocations(const Program& program) {
+ return State(typename Us::State(program.uniformLocation(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 NamedLocations getNamedLocations(const State& state) {
+ return NamedLocations{ { Us::name(), state.template get<Us>().location }... };
+ }
+
+ static void bind(State& state, const 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
diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp
index 603d82dfd5..89014fe6bc 100644
--- a/src/mbgl/gl/value.cpp
+++ b/src/mbgl/gl/value.cpp
@@ -1,6 +1,7 @@
#include <mbgl/gl/value.hpp>
#include <mbgl/gl/gl.hpp>
-#include <mbgl/gl/vertex_array.hpp>
+#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/vertex_array_extension.hpp>
namespace mbgl {
namespace gl {
@@ -266,6 +267,18 @@ Viewport::Type Viewport::Get() {
{ static_cast<uint32_t>(viewport[2]), static_cast<uint32_t>(viewport[3]) } };
}
+const constexpr ScissorTest::Type ScissorTest::Default;
+
+void ScissorTest::Set(const Type& value) {
+ MBGL_CHECK_ERROR(value ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST));
+}
+
+ScissorTest::Type ScissorTest::Get() {
+ Type scissorTest;
+ MBGL_CHECK_ERROR(scissorTest = glIsEnabled(GL_SCISSOR_TEST));
+ return scissorTest;
+}
+
const constexpr BindFramebuffer::Type BindFramebuffer::Default;
void BindFramebuffer::Set(const Type& value) {
@@ -328,15 +341,17 @@ BindElementBuffer::Type BindElementBuffer::Get() {
const constexpr BindVertexArray::Type BindVertexArray::Default;
-void BindVertexArray::Set(const Type& value) {
- if (gl::BindVertexArray) {
- MBGL_CHECK_ERROR(gl::BindVertexArray(value));
+void BindVertexArray::Set(const Type& value, const Context& context) {
+ if (auto vertexArray = context.getVertexArrayExtension()) {
+ if (vertexArray->bindVertexArray) {
+ MBGL_CHECK_ERROR(vertexArray->bindVertexArray(value));
+ }
}
}
-BindVertexArray::Type BindVertexArray::Get() {
+BindVertexArray::Type BindVertexArray::Get(const Context& context) {
GLint binding = 0;
- if (gl::BindVertexArray) {
+ if (context.getVertexArrayExtension()) {
#ifdef GL_VERTEX_ARRAY_BINDING
MBGL_CHECK_ERROR(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &binding));
#elif GL_VERTEX_ARRAY_BINDING_OES
@@ -350,6 +365,52 @@ BindVertexArray::Type BindVertexArray::Get() {
return binding;
}
+const optional<AttributeBinding> VertexAttribute::Default {};
+
+void VertexAttribute::Set(const optional<AttributeBinding>& binding, Context& context, AttributeLocation location) {
+ if (binding) {
+ context.vertexBuffer = binding->vertexBuffer;
+ MBGL_CHECK_ERROR(glEnableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttribPointer(
+ location,
+ static_cast<GLint>(binding->attributeSize),
+ static_cast<GLenum>(binding->attributeType),
+ static_cast<GLboolean>(false),
+ static_cast<GLsizei>(binding->vertexSize),
+ reinterpret_cast<GLvoid*>(binding->attributeOffset + (binding->vertexSize * binding->vertexOffset))));
+ } else {
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ }
+}
+
+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;
+}
+
#if not MBGL_USE_GLES2
const constexpr PointSize::Type PointSize::Default;
@@ -389,34 +450,6 @@ RasterPos::Type RasterPos::Get() {
return { pos[0], pos[1], pos[2], pos[3] };
}
-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) {
diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp
index eccd3e7373..19e9af194f 100644
--- a/src/mbgl/gl/value.hpp
+++ b/src/mbgl/gl/value.hpp
@@ -4,12 +4,16 @@
#include <mbgl/gl/depth_mode.hpp>
#include <mbgl/gl/stencil_mode.hpp>
#include <mbgl/gl/color_mode.hpp>
+#include <mbgl/gl/attribute.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/size.hpp>
#include <mbgl/util/range.hpp>
namespace mbgl {
namespace gl {
+
+class Context;
+
namespace value {
struct ClearDepth {
@@ -179,6 +183,13 @@ struct Viewport {
static Type Get();
};
+struct ScissorTest {
+ using Type = bool;
+ static const constexpr Type Default = false;
+ 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.size != b.size;
}
@@ -225,6 +236,26 @@ struct BindElementBuffer {
struct BindVertexArray {
using Type = gl::VertexArrayID;
static const constexpr Type Default = 0;
+ static void Set(const Type&, const Context&);
+ static Type Get(const Context&);
+};
+
+struct VertexAttribute {
+ using Type = optional<gl::AttributeBinding>;
+ static const Type Default;
+ static void Set(const Type&, Context&, AttributeLocation);
+};
+
+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();
};
@@ -268,20 +299,6 @@ 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;
diff --git a/src/mbgl/gl/vertex_array.cpp b/src/mbgl/gl/vertex_array.cpp
index df63bbc4b7..68a500ac45 100644
--- a/src/mbgl/gl/vertex_array.cpp
+++ b/src/mbgl/gl/vertex_array.cpp
@@ -1,22 +1,18 @@
#include <mbgl/gl/vertex_array.hpp>
+#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/gl.hpp>
namespace mbgl {
namespace gl {
-ExtensionFunction<void(GLuint array)>
- BindVertexArray({ { "GL_ARB_vertex_array_object", "glBindVertexArray" },
- { "GL_OES_vertex_array_object", "glBindVertexArrayOES" },
- { "GL_APPLE_vertex_array_object", "glBindVertexArrayAPPLE" } });
+void VertexArray::bind(Context& context, BufferID indexBuffer, const AttributeBindingArray& bindings) {
+ context.bindVertexArray = state->vertexArray;
+ state->indexBuffer = indexBuffer;
-ExtensionFunction<void(GLsizei n, const GLuint* arrays)>
- DeleteVertexArrays({ { "GL_ARB_vertex_array_object", "glDeleteVertexArrays" },
- { "GL_OES_vertex_array_object", "glDeleteVertexArraysOES" },
- { "GL_APPLE_vertex_array_object", "glDeleteVertexArraysAPPLE" } });
-
-ExtensionFunction<void(GLsizei n, GLuint* arrays)>
- GenVertexArrays({ { "GL_ARB_vertex_array_object", "glGenVertexArrays" },
- { "GL_OES_vertex_array_object", "glGenVertexArraysOES" },
- { "GL_APPLE_vertex_array_object", "glGenVertexArraysAPPLE" } });
+ for (AttributeLocation location = 0; location < MAX_ATTRIBUTES; ++location) {
+ state->bindings[location] = bindings[location];
+ }
+}
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/vertex_array.hpp b/src/mbgl/gl/vertex_array.hpp
index 6215e56f21..46c67017bb 100644
--- a/src/mbgl/gl/vertex_array.hpp
+++ b/src/mbgl/gl/vertex_array.hpp
@@ -1,14 +1,73 @@
#pragma once
-#include <mbgl/gl/extension.hpp>
-#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/object.hpp>
+#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/state.hpp>
+#include <mbgl/gl/value.hpp>
+
+#include <array>
+#include <memory>
namespace mbgl {
namespace gl {
-extern ExtensionFunction<void(GLuint array)> BindVertexArray;
-extern ExtensionFunction<void(GLsizei n, const GLuint* arrays)> DeleteVertexArrays;
-extern ExtensionFunction<void(GLsizei n, GLuint* arrays)> GenVertexArrays;
+class Context;
+
+class VertexArrayState {
+public:
+ VertexArrayState(UniqueVertexArray vertexArray_, Context& context)
+ : vertexArray(std::move(vertexArray_)),
+ bindings(makeBindings(context, std::make_index_sequence<MAX_ATTRIBUTES>())) {
+ }
+
+ void setDirty() {
+ indexBuffer.setDirty();
+ for (auto& binding : bindings) {
+ binding.setDirty();
+ }
+ }
+
+ UniqueVertexArray vertexArray;
+ State<value::BindElementBuffer> indexBuffer;
+
+ using AttributeState = State<value::VertexAttribute, Context&, AttributeLocation>;
+ std::array<AttributeState, MAX_ATTRIBUTES> bindings;
+
+private:
+ template <std::size_t... I>
+ std::array<AttributeState, MAX_ATTRIBUTES> makeBindings(Context& context, std::index_sequence<I...>) {
+ return {{ AttributeState { context, I }... }};
+ }
+};
+
+class VertexArrayStateDeleter {
+public:
+ VertexArrayStateDeleter(bool destroy_)
+ : destroy(destroy_) {}
+
+ void operator()(VertexArrayState* ptr) const {
+ if (destroy) {
+ delete ptr;
+ }
+ }
+
+private:
+ bool destroy;
+};
+
+using UniqueVertexArrayState = std::unique_ptr<VertexArrayState, VertexArrayStateDeleter>;
+
+class VertexArray {
+public:
+ VertexArray(UniqueVertexArrayState state_)
+ : state(std::move(state_)) {
+ }
+
+ void bind(Context&, BufferID indexBuffer, const AttributeBindingArray&);
+
+private:
+ UniqueVertexArrayState state;
+};
} // namespace gl
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/src/mbgl/gl/vertex_array_extension.hpp b/src/mbgl/gl/vertex_array_extension.hpp
new file mode 100644
index 0000000000..707a20e6f0
--- /dev/null
+++ b/src/mbgl/gl/vertex_array_extension.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <mbgl/gl/extension.hpp>
+#include <mbgl/gl/gl.hpp>
+
+namespace mbgl {
+namespace gl {
+namespace extension {
+
+class VertexArray {
+public:
+ template <typename Fn>
+ VertexArray(const Fn& loadExtension)
+ : bindVertexArray(
+ loadExtension({ { "GL_ARB_vertex_array_object", "glBindVertexArray" },
+ { "GL_OES_vertex_array_object", "glBindVertexArrayOES" },
+ { "GL_APPLE_vertex_array_object", "glBindVertexArrayAPPLE" } })),
+ deleteVertexArrays(
+ loadExtension({ { "GL_ARB_vertex_array_object", "glDeleteVertexArrays" },
+ { "GL_OES_vertex_array_object", "glDeleteVertexArraysOES" },
+ { "GL_APPLE_vertex_array_object", "glDeleteVertexArraysAPPLE" } })),
+ genVertexArrays(
+ loadExtension({ { "GL_ARB_vertex_array_object", "glGenVertexArrays" },
+ { "GL_OES_vertex_array_object", "glGenVertexArraysOES" },
+ { "GL_APPLE_vertex_array_object", "glGenVertexArraysAPPLE" } })) {
+ }
+
+ const ExtensionFunction<void(GLuint array)> bindVertexArray;
+
+ const ExtensionFunction<void(GLsizei n, const GLuint* arrays)> deleteVertexArrays;
+
+ const ExtensionFunction<void(GLsizei n, GLuint* arrays)> genVertexArrays;
+};
+
+} // namespace extension
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/vertex_buffer.hpp b/src/mbgl/gl/vertex_buffer.hpp
index c9bc01f3e8..9f8b156b25 100644
--- a/src/mbgl/gl/vertex_buffer.hpp
+++ b/src/mbgl/gl/vertex_buffer.hpp
@@ -26,7 +26,9 @@ public:
std::size_t byteSize() const { return v.size() * sizeof(Vertex); }
bool empty() const { return v.empty(); }
+ void clear() { v.clear(); }
const Vertex* data() const { return v.data(); }
+ const std::vector<Vertex>& vector() const { return v; }
private:
std::vector<Vertex> v;