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