Skip to main content

cvkg_render_gpu/subsystems/
geometry_buffers.rs

1//! P1-1 (phase 6): GeometryBuffers -- the three GPU draw buffers.
2//!
3//! Extracted from types.rs so the buffer management subsystem
4//! has its own module. The SurtrRenderer holds a single
5//! `GeometryBuffers` field; the three buffers are accessed via
6//! `renderer.geometry_buffers.{vertex,index,instance}_buffer`.
7
8use crate::vertex::{InstanceData, Vertex};
9
10/// Group of three GPU buffers used for geometry rendering:
11/// vertex, index, and instance. Owned by the renderer and used
12/// for every draw call.
13pub struct GeometryBuffers {
14    /// Vertex buffer. Stores `Vertex` (position + normal + uv + color).
15    pub vertex_buffer: wgpu::Buffer,
16    /// Index buffer. Stores u32 indices into the vertex buffer.
17    pub index_buffer: wgpu::Buffer,
18    /// Instance buffer. Stores `InstanceData` for instanced rendering.
19    pub instance_buffer: wgpu::Buffer,
20    /// Capacity in vertices (used to size the vertex and instance buffers).
21    pub max_vertices: usize,
22    /// Capacity in indices (used to size the index buffer).
23    pub max_indices: usize,
24}
25
26impl GeometryBuffers {
27    /// Create the three geometry buffers on the given device with
28    /// the given capacities. The buffers are immediately usable
29    /// for COPY_DST writes.
30    pub fn forge(
31        device: &wgpu::Device,
32        max_vertices: usize,
33        max_indices: usize,
34    ) -> Self {
35        let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
36            label: Some("Surtr Vertex Anvil"),
37            size: (max_vertices * std::mem::size_of::<Vertex>()) as u64,
38            usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
39            mapped_at_creation: false,
40        });
41        let index_buffer = device.create_buffer(&wgpu::BufferDescriptor {
42            label: Some("Surtr Index Anvil"),
43            size: (max_indices * std::mem::size_of::<u32>()) as u64,
44            usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
45            mapped_at_creation: false,
46        });
47        let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {
48            label: Some("Surtr Instance Anvil"),
49            size: (max_vertices / 4 * std::mem::size_of::<InstanceData>()) as u64,
50            usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
51            mapped_at_creation: false,
52        });
53        Self {
54            vertex_buffer,
55            index_buffer,
56            instance_buffer,
57            max_vertices,
58            max_indices,
59        }
60    }
61
62    /// Total VRAM cost of the three buffers in bytes.
63    pub fn vram_bytes(&self) -> u64 {
64        let vertex_bytes = self.max_vertices * std::mem::size_of::<Vertex>();
65        let index_bytes = self.max_indices * std::mem::size_of::<u32>();
66        let instance_bytes =
67            (self.max_vertices / 4) * std::mem::size_of::<InstanceData>();
68        (vertex_bytes + index_bytes + instance_bytes) as u64
69    }
70
71    /// Grow the vertex buffer to accommodate at least `min_capacity`
72    /// vertices. Returns true if the buffer was actually
73    /// reallocated (i.e., the previous capacity was too small).
74    /// Returns false if the buffer was already large enough,
75    /// avoiding the expensive `device.create_buffer()` call.
76    pub fn grow_vertex_buffer(
77        &mut self,
78        device: &wgpu::Device,
79        min_capacity: usize,
80        max_capacity: usize,
81    ) -> bool {
82        let current = self.vertex_buffer.size() as usize
83            / std::mem::size_of::<Vertex>();
84        if min_capacity <= current {
85            return false;
86        }
87        let new_size = (min_capacity.min(max_capacity.max(min_capacity)))
88            * std::mem::size_of::<Vertex>();
89        self.vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
90            label: Some("Vertex Buffer (Grown)"),
91            size: new_size as u64,
92            usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
93            mapped_at_creation: false,
94        });
95        true
96    }
97
98    /// Grow the index buffer to accommodate at least `min_capacity`
99    /// indices. Returns true if the buffer was actually
100    /// reallocated. Returns false if the buffer was already
101    /// large enough.
102    pub fn grow_index_buffer(
103        &mut self,
104        device: &wgpu::Device,
105        min_capacity: usize,
106        max_capacity: usize,
107    ) -> bool {
108        let current = self.index_buffer.size() as usize
109            / std::mem::size_of::<u32>();
110        if min_capacity <= current {
111            return false;
112        }
113        let new_size = (min_capacity.min(max_capacity.max(min_capacity)))
114            * std::mem::size_of::<u32>();
115        self.index_buffer = device.create_buffer(&wgpu::BufferDescriptor {
116            label: Some("Index Buffer (Grown)"),
117            size: new_size as u64,
118            usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
119            mapped_at_creation: false,
120        });
121        true
122    }
123}