From 39d5cb325012a5675676c81153c5e95d29fbc357 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 10 Oct 2016 15:58:04 -0700 Subject: [PATCH] [core] Use VAOs internally --- src/mbgl/gl/context.cpp | 82 ++++++++++++++++++++++++++++++++--------- src/mbgl/gl/context.hpp | 16 +++++++- test/gl/object.test.cpp | 7 ---- 3 files changed, 79 insertions(+), 26 deletions(-) diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 26a8e299eca..acecf2b6989 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -3,6 +3,9 @@ #include #include #include +#include + +#include 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(binding.type), - GL_FALSE, - static_cast(drawable.vertexSize), - reinterpret_cast(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(binding.type), + GL_FALSE, + static_cast(drawable.vertexSize), + reinterpret_cast(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 74c1bcba56f..84c83f8d311 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace mbgl { @@ -31,7 +32,6 @@ class Context : private util::noncopyable { UniqueShader createVertexShader(); UniqueShader createFragmentShader(); UniqueTexture createTexture(); - UniqueVertexArray createVertexArray(); template VertexBuffer createVertexBuffer(std::vector&& v) { @@ -174,6 +174,20 @@ class Context : private util::noncopyable { std::vector abandonedVertexArrays; std::vector abandonedFramebuffers; std::vector 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; + VertexArrayObjectMap vaos; }; } // namespace gl diff --git a/test/gl/object.test.cpp b/test/gl/object.test.cpp index a3457d28c65..2a1ee0a1da0 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());