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 image::ImageAccess;
use VulkanObject;
use VulkanPointers;
use vk;
#[derive(Debug, Clone)]
pub struct CmdCopyBufferToImage<S, D> {
buffer: S,
buffer_raw: vk::Buffer,
buffer_offset: vk::DeviceSize,
buffer_row_length: u32,
buffer_image_height: u32,
destination: D,
destination_raw: vk::Image,
destination_layout: vk::ImageLayout,
destination_offset: [i32; 3],
destination_aspect_mask: vk::ImageAspectFlags,
destination_mip_level: u32,
destination_base_array_layer: u32,
destination_layer_count: u32,
extent: [u32; 3],
}
impl<S, D> CmdCopyBufferToImage<S, D> where S: BufferAccess, D: ImageAccess {
#[inline]
pub fn new(source: S, destination: D)
-> Result<CmdCopyBufferToImage<S, D>, CmdCopyBufferToImageError>
{
let dims = destination.dimensions().width_height_depth();
CmdCopyBufferToImage::with_dimensions(source, destination, [0, 0, 0], dims, 0, 1, 0)
}
pub fn with_dimensions(source: S, destination: D, offset: [u32; 3], size: [u32; 3],
first_layer: u32, num_layers: u32, mipmap: u32)
-> Result<CmdCopyBufferToImage<S, D>, CmdCopyBufferToImageError>
{
assert_eq!(source.inner().buffer.device().internal_object(),
destination.inner().device().internal_object());
let (source_raw, src_offset) = {
let inner = source.inner();
if !inner.buffer.usage_transfer_src() {
return Err(CmdCopyBufferToImageError::SourceMissingTransferUsage);
}
(inner.buffer.internal_object(), inner.offset)
};
if destination.samples() != 1 {
return Err(CmdCopyBufferToImageError::DestinationMultisampled);
}
let destination_raw = {
let inner = destination.inner();
if !inner.usage_transfer_dest() {
return Err(CmdCopyBufferToImageError::DestinationMissingTransferUsage);
}
inner.internal_object()
};
if source.conflicts_image(0, source.size(), &destination, first_layer, num_layers,
mipmap, 1)
{
return Err(CmdCopyBufferToImageError::OverlappingRanges);
} else {
debug_assert!(!destination.conflicts_buffer(first_layer, num_layers, mipmap,
1, &source, 0, source.size()));
}
let aspect_mask = if destination.has_color() {
vk::IMAGE_ASPECT_COLOR_BIT
} else {
unimplemented!() };
Ok(CmdCopyBufferToImage {
buffer: source,
buffer_raw: source_raw,
buffer_offset: src_offset as vk::DeviceSize,
buffer_row_length: 0,
buffer_image_height: 0,
destination: destination,
destination_raw: destination_raw,
destination_layout: vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, destination_offset: [offset[0] as i32, offset[1] as i32, offset[2] as i32],
destination_aspect_mask: aspect_mask,
destination_mip_level: mipmap,
destination_base_array_layer: first_layer,
destination_layer_count: num_layers,
extent: size,
})
}
}
impl<S, D> CmdCopyBufferToImage<S, D> {
#[inline]
pub fn source(&self) -> &S {
&self.buffer
}
#[inline]
pub fn destination(&self) -> &D {
&self.destination
}
}
unsafe impl<S, D> DeviceOwned for CmdCopyBufferToImage<S, D> where S: DeviceOwned {
#[inline]
fn device(&self) -> &Arc<Device> {
self.buffer.device()
}
}
unsafe impl<'a, P, S, D> AddCommand<&'a CmdCopyBufferToImage<S, D>> for UnsafeCommandBufferBuilder<P>
where P: CommandPool
{
type Out = UnsafeCommandBufferBuilder<P>;
#[inline]
fn add(self, command: &'a CmdCopyBufferToImage<S, D>) -> Result<Self::Out, CommandAddError> {
unsafe {
debug_assert!(command.destination_layout == vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ||
command.destination_layout == vk::IMAGE_LAYOUT_GENERAL);
let region = vk::BufferImageCopy {
bufferOffset: command.buffer_offset,
bufferRowLength: command.buffer_row_length,
bufferImageHeight: command.buffer_image_height,
imageSubresource: vk::ImageSubresourceLayers {
aspectMask: command.destination_aspect_mask,
mipLevel: command.destination_mip_level,
baseArrayLayer: command.destination_base_array_layer,
layerCount: command.destination_layer_count,
},
imageOffset: vk::Offset3D {
x: command.destination_offset[0],
y: command.destination_offset[1],
z: command.destination_offset[2],
},
imageExtent: vk::Extent3D {
width: command.extent[0],
height: command.extent[1],
depth: command.extent[2],
},
};
let vk = self.device().pointers();
let cmd = self.internal_object();
vk.CmdCopyBufferToImage(cmd, command.buffer_raw, command.destination_raw,
command.destination_layout, 1, ®ion as *const _);
}
Ok(self)
}
}
#[derive(Debug, Copy, Clone)]
pub enum CmdCopyBufferToImageError {
SourceMissingTransferUsage,
DestinationMissingTransferUsage,
DestinationMultisampled,
OutOfImageRange,
OverlappingRanges,
}
impl error::Error for CmdCopyBufferToImageError {
#[inline]
fn description(&self) -> &str {
match *self {
CmdCopyBufferToImageError::SourceMissingTransferUsage => {
"the source buffer is missing the transfer source usage"
},
CmdCopyBufferToImageError::DestinationMissingTransferUsage => {
"the destination image is missing the transfer destination usage"
},
CmdCopyBufferToImageError::DestinationMultisampled => {
"the destination image has more than one sample per pixel"
},
CmdCopyBufferToImageError::OutOfImageRange => {
"the dimensions are out of range of the image"
},
CmdCopyBufferToImageError::OverlappingRanges => {
"the source and destination are overlapping in memory"
},
}
}
}
impl fmt::Display for CmdCopyBufferToImageError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}