mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Add a pool which can tesselate in a separate thread
This commit is contained in:
parent
0316991558
commit
45fa50962e
@ -1,3 +1,4 @@
|
||||
use mapr::io::pool::Pool;
|
||||
use mapr::main_loop;
|
||||
use winit::event_loop::EventLoop;
|
||||
use winit::window::WindowBuilder;
|
||||
@ -11,5 +12,12 @@ fn main() {
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
|
||||
pollster::block_on(main_loop::setup(window, event_loop));
|
||||
let io_tile_pool = Pool::new();
|
||||
let main_tile_pool = io_tile_pool.clone();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
io_tile_pool.run_loop();
|
||||
});
|
||||
|
||||
pollster::block_on(main_loop::setup(window, event_loop, main_tile_pool));
|
||||
}
|
||||
|
||||
@ -1 +1,25 @@
|
||||
pub mod pool;
|
||||
pub mod static_database;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct TileCoords {
|
||||
pub x: u32,
|
||||
pub y: u32,
|
||||
pub z: u8,
|
||||
}
|
||||
|
||||
impl TileCoords {
|
||||
fn hash(&self) -> u32 {
|
||||
self.x + self.y + self.z as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TileCoords> for (u32, u32, u8) {
|
||||
fn into(self) -> TileCoords {
|
||||
TileCoords {
|
||||
x: self.0,
|
||||
y: self.1,
|
||||
z: self.2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
104
src/io/pool.rs
Normal file
104
src/io/pool.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use crate::io::{static_database, TileCoords};
|
||||
use crate::render::shader_ffi::GpuVertexUniform;
|
||||
use crate::tesselation::{IndexDataType, Tesselated};
|
||||
use lyon::tessellation::VertexBuffers;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::Cursor;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vector_tile::parse_tile_reader;
|
||||
use vector_tile::tile::Tile;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TesselatedTile {
|
||||
coords: TileCoords,
|
||||
geometry: VertexBuffers<GpuVertexUniform, IndexDataType>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Pool {
|
||||
requests: WorkQueue<TileCoords>,
|
||||
responses: WorkQueue<TesselatedTile>,
|
||||
}
|
||||
|
||||
impl Pool {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
requests: WorkQueue::new(),
|
||||
responses: WorkQueue::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch(&self, coords: TileCoords) {
|
||||
self.requests.push(coords);
|
||||
}
|
||||
|
||||
pub fn get_available(&self) -> Vec<TesselatedTile> {
|
||||
self.responses.pop_all()
|
||||
}
|
||||
|
||||
pub fn run_loop(&self) {
|
||||
while let Some(coords) = self.requests.pop() {
|
||||
if let Some(file) = static_database::get_tile(&coords) {
|
||||
let tile = parse_tile_reader(&mut Cursor::new(file.contents()))
|
||||
.expect("failed to load tile");
|
||||
let mut geometry: VertexBuffers<GpuVertexUniform, IndexDataType> =
|
||||
VertexBuffers::new();
|
||||
|
||||
let (_tile_stroke_range, _tile_fill_range) = {
|
||||
(
|
||||
tile.tesselate_stroke(&mut geometry, coords.hash()),
|
||||
tile.tesselate_fill(&mut geometry, coords.hash()),
|
||||
)
|
||||
};
|
||||
self.responses.push(TesselatedTile { coords, geometry });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct WorkQueue<T: Send> {
|
||||
inner: Arc<Mutex<VecDeque<T>>>,
|
||||
}
|
||||
|
||||
impl<T: Send> WorkQueue<T> {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(VecDeque::new())),
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_all(&self) -> Vec<T> {
|
||||
let mut result = Vec::new();
|
||||
if let Ok(mut queue) = self.inner.lock() {
|
||||
while let Some(element) = queue.pop_front() {
|
||||
result.push(element);
|
||||
}
|
||||
} else {
|
||||
panic!("locking failed");
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn try_pop(&self) -> Option<T> {
|
||||
let mut queue = self.inner.try_lock().ok()?;
|
||||
queue.pop_front()
|
||||
}
|
||||
|
||||
fn pop(&self) -> Option<T> {
|
||||
if let Ok(mut queue) = self.inner.lock() {
|
||||
queue.pop_front()
|
||||
} else {
|
||||
panic!("locking failed");
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&self, work: T) -> usize {
|
||||
if let Ok(mut queue) = self.inner.lock() {
|
||||
queue.push_back(work);
|
||||
queue.len()
|
||||
} else {
|
||||
panic!("locking failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
use std::concat;
|
||||
use std::env;
|
||||
|
||||
use crate::io::TileCoords;
|
||||
use include_dir::{include_dir, Dir, File};
|
||||
|
||||
static TILES: Dir = include_dir!("$OUT_DIR/extracted-tiles");
|
||||
@ -9,8 +10,8 @@ pub fn get_source_path() -> &'static str {
|
||||
concat!(env!("OUT_DIR"), "/extracted-tiles")
|
||||
}
|
||||
|
||||
pub fn get_tile(x: u32, y: u32, z: u32) -> Option<&'static File<'static>> {
|
||||
TILES.get_file(format!("{}/{}/{}.{}", z, x, y, "pbf"))
|
||||
pub fn get_tile(coords: &TileCoords) -> Option<&'static File<'static>> {
|
||||
TILES.get_file(format!("{}/{}/{}.{}", coords.z, coords.x, coords.y, "pbf"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -19,7 +20,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_tiles_available() {
|
||||
assert!(get_tile(0, 0, 0).is_none()); // World overview
|
||||
assert!(get_tile(2179, 1421, 12).is_some()); // Maxvorstadt Munich
|
||||
assert!(get_tile((0, 0, 0).into()).is_none()); // World overview
|
||||
assert!(get_tile((2179, 1421, 12).into()).is_some()); // Maxvorstadt Munich
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,12 +3,15 @@ use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEve
|
||||
use winit::event_loop::{ControlFlow, EventLoop};
|
||||
|
||||
use crate::input::InputHandler;
|
||||
use crate::io::pool::Pool;
|
||||
use crate::platform::Instant;
|
||||
use crate::render::state::State;
|
||||
|
||||
pub async fn setup(window: winit::window::Window, event_loop: EventLoop<()>) {
|
||||
pub async fn setup(window: winit::window::Window, event_loop: EventLoop<()>, pool: Pool) {
|
||||
info!("== mapr ==");
|
||||
|
||||
pool.fetch((2179, 1421, 12).into());
|
||||
|
||||
let mut input = InputHandler::new();
|
||||
let mut state = State::new(&window).await;
|
||||
|
||||
@ -55,7 +58,7 @@ pub async fn setup(window: winit::window::Window, event_loop: EventLoop<()>) {
|
||||
let now = Instant::now();
|
||||
let dt = now - last_render_time;
|
||||
last_render_time = now;
|
||||
input.update_state( &mut state, dt);
|
||||
input.update_state(&mut state, dt);
|
||||
match state.render() {
|
||||
Ok(_) => {}
|
||||
// Reconfigure the surface if lost
|
||||
|
||||
@ -19,7 +19,7 @@ use crate::io::static_database;
|
||||
use crate::platform::{COLOR_TEXTURE_FORMAT, MIN_BUFFER_SIZE};
|
||||
use crate::render::{camera, shaders};
|
||||
use crate::tesselation::tile_mask::TileMask;
|
||||
use crate::tesselation::Tesselated;
|
||||
use crate::tesselation::{IndexDataType, Tesselated};
|
||||
use crate::util::measure::Measure;
|
||||
|
||||
use super::piplines::*;
|
||||
@ -89,7 +89,7 @@ pub struct State {
|
||||
tile_mask_range: Range<u32>,
|
||||
tile_mask_instances: wgpu::Buffer,
|
||||
|
||||
pub(crate) camera: camera::Camera,
|
||||
pub camera: camera::Camera,
|
||||
projection: camera::Projection,
|
||||
|
||||
pub scene: SceneParams,
|
||||
@ -153,7 +153,7 @@ impl State {
|
||||
);
|
||||
|
||||
let tile = parse_tile_reader(&mut Cursor::new(
|
||||
static_database::get_tile(2179, 1421, 12)
|
||||
static_database::get_tile(&(2179, 1421, 12).into())
|
||||
.unwrap()
|
||||
.contents(),
|
||||
))
|
||||
@ -172,7 +172,7 @@ impl State {
|
||||
|
||||
// tile right to it
|
||||
let tile = parse_tile_reader(&mut Cursor::new(
|
||||
static_database::get_tile(2180, 1421, 12)
|
||||
static_database::get_tile(&(2180, 1421, 12).into())
|
||||
.unwrap()
|
||||
.contents(),
|
||||
))
|
||||
|
||||
@ -10,6 +10,8 @@ use std::ops::Range;
|
||||
|
||||
const DEFAULT_TOLERANCE: f32 = 0.02;
|
||||
|
||||
pub type IndexDataType = u32; // Must match INDEX_FORMAT
|
||||
|
||||
pub trait Tesselated<OutputIndex: std::ops::Add> {
|
||||
fn tesselate_stroke(
|
||||
&self,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user