mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Refactor render loop to use a single pattern for the current view
This commit is contained in:
parent
a1b511db45
commit
575cd07924
@ -67,6 +67,39 @@ impl TileCache {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_tile(&self, coords: &WorldTileCoords) -> bool {
|
||||
coords
|
||||
.build_quad_key()
|
||||
.and_then(|key| {
|
||||
self.cache_index.get(&key).and_then(|entries| {
|
||||
if entries.is_empty() {
|
||||
None
|
||||
} else if entries.iter().all(|entry| match entry {
|
||||
LayerTessellateResult::UnavailableLayer { .. } => true,
|
||||
LayerTessellateResult::TessellatedLayer { .. } => false,
|
||||
}) {
|
||||
None
|
||||
} else {
|
||||
Some(entries)
|
||||
}
|
||||
})
|
||||
})
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn get_tile_coords_fallback(&self, coords: &WorldTileCoords) -> Option<WorldTileCoords> {
|
||||
let mut current = *coords;
|
||||
loop {
|
||||
if self.has_tile(¤t) {
|
||||
return Some(current);
|
||||
} else if let Some(parent) = current.get_parent() {
|
||||
current = parent
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_tessellated_layers_at(
|
||||
&self,
|
||||
coords: &WorldTileCoords,
|
||||
|
||||
@ -286,7 +286,7 @@ impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod, TM: bytemuck::Pod, FM:
|
||||
|
||||
pub struct BackingBufferDescriptor<B> {
|
||||
/// The buffer which is used
|
||||
buffer: B,
|
||||
pub buffer: B,
|
||||
/// The size of buffer
|
||||
inner_size: wgpu::BufferAddress,
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ mod options;
|
||||
mod piplines;
|
||||
mod shaders;
|
||||
mod texture;
|
||||
mod tile_mask_pattern;
|
||||
mod tile_view_pattern;
|
||||
|
||||
pub mod camera;
|
||||
pub mod render_state;
|
||||
|
||||
@ -7,5 +7,6 @@ pub const INDEX_FORMAT: wgpu::IndexFormat = wgpu::IndexFormat::Uint32; // Must m
|
||||
pub const VERTEX_BUFFER_SIZE: BufferAddress = 1024 * 1024 * 32;
|
||||
pub const FEATURE_METADATA_BUFFER_SIZE: BufferAddress = 1024 * 1024 * 32;
|
||||
pub const INDICES_BUFFER_SIZE: BufferAddress = 1024 * 1024 * 16;
|
||||
pub const TILE_VIEW_BUFFER_SIZE: BufferAddress = 4096;
|
||||
|
||||
pub const TILE_META_COUNT: BufferAddress = 1024 * 24;
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
use cgmath::{Matrix4, Vector4};
|
||||
use std::collections::HashSet;
|
||||
use std::default::Default;
|
||||
use std::fmt::Formatter;
|
||||
@ -6,27 +5,28 @@ use std::io::sink;
|
||||
use std::time::{Instant, SystemTime};
|
||||
use std::{cmp, fmt, iter};
|
||||
|
||||
use crate::coords::{ViewRegion, TILE_SIZE};
|
||||
|
||||
use crate::io::scheduler::IOScheduler;
|
||||
use crate::io::LayerTessellateResult;
|
||||
use style_spec::layer::{LayerPaint, StyleLayer};
|
||||
use style_spec::{EncodedSrgb, Style};
|
||||
use cgmath::{Matrix4, Vector4};
|
||||
use tracing;
|
||||
use wgpu::{Buffer, Limits, Queue};
|
||||
use winit::dpi::PhysicalSize;
|
||||
use winit::window::Window;
|
||||
|
||||
use style_spec::layer::{LayerPaint, StyleLayer};
|
||||
use style_spec::{EncodedSrgb, Style};
|
||||
|
||||
use crate::coords::{ViewRegion, TILE_SIZE};
|
||||
use crate::io::scheduler::IOScheduler;
|
||||
use crate::io::LayerTessellateResult;
|
||||
use crate::platform::{COLOR_TEXTURE_FORMAT, MIN_BUFFER_SIZE};
|
||||
use crate::render::buffer_pool::{BackingBufferDescriptor, BufferPool, IndexEntry};
|
||||
use crate::render::camera;
|
||||
use crate::render::camera::ViewProjection;
|
||||
use crate::render::options::{
|
||||
DEBUG_WIREFRAME, FEATURE_METADATA_BUFFER_SIZE, INDEX_FORMAT, INDICES_BUFFER_SIZE,
|
||||
TILE_META_COUNT, VERTEX_BUFFER_SIZE,
|
||||
TILE_META_COUNT, TILE_VIEW_BUFFER_SIZE, VERTEX_BUFFER_SIZE,
|
||||
};
|
||||
use crate::render::tile_mask_pattern::TileMaskPattern;
|
||||
use crate::render::tile_view_pattern::{TileInView, TileViewPattern};
|
||||
use crate::tessellation::{IndexDataType, OverAlignedVertexBuffer};
|
||||
|
||||
use crate::util::FPSMeter;
|
||||
|
||||
use super::piplines::*;
|
||||
@ -34,8 +34,6 @@ use super::shaders;
|
||||
use super::shaders::*;
|
||||
use super::texture::Texture;
|
||||
|
||||
use tracing;
|
||||
|
||||
pub struct RenderState {
|
||||
instance: wgpu::Instance,
|
||||
|
||||
@ -70,7 +68,7 @@ pub struct RenderState {
|
||||
ShaderFeatureStyle,
|
||||
>,
|
||||
|
||||
tile_mask_pattern: TileMaskPattern,
|
||||
tile_view_pattern: TileViewPattern<Queue, Buffer>,
|
||||
|
||||
pub camera: camera::Camera,
|
||||
pub perspective: camera::Perspective,
|
||||
@ -162,14 +160,21 @@ impl RenderState {
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let tile_view_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: TILE_VIEW_BUFFER_SIZE,
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let globals_buffer_byte_size =
|
||||
cmp::max(MIN_BUFFER_SIZE, std::mem::size_of::<ShaderGlobals>() as u64);
|
||||
|
||||
let metadata_buffer_size =
|
||||
let layer_metadata_buffer_size =
|
||||
std::mem::size_of::<ShaderLayerMetadata>() as u64 * TILE_META_COUNT;
|
||||
let metadata_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("Tiles ubo"),
|
||||
size: metadata_buffer_size,
|
||||
let layer_metadata_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("Layer Metadata ubo"),
|
||||
size: layer_metadata_buffer_size,
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
@ -297,10 +302,13 @@ impl RenderState {
|
||||
buffer_pool: BufferPool::new(
|
||||
BackingBufferDescriptor::new(vertex_buffer, VERTEX_BUFFER_SIZE),
|
||||
BackingBufferDescriptor::new(indices_buffer, INDICES_BUFFER_SIZE),
|
||||
BackingBufferDescriptor::new(metadata_buffer, metadata_buffer_size),
|
||||
BackingBufferDescriptor::new(layer_metadata_buffer, layer_metadata_buffer_size),
|
||||
BackingBufferDescriptor::new(feature_metadata_buffer, FEATURE_METADATA_BUFFER_SIZE),
|
||||
),
|
||||
tile_mask_pattern: TileMaskPattern::new(),
|
||||
tile_view_pattern: TileViewPattern::new(BackingBufferDescriptor::new(
|
||||
tile_view_buffer,
|
||||
TILE_VIEW_BUFFER_SIZE,
|
||||
)),
|
||||
zoom: 0.0,
|
||||
style,
|
||||
}
|
||||
@ -379,11 +387,16 @@ impl RenderState {
|
||||
/// tile metadata in the the `buffer_pool` gets updated exactly once and not twice.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn update_metadata(
|
||||
&self,
|
||||
_scheduler: &mut IOScheduler,
|
||||
&mut self,
|
||||
scheduler: &mut IOScheduler,
|
||||
view_region: &ViewRegion,
|
||||
view_proj: &ViewProjection,
|
||||
) {
|
||||
self.tile_view_pattern
|
||||
.update_pattern(view_region, scheduler.get_tile_cache(), self.zoom);
|
||||
self.tile_view_pattern
|
||||
.upload_pattern(&self.queue, &view_proj);
|
||||
|
||||
/*let animated_one = 0.5
|
||||
* (1.0
|
||||
+ ((SystemTime::now()
|
||||
@ -396,80 +409,59 @@ impl RenderState {
|
||||
// Factor which determines how much we need to adjust the width of lines for example.
|
||||
// If zoom == z -> zoom_factor == 1
|
||||
|
||||
for entries in self.buffer_pool.index().iter() {
|
||||
for entry in entries {
|
||||
let world_coords = entry.coords;
|
||||
/* for entries in self.buffer_pool.index().iter() {
|
||||
for entry in entries {
|
||||
let world_coords = entry.coords;*/
|
||||
|
||||
// FIXME: Does not take into account rendering tiles with different z
|
||||
/*if !view_region.is_in_view(&entry.coords) {
|
||||
continue;
|
||||
}*/
|
||||
// TODO: Update features
|
||||
/*let source_layer = entry.style_layer.source_layer.as_ref().unwrap();
|
||||
|
||||
let zoom_factor = 2.0_f64.powf(world_coords.z as f64 - self.zoom) as f32;
|
||||
if let Some(result) = scheduler
|
||||
.get_tile_cache()
|
||||
.iter_tessellated_layers_at(&world_coords)
|
||||
.unwrap()
|
||||
.find(|layer| source_layer.as_str() == layer.layer_name())
|
||||
{
|
||||
let color: Option<Vec4f32> = entry
|
||||
.style_layer
|
||||
.paint
|
||||
.as_ref()
|
||||
.and_then(|paint| paint.get_color())
|
||||
.map(|mut color| {
|
||||
color.color.b = animated_one as f32;
|
||||
color.into()
|
||||
});
|
||||
|
||||
let transform: Matrix4<f32> = (view_proj
|
||||
.to_model_view_projection(world_coords.transform_for_zoom(self.zoom)))
|
||||
.downcast();
|
||||
match result {
|
||||
LayerTessellateResult::UnavailableLayer { .. } => {}
|
||||
LayerTessellateResult::TessellatedLayer {
|
||||
layer_data,
|
||||
feature_indices,
|
||||
..
|
||||
} => {
|
||||
|
||||
self.buffer_pool.update_layer_metadata(
|
||||
&self.queue,
|
||||
entry,
|
||||
ShaderLayerMetadata::new(
|
||||
transform.into(),
|
||||
zoom_factor,
|
||||
entry.style_layer.index as f32,
|
||||
),
|
||||
);
|
||||
let feature_metadata = layer_data
|
||||
.features()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(i, _feature)| {
|
||||
iter::repeat(ShaderFeatureStyle {
|
||||
color: color.unwrap(),
|
||||
})
|
||||
.take(feature_indices[i] as usize)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// TODO: Update features
|
||||
/*let source_layer = entry.style_layer.source_layer.as_ref().unwrap();
|
||||
|
||||
if let Some(result) = scheduler
|
||||
.get_tile_cache()
|
||||
.iter_tessellated_layers_at(&world_coords)
|
||||
.unwrap()
|
||||
.find(|layer| source_layer.as_str() == layer.layer_name())
|
||||
{
|
||||
let color: Option<Vec4f32> = entry
|
||||
.style_layer
|
||||
.paint
|
||||
.as_ref()
|
||||
.and_then(|paint| paint.get_color())
|
||||
.map(|mut color| {
|
||||
color.color.b = animated_one as f32;
|
||||
color.into()
|
||||
});
|
||||
|
||||
match result {
|
||||
LayerTessellateResult::UnavailableLayer { .. } => {}
|
||||
LayerTessellateResult::TessellatedLayer {
|
||||
layer_data,
|
||||
feature_indices,
|
||||
..
|
||||
} => {
|
||||
|
||||
let feature_metadata = layer_data
|
||||
.features()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(i, _feature)| {
|
||||
iter::repeat(ShaderFeatureStyle {
|
||||
color: color.unwrap(),
|
||||
})
|
||||
.take(feature_indices[i] as usize)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.buffer_pool.update_feature_metadata(
|
||||
&self.queue,
|
||||
entry,
|
||||
&feature_metadata,
|
||||
);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
self.buffer_pool.update_feature_metadata(
|
||||
&self.queue,
|
||||
entry,
|
||||
&feature_metadata,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
/* }
|
||||
}*/
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
@ -481,10 +473,6 @@ impl RenderState {
|
||||
) {
|
||||
let visible_z = self.visible_z();
|
||||
|
||||
// Factor which determines how much we need to adjust the width of lines for example.
|
||||
// If zoom == z -> zoom_factor == 1
|
||||
let zoom_factor = 2.0_f64.powf(visible_z as f64 - self.zoom) as f32; // TODO deduplicate
|
||||
|
||||
// Upload all tessellated layers which are in view
|
||||
for world_coords in view_region.iter() {
|
||||
let loaded_layers = self
|
||||
@ -538,23 +526,12 @@ impl RenderState {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// We are casting here from 64bit to 32bit, because 32bit is more performant and is
|
||||
// better supported.
|
||||
let transform: Matrix4<f32> = (view_proj.to_model_view_projection(
|
||||
world_coords.transform_for_zoom(self.zoom),
|
||||
))
|
||||
.downcast();
|
||||
|
||||
self.buffer_pool.allocate_layer_geometry(
|
||||
&self.queue,
|
||||
*coords,
|
||||
style_layer.clone(),
|
||||
buffer,
|
||||
ShaderLayerMetadata::new(
|
||||
transform.into(),
|
||||
zoom_factor,
|
||||
style_layer.index as f32,
|
||||
),
|
||||
ShaderLayerMetadata::new(style_layer.index as f32),
|
||||
&feature_metadata,
|
||||
);
|
||||
}
|
||||
@ -567,18 +544,23 @@ impl RenderState {
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn prepare_render_data(&mut self, scheduler: &mut IOScheduler) {
|
||||
let visible_z = self.visible_z();
|
||||
let render_setup_span = tracing::span!(tracing::Level::TRACE, "setup view region");
|
||||
let _guard = render_setup_span.enter();
|
||||
|
||||
let view_region = self
|
||||
.camera
|
||||
.view_region_bounding_box(&self.camera.calc_view_proj(&self.perspective).invert())
|
||||
.map(|bounding_box| ViewRegion::new(bounding_box, 1, self.zoom, visible_z));
|
||||
let visible_z = self.visible_z();
|
||||
|
||||
let view_proj = self.camera.calc_view_proj(&self.perspective);
|
||||
|
||||
let view_region = self
|
||||
.camera
|
||||
.view_region_bounding_box(&view_proj.invert())
|
||||
.map(|bounding_box| ViewRegion::new(bounding_box, 1, self.zoom, visible_z));
|
||||
|
||||
drop(_guard);
|
||||
|
||||
if let Some(view_region) = &view_region {
|
||||
self.update_metadata(scheduler, &view_region, &view_proj);
|
||||
self.upload_tile_geometry(&view_proj, &view_region, scheduler);
|
||||
self.update_metadata(scheduler, &view_region, &view_proj);
|
||||
self.request_tiles_in_view(view_region, scheduler);
|
||||
}
|
||||
|
||||
@ -597,6 +579,9 @@ impl RenderState {
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
||||
let render_setup_span = tracing::span!(tracing::Level::TRACE, "render prepare");
|
||||
let _guard = render_setup_span.enter();
|
||||
|
||||
let frame = self.surface.get_current_texture()?;
|
||||
let frame_view = frame
|
||||
.texture
|
||||
@ -608,88 +593,84 @@ impl RenderState {
|
||||
label: Some("Encoder"),
|
||||
});
|
||||
|
||||
drop(_guard);
|
||||
|
||||
{
|
||||
let color_attachment = if let Some(multisampling_target) = &self.multisampling_texture {
|
||||
wgpu::RenderPassColorAttachment {
|
||||
view: &multisampling_target.view,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
|
||||
store: true,
|
||||
},
|
||||
resolve_target: Some(&frame_view),
|
||||
}
|
||||
} else {
|
||||
wgpu::RenderPassColorAttachment {
|
||||
view: &frame_view,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
|
||||
store: true,
|
||||
},
|
||||
resolve_target: None,
|
||||
}
|
||||
};
|
||||
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[color_attachment],
|
||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||||
view: &self.depth_texture.view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(0.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(0),
|
||||
store: true,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
pass.set_bind_group(0, &self.bind_group, &[]);
|
||||
|
||||
let _span_ = tracing::span!(tracing::Level::TRACE, "render pass").entered();
|
||||
{
|
||||
let _span_ = tracing::span!(tracing::Level::TRACE, "render pass").entered();
|
||||
let color_attachment =
|
||||
if let Some(multisampling_target) = &self.multisampling_texture {
|
||||
wgpu::RenderPassColorAttachment {
|
||||
view: &multisampling_target.view,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
|
||||
store: true,
|
||||
},
|
||||
resolve_target: Some(&frame_view),
|
||||
}
|
||||
} else {
|
||||
wgpu::RenderPassColorAttachment {
|
||||
view: &frame_view,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
|
||||
store: true,
|
||||
},
|
||||
resolve_target: None,
|
||||
}
|
||||
};
|
||||
|
||||
let visible_z = self.visible_z();
|
||||
let inverted_view_proj = self.camera.calc_view_proj(&self.perspective).invert();
|
||||
let view_region = self
|
||||
.camera
|
||||
.view_region_bounding_box(&inverted_view_proj)
|
||||
.map(|bounding_box| ViewRegion::new(bounding_box, 1, self.zoom, visible_z));
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[color_attachment],
|
||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||||
view: &self.depth_texture.view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(0.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(0),
|
||||
store: true,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
let index = self.buffer_pool.index();
|
||||
pass.set_bind_group(0, &self.bind_group, &[]);
|
||||
|
||||
if let Some(view_region) = &view_region {
|
||||
for world_coords in view_region.iter() {
|
||||
tracing::trace!("Drawing tile at {world_coords}");
|
||||
{
|
||||
let index = self.buffer_pool.index();
|
||||
|
||||
if let Some(entries) = index.get_layers_fallback(&world_coords) {
|
||||
let mut to_render: Vec<&IndexEntry> = Vec::from_iter(entries);
|
||||
to_render.sort_by_key(|entry| entry.style_layer.index);
|
||||
for TileInView { shape, fallback } in self.tile_view_pattern.iter() {
|
||||
let coords = shape.coords;
|
||||
tracing::trace!("Drawing tile at {coords}");
|
||||
|
||||
let reference = self
|
||||
.tile_mask_pattern
|
||||
.stencil_reference_value(&world_coords)
|
||||
as u32;
|
||||
let shape_to_render = fallback.as_ref().unwrap_or(shape);
|
||||
|
||||
// Draw mask
|
||||
if let Some(mask_entry) = entries.front() {
|
||||
{
|
||||
tracing::trace!("Drawing mask {}", &mask_entry.coords);
|
||||
let reference = self
|
||||
.tile_view_pattern
|
||||
.stencil_reference_value(&shape_to_render.coords)
|
||||
as u32;
|
||||
|
||||
pass.set_pipeline(&self.mask_pipeline);
|
||||
pass.set_stencil_reference(reference);
|
||||
pass.set_vertex_buffer(
|
||||
0,
|
||||
self.buffer_pool
|
||||
.metadata()
|
||||
.slice(mask_entry.layer_metadata_buffer_range()),
|
||||
);
|
||||
pass.draw(0..6, 0..1);
|
||||
}
|
||||
}
|
||||
// Draw mask
|
||||
{
|
||||
tracing::trace!("Drawing mask {}", &coords);
|
||||
|
||||
for entry in to_render {
|
||||
pass.set_pipeline(&self.mask_pipeline);
|
||||
pass.set_stencil_reference(reference);
|
||||
pass.set_vertex_buffer(
|
||||
0,
|
||||
self.tile_view_pattern
|
||||
.buffer()
|
||||
.slice(shape.buffer_range.clone()),
|
||||
);
|
||||
pass.draw(0..6, 0..1);
|
||||
}
|
||||
|
||||
if let Some(entries) = index.get_layers(&shape_to_render.coords) {
|
||||
let mut layers_to_render: Vec<&IndexEntry> = Vec::from_iter(entries);
|
||||
layers_to_render.sort_by_key(|entry| entry.style_layer.index);
|
||||
|
||||
for entry in layers_to_render {
|
||||
// Draw tile
|
||||
{
|
||||
tracing::trace!(
|
||||
@ -714,12 +695,18 @@ impl RenderState {
|
||||
);
|
||||
pass.set_vertex_buffer(
|
||||
1,
|
||||
self.tile_view_pattern
|
||||
.buffer()
|
||||
.slice(shape_to_render.buffer_range.clone()),
|
||||
);
|
||||
pass.set_vertex_buffer(
|
||||
2,
|
||||
self.buffer_pool
|
||||
.metadata()
|
||||
.slice(entry.layer_metadata_buffer_range()),
|
||||
);
|
||||
pass.set_vertex_buffer(
|
||||
2,
|
||||
3,
|
||||
self.buffer_pool
|
||||
.feature_metadata()
|
||||
.slice(entry.feature_metadata_buffer_range()),
|
||||
@ -733,8 +720,16 @@ impl RenderState {
|
||||
}
|
||||
}
|
||||
|
||||
self.queue.submit(Some(encoder.finish()));
|
||||
frame.present();
|
||||
{
|
||||
let _span = tracing::span!(tracing::Level::TRACE, "render finish").entered();
|
||||
tracing::trace!("Finished drawing");
|
||||
|
||||
self.queue.submit(Some(encoder.finish()));
|
||||
tracing::trace!("Submitted queue");
|
||||
|
||||
frame.present();
|
||||
tracing::trace!("Presented frame");
|
||||
}
|
||||
|
||||
self.fps_meter.update_and_print();
|
||||
Ok(())
|
||||
|
||||
@ -82,7 +82,7 @@ impl VertexShaderState {
|
||||
pub mod tile {
|
||||
use super::{ShaderLayerMetadata, ShaderVertex};
|
||||
use crate::platform::COLOR_TEXTURE_FORMAT;
|
||||
use crate::render::shaders::ShaderFeatureStyle;
|
||||
use crate::render::shaders::{ShaderFeatureStyle, ShaderTileMetadata};
|
||||
|
||||
use super::{FragmentShaderState, VertexShaderState};
|
||||
|
||||
@ -110,7 +110,7 @@ pub mod tile {
|
||||
},
|
||||
// tile metadata
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<ShaderLayerMetadata>() as u64,
|
||||
array_stride: std::mem::size_of::<ShaderTileMetadata>() as u64,
|
||||
step_mode: wgpu::VertexStepMode::Instance,
|
||||
attributes: &[
|
||||
// translate
|
||||
@ -134,20 +134,28 @@ pub mod tile {
|
||||
format: wgpu::VertexFormat::Float32x4,
|
||||
shader_location: 7,
|
||||
},
|
||||
// zoom_factor
|
||||
wgpu::VertexAttribute {
|
||||
offset: 4 * wgpu::VertexFormat::Float32x4.size(),
|
||||
format: wgpu::VertexFormat::Float32,
|
||||
shader_location: 9,
|
||||
},
|
||||
],
|
||||
},
|
||||
// layer metadata
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<ShaderLayerMetadata>() as u64,
|
||||
step_mode: wgpu::VertexStepMode::Instance,
|
||||
attributes: &[
|
||||
// z_index
|
||||
wgpu::VertexAttribute {
|
||||
offset: 4 * wgpu::VertexFormat::Float32x4.size()
|
||||
+ wgpu::VertexFormat::Float32.size(),
|
||||
offset: 0,
|
||||
format: wgpu::VertexFormat::Float32,
|
||||
shader_location: 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
// vertex style
|
||||
// features
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<ShaderFeatureStyle>() as u64,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
@ -188,7 +196,7 @@ pub mod tile {
|
||||
pub mod tile_mask {
|
||||
use crate::platform::COLOR_TEXTURE_FORMAT;
|
||||
use crate::render::options::DEBUG_STENCIL_PATTERN;
|
||||
use crate::render::shaders::ShaderLayerMetadata;
|
||||
use crate::render::shaders::{ShaderLayerMetadata, ShaderTileMetadata};
|
||||
use wgpu::ColorWrites;
|
||||
|
||||
use super::{FragmentShaderState, VertexShaderState};
|
||||
@ -196,7 +204,7 @@ pub mod tile_mask {
|
||||
pub const VERTEX: VertexShaderState = VertexShaderState::new(
|
||||
include_str!("tile_mask.vertex.wgsl"),
|
||||
&[wgpu::VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<ShaderLayerMetadata>() as u64,
|
||||
array_stride: std::mem::size_of::<ShaderTileMetadata>() as u64,
|
||||
step_mode: wgpu::VertexStepMode::Instance,
|
||||
attributes: &[
|
||||
// translate
|
||||
@ -309,17 +317,27 @@ pub struct ShaderFeatureStyle {
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||
pub struct ShaderLayerMetadata {
|
||||
pub transform: Mat4x4f32,
|
||||
pub zoom_factor: f32,
|
||||
pub z_index: f32,
|
||||
}
|
||||
|
||||
impl ShaderLayerMetadata {
|
||||
pub fn new(transform: Mat4x4f32, zoom_factor: f32, z_index: f32) -> Self {
|
||||
pub fn new(z_index: f32) -> Self {
|
||||
Self { z_index }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||
pub struct ShaderTileMetadata {
|
||||
pub transform: Mat4x4f32,
|
||||
pub zoom_factor: f32,
|
||||
}
|
||||
|
||||
impl ShaderTileMetadata {
|
||||
pub fn new(transform: Mat4x4f32, zoom_factor: f32) -> Self {
|
||||
Self {
|
||||
transform,
|
||||
zoom_factor,
|
||||
z_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
use crate::coords::WorldTileCoords;
|
||||
|
||||
/// The tile mask pattern assigns each tile a value which can be used for stencil testing.
|
||||
/// The pattern can be reviewed [here](https://maxammann.org/mapr/docs/stencil-masking.html).
|
||||
pub struct TileMaskPattern {}
|
||||
|
||||
impl TileMaskPattern {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
pub fn stencil_reference_value(&self, world_coords: &WorldTileCoords) -> u8 {
|
||||
match (world_coords.x, world_coords.y) {
|
||||
(x, y) if x % 2 == 0 && y % 2 == 0 => 2,
|
||||
(x, y) if x % 2 == 0 && y % 2 != 0 => 1,
|
||||
(x, y) if x % 2 != 0 && y % 2 == 0 => 4,
|
||||
(x, y) if x % 2 != 0 && y % 2 != 0 => 3,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
157
src/render/tile_view_pattern.rs
Normal file
157
src/render/tile_view_pattern.rs
Normal file
@ -0,0 +1,157 @@
|
||||
use crate::coords::{Quadkey, ViewRegion, WorldTileCoords};
|
||||
use crate::io::tile_cache::TileCache;
|
||||
use crate::render::buffer_pool::{BackingBufferDescriptor, Queue};
|
||||
use crate::render::camera::ViewProjection;
|
||||
use crate::render::shaders::ShaderTileMetadata;
|
||||
use cgmath::Matrix4;
|
||||
use lyon::geom::euclid::approxeq::ApproxEq;
|
||||
use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::size_of;
|
||||
use std::ops::Range;
|
||||
|
||||
/// The tile mask pattern assigns each tile a value which can be used for stencil testing.
|
||||
pub struct TileViewPattern<Q, B> {
|
||||
in_view: Vec<TileInView>,
|
||||
buffer: BackingBuffer<B>,
|
||||
phantom_q: PhantomData<Q>,
|
||||
}
|
||||
|
||||
pub struct TileShape {
|
||||
pub zoom_factor: f64,
|
||||
|
||||
pub coords: WorldTileCoords,
|
||||
|
||||
pub transform: Matrix4<f64>,
|
||||
pub buffer_range: Range<wgpu::BufferAddress>,
|
||||
}
|
||||
|
||||
pub struct TileInView {
|
||||
pub shape: TileShape,
|
||||
|
||||
pub fallback: Option<TileShape>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BackingBuffer<B> {
|
||||
/// The internal structure which is used for storage
|
||||
inner: B,
|
||||
/// The size of the `inner` buffer
|
||||
inner_size: wgpu::BufferAddress,
|
||||
}
|
||||
|
||||
impl<B> BackingBuffer<B> {
|
||||
fn new(inner: B, inner_size: wgpu::BufferAddress) -> Self {
|
||||
Self { inner, inner_size }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Q: Queue<B>, B> TileViewPattern<Q, B> {
|
||||
pub fn new(buffer: BackingBufferDescriptor<B>) -> Self {
|
||||
Self {
|
||||
in_view: Vec::with_capacity(64),
|
||||
buffer: BackingBuffer::new(buffer.buffer, buffer.inner_size),
|
||||
phantom_q: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn update_pattern(&mut self, view_region: &ViewRegion, tile_cache: &TileCache, zoom: f64) {
|
||||
self.in_view.clear();
|
||||
|
||||
let stride = size_of::<ShaderTileMetadata>() as u64;
|
||||
|
||||
let mut index = 0;
|
||||
|
||||
for coords in view_region.iter() {
|
||||
if let None = coords.build_quad_key() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let shape = TileShape {
|
||||
coords,
|
||||
zoom_factor: 2.0_f64.powf(coords.z as f64 - zoom),
|
||||
transform: coords.transform_for_zoom(zoom),
|
||||
buffer_range: index as u64 * stride..(index as u64 + 1) * stride,
|
||||
};
|
||||
|
||||
index += 1;
|
||||
|
||||
let fallback = {
|
||||
if !tile_cache.has_tile(&coords) {
|
||||
if let Some(fallback_coords) = tile_cache.get_tile_coords_fallback(&coords) {
|
||||
let shape = TileShape {
|
||||
coords: fallback_coords,
|
||||
zoom_factor: 2.0_f64.powf(fallback_coords.z as f64 - zoom),
|
||||
transform: fallback_coords.transform_for_zoom(zoom),
|
||||
buffer_range: index as u64 * stride..(index as u64 + 1) * stride,
|
||||
};
|
||||
|
||||
index += 1;
|
||||
Some(shape)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
self.in_view.push(TileInView { shape, fallback });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &TileInView> + '_ {
|
||||
self.in_view.iter()
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &B {
|
||||
&self.buffer.inner
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn upload_pattern(&self, queue: &Q, view_proj: &ViewProjection) {
|
||||
let mut buffer = Vec::with_capacity(self.in_view.len());
|
||||
|
||||
for tile in &self.in_view {
|
||||
buffer.push(ShaderTileMetadata {
|
||||
// We are casting here from 64bit to 32bit, because 32bit is more performant and is
|
||||
// better supported.
|
||||
transform: view_proj
|
||||
.to_model_view_projection(tile.shape.transform)
|
||||
.downcast()
|
||||
.into(),
|
||||
zoom_factor: tile.shape.zoom_factor as f32,
|
||||
});
|
||||
|
||||
if let Some(fallback_shape) = &tile.fallback {
|
||||
buffer.push(ShaderTileMetadata {
|
||||
// We are casting here from 64bit to 32bit, because 32bit is more performant and is
|
||||
// better supported.
|
||||
transform: view_proj
|
||||
.to_model_view_projection(fallback_shape.transform)
|
||||
.downcast()
|
||||
.into(),
|
||||
zoom_factor: fallback_shape.zoom_factor as f32,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
queue.write_buffer(
|
||||
&self.buffer.inner,
|
||||
0,
|
||||
&bytemuck::cast_slice(&buffer.as_slice()),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn stencil_reference_value(&self, world_coords: &WorldTileCoords) -> u8 {
|
||||
world_coords.z * 5
|
||||
+ match (world_coords.x, world_coords.y) {
|
||||
(x, y) if x % 2 == 0 && y % 2 == 0 => 2,
|
||||
(x, y) if x % 2 == 0 && y % 2 != 0 => 1,
|
||||
(x, y) if x % 2 != 0 && y % 2 == 0 => 4,
|
||||
(x, y) if x % 2 != 0 && y % 2 != 0 => 3,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user