ursus_core/assets/storage/
mesh.rs1use crate::assets::mesh::{Aabb, CpuMesh};
2use crate::vulkan::core::memory::alloc_buffer;
3use crate::vulkan::core::DeviceContext;
4use ash::vk;
5use std::collections::HashMap;
6use ursus_ecs::components::mesh::MeshHandle;
7
8enum GpuMeshState {
9 Ready(Box<GpuMesh>),
10 Failed,
11}
12
13pub struct MeshStore {
15 meshes: HashMap<MeshHandle, GpuMeshState>,
16 device: ash::Device,
17 physical_device: vk::PhysicalDevice,
18 instance: ash::Instance,
19 command_pool: vk::CommandPool,
20 queue: vk::Queue,
21}
22
23impl MeshStore {
24 pub fn new(
25 device: ash::Device,
26 physical_device: vk::PhysicalDevice,
27 instance: ash::Instance,
28 command_pool: vk::CommandPool,
29 queue: vk::Queue,
30 ) -> Self {
31 Self { meshes: HashMap::new(), device, physical_device, instance, command_pool, queue }
32 }
33
34 pub fn upload(&mut self, handle: MeshHandle, cpu_mesh: &CpuMesh) -> anyhow::Result<()> {
35 match GpuMesh::upload(
36 &self.device,
37 self.physical_device,
38 &self.instance,
39 cpu_mesh,
40 self.command_pool,
41 self.queue,
42 ) {
43 Ok(gpu) => {
44 self.meshes.insert(handle, GpuMeshState::Ready(Box::new(gpu)));
45 Ok(())
46 }
47 Err(e) => {
48 self.meshes.insert(handle, GpuMeshState::Failed);
49 Err(e)
50 }
51 }
52 }
53
54 pub fn get(&self, handle: MeshHandle) -> Option<&GpuMesh> {
55 match self.meshes.get(&handle)? {
56 GpuMeshState::Ready(gpu) => Some(gpu),
57 GpuMeshState::Failed => None,
58 }
59 }
60
61 pub fn is_ready(&self, handle: MeshHandle) -> bool {
62 matches!(self.meshes.get(&handle), Some(GpuMeshState::Ready(_)))
63 }
64}
65
66pub struct GpuMesh {
67 pub vertex_buffer: vk::Buffer,
68 pub index_buffer: vk::Buffer,
69 pub vertex_memory: vk::DeviceMemory,
70 pub index_memory: vk::DeviceMemory,
71 pub index_count: u32,
72 pub vertex_count: u32,
73 pub name: String,
74 pub aabb: Aabb,
75 device: ash::Device,
76}
77
78impl GpuMesh {
79 pub fn upload(
80 device: &ash::Device,
81 physical_device: vk::PhysicalDevice,
82 instance: &ash::Instance,
83 cpu_mesh: &CpuMesh,
84 command_pool: vk::CommandPool,
85 queue: vk::Queue,
86 ) -> anyhow::Result<Self> {
87 let vertex_data: &[u8] = bytemuck::cast_slice(&cpu_mesh.vertices);
88 let index_data: &[u8] = bytemuck::cast_slice(&cpu_mesh.indices);
89
90 let (vertex_buffer, vertex_memory) = create_buffer_with_data(
91 device,
92 instance,
93 physical_device,
94 vertex_data,
95 vk::BufferUsageFlags::VERTEX_BUFFER,
96 command_pool,
97 queue,
98 )?;
99 let (index_buffer, index_memory) = create_buffer_with_data(
100 device,
101 instance,
102 physical_device,
103 index_data,
104 vk::BufferUsageFlags::INDEX_BUFFER,
105 command_pool,
106 queue,
107 )?;
108
109 log::debug!("GpuMesh '{}': {} verts, {} idx", cpu_mesh.name, cpu_mesh.vertex_count(), cpu_mesh.index_count());
110
111 Ok(Self {
112 vertex_buffer,
113 index_buffer,
114 vertex_memory,
115 index_memory,
116 index_count: cpu_mesh.index_count(),
117 vertex_count: cpu_mesh.vertex_count(),
118 name: cpu_mesh.name.clone(),
119 aabb: Aabb::from_vertices(&cpu_mesh.vertices),
120 device: device.clone(),
121 })
122 }
123}
124
125impl Drop for GpuMesh {
126 fn drop(&mut self) {
127 unsafe {
128 self.device.destroy_buffer(self.vertex_buffer, None);
129 self.device.free_memory(self.vertex_memory, None);
130 self.device.destroy_buffer(self.index_buffer, None);
131 self.device.free_memory(self.index_memory, None);
132 }
133 log::debug!("GpuMesh '{}' выгружен", self.name);
134 }
135}
136
137fn copy_buffer(
138 device: &ash::Device,
139 command_pool: vk::CommandPool,
140 queue: vk::Queue,
141 src: vk::Buffer,
142 dst: vk::Buffer,
143 size: vk::DeviceSize,
144) -> anyhow::Result<()> {
145 let alloc_info = vk::CommandBufferAllocateInfo::default()
146 .command_pool(command_pool)
147 .level(vk::CommandBufferLevel::PRIMARY)
148 .command_buffer_count(1);
149 let cmd = unsafe { device.allocate_command_buffers(&alloc_info)?[0] };
150 unsafe {
151 device.begin_command_buffer(
152 cmd,
153 &vk::CommandBufferBeginInfo::default().flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT),
154 )?;
155 device.cmd_copy_buffer(cmd, src, dst, &[vk::BufferCopy::default().size(size)]);
156 device.end_command_buffer(cmd)?;
157 device.queue_submit(
158 queue,
159 &[vk::SubmitInfo::default().command_buffers(std::slice::from_ref(&cmd))],
160 vk::Fence::null(),
161 )?;
162 device.queue_wait_idle(queue)?;
163 device.free_command_buffers(command_pool, &[cmd]);
164 }
165 Ok(())
166}
167
168fn create_buffer_with_data(
169 device: &ash::Device,
170 instance: &ash::Instance,
171 physical_device: vk::PhysicalDevice,
172 data: &[u8],
173 usage: vk::BufferUsageFlags,
174 command_pool: vk::CommandPool,
175 queue: vk::Queue,
176) -> anyhow::Result<(vk::Buffer, vk::DeviceMemory)> {
177 let size = data.len() as vk::DeviceSize;
178 let (staging, staging_mem) = alloc_buffer(
179 DeviceContext { device, instance, physical_device },
180 size,
181 vk::BufferUsageFlags::TRANSFER_SRC,
182 vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
183 )?;
184 unsafe {
185 let ptr = device.map_memory(staging_mem, 0, size, vk::MemoryMapFlags::empty())? as *mut u8;
186 std::ptr::copy_nonoverlapping(data.as_ptr(), ptr, data.len());
187 device.unmap_memory(staging_mem);
188 }
189 let (buf, mem) = alloc_buffer(
190 DeviceContext { device, instance, physical_device },
191 size,
192 usage | vk::BufferUsageFlags::TRANSFER_DST,
193 vk::MemoryPropertyFlags::DEVICE_LOCAL,
194 )?;
195 copy_buffer(device, command_pool, queue, staging, buf, size)?;
196 unsafe {
197 device.destroy_buffer(staging, None);
198 device.free_memory(staging_mem, None);
199 }
200 Ok((buf, mem))
201}