1use {
95 gfx_hal::{
96 adapter::{Adapter, PhysicalDevice as _},
97 device::{AllocationError, Device, MapError, OutOfMemory as GfxOutOfMemory},
98 memory::{Properties, Segment},
99 Backend, MemoryTypeId,
100 },
101 gpu_alloc_types::{
102 AllocationFlags, DeviceMapError, DeviceProperties, MappedMemoryRange, MemoryDevice,
103 MemoryHeap, MemoryPropertyFlags, MemoryType, OutOfMemory,
104 },
105 std::{convert::TryFrom as _, ptr::NonNull},
106};
107
108#[repr(transparent)]
109pub struct GfxMemoryDevice<B: Backend> {
110 device: B::Device,
111}
112
113impl<B> GfxMemoryDevice<B>
114where
115 B: Backend,
116{
117 pub fn wrap<D>(device: &D) -> &Self
118 where
119 D: Device<B>,
120 B: Backend<Device = D>,
121 {
122 unsafe {
123 &*(device as *const D as *const Self)
126 }
127 }
128}
129
130impl<B> MemoryDevice<B::Memory> for GfxMemoryDevice<B>
131where
132 B: Backend,
133{
134 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
135 unsafe fn allocate_memory(
136 &self,
137 size: u64,
138 memory_type: u32,
139 flags: AllocationFlags,
140 ) -> Result<B::Memory, OutOfMemory> {
141 debug_assert!(flags.is_empty(), "No allocation flags supported");
142
143 let memory_type =
144 MemoryTypeId(usize::try_from(memory_type).expect("memory_type out of bound"));
145
146 match self.device.allocate_memory(memory_type, size) {
147 Ok(memory) => Ok(memory),
148 Err(AllocationError::OutOfMemory(GfxOutOfMemory::Device)) => {
149 Err(OutOfMemory::OutOfDeviceMemory)
150 }
151 Err(AllocationError::OutOfMemory(GfxOutOfMemory::Host)) => {
152 Err(OutOfMemory::OutOfHostMemory)
153 }
154 Err(AllocationError::TooManyObjects) => panic!("Too many objects"),
155 }
156 }
157
158 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
159 unsafe fn deallocate_memory(&self, memory: B::Memory) {
160 self.device.free_memory(memory);
161 }
162
163 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
164 unsafe fn map_memory(
165 &self,
166 memory: &mut B::Memory,
167 offset: u64,
168 size: u64,
169 ) -> Result<NonNull<u8>, DeviceMapError> {
170 let result = self.device.map_memory(
171 memory,
172 Segment {
173 offset,
174 size: Some(size),
175 },
176 );
177
178 match result {
179 Ok(ptr) => Ok(NonNull::new(ptr).expect("Pointer to memory mapping must not be null")),
180 Err(MapError::OutOfMemory(GfxOutOfMemory::Device)) => {
181 Err(DeviceMapError::OutOfDeviceMemory)
182 }
183 Err(MapError::OutOfMemory(GfxOutOfMemory::Host)) => {
184 Err(DeviceMapError::OutOfHostMemory)
185 }
186 Err(MapError::OutOfBounds) => panic!("Memory mapping out of bounds"),
187 Err(MapError::MappingFailed) => Err(DeviceMapError::MapFailed),
188 Err(MapError::Access) => panic!("Attempt to map non-host-visible memory"),
189 }
190 }
191
192 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
193 unsafe fn unmap_memory(&self, memory: &mut B::Memory) {
194 self.device.unmap_memory(memory);
195 }
196
197 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
198 unsafe fn invalidate_memory_ranges(
199 &self,
200 ranges: &[MappedMemoryRange<'_, B::Memory>],
201 ) -> Result<(), OutOfMemory> {
202 self.device
203 .invalidate_mapped_memory_ranges(ranges.iter().map(|range| {
204 (
205 &*range.memory,
206 Segment {
207 offset: range.offset,
208 size: Some(range.size),
209 },
210 )
211 }))
212 .map_err(|err| match err {
213 GfxOutOfMemory::Device => OutOfMemory::OutOfDeviceMemory,
214 GfxOutOfMemory::Host => OutOfMemory::OutOfHostMemory,
215 })
216 }
217
218 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
219 unsafe fn flush_memory_ranges(
220 &self,
221 ranges: &[MappedMemoryRange<'_, B::Memory>],
222 ) -> Result<(), OutOfMemory> {
223 self.device
224 .flush_mapped_memory_ranges(ranges.iter().map(|range| {
225 (
226 &*range.memory,
227 Segment {
228 offset: range.offset,
229 size: Some(range.size),
230 },
231 )
232 }))
233 .map_err(|err| match err {
234 GfxOutOfMemory::Device => OutOfMemory::OutOfDeviceMemory,
235 GfxOutOfMemory::Host => OutOfMemory::OutOfHostMemory,
236 })
237 }
238}
239
240pub fn gfx_device_properties<B>(adapter: &Adapter<B>) -> DeviceProperties<'static>
242where
243 B: Backend,
244{
245 let limits = adapter.physical_device.limits();
246 let memory_properties = adapter.physical_device.memory_properties();
247 DeviceProperties {
248 max_memory_allocation_count: u32::try_from(limits.max_memory_allocation_count)
249 .unwrap_or(u32::max_value()),
250 max_memory_allocation_size: u64::max_value(),
251 non_coherent_atom_size: u64::try_from(limits.non_coherent_atom_size)
252 .unwrap_or(u64::max_value()),
253 memory_types: memory_properties
254 .memory_types
255 .iter()
256 .map(|memory_type| MemoryType {
257 props: memory_properties_from_gfx(memory_type.properties),
258 heap: u32::try_from(memory_type.heap_index)
259 .expect("Memory heap index should fit `u32`"),
260 })
261 .collect(),
262 memory_heaps: memory_properties
263 .memory_heaps
264 .iter()
265 .map(|&memory_heap| MemoryHeap {
266 size: memory_heap.size,
267 })
268 .collect(),
269 buffer_device_address: false,
270 }
271}
272
273pub fn memory_properties_from_gfx(props: Properties) -> MemoryPropertyFlags {
274 let mut result = MemoryPropertyFlags::empty();
275 if props.contains(Properties::DEVICE_LOCAL) {
276 result |= MemoryPropertyFlags::DEVICE_LOCAL;
277 }
278 if props.contains(Properties::CPU_VISIBLE) {
279 result |= MemoryPropertyFlags::HOST_VISIBLE;
280 }
281 if props.contains(Properties::COHERENT) {
282 result |= MemoryPropertyFlags::HOST_COHERENT;
283 }
284 if props.contains(Properties::CPU_CACHED) {
285 result |= MemoryPropertyFlags::HOST_CACHED;
286 }
287 if props.contains(Properties::LAZILY_ALLOCATED) {
288 result |= MemoryPropertyFlags::LAZILY_ALLOCATED;
289 }
290 result
291}
292
293pub fn memory_properties_to_gfx(props: MemoryPropertyFlags) -> Properties {
294 let mut result = Properties::empty();
295 if props.contains(MemoryPropertyFlags::DEVICE_LOCAL) {
296 result |= Properties::DEVICE_LOCAL;
297 }
298 if props.contains(MemoryPropertyFlags::HOST_VISIBLE) {
299 result |= Properties::CPU_VISIBLE;
300 }
301 if props.contains(MemoryPropertyFlags::HOST_COHERENT) {
302 result |= Properties::COHERENT;
303 }
304 if props.contains(MemoryPropertyFlags::HOST_CACHED) {
305 result |= Properties::CPU_CACHED;
306 }
307 if props.contains(MemoryPropertyFlags::LAZILY_ALLOCATED) {
308 result |= Properties::LAZILY_ALLOCATED;
309 }
310 result
311}