• 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 //! 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