Skip to content

perf: cull polylines via cached projected bounding boxes#2212

Open
ben-milanko wants to merge 2 commits into
fleaflet:masterfrom
ben-milanko:perf/polyline-culling-bbox
Open

perf: cull polylines via cached projected bounding boxes#2212
ben-milanko wants to merge 2 commits into
fleaflet:masterfrom
ben-milanko:perf/polyline-culling-bbox

Conversation

@ben-milanko

Copy link
Copy Markdown
Contributor

While profiling flutter_map in a production app on low-powered hardware, I found two per-frame O(points) scans in PolylineLayer's aggressive culling:

  • stretchesBeyondTheLimits() iterates every point of every polyline that overlaps the viewport latitudes, every frame
  • fully-visible polylines still go through the per-segment aabbContainsLine scan (and sublist allocations), even though nothing needs to be culled

This PR caches the projected-space bounding box on _ProjectedPolyline (computed lazily — culled fragments never compute one; cached instances are created once per zoom level alongside simplification). The world-stretch check becomes an O(1) bbox comparison, and polylines whose bbox is contained in the viewport bounds are yielded whole, skipping the segment scan entirely.

Results

Measured with flutter test benchmark/feature_layer_benchmark_test.dart (JIT, best-of-reps):

before after
600 polylines × 60 pts, all visible, panning 2,631 µs/frame 2,484 µs/frame (~6%)
Mostly-culled scenario unchanged unchanged

Modest in this paint-dominated scenario, but the cull step itself no longer scales with point count, which matters as polyline density grows.

All existing tests pass. The benchmark harness commit is shared with #2211 (identical file content — it collapses out of this diff once either merges).

Cache the projected-space bounding box on each projected polyline
(lazily, so culled fragments never compute one). This replaces two
per-frame O(points) scans in aggressive culling:

- world-stretch detection now compares the bbox against the world east
  and west edges, instead of iterating every point of every polyline
  that overlaps the viewport latitudes
- fully-visible polylines (bbox contained in the viewport bounds) skip
  the per-segment aabbContainsLine scan and its sublist allocations

Benchmark (benchmark/feature_layer_benchmark_test.dart, JIT):
600 polylines x 60 pts, all visible, panning:
2631 -> 2484 us/frame. Mostly-culled scenario unchanged.
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant