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