use std::cmp;
use std::error;
use std::fmt;
use std::sync::Arc;
use buffer::BufferAccess;
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 CmdCopyBuffer<S, D> {
source: S,
source_raw: vk::Buffer,
destination: D,
destination_raw: vk::Buffer,
src_offset: vk::DeviceSize,
dst_offset: vk::DeviceSize,
size: vk::DeviceSize,
}
impl<S, D> CmdCopyBuffer<S, D>
where S: BufferAccess, D: BufferAccess
{
pub fn new(source: S, destination: D)
-> Result<CmdCopyBuffer<S, D>, CmdCopyBufferError>
{
assert_eq!(source.inner().buffer.device().internal_object(),
destination.inner().buffer.device().internal_object());
let (source_raw, src_offset) = {
let inner = source.inner();
if !inner.buffer.usage_transfer_src() {
return Err(CmdCopyBufferError::SourceMissingTransferUsage);
}
(inner.buffer.internal_object(), inner.offset)
};
let (destination_raw, dst_offset) = {
let inner = destination.inner();
if !inner.buffer.usage_transfer_dest() {
return Err(CmdCopyBufferError::DestinationMissingTransferUsage);
}
(inner.buffer.internal_object(), inner.offset)
};
let size = cmp::min(source.size(), destination.size());
if source.conflicts_buffer(0, size, &destination, 0, size) {
return Err(CmdCopyBufferError::OverlappingRanges);
} else {
debug_assert!(!destination.conflicts_buffer(0, size, &source, 0, size));
}
Ok(CmdCopyBuffer {
source: source,
source_raw: source_raw,
destination: destination,
destination_raw: destination_raw,
src_offset: src_offset as u64,
dst_offset: dst_offset as u64,
size: size as u64,
})
}
}
impl<S, D> CmdCopyBuffer<S, D> {
#[inline]
pub fn source(&self) -> &S {
&self.source
}
#[inline]
pub fn destination(&self) -> &D {
&self.destination
}
}
unsafe impl<S, D> DeviceOwned for CmdCopyBuffer<S, D>
where S: DeviceOwned
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.source.device()
}
}
unsafe impl<'a, P, S, D> AddCommand<&'a CmdCopyBuffer<S, D>> for UnsafeCommandBufferBuilder<P>
where S: BufferAccess,
D: BufferAccess,
P: CommandPool,
{
type Out = UnsafeCommandBufferBuilder<P>;
#[inline]
fn add(self, command: &'a CmdCopyBuffer<S, D>) -> Result<Self::Out, CommandAddError> {
unsafe {
let vk = self.device().pointers();
let cmd = self.internal_object();
let region = vk::BufferCopy {
srcOffset: command.src_offset,
dstOffset: command.dst_offset,
size: command.size,
};
vk.CmdCopyBuffer(cmd, command.source_raw, command.destination_raw, 1, ®ion);
}
Ok(self)
}
}
#[derive(Debug, Copy, Clone)]
pub enum CmdCopyBufferError {
SourceMissingTransferUsage,
DestinationMissingTransferUsage,
OverlappingRanges,
}
impl error::Error for CmdCopyBufferError {
#[inline]
fn description(&self) -> &str {
match *self {
CmdCopyBufferError::SourceMissingTransferUsage => {
"the source buffer is missing the transfer source usage"
},
CmdCopyBufferError::DestinationMissingTransferUsage => {
"the destination buffer is missing the transfer destination usage"
},
CmdCopyBufferError::OverlappingRanges => {
"the source and destination are overlapping"
},
}
}
}
impl fmt::Display for CmdCopyBufferError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}