summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-10-10 15:58:04 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-10-28 17:14:07 -0700
commit39d5cb325012a5675676c81153c5e95d29fbc357 (patch)
tree214ad773048a0ae1e0492573ba9bb21716c4d881
parent0e57d10d77e555a9229f7d522d83f87df7d5180d (diff)
downloadqtlocation-mapboxgl-39d5cb325012a5675676c81153c5e95d29fbc357.tar.gz
[core] Use VAOs internally
-rw-r--r--src/mbgl/gl/context.cpp82
-rw-r--r--src/mbgl/gl/context.hpp16
-rw-r--r--test/gl/object.test.cpp7
3 files changed, 79 insertions, 26 deletions
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index 26a8e299ec..acecf2b698 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -3,6 +3,9 @@
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/vertex_array.hpp>
#include <mbgl/util/traits.hpp>
+#include <mbgl/util/std.hpp>
+
+#include <boost/functional/hash.hpp>
namespace mbgl {
namespace gl {
@@ -68,12 +71,6 @@ UniqueTexture Context::createTexture() {
return UniqueTexture{ std::move(id), { this } };
}
-UniqueVertexArray Context::createVertexArray() {
- VertexArrayID id = 0;
- MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id));
- return UniqueVertexArray{ std::move(id), { this } };
-}
-
UniqueFramebuffer Context::createFramebuffer() {
FramebufferID id = 0;
MBGL_CHECK_ERROR(glGenFramebuffers(1, &id));
@@ -319,6 +316,15 @@ PrimitiveType Context::operator()(const TriangleStrip&) {
return PrimitiveType::TriangleStrip;
}
+std::size_t Context::VertexArrayObjectHash::operator()(const VertexArrayObjectKey& key) const {
+ std::size_t seed = 0;
+ boost::hash_combine(seed, std::get<0>(key));
+ boost::hash_combine(seed, std::get<1>(key));
+ boost::hash_combine(seed, std::get<2>(key));
+ boost::hash_combine(seed, std::get<3>(key));
+ return seed;
+}
+
void Context::setDepthMode(const DepthMode& depth) {
if (depth.func == DepthMode::Always && !depth.mask) {
depthTest = false;
@@ -374,18 +380,51 @@ void Context::draw(const Drawable& drawable) {
drawable.bindUniforms();
for (const auto& segment : drawable.segments) {
- vertexBuffer = drawable.vertexBuffer;
- elementBuffer = drawable.indexBuffer;
-
- for (const auto& binding : drawable.attributeBindings) {
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(binding.location));
- MBGL_CHECK_ERROR(glVertexAttribPointer(
- binding.location,
- binding.count,
- static_cast<GLenum>(binding.type),
- GL_FALSE,
- static_cast<GLsizei>(drawable.vertexSize),
- reinterpret_cast<GLvoid*>(binding.offset + (drawable.vertexSize * segment.vertexOffset))));
+ auto needAttributeBindings = [&] () {
+ if (!gl::GenVertexArrays || !gl::BindVertexArray) {
+ return true;
+ }
+
+ VertexArrayObjectKey vaoKey {
+ drawable.program,
+ drawable.vertexBuffer,
+ drawable.indexBuffer,
+ segment.vertexOffset
+ };
+
+ auto it = vaos.find(vaoKey);
+ if (it != vaos.end()) {
+ vertexArrayObject = it->second;
+ return false;
+ }
+
+ VertexArrayID id = 0;
+ MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id));
+ vertexArrayObject = id;
+ vaos.emplace(vaoKey, 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;
+
+ for (const auto& binding : drawable.attributeBindings) {
+ MBGL_CHECK_ERROR(glEnableVertexAttribArray(binding.location));
+ MBGL_CHECK_ERROR(glVertexAttribPointer(
+ binding.location,
+ binding.count,
+ static_cast<GLenum>(binding.type),
+ GL_FALSE,
+ static_cast<GLsizei>(drawable.vertexSize),
+ reinterpret_cast<GLvoid*>(binding.offset + (drawable.vertexSize * segment.vertexOffset))));
+ }
}
if (drawable.indexBuffer) {
@@ -408,6 +447,9 @@ void Context::performCleanup() {
if (program == id) {
program.setDirty();
}
+ mbgl::util::erase_if(vaos, [&] (const VertexArrayObjectMap::value_type& kv) {
+ return std::get<0>(kv.first) == id;
+ });
MBGL_CHECK_ERROR(glDeleteProgram(id));
}
abandonedPrograms.clear();
@@ -424,6 +466,10 @@ void Context::performCleanup() {
} else if (elementBuffer == id) {
elementBuffer.setDirty();
}
+ mbgl::util::erase_if(vaos, [&] (const VertexArrayObjectMap::value_type& kv) {
+ return std::get<1>(kv.first) == id
+ || std::get<2>(kv.first) == id;
+ });
}
MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data()));
abandonedBuffers.clear();
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index 74c1bcba56..84c83f8d31 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -14,6 +14,7 @@
#include <memory>
#include <vector>
#include <array>
+#include <unordered_map>
namespace mbgl {
@@ -31,7 +32,6 @@ public:
UniqueShader createVertexShader();
UniqueShader createFragmentShader();
UniqueTexture createTexture();
- UniqueVertexArray createVertexArray();
template <class V>
VertexBuffer<V> createVertexBuffer(std::vector<V>&& v) {
@@ -174,6 +174,20 @@ private:
std::vector<VertexArrayID> abandonedVertexArrays;
std::vector<FramebufferID> abandonedFramebuffers;
std::vector<RenderbufferID> abandonedRenderbuffers;
+
+ using VertexArrayObjectKey = std::tuple<
+ ProgramID, // Program
+ BufferID, // Vertex buffer
+ BufferID, // Index buffer
+ std::size_t // Vertex buffer offset
+ >;
+
+ struct VertexArrayObjectHash {
+ std::size_t operator()(const VertexArrayObjectKey&) const;
+ };
+
+ using VertexArrayObjectMap = std::unordered_map<VertexArrayObjectKey, UniqueVertexArray, VertexArrayObjectHash>;
+ VertexArrayObjectMap vaos;
};
} // namespace gl
diff --git a/test/gl/object.test.cpp b/test/gl/object.test.cpp
index a3457d28c6..2a1ee0a1da 100644
--- a/test/gl/object.test.cpp
+++ b/test/gl/object.test.cpp
@@ -88,13 +88,6 @@ TEST(GLObject, Store) {
context.reset();
EXPECT_TRUE(context.empty());
- mbgl::gl::UniqueVertexArray vao = context.createVertexArray();
- EXPECT_NE(vao.get(), 0u);
- vao.reset();
- EXPECT_FALSE(context.empty());
- context.performCleanup();
- EXPECT_TRUE(context.empty());
-
context.reset();
EXPECT_TRUE(context.empty());