1use super::{AllocError, AllocRequest};
4use crate::core as vk;
5
6pub struct MemoryTypeSelector {
8 pub(crate) properties: vk::PhysicalDeviceMemoryProperties,
9 pub(crate) atom: u64,
10}
11
12impl MemoryTypeSelector {
13 pub fn new(
14 properties: vk::PhysicalDeviceMemoryProperties,
15 atom: u64,
16 ) -> Result<Self, AllocError> {
17 if properties.memory_type_count == 0
18 || properties.memory_type_count > 32
19 || properties.memory_heap_count == 0
20 || properties.memory_heap_count > 16
21 {
22 return Err(AllocError::InvalidProperties(
23 "invalid memory type or heap count",
24 ));
25 }
26 if !atom.is_power_of_two() {
27 return Err(AllocError::InvalidProperties(
28 "atom size must be a nonzero power of two",
29 ));
30 }
31 for memory in &properties.memory_types[..properties.memory_type_count as usize] {
32 if memory.heap_index >= properties.memory_heap_count {
33 return Err(AllocError::InvalidProperties(
34 "memory type references an absent heap",
35 ));
36 }
37 }
38 Ok(Self { properties, atom })
39 }
40
41 pub fn find_memory_type(&self, request: &AllocRequest) -> Result<u32, AllocError> {
46 if request.size == 0 || !request.alignment.is_power_of_two() {
47 return Err(AllocError::InvalidRequest(
48 "size must be nonzero and alignment a power of two",
49 ));
50 }
51 let mut best = None;
52 let mut cost = u32::MAX;
53 for i in 0..self.properties.memory_type_count {
54 if request.memory_type_bits & (1u32 << i) == 0 {
55 continue;
56 }
57 let memory = self.properties.memory_types[i as usize];
58 let flags = memory.property_flags.as_raw();
59 let required = request.required_flags.as_raw();
60 if flags & required != required {
61 continue;
62 }
63 if self.properties.memory_heaps[memory.heap_index as usize]
66 .flags
67 .as_raw()
68 & vk::MemoryHeapFlagBits::TILE_MEMORY_BIT_QCOM.as_raw()
69 != 0
70 {
71 continue;
72 }
73 if flags & vk::MemoryPropertyFlagBits::DEVICE_COHERENT_BIT_AMD.as_raw() != 0 {
76 continue;
77 }
78 if flags & vk::MemoryPropertyFlagBits::PROTECTED_BIT.as_raw() != 0
79 && required & vk::MemoryPropertyFlagBits::PROTECTED_BIT.as_raw() == 0
80 {
81 continue;
82 }
83 if request.size > self.properties.memory_heaps[memory.heap_index as usize].size {
84 continue;
85 }
86 let candidate = (request.preferred_flags.as_raw() & !flags).count_ones();
87 if candidate < cost {
88 best = Some(i);
89 cost = candidate;
90 }
91 }
92 best.ok_or(AllocError::NoCompatibleMemoryType)
93 }
94}