Fix regressions from structure refactoring (#203)

* Add geometry index

* Switch to info level for run config

* Add setting for present_mode

* Remove unused file

* Adjust web to new message

* Rename transferables

* Remove bytemuck and add unsafe code

* Add Result to return type of APCs

* Add Result to Processable

* Resolve unwraps

* Remove unwraps and remove unused code
This commit is contained in:
Max Ammann 2022-11-13 11:24:17 +01:00 committed by GitHub
parent 193b06a49d
commit 6367d3641f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 483 additions and 349 deletions

View File

@ -10,7 +10,7 @@
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<envs>
<env name="RUST_LOG" value="debug" />
<env name="RUST_LOG" value="info" />
</envs>
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />

View File

@ -4,6 +4,7 @@ use criterion::{criterion_group, criterion_main, Criterion};
use maplibre::{
benchmarking::io::static_tile_fetcher::StaticTileFetcher,
coords::{TileCoords, ZoomLevel},
error::Error,
io::{
pipeline::{PipelineContext, PipelineProcessor, Processable},
tile_pipelines::{ParseTile, TessellateLayer},
@ -37,10 +38,12 @@ fn parse_tile(c: &mut Criterion) {
.sync_fetch_tile(&MUNICH_COORDS)
.unwrap()
.into_boxed_slice();
ParseTile::default().process(
(request, data),
&mut PipelineContext::new(DummyPipelineProcessor),
);
ParseTile::default()
.process(
(request, data),
&mut PipelineContext::new(DummyPipelineProcessor),
)
.unwrap();
})
});
}
@ -57,17 +60,21 @@ fn tessellate_tile(c: &mut Criterion) {
.sync_fetch_tile(&MUNICH_COORDS)
.unwrap()
.into_boxed_slice();
let parsed = ParseTile::default().process(
(request, data),
&mut PipelineContext::new(DummyPipelineProcessor),
);
let parsed = ParseTile::default()
.process(
(request, data),
&mut PipelineContext::new(DummyPipelineProcessor),
)
.unwrap();
c.bench_function("tessselate", |b| {
b.iter(|| {
TessellateLayer::default().process(
parsed.clone(),
&mut PipelineContext::new(DummyPipelineProcessor),
);
TessellateLayer::default()
.process(
parsed.clone(),
&mut PipelineContext::new(DummyPipelineProcessor),
)
.unwrap();
})
});
}

View File

@ -3,7 +3,7 @@
use std::time::Duration;
use cgmath::Vector2;
use maplibre::world::ViewState;
use maplibre::context::MapContext;
use winit::event::{DeviceEvent, KeyboardInput, TouchPhase, WindowEvent};
use crate::input::{
@ -126,16 +126,16 @@ impl InputController {
}
pub trait UpdateState {
fn update_state(&mut self, state: &mut ViewState, dt: Duration);
fn update_state(&mut self, state: &mut MapContext, dt: Duration);
}
impl UpdateState for InputController {
fn update_state(&mut self, state: &mut ViewState, dt: Duration) {
self.pan_handler.update_state(state, dt);
self.pinch_handler.update_state(state, dt);
self.zoom_handler.update_state(state, dt);
self.tilt_handler.update_state(state, dt);
self.shift_handler.update_state(state, dt);
self.query_handler.update_state(state, dt);
fn update_state(&mut self, map_context: &mut MapContext, dt: Duration) {
self.pan_handler.update_state(map_context, dt);
self.pinch_handler.update_state(map_context, dt);
self.zoom_handler.update_state(map_context, dt);
self.tilt_handler.update_state(map_context, dt);
self.shift_handler.update_state(map_context, dt);
self.query_handler.update_state(map_context, dt);
}
}

View File

@ -1,7 +1,7 @@
use std::time::Duration;
use cgmath::{EuclideanSpace, Point3, Vector2, Vector3, Zero};
use maplibre::{render::camera::Camera, world::ViewState};
use maplibre::{context::MapContext, render::camera::Camera, world::World};
use winit::event::{ElementState, MouseButton};
use super::UpdateState;
@ -15,7 +15,14 @@ pub struct PanHandler {
}
impl UpdateState for PanHandler {
fn update_state(&mut self, state: &mut ViewState, _dt: Duration) {
fn update_state(
&mut self,
MapContext {
world: World { view_state, .. },
..
}: &mut MapContext,
_dt: Duration,
) {
if !self.is_panning {
return;
}
@ -24,7 +31,7 @@ impl UpdateState for PanHandler {
if let (Some(window_position), Some(start_window_position)) =
(self.window_position, self.start_window_position)
{
let view_proj = state.view_projection();
let view_proj = view_state.view_projection();
let inverted_view_proj = view_proj.invert();
let delta = if let (Some(start), Some(current)) = (
@ -45,17 +52,17 @@ impl UpdateState for PanHandler {
};
if self.start_camera_position.is_none() {
self.start_camera_position = Some(state.camera().position().to_vec());
self.start_camera_position = Some(view_state.camera().position().to_vec());
}
if let Some(start_camera_position) = self.start_camera_position {
state.camera_mut().move_to(Point3::from_vec(
view_state.camera_mut().move_to(Point3::from_vec(
start_camera_position + Vector3::new(delta.x, delta.y, 0.0),
));
}
}
} else {
self.reference_camera = Some(state.camera().clone());
self.reference_camera = Some(view_state.camera().clone());
}
}
}

View File

@ -1,13 +1,13 @@
use std::time::Duration;
use maplibre::world::ViewState;
use maplibre::context::MapContext;
use super::UpdateState;
pub struct PinchHandler {}
impl UpdateState for PinchHandler {
fn update_state(&mut self, _state: &mut ViewState, _dt: Duration) {
fn update_state(&mut self, _map_context: &mut MapContext, _dt: Duration) {
// TODO
}
}

View File

@ -1,7 +1,9 @@
use std::time::Duration;
use cgmath::Vector2;
use maplibre::world::ViewState;
use maplibre::{
context::MapContext, coords::WorldCoords, io::geometry_index::IndexedGeometry, world::World,
};
use winit::event::{ElementState, MouseButton};
use crate::input::UpdateState;
@ -11,10 +13,6 @@ pub struct QueryHandler {
clicking: bool,
}
/*impl UpdateState for QueryHandler {
}*/
impl QueryHandler {
pub fn new() -> Self {
Self {
@ -57,42 +55,59 @@ impl QueryHandler {
}
impl UpdateState for QueryHandler {
fn update_state(&mut self, state: &mut ViewState, _dt: Duration) {
fn update_state(
&mut self,
MapContext {
world:
World {
view_state,
geometry_index,
..
},
..
}: &mut MapContext,
_dt: Duration,
) {
if self.clicking {
if let Some(window_position) = self.window_position {
let view_proj = state.view_projection();
let view_proj = view_state.view_projection();
let inverted_view_proj = view_proj.invert();
let _z = state.visible_level(); // FIXME: can be wrong, if tiles of different z are visible
let _zoom = state.zoom();
let z = view_state.visible_level(); // FIXME: can be wrong, if tiles of different z are visible
let zoom = view_state.zoom();
if let Some(_coordinates) = state.camera().window_to_world_at_ground(
if let Some(coordinates) = view_state.camera().window_to_world_at_ground(
&window_position,
&inverted_view_proj,
false,
) {
// TODO reenable
/*state
.scheduler()
.schedule(state.scheduler(), move |thread_local| async move {
if let Some(geometries) = thread_local.query_point(
if let Some(geometries) = geometry_index
.query_point(
&WorldCoords {
x: coordinates.x,
y: coordinates.y,
},
z,
zoom,
) {
log::info!(
"{:?}",
geometries
.iter()
.map(|geometry| &geometry.properties)
.collect::<Vec<_>>()
);
}
})
.unwrap();*/
)
.map(|geometries| {
geometries
.iter()
.cloned()
.cloned()
.collect::<Vec<IndexedGeometry<f64>>>()
})
{
log::info!(
"Clicked on geometry: {:?}",
geometries
.iter()
.map(|geometry| &geometry.properties)
.collect::<Vec<_>>()
);
} else {
log::info!("No geometry found.",);
}
}
}
self.clicking = false;

View File

@ -1,7 +1,7 @@
use std::time::Duration;
use cgmath::{Vector3, Zero};
use maplibre::world::ViewState;
use maplibre::{context::MapContext, world::World};
use super::UpdateState;
@ -13,11 +13,18 @@ pub struct ShiftHandler {
}
impl UpdateState for ShiftHandler {
fn update_state(&mut self, state: &mut ViewState, dt: Duration) {
fn update_state(
&mut self,
MapContext {
world: World { view_state, .. },
..
}: &mut MapContext,
dt: Duration,
) {
let dt = dt.as_secs_f64() * (1.0 / self.speed);
let delta = self.camera_translate * dt;
state.camera_mut().move_relative(delta);
view_state.camera_mut().move_relative(delta);
self.camera_translate -= delta;
}
}

View File

@ -1,7 +1,7 @@
use std::time::Duration;
use cgmath::{Deg, Zero};
use maplibre::world::ViewState;
use maplibre::{context::MapContext, world::World};
use super::UpdateState;
@ -13,11 +13,21 @@ pub struct TiltHandler {
}
impl UpdateState for TiltHandler {
fn update_state(&mut self, state: &mut ViewState, dt: Duration) {
fn update_state(
&mut self,
MapContext {
world: World {
view_state: _view_state,
..
},
..
}: &mut MapContext,
dt: Duration,
) {
let dt = dt.as_secs_f64() * (1.0 / self.speed);
let delta = self.delta_pitch * dt;
state.camera_mut().pitch_self(delta);
_view_state.camera_mut().pitch_self(delta);
self.delta_pitch -= delta;
}
}

View File

@ -1,7 +1,7 @@
use std::time::Duration;
use cgmath::{Vector2, Vector3};
use maplibre::{coords::Zoom, world::ViewState};
use maplibre::{context::MapContext, coords::Zoom, world::World};
use super::UpdateState;
@ -12,19 +12,26 @@ pub struct ZoomHandler {
}
impl UpdateState for ZoomHandler {
fn update_state(&mut self, state: &mut ViewState, _dt: Duration) {
fn update_state(
&mut self,
MapContext {
world: World { view_state, .. },
..
}: &mut MapContext,
_dt: Duration,
) {
if let Some(zoom_delta) = self.zoom_delta {
if let Some(window_position) = self.window_position {
let current_zoom = state.zoom();
let current_zoom = view_state.zoom();
let next_zoom = current_zoom + zoom_delta;
state.update_zoom(next_zoom);
view_state.update_zoom(next_zoom);
self.zoom_delta = None;
let view_proj = state.view_projection();
let view_proj = view_state.view_projection();
let inverted_view_proj = view_proj.invert();
if let Some(cursor_position) = state.camera().window_to_world_at_ground(
if let Some(cursor_position) = view_state.camera().window_to_world_at_ground(
&window_position,
&inverted_view_proj,
false,
@ -37,7 +44,7 @@ impl UpdateState for ZoomHandler {
cursor_position.z,
) - cursor_position;
state.camera_mut().move_relative(delta);
view_state.camera_mut().move_relative(delta);
}
}
}

View File

@ -143,7 +143,7 @@ impl<ET: 'static + PartialEq + Debug> EventLoop<ET> for WinitEventLoop<ET> {
last_render_time = now;
if let Ok(map_context) = map.context_mut() {
input_controller.update_state(map_context.world.view_state_mut(), dt);
input_controller.update_state(map_context, dt);
}
match map.run_schedule() {
@ -193,8 +193,8 @@ pub struct WinitEventLoopProxy<ET: 'static> {
}
impl<ET: 'static> EventLoopProxy<ET> for WinitEventLoopProxy<ET> {
fn send_event(&self, event: ET) {
self.proxy.send_event(event); // FIXME: Handle unwrap
fn send_event(&self, event: ET) -> Result<(), Error> {
self.proxy.send_event(event).map_err(|e| Error::EventLoop)
}
}

View File

@ -5,16 +5,12 @@
use maplibre_build_tools::wgsl::validate_project_wgsl;
const MUNICH_X: u32 = 17425;
const MUNICH_Y: u32 = 11365;
const MUNICH_Z: u8 = 15;
/*use std::fs::File;
use std::io::BufReader;
use serde_json::Value;*/
fn generate_type_def() -> Option<u32> {
/* let f = File::open("style-spec-v8.json").unwrap();
/*
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();
@ -26,10 +22,9 @@ fn generate_type_def() -> Option<u32> {
}
println!("cargo:warning={:?}", version);*/
Some(5)
println!("cargo:warning={:?}", version);
}
*/
#[cfg(feature = "embed-static-tiles")]
fn embed_tiles_statically() {
@ -37,6 +32,10 @@ fn embed_tiles_statically() {
use maplibre_build_tools::mbtiles::extract;
const MUNICH_X: u32 = 17425;
const MUNICH_Y: u32 = 11365;
const MUNICH_Z: u8 = 15;
/// Tiles which can be used by StaticTileFetcher.
fn clean_static_tiles() -> std::path::PathBuf {
let out_dir = std::env::var("OUT_DIR").unwrap();

View File

@ -7,7 +7,7 @@ use std::{
};
use bytemuck_derive::{Pod, Zeroable};
use cgmath::{num_traits::Pow, AbsDiffEq, Matrix4, Point3, Vector3};
use cgmath::{AbsDiffEq, Matrix4, Point3, Vector3};
use serde::{Deserialize, Serialize};
use crate::{
@ -521,10 +521,6 @@ pub struct WorldCoords {
pub y: f64,
}
fn tiles_with_z(z: u8) -> f64 {
2.0.pow(z)
}
impl WorldCoords {
pub fn from_lat_lon(lat_lon: LatLon, zoom: Zoom) -> WorldCoords {
let tile_size = TILE_SIZE * 2.0_f64.powf(zoom.0);

View File

@ -11,6 +11,7 @@ use crate::render::error::RenderError;
pub enum Error {
APC,
Scheduler,
EventLoop,
Network(String),
Tesselation(TessellationError),
Render(RenderError),

View File

@ -1,5 +1,6 @@
use crate::{
environment::Environment,
error::Error,
map::Map,
window::{HeadedMapWindow, MapWindowConfig},
};
@ -12,7 +13,7 @@ pub trait EventLoopConfig {
}
pub trait EventLoopProxy<T: 'static> {
fn send_event(&self, event: T);
fn send_event(&self, event: T) -> Result<(), Error>;
}
pub trait EventLoop<ET: 'static + PartialEq> {

View File

@ -115,7 +115,7 @@ impl HeadlessMap {
data,
),
&mut pipeline_context,
);
)?;
let processor = pipeline_context
.take_processor::<HeadlessPipelineProcessor>()

View File

@ -28,29 +28,31 @@ use crate::{
#[derive(Clone)]
pub enum Message<T: Transferables> {
TileTessellated(T::TileTessellated),
UnavailableLayer(T::UnavailableLayer),
TessellatedLayer(T::TessellatedLayer),
LayerUnavailable(T::LayerUnavailable),
LayerTessellated(T::LayerTessellated),
LayerIndexed(T::LayerIndexed),
}
/// Inputs for an [`AsyncProcedure`]
#[derive(Clone, Serialize, Deserialize)]
pub enum Input {
TileRequest(TileRequest),
NotYetImplemented, // TODO: Placeholder, should be removed when second input is added
}
/// Allows sending messages from workers to back to the caller.
pub trait Context<T: Transferables, HC: HttpClient>: Send + 'static {
/// Send a message back to the caller.
// FIXME (wasm-executor): handle results send() calls
fn send(&self, data: Message<T>) -> Result<(), Error>;
fn source_client(&self) -> &SourceClient<HC>;
}
#[cfg(feature = "thread-safe-futures")]
pub type AsyncProcedureFuture = Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>;
pub type AsyncProcedureFuture = Pin<Box<(dyn Future<Output = Result<(), Error>> + Send + 'static)>>;
#[cfg(not(feature = "thread-safe-futures"))]
pub type AsyncProcedureFuture = Pin<Box<(dyn Future<Output = ()> + 'static)>>;
pub type AsyncProcedureFuture = Pin<Box<(dyn Future<Output = Result<(), Error>> + 'static)>>;
/// Type definitions for asynchronous procedure calls. These functions can be called in an
/// [`AsyncProcedureCall`]. Functions of this type are required to be statically available at
@ -167,7 +169,8 @@ impl<HC: HttpClient, S: Scheduler> AsyncProcedureCall<HC> for SchedulerAsyncProc
source_client: SourceClient::new(HttpSourceClient::new(client)),
},
)
.await;
.await
.unwrap();
})
.unwrap();
}

View File

@ -9,6 +9,7 @@ use geozero::{
error::GeozeroError, geo_types::GeoWriter, ColumnValue, FeatureProcessor, GeomProcessor,
PropertyProcessor,
};
use log::warn;
use rstar::{Envelope, PointDistance, RTree, RTreeObject, AABB};
use crate::{
@ -217,6 +218,9 @@ impl GeomProcessor for IndexProcessor {
fn point_begin(&mut self, idx: usize) -> Result<(), GeozeroError> {
self.geo_writer.point_begin(idx)
}
fn point_end(&mut self, idx: usize) -> Result<(), GeozeroError> {
self.geo_writer.point_end(idx)
}
fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<(), GeozeroError> {
self.geo_writer.multipoint_begin(size, idx)
}
@ -246,6 +250,9 @@ impl GeomProcessor for IndexProcessor {
fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<(), GeozeroError> {
self.geo_writer.multipolygon_begin(size, idx)
}
fn multipolygon_end(&mut self, idx: usize) -> Result<(), GeozeroError> {
self.geo_writer.multipolygon_end(idx)
}
}
impl PropertyProcessor for IndexProcessor {
@ -295,17 +302,19 @@ impl FeatureProcessor for IndexProcessor {
}
/// End of feature geometry processing.
fn geometry_end(&mut self) -> Result<(), GeozeroError> {
let geometry = self.geo_writer.take_geometry().unwrap();
let geometry = self.geo_writer.take_geometry();
match geometry {
Geometry::Polygon(polygon) => self.geometries.push(
Some(Geometry::Polygon(polygon)) => self.geometries.push(
IndexedGeometry::from_polygon(polygon, self.properties.take().unwrap()).unwrap(),
),
Geometry::LineString(linestring) => self.geometries.push(
Some(Geometry::LineString(linestring)) => self.geometries.push(
IndexedGeometry::from_linestring(linestring, self.properties.take().unwrap())
.unwrap(),
),
_ => {}
_ => {
warn!("Unknown geometry in index")
}
};
Ok(())

View File

@ -12,7 +12,6 @@ use crate::{
};
/// Processes events which happen during the pipeline execution
// FIXME (wasm-executor): handle results for messages below
pub trait PipelineProcessor: Downcast {
fn tile_finished(&mut self, _coords: &WorldTileCoords) -> Result<(), Error> {
Ok(())
@ -73,7 +72,11 @@ pub trait Processable {
type Input;
type Output;
fn process(&self, input: Self::Input, context: &mut PipelineContext) -> Self::Output;
fn process(
&self,
input: Self::Input,
context: &mut PipelineContext,
) -> Result<Self::Output, Error>;
}
/// A pipeline which consists of multiple steps. Steps are [`Processable`] workloads. Later steps
@ -105,8 +108,12 @@ where
type Input = P::Input;
type Output = N::Output;
fn process(&self, input: Self::Input, context: &mut PipelineContext) -> Self::Output {
let output = self.step.process(input, context);
fn process(
&self,
input: Self::Input,
context: &mut PipelineContext,
) -> Result<Self::Output, Error> {
let output = self.step.process(input, context)?;
self.next_step.process(output, context)
}
}
@ -128,8 +135,12 @@ impl<I> Processable for PipelineEnd<I> {
type Input = I;
type Output = I;
fn process(&self, input: Self::Input, _context: &mut PipelineContext) -> Self::Output {
input
fn process(
&self,
input: Self::Input,
_context: &mut PipelineContext,
) -> Result<Self::Output, Error> {
Ok(input)
}
}
@ -137,8 +148,12 @@ impl<I, O> Processable for &fn(input: I, context: &mut PipelineContext) -> O {
type Input = I;
type Output = O;
fn process(&self, input: Self::Input, context: &mut PipelineContext) -> Self::Output {
(self)(input, context)
fn process(
&self,
input: Self::Input,
context: &mut PipelineContext,
) -> Result<Self::Output, Error> {
Ok((self)(input, context))
}
}
@ -146,8 +161,12 @@ impl<I, O> Processable for fn(input: I, context: &mut PipelineContext) -> O {
type Input = I;
type Output = O;
fn process(&self, input: Self::Input, context: &mut PipelineContext) -> Self::Output {
(self)(input, context)
fn process(
&self,
input: Self::Input,
context: &mut PipelineContext,
) -> Result<Self::Output, Error> {
Ok((self)(input, context))
}
}
@ -180,8 +199,12 @@ where
type Input = I;
type Output = O;
fn process(&self, input: Self::Input, context: &mut PipelineContext) -> Self::Output {
(self.func)(input, context)
fn process(
&self,
input: Self::Input,
context: &mut PipelineContext,
) -> Result<Self::Output, Error> {
Ok((self.func)(input, context))
}
}
@ -211,7 +234,8 @@ mod tests {
add_two as fn(u8, &mut PipelineContext) -> u32,
PipelineEnd::default(),
)
.process(5u8, &mut context);
.process(5u8, &mut context)
.unwrap();
assert_eq!(output, 7);
let output: u32 = DataPipeline::new(
@ -221,7 +245,8 @@ mod tests {
PipelineEnd::default(),
),
)
.process(5u32, &mut context);
.process(5u32, &mut context)
.unwrap();
assert_eq!(output, 8);
}
@ -235,8 +260,9 @@ mod tests {
ClosureProcessable::from(|input: u8, _context: &mut PipelineContext| -> u32 {
input as u32 + 2 + outer_value
});
let output: u32 =
DataPipeline::new(closure, PipelineEnd::default()).process(5u8, &mut context);
let output: u32 = DataPipeline::new(closure, PipelineEnd::default())
.process(5u8, &mut context)
.unwrap();
assert_eq!(output, 10);
// with into()
@ -245,7 +271,8 @@ mod tests {
.into(),
PipelineEnd::<u32>::default(),
)
.process(5u8, &mut context);
.process(5u8, &mut context)
.unwrap();
assert_eq!(output, 10);
}
}

View File

@ -4,6 +4,7 @@ use geozero::GeozeroDatasource;
use prost::Message;
use crate::{
error::Error,
io::{
geometry_index::IndexProcessor,
pipeline::{DataPipeline, PipelineContext, PipelineEnd, Processable},
@ -19,14 +20,13 @@ impl Processable for ParseTile {
type Input = (TileRequest, Box<[u8]>);
type Output = (TileRequest, geozero::mvt::Tile);
// TODO (perf): Maybe force inline
fn process(
&self,
(tile_request, data): Self::Input,
_context: &mut PipelineContext,
) -> Self::Output {
) -> Result<Self::Output, Error> {
let tile = geozero::mvt::Tile::decode(data.as_ref()).expect("failed to load tile");
(tile_request, tile)
Ok((tile_request, tile))
}
}
@ -37,19 +37,21 @@ impl Processable for IndexLayer {
type Input = (TileRequest, geozero::mvt::Tile);
type Output = (TileRequest, geozero::mvt::Tile);
// TODO (perf): Maybe force inline
fn process(
&self,
(tile_request, tile): Self::Input,
(tile_request, mut tile): Self::Input,
context: &mut PipelineContext,
) -> Self::Output {
let index = IndexProcessor::new();
) -> Result<Self::Output, Error> {
let mut index = IndexProcessor::new();
for layer in &mut tile.layers {
layer.process(&mut index).unwrap();
}
// FIXME: Handle result
context
.processor_mut()
.layer_indexing_finished(&tile_request.coords, index.get_geometries());
(tile_request, tile)
.layer_indexing_finished(&tile_request.coords, index.get_geometries())?;
Ok((tile_request, tile))
}
}
@ -60,12 +62,11 @@ impl Processable for TessellateLayer {
type Input = (TileRequest, geozero::mvt::Tile);
type Output = (TileRequest, geozero::mvt::Tile);
// TODO (perf): Maybe force inline
fn process(
&self,
(tile_request, mut tile): Self::Input,
context: &mut PipelineContext,
) -> Self::Output {
) -> Result<Self::Output, Error> {
let coords = &tile_request.coords;
for layer in &mut tile.layers {
@ -79,10 +80,9 @@ impl Processable for TessellateLayer {
let mut tessellator = ZeroTessellator::<IndexDataType>::default();
if let Err(e) = layer.process(&mut tessellator) {
// FIXME: Handle result
context
.processor_mut()
.layer_unavailable(coords, layer_name);
.layer_unavailable(coords, layer_name)?;
tracing::error!(
"layer {} at {} tesselation failed {:?}",
@ -91,13 +91,12 @@ impl Processable for TessellateLayer {
e
);
} else {
// FIXME: Handle result
context.processor_mut().layer_tesselation_finished(
coords,
tessellator.buffer.into(),
tessellator.feature_indices,
cloned_layer,
);
)?;
}
}
@ -108,10 +107,9 @@ impl Processable for TessellateLayer {
.collect::<HashSet<_>>();
for missing_layer in tile_request.layers.difference(&available_layers) {
// FIXME: Handle result
context
.processor_mut()
.layer_unavailable(coords, missing_layer);
.layer_unavailable(coords, missing_layer)?;
tracing::info!(
"requested layer {} at {} not found in tile",
@ -122,17 +120,21 @@ impl Processable for TessellateLayer {
tracing::info!("tile tessellated at {} finished", &tile_request.coords);
// FIXME: Handle result
context.processor_mut().tile_finished(&tile_request.coords);
context
.processor_mut()
.tile_finished(&tile_request.coords)?;
(tile_request, tile)
Ok((tile_request, tile))
}
}
pub fn build_vector_tile_pipeline() -> impl Processable<Input = <ParseTile as Processable>::Input> {
DataPipeline::new(
ParseTile,
DataPipeline::new(TessellateLayer, PipelineEnd::default()),
DataPipeline::new(
TessellateLayer,
DataPipeline::new(IndexLayer, PipelineEnd::default()),
),
)
}
@ -150,7 +152,7 @@ mod tests {
impl PipelineProcessor for DummyPipelineProcessor {}
#[test] // TODO: Add proper tile byte array
#[test]
#[ignore]
fn test() {
let mut context = PipelineContext::new(DummyPipelineProcessor);
@ -162,7 +164,7 @@ mod tests {
coords: (0, 0, ZoomLevel::default()).into(),
layers: Default::default(),
},
Box::new([0]),
Box::new([0]), // TODO: Add proper tile byte array
),
&mut context,
);

View File

@ -1,8 +1,8 @@
use geozero::mvt::{tile, tile::Layer};
use geozero::mvt::tile::Layer;
use crate::{
coords::WorldTileCoords,
io::tile_repository::StoredLayer,
io::{geometry_index::TileIndex, tile_repository::StoredLayer},
render::ShaderVertex,
tessellation::{IndexDataType, OverAlignedVertexBuffer},
};
@ -16,6 +16,8 @@ pub trait TileTessellated: Send {
pub trait UnavailableLayer: Send {
fn new(coords: WorldTileCoords, layer_name: String) -> Self;
fn coords(&self) -> &WorldTileCoords;
fn to_stored_layer(self) -> StoredLayer;
}
@ -24,11 +26,20 @@ pub trait TessellatedLayer: Send {
coords: WorldTileCoords,
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
feature_indices: Vec<u32>,
layer_data: tile::Layer,
layer_data: Layer,
) -> Self;
fn coords(&self) -> &WorldTileCoords;
fn to_stored_layer(self) -> StoredLayer;
}
pub trait IndexedLayer: Send + From<(WorldTileCoords, TileIndex)> {
fn coords(&self) -> &WorldTileCoords;
fn to_tile_index(self) -> TileIndex;
}
pub struct DefaultTileTessellated {
pub coords: WorldTileCoords,
}
@ -43,16 +54,20 @@ impl TileTessellated for DefaultTileTessellated {
}
}
pub struct DefaultUnavailableLayer {
pub struct DefaultLayerUnavailable {
pub coords: WorldTileCoords,
pub layer_name: String,
}
impl UnavailableLayer for DefaultUnavailableLayer {
impl UnavailableLayer for DefaultLayerUnavailable {
fn new(coords: WorldTileCoords, layer_name: String) -> Self {
Self { coords, layer_name }
}
fn coords(&self) -> &WorldTileCoords {
&self.coords
}
fn to_stored_layer(self) -> StoredLayer {
StoredLayer::UnavailableLayer {
coords: self.coords,
@ -61,7 +76,7 @@ impl UnavailableLayer for DefaultUnavailableLayer {
}
}
pub struct DefaultTessellatedLayer {
pub struct DefaultLayerTesselated {
pub coords: WorldTileCoords,
pub buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
/// Holds for each feature the count of indices.
@ -69,7 +84,7 @@ pub struct DefaultTessellatedLayer {
pub layer_data: Layer, // FIXME (perf): Introduce a better structure for this
}
impl TessellatedLayer for DefaultTessellatedLayer {
impl TessellatedLayer for DefaultLayerTesselated {
fn new(
coords: WorldTileCoords,
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
@ -84,6 +99,10 @@ impl TessellatedLayer for DefaultTessellatedLayer {
}
}
fn coords(&self) -> &WorldTileCoords {
&self.coords
}
fn to_stored_layer(self) -> StoredLayer {
StoredLayer::TessellatedLayer {
coords: self.coords,
@ -94,10 +113,32 @@ impl TessellatedLayer for DefaultTessellatedLayer {
}
}
pub struct DefaultLayerIndexed {
coords: WorldTileCoords,
index: TileIndex,
}
impl From<(WorldTileCoords, TileIndex)> for DefaultLayerIndexed {
fn from((coords, index): (WorldTileCoords, TileIndex)) -> Self {
Self { coords, index }
}
}
impl IndexedLayer for DefaultLayerIndexed {
fn coords(&self) -> &WorldTileCoords {
&self.coords
}
fn to_tile_index(self) -> TileIndex {
self.index
}
}
pub trait Transferables: 'static {
type TileTessellated: TileTessellated;
type UnavailableLayer: UnavailableLayer;
type TessellatedLayer: TessellatedLayer;
type LayerUnavailable: UnavailableLayer;
type LayerTessellated: TessellatedLayer;
type LayerIndexed: IndexedLayer;
}
#[derive(Copy, Clone)]
@ -105,6 +146,7 @@ pub struct DefaultTransferables;
impl Transferables for DefaultTransferables {
type TileTessellated = DefaultTileTessellated;
type UnavailableLayer = DefaultUnavailableLayer;
type TessellatedLayer = DefaultTessellatedLayer;
type LayerUnavailable = DefaultLayerUnavailable;
type LayerTessellated = DefaultLayerTesselated;
type LayerIndexed = DefaultLayerIndexed;
}

View File

@ -1,26 +0,0 @@
/* pub fn resume(&mut self, window: &<E::MapWindowConfig as MapWindowConfig>::MapWindow) {
if let EventuallyMapContext::Full(map_context) = &mut self.map_context {
let renderer = &mut map_context.renderer;
renderer.state.recreate_surface(window, &renderer.instance);
}
}*/
/* 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,
}
}*/

View File

@ -15,16 +15,6 @@ use crate::render::{
RenderState,
};
pub mod graph {
// Labels for input nodes
pub mod input {}
// Labels for non-input nodes
pub mod node {
pub const MAIN_PASS_DEPENDENCIES: &str = "main_pass_dependencies";
pub const MAIN_PASS_DRIVER: &str = "main_pass_driver";
}
}
pub struct MainPassNode {}
impl MainPassNode {

View File

@ -76,7 +76,7 @@ impl BufferedTextureHead {
use std::{fs::File, io::Write};
// Note that we're not calling `.await` here.
let buffer_slice = self.output_buffer.slice(..);
let buffer_future = buffer_slice.map_async(wgpu::MapMode::Read, |_| ());
buffer_slice.map_async(wgpu::MapMode::Read, |_| ());
// Poll the device in a blocking manner so that our future resolves.
// In an actual application, `device.poll(...)` should
@ -139,8 +139,7 @@ impl Surface {
format: settings.texture_format,
width: size.width(),
height: size.height(),
//present_mode: wgpu::PresentMode::Immediate,
present_mode: wgpu::PresentMode::Fifo, // VSync
present_mode: settings.present_mode,
};
let surface = unsafe { instance.create_surface(window.raw()) };

View File

@ -2,6 +2,7 @@
use std::borrow::Cow;
use wgpu::PresentMode;
pub use wgpu::{Backends, Features, Limits, PowerPreference, TextureFormat};
/// Provides configuration for renderer initialization. Use [`Device::features`](crate::renderer::Device::features),
@ -104,6 +105,8 @@ pub struct RendererSettings {
pub msaa: Msaa,
pub texture_format: TextureFormat,
pub depth_texture_format: TextureFormat,
/// Present mode for surfaces if a surface is used.
pub present_mode: PresentMode,
}
impl Default for RendererSettings {
@ -132,6 +135,7 @@ impl Default for RendererSettings {
texture_format: TextureFormat::Bgra8UnormSrgb,
depth_texture_format: TextureFormat::Depth24PlusStencil8,
present_mode: PresentMode::AutoVsync,
}
}
}

View File

@ -29,6 +29,7 @@ impl Stage for UploadStage {
World {
tile_repository,
view_state,
..
},
style,
renderer: Renderer { queue, state, .. },

View File

@ -11,7 +11,7 @@ use crate::{
error::Error,
io::{
apc::{Context, Message},
geometry_index::IndexedGeometry,
geometry_index::{IndexedGeometry, TileIndex},
pipeline::PipelineProcessor,
source_client::HttpClient,
transferables::{TessellatedLayer, TileTessellated, Transferables, UnavailableLayer},
@ -52,7 +52,7 @@ impl<'c, T: Transferables, HC: HttpClient, C: Context<T, HC>> PipelineProcessor
layer_name: &str,
) -> Result<(), Error> {
self.context
.send(Message::UnavailableLayer(T::UnavailableLayer::new(
.send(Message::LayerUnavailable(T::LayerUnavailable::new(
*coords,
layer_name.to_owned(),
)))
@ -66,7 +66,7 @@ impl<'c, T: Transferables, HC: HttpClient, C: Context<T, HC>> PipelineProcessor
layer_data: tile::Layer,
) -> Result<(), Error> {
self.context
.send(Message::TessellatedLayer(T::TessellatedLayer::new(
.send(Message::LayerTessellated(T::LayerTessellated::new(
*coords,
buffer,
feature_indices,
@ -76,36 +76,13 @@ impl<'c, T: Transferables, HC: HttpClient, C: Context<T, HC>> PipelineProcessor
fn layer_indexing_finished(
&mut self,
_coords: &WorldTileCoords,
_geometries: Vec<IndexedGeometry<f64>>,
coords: &WorldTileCoords,
geometries: Vec<IndexedGeometry<f64>>,
) -> Result<(), Error> {
// FIXME (wasm-executor): Readd
/* if let Ok(mut geometry_index) = self.state.geometry_index.lock() {
geometry_index.index_tile(coords, TileIndex::Linear { list: geometries })
}*/
Ok(())
self.context
.send(Message::LayerIndexed(T::LayerIndexed::from((
*coords,
TileIndex::Linear { list: geometries },
))))
}
}
// FIXME (wasm-executor): Readd
/*pub fn query_point(
&self,
world_coords: &WorldCoords,
z: ZoomLevel,
zoom: Zoom,
) -> Option<Vec<IndexedGeometry<f64>>> {
if let Ok(geometry_index) = self.geometry_index.lock() {
geometry_index
.query_point(world_coords, z, zoom)
.map(|geometries| {
geometries
.iter()
.cloned()
.cloned()
.collect::<Vec<IndexedGeometry<f64>>>()
})
} else {
unimplemented!()
}
}*/
//}

View File

@ -8,7 +8,7 @@ use crate::{
io::{
apc::{AsyncProcedureCall, Message},
tile_repository::StoredLayer,
transferables::{TessellatedLayer, TileTessellated, UnavailableLayer},
transferables::{IndexedLayer, TessellatedLayer, TileTessellated, UnavailableLayer},
},
kernel::Kernel,
schedule::Stage,
@ -29,32 +29,40 @@ impl<E: Environment> Stage for PopulateTileStore<E> {
fn run(
&mut self,
MapContext {
world: World {
tile_repository, ..
},
world:
World {
tile_repository,
geometry_index,
..
},
..
}: &mut MapContext,
) {
if let Some(result) = self.kernel.apc().receive() {
match result {
Message::TileTessellated(tranferred) => {
let coords = tranferred.coords();
tile_repository.mark_tile_succeeded(coords);
Message::TileTessellated(message) => {
let coords = message.coords();
tracing::trace!("Tile at {} finished loading", coords);
log::warn!("Tile at {} finished loading", coords);
tile_repository.mark_tile_succeeded(coords);
}
// FIXME: deduplicate
Message::UnavailableLayer(tranferred) => {
let layer: StoredLayer = tranferred.to_stored_layer();
Message::LayerUnavailable(message) => {
let layer: StoredLayer = message.to_stored_layer();
tracing::debug!(
"Layer {} at {} reached main thread",
layer.layer_name(),
layer.get_coords()
);
tile_repository.put_layer(layer);
}
Message::TessellatedLayer(data) => {
let layer: StoredLayer = data.to_stored_layer();
Message::LayerTessellated(message) => {
let layer: StoredLayer = message.to_stored_layer();
tracing::debug!(
"Layer {} at {} reached main thread",
layer.layer_name(),
@ -65,8 +73,16 @@ impl<E: Environment> Stage for PopulateTileStore<E> {
layer.layer_name(),
layer.get_coords()
);
tile_repository.put_layer(layer);
}
Message::LayerIndexed(message) => {
let coords = *message.coords();
log::warn!("Layer index at {} reached main thread", coords);
geometry_index.index_tile(&coords, message.to_tile_index());
}
}
}
}

View File

@ -40,6 +40,7 @@ impl<E: Environment> Stage for RequestStage<E> {
World {
tile_repository,
view_state,
..
},
style,
..
@ -68,14 +69,11 @@ pub fn schedule<
input: Input,
context: C,
) -> AsyncProcedureFuture {
// FIXME: improve input handling
let input = match input {
Input::TileRequest(input) => Some(input),
_ => None,
}
.unwrap(); // FIXME (wasm-executor): Remove unwrap
Box::pin(async move {
let Input::TileRequest(input) = input else {
return Err(Error::APC)
};
let coords = input.coords;
let client = context.source_client();
@ -89,24 +87,24 @@ pub fn schedule<
phantom_hc: Default::default(),
});
let pipeline = build_vector_tile_pipeline();
pipeline.process((input, data), &mut pipeline_context);
pipeline.process((input, data), &mut pipeline_context)?;
}
Err(e) => {
log::error!("{:?}", &e);
for to_load in &input.layers {
tracing::warn!("layer {} at {} unavailable", to_load, coords);
// FIXME: Handle result
context.send(
Message::UnavailableLayer(<<E::AsyncProcedureCall as AsyncProcedureCall<
Message::LayerUnavailable(<<E::AsyncProcedureCall as AsyncProcedureCall<
E::HttpClient,
>>::Transferables as Transferables>::UnavailableLayer::new(
>>::Transferables as Transferables>::LayerUnavailable::new(
input.coords,
to_load.to_string(),
)),
);
)?;
}
}
}
Ok(())
})
}

View File

@ -4,7 +4,7 @@ use cgmath::Angle;
use crate::{
coords::{LatLon, ViewRegion, WorldCoords, Zoom, ZoomLevel, TILE_SIZE},
io::tile_repository::TileRepository,
io::{geometry_index::GeometryIndex, tile_repository::TileRepository},
render::camera::{Camera, Perspective, ViewProjection},
util::ChangeObserver,
window::WindowSize,
@ -13,6 +13,7 @@ use crate::{
pub struct World {
pub view_state: ViewState,
pub tile_repository: TileRepository,
pub geometry_index: GeometryIndex,
}
impl World {
@ -46,10 +47,12 @@ impl World {
);
let tile_repository = TileRepository::new();
let geometry_index = GeometryIndex::new();
World {
view_state,
tile_repository,
geometry_index,
}
}

View File

@ -44,8 +44,6 @@ console_log = { version = "0.2.0", features = ["color"] }
tracing-wasm = { version = "0.2.1", optional = true } # TODO: Low quality dependency
# For passing Inputs in AsyncProcedureCalls
serde_json = "1.0.85"
bytemuck = "1.12.1" # FIXME (wasm-executor): Remove
bytemuck_derive = "1.2.1" # FIXME (wasm-executor): Remove
[dev-dependencies]
wasm-bindgen-test = "0.3.31"

View File

@ -43,7 +43,6 @@ impl Scheduler for WebWorkerPoolScheduler {
Ok(JsValue::undefined())
})
})
.unwrap(); // FIXME (wasm-executor): remove unwrap
Ok(())
.map_err(|e| Error::Scheduler)
}
}

View File

@ -1,4 +1,4 @@
use std::{cell::RefCell, mem, rc::Rc};
use std::{cell::RefCell, mem, mem::size_of, rc::Rc, slice};
use js_sys::Uint8Array;
use log::info;
@ -15,7 +15,8 @@ use web_sys::{DedicatedWorkerGlobalScope, Worker};
use crate::{
platform::singlethreaded::transferables::{
InnerData, LinearTessellatedLayer, LinearTransferables,
InnerData, LinearLayerIndexed, LinearLayerTesselated, LinearLayerUnavailable,
LinearTileTessellated, LinearTransferables,
},
WHATWGFetchHttpClient,
};
@ -27,22 +28,26 @@ type UsedContext = PassingContext;
#[derive(Debug)]
enum SerializedMessageTag {
TileTessellated = 1,
UnavailableLayer = 2,
TessellatedLayer = 3,
LayerUnavailable = 2,
LayerTessellated = 3,
LayerIndexed = 4,
}
impl SerializedMessageTag {
fn from_u32(tag: u32) -> Option<Self> {
match tag {
x if x == SerializedMessageTag::UnavailableLayer as u32 => {
Some(SerializedMessageTag::UnavailableLayer)
x if x == SerializedMessageTag::LayerUnavailable as u32 => {
Some(SerializedMessageTag::LayerUnavailable)
}
x if x == SerializedMessageTag::TessellatedLayer as u32 => {
Some(SerializedMessageTag::TessellatedLayer)
x if x == SerializedMessageTag::LayerTessellated as u32 => {
Some(SerializedMessageTag::LayerTessellated)
}
x if x == SerializedMessageTag::TileTessellated as u32 => {
Some(SerializedMessageTag::TileTessellated)
}
x if x == SerializedMessageTag::LayerIndexed as u32 => {
Some(SerializedMessageTag::LayerIndexed)
}
_ => None,
}
}
@ -58,34 +63,61 @@ trait SerializableMessage {
impl SerializableMessage for Message<LinearTransferables> {
fn serialize(&self) -> &[u8] {
match self {
Message::TileTessellated(data) => bytemuck::bytes_of(data),
Message::UnavailableLayer(data) => bytemuck::bytes_of(data),
Message::TessellatedLayer(data) => bytemuck::bytes_of(data.data.as_ref()),
unsafe {
match self {
// TODO https://github.com/Lokathor/bytemuck/blob/518baf9c0b73c92b4ea4406fe15e005c6d71535a/src/internal.rs#L333
Message::TileTessellated(message) => slice::from_raw_parts(
message as *const LinearTileTessellated as *mut u8,
size_of::<LinearTileTessellated>(),
),
Message::LayerUnavailable(message) => slice::from_raw_parts(
message as *const LinearLayerUnavailable as *mut u8,
size_of::<LinearLayerUnavailable>(),
),
Message::LayerTessellated(message) => slice::from_raw_parts(
message.data.as_ref() as *const InnerData as *mut u8,
size_of::<InnerData>(),
),
Message::LayerIndexed(message) => slice::from_raw_parts(
message as *const LinearLayerIndexed as *mut u8,
size_of::<LinearLayerIndexed>(),
),
}
}
}
fn deserialize(tag: SerializedMessageTag, data: Uint8Array) -> Message<UsedTransferables> {
match tag {
SerializedMessageTag::TileTessellated => {
Message::<UsedTransferables>::TileTessellated(*bytemuck::from_bytes::<
<UsedTransferables as Transferables>::TileTessellated,
>(&data.to_vec()))
}
SerializedMessageTag::UnavailableLayer => {
Message::<UsedTransferables>::UnavailableLayer(*bytemuck::from_bytes::<
<UsedTransferables as Transferables>::UnavailableLayer,
>(&data.to_vec()))
}
SerializedMessageTag::TessellatedLayer => {
Message::<UsedTransferables>::TessellatedLayer(LinearTessellatedLayer {
data: unsafe {
let mut uninit = Box::<InnerData>::new_zeroed();
data.raw_copy_to_ptr(uninit.as_mut_ptr() as *mut u8);
type TileTessellated = <UsedTransferables as Transferables>::TileTessellated;
type UnavailableLayer = <UsedTransferables as Transferables>::LayerUnavailable;
type IndexedLayer = <UsedTransferables as Transferables>::LayerIndexed;
unsafe {
// TODO: https://github.com/Lokathor/bytemuck/blob/518baf9c0b73c92b4ea4406fe15e005c6d71535a/src/internal.rs#L159
match tag {
SerializedMessageTag::TileTessellated => {
Message::<UsedTransferables>::TileTessellated(
(&*(data.to_vec().as_slice() as *const [u8] as *const TileTessellated))
.clone(),
)
}
SerializedMessageTag::LayerUnavailable => {
Message::<UsedTransferables>::LayerUnavailable(
(&*(data.to_vec().as_slice() as *const [u8] as *const UnavailableLayer))
.clone(),
)
}
SerializedMessageTag::LayerTessellated => {
Message::<UsedTransferables>::LayerTessellated(LinearLayerTesselated {
data: unsafe {
let mut uninit = Box::<InnerData>::new_zeroed();
data.raw_copy_to_ptr(uninit.as_mut_ptr() as *mut u8);
uninit.assume_init()
},
})
uninit.assume_init()
},
})
}
SerializedMessageTag::LayerIndexed => Message::<UsedTransferables>::LayerIndexed(
(&*(data.to_vec().as_slice() as *const [u8] as *const IndexedLayer)).clone(),
),
}
}
}
@ -93,8 +125,9 @@ impl SerializableMessage for Message<LinearTransferables> {
fn tag(&self) -> SerializedMessageTag {
match self {
Message::TileTessellated(_) => SerializedMessageTag::TileTessellated,
Message::UnavailableLayer(_) => SerializedMessageTag::UnavailableLayer,
Message::TessellatedLayer(_) => SerializedMessageTag::TessellatedLayer,
Message::LayerUnavailable(_) => SerializedMessageTag::LayerUnavailable,
Message::LayerTessellated(_) => SerializedMessageTag::LayerTessellated,
Message::LayerIndexed(_) => SerializedMessageTag::LayerIndexed,
}
}
}

View File

@ -1,91 +1,73 @@
use bytemuck::{TransparentWrapper, Zeroable};
use bytemuck_derive::{Pod, Zeroable};
use log::warn;
use maplibre::{
benchmarking::tessellation::{IndexDataType, OverAlignedVertexBuffer},
coords::WorldTileCoords,
io::{
geometry_index::TileIndex,
tile_repository::StoredLayer,
transferables::{TessellatedLayer, TileTessellated, Transferables, UnavailableLayer},
transferables::{
IndexedLayer, TessellatedLayer, TileTessellated, Transferables, UnavailableLayer,
},
},
render::ShaderVertex,
tile::Layer,
};
// FIXME (wasm-executor): properly do this!, fix this whole file
#[derive(Copy, Clone, Debug)]
#[repr(transparent)]
pub struct WrapperWorldTileCoords(WorldTileCoords);
unsafe impl TransparentWrapper<WorldTileCoords> for WrapperWorldTileCoords {}
unsafe impl bytemuck::Zeroable for WrapperWorldTileCoords {}
unsafe impl bytemuck::Pod for WrapperWorldTileCoords {}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct LongVertexShader([ShaderVertex; 15000]);
unsafe impl TransparentWrapper<[ShaderVertex; 15000]> for LongVertexShader {}
unsafe impl bytemuck::Zeroable for LongVertexShader {}
unsafe impl bytemuck::Pod for LongVertexShader {}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct LongIndices([IndexDataType; 40000]);
unsafe impl TransparentWrapper<[IndexDataType; 40000]> for LongIndices {}
unsafe impl bytemuck::Zeroable for LongIndices {}
unsafe impl bytemuck::Pod for LongIndices {}
#[derive(Copy, Clone, Pod, Zeroable)]
#[repr(C)]
pub struct LinearTileTessellated {
pub coords: WrapperWorldTileCoords,
pub coords: WorldTileCoords,
pub _padding: u8,
}
impl TileTessellated for LinearTileTessellated {
fn new(coords: WorldTileCoords) -> Self {
Self {
coords: WrapperWorldTileCoords::wrap(coords),
coords,
_padding: 0,
}
}
fn coords(&self) -> &WorldTileCoords {
WrapperWorldTileCoords::peel_ref(&self.coords)
&self.coords
}
}
#[derive(Copy, Clone, Pod, Zeroable)]
#[repr(C)]
pub struct LinearUnavailableLayer {
pub coords: WrapperWorldTileCoords,
#[derive(Copy, Clone)]
pub struct LinearLayerUnavailable {
pub coords: WorldTileCoords,
pub layer_name: [u8; 32],
}
impl UnavailableLayer for LinearUnavailableLayer {
impl UnavailableLayer for LinearLayerUnavailable {
fn new(coords: WorldTileCoords, layer_name: String) -> Self {
let mut new_layer_name = [0; 32];
new_layer_name[0..layer_name.len()].clone_from_slice(layer_name.as_bytes());
Self {
coords: WrapperWorldTileCoords::wrap(coords),
coords,
layer_name: new_layer_name,
}
}
fn coords(&self) -> &WorldTileCoords {
&self.coords
}
fn to_stored_layer(self) -> StoredLayer {
StoredLayer::UnavailableLayer {
coords: WrapperWorldTileCoords::peel(self.coords),
coords: self.coords,
layer_name: String::from_utf8(Vec::from(self.layer_name)).unwrap(), // FIXME (wasm-executor): Remove unwrap
}
}
}
#[derive(Copy, Clone, Pod, Zeroable)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct InnerData {
pub coords: WrapperWorldTileCoords,
pub coords: WorldTileCoords,
pub layer_name: [u8; 32],
pub layer_name_len: usize,
pub vertices: LongVertexShader,
pub vertices: [ShaderVertex; 15000],
pub vertices_len: usize,
pub indices: LongIndices,
pub indices: [IndexDataType; 40000],
pub indices_len: usize,
pub usable_indices: u32,
/// Holds for each feature the count of indices.
@ -94,11 +76,11 @@ pub struct InnerData {
}
#[derive(Clone)]
pub struct LinearTessellatedLayer {
pub struct LinearLayerTesselated {
pub data: Box<InnerData>,
}
impl TessellatedLayer for LinearTessellatedLayer {
impl TessellatedLayer for LinearLayerTesselated {
fn new(
coords: WorldTileCoords,
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
@ -106,15 +88,15 @@ impl TessellatedLayer for LinearTessellatedLayer {
layer_data: Layer,
) -> Self {
let mut data = Box::new(InnerData {
coords: WrapperWorldTileCoords::wrap(coords),
coords,
layer_name: [0; 32],
layer_name_len: layer_data.name.len(),
vertices: LongVertexShader::wrap([ShaderVertex::zeroed(); 15000]),
vertices: [ShaderVertex::new([0.0, 0.0], [0.0, 0.0]); 15000],
vertices_len: buffer.buffer.vertices.len(),
indices: LongIndices::wrap([IndexDataType::zeroed(); 40000]),
indices: [0; 40000],
indices_len: buffer.buffer.indices.len(),
usable_indices: buffer.usable_indices,
@ -127,15 +109,15 @@ impl TessellatedLayer for LinearTessellatedLayer {
warn!("vertices too large");
return Self {
data: Box::new(InnerData {
coords: WrapperWorldTileCoords::wrap(coords),
coords,
layer_name: [0; 32],
layer_name_len: 0,
vertices: LongVertexShader::wrap([ShaderVertex::zeroed(); 15000]),
vertices: [ShaderVertex::new([0.0, 0.0], [0.0, 0.0]); 15000],
vertices_len: 0,
indices: LongIndices::wrap([IndexDataType::zeroed(); 40000]),
indices: [0; 40000],
indices_len: 0,
usable_indices: 0,
@ -150,15 +132,15 @@ impl TessellatedLayer for LinearTessellatedLayer {
warn!("indices too large");
return Self {
data: Box::new(InnerData {
coords: WrapperWorldTileCoords::wrap(coords),
coords,
layer_name: [0; 32],
layer_name_len: 0,
vertices: LongVertexShader::wrap([ShaderVertex::zeroed(); 15000]),
vertices: [ShaderVertex::new([0.0, 0.0], [0.0, 0.0]); 15000],
vertices_len: 0,
indices: LongIndices::wrap([IndexDataType::zeroed(); 40000]),
indices: [0; 40000],
indices_len: 0,
usable_indices: 0,
@ -173,15 +155,15 @@ impl TessellatedLayer for LinearTessellatedLayer {
warn!("feature_indices too large");
return Self {
data: Box::new(InnerData {
coords: WrapperWorldTileCoords::wrap(coords),
coords,
layer_name: [0; 32],
layer_name_len: 0,
vertices: LongVertexShader::wrap([ShaderVertex::zeroed(); 15000]),
vertices: [ShaderVertex::new([0.0, 0.0], [0.0, 0.0]); 15000],
vertices_len: 0,
indices: LongIndices::wrap([IndexDataType::zeroed(); 40000]),
indices: [0; 40000],
indices_len: 0,
usable_indices: 0,
@ -192,25 +174,29 @@ impl TessellatedLayer for LinearTessellatedLayer {
};
}
data.vertices.0[0..buffer.buffer.vertices.len()].clone_from_slice(&buffer.buffer.vertices);
data.indices.0[0..buffer.buffer.indices.len()].clone_from_slice(&buffer.buffer.indices);
data.vertices[0..buffer.buffer.vertices.len()].clone_from_slice(&buffer.buffer.vertices);
data.indices[0..buffer.buffer.indices.len()].clone_from_slice(&buffer.buffer.indices);
data.feature_indices[0..feature_indices.len()].clone_from_slice(&feature_indices);
data.layer_name[0..layer_data.name.len()].clone_from_slice(layer_data.name.as_bytes());
Self { data }
}
fn coords(&self) -> &WorldTileCoords {
&self.data.coords
}
fn to_stored_layer(self) -> StoredLayer {
// TODO: Avoid copies here
StoredLayer::TessellatedLayer {
coords: WrapperWorldTileCoords::peel(self.data.coords),
coords: self.data.coords,
layer_name: String::from_utf8(Vec::from(
&self.data.layer_name[..self.data.layer_name_len],
))
.unwrap(), // FIXME (wasm-executor): Remove unwrap
buffer: OverAlignedVertexBuffer::from_slices(
&self.data.vertices.0[..self.data.vertices_len],
&self.data.indices.0[..self.data.indices_len],
&self.data.vertices[..self.data.vertices_len],
&self.data.indices[..self.data.indices_len],
self.data.usable_indices,
),
feature_indices: Vec::from(&self.data.feature_indices[..self.data.feature_indices_len]),
@ -218,10 +204,33 @@ impl TessellatedLayer for LinearTessellatedLayer {
}
}
#[derive(Copy, Clone)]
pub struct LinearLayerIndexed {
pub coords: WorldTileCoords,
}
impl From<(WorldTileCoords, TileIndex)> for LinearLayerIndexed {
fn from((coords, _index): (WorldTileCoords, TileIndex)) -> Self {
Self { coords }
}
}
impl IndexedLayer for LinearLayerIndexed {
fn coords(&self) -> &WorldTileCoords {
&self.coords
}
fn to_tile_index(self) -> TileIndex {
// FIXME replace this stub implementation
TileIndex::Linear { list: vec![] }
}
}
pub struct LinearTransferables;
impl Transferables for LinearTransferables {
type TileTessellated = LinearTileTessellated;
type UnavailableLayer = LinearUnavailableLayer;
type TessellatedLayer = LinearTessellatedLayer;
type LayerUnavailable = LinearLayerUnavailable;
type LayerTessellated = LinearLayerTesselated;
type LayerIndexed = LinearLayerIndexed;
}