From c6eadbf2cc6841bccf07321f08920d148d0c90cc Mon Sep 17 00:00:00 2001 From: Maximilian Ammann Date: Sun, 25 Sep 2022 16:25:00 +0200 Subject: [PATCH] Fix compilation issues and cleanup --- maplibre/src/context.rs | 7 + maplibre/src/error.rs | 9 + maplibre/src/headless/map.rs | 15 +- maplibre/src/headless/mod.rs | 4 +- maplibre/src/headless/window.rs | 8 +- maplibre/src/lib.rs | 10 +- maplibre/src/map.rs | 83 ++++----- maplibre/src/map_schedule.rs | 218 +++--------------------- maplibre/src/render/builder.rs | 74 ++++++-- maplibre/src/render/error.rs | 16 +- maplibre/src/render/resource/surface.rs | 4 +- maplibre/src/window.rs | 11 +- maplibre/src/world.rs | 5 + 13 files changed, 189 insertions(+), 275 deletions(-) diff --git a/maplibre/src/context.rs b/maplibre/src/context.rs index cb970f2c..20f06401 100644 --- a/maplibre/src/context.rs +++ b/maplibre/src/context.rs @@ -6,3 +6,10 @@ pub struct MapContext { pub world: World, pub renderer: Renderer, } + +impl MapContext { + pub fn resize(&mut self, width: u32, height: u32) { + self.world.view_state.resize(width, height); + self.renderer.resize(width, height) + } +} diff --git a/maplibre/src/error.rs b/maplibre/src/error.rs index 4d5f7fbe..cd2d1fe3 100644 --- a/maplibre/src/error.rs +++ b/maplibre/src/error.rs @@ -15,6 +15,15 @@ pub enum Error { Render(RenderError), } +impl From for Error +where + E: Into, +{ + fn from(e: E) -> Self { + Error::Render(e.into()) + } +} + impl From for Error { fn from(e: TessellationError) -> Self { Error::Tesselation(e) diff --git a/maplibre/src/headless/map.rs b/maplibre/src/headless/map.rs index 54deef43..33ec7861 100644 --- a/maplibre/src/headless/map.rs +++ b/maplibre/src/headless/map.rs @@ -1,4 +1,5 @@ use crate::io::pipeline::Processable; +use crate::render::builder::UninitializedRenderer; use crate::{ context::MapContext, coords::{WorldCoords, WorldTileCoords, Zoom, TILE_SIZE}, @@ -28,19 +29,19 @@ use crate::{ use std::collections::HashSet; pub struct HeadlessMap { - window_size: WindowSize, kernel: Kernel, - map_context: MapContext, schedule: Schedule, + map_context: MapContext, } impl HeadlessMap { pub fn new( style: Style, - window_size: WindowSize, renderer: Renderer, kernel: Kernel, ) -> Result { + let window_size = renderer.state().surface().size(); + let world = World::new( window_size, WorldCoords::from((TILE_SIZE / 2., TILE_SIZE / 2.)), @@ -67,7 +68,6 @@ impl HeadlessMap { ); Ok(Self { - window_size, kernel, map_context: MapContext { style, @@ -94,7 +94,7 @@ impl HeadlessMap { pub async fn fetch_tile( &self, coords: WorldTileCoords, - source_layers: HashSet, + source_layers: &[&str], ) -> Result { let source_client = &self.kernel.source_client; @@ -107,7 +107,10 @@ impl HeadlessMap { ( TileRequest { coords: WorldTileCoords::default(), - layers: source_layers, + layers: source_layers + .iter() + .map(|layer| layer.to_string()) + .collect::>(), }, data, ), diff --git a/maplibre/src/headless/mod.rs b/maplibre/src/headless/mod.rs index 24362188..3b7eefbc 100644 --- a/maplibre/src/headless/mod.rs +++ b/maplibre/src/headless/mod.rs @@ -1,6 +1,6 @@ -mod environment; mod graph_node; mod stage; -mod window; +pub mod environment; pub mod map; +pub mod window; diff --git a/maplibre/src/headless/window.rs b/maplibre/src/headless/window.rs index 7faf5991..16454962 100644 --- a/maplibre/src/headless/window.rs +++ b/maplibre/src/headless/window.rs @@ -1,7 +1,13 @@ use crate::window::{MapWindow, MapWindowConfig, WindowSize}; pub struct HeadlessMapWindowConfig { - pub size: WindowSize, + size: WindowSize, +} + +impl HeadlessMapWindowConfig { + pub fn new(size: WindowSize) -> Self { + Self { size } + } } impl MapWindowConfig for HeadlessMapWindowConfig { diff --git a/maplibre/src/lib.rs b/maplibre/src/lib.rs index 50774a5d..2f702f18 100644 --- a/maplibre/src/lib.rs +++ b/maplibre/src/lib.rs @@ -16,14 +16,15 @@ //! maplibre = "0.0.2" //! ``` +// Internal modules +pub(crate) mod tessellation; + pub mod context; pub mod coords; pub mod error; #[cfg(feature = "headless")] pub mod headless; pub mod io; -// Exposed because of input handlers in maplibre-winit -pub mod map_schedule; pub mod platform; // TODO: Exposed because of camera pub mod render; @@ -41,9 +42,8 @@ pub mod environment; // Used for benchmarking pub mod benchmarking; -// Internal modules -pub(crate) mod tessellation; -mod world; +pub mod map; +pub mod world; // Export tile format pub use geozero::mvt::tile; diff --git a/maplibre/src/map.rs b/maplibre/src/map.rs index 3f7952fc..4a71ff99 100644 --- a/maplibre/src/map.rs +++ b/maplibre/src/map.rs @@ -1,47 +1,50 @@ -/// The [`Map`] defines the public interface of the map renderer. -// DO NOT IMPLEMENT INTERNALS ON THIS STRUCT. +use crate::context::MapContext; +use crate::coords::{LatLon, WorldCoords, Zoom, TILE_SIZE}; +use crate::environment::{Environment, Kernel}; +use crate::error::Error; +use crate::headless::environment::HeadlessEnvironment; +use crate::render::{create_default_render_graph, register_default_render_stages, Renderer}; +use crate::schedule::{Schedule, Stage}; +use crate::style::Style; +use crate::world::World; + pub struct Map { - // FIXME (wasm-executor): Avoid RefCell, change ownership model! - map_schedule: Rc>>, - window: RefCell::MapWindow>>, + kernel: Kernel, + schedule: Schedule, + map_context: MapContext, } -impl Map -where - ::MapWindow: EventLoop, -{ - /// Starts the [`crate::map_schedule::MapState`] Runnable with the configured event loop. - pub fn run(&self) { - self.run_with_optionally_max_frames(None); +impl Map { + pub fn new(style: Style, kernel: Kernel, renderer: Renderer) -> Result { + let window_size = renderer.state().surface().size(); + + let center = style.center.unwrap_or_default(); + let world = World::new_at( + window_size, + LatLon::new(center[0], center[1]), + style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default(), + cgmath::Deg::(style.pitch.unwrap_or_default()), + ); + + let mut schedule = Schedule::default(); + + let graph = create_default_render_graph().unwrap(); // TODO: Remove unwrap + register_default_render_stages(graph, &mut schedule); + + Ok(Self { + kernel, + map_context: MapContext { + style, + world, + renderer, + }, + schedule, + }) } - /// Starts the [`crate::map_schedule::MapState`] Runnable with the configured event loop. - /// - /// # Arguments - /// - /// * `max_frames` - Maximum number of frames per second. - pub fn run_with_max_frames(&self, max_frames: u64) { - self.run_with_optionally_max_frames(Some(max_frames)); + #[tracing::instrument(name = "update_and_redraw", skip_all)] + pub fn run_schedule(&mut self) -> Result<(), Error> { + self.schedule.run(&mut self.map_context); + Ok(()) } - - /// Starts the MapState Runnable with the configured event loop. - /// - /// # Arguments - /// - /// * `max_frames` - Optional maximum number of frames per second. - pub fn run_with_optionally_max_frames(&self, max_frames: Option) { - self.window - .borrow_mut() - .take() - .unwrap() // FIXME (wasm-executor): Remove unwrap - .run(self.map_schedule.clone(), max_frames); - } - - pub fn map_schedule(&self) -> Rc>> { - self.map_schedule.clone() - } - - /* pub fn map_schedule_mut(&mut self) -> &mut InteractiveMapSchedule { - &mut self.map_schedule - }*/ } diff --git a/maplibre/src/map_schedule.rs b/maplibre/src/map_schedule.rs index c191cd35..afea13f9 100644 --- a/maplibre/src/map_schedule.rs +++ b/maplibre/src/map_schedule.rs @@ -1,198 +1,26 @@ -use std::{cell::RefCell, marker::PhantomData, mem, rc::Rc}; +/* pub fn resume(&mut self, window: &::MapWindow) { + if let EventuallyMapContext::Full(map_context) = &mut self.map_context { + let renderer = &mut map_context.renderer; + renderer.state.recreate_surface(window, &renderer.instance); + } +}*/ -use crate::{ - context::MapContext, - coords::{LatLon, WorldCoords, Zoom, TILE_SIZE}, - environment::Environment, - error::Error, - io::{ - scheduler::Scheduler, - source_client::{HttpClient, HttpSourceClient}, - tile_repository::TileRepository, - }, - render::{ - create_default_render_graph, register_default_render_stages, - settings::{RendererSettings, WgpuSettings}, - Renderer, - }, - schedule::{Schedule, Stage}, - stages::register_stages, - style::Style, - window::{HeadedMapWindow, MapWindowConfig, WindowSize}, - world::{ViewState, World}, -}; - -/// Stores the state of the map, dispatches tile fetching and caching, tessellation and drawing. -pub struct InteractiveMapSchedule { - map_window_config: E::MapWindowConfig, - - // FIXME (wasm-executor): avoid RefCell, change ownership model - pub apc: Rc>, - - map_context: EventuallyMapContext, - - schedule: Schedule, - - suspended: bool, -} - -impl InteractiveMapSchedule { - pub fn new(window_size: WindowSize, renderer: Option, style: Style) -> Self { - let center = style.center.unwrap_or_default(); - let world = World::new_at( - window_size, - LatLon::new(center[0], center[1]), - style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default(), - cgmath::Deg::(style.pitch.unwrap_or_default()), - ); - - let mut schedule = Schedule::default(); - - let apc = Rc::new(RefCell::new(apc)); - - let http_source_client: HttpSourceClient = - HttpSourceClient::new(http_client); - register_stages::(&mut schedule, http_source_client, apc.clone()); - - let graph = create_default_render_graph().unwrap(); // TODO: Remove unwrap - register_default_render_stages(graph, &mut schedule); - - Self { - apc, - map_window_config, - map_context: match renderer { - None => EventuallyMapContext::Premature(PrematureMapContext { - world, - style, - wgpu_settings, - renderer_settings, - }), - Some(renderer) => EventuallyMapContext::Full(MapContext { - world, - style, - renderer, - }), - }, - schedule, - suspended: false, +/* pub async fn late_init(&mut self) -> bool { + match &self.map_context { + EventuallyMapContext::Full(_) => false, + EventuallyMapContext::Uninizalized(PrematureMapContext { + wgpu_settings, + renderer_settings, + .. + }) => { + let window = self.map_window_config.create(); + let renderer = + Renderer::initialize(&window, wgpu_settings.clone(), renderer_settings.clone()) + .await + .unwrap(); // TODO: Remove unwrap + self.map_context.make_full(renderer); + true } + EventuallyMapContext::_Uninitialized => false, } - - #[tracing::instrument(name = "update_and_redraw", skip_all)] - pub fn update_and_redraw(&mut self) -> Result<(), Error> { - if self.suspended { - return Ok(()); - } - - if let EventuallyMapContext::Full(map_context) = &mut self.map_context { - self.schedule.run(map_context) - } - - Ok(()) - } - - pub fn resize(&mut self, width: u32, height: u32) { - if let EventuallyMapContext::Full(map_context) = &mut self.map_context { - let view_state = &mut map_context.view_state; - view_state.perspective.resize(width, height); - view_state.camera.resize(width, height); - - map_context.renderer.resize(width, height) - } - } - - pub fn is_initialized(&self) -> bool { - match &self.map_context { - EventuallyMapContext::Full(_) => true, - _ => false, - } - } - - pub fn view_state_mut(&mut self) -> &mut ViewState { - match &mut self.map_context { - EventuallyMapContext::Full(MapContext { view_state, .. }) => view_state, - EventuallyMapContext::Premature(PrematureMapContext { view_state, .. }) => view_state, - _ => panic!("should not happen"), - } - } - - pub fn apc(&self) -> &Rc> { - &self.apc - } -} - -impl InteractiveMapSchedule -where - ::MapWindow: HeadedMapWindow, -{ - pub fn suspend(&mut self) { - self.suspended = true; - } - - pub fn resume(&mut self, window: &::MapWindow) { - if let EventuallyMapContext::Full(map_context) = &mut self.map_context { - let renderer = &mut map_context.renderer; - renderer.state.recreate_surface(window, &renderer.instance); - self.suspended = false; - } - } - - pub async fn late_init(&mut self) -> bool { - match &self.map_context { - EventuallyMapContext::Full(_) => false, - EventuallyMapContext::Premature(PrematureMapContext { - wgpu_settings, - renderer_settings, - .. - }) => { - let window = self.map_window_config.create(); - let renderer = - Renderer::initialize(&window, wgpu_settings.clone(), renderer_settings.clone()) - .await - .unwrap(); // TODO: Remove unwrap - self.map_context.make_full(renderer); - true - } - EventuallyMapContext::_Uninitialized => false, - } - } -} - -pub struct PrematureMapContext { - world: World, - - style: Style, - - wgpu_settings: WgpuSettings, - renderer_settings: RendererSettings, -} - -pub enum EventuallyMapContext { - Full(MapContext), - Premature(PrematureMapContext), - _Uninitialized, -} - -impl EventuallyMapContext { - pub fn make_full(&mut self, renderer: Renderer) { - let context = mem::replace(self, EventuallyMapContext::_Uninitialized); - - match context { - EventuallyMapContext::Full(_) => {} - EventuallyMapContext::Premature(PrematureMapContext { - view_state, - style, - tile_repository, - .. - }) => { - *self = EventuallyMapContext::Full(MapContext { - view_state, - style, - tile_repository, - renderer, - }); - } - EventuallyMapContext::_Uninitialized => {} - } - } -} +}*/ diff --git a/maplibre/src/render/builder.rs b/maplibre/src/render/builder.rs index c4153b7e..355d9c99 100644 --- a/maplibre/src/render/builder.rs +++ b/maplibre/src/render/builder.rs @@ -1,3 +1,5 @@ +use crate::environment::Kernel; +use crate::error::Error; use crate::{ environment::Environment, render::{ @@ -14,6 +16,13 @@ pub struct RenderBuilder { } impl RenderBuilder { + pub fn new() -> Self { + Self { + wgpu_settings: None, + renderer_settings: None, + } + } + pub fn with_renderer_settings(mut self, renderer_settings: RendererSettings) -> Self { self.renderer_settings = Some(renderer_settings); self @@ -32,6 +41,20 @@ impl RenderBuilder { } } +pub enum InitializationResult { + Initialized(Renderer), + Uninizalized(UninitializedRenderer), +} + +impl InitializationResult { + pub fn unwarp(self) -> Renderer { + match self { + InitializationResult::Initialized(renderer) => renderer, + InitializationResult::Uninizalized(_) => panic!("Renderer is not initialized"), + } + } +} + pub struct UninitializedRenderer { wgpu_settings: WgpuSettings, renderer_settings: RendererSettings, @@ -40,41 +63,64 @@ pub struct UninitializedRenderer { impl UninitializedRenderer { /// Initializes the whole rendering pipeline for the given configuration. /// Returns the initialized map, ready to be run. - pub async fn initialize(self, map_window_config: MWC) -> Option + async fn initialize( + self, + map_window_config: &MWC, + ) -> Result where MWC::MapWindow: MapWindow + HeadedMapWindow, { let window = map_window_config.create(); #[cfg(target_os = "android")] - let renderer = None; + let renderer = Ok(InitializationResult::Uninizalized(self)); #[cfg(not(target_os = "android"))] - let renderer = Renderer::initialize( - &window, - self.wgpu_settings.clone(), - self.renderer_settings.clone(), - ) - .await - .ok(); + let renderer = Ok(InitializationResult::Initialized( + Renderer::initialize( + &window, + self.wgpu_settings.clone(), + self.renderer_settings.clone(), + ) + .await?, + )); renderer } + + pub async fn initialize_with( + self, + kernel: &Kernel, + ) -> Result + where + ::MapWindow: MapWindow + HeadedMapWindow, + { + self.initialize(&kernel.map_window_config).await + } } #[cfg(feature = "headless")] impl UninitializedRenderer { - pub async fn initialize_headless( + async fn initialize_headless( self, map_window_config: MWC, - ) -> Option { + ) -> Result { let window = map_window_config.create(); - Renderer::initialize_headless( + Ok(Renderer::initialize_headless( &window, self.wgpu_settings.clone(), self.renderer_settings.clone(), ) - .await - .ok() + .await?) + } + + pub async fn initialize_headless_with( + self, + kernel: &Kernel, + ) -> Result + where + ::MapWindow: MapWindow + HeadedMapWindow, + { + self.initialize(&kernel.map_window_config).await } } diff --git a/maplibre/src/render/error.rs b/maplibre/src/render/error.rs index 548c07f3..3bd2c81c 100644 --- a/maplibre/src/render/error.rs +++ b/maplibre/src/render/error.rs @@ -6,13 +6,15 @@ use crate::{error::Error, render::graph::RenderGraphError}; pub enum RenderError { Surface(wgpu::SurfaceError), Graph(RenderGraphError), + Device(wgpu::RequestDeviceError), } impl fmt::Display for RenderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { RenderError::Surface(e) => write!(f, "{}", e), - RenderError::Graph(e) => write!(f, "{}", e), + RenderError::Graph(e) => write!(f, "{:?}", e), + RenderError::Device(e) => write!(f, "{}", e), } } } @@ -29,8 +31,20 @@ impl RenderError { } } +impl From for RenderError { + fn from(e: RenderGraphError) -> Self { + RenderError::Graph(e) + } +} + impl From for Error { fn from(e: wgpu::SurfaceError) -> Self { Error::Render(RenderError::Surface(e)) } } + +impl From for Error { + fn from(e: wgpu::RequestDeviceError) -> Self { + Error::Render(RenderError::Device(e)) + } +} diff --git a/maplibre/src/render/resource/surface.rs b/maplibre/src/render/resource/surface.rs index c28ae3a9..4a5ad66d 100644 --- a/maplibre/src/render/resource/surface.rs +++ b/maplibre/src/render/resource/surface.rs @@ -50,7 +50,7 @@ impl WindowHead { where MW: MapWindow + HeadedMapWindow, { - self.surface = unsafe { instance.create_surface(window.inner()) }; + self.surface = unsafe { instance.create_surface(window.raw()) }; } pub fn surface(&self) -> &wgpu::Surface { &self.surface @@ -140,7 +140,7 @@ impl Surface { present_mode: wgpu::PresentMode::Fifo, // VSync }; - let surface = unsafe { instance.create_surface(window.inner()) }; + let surface = unsafe { instance.create_surface(window.raw()) }; Self { size, diff --git a/maplibre/src/window.rs b/maplibre/src/window.rs index 91c0d994..79eb5bf9 100644 --- a/maplibre/src/window.rs +++ b/maplibre/src/window.rs @@ -4,7 +4,7 @@ use std::{cell::RefCell, rc::Rc}; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; -use crate::{environment::Environment, map_schedule::InteractiveMapSchedule}; +use crate::environment::Environment; /// Window of a certain [`WindowSize`]. This can either be a proper window or a headless one. pub trait MapWindow { @@ -16,7 +16,7 @@ pub trait MapWindow { pub trait HeadedMapWindow: MapWindow { type RawWindow: HasRawWindowHandle + HasRawDisplayHandle; - fn inner(&self) -> &Self::RawWindow; + fn raw(&self) -> &Self::RawWindow; } /// A configuration for a window which determines the corresponding implementation of a @@ -27,13 +27,6 @@ pub trait MapWindowConfig: 'static { fn create(&self) -> Self::MapWindow; } -/// The event loop is responsible for processing events and propagating them to the map renderer. -/// Only non-headless windows use an [`EventLoop`]. -pub trait EventLoop { - // FIXME (wasm-executor): Avoid Rc, change ownership model - fn run(self, map_schedule: Rc>>, max_frames: Option); -} - /// Window size with a width and an height in pixels. #[derive(Clone, Copy, Eq, PartialEq)] pub struct WindowSize { diff --git a/maplibre/src/world.rs b/maplibre/src/world.rs index cd87979d..8f056de6 100644 --- a/maplibre/src/world.rs +++ b/maplibre/src/world.rs @@ -99,6 +99,11 @@ impl ViewState { } } + pub fn resize(&mut self, width: u32, height: u32) { + self.perspective.resize(width, height); + self.camera.resize(width, height); + } + pub fn create_view_region(&self) -> Option { self.camera .view_region_bounding_box(&self.view_projection().invert())