Merge pull request #616 from tomaka/copy_image_to_buffer

Add copy_image_to_buffer
This commit is contained in:
tomaka 2017-07-08 10:58:13 +02:00 committed by GitHub
commit 819401bbc9
3 changed files with 218 additions and 4 deletions

View File

@ -252,7 +252,7 @@ impl<P> AutoCommandBufferBuilder<P> {
/// Adds a command that copies from a buffer to an image.
pub fn copy_buffer_to_image<S, D>(self, source: S, destination: D)
-> Result<Self, CopyBufferToImageError>
-> Result<Self, CopyBufferImageError>
where S: BufferAccess + Send + Sync + 'static,
D: ImageAccess + Send + Sync + 'static
{
@ -265,7 +265,7 @@ impl<P> AutoCommandBufferBuilder<P> {
/// Adds a command that copies from a buffer to an image.
pub fn copy_buffer_to_image_dimensions<S, D>(
mut self, source: S, destination: D, offset: [u32; 3], size: [u32; 3], first_layer: u32,
num_layers: u32, mipmap: u32) -> Result<Self, CopyBufferToImageError>
num_layers: u32, mipmap: u32) -> Result<Self, CopyBufferImageError>
where S: BufferAccess + Send + Sync + 'static,
D: ImageAccess + Send + Sync + 'static
{
@ -295,13 +295,63 @@ impl<P> AutoCommandBufferBuilder<P> {
image_extent: size,
};
let size = source.size();
self.inner.copy_buffer_to_image(source, destination, ImageLayout::TransferDstOptimal, // TODO: let choose layout
iter::once(copy))?;
Ok(self)
}
}
/// Adds a command that copies from an image to a buffer.
pub fn copy_image_to_buffer<S, D>(self, source: S, destination: D)
-> Result<Self, CopyBufferImageError>
where S: ImageAccess + Send + Sync + 'static,
D: BufferAccess + Send + Sync + 'static
{
self.ensure_outside_render_pass()?;
let dims = source.dimensions().width_height_depth();
self.copy_image_to_buffer_dimensions(source, destination, [0, 0, 0], dims, 0, 1, 0)
}
/// Adds a command that copies from an image to a buffer.
pub fn copy_image_to_buffer_dimensions<S, D>(
mut self, source: S, destination: D, offset: [u32; 3], size: [u32; 3], first_layer: u32,
num_layers: u32, mipmap: u32) -> Result<Self, CopyBufferImageError>
where S: ImageAccess + Send + Sync + 'static,
D: BufferAccess + Send + Sync + 'static
{
unsafe {
self.ensure_outside_render_pass()?;
// TODO: check validity
// TODO: hastily implemented
let copy = UnsafeCommandBufferBuilderBufferImageCopy {
buffer_offset: 0,
buffer_row_length: 0,
buffer_image_height: 0,
image_aspect: if source.has_color() {
UnsafeCommandBufferBuilderImageAspect {
color: true,
depth: false,
stencil: false,
}
} else {
unimplemented!()
},
image_mip_level: mipmap,
image_base_array_layer: first_layer,
image_layer_count: num_layers,
image_offset: [offset[0] as i32, offset[1] as i32, offset[2] as i32],
image_extent: size,
};
self.inner.copy_image_to_buffer(source, ImageLayout::TransferSrcOptimal, destination, // TODO: let choose layout
iter::once(copy))?;
Ok(self)
}
}
#[inline]
pub fn dispatch<Cp, S, Pc>(mut self, dimensions: [u32; 3], pipeline: Cp, sets: S, constants: Pc)
-> Result<Self, DispatchError>
@ -801,7 +851,7 @@ err_gen!(CopyBufferError {
SyncCommandBufferBuilderError
});
err_gen!(CopyBufferToImageError {
err_gen!(CopyBufferImageError {
AutoCommandBufferBuilderContextError,
SyncCommandBufferBuilderError
});

View File

@ -1062,6 +1062,106 @@ impl<P> SyncCommandBufferBuilder<P> {
Ok(())
}
/// Calls `vkCmdCopyImageToBuffer` on the builder.
///
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
/// usage of the command anyway.
#[inline]
pub unsafe fn copy_image_to_buffer<S, D, R>(&mut self, source: S, source_layout: ImageLayout,
destination: D, regions: R)
-> Result<(), SyncCommandBufferBuilderError>
where S: ImageAccess + Send + Sync + 'static,
D: BufferAccess + Send + Sync + 'static,
R: Iterator<Item = UnsafeCommandBufferBuilderBufferImageCopy> + Send + Sync + 'static
{
struct Cmd<S, D, R> {
source: Option<S>,
source_layout: ImageLayout,
destination: Option<D>,
regions: Option<R>,
}
impl<P, S, D, R> Command<P> for Cmd<S, D, R>
where S: ImageAccess + Send + Sync + 'static,
D: BufferAccess + Send + Sync + 'static,
R: Iterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>
{
unsafe fn send(&mut self, out: &mut UnsafeCommandBufferBuilder<P>) {
out.copy_image_to_buffer(self.source.as_ref().unwrap(),
self.source_layout,
self.destination.as_ref().unwrap(),
self.regions.take().unwrap());
}
fn into_final_command(mut self: Box<Self>) -> Box<FinalCommand + Send + Sync> {
struct Fin<S, D>(S, D);
impl<S, D> FinalCommand for Fin<S, D>
where S: ImageAccess + Send + Sync + 'static,
D: BufferAccess + Send + Sync + 'static
{
fn buffer(&self, num: usize) -> &BufferAccess {
assert_eq!(num, 0);
&self.1
}
fn image(&self, num: usize) -> &ImageAccess {
assert_eq!(num, 0);
&self.0
}
}
// Note: borrow checker somehow doesn't accept `self.source` and `self.destination`
// without using an Option.
Box::new(Fin(self.source.take().unwrap(),
self.destination.take().unwrap()))
}
fn buffer(&self, num: usize) -> &BufferAccess {
assert_eq!(num, 0);
self.destination.as_ref().unwrap()
}
fn image(&self, num: usize) -> &ImageAccess {
assert_eq!(num, 0);
self.source.as_ref().unwrap()
}
}
self.commands.lock().unwrap().commands.push(Box::new(Cmd {
source: Some(source),
destination: Some(destination),
source_layout: source_layout,
regions: Some(regions),
}));
self.prev_cmd_resource(KeyTy::Image,
0,
false,
PipelineStages {
transfer: true,
..PipelineStages::none()
},
AccessFlagBits {
transfer_read: true,
..AccessFlagBits::none()
},
source_layout,
source_layout)?;
self.prev_cmd_resource(KeyTy::Buffer,
0,
true,
PipelineStages {
transfer: true,
..PipelineStages::none()
},
AccessFlagBits {
transfer_write: true,
..AccessFlagBits::none()
},
ImageLayout::Undefined,
ImageLayout::Undefined)?;
Ok(())
}
/// Calls `vkCmdDispatch` on the builder.
#[inline]
pub unsafe fn dispatch(&mut self, dimensions: [u32; 3]) {

View File

@ -730,6 +730,70 @@ impl<P> UnsafeCommandBufferBuilder<P> {
regions.as_ptr());
}
/// Calls `vkCmdCopyImageToBuffer` on the builder.
///
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
/// usage of the command anyway.
#[inline]
pub unsafe fn copy_image_to_buffer<S, D, R>(&mut self, source: &S, source_layout: ImageLayout,
destination: &D, regions: R)
where S: ?Sized + ImageAccess,
D: ?Sized + BufferAccess,
R: Iterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>
{
debug_assert_eq!(source.samples(), 1);
let source = source.inner();
debug_assert!(source.image.usage_transfer_source());
debug_assert!(source_layout == ImageLayout::General ||
source_layout == ImageLayout::TransferSrcOptimal);
let destination = destination.inner();
debug_assert!(destination.offset < destination.buffer.size());
debug_assert!(destination.buffer.usage_transfer_destination());
let regions: SmallVec<[_; 8]> = regions
.map(|copy| {
debug_assert!(copy.image_layer_count <= source.num_layers as u32);
debug_assert!(copy.image_mip_level < source.num_mipmap_levels as u32);
vk::BufferImageCopy {
bufferOffset: (destination.offset + copy.buffer_offset) as vk::DeviceSize,
bufferRowLength: copy.buffer_row_length,
bufferImageHeight: copy.buffer_image_height,
imageSubresource: vk::ImageSubresourceLayers {
aspectMask: copy.image_aspect.to_vk_bits(),
mipLevel: copy.image_mip_level + source.first_mipmap_level as u32,
baseArrayLayer: copy.image_base_array_layer + source.first_layer as u32,
layerCount: copy.image_layer_count,
},
imageOffset: vk::Offset3D {
x: copy.image_offset[0],
y: copy.image_offset[1],
z: copy.image_offset[2],
},
imageExtent: vk::Extent3D {
width: copy.image_extent[0],
height: copy.image_extent[1],
depth: copy.image_extent[2],
},
}
})
.collect();
if regions.is_empty() {
return;
}
let vk = self.device().pointers();
let cmd = self.internal_object();
vk.CmdCopyImageToBuffer(cmd,
source.image.internal_object(),
source_layout as u32,
destination.buffer.internal_object(),
regions.len() as u32,
regions.as_ptr());
}
/// Calls `vkCmdDispatch` on the builder.
#[inline]
pub unsafe fn dispatch(&mut self, dimensions: [u32; 3]) {