diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index b13a93b75..13feb6e59 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -18,8 +18,11 @@ namespace mbgl { class Color; class PaintParameters; +class LayerTweaker; enum class RenderPass : uint8_t; +using LayerTweakerPtr = std::shared_ptr; + namespace gfx { class ColorMode; @@ -234,6 +237,10 @@ public: /// Get drawable user-defined type size_t getType() const { return type; } + /// Associate the drawable with a layer tweaker. This is used to manage the lifetime of the tweaker. + void setLayerTweaker(LayerTweakerPtr tweaker) { layerTweaker = std::move(tweaker); } + const LayerTweakerPtr& getLayerTweaker() const { return layerTweaker; } + protected: bool enabled = true; bool enableColor = true; @@ -257,6 +264,7 @@ protected: Textures textures; std::vector tweakers; + LayerTweakerPtr layerTweaker; std::size_t type = 0; }; diff --git a/include/mbgl/gfx/drawable_builder.hpp b/include/mbgl/gfx/drawable_builder.hpp index b13249425..bc5fd59f0 100644 --- a/include/mbgl/gfx/drawable_builder.hpp +++ b/include/mbgl/gfx/drawable_builder.hpp @@ -145,6 +145,9 @@ public: /// @param location A sampler location in the shader being used. void setTexture(const gfx::Texture2DPtr&, int32_t location); + /// Direct access to the current texture set + const gfx::Drawable::Textures& getTextures() const { return textures; } + /// Add a tweaker to emitted drawable void addTweaker(DrawableTweakerPtr value) { tweakers.emplace_back(std::move(value)); } @@ -225,5 +228,7 @@ protected: std::unique_ptr impl; }; +using UniqueDrawableBuilder = std::unique_ptr; + } // namespace gfx } // namespace mbgl diff --git a/include/mbgl/renderer/layer_group.hpp b/include/mbgl/renderer/layer_group.hpp index dd708f8ea..8780ba8d3 100644 --- a/include/mbgl/renderer/layer_group.hpp +++ b/include/mbgl/renderer/layer_group.hpp @@ -13,6 +13,7 @@ namespace mbgl { class LayerGroupBase; class PaintParameters; class RenderOrchestrator; +class RenderTree; class TileLayerGroup; using LayerGroupBasePtr = std::shared_ptr; @@ -28,6 +29,7 @@ using UniqueDrawable = std::unique_ptr; class LayerTweaker; using LayerTweakerPtr = std::shared_ptr; +using LayerTweakerWeakPtr = std::weak_ptr; /** A layer-like group of drawables, not a group of layers. @@ -86,16 +88,16 @@ public: /// @return The number of items removed virtual std::size_t removeDrawablesIf(const std::function&& f) = 0; - /// Attach a tweaker to be run on this layer group for each frame - void setLayerTweaker(LayerTweakerPtr tweaker) { layerTweaker = std::move(tweaker); } + /// Attach a tweaker to be run on this layer group for each frame. + /// Tweaker lifetime is controlled by the render layer and drawables, the layer group retains a weak reference. + void addLayerTweaker(const LayerTweakerPtr& tweaker) { layerTweakers.emplace_back(tweaker); } - /// Get the tweaker attached to this layer group - const LayerTweakerPtr& getLayerTweaker() const { return layerTweaker; } + void runTweakers(const RenderTree&, PaintParameters&); protected: bool enabled = true; int32_t layerIndex; - LayerTweakerPtr layerTweaker; + std::vector layerTweakers; std::string name; }; diff --git a/include/mbgl/renderer/layer_tweaker.hpp b/include/mbgl/renderer/layer_tweaker.hpp index 2b81f1746..4eba01e09 100644 --- a/include/mbgl/renderer/layer_tweaker.hpp +++ b/include/mbgl/renderer/layer_tweaker.hpp @@ -9,6 +9,7 @@ namespace mbgl { namespace gfx { +class Drawable; class UniformBuffer; using UniformBufferPtr = std::shared_ptr; } // namespace gfx @@ -45,17 +46,21 @@ public: /// Build the common expression inupts UBO static shaders::ExpressionInputsUBO buildExpressionUBO(double zoom, uint64_t frameCount); - /// @brief Set the collection of attribute names which will be provided at uniform values rather than per-vertex - /// attributes. - /// @details These values should not have "a_" prefixes, as produced by `readDataDrivenPaintProperties`. - void setPropertiesAsUniforms(std::vector); - /// @brief Check whether a property name exists within the previously set collection. /// @details The string value provided is expected to have the "a_" prefix, as defined in the shader classes. bool hasPropertyAsUniform(std::string_view) const; shaders::AttributeSource getAttributeSource(const std::string_view& attribName) const; #endif // MLN_RENDER_BACKEND_METAL + /// @brief Set the collection of attribute names which will be provided at uniform values rather than per-vertex + /// attributes. + /// @details These values should not have "a_" prefixes, as produced by `readDataDrivenPaintProperties`. +#if MLN_RENDER_BACKEND_OPENGL + void setPropertiesAsUniforms(const std::vector&) {} +#else + void setPropertiesAsUniforms(std::vector); +#endif + void enableOverdrawInspector(bool); virtual void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) = 0; @@ -63,6 +68,9 @@ public: void updateProperties(Immutable); protected: + /// Determine whether this tweaker should apply to the given drawable + bool checkTweakDrawable(const gfx::Drawable&) const; + /// Calculate matrices for this tile. /// @param nearClipped If true, the near plane is moved further to enhance depth buffer precision. /// @param inViewportPixelUnits If false, the translation is scaled based on the current zoom. @@ -78,7 +86,6 @@ protected: protected: std::string id; Immutable evaluatedProperties; - bool propertiesUpdated = true; #if MLN_RENDER_BACKEND_METAL // For Metal, whether a property is provided through attribtues or uniforms is specified in @@ -86,7 +93,12 @@ protected: std::vector propertiesAsUniforms; #endif // MLN_RENDER_BACKEND_METAL - bool propertiesChanged = true; + // Indicates that the evaluated properties have changed + bool propertiesUpdated = true; + + // Indicates that the properties-as-uniforms has changed + bool permutationUpdated = true; + bool overdrawInspector = false; }; diff --git a/src/mbgl/gfx/index_vector.hpp b/src/mbgl/gfx/index_vector.hpp index f5befbf5d..f3854ef42 100644 --- a/src/mbgl/gfx/index_vector.hpp +++ b/src/mbgl/gfx/index_vector.hpp @@ -27,13 +27,18 @@ public: : v(other.v) {} // buffer is not copied IndexVectorBase(IndexVectorBase&& other) : v(std::move(other.v)), +#if MLN_DRAWABLE_RENDERER buffer(std::move(other.buffer)), +#endif // MLN_DRAWABLE_RENDERER dirty(other.dirty), - released(other.released) {} + released(other.released) { + } virtual ~IndexVectorBase() = default; +#if MLN_DRAWABLE_RENDERER IndexBufferBase* getBuffer() const { return buffer.get(); } void setBuffer(std::unique_ptr&& value) { buffer = std::move(value); } +#endif // MLN_DRAWABLE_RENDERER bool getDirty() const { return dirty; } void setDirty(bool value = true) { dirty = value; } @@ -41,12 +46,14 @@ public: bool isReleased() const { return released; } void extend(std::size_t n, const uint16_t val) { + assert(!released); v.resize(v.size() + n, val); dirty = true; } uint16_t& at(std::size_t n) { assert(n < v.size()); + assert(!released); dirty = true; return v.at(n); } @@ -66,11 +73,14 @@ public: v.clear(); } + /// Indicate that this shared index vector will no longer be updated. void release() { +#if MLN_DRAWABLE_RENDERER // If we've already created a buffer, we don't need the raw data any more. if (buffer) { - clear(); + v.clear(); } +#endif // MLN_DRAWABLE_RENDERER released = true; } @@ -79,7 +89,9 @@ public: const std::vector& vector() const { return v; } protected: +#if MLN_DRAWABLE_RENDERER std::unique_ptr buffer; +#endif // MLN_DRAWABLE_RENDERER bool dirty = true; bool released = false; }; @@ -94,6 +106,7 @@ public: template void emplace_back(Args&&... args) { static_assert(sizeof...(args) == groupSize, "wrong buffer element count"); + assert(!released); util::ignore({(v.emplace_back(std::forward(args)), 0)...}); } }; diff --git a/src/mbgl/gfx/vertex_vector.hpp b/src/mbgl/gfx/vertex_vector.hpp index 1066b1f58..94d26a13c 100644 --- a/src/mbgl/gfx/vertex_vector.hpp +++ b/src/mbgl/gfx/vertex_vector.hpp @@ -17,17 +17,23 @@ public: VertexVectorBase() = default; VertexVectorBase(const VertexVectorBase&) {} // buffer is not copied VertexVectorBase(VertexVectorBase&& other) - : buffer(std::move(other.buffer)), + : +#if MLN_DRAWABLE_RENDERER + buffer(std::move(other.buffer)), +#endif // MLN_DRAWABLE_RENDERER dirty(other.dirty), - released(other.released) {} + released(other.released) { + } virtual ~VertexVectorBase() = default; virtual const void* getRawData() const = 0; virtual std::size_t getRawSize() const = 0; virtual std::size_t getRawCount() const = 0; +#if MLN_DRAWABLE_RENDERER VertexBufferBase* getBuffer() const { return buffer.get(); } void setBuffer(std::unique_ptr&& value) { buffer = std::move(value); } +#endif // MLN_DRAWABLE_RENDERER bool getDirty() const { return dirty; } void setDirty(bool value = true) { dirty = value; } @@ -35,7 +41,9 @@ public: bool isReleased() const { return released; } protected: +#if MLN_DRAWABLE_RENDERER std::unique_ptr buffer; +#endif // MLN_DRAWABLE_RENDERER bool dirty = true; bool released = false; }; @@ -57,16 +65,20 @@ public: template void emplace_back(Arg&& vertex) { + assert(!released); v.emplace_back(std::forward(vertex)); + dirty = true; } void extend(std::size_t n, const Vertex& val) { + assert(!released); v.resize(v.size() + n, val); dirty = true; } Vertex& at(std::size_t n) { assert(n < v.size()); + assert(!released); dirty = true; return v.at(n); } @@ -86,11 +98,14 @@ public: v.clear(); } + /// Indicate that this shared vertex vector instance will no longer be updated. void release() { +#if MLN_DRAWABLE_RENDERER // If we've already created a buffer, we don't need the raw data any more. if (buffer) { - clear(); + v.clear(); } +#endif // MLN_DRAWABLE_RENDERER released = true; } diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index f9adc544e..314243ff0 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -122,9 +122,11 @@ void DrawableGL::bindUniformBuffers() const { const auto& uniformBuffer = getUniformBuffers().get(element.first); if (!uniformBuffer) { using namespace std::string_literals; + const auto tileID = getTileID() ? util::toString(*getTileID()) : ""; Log::Error(Event::General, - "DrawableGL::bindUniformBuffers: UBO "s + std::string(StringIndexer::get(element.first)) + - " not found. skipping."); + "bindUniformBuffers: UBO "s + std::string(StringIndexer::get(element.first)) + + " not found for " + util::toString(getID()) + " / " + getName() + " / " + tileID + + ". skipping."); assert(false); continue; } diff --git a/src/mbgl/gl/drawable_gl_builder.cpp b/src/mbgl/gl/drawable_gl_builder.cpp index 6b1a55134..caa3afdb9 100644 --- a/src/mbgl/gl/drawable_gl_builder.cpp +++ b/src/mbgl/gl/drawable_gl_builder.cpp @@ -43,6 +43,7 @@ void DrawableGLBuilder::init() { impl->buildIndexes.clear(); impl->segments.clear(); impl->vertices.clear(); + textures.clear(); } } // namespace gl diff --git a/src/mbgl/gl/layer_group_gl.cpp b/src/mbgl/gl/layer_group_gl.cpp index d8df4c621..0ce9a50e6 100644 --- a/src/mbgl/gl/layer_group_gl.cpp +++ b/src/mbgl/gl/layer_group_gl.cpp @@ -103,7 +103,8 @@ void TileLayerGroupGL::render(RenderOrchestrator&, PaintParameters& parameters) #if !defined(NDEBUG) std::string label_tile; if (const auto& tileID = drawable.getTileID()) { - label_tile = drawable.getName() + "/" + util::toString(*tileID); + label_tile = util::toString(drawable.getID().id()) + "/" + drawable.getName() + "/" + + util::toString(*tileID); } const auto labelPtr = (label_tile.empty() ? drawable.getName() : label_tile).c_str(); const auto debugGroupTile = parameters.encoder->createDebugGroup(labelPtr); diff --git a/src/mbgl/mtl/drawable.cpp b/src/mbgl/mtl/drawable.cpp index 2caaaf3b6..89e36092b 100644 --- a/src/mbgl/mtl/drawable.cpp +++ b/src/mbgl/mtl/drawable.cpp @@ -377,9 +377,11 @@ void Drawable::bindUniformBuffers(const RenderPass& renderPass) const { const auto& uniformBuffer = getUniformBuffers().get(element.first); if (!uniformBuffer) { using namespace std::string_literals; + const auto tileID = getTileID() ? util::toString(*getTileID()) : ""; + const auto tileLabel = util::toString(getID()) + "/" + getName() + "/" + tileID; Log::Error(Event::General, - "Drawable::bindUniformBuffers: UBO "s + StringIndexer::get(element.first) + - " not found. skipping."); + "bindUniformBuffers: UBO "s + StringIndexer::get(element.first) + " not found on " + + tileLabel + ". skipping."); assert(false); continue; } @@ -518,7 +520,9 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { auto& context = static_cast(contextBase); constexpr auto usage = gfx::BufferUsageType::StaticDraw; - if (!impl->indexes || !impl->indexes->bytes()) { + // We need either raw index data or a buffer already created from them. + // We can have a buffer and no indexes, but only if it's not marked dirty. + if (!impl->indexes || (impl->indexes->empty() && (!impl->indexes->getBuffer() || impl->indexes->getDirty()))) { assert(!"Missing index data"); return; } diff --git a/src/mbgl/mtl/drawable_builder.cpp b/src/mbgl/mtl/drawable_builder.cpp index ec436fbc7..4144f802b 100644 --- a/src/mbgl/mtl/drawable_builder.cpp +++ b/src/mbgl/mtl/drawable_builder.cpp @@ -38,11 +38,13 @@ void DrawableBuilder::init() { if (!impl->sharedIndexes && !impl->buildIndexes.empty()) { impl->sharedIndexes = std::make_shared(std::move(impl->buildIndexes)); } + assert(impl->sharedIndexes && impl->sharedIndexes->elements()); drawable.setIndexData(std::move(impl->sharedIndexes), std::move(impl->segments)); impl->buildIndexes.clear(); impl->segments.clear(); impl->vertices.clear(); + textures.clear(); } } // namespace mtl diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp index b011ff82a..d5d4ec32f 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.cpp +++ b/src/mbgl/renderer/buckets/raster_bucket.cpp @@ -13,7 +13,10 @@ RasterBucket::RasterBucket(PremultipliedImage&& image_) RasterBucket::RasterBucket(std::shared_ptr image_) : image(std::move(image_)) {} -RasterBucket::~RasterBucket() = default; +RasterBucket::~RasterBucket() { + clear(); + setImage({}); +} void RasterBucket::upload([[maybe_unused]] gfx::UploadPass& uploadPass) { if (!hasData()) { @@ -49,6 +52,7 @@ void RasterBucket::clear() { void RasterBucket::setImage(std::shared_ptr image_) { image = std::move(image_); texture = {}; + texture2d.reset(); uploaded = false; } diff --git a/src/mbgl/renderer/buckets/raster_bucket.hpp b/src/mbgl/renderer/buckets/raster_bucket.hpp index da218bec3..d9e21e75a 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.hpp +++ b/src/mbgl/renderer/buckets/raster_bucket.hpp @@ -9,10 +9,16 @@ #include #include +#include #include namespace mbgl { +namespace gfx { +class Texture2D; +using Texture2DPtr = std::shared_ptr; +} // namespace gfx + class RasterBucket final : public Bucket { public: RasterBucket(PremultipliedImage&&); @@ -28,6 +34,7 @@ public: std::shared_ptr image; std::optional texture; + gfx::Texture2DPtr texture2d; TileMask mask{{0, 0, 0}}; // Bucket specific vertices are used for Image Sources only diff --git a/src/mbgl/renderer/layer_group.cpp b/src/mbgl/renderer/layer_group.cpp index cc9ffdb97..48c423d6a 100644 --- a/src/mbgl/renderer/layer_group.cpp +++ b/src/mbgl/renderer/layer_group.cpp @@ -2,8 +2,10 @@ #include #include +#include #include #include +#include #include @@ -16,6 +18,17 @@ void LayerGroupBase::addDrawable(gfx::UniqueDrawable& drawable) { } } +void LayerGroupBase::runTweakers(const RenderTree& renderTree, PaintParameters& parameters) { + for (auto it = layerTweakers.begin(); it != layerTweakers.end();) { + if (auto tweaker = it->lock()) { + tweaker->execute(*this, renderTree, parameters); + ++it; + } else { + it = layerTweakers.erase(it); + } + } +} + struct LayerGroup::Impl { using DrawableCollection = std::set; DrawableCollection drawables; diff --git a/src/mbgl/renderer/layer_tweaker.cpp b/src/mbgl/renderer/layer_tweaker.cpp index b982f2978..fe299946f 100644 --- a/src/mbgl/renderer/layer_tweaker.cpp +++ b/src/mbgl/renderer/layer_tweaker.cpp @@ -19,6 +19,12 @@ LayerTweaker::LayerTweaker(std::string id_, Immutable pr : id(std::move(id_)), evaluatedProperties(std::move(properties)) {} +bool LayerTweaker::checkTweakDrawable(const gfx::Drawable& drawable) const { + // Apply to a drawable if it references us, or if doesn't reference anything. + const auto& tweaker = drawable.getLayerTweaker(); + return !tweaker || tweaker.get() == this; +} + mat4 LayerTweaker::getTileMatrix(const UnwrappedTileID& tileID, const RenderTree& renderTree, const TransformState& state, @@ -60,12 +66,15 @@ shaders::ExpressionInputsUBO LayerTweaker::buildExpressionUBO(double zoom, uint6 0}; } +#if !MLN_RENDER_BACKEND_OPENGL void LayerTweaker::setPropertiesAsUniforms(std::vector props) { if (props != propertiesAsUniforms) { propertiesAsUniforms = std::move(props); - propertiesChanged = true; + permutationUpdated = true; } } +#endif + bool LayerTweaker::hasPropertyAsUniform(const std::string_view attrName) const { // `attrName` is expected to have the "a_" prefix, while the values in `propertiesAsUniforms` // do not. Search for the former within the latter without allocating temporary strings. @@ -84,7 +93,7 @@ AttributeSource LayerTweaker::getAttributeSource(const std::string_view& attribN void LayerTweaker::enableOverdrawInspector(bool value) { if (overdrawInspector != value) { overdrawInspector = value; - propertiesChanged = true; + permutationUpdated = true; } } diff --git a/src/mbgl/renderer/layers/background_layer_tweaker.cpp b/src/mbgl/renderer/layers/background_layer_tweaker.cpp index ceb875b3f..d4ee0b033 100644 --- a/src/mbgl/renderer/layers/background_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/background_layer_tweaker.cpp @@ -54,6 +54,9 @@ void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTre std::optional samplerLocation{}; layerGroup.visitDrawables([&](gfx::Drawable& drawable) { assert(drawable.getTileID()); + if (!drawable.getTileID() || !checkTweakDrawable(drawable)) { + return; + } // We assume that drawables don't change between pattern and non-pattern. const auto& shader = drawable.getShader(); diff --git a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp index 9d1500127..f328743b5 100644 --- a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp @@ -61,7 +61,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, #if MLN_RENDER_BACKEND_METAL using ShaderClass = shaders::ShaderSource; - if (propertiesChanged) { + if (permutationUpdated) { const auto source = [this](const std::string_view& attrName) { return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex; }; @@ -86,7 +86,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, permutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO)); } - propertiesChanged = false; + permutationUpdated = false; } if (!expressionUniformBuffer) { const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount); @@ -114,16 +114,16 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, } layerGroup.visitDrawables([&](gfx::Drawable& drawable) { - auto& uniforms = drawable.mutableUniformBuffers(); - uniforms.addOrReplace(idCirclePaintParamsUBOName, paintParamsUniformBuffer); - uniforms.addOrReplace(idCircleEvaluatedPropsUBOName, evaluatedPropsUniformBuffer); - - if (!drawable.getTileID()) { - assert(!"Circles only render with tiles"); + assert(drawable.getTileID() || !"Circles only render with tiles"); + if (!drawable.getTileID() || !checkTweakDrawable(drawable)) { return; } const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); + auto& uniforms = drawable.mutableUniformBuffers(); + uniforms.addOrReplace(idCirclePaintParamsUBOName, paintParamsUniformBuffer); + uniforms.addOrReplace(idCircleEvaluatedPropsUBOName, evaluatedPropsUniformBuffer); + const auto& translation = evaluated.get(); const auto anchor = evaluated.get(); constexpr bool inViewportPixelUnits = false; // from RenderTile::translatedMatrix diff --git a/src/mbgl/renderer/layers/collision_layer_tweaker.cpp b/src/mbgl/renderer/layers/collision_layer_tweaker.cpp index 5e8d0bd9a..508f16888 100644 --- a/src/mbgl/renderer/layers/collision_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/collision_layer_tweaker.cpp @@ -50,7 +50,7 @@ void CollisionLayerTweaker::execute(LayerGroupBase& layerGroup, #endif layerGroup.visitDrawables([&](gfx::Drawable& drawable) { - if (!drawable.getTileID() || !drawable.getData()) { + if (!drawable.getTileID() || !drawable.getData() || !checkTweakDrawable(drawable)) { return; } diff --git a/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp b/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp index deb0c8ab9..f5add4533 100644 --- a/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp @@ -77,7 +77,7 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup, #if MLN_RENDER_BACKEND_METAL const auto zoom = parameters.state.getZoom(); - if (propertiesChanged) { + if (permutationUpdated) { const FillExtrusionPermutationUBO permutationUBO = { /* .color = */ {/*.source=*/getAttributeSource("a_color"), /*.expression=*/{}}, /* .base = */ {/*.source=*/getAttributeSource("a_base"), /*.expression=*/{}}, @@ -93,7 +93,7 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup, } else { permutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO)); } - propertiesChanged = false; + permutationUpdated = false; } if (!expressionUniformBuffer) { const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount); @@ -102,15 +102,15 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup, #endif layerGroup.visitDrawables([&](gfx::Drawable& drawable) { - auto& uniforms = drawable.mutableUniformBuffers(); - uniforms.addOrReplace(idFillExtrusionDrawablePropsUBOName, propsBuffer); - - if (!drawable.getTileID()) { + if (!drawable.getTileID() || !checkTweakDrawable(drawable)) { return; } const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); + auto& uniforms = drawable.mutableUniformBuffers(); + uniforms.addOrReplace(idFillExtrusionDrawablePropsUBOName, propsBuffer); + const auto& translation = evaluated.get(); const auto anchor = evaluated.get(); constexpr bool inViewportPixelUnits = false; // from RenderTile::translatedMatrix diff --git a/src/mbgl/renderer/layers/fill_layer_tweaker.cpp b/src/mbgl/renderer/layers/fill_layer_tweaker.cpp index ebd33424f..f7ed4cd0a 100644 --- a/src/mbgl/renderer/layers/fill_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/fill_layer_tweaker.cpp @@ -93,7 +93,7 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, #if MLN_RENDER_BACKEND_METAL using ShaderClass = ShaderSource; - if (propertiesChanged || !fillPermutationUniformBuffer) { + if (permutationUpdated || !fillPermutationUniformBuffer) { const FillPermutationUBO permutationUBO = { /* .color = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, /* .opacity = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, @@ -132,7 +132,7 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, #if MLN_RENDER_BACKEND_METAL using ShaderClass = ShaderSource; - if (propertiesChanged || !fillOutlinePermutationUniformBuffer) { + if (permutationUpdated || !fillOutlinePermutationUniformBuffer) { const FillOutlinePermutationUBO permutationUBO = { /* .outline_color = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, /* .opacity = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, @@ -173,7 +173,7 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, #if MLN_RENDER_BACKEND_METAL using ShaderClass = ShaderSource; - if (propertiesChanged || !fillPatternPermutationUniformBuffer) { + if (permutationUpdated || !fillPatternPermutationUniformBuffer) { const FillPatternPermutationUBO permutationUBO = { /* .pattern_from = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, /* .pattern_to = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, @@ -212,7 +212,7 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, #if MLN_RENDER_BACKEND_METAL using ShaderClass = ShaderSource; - if (propertiesChanged || !fillOutlinePermutationUniformBuffer) { + if (permutationUpdated || !fillOutlinePatternPermutationUniformBuffer) { const FillOutlinePatternPermutationUBO permutationUBO = { /* .pattern_from = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, /* .pattern_to = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, @@ -255,6 +255,10 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, #endif layerGroup.visitDrawables([&](gfx::Drawable& drawable) { + if (!drawable.getTileID() || !checkTweakDrawable(drawable)) { + return; + } + auto& uniforms = drawable.mutableUniformBuffers(); // auto& drawableType = drawable.getShader()->typeName(); @@ -287,9 +291,6 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, } } } - if (!drawable.getTileID()) { - return; - } if (uniforms.get(idFillInterpolateUBOName)) { UpdateFillUniformBuffers(); @@ -361,7 +362,7 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, #endif // MLN_RENDER_BACKEND_METAL }); - propertiesChanged = false; + permutationUpdated = false; } } // namespace mbgl diff --git a/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp index 4fa4f5699..f4b44c468 100644 --- a/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp @@ -44,7 +44,7 @@ void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup, #if MLN_RENDER_BACKEND_METAL using ShaderClass = shaders::ShaderSource; - if (propertiesChanged) { + if (permutationUpdated) { const auto source = [this](const std::string_view& attrName) { return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex; }; @@ -66,7 +66,7 @@ void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup, permutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO)); } - propertiesChanged = false; + permutationUpdated = false; } if (!expressionUniformBuffer) { const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount); @@ -85,13 +85,15 @@ void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup, } layerGroup.visitDrawables([&](gfx::Drawable& drawable) { + if (!drawable.getTileID() || !checkTweakDrawable(drawable)) { + return; + } + + const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); + auto& uniforms = drawable.mutableUniformBuffers(); uniforms.addOrReplace(idHeatmapEvaluatedPropsUBOName, evaluatedPropsUniformBuffer); - if (!drawable.getTileID()) { - return; - } - const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); constexpr bool nearClipped = false; constexpr bool inViewportPixelUnits = false; const auto matrix = getTileMatrix(tileID, diff --git a/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp b/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp index 2331c6846..d7542bbbd 100644 --- a/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp @@ -33,6 +33,10 @@ void HeatmapTextureLayerTweaker::execute(LayerGroupBase& layerGroup, #endif layerGroup.visitDrawables([&](gfx::Drawable& drawable) { + if (!checkTweakDrawable(drawable)) { + return; + } + const auto& size = parameters.staticData.backendSize; mat4 viewportMat; matrix::ortho(viewportMat, 0, size.width, size.height, 0, -1, 1); diff --git a/src/mbgl/renderer/layers/hillshade_layer_tweaker.cpp b/src/mbgl/renderer/layers/hillshade_layer_tweaker.cpp index 088785304..7e030ba36 100644 --- a/src/mbgl/renderer/layers/hillshade_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/hillshade_layer_tweaker.cpp @@ -55,12 +55,14 @@ void HillshadeLayerTweaker::execute(LayerGroupBase& layerGroup, } layerGroup.visitDrawables([&](gfx::Drawable& drawable) { - drawable.mutableUniformBuffers().addOrReplace(idHillshadeEvaluatedPropsUBOName, evaluatedPropsUniformBuffer); - - if (!drawable.getTileID()) { + if (!drawable.getTileID() || !checkTweakDrawable(drawable)) { return; } + const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); + + drawable.mutableUniformBuffers().addOrReplace(idHillshadeEvaluatedPropsUBOName, evaluatedPropsUniformBuffer); + const auto matrix = getTileMatrix( tileID, renderTree, parameters.state, {0.f, 0.f}, TranslateAnchorType::Viewport, false, false, true); HillshadeDrawableUBO drawableUBO = {/* .matrix = */ util::cast(matrix), diff --git a/src/mbgl/renderer/layers/hillshade_prepare_layer_tweaker.cpp b/src/mbgl/renderer/layers/hillshade_prepare_layer_tweaker.cpp index dfd33efe5..d8971b00a 100644 --- a/src/mbgl/renderer/layers/hillshade_prepare_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/hillshade_prepare_layer_tweaker.cpp @@ -42,7 +42,7 @@ void HillshadePrepareLayerTweaker::execute(LayerGroupBase& layerGroup, #endif layerGroup.visitDrawables([&](gfx::Drawable& drawable) { - if (!drawable.getTileID() || !drawable.getData()) { + if (!drawable.getTileID() || !drawable.getData() || !checkTweakDrawable(drawable)) { return; } const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); @@ -52,7 +52,7 @@ void HillshadePrepareLayerTweaker::execute(LayerGroupBase& layerGroup, matrix::ortho(matrix, 0, util::EXTENT, -util::EXTENT, 0, -1, 1); matrix::translate(matrix, matrix, 0, -util::EXTENT, 0); - HillshadePrepareDrawableUBO drawableUBO = { + const HillshadePrepareDrawableUBO drawableUBO = { /* .matrix = */ util::cast(matrix), /* .unpack = */ getUnpackVector(drawableData.encoding), /* .dimension = */ {static_cast(drawableData.stride), static_cast(drawableData.stride)}, diff --git a/src/mbgl/renderer/layers/line_layer_tweaker.cpp b/src/mbgl/renderer/layers/line_layer_tweaker.cpp index a0275e54b..9bd15fac5 100644 --- a/src/mbgl/renderer/layers/line_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/line_layer_tweaker.cpp @@ -113,7 +113,7 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, #if MLN_RENDER_BACKEND_METAL using LineShaderClass = shaders::ShaderSource; - if (propertiesChanged) { + if (permutationUpdated) { const auto source = [this](const std::string_view& attrName) { return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex; }; @@ -139,7 +139,7 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, } else { permutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO)); } - propertiesChanged = false; + permutationUpdated = false; } if (!expressionUniformBuffer) { const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount); @@ -149,7 +149,7 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, layerGroup.visitDrawables([&](gfx::Drawable& drawable) { const auto shader = drawable.getShader(); - if (!drawable.getTileID() || !shader) { + if (!drawable.getTileID() || !shader || !checkTweakDrawable(drawable)) { return; } diff --git a/src/mbgl/renderer/layers/raster_layer_tweaker.cpp b/src/mbgl/renderer/layers/raster_layer_tweaker.cpp index 945309f8c..2854f82dd 100644 --- a/src/mbgl/renderer/layers/raster_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/raster_layer_tweaker.cpp @@ -25,6 +25,10 @@ void RasterLayerTweaker::execute([[maybe_unused]] LayerGroupBase& layerGroup, const auto& evaluated = static_cast(*evaluatedProperties).evaluated; layerGroup.visitDrawables([&](gfx::Drawable& drawable) { + if (!checkTweakDrawable(drawable)) { + return; + } + const auto spinWeights = [](float spin) -> std::array { spin = util::deg2radf(spin); const float s = std::sin(spin); diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index b13b44914..6f50db3d4 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -67,7 +66,8 @@ void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters& paramet #if MLN_DRAWABLE_RENDERER if (layerGroup) { - layerGroup->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); + auto newTweaker = std::make_shared(getID(), evaluatedProperties); + replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup}); } #endif } @@ -250,12 +250,18 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders, if (!layerGroup) { if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { - layerGroup_->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); setLayerGroup(std::move(layerGroup_), changes); + } else { + return; } } auto* tileLayerGroup = static_cast(layerGroup.get()); + if (!layerTweaker) { + layerTweaker = std::make_shared(getID(), evaluatedProperties); + layerGroup->addLayerTweaker(layerTweaker); + } + if (!hasPattern && !plainShader) { plainShader = context.getGenericShader(shaders, std::string(BackgroundPlainShaderName)); } @@ -312,6 +318,7 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder->clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); tileLayerGroup->addDrawable(drawPasses, tileID, std::move(drawable)); ++stats.drawablesAdded; } diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index b3c704d95..27aa14606 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -93,7 +93,10 @@ void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters) evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - updateLayerTweaker(); + if (layerGroup) { + auto newTweaker = std::make_shared(getID(), evaluatedProperties); + replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup}); + } #endif // MLN_DRAWABLE_RENDERER } @@ -276,19 +279,6 @@ static const StringIdentity idVertexAttribName = StringIndexer::get("a_pos"); using namespace shaders; -#if MLN_DRAWABLE_RENDERER -void RenderCircleLayer::updateLayerTweaker() { - if (layerGroup) { - tweaker = std::make_shared(getID(), evaluatedProperties); -#if MLN_RENDER_BACKEND_METAL - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); -#endif // MLN_RENDER_BACKEND_METAL - tweaker->enableOverdrawInspector(overdrawInspector); - layerGroup->setLayerTweaker(tweaker); - } -} -#endif // MLN_DRAWABLE_RENDERER - void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, @@ -305,12 +295,19 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, // Set up a layer group if (!layerGroup) { if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { - layerGroup_->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); setLayerGroup(std::move(layerGroup_), changes); + } else { + return; } } auto* tileLayerGroup = static_cast(layerGroup.get()); + if (!layerTweaker) { + layerTweaker = std::make_shared(getID(), evaluatedProperties); + layerGroup->addLayerTweaker(layerTweaker); + } + layerTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw)); + if (!circleShaderGroup) { circleShaderGroup = shaders.getShaderGroup(CircleShaderGroupName); } @@ -319,14 +316,6 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, return; } - const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw); - if (overdrawInspector != overdraw) { - overdrawInspector = overdraw; - if (tweaker) { - tweaker->enableOverdrawInspector(overdrawInspector); - } - } - std::unique_ptr circleBuilder; constexpr auto renderPass = RenderPass::Translucent; @@ -375,6 +364,11 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, // If there are already drawables for this tile, update their UBOs and move on to the next tile. auto updateExisting = [&](gfx::Drawable& drawable) { + if (drawable.getLayerTweaker() != layerTweaker) { + // This drawable was produced on a previous style/bucket, and should not be updated. + return; + } + auto& uniforms = drawable.mutableUniformBuffers(); uniforms.createOrUpdate(idCircleInterpolateUBOName, &interpolateUBO, context); }; @@ -385,29 +379,26 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, const auto interpBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO)); gfx::VertexAttributeArray circleVertexAttrs; - auto propertiesAsUniforms_ = circleVertexAttrs.readDataDrivenPaintProperties( + auto propertiesAsUniforms = circleVertexAttrs.readDataDrivenPaintProperties( paintPropertyBinders, evaluated); if (!circleShaderGroup) { continue; } - const auto circleShader = circleShaderGroup->getOrCreateShader(context, propertiesAsUniforms_); + const auto circleShader = circleShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!circleShader) { continue; } -#if MLN_RENDER_BACKEND_METAL - propertiesAsUniforms = std::move(propertiesAsUniforms_); - if (tweaker) { - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); + if (layerTweaker) { + layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); } -#endif // MLN_RENDER_BACKEND_METAL if (const auto& attr = circleVertexAttrs.add(idVertexAttribName)) { attr->setSharedRawData(bucket.sharedVertices, @@ -434,6 +425,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : circleBuilder->clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); auto& uniforms = drawable->mutableUniformBuffers(); uniforms.addOrReplace(idCircleInterpolateUBOName, interpBuffer); diff --git a/src/mbgl/renderer/layers/render_circle_layer.hpp b/src/mbgl/renderer/layers/render_circle_layer.hpp index 43ed687c3..da8c50dbb 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.hpp +++ b/src/mbgl/renderer/layers/render_circle_layer.hpp @@ -49,10 +49,6 @@ private: void render(PaintParameters&) override; #endif // MLN_LEGACY_RENDERER -#if MLN_DRAWABLE_RENDERER - void updateLayerTweaker(); -#endif // MLN_DRAWABLE_RENDERER - private: // Paint properties style::CirclePaintProperties::Unevaluated unevaluated; @@ -64,13 +60,6 @@ private: #if MLN_DRAWABLE_RENDERER gfx::ShaderGroupPtr circleShaderGroup; - - CircleLayerTweakerPtr tweaker; -#if MLN_RENDER_BACKEND_METAL - std::vector propertiesAsUniforms; -#endif // MLN_RENDER_BACKEND_METAL - - bool overdrawInspector = false; #endif }; diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index d0364ac7b..62b5c477c 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #endif // MLN_DRAWABLE_RENDERER @@ -75,7 +76,8 @@ void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& para #if MLN_DRAWABLE_RENDERER if (layerGroup) { - layerGroup->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); + auto newTweaker = std::make_shared(getID(), evaluatedProperties); + replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup}); } #endif // MLN_DRAWABLE_RENDERER } @@ -275,7 +277,7 @@ bool RenderFillExtrusionLayer::queryIntersectsFeature(const GeometryCoordinates& void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, - const std::shared_ptr&, + const std::shared_ptr& updateParameters, const RenderTree& /*renderTree*/, UniqueChangeRequestVec& changes) { if (!renderTiles || renderTiles->empty() || passes == RenderPass::None) { @@ -286,11 +288,19 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, // Set up a layer group if (!layerGroup) { if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { - layerGroup_->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); setLayerGroup(std::move(layerGroup_), changes); + } else { + return; } } + if (!layerTweaker) { + layerTweaker = std::make_shared(getID(), evaluatedProperties); + layerGroup->addLayerTweaker(layerTweaker); + } + + layerTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw)); + if (!fillExtrusionGroup) { fillExtrusionGroup = shaders.getShaderGroup("FillExtrusionShader"); } @@ -388,6 +398,11 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, 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& uniforms = drawable.mutableUniformBuffers(); uniforms.createOrUpdate( FillExtrusionLayerTweaker::idFillExtrusionTilePropsUBOName, &tilePropsUBO, context); @@ -398,20 +413,25 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, } gfx::VertexAttributeArray vertexAttrs; - const auto uniformProps = vertexAttrs.readDataDrivenPaintProperties(binders, evaluated); + const auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(binders, + evaluated); if (!shaderGroup) { continue; } const auto shader = std::static_pointer_cast( - shaderGroup->getOrCreateShader(context, uniformProps)); + shaderGroup->getOrCreateShader(context, propertiesAsUniforms)); if (!shader) { continue; } + if (layerTweaker) { + layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); + } + // The non-pattern path in `render()` only uses two-pass rendering if there's translucency. // The pattern path always uses two passes. const auto doDepthPass = (!opaque || hasPattern); @@ -492,6 +512,9 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, colorBuilder->setVertexAttributes(std::move(vertexAttrs)); const auto finish = [&](gfx::DrawableBuilder& builder) { + if (!bucket.sharedTriangles->elements()) { + return; + } builder.setSegments(gfx::Triangles(), bucket.sharedTriangles, bucket.triangleSegments.data(), @@ -501,6 +524,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder.clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); auto& uniforms = drawable->mutableUniformBuffers(); uniforms.createOrUpdate( diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index fcba89c00..02176fdb7 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -104,9 +104,9 @@ void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) { #if MLN_DRAWABLE_RENDERER if (layerGroup) { - layerGroup->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); + auto newTweaker = std::make_shared(getID(), evaluatedProperties); + replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup}); } - updateLayerTweaker(); #endif } @@ -308,17 +308,6 @@ bool RenderFillLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeo #if MLN_DRAWABLE_RENDERER -void RenderFillLayer::updateLayerTweaker() { - if (layerGroup) { - tweaker = std::make_shared(getID(), evaluatedProperties); -#if MLN_RENDER_BACKEND_METAL - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); -#endif // MLN_RENDER_BACKEND_METAL - tweaker->enableOverdrawInspector(overdrawInspector); - layerGroup->setLayerTweaker(tweaker); - } -} - void RenderFillLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, @@ -332,24 +321,22 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, return; } - const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw); - if (overdrawInspector != overdraw) { - overdrawInspector = overdraw; - if (tweaker) { - tweaker->enableOverdrawInspector(overdrawInspector); - } - } - // Set up a layer group if (!layerGroup) { if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { - layerGroup_->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); setLayerGroup(std::move(layerGroup_), changes); - updateLayerTweaker(); + } else { + return; } } auto* tileLayerGroup = static_cast(layerGroup.get()); + if (!layerTweaker) { + layerTweaker = std::make_shared(getID(), evaluatedProperties); + layerGroup->addLayerTweaker(layerTweaker); + } + layerTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw)); + if (!fillShaderGroup) { fillShaderGroup = shaders.getShaderGroup(std::string(FillShaderName)); } @@ -373,7 +360,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, std::unique_ptr outlinePatternBuilder; const auto layerPrefix = getID() + "/"; - const auto renderPass = RenderPass::Translucent; + constexpr auto renderPass = RenderPass::Translucent; const auto commonInit = [&](gfx::DrawableBuilder& builder) { builder.setCullFaceMode(gfx::CullFaceMode::disabled()); @@ -383,10 +370,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, stats.drawablesRemoved += tileLayerGroup->removeDrawablesIf([&](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 (tileID && !hasRenderTile(*tileID)) { - return true; - } - return false; + return tileID && !hasRenderTile(*tileID); }); for (const RenderTile& tile : *renderTiles) { @@ -519,10 +503,14 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, // `Fill*Program` all use `style::FillPaintProperties` gfx::VertexAttributeArray vertexAttrs; - const auto propertiesAsUniforms_ = + const auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(binders, evaluated); + if (layerTweaker) { + layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); + } + const auto vertexCount = bucket.vertices.elements(); if (const auto& attr = vertexAttrs.add(idPosAttribName)) { attr->setSharedRawData(bucket.sharedVertices, @@ -534,6 +522,11 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, // If we already have drawables for this tile, update them. auto updateExisting = [&](gfx::Drawable& drawable) { + if (drawable.getLayerTweaker() != layerTweaker) { + // This drawable was produced on a previous style/bucket, and should not be updated. + return; + } + auto& uniforms = drawable.mutableUniformBuffers(); if (uniforms.get(FillLayerTweaker::idFillInterpolateUBOName)) { uniforms.createOrUpdate(FillLayerTweaker::idFillInterpolateUBOName, &getFillInterpolateUBO(), context); @@ -566,19 +559,12 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, continue; } const auto fillShader = std::static_pointer_cast( - fillShaderGroup->getOrCreateShader(context, propertiesAsUniforms_)); + fillShaderGroup->getOrCreateShader(context, propertiesAsUniforms)); const auto outlineShader = doOutline ? std::static_pointer_cast( - outlineShaderGroup->getOrCreateShader(context, propertiesAsUniforms_)) + outlineShaderGroup->getOrCreateShader(context, propertiesAsUniforms)) : nullptr; -#if MLN_RENDER_BACKEND_METAL - propertiesAsUniforms = std::move(propertiesAsUniforms_); - if (tweaker) { - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); - } -#endif // MLN_RENDER_BACKEND_METAL - if (!fillBuilder && fillShader) { if (auto builder = context.createDrawableBuilder(layerPrefix + "fill")) { commonInit(*builder); @@ -610,6 +596,8 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder.clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); + auto& uniforms = drawable->mutableUniformBuffers(); uniforms.createOrUpdate(interpolateUBONameId, &interpolateUBO, context); tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); @@ -653,19 +641,12 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, } const auto fillShader = std::static_pointer_cast( - patternShaderGroup->getOrCreateShader(context, propertiesAsUniforms_)); + patternShaderGroup->getOrCreateShader(context, propertiesAsUniforms)); const auto outlineShader = doOutline ? std::static_pointer_cast( outlinePatternShaderGroup->getOrCreateShader( - context, propertiesAsUniforms_)) + context, propertiesAsUniforms)) : nullptr; -#if MLN_RENDER_BACKEND_METAL - propertiesAsUniforms = std::move(propertiesAsUniforms_); - if (tweaker) { - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); - } -#endif // MLN_RENDER_BACKEND_METAL - if (!patternBuilder) { if (auto builder = context.createDrawableBuilder(layerPrefix + "fill-pattern")) { commonInit(*builder); @@ -708,6 +689,8 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder.clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); + auto& uniforms = drawable->mutableUniformBuffers(); uniforms.createOrUpdate(interpolateNameId, &interpolateUBO, context); uniforms.createOrUpdate(tileUBONameId, &tileUBO, context); diff --git a/src/mbgl/renderer/layers/render_fill_layer.hpp b/src/mbgl/renderer/layers/render_fill_layer.hpp index c077d926f..9ba69f8e3 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.hpp +++ b/src/mbgl/renderer/layers/render_fill_layer.hpp @@ -46,10 +46,6 @@ private: void render(PaintParameters&) override; #endif -#if MLN_DRAWABLE_RENDERER - void updateLayerTweaker(); -#endif // MLN_DRAWABLE_RENDERER - bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, float, @@ -73,13 +69,6 @@ private: gfx::ShaderGroupPtr outlineShaderGroup; gfx::ShaderGroupPtr patternShaderGroup; gfx::ShaderGroupPtr outlinePatternShaderGroup; - - FillLayerTweakerPtr tweaker; -#if MLN_RENDER_BACKEND_METAL - std::vector propertiesAsUniforms; -#endif // MLN_RENDER_BACKEND_METAL - bool overdrawInspector = false; - #endif }; diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index e980da01e..aade91552 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -70,8 +70,17 @@ void RenderHeatmapLayer::evaluate(const PropertyEvaluationParameters& parameters evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - updateLayerTweaker(); - updateLayerTextureTweaker(); + if (layerGroup) { + auto newTextureTweaker = std::make_shared(getID(), evaluatedProperties); + replaceTweaker(textureTweaker, std::move(newTextureTweaker), {layerGroup}); + } + + if (renderTarget) { + if (auto tileLayerGroup = renderTarget->getLayerGroup(0)) { + auto newTweaker = std::make_shared(getID(), evaluatedProperties); + replaceTweaker(layerTweaker, std::move(newTweaker), {std::move(tileLayerGroup)}); + } + } #endif } @@ -247,17 +256,24 @@ void RenderHeatmapLayer::markLayerRenderable(bool willRender, UniqueChangeReques activateRenderTarget(renderTarget, willRender, changes); } -void RenderHeatmapLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { - auto* tileLayerGroup = static_cast(renderTarget->getLayerGroup(0).get()); - stats.drawablesRemoved += tileLayerGroup->removeDrawables(renderPass, tileID).size(); +std::size_t RenderHeatmapLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { + if (auto* tileLayerGroup = static_cast(renderTarget->getLayerGroup(0).get())) { + const auto count = tileLayerGroup->removeDrawables(renderPass, tileID).size(); + stats.drawablesRemoved += count; + return count; + } + return 0; } -void RenderHeatmapLayer::removeAllDrawables() { - RenderLayer::removeAllDrawables(); +std::size_t RenderHeatmapLayer::removeAllDrawables() { + auto removed = RenderLayer::removeAllDrawables(); if (renderTarget) { - stats.drawablesRemoved += renderTarget->getLayerGroup(0)->getDrawableCount(); + const auto count = renderTarget->getLayerGroup(0)->getDrawableCount(); + removed += count; + stats.drawablesRemoved += count; renderTarget->getLayerGroup(0)->clearDrawables(); } + return removed; } namespace { @@ -273,27 +289,6 @@ static const StringIdentity idTexColorRampName = StringIndexer::get("u_color_ram using namespace shaders; -#if MLN_DRAWABLE_RENDERER -void RenderHeatmapLayer::updateLayerTweaker() { - if (renderTarget) { - tweaker = std::make_shared(getID(), evaluatedProperties); -#if MLN_RENDER_BACKEND_METAL - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); -#endif // MLN_RENDER_BACKEND_METAL - tweaker->enableOverdrawInspector(overdrawInspector); - renderTarget->getLayerGroup(0)->setLayerTweaker(tweaker); - } -} - -void RenderHeatmapLayer::updateLayerTextureTweaker() { - if (layerGroup) { - textureTweaker = std::make_shared(getID(), evaluatedProperties); - textureTweaker->enableOverdrawInspector(overdrawInspector); - layerGroup->setLayerTweaker(textureTweaker); - } -} -#endif // MLN_DRAWABLE_RENDERER - void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, @@ -324,7 +319,7 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, return; } renderTarget->addLayerGroup(tileLayerGroup, /*replace=*/true); - updateLayerTweaker(); + textureTweaker.reset(); } if (renderTarget->getTexture()->getSize() != size) { @@ -341,14 +336,11 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, return; } - const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw); - if (overdrawInspector != overdraw) { - overdrawInspector = overdraw; - if (tweaker) { - tweaker->enableOverdrawInspector(overdrawInspector); - textureTweaker->enableOverdrawInspector(overdrawInspector); - } + if (!layerTweaker) { + layerTweaker = std::make_shared(getID(), evaluatedProperties); + tileLayerGroup->addLayerTweaker(layerTweaker); } + layerTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw)); std::unique_ptr heatmapBuilder; constexpr auto renderPass = RenderPass::Translucent; @@ -383,40 +375,52 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, setRenderTileBucketID(tileID, bucket.getID()); const float zoom = static_cast(state.getZoom()); - const HeatmapInterpolateUBO interpolateUBO = { - /* .weight_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /* .radius_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /* .padding = */ {0}}; - tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { - drawable.mutableUniformBuffers().createOrUpdate(idHeatmapInterpolateUBOName, &interpolateUBO, context); - }); - - if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) { - continue; - } + gfx::UniformBufferPtr interpolateBuffer; + const auto getInterpolateBuffer = [&]() { + if (!interpolateBuffer) { + const HeatmapInterpolateUBO interpolateUBO = { + /* .weight_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .radius_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .padding = */ {0}}; + interpolateBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO)); + } + return interpolateBuffer; + }; gfx::VertexAttributeArray heatmapVertexAttrs; - - const auto propertiesAsUniforms_ = + const auto propertiesAsUniforms = heatmapVertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, evaluated); + if (layerTweaker) { + layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); + } - if (!heatmapShaderGroup) { + const auto updatedCount = tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + if (drawable.getLayerTweaker() != layerTweaker) { + // This drawable was produced on a previous style/bucket, and should not be updated. + return; + } + + // We assume vertex attributes don't change, and so don't update them to avoid re-uploading + // drawable.setVertexAttributes(heatmapVertexAttrs); + + auto& uniforms = drawable.mutableUniformBuffers(); + + if (auto buffer = getInterpolateBuffer()) { + uniforms.addOrReplace(idHeatmapInterpolateUBOName, std::move(buffer)); + } + }); + + if (updatedCount > 0) { continue; } - const auto heatmapShader = heatmapShaderGroup->getOrCreateShader(context, propertiesAsUniforms_); + + const auto heatmapShader = heatmapShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!heatmapShader) { continue; } -#if MLN_RENDER_BACKEND_METAL - propertiesAsUniforms = std::move(propertiesAsUniforms_); - if (tweaker) { - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); - } -#endif // MLN_RENDER_BACKEND_METAL - if (const auto& attr = heatmapVertexAttrs.add(idVertexAttribName)) { attr->setSharedRawData(bucket.sharedVertices, offsetof(HeatmapLayoutVertex, a1), @@ -441,7 +445,13 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : heatmapBuilder->clearDrawables()) { drawable->setTileID(tileID); - drawable->mutableUniformBuffers().createOrUpdate(idHeatmapInterpolateUBOName, &interpolateUBO, context); + drawable->setLayerTweaker(layerTweaker); + + auto& uniforms = drawable->mutableUniformBuffers(); + + if (auto buffer = getInterpolateBuffer()) { + uniforms.addOrReplace(idHeatmapInterpolateUBOName, std::move(buffer)); + } tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); ++stats.drawablesAdded; @@ -450,13 +460,20 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, // Set up texture layer group if (!layerGroup) { - auto layerGroup_ = context.createLayerGroup(layerIndex, /*initialCapacity=*/1, getID()); - if (!layerGroup_) { + if (auto layerGroup_ = context.createLayerGroup(layerIndex, /*initialCapacity=*/1, getID())) { + if (textureTweaker) { + layerGroup_->addLayerTweaker(textureTweaker); + } + setLayerGroup(std::move(layerGroup_), changes); + } else { return; } - setLayerGroup(std::move(layerGroup_), changes); - updateLayerTextureTweaker(); } + if (!textureTweaker) { + textureTweaker = std::make_shared(getID(), evaluatedProperties); + layerGroup->addLayerTweaker(textureTweaker); + } + textureTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw)); if (!heatmapTextureShader) { heatmapTextureShader = context.getGenericShader(shaders, HeatmapTextureShaderGroupName); @@ -467,6 +484,7 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, } auto* textureLayerGroup = static_cast(layerGroup.get()); + // TODO: Don't rebuild drawables every time textureLayerGroup->clearDrawables(); std::unique_ptr heatmapTextureBuilder; @@ -516,6 +534,7 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, heatmapTextureBuilder->flush(); for (auto& drawable : heatmapTextureBuilder->clearDrawables()) { + drawable->setLayerTweaker(textureTweaker); textureLayerGroup->addDrawable(std::move(drawable)); ++stats.drawablesAdded; } diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.hpp b/src/mbgl/renderer/layers/render_heatmap_layer.hpp index 4d259fc06..d5c499f11 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.hpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.hpp @@ -47,11 +47,6 @@ private: void render(PaintParameters&) override; #endif -#if MLN_DRAWABLE_RENDERER - void updateLayerTweaker(); - void updateLayerTextureTweaker(); -#endif // MLN_DRAWABLE_RENDERER - bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, float, @@ -63,10 +58,12 @@ private: #if MLN_DRAWABLE_RENDERER /// Remove all drawables for the tile from the layer group - void removeTile(RenderPass, const OverscaledTileID&) override; + /// @return The number of drawables actually removed. + std::size_t removeTile(RenderPass, const OverscaledTileID&) override; /// Remove all the drawables for tiles - void removeAllDrawables() override; + /// @return The number of drawables actually removed. + std::size_t removeAllDrawables() override; #endif // Paint properties @@ -90,13 +87,9 @@ private: using TextureVertexVector = gfx::VertexVector; std::shared_ptr sharedTextureVertices; - HeatmapLayerTweakerPtr tweaker; - HeatmapTextureLayerTweakerPtr textureTweaker; -#if MLN_RENDER_BACKEND_METAL - std::vector propertiesAsUniforms; -#endif // MLN_RENDER_BACKEND_METAL - - bool overdrawInspector = false; + // This is the layer tweaker for applying the off-screen texture to the framebuffer. + // The inherited layer tweaker is for applying tiles to the off-screen texture. + LayerTweakerPtr textureTweaker; #endif }; diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index 04297439c..6a1bcc196 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -73,7 +73,26 @@ void RenderHillshadeLayer::evaluate(const PropertyEvaluationParameters& paramete properties->renderPasses = mbgl::underlying_type(passes); evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - updateLayerTweaker(); + if (layerGroup) { + auto newTweaker = std::make_shared(getID(), evaluatedProperties); + replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup}); + } + + if (!activatedRenderTargets.empty()) { + auto newTweaker2 = std::make_shared(getID(), evaluatedProperties); + + std::vector groups; + for (const auto& target : activatedRenderTargets) { + if (const auto& group = target->getLayerGroup(0)) { + groups.push_back(group); + } + } + if (groups.empty()) { + prepareLayerTweaker = newTweaker2; + } else { + replaceTweaker(prepareLayerTweaker, std::move(newTweaker2), groups); + } + } #endif } @@ -284,16 +303,6 @@ static const StringIdentity idPosAttribName = StringIndexer::get("a_pos"); static const StringIdentity idTexturePosAttribName = StringIndexer::get("a_texture_pos"); static const StringIdentity idTexImageName = StringIndexer::get("u_image"); -#if MLN_DRAWABLE_RENDERER -void RenderHillshadeLayer::updateLayerTweaker() { - if (layerGroup) { - tweaker = std::make_shared(getID(), evaluatedProperties); - tweaker->enableOverdrawInspector(overdrawInspector); - layerGroup->setLayerTweaker(tweaker); - } -} -#endif // MLN_DRAWABLE_RENDERER - void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, [[maybe_unused]] const TransformState& state, @@ -309,16 +318,21 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, // Set up a layer group if (!layerGroup) { - auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID()); - if (!layerGroup_) { + if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { + setLayerGroup(std::move(layerGroup_), changes); + } else { return; } - setLayerGroup(std::move(layerGroup_), changes); - updateLayerTweaker(); } auto* tileLayerGroup = static_cast(layerGroup.get()); + if (!layerTweaker) { + layerTweaker = std::make_shared(getID(), evaluatedProperties); + layerGroup->addLayerTweaker(layerTweaker); + } + layerTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw)); + if (!hillshadePrepareShader) { hillshadePrepareShader = context.getGenericShader(shaders, HillshadePrepareShaderGroupName); } @@ -330,12 +344,8 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, return; } - const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw); - if (overdrawInspector != overdraw) { - overdrawInspector = overdraw; - if (tweaker) { - tweaker->enableOverdrawInspector(overdrawInspector); - } + if (!hillshadeImageLocation) { + hillshadeImageLocation = hillshadeShader->getSamplerLocation(idTexImageName); } auto renderPass = RenderPass::Translucent; @@ -389,11 +399,13 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, if (!singleTileLayerGroup) { return; } - const auto prepareTweaker = std::make_shared(getID(), evaluatedProperties); - prepareTweaker->enableOverdrawInspector(overdrawInspector); - singleTileLayerGroup->setLayerTweaker(prepareTweaker); renderTarget->addLayerGroup(singleTileLayerGroup, /*replace=*/true); + if (!prepareLayerTweaker) { + prepareLayerTweaker = std::make_shared(getID(), evaluatedProperties); + } + singleTileLayerGroup->addLayerTweaker(prepareLayerTweaker); + gfx::VertexAttributeArray hillshadePrepareVertexAttrs; if (const auto& attr = hillshadePrepareVertexAttrs.add(idPosAttribName)) { @@ -437,6 +449,7 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : hillshadePrepareBuilder->clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(prepareLayerTweaker); drawable->setData(std::make_unique( bucket.getDEMData().stride, bucket.getDEMData().encoding, maxzoom)); singleTileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); @@ -474,31 +487,38 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, hillshadeBuilder = context.createDrawableBuilder("hillshade"); - if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) { - tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { - drawable.setVertexAttributes(std::move(hillshadeVertexAttrs)); - drawable.setVertices({}, vertices->elements(), gfx::AttributeDataType::Short2); + 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; + } - std::vector> drawSegments; - for (std::size_t i = 0; i < segments->size(); ++i) { - const auto& seg = segments->data()[i]; - auto segCopy = SegmentBase{ - // no copy constructor - seg.vertexOffset, - seg.indexOffset, - seg.vertexLength, - seg.indexLength, - seg.sortKey, - }; - drawSegments.emplace_back(hillshadeBuilder->createSegment(gfx::Triangles(), std::move(segCopy))); - } - drawable.setIndexData(indices->vector(), std::move(drawSegments)); + drawable.setVertexAttributes(std::move(hillshadeVertexAttrs)); + drawable.setVertices({}, vertices->elements(), gfx::AttributeDataType::Short2); - auto imageLocation = hillshadeShader->getSamplerLocation(idTexImageName); - if (imageLocation.has_value()) { - drawable.setTexture(bucket.renderTarget->getTexture(), imageLocation.value()); - } - }); + // Rebuild segments, since they're not shared. + std::vector> drawSegments; + drawSegments.reserve(segments->size()); + for (std::size_t i = 0; i < segments->size(); ++i) { + const auto& seg = segments->data()[i]; + auto segCopy = SegmentBase{ + // no copy constructor + seg.vertexOffset, + seg.indexOffset, + seg.vertexLength, + seg.indexLength, + seg.sortKey, + }; + drawSegments.emplace_back(hillshadeBuilder->createSegment(gfx::Triangles(), std::move(segCopy))); + } + drawable.setIndexData(indices->vector(), std::move(drawSegments)); + + if (hillshadeImageLocation) { + drawable.setTexture(bucket.renderTarget->getTexture(), *hillshadeImageLocation); + } + }; + if (0 < tileLayerGroup->visitDrawables(renderPass, tileID, std::move(updateExisting))) { continue; } @@ -512,15 +532,16 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders, hillshadeBuilder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2); hillshadeBuilder->setSegments(gfx::Triangles(), indices->vector(), segments->data(), segments->size()); - auto imageLocation = hillshadeShader->getSamplerLocation(idTexImageName); - if (imageLocation.has_value()) { - hillshadeBuilder->setTexture(bucket.renderTarget->getTexture(), imageLocation.value()); + if (hillshadeImageLocation) { + hillshadeBuilder->setTexture(bucket.renderTarget->getTexture(), *hillshadeImageLocation); } hillshadeBuilder->flush(); for (auto& drawable : hillshadeBuilder->clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); ++stats.drawablesAdded; } diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.hpp b/src/mbgl/renderer/layers/render_hillshade_layer.hpp index 050ce023a..0c7faadba 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.hpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.hpp @@ -70,13 +70,13 @@ private: #if MLN_DRAWABLE_RENDERER gfx::ShaderProgramBasePtr hillshadePrepareShader; gfx::ShaderProgramBasePtr hillshadeShader; + std::optional hillshadeImageLocation; std::vector activatedRenderTargets; using HillshadeVertexVector = gfx::VertexVector; std::shared_ptr staticDataSharedVertices; - HillshadeLayerTweakerPtr tweaker; - bool overdrawInspector = false; + LayerTweakerPtr prepareLayerTweaker; #endif }; diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 2f79b0f76..9f0760312 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -21,16 +21,6 @@ #include #include -#if MLN_DRAWABLE_RENDERER -#include -#include -#include -#include -#include -#include -#include -#endif - #if MLN_DRAWABLE_RENDERER #include #include @@ -40,6 +30,7 @@ #include #include #include +#include #endif namespace mbgl { @@ -90,7 +81,10 @@ void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) { evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - updateLayerTweaker(); + if (layerGroup) { + auto newTweaker = std::make_shared(getID(), evaluatedProperties); + replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup}); + } #endif } @@ -364,16 +358,6 @@ static const StringIdentity idLineSDFInterpolationUBOName = StringIndexer::get(" /// Evaluated properties that depend on the tile static const StringIdentity idLinePatternTilePropertiesUBOName = StringIndexer::get("LinePatternTilePropertiesUBO"); -void RenderLineLayer::updateLayerTweaker() { - if (layerGroup) { - tweaker = std::make_shared(getID(), evaluatedProperties); -#if MLN_RENDER_BACKEND_METAL - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); -#endif // MLN_RENDER_BACKEND_METAL - tweaker->enableOverdrawInspector(overdrawInspector); - layerGroup->setLayerTweaker(tweaker); - } -} static const StringIdentity idLineImageUniformName = StringIndexer::get("u_image"); @@ -390,23 +374,22 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, return; } - const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw); - if (overdrawInspector != overdraw) { - overdrawInspector = overdraw; - if (tweaker) { - tweaker->enableOverdrawInspector(overdrawInspector); - } - } - // Set up a layer group if (!layerGroup) { if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { setLayerGroup(std::move(layerGroup_), changes); - updateLayerTweaker(); + } else { + return; } } auto* tileLayerGroup = static_cast(layerGroup.get()); + if (!layerTweaker) { + layerTweaker = std::make_shared(getID(), evaluatedProperties); + layerGroup->addLayerTweaker(layerTweaker); + } + layerTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw)); + if (!lineShaderGroup) { lineShaderGroup = shaders.getShaderGroup("LineShader"); } @@ -486,6 +469,11 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, } auto& bucket = static_cast(*renderData->bucket); + if (!bucket.sharedTriangles->elements()) { + removeTile(renderPass, tileID); + continue; + } + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); const auto& evaluated = getEvaluated(renderData->layerProperties); const auto& crossfade = getCrossfade(renderData->layerProperties); @@ -546,6 +534,11 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, // update existing drawables tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + if (drawable.getLayerTweaker() != layerTweaker) { + // This drawable was produced on a previous style/bucket, and should not be updated. + return; + } + const auto& shader = drawable.getShader(); const auto& shaderUniforms = shader->getUniformBlocks(); auto& drawableUniforms = drawable.mutableUniformBuffers(); @@ -581,29 +574,26 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, if (!evaluated.get().from.empty()) { // dash array line (SDF) gfx::VertexAttributeArray vertexAttrs; - auto propertiesAsUniforms_ = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, - evaluated); + auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, + evaluated); if (!lineSDFShaderGroup) { continue; } - auto shader = lineSDFShaderGroup->getOrCreateShader(context, propertiesAsUniforms_); + auto shader = lineSDFShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!shader) { continue; } -#if MLN_RENDER_BACKEND_METAL - propertiesAsUniforms = std::move(propertiesAsUniforms_); - if (tweaker) { - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); + if (layerTweaker) { + layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); } -#endif // MLN_RENDER_BACKEND_METAL auto builder = createLineBuilder("lineSDF", std::move(shader)); @@ -618,6 +608,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder->clearDrawables()) { drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::SDF)); drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); drawable->setData(std::make_unique(cap)); drawable->mutableUniformBuffers().createOrUpdate( idLineSDFInterpolationUBOName, &lineSDFInterpolationUBO, context); @@ -629,28 +620,25 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, // pattern line gfx::VertexAttributeArray vertexAttrs; paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade); - auto propertiesAsUniforms_ = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, - evaluated); + auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, + evaluated); if (!linePatternShaderGroup) { continue; } - auto shader = linePatternShaderGroup->getOrCreateShader(context, propertiesAsUniforms_); + auto shader = linePatternShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!shader) { continue; } -#if MLN_RENDER_BACKEND_METAL - propertiesAsUniforms = std::move(propertiesAsUniforms_); - if (tweaker) { - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); + if (layerTweaker) { + layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); } -#endif // MLN_RENDER_BACKEND_METAL auto builder = createLineBuilder("linePattern", std::move(shader)); @@ -679,6 +667,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder->clearDrawables()) { drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Pattern)); drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); drawable->mutableUniformBuffers().createOrUpdate( idLinePatternInterpolationUBOName, &linePatternInterpolationUBO, context); drawable->mutableUniformBuffers().createOrUpdate( @@ -691,24 +680,21 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, } else if (!unevaluated.get().getValue().isUndefined()) { // gradient line gfx::VertexAttributeArray vertexAttrs; - auto propertiesAsUniforms_ = + auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties( paintPropertyBinders, evaluated); if (!lineGradientShaderGroup) { continue; } - auto shader = lineGradientShaderGroup->getOrCreateShader(context, propertiesAsUniforms_); + auto shader = lineGradientShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!shader) { continue; } -#if MLN_RENDER_BACKEND_METAL - propertiesAsUniforms = std::move(propertiesAsUniforms_); - if (tweaker) { - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); + if (layerTweaker) { + layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); } -#endif // MLN_RENDER_BACKEND_METAL auto builder = createLineBuilder("lineGradient", std::move(shader)); @@ -736,6 +722,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder->clearDrawables()) { drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Gradient)); drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); drawable->mutableUniformBuffers().createOrUpdate( idLineGradientInterpolationUBOName, &lineGradientInterpolationUBO, context); @@ -748,33 +735,30 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, } else { // simple line gfx::VertexAttributeArray vertexAttrs; - const auto propertiesAsUniforms_ = vertexAttrs.readDataDrivenPaintProperties( - paintPropertyBinders, evaluated); + const auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, + evaluated); - assert(6 == propertiesAsUniforms_.size()); - assert(vertexAttrs.size() == (size_t)std::count_if(propertiesAsUniforms_.begin(), - propertiesAsUniforms_.end(), + assert(6 == propertiesAsUniforms.size()); + assert(vertexAttrs.size() == (size_t)std::count_if(propertiesAsUniforms.begin(), + propertiesAsUniforms.end(), [](const auto& s) { return s.empty(); })); if (!lineShaderGroup) { continue; } - auto shader = lineShaderGroup->getOrCreateShader(context, propertiesAsUniforms_); + auto shader = lineShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!shader) { continue; } -#if MLN_RENDER_BACKEND_METAL - propertiesAsUniforms = std::move(propertiesAsUniforms_); - if (tweaker) { - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); + if (layerTweaker) { + layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); } -#endif // MLN_RENDER_BACKEND_METAL auto builder = createLineBuilder("line", std::move(shader)); @@ -787,6 +771,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder->clearDrawables()) { drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Simple)); drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); drawable->mutableUniformBuffers().createOrUpdate( idLineInterpolationUBOName, &lineInterpolationUBO, context); diff --git a/src/mbgl/renderer/layers/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp index 78424ff52..7b147bdc1 100644 --- a/src/mbgl/renderer/layers/render_line_layer.hpp +++ b/src/mbgl/renderer/layers/render_line_layer.hpp @@ -58,9 +58,6 @@ private: #if MLN_LEGACY_RENDERER void render(PaintParameters&) override; #endif -#if MLN_DRAWABLE_RENDERER - void updateLayerTweaker(); -#endif bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, @@ -97,13 +94,6 @@ private: gfx::ShaderGroupPtr linePatternShaderGroup; gfx::DrawableTweakerPtr iconTweaker; - LineLayerTweakerPtr tweaker; - -#if MLN_RENDER_BACKEND_METAL - std::vector propertiesAsUniforms; -#endif // MLN_RENDER_BACKEND_METAL - - bool overdrawInspector = false; #endif }; diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index a3022b59c..3f568b6a8 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #if MLN_DRAWABLE_RENDERER #include @@ -53,7 +54,10 @@ void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters) evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - updateLayerTweaker(); + if (layerGroup) { + auto newTweaker = std::make_shared(getID(), evaluatedProperties); + replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup, imageLayerGroup}); + } #endif } @@ -247,19 +251,6 @@ static const StringIdentity idTexturePosAttribName = StringIndexer::get("a_textu static const StringIdentity idTexImage0Name = StringIndexer::get("u_image0"); static const StringIdentity idTexImage1Name = StringIndexer::get("u_image1"); -void RenderRasterLayer::updateLayerTweaker() { - if (layerGroup || imageLayerGroup) { - tweaker = std::make_shared(getID(), evaluatedProperties); - tweaker->enableOverdrawInspector(overdrawInspector); - if (layerGroup) { - layerGroup->setLayerTweaker(tweaker); - } - if (imageLayerGroup) { - imageLayerGroup->setLayerTweaker(tweaker); - } - } -} - void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& /*state*/, @@ -278,22 +269,28 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, return; } - auto renderPass = RenderPass::Translucent; + constexpr auto renderPass = RenderPass::Translucent; if (!rasterShader) { rasterShader = context.getGenericShader(shaders, "RasterShader"); if (!rasterShader) { return; } + rasterSampler0 = rasterShader->getSamplerLocation(idTexImage0Name); + rasterSampler1 = rasterShader->getSamplerLocation(idTexImage1Name); } - const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw); - if (overdrawInspector != overdraw) { - overdrawInspector = overdraw; - if (tweaker) { - tweaker->enableOverdrawInspector(overdrawInspector); + if (!layerTweaker) { + layerTweaker = std::make_shared(getID(), evaluatedProperties); + + if (layerGroup) { + layerGroup->addLayerTweaker(layerTweaker); + } + if (imageLayerGroup) { + imageLayerGroup->addLayerTweaker(layerTweaker); } } + layerTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw)); if (!staticDataVertices) { staticDataVertices = std::make_shared(RenderStaticData::rasterVertices()); @@ -305,61 +302,65 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, staticDataSegments = std::make_shared(RenderStaticData::rasterSegments()); } - const auto& evaluated = static_cast(*evaluatedProperties).evaluated; - RasterProgram::Binders paintAttributeData{evaluated, 0}; - - const gfx::TextureFilterType filter = evaluated.get() == RasterResamplingType::Nearest - ? gfx::TextureFilterType::Nearest - : gfx::TextureFilterType::Linear; - - auto createBuilder = [&context, &renderPass, this]() -> std::unique_ptr { - std::unique_ptr builder{context.createDrawableBuilder("raster")}; + const auto createBuilder = [&] { + auto builder = context.createDrawableBuilder("raster"); builder->setShader(rasterShader); builder->setRenderPass(renderPass); builder->setSubLayerIndex(0); - builder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite - : gfx::DepthMaskType::ReadOnly); + builder->setDepthType(gfx::DepthMaskType::ReadOnly); builder->setColorMode(gfx::ColorMode::alphaBlended()); builder->setCullFaceMode(gfx::CullFaceMode::disabled()); builder->setVertexAttrNameId(idPosAttribName); - return builder; }; - auto setTextures = [&context, &filter, this](std::unique_ptr& builder, - const RasterBucket& bucket) { - // textures - auto location0 = rasterShader->getSamplerLocation(idTexImage0Name); - if (location0.has_value()) { - std::shared_ptr tex0 = context.createTexture2D(); - tex0->setImage(bucket.image); - tex0->setSamplerConfiguration({filter, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); - builder->setTexture(tex0, location0.value()); - } - auto location1 = rasterShader->getSamplerLocation(idTexImage1Name); - if (location1.has_value()) { - std::shared_ptr tex1 = context.createTexture2D(); - tex1->setImage(bucket.image); - tex1->setSamplerConfiguration({filter, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); - builder->setTexture(tex1, location1.value()); + const auto setTextures = [&](gfx::UniqueDrawableBuilder& builder, RasterBucket& bucket) { + if (bucket.image && (rasterSampler0 || rasterSampler1)) { + if (!bucket.texture2d) { + if (auto tex = context.createTexture2D()) { + tex->setImage(bucket.image); + bucket.texture2d = std::move(tex); + } + } + + if (bucket.texture2d) { + const auto& evaluated = static_cast(*evaluatedProperties).evaluated; + const bool nearest = evaluated.get() == RasterResamplingType::Nearest; + const auto filter = nearest ? gfx::TextureFilterType::Nearest : gfx::TextureFilterType::Linear; + + bucket.texture2d->setSamplerConfiguration( + {filter, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); + + if (rasterSampler0) { + builder->setTexture(bucket.texture2d, *rasterSampler0); + } + if (rasterSampler1) { + builder->setTexture(bucket.texture2d, *rasterSampler1); + } + } } }; - auto buildVertexData = [this](std::unique_ptr& builder, const RasterBucket& bucket) { - RasterVertexVectorPtr vertices = staticDataVertices; - TriangleIndexVectorPtr indices = staticDataIndices; - const RasterSegmentVector* segments = staticDataSegments.get(); + // Build vertex attributes and apply them to a drawable or a builder. + // Populates a drawable xor a drawable builder for creates and updates, respectively. + // Returns false if the drawable must be re-created. + const auto buildVertexData = + [this](const gfx::UniqueDrawableBuilder& builder, gfx::Drawable* drawable, const RasterBucket& bucket) { + // The bucket only fills in geometry for masked tiles, + // otherwise the standard tile extent geometry should be used. + const bool shared = (!bucket.sharedVertices->empty() && !bucket.sharedTriangles->empty() && + !bucket.segments.empty()); + const auto& vertices = shared ? bucket.sharedVertices : staticDataVertices; + const auto& indices = shared ? bucket.sharedTriangles : staticDataIndices; + const auto* segments = shared ? &bucket.segments : staticDataSegments.get(); - if (!bucket.vertices.empty() && !bucket.indices.empty() && !bucket.segments.empty()) { - vertices = bucket.sharedVertices; - indices = bucket.sharedTriangles; - segments = &bucket.segments; - } + // The bucket may later add, remove, or change masking. In that case, the tile's + // shared data and segments are not updated, and it needs to be re-created. + if (drawable && (bucket.sharedVertices->getDirty() || bucket.sharedTriangles->getDirty())) { + return false; + } - // attributes - { gfx::VertexAttributeArray vertexAttrs; - if (auto& attr = vertexAttrs.add(idPosAttribName)) { attr->setSharedRawData(vertices, offsetof(RasterLayoutVertex, a1), @@ -376,109 +377,128 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, gfx::AttributeDataType::Short2); } - builder->setVertexAttributes(std::move(vertexAttrs)); + assert(!!drawable ^ !!builder); + if (drawable) { + drawable->setVertexAttributes(std::move(vertexAttrs)); + } else if (builder) { + builder->setVertexAttributes(std::move(vertexAttrs)); + builder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2); + builder->setSegments(gfx::Triangles(), indices, segments->data(), segments->size()); + } + return true; + }; + + gfx::UniqueDrawableBuilder builder; + if (imageData) { + // TODO: Can we avoid rebuilding drawables each time in this case as well? + if (imageLayerGroup) { + stats.drawablesRemoved += imageLayerGroup->clearDrawables(); } - builder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2); - builder->setSegments(gfx::Triangles(), indices, segments->data(), segments->size()); - }; - - auto buildDrawables = [&setTextures, &buildVertexData](std::unique_ptr& builder, - const RasterBucket& bucket) { - buildVertexData(builder, bucket); - setTextures(builder, bucket); - }; - - auto updateTileDrawables = [&](std::unique_ptr& builder, - auto* tileLayerGroup, - const auto& tileID, - const RasterBucket& bucket) { - // TODO: check for oportunity to skip - - buildVertexData(builder, bucket); - tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { - for (auto& tex : drawable.getTextures()) { - builder->setTexture(tex.second, tex.first); - } - }); - }; - - if (imageData) { RasterBucket& bucket = *imageData->bucket; if (!bucket.vertices.empty()) { - if (imageLayerGroup) { - stats.drawablesRemoved += imageLayerGroup->clearDrawables(); - } else { + if (!imageLayerGroup) { // Set up a layer group imageLayerGroup = context.createLayerGroup(layerIndex, /*initialCapacity=*/64, getID()); + imageLayerGroup->addLayerTweaker(layerTweaker); activateLayerGroup(imageLayerGroup, isRenderable, changes); - updateLayerTweaker(); } - auto builder = createBuilder(); + // Create a drawable for each transformation + // TODO: Share textures + builder = createBuilder(); for (const auto& matrix_ : imageData->matrices) { - buildDrawables(builder, bucket); + buildVertexData(builder, /*drawable=*/nullptr, bucket); + setTextures(builder, bucket); // finish builder->flush(); for (auto& drawable : builder->clearDrawables()) { drawable->setData(std::make_unique(matrix_)); + drawable->setLayerTweaker(layerTweaker); imageLayerGroup->addDrawable(std::move(drawable)); ++stats.drawablesAdded; } } } } else if (renderTiles) { + // Remove existing drawables that are no longer in the cover set if (layerGroup) { - stats.drawablesRemoved += layerGroup->removeDrawablesIf([&](gfx::Drawable& drawable) { - // Has this tile dropped out of the cover set? - return drawable.getTileID() && !hasRenderTile(*drawable.getTileID()); - }); + stats.drawablesRemoved += layerGroup->removeDrawablesIf( + [&](gfx::Drawable& drawable) { return drawable.getTileID() && !hasRenderTile(*drawable.getTileID()); }); } else { // Set up a tile layer group if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { + layerGroup_->addLayerTweaker(layerTweaker); setLayerGroup(std::move(layerGroup_), changes); - updateLayerTweaker(); } } auto* tileLayerGroup = static_cast(layerGroup.get()); - auto builder = createBuilder(); for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); - const auto* bucket_ = tile.getBucket(*baseImpl); + auto* bucket_ = tile.getBucket(*baseImpl); if (!bucket_ || !bucket_->hasData()) { removeTile(renderPass, tileID); continue; } - const auto& bucket = static_cast(*bucket_); + bool cleared = false; + 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. + // If the bucket data has changed, rebuild the drawables. + const bool bucketSharedData = (!bucket.vertices.empty() && !bucket.indices.empty() && + !bucket.segments.empty()); + const bool bucketDirty = bucketSharedData && (bucket.vertices.getDirty() || bucket.indices.getDirty()); + if (bucketDirty) { + // Note, vertex/index dirty flags will be reset when those buffers are uploaded. removeTile(renderPass, tileID); + cleared = true; + } else if (setRenderTileBucketID(tileID, bucket.getID())) { + // Bucket ID changed, we need to rebuild the drawables + removeTile(renderPass, tileID); + cleared = true; } - setRenderTileBucketID(tileID, bucket.getID()); - if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) { - // re-create drawable geometry and pass texture - updateTileDrawables(builder, tileLayerGroup, tileID, bucket); + if (!cleared) { + // Update existing drawables + bool geometryChanged = false; + const auto updated = tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + gfx::UniqueDrawableBuilder none; + if (!geometryChanged && !buildVertexData(none, &drawable, bucket)) { + // Masking changed, need to rebuild this tile + geometryChanged = true; + } + }); - // erase current drawable - removeTile(renderPass, tileID); - } else if (bucket.image) { - // build new drawable for this tile - buildDrawables(builder, bucket); + if (geometryChanged) { + removeTile(renderPass, tileID); + cleared = true; + } else if (0 < updated) { + // If we modified drawables without removing them, we're done with this tile. + continue; + } + } + + // Otherwise, create new ones. + if (!builder) { + builder = createBuilder(); + } + + if (bucket.image && builder->getTextures().size() == 0) { + setTextures(builder, bucket); }; + buildVertexData(builder, /*drawable=*/nullptr, bucket); + // finish builder->flush(); for (auto& drawable : builder->clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); ++stats.drawablesAdded; } diff --git a/src/mbgl/renderer/layers/render_raster_layer.hpp b/src/mbgl/renderer/layers/render_raster_layer.hpp index 849a3dbc1..361392d82 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.hpp +++ b/src/mbgl/renderer/layers/render_raster_layer.hpp @@ -8,11 +8,6 @@ namespace mbgl { -#if MLN_DRAWABLE_RENDERER -class RasterLayerTweaker; -using RasterLayerTweakerPtr = std::shared_ptr; -#endif // MLN_DRAWABLE_RENDERER - class ImageSourceRenderData; class RasterProgram; @@ -60,10 +55,6 @@ private: void render(PaintParameters&) override; #endif -#if MLN_DRAWABLE_RENDERER - void updateLayerTweaker(); -#endif // MLN_DRAWABLE_RENDERER - // Paint properties style::RasterPaintProperties::Unevaluated unevaluated; const ImageSourceRenderData* imageData = nullptr; @@ -75,6 +66,8 @@ private: #if MLN_DRAWABLE_RENDERER gfx::ShaderProgramBasePtr rasterShader; + std::optional rasterSampler0; + std::optional rasterSampler1; LayerGroupPtr imageLayerGroup; using RasterVertexVector = gfx::VertexVector; @@ -88,9 +81,6 @@ private: using RasterSegmentVector = SegmentVector; using RasterSegmentVectorPtr = std::shared_ptr; std::shared_ptr staticDataSegments; - - RasterLayerTweakerPtr tweaker; - bool overdrawInspector = false; #endif }; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 3a06160ef..f32d91a31 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -379,11 +380,10 @@ void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - if (layerGroup && layerGroup->getLayerTweaker()) { -#if MLN_RENDER_BACKEND_METAL - layerGroup->getLayerTweaker()->setPropertiesAsUniforms(propertiesAsUniforms); -#endif // MLN_RENDER_BACKEND_METAL - layerGroup->getLayerTweaker()->updateProperties(evaluatedProperties); + // The symbol tweaker supports updating properties. + // When the style changes, it will be replaced in `RenderLayer::layerChanged` + if (layerTweaker) { + layerTweaker->updateProperties(evaluatedProperties); } #endif // MLN_DRAWABLE_RENDERER } @@ -970,16 +970,19 @@ void RenderSymbolLayer::layerIndexChanged(int32_t newLayerIndex, UniqueChangeReq changeLayerIndex(collisionTileLayerGroup, newLayerIndex, changes); } -void RenderSymbolLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { +std::size_t RenderSymbolLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { + const auto oldValue = stats.drawablesRemoved; if (const auto tileGroup = static_cast(layerGroup.get())) { stats.drawablesRemoved += tileGroup->removeDrawables(renderPass, tileID).size(); } if (collisionTileLayerGroup) { stats.drawablesRemoved += collisionTileLayerGroup->removeDrawables(renderPass, tileID).size(); } + return stats.drawablesRemoved - oldValue; } -void RenderSymbolLayer::removeAllDrawables() { +std::size_t RenderSymbolLayer::removeAllDrawables() { + const auto oldValue = stats.drawablesRemoved; if (layerGroup) { stats.drawablesRemoved += layerGroup->getDrawableCount(); layerGroup->clearDrawables(); @@ -988,12 +991,13 @@ void RenderSymbolLayer::removeAllDrawables() { stats.drawablesRemoved += collisionTileLayerGroup->getDrawableCount(); collisionTileLayerGroup->clearDrawables(); } + return stats.drawablesRemoved - oldValue; } void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, - const std::shared_ptr&, + const std::shared_ptr& updateParameters, const RenderTree& /*renderTree*/, UniqueChangeRequestVec& changes) { if (!renderTiles || renderTiles->empty() || passes == RenderPass::None) { @@ -1004,24 +1008,27 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, // Set up a layer group if (!layerGroup) { if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { - tweaker = std::make_shared(getID(), evaluatedProperties); -#if MLN_RENDER_BACKEND_METAL - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); -#endif // MLN_RENDER_BACKEND_METAL - layerGroup_->setLayerTweaker(tweaker); setLayerGroup(std::move(layerGroup_), changes); } } + if (!layerTweaker) { + layerTweaker = std::make_shared(getID(), evaluatedProperties); + layerGroup->addLayerTweaker(layerTweaker); + } + layerTweaker->enableOverdrawInspector(!!(updateParameters->debugOptions & MapDebugOptions::Overdraw)); + const auto& getCollisionTileLayerGroup = [&] { if (!collisionTileLayerGroup) { if ((collisionTileLayerGroup = context.createTileLayerGroup( layerIndex, /*initialCapacity=*/64, getID() + "-collision"))) { - collisionTileLayerGroup->setLayerTweaker( - std::make_shared(getID(), evaluatedProperties)); activateLayerGroup(collisionTileLayerGroup, true, changes); } } + if (!collisionLayerTweaker) { + collisionLayerTweaker = std::make_shared(getID(), evaluatedProperties); + collisionTileLayerGroup->addLayerTweaker(collisionLayerTweaker); + } return collisionTileLayerGroup; }; @@ -1168,6 +1175,8 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, // add drawables to layer group for (auto& drawable : collisionBuilder->clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(collisionLayerTweaker); + auto drawData = std::make_unique(values.translate, values.translateAnchor); drawable->setData(std::move(drawData)); group->addDrawable(passes, tileID, std::move(drawable)); @@ -1181,6 +1190,11 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, // 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; + } + const auto& evaluated = getEvaluated(renderData.layerProperties); updateTileDrawable( drawable, context, bucket, bucketPaintProperties, evaluated, state, textInterpUBO, iconInterpUBO); @@ -1247,6 +1261,10 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto& bucket = static_cast(*renderable.renderData.bucket); const auto& buffer = isText ? bucket.text : (sdfIcons ? bucket.sdfIcon : bucket.icon); + if (!buffer.sharedTriangles->elements()) { + continue; + } + const auto& evaluated = getEvaluated(renderable.renderData.layerProperties); const auto& bucketPaintProperties = bucket.paintProperties.at(getID()); @@ -1264,14 +1282,11 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto vertexCount = buffer.vertices().elements(); gfx::VertexAttributeArray attribs; - const auto uniformProps = updateTileAttributes(buffer, isText, bucketPaintProperties, evaluated, attribs); - -#if MLN_RENDER_BACKEND_METAL - propertiesAsUniforms = uniformProps; - if (tweaker) { - tweaker->setPropertiesAsUniforms(propertiesAsUniforms); + const auto propertiesAsUniforms = updateTileAttributes( + buffer, isText, bucketPaintProperties, evaluated, attribs); + if (layerTweaker) { + layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); } -#endif // MLN_RENDER_BACKEND_METAL const auto textHalo = evaluated.get().constantOr(Color::black()).a > 0.0f && evaluated.get().constantOr(1); @@ -1340,8 +1355,8 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, if (!shaderGroup) { return; } - const auto shader = std::static_pointer_cast( - shaderGroup->getOrCreateShader(context, uniformProps, StringIndexer::get(idPosOffsetAttribName))); + const auto shader = std::static_pointer_cast(shaderGroup->getOrCreateShader( + context, propertiesAsUniforms, StringIndexer::get(idPosOffsetAttribName))); if (!shader) { return; } @@ -1359,6 +1374,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder->clearDrawables()) { drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); auto drawData = std::make_unique( /*.isHalo=*/isHalo, diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index c391d266b..a1e483313 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -118,10 +118,10 @@ protected: void layerRemoved(UniqueChangeRequestVec&) override; /// Remove all drawables for the tile from the layer group - void removeTile(RenderPass, const OverscaledTileID&) override; + std::size_t removeTile(RenderPass, const OverscaledTileID&) override; /// Remove all the drawables for tiles - void removeAllDrawables() override; + std::size_t removeAllDrawables() override; #endif // MLN_DRAWABLE_RENDERER private: @@ -151,8 +151,6 @@ private: #endif // MLN_LEGACY_RENDERER #if MLN_DRAWABLE_RENDERER - SymbolLayerTweakerPtr tweaker; - gfx::ShaderGroupPtr symbolIconGroup; gfx::ShaderGroupPtr symbolSDFGroup; gfx::ShaderGroupPtr symbolTextAndIconGroup; @@ -160,11 +158,9 @@ private: gfx::ShaderGroupPtr collisionBoxGroup; gfx::ShaderGroupPtr collisionCircleGroup; std::shared_ptr collisionTileLayerGroup; -#endif // MLN_DRAWABLE_RENDERER -#if MLN_RENDER_BACKEND_METAL - std::vector propertiesAsUniforms; -#endif // MLN_RENDER_BACKEND_METAL + LayerTweakerPtr collisionLayerTweaker; +#endif // MLN_DRAWABLE_RENDERER }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp index a7b7f16bf..21ad4983b 100644 --- a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp @@ -90,7 +90,7 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, const auto zoom = parameters.state.getZoom(); #if MLN_RENDER_BACKEND_METAL - if (propertiesChanged) { + if (permutationUpdated) { const SymbolPermutationUBO permutationUBO = { /* .fill_color = */ {/*.source=*/getAttributeSource("a_fill_color"), /*.expression=*/{}}, /* .halo_color = */ {/*.source=*/getAttributeSource("a_halo_color"), /*.expression=*/{}}, @@ -108,7 +108,7 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, permutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO)); } - propertiesChanged = false; + permutationUpdated = false; } if (!expressionUniformBuffer) { const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount); @@ -116,6 +116,12 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, } #endif + if (propertiesUpdated) { + textPropertiesUpdated = true; + iconPropertiesUpdated = true; + propertiesUpdated = false; + } + layerGroup.visitDrawables([&](gfx::Drawable& drawable) { if (!drawable.getTileID() || !drawable.getData()) { return; @@ -125,14 +131,15 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, const auto& symbolData = static_cast(*drawable.getData()); const auto isText = (symbolData.symbolType == SymbolType::Text); - if (isText && (!textPaintBuffer || propertiesUpdated)) { + if (isText && (!textPaintBuffer || textPropertiesUpdated)) { const auto props = buildPaintUBO(true, evaluated); textPaintBuffer = parameters.context.createUniformBuffer(&props, sizeof(props)); - } else if (!isText && (!iconPaintBuffer || propertiesUpdated)) { + textPropertiesUpdated = false; + } else if (!isText && (!iconPaintBuffer || iconPropertiesUpdated)) { const auto props = buildPaintUBO(false, evaluated); iconPaintBuffer = parameters.context.createUniformBuffer(&props, sizeof(props)); + iconPropertiesUpdated = false; } - propertiesUpdated = false; // from RenderTile::translatedMatrix const auto translate = isText ? evaluated.get() : evaluated.get(); diff --git a/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp b/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp index 97098d99f..a632da3ff 100644 --- a/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp +++ b/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp @@ -30,6 +30,9 @@ private: gfx::UniformBufferPtr textPaintBuffer; gfx::UniformBufferPtr iconPaintBuffer; + bool textPropertiesUpdated = false; + bool iconPropertiesUpdated = false; + #if MLN_RENDER_BACKEND_METAL gfx::UniformBufferPtr permutationUniformBuffer; gfx::UniformBufferPtr expressionUniformBuffer; diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index ea974117b..bc9773573 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -70,11 +70,41 @@ std::optional RenderLayer::getSolidBackground() const { } #if MLN_DRAWABLE_RENDERER +void RenderLayer::replaceTweaker(LayerTweakerPtr& curTweaker, + LayerTweakerPtr newTweaker, + const std::vector& layerGroups) { + const auto prevTweaker = curTweaker; + + // We need to re-create the tweaker because it doesn't yet support modifying evaluated + // properties, but we don't want to stop updating drawables (as in the `layerChanged` case) + // so we need to update the tweaker reference on the outstanding drawables so that they + // pass the check in `updateExisting`. + // TODO: Once the tweaker doesn't need to be re-created on each property evaluation, this won't be needed. + for (const auto& group : layerGroups) { + if (group) { + group->addLayerTweaker(newTweaker); + + group->visitDrawables([&](gfx::Drawable& drawable) { + if (drawable.getLayerTweaker() == prevTweaker) { + drawable.setLayerTweaker(newTweaker); + } + }); + } + } + + curTweaker = std::move(newTweaker); +} + void RenderLayer::layerChanged(const TransitionParameters&, const Immutable&, 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. + + // Detach the layer tweaker, if any. This keeps the existing tiles up-to-date with the + // most recent evaluated properties, while a new one will be created along with new drawables + // when tiles are loaded and new buckets are available. + layerTweaker.reset(); } void RenderLayer::layerRemoved(UniqueChangeRequestVec& changes) { @@ -136,17 +166,23 @@ const LayerRenderData* RenderLayer::getRenderDataForPass(const RenderTile& tile, } #if MLN_DRAWABLE_RENDERER -void RenderLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { +std::size_t RenderLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { if (const auto tileGroup = static_cast(layerGroup.get())) { - stats.drawablesRemoved += tileGroup->removeDrawables(renderPass, tileID).size(); + const auto n = tileGroup->removeDrawables(renderPass, tileID).size(); + stats.drawablesRemoved += n; + return n; } + return 0; } -void RenderLayer::removeAllDrawables() { +std::size_t RenderLayer::removeAllDrawables() { if (layerGroup) { - stats.drawablesRemoved += layerGroup->getDrawableCount(); + const auto count = layerGroup->getDrawableCount(); + stats.drawablesRemoved += count; layerGroup->clearDrawables(); + return count; } + return 0; } void RenderLayer::updateRenderTileIDs() { diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index 020576462..6ad7b0b02 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -211,10 +211,11 @@ protected: void changeLayerIndex(const LayerGroupBasePtr&, int32_t newLayerIndex, UniqueChangeRequestVec&); /// Remove all drawables for the tile from the layer group - virtual void removeTile(RenderPass, const OverscaledTileID&); + /// @return The number of drawables actually removed. + virtual std::size_t removeTile(RenderPass, const OverscaledTileID&); /// Remove all the drawables for tiles - virtual void removeAllDrawables(); + virtual std::size_t removeAllDrawables(); /// Update `renderTileIDs` from `renderTiles` void updateRenderTileIDs(); @@ -233,6 +234,12 @@ protected: /// @return true if updated, false if the tile ID is not present in the set of tiles to be rendered or the ID is /// unchanged bool setRenderTileBucketID(const OverscaledTileID&, util::SimpleIdentity bucketID); + + /// Update the layer tweaker and drawables which reference it + static void replaceTweaker(LayerTweakerPtr& toReplace, + LayerTweakerPtr newTweaker, + const std::vector&); + #endif // MLN_DRAWABLE_RENDERER static bool applyColorRamp(const style::ColorRampPropertyValue&, PremultipliedImage&); @@ -251,6 +258,9 @@ protected: // will need to be overriden to handle their activation. LayerGroupBasePtr layerGroup; + // An optional tweaker that will update drawables + LayerTweakerPtr layerTweaker; + // The set of Tile IDs in `renderTiles`, along with the // identity of the bucket from which they were built. std::unordered_map renderTileIDs; diff --git a/src/mbgl/renderer/render_target.cpp b/src/mbgl/renderer/render_target.cpp index 924dae958..4d707d13e 100644 --- a/src/mbgl/renderer/render_target.cpp +++ b/src/mbgl/renderer/render_target.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace mbgl { @@ -84,11 +85,7 @@ void RenderTarget::render(RenderOrchestrator& orchestrator, const RenderTree& re "render target", {*offscreenTexture, Color{0.0f, 0.0f, 0.0f, 1.0f}, {}, {}}); // Run layer tweakers to update any dynamic elements - visitLayerGroups([&](LayerGroupBase& layerGroup) { - if (layerGroup.getLayerTweaker()) { - layerGroup.getLayerTweaker()->execute(layerGroup, renderTree, parameters); - } - }); + visitLayerGroups([&](LayerGroupBase& layerGroup) { layerGroup.runTweakers(renderTree, parameters); }); // draw layer groups, opaque pass parameters.pass = RenderPass::Opaque; diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index bf6c2df29..c917bdf69 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -152,11 +152,8 @@ void Renderer::Impl::render(const RenderTree& renderTree, #endif // Tweakers are run in the upload pass so they can set up uniforms. - orchestrator.visitLayerGroups([&](LayerGroupBase& layerGroup) { - if (layerGroup.getLayerTweaker()) { - layerGroup.getLayerTweaker()->execute(layerGroup, renderTree, parameters); - } - }); + orchestrator.visitLayerGroups( + [&](LayerGroupBase& layerGroup) { layerGroup.runTweakers(renderTree, parameters); }); } // Update the debug layer groups