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 GpuRenderer 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(device: &wgpu::Device, max_vertices: usize, max_indices: usize) -> Self {
31        let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
32            label: Some("Surtr Vertex Anvil"),
33            size: (max_vertices * std::mem::size_of::<Vertex>()) as u64,
34            usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
35            mapped_at_creation: false,
36        });
37        let index_buffer = device.create_buffer(&wgpu::BufferDescriptor {
38            label: Some("Surtr Index Anvil"),
39            size: (max_indices * std::mem::size_of::<u32>()) as u64,
40            usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
41            mapped_at_creation: false,
42        });
43        let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {
44            label: Some("Surtr Instance Anvil"),
45            size: (max_vertices / 4 * std::mem::size_of::<InstanceData>()) as u64,
46            usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
47            mapped_at_creation: false,
48        });
49        Self {
50            vertex_buffer,
51            index_buffer,
52            instance_buffer,
53            max_vertices,
54            max_indices,
55        }
56    }
57
58    /// Total VRAM cost of the three buffers in bytes.
59    pub fn vram_bytes(&self) -> u64 {
60        let vertex_bytes = self.max_vertices * std::mem::size_of::<Vertex>();
61        let index_bytes = self.max_indices * std::mem::size_of::<u32>();
62        let instance_bytes = (self.max_vertices / 4) * std::mem::size_of::<InstanceData>();
63        (vertex_bytes + index_bytes + instance_bytes) as u64
64    }
65
66    /// Grow the vertex buffer to accommodate at least `min_capacity`
67    /// vertices. Returns true if the buffer was actually
68    /// reallocated (i.e., the previous capacity was too small).
69    /// Returns false if the buffer was already large enough,
70    /// avoiding the expensive `device.create_buffer()` call.
71    pub fn grow_vertex_buffer(
72        &mut self,
73        device: &wgpu::Device,
74        min_capacity: usize,
75        max_capacity: usize,
76    ) -> bool {
77        let current = self.vertex_buffer.size() as usize / std::mem::size_of::<Vertex>();
78        if min_capacity <= current {
79            return false;
80        }
81        let new_size = (min_capacity.min(max_capacity)) * std::mem::size_of::<Vertex>();
82        self.vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
83            label: Some("Vertex Buffer (Grown)"),
84            size: new_size as u64,
85            usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
86            mapped_at_creation: false,
87        });
88        true
89    }
90
91    /// Grow the index buffer to accommodate at least `min_capacity`
92    /// indices. Returns true if the buffer was actually
93    /// reallocated. Returns false if the buffer was already
94    /// large enough.
95    pub fn grow_index_buffer(
96        &mut self,
97        device: &wgpu::Device,
98        min_capacity: usize,
99        max_capacity: usize,
100    ) -> bool {
101        let current = self.index_buffer.size() as usize / std::mem::size_of::<u32>();
102        if min_capacity <= current {
103            return false;
104        }
105        let new_size = (min_capacity.min(max_capacity)) * std::mem::size_of::<u32>();
106        self.index_buffer = device.create_buffer(&wgpu::BufferDescriptor {
107            label: Some("Index Buffer (Grown)"),
108            size: new_size as u64,
109            usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
110            mapped_at_creation: false,
111        });
112        true
113    }
114}