diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index dc154c23a..5dc1dfbba 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -365,13 +365,14 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, auto updateExisting = [&](gfx::Drawable& drawable) { if (drawable.getLayerTweaker() != layerTweaker) { // This drawable was produced on a previous style/bucket, and should not be updated. - return; + return false; } auto& uniforms = drawable.mutableUniformBuffers(); uniforms.createOrUpdate(idCircleInterpolateUBOName, &interpolateUBO, context); + return true; }; - if (0 < tileLayerGroup->visitDrawables(renderPass, tileID, std::move(updateExisting))) { + if (updateTile(renderPass, tileID, std::move(updateExisting))) { continue; } diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index e4cf026c5..fa6dca976 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -404,24 +404,18 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, }; // If we already have drawables for this tile, update them. - if (tileLayerGroup->getDrawableCount(drawPass, tileID) > 0) { - // Just update the drawables we already created - tileLayerGroup->visitDrawables(drawPass, tileID, [&](gfx::Drawable& drawable) { - if (drawable.getLayerTweaker() != layerTweaker) { - // This drawable was produced on a previous style/bucket, and should not be updated. - return; - } + auto updateExisting = [&](gfx::Drawable& drawable) { + if (drawable.getLayerTweaker() != layerTweaker) { + // This drawable was produced on a previous style/bucket, and should not be updated. + return false; + } - auto& uniforms = drawable.mutableUniformBuffers(); - uniforms.createOrUpdate( - FillExtrusionLayerTweaker::idFillExtrusionTilePropsUBOName, &tilePropsUBO, context); - uniforms.createOrUpdate( - FillExtrusionLayerTweaker::idFillExtrusionInterpolateUBOName, &interpUBO, context); - }); - continue; - } - - if (!shaderGroup) { + auto& uniforms = drawable.mutableUniformBuffers(); + uniforms.createOrUpdate(FillExtrusionLayerTweaker::idFillExtrusionTilePropsUBOName, &tilePropsUBO, context); + uniforms.createOrUpdate(FillExtrusionLayerTweaker::idFillExtrusionInterpolateUBOName, &interpUBO, context); + return true; + }; + if (updateTile(drawPass, tileID, std::move(updateExisting))) { continue; } diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index e57a05cb9..41cfd4dc9 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -518,7 +518,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, auto updateExisting = [&](gfx::Drawable& drawable) { if (drawable.getLayerTweaker() != layerTweaker) { // This drawable was produced on a previous style/bucket, and should not be updated. - return; + return false; } auto& uniforms = drawable.mutableUniformBuffers(); @@ -539,8 +539,9 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, } drawable.setVertexAttributes(vertexAttrs); + return true; }; - if (0 < tileLayerGroup->visitDrawables(renderPass, tileID, std::move(updateExisting))) { + if (updateTile(renderPass, tileID, std::move(updateExisting))) { continue; } diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index e5df0649c..700cc4c85 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -491,7 +491,7 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, // Only current drawables are updated, ones produced for // a previous style retain the attribute values for that style. if (drawable.getLayerTweaker() != layerTweaker) { - return; + return false; } drawable.setVertexAttributes(std::move(hillshadeVertexAttrs)); @@ -516,8 +516,9 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, if (hillshadeImageLocation) { drawable.setTexture(bucket.renderTarget->getTexture(), *hillshadeImageLocation); } + return true; }; - if (0 < tileLayerGroup->visitDrawables(renderPass, tileID, std::move(updateExisting))) { + if (updateTile(renderPass, tileID, std::move(updateExisting))) { continue; } diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 8bec28b40..0764da1c9 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -537,11 +537,10 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, /*pattern_from =*/patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, /*pattern_to =*/patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}}; - // update existing drawables - tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + auto updateExisting = [&](gfx::Drawable& drawable) { if (drawable.getLayerTweaker() != layerTweaker) { // This drawable was produced on a previous style/bucket, and should not be updated. - return; + return false; } const auto& shader = drawable.getShader(); @@ -572,9 +571,9 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, } // TODO: vertex attributes or `propertiesAsUniforms` updated, is that needed? - }); - - if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) { + return true; + }; + if (updateTile(renderPass, tileID, std::move(updateExisting))) { continue; } diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index 70abfbc71..76d065715 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -466,20 +466,26 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, if (!cleared) { // Update existing drawables bool geometryChanged = false; - const auto updated = tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + auto updateExisting = [&](gfx::Drawable& drawable) { + // Only current drawables are updated, ones produced for + // a previous style retain the attribute values for that style. + if (drawable.getLayerTweaker() != layerTweaker) { + return false; + } + gfx::UniqueDrawableBuilder none; if (!geometryChanged && !buildVertexData(none, &drawable, bucket)) { // Masking changed, need to rebuild this tile geometryChanged = true; } - }); - - if (geometryChanged) { - removeTile(renderPass, tileID); - // cleared = true; - } else if (0 < updated) { + return true; + }; + if (updateTile(renderPass, tileID, std::move(updateExisting))) { // If we modified drawables without removing them, we're done with this tile. continue; + } else if (geometryChanged) { + // If the geometry has changed, the drawable needs to be re-built + removeTile(renderPass, tileID); } } diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 2b0137047..f50a2e16d 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -1148,35 +1148,34 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, }; // If we already have drawables for this tile, update them. - if (tileLayerGroup->getDrawableCount(passes, tileID) > 0) { - gfx::UniformBufferPtr textInterpUBO, iconInterpUBO; + // Just update the drawables we already created + gfx::UniformBufferPtr textInterpUBO, iconInterpUBO; + auto updateExisting = [&](gfx::Drawable& drawable) { + if (drawable.getLayerTweaker() != layerTweaker) { + // This drawable was produced on a previous style/bucket, and should not be updated. + return false; + } - // Just update the drawables we already created - tileLayerGroup->visitDrawables(passes, tileID, [&](gfx::Drawable& drawable) { - if (drawable.getLayerTweaker() != layerTweaker) { - // This drawable was produced on a previous style/bucket, and should not be updated. - return; - } + propertiesAsUniforms.clear(); - propertiesAsUniforms.clear(); - - const auto& evaluated = getEvaluated(renderData.layerProperties); - updateTileDrawable(drawable, - context, - bucket, - bucketPaintProperties, - evaluated, - state, - textInterpUBO, - iconInterpUBO, - propertiesAsUniforms); - - // We assume that the properties-as-uniforms doesn't change without the style changing. - // That would require updating the shader as well. - [[maybe_unused]] const auto& drawData = static_cast(*drawable.getData()); - assert(drawData.propertiesAsUniforms == toMap(propertiesAsUniforms)); - }); + const auto& evaluated = getEvaluated(renderData.layerProperties); + updateTileDrawable(drawable, + context, + bucket, + bucketPaintProperties, + evaluated, + state, + textInterpUBO, + iconInterpUBO, + propertiesAsUniforms); + // We assume that the properties-as-uniforms doesn't change without the style changing. + // That would require updating the shader as well. + [[maybe_unused]] const auto& drawData = static_cast(*drawable.getData()); + assert(drawData.propertiesAsUniforms == toMap(propertiesAsUniforms)); + return true; + }; + if (updateTile(passes, tileID, std::move(updateExisting))) { // re-create collision drawables if (collisionTileLayerGroup) { collisionTileLayerGroup->removeDrawables(passes, tileID); diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index 927815e4b..fcbdf4a9a 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -166,6 +166,30 @@ const LayerRenderData* RenderLayer::getRenderDataForPass(const RenderTile& tile, } #if MLN_DRAWABLE_RENDERER +bool RenderLayer::updateTile(RenderPass renderPass, + const OverscaledTileID& tileID, + std::function update) { + bool anyUpdated = false; + if (const auto tileGroup = static_cast(layerGroup.get())) { + bool unUpdatedDrawables = false; + tileGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + if (update(drawable)) { + anyUpdated = true; + } else { + unUpdatedDrawables = true; + } + }); + + // If any are updated, the caller shouldn't add new ones. + // If none are updated and some were skipped, remove those. + // This is to handle the case that the style layer changes but the bucket is not re-created. + if (!anyUpdated && unUpdatedDrawables) { + removeTile(renderPass, tileID); + } + } + return anyUpdated; +} + std::size_t RenderLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { if (const auto tileGroup = static_cast(layerGroup.get())) { const auto n = tileGroup->removeDrawables(renderPass, tileID).size(); diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index ed4a509b9..4091700c2 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -209,6 +209,16 @@ protected: /// Change the layer index on a layer group associated with this layer void changeLayerIndex(const LayerGroupBasePtr&, int32_t newLayerIndex, UniqueChangeRequestVec&); + /// Update the drawables for a tile. + /// @param renderPass The pass to consider + /// @param tileID The tile to consider + /// @param updateFunction A function that updates a single drawable. Should return true if the drawable + /// was updated or false if it was skipped because it's for a previous style. + /// @return true if drawables were updated + bool updateTile(RenderPass renderPass, + const OverscaledTileID& tileID, + std::function updateFunction); + /// Remove all drawables for the tile from the layer group /// @return The number of drawables actually removed. virtual std::size_t removeTile(RenderPass, const OverscaledTileID&);