diff options
Diffstat (limited to 'src/command_buffer/validity/update_buffer.rs')
-rw-r--r-- | src/command_buffer/validity/update_buffer.rs | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/command_buffer/validity/update_buffer.rs b/src/command_buffer/validity/update_buffer.rs new file mode 100644 index 0000000..39f60be --- /dev/null +++ b/src/command_buffer/validity/update_buffer.rs @@ -0,0 +1,181 @@ +// Copyright (c) 2017 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT +// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +use crate::buffer::TypedBufferAccess; +use crate::device::Device; +use crate::device::DeviceOwned; +use crate::DeviceSize; +use crate::VulkanObject; +use std::cmp; +use std::error; +use std::fmt; +use std::mem; + +/// Checks whether an update buffer command is valid. +/// +/// # Panic +/// +/// - Panics if the buffer not created with `device`. +/// +pub fn check_update_buffer<B, D>( + device: &Device, + buffer: &B, + data: &D, +) -> Result<(), CheckUpdateBufferError> +where + B: ?Sized + TypedBufferAccess<Content = D>, + D: ?Sized, +{ + assert_eq!( + buffer.inner().buffer.device().internal_object(), + device.internal_object() + ); + + if !buffer.inner().buffer.usage().transfer_destination { + return Err(CheckUpdateBufferError::BufferMissingUsage); + } + + if buffer.inner().offset % 4 != 0 { + return Err(CheckUpdateBufferError::WrongAlignment); + } + + let size = cmp::min(buffer.size(), mem::size_of_val(data) as DeviceSize); + + if size % 4 != 0 { + return Err(CheckUpdateBufferError::WrongAlignment); + } + + if size > 65536 { + return Err(CheckUpdateBufferError::DataTooLarge); + } + + Ok(()) +} + +/// Error that can happen when attempting to add an `update_buffer` command. +#[derive(Debug, Copy, Clone)] +pub enum CheckUpdateBufferError { + /// The "transfer destination" usage must be enabled on the buffer. + BufferMissingUsage, + /// The data or size must be 4-bytes aligned. + WrongAlignment, + /// The data must not be larger than 64k bytes. + DataTooLarge, +} + +impl error::Error for CheckUpdateBufferError {} + +impl fmt::Display for CheckUpdateBufferError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + CheckUpdateBufferError::BufferMissingUsage => { + "the transfer destination usage must be enabled on the buffer" + } + CheckUpdateBufferError::WrongAlignment => { + "the offset or size are not aligned to 4 bytes" + } + CheckUpdateBufferError::DataTooLarge => "data is too large", + } + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::buffer::BufferAccess; + use crate::buffer::BufferUsage; + use crate::buffer::CpuAccessibleBuffer; + + #[test] + fn missing_usage() { + let (device, queue) = gfx_dev_and_queue!(); + let buffer = CpuAccessibleBuffer::from_data( + device.clone(), + BufferUsage::vertex_buffer(), + false, + 0u32, + ) + .unwrap(); + + match check_update_buffer(&device, &buffer, &0) { + Err(CheckUpdateBufferError::BufferMissingUsage) => (), + _ => panic!(), + } + } + + #[test] + fn data_too_large() { + let (device, queue) = gfx_dev_and_queue!(); + let buffer = CpuAccessibleBuffer::from_iter( + device.clone(), + BufferUsage::transfer_destination(), + false, + 0..65536, + ) + .unwrap(); + let data = (0..65536).collect::<Vec<u32>>(); + + match check_update_buffer(&device, &buffer, &data[..]) { + Err(CheckUpdateBufferError::DataTooLarge) => (), + _ => panic!(), + } + } + + #[test] + fn data_just_large_enough() { + let (device, queue) = gfx_dev_and_queue!(); + let buffer = CpuAccessibleBuffer::from_iter( + device.clone(), + BufferUsage::transfer_destination(), + false, + (0..100000).map(|_| 0), + ) + .unwrap(); + let data = (0..65536).map(|_| 0).collect::<Vec<u8>>(); + + match check_update_buffer(&device, &buffer, &data[..]) { + Ok(_) => (), + _ => panic!(), + } + } + + #[test] + fn wrong_alignment() { + let (device, queue) = gfx_dev_and_queue!(); + let buffer = CpuAccessibleBuffer::from_iter( + device.clone(), + BufferUsage::transfer_destination(), + false, + 0..100, + ) + .unwrap(); + let data = (0..30).collect::<Vec<u8>>(); + + match check_update_buffer(&device, &buffer.slice(1..50).unwrap(), &data[..]) { + Err(CheckUpdateBufferError::WrongAlignment) => (), + _ => panic!(), + } + } + + #[test] + fn wrong_device() { + let (dev1, queue) = gfx_dev_and_queue!(); + let (dev2, _) = gfx_dev_and_queue!(); + let buffer = CpuAccessibleBuffer::from_data(dev1, BufferUsage::all(), false, 0u32).unwrap(); + + assert_should_panic!({ + let _ = check_update_buffer(&dev2, &buffer, &0); + }); + } +} |