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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
use std::mem::transmute;
use crate::{arc, define_mtl, define_obj_type, define_opts, mtl, ns, objc};
/// Options for set_purgeable call.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(usize)]
pub enum PurgableState {
/// The purgeabelity state is not changed.
KeepCurrent = 1,
/// The contents of this resource may not be discarded.
NoneVolatile = 2,
/// The contents of this resource may be discarded.
Volatile = 3,
/// The contents of this are discarded.
Empty = 4,
}
/// Describes what CPU cache mode is used for the CPU's mapping of a texture resource.
///
/// Applications should only investigate changing the cache mode if writing to normally
/// cached buffers is known to cause performance issues due to cache pollution, as write
/// combined memory can have surprising performance pitfalls. Another approach is to use
/// non-temporal stores to normally cached memory (STNP on ARMv8, _mm_stream_* on x86_64).
/// MTLCPUCacheMode
#[doc(alias = "MTLCPUCacheMode")]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(usize)]
pub enum CpuCacheMode {
/// The default cache mode for the system.
DefaultCache = 0,
/// Write combined memory is optimized for resources that the CPU will write into,
/// but never read. On some implementations, writes may bypass caches avoiding cache
/// pollution, and reads perform very poorly.
WriteCombined = 1,
}
impl CpuCacheMode {
#[inline]
pub fn to_ns_number(&self) -> arc::R<ns::Number> {
ns::Number::with_u64(*self as u64)
}
}
/// Describes location and CPU mapping of MTLTexture.
#[doc(alias = "MTLStorageMode")]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(usize)]
pub enum StorageMode {
/// In this mode, CPU and device will nominally both use the same underlying memory
/// when accessing the contents of the texture resource.
/// However, coherency is only guaranteed at command buffer boundaries to minimize
/// the required flushing of CPU and GPU caches.
/// This is the default storage mode for iOS Textures.
Shared = 0,
/// This mode relaxes the coherency requirements and requires that the developer make explicit requests to maintain
/// coherency between a CPU and GPU version of the texture resource. In order for CPU to access up to date GPU results,
/// first, a blit synchronizations must be completed (see synchronize methods of [`mtl::BlitCmdEncoder`][crate::mtl::BlitCmdEncoder]).
/// Blit overhead is only incurred if GPU has modified the resource.
/// This is the default storage mode for OS X textures.
Managed = 1,
/// This mode allows the texture resource data to be kept entirely to GPU (or driver) private memory
/// that will never be accessed by the CPU directly, so no
/// conherency of any kind must be maintained.
Private = 2,
/// This mode allows creation of resources that do not have a GPU or CPU memory backing, but do have on-chip storage for TBDR
/// devices. The contents of the on-chip storage is undefined and does not persist, but its configuration is controlled by the
/// mtl::Texture descriptor. Textures created with MTLStorageModeMemoryless dont have an IOAccelResource at any point in their
/// lifetime. The only way to populate such resource is to perform rendering operations on it. Blit operations are disallowed.
Memoryless = 3,
}
impl StorageMode {
pub fn to_ns_number(&self) -> arc::R<ns::Number> {
ns::Number::with_u64(*self as _)
}
}
/// Describes how hazard tracking is performed.
#[doc(alias = "MTLHazardTrackingMode")]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(usize)]
pub enum HazardTrackingMode {
/// The default hazard tracking mode for the context. Refer to the usage of the field for semantics.
Default = 0,
/// Do not perform hazard tracking.
Untracked = 1,
/// Do perform hazard tracking.
Tracked = 2,
}
impl Default for HazardTrackingMode {
#[inline]
fn default() -> Self {
Self::Default
}
}
define_opts!(
#[doc(alias = "MTLResourceOptions")]
pub Opts(usize)
);
pub const CPU_CACHE_MODE_SHIFT: usize = 0;
pub const CPU_CACHE_MODE_MASK: usize = 0xfusize << CPU_CACHE_MODE_SHIFT;
pub const STORAGE_MODE_SHIFT: usize = 4;
pub const STORAGE_MODE_MASK: usize = 0xfusize << STORAGE_MODE_SHIFT;
pub const HAZARD_TRACKING_MODE_SHIFT: usize = 8;
pub const HAZARD_TRACKING_MODE_MASK: usize = 0x3usize << HAZARD_TRACKING_MODE_SHIFT;
/// A set of optional arguments to influence the creation of a mtl::Res (mtl::Texture or mtl::Buf)
impl Opts {
pub const CPU_CACHE_MODE_DEFAULT: Self =
Self((CpuCacheMode::DefaultCache as usize) << CPU_CACHE_MODE_SHIFT);
pub const CPU_CACHE_MODE_WRITE_COMBINED: Self =
Self((CpuCacheMode::WriteCombined as usize) << CPU_CACHE_MODE_SHIFT);
pub const STORAGE_MODE_SHARED: Self =
Self((StorageMode::Shared as usize) << STORAGE_MODE_SHIFT);
pub const STORAGE_MODE_MANAGED: Self =
Self((StorageMode::Managed as usize) << STORAGE_MODE_SHIFT);
pub const STORAGE_MODE_PRIVATE: Self =
Self((StorageMode::Private as usize) << STORAGE_MODE_SHIFT);
pub const STORAGE_MODE_MEMORYLESS: Self =
Self((StorageMode::Memoryless as usize) << STORAGE_MODE_SHIFT);
pub const HAZARD_TRACKING_MODE_DEFAULT: Self =
Self((HazardTrackingMode::Default as usize) << HAZARD_TRACKING_MODE_SHIFT);
pub const HAZARD_TRACKING_MODE_UNTRACKED: Self =
Self((HazardTrackingMode::Untracked as usize) << HAZARD_TRACKING_MODE_SHIFT);
pub const HAZARD_TRACKING_MODE_TRACKED: Self =
Self((HazardTrackingMode::Tracked as usize) << HAZARD_TRACKING_MODE_SHIFT);
#[inline]
pub fn hazard_tracking_mode(&self) -> HazardTrackingMode {
unsafe { transmute((self.0 & HAZARD_TRACKING_MODE_MASK) >> HAZARD_TRACKING_MODE_SHIFT) }
}
#[inline]
pub fn storage_mode(&self) -> StorageMode {
unsafe { transmute((self.0 & STORAGE_MODE_MASK) >> STORAGE_MODE_SHIFT) }
}
#[inline]
pub fn cpu_cache_mode(&self) -> CpuCacheMode {
unsafe { transmute(self.0 & CPU_CACHE_MODE_MASK) }
}
}
define_obj_type!(
#[doc(alias = "MTLResource")]
pub Res(mtl::Allocation)
);
impl Res {
define_mtl!(
set_label,
cpu_cache_mode,
storage_mode,
hazard_tracking_mode,
res_opts
);
#[objc::msg_send(device)]
pub fn device(&self) -> arc::R<mtl::Device>;
#[objc::msg_send(label)]
pub fn label(&self) -> Option<arc::R<ns::String>>;
}
#[cfg(test)]
mod tests {
use crate::mtl::{CpuCacheMode, HazardTrackingMode, ResOpts, StorageMode};
#[test]
fn options_default() {
let opts = ResOpts::default();
assert_eq!(opts.cpu_cache_mode(), CpuCacheMode::DefaultCache);
assert_eq!(opts.storage_mode(), StorageMode::Shared);
assert_eq!(opts.hazard_tracking_mode(), HazardTrackingMode::Default);
}
#[test]
fn options_non_default() {
let opts = ResOpts::CPU_CACHE_MODE_WRITE_COMBINED
| ResOpts::STORAGE_MODE_MEMORYLESS
| ResOpts::HAZARD_TRACKING_MODE_UNTRACKED;
assert_eq!(opts.cpu_cache_mode(), CpuCacheMode::WriteCombined);
assert_eq!(opts.storage_mode(), StorageMode::Memoryless);
assert_eq!(opts.hazard_tracking_mode(), HazardTrackingMode::Untracked);
}
}