perf: cache zoom-independent marker projections in MarkerLayer#2213
Open
ben-milanko wants to merge 2 commits into
Open
perf: cache zoom-independent marker projections in MarkerLayer#2213ben-milanko wants to merge 2 commits into
ben-milanko wants to merge 2 commits into
Conversation
Widget- and kernel-level CPU benchmarks for the polyline, polygon, and
marker layers, plus a direct getOffsetsXY benchmark. Lives in
benchmark/ (not test/) so it is opt-in and does not extend CI runtime:
flutter test benchmark/feature_layer_benchmark_test.dart
Numbers are JIT and only meaningful relative to each other (before vs
after a change on the same machine).
(cherry picked from commit ed76dc6)
MarkerLayer re-projected every marker (LatLng -> projected space, which involves trigonometry for spherical mercator) on every camera change. The projection only depends on the CRS - not on the camera position or zoom - so cache it per markers list and apply just the linear projected -> screen transform per frame. Also hoists pixelBounds, pixelOrigin, and the zoom scale out of the per-marker loop. Cache invalidation matches the polyline/polygon layers' convention: any new widget instance re-projects (didUpdateWidget), so in-place mutation of the markers list behaves as before. The finiteness guard from Crs.latLngToXY (fleaflet#2178) is preserved at cache-build time. Benchmark (benchmark/feature_layer_benchmark_test.dart, JIT): 10k markers, mostly culled, panning: 1861 -> 1522 us/frame (~18%). Scenarios with many visible markers are dominated by Stack diffing and unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
While profiling flutter_map in a production app on low-powered hardware, I found that
MarkerLayerre-projects every marker (projectAtZoom, which involves trigonometry for spherical mercator) on every camera change. The LatLng → projected-space step only depends on the CRS — not on the camera position or zoom — so it can be cached, leaving only the linear projected → screen transform per marker per frame.This PR converts
MarkerLayerto aStatefulWidgetthat caches the projected coordinates per markers list (re-projecting on anydidUpdateWidget, matching the invalidation convention of the polyline/polygon layers, so in-place list mutation behaves exactly as before). It also hoistspixelBounds,pixelOrigin, and the zoom scale out of the per-marker loop. The non-finite-LatLng guard fromCrs.latLngToXY(#2178) is preserved at cache-build time.Results
Measured with
flutter test benchmark/feature_layer_benchmark_test.dart(JIT, best-of-reps):Stackdiffing)All existing tests pass. No API change —
MarkerLayer's constructor and fields are untouched.The benchmark harness commit is shared with #2211 (identical file content — it collapses out of this diff once either merges).