maplibre/render/tile_view_pattern/
pattern.rs1use std::{collections::HashSet, marker::PhantomData};
2
3use crate::{
4 coords::{ViewRegion, Zoom},
5 render::{
6 camera::ViewProjection,
7 resource::{BackingBufferDescriptor, Queue},
8 shaders::ShaderTileMetadata,
9 tile_view_pattern::{HasTile, SourceShapes, TileShape, ViewTile},
10 },
11 tcs::world::World,
12};
13
14pub const DEFAULT_TILE_VIEW_PATTERN_SIZE: wgpu::BufferAddress = 512;
19pub const CHILDREN_SEARCH_DEPTH: usize = 4;
20
21#[derive(Debug)]
22struct BackingBuffer<B> {
23 inner: B,
25 inner_size: wgpu::BufferAddress,
27}
28
29impl<B> BackingBuffer<B> {
30 fn new(inner: B, inner_size: wgpu::BufferAddress) -> Self {
31 Self { inner, inner_size }
32 }
33}
34
35pub struct TileViewPattern<Q, B> {
37 view_tiles: Vec<ViewTile>,
38 view_tiles_buffer: BackingBuffer<B>,
39 phantom_q: PhantomData<Q>,
40}
41
42impl<Q: Queue<B>, B> TileViewPattern<Q, B> {
43 pub fn new(view_tiles_buffer: BackingBufferDescriptor<B>) -> Self {
44 Self {
45 view_tiles: Vec::with_capacity(64),
46 view_tiles_buffer: BackingBuffer::new(
47 view_tiles_buffer.buffer,
48 view_tiles_buffer.inner_size,
49 ),
50 phantom_q: Default::default(),
51 }
52 }
53
54 #[tracing::instrument(skip_all)]
55 #[must_use]
56 pub fn generate_pattern<T: HasTile>(
57 &self,
58 view_region: &ViewRegion,
59 container: &T,
60 zoom: Zoom,
61 world: &World,
62 ) -> Vec<ViewTile> {
63 let mut view_tiles = Vec::with_capacity(self.view_tiles.len());
64 let mut source_tiles = HashSet::new(); for coords in view_region.iter() {
67 if coords.build_quad_key().is_none() {
68 continue;
69 }
70
71 let source_shapes = {
72 if container.has_tile(coords, world) {
73 SourceShapes::SourceEqTarget(TileShape::new(coords, zoom))
74 } else if let Some(parent_coords) = container.get_available_parent(coords, world) {
75 log::debug!("Could not find data at {coords}. Falling back to {parent_coords}");
76
77 if source_tiles.contains(&parent_coords) {
78 continue;
83 }
84
85 source_tiles.insert(parent_coords);
86
87 SourceShapes::Parent(TileShape::new(parent_coords, zoom))
88 } else if let Some(children_coords) =
89 container.get_available_children(coords, world, CHILDREN_SEARCH_DEPTH)
90 {
91 log::debug!(
92 "Could not find data at {coords}. Falling back children: {children_coords:?}"
93 );
94
95 SourceShapes::Children(
96 children_coords
97 .iter()
98 .map(|child_coord| TileShape::new(*child_coord, zoom))
99 .collect(),
100 )
101 } else {
102 SourceShapes::None
103 }
104 };
105
106 view_tiles.push(ViewTile {
107 target: coords,
108 source: source_shapes,
109 });
110 }
111
112 view_tiles
113 }
114
115 pub fn update_pattern(&mut self, mut view_tiles: Vec<ViewTile>) {
116 self.view_tiles.clear();
117 self.view_tiles.append(&mut view_tiles)
118 }
119
120 pub fn iter(&self) -> impl Iterator<Item = &ViewTile> + '_ {
121 self.view_tiles.iter()
122 }
123
124 pub fn buffer(&self) -> &B {
125 &self.view_tiles_buffer.inner
126 }
127
128 #[tracing::instrument(skip_all)]
129 pub fn upload_pattern(
130 &mut self,
131 queue: &Q,
132 view_proj: &ViewProjection,
133 viewport_width: f32,
134 viewport_height: f32,
135 ) {
136 let mut buffer = Vec::with_capacity(self.view_tiles.len());
137
138 let mut add_to_buffer = |shape: &mut TileShape| {
139 shape.set_buffer_range(buffer.len() as u64);
140 let transform = view_proj
142 .to_model_view_projection(shape.transform)
143 .downcast()
144 .into(); buffer.push(ShaderTileMetadata {
146 transform,
149 zoom_factor: shape.zoom_factor as f32,
150 viewport_width,
151 viewport_height,
152 });
153 };
154
155 for view_tile in &mut self.view_tiles {
156 match &mut view_tile.source {
157 SourceShapes::Parent(source_shape) => {
158 add_to_buffer(source_shape);
159 }
160 SourceShapes::Children(source_shapes) => {
161 for source_shape in source_shapes {
162 add_to_buffer(source_shape);
163 }
164 }
165 SourceShapes::SourceEqTarget(source_shape) => add_to_buffer(source_shape),
166 SourceShapes::None => {}
167 }
168 }
169
170 let raw_buffer = bytemuck::cast_slice(buffer.as_slice());
171 if raw_buffer.len() as wgpu::BufferAddress > self.view_tiles_buffer.inner_size {
172 panic!("Buffer is too small to store the tile pattern!");
175 }
176 queue.write_buffer(&self.view_tiles_buffer.inner, 0, raw_buffer);
177 }
178}