Make the scheduler work with future(-factories) for simple scheduling arbitrary workloads

This commit is contained in:
Maximilian Ammann 2022-04-05 15:14:19 +02:00
parent 945d3f502c
commit 197a3a3662
29 changed files with 574 additions and 465 deletions

View File

@ -9,7 +9,7 @@
<option name="withSudo" value="false" />
<option name="backtrace" value="SHORT" />
<envs>
<env name="RUSTUP_TOOLCHAIN" value="nightly-2022-02-26-x86_64-unknown-linux-gnu" />
<env name="RUSTUP_TOOLCHAIN" value="nightly-2022-04-04-x86_64-unknown-linux-gnu" />
</envs>
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />

View File

@ -17,9 +17,7 @@ fn main() {
enable_tracing();
MapBuilder::from_window("A fantastic window!")
.with_schedule_method(ScheduleMethod::Tokio(TokioScheduleMethod::new(Some(
"/tmp/mapr_cache".to_string(),
))))
.with_schedule_method(ScheduleMethod::Tokio(TokioScheduleMethod::new()))
.build()
.run_sync();
}

View File

@ -4,6 +4,7 @@ use lyon::tessellation::TessellationError;
#[derive(Debug)]
pub enum Error {
Schedule,
Network(String),
File(String),
Tesselation(TessellationError),

View File

@ -13,6 +13,7 @@ use crate::input::tilt_handler::TiltHandler;
use crate::input::zoom_handler::ZoomHandler;
use crate::io::tile_cache::TileCache;
use crate::render::render_state::RenderState;
use crate::IOScheduler;
mod pan_handler;
mod pinch_handler;
@ -125,17 +126,17 @@ impl InputController {
}
pub trait UpdateState {
fn update_state(&mut self, state: &mut RenderState, tile_cache: &TileCache, dt: Duration);
fn update_state(&mut self, state: &mut RenderState, scheduler: &IOScheduler, dt: Duration);
}
impl UpdateState for InputController {
#[tracing::instrument(skip_all)]
fn update_state(&mut self, state: &mut RenderState, tile_cache: &TileCache, dt: Duration) {
self.pan_handler.update_state(state, tile_cache, dt);
self.pinch_handler.update_state(state, tile_cache, dt);
self.zoom_handler.update_state(state, tile_cache, dt);
self.tilt_handler.update_state(state, tile_cache, dt);
self.shift_handler.update_state(state, tile_cache, dt);
self.query_handler.update_state(state, tile_cache, dt);
fn update_state(&mut self, state: &mut RenderState, scheduler: &IOScheduler, dt: Duration) {
self.pan_handler.update_state(state, scheduler, dt);
self.pinch_handler.update_state(state, scheduler, dt);
self.zoom_handler.update_state(state, scheduler, dt);
self.tilt_handler.update_state(state, scheduler, dt);
self.shift_handler.update_state(state, scheduler, dt);
self.query_handler.update_state(state, scheduler, dt);
}
}

View File

@ -2,6 +2,7 @@ use super::UpdateState;
use crate::io::tile_cache::TileCache;
use crate::render::camera::Camera;
use crate::render::render_state::RenderState;
use crate::IOScheduler;
use cgmath::{EuclideanSpace, Point3, Vector2, Vector3, Zero};
use std::time::Duration;
use winit::event::{ElementState, MouseButton};
@ -15,7 +16,7 @@ pub struct PanHandler {
}
impl UpdateState for PanHandler {
fn update_state(&mut self, state: &mut RenderState, _tile_cache: &TileCache, _dt: Duration) {
fn update_state(&mut self, state: &mut RenderState, _scheduler: &IOScheduler, _dt: Duration) {
if !self.is_panning {
return;
}

View File

@ -1,12 +1,13 @@
use super::UpdateState;
use crate::io::tile_cache::TileCache;
use crate::render::render_state::RenderState;
use crate::IOScheduler;
use std::time::Duration;
pub struct PinchHandler {}
impl UpdateState for PinchHandler {
fn update_state(&mut self, _state: &mut RenderState, _tile_cache: &TileCache, _dt: Duration) {
fn update_state(&mut self, _state: &mut RenderState, _scheduler: &IOScheduler, _dt: Duration) {
// TODO
}
}

View File

@ -3,6 +3,7 @@ use crate::io::tile_cache::TileCache;
use crate::render::render_state::RenderState;
use crate::IOScheduler;
use cgmath::Vector2;
use log::info;
use std::time::Duration;
@ -57,7 +58,7 @@ impl QueryHandler {
true
}
pub fn update_state(&mut self, state: &mut RenderState, tile_cache: &TileCache, _dt: Duration) {
pub fn update_state(&mut self, state: &mut RenderState, scheduler: &IOScheduler, dt: Duration) {
if self.clicking {
if let Some(window_position) = self.window_position {
let perspective = &state.perspective;
@ -68,7 +69,7 @@ impl QueryHandler {
.camera
.window_to_world_at_ground(&window_position, &inverted_view_proj)
{
let option = tile_cache.query_point(
/*let option = tile_cache.query_point(
&WorldCoords {
x: coordinates.x,
y: coordinates.y,
@ -83,7 +84,7 @@ impl QueryHandler {
.iter()
.map(|geometry| &geometry.properties)
.collect::<Vec<_>>())
);
);*/
}
}
self.clicking = false;

View File

@ -1,6 +1,7 @@
use super::UpdateState;
use crate::io::tile_cache::TileCache;
use crate::render::render_state::RenderState;
use crate::IOScheduler;
use cgmath::{Vector3, Zero};
use std::time::Duration;
@ -12,7 +13,7 @@ pub struct ShiftHandler {
}
impl UpdateState for ShiftHandler {
fn update_state(&mut self, state: &mut RenderState, _tile_cache: &TileCache, dt: Duration) {
fn update_state(&mut self, state: &mut RenderState, _scheduler: &IOScheduler, dt: Duration) {
let dt = dt.as_secs_f64() * (1.0 / self.speed);
let delta = self.camera_translate * dt;

View File

@ -1,6 +1,7 @@
use super::UpdateState;
use crate::io::tile_cache::TileCache;
use crate::render::render_state::RenderState;
use crate::IOScheduler;
use cgmath::{Deg, Rad, Zero};
use std::time::Duration;
@ -12,7 +13,7 @@ pub struct TiltHandler {
}
impl UpdateState for TiltHandler {
fn update_state(&mut self, state: &mut RenderState, _tile_cache: &TileCache, dt: Duration) {
fn update_state(&mut self, state: &mut RenderState, _scheduler: &IOScheduler, dt: Duration) {
let dt = dt.as_secs_f64() * (1.0 / self.speed);
let delta = self.delta_pitch * dt;

View File

@ -2,6 +2,7 @@ use super::UpdateState;
use crate::io::tile_cache::TileCache;
use crate::render::render_state::RenderState;
use crate::IOScheduler;
use cgmath::num_traits::Pow;
use cgmath::{Vector2, Vector3};
use std::time::Duration;
@ -13,7 +14,7 @@ pub struct ZoomHandler {
}
impl UpdateState for ZoomHandler {
fn update_state(&mut self, state: &mut RenderState, _tile_cache: &TileCache, _dt: Duration) {
fn update_state(&mut self, state: &mut RenderState, _scheduler: &IOScheduler, _dt: Duration) {
if self.zoom_delta != 0.0 {
if let Some(window_position) = self.window_position {
let current_zoom = state.zoom;

View File

@ -1,6 +1,6 @@
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use cgmath::num_traits::Signed;
use cgmath::num_traits::{Pow, Signed};
use cgmath::Bounded;
use geo::prelude::*;
use geo_types::{CoordFloat, Coordinate, Geometry, LineString, Point, Polygon};
@ -9,9 +9,52 @@ use geozero::geo_types::GeoWriter;
use geozero::{ColumnValue, FeatureProcessor, GeomProcessor, PropertyProcessor};
use rstar::{Envelope, PointDistance, RTree, RTreeObject, AABB};
use crate::coords::InnerCoords;
use crate::coords::{InnerCoords, Quadkey, WorldCoords, WorldTileCoords, EXTENT, TILE_SIZE};
use crate::util::math::bounds_from_points;
pub struct GeometryIndex {
index: BTreeMap<Quadkey, TileIndex>,
}
impl GeometryIndex {
pub fn new() -> Self {
Self {
index: Default::default(),
}
}
pub fn index_tile(&mut self, coords: &&WorldTileCoords, tile_index: TileIndex) {
coords
.build_quad_key()
.and_then(|key| self.index.insert(key, tile_index));
}
pub fn query_point(
&self,
world_coords: &WorldCoords,
z: u8,
zoom: f64,
) -> Option<Vec<&IndexGeometry<f64>>> {
let world_tile_coords = world_coords.into_world_tile(z, zoom);
if let Some(index) = world_tile_coords
.build_quad_key()
.and_then(|key| self.index.get(&key))
{
let scale = 2.0f64.pow(z as f64 - zoom); // TODO deduplicate
let delta_x = world_coords.x / TILE_SIZE * scale - world_tile_coords.x as f64;
let delta_y = world_coords.y / TILE_SIZE * scale - world_tile_coords.y as f64;
let x = delta_x * EXTENT;
let y = delta_y * EXTENT;
Some(index.point_query(InnerCoords { x, y }))
} else {
None
}
}
}
pub enum TileIndex {
Spatial { tree: RTree<IndexGeometry<f64>> },
Linear { list: Vec<IndexGeometry<f64>> },

View File

@ -13,6 +13,7 @@ use vector_tile::tile::Layer;
mod geometry_index;
pub mod scheduler;
mod source_client;
pub mod static_tile_fetcher;
pub mod tile_cache;
@ -39,18 +40,16 @@ impl fmt::Debug for TileFetchResult {
}
}
pub struct TileIndexResult {
pub enum TessellateMessage {
Tile(TileTessellateMessage),
Layer(LayerTessellateMessage),
}
pub struct TileTessellateMessage {
request_id: TileRequestID,
coords: WorldTileCoords,
index: TileIndex,
}
pub enum TileTessellateResult {
Tile { request_id: TileRequestID },
Layer(LayerTessellateResult),
}
pub enum LayerTessellateResult {
pub enum LayerTessellateMessage {
UnavailableLayer {
coords: WorldTileCoords,
layer_name: String,
@ -64,24 +63,24 @@ pub enum LayerTessellateResult {
},
}
impl fmt::Debug for LayerTessellateResult {
impl fmt::Debug for LayerTessellateMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "LayerResult{}", self.get_coords())
write!(f, "LayerTessellateMessage{}", self.get_coords())
}
}
impl LayerTessellateResult {
impl LayerTessellateMessage {
pub fn get_coords(&self) -> WorldTileCoords {
match self {
LayerTessellateResult::UnavailableLayer { coords, .. } => *coords,
LayerTessellateResult::TessellatedLayer { coords, .. } => *coords,
LayerTessellateMessage::UnavailableLayer { coords, .. } => *coords,
LayerTessellateMessage::TessellatedLayer { coords, .. } => *coords,
}
}
pub fn layer_name(&self) -> &str {
match self {
LayerTessellateResult::UnavailableLayer { layer_name, .. } => layer_name.as_str(),
LayerTessellateResult::TessellatedLayer { layer_data, .. } => layer_data.name(),
LayerTessellateMessage::UnavailableLayer { layer_name, .. } => layer_name.as_str(),
LayerTessellateMessage::TessellatedLayer { layer_data, .. } => layer_data.name(),
}
}
}
@ -94,7 +93,7 @@ pub struct TileRequest {
impl fmt::Debug for TileRequest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "TileRequest({})", &self.coords)
write!(f, "TileRequest({}, {:?})", &self.coords, &self.layers)
}
}

View File

@ -1,4 +1,5 @@
use std::collections::{HashMap, HashSet};
use std::future::Future;
use geozero::mvt::Tile;
use geozero::GeozeroDatasource;
@ -13,62 +14,67 @@ use vector_tile::parse_tile_bytes;
use crate::coords::{TileCoords, WorldTileCoords};
use crate::io::tile_cache::TileCache;
use crate::io::{
LayerTessellateResult, TileFetchResult, TileIndexResult, TileRequest, TileRequestID,
TileTessellateResult,
LayerTessellateMessage, TessellateMessage, TileFetchResult, TileRequest, TileRequestID,
TileTessellateMessage,
};
use crate::error::Error;
use crate::io::geometry_index::{GeometryIndex, IndexProcessor, TileIndex};
use crate::io::source_client::{HttpSourceClient, SourceClient};
use crate::tessellation::Tessellated;
use prost::Message;
pub enum ScheduleMethod {
#[cfg(not(target_arch = "wasm32"))]
Tokio(crate::platform::scheduler::TokioScheduleMethod),
Tokio(crate::platform::schedule_method::TokioScheduleMethod),
#[cfg(target_arch = "wasm32")]
WebWorker(crate::platform::scheduler::WebWorkerScheduleMethod),
#[cfg(target_arch = "wasm32")]
WebWorkerPool(crate::platform::scheduler::WebWorkerPoolScheduleMethod),
WebWorkerPool(crate::platform::schedule_method::WebWorkerPoolScheduleMethod),
}
impl Default for ScheduleMethod {
fn default() -> Self {
#[cfg(not(target_arch = "wasm32"))]
{
ScheduleMethod::Tokio(crate::platform::scheduler::TokioScheduleMethod::new(None))
ScheduleMethod::Tokio(crate::platform::schedule_method::TokioScheduleMethod::new())
}
#[cfg(target_arch = "wasm32")]
{
ScheduleMethod::WebWorker(crate::platform::scheduler::WebWorkerScheduleMethod::new())
panic!("No default ScheduleMethod on web")
}
}
}
impl ScheduleMethod {
pub fn schedule_tile_request(
pub fn schedule_fn<T>(
&self,
scheduler: &IOScheduler,
request_id: TileRequestID,
coords: TileCoords,
) {
future_factory: impl (FnOnce() -> T) + Send + 'static,
) -> Result<(), Error>
where
T: Future<Output = ()> + 'static,
{
match self {
#[cfg(target_arch = "wasm32")]
ScheduleMethod::WebWorkerPool(method) => Ok(method.schedule(future_factory)),
_ => Err(Error::Schedule),
}
}
pub fn schedule<T>(&self, future: T) -> Result<(), Error>
where
T: Future<Output = ()> + Send + 'static,
{
match self {
#[cfg(not(target_arch = "wasm32"))]
ScheduleMethod::Tokio(method) => {
method.schedule_tile_request(scheduler, request_id, coords)
}
#[cfg(target_arch = "wasm32")]
ScheduleMethod::WebWorker(method) => {
method.schedule_tile_request(scheduler, request_id, coords)
}
#[cfg(target_arch = "wasm32")]
ScheduleMethod::WebWorkerPool(method) => {
method.schedule_tile_request(scheduler, request_id, coords)
}
ScheduleMethod::Tokio(method) => Ok(method.schedule(future)),
_ => Err(Error::Schedule),
}
}
}
pub struct ThreadLocalTessellatorState {
tile_request_state: Arc<Mutex<TileRequestState>>,
tessellate_result_sender: Sender<TileTessellateResult>,
index_result_sender: Sender<TileIndexResult>,
tessellate_result_sender: Sender<TessellateMessage>,
geometry_index: Arc<Mutex<GeometryIndex>>,
}
#[cfg(target_arch = "wasm32")]
@ -81,8 +87,6 @@ impl Drop for ThreadLocalTessellatorState {
);
}
}
use crate::io::geometry_index::{IndexProcessor, TileIndex};
use prost::Message;
impl ThreadLocalTessellatorState {
fn get_tile_request(&self, request_id: TileRequestID) -> Option<TileRequest> {
@ -97,7 +101,7 @@ impl ThreadLocalTessellatorState {
&self,
request_id: TileRequestID,
data: Box<[u8]>,
) -> Result<(), SendError<TileTessellateResult>> {
) -> Result<(), SendError<TessellateMessage>> {
if let Some(tile_request) = self.get_tile_request(request_id) {
let tile_result = TileFetchResult::Tile {
coords: tile_request.coords,
@ -105,8 +109,7 @@ impl ThreadLocalTessellatorState {
};
self.tessellate_layers_with_request(&tile_result, &tile_request, request_id)?;
self.index_geometry(request_id, &tile_result);
self.index_geometry(&tile_result);
}
Ok(())
@ -115,7 +118,7 @@ impl ThreadLocalTessellatorState {
pub fn tile_unavailable(
&self,
request_id: TileRequestID,
) -> Result<(), SendError<TileTessellateResult>> {
) -> Result<(), SendError<TessellateMessage>> {
if let Some(tile_request) = self.get_tile_request(request_id) {
let tile_result = TileFetchResult::Unavailable {
coords: tile_request.coords,
@ -127,7 +130,7 @@ impl ThreadLocalTessellatorState {
}
#[tracing::instrument(skip(self))]
fn index_geometry(&self, request_id: TileRequestID, tile_result: &TileFetchResult) {
fn index_geometry(&self, tile_result: &TileFetchResult) {
match tile_result {
TileFetchResult::Tile { data, coords } => {
let tile: Tile = Tile::decode(data.as_ref()).unwrap();
@ -137,18 +140,14 @@ impl ThreadLocalTessellatorState {
layer.process(&mut processor).unwrap();
}
self.index_result_sender
.send(TileIndexResult {
request_id,
coords: *coords,
/*index: TileIndex::Spatial {
tree: processor.build_tree(),
},*/
index: TileIndex::Linear {
if let Some(mut geometry_index) = self.geometry_index.lock().ok() {
geometry_index.index_tile(
&coords,
TileIndex::Linear {
list: processor.get_geometries(),
},
})
.unwrap();
)
}
}
_ => {}
}
@ -160,13 +159,13 @@ impl ThreadLocalTessellatorState {
tile_result: &TileFetchResult,
tile_request: &TileRequest,
request_id: TileRequestID,
) -> Result<(), SendError<TileTessellateResult>> {
) -> Result<(), SendError<TessellateMessage>> {
match tile_result {
TileFetchResult::Unavailable { coords } => {
for to_load in &tile_request.layers {
self.tessellate_result_sender
.send(TileTessellateResult::Layer(
LayerTessellateResult::UnavailableLayer {
.send(TessellateMessage::Layer(
LayerTessellateMessage::UnavailableLayer {
coords: *coords,
layer_name: to_load.to_string(),
},
@ -186,8 +185,8 @@ impl ThreadLocalTessellatorState {
match layer.tessellate() {
Ok((buffer, feature_indices)) => {
self.tessellate_result_sender
.send(TileTessellateResult::Layer(
LayerTessellateResult::TessellatedLayer {
.send(TessellateMessage::Layer(
LayerTessellateMessage::TessellatedLayer {
coords: *coords,
buffer: buffer.into(),
feature_indices,
@ -197,8 +196,8 @@ impl ThreadLocalTessellatorState {
}
Err(e) => {
self.tessellate_result_sender
.send(TileTessellateResult::Layer(
LayerTessellateResult::UnavailableLayer {
.send(TessellateMessage::Layer(
LayerTessellateMessage::UnavailableLayer {
coords: *coords,
layer_name: to_load.to_string(),
},
@ -214,8 +213,8 @@ impl ThreadLocalTessellatorState {
info!("layer {} ready: {}", to_load, &coords);
} else {
self.tessellate_result_sender
.send(TileTessellateResult::Layer(
LayerTessellateResult::UnavailableLayer {
.send(TessellateMessage::Layer(
LayerTessellateMessage::UnavailableLayer {
coords: *coords,
layer_name: to_load.to_string(),
},
@ -228,16 +227,18 @@ impl ThreadLocalTessellatorState {
}
self.tessellate_result_sender
.send(TileTessellateResult::Tile { request_id })?;
.send(TessellateMessage::Tile(TileTessellateMessage {
request_id,
}))?;
Ok(())
}
}
pub struct IOScheduler {
index_channel: (Sender<TileIndexResult>, Receiver<TileIndexResult>),
tessellate_channel: (Sender<TileTessellateResult>, Receiver<TileTessellateResult>),
tessellate_channel: (Sender<TessellateMessage>, Receiver<TessellateMessage>),
tile_request_state: Arc<Mutex<TileRequestState>>,
geometry_index: Arc<Mutex<GeometryIndex>>,
tile_cache: TileCache,
schedule_method: ScheduleMethod,
}
@ -253,9 +254,9 @@ const _: () = {
impl IOScheduler {
pub fn new(schedule_method: ScheduleMethod) -> Self {
Self {
index_channel: channel(),
tessellate_channel: channel(),
tile_request_state: Arc::new(Mutex::new(TileRequestState::new())),
geometry_index: Arc::new(Mutex::new(GeometryIndex::new())),
tile_cache: TileCache::new(),
schedule_method,
}
@ -266,26 +267,22 @@ impl IOScheduler {
if let Ok(mut tile_request_state) = self.tile_request_state.try_lock() {
if let Ok(result) = self.tessellate_channel.1.try_recv() {
match result {
TileTessellateResult::Tile { request_id } => {
TessellateMessage::Tile(TileTessellateMessage { request_id }) => {
tile_request_state.finish_tile_request(request_id);
}
TileTessellateResult::Layer(layer_result) => {
self.tile_cache.put_tessellation_result(layer_result);
TessellateMessage::Layer(layer_result) => {
self.tile_cache.put_tesselated_layer(layer_result);
}
}
}
}
if let Ok(result) = self.index_channel.1.try_recv() {
self.tile_cache.put_index_result(result);
}
}
pub fn new_tessellator_state(&self) -> ThreadLocalTessellatorState {
ThreadLocalTessellatorState {
tile_request_state: self.tile_request_state.clone(),
tessellate_result_sender: self.tessellate_channel.0.clone(),
index_result_sender: self.index_channel.0.clone(),
geometry_index: self.geometry_index.clone(),
}
}
@ -299,15 +296,41 @@ impl IOScheduler {
}
if let Ok(mut tile_request_state) = self.tile_request_state.try_lock() {
if let Some(id) = tile_request_state.start_tile_request(TileRequest {
if let Some(request_id) = tile_request_state.start_tile_request(TileRequest {
coords: *coords,
layers: layers.clone(),
}) {
if let Some(tile_coords) = coords.into_tile(TileAddressingScheme::TMS) {
info!("new tile request: {}", &tile_coords);
info!("new tile request: {}", &coords);
self.schedule_method
.schedule_tile_request(self, id, tile_coords);
// The following snippet can be added instead of the next code block to demonstrate
// an understanable approach of fetching
/*#[cfg(target_arch = "wasm32")]
if let Some(tile_coords) = coords.into_tile(TileAddressingScheme::TMS) {
crate::platform::legacy_webworker_fetcher::request_tile(
request_id,
tile_coords,
);
}*/
{
let state = self.new_tessellator_state();
let client = SourceClient::Http(HttpSourceClient::new());
let copied_coords = *coords;
let future_fn = move || async move {
if let Ok(data) = client.fetch(&copied_coords).await {
state
.process_tile(request_id, data.into_boxed_slice())
.unwrap();
} else {
state.tile_unavailable(request_id).unwrap();
}
};
#[cfg(target_arch = "wasm32")]
self.schedule_method.schedule_fn(future_fn);
#[cfg(not(target_arch = "wasm32"))]
self.schedule_method.schedule(future_fn());
}
}
}

54
src/io/source_client.rs Normal file
View File

@ -0,0 +1,54 @@
use crate::coords::{TileCoords, WorldTileCoords};
use crate::error::Error;
use style_spec::source::TileAddressingScheme;
pub struct HttpSourceClient {
#[cfg(not(target_arch = "wasm32"))]
inner_client: crate::platform::http_client::ReqwestHttpClient,
#[cfg(target_arch = "wasm32")]
inner_client: crate::platform::http_client::WHATWGFetchHttpClient,
}
pub enum SourceClient {
Http(HttpSourceClient),
Mbtiles {
// TODO
},
}
impl SourceClient {
pub async fn fetch(&self, coords: &WorldTileCoords) -> Result<Vec<u8>, Error> {
match self {
SourceClient::Http(client) => client.fetch(coords).await,
SourceClient::Mbtiles { .. } => unimplemented!(),
}
}
}
impl HttpSourceClient {
pub fn new() -> Self {
Self {
#[cfg(not(target_arch = "wasm32"))]
inner_client: crate::platform::http_client::ReqwestHttpClient::new(Some(
"/tmp/mapr-cache".to_string(), // TODO make path dynamic
)),
#[cfg(target_arch = "wasm32")]
inner_client: crate::platform::http_client::WHATWGFetchHttpClient::new(),
}
}
pub async fn fetch(&self, coords: &WorldTileCoords) -> Result<Vec<u8>, Error> {
let tile_coords = coords.into_tile(TileAddressingScheme::TMS).unwrap();
self.inner_client
.fetch(
format!(
"https://maps.tuerantuer.org/europe_germany/{z}/{x}/{y}.pbf",
x = tile_coords.x,
y = tile_coords.y,
z = tile_coords.z
)
.as_str(),
)
.await
}
}

View File

@ -1,82 +1,48 @@
use crate::coords::{InnerCoords, Quadkey, WorldCoords, WorldTileCoords, EXTENT, TILE_SIZE};
use crate::io::geometry_index::IndexGeometry;
use crate::io::{LayerTessellateResult, TileIndexResult};
use crate::io::LayerTessellateMessage;
use cgmath::num_traits::Pow;
use std::collections::{btree_map, BTreeMap, HashSet};
#[derive(Default)]
pub struct TileCache {
cache_index: BTreeMap<Quadkey, Vec<LayerTessellateResult>>,
tile_geometry_index: BTreeMap<Quadkey, TileIndexResult>,
cache: BTreeMap<Quadkey, Vec<LayerTessellateMessage>>,
}
impl TileCache {
pub fn new() -> Self {
Self {
cache_index: BTreeMap::new(),
tile_geometry_index: BTreeMap::new(),
cache: BTreeMap::new(),
}
}
pub fn put_tessellation_result(&mut self, result: LayerTessellateResult) {
if let Some(entry) = result
pub fn put_tesselated_layer(&mut self, message: LayerTessellateMessage) {
if let Some(entry) = message
.get_coords()
.build_quad_key()
.map(|key| self.cache_index.entry(key))
.map(|key| self.cache.entry(key))
{
match entry {
btree_map::Entry::Vacant(entry) => {
entry.insert(vec![result]);
entry.insert(vec![message]);
}
btree_map::Entry::Occupied(mut entry) => {
entry.get_mut().push(result);
entry.get_mut().push(message);
}
}
}
}
pub fn put_index_result(&mut self, result: TileIndexResult) {
result
.coords
.build_quad_key()
.and_then(|key| self.tile_geometry_index.insert(key, result));
}
pub fn query_point(
&self,
world_coords: &WorldCoords,
z: u8,
zoom: f64,
) -> Option<Vec<&IndexGeometry<f64>>> {
let world_tile_coords = world_coords.into_world_tile(z, zoom);
if let Some(index) = world_tile_coords
.build_quad_key()
.and_then(|key| self.tile_geometry_index.get(&key))
{
let scale = 2.0.pow(z as f64 - zoom); // TODO deduplicate
let delta_x = world_coords.x / TILE_SIZE * scale - world_tile_coords.x as f64;
let delta_y = world_coords.y / TILE_SIZE * scale - world_tile_coords.y as f64;
let x = delta_x * EXTENT;
let y = delta_y * EXTENT;
Some(index.index.point_query(InnerCoords { x, y }))
} else {
None
}
}
pub fn has_tile(&self, coords: &WorldTileCoords) -> bool {
coords
.build_quad_key()
.and_then(|key| {
self.cache_index.get(&key).and_then(|entries| {
self.cache.get(&key).and_then(|entries| {
if entries.is_empty() {
None
} else if entries.iter().all(|entry| match entry {
LayerTessellateResult::UnavailableLayer { .. } => true,
LayerTessellateResult::TessellatedLayer { .. } => false,
LayerTessellateMessage::UnavailableLayer { .. } => true,
LayerTessellateMessage::TessellatedLayer { .. } => false,
}) {
None
} else {
@ -103,10 +69,10 @@ impl TileCache {
pub fn iter_tessellated_layers_at(
&self,
coords: &WorldTileCoords,
) -> Option<impl Iterator<Item = &LayerTessellateResult> + '_> {
) -> Option<impl Iterator<Item = &LayerTessellateMessage> + '_> {
coords
.build_quad_key()
.and_then(|key| self.cache_index.get(&key))
.and_then(|key| self.cache.get(&key))
.map(|results| results.iter())
}
@ -115,10 +81,7 @@ impl TileCache {
coords: &WorldTileCoords,
layers: &mut HashSet<String>,
) {
if let Some(results) = coords
.build_quad_key()
.and_then(|key| self.cache_index.get(&key))
{
if let Some(results) = coords.build_quad_key().and_then(|key| self.cache.get(&key)) {
let tessellated_set: HashSet<String> = results
.iter()
.map(|tessellated_layer| tessellated_layer.layer_name().to_string())
@ -129,10 +92,7 @@ impl TileCache {
}
pub fn is_layers_missing(&self, coords: &WorldTileCoords, layers: &HashSet<String>) -> bool {
if let Some(results) = coords
.build_quad_key()
.and_then(|key| self.cache_index.get(&key))
{
if let Some(results) = coords.build_quad_key().and_then(|key| self.cache.get(&key)) {
let tessellated_set: HashSet<&str> = results
.iter()
.map(|tessellated_layer| tessellated_layer.layer_name())

View File

@ -17,7 +17,7 @@ pub(crate) mod util;
pub mod benchmarking;
pub use io::scheduler::ScheduleMethod;
pub use platform::scheduler::*;
pub use platform::schedule_method::*;
use style_spec::Style;
pub struct Map {

View File

@ -102,7 +102,7 @@ pub async fn run(
scheduler.try_populate_cache();
input.update_state(state, scheduler.get_tile_cache(), dt);
input.update_state(state, &scheduler, dt);
state.prepare_render_data(&mut scheduler);
match state.render() {
Ok(_) => {}

View File

@ -1,5 +1,5 @@
use crate::io::scheduler::ScheduleMethod;
use crate::platform::scheduler::TokioScheduleMethod;
use crate::platform::schedule_method::TokioScheduleMethod;
use crate::MapBuilder;
pub use std::time::Instant;

View File

@ -1,5 +1,5 @@
use crate::io::scheduler::ScheduleMethod;
use crate::platform::scheduler::TokioScheduleMethod;
use crate::platform::schedule_method::TokioScheduleMethod;
use crate::MapBuilder;
pub use std::time::Instant;

View File

@ -0,0 +1,47 @@
use crate::error::Error;
use reqwest::{Client, StatusCode};
use reqwest_middleware::ClientWithMiddleware;
use reqwest_middleware_cache::managers::CACacheManager;
use reqwest_middleware_cache::{Cache, CacheMode};
pub struct ReqwestHttpClient {
client: ClientWithMiddleware,
}
impl From<reqwest::Error> for Error {
fn from(err: reqwest::Error) -> Self {
Error::Network(err.to_string())
}
}
impl From<reqwest_middleware::Error> for Error {
fn from(err: reqwest_middleware::Error) -> Self {
Error::Network(err.to_string())
}
}
impl ReqwestHttpClient {
/// cache_path: Under which path should we cache requests.
pub fn new(cache_path: Option<String>) -> Self {
let mut builder = reqwest_middleware::ClientBuilder::new(Client::new());
if let Some(cache_path) = cache_path {
builder = builder.with(Cache {
mode: CacheMode::Default,
cache_manager: CACacheManager { path: cache_path },
});
}
Self {
client: builder.build(),
}
}
pub async fn fetch(&self, url: &str) -> Result<Vec<u8>, Error> {
let response = self.client.get(url).send().await?;
if response.status() != StatusCode::OK {
return Err(Error::Network("response code not 200".to_string()));
}
let body = response.bytes().await?;
Ok(Vec::from(body.as_ref()))
}
}

View File

@ -1,89 +1,6 @@
//! Module which is used target platform is not web related.
pub mod http_client;
pub mod schedule_method;
pub use std::time::Instant;
pub mod scheduler {
use reqwest::{Client, StatusCode};
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
use reqwest_middleware_cache::managers::CACacheManager;
use reqwest_middleware_cache::{Cache, CacheMode};
use crate::coords::TileCoords;
use crate::error::Error;
use crate::io::scheduler::IOScheduler;
use crate::io::TileRequestID;
impl From<reqwest::Error> for Error {
fn from(err: reqwest::Error) -> Self {
Error::Network(err.to_string())
}
}
impl From<reqwest_middleware::Error> for Error {
fn from(err: reqwest_middleware::Error) -> Self {
Error::Network(err.to_string())
}
}
pub struct TokioScheduleMethod {
client: ClientWithMiddleware,
}
impl TokioScheduleMethod {
/// cache_path: Under which path should we cache requests.
pub fn new(cache_path: Option<String>) -> Self {
let mut builder = ClientBuilder::new(Client::new());
if let Some(cache_path) = cache_path {
builder = builder.with(Cache {
mode: CacheMode::Default,
cache_manager: CACacheManager { path: cache_path },
});
}
Self {
client: builder.build(),
}
}
async fn fetch(client: &ClientWithMiddleware, url: &str) -> Result<Vec<u8>, Error> {
let response = client.get(url).send().await?;
if response.status() != StatusCode::OK {
return Err(Error::Network("response code not 200".to_string()));
}
let body = response.bytes().await?;
Ok(Vec::from(body.as_ref()))
}
pub fn schedule_tile_request(
&self,
scheduler: &IOScheduler,
request_id: TileRequestID,
coords: TileCoords,
) {
let state = scheduler.new_tessellator_state();
let client = self.client.clone();
tokio::task::spawn(async move {
if let Ok(data) = Self::fetch(
&client,
format!(
"https://maps.tuerantuer.org/europe_germany/{z}/{x}/{y}.pbf",
x = coords.x,
y = coords.y,
z = coords.z
)
.as_str(),
)
.await
{
state
.process_tile(request_id, data.into_boxed_slice())
.unwrap();
} else {
state.tile_unavailable(request_id).unwrap();
}
});
}
}
}

View File

@ -0,0 +1,26 @@
use reqwest::{Client, StatusCode};
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
use reqwest_middleware_cache::managers::CACacheManager;
use reqwest_middleware_cache::{Cache, CacheMode};
use std::future::Future;
use crate::coords::TileCoords;
use crate::error::Error;
use crate::io::scheduler::IOScheduler;
use crate::io::TileRequestID;
pub struct TokioScheduleMethod;
impl TokioScheduleMethod {
pub fn new() -> Self {
Self {}
}
pub fn schedule<T>(&self, future: T)
where
T: Future<Output = ()> + Send + 'static,
{
tokio::task::spawn(future);
}
}

View File

@ -0,0 +1,69 @@
use std::thread::Thread;
use log::warn;
use js_sys::{ArrayBuffer, Error as JSError, Uint8Array};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::Worker;
use web_sys::{Request, RequestInit, RequestMode, Response, WorkerGlobalScope};
use crate::coords::{TileCoords, WorldTileCoords};
use crate::error::Error;
use crate::io::scheduler::{IOScheduler, ScheduleMethod, ThreadLocalTessellatorState};
use crate::io::tile_cache::TileCache;
use crate::io::TileRequestID;
use super::pool::WorkerPool;
pub struct WHATWGFetchHttpClient {}
impl From<JsValue> for Error {
fn from(maybe_error: JsValue) -> Self {
assert!(maybe_error.is_instance_of::<JSError>());
let error: JSError = maybe_error.dyn_into().unwrap();
Error::Network(error.message().as_string().unwrap())
}
}
impl WHATWGFetchHttpClient {
pub fn new() -> Self {
Self {}
}
pub async fn fetch(&self, url: &str) -> Result<Vec<u8>, Error> {
let maybe_array_buffer = Self::whatwg_fetch(url).await?;
assert!(maybe_array_buffer.is_instance_of::<ArrayBuffer>());
let array_buffer: ArrayBuffer = maybe_array_buffer.dyn_into().unwrap();
// Copy data to Vec<u8>
let buffer: Uint8Array = Uint8Array::new(&array_buffer);
let mut output: Vec<u8> = vec![0; array_buffer.byte_length() as usize];
buffer.copy_to(output.as_mut_slice());
Ok(output)
}
async fn whatwg_fetch(url: &str) -> Result<JsValue, JsValue> {
let mut opts = RequestInit::new();
opts.method("GET");
let request = Request::new_with_str_and_init(&url, &opts)?;
// Get the global scope
let global = js_sys::global();
assert!(global.is_instance_of::<WorkerGlobalScope>());
let scope = global.dyn_into::<WorkerGlobalScope>().unwrap();
// Call fetch on global scope
let maybe_response = JsFuture::from(scope.fetch_with_request(&request)).await?;
assert!(maybe_response.is_instance_of::<Response>());
let response: Response = maybe_response.dyn_into().unwrap();
// Get ArrayBuffer
let maybe_array_buffer = JsFuture::from(response.array_buffer()?).await?;
Ok(maybe_array_buffer)
}
}

View File

@ -0,0 +1,77 @@
use std::panic;
use std::thread::Thread;
use log::error;
use log::info;
use log::warn;
use log::Level;
use winit::dpi::LogicalSize;
use winit::event_loop::EventLoop;
use winit::platform::web::WindowBuilderExtWebSys;
use winit::window::{Window, WindowBuilder};
use super::schedule_method::WebWorkerPoolScheduleMethod;
use console_error_panic_hook;
pub use instant::Instant;
use js_sys::{ArrayBuffer, Error as JSError, Uint8Array};
use style_spec::source::TileAddressingScheme;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::Window as WebSysWindow;
use web_sys::Worker;
use web_sys::{Request, RequestInit, RequestMode, Response, WorkerGlobalScope};
use crate::coords::{TileCoords, WorldTileCoords};
use crate::error::Error;
use crate::io::scheduler::IOScheduler;
use crate::io::scheduler::ScheduleMethod;
use crate::io::scheduler::ThreadLocalTessellatorState;
use crate::io::tile_cache::TileCache;
use crate::io::TileRequestID;
use crate::MapBuilder;
use super::pool::WorkerPool;
#[wasm_bindgen]
extern "C" {
fn schedule_tile_request(url: &str, request_id: u32);
}
#[wasm_bindgen]
pub fn new_tessellator_state(scheduler_ptr: *mut IOScheduler) -> *mut ThreadLocalTessellatorState {
let scheduler: Box<IOScheduler> = unsafe { Box::from_raw(scheduler_ptr) };
let tessellator_state = Box::new(scheduler.new_tessellator_state());
let tessellator_state_ptr = Box::into_raw(tessellator_state);
// Call forget such that scheduler does not get deallocated
std::mem::forget(scheduler);
return tessellator_state_ptr;
}
#[wasm_bindgen]
pub fn tessellate_layers(
tessellator_state_ptr: *mut ThreadLocalTessellatorState,
request_id: u32,
data: Box<[u8]>,
) {
let tessellator_state: Box<ThreadLocalTessellatorState> =
unsafe { Box::from_raw(tessellator_state_ptr) };
tessellator_state.process_tile(request_id, data).unwrap();
// Call forget such that scheduler does not get deallocated
std::mem::forget(tessellator_state);
}
pub fn request_tile(request_id: TileRequestID, coords: TileCoords) {
schedule_tile_request(
format!(
"https://maps.tuerantuer.org/europe_germany/{z}/{x}/{y}.pbf",
x = coords.x,
y = coords.y,
z = coords.z,
)
.as_str(),
request_id,
)
}

View File

@ -1,5 +1,3 @@
mod pool;
use std::panic;
use log::error;
@ -10,14 +8,9 @@ use winit::event_loop::EventLoop;
use winit::platform::web::WindowBuilderExtWebSys;
use winit::window::{Window, WindowBuilder};
use crate::io::scheduler::IOScheduler;
use crate::io::scheduler::ScheduleMethod;
use crate::io::scheduler::ThreadLocalTessellatorState;
use crate::MapBuilder;
use console_error_panic_hook;
pub use instant::Instant;
use scheduler::WebWorkerPoolScheduleMethod;
use scheduler::WebWorkerScheduleMethod;
use schedule_method::WebWorkerPoolScheduleMethod;
use style_spec::source::TileAddressingScheme;
use wasm_bindgen::prelude::*;
use wasm_bindgen::prelude::*;
@ -25,6 +18,16 @@ use wasm_bindgen::JsCast;
use web_sys::Window as WebSysWindow;
use web_sys::Worker;
use crate::io::scheduler::IOScheduler;
use crate::io::scheduler::ScheduleMethod;
use crate::io::scheduler::ThreadLocalTessellatorState;
use crate::MapBuilder;
pub mod http_client;
pub mod legacy_webworker_fetcher;
mod pool;
pub mod schedule_method;
// WebGPU
#[cfg(not(feature = "web-webgl"))]
pub const COLOR_TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8Unorm;
@ -41,15 +44,6 @@ pub fn wasm_bindgen_start() {
panic::set_hook(Box::new(console_error_panic_hook::hook));
}
#[wasm_bindgen]
pub fn create_scheduler() -> *mut IOScheduler {
let scheduler = Box::new(IOScheduler::new(ScheduleMethod::WebWorker(
WebWorkerScheduleMethod::new(),
)));
let scheduler_ptr = Box::into_raw(scheduler);
return scheduler_ptr;
}
#[wasm_bindgen]
pub fn create_pool_scheduler(new_worker: js_sys::Function) -> *mut IOScheduler {
let scheduler = Box::new(IOScheduler::new(ScheduleMethod::WebWorkerPool(
@ -92,167 +86,3 @@ pub async fn run(scheduler_ptr: *mut IOScheduler) {
// std::mem::forget(scheduler);
}
pub mod scheduler {
use super::pool::WorkerPool;
use crate::coords::{TileCoords, WorldTileCoords};
use crate::error::Error;
use crate::io::scheduler::{IOScheduler, ScheduleMethod, ThreadLocalTessellatorState};
use crate::io::tile_cache::TileCache;
use crate::io::TileRequestID;
use js_sys::{ArrayBuffer, Error as JSError, Uint8Array};
use log::warn;
use std::thread::Thread;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::Worker;
use web_sys::{Request, RequestInit, RequestMode, Response, WorkerGlobalScope};
#[wasm_bindgen]
extern "C" {
pub fn schedule_tile_request(url: &str, request_id: u32);
}
#[wasm_bindgen]
pub fn new_tessellator_state(
scheduler_ptr: *mut IOScheduler,
) -> *mut ThreadLocalTessellatorState {
let scheduler: Box<IOScheduler> = unsafe { Box::from_raw(scheduler_ptr) };
let tessellator_state = Box::new(scheduler.new_tessellator_state());
let tessellator_state_ptr = Box::into_raw(tessellator_state);
// Call forget such that scheduler does not get deallocated
std::mem::forget(scheduler);
return tessellator_state_ptr;
}
#[wasm_bindgen]
pub fn tessellate_layers(
tessellator_state_ptr: *mut ThreadLocalTessellatorState,
request_id: u32,
data: Box<[u8]>,
) {
let tessellator_state: Box<ThreadLocalTessellatorState> =
unsafe { Box::from_raw(tessellator_state_ptr) };
tessellator_state.process_tile(request_id, data).unwrap();
// Call forget such that scheduler does not get deallocated
std::mem::forget(tessellator_state);
}
pub struct WebWorkerScheduleMethod;
impl WebWorkerScheduleMethod {
pub fn new() -> Self {
Self
}
pub fn schedule_tile_request(
&self,
_scheduler: &IOScheduler,
request_id: TileRequestID,
coords: TileCoords,
) {
schedule_tile_request(
format!(
"https://maps.tuerantuer.org/europe_germany/{z}/{x}/{y}.pbf",
x = coords.x,
y = coords.y,
z = coords.z,
)
.as_str(),
request_id,
)
}
}
impl From<JsValue> for Error {
fn from(maybe_error: JsValue) -> Self {
assert!(maybe_error.is_instance_of::<JSError>());
let error: JSError = maybe_error.dyn_into().unwrap();
Error::Network(error.message().as_string().unwrap())
}
}
pub struct WebWorkerPoolScheduleMethod {
pool: WorkerPool,
}
impl WebWorkerPoolScheduleMethod {
pub fn new(new_worker: js_sys::Function) -> Self {
Self {
pool: WorkerPool::new(
4,
Box::new(move || {
new_worker
.call0(&JsValue::undefined())
.unwrap()
.dyn_into::<Worker>()
.unwrap()
}),
)
.unwrap(),
}
}
async fn fetch(url: &str) -> Result<JsValue, JsValue> {
let mut opts = RequestInit::new();
opts.method("GET");
let request = Request::new_with_str_and_init(&url, &opts)?;
// Get the global scope
let global = js_sys::global();
assert!(global.is_instance_of::<WorkerGlobalScope>());
let scope = global.dyn_into::<WorkerGlobalScope>().unwrap();
// Call fetch on global scope
let maybe_response = JsFuture::from(scope.fetch_with_request(&request)).await?;
assert!(maybe_response.is_instance_of::<Response>());
let response: Response = maybe_response.dyn_into().unwrap();
// Get ArrayBuffer
let maybe_array_buffer = JsFuture::from(response.array_buffer()?).await?;
Ok(maybe_array_buffer)
}
pub fn schedule_tile_request(
&self,
scheduler: &IOScheduler,
request_id: TileRequestID,
coords: TileCoords,
) {
let state = scheduler.new_tessellator_state();
self.pool
.run(move || {
wasm_bindgen_futures::future_to_promise(async move {
let string = format!(
"https://maps.tuerantuer.org/europe_germany/{z}/{x}/{y}.pbf",
x = coords.x,
y = coords.y,
z = coords.z,
);
if let Ok(maybe_array_buffer) = Self::fetch(string.as_str()).await {
assert!(maybe_array_buffer.is_instance_of::<ArrayBuffer>());
let array_buffer: ArrayBuffer = maybe_array_buffer.dyn_into().unwrap();
// Copy data to Vec<u8>
let buffer: Uint8Array = Uint8Array::new(&array_buffer);
let mut output: Vec<u8> = vec![0; array_buffer.byte_length() as usize];
buffer.copy_to(output.as_mut_slice());
state
.process_tile(request_id, output.into_boxed_slice())
.unwrap();
} else {
state.tile_unavailable(request_id).unwrap();
}
Ok(JsValue::undefined())
})
})
.unwrap();
}
}
}

View File

@ -2,11 +2,13 @@
//! web workers which can be used to execute work.
//! Adopted from [wasm-bindgen example](https://github.com/rustwasm/wasm-bindgen/blob/0eba2efe45801b71f8873bc368c58a8ed8e894ff/examples/raytrace-parallel/src/pool.rs)
use js_sys::Promise;
use log::{info, warn};
use std::cell::RefCell;
use std::future::Future;
use std::rc::Rc;
use log::{info, warn};
use js_sys::Promise;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;

View File

@ -0,0 +1,55 @@
use std::thread::Thread;
use log::warn;
use js_sys::{ArrayBuffer, Error as JSError, Uint8Array};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::Worker;
use web_sys::{Request, RequestInit, RequestMode, Response, WorkerGlobalScope};
use crate::coords::{TileCoords, WorldTileCoords};
use crate::error::Error;
use crate::io::scheduler::{IOScheduler, ScheduleMethod, ThreadLocalTessellatorState};
use crate::io::tile_cache::TileCache;
use crate::io::TileRequestID;
use super::pool::WorkerPool;
pub struct WebWorkerPoolScheduleMethod {
pool: WorkerPool,
}
impl WebWorkerPoolScheduleMethod {
pub fn new(new_worker: js_sys::Function) -> Self {
Self {
pool: WorkerPool::new(
4,
Box::new(move || {
new_worker
.call0(&JsValue::undefined())
.unwrap()
.dyn_into::<Worker>()
.unwrap()
}),
)
.unwrap(),
}
}
pub fn schedule<T>(&self, future_factory: impl (FnOnce() -> T) + Send + 'static)
where
T: std::future::Future + 'static,
T::Output: Send + 'static,
{
self.pool
.run(move || {
wasm_bindgen_futures::future_to_promise(async move {
future_factory().await;
Ok(JsValue::undefined())
})
})
.unwrap();
}
}

View File

@ -12,7 +12,7 @@ use style_spec::Style;
use crate::coords::{ViewRegion, TILE_SIZE};
use crate::io::scheduler::IOScheduler;
use crate::io::LayerTessellateResult;
use crate::io::LayerTessellateMessage;
use crate::platform::{COLOR_TEXTURE_FORMAT, MIN_BUFFER_SIZE};
use crate::render::buffer_pool::{BackingBufferDescriptor, BufferPool, IndexEntry};
use crate::render::camera;
@ -487,7 +487,7 @@ impl RenderState {
for style_layer in &self.style.layers {
let source_layer = style_layer.source_layer.as_ref().unwrap();
if let Some(result) = available_layers
if let Some(message) = available_layers
.iter()
.find(|layer| source_layer.as_str() == layer.layer_name())
{
@ -497,11 +497,11 @@ impl RenderState {
.and_then(|paint| paint.get_color())
.map(|color| color.into());
match result {
LayerTessellateResult::UnavailableLayer { coords: _, .. } => {
match message {
LayerTessellateMessage::UnavailableLayer { coords: _, .. } => {
/*self.buffer_pool.mark_layer_unavailable(*coords);*/
}
LayerTessellateResult::TessellatedLayer {
LayerTessellateMessage::TessellatedLayer {
coords,
feature_indices,
layer_data,

View File

@ -1,4 +1,4 @@
import init, {create_pool_scheduler, create_scheduler, new_tessellator_state, run} from "./dist/libs/mapr"
import init, {create_pool_scheduler, new_tessellator_state, run} from "./dist/libs/mapr"
import {Spector} from "spectorjs"
import {WebWorkerMessageType} from "./types"
@ -72,28 +72,7 @@ const registerServiceWorker = () => {
}
}
const start = async () => {
if (!checkRequirements()) {
return
}
registerServiceWorker()
preventDefaultTouchActions();
let MEMORY_PAGES = 16 * 1024
const memory = new WebAssembly.Memory({initial: 1024, maximum: MEMORY_PAGES, shared: true})
await init(undefined, memory)
/*const schedulerPtr = create_pool_scheduler(() => {
return new Worker(new URL('./pool_worker.ts', import.meta.url), {
type: 'module'
});
})*/
const schedulerPtr = create_scheduler()
const setupLegacyWebWorker = (schedulerPtr: number, memory: WebAssembly.Memory) => {
let WORKER_COUNT = 4
const createWorker = (id: number) => {
const worker = new Worker(new URL('./worker.ts', import.meta.url), {
@ -119,6 +98,28 @@ const start = async () => {
request_id
} as WebWorkerMessageType)
}
}
const start = async () => {
if (!checkRequirements()) {
return
}
registerServiceWorker()
preventDefaultTouchActions();
let MEMORY_PAGES = 16 * 1024
const memory = new WebAssembly.Memory({initial: 1024, maximum: MEMORY_PAGES, shared: true})
await init(undefined, memory)
const schedulerPtr = create_pool_scheduler(() => {
return new Worker(new URL('./pool_worker.ts', import.meta.url), {
type: 'module'
});
})
setupLegacyWebWorker(schedulerPtr, memory)
await run(schedulerPtr)
}