diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index 97a064da6..b457d4d62 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -48,7 +48,7 @@ public: struct DrawSegment; using UniqueDrawSegment = std::unique_ptr; - const util::SimpleIdentity& getId() const { return uniqueID; } + const util::SimpleIdentity& getID() const { return uniqueID; } /// Draw the drawable virtual void draw(PaintParameters&) const = 0; @@ -208,7 +208,7 @@ struct DrawableLessByPriority { if (a.getDrawPriority() != b.getDrawPriority()) { return a.getDrawPriority() < b.getDrawPriority(); } - return a.getId() < b.getId(); + return a.getID() < b.getID(); } bool operator()(const Drawable* left, const Drawable* right) const { return operator()(*left, *right); } bool operator()(const UniqueDrawable& left, const UniqueDrawable& right) const { return operator()(*left, *right); } diff --git a/src/mbgl/gfx/drawable_builder.cpp b/src/mbgl/gfx/drawable_builder.cpp index ec76d87a9..606dd4a33 100644 --- a/src/mbgl/gfx/drawable_builder.cpp +++ b/src/mbgl/gfx/drawable_builder.cpp @@ -73,7 +73,7 @@ void DrawableBuilder::flush() { } util::SimpleIdentity DrawableBuilder::getDrawableId() { - return currentDrawable ? currentDrawable->getId() : util::SimpleIdentity::Empty; + return currentDrawable ? currentDrawable->getID() : util::SimpleIdentity::Empty; } DrawPriority DrawableBuilder::getDrawPriority() const { diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index 71a7b2c44..9e4d5ecb4 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -35,7 +35,7 @@ void DrawableGL::draw(PaintParameters& parameters) const { } } if (!shader || context.program.getCurrentValue() == 0) { - mbgl::Log::Warning(Event::General, "Missing shader for drawable " + util::toString(getId()) + "/" + getName()); + mbgl::Log::Warning(Event::General, "Missing shader for drawable " + util::toString(getID()) + "/" + getName()); assert(false); return; } diff --git a/src/mbgl/gl/texture2d.cpp b/src/mbgl/gl/texture2d.cpp index 8e0919e72..780d1ee5d 100644 --- a/src/mbgl/gl/texture2d.cpp +++ b/src/mbgl/gl/texture2d.cpp @@ -114,7 +114,7 @@ void Texture2D::create() noexcept { } platform::GLuint Texture2D::getTextureID() const noexcept { - return static_cast(*textureResource).texture; + return textureResource ? static_cast(*textureResource).texture : 0; } void Texture2D::updateSamplerConfiguration() noexcept { diff --git a/src/mbgl/layermanager/fill_layer_factory.cpp b/src/mbgl/layermanager/fill_layer_factory.cpp index 5690c2d34..5f2de1ed1 100644 --- a/src/mbgl/layermanager/fill_layer_factory.cpp +++ b/src/mbgl/layermanager/fill_layer_factory.cpp @@ -13,12 +13,8 @@ const style::LayerTypeInfo* FillLayerFactory::getTypeInfo() const noexcept { std::unique_ptr FillLayerFactory::createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept { - std::optional source = getSource(value); - if (!source) { - return nullptr; - } - - return std::unique_ptr(new style::FillLayer(id, *source)); + const auto source = getSource(value); + return std::unique_ptr(source ? new (std::nothrow) style::FillLayer(id, *source) : nullptr); } std::unique_ptr FillLayerFactory::createLayout( diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index 0bae72e66..374d365d8 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -4,6 +4,8 @@ #include #include #include +#include + #include namespace mbgl { @@ -65,9 +67,13 @@ public: virtual void updateVertices( const Placement&, bool /*updateOpacities*/, const TransformState&, const RenderTile&, std::set&) {} + const util::SimpleIdentity& getID() const { return bucketID; } + protected: Bucket() = default; std::atomic uploaded{false}; + + util::SimpleIdentity bucketID; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index caed90c78..cfa204886 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -283,7 +283,7 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders, tileLayerGroup->observeDrawables([&](gfx::Drawable& drawable) -> bool { // Has this tile dropped out of the cover set? - return (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end()); + return (!drawable.getTileID() || hasRenderTile(*drawable.getTileID())); }); // For each tile in the cover set, add a tile drawable if one doesn't already exist. diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index a2431df5c..57bbda051 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -319,9 +319,8 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, return; } - stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { - return (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end()); - }); + stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove( + [&](gfx::Drawable& drawable) { return (!drawable.getTileID() || hasRenderTile(*drawable.getTileID())); }); const auto& evaluated = static_cast(*evaluatedProperties).evaluated; @@ -329,7 +328,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, const auto& tileID = tile.getOverscaledTileID(); const LayerRenderData* renderData = getRenderDataForPass(tile, renderPass); - if (!renderData) { + if (!renderData || !renderData->bucket || !renderData->bucket->hasData()) { removeTile(renderPass, tileID); continue; } @@ -338,6 +337,13 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, const auto vertexCount = bucket.vertices.elements(); const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + const auto prevBucketID = getRenderTileBucketID(tileID); + if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { + // This tile was previously set up from a different bucket, drop and re-create any drawables for it. + removeTile(renderPass, tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); + const float zoom = static_cast(state.getZoom()); const CircleInterpolateUBO interpolateUBO = { /* .color_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index f3b6ca1e5..80fd14474 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -311,7 +311,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { // If the render pass has changed or the tile has dropped out of the cover set, remove it. return (drawable.getRenderPass() == drawPass && - (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end())); + (!drawable.getTileID() || hasRenderTile(*drawable.getTileID()))); }); const auto zoom = static_cast(state.getZoom()); @@ -332,7 +332,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, const auto& tileID = tile.getOverscaledTileID(); const auto* optRenderData = getRenderDataForPass(tile, passes); - if (!optRenderData || !optRenderData->bucket) { + if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { removeTile(drawPass, tileID); continue; } @@ -340,7 +340,12 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, const auto& renderData = *optRenderData; const auto& bucket = static_cast(*renderData.bucket); - gfx::VertexAttributeArray vertexAttrs; + const auto prevBucketID = getRenderTileBucketID(tileID); + if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { + // This tile was previously set up from a different bucket, drop and re-create any drawables for it. + removeTile(passes, tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); gfx::DrawableTweakerPtr tweaker; if (depthBuilder) { @@ -389,6 +394,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, continue; } + gfx::VertexAttributeArray vertexAttrs; const auto uniformProps = vertexAttrs.readDataDrivenPaintPropertiesobserveDrawablesRemove([&](gfx::Drawable& drawable) { - // If the render pass has changed or the tile has dropped out of the cover set, remove it. - return (drawable.getRenderPass() == renderPass && - (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end())); + // If the render pass has changed or the tile has dropped out of the cover set, remove it. + return drawable.getRenderPass() == renderPass && drawable.getTileID() && hasRenderTile(*drawable.getTileID()); }); for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); const LayerRenderData* renderData = getRenderDataForPass(tile, renderPass); - if (!renderData) { + if (!renderData || !renderData->bucket || !renderData->bucket->hasData()) { removeTile(renderPass, tileID); continue; } @@ -380,6 +379,13 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, auto& bucket = static_cast(*renderData->bucket); const auto& binders = bucket.paintPropertyBinders.at(getID()); + const auto prevBucketID = getRenderTileBucketID(tileID); + if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { + // This tile was previously set up from a different bucket, drop and re-create any drawables for it. + removeTile(renderPass, tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); + const auto& evaluated = getEvaluated(renderData->layerProperties); const auto& crossfade = getCrossfade(renderData->layerProperties); @@ -404,20 +410,6 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, /* pattern_to = */ patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}, }; - // If we already have drawables for this tile, update them. - auto updateExisting = [&](gfx::Drawable& drawable) { - auto& uniforms = drawable.mutableUniformBuffers(); - uniforms.createOrUpdate(FillLayerTweaker::FillInterpolateUBOName, &interpolateUBO, context); - uniforms.createOrUpdate(FillLayerTweaker::FillTilePropsUBOName, &tileProps, context); - }; - if (0 < tileLayerGroup->observeDrawables(renderPass, tileID, std::move(updateExisting))) { - continue; - } - - // Share UBO buffers among any drawables created for this tile - const auto interpBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO)); - const auto tilePropsBuffer = context.createUniformBuffer(&tileProps, sizeof(tileProps)); - // `Fill*Program` all use `style::FillPaintProperties` gfx::VertexAttributeArray vertexAttrs; const auto uniformProps = @@ -433,6 +425,21 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, gfx::AttributeDataType::Short2); } + // If we already have drawables for this tile, update them. + auto updateExisting = [&](gfx::Drawable& drawable) { + auto& uniforms = drawable.mutableUniformBuffers(); + uniforms.createOrUpdate(FillLayerTweaker::FillInterpolateUBOName, &interpolateUBO, context); + uniforms.createOrUpdate(FillLayerTweaker::FillTilePropsUBOName, &tileProps, context); + drawable.setVertexAttributes(vertexAttrs); + }; + if (0 < tileLayerGroup->observeDrawables(renderPass, tileID, std::move(updateExisting))) { + continue; + } + + // Share UBO buffers among any drawables created for this tile + const auto interpBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO)); + const auto tilePropsBuffer = context.createUniformBuffer(&tileProps, sizeof(tileProps)); + if (unevaluated.get().isUndefined()) { // Fill will occur in opaque or translucent pass based on `opaquePassCutoff`. // Outline always occurs in translucent pass, defaults to fill color diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index 0d3b324d9..c5bacff2d 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -338,9 +338,8 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, return; } - stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { - return (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end()); - }); + stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove( + [&](gfx::Drawable& drawable) { return (!drawable.getTileID() || hasRenderTile(*drawable.getTileID())); }); const auto& evaluated = static_cast(*evaluatedProperties).evaluated; @@ -357,6 +356,13 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, const auto vertexCount = bucket.vertices.elements(); const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + const auto prevBucketID = getRenderTileBucketID(tileID); + if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { + // This tile was previously set up from a different bucket, drop and re-create any drawables for it. + removeTile(renderPass, tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); + const float zoom = static_cast(state.getZoom()); const HeatmapInterpolateUBO interpolateUBO = { /* .weight_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index e44c34162..8e69997c4 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -324,9 +324,8 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, return; } - stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { - return (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end()); - }); + stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove( + [&](gfx::Drawable& drawable) { return (!drawable.getTileID() || hasRenderTile(*drawable.getTileID())); }); if (!staticDataSharedVertices) { staticDataSharedVertices = std::make_shared(RenderStaticData::rasterVertices()); @@ -341,15 +340,19 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, const auto& tileID = tile.getOverscaledTileID(); auto* bucket_ = tile.getBucket(*baseImpl); - if (!bucket_) { + if (!bucket_ || !bucket_->hasData()) { removeTile(renderPass, tileID); continue; } + auto& bucket = static_cast(*bucket_); - if (!bucket.hasData()) { - continue; + const auto prevBucketID = getRenderTileBucketID(tileID); + if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { + // This tile was previously set up from a different bucket, drop and re-create any drawables for it. + removeTile(renderPass, tileID); } + setRenderTileBucketID(tileID, bucket.getID()); if (!bucket.renderTargetPrepared) { // Set up tile render target diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index c04295ba6..b38d864f2 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -458,7 +458,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { // If the render pass has changed or the tile has dropped out of the cover set, remove it. return (drawable.getRenderPass() == renderPass && - (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end())); + (!drawable.getTileID() || hasRenderTile(*drawable.getTileID()))); }); auto createLineBuilder = [&](const std::string& name, @@ -520,6 +520,13 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, const auto& evaluated = getEvaluated(renderData->layerProperties); const auto& crossfade = getCrossfade(renderData->layerProperties); + const auto prevBucketID = getRenderTileBucketID(tileID); + if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { + // This tile was previously set up from a different bucket, drop and re-create any drawables for it. + removeTile(renderPass, tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); + // interpolation UBOs const float zoom = static_cast(state.getZoom()); const LineInterpolationUBO lineInterpolationUBO{ diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index 7a77f44dd..ea52f2b62 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -271,7 +271,8 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, return builder; }; - auto setTextures = [&context, &filter, this](std::unique_ptr& builder, RasterBucket& bucket) { + auto setTextures = [&context, &filter, this](std::unique_ptr& builder, + const RasterBucket& bucket) { // textures auto location0 = rasterShader->getSamplerLocation("u_image0"); if (location0.has_value()) { @@ -289,7 +290,8 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, } }; - auto buildTileDrawables = [&setTextures](std::unique_ptr& builder, RasterBucket& bucket) { + auto buildTileDrawables = [&setTextures](std::unique_ptr& builder, + const RasterBucket& bucket) { auto buildRenderData = [](const TileMask& mask, std::vector>& vertices, std::vector>& attributes, @@ -422,7 +424,7 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, if (layerGroup) { stats.drawablesRemoved += layerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { // Has this tile dropped out of the cover set? - return (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end()); + return (!drawable.getTileID() || hasRenderTile(*drawable.getTileID())); }); } else { // Set up a tile layer group @@ -437,12 +439,21 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, auto builder = createBuilder(); for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); - auto* bucket_ = tile.getBucket(*baseImpl); - if (!bucket_) { + + const auto* bucket_ = tile.getBucket(*baseImpl); + if (!bucket_ || !bucket_->hasData()) { + removeTile(renderPass, tileID); continue; } - auto& bucket = static_cast(*bucket_); - if (!bucket.hasData()) continue; + + const auto& bucket = static_cast(*bucket_); + + const auto prevBucketID = getRenderTileBucketID(tileID); + if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { + // This tile was previously set up from a different bucket, drop and re-create any drawables for it. + removeTile(renderPass, tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) continue; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 0218549ac..081253b00 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -748,10 +748,65 @@ constexpr auto fadeOpacityAttribName = "a_fade_opacity"; constexpr auto texUniformName = "u_texture"; constexpr auto iconTexUniformName = "u_texture_icon"; +std::vector updateTileAttributes(gfx::Context& context, + const SymbolBucket::Buffer& buffer, + const bool isText, + const SymbolBucket::PaintProperties& paintProps, + const SymbolPaintProperties::PossiblyEvaluated& evaluated, + gfx::VertexAttributeArray& attribs) { + if (const auto& attr = attribs.getOrAdd(posOffsetAttribName)) { + attr->setSharedRawData(buffer.sharedVertices, + offsetof(SymbolLayoutVertex, a1), + /*vertexOffset=*/0, + sizeof(SymbolLayoutVertex), + gfx::AttributeDataType::Short4); + } + if (const auto& attr = attribs.getOrAdd(dataAttibName)) { + attr->setSharedRawData(buffer.sharedVertices, + offsetof(SymbolLayoutVertex, a2), + /*vertexOffset=*/0, + sizeof(SymbolLayoutVertex), + gfx::AttributeDataType::UShort4); + } + if (const auto& attr = attribs.getOrAdd(pixOffsetAttribName)) { + attr->setSharedRawData(buffer.sharedVertices, + offsetof(SymbolLayoutVertex, a3), + /*vertexOffset=*/0, + sizeof(SymbolLayoutVertex), + gfx::AttributeDataType::Short4); + } + + if (const auto& attr = attribs.getOrAdd(projPosAttribName)) { + using Vertex = gfx::Vertex; + attr->setSharedRawData(buffer.sharedDynamicVertices, + offsetof(Vertex, a1), + /*vertexOffset=*/0, + sizeof(Vertex), + gfx::AttributeDataType::Float3); + } + if (const auto& attr = attribs.getOrAdd(fadeOpacityAttribName)) { + using Vertex = gfx::Vertex; + attr->setSharedRawData(buffer.sharedOpacityVertices, + offsetof(Vertex, a1), + /*vertexOffset=*/0, + sizeof(Vertex), + gfx::AttributeDataType::Float); + } + + return isText + ? attribs + .readDataDrivenPaintProperties( + paintProps.textBinders, evaluated) + : attribs + .readDataDrivenPaintProperties( + paintProps.iconBinders, evaluated); +} + void updateTileDrawable(gfx::Drawable& drawable, gfx::Context& context, const SymbolBucket& bucket, const SymbolBucket::PaintProperties& paintProps, + const SymbolPaintProperties::PossiblyEvaluated& evaluated, const TransformState& state) { if (!drawable.getData()) { return; @@ -759,6 +814,7 @@ void updateTileDrawable(gfx::Drawable& drawable, auto& drawData = static_cast(*drawable.getData()); const auto isText = (drawData.symbolType == SymbolType::Text); + const auto sdfIcons = (drawData.symbolType == SymbolType::IconSDF); const auto currentZoom = static_cast(state.getZoom()); // This property can be set after the initial appearance of the tile, as part of the layout process. @@ -771,22 +827,17 @@ void updateTileDrawable(gfx::Drawable& drawable, uniforms.createOrUpdate(SymbolLayerTweaker::SymbolDrawableTilePropsUBOName, &tileUBO, context); uniforms.createOrUpdate(SymbolLayerTweaker::SymbolDrawableInterpolateUBOName, &interpolateUBO, context); + const auto& buffer = isText ? bucket.text : (sdfIcons ? bucket.sdfIcon : bucket.icon); + const auto vertexCount = buffer.vertices().elements(); + + drawable.setVertices({}, vertexCount, gfx::AttributeDataType::Short4); + // TODO: detect whether anything has actually changed // See `Placement::updateBucketDynamicVertices` - const auto sdfIcons = (drawData.symbolType == SymbolType::IconSDF); - const auto& buffer = isText ? bucket.text : (sdfIcons ? bucket.sdfIcon : bucket.icon); - auto& attribs = drawable.mutableVertexAttributes(); - if (const auto& attr = attribs.get(projPosAttribName)) { - using Vertex = gfx::Vertex; - attr->setSharedRawData( - buffer.sharedDynamicVertices, offsetof(Vertex, a1), 0, sizeof(Vertex), gfx::AttributeDataType::Float3); - } - if (const auto& attr = attribs.get(fadeOpacityAttribName)) { - using Vertex = gfx::Vertex; - attr->setSharedRawData( - buffer.sharedOpacityVertices, offsetof(Vertex, a1), 0, sizeof(Vertex), gfx::AttributeDataType::Float); - } + gfx::VertexAttributeArray attribs; + updateTileAttributes(context, buffer, isText, paintProps, evaluated, attribs); + drawable.setVertexAttributes(std::move(attribs)); } } // namespace @@ -826,8 +877,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { // If the render pass has changed or the tile has dropped out of the cover set, remove it. const auto& tileID = drawable.getTileID(); - if (drawable.getRenderPass() != passes || (tileID && renderTileIDs.find(*tileID) == renderTileIDs.end())) { - tileBucketInstances.erase(*tileID); + if (drawable.getRenderPass() != passes || (tileID && !hasRenderTile(*tileID))) { return false; } return true; @@ -844,7 +894,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto& tileID = tile.getOverscaledTileID(); const auto* optRenderData = getRenderDataForPass(tile, passes); - if (!optRenderData || !optRenderData->bucket) { + if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { removeTile(passes, tileID); continue; } @@ -852,23 +902,24 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto& renderData = *optRenderData; const auto& bucket = static_cast(*renderData.bucket); + const auto prevBucketID = getRenderTileBucketID(tileID); + if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { + // This tile was previously set up from a different bucket, drop and re-create any drawables for it. + removeTile(passes, tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); + assert(bucket.paintProperties.find(getID()) != bucket.paintProperties.end()); const auto& bucketPaintProperties = bucket.paintProperties.at(getID()); // If we already have drawables for this tile, update them. if (tileLayerGroup->getDrawableCount(passes, tileID) > 0) { - const auto hit = tileBucketInstances.insert(std::make_pair(tileID, bucket.bucketInstanceId)); - if (!hit.second && hit.first->second != bucket.bucketInstanceId) { - // The bucket has changed, reset the drawables for this tile. - tileLayerGroup->removeDrawables(passes, tileID); - hit.first->second = bucket.bucketInstanceId; - } else { - // Just update the drawables we already created - tileLayerGroup->observeDrawables(passes, tileID, [&](gfx::Drawable& drawable) { - updateTileDrawable(drawable, context, bucket, bucketPaintProperties, state); - }); - continue; - } + // Just update the drawables we already created + tileLayerGroup->observeDrawables(passes, tileID, [&](gfx::Drawable& drawable) { + const auto& evaluated = getEvaluated(renderData.layerProperties); + updateTileDrawable(drawable, context, bucket, bucketPaintProperties, evaluated, state); + }); + continue; } float serialKey = 1.0f; @@ -919,52 +970,11 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, auto& tileInfo = tileCache[tile.id]; - gfx::VertexAttributeArray attrs; const auto vertexCount = buffer.vertices().elements(); - if (const auto& attr = attrs.add(posOffsetAttribName)) { - attr->setSharedRawData(buffer.sharedVertices, - offsetof(SymbolLayoutVertex, a1), - 0, - sizeof(SymbolLayoutVertex), - gfx::AttributeDataType::Short4); - } - if (const auto& attr = attrs.add(dataAttibName)) { - attr->setSharedRawData(buffer.sharedVertices, - offsetof(SymbolLayoutVertex, a2), - 0, - sizeof(SymbolLayoutVertex), - gfx::AttributeDataType::UShort4); - } - if (const auto& attr = attrs.add(pixOffsetAttribName)) { - attr->setSharedRawData(buffer.sharedVertices, - offsetof(SymbolLayoutVertex, a3), - 0, - sizeof(SymbolLayoutVertex), - gfx::AttributeDataType::Short4); - } - if (const auto& attr = attrs.add(projPosAttribName)) { - using Vertex = gfx::Vertex; - attr->setSharedRawData( - buffer.sharedDynamicVertices, offsetof(Vertex, a1), 0, sizeof(Vertex), gfx::AttributeDataType::Float3); - } - if (const auto& attr = attrs.add(fadeOpacityAttribName)) { - using Vertex = gfx::Vertex; - attr->setSharedRawData( - buffer.sharedOpacityVertices, offsetof(Vertex, a1), 0, sizeof(Vertex), gfx::AttributeDataType::Float); - } - const auto uniformProps = isText ? attrs.readDataDrivenPaintProperties( - bucketPaintProperties.textBinders, evaluated) - : attrs.readDataDrivenPaintProperties( - bucketPaintProperties.iconBinders, evaluated); + gfx::VertexAttributeArray attribs; + const auto uniformProps = updateTileAttributes( + context, buffer, isText, bucketPaintProperties, evaluated, attribs); const auto textHalo = evaluated.get().constantOr(Color::black()).a > 0.0f && evaluated.get().constantOr(1); @@ -1013,7 +1023,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, builder->addTweaker(isText ? tileInfo.textTweaker : tileInfo.iconTweaker); builder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short4); builder->setDrawableName(layerPrefix + std::string(suffix)); - builder->setVertexAttributes(attrs); + builder->setVertexAttributes(attribs); const auto shader = std::static_pointer_cast( shaderGroup->getOrCreateShader(context, uniformProps, posOffsetAttribName)); diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index 9e4d9e9f1..fa50c8532 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -125,8 +125,6 @@ private: gfx::ShaderGroupPtr symbolSDFIconGroup; gfx::ShaderGroupPtr symbolSDFTextGroup; gfx::ShaderGroupPtr symbolTextAndIconGroup; - - std::unordered_map tileBucketInstances; #endif // MLN_DRAWABLE_RENDERER }; diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index 477afe74c..8b061ef8f 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -71,10 +71,9 @@ std::optional RenderLayer::getSolidBackground() const { #if MLN_DRAWABLE_RENDERER void RenderLayer::layerChanged(const TransitionParameters&, const Immutable&, - UniqueChangeRequestVec& changes) { - // Treat a layer change the same as a remove. - // It will be set up again when `update()` is called. - layerRemoved(changes); + UniqueChangeRequestVec&) { + // When a layer changes, the bucket won't be replaced until the new source(s) load. + // If we remove the drawables here, they will just be re-created based on the current data. } void RenderLayer::layerRemoved(UniqueChangeRequestVec& changes) { @@ -150,17 +149,38 @@ void RenderLayer::removeAllDrawables() { } void RenderLayer::updateRenderTileIDs() { - renderTileIDs.clear(); + const auto oldMap = std::move(renderTileIDs); if (renderTiles) { - const auto inserter = std::inserter(renderTileIDs, renderTileIDs.end()); - const auto getID = [](const auto& tile) { - return tile.get().getOverscaledTileID(); - }; renderTileIDs.reserve(renderTiles->size()); - std::transform(renderTiles->begin(), renderTiles->end(), inserter, getID); + for (const auto& tile : *renderTiles) { + // If the tile existed previously, retain the mapped value + const auto tileID = tile.get().getOverscaledTileID(); + const auto hit = oldMap.find(tileID); + const auto bucketID = (hit != oldMap.end()) ? hit->second : util::SimpleIdentity::Empty; + [[maybe_unused]] const auto result = renderTileIDs.insert(std::make_pair(tileID, bucketID)); + assert(result.second && "Unexpected duplicate TileID in renderTiles"); + } } } +bool RenderLayer::hasRenderTile(const OverscaledTileID& tileID) const { + return renderTileIDs.find(tileID) != renderTileIDs.end(); +} + +util::SimpleIdentity RenderLayer::getRenderTileBucketID(const OverscaledTileID& tileID) const { + const auto hit = renderTileIDs.find(tileID); + return (hit != renderTileIDs.end()) ? hit->second : util::SimpleIdentity::Empty; +} + +bool RenderLayer::setRenderTileBucketID(const OverscaledTileID& tileID, util::SimpleIdentity bucketID) { + const auto hit = renderTileIDs.find(tileID); + if (hit != renderTileIDs.end() && hit->second != bucketID) { + hit->second = bucketID; + return true; + } + return false; +} + void RenderLayer::layerIndexChanged(int32_t newLayerIndex, UniqueChangeRequestVec& changes) { layerIndex = newLayerIndex; diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index eecf333c4..0cb6bda0c 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #endif // MLN_DRAWABLE_RENDERER #include @@ -205,8 +205,18 @@ protected: /// Remove all the drawables for tiles virtual void removeAllDrawables(); - // Update `renderTileIDs` from `renderTiles` + /// Update `renderTileIDs` from `renderTiles` void updateRenderTileIDs(); + + /// Whether a given tile ID is present in the current cover set (`renderTiles`) + bool hasRenderTile(const OverscaledTileID&) const; + + /// Get the bucket ID from which a given tile was built + util::SimpleIdentity getRenderTileBucketID(const OverscaledTileID&) const; + + /// Set the bucket ID from which a given tile was built + /// @return true if updated, false if missing or unchanged + bool setRenderTileBucketID(const OverscaledTileID&, util::SimpleIdentity bucketID); #endif // MLN_DRAWABLE_RENDERER protected: @@ -223,9 +233,11 @@ protected: // will need to be overriden to handle their activation. LayerGroupBasePtr layerGroup; - // The set of Tile IDs in `renderTiles` - std::unordered_set renderTileIDs; + // The set of Tile IDs in `renderTiles`, along with the + // identity of the bucket from which they were built. + std::unordered_map renderTileIDs; #endif + // Current layer index as specified by the layerIndexChanged event int32_t layerIndex{0}; diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 9eca0168d..90452bd24 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -133,8 +133,8 @@ void Renderer::Impl::render(const RenderTree& renderTree) { // Run layer tweakers to update any dynamic elements orchestrator.observeLayerGroups([&](LayerGroupBase& layerGroup) { - if (layerGroup.getLayerTweaker()) { - layerGroup.getLayerTweaker()->execute(layerGroup, renderTree, parameters); + if (const auto& tweaker = layerGroup.getLayerTweaker()) { + tweaker->execute(layerGroup, renderTree, parameters); } });