use std::error;
use std::fmt;
use std::sync::Arc;
use buffer::Buffer;
use buffer::BufferAccess;
use buffer::TypedBuffer;
use buffer::TypedBufferAccess;
use buffer::BufferInner;
use command_buffer::CommandAddError;
use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use device::Device;
use device::DeviceOwned;
use VulkanObject;
use VulkanPointers;
use vk;
pub struct CmdUpdateBuffer<B, D> {
buffer: B,
buffer_handle: vk::Buffer,
offset: vk::DeviceSize,
size: vk::DeviceSize,
data: D,
}
impl<B, D> CmdUpdateBuffer<B, D> {
#[inline]
pub fn new<P>(buffer: P, data: D) -> Result<CmdUpdateBuffer<B, D>, CmdUpdateBufferError>
where P: Buffer<Access = B> + TypedBuffer<Content = D>,
B: BufferAccess,
D: 'static
{
unsafe {
CmdUpdateBuffer::unchecked_type(buffer.access(), data)
}
}
#[inline]
pub fn from_access(buffer: B, data: D) -> Result<CmdUpdateBuffer<B, D>, CmdUpdateBufferError>
where B: BufferAccess + TypedBufferAccess<Content = D>,
D: 'static
{
unsafe {
CmdUpdateBuffer::unchecked_type(buffer, data)
}
}
pub unsafe fn unchecked_type(buffer: B, data: D)
-> Result<CmdUpdateBuffer<B, D>, CmdUpdateBufferError>
where B: BufferAccess
{
let size = buffer.size();
let (buffer_handle, offset) = {
let BufferInner { buffer: buffer_inner, offset } = buffer.inner();
if !buffer_inner.usage_transfer_dest() {
return Err(CmdUpdateBufferError::BufferMissingUsage);
}
if offset % 4 != 0 {
return Err(CmdUpdateBufferError::WrongAlignment);
}
(buffer_inner.internal_object(), offset)
};
if size % 4 != 0 {
return Err(CmdUpdateBufferError::WrongAlignment);
}
if size > 65536 {
return Err(CmdUpdateBufferError::DataTooLarge);
}
Ok(CmdUpdateBuffer {
buffer: buffer,
buffer_handle: buffer_handle,
offset: offset as vk::DeviceSize,
size: size as vk::DeviceSize,
data: data,
})
}
#[inline]
pub fn buffer(&self) -> &B {
&self.buffer
}
}
unsafe impl<B, D> DeviceOwned for CmdUpdateBuffer<B, D>
where B: DeviceOwned
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.buffer.device()
}
}
unsafe impl<'a, P, B, D> AddCommand<&'a CmdUpdateBuffer<B, D>> for UnsafeCommandBufferBuilder<P>
where B: BufferAccess,
P: CommandPool,
{
type Out = UnsafeCommandBufferBuilder<P>;
#[inline]
fn add(self, command: &'a CmdUpdateBuffer<B, D>) -> Result<Self::Out, CommandAddError> {
unsafe {
let data = &command.data as *const D as *const _;
let vk = self.device().pointers();
let cmd = self.internal_object();
vk.CmdUpdateBuffer(cmd, command.buffer_handle, command.offset, command.size, data);
}
Ok(self)
}
}
#[derive(Debug, Copy, Clone)]
pub enum CmdUpdateBufferError {
BufferMissingUsage,
WrongAlignment,
DataTooLarge,
}
impl error::Error for CmdUpdateBufferError {
#[inline]
fn description(&self) -> &str {
match *self {
CmdUpdateBufferError::BufferMissingUsage => {
"the transfer destination usage must be enabled on the buffer"
},
CmdUpdateBufferError::WrongAlignment => {
"the offset or size are not aligned to 4 bytes"
},
CmdUpdateBufferError::DataTooLarge => "data is too large",
}
}
}
impl fmt::Display for CmdUpdateBufferError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}