mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Asynchronously render tiles
This commit is contained in:
parent
b863d12992
commit
8c99a58fca
@ -14,8 +14,8 @@ use crate::tesselation::{IndexDataType, Tesselated};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TesselatedTile {
|
||||
coords: TileCoords,
|
||||
geometry: VertexBuffers<GpuVertexUniform, IndexDataType>,
|
||||
pub coords: TileCoords,
|
||||
pub geometry: VertexBuffers<GpuVertexUniform, IndexDataType>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -50,12 +50,7 @@ impl Pool {
|
||||
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()),
|
||||
)
|
||||
};
|
||||
tile.tesselate_stroke(&mut geometry, 1);
|
||||
self.responses.push(TesselatedTile { coords, geometry });
|
||||
info!("tile ready: {:?}", &coords);
|
||||
} else {
|
||||
|
||||
@ -10,8 +10,8 @@ use crate::render::state::State;
|
||||
pub async fn setup(window: winit::window::Window, event_loop: EventLoop<()>, pool: Pool) {
|
||||
info!("== mapr ==");
|
||||
|
||||
for x in 0..10 {
|
||||
for y in 0..10 {
|
||||
for x in 0..2 {
|
||||
for y in 0..2 {
|
||||
pool.fetch((2179 + x, 1421 + y, 12).into())
|
||||
}
|
||||
}
|
||||
@ -63,6 +63,7 @@ pub async fn setup(window: winit::window::Window, event_loop: EventLoop<()>, poo
|
||||
let dt = now - last_render_time;
|
||||
last_render_time = now;
|
||||
input.update_state(&mut state, dt);
|
||||
state.update(&pool);
|
||||
match state.render() {
|
||||
Ok(_) => {}
|
||||
// Reconfigure the surface if lost
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use std::any::Any;
|
||||
use std::collections::vec_deque::Iter;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
@ -12,13 +13,13 @@ use crate::render::shader_ffi::GpuVertexUniform;
|
||||
use crate::tesselation::IndexDataType;
|
||||
|
||||
/// Buffer and its size
|
||||
pub struct BackingBufferDescriptor<B>(B, wgpu::BufferAddress);
|
||||
pub struct BackingBufferDescriptor<B>(pub B, pub wgpu::BufferAddress);
|
||||
|
||||
pub trait WriteableQueue<B> {
|
||||
trait Queue<B> {
|
||||
fn write_buffer(&self, buffer: &B, offset: wgpu::BufferAddress, data: &[u8]);
|
||||
}
|
||||
|
||||
impl WriteableQueue<wgpu::Buffer> for wgpu::Queue {
|
||||
impl Queue<wgpu::Buffer> for wgpu::Queue {
|
||||
fn write_buffer(&self, buffer: &wgpu::Buffer, offset: wgpu::BufferAddress, data: &[u8]) {
|
||||
self.write_buffer(buffer, offset, data)
|
||||
}
|
||||
@ -29,13 +30,13 @@ pub struct BufferPool<Q, B, V, I> {
|
||||
vertices: BackingBuffer<B>,
|
||||
indices: BackingBuffer<B>,
|
||||
|
||||
index: VecDeque<IndexEntry>,
|
||||
pub index: VecDeque<IndexEntry>,
|
||||
phantom_v: PhantomData<V>,
|
||||
phantom_i: PhantomData<I>,
|
||||
phantom_q: PhantomData<Q>,
|
||||
}
|
||||
|
||||
impl<Q: WriteableQueue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod> BufferPool<Q, B, V, I> {
|
||||
impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod> BufferPool<Q, B, V, I> {
|
||||
pub fn new(vertices: BackingBufferDescriptor<B>, indices: BackingBufferDescriptor<B>) -> Self {
|
||||
Self {
|
||||
vertices: BackingBuffer::new(vertices.0, vertices.1),
|
||||
@ -51,14 +52,29 @@ impl<Q: WriteableQueue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod> BufferPool<Q,
|
||||
let gap = self.vertices.find_gap(&self.index, vertices);
|
||||
gap.end - gap.start
|
||||
}
|
||||
pub fn vertices(&self) -> &B {
|
||||
&self.vertices.inner
|
||||
}
|
||||
|
||||
pub fn indices(&self) -> &B {
|
||||
&self.indices.inner
|
||||
}
|
||||
|
||||
/// Allocates `buffer` and uploads it to the GPU
|
||||
pub fn allocate_buffer(&mut self, queue: &Q, coords: TileCoords, data: &VertexBuffers<V, I>) {
|
||||
let new_vertices = (data.vertices.len() * size_of::<V>()) as wgpu::BufferAddress;
|
||||
let new_indices = (data.indices.len() * size_of::<I>()) as wgpu::BufferAddress;
|
||||
pub fn allocate_geometry(
|
||||
&mut self,
|
||||
queue: &Q,
|
||||
coords: TileCoords,
|
||||
geometry: &VertexBuffers<V, I>,
|
||||
) {
|
||||
let vertices_stride = size_of::<V>();
|
||||
let new_vertices = (geometry.vertices.len() * vertices_stride) as wgpu::BufferAddress;
|
||||
let indices_stride = size_of::<I>();
|
||||
let new_indices = (geometry.indices.len() * indices_stride) as wgpu::BufferAddress;
|
||||
|
||||
let maybe_entry = IndexEntry {
|
||||
coords,
|
||||
indices_stride: indices_stride as u64,
|
||||
vertices: self.vertices.make_room(new_vertices, &mut self.index, true),
|
||||
indices: self.indices.make_room(new_indices, &mut self.index, false),
|
||||
};
|
||||
@ -75,18 +91,18 @@ impl<Q: WriteableQueue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod> BufferPool<Q,
|
||||
queue.write_buffer(
|
||||
&self.vertices.inner,
|
||||
maybe_entry.vertices.start,
|
||||
bytemuck::cast_slice(&data.vertices),
|
||||
bytemuck::cast_slice(&geometry.vertices),
|
||||
);
|
||||
queue.write_buffer(
|
||||
&self.indices.inner,
|
||||
maybe_entry.indices.start,
|
||||
bytemuck::cast_slice(&data.indices),
|
||||
bytemuck::cast_slice(&geometry.indices),
|
||||
);
|
||||
self.index.push_back(maybe_entry);
|
||||
}
|
||||
|
||||
pub fn draw(&self) {
|
||||
for entry in &self.index {}
|
||||
pub fn available_vertices(&self) -> Iter<'_, IndexEntry> {
|
||||
self.index.iter()
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,13 +139,7 @@ impl<B> BackingBuffer<B> {
|
||||
|
||||
while new_data > available_gap.end - available_gap.start {
|
||||
// no more space, we need to evict items
|
||||
if let Some(evicted) = index.pop_front() {
|
||||
/* self.inner_offset = if vertices {
|
||||
evicted.vertices
|
||||
} else {
|
||||
evicted.indices
|
||||
}
|
||||
.start;*/
|
||||
if let Some(_) = index.pop_front() {
|
||||
available_gap = self.find_gap(index, vertices);
|
||||
} else {
|
||||
panic!("evicted even though index is empty")
|
||||
@ -171,20 +181,33 @@ impl<B> BackingBuffer<B> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct IndexEntry {
|
||||
coords: TileCoords,
|
||||
pub struct IndexEntry {
|
||||
pub coords: TileCoords,
|
||||
indices_stride: u64,
|
||||
vertices: Range<wgpu::BufferAddress>,
|
||||
indices: Range<wgpu::BufferAddress>,
|
||||
}
|
||||
|
||||
impl IndexEntry {}
|
||||
impl IndexEntry {
|
||||
pub fn indices_range(&self) -> Range<u32> {
|
||||
0..((self.indices.end - self.indices.start) / self.indices_stride) as u32
|
||||
}
|
||||
|
||||
pub fn indices_buffer_range(&self) -> Range<wgpu::BufferAddress> {
|
||||
self.indices.clone()
|
||||
}
|
||||
|
||||
pub fn vertices_buffer_range(&self) -> Range<wgpu::BufferAddress> {
|
||||
self.vertices.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use lyon::tessellation::VertexBuffers;
|
||||
use wgpu::BufferAddress;
|
||||
|
||||
use crate::render::buffer_pool::{BackingBufferDescriptor, BufferPool, WriteableQueue};
|
||||
use crate::render::buffer_pool::{BackingBufferDescriptor, BufferPool, Queue};
|
||||
use crate::render::shader_ffi::GpuVertexUniform;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -193,7 +216,7 @@ mod tests {
|
||||
}
|
||||
struct TestQueue;
|
||||
|
||||
impl WriteableQueue<TestBuffer> for TestQueue {
|
||||
impl Queue<TestBuffer> for TestQueue {
|
||||
fn write_buffer(&self, buffer: &TestBuffer, offset: BufferAddress, data: &[u8]) {
|
||||
if offset + data.len() as BufferAddress > buffer.size {
|
||||
panic!("write out of bounds");
|
||||
@ -222,7 +245,7 @@ mod tests {
|
||||
data.vertices.append(&mut create_48byte());
|
||||
data.indices.append(&mut vec![1, 2, 3, 4]);
|
||||
for i in 0..2 {
|
||||
pool.allocate_buffer(&queue, (0, 0, 0).into(), &data);
|
||||
pool.allocate_geometry(&queue, (0, 0, 0).into(), &data);
|
||||
}
|
||||
|
||||
assert_eq!(128 - 2 * 48, pool.available_space(true));
|
||||
@ -230,9 +253,9 @@ mod tests {
|
||||
let mut data = VertexBuffers::new();
|
||||
data.vertices.append(&mut create_24byte());
|
||||
data.indices.append(&mut vec![1, 2, 3, 4]);
|
||||
pool.allocate_buffer(&queue, (0, 0, 0).into(), &data);
|
||||
pool.allocate_geometry(&queue, (0, 0, 0).into(), &data);
|
||||
|
||||
assert_eq!(128 - 2 * 48 - 24, pool.available_space(true));
|
||||
println!("{:?}", &pool.index)
|
||||
//println!("{:?}", &pool.index)
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ pub fn create_map_render_pipeline_description<'a>(
|
||||
}
|
||||
} else {
|
||||
wgpu::StencilFaceState {
|
||||
compare: wgpu::CompareFunction::Equal,
|
||||
compare: wgpu::CompareFunction::Always,
|
||||
fail_op: wgpu::StencilOperation::Keep,
|
||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
||||
pass_op: wgpu::StencilOperation::Keep,
|
||||
|
||||
@ -2,10 +2,10 @@ use std::cmp;
|
||||
use std::io::Cursor;
|
||||
use std::ops::Range;
|
||||
|
||||
use log::warn;
|
||||
use log::{trace, warn};
|
||||
use lyon::tessellation::VertexBuffers;
|
||||
use wgpu::util::DeviceExt;
|
||||
use wgpu::Limits;
|
||||
use wgpu::{Buffer, Limits, Queue};
|
||||
use winit::dpi::PhysicalSize;
|
||||
use winit::event::{
|
||||
DeviceEvent, ElementState, KeyboardInput, MouseButton, TouchPhase, WindowEvent,
|
||||
@ -15,8 +15,10 @@ use winit::window::Window;
|
||||
use vector_tile::parse_tile_reader;
|
||||
|
||||
use crate::fps_meter::FPSMeter;
|
||||
use crate::io::pool::Pool;
|
||||
use crate::io::static_database;
|
||||
use crate::platform::{COLOR_TEXTURE_FORMAT, MIN_BUFFER_SIZE};
|
||||
use crate::render::buffer_pool::{BackingBufferDescriptor, BufferPool};
|
||||
use crate::render::{camera, shaders};
|
||||
use crate::tesselation::{IndexDataType, Tesselated};
|
||||
use crate::util::measure::Measure;
|
||||
@ -73,12 +75,7 @@ pub struct State {
|
||||
prims_uniform_buffer: wgpu::Buffer,
|
||||
globals_uniform_buffer: wgpu::Buffer,
|
||||
|
||||
vertex_uniform_buffer: wgpu::Buffer,
|
||||
indices_uniform_buffer: wgpu::Buffer,
|
||||
tile_fill_range: Range<u32>,
|
||||
tile_stroke_range: Range<u32>,
|
||||
tile2_fill_range: Range<u32>,
|
||||
tile2_stroke_range: Range<u32>,
|
||||
buffer_pool: BufferPool<Queue, Buffer, GpuVertexUniform, IndexDataType>,
|
||||
|
||||
tile_mask_instances: wgpu::Buffer,
|
||||
|
||||
@ -133,50 +130,11 @@ impl State {
|
||||
window.inner_size()
|
||||
};
|
||||
|
||||
let mut geometry: VertexBuffers<GpuVertexUniform, IndexDataType> = VertexBuffers::new();
|
||||
|
||||
measure.breadcrumb("start tessellate");
|
||||
|
||||
println!(
|
||||
"Using static database from {}",
|
||||
static_database::get_source_path()
|
||||
);
|
||||
|
||||
let tile = parse_tile_reader(&mut Cursor::new(
|
||||
static_database::get_tile(&(2179, 1421, 12).into())
|
||||
.unwrap()
|
||||
.contents(),
|
||||
))
|
||||
.expect("failed to load tile");
|
||||
|
||||
measure.breadcrumb("loaded tile");
|
||||
|
||||
let (tile_stroke_range, tile_fill_range) = {
|
||||
(
|
||||
tile.tesselate_stroke(&mut geometry, STROKE_PRIM_ID),
|
||||
//tile.empty_range(&mut geometry, STROKE_PRIM_ID),
|
||||
tile.tesselate_fill(&mut geometry, FILL_PRIM_ID),
|
||||
)
|
||||
};
|
||||
measure.breadcrumb("tessellated tile");
|
||||
|
||||
// tile right to it
|
||||
let tile = parse_tile_reader(&mut Cursor::new(
|
||||
static_database::get_tile(&(2180, 1421, 12).into())
|
||||
.unwrap()
|
||||
.contents(),
|
||||
))
|
||||
.expect("failed to load tile");
|
||||
|
||||
measure.breadcrumb("loaded tile2");
|
||||
|
||||
let (tile2_stroke_range, tile2_fill_range) = (
|
||||
tile.tesselate_stroke(&mut geometry, SECOND_TILE_STROKE_PRIM_ID),
|
||||
//tile.empty_range(&mut geometry, STROKE_PRIM_ID),
|
||||
tile.tesselate_fill(&mut geometry, SECOND_TILE_FILL_PRIM_ID),
|
||||
);
|
||||
measure.breadcrumb("tessellated tile2");
|
||||
|
||||
// create an instance
|
||||
let instance = wgpu::Instance::new(wgpu::Backends::all());
|
||||
|
||||
@ -221,16 +179,18 @@ impl State {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let vertex_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
let vertex_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
contents: bytemuck::cast_slice(&geometry.vertices),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
size: 1024 * 1024 * 16,
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let indices_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
let indices_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
contents: bytemuck::cast_slice(&geometry.indices),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
size: 1024 * 1024 * 16,
|
||||
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let instances = [
|
||||
@ -405,20 +365,18 @@ impl State {
|
||||
multisampling_texture,
|
||||
depth_texture,
|
||||
sample_count,
|
||||
tile_fill_range,
|
||||
scene: SceneParams::new(),
|
||||
vertex_uniform_buffer,
|
||||
globals_uniform_buffer,
|
||||
prims_uniform_buffer,
|
||||
indices_uniform_buffer,
|
||||
fps_meter: FPSMeter::new(),
|
||||
tile_stroke_range,
|
||||
tile2_fill_range,
|
||||
tile_mask_instances,
|
||||
camera,
|
||||
projection,
|
||||
tile2_stroke_range,
|
||||
suspended: false, // Initially the app is not suspended
|
||||
buffer_pool: BufferPool::new(
|
||||
BackingBufferDescriptor(vertex_uniform_buffer, 1024 * 1024 * 16),
|
||||
BackingBufferDescriptor(indices_uniform_buffer, 1024 * 1024 * 16),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,6 +425,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, pool: &Pool) {
|
||||
for tile in pool.pop_all().iter() {
|
||||
self.buffer_pool
|
||||
.allocate_geometry(&self.queue, tile.coords, &tile.geometry);
|
||||
}
|
||||
}
|
||||
pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
||||
let frame = self.surface.get_current_texture()?;
|
||||
let scene = &mut self.scene;
|
||||
@ -543,24 +507,27 @@ impl State {
|
||||
pass.draw(0..6, 0..11);
|
||||
}
|
||||
{
|
||||
pass.set_pipeline(&self.render_pipeline);
|
||||
pass.set_stencil_reference(1);
|
||||
pass.set_index_buffer(self.indices_uniform_buffer.slice(..), INDEX_FORMAT);
|
||||
pass.set_vertex_buffer(0, self.vertex_uniform_buffer.slice(..));
|
||||
if !self.tile_fill_range.is_empty() {
|
||||
pass.draw_indexed(self.tile_fill_range.clone(), 0, 0..1);
|
||||
for entry in self.buffer_pool.available_vertices() {
|
||||
pass.set_pipeline(&self.render_pipeline);
|
||||
pass.set_stencil_reference(1);
|
||||
pass.set_index_buffer(
|
||||
self.buffer_pool
|
||||
.indices()
|
||||
.slice(entry.indices_buffer_range()),
|
||||
INDEX_FORMAT,
|
||||
);
|
||||
pass.set_vertex_buffer(
|
||||
0,
|
||||
self.buffer_pool
|
||||
.vertices()
|
||||
.slice(entry.vertices_buffer_range()),
|
||||
);
|
||||
/* if !self.tile_fill_range.is_empty() {
|
||||
pass.draw_indexed(self.tile_fill_range.clone(), 0, 0..1);
|
||||
}*/
|
||||
trace!("current buffer_pool index {:?}", self.buffer_pool.index);
|
||||
pass.draw_indexed(entry.indices_range(), 0, 0..1);
|
||||
}
|
||||
pass.draw_indexed(self.tile_stroke_range.clone(), 0, 0..1);
|
||||
}
|
||||
{
|
||||
pass.set_pipeline(&self.render_pipeline);
|
||||
pass.set_stencil_reference(2);
|
||||
pass.set_index_buffer(self.indices_uniform_buffer.slice(..), INDEX_FORMAT);
|
||||
pass.set_vertex_buffer(0, self.vertex_uniform_buffer.slice(..));
|
||||
if !self.tile2_fill_range.is_empty() {
|
||||
pass.draw_indexed(self.tile2_fill_range.clone(), 0, 0..1);
|
||||
}
|
||||
pass.draw_indexed(self.tile2_stroke_range.clone(), 0, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user