diff options
-rw-r--r-- | src/mbgl/geometry/buffer.hpp | 1 | ||||
-rw-r--r-- | src/mbgl/geometry/glyph_atlas.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/geometry/glyph_atlas.hpp | 5 | ||||
-rw-r--r-- | src/mbgl/geometry/line_atlas.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/geometry/line_atlas.hpp | 5 | ||||
-rw-r--r-- | src/mbgl/geometry/sprite_atlas.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/geometry/sprite_atlas.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/renderer/debug_bucket.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/fill_bucket.cpp | 8 | ||||
-rw-r--r-- | src/mbgl/renderer/line_bucket.cpp | 5 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.cpp | 66 | ||||
-rw-r--r-- | src/mbgl/renderer/raster_bucket.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/symbol_bucket.cpp | 11 |
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, |