Add feature metadata

This commit is contained in:
Maximilian Ammann 2022-01-15 15:14:26 +01:00
parent 635df81f1c
commit e044b81a72
4 changed files with 168 additions and 52 deletions

View File

@ -23,16 +23,18 @@ impl Queue<wgpu::Buffer> for wgpu::Queue {
/// This is inspired by the memory pool in Vulkan documented /// This is inspired by the memory pool in Vulkan documented
/// [here](https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/custom_memory_pools.html). /// [here](https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/custom_memory_pools.html).
#[derive(Debug)] #[derive(Debug)]
pub struct BufferPool<Q, B, V, I, M> { pub struct BufferPool<Q, B, V, I, M, FM> {
vertices: BackingBuffer<B>, vertices: BackingBuffer<B>,
indices: BackingBuffer<B>, indices: BackingBuffer<B>,
metadata: BackingBuffer<B>, metadata: BackingBuffer<B>,
feature_metadata: BackingBuffer<B>,
pub index: VecDeque<IndexEntry>, pub index: VecDeque<IndexEntry>,
phantom_v: PhantomData<V>, phantom_v: PhantomData<V>,
phantom_i: PhantomData<I>, phantom_i: PhantomData<I>,
phantom_q: PhantomData<Q>, phantom_q: PhantomData<Q>,
phantom_m: PhantomData<M>, phantom_m: PhantomData<M>,
phantom_fm: PhantomData<FM>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -40,15 +42,17 @@ enum BackingBufferType {
VERTICES, VERTICES,
INDICES, INDICES,
METADATA, METADATA,
FEATURE_METADATA,
} }
impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod, M: bytemuck::Pod> impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod, M: bytemuck::Pod, FM: bytemuck::Pod>
BufferPool<Q, B, V, I, M> BufferPool<Q, B, V, I, M, FM>
{ {
pub fn new( pub fn new(
vertices: BackingBufferDescriptor<B>, vertices: BackingBufferDescriptor<B>,
indices: BackingBufferDescriptor<B>, indices: BackingBufferDescriptor<B>,
metadata: BackingBufferDescriptor<B>, metadata: BackingBufferDescriptor<B>,
feature_metadata: BackingBufferDescriptor<B>,
) -> Self { ) -> Self {
Self { Self {
vertices: BackingBuffer::new( vertices: BackingBuffer::new(
@ -66,11 +70,17 @@ impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod, M: bytemuck::Pod>
metadata.inner_size, metadata.inner_size,
BackingBufferType::METADATA, BackingBufferType::METADATA,
), ),
feature_metadata: BackingBuffer::new(
feature_metadata.buffer,
feature_metadata.inner_size,
BackingBufferType::FEATURE_METADATA,
),
index: VecDeque::new(), // TODO: Approximate amount of buffers in pool index: VecDeque::new(), // TODO: Approximate amount of buffers in pool
phantom_v: Default::default(), phantom_v: Default::default(),
phantom_i: Default::default(), phantom_i: Default::default(),
phantom_q: Default::default(), phantom_q: Default::default(),
phantom_m: Default::default(), phantom_m: Default::default(),
phantom_fm: Default::default(),
} }
} }
@ -80,6 +90,7 @@ impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod, M: bytemuck::Pod>
BackingBufferType::VERTICES => &self.vertices, BackingBufferType::VERTICES => &self.vertices,
BackingBufferType::INDICES => &self.indices, BackingBufferType::INDICES => &self.indices,
BackingBufferType::METADATA => &self.metadata, BackingBufferType::METADATA => &self.metadata,
BackingBufferType::FEATURE_METADATA => &self.feature_metadata,
} }
.find_largest_gap(&self.index); .find_largest_gap(&self.index);
@ -98,6 +109,10 @@ impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod, M: bytemuck::Pod>
&self.metadata.inner &self.metadata.inner
} }
pub fn feature_metadata(&self) -> &B {
&self.feature_metadata.inner
}
/// The VertexBuffers can contain padding elements. Not everything from a VertexBuffers is useable. /// The VertexBuffers can contain padding elements. Not everything from a VertexBuffers is useable.
/// The function returns the `bytes` and `aligned_bytes`. See [`OverAlignedVertexBuffer`]. /// The function returns the `bytes` and `aligned_bytes`. See [`OverAlignedVertexBuffer`].
fn align( fn align(
@ -121,14 +136,15 @@ impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod, M: bytemuck::Pod>
pub fn allocate_geometry( pub fn allocate_geometry(
&mut self, &mut self,
queue: &Q, queue: &Q,
id: u32,
coords: TileCoords, coords: TileCoords,
over_aligned: &OverAlignedVertexBuffer<V, I>, over_aligned: &OverAlignedVertexBuffer<V, I>,
metadata: M, metadata: M,
feature_metadata: &Vec<FM>,
) { ) {
let vertices_stride = size_of::<V>() as wgpu::BufferAddress; let vertices_stride = size_of::<V>() as wgpu::BufferAddress;
let indices_stride = size_of::<I>() as wgpu::BufferAddress; let indices_stride = size_of::<I>() as wgpu::BufferAddress;
let metadata_stride = size_of::<M>() as wgpu::BufferAddress; let metadata_stride = size_of::<M>() as wgpu::BufferAddress;
let feature_metadata_stride = size_of::<FM>() as wgpu::BufferAddress;
let (vertices_bytes, aligned_vertices_bytes) = Self::align( let (vertices_bytes, aligned_vertices_bytes) = Self::align(
vertices_stride, vertices_stride,
@ -141,14 +157,28 @@ impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod, M: bytemuck::Pod>
over_aligned.usable_indices as BufferAddress, over_aligned.usable_indices as BufferAddress,
); );
let (metadata_bytes, aligned_metadata_bytes) = Self::align(metadata_stride, 1, 1); let (metadata_bytes, aligned_metadata_bytes) = Self::align(metadata_stride, 1, 1);
let (feature_metadata_bytes, aligned_feature_metadata_bytes) = Self::align(
feature_metadata_stride,
feature_metadata.len() as BufferAddress,
feature_metadata.len() as BufferAddress,
);
if feature_metadata_bytes != aligned_feature_metadata_bytes {
// FIXME: align if not aligned?
panic!(
"feature_metadata is not aligned. This should not happen as long as size_of::<FM>() is a multiple of the alignment."
)
}
let maybe_entry = IndexEntry { let maybe_entry = IndexEntry {
id,
coords, coords,
buffer_vertices: self.vertices.make_room(vertices_bytes, &mut self.index), buffer_vertices: self.vertices.make_room(vertices_bytes, &mut self.index),
buffer_indices: self.indices.make_room(indices_bytes, &mut self.index), buffer_indices: self.indices.make_room(indices_bytes, &mut self.index),
usable_indices: over_aligned.usable_indices as u32, usable_indices: over_aligned.usable_indices as u32,
buffer_metadata: self.metadata.make_room(metadata_bytes, &mut self.index), buffer_metadata: self.metadata.make_room(metadata_bytes, &mut self.index),
buffer_feature_metadata: self
.feature_metadata
.make_room(feature_metadata_bytes, &mut self.index),
}; };
// write_buffer() is the preferred method for WASM: https://toji.github.io/webgpu-best-practices/buffer-uploads.html#when-in-doubt-writebuffer // write_buffer() is the preferred method for WASM: https://toji.github.io/webgpu-best-practices/buffer-uploads.html#when-in-doubt-writebuffer
@ -168,6 +198,12 @@ impl<Q: Queue<B>, B, V: bytemuck::Pod, I: bytemuck::Pod, M: bytemuck::Pod>
maybe_entry.buffer_metadata.start, maybe_entry.buffer_metadata.start,
&bytemuck::cast_slice(&[metadata])[0..aligned_metadata_bytes as usize], &bytemuck::cast_slice(&[metadata])[0..aligned_metadata_bytes as usize],
); );
queue.write_buffer(
&self.feature_metadata.inner,
maybe_entry.buffer_feature_metadata.start,
&bytemuck::cast_slice(feature_metadata.as_slice())
[0..aligned_feature_metadata_bytes as usize],
);
self.index.push_back(maybe_entry); self.index.push_back(maybe_entry);
} }
@ -235,11 +271,13 @@ impl<B> BackingBuffer<B> {
BackingBufferType::VERTICES => first.buffer_vertices.start, BackingBufferType::VERTICES => first.buffer_vertices.start,
BackingBufferType::INDICES => first.buffer_indices.start, BackingBufferType::INDICES => first.buffer_indices.start,
BackingBufferType::METADATA => first.buffer_metadata.start, BackingBufferType::METADATA => first.buffer_metadata.start,
BackingBufferType::FEATURE_METADATA => first.buffer_feature_metadata.start,
}); });
let end = index.back().map(|first| match self.typ { let end = index.back().map(|first| match self.typ {
BackingBufferType::VERTICES => first.buffer_vertices.end, BackingBufferType::VERTICES => first.buffer_vertices.end,
BackingBufferType::INDICES => first.buffer_indices.end, BackingBufferType::INDICES => first.buffer_indices.end,
BackingBufferType::METADATA => first.buffer_metadata.end, BackingBufferType::METADATA => first.buffer_metadata.end,
BackingBufferType::FEATURE_METADATA => first.buffer_feature_metadata.end,
}); });
if let Some(start) = start { if let Some(start) = start {
@ -272,7 +310,6 @@ impl<B> BackingBuffer<B> {
#[derive(Debug)] #[derive(Debug)]
pub struct IndexEntry { pub struct IndexEntry {
pub id: u32,
pub coords: TileCoords, pub coords: TileCoords,
// Range of bytes within the backing buffer for vertices // Range of bytes within the backing buffer for vertices
buffer_vertices: Range<wgpu::BufferAddress>, buffer_vertices: Range<wgpu::BufferAddress>,
@ -280,6 +317,8 @@ pub struct IndexEntry {
buffer_indices: Range<wgpu::BufferAddress>, buffer_indices: Range<wgpu::BufferAddress>,
// Range of bytes within the backing buffer for metadata // Range of bytes within the backing buffer for metadata
buffer_metadata: Range<wgpu::BufferAddress>, buffer_metadata: Range<wgpu::BufferAddress>,
// Range of bytes within the backing buffer for feature metadata
buffer_feature_metadata: Range<wgpu::BufferAddress>,
// Amount of actually usable indices. Each index has the size/format `IndexDataType`. // Amount of actually usable indices. Each index has the size/format `IndexDataType`.
// Can be lower than size(buffer_indices) / indices_stride because of alignment. // Can be lower than size(buffer_indices) / indices_stride because of alignment.
usable_indices: u32, usable_indices: u32,
@ -301,6 +340,10 @@ impl IndexEntry {
pub fn metadata_buffer_range(&self) -> Range<wgpu::BufferAddress> { pub fn metadata_buffer_range(&self) -> Range<wgpu::BufferAddress> {
self.buffer_metadata.clone() self.buffer_metadata.clone()
} }
pub fn feature_metadata_buffer_range(&self) -> Range<wgpu::BufferAddress> {
self.buffer_feature_metadata.clone()
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,7 +1,8 @@
use std::cmp;
use std::default::Default; use std::default::Default;
use std::{cmp, iter};
use log::trace; use log::trace;
use vector_tile::tile::Layer;
use wgpu::{Buffer, BufferAddress, Limits, Queue}; use wgpu::{Buffer, BufferAddress, Limits, Queue};
use winit::dpi::PhysicalSize; use winit::dpi::PhysicalSize;
use winit::window::Window; use winit::window::Window;
@ -10,6 +11,10 @@ use crate::io::worker_loop::WorkerLoop;
use crate::platform::{COLOR_TEXTURE_FORMAT, MIN_BUFFER_SIZE}; use crate::platform::{COLOR_TEXTURE_FORMAT, MIN_BUFFER_SIZE};
use crate::render::buffer_pool::{BackingBufferDescriptor, BufferPool}; use crate::render::buffer_pool::{BackingBufferDescriptor, BufferPool};
use crate::render::camera; use crate::render::camera;
use crate::render::options::{
DEBUG_WIREFRAME, FEATURE_METADATA_BUFFER_SIZE, INDEX_FORMAT, INDICES_BUFFER_SIZE,
TILE_MASK_INSTANCE_COUNT, TILE_META_COUNT, VERTEX_BUFFER_SIZE,
};
use crate::render::tile_mask_pattern::TileMaskPattern; use crate::render::tile_mask_pattern::TileMaskPattern;
use crate::tesselation::IndexDataType; use crate::tesselation::IndexDataType;
use crate::util::FPSMeter; use crate::util::FPSMeter;
@ -19,12 +24,6 @@ use super::shaders;
use super::shaders::*; use super::shaders::*;
use super::texture::Texture; use super::texture::Texture;
const INDEX_FORMAT: wgpu::IndexFormat = wgpu::IndexFormat::Uint16; // Must match IndexDataType
const VERTEX_BUFFER_SIZE: BufferAddress = 1024 * 1024 * 8;
const INDICES_BUFFER_SIZE: BufferAddress = 1024 * 1024 * 8;
const TILE_META_COUNT: BufferAddress = 1024 * 8; // FIXME: Move this to BufferPool
const TILE_MASK_INSTANCE_COUNT: BufferAddress = 512; // FIXME: Pick reasonable size
pub struct RenderState { pub struct RenderState {
instance: wgpu::Instance, instance: wgpu::Instance,
@ -50,7 +49,14 @@ pub struct RenderState {
globals_uniform_buffer: wgpu::Buffer, globals_uniform_buffer: wgpu::Buffer,
buffer_pool: BufferPool<Queue, Buffer, ShaderVertex, IndexDataType, ShaderTileMetadata>, buffer_pool: BufferPool<
Queue,
Buffer,
ShaderVertex,
IndexDataType,
ShaderTileMetadata,
ShaderFeatureStyle,
>,
tile_mask_pattern: TileMaskPattern, tile_mask_pattern: TileMaskPattern,
tile_mask_instances_buffer: wgpu::Buffer, tile_mask_instances_buffer: wgpu::Buffer,
@ -103,11 +109,17 @@ impl RenderState {
}; };
// create a device and a queue // create a device and a queue
let features = if DEBUG_WIREFRAME {
wgpu::Features::default() | wgpu::Features::POLYGON_MODE_LINE
} else {
wgpu::Features::default()
};
let (device, queue) = adapter let (device, queue) = adapter
.request_device( .request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
features: wgpu::Features::default(), features,
limits, limits,
}, },
None, None,
@ -115,26 +127,33 @@ impl RenderState {
.await .await
.unwrap(); .unwrap();
let vertex_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: None, label: None,
size: VERTEX_BUFFER_SIZE, size: VERTEX_BUFFER_SIZE,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false, mapped_at_creation: false,
}); });
let indices_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { let feature_metadata_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: FEATURE_METADATA_BUFFER_SIZE,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let indices_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: None, label: None,
size: INDICES_BUFFER_SIZE, size: INDICES_BUFFER_SIZE,
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false, mapped_at_creation: false,
}); });
let tile_masks_uniform_buffer_size = let tile_masks_instances_buffer_size =
std::mem::size_of::<ShaderTileMaskInstance>() as u64 * TILE_MASK_INSTANCE_COUNT; std::mem::size_of::<ShaderTileMaskInstance>() as u64 * TILE_MASK_INSTANCE_COUNT;
let tile_mask_instances = device.create_buffer(&wgpu::BufferDescriptor { let tile_mask_instances = device.create_buffer(&wgpu::BufferDescriptor {
label: None, label: None,
size: tile_masks_uniform_buffer_size, size: tile_masks_instances_buffer_size,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false, mapped_at_creation: false,
}); });
@ -142,11 +161,11 @@ impl RenderState {
let globals_buffer_byte_size = let globals_buffer_byte_size =
cmp::max(MIN_BUFFER_SIZE, std::mem::size_of::<ShaderGlobals>() as u64); cmp::max(MIN_BUFFER_SIZE, std::mem::size_of::<ShaderGlobals>() as u64);
let tiles_uniform_buffer_size = let metadata_buffer_size =
std::mem::size_of::<ShaderTileMetadata>() as u64 * TILE_META_COUNT; std::mem::size_of::<ShaderTileMetadata>() as u64 * TILE_META_COUNT;
let tiles_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { let metadata_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Tiles ubo"), label: Some("Tiles ubo"),
size: tiles_uniform_buffer_size, size: metadata_buffer_size,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false, mapped_at_creation: false,
}); });
@ -273,9 +292,10 @@ impl RenderState {
perspective: projection, perspective: projection,
suspended: false, // Initially the app is not suspended suspended: false, // Initially the app is not suspended
buffer_pool: BufferPool::new( buffer_pool: BufferPool::new(
BackingBufferDescriptor::new(vertex_uniform_buffer, VERTEX_BUFFER_SIZE), BackingBufferDescriptor::new(vertex_buffer, VERTEX_BUFFER_SIZE),
BackingBufferDescriptor::new(indices_uniform_buffer, INDICES_BUFFER_SIZE), BackingBufferDescriptor::new(indices_buffer, INDICES_BUFFER_SIZE),
BackingBufferDescriptor::new(tiles_uniform_buffer, tiles_uniform_buffer_size), BackingBufferDescriptor::new(metadata_buffer, metadata_buffer_size),
BackingBufferDescriptor::new(feature_metadata_buffer, FEATURE_METADATA_BUFFER_SIZE),
), ),
tile_mask_pattern: TileMaskPattern::new(), tile_mask_pattern: TileMaskPattern::new(),
} }
@ -332,19 +352,47 @@ impl RenderState {
pub fn upload_tile_geometry(&mut self, worker_loop: &WorkerLoop) { pub fn upload_tile_geometry(&mut self, worker_loop: &WorkerLoop) {
let upload = worker_loop.pop_all(); let upload = worker_loop.pop_all();
for tile in upload.iter() { for layer in upload.iter() {
let world_coords = tile.coords.into_world_tile(); let world_coords = layer.coords.into_world_tile();
self.tile_mask_pattern.update_bounds(&world_coords); self.tile_mask_pattern.update_bounds(&world_coords);
/*match tile.layer_data.name() {
"transportation" => {}
"building" => {}
"boundary" => {}
"water" => {}
"waterway" => {}
_ => {
continue;
}
};*/
let feature_metadata = layer
.layer_data
.features()
.iter()
.enumerate()
.flat_map(|(i, feature)| {
iter::repeat(ShaderFeatureStyle {
color: match layer.layer_data.name() {
"transportation" => [1.0, 0.0, 0.0, 1.0],
"building" => [0.0, 1.0, 1.0, 1.0],
"boundary" => [0.0, 0.0, 0.0, 1.0],
"water" => [0.0, 0.0, 1.0, 1.0],
"waterway" => [0.0, 0.0, 1.0, 1.0],
_ => [0.0, 0.0, 0.0, 0.0],
},
})
.take(*layer.feature_vertices.get(i).unwrap() as usize)
})
.collect::<Vec<_>>();
self.buffer_pool.allocate_geometry( self.buffer_pool.allocate_geometry(
&self.queue, &self.queue,
tile.id, layer.coords,
tile.coords, &layer.buffer,
&tile.over_aligned, ShaderTileMetadata::new(world_coords.into_world(4096.0).into()),
ShaderTileMetadata::new( &feature_metadata,
[0.0, 0.0, 0.0, 1.0],
world_coords.into_world(4096.0).into(),
),
); );
} }
@ -442,18 +490,18 @@ impl RenderState {
.vertices() .vertices()
.slice(entry.vertices_buffer_range()), .slice(entry.vertices_buffer_range()),
); );
let id = entry.id as BufferAddress;
pass.set_vertex_buffer( pass.set_vertex_buffer(
1, 1,
self.buffer_pool self.buffer_pool
.metadata() .metadata()
.slice(entry.metadata_buffer_range()), .slice(entry.metadata_buffer_range()),
); );
/* if !self.tile_fill_range.is_empty() { pass.set_vertex_buffer(
pass.draw_indexed(self.tile_fill_range.clone(), 0, 0..1); 2,
}*/ self.buffer_pool
trace!("current buffer_pool index {:?}", self.buffer_pool.index); .feature_metadata()
// FIXME: Custom Instance index possibly breaks on Metal .slice(entry.feature_metadata_buffer_range()),
);
pass.draw_indexed(entry.indices_range(), 0, 0..1); pass.draw_indexed(entry.indices_range(), 0, 0..1);
} }
} }

View File

@ -81,12 +81,14 @@ impl VertexShaderState {
pub mod tile { pub mod tile {
use super::{ShaderTileMetadata, ShaderVertex}; use super::{ShaderTileMetadata, ShaderVertex};
use crate::platform::COLOR_TEXTURE_FORMAT; use crate::platform::COLOR_TEXTURE_FORMAT;
use wgpu::BlendState;
use super::{FragmentShaderState, VertexShaderState}; use super::{FragmentShaderState, VertexShaderState};
pub const VERTEX: VertexShaderState = VertexShaderState::new( pub const VERTEX: VertexShaderState = VertexShaderState::new(
include_str!("tile.vertex.wgsl"), include_str!("tile.vertex.wgsl"),
&[ &[
// vertex data
wgpu::VertexBufferLayout { wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<ShaderVertex>() as u64, array_stride: std::mem::size_of::<ShaderVertex>() as u64,
step_mode: wgpu::VertexStepMode::Vertex, step_mode: wgpu::VertexStepMode::Vertex,
@ -105,21 +107,29 @@ pub mod tile {
}, },
], ],
}, },
// tile metadata
wgpu::VertexBufferLayout { wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<ShaderTileMetadata>() as u64, array_stride: std::mem::size_of::<ShaderTileMetadata>() as u64,
step_mode: wgpu::VertexStepMode::Instance, step_mode: wgpu::VertexStepMode::Instance,
attributes: &[
// translate
wgpu::VertexAttribute {
offset: 0,
format: wgpu::VertexFormat::Float32x3,
shader_location: 4,
},
],
},
// vertex style
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<ShaderTileMetadata>() as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[ attributes: &[
// color // color
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: 0, offset: 0,
format: wgpu::VertexFormat::Float32x4, format: wgpu::VertexFormat::Float32x4,
shader_location: 3, shader_location: 5,
},
// translate
wgpu::VertexAttribute {
offset: wgpu::VertexFormat::Float32x4.size(),
format: wgpu::VertexFormat::Float32x3,
shader_location: 4,
}, },
], ],
}, },
@ -130,7 +140,18 @@ pub mod tile {
include_str!("tile.fragment.wgsl"), include_str!("tile.fragment.wgsl"),
&[wgpu::ColorTargetState { &[wgpu::ColorTargetState {
format: COLOR_TEXTURE_FORMAT, format: COLOR_TEXTURE_FORMAT,
blend: None, blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::SrcAlpha,
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
operation: wgpu::BlendOperation::Add,
},
alpha: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::SrcAlpha,
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
operation: wgpu::BlendOperation::Add,
},
}),
write_mask: wgpu::ColorWrites::ALL, write_mask: wgpu::ColorWrites::ALL,
}], }],
); );
@ -281,18 +302,22 @@ impl ShaderTileMaskInstance {
} }
} }
#[repr(C)]
#[derive(Debug, Copy, Clone, Pod, Zeroable)]
pub struct ShaderFeatureStyle {
pub color: Vec4f32,
}
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)] #[derive(Copy, Clone, Pod, Zeroable)]
pub struct ShaderTileMetadata { pub struct ShaderTileMetadata {
pub color: Vec4f32,
pub translate: Vec3f32, pub translate: Vec3f32,
_pad1: i32, // _padX aligns it to 16 bytes = AlignOf(Vec4f32/vec4<f32>): // https://gpuweb.github.io/gpuweb/wgsl/#alignment-and-size _pad1: i32, // _padX aligns it to 16 bytes = AlignOf(Vec4f32/vec4<f32>): // https://gpuweb.github.io/gpuweb/wgsl/#alignment-and-size
} }
impl ShaderTileMetadata { impl ShaderTileMetadata {
pub fn new(color: Vec4f32, translate: Vec3f32) -> Self { pub fn new(translate: Vec3f32) -> Self {
Self { Self {
color,
translate, translate,
_pad1: Default::default(), _pad1: Default::default(),
} }

View File

@ -18,8 +18,8 @@ struct VertexOutput {
fn main( fn main(
[[location(0)]] position: vec2<f32>, [[location(0)]] position: vec2<f32>,
[[location(1)]] normal: vec2<f32>, [[location(1)]] normal: vec2<f32>,
[[location(3)]] color: vec4<f32>,
[[location(4)]] translate: vec3<f32>, [[location(4)]] translate: vec3<f32>,
[[location(5)]] color: vec4<f32>,
[[builtin(instance_index)]] instance_idx: u32 // instance_index is used when we have multiple instances of the same "object" [[builtin(instance_index)]] instance_idx: u32 // instance_index is used when we have multiple instances of the same "object"
) -> VertexOutput { ) -> VertexOutput {
let z = 0.0; let z = 0.0;