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 //! # Example 19 //! 20 //! ``` 21 //! # use std::sync::Arc; 22 //! use vulkano::buffer::immutable::ImmutableBuffer; 23 //! use vulkano::buffer::BufferUsage; 24 //! use vulkano::buffer::BufferView; 25 //! use vulkano::format::Format; 26 //! 27 //! # let device: Arc<vulkano::device::Device> = return; 28 //! # let queue: Arc<vulkano::device::Queue> = return; 29 //! let usage = BufferUsage { 30 //! storage_texel_buffer: true, 31 //! .. BufferUsage::none() 32 //! }; 33 //! 34 //! let (buffer, _future) = ImmutableBuffer::<[u32]>::from_iter((0..128).map(|n| n), usage, 35 //! queue.clone()).unwrap(); 36 //! let _view = BufferView::new(buffer, Format::R32Uint).unwrap(); 37 //! ``` 38 39 use crate::buffer::BufferAccess; 40 use crate::buffer::BufferInner; 41 use crate::buffer::TypedBufferAccess; 42 use crate::check_errors; 43 use crate::device::Device; 44 use crate::device::DeviceOwned; 45 use crate::format::Format; 46 use crate::format::Pixel; 47 use crate::Error; 48 use crate::OomError; 49 use crate::SafeDeref; 50 use crate::VulkanObject; 51 use std::error; 52 use std::fmt; 53 use std::mem::MaybeUninit; 54 use std::ptr; 55 use std::sync::Arc; 56 57 /// Represents a way for the GPU to interpret buffer data. See the documentation of the 58 /// `view` module. 59 pub struct BufferView<B> 60 where 61 B: BufferAccess, 62 { 63 view: ash::vk::BufferView, 64 buffer: B, 65 atomic_accesses: bool, 66 } 67 68 impl<B> BufferView<B> 69 where 70 B: BufferAccess, 71 { 72 /// Builds a new buffer view. 73 #[inline] new<Px>(buffer: B, format: Format) -> Result<BufferView<B>, BufferViewCreationError> where B: TypedBufferAccess<Content = [Px]>, Px: Pixel,74 pub fn new<Px>(buffer: B, format: Format) -> Result<BufferView<B>, BufferViewCreationError> 75 where 76 B: TypedBufferAccess<Content = [Px]>, 77 Px: Pixel, 78 { 79 unsafe { BufferView::unchecked(buffer, format) } 80 } 81 82 /// Builds a new buffer view without checking that the format is correct. unchecked( org_buffer: B, format: Format, ) -> Result<BufferView<B>, BufferViewCreationError> where B: BufferAccess,83 pub unsafe fn unchecked( 84 org_buffer: B, 85 format: Format, 86 ) -> Result<BufferView<B>, BufferViewCreationError> 87 where 88 B: BufferAccess, 89 { 90 let (view, format_props) = { 91 let size = org_buffer.size(); 92 let BufferInner { buffer, offset } = org_buffer.inner(); 93 94 let device = buffer.device(); 95 96 if (offset 97 % device 98 .physical_device() 99 .properties() 100 .min_texel_buffer_offset_alignment) 101 != 0 102 { 103 return Err(BufferViewCreationError::WrongBufferAlignment); 104 } 105 106 if !buffer.usage().uniform_texel_buffer && !buffer.usage().storage_texel_buffer { 107 return Err(BufferViewCreationError::WrongBufferUsage); 108 } 109 110 { 111 let nb = size 112 / format 113 .size() 114 .expect("Can't use a compressed format for buffer views"); 115 let l = device 116 .physical_device() 117 .properties() 118 .max_texel_buffer_elements; 119 120 if nb as u32 > l { 121 return Err(BufferViewCreationError::MaxTexelBufferElementsExceeded); 122 } 123 } 124 125 let format_props = { 126 let fns_i = device.instance().fns(); 127 let mut output = MaybeUninit::uninit(); 128 fns_i.v1_0.get_physical_device_format_properties( 129 device.physical_device().internal_object(), 130 format.into(), 131 output.as_mut_ptr(), 132 ); 133 output.assume_init().buffer_features 134 }; 135 136 if buffer.usage().uniform_texel_buffer { 137 if (format_props & ash::vk::FormatFeatureFlags::UNIFORM_TEXEL_BUFFER).is_empty() { 138 return Err(BufferViewCreationError::UnsupportedFormat); 139 } 140 } 141 142 if buffer.usage().storage_texel_buffer { 143 if (format_props & ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER).is_empty() { 144 return Err(BufferViewCreationError::UnsupportedFormat); 145 } 146 } 147 148 let infos = ash::vk::BufferViewCreateInfo { 149 flags: ash::vk::BufferViewCreateFlags::empty(), 150 buffer: buffer.internal_object(), 151 format: format.into(), 152 offset, 153 range: size, 154 ..Default::default() 155 }; 156 157 let fns = device.fns(); 158 let mut output = MaybeUninit::uninit(); 159 check_errors(fns.v1_0.create_buffer_view( 160 device.internal_object(), 161 &infos, 162 ptr::null(), 163 output.as_mut_ptr(), 164 ))?; 165 (output.assume_init(), format_props) 166 }; 167 168 Ok(BufferView { 169 view, 170 buffer: org_buffer, 171 atomic_accesses: !(format_props 172 & ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER_ATOMIC) 173 .is_empty(), 174 }) 175 } 176 177 /// Returns the buffer associated to this view. 178 #[inline] buffer(&self) -> &B179 pub fn buffer(&self) -> &B { 180 &self.buffer 181 } 182 183 /// Returns true if the buffer view can be used as a uniform texel buffer. 184 #[inline] uniform_texel_buffer(&self) -> bool185 pub fn uniform_texel_buffer(&self) -> bool { 186 self.buffer.inner().buffer.usage().uniform_texel_buffer 187 } 188 189 /// Returns true if the buffer view can be used as a storage texel buffer. 190 #[inline] storage_texel_buffer(&self) -> bool191 pub fn storage_texel_buffer(&self) -> bool { 192 self.buffer.inner().buffer.usage().storage_texel_buffer 193 } 194 195 /// Returns true if the buffer view can be used as a storage texel buffer with atomic accesses. 196 #[inline] storage_texel_buffer_atomic(&self) -> bool197 pub fn storage_texel_buffer_atomic(&self) -> bool { 198 self.atomic_accesses && self.storage_texel_buffer() 199 } 200 } 201 202 unsafe impl<B> VulkanObject for BufferView<B> 203 where 204 B: BufferAccess, 205 { 206 type Object = ash::vk::BufferView; 207 208 #[inline] internal_object(&self) -> ash::vk::BufferView209 fn internal_object(&self) -> ash::vk::BufferView { 210 self.view 211 } 212 } 213 214 unsafe impl<B> DeviceOwned for BufferView<B> 215 where 216 B: BufferAccess, 217 { 218 #[inline] device(&self) -> &Arc<Device>219 fn device(&self) -> &Arc<Device> { 220 self.buffer.device() 221 } 222 } 223 224 impl<B> fmt::Debug for BufferView<B> 225 where 226 B: BufferAccess + fmt::Debug, 227 { fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>228 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 229 fmt.debug_struct("BufferView") 230 .field("raw", &self.view) 231 .field("buffer", &self.buffer) 232 .finish() 233 } 234 } 235 236 impl<B> Drop for BufferView<B> 237 where 238 B: BufferAccess, 239 { 240 #[inline] drop(&mut self)241 fn drop(&mut self) { 242 unsafe { 243 let fns = self.buffer.inner().buffer.device().fns(); 244 fns.v1_0.destroy_buffer_view( 245 self.buffer.inner().buffer.device().internal_object(), 246 self.view, 247 ptr::null(), 248 ); 249 } 250 } 251 } 252 253 pub unsafe trait BufferViewRef { 254 type BufferAccess: BufferAccess; 255 view(&self) -> &BufferView<Self::BufferAccess>256 fn view(&self) -> &BufferView<Self::BufferAccess>; 257 } 258 259 unsafe impl<B> BufferViewRef for BufferView<B> 260 where 261 B: BufferAccess, 262 { 263 type BufferAccess = B; 264 265 #[inline] view(&self) -> &BufferView<B>266 fn view(&self) -> &BufferView<B> { 267 self 268 } 269 } 270 271 unsafe impl<T, B> BufferViewRef for T 272 where 273 T: SafeDeref<Target = BufferView<B>>, 274 B: BufferAccess, 275 { 276 type BufferAccess = B; 277 278 #[inline] view(&self) -> &BufferView<B>279 fn view(&self) -> &BufferView<B> { 280 &**self 281 } 282 } 283 284 /// Error that can happen when creating a buffer view. 285 #[derive(Debug, Copy, Clone)] 286 pub enum BufferViewCreationError { 287 /// Out of memory. 288 OomError(OomError), 289 290 /// The buffer was not creating with one of the `storage_texel_buffer` or 291 /// `uniform_texel_buffer` usages. 292 WrongBufferUsage, 293 294 /// The offset within the buffer is not a multiple of the `min_texel_buffer_offset_alignment` 295 /// limit. 296 WrongBufferAlignment, 297 298 /// The requested format is not supported for this usage. 299 UnsupportedFormat, 300 301 /// The maximum number of elements in the buffer view has been exceeded. 302 MaxTexelBufferElementsExceeded, 303 } 304 305 impl error::Error for BufferViewCreationError { 306 #[inline] source(&self) -> Option<&(dyn error::Error + 'static)>307 fn source(&self) -> Option<&(dyn error::Error + 'static)> { 308 match *self { 309 BufferViewCreationError::OomError(ref err) => Some(err), 310 _ => None, 311 } 312 } 313 } 314 315 impl fmt::Display for BufferViewCreationError { 316 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>317 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 318 write!( 319 fmt, 320 "{}", 321 match *self { 322 BufferViewCreationError::OomError(_) => "out of memory when creating buffer view", 323 BufferViewCreationError::WrongBufferUsage => { 324 "the buffer is missing correct usage flags" 325 } 326 BufferViewCreationError::WrongBufferAlignment => { 327 "the offset within the buffer is not a multiple of the 328 `min_texel_buffer_offset_alignment` limit" 329 } 330 BufferViewCreationError::UnsupportedFormat => { 331 "the requested format is not supported for this usage" 332 } 333 BufferViewCreationError::MaxTexelBufferElementsExceeded => { 334 "the maximum number of texel elements is exceeded" 335 } 336 } 337 ) 338 } 339 } 340 341 impl From<OomError> for BufferViewCreationError { 342 #[inline] from(err: OomError) -> BufferViewCreationError343 fn from(err: OomError) -> BufferViewCreationError { 344 BufferViewCreationError::OomError(err) 345 } 346 } 347 348 impl From<Error> for BufferViewCreationError { 349 #[inline] from(err: Error) -> BufferViewCreationError350 fn from(err: Error) -> BufferViewCreationError { 351 OomError::from(err).into() 352 } 353 } 354 355 #[cfg(test)] 356 mod tests { 357 use crate::buffer::immutable::ImmutableBuffer; 358 use crate::buffer::view::BufferViewCreationError; 359 use crate::buffer::BufferUsage; 360 use crate::buffer::BufferView; 361 use crate::format::Format; 362 363 #[test] create_uniform()364 fn create_uniform() { 365 // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format 366 let (device, queue) = gfx_dev_and_queue!(); 367 368 let usage = BufferUsage { 369 uniform_texel_buffer: true, 370 ..BufferUsage::none() 371 }; 372 373 let (buffer, _) = 374 ImmutableBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), usage, queue.clone()) 375 .unwrap(); 376 let view = BufferView::new(buffer, Format::R8G8B8A8Unorm).unwrap(); 377 378 assert!(view.uniform_texel_buffer()); 379 } 380 381 #[test] create_storage()382 fn create_storage() { 383 // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format 384 let (device, queue) = gfx_dev_and_queue!(); 385 386 let usage = BufferUsage { 387 storage_texel_buffer: true, 388 ..BufferUsage::none() 389 }; 390 391 let (buffer, _) = 392 ImmutableBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), usage, queue.clone()) 393 .unwrap(); 394 let view = BufferView::new(buffer, Format::R8G8B8A8Unorm).unwrap(); 395 396 assert!(view.storage_texel_buffer()); 397 } 398 399 #[test] create_storage_atomic()400 fn create_storage_atomic() { 401 // `VK_FORMAT_R32_UINT` guaranteed to be a supported format for atomics 402 let (device, queue) = gfx_dev_and_queue!(); 403 404 let usage = BufferUsage { 405 storage_texel_buffer: true, 406 ..BufferUsage::none() 407 }; 408 409 let (buffer, _) = 410 ImmutableBuffer::<[u32]>::from_iter((0..128).map(|_| 0), usage, queue.clone()).unwrap(); 411 let view = BufferView::new(buffer, Format::R32Uint).unwrap(); 412 413 assert!(view.storage_texel_buffer()); 414 assert!(view.storage_texel_buffer_atomic()); 415 } 416 417 #[test] wrong_usage()418 fn wrong_usage() { 419 // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format 420 let (device, queue) = gfx_dev_and_queue!(); 421 422 let (buffer, _) = ImmutableBuffer::<[[u8; 4]]>::from_iter( 423 (0..128).map(|_| [0; 4]), 424 BufferUsage::none(), 425 queue.clone(), 426 ) 427 .unwrap(); 428 429 match BufferView::new(buffer, Format::R8G8B8A8Unorm) { 430 Err(BufferViewCreationError::WrongBufferUsage) => (), 431 _ => panic!(), 432 } 433 } 434 435 #[test] unsupported_format()436 fn unsupported_format() { 437 let (device, queue) = gfx_dev_and_queue!(); 438 439 let usage = BufferUsage { 440 uniform_texel_buffer: true, 441 storage_texel_buffer: true, 442 ..BufferUsage::none() 443 }; 444 445 let (buffer, _) = ImmutableBuffer::<[[f64; 4]]>::from_iter( 446 (0..128).map(|_| [0.0; 4]), 447 usage, 448 queue.clone(), 449 ) 450 .unwrap(); 451 452 // TODO: what if R64G64B64A64Sfloat is supported? 453 match BufferView::new(buffer, Format::R64G64B64A64Sfloat) { 454 Err(BufferViewCreationError::UnsupportedFormat) => (), 455 _ => panic!(), 456 } 457 } 458 } 459