vulk_ext/vkx/
memory.rs

1use super::*;
2
3//
4// Buffers
5//
6
7#[derive(Clone, Copy, Debug)]
8pub struct BufferAllocation {
9    address: vk::DeviceAddress,
10    size: vk::DeviceSize,
11    ptr: Option<*mut c_void>,
12}
13
14impl BufferAllocation {
15    #[must_use]
16    pub fn device_address(&self) -> vk::DeviceAddress {
17        self.address
18    }
19
20    #[must_use]
21    pub fn size(&self) -> vk::DeviceSize {
22        self.size
23    }
24
25    #[must_use]
26    pub fn as_ptr<T>(&self) -> *const T {
27        if let Some(ptr) = self.ptr {
28            ptr.cast()
29        } else {
30            null()
31        }
32    }
33
34    #[must_use]
35    pub fn as_mut_ptr<T>(&self) -> *mut T {
36        if let Some(ptr) = self.ptr {
37            ptr.cast()
38        } else {
39            null_mut()
40        }
41    }
42
43    #[must_use]
44    pub unsafe fn as_slice<T>(&self, len: usize) -> &[T] {
45        if let Some(ptr) = self.ptr {
46            std::slice::from_raw_parts(ptr.cast(), len)
47        } else {
48            &[]
49        }
50    }
51
52    #[must_use]
53    pub unsafe fn as_mut_slice<T>(&mut self, len: usize) -> &mut [T] {
54        if let Some(ptr) = self.ptr {
55            std::slice::from_raw_parts_mut(ptr.cast(), len)
56        } else {
57            &mut []
58        }
59    }
60}
61
62#[derive(Debug)]
63pub struct BufferAllocations {
64    memory: vk::DeviceMemory,
65    allocations: Vec<BufferAllocation>,
66}
67
68impl BufferAllocations {
69    pub unsafe fn allocate(
70        physical_device: &PhysicalDevice,
71        device: &Device,
72        buffers: &[vk::Buffer],
73        buffer_create_infos: &[vk::BufferCreateInfo],
74        property_flags: impl Into<vk::MemoryPropertyFlags> + Copy,
75    ) -> Result<Self> {
76        // Validation.
77        ensure!(!buffers.is_empty());
78        ensure!(!buffer_create_infos.is_empty());
79        ensure!(buffers.len() == buffer_create_infos.len());
80        ensure!(buffer_create_infos
81            .iter()
82            .all(|info| info.s_type == vk::StructureType::BufferCreateInfo));
83        ensure!(buffer_create_infos.iter().all(|info| info.p_next.is_null()));
84        ensure!(buffer_create_infos
85            .iter()
86            .all(|info| info.flags == vk::BufferCreateFlags::empty()));
87        ensure!(buffer_create_infos.iter().all(|info| info.size > 0));
88        ensure!(buffer_create_infos.iter().all(|info| info
89            .usage
90            .contains(vk::BufferUsageFlagBits::ShaderDeviceAddress)));
91        ensure!(buffer_create_infos
92            .iter()
93            .all(|info| info.sharing_mode == vk::SharingMode::Exclusive));
94        ensure!(buffer_create_infos.iter().all(
95            |info| info.queue_family_index_count == 0 && info.p_queue_family_indices.is_null()
96        ));
97        ensure!(property_flags.into() != vk::MemoryPropertyFlags::empty());
98
99        // Requirements.
100        let mut memory_requirements = vec![];
101        for &buffer_create_info in buffer_create_infos {
102            let device_buffer_memory_requirements = vk::DeviceBufferMemoryRequirements {
103                s_type: vk::StructureType::DeviceBufferMemoryRequirements,
104                p_next: null(),
105                p_create_info: addr_of!(buffer_create_info).cast(),
106            };
107            let mut memory_requirements2 = vk::MemoryRequirements2 {
108                s_type: vk::StructureType::MemoryRequirements2,
109                p_next: null_mut(),
110                memory_requirements: zeroed(),
111            };
112            device.get_device_buffer_memory_requirements(
113                &device_buffer_memory_requirements,
114                &mut memory_requirements2,
115            );
116            memory_requirements.push(memory_requirements2.memory_requirements);
117        }
118
119        // Buffers must be compatible with the allocation we make.
120        ensure!(memory_requirements
121            .iter()
122            .all(|req| req.alignment == memory_requirements[0].alignment));
123        ensure!(memory_requirements
124            .iter()
125            .all(|req| req.memory_type_bits == memory_requirements[0].memory_type_bits));
126        let alignment = memory_requirements[0].alignment;
127        let memory_type_bits = memory_requirements[0].memory_type_bits;
128
129        // Memory type index.
130        let memory_type_index = memory_type_index(
131            &physical_device.memory_properties,
132            property_flags,
133            memory_type_bits,
134        );
135
136        // Allocation size.
137        let allocation_size = memory_requirements
138            .iter()
139            .map(|req| aligned_size(req.size, alignment))
140            .sum::<vk::DeviceSize>();
141
142        // Allocation.
143        let device_memory = {
144            let memory_allocate_flags_info = vk::MemoryAllocateFlagsInfo {
145                s_type: vk::StructureType::MemoryAllocateFlagsInfo,
146                p_next: null(),
147                flags: vk::MemoryAllocateFlagBits::DeviceAddress.into(),
148                device_mask: 0,
149            };
150            device
151                .allocate_memory(&vk::MemoryAllocateInfo {
152                    s_type: vk::StructureType::MemoryAllocateInfo,
153                    p_next: addr_of!(memory_allocate_flags_info).cast(),
154                    allocation_size,
155                    memory_type_index,
156                })
157                .with_context(|| {
158                    format!("Allocating device memory for {} buffers", buffers.len())
159                })?
160        };
161
162        // Map memory.
163        let mut memory_ptr = None;
164        if property_flags
165            .into()
166            .contains(vk::MemoryPropertyFlagBits::HostVisible)
167        {
168            let ptr = device
169                .map_memory2_khr(&vk::MemoryMapInfoKHR {
170                    s_type: vk::StructureType::MemoryMapInfoKHR,
171                    p_next: null(),
172                    flags: vk::MemoryMapFlags::empty(),
173                    memory: device_memory,
174                    offset: 0,
175                    size: allocation_size,
176                })
177                .with_context(|| format!("Mapping buffer size={allocation_size}"))?;
178            memory_ptr = Some(ptr);
179        }
180
181        // Sub-allocations.
182        let mut allocations = vec![];
183        let mut memory_offset = 0;
184        for (buffer_index, (buffer, requirements)) in
185            buffers.iter().zip(memory_requirements).enumerate()
186        {
187            // Aligned size.
188            let aligned_size = aligned_size(requirements.size, alignment);
189
190            // Bind buffer memory.
191            device
192                .bind_buffer_memory2(
193                    1,
194                    &vk::BindBufferMemoryInfo {
195                        s_type: vk::StructureType::BindBufferMemoryInfo,
196                        p_next: null(),
197                        buffer: *buffer,
198                        memory: device_memory,
199                        memory_offset,
200                    },
201                )
202                .with_context(|| {
203                    format!(
204                        "Binding buffer {buffer_index} \
205                        size={aligned_size} into \
206                        device memory offset={memory_offset}"
207                    )
208                })?;
209
210            // Device address.
211            let device_address = device.get_buffer_device_address(&vk::BufferDeviceAddressInfo {
212                s_type: vk::StructureType::BufferDeviceAddressInfo,
213                p_next: null(),
214                buffer: *buffer,
215            });
216
217            // Map memory.
218            let buffer_ptr = memory_ptr.map(|ptr| ptr.add(memory_offset as _));
219
220            // Advance.
221            memory_offset += aligned_size;
222
223            // Output.
224            allocations.push(BufferAllocation {
225                address: device_address,
226                size: requirements.size,
227                ptr: buffer_ptr,
228            });
229        }
230
231        Ok(Self {
232            memory: device_memory,
233            allocations,
234        })
235    }
236
237    pub unsafe fn free(self, device: &Device) {
238        device.free_memory(self.memory);
239    }
240
241    #[must_use]
242    pub fn allocations(&self) -> &[BufferAllocation] {
243        &self.allocations
244    }
245}
246
247//
248// Images
249//
250
251#[derive(Debug)]
252pub struct ImageAllocations {
253    memory: vk::DeviceMemory,
254}
255
256impl ImageAllocations {
257    pub unsafe fn allocate(
258        physical_device: &PhysicalDevice,
259        device: &Device,
260        images: &[vk::Image],
261        image_create_infos: &[vk::ImageCreateInfo],
262        property_flags: impl Into<vk::MemoryPropertyFlags> + Copy,
263    ) -> Result<Self> {
264        // Validation.
265        ensure!(!images.is_empty());
266        ensure!(!image_create_infos.is_empty());
267        ensure!(images.len() == image_create_infos.len());
268        ensure!(image_create_infos
269            .iter()
270            .all(|info| info.s_type == vk::StructureType::ImageCreateInfo));
271        ensure!(image_create_infos.iter().all(|info| info.p_next.is_null()));
272        ensure!(image_create_infos
273            .iter()
274            .all(|info| info.flags == vk::ImageCreateFlags::empty()));
275        ensure!(image_create_infos
276            .iter()
277            .all(|info| info.extent.width > 0 && info.extent.height > 0 && info.extent.depth > 0));
278        ensure!(image_create_infos.iter().all(|info| info.mip_levels > 0));
279        ensure!(image_create_infos.iter().all(|info| info.array_layers > 0));
280        ensure!(image_create_infos
281            .iter()
282            .all(|info| info.tiling == vk::ImageTiling::Optimal));
283        ensure!(image_create_infos
284            .iter()
285            .all(|info| info.sharing_mode == vk::SharingMode::Exclusive));
286        ensure!(image_create_infos.iter().all(
287            |info| info.queue_family_index_count == 0 && info.p_queue_family_indices.is_null()
288        ));
289        ensure!(image_create_infos
290            .iter()
291            .all(|info| info.initial_layout == vk::ImageLayout::Undefined));
292
293        // Requirements.
294        let mut memory_requirements = vec![];
295        for &image_create_info in image_create_infos {
296            let device_image_memory_requirements = vk::DeviceImageMemoryRequirements {
297                s_type: vk::StructureType::DeviceImageMemoryRequirements,
298                p_next: null(),
299                p_create_info: &image_create_info,
300                plane_aspect: zeroed(),
301            };
302            let mut memory_requirements2 = vk::MemoryRequirements2 {
303                s_type: vk::StructureType::MemoryRequirements2,
304                p_next: null_mut(),
305                memory_requirements: zeroed(),
306            };
307            device.get_device_image_memory_requirements(
308                &device_image_memory_requirements,
309                &mut memory_requirements2,
310            );
311            memory_requirements.push(memory_requirements2.memory_requirements);
312        }
313
314        // Images must be compatible with the allocation we make.
315        ensure!(memory_requirements
316            .iter()
317            .all(|req| req.alignment == memory_requirements[0].alignment));
318        ensure!(memory_requirements
319            .iter()
320            .all(|req| req.memory_type_bits == memory_requirements[0].memory_type_bits));
321        let alignment = memory_requirements[0].alignment;
322        let memory_type_bits = memory_requirements[0].memory_type_bits;
323
324        // Memory type index.
325        let memory_type_index = memory_type_index(
326            &physical_device.memory_properties,
327            property_flags,
328            memory_type_bits,
329        );
330
331        // Allocation size.
332        let allocation_size = memory_requirements
333            .iter()
334            .map(|req| aligned_size(req.size, alignment))
335            .sum::<vk::DeviceSize>();
336
337        // Allocation.
338        let device_memory = device
339            .allocate_memory(&vk::MemoryAllocateInfo {
340                s_type: vk::StructureType::MemoryAllocateInfo,
341                p_next: null(),
342                allocation_size,
343                memory_type_index,
344            })
345            .with_context(|| {
346                format!(
347                    "\
348                    Allocating device memory for {} images",
349                    images.len()
350                )
351            })?;
352
353        // Sub-allocations.
354        let mut memory_offset = 0;
355        for (image_index, (image, requirements)) in
356            images.iter().zip(memory_requirements).enumerate()
357        {
358            // Aligned size.
359            let aligned_size = aligned_size(requirements.size, alignment);
360
361            // Bind image memory.
362            device
363                .bind_image_memory2(
364                    1,
365                    &vk::BindImageMemoryInfo {
366                        s_type: vk::StructureType::BindImageMemoryInfo,
367                        p_next: null(),
368                        image: *image,
369                        memory: device_memory,
370                        memory_offset,
371                    },
372                )
373                .with_context(|| {
374                    format!(
375                        "\
376                        Binding image {image_index} \
377                        size={aligned_size} into \
378                        device memory offset={memory_offset}"
379                    )
380                })?;
381
382            // Advance.
383            memory_offset += aligned_size;
384        }
385
386        Ok(Self {
387            memory: device_memory,
388        })
389    }
390
391    pub unsafe fn free(self, device: &Device) {
392        device.free_memory(self.memory);
393    }
394}
395
396//
397// Utilities
398//
399
400fn memory_type_index(
401    memory: &vk::PhysicalDeviceMemoryProperties,
402    property_flags: impl Into<vk::MemoryPropertyFlags> + Copy,
403    memory_type_bits: u32,
404) -> u32 {
405    for memory_type_index in 0..memory.memory_type_count {
406        let memory_type = memory.memory_types[memory_type_index as usize];
407        let type_matches = (1 << memory_type_index) & memory_type_bits != 0;
408        let property_matches = memory_type.property_flags.contains(property_flags);
409        if type_matches && property_matches {
410            debug!(
411                "index={}, type={:?}, heap={:?}",
412                memory_type_index,
413                &memory.memory_types[memory_type_index as usize].property_flags,
414                &memory.memory_heaps[memory_type.heap_index as usize].flags
415            );
416            return memory_type_index;
417        }
418    }
419    panic!("Unable to find suitable memory type for the buffer, memory_type_bits=0b{memory_type_bits:b}");
420}