Asynchronously render tiles

This commit is contained in:
Maximilian Ammann 2021-12-30 17:22:50 +01:00
parent b863d12992
commit 8c99a58fca
5 changed files with 100 additions and 114 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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)
}
}

View File

@ -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,

View File

@ -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);
}
}