mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2025-02-16 17:12:29 +00:00
Merge pull request #616 from tomaka/copy_image_to_buffer
Add copy_image_to_buffer
This commit is contained in:
commit
819401bbc9
@ -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
|
||||
});
|
||||
|
@ -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]) {
|
||||
|
@ -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]) {
|
||||
|
Loading…
Reference in New Issue
Block a user