Add some comments and rename

This commit is contained in:
Maximilian Ammann 2022-06-01 17:15:24 +02:00
parent a150d8776c
commit 9c5dc1965b
14 changed files with 127 additions and 120 deletions

View File

@ -3,9 +3,9 @@ use maplibre::coords::{WorldTileCoords, ZoomLevel};
use maplibre::error::Error;
use maplibre::io::pipeline::Processable;
use maplibre::io::pipeline::{PipelineContext, PipelineProcessor};
use maplibre::io::pipeline_steps::build_vector_tile_pipeline;
use maplibre::io::scheduler::ScheduleMethod;
use maplibre::io::source_client::{HttpClient, HttpSourceClient};
use maplibre::io::tile_pipelines::build_vector_tile_pipeline;
use maplibre::io::tile_repository::StoredLayer;
use maplibre::io::{RawLayer, TileRequest, TileRequestID};
use maplibre::map_schedule::{EventuallyMapContext, InteractiveMapSchedule};
@ -70,7 +70,7 @@ struct HeadlessPipelineProcessor {
}
impl PipelineProcessor for HeadlessPipelineProcessor {
fn finished_layer_tesselation(
fn layer_tesselation_finished(
&mut self,
coords: &WorldTileCoords,
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,

View File

@ -136,9 +136,7 @@ where
let dt = now - last_render_time;
last_render_time = now;
{
input_controller.update_state(map_schedule.view_state_mut(), dt);
}
input_controller.update_state(map_schedule.view_state_mut(), dt);
match map_schedule.update_and_redraw() {
Ok(_) => {}

View File

@ -11,7 +11,7 @@ pub mod static_tile_fetcher;
pub mod geometry_index;
pub mod pipeline;
pub mod pipeline_steps;
pub mod tile_pipelines;
pub mod tile_repository;
pub mod tile_request_state;

View File

@ -10,19 +10,19 @@ use std::marker::PhantomData;
use std::process::Output;
use std::sync::mpsc;
/// Processes events which happen during the pipeline execution
pub trait PipelineProcessor: Downcast {
fn finished_tile_tesselation(&mut self, request_id: TileRequestID, coords: &WorldTileCoords) {}
fn unavailable_layer(&mut self, coords: &WorldTileCoords, layer_name: &str) {}
fn finished_layer_tesselation(
fn tile_finished(&mut self, request_id: TileRequestID, coords: &WorldTileCoords) {}
fn layer_unavailable(&mut self, coords: &WorldTileCoords, layer_name: &str) {}
fn layer_tesselation_finished(
&mut self,
coords: &WorldTileCoords,
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
// Holds for each feature the count of indices.
feature_indices: Vec<u32>,
layer_data: tile::Layer,
) {
}
fn finished_layer_indexing(
fn layer_indexing_finished(
&mut self,
coords: &WorldTileCoords,
geometries: Vec<IndexedGeometry<f64>>,
@ -32,6 +32,7 @@ pub trait PipelineProcessor: Downcast {
impl_downcast!(PipelineProcessor);
/// Context which is available to each step within a [`DataPipeline`]
pub struct PipelineContext {
processor: Box<dyn PipelineProcessor>,
}
@ -52,6 +53,7 @@ impl PipelineContext {
{
self.processor.into_any().downcast::<P>().ok()
}
pub fn processor_mut(&mut self) -> &mut dyn PipelineProcessor {
self.processor.as_mut()
}
@ -64,26 +66,28 @@ pub trait Processable {
fn process(&self, input: Self::Input, context: &mut PipelineContext) -> Self::Output;
}
pub struct PipelineStep<P, N>
/// A pipeline which consists of multiple steps. Steps are [`Processable`] workloads. Later steps
/// depend on previous ones.
pub struct DataPipeline<P, N>
where
P: Processable,
N: Processable<Input = P::Output>,
{
process: P,
next: N,
step: P,
next_step: N,
}
impl<P, N> PipelineStep<P, N>
impl<P, N> DataPipeline<P, N>
where
P: Processable,
N: Processable<Input = P::Output>,
{
pub fn new(process: P, next: N) -> Self {
Self { process, next }
pub fn new(step: P, next_step: N) -> Self {
Self { step, next_step }
}
}
impl<P, N> Processable for PipelineStep<P, N>
impl<P, N> Processable for DataPipeline<P, N>
where
P: Processable,
N: Processable<Input = P::Output>,
@ -92,16 +96,17 @@ where
type Output = N::Output;
fn process(&self, input: Self::Input, context: &mut PipelineContext) -> Self::Output {
let output = self.process.process(input, context);
self.next.process(output, context)
let output = self.step.process(input, context);
self.next_step.process(output, context)
}
}
pub struct EndStep<I> {
/// Marks the end of a [`DataPipeline`]
pub struct PipelineEnd<I> {
phantom: PhantomData<I>,
}
impl<I> Default for EndStep<I> {
impl<I> Default for PipelineEnd<I> {
fn default() -> Self {
Self {
phantom: PhantomData::default(),
@ -109,7 +114,7 @@ impl<I> Default for EndStep<I> {
}
}
impl<I> Processable for EndStep<I> {
impl<I> Processable for PipelineEnd<I> {
type Input = I;
type Output = I;
@ -173,7 +178,8 @@ where
#[cfg(test)]
mod tests {
use crate::io::pipeline::{
ClosureProcessable, EndStep, PipelineContext, PipelineProcessor, PipelineStep, Processable,
ClosureProcessable, DataPipeline, PipelineContext, PipelineEnd, PipelineProcessor,
Processable,
};
use std::sync::mpsc;
@ -190,65 +196,48 @@ mod tests {
}
#[test]
fn test() {
let mut context = PipelineContext {
processor: Box::new(DummyPipelineProcessor),
};
let output: u32 = PipelineStep {
process: add_two as fn(u8, &mut PipelineContext) -> u32,
next: EndStep::default(),
}
.process(5u8, &mut context);
assert_eq!(output, 7);
let output = PipelineStep {
process: add_one as fn(u32, &mut PipelineContext) -> u8,
next: PipelineStep {
process: add_two as fn(u8, &mut PipelineContext) -> u32,
next: EndStep::default(),
},
}
.process(5u32, &mut context);
assert_eq!(output, 8);
let mut a = 3;
let closure = |input: u8, context: &mut PipelineContext| -> u32 {
return input as u32 + 2 + a;
};
let output: u32 = PipelineStep {
process: ClosureProcessable {
func: closure,
phantom_i: Default::default(),
},
next: EndStep::default(),
}
.process(5u8, &mut context);
assert_eq!(output, 10);
let processable =
ClosureProcessable::from(|input: u8, context: &mut PipelineContext| -> u32 {
return input as u32 + 2 + a;
});
let output: u32 = PipelineStep {
process: processable,
next: EndStep::default(),
}
.process(5u8, &mut context);
assert_eq!(output, 10);
let output: u32 = PipelineStep::<ClosureProcessable<_, u8, u32>, _>::new(
(|input: u8, context: &mut PipelineContext| -> u32 {
return input as u32 + 2 + a;
})
.into(),
EndStep::<u32>::default(),
fn test_fn_pointer() {
let mut context = PipelineContext::new(DummyPipelineProcessor);
let output: u32 = DataPipeline::new(
add_two as fn(u8, &mut PipelineContext) -> u32,
PipelineEnd::default(),
)
.process(5u8, &mut context);
assert_eq!(output, 7);
let output: u32 = DataPipeline::new(
add_one as fn(u32, &mut PipelineContext) -> u8,
DataPipeline::new(
add_two as fn(u8, &mut PipelineContext) -> u32,
PipelineEnd::default(),
),
)
.process(5u32, &mut context);
assert_eq!(output, 8);
}
#[test]
fn test_closure() {
let mut context = PipelineContext::new(DummyPipelineProcessor);
let mut outer_value = 3;
// using from()
let closure = ClosureProcessable::from(|input: u8, context: &mut PipelineContext| -> u32 {
return input as u32 + 2 + outer_value;
});
let output: u32 =
DataPipeline::new(closure, PipelineEnd::default()).process(5u8, &mut context);
assert_eq!(output, 10);
// with into()
let output: u32 = DataPipeline::<ClosureProcessable<_, u8, u32>, _>::new(
(|input: u8, context: &mut PipelineContext| -> u32 {
return input as u32 + 2 + outer_value;
})
.into(),
PipelineEnd::<u32>::default(),
)
.process(5u8, &mut context);
assert_eq!(output, 10);
}
}

View File

@ -1,5 +1,5 @@
use crate::io::geometry_index::IndexProcessor;
use crate::io::pipeline::{EndStep, PipelineContext, PipelineStep, Processable};
use crate::io::pipeline::{DataPipeline, PipelineContext, PipelineEnd, Processable};
use crate::io::{TileRequest, TileRequestID};
use crate::tessellation::zero_tessellator::ZeroTessellator;
use crate::tessellation::IndexDataType;
@ -7,9 +7,9 @@ use geozero::GeozeroDatasource;
use prost::Message;
use std::collections::HashSet;
pub struct ParseTileStep;
pub struct ParseTile;
impl Processable for ParseTileStep {
impl Processable for ParseTile {
type Input = (TileRequest, TileRequestID, Box<[u8]>);
type Output = (TileRequest, TileRequestID, geozero::mvt::Tile);
@ -24,9 +24,9 @@ impl Processable for ParseTileStep {
}
}
pub struct IndexLayerStep;
pub struct IndexLayer;
impl Processable for IndexLayerStep {
impl Processable for IndexLayer {
type Input = (TileRequest, TileRequestID, geozero::mvt::Tile);
type Output = (TileRequest, TileRequestID, geozero::mvt::Tile);
@ -40,14 +40,14 @@ impl Processable for IndexLayerStep {
context
.processor_mut()
.finished_layer_indexing(&tile_request.coords, index.get_geometries());
.layer_indexing_finished(&tile_request.coords, index.get_geometries());
(tile_request, request_id, tile)
}
}
pub struct TessellateLayerStep;
pub struct TessellateLayer;
impl Processable for TessellateLayerStep {
impl Processable for TessellateLayer {
type Input = (TileRequest, TileRequestID, geozero::mvt::Tile);
type Output = (TileRequest, TileRequestID, geozero::mvt::Tile);
@ -72,7 +72,7 @@ impl Processable for TessellateLayerStep {
if let Err(e) = layer.process(&mut tessellator) {
context
.processor_mut()
.unavailable_layer(coords, layer_name);
.layer_unavailable(coords, layer_name);
tracing::error!(
"layer {} at {} tesselation failed {:?}",
@ -81,7 +81,7 @@ impl Processable for TessellateLayerStep {
e
);
} else {
context.processor_mut().finished_layer_tesselation(
context.processor_mut().layer_tesselation_finished(
coords,
tessellator.buffer.into(),
tessellator.feature_indices,
@ -99,7 +99,7 @@ impl Processable for TessellateLayerStep {
for missing_layer in tile_request.layers.difference(&available_layers) {
context
.processor_mut()
.unavailable_layer(coords, missing_layer);
.layer_unavailable(coords, missing_layer);
tracing::info!(
"requested layer {} at {} not found in tile",
@ -112,23 +112,23 @@ impl Processable for TessellateLayerStep {
context
.processor_mut()
.finished_tile_tesselation(request_id, &tile_request.coords);
.tile_finished(request_id, &tile_request.coords);
(tile_request, request_id, tile)
}
}
pub fn build_vector_tile_pipeline(
) -> impl Processable<Input = <ParseTileStep as Processable>::Input> {
PipelineStep::new(
ParseTileStep,
PipelineStep::new(TessellateLayerStep, EndStep::default()),
pub fn build_vector_tile_pipeline() -> impl Processable<Input = <ParseTile as Processable>::Input> {
DataPipeline::new(
ParseTile,
DataPipeline::new(TessellateLayer, PipelineEnd::default()),
)
}
#[cfg(test)]
mod tests {
use super::build_vector_tile_pipeline;
use crate::coords::ZoomLevel;
use crate::io::pipeline::{PipelineContext, PipelineProcessor, Processable};
use crate::io::TileRequest;
pub struct DummyPipelineProcessor;
@ -144,7 +144,7 @@ mod tests {
let output = pipeline.process(
(
TileRequest {
coords: (0, 0, 0).into(),
coords: (0, 0, ZoomLevel::default()).into(),
layers: Default::default(),
},
0,

View File

@ -47,7 +47,8 @@ pub mod benchmarking;
pub(crate) mod tessellation;
pub mod util;
/// Map's configuration and execution.
/// The [`Map`] defines the public interface of the map renderer.
// DO NOT IMPLEMENT INTERNALS ON THIS STRUCT.
pub struct Map<MWC, SM, HC>
where
MWC: MapWindowConfig,
@ -114,6 +115,7 @@ where
map_schedule: SimpleMapSchedule<MWC, SM, HC>,
window: MWC::MapWindow,
}
impl<MWC, SM, HC> HeadlessMap<MWC, SM, HC>
where
MWC: MapWindowConfig,

View File

@ -1,3 +1,7 @@
//! Node which copies the contents of the GPU-side texture in [`BufferedTextureHead`] to an
//! unmapped GPU-side buffer. This buffer will be mapped in
//! [`crate::render::stages::write_surface_buffer_stage::WriteSurfaceBufferStage`].
use crate::render::graph::{Node, NodeRunError, RenderContext, RenderGraphContext, SlotInfo};
use crate::render::render_commands::{DrawMasks, DrawTiles};
use crate::render::render_phase::{PhaseItem, RenderCommand};

View File

@ -31,17 +31,19 @@ use crate::{HeadedMapWindow, MapWindow, MapWindowConfig};
use log::info;
use std::sync::Arc;
// Rendering internals
#[cfg(feature = "headless")]
mod copy_surface_to_buffer_node;
// Exposed because it should be addable conditionally
pub mod copy_surface_to_buffer_node;
pub mod graph;
pub mod resource;
pub mod stages;
// Rendering internals
mod graph_runner;
mod main_pass;
mod render_commands;
mod render_phase;
pub mod resource;
mod shaders;
mod stages;
mod tile_pipeline;
mod tile_view_pattern;
mod util;
@ -434,7 +436,7 @@ mod tests {
.ok()
.unwrap();
let render_state = RenderState::new(Surface::from_image::<HeadlessMapWindowConfig>(
let render_state = RenderState::new(Surface::from_image(
&device,
&HeadlessMapWindow {
size: WindowSize::new(100, 100).unwrap(),

View File

@ -578,6 +578,7 @@ impl RingIndex {
#[cfg(test)]
mod tests {
use crate::coords::ZoomLevel;
use crate::style::layer::StyleLayer;
use lyon::tessellation::VertexBuffers;
@ -638,7 +639,7 @@ mod tests {
for _ in 0..2 {
pool.allocate_layer_geometry(
&queue,
(0, 0, 0).into(),
(0, 0, ZoomLevel::default()).into(),
style_layer.clone(),
&data48bytes_aligned,
2,
@ -652,7 +653,7 @@ mod tests {
pool.allocate_layer_geometry(
&queue,
(0, 0, 0).into(),
(0, 0, ZoomLevel::default()).into(),
style_layer.clone(),
&data24bytes_aligned,
2,
@ -666,7 +667,7 @@ mod tests {
pool.allocate_layer_geometry(
&queue,
(0, 0, 0).into(),
(0, 0, ZoomLevel::default()).into(),
style_layer.clone(),
&data24bytes_aligned,
2,
@ -678,7 +679,7 @@ mod tests {
pool.allocate_layer_geometry(
&queue,
(0, 0, 0).into(),
(0, 0, ZoomLevel::default()).into(),
style_layer.clone(),
&data24bytes_aligned,
2,
@ -689,7 +690,7 @@ mod tests {
pool.allocate_layer_geometry(
&queue,
(0, 0, 0).into(),
(0, 0, ZoomLevel::default()).into(),
style_layer.clone(),
&data24bytes_aligned,
2,
@ -700,7 +701,7 @@ mod tests {
pool.allocate_layer_geometry(
&queue,
(0, 0, 0).into(),
(0, 0, ZoomLevel::default()).into(),
style_layer,
&data24bytes_aligned,
2,

View File

@ -19,8 +19,10 @@ mod phase_sort_stage;
mod queue_stage;
mod resource_stage;
mod upload_stage;
#[cfg(feature = "headless")]
mod write_surface_buffer_stage;
// Exposed because it should be addable conditionally
pub mod write_surface_buffer_stage;
/// The labels of the default App rendering stages.
#[derive(Debug, Hash, PartialEq, Eq, Clone)]

View File

@ -1,4 +1,5 @@
//! Sorts items of the [RenderPhases](RenderPhase).
//! Stage which writes the current contents of the GPU/CPU buffer in [`BufferedTextureHead`]
//! to disk as PNG.
use crate::context::MapContext;
use crate::coords::{ViewRegion, Zoom};
@ -18,6 +19,7 @@ use std::future::Future;
use std::io::Write;
use std::iter;
use std::ops::Deref;
use std::sync::Arc;
use tokio::runtime::Handle;
use tokio::task;
use wgpu::{BufferAsyncError, BufferSlice};
@ -38,7 +40,7 @@ impl Stage for WriteSurfaceBufferStage {
match state.surface.head() {
Head::Headed(_) => {}
Head::Headless(buffered_texture) => {
let buffered_texture = buffered_texture.clone();
let buffered_texture: Arc<BufferedTextureHead> = buffered_texture.clone();
let device = device.clone();
let current_frame = self.frame;

View File

@ -3,7 +3,7 @@ use crate::error::Error;
use crate::io::geometry_index::{GeometryIndex, IndexedGeometry};
use crate::io::pipeline::PipelineContext;
use crate::io::pipeline::Processable;
use crate::io::pipeline_steps::build_vector_tile_pipeline;
use crate::io::tile_pipelines::build_vector_tile_pipeline;
use crate::io::tile_repository::StoredLayer;
use crate::io::tile_request_state::TileRequestState;
use crate::io::{TileRequest, TileRequestID};

View File

@ -7,8 +7,8 @@ use crate::io::geometry_index::GeometryIndex;
use crate::io::geometry_index::{IndexProcessor, IndexedGeometry, TileIndex};
use crate::io::pipeline::Processable;
use crate::io::pipeline::{PipelineContext, PipelineProcessor};
use crate::io::pipeline_steps::build_vector_tile_pipeline;
use crate::io::source_client::{HttpSourceClient, SourceClient};
use crate::io::tile_pipelines::build_vector_tile_pipeline;
use crate::io::tile_repository::StoredLayer;
use crate::io::tile_request_state::TileRequestState;
use crate::io::{TileRequest, TileRequestID};
@ -34,6 +34,7 @@ mod message;
mod populate_tile_store_stage;
mod request_stage;
/// Register stages required for requesting and preparing new tiles.
pub fn register_stages<HC: HttpClient, SM: ScheduleMethod>(
schedule: &mut Schedule,
http_source_client: HttpSourceClient<HC>,
@ -61,7 +62,7 @@ pub struct HeadedPipelineProcessor {
}
impl PipelineProcessor for HeadedPipelineProcessor {
fn finished_tile_tesselation(&mut self, request_id: TileRequestID, coords: &WorldTileCoords) {
fn tile_finished(&mut self, request_id: TileRequestID, coords: &WorldTileCoords) {
self.state
.message_sender
.send(TessellateMessage::Tile(TileTessellateMessage {
@ -71,7 +72,7 @@ impl PipelineProcessor for HeadedPipelineProcessor {
.unwrap();
}
fn unavailable_layer(&mut self, coords: &WorldTileCoords, layer_name: &str) {
fn layer_unavailable(&mut self, coords: &WorldTileCoords, layer_name: &str) {
self.state
.message_sender
.send(TessellateMessage::Layer(
@ -83,7 +84,7 @@ impl PipelineProcessor for HeadedPipelineProcessor {
.unwrap();
}
fn finished_layer_tesselation(
fn layer_tesselation_finished(
&mut self,
coords: &WorldTileCoords,
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
@ -103,7 +104,7 @@ impl PipelineProcessor for HeadedPipelineProcessor {
.unwrap();
}
fn finished_layer_indexing(
fn layer_indexing_finished(
&mut self,
coords: &WorldTileCoords,
geometries: Vec<IndexedGeometry<f64>>,

View File

@ -3,23 +3,29 @@
use crate::{HttpClient, InteractiveMapSchedule, ScheduleMethod};
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
/// Window with a [carte::window::WindowSize].
/// Window of a certain [`WindowSize`]. This can either be a proper window or a headless one.
pub trait MapWindow {
fn size(&self) -> WindowSize;
}
/// Window which references a physical `RawWindow`. This is only implemented by headed windows and
/// not by headless windows.
pub trait HeadedMapWindow: MapWindow {
type RawWindow: HasRawWindowHandle;
fn inner(&self) -> &Self::RawWindow;
}
/// A configuration for a window which determines the corresponding implementation of a
/// [`MapWindow`] and is able to create it.
pub trait MapWindowConfig: 'static {
type MapWindow: MapWindow;
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<MWC, SM, HC>
where
MWC: MapWindowConfig,