myth_render/core/gpu/
geometry.rs1use std::ops::Range;
4
5use crate::core::gpu::generate_gpu_resource_id;
6use crate::pipeline::vertex::GeneratedVertexLayout;
7use myth_assets::{AssetServer, GeometryHandle};
8use myth_resources::geometry::Geometry;
9
10use super::ResourceManager;
11
12pub struct GpuGeometry {
16 pub layout_info: GeneratedVertexLayout,
17 pub layout_id: u64,
18 pub vertex_buffers: Vec<wgpu::Buffer>,
19 pub vertex_buffer_ids: Vec<u64>,
20 pub index_buffer: Option<(wgpu::Buffer, wgpu::IndexFormat, u32, u64)>,
21 pub draw_range: Range<u32>,
22 pub instance_range: Range<u32>,
23 pub version: u64,
24 pub last_data_version: u64,
25 pub last_used_frame: u64,
26}
27
28#[derive(Debug, Clone)]
32#[allow(dead_code)]
33pub struct GeometryPrepareResult {
34 pub vertex_buffer_ids: Vec<u64>,
35 pub index_buffer_id: Option<u64>,
36 pub any_recreated: bool,
37}
38
39impl ResourceManager {
40 pub(crate) fn prepare_geometry(
44 &mut self,
45 assets: &AssetServer,
46 handle: GeometryHandle,
47 ) -> Option<GeometryPrepareResult> {
48 let geometry = assets.geometries.get(handle)?;
49
50 if let Some(gpu_geo) = self.gpu_geometries.get_mut(handle)
52 && geometry.structure_version() == gpu_geo.version
53 && geometry.data_version() == gpu_geo.last_data_version
54 {
55 gpu_geo.last_used_frame = self.frame_index;
56 return Some(GeometryPrepareResult {
57 vertex_buffer_ids: gpu_geo.vertex_buffer_ids.clone(),
58 index_buffer_id: gpu_geo.index_buffer.as_ref().map(|(_, _, _, id)| *id),
59 any_recreated: false,
60 });
61 }
62
63 let mut any_buffer_recreated = false;
65 let mut new_vertex_ids = Vec::new();
66
67 for attr in geometry.attributes().values() {
68 let result = self.prepare_attribute(attr);
69 new_vertex_ids.push(result.resource_id);
70 if result.was_recreated {
71 any_buffer_recreated = true;
72 }
73 }
74
75 let mut new_index_id = None;
76 if let Some(indices) = geometry.index_attribute() {
77 let result = self.prepare_index(indices);
78 new_index_id = Some(result.resource_id);
79 if result.was_recreated {
80 any_buffer_recreated = true;
81 }
82 }
83
84 let needs_rebuild = if let Some(gpu_geo) = self.gpu_geometries.get(handle) {
86 geometry.structure_version() > gpu_geo.version
87 || any_buffer_recreated
88 || gpu_geo.vertex_buffer_ids != new_vertex_ids
89 } else {
90 true
91 };
92
93 if needs_rebuild {
94 self.create_gpu_geometry(&geometry, handle);
95 } else {
96 if let Some(gpu_geo) = self.gpu_geometries.get_mut(handle) {
98 gpu_geo.last_data_version = geometry.data_version();
99 }
100 }
101
102 if let Some(gpu_geo) = self.gpu_geometries.get_mut(handle) {
103 gpu_geo.last_used_frame = self.frame_index;
104 Some(GeometryPrepareResult {
105 vertex_buffer_ids: gpu_geo.vertex_buffer_ids.clone(),
106 index_buffer_id: new_index_id,
107 any_recreated: any_buffer_recreated || needs_rebuild,
108 })
109 } else {
110 None
111 }
112 }
113
114 fn create_gpu_geometry(&mut self, geometry: &Geometry, handle: GeometryHandle) {
115 let layout_info = crate::pipeline::vertex::generate_vertex_layout(geometry);
116
117 let layout_id = self.get_or_create_vertex_layout_id(&layout_info);
118
119 let mut vertex_buffers = Vec::new();
120 let mut vertex_buffer_ids = Vec::new();
121
122 for layout_desc in &layout_info.buffers {
123 let gpu_buf = self
124 .get_gpu_buffer_by_cpu_id(layout_desc.buffer.id())
125 .expect("Vertex buffer should be prepared");
126 vertex_buffers.push(gpu_buf.buffer.clone());
127 vertex_buffer_ids.push(gpu_buf.id);
128 }
129
130 let index_buffer = if let Some(indices) = geometry.index_attribute() {
131 let gpu_buf = self
132 .get_gpu_buffer_by_cpu_id(indices.buffer.id())
133 .expect("Index buffer should be prepared");
134 Some((
135 gpu_buf.buffer.clone(),
136 indices.format,
137 indices.count,
138 gpu_buf.id,
139 ))
140 } else {
141 None
142 };
143
144 let mut draw_range = geometry.draw_range.clone();
145 if draw_range == (0..u32::MAX) {
146 if let Some(attr) = geometry.attributes().get("position") {
147 draw_range = draw_range.start..std::cmp::min(attr.count, draw_range.end);
148 } else if let Some(attr) = geometry.attributes().values().next() {
149 draw_range = draw_range.start..std::cmp::min(attr.count, draw_range.end);
150 } else {
151 draw_range = 0..0;
152 }
153 }
154
155 let gpu_geo = GpuGeometry {
156 layout_info,
157 layout_id,
158 vertex_buffers,
159 vertex_buffer_ids,
160 index_buffer,
161 draw_range,
162 instance_range: 0..1,
163 version: geometry.structure_version(),
164 last_data_version: geometry.data_version(),
165 last_used_frame: self.frame_index,
166 };
167
168 self.gpu_geometries.insert(handle, gpu_geo);
169 }
170
171 pub fn get_geometry(&self, handle: GeometryHandle) -> Option<&GpuGeometry> {
172 self.gpu_geometries.get(handle)
173 }
174
175 pub fn get_or_create_vertex_layout_id(&mut self, layout: &GeneratedVertexLayout) -> u64 {
176 let signature = layout.to_signature();
177
178 if let Some(&id) = self.vertex_layout_cache.get(&signature) {
179 return id;
180 }
181
182 let id = generate_gpu_resource_id();
183 self.vertex_layout_cache.insert(signature, id);
184 id
185 }
186}