summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mbgl/geometry/buffer.hpp1
-rw-r--r--src/mbgl/geometry/glyph_atlas.cpp6
-rw-r--r--src/mbgl/geometry/glyph_atlas.hpp5
-rw-r--r--src/mbgl/geometry/line_atlas.cpp6
-rw-r--r--src/mbgl/geometry/line_atlas.hpp5
-rw-r--r--src/mbgl/geometry/sprite_atlas.cpp6
-rw-r--r--src/mbgl/geometry/sprite_atlas.hpp7
-rw-r--r--src/mbgl/renderer/debug_bucket.cpp3
-rw-r--r--src/mbgl/renderer/fill_bucket.cpp8
-rw-r--r--src/mbgl/renderer/line_bucket.cpp5
-rw-r--r--src/mbgl/renderer/painter.cpp66
-rw-r--r--src/mbgl/renderer/raster_bucket.cpp3
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp11
13 files changed, 111 insertions, 21 deletions
diff --git a/src/mbgl/geometry/buffer.hpp b/src/mbgl/geometry/buffer.hpp
index 01af5df18e..7e3ced4424 100644
--- a/src/mbgl/geometry/buffer.hpp
+++ b/src/mbgl/geometry/buffer.hpp
@@ -67,6 +67,7 @@ public:
return buffer;
}
+ // Uploads the buffer to the GPU to be available when we need it.
inline void upload() {
if (!buffer) {
bind();
diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp
index f690004b52..378664f303 100644
--- a/src/mbgl/geometry/glyph_atlas.cpp
+++ b/src/mbgl/geometry/glyph_atlas.cpp
@@ -140,6 +140,12 @@ void GlyphAtlas::removeGlyphs(uintptr_t tileUID) {
}
}
+void GlyphAtlas::upload() {
+ if (dirty) {
+ bind();
+ }
+}
+
void GlyphAtlas::bind() {
if (!texture) {
MBGL_CHECK_ERROR(glGenTextures(1, &texture));
diff --git a/src/mbgl/geometry/glyph_atlas.hpp b/src/mbgl/geometry/glyph_atlas.hpp
index a25c735a8e..dfa568f0fd 100644
--- a/src/mbgl/geometry/glyph_atlas.hpp
+++ b/src/mbgl/geometry/glyph_atlas.hpp
@@ -24,8 +24,13 @@ public:
GlyphPositions&);
void removeGlyphs(uintptr_t tileUID);
+ // Binds the atlas texture to the GPU, and uploads data if it is out of date.
void bind();
+ // Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
+ // the texture is only bound when the data is out of date (=dirty).
+ void upload();
+
const uint16_t width = 0;
const uint16_t height = 0;
diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp
index f64989d661..0dcaab2c45 100644
--- a/src/mbgl/geometry/line_atlas.cpp
+++ b/src/mbgl/geometry/line_atlas.cpp
@@ -129,6 +129,12 @@ LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool roun
return position;
};
+void LineAtlas::upload() {
+ if (dirty) {
+ bind();
+ }
+}
+
void LineAtlas::bind() {
std::lock_guard<std::recursive_mutex> lock(mtx);
diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp
index df60a2dec5..3683272f98 100644
--- a/src/mbgl/geometry/line_atlas.hpp
+++ b/src/mbgl/geometry/line_atlas.hpp
@@ -19,8 +19,13 @@ public:
LineAtlas(uint16_t width, uint16_t height);
~LineAtlas();
+ // Binds the atlas texture to the GPU, and uploads data if it is out of date.
void bind();
+ // Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
+ // the texture is only bound when the data is out of date (=dirty).
+ void upload();
+
LinePatternPos getDashPosition(const std::vector<float>&, bool);
LinePatternPos addDash(const std::vector<float> &dasharray, bool round);
diff --git a/src/mbgl/geometry/sprite_atlas.cpp b/src/mbgl/geometry/sprite_atlas.cpp
index c2686e2f34..a6156febbc 100644
--- a/src/mbgl/geometry/sprite_atlas.cpp
+++ b/src/mbgl/geometry/sprite_atlas.cpp
@@ -230,6 +230,12 @@ void SpriteAtlas::setSprite(util::ptr<Sprite> sprite_) {
});
}
+void SpriteAtlas::upload() {
+ if (dirty) {
+ bind();
+ }
+}
+
void SpriteAtlas::bind(bool linear) {
bool first = false;
if (!texture) {
diff --git a/src/mbgl/geometry/sprite_atlas.hpp b/src/mbgl/geometry/sprite_atlas.hpp
index 079c15cefd..5605143104 100644
--- a/src/mbgl/geometry/sprite_atlas.hpp
+++ b/src/mbgl/geometry/sprite_atlas.hpp
@@ -50,10 +50,13 @@ public:
SpriteAtlasPosition getPosition(const std::string& name, bool repeating = false);
- // Binds the image buffer of this sprite atlas to the GPU, and uploads data if it is out
- // of date.
+ // Binds the atlas texture to the GPU, and uploads data if it is out of date.
void bind(bool linear = false);
+ // Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
+ // the texture is only bound when the data is out of date (=dirty).
+ void upload();
+
inline float getWidth() const { return width; }
inline float getHeight() const { return height; }
inline float getTextureWidth() const { return width * pixelRatio; }
diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp
index 7e367a95b5..edd2165716 100644
--- a/src/mbgl/renderer/debug_bucket.cpp
+++ b/src/mbgl/renderer/debug_bucket.cpp
@@ -17,6 +17,9 @@ DebugBucket::DebugBucket(DebugFontBuffer& fontBuffer_)
}
void DebugBucket::prepare() {
+ fontBuffer.upload();
+
+ renderPass = RenderPass::Translucent;
}
void DebugBucket::render(Painter& painter, const StyleLayer&, const TileID&, const mat4& matrix) {
diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp
index f8e604ee29..39163c863d 100644
--- a/src/mbgl/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/fill_bucket.cpp
@@ -201,6 +201,14 @@ void FillBucket::tessellate() {
}
void FillBucket::prepare() {
+ vertexBuffer.upload();
+ triangleElementsBuffer.upload();
+ lineElementsBuffer.upload();
+
+ // From now on, we're going to render during the opaque and translucent pass.
+ renderPass = static_cast<RenderPass>(
+ static_cast<std::underlying_type<RenderPass>::type>(RenderPass::Opaque) |
+ static_cast<std::underlying_type<RenderPass>::type>(RenderPass::Translucent));
}
void FillBucket::render(Painter& painter,
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index 8e3a8ce9c5..8ef5306d8e 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
@@ -343,6 +343,11 @@ void LineBucket::addCurrentVertex(const Coordinate& currentVertex,
}
void LineBucket::prepare() {
+ vertexBuffer.upload();
+ triangleElementsBuffer.upload();
+
+ // From now on, we're only going to render during the translucent pass.
+ renderPass = RenderPass::Translucent;
}
void LineBucket::render(Painter& painter,
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index 74ad8b477f..06f58f9c46 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -10,6 +10,8 @@
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
+#include <mbgl/geometry/line_atlas.hpp>
+#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/shader/pattern_shader.hpp>
#include <mbgl/shader/plain_shader.hpp>
@@ -23,7 +25,6 @@
#include <mbgl/shader/dot_shader.hpp>
#include <mbgl/shader/gaussian_shader.hpp>
-
#include <mbgl/util/std.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/mat3.hpp>
@@ -210,10 +211,6 @@ void Painter::prepareTile(const Tile& tile) {
void Painter::render(const Style& style, TransformState state_, TimePoint time) {
state = state_;
- clear();
- resize();
- changeMatrix();
-
std::set<Source*> sources;
for (const auto& source : style.sources) {
if (source->enabled) {
@@ -221,6 +218,27 @@ void Painter::render(const Style& style, TransformState state_, TimePoint time)
}
}
+ // - PREPARATION PASS --------------------------------------------------------------------------
+ // Uploads all required buffers and images before we do any actual rendering.
+
+ // Figure out what buckets we have to draw and what order we have to draw them in.
+ const auto order = determineRenderOrder(style);
+
+ tileStencilBuffer.upload();
+ tileBorderBuffer.upload();
+ spriteAtlas.upload();
+ lineAtlas.upload();
+ glyphAtlas.upload();
+
+ for (const auto& item : order) {
+ if (item.bucket && item.bucket->hasRenderPass(RenderPass::Prepare)) {
+ item.bucket->prepare();
+ }
+ }
+
+ // - CLIPPING MASKS ----------------------------------------------------------------------------
+ // Draws the clipping masks to the stencil buffer.
+
// Update all clipping IDs.
ClipIDGenerator generator;
for (const auto& source : sources) {
@@ -228,6 +246,10 @@ void Painter::render(const Style& style, TransformState state_, TimePoint time)
source->updateMatrices(projMatrix, state);
}
+ clear();
+ resize();
+ changeMatrix();
+
drawClippingMasks(sources);
frameHistory.record(time, state.getNormalizedZoom());
@@ -235,15 +257,12 @@ void Painter::render(const Style& style, TransformState state_, TimePoint time)
// Actually render the layers
if (debug::renderTree) { Log::Info(Event::Render, "{"); indent++; }
- // Figure out what buckets we have to draw and what order we have to draw them in.
- const auto order = determineRenderOrder(style);
// TODO: Correctly compute the number of layers recursively beforehand.
const float strata_thickness = 1.0f / (order.size() + 1);
- // - FIRST PASS ------------------------------------------------------------
- // Render everything top-to-bottom by using reverse iterators. Render opaque
- // objects first.
+ // - OPAQUE PASS -------------------------------------------------------------------------------
+ // Render everything top-to-bottom by using reverse iterators. Render opaque objects first.
if (debug::renderTree) {
Log::Info(Event::Render, "%*s%s", indent++ * 4, "", "OPAQUE {");
@@ -253,9 +272,11 @@ void Painter::render(const Style& style, TransformState state_, TimePoint time)
for (auto it = order.rbegin(), end = order.rend(); it != end; ++it, ++i) {
const auto& item = *it;
if (item.bucket && item.tile) {
- setStrata(i * strata_thickness);
- prepareTile(*item.tile);
- item.bucket->render(*this, item.layer, item.tile->id, item.tile->matrix);
+ if (item.bucket->hasRenderPass(RenderPass::Opaque)) {
+ setStrata(i * strata_thickness);
+ prepareTile(*item.tile);
+ item.bucket->render(*this, item.layer, item.tile->id, item.tile->matrix);
+ }
} else {
renderBackground(item.layer);
}
@@ -264,9 +285,9 @@ void Painter::render(const Style& style, TransformState state_, TimePoint time)
Log::Info(Event::Render, "%*s%s", --indent * 4, "", "}");
}
- // - SECOND PASS -----------------------------------------------------------
- // Make a second pass, rendering translucent objects. This time, we render
- // bottom-to-top.
+ // - TRANSLUCENT PASS --------------------------------------------------------------------------
+ // Make a second pass, rendering translucent objects. This time, we render bottom-to-top.
+
if (debug::renderTree) {
Log::Info(Event::Render, "%*s%s", indent++ * 4, "", "TRANSLUCENT {");
}
@@ -275,9 +296,11 @@ void Painter::render(const Style& style, TransformState state_, TimePoint time)
for (auto it = order.begin(), end = order.end(); it != end; ++it, --i) {
const auto& item = *it;
if (item.bucket && item.tile) {
- setStrata(i * strata_thickness);
- prepareTile(*item.tile);
- item.bucket->render(*this, item.layer, item.tile->id, item.tile->matrix);
+ if (item.bucket->hasRenderPass(RenderPass::Translucent)) {
+ setStrata(i * strata_thickness);
+ prepareTile(*item.tile);
+ item.bucket->render(*this, item.layer, item.tile->id, item.tile->matrix);
+ }
}
}
if (debug::renderTree) {
@@ -293,6 +316,11 @@ void Painter::render(const Style& style, TransformState state_, TimePoint time)
for (const auto& source : sources) {
source->finishRender(*this);
}
+
+ // TODO: Find a better way to unbind VAOs after we're done with them without introducing
+ // unnecessary bind(0)/bind(N) sequences.
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, 0));
+ MBGL_CHECK_ERROR(gl::BindVertexArray(0));
}
std::vector<RenderItem> Painter::determineRenderOrder(const Style& style) {
diff --git a/src/mbgl/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp
index 7f1f92b5ca..946d817498 100644
--- a/src/mbgl/renderer/raster_bucket.cpp
+++ b/src/mbgl/renderer/raster_bucket.cpp
@@ -14,6 +14,9 @@ RasterBucket::RasterBucket(TexturePool& texturePool, const StyleLayoutRaster& la
}
void RasterBucket::prepare() {
+ if (hasData()) {
+ raster.upload();
+ }
}
void RasterBucket::render(Painter& painter,
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index d520e4de2e..62ede28401 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
@@ -37,6 +37,17 @@ SymbolBucket::~SymbolBucket() {
}
void SymbolBucket::prepare() {
+ if (hasTextData()) {
+ text.vertices.upload();
+ text.triangles.upload();
+ }
+ if (hasIconData()) {
+ icon.vertices.upload();
+ icon.triangles.upload();
+ }
+
+ // From now on, we're going to render during the opaque and translucent pass.
+ renderPass = RenderPass::Translucent;
}
void SymbolBucket::render(Painter& painter,