Skip to main content

sable_gpu/
buffer.rs

1//! GPU buffer types for vertex, index, and uniform data.
2
3#![allow(clippy::cast_possible_truncation)]
4
5use bytemuck::Pod;
6use wgpu::{Device, util::DeviceExt};
7
8use crate::vertex::Vertex;
9
10/// Buffer usage flags.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum BufferUsage {
13    /// Vertex buffer.
14    Vertex,
15    /// Index buffer.
16    Index,
17    /// Uniform buffer.
18    Uniform,
19    /// Storage buffer (read/write from shaders).
20    Storage,
21    /// Indirect buffer for indirect draw commands.
22    Indirect,
23}
24
25impl From<BufferUsage> for wgpu::BufferUsages {
26    fn from(usage: BufferUsage) -> Self {
27        match usage {
28            BufferUsage::Vertex => wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
29            BufferUsage::Index => wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
30            BufferUsage::Uniform => wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
31            BufferUsage::Storage => {
32                wgpu::BufferUsages::STORAGE
33                    | wgpu::BufferUsages::COPY_DST
34                    | wgpu::BufferUsages::COPY_SRC
35            }
36            BufferUsage::Indirect => wgpu::BufferUsages::INDIRECT | wgpu::BufferUsages::COPY_DST,
37        }
38    }
39}
40
41/// A GPU buffer with type information.
42#[derive(Debug)]
43pub struct Buffer {
44    inner: wgpu::Buffer,
45    usage: BufferUsage,
46    size: u64,
47}
48
49impl Buffer {
50    /// Create a new buffer with initial data.
51    #[must_use]
52    pub fn new<T: Pod>(
53        device: &Device,
54        usage: BufferUsage,
55        data: &[T],
56        label: Option<&str>,
57    ) -> Self {
58        let inner = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
59            label,
60            contents: bytemuck::cast_slice(data),
61            usage: usage.into(),
62        });
63
64        Self {
65            inner,
66            usage,
67            size: std::mem::size_of_val(data) as u64,
68        }
69    }
70
71    /// Create an empty buffer with the specified size.
72    #[must_use]
73    pub fn empty(device: &Device, usage: BufferUsage, size: u64, label: Option<&str>) -> Self {
74        let inner = device.create_buffer(&wgpu::BufferDescriptor {
75            label,
76            size,
77            usage: usage.into(),
78            mapped_at_creation: false,
79        });
80
81        Self { inner, usage, size }
82    }
83
84    /// Get a reference to the underlying wgpu buffer.
85    #[must_use]
86    pub fn inner(&self) -> &wgpu::Buffer {
87        &self.inner
88    }
89
90    /// Get the buffer usage.
91    #[must_use]
92    pub fn usage(&self) -> BufferUsage {
93        self.usage
94    }
95
96    /// Get the buffer size in bytes.
97    #[must_use]
98    pub fn size(&self) -> u64 {
99        self.size
100    }
101
102    /// Get a buffer slice for the entire buffer.
103    #[must_use]
104    pub fn slice(&self) -> wgpu::BufferSlice<'_> {
105        self.inner.slice(..)
106    }
107}
108
109/// A typed vertex buffer.
110#[derive(Debug)]
111pub struct VertexBuffer<V: Vertex> {
112    buffer: Buffer,
113    vertex_count: u32,
114    _marker: std::marker::PhantomData<V>,
115}
116
117impl<V: Vertex> VertexBuffer<V> {
118    /// Create a new vertex buffer from vertices.
119    #[must_use]
120    pub fn new(device: &Device, vertices: &[V]) -> Self {
121        let buffer = Buffer::new(device, BufferUsage::Vertex, vertices, Some("Vertex Buffer"));
122
123        Self {
124            buffer,
125            vertex_count: vertices.len() as u32,
126            _marker: std::marker::PhantomData,
127        }
128    }
129
130    /// Create a new vertex buffer with a custom label.
131    #[must_use]
132    pub fn with_label(device: &Device, vertices: &[V], label: &str) -> Self {
133        let buffer = Buffer::new(device, BufferUsage::Vertex, vertices, Some(label));
134
135        Self {
136            buffer,
137            vertex_count: vertices.len() as u32,
138            _marker: std::marker::PhantomData,
139        }
140    }
141
142    /// Get the number of vertices in the buffer.
143    #[must_use]
144    pub fn vertex_count(&self) -> u32 {
145        self.vertex_count
146    }
147
148    /// Get a reference to the underlying buffer.
149    #[must_use]
150    pub fn buffer(&self) -> &Buffer {
151        &self.buffer
152    }
153
154    /// Get a buffer slice for the entire buffer.
155    #[must_use]
156    pub fn slice(&self) -> wgpu::BufferSlice<'_> {
157        self.buffer.slice()
158    }
159}
160
161/// An index buffer for indexed drawing.
162#[derive(Debug)]
163pub struct IndexBuffer {
164    buffer: Buffer,
165    index_count: u32,
166    format: wgpu::IndexFormat,
167}
168
169impl IndexBuffer {
170    /// Create a new index buffer from 16-bit indices.
171    #[must_use]
172    pub fn new_u16(device: &Device, indices: &[u16]) -> Self {
173        let buffer = Buffer::new(device, BufferUsage::Index, indices, Some("Index Buffer"));
174
175        Self {
176            buffer,
177            index_count: indices.len() as u32,
178            format: wgpu::IndexFormat::Uint16,
179        }
180    }
181
182    /// Create a new index buffer from 32-bit indices.
183    #[must_use]
184    pub fn new_u32(device: &Device, indices: &[u32]) -> Self {
185        let buffer = Buffer::new(device, BufferUsage::Index, indices, Some("Index Buffer"));
186
187        Self {
188            buffer,
189            index_count: indices.len() as u32,
190            format: wgpu::IndexFormat::Uint32,
191        }
192    }
193
194    /// Get the number of indices in the buffer.
195    #[must_use]
196    pub fn index_count(&self) -> u32 {
197        self.index_count
198    }
199
200    /// Get the index format.
201    #[must_use]
202    pub fn format(&self) -> wgpu::IndexFormat {
203        self.format
204    }
205
206    /// Get a reference to the underlying buffer.
207    #[must_use]
208    pub fn buffer(&self) -> &Buffer {
209        &self.buffer
210    }
211
212    /// Get a buffer slice for the entire buffer.
213    #[must_use]
214    pub fn slice(&self) -> wgpu::BufferSlice<'_> {
215        self.buffer.slice()
216    }
217}