1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use {crate::PrettySize, ash::vk, indoc::indoc};

#[derive(Debug, Clone)]
pub struct MemoryProperties {
    types: Vec<vk::MemoryType>,
    heaps: Vec<vk::MemoryHeap>,
}

impl MemoryProperties {
    /// Get the memory properties for the given physical device.
    pub fn new(
        instance: &ash::Instance,
        physical_device: vk::PhysicalDevice,
    ) -> Self {
        let properties = unsafe {
            instance.get_physical_device_memory_properties(physical_device)
        };
        let mut types =
            Vec::with_capacity(properties.memory_type_count as usize);
        types.extend_from_slice(
            &properties.memory_types[0..properties.memory_type_count as usize],
        );
        let mut heaps =
            Vec::with_capacity(properties.memory_heap_count as usize);
        heaps.extend_from_slice(
            &properties.memory_heaps[0..properties.memory_heap_count as usize],
        );
        Self { types, heaps }
    }

    /// Create memory properties directly from a slice of memory types and
    /// heaps.
    ///
    /// This is primarily used for testing.
    ///
    /// # Safety
    ///
    /// Unsafe because:
    /// - Types and heaps are expected to reference one another. Using a memory
    ///   type or heap which wasn't returned by the device itself can result in
    ///   undefined behavior.
    pub unsafe fn from_raw(
        types: &[vk::MemoryType],
        heaps: &[vk::MemoryHeap],
    ) -> Self {
        Self {
            types: types.to_owned(),
            heaps: heaps.to_owned(),
        }
    }

    /// All of the currently usable memory heaps on this system.
    pub fn heaps(&self) -> &[vk::MemoryHeap] {
        &self.heaps
    }

    /// All of the currently usable memory types on this system.
    pub fn types(&self) -> &[vk::MemoryType] {
        &self.types
    }
}

impl std::fmt::Display for MemoryProperties {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("# Memory Properties\n\n")?;
        f.write_str("## Memory Types\n\n")?;

        for (index, memory_type) in self.types.iter().enumerate() {
            f.write_fmt(format_args!(
                indoc!(
                    "
                        [{}] property_flags: {:#?}
                                heap_index: {}

                        "
                ),
                index, memory_type.property_flags, memory_type.heap_index,
            ))?;
        }

        f.write_str("\n## Memory Heaps\n\n")?;

        for (index, heap) in self.heaps.iter().enumerate() {
            f.write_fmt(format_args!(
                indoc!(
                    "
                        [{}] flags: {:#?}
                             size: {}

                        "
                ),
                index,
                heap.flags,
                PrettySize(heap.size),
            ))?;
        }

        Ok(())
    }
}