1use super::{AllocError, AllocationCreateInfo};
6use crate as vk;
7
8#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
10pub enum MemoryUsage {
11 #[default]
12 Explicit,
13 Auto,
14 PreferDevice,
15 PreferHost,
16}
17
18#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
20pub enum HostAccess {
21 #[default]
22 None,
23 SequentialWrite,
24 Random,
25}
26
27pub(super) fn prefers_mapped(info: &AllocationCreateInfo) -> bool {
30 info.usage == MemoryUsage::Explicit || info.host_access != HostAccess::None || info.persistent_map
31}
32
33pub(super) fn preferences(
34 info: &AllocationCreateInfo,
35 device_access: bool,
36 integrated: Option<bool>,
37) -> Result<
38 (
39 vk::MemoryPropertyFlags,
40 vk::MemoryPropertyFlags,
41 vk::MemoryPropertyFlags,
42 ),
43 AllocError,
44> {
45 use vk::MemoryPropertyFlagBits as Flag;
46 let mut required = info.required_flags;
47 let mut preferred = info.preferred_flags;
48 let mut avoided = info.avoided_flags;
49 if info.allow_transfer_instead
50 && (info.usage == MemoryUsage::Explicit || info.host_access == HostAccess::None)
51 {
52 return Err(AllocError::InvalidRequest(
53 "transfer fallback needs automatic host intent",
54 ));
55 }
56 if info.usage != MemoryUsage::Explicit {
57 let prefer_host = info.usage == MemoryUsage::PreferHost;
58 let prefer_device = info.usage == MemoryUsage::PreferDevice;
59 let discrete_transfer = info.allow_transfer_instead
60 && !integrated.ok_or(AllocError::UnsupportedCapability(
61 "transfer fallback requires queried physical-device type",
62 ))? && device_access
63 && !prefer_host;
64 match info.host_access {
65 HostAccess::Random => {
66 preferred = preferred | Flag::HOST_CACHED_BIT;
67 if discrete_transfer {
68 preferred = preferred | Flag::DEVICE_LOCAL_BIT;
69 } else if info.allow_transfer_instead {
70 preferred = preferred | Flag::HOST_VISIBLE_BIT;
71 } else {
72 required = required | Flag::HOST_VISIBLE_BIT;
73 }
74 }
75 HostAccess::SequentialWrite => {
76 avoided = avoided | Flag::HOST_CACHED_BIT;
77 if discrete_transfer {
78 preferred = preferred | Flag::DEVICE_LOCAL_BIT | Flag::HOST_VISIBLE_BIT;
79 } else {
80 if info.allow_transfer_instead {
81 preferred = preferred | Flag::HOST_VISIBLE_BIT;
82 } else {
83 required = required | Flag::HOST_VISIBLE_BIT;
84 }
85 if (device_access && !prefer_host) || (!device_access && prefer_device) {
86 preferred = preferred | Flag::DEVICE_LOCAL_BIT;
87 } else {
88 avoided = avoided | Flag::DEVICE_LOCAL_BIT;
89 }
90 }
91 }
92 HostAccess::None => {
93 if prefer_host {
94 avoided = avoided | Flag::DEVICE_LOCAL_BIT;
95 } else {
96 preferred = preferred | Flag::DEVICE_LOCAL_BIT;
97 }
98 }
99 }
100 } else if info.host_access != HostAccess::None {
101 return Err(AllocError::InvalidRequest(
102 "host intent requires automatic memory usage",
103 ));
104 }
105 if (required | preferred).as_raw()
106 & (Flag::DEVICE_COHERENT_BIT_AMD | Flag::DEVICE_UNCACHED_BIT_AMD).as_raw()
107 == 0
108 {
109 avoided = avoided | Flag::DEVICE_UNCACHED_BIT_AMD;
110 }
111 if info.persistent_map {
112 required = required | Flag::HOST_VISIBLE_BIT;
113 }
114 Ok((required, preferred, avoided))
115}
116
117#[cfg(test)]
118#[path = "../../../test/rs/mem/test_policy.rs"]
119mod tests;