• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 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 use crate::buffer::TypedBufferAccess;
11 use crate::device::Device;
12 use crate::device::DeviceOwned;
13 use crate::DeviceSize;
14 use crate::VulkanObject;
15 use std::cmp;
16 use std::error;
17 use std::fmt;
18 use std::mem;
19 
20 /// Checks whether an update buffer command is valid.
21 ///
22 /// # Panic
23 ///
24 /// - Panics if the buffer not created with `device`.
25 ///
check_update_buffer<B, D>( device: &Device, buffer: &B, data: &D, ) -> Result<(), CheckUpdateBufferError> where B: ?Sized + TypedBufferAccess<Content = D>, D: ?Sized,26 pub fn check_update_buffer<B, D>(
27     device: &Device,
28     buffer: &B,
29     data: &D,
30 ) -> Result<(), CheckUpdateBufferError>
31 where
32     B: ?Sized + TypedBufferAccess<Content = D>,
33     D: ?Sized,
34 {
35     assert_eq!(
36         buffer.inner().buffer.device().internal_object(),
37         device.internal_object()
38     );
39 
40     if !buffer.inner().buffer.usage().transfer_destination {
41         return Err(CheckUpdateBufferError::BufferMissingUsage);
42     }
43 
44     if buffer.inner().offset % 4 != 0 {
45         return Err(CheckUpdateBufferError::WrongAlignment);
46     }
47 
48     let size = cmp::min(buffer.size(), mem::size_of_val(data) as DeviceSize);
49 
50     if size % 4 != 0 {
51         return Err(CheckUpdateBufferError::WrongAlignment);
52     }
53 
54     if size > 65536 {
55         return Err(CheckUpdateBufferError::DataTooLarge);
56     }
57 
58     Ok(())
59 }
60 
61 /// Error that can happen when attempting to add an `update_buffer` command.
62 #[derive(Debug, Copy, Clone)]
63 pub enum CheckUpdateBufferError {
64     /// The "transfer destination" usage must be enabled on the buffer.
65     BufferMissingUsage,
66     /// The data or size must be 4-bytes aligned.
67     WrongAlignment,
68     /// The data must not be larger than 64k bytes.
69     DataTooLarge,
70 }
71 
72 impl error::Error for CheckUpdateBufferError {}
73 
74 impl fmt::Display for CheckUpdateBufferError {
75     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>76     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
77         write!(
78             fmt,
79             "{}",
80             match *self {
81                 CheckUpdateBufferError::BufferMissingUsage => {
82                     "the transfer destination usage must be enabled on the buffer"
83                 }
84                 CheckUpdateBufferError::WrongAlignment => {
85                     "the offset or size are not aligned to 4 bytes"
86                 }
87                 CheckUpdateBufferError::DataTooLarge => "data is too large",
88             }
89         )
90     }
91 }
92 
93 #[cfg(test)]
94 mod tests {
95     use super::*;
96     use crate::buffer::BufferAccess;
97     use crate::buffer::BufferUsage;
98     use crate::buffer::CpuAccessibleBuffer;
99 
100     #[test]
missing_usage()101     fn missing_usage() {
102         let (device, queue) = gfx_dev_and_queue!();
103         let buffer = CpuAccessibleBuffer::from_data(
104             device.clone(),
105             BufferUsage::vertex_buffer(),
106             false,
107             0u32,
108         )
109         .unwrap();
110 
111         match check_update_buffer(&device, &buffer, &0) {
112             Err(CheckUpdateBufferError::BufferMissingUsage) => (),
113             _ => panic!(),
114         }
115     }
116 
117     #[test]
data_too_large()118     fn data_too_large() {
119         let (device, queue) = gfx_dev_and_queue!();
120         let buffer = CpuAccessibleBuffer::from_iter(
121             device.clone(),
122             BufferUsage::transfer_destination(),
123             false,
124             0..65536,
125         )
126         .unwrap();
127         let data = (0..65536).collect::<Vec<u32>>();
128 
129         match check_update_buffer(&device, &buffer, &data[..]) {
130             Err(CheckUpdateBufferError::DataTooLarge) => (),
131             _ => panic!(),
132         }
133     }
134 
135     #[test]
data_just_large_enough()136     fn data_just_large_enough() {
137         let (device, queue) = gfx_dev_and_queue!();
138         let buffer = CpuAccessibleBuffer::from_iter(
139             device.clone(),
140             BufferUsage::transfer_destination(),
141             false,
142             (0..100000).map(|_| 0),
143         )
144         .unwrap();
145         let data = (0..65536).map(|_| 0).collect::<Vec<u8>>();
146 
147         match check_update_buffer(&device, &buffer, &data[..]) {
148             Ok(_) => (),
149             _ => panic!(),
150         }
151     }
152 
153     #[test]
wrong_alignment()154     fn wrong_alignment() {
155         let (device, queue) = gfx_dev_and_queue!();
156         let buffer = CpuAccessibleBuffer::from_iter(
157             device.clone(),
158             BufferUsage::transfer_destination(),
159             false,
160             0..100,
161         )
162         .unwrap();
163         let data = (0..30).collect::<Vec<u8>>();
164 
165         match check_update_buffer(&device, &buffer.slice(1..50).unwrap(), &data[..]) {
166             Err(CheckUpdateBufferError::WrongAlignment) => (),
167             _ => panic!(),
168         }
169     }
170 
171     #[test]
wrong_device()172     fn wrong_device() {
173         let (dev1, queue) = gfx_dev_and_queue!();
174         let (dev2, _) = gfx_dev_and_queue!();
175         let buffer = CpuAccessibleBuffer::from_data(dev1, BufferUsage::all(), false, 0u32).unwrap();
176 
177         assert_should_panic!({
178             let _ = check_update_buffer(&dev2, &buffer, &0);
179         });
180     }
181 }
182