Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core] Orchestration performance for styles with multiple sources #15756

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 40 additions & 4 deletions benchmark/api/render.benchmark.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
#include <benchmark/benchmark.h>

#include <mbgl/gfx/headless_frontend.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/map/map_observer.hpp>
#include <mbgl/map/map_options.hpp>
#include <mbgl/gfx/headless_frontend.hpp>
#include <mbgl/renderer/renderer.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/storage/resource_options.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/storage/resource_options.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/io.hpp>
#include <mbgl/util/run_loop.hpp>

#include <sstream>

using namespace mbgl;

namespace {
Expand Down Expand Up @@ -94,7 +98,39 @@ static void API_renderStill_recreate_map(::benchmark::State& state) {
}
}

static void API_renderStill_multiple_sources(::benchmark::State& state) {
using namespace mbgl::style;
RenderBenchmark bench;
HeadlessFrontend frontend{size, pixelRatio};
Map map{frontend,
MapObserver::nullObserver(),
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
ResourceOptions().withCachePath(cachePath).withAccessToken("foobar")};
prepare(map);
auto& style = map.getStyle();
const int kSourcesCount = 50;
const int kLayersCount = 50;
for (int i = 0; i < kSourcesCount; ++i) {
std::ostringstream sourceOss;
sourceOss << "GeoJSONSource" << i;
std::string sourceId{sourceOss.str()};
auto source = std::make_unique<GeoJSONSource>(sourceId);
style.addSource(std::move(source));
for (int j = 0; j < kLayersCount; ++j) {
std::ostringstream layerOss;
layerOss << sourceId << '#' << j;
auto layer = std::make_unique<SymbolLayer>(layerOss.str(), sourceId);
style.addLayer(std::move(layer));
}
}

while (state.KeepRunning()) {
frontend.render(map);
}
}

BENCHMARK(API_renderStill_reuse_map);
BENCHMARK(API_renderStill_reuse_map_formatted_labels);
BENCHMARK(API_renderStill_reuse_map_switch_styles);
BENCHMARK(API_renderStill_recreate_map);
BENCHMARK(API_renderStill_multiple_sources);
3 changes: 3 additions & 0 deletions platform/android/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to

## master

### Performance improvements
- Improved rendering performance for the styles with multiple sources [#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756)

## 8.5.0-alpha.1 - October 3, 2019
[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0...android-v8.5.0-alpha.1) since [Mapbox Maps SDK for Android v8.4.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0):
### Bug fixes
Expand Down
6 changes: 6 additions & 0 deletions platform/ios/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started.

## master

### Performance improvements

* Improved rendering performance for the styles with multiple sources ([#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756))

## 5.5.0

### Other changes
Expand Down
61 changes: 36 additions & 25 deletions src/mbgl/renderer/render_orchestrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar

const LayerDifference layerDiff = diffLayers(layerImpls, updateParameters.layers);
layerImpls = updateParameters.layers;
const bool layersAddedOrRemoved = !layerDiff.added.empty() || !layerDiff.removed.empty();

// Remove render layers for removed layers.
for (const auto& entry : layerDiff.removed) {
Expand All @@ -238,20 +239,31 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar
renderLayers.at(entry.first)->transition(transitionParameters, entry.second.after);
}

if (!layerDiff.removed.empty() || !layerDiff.added.empty() || !layerDiff.changed.empty()) {
glyphManager->evict(fontStacks(*updateParameters.layers));
if (layersAddedOrRemoved) {
orderedLayers.clear();
orderedLayers.reserve(layerImpls->size());
for (const auto& layerImpl : *layerImpls) {
RenderLayer* layer = renderLayers.at(layerImpl->id).get();
assert(layer);
orderedLayers.emplace_back(*layer);
}
}
assert(orderedLayers.size() == renderLayers.size());

if (layersAddedOrRemoved || !layerDiff.changed.empty()) {
glyphManager->evict(fontStacks(*layerImpls));
}

// Update layers for class and zoom changes.
std::unordered_set<std::string> constantsMaskChanged;
for (const auto& entry : renderLayers) {
RenderLayer& layer = *entry.second;
const bool layerAddedOrChanged = layerDiff.added.count(entry.first) || layerDiff.changed.count(entry.first);
for (RenderLayer& layer : orderedLayers) {
const std::string& id = layer.getID();
const bool layerAddedOrChanged = layerDiff.added.count(id) || layerDiff.changed.count(id);
if (layerAddedOrChanged || zoomChanged || layer.hasTransition() || layer.hasCrossfade()) {
auto previousMask = layer.evaluatedProperties->constantsMask();
layer.evaluate(evaluationParameters);
if (previousMask != layer.evaluatedProperties->constantsMask()) {
constantsMaskChanged.insert(layer.getID());
constantsMaskChanged.insert(id);
}
}
}
Expand Down Expand Up @@ -281,7 +293,7 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar
renderLight.getEvaluated());

std::set<LayerRenderItem> layerRenderItems;
std::vector<std::reference_wrapper<RenderLayer>> layersNeedPlacement;
layersNeedPlacement.clear();
auto renderItemsEmplaceHint = layerRenderItems.begin();

// Reserve size for filteredLayersForSource if there are sources.
Expand All @@ -293,27 +305,26 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar
for (const auto& sourceImpl : *sourceImpls) {
RenderSource* source = renderSources.at(sourceImpl->id).get();
bool sourceNeedsRendering = false;
bool sourceNeedsRelayout = false;

uint32_t index = 0u;
const auto begin = layerImpls->begin();
const auto end = layerImpls->end();
for (auto it = begin; it != end; ++it, ++index) {
const Immutable<Layer::Impl>& layerImpl = *it;
RenderLayer* layer = getRenderLayer(layerImpl->id);
const auto* layerInfo = layerImpl->getTypeInfo();
const bool layerIsVisible = layer->baseImpl->visibility != style::VisibilityType::None;
const bool zoomFitsLayer = layer->supportsZoom(zoomHistory.lastZoom);
bool sourceNeedsRelayout = false;

for (uint32_t index = 0u; index < orderedLayers.size(); ++index) {
RenderLayer& layer = orderedLayers[index];
const auto* layerInfo = layer.baseImpl->getTypeInfo();
const bool layerIsVisible = layer.baseImpl->visibility != style::VisibilityType::None;
const bool zoomFitsLayer = layer.supportsZoom(zoomHistory.lastZoom);
renderTreeParameters->has3D |= (layerInfo->pass3d == LayerTypeInfo::Pass3D::Required);

if (layerInfo->source != LayerTypeInfo::Source::NotRequired) {
if (layerImpl->source == sourceImpl->id) {
sourceNeedsRelayout = (sourceNeedsRelayout || hasImageDiff || constantsMaskChanged.count(layerImpl->id) || hasLayoutDifference(layerDiff, layerImpl->id));
if (layer.baseImpl->source == sourceImpl->id) {
const std::string& layerId = layer.getID();
sourceNeedsRelayout = (sourceNeedsRelayout || hasImageDiff || constantsMaskChanged.count(layerId) ||
hasLayoutDifference(layerDiff, layerId));
if (layerIsVisible) {
filteredLayersForSource.push_back(layer->evaluatedProperties);
filteredLayersForSource.push_back(layer.evaluatedProperties);
if (zoomFitsLayer) {
sourceNeedsRendering = true;
renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, source, index);
renderItemsEmplaceHint =
layerRenderItems.emplace_hint(renderItemsEmplaceHint, layer, source, index);
}
}
}
Expand All @@ -322,14 +333,14 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar

// Handle layers without source.
if (layerIsVisible && zoomFitsLayer && sourceImpl.get() == sourceImpls->at(0).get()) {
if (backgroundLayerAsColor && layerImpl.get() == layerImpls->at(0).get()) {
const auto& solidBackground = layer->getSolidBackground();
if (backgroundLayerAsColor && layer.baseImpl == layerImpls->front()) {
const auto& solidBackground = layer.getSolidBackground();
if (solidBackground) {
renderTreeParameters->backgroundColor = *solidBackground;
continue; // This layer is shown with background color, and it shall not be added to render items.
}
}
renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, nullptr, index);
renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, layer, nullptr, index);
}
}
source->update(sourceImpl,
Expand Down
4 changes: 3 additions & 1 deletion src/mbgl/renderer/render_orchestrator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,11 @@ class RenderOrchestrator final : public GlyphManagerObserver,
const bool backgroundLayerAsColor;
bool contextLost = false;

// Vector with reserved capacity of layerImpls->size() to avoid reallocation
// Vectors with reserved capacity of layerImpls->size() to avoid reallocation
// on each frame.
std::vector<Immutable<style::LayerProperties>> filteredLayersForSource;
std::vector<std::reference_wrapper<RenderLayer>> orderedLayers;
std::vector<std::reference_wrapper<RenderLayer>> layersNeedPlacement;
};

} // namespace mbgl