diff --git a/maplibre/build.rs b/maplibre/build.rs index b229f876..4429fb1a 100644 --- a/maplibre/build.rs +++ b/maplibre/build.rs @@ -5,27 +5,6 @@ use maplibre_build_tools::wgsl::validate_project_wgsl; -/* -fn generate_type_def() { - use std::fs::File; - use std::io::BufReader; - use serde_json::Value; - let f = File::open("style-spec-v8.json").unwrap(); - let mut reader = BufReader::new(f); - let result = serde_json::from_reader::<_, Value>(&mut reader).unwrap(); - - let spec_root = result.as_object()?; - let version = &spec_root["$version"].as_i64()?; - let root = &spec_root["$root"].as_object()?; - - for x in spec_root { - - } - - println!("cargo:warning={:?}", version); -} -*/ - #[cfg(feature = "embed-static-tiles")] fn embed_tiles_statically() { use std::{env, path::Path}; diff --git a/maplibre/src/io/tile_repository.rs b/maplibre/src/io/tile_repository.rs index 4e3805f7..a38aa645 100644 --- a/maplibre/src/io/tile_repository.rs +++ b/maplibre/src/io/tile_repository.rs @@ -1,8 +1,9 @@ //! Tile cache. -use std::collections::{btree_map, BTreeMap}; +use std::collections::{btree_map, btree_map::Entry, BTreeMap}; use bytemuck::Pod; +use thiserror::Error; use crate::{ coords::{Quadkey, WorldTileCoords}, @@ -85,6 +86,13 @@ impl StoredTile { } } } +#[derive(Error, Debug)] +pub enum MarkError { + #[error("no pending tile at coords")] + NoPendingTile, + #[error("unable to construct quadkey")] + QuadKey, +} /// Stores and provides access to a quad tree of cached tiles with world tile coords. #[derive(Default)] @@ -99,10 +107,6 @@ impl TileRepository { } } - pub fn clear(&mut self) { - self.tree.clear(); - } - /// Inserts a tessellated layer into the quad tree at its world tile coords. /// If the space is vacant, the tessellated layer is inserted into a new /// [crate::io::tile_repository::StoredLayer]. @@ -126,12 +130,6 @@ impl TileRepository { } } - pub fn put_tile(&mut self, tile: StoredTile) { - if let Some(key) = tile.coords.build_quad_key() { - self.tree.insert(key, tile); - } - } - /// Returns the list of tessellated layers at the given world tile coords. None if tile is /// missing from the cache. pub fn iter_layers_at( @@ -141,7 +139,14 @@ impl TileRepository { coords .build_quad_key() .and_then(|key| self.tree.get(&key)) - .map(|results| results.layers.iter()) + .and_then(|tile| { + if tile.status == TileStatus::Success { + Some(tile) + } else { + None + } + }) + .map(|tile| tile.layers.iter()) } /// Returns the list of tessellated layers at the given world tile coords, which are loaded in @@ -160,18 +165,8 @@ impl TileRepository { }) } - /// Create a new tile. - pub fn create_tile(&mut self, coords: WorldTileCoords) -> bool { - if let Some(btree_map::Entry::Vacant(entry)) = - coords.build_quad_key().map(|key| self.tree.entry(key)) - { - entry.insert(StoredTile::pending(coords)); - } - true - } - - /// Checks if a layer has been fetched. - pub fn has_tile(&self, coords: &WorldTileCoords) -> bool { + /// Checks fetching of a tile has been started + pub fn is_tile_pending_or_done(&self, coords: &WorldTileCoords) -> bool { if coords .build_quad_key() .and_then(|key| self.tree.get(&key)) @@ -182,22 +177,52 @@ impl TileRepository { true } - pub fn mark_tile_succeeded(&mut self, coords: &WorldTileCoords) { - if let Some(cached_tile) = coords - .build_quad_key() - .and_then(|key| self.tree.get_mut(&key)) - { - cached_tile.status = TileStatus::Success; + /// Mark the tile at `coords` pending in this tile repository. + pub fn mark_tile_pending(&mut self, coords: WorldTileCoords) -> Result<(), MarkError> { + let Some(key) = coords.build_quad_key() else { return Err(MarkError::QuadKey); }; + + match self.tree.entry(key) { + Entry::Vacant(entry) => { + entry.insert(StoredTile::pending(coords)); + } + Entry::Occupied(mut entry) => { + entry.get_mut().status = TileStatus::Pending; + } + } + + Ok(()) + } + + /// Mark the tile at `coords` succeeded in this tile repository. Only succeeds if there is a + /// pending tile at `coords`. + pub fn mark_tile_succeeded(&mut self, coords: &WorldTileCoords) -> Result<(), MarkError> { + self.mark_tile(coords, TileStatus::Success) + } + + /// Mark the tile at `coords` failed in this tile repository. Only succeeds if there is a + /// pending tile at `coords`. + pub fn mark_tile_failed(&mut self, coords: &WorldTileCoords) -> Result<(), MarkError> { + self.mark_tile(coords, TileStatus::Failed) + } + + fn mark_tile(&mut self, coords: &WorldTileCoords, status: TileStatus) -> Result<(), MarkError> { + let Some(key) = coords.build_quad_key() else { return Err(MarkError::QuadKey); }; + + if let Entry::Occupied(mut entry) = self.tree.entry(key) { + entry.get_mut().status = status; + Ok(()) + } else { + Err(MarkError::NoPendingTile) } } - /// Checks if a layer has been fetched. - pub fn mark_tile_failed(&mut self, coords: &WorldTileCoords) { - if let Some(cached_tile) = coords - .build_quad_key() - .and_then(|key| self.tree.get_mut(&key)) - { - cached_tile.status = TileStatus::Failed; + pub fn put_tile(&mut self, tile: StoredTile) { + if let Some(key) = tile.coords.build_quad_key() { + self.tree.insert(key, tile); } } + + pub fn clear(&mut self) { + self.tree.clear(); + } } diff --git a/maplibre/src/map.rs b/maplibre/src/map.rs index 68592ced..732ab376 100644 --- a/maplibre/src/map.rs +++ b/maplibre/src/map.rs @@ -93,7 +93,7 @@ where .build() .initialize_renderer::(&self.window) .await - .map_err(|e| MapError::DeviceInit(e))?; + .map_err(MapError::DeviceInit)?; let window_size = self.window.size(); diff --git a/maplibre/src/render/debug_pass.rs b/maplibre/src/render/debug_pass.rs new file mode 100644 index 00000000..d17a5f7b --- /dev/null +++ b/maplibre/src/render/debug_pass.rs @@ -0,0 +1,65 @@ +use std::ops::Deref; + +use crate::render::{ + graph::{Node, NodeRunError, RenderContext, RenderGraphContext, SlotInfo}, + render_commands::DrawDebugOutlines, + render_phase::RenderCommand, + resource::TrackedRenderPass, + Eventually::Initialized, + RenderState, +}; + +/// Pass which renders debug information on top of the map. +pub struct DebugPassNode {} + +impl DebugPassNode { + pub fn new() -> Self { + Self {} + } +} + +impl Node for DebugPassNode { + fn input(&self) -> Vec { + vec![] + } + + fn update(&mut self, _state: &mut RenderState) {} + + fn run( + &self, + _graph: &mut RenderGraphContext, + render_context: &mut RenderContext, + state: &RenderState, + ) -> Result<(), NodeRunError> { + let Initialized(render_target) = &state.render_target else { + return Ok(()); + }; + + let color_attachment = wgpu::RenderPassColorAttachment { + view: render_target.deref(), + ops: wgpu::Operations { + // Draws on-top of previously rendered data + load: wgpu::LoadOp::Load, + store: true, + }, + resolve_target: None, + }; + + let render_pass = + render_context + .command_encoder + .begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(color_attachment)], + depth_stencil_attachment: None, + }); + + let mut tracked_pass = TrackedRenderPass::new(render_pass); + + for item in &state.mask_phase.items { + DrawDebugOutlines::render(state, item, &mut tracked_pass); + } + + Ok(()) + } +} diff --git a/maplibre/src/render/error.rs b/maplibre/src/render/error.rs index 3148d501..2d866493 100644 --- a/maplibre/src/render/error.rs +++ b/maplibre/src/render/error.rs @@ -14,12 +14,6 @@ pub enum RenderError { impl RenderError { pub fn should_exit(&self) -> bool { - match self { - RenderError::Surface(e) => match e { - wgpu::SurfaceError::OutOfMemory => true, - _ => false, - }, - _ => true, - } + matches!(self, RenderError::Surface(wgpu::SurfaceError::OutOfMemory)) } } diff --git a/maplibre/src/render/eventually.rs b/maplibre/src/render/eventually.rs index 4d4ff086..23d2b395 100644 --- a/maplibre/src/render/eventually.rs +++ b/maplibre/src/render/eventually.rs @@ -27,7 +27,7 @@ where } } -impl<'a, T> Eventually +impl Eventually where T: HasChanged, { diff --git a/maplibre/src/render/main_pass.rs b/maplibre/src/render/main_pass.rs index 419c2252..635f1063 100644 --- a/maplibre/src/render/main_pass.rs +++ b/maplibre/src/render/main_pass.rs @@ -36,17 +36,13 @@ impl Node for MainPassNode { render_context: &mut RenderContext, state: &RenderState, ) -> Result<(), NodeRunError> { - let (render_target, multisampling_texture, depth_texture) = if let ( - Initialized(render_target), - Initialized(multisampling_texture), - Initialized(depth_texture), - ) = ( - &state.render_target, - &state.multisampling_texture, - &state.depth_texture, - ) { - (render_target, multisampling_texture, depth_texture) - } else { + let Initialized(render_target) = &state.render_target else { + return Ok(()); + }; + let Initialized(multisampling_texture) = &state.multisampling_texture else { + return Ok(()); + }; + let Initialized(depth_texture) = &state.depth_texture else { return Ok(()); }; @@ -98,6 +94,7 @@ impl Node for MainPassNode { for item in &state.tile_phase.items { DrawTiles::render(state, item, &mut tracked_pass); } + Ok(()) } } diff --git a/maplibre/src/render/mod.rs b/maplibre/src/render/mod.rs index 9aa3aa0b..30c8a4fc 100644 --- a/maplibre/src/render/mod.rs +++ b/maplibre/src/render/mod.rs @@ -27,7 +27,7 @@ use crate::{ resource::{BufferPool, Globals, Head, IndexEntry, Surface, Texture, TextureView}, settings::{RendererSettings, WgpuSettings}, shaders::{ShaderFeatureStyle, ShaderLayerMetadata}, - tile_view_pattern::{TileInView, TileShape, TileViewPattern}, + tile_view_pattern::{TileShape, TileViewPattern}, }, tessellation::IndexDataType, }; @@ -37,6 +37,7 @@ pub mod resource; pub mod stages; // Rendering internals +mod debug_pass; mod graph_runner; mod main_pass; mod render_commands; @@ -57,6 +58,7 @@ pub use stages::register_default_render_stages; use crate::{ render::{ + debug_pass::DebugPassNode, error::RenderError, graph::{EmptyNode, RenderGraph, RenderGraphError}, main_pass::{MainPassDriverNode, MainPassNode}, @@ -83,6 +85,7 @@ pub struct RenderState { tile_pipeline: Eventually, mask_pipeline: Eventually, + debug_pipeline: Eventually, globals_bind_group: Eventually, @@ -91,7 +94,7 @@ pub struct RenderState { surface: Surface, - mask_phase: RenderPhase, + mask_phase: RenderPhase, tile_phase: RenderPhase<(IndexEntry, TileShape)>, } @@ -103,6 +106,7 @@ impl RenderState { tile_view_pattern: Default::default(), tile_pipeline: Default::default(), mask_pipeline: Default::default(), + debug_pipeline: Default::default(), globals_bind_group: Default::default(), depth_texture: Default::default(), multisampling_texture: Default::default(), @@ -242,7 +246,7 @@ impl Renderer { let adapter = instance .request_adapter(request_adapter_options) .await - .ok_or_else(|| wgpu::RequestDeviceError)?; + .ok_or(wgpu::RequestDeviceError)?; let adapter_info = adapter.get_info(); @@ -497,6 +501,7 @@ pub mod draw_graph { // Labels for non-input nodes pub mod node { pub const MAIN_PASS: &str = "main_pass"; + pub const DEBUG_PASS: &str = "debug_pass"; #[cfg(feature = "headless")] pub const COPY: &str = "copy"; } @@ -506,9 +511,15 @@ pub fn create_default_render_graph() -> Result { let mut graph = RenderGraph::default(); let mut draw_graph = RenderGraph::default(); + // Draw nodes draw_graph.add_node(draw_graph::node::MAIN_PASS, MainPassNode::new()); + draw_graph.add_node(draw_graph::node::DEBUG_PASS, DebugPassNode::new()); + // Input node let input_node_id = draw_graph.set_input(vec![]); + // Edges draw_graph.add_node_edge(input_node_id, draw_graph::node::MAIN_PASS)?; + // TODO: Enable debug pass via runtime flag + draw_graph.add_node_edge(draw_graph::node::MAIN_PASS, draw_graph::node::DEBUG_PASS)?; graph.add_sub_graph(draw_graph::NAME, draw_graph); graph.add_node(main_graph::node::MAIN_PASS_DEPENDENCIES, EmptyNode); diff --git a/maplibre/src/render/render_commands.rs b/maplibre/src/render/render_commands.rs index 015cf0cb..5416f1d4 100644 --- a/maplibre/src/render/render_commands.rs +++ b/maplibre/src/render/render_commands.rs @@ -5,11 +5,11 @@ use crate::render::{ eventually::Eventually::Initialized, render_phase::{PhaseItem, RenderCommand, RenderCommandResult}, resource::{Globals, IndexEntry, TrackedRenderPass}, - tile_view_pattern::{TileInView, TileShape}, + tile_view_pattern::TileShape, RenderState, INDEX_FORMAT, }; -impl PhaseItem for TileInView { +impl PhaseItem for TileShape { type SortKey = (); fn sort_key(&self) -> Self::SortKey {} @@ -49,6 +49,19 @@ impl RenderCommand

for SetMaskPipeline { } } +pub struct SetDebugPipeline; +impl RenderCommand

for SetDebugPipeline { + fn render<'w>( + state: &'w RenderState, + _item: &P, + pass: &mut TrackedRenderPass<'w>, + ) -> RenderCommandResult { + let Initialized(pipeline) = &state.debug_pipeline else { return RenderCommandResult::Failure; }; + pass.set_render_pipeline(pipeline); + RenderCommandResult::Success + } +} + pub struct SetTilePipeline; impl RenderCommand

for SetTilePipeline { fn render<'w>( @@ -63,25 +76,50 @@ impl RenderCommand

for SetTilePipeline { } pub struct DrawMask; -impl RenderCommand for DrawMask { +impl RenderCommand for DrawMask { fn render<'w>( state: &'w RenderState, - TileInView { shape, fallback }: &TileInView, + source_shape: &TileShape, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { let Initialized(tile_view_pattern) = &state.tile_view_pattern else { return RenderCommandResult::Failure; }; - tracing::trace!("Drawing mask {}", &shape.coords); + tracing::trace!("Drawing mask {}", &source_shape.coords()); - let shape_to_render = fallback.as_ref().unwrap_or(shape); - - let reference = tile_view_pattern.stencil_reference_value(&shape_to_render.coords) as u32; + // Draw mask with stencil value of e.g. parent + let reference = tile_view_pattern.stencil_reference_value_3d(&source_shape.coords()) as u32; pass.set_stencil_reference(reference); pass.set_vertex_buffer( 0, - tile_view_pattern.buffer().slice(shape.buffer_range.clone()), + // Mask is of the requested shape + tile_view_pattern + .buffer() + .slice(source_shape.buffer_range()), ); - pass.draw(0..6, 0..1); + const TILE_MASK_SHADER_VERTICES: u32 = 6; + pass.draw(0..TILE_MASK_SHADER_VERTICES, 0..1); + + RenderCommandResult::Success + } +} + +pub struct DrawDebugOutline; +impl RenderCommand for DrawDebugOutline { + fn render<'w>( + state: &'w RenderState, + source_shape: &TileShape, + pass: &mut TrackedRenderPass<'w>, + ) -> RenderCommandResult { + let Initialized(tile_view_pattern) = &state.tile_view_pattern else { return RenderCommandResult::Failure; }; + pass.set_vertex_buffer( + 0, + tile_view_pattern + .buffer() + .slice(source_shape.buffer_range()), + ); + const TILE_MASK_SHADER_VERTICES: u32 = 24; + pass.draw(0..TILE_MASK_SHADER_VERTICES, 0..1); + RenderCommandResult::Success } } @@ -96,7 +134,8 @@ impl RenderCommand<(IndexEntry, TileShape)> for DrawTile { let (Initialized(buffer_pool), Initialized(tile_view_pattern)) = (&state.buffer_pool, &state.tile_view_pattern) else { return RenderCommandResult::Failure; }; - let reference = tile_view_pattern.stencil_reference_value(&shape.coords) as u32; + // Uses stencil value of requested tile and the shape of the requested tile + let reference = tile_view_pattern.stencil_reference_value_3d(&shape.coords()) as u32; tracing::trace!( "Drawing layer {:?} at {}", @@ -113,10 +152,7 @@ impl RenderCommand<(IndexEntry, TileShape)> for DrawTile { 0, buffer_pool.vertices().slice(entry.vertices_buffer_range()), ); - pass.set_vertex_buffer( - 1, - tile_view_pattern.buffer().slice(shape.buffer_range.clone()), - ); + pass.set_vertex_buffer(1, tile_view_pattern.buffer().slice(shape.buffer_range())); pass.set_vertex_buffer( 2, buffer_pool @@ -137,3 +173,5 @@ impl RenderCommand<(IndexEntry, TileShape)> for DrawTile { pub type DrawTiles = (SetTilePipeline, SetViewBindGroup<0>, DrawTile); pub type DrawMasks = (SetMaskPipeline, DrawMask); + +pub type DrawDebugOutlines = (SetDebugPipeline, DrawDebugOutline); diff --git a/maplibre/src/render/resource/buffer_pool.rs b/maplibre/src/render/resource/buffer_pool.rs index 9cdc41df..18e8c544 100644 --- a/maplibre/src/render/resource/buffer_pool.rs +++ b/maplibre/src/render/resource/buffer_pool.rs @@ -17,11 +17,12 @@ use crate::{ tessellation::OverAlignedVertexBuffer, }; -pub const VERTEX_SIZE: wgpu::BufferAddress = 1_000_000; -pub const INDICES_SIZE: wgpu::BufferAddress = 1_000_000; +// FIXME: Too low values can cause a back-and-forth between unloading and loading layers +pub const VERTEX_SIZE: wgpu::BufferAddress = 10 * 1_000_000; +pub const INDICES_SIZE: wgpu::BufferAddress = 10 * 1_000_000; -pub const FEATURE_METADATA_SIZE: wgpu::BufferAddress = 1024 * 1000; -pub const LAYER_METADATA_SIZE: wgpu::BufferAddress = 1024; +pub const FEATURE_METADATA_SIZE: wgpu::BufferAddress = 10 * 1024 * 1000; +pub const LAYER_METADATA_SIZE: wgpu::BufferAddress = 10 * 1024; /// This is inspired by the memory pool in Vulkan documented /// [here](https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/custom_memory_pools.html). @@ -476,9 +477,14 @@ impl IndexEntry { } } +#[derive(Debug)] +pub struct RingIndexEntry { + layers: VecDeque, +} + #[derive(Debug)] pub struct RingIndex { - tree_index: BTreeMap>, + tree_index: BTreeMap, linear_index: VecDeque, } @@ -496,44 +502,33 @@ impl RingIndex { } pub fn front(&self) -> Option<&IndexEntry> { - self.linear_index - .front() - .and_then(|key| self.tree_index.get(key).and_then(|entries| entries.front())) + self.linear_index.front().and_then(|key| { + self.tree_index + .get(key) + .and_then(|entry| entry.layers.front()) + }) } pub fn back(&self) -> Option<&IndexEntry> { - self.linear_index - .back() - .and_then(|key| self.tree_index.get(key).and_then(|entries| entries.back())) + self.linear_index.back().and_then(|key| { + self.tree_index + .get(key) + .and_then(|entry| entry.layers.back()) + }) } pub fn get_layers(&self, coords: &WorldTileCoords) -> Option<&VecDeque> { coords .build_quad_key() .and_then(|key| self.tree_index.get(&key)) - } - - pub fn get_layers_fallback(&self, coords: &WorldTileCoords) -> Option<&VecDeque> { - let mut current = *coords; - loop { - if let Some(entries) = self.get_layers(¤t) { - return Some(entries); - } else if let Some(parent) = current.get_parent() { - current = parent - } else { - return None; - } - } + .map(|entry| &entry.layers) } pub fn has_tile(&self, coords: &WorldTileCoords) -> bool { - coords - .build_quad_key() - .and_then(|key| self.tree_index.get(&key)) - .is_some() + self.get_layers(coords).is_some() } - pub fn get_tile_coords_fallback(&self, coords: &WorldTileCoords) -> Option { + pub fn get_available_parent(&self, coords: &WorldTileCoords) -> Option { let mut current = *coords; loop { if self.has_tile(¤t) { @@ -546,19 +541,45 @@ impl RingIndex { } } + pub fn get_available_children( + &self, + coords: &WorldTileCoords, + search_depth: usize, + ) -> Option> { + let mut children = coords.get_children().to_vec(); + + let mut output = Vec::new(); + + for _ in 0..search_depth { + let mut new_children = Vec::with_capacity(children.len() * 4); + + for child in children { + if self.has_tile(&child) { + output.push(child); + } else { + new_children.extend(child.get_children()) + } + } + + children = new_children; + } + + Some(output) + } + pub fn iter(&self) -> impl Iterator> + '_ { self.linear_index .iter() - .flat_map(|key| self.tree_index.get(key).map(|entries| entries.iter())) + .flat_map(|key| self.tree_index.get(key).map(|entry| entry.layers.iter())) } fn pop_front(&mut self) -> Option { - if let Some(entries) = self + if let Some(entry) = self .linear_index .pop_front() .and_then(|key| self.tree_index.get_mut(&key)) { - entries.pop_front() + entry.layers.pop_front() } else { None } @@ -568,10 +589,12 @@ impl RingIndex { if let Some(key) = entry.coords.build_quad_key() { match self.tree_index.entry(key) { btree_map::Entry::Vacant(index_entry) => { - index_entry.insert(VecDeque::from([entry])); + index_entry.insert(RingIndexEntry { + layers: VecDeque::from([entry]), + }); } btree_map::Entry::Occupied(mut index_entry) => { - index_entry.get_mut().push_back(entry); + index_entry.get_mut().layers.push_back(entry); } } diff --git a/maplibre/src/render/resource/surface.rs b/maplibre/src/render/resource/surface.rs index 658515f3..aa7bde91 100644 --- a/maplibre/src/render/resource/surface.rs +++ b/maplibre/src/render/resource/surface.rs @@ -278,7 +278,7 @@ impl Surface { match &mut self.head { Head::Headed(window) => { if window.has_changed(&(self.size.width(), self.size.height())) { - window.resize_and_configure(self.size.height(), self.size.width(), device); + window.resize_and_configure(self.size.width(), self.size.height(), device); } } Head::Headless(_) => {} diff --git a/maplibre/src/render/shaders/tile.fragment.wgsl b/maplibre/src/render/shaders/basic.fragment.wgsl similarity index 100% rename from maplibre/src/render/shaders/tile.fragment.wgsl rename to maplibre/src/render/shaders/basic.fragment.wgsl diff --git a/maplibre/src/render/shaders/mod.rs b/maplibre/src/render/shaders/mod.rs index 8e3920d6..0bdfc679 100644 --- a/maplibre/src/render/shaders/mod.rs +++ b/maplibre/src/render/shaders/mod.rs @@ -27,12 +27,17 @@ pub trait Shader { pub struct TileMaskShader { pub format: wgpu::TextureFormat, pub draw_colors: bool, + pub debug_lines: bool, } impl Shader for TileMaskShader { fn describe_vertex(&self) -> VertexState { VertexState { - source: include_str!("tile_mask.vertex.wgsl"), + source: if self.debug_lines { + include_str!("tile_debug.vertex.wgsl") + } else { + include_str!("tile_mask.vertex.wgsl") + }, entry_point: "main", buffers: vec![VertexBufferLayout { array_stride: std::mem::size_of::() as u64, @@ -66,7 +71,7 @@ impl Shader for TileMaskShader { fn describe_fragment(&self) -> FragmentState { FragmentState { - source: include_str!("tile_mask.fragment.wgsl"), + source: include_str!("basic.fragment.wgsl"), entry_point: "main", targets: vec![Some(wgpu::ColorTargetState { format: self.format, @@ -176,22 +181,10 @@ impl Shader for TileShader { fn describe_fragment(&self) -> FragmentState { FragmentState { - source: include_str!("tile.fragment.wgsl"), + source: include_str!("basic.fragment.wgsl"), entry_point: "main", targets: vec![Some(wgpu::ColorTargetState { format: self.format, - /*blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent { - src_factor: wgpu::BlendFactor::SrcAlpha, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - alpha: wgpu::BlendComponent { - src_factor: wgpu::BlendFactor::SrcAlpha, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - }),*/ blend: None, write_mask: wgpu::ColorWrites::ALL, })], diff --git a/maplibre/src/render/shaders/tile_debug.vertex.wgsl b/maplibre/src/render/shaders/tile_debug.vertex.wgsl new file mode 100644 index 00000000..f469a328 --- /dev/null +++ b/maplibre/src/render/shaders/tile_debug.vertex.wgsl @@ -0,0 +1,75 @@ +struct VertexOutput { + @location(0) v_color: vec4, + @builtin(position) position: vec4, +}; + +var EXTENT: f32 = 4096.0; +var DEBUG_COLOR: vec4 = vec4(1.0, 0.0, 0.0, 1.0); + +@vertex +fn main( + @location(4) translate1: vec4, + @location(5) translate2: vec4, + @location(6) translate3: vec4, + @location(7) translate4: vec4, + @builtin(vertex_index) vertex_idx: u32, + @builtin(instance_index) instance_idx: u32 // instance_index is used when we have multiple instances of the same "object" +) -> VertexOutput { + let z = 0.0; + + let target_width = 1.0; + let target_height = 1.0; + + let WIDTH = EXTENT / 1024.0; + + var VERTICES: array, 24> = array, 24>( + // Debug lines vertices + // left + vec3(0.0, 0.0, z), + vec3(0.0, EXTENT, z), + vec3(WIDTH, EXTENT, z), + + vec3(0.0, 0.0, z), + vec3(WIDTH, EXTENT, z), + vec3(WIDTH, 0.0, z), + + // right + vec3(EXTENT - WIDTH, 0.0, z), + vec3(EXTENT - WIDTH, EXTENT, z), + vec3(EXTENT, EXTENT, z), + + vec3(EXTENT - WIDTH, 0.0, z), + vec3(EXTENT, EXTENT, z), + vec3(EXTENT, 0.0, z), + + // top + vec3(0.0, 0.0, z), + vec3(0.0, WIDTH, z), + vec3(EXTENT, WIDTH, z), + + vec3(0.0, 0.0, z), + vec3(EXTENT, WIDTH, z), + vec3(EXTENT, 0.0, z), + + // bottom + vec3(0.0, EXTENT - WIDTH, z), + vec3(0.0, EXTENT, z), + vec3(EXTENT, EXTENT, z), + + vec3(0.0, EXTENT - WIDTH, z), + vec3(EXTENT, EXTENT, z), + vec3(EXTENT, EXTENT - WIDTH, z) + ); + + let a_position = VERTICES[vertex_idx]; + + let scaling: mat3x3 = mat3x3( + vec3(target_width, 0.0, 0.0), + vec3(0.0, target_height, 0.0), + vec3(0.0, 0.0, 1.0) + ); + + var position = mat4x4(translate1, translate2, translate3, translate4) * vec4((scaling * a_position), 1.0); + position.z = 1.0; + return VertexOutput(DEBUG_COLOR, position); +} diff --git a/maplibre/src/render/shaders/tile_mask.fragment.wgsl b/maplibre/src/render/shaders/tile_mask.fragment.wgsl deleted file mode 100644 index 977de422..00000000 --- a/maplibre/src/render/shaders/tile_mask.fragment.wgsl +++ /dev/null @@ -1,8 +0,0 @@ -struct Output { - @location(0) out_color: vec4, -}; - -@fragment -fn main(@location(0) v_color: vec4) -> Output { - return Output(v_color); -} diff --git a/maplibre/src/render/shaders/tile_mask.vertex.wgsl b/maplibre/src/render/shaders/tile_mask.vertex.wgsl index 5d866e56..80ad1ba8 100644 --- a/maplibre/src/render/shaders/tile_mask.vertex.wgsl +++ b/maplibre/src/render/shaders/tile_mask.vertex.wgsl @@ -1,20 +1,10 @@ -struct ShaderCamera { - view_proj: mat4x4, - view_position: vec4, -}; - -struct ShaderGlobal { - camera: ShaderCamera, -}; - -@group(0) @binding(0) var globals: ShaderGlobal; - struct VertexOutput { - @location(0) v_color: vec4, + @location(0) v_color: vec4, @builtin(position) position: vec4, }; -let EXTENT = 4096.0; +var EXTENT: f32 = 4096.0; +var DEBUG_COLOR: vec4 = vec4(1.0, 0.0, 0.0, 1.0); @vertex fn main( @@ -29,15 +19,15 @@ fn main( let target_width = 1.0; let target_height = 1.0; - let debug_color = vec4(1.0, 0.0, 0.0, 1.0); var VERTICES: array, 6> = array, 6>( + // Tile vertices vec3(0.0, 0.0, z), vec3(0.0, EXTENT, z), vec3(EXTENT, 0.0, z), vec3(EXTENT, 0.0, z), vec3(0.0, EXTENT, z), - vec3(EXTENT, EXTENT, z) + vec3(EXTENT, EXTENT, z), ); let a_position = VERTICES[vertex_idx]; @@ -51,5 +41,5 @@ fn main( // FIXME: how to fix z-fighting? position.z = 1.0; - return VertexOutput(debug_color, position); + return VertexOutput(DEBUG_COLOR, position); } diff --git a/maplibre/src/render/stages/queue_stage.rs b/maplibre/src/render/stages/queue_stage.rs index 8be402bd..349a2d20 100644 --- a/maplibre/src/render/stages/queue_stage.rs +++ b/maplibre/src/render/stages/queue_stage.rs @@ -2,10 +2,7 @@ use crate::{ context::MapContext, - render::{ - eventually::Eventually::Initialized, resource::IndexEntry, tile_view_pattern::TileInView, - RenderState, Renderer, - }, + render::{eventually::Eventually::Initialized, resource::IndexEntry, RenderState, Renderer}, schedule::Stage, }; @@ -40,28 +37,28 @@ impl Stage for QueueStage { let index = buffer_pool.index(); - for tile_in_view in tile_view_pattern.iter() { - let TileInView { shape, fallback } = &tile_in_view; - let coords = shape.coords; + for view_tile in tile_view_pattern.iter() { + let coords = &view_tile.coords(); tracing::trace!("Drawing tile at {coords}"); - let shape_to_render = fallback.as_ref().unwrap_or(shape); + // draw tile normal or the source e.g. parent or children + view_tile.render(|source_shape| { + // Draw masks for all source_shapes + mask_phase.add(source_shape.clone()); - // Draw mask - mask_phase.add(tile_in_view.clone()); - - let Some(entries) = index.get_layers(&shape_to_render.coords) else { - tracing::trace!("No layers found at {}", &shape_to_render.coords); - continue; + let Some(entries) = index.get_layers(&source_shape.coords()) else { + tracing::trace!("No layers found at {}", &source_shape.coords()); + return; }; - let mut layers_to_render: Vec<&IndexEntry> = Vec::from_iter(entries); - layers_to_render.sort_by_key(|entry| entry.style_layer.index); + let mut layers_to_render: Vec<&IndexEntry> = Vec::from_iter(entries); + layers_to_render.sort_by_key(|entry| entry.style_layer.index); - for entry in layers_to_render { - // Draw tile - tile_phase.add((entry.clone(), shape_to_render.clone())) - } + for entry in layers_to_render { + // Draw tile + tile_phase.add((entry.clone(), source_shape.clone())) + } + }); } } } diff --git a/maplibre/src/render/stages/resource_stage.rs b/maplibre/src/render/stages/resource_stage.rs index 3c5541b8..3521e64e 100644 --- a/maplibre/src/render/stages/resource_stage.rs +++ b/maplibre/src/render/stages/resource_stage.rs @@ -9,7 +9,7 @@ use crate::{ shaders, shaders::{Shader, ShaderTileMetadata}, tile_pipeline::TilePipeline, - tile_view_pattern::{TileViewPattern, DEFAULT_TILE_VIEW_SIZE}, + tile_view_pattern::{TileViewPattern, DEFAULT_TILE_VIEW_PATTERN_SIZE}, Renderer, }, schedule::Stage, @@ -83,7 +83,7 @@ impl Stage for ResourceStage { let tile_view_buffer_desc = wgpu::BufferDescriptor { label: Some("tile view buffer"), size: size_of::() as wgpu::BufferAddress - * DEFAULT_TILE_VIEW_SIZE, + * DEFAULT_TILE_VIEW_PATTERN_SIZE, usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }; @@ -104,9 +104,11 @@ impl Stage for ResourceStage { tile_shader.describe_vertex(), tile_shader.describe_fragment(), true, + true, false, false, false, + true, ) .describe_render_pipeline() .initialize(device); @@ -122,6 +124,7 @@ impl Stage for ResourceStage { let mask_shader = shaders::TileMaskShader { format: surface.surface_format(), draw_colors: false, + debug_lines: false, }; TilePipeline::new( @@ -130,6 +133,30 @@ impl Stage for ResourceStage { mask_shader.describe_fragment(), false, true, + true, + false, + false, + true, + ) + .describe_render_pipeline() + .initialize(device) + }); + + state.debug_pipeline.initialize(|| { + let mask_shader = shaders::TileMaskShader { + format: surface.surface_format(), + draw_colors: true, + debug_lines: true, + }; + + TilePipeline::new( + *settings, + mask_shader.describe_vertex(), + mask_shader.describe_fragment(), + false, + false, + false, + true, false, false, ) diff --git a/maplibre/src/render/stages/upload_stage.rs b/maplibre/src/render/stages/upload_stage.rs index a40d87c6..6da45dd1 100644 --- a/maplibre/src/render/stages/upload_stage.rs +++ b/maplibre/src/render/stages/upload_stage.rs @@ -133,7 +133,7 @@ impl UploadStage { }) .collect::>(); - buffer_pool.update_feature_metadata(&queue, entry, &feature_metadata); + buffer_pool.update_feature_metadata(queue, entry, &feature_metadata); } } } @@ -163,15 +163,16 @@ impl UploadStage { view_region: &ViewRegion, ) { let Initialized(buffer_pool) = buffer_pool else { return; }; + // Upload all tessellated layers which are in view for coords in view_region.iter() { let Some(available_layers) = - tile_repository.iter_loaded_layers_at(&buffer_pool, &coords) else { continue; }; + tile_repository.iter_loaded_layers_at(buffer_pool, &coords) else { continue; }; for style_layer in &style.layers { let source_layer = style_layer.source_layer.as_ref().unwrap(); // TODO: Remove unwrap - let Some(message) = available_layers + let Some(stored_layer) = available_layers .iter() .find(|layer| source_layer.as_str() == layer.layer_name()) else { continue; }; @@ -181,7 +182,7 @@ impl UploadStage { .and_then(|paint| paint.get_color()) .map(|color| color.into()); - match message { + match stored_layer { StoredLayer::UnavailableLayer { .. } => {} StoredLayer::TessellatedLayer { coords, @@ -190,7 +191,7 @@ impl UploadStage { .. } => { let allocate_feature_metadata = - tracing::span!(tracing::Level::TRACE, "allocate_layer_geometry"); + tracing::span!(tracing::Level::TRACE, "allocate_feature_metadata"); let guard = allocate_feature_metadata.enter(); let feature_metadata = (0..feature_indices.len()) // FIXME: Iterate over actual featrues diff --git a/maplibre/src/render/tile_pipeline.rs b/maplibre/src/render/tile_pipeline.rs index 2548d378..56750d7d 100644 --- a/maplibre/src/render/tile_pipeline.rs +++ b/maplibre/src/render/tile_pipeline.rs @@ -13,9 +13,14 @@ use crate::{ pub struct TilePipeline { bind_globals: bool, + /// Is the depth stencil used? + depth_stencil_enabled: bool, + /// This pipeline updates the stenctil update_stencil: bool, + /// Force a write and ignore stencil debug_stencil: bool, wireframe: bool, + multisampling: bool, settings: RendererSettings, vertex_state: VertexState, @@ -28,15 +33,19 @@ impl TilePipeline { vertex_state: VertexState, fragment_state: FragmentState, bind_globals: bool, + depth_stencil_enabled: bool, update_stencil: bool, debug_stencil: bool, wireframe: bool, + multisampling: bool, ) -> Self { TilePipeline { bind_globals, + depth_stencil_enabled, update_stencil, debug_stencil, wireframe, + multisampling, settings, vertex_state, fragment_state, @@ -104,20 +113,28 @@ impl RenderPipeline for TilePipeline { conservative: false, unclipped_depth: false, }, - depth_stencil: Some(wgpu::DepthStencilState { - format: self.settings.depth_texture_format, - depth_write_enabled: !self.update_stencil, - depth_compare: wgpu::CompareFunction::Greater, - stencil: wgpu::StencilState { - front: stencil_state, - back: stencil_state, - read_mask: 0xff, // Applied to stencil values being read from the stencil buffer - write_mask: 0xff, // Applied to fragment stencil values before being written to the stencil buffer - }, - bias: wgpu::DepthBiasState::default(), - }), + depth_stencil: if !self.depth_stencil_enabled { + None + } else { + Some(wgpu::DepthStencilState { + format: self.settings.depth_texture_format, + depth_write_enabled: !self.update_stencil, + depth_compare: wgpu::CompareFunction::Greater, + stencil: wgpu::StencilState { + front: stencil_state, + back: stencil_state, + read_mask: 0xff, // Applied to stencil values being read from the stencil buffer + write_mask: 0xff, // Applied to fragment stencil values before being written to the stencil buffer + }, + bias: wgpu::DepthBiasState::default(), + }) + }, multisample: wgpu::MultisampleState { - count: self.settings.msaa.samples, + count: if self.multisampling { + self.settings.msaa.samples + } else { + 1 + }, mask: !0, alpha_to_coverage_enabled: false, }, diff --git a/maplibre/src/render/tile_view_pattern.rs b/maplibre/src/render/tile_view_pattern.rs index 39fe541d..2c9026fe 100644 --- a/maplibre/src/render/tile_view_pattern.rs +++ b/maplibre/src/render/tile_view_pattern.rs @@ -15,42 +15,91 @@ use crate::{ tessellation::IndexDataType, }; -pub const DEFAULT_TILE_VIEW_SIZE: wgpu::BufferAddress = 32 * 4; - -/// The tile mask pattern assigns each tile a value which can be used for stencil testing. -pub struct TileViewPattern { - in_view: Vec, - buffer: BackingBuffer, - phantom_q: PhantomData, -} +pub const DEFAULT_TILE_VIEW_PATTERN_SIZE: wgpu::BufferAddress = 32 * 4; +pub const CHILDREN_SEARCH_DEPTH: usize = 4; +/// Defines the exact location where a specific tile on the map is rendered. It defines the shape +/// of the tile with its location for the current zoom factor. #[derive(Clone)] pub struct TileShape { - pub zoom_factor: f64, + coords: WorldTileCoords, - pub coords: WorldTileCoords, + // TODO: optimization, `zoom_factor` and `transform` are no longer required if `buffer_range` is Some() + zoom_factor: f64, + transform: Matrix4, - pub transform: Matrix4, - pub buffer_range: Range, + buffer_range: Option>, } impl TileShape { - fn new(coords: WorldTileCoords, zoom: Zoom, index: u64) -> Self { - const STRIDE: u64 = size_of::() as u64; + fn new(coords: WorldTileCoords, zoom: Zoom) -> Self { Self { coords, zoom_factor: zoom.scale_to_tile(&coords), transform: coords.transform_for_zoom(zoom), - buffer_range: index * STRIDE..(index + 1) * STRIDE, + buffer_range: None, } } + + fn set_buffer_range(&mut self, index: u64) { + const STRIDE: u64 = size_of::() as u64; + self.buffer_range = Some(index * STRIDE..(index + 1) * STRIDE); + } + + pub fn buffer_range(&self) -> Range { + self.buffer_range.as_ref().unwrap().clone() + } + + pub fn coords(&self) -> WorldTileCoords { + self.coords + } } +/// This defines the source tile shaped from which the content for the `target` is taken. +/// For example if the target is `(0, 0, 1)` (of [`ViewTile`]) , we might use +/// `SourceShapes::Parent((0, 0, 0))` as source. +/// Similarly if we have the target `(0, 0, 0)` we might use +/// `SourceShapes::Children((0, 0, 1), (0, 1, 1), (1, 0, 1), (1, 1, 1))` as sources. #[derive(Clone)] -pub struct TileInView { - pub shape: TileShape, +pub enum SourceShapes { + /// Parent tile is the source. We construct the `target` from parts of a parent. + Parent(TileShape), + /// Children are the source. We construct the `target` from multiple children. + Children(Vec), + /// Source and target are equal, so no need to differentiate. We render the `source` shape + /// exactly at the `target`. + SourceEqTarget(TileShape), + /// No data available so nothing to render + None, +} - pub fallback: Option, +/// Defines the `target` tile and its `source` from which data tile data comes. +#[derive(Clone)] +pub struct ViewTile { + target: WorldTileCoords, + source: SourceShapes, +} + +impl ViewTile { + pub fn coords(&self) -> WorldTileCoords { + self.target + } + + pub fn render(&self, mut callback: F) + where + F: FnMut(&TileShape), + { + match &self.source { + SourceShapes::Parent(source_shape) => callback(source_shape), + SourceShapes::Children(source_shapes) => { + for shape in source_shapes { + callback(shape) + } + } + SourceShapes::SourceEqTarget(source_shape) => callback(source_shape), + SourceShapes::None => {} + } + } } #[derive(Debug)] @@ -67,6 +116,13 @@ impl BackingBuffer { } } +/// The tile mask pattern assigns each tile a value which can be used for stencil testing. +pub struct TileViewPattern { + in_view: Vec, + buffer: BackingBuffer, + phantom_q: PhantomData, +} + impl, B> TileViewPattern { pub fn new(buffer: BackingBufferDescriptor) -> Self { Self { @@ -92,8 +148,6 @@ impl, B> TileViewPattern { ) { self.in_view.clear(); - let mut index = 0; - let pool_index = buffer_pool.index(); for coords in view_region.iter() { @@ -101,34 +155,39 @@ impl, B> TileViewPattern { continue; } - let shape = TileShape::new(coords, zoom, index); + let source_shapes = { + if pool_index.has_tile(&coords) { + SourceShapes::SourceEqTarget(TileShape::new(coords, zoom)) + } else if let Some(parent_coords) = pool_index.get_available_parent(&coords) { + log::info!("Could not find data at {coords}. Falling back to {parent_coords}"); - index += 1; + SourceShapes::Parent(TileShape::new(parent_coords, zoom)) + } else if let Some(children_coords) = + pool_index.get_available_children(&coords, CHILDREN_SEARCH_DEPTH) + { + log::info!( + "Could not find data at {coords}. Falling back children: {children_coords:?}" + ); - let fallback = { - if !pool_index.has_tile(&coords) { - if let Some(fallback_coords) = pool_index.get_tile_coords_fallback(&coords) { - tracing::trace!( - "Could not find data at {coords}. Falling back to {fallback_coords}" - ); - - let shape = TileShape::new(fallback_coords, zoom, index); - - index += 1; - Some(shape) - } else { - None - } + SourceShapes::Children( + children_coords + .iter() + .map(|child_coord| TileShape::new(*child_coord, zoom)) + .collect(), + ) } else { - None + SourceShapes::None } }; - self.in_view.push(TileInView { shape, fallback }); + self.in_view.push(ViewTile { + target: coords, + source: source_shapes, + }); } } - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator + '_ { self.in_view.iter() } @@ -137,30 +196,34 @@ impl, B> TileViewPattern { } #[tracing::instrument(skip_all)] - pub fn upload_pattern(&self, queue: &Q, view_proj: &ViewProjection) { + pub fn upload_pattern(&mut self, queue: &Q, view_proj: &ViewProjection) { let mut buffer = Vec::with_capacity(self.in_view.len()); - for tile in &self.in_view { + let mut add_to_buffer = |shape: &mut TileShape| { + shape.set_buffer_range(buffer.len() as u64); buffer.push(ShaderTileMetadata { // We are casting here from 64bit to 32bit, because 32bit is more performant and is // better supported. transform: view_proj - .to_model_view_projection(tile.shape.transform) + .to_model_view_projection(shape.transform) .downcast() .into(), - zoom_factor: tile.shape.zoom_factor as f32, + zoom_factor: shape.zoom_factor as f32, }); + }; - if let Some(fallback_shape) = &tile.fallback { - buffer.push(ShaderTileMetadata { - // We are casting here from 64bit to 32bit, because 32bit is more performant and is - // better supported. - transform: view_proj - .to_model_view_projection(fallback_shape.transform) - .downcast() - .into(), - zoom_factor: fallback_shape.zoom_factor as f32, - }); + for view_tile in &mut self.in_view { + match &mut view_tile.source { + SourceShapes::Parent(source_shape) => { + add_to_buffer(source_shape); + } + SourceShapes::Children(source_shapes) => { + for source_shape in source_shapes { + add_to_buffer(source_shape); + } + } + SourceShapes::SourceEqTarget(source_shape) => add_to_buffer(source_shape), + SourceShapes::None => {} } } @@ -173,7 +236,9 @@ impl, B> TileViewPattern { queue.write_buffer(&self.buffer.inner, 0, raw_buffer); } - pub fn stencil_reference_value(&self, world_coords: &WorldTileCoords) -> u8 { + /// 2D version of [`TileViewPattern::stencil_reference_value_3d`]. This is kept for reference. + /// For the 2D case we do not take into account the Z value, so only 4 cases exist. + pub fn stencil_reference_value_2d(&self, world_coords: &WorldTileCoords) -> u8 { match (world_coords.x, world_coords.y) { (x, y) if x % 2 == 0 && y % 2 == 0 => 2, (x, y) if x % 2 == 0 && y % 2 != 0 => 1, @@ -182,4 +247,18 @@ impl, B> TileViewPattern { _ => unreachable!(), } } + + /// Returns unique stencil reference values for WorldTileCoords which are 3D. + /// Tiles from arbitrary `z` can lie next to each other, because we mix tiles from + /// different levels based on availability. + pub fn stencil_reference_value_3d(&self, world_coords: &WorldTileCoords) -> u8 { + const CASES: u8 = 4; + match (world_coords.x, world_coords.y, u8::from(world_coords.z)) { + (x, y, z) if x % 2 == 0 && y % 2 == 0 => 0 + z * CASES, + (x, y, z) if x % 2 == 0 && y % 2 != 0 => 1 + z * CASES, + (x, y, z) if x % 2 != 0 && y % 2 == 0 => 2 + z * CASES, + (x, y, z) if x % 2 != 0 && y % 2 != 0 => 3 + z * CASES, + _ => unreachable!(), + } + } } diff --git a/maplibre/src/stages/mod.rs b/maplibre/src/stages/mod.rs index b81d056b..40807ed2 100644 --- a/maplibre/src/stages/mod.rs +++ b/maplibre/src/stages/mod.rs @@ -39,7 +39,7 @@ pub struct HeadedPipelineProcessor, } -impl<'c, T: Transferables, HC: HttpClient, C: Context> PipelineProcessor +impl> PipelineProcessor for HeadedPipelineProcessor { fn tile_finished(&mut self, coords: &WorldTileCoords) -> Result<(), PipelineError> { diff --git a/maplibre/src/stages/populate_tile_store_stage.rs b/maplibre/src/stages/populate_tile_store_stage.rs index 5ee85d35..e57bb803 100644 --- a/maplibre/src/stages/populate_tile_store_stage.rs +++ b/maplibre/src/stages/populate_tile_store_stage.rs @@ -42,6 +42,7 @@ impl Stage for PopulateTileStore { // available this might cause frame drops. while let Some(result) = self.kernel.apc().receive() { match result { + // TODO: deduplicate Message::TileTessellated(message) => { let coords = message.coords(); tracing::event!(tracing::Level::ERROR, %coords, "tile request done: {}", &coords); @@ -49,9 +50,8 @@ impl Stage for PopulateTileStore { tracing::trace!("Tile at {} finished loading", coords); log::warn!("Tile at {} finished loading", coords); - tile_repository.mark_tile_succeeded(&coords); + tile_repository.mark_tile_succeeded(&coords).unwrap(); // TODO: unwrap } - // FIXME: deduplicate Message::LayerUnavailable(message) => { let layer: StoredLayer = message.to_stored_layer(); diff --git a/maplibre/src/stages/request_stage.rs b/maplibre/src/stages/request_stage.rs index 413fff59..82465728 100644 --- a/maplibre/src/stages/request_stage.rs +++ b/maplibre/src/stages/request_stage.rs @@ -142,13 +142,8 @@ impl RequestStage { coords: WorldTileCoords, layers: &HashSet, ) { - /* TODO: is this still required? - if !tile_repository.is_layers_missing(coords, layers) { - return Ok(false); - }*/ - - if tile_repository.has_tile(&coords) { - tile_repository.create_tile(coords); + if tile_repository.is_tile_pending_or_done(&coords) { + tile_repository.mark_tile_pending(coords).unwrap(); // TODO: Remove unwrap tracing::event!(tracing::Level::ERROR, %coords, "tile request started: {}", &coords); diff --git a/web/demo/package-lock.json b/web/demo/package-lock.json index 9dfadb41..98c1f550 100644 --- a/web/demo/package-lock.json +++ b/web/demo/package-lock.json @@ -26,7 +26,6 @@ } }, "../lib": { - "name": "maplibre-rs", "version": "0.0.1", "license": "MIT", "dependencies": { @@ -262,13 +261,13 @@ "dev": true }, "node_modules/@types/express": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", - "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", + "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", "dev": true, "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", + "@types/express-serve-static-core": "^4.17.31", "@types/qs": "*", "@types/serve-static": "*" } @@ -312,9 +311,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "version": "18.11.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", + "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", "dev": true }, "node_modules/@types/qs": { @@ -621,9 +620,9 @@ } }, "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -702,9 +701,9 @@ } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -896,9 +895,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001430", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001430.tgz", - "integrity": "sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg==", + "version": "1.0.30001439", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", + "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", "dev": true, "funding": [ { @@ -1398,9 +1397,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -1640,9 +1639,9 @@ } }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -1907,9 +1906,9 @@ "dev": true }, "node_modules/globby": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", - "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", + "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", "dev": true, "dependencies": { "dir-glob": "^3.0.1", @@ -2178,9 +2177,9 @@ } }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true, "engines": { "node": ">= 4" @@ -2449,9 +2448,9 @@ } }, "node_modules/loader-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", - "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -2521,9 +2520,9 @@ } }, "node_modules/memfs": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.10.tgz", - "integrity": "sha512-0bCUP+L79P4am30yP1msPzApwuMQG23TjwlwdHeEV5MxioDR1a0AgB0T9FfggU52eJuDCq8WVwb5ekznFyWiTQ==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.12.tgz", + "integrity": "sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==", "dev": true, "dependencies": { "fs-monkey": "^1.0.3" @@ -2689,9 +2688,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.7.tgz", + "integrity": "sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ==", "dev": true }, "node_modules/normalize-path": { @@ -3699,9 +3698,9 @@ } }, "node_modules/terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.2", @@ -3833,9 +3832,9 @@ } }, "node_modules/ts-loader": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", - "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz", + "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==", "dev": true, "dependencies": { "chalk": "^4.1.0", @@ -3914,9 +3913,9 @@ } }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -4038,9 +4037,9 @@ } }, "node_modules/webpack": { - "version": "5.74.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", - "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -4340,9 +4339,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.10.0.tgz", - "integrity": "sha512-+s49uSmZpvtAsd2h37vIPy1RBusaLawVe8of+GyEPsaJTCMpj/2v8NpeK1SHXjBlQ95lQTmQofOJnFiLoaN3yw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, "engines": { "node": ">=10.0.0" @@ -4574,13 +4573,13 @@ "dev": true }, "@types/express": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", - "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", + "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", "dev": true, "requires": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", + "@types/express-serve-static-core": "^4.17.31", "@types/qs": "*", "@types/serve-static": "*" } @@ -4624,9 +4623,9 @@ "dev": true }, "@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "version": "18.11.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", + "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", "dev": true }, "@types/qs": { @@ -4906,9 +4905,9 @@ "dev": true }, "ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -4957,9 +4956,9 @@ } }, "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -5112,9 +5111,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001430", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001430.tgz", - "integrity": "sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg==", + "version": "1.0.30001439", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", + "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", "dev": true }, "chalk": { @@ -5487,9 +5486,9 @@ "dev": true }, "enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -5684,9 +5683,9 @@ "dev": true }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -5873,9 +5872,9 @@ "dev": true }, "globby": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", - "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", + "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", "dev": true, "requires": { "dir-glob": "^3.0.1", @@ -6079,9 +6078,9 @@ } }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true }, "import-local": { @@ -6268,9 +6267,9 @@ "dev": true }, "loader-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", - "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -6338,9 +6337,9 @@ "dev": true }, "memfs": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.10.tgz", - "integrity": "sha512-0bCUP+L79P4am30yP1msPzApwuMQG23TjwlwdHeEV5MxioDR1a0AgB0T9FfggU52eJuDCq8WVwb5ekznFyWiTQ==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.12.tgz", + "integrity": "sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==", "dev": true, "requires": { "fs-monkey": "^1.0.3" @@ -6467,9 +6466,9 @@ "dev": true }, "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.7.tgz", + "integrity": "sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ==", "dev": true }, "normalize-path": { @@ -7219,9 +7218,9 @@ "dev": true }, "terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.2", @@ -7311,9 +7310,9 @@ "dev": true }, "ts-loader": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", - "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz", + "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -7360,9 +7359,9 @@ } }, "typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true }, "unpipe": { @@ -7446,9 +7445,9 @@ } }, "webpack": { - "version": "5.74.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", - "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -7648,9 +7647,9 @@ "dev": true }, "ws": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.10.0.tgz", - "integrity": "sha512-+s49uSmZpvtAsd2h37vIPy1RBusaLawVe8of+GyEPsaJTCMpj/2v8NpeK1SHXjBlQ95lQTmQofOJnFiLoaN3yw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, "requires": {} },