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 //! View of a buffer, in order to use it as a uniform texel buffer or storage texel buffer. 11 //! 12 //! In order to use a buffer as a uniform texel buffer or a storage texel buffer, you have to 13 //! create a `BufferView`, which indicates which format the data is in. 14 //! 15 //! In order to create a view from a buffer, the buffer must have been created with either the 16 //! `uniform_texel_buffer` or the `storage_texel_buffer` usage. 17 //! 18 //! # Examples 19 //! 20 //! ``` 21 //! # use std::sync::Arc; 22 //! use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage}; 23 //! use vulkano::buffer::view::{BufferView, BufferViewCreateInfo}; 24 //! use vulkano::format::Format; 25 //! use vulkano::memory::allocator::AllocationCreateInfo; 26 //! 27 //! # let queue: Arc<vulkano::device::Queue> = return; 28 //! # let memory_allocator: vulkano::memory::allocator::StandardMemoryAllocator = return; 29 //! let buffer = Buffer::new_slice::<u32>( 30 //! &memory_allocator, 31 //! BufferCreateInfo { 32 //! usage: BufferUsage::STORAGE_TEXEL_BUFFER, 33 //! ..Default::default() 34 //! }, 35 //! AllocationCreateInfo::default(), 36 //! 128, 37 //! ) 38 //! .unwrap(); 39 //! 40 //! let view = BufferView::new( 41 //! buffer, 42 //! BufferViewCreateInfo { 43 //! format: Some(Format::R32_UINT), 44 //! ..Default::default() 45 //! }, 46 //! ) 47 //! .unwrap(); 48 //! ``` 49 50 use super::{BufferUsage, Subbuffer}; 51 use crate::{ 52 device::{Device, DeviceOwned}, 53 format::{Format, FormatFeatures}, 54 macros::impl_id_counter, 55 memory::{is_aligned, DeviceAlignment}, 56 DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, 57 }; 58 use std::{ 59 error::Error, 60 fmt::{Display, Error as FmtError, Formatter}, 61 mem::MaybeUninit, 62 num::NonZeroU64, 63 ops::Range, 64 ptr, 65 sync::Arc, 66 }; 67 68 /// Represents a way for the GPU to interpret buffer data. See the documentation of the 69 /// `view` module. 70 #[derive(Debug)] 71 pub struct BufferView { 72 handle: ash::vk::BufferView, 73 subbuffer: Subbuffer<[u8]>, 74 id: NonZeroU64, 75 76 format: Option<Format>, 77 format_features: FormatFeatures, 78 range: Range<DeviceSize>, 79 } 80 81 impl BufferView { 82 /// Creates a new `BufferView`. 83 #[inline] new( subbuffer: Subbuffer<impl ?Sized>, create_info: BufferViewCreateInfo, ) -> Result<Arc<BufferView>, BufferViewCreationError>84 pub fn new( 85 subbuffer: Subbuffer<impl ?Sized>, 86 create_info: BufferViewCreateInfo, 87 ) -> Result<Arc<BufferView>, BufferViewCreationError> { 88 Self::new_inner(subbuffer.into_bytes(), create_info) 89 } 90 new_inner( subbuffer: Subbuffer<[u8]>, create_info: BufferViewCreateInfo, ) -> Result<Arc<BufferView>, BufferViewCreationError>91 fn new_inner( 92 subbuffer: Subbuffer<[u8]>, 93 create_info: BufferViewCreateInfo, 94 ) -> Result<Arc<BufferView>, BufferViewCreationError> { 95 let BufferViewCreateInfo { format, _ne: _ } = create_info; 96 97 let buffer = subbuffer.buffer(); 98 let device = buffer.device(); 99 let properties = device.physical_device().properties(); 100 let size = subbuffer.size(); 101 let offset = subbuffer.offset(); 102 103 // No VUID, but seems sensible? 104 let format = format.unwrap(); 105 106 // VUID-VkBufferViewCreateInfo-format-parameter 107 format.validate_device(device)?; 108 109 // VUID-VkBufferViewCreateInfo-buffer-00932 110 if !buffer 111 .usage() 112 .intersects(BufferUsage::UNIFORM_TEXEL_BUFFER | BufferUsage::STORAGE_TEXEL_BUFFER) 113 { 114 return Err(BufferViewCreationError::BufferMissingUsage); 115 } 116 117 // Use unchecked, because all validation has been done above. 118 let format_features = unsafe { 119 device 120 .physical_device() 121 .format_properties_unchecked(format) 122 .buffer_features 123 }; 124 125 // VUID-VkBufferViewCreateInfo-buffer-00933 126 if buffer.usage().intersects(BufferUsage::UNIFORM_TEXEL_BUFFER) 127 && !format_features.intersects(FormatFeatures::UNIFORM_TEXEL_BUFFER) 128 { 129 return Err(BufferViewCreationError::UnsupportedFormat); 130 } 131 132 // VUID-VkBufferViewCreateInfo-buffer-00934 133 if buffer.usage().intersects(BufferUsage::STORAGE_TEXEL_BUFFER) 134 && !format_features.intersects(FormatFeatures::STORAGE_TEXEL_BUFFER) 135 { 136 return Err(BufferViewCreationError::UnsupportedFormat); 137 } 138 139 let block_size = format.block_size().unwrap(); 140 let texels_per_block = format.texels_per_block(); 141 142 // VUID-VkBufferViewCreateInfo-range-00929 143 if size % block_size != 0 { 144 return Err(BufferViewCreationError::RangeNotAligned { 145 range: size, 146 required_alignment: block_size, 147 }); 148 } 149 150 // VUID-VkBufferViewCreateInfo-range-00930 151 if ((size / block_size) * texels_per_block as DeviceSize) as u32 152 > properties.max_texel_buffer_elements 153 { 154 return Err(BufferViewCreationError::MaxTexelBufferElementsExceeded); 155 } 156 157 if device.api_version() >= Version::V1_3 || device.enabled_features().texel_buffer_alignment 158 { 159 let element_size = DeviceAlignment::new(if block_size % 3 == 0 { 160 block_size / 3 161 } else { 162 block_size 163 }) 164 .unwrap(); 165 166 if buffer.usage().intersects(BufferUsage::STORAGE_TEXEL_BUFFER) { 167 let mut required_alignment = properties 168 .storage_texel_buffer_offset_alignment_bytes 169 .unwrap(); 170 171 if properties 172 .storage_texel_buffer_offset_single_texel_alignment 173 .unwrap() 174 { 175 required_alignment = required_alignment.min(element_size); 176 } 177 178 // VUID-VkBufferViewCreateInfo-buffer-02750 179 if !is_aligned(offset, required_alignment) { 180 return Err(BufferViewCreationError::OffsetNotAligned { 181 offset, 182 required_alignment, 183 }); 184 } 185 } 186 187 if buffer.usage().intersects(BufferUsage::UNIFORM_TEXEL_BUFFER) { 188 let mut required_alignment = properties 189 .uniform_texel_buffer_offset_alignment_bytes 190 .unwrap(); 191 192 if properties 193 .uniform_texel_buffer_offset_single_texel_alignment 194 .unwrap() 195 { 196 required_alignment = required_alignment.min(element_size); 197 } 198 199 // VUID-VkBufferViewCreateInfo-buffer-02751 200 if !is_aligned(offset, required_alignment) { 201 return Err(BufferViewCreationError::OffsetNotAligned { 202 offset, 203 required_alignment, 204 }); 205 } 206 } 207 } else { 208 let required_alignment = properties.min_texel_buffer_offset_alignment; 209 210 // VUID-VkBufferViewCreateInfo-offset-02749 211 if !is_aligned(offset, required_alignment) { 212 return Err(BufferViewCreationError::OffsetNotAligned { 213 offset, 214 required_alignment, 215 }); 216 } 217 } 218 219 let create_info = ash::vk::BufferViewCreateInfo { 220 flags: ash::vk::BufferViewCreateFlags::empty(), 221 buffer: buffer.handle(), 222 format: format.into(), 223 offset, 224 range: size, 225 ..Default::default() 226 }; 227 228 let handle = unsafe { 229 let fns = device.fns(); 230 let mut output = MaybeUninit::uninit(); 231 (fns.v1_0.create_buffer_view)( 232 device.handle(), 233 &create_info, 234 ptr::null(), 235 output.as_mut_ptr(), 236 ) 237 .result() 238 .map_err(VulkanError::from)?; 239 output.assume_init() 240 }; 241 242 Ok(Arc::new(BufferView { 243 handle, 244 subbuffer, 245 id: Self::next_id(), 246 format: Some(format), 247 format_features, 248 range: 0..size, 249 })) 250 } 251 252 /// Returns the buffer associated to this view. 253 #[inline] buffer(&self) -> &Subbuffer<[u8]>254 pub fn buffer(&self) -> &Subbuffer<[u8]> { 255 &self.subbuffer 256 } 257 258 /// Returns the format of this view. 259 #[inline] format(&self) -> Option<Format>260 pub fn format(&self) -> Option<Format> { 261 self.format 262 } 263 264 /// Returns the features supported by this view’s format. 265 #[inline] format_features(&self) -> FormatFeatures266 pub fn format_features(&self) -> FormatFeatures { 267 self.format_features 268 } 269 270 /// Returns the byte range of the wrapped buffer that this view exposes. 271 #[inline] range(&self) -> Range<DeviceSize>272 pub fn range(&self) -> Range<DeviceSize> { 273 self.range.clone() 274 } 275 } 276 277 impl Drop for BufferView { 278 #[inline] drop(&mut self)279 fn drop(&mut self) { 280 unsafe { 281 let fns = self.subbuffer.device().fns(); 282 (fns.v1_0.destroy_buffer_view)( 283 self.subbuffer.device().handle(), 284 self.handle, 285 ptr::null(), 286 ); 287 } 288 } 289 } 290 291 unsafe impl VulkanObject for BufferView { 292 type Handle = ash::vk::BufferView; 293 294 #[inline] handle(&self) -> Self::Handle295 fn handle(&self) -> Self::Handle { 296 self.handle 297 } 298 } 299 300 unsafe impl DeviceOwned for BufferView { 301 #[inline] device(&self) -> &Arc<Device>302 fn device(&self) -> &Arc<Device> { 303 self.subbuffer.device() 304 } 305 } 306 307 impl_id_counter!(BufferView); 308 309 /// Parameters to create a new `BufferView`. 310 #[derive(Clone, Debug)] 311 pub struct BufferViewCreateInfo { 312 /// The format of the buffer view. 313 /// 314 /// The default value is `None`, which must be overridden. 315 pub format: Option<Format>, 316 317 pub _ne: crate::NonExhaustive, 318 } 319 320 impl Default for BufferViewCreateInfo { 321 #[inline] default() -> Self322 fn default() -> Self { 323 Self { 324 format: None, 325 _ne: crate::NonExhaustive(()), 326 } 327 } 328 } 329 330 /// Error that can happen when creating a buffer view. 331 #[derive(Debug, Copy, Clone)] 332 pub enum BufferViewCreationError { 333 /// Out of memory. 334 OomError(OomError), 335 336 RequirementNotMet { 337 required_for: &'static str, 338 requires_one_of: RequiresOneOf, 339 }, 340 341 /// The buffer was not created with one of the `storage_texel_buffer` or 342 /// `uniform_texel_buffer` usages. 343 BufferMissingUsage, 344 345 /// The offset within the buffer is not a multiple of the required alignment. 346 OffsetNotAligned { 347 offset: DeviceSize, 348 required_alignment: DeviceAlignment, 349 }, 350 351 /// The range within the buffer is not a multiple of the required alignment. 352 RangeNotAligned { 353 range: DeviceSize, 354 required_alignment: DeviceSize, 355 }, 356 357 /// The requested format is not supported for this usage. 358 UnsupportedFormat, 359 360 /// The `max_texel_buffer_elements` limit has been exceeded. 361 MaxTexelBufferElementsExceeded, 362 } 363 364 impl Error for BufferViewCreationError { source(&self) -> Option<&(dyn Error + 'static)>365 fn source(&self) -> Option<&(dyn Error + 'static)> { 366 match self { 367 BufferViewCreationError::OomError(err) => Some(err), 368 _ => None, 369 } 370 } 371 } 372 373 impl Display for BufferViewCreationError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>374 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 375 match self { 376 Self::OomError(_) => write!(f, "out of memory when creating buffer view"), 377 Self::RequirementNotMet { 378 required_for, 379 requires_one_of, 380 } => write!( 381 f, 382 "a requirement was not met for: {}; requires one of: {}", 383 required_for, requires_one_of, 384 ), 385 Self::BufferMissingUsage => write!( 386 f, 387 "the buffer was not created with one of the `storage_texel_buffer` or \ 388 `uniform_texel_buffer` usages", 389 ), 390 Self::OffsetNotAligned { .. } => write!( 391 f, 392 "the offset within the buffer is not a multiple of the required alignment", 393 ), 394 Self::RangeNotAligned { .. } => write!( 395 f, 396 "the range within the buffer is not a multiple of the required alignment", 397 ), 398 Self::UnsupportedFormat => { 399 write!(f, "the requested format is not supported for this usage") 400 } 401 Self::MaxTexelBufferElementsExceeded => { 402 write!(f, "the `max_texel_buffer_elements` limit has been exceeded") 403 } 404 } 405 } 406 } 407 408 impl From<OomError> for BufferViewCreationError { from(err: OomError) -> Self409 fn from(err: OomError) -> Self { 410 Self::OomError(err) 411 } 412 } 413 414 impl From<VulkanError> for BufferViewCreationError { from(err: VulkanError) -> Self415 fn from(err: VulkanError) -> Self { 416 OomError::from(err).into() 417 } 418 } 419 420 impl From<RequirementNotMet> for BufferViewCreationError { from(err: RequirementNotMet) -> Self421 fn from(err: RequirementNotMet) -> Self { 422 Self::RequirementNotMet { 423 required_for: err.required_for, 424 requires_one_of: err.requires_one_of, 425 } 426 } 427 } 428 429 #[cfg(test)] 430 mod tests { 431 use super::{BufferView, BufferViewCreateInfo, BufferViewCreationError}; 432 use crate::{ 433 buffer::{Buffer, BufferCreateInfo, BufferUsage}, 434 format::Format, 435 memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator}, 436 }; 437 438 #[test] create_uniform()439 fn create_uniform() { 440 // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format 441 let (device, _) = gfx_dev_and_queue!(); 442 let memory_allocator = StandardMemoryAllocator::new_default(device); 443 444 let buffer = Buffer::new_slice::<[u8; 4]>( 445 &memory_allocator, 446 BufferCreateInfo { 447 usage: BufferUsage::UNIFORM_TEXEL_BUFFER, 448 ..Default::default() 449 }, 450 AllocationCreateInfo { 451 usage: MemoryUsage::Upload, 452 ..Default::default() 453 }, 454 128, 455 ) 456 .unwrap(); 457 BufferView::new( 458 buffer, 459 BufferViewCreateInfo { 460 format: Some(Format::R8G8B8A8_UNORM), 461 ..Default::default() 462 }, 463 ) 464 .unwrap(); 465 } 466 467 #[test] create_storage()468 fn create_storage() { 469 // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format 470 let (device, _) = gfx_dev_and_queue!(); 471 let memory_allocator = StandardMemoryAllocator::new_default(device); 472 473 let buffer = Buffer::new_slice::<[u8; 4]>( 474 &memory_allocator, 475 BufferCreateInfo { 476 usage: BufferUsage::STORAGE_TEXEL_BUFFER, 477 ..Default::default() 478 }, 479 AllocationCreateInfo::default(), 480 128, 481 ) 482 .unwrap(); 483 BufferView::new( 484 buffer, 485 BufferViewCreateInfo { 486 format: Some(Format::R8G8B8A8_UNORM), 487 ..Default::default() 488 }, 489 ) 490 .unwrap(); 491 } 492 493 #[test] create_storage_atomic()494 fn create_storage_atomic() { 495 // `VK_FORMAT_R32_UINT` guaranteed to be a supported format for atomics 496 let (device, _) = gfx_dev_and_queue!(); 497 let memory_allocator = StandardMemoryAllocator::new_default(device); 498 499 let buffer = Buffer::new_slice::<u32>( 500 &memory_allocator, 501 BufferCreateInfo { 502 usage: BufferUsage::STORAGE_TEXEL_BUFFER, 503 ..Default::default() 504 }, 505 AllocationCreateInfo::default(), 506 128, 507 ) 508 .unwrap(); 509 BufferView::new( 510 buffer, 511 BufferViewCreateInfo { 512 format: Some(Format::R32_UINT), 513 ..Default::default() 514 }, 515 ) 516 .unwrap(); 517 } 518 519 #[test] wrong_usage()520 fn wrong_usage() { 521 // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format 522 let (device, _) = gfx_dev_and_queue!(); 523 let memory_allocator = StandardMemoryAllocator::new_default(device); 524 525 let buffer = Buffer::new_slice::<[u8; 4]>( 526 &memory_allocator, 527 BufferCreateInfo { 528 usage: BufferUsage::TRANSFER_DST, // Dummy value 529 ..Default::default() 530 }, 531 AllocationCreateInfo::default(), 532 128, 533 ) 534 .unwrap(); 535 536 match BufferView::new( 537 buffer, 538 BufferViewCreateInfo { 539 format: Some(Format::R8G8B8A8_UNORM), 540 ..Default::default() 541 }, 542 ) { 543 Err(BufferViewCreationError::BufferMissingUsage) => (), 544 _ => panic!(), 545 } 546 } 547 548 #[test] unsupported_format()549 fn unsupported_format() { 550 let (device, _) = gfx_dev_and_queue!(); 551 let memory_allocator = StandardMemoryAllocator::new_default(device); 552 553 let buffer = Buffer::new_slice::<[f64; 4]>( 554 &memory_allocator, 555 BufferCreateInfo { 556 usage: BufferUsage::UNIFORM_TEXEL_BUFFER | BufferUsage::STORAGE_TEXEL_BUFFER, 557 ..Default::default() 558 }, 559 AllocationCreateInfo::default(), 560 128, 561 ) 562 .unwrap(); 563 564 // TODO: what if R64G64B64A64_SFLOAT is supported? 565 match BufferView::new( 566 buffer, 567 BufferViewCreateInfo { 568 format: Some(Format::R64G64B64A64_SFLOAT), 569 ..Default::default() 570 }, 571 ) { 572 Err(BufferViewCreationError::UnsupportedFormat) => (), 573 _ => panic!(), 574 } 575 } 576 } 577