Skip to main content

ursus_core/vulkan/core/
memory.rs

1use crate::vulkan::core::DeviceContext;
2use ash::vk;
3
4pub struct AllocatedImage {
5    pub image: vk::Image,
6    pub view: vk::ImageView,
7    pub memory: vk::DeviceMemory,
8}
9
10pub struct ImageDesc {
11    pub format: vk::Format,
12    pub width: u32,
13    pub height: u32,
14    pub usage: vk::ImageUsageFlags,
15    pub aspect_mask: vk::ImageAspectFlags,
16    pub mip_levels: u32,
17}
18
19impl ImageDesc {
20    pub fn color(format: vk::Format, width: u32, height: u32, usage: vk::ImageUsageFlags) -> Self {
21        Self { format, width, height, usage, aspect_mask: vk::ImageAspectFlags::COLOR, mip_levels: 1 }
22    }
23
24    pub fn depth(format: vk::Format, width: u32, height: u32, usage: vk::ImageUsageFlags) -> Self {
25        Self { format, width, height, usage, aspect_mask: vk::ImageAspectFlags::DEPTH, mip_levels: 1 }
26    }
27}
28
29pub fn alloc_image(ctx: DeviceContext, desc: &ImageDesc) -> anyhow::Result<AllocatedImage> {
30    let image_info = vk::ImageCreateInfo::default()
31        .image_type(vk::ImageType::TYPE_2D)
32        .format(desc.format)
33        .extent(vk::Extent3D { width: desc.width, height: desc.height, depth: 1 })
34        .mip_levels(desc.mip_levels)
35        .array_layers(1)
36        .samples(vk::SampleCountFlags::TYPE_1)
37        .tiling(vk::ImageTiling::OPTIMAL)
38        .usage(desc.usage)
39        .sharing_mode(vk::SharingMode::EXCLUSIVE)
40        .initial_layout(vk::ImageLayout::UNDEFINED);
41
42    let image = unsafe { ctx.device.create_image(&image_info, None)? };
43    let req = unsafe { ctx.device.get_image_memory_requirements(image) };
44
45    let mem_type = find_memory_type(
46        ctx.instance,
47        ctx.physical_device,
48        req.memory_type_bits,
49        vk::MemoryPropertyFlags::DEVICE_LOCAL,
50    )?;
51
52    let memory = unsafe {
53        ctx.device.allocate_memory(
54            &vk::MemoryAllocateInfo::default().allocation_size(req.size).memory_type_index(mem_type),
55            None,
56        )?
57    };
58    unsafe { ctx.device.bind_image_memory(image, memory, 0)? };
59
60    let view = unsafe {
61        ctx.device.create_image_view(
62            &vk::ImageViewCreateInfo::default()
63                .image(image)
64                .view_type(vk::ImageViewType::TYPE_2D)
65                .format(desc.format)
66                .subresource_range(vk::ImageSubresourceRange {
67                    aspect_mask: desc.aspect_mask,
68                    base_mip_level: 0,
69                    level_count: desc.mip_levels,
70                    base_array_layer: 0,
71                    layer_count: 1,
72                }),
73            None,
74        )?
75    };
76
77    Ok(AllocatedImage { image, view, memory })
78}
79
80pub fn find_memory_type(
81    instance: &ash::Instance,
82    physical_device: vk::PhysicalDevice,
83    type_filter: u32,
84    required: vk::MemoryPropertyFlags,
85) -> anyhow::Result<u32> {
86    let mem_props = unsafe { instance.get_physical_device_memory_properties(physical_device) };
87    for i in 0..mem_props.memory_type_count {
88        if (type_filter & (1 << i)) != 0 && mem_props.memory_types[i as usize].property_flags.contains(required) {
89            return Ok(i);
90        }
91    }
92
93    anyhow::bail!("Не найден тип памяти с флагами {:?}, type_filter={:#034b}", required, type_filter)
94}
95
96pub fn alloc_buffer(
97    ctx: DeviceContext,
98    size: vk::DeviceSize,
99    usage: vk::BufferUsageFlags,
100    props: vk::MemoryPropertyFlags,
101) -> anyhow::Result<(vk::Buffer, vk::DeviceMemory)> {
102    let buf_info = vk::BufferCreateInfo::default().size(size).usage(usage).sharing_mode(vk::SharingMode::EXCLUSIVE);
103    let buf = unsafe { ctx.device.create_buffer(&buf_info, None)? };
104    let req = unsafe { ctx.device.get_buffer_memory_requirements(buf) };
105    let alloc = vk::MemoryAllocateInfo::default().allocation_size(req.size).memory_type_index(find_memory_type(
106        ctx.instance,
107        ctx.physical_device,
108        req.memory_type_bits,
109        props,
110    )?);
111    let mem = unsafe { ctx.device.allocate_memory(&alloc, None)? };
112    unsafe { ctx.device.bind_buffer_memory(buf, mem, 0)? };
113    Ok((buf, mem))
114}
115
116/// # Safety
117///
118/// - `image`, `view`, and `memory` must be created via the same `device`.
119/// - None of the objects must be currently in use by the GPU
120///   (all command buffers referencing them must be finalized -
121///   usually guaranteed via `device_wait_idle` or a fence/semaphore before the call).
122/// - Each object must not be destroyed more than once.
123pub unsafe fn destroy_image_resources(
124    device: &ash::Device,
125    image: vk::Image,
126    view: vk::ImageView,
127    memory: vk::DeviceMemory,
128) {
129    device.destroy_image_view(view, None);
130    device.destroy_image(image, None);
131    device.free_memory(memory, None);
132}