Skip to main content

ursus_core/assets/storage/
mesh.rs

1use 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
13/// Owns GPU meshes and the Vulkan resources required to upload them.
14pub 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}