use bytemuck::{Pod, Zeroable};
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct QuadInstance {
pub pos: [f32; 2],
pub quad_size: [f32; 2],
pub color: [f32; 4],
pub border_radii: [f32; 4], pub border_color: [f32; 4],
pub border_widths: [f32; 4], pub shadow_color: [f32; 4],
pub shadow_offset: [f32; 4], pub shadow_params: [f32; 4], pub effects: [f32; 4], pub clip_rect: [f32; 4], }
impl QuadInstance {
pub const ATTRIBS: [wgpu::VertexAttribute; 11] = [
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
offset: 8,
shader_location: 1,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 16,
shader_location: 2,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 32,
shader_location: 3,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 48,
shader_location: 4,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 64,
shader_location: 5,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 80,
shader_location: 6,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 96,
shader_location: 7,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 112,
shader_location: 8,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 128,
shader_location: 9,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 144,
shader_location: 10,
},
];
pub fn desc() -> wgpu::VertexBufferLayout<'static> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Instance,
attributes: &Self::ATTRIBS,
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct SolidPushConstants {
pub screen_size: [f32; 2],
}
pub struct QuadBatch {
pub buffer: wgpu::Buffer,
pub capacity: usize,
}
impl QuadBatch {
pub fn new(device: &wgpu::Device) -> Self {
let capacity = 1024;
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Quad Instance Vertex Buffer"),
size: (capacity * std::mem::size_of::<QuadInstance>()) as u64,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
Self { buffer, capacity }
}
pub fn ensure_capacity(&mut self, device: &wgpu::Device, count: usize) {
if count > self.capacity {
self.capacity = (count * 2).max(1024);
self.buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Quad Instance Vertex Buffer"),
size: (self.capacity * std::mem::size_of::<QuadInstance>()) as u64,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
}
}
pub fn upload(&self, queue: &wgpu::Queue, instances: &[QuadInstance]) {
if !instances.is_empty() {
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(instances));
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_quad_instance_layout() {
assert_eq!(std::mem::size_of::<QuadInstance>(), 160);
assert_eq!(std::mem::align_of::<QuadInstance>(), 4);
assert_eq!(std::mem::size_of::<SolidPushConstants>(), 8);
let desc = QuadInstance::desc();
assert_eq!(desc.array_stride, 160);
assert_eq!(desc.step_mode, wgpu::VertexStepMode::Instance);
assert_eq!(desc.attributes.len(), 11);
assert_eq!(desc.attributes[0].offset, 0);
assert_eq!(desc.attributes[1].offset, 8);
assert_eq!(desc.attributes[2].offset, 16);
assert_eq!(desc.attributes[3].offset, 32);
assert_eq!(desc.attributes[4].offset, 48);
assert_eq!(desc.attributes[5].offset, 64);
assert_eq!(desc.attributes[6].offset, 80);
assert_eq!(desc.attributes[7].offset, 96);
assert_eq!(desc.attributes[8].offset, 112);
assert_eq!(desc.attributes[9].offset, 128);
assert_eq!(desc.attributes[10].offset, 144);
}
}