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