Skip to content

Commit 3678449

Browse files
committed
perf: Do not duplicate same vector tiles in GPU memory
1 parent 3565fe7 commit 3678449

10 files changed

Lines changed: 119 additions & 47 deletions

File tree

galileo/src/layer/raster_tile_layer/mod.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::any::Any;
44
use std::sync::Arc;
55

6+
use galileo_types::cartesian::Vector2;
67
use provider::RasterTileProvider;
78
use web_time::Duration;
89

@@ -89,9 +90,12 @@ impl RasterTileLayer {
8990
};
9091

9192
let needed_indices: Vec<_> = tile_iter.collect();
93+
let mut to_pack: Vec<TileIndex> = needed_indices.iter().map(|t| (*t).into()).collect();
94+
to_pack.dedup();
95+
9296
self.tile_container
9397
.tile_provider
94-
.pack_tiles(&needed_indices, canvas);
98+
.pack_tiles(&to_pack, canvas);
9599
let requires_redraw = self
96100
.tile_container
97101
.update_displayed_tiles(needed_indices, ());
@@ -137,7 +141,13 @@ impl RasterTileLayer {
137141
for index in iter {
138142
let tile_provider = self.tile_loader.clone();
139143
let messenger = self.messenger.clone();
140-
Self::load_tile(index, tile_provider, self.tile_container.clone(), messenger).await;
144+
Self::load_tile(
145+
index.into(),
146+
tile_provider,
147+
self.tile_container.clone(),
148+
messenger,
149+
)
150+
.await;
141151
}
142152
}
143153
}
@@ -155,7 +165,11 @@ impl Layer for RasterTileLayer {
155165
let displayed_tiles = self.tile_container.tiles.lock();
156166
let to_render: Vec<_> = displayed_tiles
157167
.iter()
158-
.map(|v| BundleToDraw::with_opacity(&*v.bundle, v.opacity))
168+
.filter_map(|v| {
169+
let tile_bbox = self.tile_schema.tile_bbox(v.index)?;
170+
let offset = Vector2::new(tile_bbox.x_min() as f32, tile_bbox.y_max() as f32);
171+
Some(BundleToDraw::new(&*v.bundle, v.opacity, offset))
172+
})
159173
.collect();
160174

161175
canvas.draw_bundles(&to_render, RenderOptions::default());
@@ -168,7 +182,7 @@ impl Layer for RasterTileLayer {
168182
let container = self.tile_container.clone();
169183
let messenger = self.messenger.clone();
170184
crate::async_runtime::spawn(async move {
171-
Self::load_tile(index, tile_provider, container, messenger).await;
185+
Self::load_tile(index.into(), tile_provider, container, messenger).await;
172186
});
173187
}
174188
}

galileo/src/layer/raster_tile_layer/provider.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::sync::Arc;
22

33
use bytes::Bytes;
4+
use galileo_types::cartesian::Rect;
45
use maybe_sync::{MaybeSend, MaybeSync};
56
use parking_lot::Mutex;
67
use quick_cache::sync::Cache;
@@ -167,10 +168,12 @@ impl RasterTileProvider {
167168
let tiles = self.tiles.lock();
168169
for index in indices {
169170
if let Some(TileState::Loaded(image)) = tiles.get(index) {
170-
let Some(tile_bbox) = self.tile_schema.tile_bbox(*index) else {
171-
log::warn!("Failed to get bbox for tile {index:?}");
171+
let Some(resolution) = self.tile_schema.lod_resolution(index.z) else {
172172
continue;
173173
};
174+
let width = self.tile_schema.tile_width() as f64;
175+
let height = self.tile_schema.tile_height() as f64;
176+
let tile_bbox = Rect::new(0.0, 0.0, width * resolution, -height * resolution);
174177

175178
let mut bundle = RenderBundle::default();
176179
bundle.add_image(

galileo/src/layer/tiles.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use std::time::Duration;
44
use parking_lot::Mutex;
55

66
use crate::render::PackedBundle;
7-
use crate::tile_schema::TileIndex;
7+
use crate::tile_schema::{TileIndex, WrappingTileIndex};
88
use crate::TileSchema;
99

1010
#[derive(Clone)]
1111
pub(crate) struct DisplayedTile<StyleId: Copy> {
12-
pub(crate) index: TileIndex,
12+
pub(crate) index: WrappingTileIndex,
1313
pub(crate) bundle: Arc<dyn PackedBundle>,
1414
style_id: StyleId,
1515
pub(crate) opacity: f32,
@@ -51,7 +51,7 @@ where
5151

5252
pub(crate) fn update_displayed_tiles(
5353
&self,
54-
needed_indices: impl IntoIterator<Item = TileIndex>,
54+
needed_indices: impl IntoIterator<Item = WrappingTileIndex>,
5555
style_id: StyleId,
5656
) -> bool {
5757
let mut displayed_tiles = self.tiles.lock();
@@ -78,7 +78,7 @@ where
7878

7979
needed_tiles.push(displayed.clone());
8080
} else {
81-
match self.tile_provider.get_tile(index, style_id) {
81+
match self.tile_provider.get_tile(index.into(), style_id) {
8282
None => to_substitute.push(index),
8383
Some(bundle) => {
8484
needed_tiles.push(DisplayedTile {

galileo/src/layer/vector_tile_layer/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::layer::Layer;
2121
use crate::messenger::Messenger;
2222
use crate::render::render_bundle::RenderBundle;
2323
use crate::render::{BundleToDraw, Canvas, PackedBundle, PolygonPaint, RenderOptions};
24-
use crate::tile_schema::TileSchema;
24+
use crate::tile_schema::{TileIndex, TileSchema};
2525
use crate::view::MapView;
2626
use crate::Color;
2727

@@ -87,7 +87,7 @@ impl Layer for VectorTileLayer {
8787
fn prepare(&self, view: &MapView) {
8888
if let Some(iter) = self.tile_schema.iter_tiles(view) {
8989
for index in iter {
90-
self.tile_provider.load_tile(index, self.style_id);
90+
self.tile_provider.load_tile(index.into(), self.style_id);
9191
}
9292
}
9393
}
@@ -145,8 +145,11 @@ impl VectorTileLayer {
145145
};
146146

147147
let needed_indices: Vec<_> = tile_iter.collect();
148+
let mut to_pack: Vec<TileIndex> = needed_indices.iter().map(|t| (*t).into()).collect();
149+
to_pack.dedup();
150+
148151
self.tile_provider
149-
.pack_tiles(&needed_indices, self.style_id, canvas);
152+
.pack_tiles(&to_pack, self.style_id, canvas);
150153
let requires_redraw = self
151154
.displayed_tiles
152155
.update_displayed_tiles(needed_indices, self.style_id);
@@ -207,7 +210,7 @@ impl VectorTileLayer {
207210

208211
let tolerance = ((view.resolution() / tile_resolution) * PIXEL_TOLERANCE) as f32;
209212

210-
if let Some(mvt_tile) = self.tile_provider.get_mvt_tile(index) {
213+
if let Some(mvt_tile) = self.tile_provider.get_mvt_tile(index.into()) {
211214
for layer in &mvt_tile.layers {
212215
for feature in &layer.features {
213216
match &feature.geometry {

galileo/src/layer/vector_tile_layer/tile_provider/vt_processor.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use galileo_mvt::{MvtFeature, MvtGeometry, MvtPolygon, MvtTile};
2-
use galileo_types::cartesian::{CartesianPoint2d, CartesianPoint3d, Point2, Point3, Vector2};
2+
use galileo_types::cartesian::{CartesianPoint2d, Point3, Rect, Vector2};
33
use galileo_types::impls::{ClosedContour, Polygon};
44
use galileo_types::{Contour, MultiContour, MultiPolygon, Polygon as PolygonTrait};
55
use num_traits::ToPrimitive;
@@ -37,14 +37,15 @@ impl VtProcessor {
3737
style: &VectorTileStyle,
3838
tile_schema: &TileSchema,
3939
) -> Result<(), GalileoError> {
40-
let bbox = tile_schema
41-
.tile_bbox(index)
42-
.ok_or_else(|| GalileoError::Generic("cannot get tile bbox".into()))?;
4340
let lod_resolution = tile_schema.lod_resolution(index.z).ok_or_else(|| {
4441
GalileoError::Generic(format!("cannot get lod resolution for lod {}", index.z))
4542
})?;
4643
let tile_resolution = lod_resolution * tile_schema.tile_width() as f64;
4744

45+
let width = tile_schema.tile_width() as f64;
46+
let height = tile_schema.tile_height() as f64;
47+
let bbox = Rect::new(0.0, 0.0, width * lod_resolution, -height * lod_resolution);
48+
4849
let bounds = Polygon::new(
4950
ClosedContour::new(vec![
5051
Point3::new(bbox.x_min(), bbox.y_min(), 0.0),
@@ -70,13 +71,6 @@ impl VtProcessor {
7071

7172
for point in points {
7273
let position = Self::transform_point(point, tile_resolution);
73-
if !bbox.contains(&Point2::new(position.x(), position.y())) {
74-
// Some vector tiles add out-of-bounds point to start displaying labels that
75-
// are not fully on the screen yet. We need to deal with that case
76-
// in some clever way, but for now let's ignore those points.
77-
continue;
78-
}
79-
8074
match &paint.shape {
8175
PointShape::Label { text, style } => {
8276
if !text.is_empty() {

galileo/src/render/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@ pub trait PackedBundle: MaybeSend + MaybeSync {
5353
fn as_any(&self) -> &dyn Any;
5454
}
5555

56-
/// Packed bundle that is ready to be renderred with the given paramters.
56+
/// Packed bundle that is ready to be renderred with the given parameters.
5757
pub struct BundleToDraw<'a> {
5858
bundle: &'a dyn PackedBundle,
5959
opacity: f32,
6060
pub(crate) offset: Vector2<f32>,
6161
}
6262

6363
impl<'a> BundleToDraw<'a> {
64-
/// Packed bundle with offset and opacity speicified.
64+
/// Packed bundle with offset and opacity specified.
6565
pub fn new(bundle: &'a dyn PackedBundle, opacity: f32, offset: Vector2<f32>) -> Self {
6666
Self {
6767
bundle,

galileo/src/render/wgpu/mod.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -984,8 +984,14 @@ impl Canvas for WgpuCanvas<'_> {
984984
let screen_sets = std::mem::take(&mut self.screen_sets);
985985
let mut sets: Vec<_> = screen_sets
986986
.iter()
987-
.map(|(set, _, offset)| {
988-
let locked = set.lock();
987+
.filter_map(|(set, _, offset)| {
988+
let Some(locked) = set.try_lock() else {
989+
// TODO: this means that the same tile is reused. We just wait for it to
990+
// disappear from the map. This would result in some visual bugs, but not so
991+
// critical as to be blocked by it ATM.
992+
return None;
993+
};
994+
989995
let projected_anchor = transform
990996
* Point4::new(
991997
locked.anchor_point[0] as f64 + offset.dx() as f64,
@@ -995,7 +1001,7 @@ impl Canvas for WgpuCanvas<'_> {
9951001
);
9961002
let normalaized = projected_anchor / projected_anchor.w.abs();
9971003

998-
(locked, normalaized, offset)
1004+
Some((locked, normalaized, offset))
9991005
})
10001006
.collect();
10011007
sets.sort_by(|a, b| {

galileo/src/render/wgpu/pipelines/clip.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,14 @@ impl ClipPipeline {
7171
buffers: &'a WgpuVertexBuffers,
7272
render_pass: &mut RenderPass<'a>,
7373
render_options: RenderOptions,
74+
bundle_index: u32,
7475
) {
7576
self.render(
7677
buffers,
7778
render_pass,
7879
Self::CLIP_STENCIL_VALUE,
7980
render_options,
81+
bundle_index,
8082
);
8183
}
8284

@@ -85,8 +87,15 @@ impl ClipPipeline {
8587
buffers: &'a WgpuVertexBuffers,
8688
render_pass: &mut RenderPass<'a>,
8789
render_options: RenderOptions,
90+
bundle_index: u32,
8891
) {
89-
self.render(buffers, render_pass, Self::UNCLIP_REFERENCE, render_options);
92+
self.render(
93+
buffers,
94+
render_pass,
95+
Self::UNCLIP_REFERENCE,
96+
render_options,
97+
bundle_index,
98+
);
9099
}
91100

92101
fn render<'a>(
@@ -95,6 +104,7 @@ impl ClipPipeline {
95104
render_pass: &mut RenderPass<'a>,
96105
stencil_reference: u32,
97106
render_options: RenderOptions,
107+
bundle_index: u32,
98108
) {
99109
if render_options.antialias {
100110
render_pass.set_pipeline(&self.wgpu_pipeline_antialias);
@@ -105,6 +115,6 @@ impl ClipPipeline {
105115
render_pass.set_stencil_reference(stencil_reference);
106116
render_pass.set_vertex_buffer(0, buffers.vertex.slice(..));
107117
render_pass.set_index_buffer(buffers.index.slice(..), wgpu::IndexFormat::Uint32);
108-
render_pass.draw_indexed(0..buffers.index_count, 0, 0..1);
118+
render_pass.draw_indexed(0..buffers.index_count, 0, bundle_index..(bundle_index + 1));
109119
}
110120
}

galileo/src/render/wgpu/pipelines/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ impl Pipelines {
130130
self.set_bindings(render_pass);
131131

132132
if let Some(clip) = &bundle.clip_area_buffers {
133-
self.clip.clip(clip, render_pass, render_options);
133+
self.clip
134+
.clip(clip, render_pass, render_options, bundle_index);
134135
}
135136

136137
for image in &bundle.image_buffers {
@@ -148,7 +149,8 @@ impl Pipelines {
148149
}
149150

150151
if let Some(clip) = &bundle.clip_area_buffers {
151-
self.clip.unclip(clip, render_pass, render_options);
152+
self.clip
153+
.unclip(clip, render_pass, render_options, bundle_index);
152154
}
153155

154156
if let Some(dot_buffers) = &bundle.dot_buffers {

0 commit comments

Comments
 (0)