Skip to main content

anvilkit_render/renderer/
assets.rs

1//! # GPU 资产管理
2//!
3//! 管理 GPU 端的网格和材质资源,提供 Handle-based 的资产引用系统。
4//! 支持管线共享:多个材质可引用同一渲染管线,避免重复创建。
5
6use std::collections::HashMap;
7use std::sync::atomic::{AtomicU64, Ordering};
8
9use bevy_ecs::prelude::*;
10use wgpu::{Buffer, RenderPipeline, BindGroup, IndexFormat};
11
12use crate::renderer::RenderDevice;
13use crate::renderer::buffer::{Vertex, create_vertex_buffer, create_index_buffer, create_index_buffer_u32};
14
15static NEXT_HANDLE_ID: AtomicU64 = AtomicU64::new(1);
16
17fn next_id() -> u64 {
18    NEXT_HANDLE_ID.fetch_add(1, Ordering::Relaxed)
19}
20
21/// 网格 GPU 句柄
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Component)]
23pub struct MeshHandle(pub u64);
24
25impl MeshHandle {
26    /// 获取内部 ID(用于排序和批处理)
27    pub fn index(&self) -> u64 { self.0 }
28}
29
30/// 材质 GPU 句柄
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Component)]
32pub struct MaterialHandle(pub u64);
33
34impl MaterialHandle {
35    /// 获取内部 ID(用于排序和批处理)
36    pub fn index(&self) -> u64 { self.0 }
37}
38
39/// 渲染管线句柄
40///
41/// 多个材质可引用同一管线,减少 GPU 管线对象的数量。
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43pub struct PipelineHandle(pub u64);
44
45/// GPU 端网格数据
46pub struct GpuMesh {
47    pub vertex_buffer: Buffer,
48    pub index_buffer: Buffer,
49    pub index_count: u32,
50    pub index_format: IndexFormat,
51}
52
53/// GPU 端材质数据
54///
55/// 材质通过 [`PipelineHandle`] 引用共享管线,而非直接持有 `RenderPipeline`。
56pub struct GpuMaterial {
57    pub pipeline_handle: PipelineHandle,
58    pub bind_group: BindGroup,
59}
60
61/// GPU 资产存储
62///
63/// 管理所有已上传到 GPU 的网格、材质和渲染管线资源。
64#[derive(Resource, Default)]
65pub struct RenderAssets {
66    meshes: HashMap<MeshHandle, GpuMesh>,
67    materials: HashMap<MaterialHandle, GpuMaterial>,
68    pipelines: HashMap<PipelineHandle, RenderPipeline>,
69}
70
71impl RenderAssets {
72    /// 上传网格到 GPU 并返回句柄
73    pub fn upload_mesh<V: Vertex>(
74        &mut self,
75        device: &RenderDevice,
76        vertices: &[V],
77        indices: &[u16],
78        label: &str,
79    ) -> MeshHandle {
80        let vertex_buffer = create_vertex_buffer(device, &format!("{} VB", label), vertices);
81        let index_buffer = create_index_buffer(device, &format!("{} IB", label), indices);
82        let handle = MeshHandle(next_id());
83        self.meshes.insert(handle, GpuMesh {
84            vertex_buffer,
85            index_buffer,
86            index_count: indices.len() as u32,
87            index_format: IndexFormat::Uint16,
88        });
89        handle
90    }
91
92    /// 上传网格到 GPU(u32 索引)并返回句柄
93    pub fn upload_mesh_u32<V: Vertex>(
94        &mut self,
95        device: &RenderDevice,
96        vertices: &[V],
97        indices: &[u32],
98        label: &str,
99    ) -> MeshHandle {
100        let vertex_buffer = create_vertex_buffer(device, &format!("{} VB", label), vertices);
101        let index_buffer = create_index_buffer_u32(device, &format!("{} IB", label), indices);
102        let handle = MeshHandle(next_id());
103        self.meshes.insert(handle, GpuMesh {
104            vertex_buffer,
105            index_buffer,
106            index_count: indices.len() as u32,
107            index_format: IndexFormat::Uint32,
108        });
109        handle
110    }
111
112    /// 注册渲染管线并返回句柄
113    ///
114    /// 注册后的管线可被多个材质共享引用。
115    pub fn register_pipeline(&mut self, pipeline: RenderPipeline) -> PipelineHandle {
116        let handle = PipelineHandle(next_id());
117        self.pipelines.insert(handle, pipeline);
118        handle
119    }
120
121    /// 创建引用共享管线的材质
122    ///
123    /// # 参数
124    ///
125    /// - `pipeline_handle`: 通过 [`register_pipeline`](Self::register_pipeline) 获得的管线句柄
126    /// - `bind_group`: 材质专属的绑定组
127    pub fn create_material_with_pipeline(
128        &mut self,
129        pipeline_handle: PipelineHandle,
130        bind_group: BindGroup,
131    ) -> MaterialHandle {
132        let handle = MaterialHandle(next_id());
133        self.materials.insert(handle, GpuMaterial {
134            pipeline_handle,
135            bind_group,
136        });
137        handle
138    }
139
140    /// 创建材质并返回句柄(向后兼容 API)
141    ///
142    /// 内部自动注册管线并创建材质。适用于不需要管线共享的场景。
143    pub fn create_material(
144        &mut self,
145        pipeline: RenderPipeline,
146        bind_group: BindGroup,
147    ) -> MaterialHandle {
148        let pipeline_handle = self.register_pipeline(pipeline);
149        self.create_material_with_pipeline(pipeline_handle, bind_group)
150    }
151
152    /// 获取 GPU 网格
153    pub fn get_mesh(&self, handle: &MeshHandle) -> Option<&GpuMesh> {
154        self.meshes.get(handle)
155    }
156
157    /// 获取 GPU 材质
158    pub fn get_material(&self, handle: &MaterialHandle) -> Option<&GpuMaterial> {
159        self.materials.get(handle)
160    }
161
162    /// 获取渲染管线
163    pub fn get_pipeline(&self, handle: &PipelineHandle) -> Option<&RenderPipeline> {
164        self.pipelines.get(handle)
165    }
166
167    /// 移除 GPU 网格资源,释放顶点和索引缓冲区
168    pub fn remove_mesh(&mut self, handle: &MeshHandle) -> bool {
169        self.meshes.remove(handle).is_some()
170    }
171
172    /// 移除 GPU 材质资源,释放绑定组
173    pub fn remove_material(&mut self, handle: &MaterialHandle) -> bool {
174        self.materials.remove(handle).is_some()
175    }
176
177    /// 移除渲染管线
178    ///
179    /// 注意:如果仍有材质引用此管线,那些材质的渲染将失败。
180    /// 调用者应确保先移除所有引用此管线的材质。
181    pub fn remove_pipeline(&mut self, handle: &PipelineHandle) -> bool {
182        self.pipelines.remove(handle).is_some()
183    }
184
185    /// 已注册的网格数量
186    pub fn mesh_count(&self) -> usize {
187        self.meshes.len()
188    }
189
190    /// 已注册的材质数量
191    pub fn material_count(&self) -> usize {
192        self.materials.len()
193    }
194
195    /// 已注册的管线数量
196    pub fn pipeline_count(&self) -> usize {
197        self.pipelines.len()
198    }
199}