From c0cb210ddca1901a956cd68e9142b7fb04183248 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Thu, 9 Nov 2017 13:24:43 -0800 Subject: [core] Switch from background to foreground placement - Background placement code now just generates static symbol buffers - Don't render GeometryTiles until their symbols are loaded. This is necessary for the CrossTileSymbolIndex to successfully prevent flicker. - SymbolInstances are transferred to SymbolBucket for use on foreground during collision detection - Symbols are sorted on foreground by sorting their index buffer but leaving vertex buffers intact (only works within one segment) - Vertical glyphs are generated at same time as horizontal glyphs. `reprojectLineLabels` chooses which one to use at render time and hides the other. - Icons are now always represented with a single collision box, even if they're placed along a line (this means their rotation alignment may be wrong, but the approach of representing them with multiple collision boxes wasn't very accurate either). - Generate vertices for new debug collision boxes and collision circles - Only add symbols within tile boundaries (reduces work, avoids double-draw) - Update symbol_projection.cpp to support line label projection calls from CollisionIndex. --- src/mbgl/renderer/buckets/symbol_bucket.cpp | 166 +++++++++++++++++++++++++--- 1 file changed, 152 insertions(+), 14 deletions(-) (limited to 'src/mbgl/renderer/buckets/symbol_bucket.cpp') diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index a3f71f1f6e..ebcf93f2b1 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -16,10 +16,14 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo const style::DataDrivenPropertyValue& iconSize, float zoom, bool sdfIcons_, - bool iconsNeedLinear_) + bool iconsNeedLinear_, + bool sortFeaturesByY_, + const std::vector&& symbolInstances_) : layout(std::move(layout_)), sdfIcons(sdfIcons_), iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()), + sortFeaturesByY(sortFeaturesByY_), + symbolInstances(std::move(symbolInstances_)), textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())), iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) { @@ -36,28 +40,84 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo void SymbolBucket::upload(gl::Context& context) { if (hasTextData()) { - text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices)); - text.dynamicVertexBuffer = context.createVertexBuffer(std::move(text.dynamicVertices), gl::BufferUsage::StreamDraw); - text.indexBuffer = context.createIndexBuffer(std::move(text.triangles)); + if (!staticUploaded) { + text.indexBuffer = context.createIndexBuffer(std::move(text.triangles), sortFeaturesByY ? gl::BufferUsage::StreamDraw : gl::BufferUsage::StaticDraw); + text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices)); + } else if (!sortUploaded) { + context.updateIndexBuffer(*text.indexBuffer, std::move(text.triangles)); + } + + if (!dynamicUploaded) { + text.dynamicVertexBuffer = context.createVertexBuffer(std::move(text.dynamicVertices), gl::BufferUsage::StreamDraw); + } + if (!placementChangesUploaded) { + if (!text.opacityVertexBuffer) { + text.opacityVertexBuffer = context.createVertexBuffer(std::move(text.opacityVertices), gl::BufferUsage::StreamDraw); + } else { + context.updateVertexBuffer(*text.opacityVertexBuffer, std::move(text.opacityVertices)); + } + } } if (hasIconData()) { - icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices)); - icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsage::StreamDraw); - icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles)); + if (!staticUploaded) { + icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles), sortFeaturesByY ? gl::BufferUsage::StreamDraw : gl::BufferUsage::StaticDraw); + icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices)); + } else if (!sortUploaded) { + context.updateIndexBuffer(*icon.indexBuffer, std::move(icon.triangles)); + } + if (!dynamicUploaded) { + icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsage::StreamDraw); + } + if (!placementChangesUploaded) { + if (!icon.opacityVertexBuffer) { + icon.opacityVertexBuffer = context.createVertexBuffer(std::move(icon.opacityVertices), gl::BufferUsage::StreamDraw); + } else { + context.updateVertexBuffer(*icon.opacityVertexBuffer, std::move(icon.opacityVertices)); + } + } } - if (!collisionBox.vertices.empty()) { - collisionBox.vertexBuffer = context.createVertexBuffer(std::move(collisionBox.vertices)); - collisionBox.indexBuffer = context.createIndexBuffer(std::move(collisionBox.lines)); + if (hasCollisionBoxData()) { + if (!staticUploaded) { + collisionBox.indexBuffer = context.createIndexBuffer(std::move(collisionBox.lines)); + collisionBox.vertexBuffer = context.createVertexBuffer(std::move(collisionBox.vertices)); + } + if (!placementChangesUploaded) { + if (!collisionBox.dynamicVertexBuffer) { + collisionBox.dynamicVertexBuffer = context.createVertexBuffer(std::move(collisionBox.dynamicVertices), gl::BufferUsage::StreamDraw); + } else { + context.updateVertexBuffer(*collisionBox.dynamicVertexBuffer, std::move(collisionBox.dynamicVertices)); + } + } } - - for (auto& pair : paintPropertyBinders) { - pair.second.first.upload(context); - pair.second.second.upload(context); + + if (hasCollisionCircleData()) { + if (!staticUploaded) { + collisionCircle.indexBuffer = context.createIndexBuffer(std::move(collisionCircle.triangles)); + collisionCircle.vertexBuffer = context.createVertexBuffer(std::move(collisionCircle.vertices)); + } + if (!placementChangesUploaded) { + if (!collisionCircle.dynamicVertexBuffer) { + collisionCircle.dynamicVertexBuffer = context.createVertexBuffer(std::move(collisionCircle.dynamicVertices), gl::BufferUsage::StreamDraw); + } else { + context.updateVertexBuffer(*collisionCircle.dynamicVertexBuffer, std::move(collisionCircle.dynamicVertices)); + } + } } + if (!staticUploaded) { + for (auto& pair : paintPropertyBinders) { + pair.second.first.upload(context); + pair.second.second.upload(context); + } + } + uploaded = true; + staticUploaded = true; + placementChangesUploaded = true; + dynamicUploaded = true; + sortUploaded = true; } bool SymbolBucket::hasData() const { @@ -76,4 +136,82 @@ bool SymbolBucket::hasCollisionBoxData() const { return !collisionBox.segments.empty(); } +bool SymbolBucket::hasCollisionCircleData() const { + return !collisionCircle.segments.empty(); +} + +void SymbolBucket::updateOpacity() { + placementChangesUploaded = false; + uploaded = false; +} + +void addPlacedSymbol(gl::IndexVector& triangles, const PlacedSymbol& placedSymbol) { + auto endIndex = placedSymbol.vertexStartIndex + placedSymbol.glyphOffsets.size() * 4; + for (auto vertexIndex = placedSymbol.vertexStartIndex; vertexIndex < endIndex; vertexIndex += 4) { + triangles.emplace_back(vertexIndex + 0, vertexIndex + 1, vertexIndex + 2); + triangles.emplace_back(vertexIndex + 1, vertexIndex + 2, vertexIndex + 3); + } +} + +void SymbolBucket::sortFeatures(const float angle) { + if (!sortFeaturesByY) { + return; + } + + if (sortedAngle && *sortedAngle == angle) { + return; + } + + sortedAngle = angle; + + // The current approach to sorting doesn't sort across segments so don't try. + // Sorting within segments separately seemed not to be worth the complexity. + if (text.segments.size() > 1 || icon.segments.size() > 1) { + return; + } + + sortUploaded = false; + uploaded = false; + + // If the symbols are allowed to overlap sort them by their vertical screen position. + // The index array buffer is rewritten to reference the (unchanged) vertices in the + // sorted order. + + // To avoid sorting the actual symbolInstance array we sort an array of indexes. + std::vector symbolInstanceIndexes; + for (size_t i = 0; i < symbolInstances.size(); i++) { + symbolInstanceIndexes.push_back(i); + } + + const float sin = std::sin(angle); + const float cos = std::cos(angle); + + std::sort(symbolInstanceIndexes.begin(), symbolInstanceIndexes.end(), [sin, cos, this](size_t &aIndex, size_t &bIndex) { + const SymbolInstance& a = symbolInstances[aIndex]; + const SymbolInstance& b = symbolInstances[bIndex]; + const int32_t aRotated = sin * a.anchor.point.x + cos * a.anchor.point.y; + const int32_t bRotated = sin * b.anchor.point.x + cos * b.anchor.point.y; + return aRotated != bRotated ? + aRotated < bRotated : + a.index > b.index; + }); + + text.triangles.clear(); + icon.triangles.clear(); + + for (auto i : symbolInstanceIndexes) { + const SymbolInstance& symbolInstance = symbolInstances[i]; + + if (symbolInstance.placedTextIndex) { + addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedTextIndex]); + } + if (symbolInstance.placedVerticalTextIndex) { + addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedVerticalTextIndex]); + } + if (symbolInstance.placedIconIndex) { + addPlacedSymbol(icon.triangles, icon.placedSymbols[*symbolInstance.placedIconIndex]); + } + } +} + } // namespace mbgl -- cgit v1.2.1