From 29319a76bfa77a4b7ba34dc6487c5aba1aec7293 Mon Sep 17 00:00:00 2001 From: Tim Sylvester Date: Tue, 10 Sep 2024 11:37:50 -0700 Subject: [PATCH] Move UBO updates from render layers to tweakers (#2703) --- include/mbgl/gfx/drawable.hpp | 17 +- include/mbgl/renderer/layer_tweaker.hpp | 2 +- include/mbgl/util/containers.hpp | 8 +- src/mbgl/gfx/drawable.cpp | 33 +++ .../renderer/layers/circle_layer_tweaker.cpp | 25 +- .../layers/fill_extrusion_layer_tweaker.cpp | 38 ++- .../renderer/layers/fill_layer_tweaker.cpp | 59 +++- .../renderer/layers/heatmap_layer_tweaker.cpp | 23 +- .../renderer/layers/line_layer_tweaker.cpp | 76 +++++- .../renderer/layers/render_circle_layer.cpp | 36 +-- .../layers/render_fill_extrusion_layer.cpp | 53 +--- .../renderer/layers/render_fill_layer.cpp | 205 +++----------- .../renderer/layers/render_heatmap_layer.cpp | 48 +--- .../renderer/layers/render_line_layer.cpp | 203 +++----------- .../renderer/layers/render_symbol_layer.cpp | 256 ++++++------------ .../renderer/layers/symbol_layer_tweaker.cpp | 86 +++++- .../renderer/layers/symbol_layer_tweaker.hpp | 21 +- src/mbgl/renderer/paint_property_binder.hpp | 6 +- src/mbgl/renderer/render_layer.cpp | 4 +- src/mbgl/renderer/render_layer.hpp | 3 + src/mbgl/renderer/render_source.cpp | 12 +- src/mbgl/renderer/render_source.hpp | 1 + src/mbgl/renderer/render_tile.cpp | 10 +- .../renderer/sources/render_tile_source.hpp | 1 + 24 files changed, 566 insertions(+), 660 deletions(-) diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index f653fd3d34b..034177c9d0a 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -18,12 +18,16 @@ namespace mbgl { +class Bucket; class Color; -class PaintParameters; class LayerTweaker; +class PaintParameters; +class PaintPropertyBindersBase; enum class RenderPass : uint8_t; +class RenderTile; using LayerTweakerPtr = std::shared_ptr; +using RenderTiles = std::shared_ptr>>; namespace gfx { @@ -245,6 +249,17 @@ class Drawable { /// Set origin point void setOrigin(std::optional> p) { origin = std::move(p); } + /// Get the property binders used for property updates + PaintPropertyBindersBase* getBinders(); + const PaintPropertyBindersBase* getBinders() const; + + /// Set the property binders used for property updates + void setBinders(std::shared_ptr, PaintPropertyBindersBase*); + + const RenderTile* getRenderTile() const; + const std::shared_ptr& getBucket() const; + void setRenderTile(Immutable>, const RenderTile*); + const std::chrono::duration createTime = util::MonotonicTimer::now(); protected: diff --git a/include/mbgl/renderer/layer_tweaker.hpp b/include/mbgl/renderer/layer_tweaker.hpp index b533fcd3569..485d0b22a67 100644 --- a/include/mbgl/renderer/layer_tweaker.hpp +++ b/include/mbgl/renderer/layer_tweaker.hpp @@ -23,10 +23,10 @@ class LayerProperties; enum class TranslateAnchorType : bool; } // namespace style -class TransformState; class LayerGroupBase; class PaintParameters; class RenderTree; +class TransformState; class UnwrappedTileID; /** diff --git a/include/mbgl/util/containers.hpp b/include/mbgl/util/containers.hpp index c93bb868268..5ddbda154be 100644 --- a/include/mbgl/util/containers.hpp +++ b/include/mbgl/util/containers.hpp @@ -8,14 +8,14 @@ namespace mbgl { #if MLN_USE_UNORDERED_DENSE -template -using unordered_map = ankerl::unordered_dense::map; +template > +using unordered_map = ankerl::unordered_dense::map; template using unordered_set = ankerl::unordered_dense::set; #else -template -using unordered_map = std::unordered_map; +template > +using unordered_map = std::unordered_map; template using unordered_set = std::unordered_set; diff --git a/src/mbgl/gfx/drawable.cpp b/src/mbgl/gfx/drawable.cpp index 69dd9802217..34fea6d9211 100644 --- a/src/mbgl/gfx/drawable.cpp +++ b/src/mbgl/gfx/drawable.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace mbgl { namespace gfx { @@ -13,6 +14,12 @@ namespace gfx { struct Drawable::Impl { gfx::ColorMode colorMode = gfx::ColorMode::disabled(); gfx::CullFaceMode cullFaceMode = gfx::CullFaceMode::disabled(); + + std::shared_ptr bucket; + PaintPropertyBindersBase* binders = nullptr; // owned by `bucket` + + Immutable> renderTiles = makeMutable>(); + const RenderTile* renderTile = nullptr; // owned by `renderTiles` }; Drawable::Drawable(std::string name_) @@ -57,5 +64,31 @@ void Drawable::setTexture(std::shared_ptr texture, size_t id) { textures[id] = std::move(texture); } +PaintPropertyBindersBase* Drawable::getBinders() { + return impl->binders; +} +const PaintPropertyBindersBase* Drawable::getBinders() const { + return impl->binders; +} + +/// Set the property binders used for property updates +void Drawable::setBinders(std::shared_ptr bucket_, PaintPropertyBindersBase* binders_) { + impl->bucket = std::move(bucket_); + impl->binders = binders_; +} + +const RenderTile* Drawable::getRenderTile() const { + return impl->renderTile; +} + +const std::shared_ptr& Drawable::getBucket() const { + return impl->bucket; +} + +void Drawable::setRenderTile(Immutable> renderTiles_, const RenderTile* tile_) { + impl->renderTiles = std::move(renderTiles_); + impl->renderTile = tile_; +} + } // namespace gfx } // namespace mbgl diff --git a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp index 8d98756f0d6..21348ae1619 100644 --- a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -34,7 +35,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str()); #endif - const auto zoom = parameters.state.getZoom(); + const auto zoom = static_cast(parameters.state.getZoom()); const bool pitchWithMap = evaluated.get() == AlignmentType::Map; const bool scaleWithMap = evaluated.get() == CirclePitchScaleType::Map; @@ -64,6 +65,12 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete } const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); + auto* binders = static_cast(drawable.getBinders()); + if (!binders) { + assert(false); + return; + } + const auto& translation = evaluated.get(); const auto anchor = evaluated.get(); constexpr bool inViewportPixelUnits = false; // from RenderTile::translatedMatrix @@ -71,7 +78,7 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete const auto matrix = getTileMatrix( tileID, parameters, translation, anchor, nearClipped, inViewportPixelUnits, drawable); - const auto pixelsToTileUnits = tileID.pixelsToTileUnits(1.0f, static_cast(zoom)); + const auto pixelsToTileUnits = tileID.pixelsToTileUnits(1.0f, zoom); const auto extrudeScale = pitchWithMap ? std::array{pixelsToTileUnits, pixelsToTileUnits} : parameters.pixelsToGLUnits; @@ -82,6 +89,20 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete auto& drawableUniforms = drawable.mutableUniformBuffers(); drawableUniforms.createOrUpdate(idCircleDrawableUBO, &drawableUBO, context); + + const CircleInterpolateUBO interpolateUBO = { + /* .color_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .radius_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .blur_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .opacity_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .stroke_color_t = */ + std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .stroke_width_t = */ + std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .stroke_opacity_t = */ + std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .padding = */ 0}; + drawableUniforms.createOrUpdate(idCircleInterpolateUBO, &interpolateUBO, context); }); } diff --git a/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp b/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp index 0067b46d1bd..24057479af8 100644 --- a/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp @@ -6,14 +6,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include -#include #if MLN_RENDER_BACKEND_METAL #include @@ -62,11 +61,22 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintP propertiesUpdated = false; + const auto zoom = static_cast(parameters.state.getZoom()); + const auto defPattern = mbgl::Faded{"", ""}; + const auto fillPatternValue = evaluated.get().constantOr(defPattern); + visitLayerGroupDrawables(layerGroup, [&](gfx::Drawable& drawable) { if (!drawable.getTileID() || !checkTweakDrawable(drawable)) { return; } + auto* binders = static_cast(drawable.getBinders()); + const auto* tile = drawable.getRenderTile(); + if (!binders || !tile) { + assert(false); + return; + } + const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); const auto& translation = evaluated.get(); const auto anchor = evaluated.get(); @@ -90,6 +100,13 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintP textureSize = tex->getSize(); } + const auto hasPattern = !!drawable.getType(); + const auto patternPosA = tile->getPattern(fillPatternValue.from.id()); + const auto patternPosB = tile->getPattern(fillPatternValue.to.id()); + if (hasPattern) { + binders->setPatternParameters(patternPosA, patternPosB, crossfade); + } + const FillExtrusionDrawableUBO drawableUBO = { /* .matrix = */ util::cast(matrix), /* .texsize = */ {static_cast(textureSize.width), static_cast(textureSize.height)}, @@ -98,8 +115,25 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintP /* .height_factor = */ heightFactor, /* .tile_ratio = */ tileRatio}; + const FillExtrusionInterpolateUBO interpUBO = { + /* .base_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .height_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .color_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .pattern_from_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .pattern_to_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .pad = */ 0, + 0, + 0}; + + const FillExtrusionTilePropsUBO tilePropsUBO = { + /* pattern_from = */ patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, + /* pattern_to = */ patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}, + }; + auto& drawableUniforms = drawable.mutableUniformBuffers(); drawableUniforms.createOrUpdate(idFillExtrusionDrawableUBO, &drawableUBO, context); + drawableUniforms.createOrUpdate(idFillExtrusionTilePropsUBO, &tilePropsUBO, context); + drawableUniforms.createOrUpdate(idFillExtrusionInterpolateUBO, &interpUBO, context); }); } diff --git a/src/mbgl/renderer/layers/fill_layer_tweaker.cpp b/src/mbgl/renderer/layers/fill_layer_tweaker.cpp index 4ea3b4f386e..352f32cb879 100644 --- a/src/mbgl/renderer/layers/fill_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/fill_layer_tweaker.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters const auto& translation = evaluated.get(); const auto anchor = evaluated.get(); + const auto zoom = static_cast(parameters.state.getZoom()); const auto intZoom = parameters.state.getIntegerZoom(); visitLayerGroupDrawables(layerGroup, [&](gfx::Drawable& drawable) { @@ -62,9 +64,20 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); + auto* binders = static_cast(drawable.getBinders()); + const auto* tile = drawable.getRenderTile(); + if (!binders || !tile) { + assert(false); + return; + } + + const auto& fillPatternValue = evaluated.get().constantOr(Faded{"", ""}); + const auto patternPosA = tile->getPattern(fillPatternValue.from.id()); + const auto patternPosB = tile->getPattern(fillPatternValue.to.id()); + binders->setPatternParameters(patternPosA, patternPosB, crossfade); + constexpr bool inViewportPixelUnits = false; // from RenderTile::translatedMatrix constexpr bool nearClipped = false; - const auto matrix = getTileMatrix( tileID, parameters, translation, anchor, nearClipped, inViewportPixelUnits, drawable); @@ -88,11 +101,27 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters case RenderFillLayer::FillVariant::Fill: { const FillDrawableUBO drawableUBO = {/*.matrix=*/util::cast(matrix)}; drawableUniforms.createOrUpdate(idFillDrawableUBO, &drawableUBO, context); + + const auto fillInterpolateUBO = FillInterpolateUBO{ + /* .color_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .opacity_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + 0, + 0, + }; + drawableUniforms.createOrUpdate(idFillInterpolateUBO, &fillInterpolateUBO, context); break; } case RenderFillLayer::FillVariant::FillOutline: { const FillOutlineDrawableUBO drawableUBO = {/*.matrix=*/util::cast(matrix)}; drawableUniforms.createOrUpdate(idFillDrawableUBO, &drawableUBO, context); + + const auto fillOutlineInterpolateUBO = FillOutlineInterpolateUBO{ + /* .color_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .opacity_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + 0, + 0, + }; + drawableUniforms.createOrUpdate(idFillInterpolateUBO, &fillOutlineInterpolateUBO, context); break; } case RenderFillLayer::FillVariant::FillPattern: { @@ -105,6 +134,20 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters 0, }; drawableUniforms.createOrUpdate(idFillDrawableUBO, &drawableUBO, context); + + const auto fillPatternInterpolateUBO = FillPatternInterpolateUBO{ + /* .pattern_from_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .pattern_to_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .opacity_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + 0, + }; + drawableUniforms.createOrUpdate(idFillInterpolateUBO, &fillPatternInterpolateUBO, context); + + const auto fillPatternTilePropsUBO = FillPatternTilePropsUBO{ + /* pattern_from = */ patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, + /* pattern_to = */ patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}, + }; + drawableUniforms.createOrUpdate(idFillTilePropsUBO, &fillPatternTilePropsUBO, context); break; } case RenderFillLayer::FillVariant::FillOutlinePattern: { @@ -116,6 +159,20 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters /*.tile_ratio = */ tileRatio, 0}; drawableUniforms.createOrUpdate(idFillDrawableUBO, &drawableUBO, context); + + const auto fillOutlinePatternInterpolateUBO = FillPatternInterpolateUBO{ + /* .pattern_from_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .pattern_to_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .opacity_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + 0, + }; + drawableUniforms.createOrUpdate(idFillInterpolateUBO, &fillOutlinePatternInterpolateUBO, context); + + const auto fillOutlinePatternTilePropsUBO = FillOutlinePatternTilePropsUBO{ + /* pattern_from = */ patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, + /* pattern_to = */ patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}, + }; + drawableUniforms.createOrUpdate(idFillTilePropsUBO, &fillOutlinePatternTilePropsUBO, context); break; } case RenderFillLayer::FillVariant::FillOutlineTriangulated: { diff --git a/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp index ee443e8e017..348a998c90a 100644 --- a/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -21,7 +22,7 @@ using namespace shaders; void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters& parameters) { auto& context = parameters.context; - const auto zoom = parameters.state.getZoom(); + const auto zoom = static_cast(parameters.state.getZoom()); const auto& evaluated = static_cast(*evaluatedProperties).evaluated; if (layerGroup.empty()) { @@ -52,17 +53,29 @@ void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamet const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); + auto* binders = static_cast(drawable.getBinders()); + const auto* tile = drawable.getRenderTile(); + if (!binders || !tile) { + assert(false); + return; + } + constexpr bool nearClipped = false; constexpr bool inViewportPixelUnits = false; const auto matrix = getTileMatrix( tileID, parameters, {0.f, 0.f}, TranslateAnchorType::Viewport, nearClipped, inViewportPixelUnits, drawable); - const HeatmapDrawableUBO drawableUBO = { - /* .matrix = */ util::cast(matrix), - /* .extrude_scale = */ tileID.pixelsToTileUnits(1.0f, static_cast(zoom)), - /* .padding = */ {0}}; + const HeatmapDrawableUBO drawableUBO = {/* .matrix = */ util::cast(matrix), + /* .extrude_scale = */ tileID.pixelsToTileUnits(1.0f, zoom), + /* .padding = */ {0}}; auto& drawableUniforms = drawable.mutableUniformBuffers(); drawableUniforms.createOrUpdate(idHeatmapDrawableUBO, &drawableUBO, context); + + const HeatmapInterpolateUBO interpolateUBO = { + /* .weight_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .radius_t = */ std::get<0>(binders->get()->interpolationFactor(zoom)), + /* .padding = */ {0}}; + drawableUniforms.createOrUpdate(idHeatmapInterpolateUBO, &interpolateUBO, context); }); } diff --git a/src/mbgl/renderer/layers/line_layer_tweaker.cpp b/src/mbgl/renderer/layers/line_layer_tweaker.cpp index f73f2c34090..a90b4c6af1d 100644 --- a/src/mbgl/renderer/layers/line_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/line_layer_tweaker.cpp @@ -4,13 +4,14 @@ #include #include #include +#include #include #include #include +#include #include #include #include -#include #include #include @@ -69,6 +70,8 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters const auto& evaluated = static_cast(*evaluatedProperties).evaluated; const auto& crossfade = static_cast(*evaluatedProperties).crossfade; + const auto& linePatternValue = evaluated.get().constantOr(Faded{"", ""}); + const auto zoom = static_cast(parameters.state.getZoom()); const auto intZoom = parameters.state.getIntegerZoom(); @@ -160,17 +163,27 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters } const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); + + auto* binders = static_cast(drawable.getBinders()); + const auto* tile = drawable.getRenderTile(); + if (!binders || !tile) { + assert(false); + return; + } + + const auto patternPosA = tile->getPattern(linePatternValue.from.id()); + const auto patternPosB = tile->getPattern(linePatternValue.to.id()); + binders->setPatternParameters(patternPosA, patternPosB, crossfade); + const auto& translation = evaluated.get(); const auto anchor = evaluated.get(); constexpr bool nearClipped = false; constexpr bool inViewportPixelUnits = false; // from RenderTile::translatedMatrix - auto& drawableUniforms = drawable.mutableUniformBuffers(); - const auto matrix = getTileMatrix( tileID, parameters, translation, anchor, nearClipped, inViewportPixelUnits, drawable); - const LineType type = static_cast(drawable.getType()); - switch (type) { + auto& drawableUniforms = drawable.mutableUniformBuffers(); + switch (static_cast(drawable.getType())) { case LineType::Simple: { const LineDrawableUBO drawableUBO = { /*matrix = */ util::cast(matrix), @@ -179,6 +192,17 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters 0, 0}; drawableUniforms.createOrUpdate(idLineDrawableUBO, &drawableUBO, context); + + const auto lineInterpolationUBO = LineInterpolationUBO{ + /*color_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*blur_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*opacity_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*gapwidth_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*offset_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*width_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + 0, + 0}; + drawableUniforms.createOrUpdate(idLineInterpolationUBO, &lineInterpolationUBO, context); } break; case LineType::Gradient: { @@ -189,6 +213,17 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters 0, 0}; drawableUniforms.createOrUpdate(idLineDrawableUBO, &drawableUBO, context); + + const auto lineGradientInterpolationUBO = LineGradientInterpolationUBO{ + /*blur_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*opacity_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*gapwidth_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*offset_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*width_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + 0, + 0, + 0}; + drawableUniforms.createOrUpdate(idLineInterpolationUBO, &lineGradientInterpolationUBO, context); } break; case LineType::Pattern: { @@ -207,6 +242,22 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters /*ratio =*/1.0f / tileID.pixelsToTileUnits(1.0f, static_cast(zoom)), /*fade =*/crossfade.t}; drawableUniforms.createOrUpdate(idLineDrawableUBO, &drawableUBO, context); + + const auto linePatternInterpolationUBO = LinePatternInterpolationUBO{ + /*blur_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*opacity_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*offset_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*gapwidth_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*width_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*pattern_from_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*pattern_to_t =*/std::get<1>(binders->get()->interpolationFactor(zoom)), + 0}; + drawableUniforms.createOrUpdate(idLineInterpolationUBO, &linePatternInterpolationUBO, context); + + const auto linePatternTilePropertiesUBO = LinePatternTilePropertiesUBO{ + /*pattern_from =*/patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, + /*pattern_to =*/patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}}; + drawableUniforms.createOrUpdate(idLineTilePropertiesUBO, &linePatternTilePropertiesUBO, context); } break; case LineType::SDF: { @@ -246,13 +297,24 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters 0, 0}; drawableUniforms.createOrUpdate(idLineDrawableUBO, &drawableUBO, context); + + const auto lineSDFInterpolationUBO = LineSDFInterpolationUBO{ + /*color_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*blur_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*opacity_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*gapwidth_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*offset_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*width_t =*/std::get<0>(binders->get()->interpolationFactor(zoom)), + /*floorwidth_t =*/ + std::get<0>(binders->get()->interpolationFactor(zoom)), + 0}; + drawableUniforms.createOrUpdate(idLineInterpolationUBO, &lineSDFInterpolationUBO, context); } } break; default: { - using namespace std::string_literals; Log::Error(Event::General, - "LineLayerTweaker: unknown line type: "s + std::to_string(mbgl::underlying_type(type))); + "LineLayerTweaker: unknown line type: " + std::to_string(drawable.getType())); } break; } }); diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index c932516308a..ed03edd4f05 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -118,7 +118,7 @@ void RenderCircleLayer::render(PaintParameters& parameters) { const auto& evaluated = getEvaluated(data->layerProperties); const bool scaleWithMap = evaluated.template get() == CirclePitchScaleType::Map; const bool pitchWithMap = evaluated.template get() == AlignmentType::Map; - const auto& paintPropertyBinders = circleBucket.paintPropertyBinders.at(getID()); + auto& paintPropertyBinders = circleBucket.paintPropertyBinders.at(getID()); using LayoutUniformValues = CircleProgram::LayoutUniformValues; const auto& allUniformValues = CircleProgram::computeAllUniformValues( @@ -274,9 +274,9 @@ using namespace shaders; void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, - const TransformState& state, - [[maybe_unused]] const std::shared_ptr&, - [[maybe_unused]] const RenderTree& renderTree, + const TransformState&, + const std::shared_ptr&, + const RenderTree&, UniqueChangeRequestVec& changes) { if (!renderTiles || renderTiles->empty()) { removeAllDrawables(); @@ -327,9 +327,9 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, continue; } - const auto& bucket = static_cast(*renderData->bucket); + auto& bucket = static_cast(*renderData->bucket); const auto vertexCount = bucket.vertices.elements(); - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); const auto prevBucketID = getRenderTileBucketID(tileID); if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { @@ -338,37 +338,18 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, } setRenderTileBucketID(tileID, bucket.getID()); - const float zoom = static_cast(state.getZoom()); - const CircleInterpolateUBO interpolateUBO = { - /* .color_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /* .radius_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /* .blur_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /* .opacity_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /* .stroke_color_t = */ - std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /* .stroke_width_t = */ - std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /* .stroke_opacity_t = */ - std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /* .padding = */ 0}; - // 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 false; } - - auto& drawableUniforms = drawable.mutableUniformBuffers(); - drawableUniforms.createOrUpdate(idCircleInterpolateUBO, &interpolateUBO, context); return true; }; if (updateTile(renderPass, tileID, std::move(updateExisting))) { continue; } - const auto interpBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO)); - propertiesAsUniforms.first.clear(); propertiesAsUniforms.second.clear(); @@ -413,9 +394,8 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : circleBuilder->clearDrawables()) { drawable->setTileID(tileID); drawable->setLayerTweaker(layerTweaker); - - auto& drawableUniforms = drawable->mutableUniformBuffers(); - drawableUniforms.set(idCircleInterpolateUBO, interpBuffer); + drawable->setBinders(renderData->bucket, &paintPropertyBinders); + drawable->setRenderTile(renderTilesOwner, &tile); tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); ++stats.drawablesAdded; diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index d78cdb52d9e..bda207767e4 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -112,13 +111,13 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters) { const auto& crossfade_, const gfx::StencilMode& stencilMode, const gfx::ColorMode& colorMode, - const auto& tileBucket, + auto& tileBucket, const auto& uniformValues, const std::optional& patternPositionA, const std::optional& patternPositionB, const auto& textureBindings, const std::string& uniqueName) { - const auto& paintPropertyBinders = tileBucket.paintPropertyBinders.at(getID()); + auto& paintPropertyBinders = tileBucket.paintPropertyBinders.at(getID()); paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade_); const auto allUniformValues = programInstance.computeAllUniformValues( @@ -152,7 +151,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters) { if (!renderData) { continue; } - const auto& bucket = static_cast(*renderData->bucket); + auto& bucket = static_cast(*renderData->bucket); draw(*fillExtrusionProgram, evaluated, crossfade, @@ -200,7 +199,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters) { if (!renderData) { continue; } - const auto& bucket = static_cast(*renderData->bucket); + auto& bucket = static_cast(*renderData->bucket); const std::optional patternPosA = tile.getPattern(fillPatternValue.from.id()); const std::optional patternPosB = tile.getPattern(fillPatternValue.to.id()); const auto numTiles = std::pow(2, tile.id.canonical.z); @@ -271,9 +270,9 @@ bool RenderFillExtrusionLayer::queryIntersectsFeature(const GeometryCoordinates& void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, - const TransformState& state, + const TransformState&, const std::shared_ptr&, - const RenderTree& /*renderTree*/, + const RenderTree&, UniqueChangeRequestVec& changes) { if (!renderTiles || renderTiles->empty() || passes == RenderPass::None) { removeAllDrawables(); @@ -304,7 +303,6 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, auto* tileLayerGroup = static_cast(layerGroup.get()); const auto& evaluated = static_cast(*evaluatedProperties).evaluated; - const auto& crossfade = static_cast(*evaluatedProperties).crossfade; // `passes` is set to (RenderPass::Translucent | RenderPass::Pass3D), but `render()` // only runs on the translucent pass, so although our output is 3D, it does not render @@ -320,7 +318,6 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, return false; }); - const auto zoom = static_cast(state.getZoom()); const auto layerPrefix = getID() + "/"; const auto hasPattern = !unevaluated.get().isUndefined(); const auto opaque = evaluated.get() >= 1; @@ -347,7 +344,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, } const auto& renderData = *optRenderData; - const auto& bucket = static_cast(*renderData.bucket); + auto& bucket = static_cast(*renderData.bucket); const auto prevBucketID = getRenderTileBucketID(tileID); if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { @@ -365,30 +362,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, } const auto vertexCount = bucket.vertices.elements(); - const auto defPattern = mbgl::Faded{"", ""}; - const auto fillPatternValue = evaluated.get().constantOr(defPattern); - const auto patternPosA = tile.getPattern(fillPatternValue.from.id()); - const auto patternPosB = tile.getPattern(fillPatternValue.to.id()); - - const auto& binders = bucket.paintPropertyBinders.at(getID()); - if (hasPattern) { - binders.setPatternParameters(patternPosA, patternPosB, crossfade); - } - - const FillExtrusionInterpolateUBO interpUBO = { - /* .base_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .height_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .color_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .pattern_from_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .pattern_to_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .pad = */ 0, - 0, - 0}; - - const FillExtrusionTilePropsUBO tilePropsUBO = { - /* pattern_from = */ patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, - /* pattern_to = */ patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}, - }; + auto& binders = bucket.paintPropertyBinders.at(getID()); // If we already have drawables for this tile, update them. auto updateExisting = [&](gfx::Drawable& drawable) { @@ -396,10 +370,6 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, // This drawable was produced on a previous style/bucket, and should not be updated. return false; } - - auto& drawableUniforms = drawable.mutableUniformBuffers(); - drawableUniforms.createOrUpdate(idFillExtrusionTilePropsUBO, &tilePropsUBO, context); - drawableUniforms.createOrUpdate(idFillExtrusionInterpolateUBO, &interpUBO, context); return true; }; if (updateTile(drawPass, tileID, std::move(updateExisting))) { @@ -512,11 +482,10 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : builder.clearDrawables()) { drawable->setTileID(tileID); + drawable->setType(static_cast(hasPattern)); drawable->setLayerTweaker(layerTweaker); - - auto& drawableUniforms = drawable->mutableUniformBuffers(); - drawableUniforms.createOrUpdate(idFillExtrusionTilePropsUBO, &tilePropsUBO, context); - drawableUniforms.createOrUpdate(idFillExtrusionInterpolateUBO, &interpUBO, context); + drawable->setBinders(renderData.bucket, &binders); + drawable->setRenderTile(renderTilesOwner, &tile); tileLayerGroup->addDrawable(drawPass, tileID, std::move(drawable)); ++stats.drawablesAdded; diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 63f9ecfec52..853292d6ef3 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -130,7 +130,7 @@ void RenderFillLayer::render(PaintParameters& parameters) { const auto& indexBuffer, const auto& segments, auto&& textureBindings) { - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); const auto allUniformValues = programInstance.computeAllUniformValues( FillProgram::LayoutUniformValues{ @@ -214,7 +214,7 @@ void RenderFillLayer::render(PaintParameters& parameters) { const auto& indexBuffer, const auto& segments, auto&& textureBindings) { - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade); const auto allUniformValues = programInstance.computeAllUniformValues( @@ -297,10 +297,10 @@ bool RenderFillLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeo void RenderFillLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, - const TransformState& state, + const TransformState&, const std::shared_ptr&, - [[maybe_unused]] const RenderTree& renderTree, - [[maybe_unused]] UniqueChangeRequestVec& changes) { + const RenderTree&, + UniqueChangeRequestVec& changes) { if (!renderTiles || renderTiles->empty()) { removeAllDrawables(); return; @@ -376,7 +376,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, } auto& bucket = static_cast(*renderData->bucket); - const auto& binders = bucket.paintPropertyBinders.at(getID()); + auto& binders = bucket.paintPropertyBinders.at(getID()); const auto prevBucketID = getRenderTileBucketID(tileID); if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { @@ -386,95 +386,6 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, setRenderTileBucketID(tileID, bucket.getID()); const auto& evaluated = getEvaluated(renderData->layerProperties); - const auto& crossfade = getCrossfade(renderData->layerProperties); - - const auto& fillPatternValue = evaluated.get().constantOr(Faded{"", ""}); - const auto patternPosA = tile.getPattern(fillPatternValue.from.id()); - const auto patternPosB = tile.getPattern(fillPatternValue.to.id()); - binders.setPatternParameters(patternPosA, patternPosB, crossfade); - - const auto zoom = static_cast(state.getZoom()); - - std::optional fillInterpolateUBO = std::nullopt; - std::optional fillOutlineInterpolateUBO = std::nullopt; - std::optional fillPatternInterpolateUBO = std::nullopt; - std::optional fillOutlinePatternInterpolateUBO = std::nullopt; - - auto getFillInterpolateUBO = [&]() -> const FillInterpolateUBO& { - if (!fillInterpolateUBO) { - fillInterpolateUBO = { - /* .color_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .opacity_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - 0, - 0, - }; - } - - return *fillInterpolateUBO; - }; - - auto getFillOutlineInterpolateUBO = [&]() -> const FillOutlineInterpolateUBO& { - if (!fillOutlineInterpolateUBO) { - fillOutlineInterpolateUBO = { - /* .color_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .opacity_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - 0, - 0, - }; - } - - return *fillOutlineInterpolateUBO; - }; - - auto getFillPatternInterpolateUBO = [&]() -> const FillPatternInterpolateUBO& { - if (!fillPatternInterpolateUBO) { - fillPatternInterpolateUBO = { - /* .pattern_from_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .pattern_to_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .opacity_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - 0, - }; - } - - return *fillPatternInterpolateUBO; - }; - - auto getFillOutlinePatternInterpolateUBO = [&]() -> const FillOutlinePatternInterpolateUBO& { - if (!fillOutlinePatternInterpolateUBO) { - fillOutlinePatternInterpolateUBO = { - /* .pattern_from_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .pattern_to_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - /* .opacity_t = */ std::get<0>(binders.get()->interpolationFactor(zoom)), - 0, - }; - } - - return *fillOutlinePatternInterpolateUBO; - }; - - std::optional fillPatternTilePropsUBO = std::nullopt; - auto getFillPatternTilePropsUBO = [&]() -> const FillPatternTilePropsUBO& { - if (!fillPatternTilePropsUBO) { - fillPatternTilePropsUBO = { - /* pattern_from = */ patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, - /* pattern_to = */ patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}, - }; - } - - return *fillPatternTilePropsUBO; - }; - - std::optional fillOutlinePatternTilePropsUBO = std::nullopt; - auto getFillOutlinePatternTilePropsUBO = [&]() -> const FillOutlinePatternTilePropsUBO& { - if (!fillOutlinePatternTilePropsUBO) { - fillOutlinePatternTilePropsUBO = { - /* pattern_from = */ patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, - /* pattern_to = */ patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}, - }; - } - - return *fillOutlinePatternTilePropsUBO; - }; gfx::DrawableTweakerPtr atlasTweaker; auto getAtlasTweaker = [&]() { @@ -498,6 +409,8 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, propertiesAsUniforms.second.clear(); // `Fill*Program` all use `style::FillPaintProperties` + // TODO: Only rebuild the vertex attributes when something has changed. + // TODO: Can we update them in-place instead of replacing? auto vertexAttrs = context.createVertexAttributeArray(); vertexAttrs->readDataDrivenPaintProperties( binders, evaluated, propertiesAsUniforms, idFillColorVertexAttribute); @@ -513,38 +426,10 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, // If we already have drawables for this tile, update them. auto updateExisting = [&](gfx::Drawable& drawable) { - auto& drawableUniforms = drawable.mutableUniformBuffers(); - switch (static_cast(drawable.getType())) { - case FillVariant::Fill: { - drawableUniforms.createOrUpdate(idFillInterpolateUBO, &getFillInterpolateUBO(), context); - break; - } - case FillVariant::FillOutline: { - drawableUniforms.createOrUpdate(idFillInterpolateUBO, &getFillOutlineInterpolateUBO(), context); - break; - } - case FillVariant::FillPattern: { - drawableUniforms.createOrUpdate(idFillInterpolateUBO, &getFillPatternInterpolateUBO(), context); - drawableUniforms.createOrUpdate(idFillTilePropsUBO, &getFillPatternTilePropsUBO(), context); - break; - } - case FillVariant::FillOutlinePattern: { - drawableUniforms.createOrUpdate( - idFillInterpolateUBO, &getFillOutlinePatternInterpolateUBO(), context); - drawableUniforms.createOrUpdate(idFillTilePropsUBO, &getFillOutlinePatternTilePropsUBO(), context); - break; - } - case FillVariant::FillOutlineTriangulated: { - break; - } - default: { -#ifndef NDEBUG - mbgl::Log::Error(mbgl::Event::Render, "Invalid fill variant type supplied during drawable update!"); -#endif - break; - } + if (drawable.getLayerTweaker() != layerTweaker) { + // This drawable was produced on a previous style/bucket, and should not be updated. + return false; } - drawable.setVertexAttributes(vertexAttrs); return true; }; @@ -552,6 +437,16 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, continue; } + const auto addDrawable = [&](std::unique_ptr drawable, FillVariant type) { + drawable->setTileID(tileID); + drawable->setType(static_cast(type)); + drawable->setLayerTweaker(layerTweaker); + drawable->setBinders(renderData->bucket, &binders); + drawable->setRenderTile(renderTilesOwner, &tile); + fillTileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.drawablesAdded; + }; + // Outline always occurs in translucent pass, defaults to fill color // Outline does not default to fill in the pattern case const auto doOutline = evaluated.get() && (unevaluated.get().isUndefined() || @@ -606,13 +501,9 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, bucket.lineSegments.data(), bucket.lineSegments.size()); - // finish builder->flush(context); for (auto& drawable : builder->clearDrawables()) { - drawable->setTileID(tileID); - drawable->setType(static_cast(FillVariant::FillOutlineTriangulated)); - fillTileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.drawablesAdded; + addDrawable(std::move(drawable), FillVariant::FillOutlineTriangulated); } } }; @@ -648,21 +539,11 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, } } - const auto finish = [&](gfx::DrawableBuilder& builder, - const size_t interpolateUBOId, - const auto& interpolateUBO, - FillVariant type) { + const auto finish = [&](gfx::DrawableBuilder& builder, FillVariant type) { builder.flush(context); for (auto& drawable : builder.clearDrawables()) { - drawable->setTileID(tileID); - drawable->setLayerTweaker(layerTweaker); - drawable->setType(static_cast(type)); - - auto& drawableUniforms = drawable->mutableUniformBuffers(); - drawableUniforms.createOrUpdate(interpolateUBOId, &interpolateUBO, context); - fillTileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.drawablesAdded; + addDrawable(std::move(drawable), type); } }; @@ -688,7 +569,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, bucket.sharedTriangles, bucket.triangleSegments.data(), bucket.triangleSegments.size()); - finish(*fillBuilder, idFillInterpolateUBO, getFillInterpolateUBO(), FillVariant::Fill); + finish(*fillBuilder, FillVariant::Fill); } #if MLN_TRIANGULATE_FILL_OUTLINES @@ -704,8 +585,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, bucket.sharedBasicLineIndexes, bucket.basicLineSegments.data(), bucket.basicLineSegments.size()); - finish( - *outlineBuilder, idFillInterpolateUBO, getFillInterpolateUBO(), FillVariant::FillOutline); + finish(*outlineBuilder, FillVariant::FillOutline); } } } @@ -717,7 +597,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, bucket.sharedBasicLineIndexes, bucket.basicLineSegments.data(), bucket.basicLineSegments.size()); - finish(*outlineBuilder, idFillInterpolateUBO, getFillOutlineInterpolateUBO(), FillVariant::FillOutline); + finish(*outlineBuilder, FillVariant::FillOutline); } #endif } else { @@ -770,24 +650,11 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, outlinePatternBuilder->addTweaker(getAtlasTweaker()); } - const auto finish = [&](gfx::DrawableBuilder& builder, - const size_t interpolateNameId, - const auto& interpolateUBO, - const size_t tileUBOId, - const auto& tileUBO, - FillVariant type) { + const auto finish = [&](gfx::DrawableBuilder& builder, FillVariant type) { builder.flush(context); for (auto& drawable : builder.clearDrawables()) { - drawable->setTileID(tileID); - drawable->setLayerTweaker(layerTweaker); - drawable->setType(static_cast(type)); - - auto& drawableUniforms = drawable->mutableUniformBuffers(); - drawableUniforms.createOrUpdate(interpolateNameId, &interpolateUBO, context); - drawableUniforms.createOrUpdate(tileUBOId, &tileUBO, context); - fillTileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.drawablesAdded; + addDrawable(std::move(drawable), type); } }; @@ -806,12 +673,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, bucket.triangleSegments.data(), bucket.triangleSegments.size()); - finish(*patternBuilder, - idFillInterpolateUBO, - getFillPatternInterpolateUBO(), - idFillTilePropsUBO, - getFillPatternTilePropsUBO(), - FillVariant::FillPattern); + finish(*patternBuilder, FillVariant::FillPattern); } if (doOutline && outlinePatternBuilder && bucket.sharedBasicLineIndexes->elements()) { @@ -823,12 +685,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, bucket.basicLineSegments.data(), bucket.basicLineSegments.size()); - finish(*outlinePatternBuilder, - idFillInterpolateUBO, - getFillOutlinePatternInterpolateUBO(), - idFillTilePropsUBO, - getFillOutlinePatternTilePropsUBO(), - FillVariant::FillOutlinePattern); + finish(*outlinePatternBuilder, FillVariant::FillOutlinePattern); } } } diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index f7d17e2c007..03f76378dcf 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -130,7 +130,7 @@ void RenderHeatmapLayer::render(PaintParameters& parameters) { const auto extrudeScale = tile.id.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())); - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); const auto allUniformValues = HeatmapProgram::computeAllUniformValues( HeatmapProgram::LayoutUniformValues{ @@ -361,9 +361,9 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, continue; } - const auto& bucket = static_cast(*renderData->bucket); + auto& bucket = static_cast(*renderData->bucket); const auto vertexCount = bucket.vertices.elements(); - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); const auto prevBucketID = getRenderTileBucketID(tileID); if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { @@ -372,37 +372,14 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, } setRenderTileBucketID(tileID, bucket.getID()); - const float zoom = static_cast(state.getZoom()); - - 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), false); - } - return interpolateBuffer; - }; - - const auto updatedCount = tileLayerGroup->visitDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + auto updateExisting = [&](gfx::Drawable& drawable) { if (drawable.getLayerTweaker() != layerTweaker) { // This drawable was produced on a previous style/bucket, and should not be updated. - return; - } - - // We assume vertex attributes don't change, and so don't update them to avoid re-uploading - // drawable.setVertexAttributes(heatmapVertexAttrs); - - auto& drawableUniforms = drawable.mutableUniformBuffers(); - - if (auto buffer = getInterpolateBuffer()) { - drawableUniforms.set(idHeatmapInterpolateUBO, std::move(buffer)); + return false; } - }); - - if (updatedCount > 0) { + return true; + }; + if (updateTile(renderPass, tileID, std::move(updateExisting))) { continue; } @@ -460,13 +437,8 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, for (auto& drawable : heatmapBuilder->clearDrawables()) { drawable->setTileID(tileID); drawable->setLayerTweaker(layerTweaker); - - auto& drawableUniforms = drawable->mutableUniformBuffers(); - - if (auto buffer = getInterpolateBuffer()) { - drawableUniforms.set(idHeatmapInterpolateUBO, std::move(buffer)); - } - + drawable->setBinders(renderData->bucket, &paintPropertyBinders); + drawable->setRenderTile(renderTilesOwner, &tile); tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); ++stats.drawablesAdded; } diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index bbe2b492a1d..32a75fcb2bb 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -157,7 +157,7 @@ void RenderLineLayer::render(PaintParameters& parameters) { const std::optional& patternPositionA, const std::optional& patternPositionB, auto&& textureBindings) { - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade); @@ -355,12 +355,20 @@ float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, } #if MLN_DRAWABLE_RENDERER +namespace { + +inline void setSegments(std::unique_ptr& builder, const LineBucket& bucket) { + builder->setSegments(gfx::Triangles(), bucket.sharedTriangles, bucket.segments.data(), bucket.segments.size()); +} + +} // namespace + void RenderLineLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, - const TransformState& state, + const TransformState&, [[maybe_unused]] const std::shared_ptr& parameters, - [[maybe_unused]] const RenderTree& renderTree, - [[maybe_unused]] UniqueChangeRequestVec& changes) { + const RenderTree&, + UniqueChangeRequestVec& changes) { if (!renderTiles || renderTiles->empty()) { removeAllDrawables(); return; @@ -437,10 +445,6 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, builder.setVertexAttributes(std::move(vertexAttrs)); }; - auto setSegments = [&](std::unique_ptr& builder, const LineBucket& bucket) { - builder->setSegments(gfx::Triangles(), bucket.sharedTriangles, bucket.segments.data(), bucket.segments.size()); - }; - tileLayerGroup->setStencilTiles(renderTiles); StringIDSetsPair propertiesAsUniforms; @@ -459,9 +463,8 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, continue; } - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); const auto& evaluated = getEvaluated(renderData->layerProperties); - const auto& crossfade = getCrossfade(renderData->layerProperties); const auto prevBucketID = getRenderTileBucketID(tileID); if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { @@ -470,137 +473,32 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, } setRenderTileBucketID(tileID, bucket.getID()); - // interpolation UBOs - const float zoom = static_cast(state.getZoom()); - - std::optional lineInterpolationUBO = std::nullopt; - std::optional lineGradientInterpolationUBO = std::nullopt; - std::optional linePatternInterpolationUBO = std::nullopt; - std::optional lineSDFInterpolationUBO = std::nullopt; - - auto getLineInterpolationUBO = [&]() -> const LineInterpolationUBO& { - if (!lineInterpolationUBO) { - lineInterpolationUBO = { - /*color_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*blur_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*opacity_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*gapwidth_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*offset_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*width_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - 0, - 0}; - } - - return *lineInterpolationUBO; - }; - - auto getLineGradientInterpolationUBO = [&]() -> const LineGradientInterpolationUBO& { - if (!lineGradientInterpolationUBO) { - lineGradientInterpolationUBO = { - /*blur_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*opacity_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*gapwidth_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*offset_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*width_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - 0, - 0, - 0}; - } - - return *lineGradientInterpolationUBO; - }; - - auto getLinePatternInterpolationUBO = [&]() -> const LinePatternInterpolationUBO& { - if (!linePatternInterpolationUBO) { - linePatternInterpolationUBO = { - /*blur_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*opacity_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*offset_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*gapwidth_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*width_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*pattern_from_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*pattern_to_t =*/std::get<1>(paintPropertyBinders.get()->interpolationFactor(zoom)), - 0}; - } - - return *linePatternInterpolationUBO; - }; - - auto getLineSDFInterpolationUBO = [&]() -> const LineSDFInterpolationUBO& { - if (!lineSDFInterpolationUBO) { - lineSDFInterpolationUBO = { - /*color_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*blur_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*opacity_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*gapwidth_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*offset_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*width_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - /*floorwidth_t =*/ - std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), - 0}; - } - - return *lineSDFInterpolationUBO; - }; - - // tile dependent properties UBOs: - std::optional linePatternTilePropertiesUBO = std::nullopt; - const auto& linePatternValue = evaluated.get().constantOr(Faded{"", ""}); - const std::optional patternPosA = tile.getPattern(linePatternValue.from.id()); - const std::optional patternPosB = tile.getPattern(linePatternValue.to.id()); - paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade); - - auto getLinePatternTilePropertiesUBO = [&]() -> const LinePatternTilePropertiesUBO& { - if (!linePatternTilePropertiesUBO) { - linePatternTilePropertiesUBO = { - /*pattern_from =*/patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, - /*pattern_to =*/patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}}; - } - - return *linePatternTilePropertiesUBO; - }; - auto updateExisting = [&](gfx::Drawable& drawable) { if (drawable.getLayerTweaker() != layerTweaker) { // This drawable was produced on a previous style/bucket, and should not be updated. return false; } - - auto& drawableUniforms = drawable.mutableUniformBuffers(); - const LineLayerTweaker::LineType type = static_cast(drawable.getType()); - switch (type) { - case LineLayerTweaker::LineType::Simple: { - drawableUniforms.createOrUpdate(idLineInterpolationUBO, &getLineInterpolationUBO(), context); - } break; - - case LineLayerTweaker::LineType::Gradient: { - drawableUniforms.createOrUpdate( - idLineInterpolationUBO, &getLineGradientInterpolationUBO(), context); - } break; - - case LineLayerTweaker::LineType::Pattern: { - drawableUniforms.createOrUpdate(idLineInterpolationUBO, &getLinePatternInterpolationUBO(), context); - - drawableUniforms.createOrUpdate( - idLineTilePropertiesUBO, &getLinePatternTilePropertiesUBO(), context); - } break; - - case LineLayerTweaker::LineType::SDF: { - drawableUniforms.createOrUpdate(idLineInterpolationUBO, &getLineSDFInterpolationUBO(), context); - } break; - - default: { - using namespace std::string_literals; - Log::Error(Event::General, - "RenderLineLayer: unknown line type: "s + std::to_string(mbgl::underlying_type(type))); - } break; - } return true; }; if (updateTile(renderPass, tileID, std::move(updateExisting))) { continue; } + const auto addDrawable = [&](std::unique_ptr&& drawable, LineLayerTweaker::LineType type) { + drawable->setTileID(tileID); + drawable->setType(mbgl::underlying_type(type)); + drawable->setLayerTweaker(layerTweaker); + drawable->setRenderTile(renderTilesOwner, &tile); + drawable->setBinders(renderData->bucket, &paintPropertyBinders); + + const bool roundCap = bucket.layout.get() == LineCapType::Round; + const auto capType = roundCap ? LinePatternCap::Round : LinePatternCap::Square; + drawable->setData(std::make_unique(capType)); + + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.drawablesAdded; + }; + propertiesAsUniforms.first.clear(); propertiesAsUniforms.second.clear(); @@ -635,20 +533,9 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, addAttributes(*builder, bucket, std::move(vertexAttrs)); setSegments(builder, bucket); - // finish builder->flush(context); - const LinePatternCap cap = bucket.layout.get() == LineCapType::Round ? LinePatternCap::Round - : LinePatternCap::Square; 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( - idLineInterpolationUBO, &getLineSDFInterpolationUBO(), context); - - tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.drawablesAdded; + addDrawable(std::move(drawable), LineLayerTweaker::LineType::SDF); } } else if (!unevaluated.get().isUndefined()) { // pattern line @@ -689,16 +576,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, builder->flush(context); for (auto& drawable : builder->clearDrawables()) { - drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Pattern)); - drawable->setTileID(tileID); - drawable->setLayerTweaker(layerTweaker); - drawable->mutableUniformBuffers().createOrUpdate( - idLineInterpolationUBO, &getLinePatternInterpolationUBO(), context); - drawable->mutableUniformBuffers().createOrUpdate( - idLineTilePropertiesUBO, &getLinePatternTilePropertiesUBO(), context); - - tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.drawablesAdded; + addDrawable(std::move(drawable), LineLayerTweaker::LineType::Pattern); } } } else if (!unevaluated.get().getValue().isUndefined()) { @@ -733,20 +611,11 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, if (colorRampTexture2D) { builder->setTexture(colorRampTexture2D, idLineImageTexture); - // segments setSegments(builder, bucket); - // finish builder->flush(context); for (auto& drawable : builder->clearDrawables()) { - drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Gradient)); - drawable->setTileID(tileID); - drawable->setLayerTweaker(layerTweaker); - drawable->mutableUniformBuffers().createOrUpdate( - idLineInterpolationUBO, &getLineGradientInterpolationUBO(), context); - - tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.drawablesAdded; + addDrawable(std::move(drawable), LineLayerTweaker::LineType::Gradient); } } } else { @@ -769,17 +638,9 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, addAttributes(*builder, bucket, std::move(vertexAttrs)); setSegments(builder, bucket); - // finish builder->flush(context); for (auto& drawable : builder->clearDrawables()) { - drawable->setType(mbgl::underlying_type(LineLayerTweaker::LineType::Simple)); - drawable->setTileID(tileID); - drawable->setLayerTweaker(layerTweaker); - drawable->mutableUniformBuffers().createOrUpdate( - idLineInterpolationUBO, &getLineInterpolationUBO(), context); - - tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.drawablesAdded; + addDrawable(std::move(drawable), LineLayerTweaker::LineType::Simple); } } } diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index f30bef482e0..760450a28f5 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -725,49 +725,8 @@ void RenderSymbolLayer::prepare(const LayerPrepareParameters& params) { #if MLN_DRAWABLE_RENDERER namespace { - const SegmentVector emptySegmentVector; - -template -const auto& getProperty(const SymbolBucket::PaintProperties& paintProps, bool isText) { - return isText ? paintProps.textBinders.get() : paintProps.iconBinders.get(); -} - -template -auto getInterpFactor(const SymbolBucket::PaintProperties& paintProps, bool isText, float currentZoom) { - return std::get(getProperty(paintProps, isText)->interpolationFactor(currentZoom)); -} - -SymbolInterpolateUBO buildInterpUBO(const SymbolBucket::PaintProperties& paint, const bool t, const float z) { - return {/* .fill_color_t = */ getInterpFactor(paint, t, z), - /* .halo_color_t = */ getInterpFactor(paint, t, z), - /* .opacity_t = */ getInterpFactor(paint, t, z), - /* .halo_width_t = */ getInterpFactor(paint, t, z), - /* .halo_blur_t = */ getInterpFactor(paint, t, z), - /* .padding = */ 0, - 0, - 0}; -} - -SymbolTilePropsUBO buildTileUBO(const SymbolBucket& bucket, - const gfx::SymbolDrawableData& drawData, - const float currentZoom) { - const bool isText = (drawData.symbolType == SymbolType::Text); - const ZoomEvaluatedSize size = isText ? bucket.textSizeBinder->evaluateForZoom(currentZoom) - : bucket.iconSizeBinder->evaluateForZoom(currentZoom); - return { - /* .is_text = */ isText, - /* .is_halo = */ drawData.isHalo, - /* .pitch_with_map = */ (drawData.pitchAlignment == style::AlignmentType::Map), - /* .is_size_zoom_constant = */ size.isZoomConstant, - /* .is_size_feature_constant = */ size.isFeatureConstant, - /* .size_t = */ size.sizeT, - /* .size = */ size.size, - /* .padding = */ 0, - }; -} - -const auto posOffsetAttribName = "a_pos_offset"; +constexpr auto posOffsetAttribName = "a_pos_offset"; void updateTileAttributes(const SymbolBucket::Buffer& buffer, const bool isText, @@ -824,13 +783,9 @@ void updateTileAttributes(const SymbolBucket::Buffer& buffer, } void updateTileDrawable(gfx::Drawable& drawable, - gfx::Context& context, const SymbolBucket& bucket, const SymbolBucket::PaintProperties& paintProps, - const SymbolPaintProperties::PossiblyEvaluated& evaluated, - const TransformState& state, - gfx::UniformBufferPtr& textInterpUBO, - gfx::UniformBufferPtr& iconInterpUBO) { + const SymbolPaintProperties::PossiblyEvaluated& evaluated) { if (!drawable.getData()) { return; } @@ -838,31 +793,10 @@ void updateTileDrawable(gfx::Drawable& drawable, auto& drawData = static_cast(*drawable.getData()); const auto isText = (drawData.symbolType == SymbolType::Text); const auto sdfIcons = (drawData.symbolType == SymbolType::IconSDF); - const auto currentZoom = static_cast(state.getZoom()); // This property can be set after the initial appearance of the tile, as part of the layout process. drawData.bucketVariablePlacement = bucket.hasVariablePlacement; - auto& drawableUniforms = drawable.mutableUniformBuffers(); - - // Create or update the shared interpolation UBO - gfx::UniformBufferPtr& interpUBO = isText ? textInterpUBO : iconInterpUBO; - if (interpUBO) { - drawableUniforms.set(idSymbolInterpolateUBO, interpUBO); - } else { - const auto ubo = buildInterpUBO(paintProps, isText, currentZoom); - interpUBO = drawableUniforms.get(idSymbolInterpolateUBO); - if (interpUBO) { - interpUBO->update(&ubo, sizeof(ubo)); - } else { - interpUBO = context.createUniformBuffer(&ubo, sizeof(ubo)); - drawableUniforms.set(idSymbolInterpolateUBO, interpUBO); - } - } - - const auto tileUBO = buildTileUBO(bucket, drawData, currentZoom); - drawableUniforms.createOrUpdate(idSymbolTilePropsUBO, &tileUBO, context); - const auto& buffer = isText ? bucket.text : (sdfIcons ? bucket.sdfIcon : bucket.icon); const auto vertexCount = buffer.vertices().elements(); @@ -973,7 +907,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, const std::shared_ptr&, - const RenderTree& /*renderTree*/, + const RenderTree&, UniqueChangeRequestVec& changes) { if (!renderTiles || renderTiles->empty() || passes == RenderPass::None) { removeAllDrawables(); @@ -1071,6 +1005,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto& renderData = *optRenderData; const auto& bucket = static_cast(*renderData.bucket); + const auto& evaluated = getEvaluated(renderData.layerProperties); const auto prevBucketID = getRenderTileBucketID(tileID); if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { @@ -1091,11 +1026,10 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, } const auto& layout = *bucket.layout; - const auto& evaluated = getEvaluated(renderData.layerProperties); const auto values = isText ? textPropertyValues(evaluated, layout) : iconPropertyValues(evaluated, layout); const std::string suffix = isText ? "text/" : "icon/"; - auto addVertices = [&collisionBuilder](const auto& vertices) { + const auto addVertices = [&collisionBuilder](const auto& vertices) { collisionBuilder->setRawVertices({}, vertices.size(), gfx::AttributeDataType::Short2); }; @@ -1145,7 +1079,6 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, // If we already have drawables for this tile, update them. // Just update the drawables we already created - gfx::UniformBufferPtr textInterpUBO, iconInterpUBO; auto updateExisting = [&](gfx::Drawable& drawable) { if (drawable.getLayerTweaker() != layerTweaker) { // This drawable was produced on a previous style/bucket, and should not be updated. @@ -1155,9 +1088,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, propertiesAsUniforms.first.clear(); propertiesAsUniforms.second.clear(); - const auto& evaluated = getEvaluated(renderData.layerProperties); - updateTileDrawable( - drawable, context, bucket, bucketPaintProperties, evaluated, state, textInterpUBO, iconInterpUBO); + updateTileDrawable(drawable, bucket, bucketPaintProperties, evaluated); return true; }; if (updateTile(passes, tileID, std::move(updateExisting))) { @@ -1216,10 +1147,9 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, struct TileInfo { RawVertexVec textVertices, iconVertices; gfx::DrawableTweakerPtr textTweaker, iconTweaker; - gfx::UniformBufferPtr textInterp, iconInterp; }; - std::unordered_map tileCache; + mbgl::unordered_map tileCache; tileCache.reserve(renderTiles->size()); for (auto& group : renderableSegments) { @@ -1231,7 +1161,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto& tile = renderable.tile; const auto tileID = tile.id.overscaleTo(renderable.overscaledZ); - const auto& bucket = static_cast(*renderable.renderData.bucket); + auto& bucket = static_cast(*renderable.renderData.bucket); const auto& buffer = isText ? bucket.text : (sdfIcons ? bucket.sdfIcon : bucket.icon); if (!buffer.sharedTriangles->elements()) { @@ -1239,7 +1169,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, } const auto& evaluated = getEvaluated(renderable.renderData.layerProperties); - const auto& bucketPaintProperties = bucket.paintProperties.at(getID()); + auto& bucketPaintProperties = bucket.paintProperties.at(getID()); const auto& layout = *bucket.layout; const auto values = isText ? textPropertyValues(evaluated, layout) : iconPropertyValues(evaluated, layout); @@ -1268,105 +1198,97 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, evaluated.get().constantOr(1); const auto iconFill = evaluated.get().constantOr(Color::black()).a > 0.0f; - // Share interpolation UBOs across all the elements of the same type in each tile - auto& interpUBO = isText ? tileInfo.textInterp : tileInfo.iconInterp; - if (!interpUBO) { - const auto interpolateBuf = buildInterpUBO(bucketPaintProperties, isText, currentZoom); - interpUBO = context.createUniformBuffer(&interpolateBuf, sizeof(interpolateBuf)); - } - if (builder) { builder->clearTweakers(); } - const auto draw = - [&](const gfx::ShaderGroupPtr& shaderGroup, const bool isHalo, const std::string_view suffix) { - if (!shaderGroup) { - return; - } - - // We can use the same tweakers for all the segments in a tile - if (isText && !tileInfo.textTweaker) { - const bool textSizeIsZoomConstant = - bucket.textSizeBinder->evaluateForZoom(static_cast(state.getZoom())).isZoomConstant; - tileInfo.textTweaker = std::make_shared(atlases, - idSymbolImageIconTexture, - idSymbolImageTexture, - isText, - false, - values.rotationAlignment, - false, - textSizeIsZoomConstant); - } - if (!isText && !tileInfo.iconTweaker) { - const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; - tileInfo.iconTweaker = std::make_shared(atlases, - idSymbolImageIconTexture, - idSymbolImageTexture, - isText, - sdfIcons, - values.rotationAlignment, - iconScaled, - false); - } - - if (!builder) { - builder = context.createDrawableBuilder(layerPrefix); - builder->setSubLayerIndex(0); - builder->setRenderPass(passes); - builder->setCullFaceMode(gfx::CullFaceMode::disabled()); - builder->setDepthType(gfx::DepthMaskType::ReadOnly); - builder->setColorMode( - ((mbgl::underlying_type(passes) & mbgl::underlying_type(RenderPass::Translucent)) != 0) - ? gfx::ColorMode::alphaBlended() - : gfx::ColorMode::unblended()); - } + const auto draw = [&](const gfx::ShaderGroupPtr& shaderGroup, + const bool isHalo, + const std::string_view suffix) { + if (!shaderGroup) { + return; + } - const auto shader = std::static_pointer_cast( - shaderGroup->getOrCreateShader(context, propertiesAsUniforms, posOffsetAttribName)); - if (!shader) { - return; - } - builder->setShader(shader); - - builder->clearTweakers(); - builder->addTweaker(isText ? tileInfo.textTweaker : tileInfo.iconTweaker); - builder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short4); - builder->setDrawableName(layerPrefix + std::string(suffix)); - builder->setVertexAttributes(attribs); - - if (segments.empty()) { - builder->setSegments(gfx::Triangles(), buffer.sharedTriangles, &renderable.segment.get(), 1); - } else { - builder->setSegments(gfx::Triangles(), buffer.sharedTriangles, segments.data(), segments.size()); - } + // We can use the same tweakers for all the segments in a tile + if (isText && !tileInfo.textTweaker) { + const bool textSizeIsZoomConstant = bucket.textSizeBinder->evaluateForZoom(currentZoom).isZoomConstant; + tileInfo.textTweaker = std::make_shared(atlases, + idSymbolImageIconTexture, + idSymbolImageTexture, + isText, + false, + values.rotationAlignment, + false, + textSizeIsZoomConstant); + } + if (!isText && !tileInfo.iconTweaker) { + const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; + tileInfo.iconTweaker = std::make_shared(atlases, + idSymbolImageIconTexture, + idSymbolImageTexture, + isText, + sdfIcons, + values.rotationAlignment, + iconScaled, + false); + } - builder->flush(context); + if (!builder) { + builder = context.createDrawableBuilder(layerPrefix); + builder->setSubLayerIndex(0); + builder->setRenderPass(passes); + builder->setCullFaceMode(gfx::CullFaceMode::disabled()); + builder->setDepthType(gfx::DepthMaskType::ReadOnly); + builder->setColorMode( + ((mbgl::underlying_type(passes) & mbgl::underlying_type(RenderPass::Translucent)) != 0) + ? gfx::ColorMode::alphaBlended() + : gfx::ColorMode::unblended()); + } - for (auto& drawable : builder->clearDrawables()) { - drawable->setTileID(tileID); - drawable->setLayerTweaker(layerTweaker); + const auto shader = std::static_pointer_cast( + shaderGroup->getOrCreateShader(context, propertiesAsUniforms, posOffsetAttribName)); + if (!shader) { + return; + } + builder->setShader(shader); - auto drawData = std::make_unique( - /*.isHalo=*/isHalo, - /*.bucketVariablePlacement=*/bucket.hasVariablePlacement, - /*.symbolType=*/renderable.type, - /*.pitchAlignment=*/values.pitchAlignment, - /*.rotationAlignment=*/values.rotationAlignment, - /*.placement=*/layout.get(), - /*.textFit=*/layout.get()); + builder->clearTweakers(); + builder->addTweaker(isText ? tileInfo.textTweaker : tileInfo.iconTweaker); + builder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short4); + builder->setDrawableName(layerPrefix + std::string(suffix)); + builder->setVertexAttributes(attribs); - const auto tileUBO = buildTileUBO(bucket, *drawData, currentZoom); - drawable->setData(std::move(drawData)); + if (segments.empty()) { + builder->setSegments(gfx::Triangles(), buffer.sharedTriangles, &renderable.segment.get(), 1); + } else { + builder->setSegments(gfx::Triangles(), buffer.sharedTriangles, segments.data(), segments.size()); + } - auto& drawableUniforms = drawable->mutableUniformBuffers(); - drawableUniforms.createOrUpdate(idSymbolTilePropsUBO, &tileUBO, context); - drawableUniforms.set(idSymbolInterpolateUBO, interpUBO); + builder->flush(context); - tileLayerGroup->addDrawable(passes, tileID, std::move(drawable)); - ++stats.drawablesAdded; - } - }; + for (auto& drawable : builder->clearDrawables()) { + drawable->setTileID(tileID); + drawable->setLayerTweaker(layerTweaker); + drawable->setRenderTile(renderTilesOwner, &tile); + + PaintPropertyBindersBase& textBinders = bucketPaintProperties.textBinders; + PaintPropertyBindersBase& iconBinders = bucketPaintProperties.iconBinders; + drawable->setBinders(renderable.renderData.bucket, isText ? &textBinders : &iconBinders); + + const bool hasVariablePlacement = bucket.hasVariablePlacement; + drawable->setData(std::make_unique( + /*.isHalo=*/isHalo, + /*.bucketVaraiblePlacement=*/hasVariablePlacement, + /*.symbolType=*/renderable.type, + /*.pitchAlignment=*/values.pitchAlignment, + /*.rotationAlignment=*/values.rotationAlignment, + /*.placement=*/layout.get(), + /*.textFit=*/layout.get())); + + tileLayerGroup->addDrawable(passes, tileID, std::move(drawable)); + ++stats.drawablesAdded; + } + }; if (isText) { if (bucket.iconsInText) { diff --git a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp index 93173234bb4..26a2a56f9d2 100644 --- a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp @@ -7,10 +7,11 @@ #include #include #include +#include #include -#include #include #include +#include #include #include #include @@ -40,6 +41,27 @@ std::array toArray(const Size& s) { return util::cast(std::array{s.width, s.height}); } +template +const auto& getProperty(const SymbolBucket::PaintProperties& paintProps, bool isText) { + return isText ? paintProps.textBinders.get() : paintProps.iconBinders.get(); +} + +template +auto getInterpFactor(const SymbolBucket::PaintProperties& paintProps, bool isText, float currentZoom) { + return std::get(getProperty(paintProps, isText)->interpolationFactor(currentZoom)); +} + +SymbolInterpolateUBO buildInterpUBO(const SymbolBucket::PaintProperties& paint, const bool t, const float z) { + return {/* .fill_color_t = */ getInterpFactor(paint, t, z), + /* .halo_color_t = */ getInterpFactor(paint, t, z), + /* .opacity_t = */ getInterpFactor(paint, t, z), + /* .halo_width_t = */ getInterpFactor(paint, t, z), + /* .halo_blur_t = */ getInterpFactor(paint, t, z), + /* .padding = */ 0, + 0, + 0}; +} + } // namespace void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters& parameters) { @@ -56,25 +78,44 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str()); #endif + const auto zoom = static_cast(state.getZoom()); + if (!evaluatedPropsUniformBuffer || propertiesUpdated) { const SymbolEvaluatedPropsUBO propsUBO = {/*.text_fill_color=*/constOrDefault(evaluated), /*.text_halo_color=*/constOrDefault(evaluated), /*.text_opacity=*/constOrDefault(evaluated), /*.text_halo_width=*/constOrDefault(evaluated), /*.text_halo_blur=*/constOrDefault(evaluated), - 0, + /* pad */ 0, /*.icon_fill_color=*/constOrDefault(evaluated), /*.icon_halo_color=*/constOrDefault(evaluated), /*.icon_opacity=*/constOrDefault(evaluated), /*.icon_halo_width=*/constOrDefault(evaluated), /*.icon_halo_blur=*/constOrDefault(evaluated), - 0}; + /* pad */ 0}; context.emplaceOrUpdateUniformBuffer(evaluatedPropsUniformBuffer, &propsUBO); propertiesUpdated = false; } auto& layerUniforms = layerGroup.mutableUniformBuffers(); layerUniforms.set(idSymbolEvaluatedPropsUBO, evaluatedPropsUniformBuffer); + const auto getInterpUBO = + [&](const UnwrappedTileID& tileID, bool isText, const SymbolBucket::PaintProperties& paintProps) { + auto result = interpUBOs.insert( + std::make_pair(InterpUBOKey{tileID, isText}, InterpUBOValue{{}, parameters.frameCount})); + if (result.second) { + // new item inserted + const auto interpolateBuf = buildInterpUBO(paintProps, isText, zoom); + result.first->second.ubo = context.createUniformBuffer(&interpolateBuf, sizeof(interpolateBuf)); + } else if (result.first->second.updatedFrame < parameters.frameCount) { + // existing item found, but hasn't been updated this frame + const auto interpolateBuf = buildInterpUBO(paintProps, isText, zoom); + result.first->second.ubo->update(&interpolateBuf, sizeof(interpolateBuf)); + result.first->second.updatedFrame = parameters.frameCount; + } + return result.first->second.ubo; + }; + const auto camDist = state.getCameraToCenterDistance(); visitLayerGroupDrawables(layerGroup, [&](gfx::Drawable& drawable) { if (!drawable.getTileID() || !drawable.getData()) { @@ -85,6 +126,18 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete const auto& symbolData = static_cast(*drawable.getData()); const auto isText = (symbolData.symbolType == SymbolType::Text); + const auto* textBinders = isText ? static_cast(drawable.getBinders()) : nullptr; + const auto* iconBinders = isText ? nullptr : static_cast(drawable.getBinders()); + + const auto bucket = std::static_pointer_cast(drawable.getBucket()); + const auto* tile = drawable.getRenderTile(); + if (!bucket || !tile || (!textBinders && !iconBinders)) { + assert(false); + return; + } + + const auto& paintProperties = bucket->paintProperties.at(id); + // from RenderTile::translatedMatrix const auto translate = isText ? evaluated.get() : evaluated.get(); const auto anchor = isText ? evaluated.get() @@ -131,9 +184,36 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParamete /*.pad=*/{0}, }; + const auto& sizeBinder = isText ? bucket->textSizeBinder : bucket->iconSizeBinder; + const auto size = sizeBinder->evaluateForZoom(currentZoom); + const auto tileUBO = SymbolTilePropsUBO{ + /* .is_text = */ isText, + /* .is_halo = */ symbolData.isHalo, + /* .pitch_with_map = */ (symbolData.pitchAlignment == style::AlignmentType::Map), + /* .is_size_zoom_constant = */ size.isZoomConstant, + /* .is_size_feature_constant = */ size.isFeatureConstant, + /* .size_t = */ size.sizeT, + /* .size = */ size.size, + /* .padding = */ 0, + }; + auto& drawableUniforms = drawable.mutableUniformBuffers(); drawableUniforms.createOrUpdate(idSymbolDrawableUBO, &drawableUBO, context); + drawableUniforms.createOrUpdate(idSymbolTilePropsUBO, &tileUBO, context); + drawableUniforms.set(idSymbolInterpolateUBO, getInterpUBO(tileID, isText, paintProperties)); }); + + // Regularly remove UBOs which are not being updated + constexpr int pruneFrameInterval = 10; + if ((parameters.frameCount % pruneFrameInterval) == 0) { + for (auto i = interpUBOs.begin(); i != interpUBOs.end();) { + if (i->second.updatedFrame < parameters.frameCount) { + i = interpUBOs.erase(i); + } else { + i++; + } + } + } } } // namespace mbgl diff --git a/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp b/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp index 0c0d1030cd2..1ac4fb46baa 100644 --- a/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp +++ b/src/mbgl/renderer/layers/symbol_layer_tweaker.hpp @@ -1,6 +1,9 @@ #pragma once #include +#include +#include +#include #include @@ -13,14 +16,28 @@ class SymbolLayerTweaker : public LayerTweaker { public: SymbolLayerTweaker(std::string id_, Immutable properties) : LayerTweaker(std::move(id_), properties) {} - -public: ~SymbolLayerTweaker() override = default; void execute(LayerGroupBase&, const PaintParameters&) override; private: gfx::UniformBufferPtr evaluatedPropsUniformBuffer; + + // Interpolation UBOs are shared by drawables of the same type (text/icon) in each tile + struct InterpUBOKey { + UnwrappedTileID tileID; + bool isText; + + bool operator==(const InterpUBOKey& other) const { return isText == other.isText && tileID == other.tileID; } + }; + struct InterpUBOValue { + gfx::UniformBufferPtr ubo; + uint64_t updatedFrame = 0; + }; + struct InterpUBOHash { + size_t operator()(const InterpUBOKey& k) const { return util::hash(k.tileID, k.isText); } + }; + mbgl::unordered_map interpUBOs; }; } // namespace mbgl diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index b239f182257..b34e8113f37 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -717,11 +717,13 @@ struct InterpolationUniform { static constexpr auto name() { return concat_literals<&Attr::name, &string_literal<'_', 't'>::value>::value(); } }; +class PaintPropertyBindersBase {}; + template class PaintPropertyBinders; template -class PaintPropertyBinders> { +class PaintPropertyBinders> : public PaintPropertyBindersBase { private: template struct Detail; @@ -774,7 +776,7 @@ class PaintPropertyBinders> { void setPatternParameters(const std::optional& posA, const std::optional& posB, - const CrossfadeParameters& crossfade) const { + const CrossfadeParameters& crossfade) { util::ignore({(binders.template get()->setPatternParameters(posA, posB, crossfade), 0)...}); } diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index 5a52417694f..070599044aa 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -21,7 +21,8 @@ using namespace style; RenderLayer::RenderLayer(Immutable properties) : evaluatedProperties(std::move(properties)), - baseImpl(evaluatedProperties->baseImpl) {} + baseImpl(evaluatedProperties->baseImpl), + renderTilesOwner(makeMutable>()) {} void RenderLayer::transition(const TransitionParameters& parameters, Immutable newImpl) { baseImpl = std::move(newImpl); @@ -58,6 +59,7 @@ void RenderLayer::prepare(const LayerPrepareParameters& params) { assert(params.source); assert(params.source->isEnabled()); renderTiles = params.source->getRenderTiles(); + renderTilesOwner = params.source->getRawRenderTiles(); addRenderPassesFromTiles(); #if MLN_DRAWABLE_RENDERER diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index 81cf911be89..be8d6da94cb 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -276,6 +276,9 @@ class RenderLayer { // Stores current set of tiles to be rendered for this layer. RenderTiles renderTiles; + // Retains ownership of tiles + Immutable> renderTilesOwner; + // Stores what render passes this layer is currently enabled for. This depends on the // evaluated StyleProperties object and is updated accordingly. RenderPass passes = RenderPass::None; diff --git a/src/mbgl/renderer/render_source.cpp b/src/mbgl/renderer/render_source.cpp index 405030a76c7..46eddb69cef 100644 --- a/src/mbgl/renderer/render_source.cpp +++ b/src/mbgl/renderer/render_source.cpp @@ -1,16 +1,16 @@ #include + +#include +#include #include #include #include #include #include -#include -#include #include #include +#include #include - -#include #include #include @@ -91,4 +91,8 @@ uint8_t RenderSource::getMaxZoom() const { return util::TERRAIN_RGB_MAXZOOM; } +Immutable> RenderSource::getRawRenderTiles() const { + return makeMutable>(); +} + } // namespace mbgl diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp index 58e6d129f76..80a8dbe6d2f 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -76,6 +76,7 @@ class RenderSource : protected TileObserver { // If supported, returns pointer to image data; returns nullptr otherwise. virtual const ImageSourceRenderData* getImageRenderData() const { return nullptr; } virtual const Tile* getRenderedTile(const UnwrappedTileID&) const { return nullptr; } + virtual Immutable> getRawRenderTiles() const; virtual std::unordered_map> queryRenderedFeatures( const ScreenLineString& geometry, diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index f700d9ffea0..2ada89a46e5 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -1,15 +1,15 @@ #include -#include +#include +#include +#include #include +#include #include #include #include -#include -#include -#include -#include #include +#include #include namespace mbgl { diff --git a/src/mbgl/renderer/sources/render_tile_source.hpp b/src/mbgl/renderer/sources/render_tile_source.hpp index 66681a7f197..1378ade4a1b 100644 --- a/src/mbgl/renderer/sources/render_tile_source.hpp +++ b/src/mbgl/renderer/sources/render_tile_source.hpp @@ -29,6 +29,7 @@ class RenderTileSource : public RenderSource { RenderTiles getRenderTiles() const override; RenderTiles getRenderTilesSortedByYPosition() const override; const Tile* getRenderedTile(const UnwrappedTileID&) const override; + Immutable> getRawRenderTiles() const override { return renderTiles; } std::unordered_map> queryRenderedFeatures( const ScreenLineString& geometry,