1use super::{AllocError, AllocRequest};
4use crate as vk;
5
6pub struct MemoryTypeSelector {
8 pub(crate) properties: vk::PhysicalDeviceMemoryProperties,
9 pub(crate) atom: u64,
10 pub(super) device_coherent: bool,
11 pub(super) allowed_bits: u32,
12}
13
14impl MemoryTypeSelector {
15 pub fn new(
16 properties: vk::PhysicalDeviceMemoryProperties,
17 atom: u64,
18 ) -> Result<Self, AllocError> {
19 if properties.memory_type_count == 0
20 || properties.memory_type_count > 32
21 || properties.memory_heap_count == 0
22 || properties.memory_heap_count > 16
23 {
24 return Err(AllocError::InvalidProperties(
25 "invalid memory type or heap count",
26 ));
27 }
28 if !atom.is_power_of_two() {
29 return Err(AllocError::InvalidProperties(
30 "atom size must be a nonzero power of two",
31 ));
32 }
33 for memory in &properties.memory_types[..properties.memory_type_count as usize] {
34 if memory.heap_index >= properties.memory_heap_count {
35 return Err(AllocError::InvalidProperties(
36 "memory type references an absent heap",
37 ));
38 }
39 }
40 Ok(Self {
41 properties,
42 atom,
43 device_coherent: false,
44 allowed_bits: u32::MAX,
45 })
46 }
47
48 pub fn find_memory_type(&self, request: &AllocRequest) -> Result<u32, AllocError> {
53 self.find_memory_type_with_preferences(request, vk::MemoryPropertyFlags::empty())
54 }
55
56 pub fn find_memory_type_with_preferences(
58 &self,
59 request: &AllocRequest,
60 avoided: vk::MemoryPropertyFlags,
61 ) -> Result<u32, AllocError> {
62 if request.size == 0 || !request.alignment.is_power_of_two() {
63 return Err(AllocError::InvalidRequest(
64 "size must be nonzero and alignment a power of two",
65 ));
66 }
67 let mut best = None;
68 let mut cost = u32::MAX;
69 let mut bits = request.memory_type_bits
71 & self.allowed_bits
72 & (u32::MAX >> (32 - self.properties.memory_type_count));
73 while bits != 0 {
74 let i = bits.trailing_zeros();
75 bits &= bits - 1;
76 let memory = self.properties.memory_types[i as usize];
77 let flags = memory.property_flags.as_raw();
78 let required = request.required_flags.as_raw();
79 if flags & required != required {
80 continue;
81 }
82 if self.properties.memory_heaps[memory.heap_index as usize]
85 .flags
86 .as_raw()
87 & vk::MemoryHeapFlagBits::TILE_MEMORY_BIT_QCOM.as_raw()
88 != 0
89 {
90 continue;
91 }
92 if !self.device_coherent
95 && flags & vk::MemoryPropertyFlagBits::DEVICE_COHERENT_BIT_AMD.as_raw() != 0
96 {
97 continue;
98 }
99 if flags & vk::MemoryPropertyFlagBits::PROTECTED_BIT.as_raw() != 0
100 && required & vk::MemoryPropertyFlagBits::PROTECTED_BIT.as_raw() == 0
101 {
102 continue;
103 }
104 if request.size > self.properties.memory_heaps[memory.heap_index as usize].size {
105 continue;
106 }
107 let candidate = (request.preferred_flags.as_raw() & !flags).count_ones()
108 + (avoided.as_raw() & flags).count_ones();
109 if candidate < cost {
110 best = Some(i);
111 cost = candidate;
112 if cost == 0 {
114 break;
115 }
116 }
117 }
118 best.ok_or(AllocError::NoCompatibleMemoryType)
119 }
120}