• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! Low level implementation of buffers.
11 //!
12 //! Wraps directly around Vulkan buffers, with the exceptions of a few safety checks.
13 //!
14 //! The `UnsafeBuffer` type is the lowest-level buffer object provided by this library. It is used
15 //! internally by the higher-level buffer types. You are strongly encouraged to have excellent
16 //! knowledge of the Vulkan specs if you want to use an `UnsafeBuffer`.
17 //!
18 //! Here is what you must take care of when you use an `UnsafeBuffer`:
19 //!
20 //! - Synchronization, ie. avoid reading and writing simultaneously to the same buffer.
21 //! - Memory aliasing considerations. If you use the same memory to back multiple resources, you
22 //!   must ensure that they are not used together and must enable some additional flags.
23 //! - Binding memory correctly and only once. If you use sparse binding, respect the rules of
24 //!   sparse binding.
25 //! - Type safety.
26 
27 use crate::check_errors;
28 use crate::device::Device;
29 use crate::device::DeviceOwned;
30 use crate::memory::DeviceMemory;
31 use crate::memory::DeviceMemoryAllocError;
32 use crate::memory::MemoryRequirements;
33 use crate::sync::Sharing;
34 use crate::DeviceSize;
35 use crate::Error;
36 use crate::OomError;
37 use crate::VulkanObject;
38 use crate::{buffer::BufferUsage, Version};
39 use ash::vk::Handle;
40 use smallvec::SmallVec;
41 use std::error;
42 use std::fmt;
43 use std::hash::Hash;
44 use std::hash::Hasher;
45 use std::mem::MaybeUninit;
46 use std::ptr;
47 use std::sync::Arc;
48 
49 /// Data storage in a GPU-accessible location.
50 pub struct UnsafeBuffer {
51     buffer: ash::vk::Buffer,
52     device: Arc<Device>,
53     size: DeviceSize,
54     usage: BufferUsage,
55 }
56 
57 impl UnsafeBuffer {
58     /// Creates a new buffer of the given size.
59     ///
60     /// See the module's documentation for information about safety.
61     ///
62     /// # Panic
63     ///
64     /// - Panics if `sparse.sparse` is false and `sparse.sparse_residency` or `sparse.sparse_aliased` is true.
65     /// - Panics if `usage` is empty.
66     ///
new<'a, I>( device: Arc<Device>, size: DeviceSize, mut usage: BufferUsage, sharing: Sharing<I>, sparse: Option<SparseLevel>, ) -> Result<(UnsafeBuffer, MemoryRequirements), BufferCreationError> where I: Iterator<Item = u32>,67     pub unsafe fn new<'a, I>(
68         device: Arc<Device>,
69         size: DeviceSize,
70         mut usage: BufferUsage,
71         sharing: Sharing<I>,
72         sparse: Option<SparseLevel>,
73     ) -> Result<(UnsafeBuffer, MemoryRequirements), BufferCreationError>
74     where
75         I: Iterator<Item = u32>,
76     {
77         let fns = device.fns();
78 
79         // Ensure we're not trying to create an empty buffer.
80         let size = if size == 0 {
81             // To avoid panicking when allocating 0 bytes, use a 1-byte buffer.
82             1
83         } else {
84             size
85         };
86 
87         // Checking sparse features.
88         let flags = if let Some(sparse_level) = sparse {
89             if !device.enabled_features().sparse_binding {
90                 return Err(BufferCreationError::SparseBindingFeatureNotEnabled);
91             }
92 
93             if sparse_level.sparse_residency && !device.enabled_features().sparse_residency_buffer {
94                 return Err(BufferCreationError::SparseResidencyBufferFeatureNotEnabled);
95             }
96 
97             if sparse_level.sparse_aliased && !device.enabled_features().sparse_residency_aliased {
98                 return Err(BufferCreationError::SparseResidencyAliasedFeatureNotEnabled);
99             }
100 
101             sparse_level.into()
102         } else {
103             ash::vk::BufferCreateFlags::empty()
104         };
105 
106         if usage.device_address && !device.enabled_features().buffer_device_address {
107             usage.device_address = false;
108             if ash::vk::BufferUsageFlags::from(usage).is_empty() {
109                 // return an error iff device_address was the only requested usage and the
110                 // feature isn't enabled. Otherwise we'll hit that assert below.
111                 // TODO: This is weird, why not just return an error always if the feature is not enabled?
112                 // You can't use BufferUsage::all() anymore, but is that a good idea anyway?
113                 return Err(BufferCreationError::DeviceAddressFeatureNotEnabled);
114             }
115         }
116 
117         let usage_bits = ash::vk::BufferUsageFlags::from(usage);
118         // Checking for empty BufferUsage.
119         assert!(
120             !usage_bits.is_empty(),
121             "Can't create buffer with empty BufferUsage"
122         );
123 
124         let buffer = {
125             let (sh_mode, sh_indices) = match sharing {
126                 Sharing::Exclusive => {
127                     (ash::vk::SharingMode::EXCLUSIVE, SmallVec::<[u32; 8]>::new())
128                 }
129                 Sharing::Concurrent(ids) => (ash::vk::SharingMode::CONCURRENT, ids.collect()),
130             };
131 
132             let infos = ash::vk::BufferCreateInfo {
133                 flags,
134                 size,
135                 usage: usage_bits,
136                 sharing_mode: sh_mode,
137                 queue_family_index_count: sh_indices.len() as u32,
138                 p_queue_family_indices: sh_indices.as_ptr(),
139                 ..Default::default()
140             };
141 
142             let mut output = MaybeUninit::uninit();
143             check_errors(fns.v1_0.create_buffer(
144                 device.internal_object(),
145                 &infos,
146                 ptr::null(),
147                 output.as_mut_ptr(),
148             ))?;
149             output.assume_init()
150         };
151 
152         let mem_reqs = {
153             #[inline]
154             fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
155                 al * (1 + (val - 1) / al)
156             }
157 
158             let mut output = if device.api_version() >= Version::V1_1
159                 || device.enabled_extensions().khr_get_memory_requirements2
160             {
161                 let infos = ash::vk::BufferMemoryRequirementsInfo2 {
162                     buffer: buffer,
163                     ..Default::default()
164                 };
165 
166                 let mut output2 = if device.api_version() >= Version::V1_1
167                     || device.enabled_extensions().khr_dedicated_allocation
168                 {
169                     Some(ash::vk::MemoryDedicatedRequirementsKHR::default())
170                 } else {
171                     None
172                 };
173 
174                 let mut output = ash::vk::MemoryRequirements2 {
175                     p_next: output2
176                         .as_mut()
177                         .map(|o| o as *mut ash::vk::MemoryDedicatedRequirementsKHR)
178                         .unwrap_or(ptr::null_mut()) as *mut _,
179                     ..Default::default()
180                 };
181 
182                 if device.api_version() >= Version::V1_1 {
183                     fns.v1_1.get_buffer_memory_requirements2(
184                         device.internal_object(),
185                         &infos,
186                         &mut output,
187                     );
188                 } else {
189                     fns.khr_get_memory_requirements2
190                         .get_buffer_memory_requirements2_khr(
191                             device.internal_object(),
192                             &infos,
193                             &mut output,
194                         );
195                 }
196 
197                 debug_assert!(output.memory_requirements.size >= size);
198                 debug_assert!(output.memory_requirements.memory_type_bits != 0);
199 
200                 let mut out = MemoryRequirements::from(output.memory_requirements);
201                 if let Some(output2) = output2 {
202                     debug_assert_eq!(output2.requires_dedicated_allocation, 0);
203                     out.prefer_dedicated = output2.prefers_dedicated_allocation != 0;
204                 }
205                 out
206             } else {
207                 let mut output: MaybeUninit<ash::vk::MemoryRequirements> = MaybeUninit::uninit();
208                 fns.v1_0.get_buffer_memory_requirements(
209                     device.internal_object(),
210                     buffer,
211                     output.as_mut_ptr(),
212                 );
213                 let output = output.assume_init();
214                 debug_assert!(output.size >= size);
215                 debug_assert!(output.memory_type_bits != 0);
216                 MemoryRequirements::from(output)
217             };
218 
219             // We have to manually enforce some additional requirements for some buffer types.
220             let properties = device.physical_device().properties();
221             if usage.uniform_texel_buffer || usage.storage_texel_buffer {
222                 output.alignment = align(
223                     output.alignment,
224                     properties.min_texel_buffer_offset_alignment,
225                 );
226             }
227 
228             if usage.storage_buffer {
229                 output.alignment = align(
230                     output.alignment,
231                     properties.min_storage_buffer_offset_alignment,
232                 );
233             }
234 
235             if usage.uniform_buffer {
236                 output.alignment = align(
237                     output.alignment,
238                     properties.min_uniform_buffer_offset_alignment,
239                 );
240             }
241 
242             output
243         };
244 
245         let obj = UnsafeBuffer {
246             buffer,
247             device: device.clone(),
248             size,
249             usage,
250         };
251 
252         Ok((obj, mem_reqs))
253     }
254 
255     /// Binds device memory to this buffer.
bind_memory( &self, memory: &DeviceMemory, offset: DeviceSize, ) -> Result<(), OomError>256     pub unsafe fn bind_memory(
257         &self,
258         memory: &DeviceMemory,
259         offset: DeviceSize,
260     ) -> Result<(), OomError> {
261         let fns = self.device.fns();
262 
263         // We check for correctness in debug mode.
264         debug_assert!({
265             let mut mem_reqs = MaybeUninit::uninit();
266             fns.v1_0.get_buffer_memory_requirements(
267                 self.device.internal_object(),
268                 self.buffer,
269                 mem_reqs.as_mut_ptr(),
270             );
271 
272             let mem_reqs = mem_reqs.assume_init();
273             mem_reqs.size <= (memory.size() - offset)
274                 && (offset % mem_reqs.alignment) == 0
275                 && mem_reqs.memory_type_bits & (1 << memory.memory_type().id()) != 0
276         });
277 
278         // Check for alignment correctness.
279         {
280             let properties = self.device().physical_device().properties();
281             if self.usage().uniform_texel_buffer || self.usage().storage_texel_buffer {
282                 debug_assert!(offset % properties.min_texel_buffer_offset_alignment == 0);
283             }
284             if self.usage().storage_buffer {
285                 debug_assert!(offset % properties.min_storage_buffer_offset_alignment == 0);
286             }
287             if self.usage().uniform_buffer {
288                 debug_assert!(offset % properties.min_uniform_buffer_offset_alignment == 0);
289             }
290         }
291 
292         check_errors(fns.v1_0.bind_buffer_memory(
293             self.device.internal_object(),
294             self.buffer,
295             memory.internal_object(),
296             offset,
297         ))?;
298         Ok(())
299     }
300 
301     /// Returns the size of the buffer in bytes.
302     #[inline]
size(&self) -> DeviceSize303     pub fn size(&self) -> DeviceSize {
304         self.size
305     }
306 
307     /// Returns the buffer the image was created with.
308     #[inline]
usage(&self) -> BufferUsage309     pub fn usage(&self) -> BufferUsage {
310         self.usage
311     }
312 
313     /// Returns a key unique to each `UnsafeBuffer`. Can be used for the `conflicts_key` method.
314     #[inline]
key(&self) -> u64315     pub fn key(&self) -> u64 {
316         self.buffer.as_raw()
317     }
318 }
319 
320 unsafe impl VulkanObject for UnsafeBuffer {
321     type Object = ash::vk::Buffer;
322 
323     #[inline]
internal_object(&self) -> ash::vk::Buffer324     fn internal_object(&self) -> ash::vk::Buffer {
325         self.buffer
326     }
327 }
328 
329 unsafe impl DeviceOwned for UnsafeBuffer {
330     #[inline]
device(&self) -> &Arc<Device>331     fn device(&self) -> &Arc<Device> {
332         &self.device
333     }
334 }
335 
336 impl fmt::Debug for UnsafeBuffer {
337     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>338     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
339         write!(fmt, "<Vulkan buffer {:?}>", self.buffer)
340     }
341 }
342 
343 impl Drop for UnsafeBuffer {
344     #[inline]
drop(&mut self)345     fn drop(&mut self) {
346         unsafe {
347             let fns = self.device.fns();
348             fns.v1_0
349                 .destroy_buffer(self.device.internal_object(), self.buffer, ptr::null());
350         }
351     }
352 }
353 
354 impl PartialEq for UnsafeBuffer {
355     #[inline]
eq(&self, other: &Self) -> bool356     fn eq(&self, other: &Self) -> bool {
357         self.buffer == other.buffer && self.device == other.device
358     }
359 }
360 
361 impl Eq for UnsafeBuffer {}
362 
363 impl Hash for UnsafeBuffer {
364     #[inline]
hash<H: Hasher>(&self, state: &mut H)365     fn hash<H: Hasher>(&self, state: &mut H) {
366         self.buffer.hash(state);
367         self.device.hash(state);
368     }
369 }
370 
371 /// The level of sparse binding that a buffer should be created with.
372 #[derive(Debug, Copy, Clone)]
373 pub struct SparseLevel {
374     pub sparse_residency: bool,
375     pub sparse_aliased: bool,
376 }
377 
378 impl SparseLevel {
379     #[inline]
none() -> SparseLevel380     pub fn none() -> SparseLevel {
381         SparseLevel {
382             sparse_residency: false,
383             sparse_aliased: false,
384         }
385     }
386 }
387 
388 impl From<SparseLevel> for ash::vk::BufferCreateFlags {
389     #[inline]
from(val: SparseLevel) -> Self390     fn from(val: SparseLevel) -> Self {
391         let mut result = ash::vk::BufferCreateFlags::SPARSE_BINDING;
392         if val.sparse_residency {
393             result |= ash::vk::BufferCreateFlags::SPARSE_RESIDENCY;
394         }
395         if val.sparse_aliased {
396             result |= ash::vk::BufferCreateFlags::SPARSE_ALIASED;
397         }
398         result
399     }
400 }
401 
402 /// The device address usage flag was not set.
403 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
404 pub struct DeviceAddressUsageNotEnabledError;
405 impl error::Error for DeviceAddressUsageNotEnabledError {}
406 impl fmt::Display for DeviceAddressUsageNotEnabledError {
407     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result408     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
409         fmt.write_str("the device address usage flag was not set on this buffer")
410     }
411 }
412 
413 /// Error that can happen when creating a buffer.
414 #[derive(Clone, Debug, PartialEq, Eq)]
415 pub enum BufferCreationError {
416     /// Allocating memory failed.
417     AllocError(DeviceMemoryAllocError),
418     /// Sparse binding was requested but the corresponding feature wasn't enabled.
419     SparseBindingFeatureNotEnabled,
420     /// Sparse residency was requested but the corresponding feature wasn't enabled.
421     SparseResidencyBufferFeatureNotEnabled,
422     /// Sparse aliasing was requested but the corresponding feature wasn't enabled.
423     SparseResidencyAliasedFeatureNotEnabled,
424     /// Device address was requested but the corresponding feature wasn't enabled.
425     DeviceAddressFeatureNotEnabled,
426 }
427 
428 impl error::Error for BufferCreationError {
429     #[inline]
source(&self) -> Option<&(dyn error::Error + 'static)>430     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
431         match *self {
432             BufferCreationError::AllocError(ref err) => Some(err),
433             _ => None,
434         }
435     }
436 }
437 
438 impl fmt::Display for BufferCreationError {
439     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>440     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
441         write!(
442             fmt,
443             "{}",
444             match *self {
445                 BufferCreationError::AllocError(_) => "allocating memory failed",
446                 BufferCreationError::SparseBindingFeatureNotEnabled => {
447                     "sparse binding was requested but the corresponding feature wasn't enabled"
448                 }
449                 BufferCreationError::SparseResidencyBufferFeatureNotEnabled => {
450                     "sparse residency was requested but the corresponding feature wasn't enabled"
451                 }
452                 BufferCreationError::SparseResidencyAliasedFeatureNotEnabled => {
453                     "sparse aliasing was requested but the corresponding feature wasn't enabled"
454                 }
455                 BufferCreationError::DeviceAddressFeatureNotEnabled => {
456                     "device address was requested but the corresponding feature wasn't enabled"
457                 }
458             }
459         )
460     }
461 }
462 
463 impl From<OomError> for BufferCreationError {
464     #[inline]
from(err: OomError) -> BufferCreationError465     fn from(err: OomError) -> BufferCreationError {
466         BufferCreationError::AllocError(err.into())
467     }
468 }
469 
470 impl From<Error> for BufferCreationError {
471     #[inline]
from(err: Error) -> BufferCreationError472     fn from(err: Error) -> BufferCreationError {
473         match err {
474             err @ Error::OutOfHostMemory => {
475                 BufferCreationError::AllocError(DeviceMemoryAllocError::from(err))
476             }
477             err @ Error::OutOfDeviceMemory => {
478                 BufferCreationError::AllocError(DeviceMemoryAllocError::from(err))
479             }
480             _ => panic!("unexpected error: {:?}", err),
481         }
482     }
483 }
484 
485 #[cfg(test)]
486 mod tests {
487     use std::iter::Empty;
488 
489     use super::BufferCreationError;
490     use super::BufferUsage;
491     use super::SparseLevel;
492     use super::UnsafeBuffer;
493 
494     use crate::device::Device;
495     use crate::device::DeviceOwned;
496     use crate::sync::Sharing;
497 
498     #[test]
create()499     fn create() {
500         let (device, _) = gfx_dev_and_queue!();
501         let (buf, reqs) = unsafe {
502             UnsafeBuffer::new(
503                 device.clone(),
504                 128,
505                 BufferUsage::all(),
506                 Sharing::Exclusive::<Empty<_>>,
507                 None,
508             )
509         }
510         .unwrap();
511 
512         assert!(reqs.size >= 128);
513         assert_eq!(buf.size(), 128);
514         assert_eq!(&**buf.device() as *const Device, &*device as *const Device);
515     }
516 
517     #[test]
missing_feature_sparse_binding()518     fn missing_feature_sparse_binding() {
519         let (device, _) = gfx_dev_and_queue!();
520         let sparse = Some(SparseLevel::none());
521         unsafe {
522             match UnsafeBuffer::new(
523                 device,
524                 128,
525                 BufferUsage::all(),
526                 Sharing::Exclusive::<Empty<_>>,
527                 sparse,
528             ) {
529                 Err(BufferCreationError::SparseBindingFeatureNotEnabled) => (),
530                 _ => panic!(),
531             }
532         };
533     }
534 
535     #[test]
missing_feature_sparse_residency()536     fn missing_feature_sparse_residency() {
537         let (device, _) = gfx_dev_and_queue!(sparse_binding);
538         let sparse = Some(SparseLevel {
539             sparse_residency: true,
540             sparse_aliased: false,
541         });
542         unsafe {
543             match UnsafeBuffer::new(
544                 device,
545                 128,
546                 BufferUsage::all(),
547                 Sharing::Exclusive::<Empty<_>>,
548                 sparse,
549             ) {
550                 Err(BufferCreationError::SparseResidencyBufferFeatureNotEnabled) => (),
551                 _ => panic!(),
552             }
553         };
554     }
555 
556     #[test]
missing_feature_sparse_aliased()557     fn missing_feature_sparse_aliased() {
558         let (device, _) = gfx_dev_and_queue!(sparse_binding);
559         let sparse = Some(SparseLevel {
560             sparse_residency: false,
561             sparse_aliased: true,
562         });
563         unsafe {
564             match UnsafeBuffer::new(
565                 device,
566                 128,
567                 BufferUsage::all(),
568                 Sharing::Exclusive::<Empty<_>>,
569                 sparse,
570             ) {
571                 Err(BufferCreationError::SparseResidencyAliasedFeatureNotEnabled) => (),
572                 _ => panic!(),
573             }
574         };
575     }
576 
577     #[test]
create_empty_buffer()578     fn create_empty_buffer() {
579         let (device, _) = gfx_dev_and_queue!();
580 
581         unsafe {
582             let _ = UnsafeBuffer::new(
583                 device,
584                 0,
585                 BufferUsage::all(),
586                 Sharing::Exclusive::<Empty<_>>,
587                 None,
588             );
589         };
590     }
591 }
592