diff --git a/wgpu-bindings/wgpu.h b/wgpu-bindings/wgpu.h index ac330f4de..01c6eefed 100644 --- a/wgpu-bindings/wgpu.h +++ b/wgpu-bindings/wgpu.h @@ -558,11 +558,28 @@ WGPUComputePassId wgpu_command_buffer_begin_compute_pass(WGPUCommandBufferId com WGPURenderPassId wgpu_command_buffer_begin_render_pass(WGPUCommandBufferId command_buffer_id, WGPURenderPassDescriptor desc); +void wgpu_command_buffer_copy_buffer_to_buffer(WGPUCommandBufferId command_buffer_id, + WGPUBufferId src, + uint32_t src_offset, + WGPUBufferId dst, + uint32_t dst_offset, + uint32_t size); + void wgpu_command_buffer_copy_buffer_to_texture(WGPUCommandBufferId command_buffer_id, const WGPUBufferCopyView *source, const WGPUTextureCopyView *destination, WGPUExtent3d copy_size); +void wgpu_command_buffer_copy_texture_to_buffer(WGPUCommandBufferId command_buffer_id, + const WGPUTextureCopyView *source, + const WGPUBufferCopyView *destination, + WGPUExtent3d copy_size); + +void wgpu_command_buffer_copy_texture_to_texture(WGPUCommandBufferId command_buffer_id, + const WGPUTextureCopyView *source, + const WGPUTextureCopyView *destination, + WGPUExtent3d copy_size); + void wgpu_compute_pass_dispatch(WGPUComputePassId pass_id, uint32_t x, uint32_t y, uint32_t z); WGPUCommandBufferId wgpu_compute_pass_end_pass(WGPUComputePassId pass_id); diff --git a/wgpu-native/src/command/mod.rs b/wgpu-native/src/command/mod.rs index f89799126..1c54faa5c 100644 --- a/wgpu-native/src/command/mod.rs +++ b/wgpu-native/src/command/mod.rs @@ -2,10 +2,12 @@ mod allocator; mod bind; mod compute; mod render; +mod transfer; pub(crate) use self::allocator::CommandAllocator; pub use self::compute::*; pub use self::render::*; +pub use self::transfer::*; use crate::device::{ FramebufferKey, RenderPassKey, @@ -13,13 +15,12 @@ use crate::device::{ }; use crate::registry::{Items, HUB}; use crate::swap_chain::{SwapChainLink, SwapImageEpoch}; -use crate::track::{BufferTracker, TextureTracker, TrackPermit, Tracktion}; +use crate::track::{BufferTracker, TextureTracker}; use crate::{conv, resource}; use crate::{ BufferId, CommandBufferId, ComputePassId, DeviceId, RenderPassId, TextureId, TextureViewId, BufferUsageFlags, TextureUsageFlags, Color, - Extent3d, Origin3d, LifeGuard, Stored, WeaklyStored, B, }; @@ -34,8 +35,6 @@ use std::{iter, slice}; use std::thread::ThreadId; -const BITS_PER_BYTE: u32 = 8; - #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub enum LoadOp { @@ -75,22 +74,6 @@ pub struct RenderPassDescriptor { pub depth_stencil_attachment: *const RenderPassDepthStencilAttachmentDescriptor, } -#[repr(C)] -pub struct BufferCopyView { - pub buffer: BufferId, - pub offset: u32, - pub row_pitch: u32, - pub image_height: u32, -} - -#[repr(C)] -pub struct TextureCopyView { - pub texture: TextureId, - pub level: u32, - pub slice: u32, - pub origin: Origin3d, - //TODO: pub aspect: TextureAspect, -} pub struct CommandBuffer { pub(crate) raw: Vec, @@ -382,97 +365,3 @@ pub extern "C" fn wgpu_command_buffer_begin_compute_pass( .write() .register(ComputePass::new(raw, stored)) } - -#[no_mangle] -pub extern "C" fn wgpu_command_buffer_copy_buffer_to_texture( - command_buffer_id: CommandBufferId, - source: &BufferCopyView, - destination: &TextureCopyView, - copy_size: Extent3d, -) { - let mut cmb_guard = HUB.command_buffers.write(); - let cmb = cmb_guard.get_mut(command_buffer_id); - let buffer_guard = HUB.buffers.read(); - let texture_guard = HUB.textures.read(); - - let (src_buffer, src_tracktion) = cmb.buffer_tracker - .get_with_usage( - &*buffer_guard, - source.buffer, - BufferUsageFlags::TRANSFER_SRC, - TrackPermit::REPLACE, - ) - .unwrap(); - let src_barrier = match src_tracktion { - Tracktion::Init | - Tracktion::Keep => None, - Tracktion::Extend { .. } => unreachable!(), - Tracktion::Replace { old } => Some(hal::memory::Barrier::Buffer { - states: conv::map_buffer_state(old) .. hal::buffer::Access::TRANSFER_WRITE, - target: &src_buffer.raw, - families: None, - range: None .. None, - }), - }; - - let (dst_texture, dst_tracktion) = cmb.texture_tracker - .get_with_usage( - &*texture_guard, - destination.texture, - TextureUsageFlags::TRANSFER_DST, - TrackPermit::REPLACE, - ) - .unwrap(); - let aspects = dst_texture.full_range.aspects; - let dst_texture_state = conv::map_texture_state(TextureUsageFlags::TRANSFER_DST, aspects); - let dst_barrier = match dst_tracktion { - Tracktion::Init | - Tracktion::Keep => None, - Tracktion::Extend { .. } => unreachable!(), - Tracktion::Replace { old } => Some(hal::memory::Barrier::Image { - states: conv::map_texture_state(old, aspects) .. dst_texture_state, - target: &dst_texture.raw, - families: None, - range: dst_texture.full_range.clone(), - }), - }; - - if let Some(ref link) = dst_texture.swap_chain_link { - cmb.swap_chain_links.push(SwapChainLink { - swap_chain_id: link.swap_chain_id.clone(), - epoch: *link.epoch.lock(), - image_index: link.image_index, - }); - } - - let bytes_per_texel = conv::map_texture_format(dst_texture.format) - .surface_desc().bits as u32 / BITS_PER_BYTE; - let buffer_width = source.row_pitch / bytes_per_texel; - assert_eq!(source.row_pitch % bytes_per_texel, 0); - let region = hal::command::BufferImageCopy { - buffer_offset: source.offset as hal::buffer::Offset, - buffer_width, - buffer_height: source.image_height, - image_layers: hal::image::SubresourceLayers { - aspects, //TODO - level: destination.level as hal::image::Level, - layers: destination.slice as u16 .. destination.slice as u16 + 1, - }, - image_offset: conv::map_origin(destination.origin), - image_extent: conv::map_extent(copy_size), - }; - let cmb_raw = cmb.raw.last_mut().unwrap(); - unsafe { - cmb_raw.pipeline_barrier( - all_buffer_stages() .. all_image_stages(), - hal::memory::Dependencies::empty(), - src_barrier.into_iter().chain(dst_barrier), - ); - cmb_raw.copy_buffer_to_image( - &src_buffer.raw, - &dst_texture.raw, - dst_texture_state.1, - iter::once(region), - ); - } -} diff --git a/wgpu-native/src/command/render.rs b/wgpu-native/src/command/render.rs index 62057071b..8b3b772d3 100644 --- a/wgpu-native/src/command/render.rs +++ b/wgpu-native/src/command/render.rs @@ -1,7 +1,7 @@ use crate::command::bind::Binder; use crate::resource::BufferUsageFlags; use crate::registry::{Items, HUB}; -use crate::track::{BufferTracker, TextureTracker, TrackPermit}; +use crate::track::{BufferTracker, TextureTracker}; use crate::{ CommandBuffer, Stored, BindGroupId, BufferId, CommandBufferId, RenderPassId, RenderPipelineId, @@ -65,12 +65,11 @@ pub extern "C" fn wgpu_render_pass_set_index_buffer( let buffer_guard = HUB.buffers.read(); let pass = pass_guard.get_mut(pass_id); - let (buffer, _) = pass.buffer_tracker - .get_with_usage( + let buffer = pass.buffer_tracker + .get_with_extended_usage( &*buffer_guard, buffer_id, BufferUsageFlags::INDEX, - TrackPermit::EXTEND, ) .unwrap(); @@ -104,11 +103,10 @@ pub extern "C" fn wgpu_render_pass_set_vertex_buffers( let pass = pass_guard.get_mut(pass_id); for &id in buffers { pass.buffer_tracker - .get_with_usage( + .get_with_extended_usage( &*buffer_guard, id, BufferUsageFlags::VERTEX, - TrackPermit::EXTEND, ) .unwrap(); } diff --git a/wgpu-native/src/command/transfer.rs b/wgpu-native/src/command/transfer.rs new file mode 100644 index 000000000..a9e96e384 --- /dev/null +++ b/wgpu-native/src/command/transfer.rs @@ -0,0 +1,336 @@ +use crate::device::{all_buffer_stages, all_image_stages}; +use crate::registry::{Items, HUB}; +use crate::swap_chain::SwapChainLink; +use crate::conv; +use crate::{ + BufferId, CommandBufferId, TextureId, + BufferUsageFlags, TextureUsageFlags, + Extent3d, Origin3d, +}; + +use hal::command::RawCommandBuffer; + +use std::iter; + + +const BITS_PER_BYTE: u32 = 8; + +#[repr(C)] +pub struct BufferCopyView { + pub buffer: BufferId, + pub offset: u32, + pub row_pitch: u32, + pub image_height: u32, +} + +#[repr(C)] +pub struct TextureCopyView { + pub texture: TextureId, + pub level: u32, + pub slice: u32, + pub origin: Origin3d, + //TODO: pub aspect: TextureAspect, +} + +#[no_mangle] +pub extern "C" fn wgpu_command_buffer_copy_buffer_to_buffer( + command_buffer_id: CommandBufferId, + src: BufferId, + src_offset: u32, + dst: BufferId, + dst_offset: u32, + size: u32, +) { + let mut cmb_guard = HUB.command_buffers.write(); + let cmb = cmb_guard.get_mut(command_buffer_id); + let buffer_guard = HUB.buffers.read(); + + let (src_buffer, src_usage) = cmb.buffer_tracker + .get_with_replaced_usage( + &*buffer_guard, + src, + BufferUsageFlags::TRANSFER_SRC, + ) + .unwrap(); + let src_barrier = src_usage.map(|old| hal::memory::Barrier::Buffer { + states: conv::map_buffer_state(old) .. hal::buffer::Access::TRANSFER_READ, + target: &src_buffer.raw, + families: None, + range: None .. None, + }); + + let (dst_buffer, dst_usage) = cmb.buffer_tracker + .get_with_replaced_usage( + &*buffer_guard, + dst, + BufferUsageFlags::TRANSFER_DST, + ) + .unwrap(); + let dst_barrier = dst_usage.map(|old| hal::memory::Barrier::Buffer { + states: conv::map_buffer_state(old) .. hal::buffer::Access::TRANSFER_WRITE, + target: &dst_buffer.raw, + families: None, + range: None .. None, + }); + + let region = hal::command::BufferCopy { + src: src_offset as hal::buffer::Offset, + dst: dst_offset as hal::buffer::Offset, + size: size as hal::buffer::Offset, + }; + let cmb_raw = cmb.raw.last_mut().unwrap(); + unsafe { + cmb_raw.pipeline_barrier( + all_buffer_stages() .. all_buffer_stages(), + hal::memory::Dependencies::empty(), + src_barrier.into_iter().chain(dst_barrier), + ); + cmb_raw.copy_buffer( + &src_buffer.raw, + &dst_buffer.raw, + iter::once(region), + ); + } +} + +#[no_mangle] +pub extern "C" fn wgpu_command_buffer_copy_buffer_to_texture( + command_buffer_id: CommandBufferId, + source: &BufferCopyView, + destination: &TextureCopyView, + copy_size: Extent3d, +) { + let mut cmb_guard = HUB.command_buffers.write(); + let cmb = cmb_guard.get_mut(command_buffer_id); + let buffer_guard = HUB.buffers.read(); + let texture_guard = HUB.textures.read(); + + let (src_buffer, src_usage) = cmb.buffer_tracker + .get_with_replaced_usage( + &*buffer_guard, + source.buffer, + BufferUsageFlags::TRANSFER_SRC, + ) + .unwrap(); + let src_barrier = src_usage.map(|old| hal::memory::Barrier::Buffer { + states: conv::map_buffer_state(old) .. hal::buffer::Access::TRANSFER_READ, + target: &src_buffer.raw, + families: None, + range: None .. None, + }); + + let (dst_texture, dst_usage) = cmb.texture_tracker + .get_with_replaced_usage( + &*texture_guard, + destination.texture, + TextureUsageFlags::TRANSFER_DST, + ) + .unwrap(); + let aspects = dst_texture.full_range.aspects; + let dst_texture_state = conv::map_texture_state(TextureUsageFlags::TRANSFER_DST, aspects); + let dst_barrier = dst_usage.map(|old| hal::memory::Barrier::Image { + states: conv::map_texture_state(old, aspects) .. dst_texture_state, + target: &dst_texture.raw, + families: None, + range: dst_texture.full_range.clone(), + }); + + if let Some(ref link) = dst_texture.swap_chain_link { + cmb.swap_chain_links.push(SwapChainLink { + swap_chain_id: link.swap_chain_id.clone(), + epoch: *link.epoch.lock(), + image_index: link.image_index, + }); + } + + let bytes_per_texel = conv::map_texture_format(dst_texture.format) + .surface_desc().bits as u32 / BITS_PER_BYTE; + let buffer_width = source.row_pitch / bytes_per_texel; + assert_eq!(source.row_pitch % bytes_per_texel, 0); + let region = hal::command::BufferImageCopy { + buffer_offset: source.offset as hal::buffer::Offset, + buffer_width, + buffer_height: source.image_height, + image_layers: hal::image::SubresourceLayers { + aspects, //TODO + level: destination.level as hal::image::Level, + layers: destination.slice as u16 .. destination.slice as u16 + 1, + }, + image_offset: conv::map_origin(destination.origin), + image_extent: conv::map_extent(copy_size), + }; + let cmb_raw = cmb.raw.last_mut().unwrap(); + let stages = all_buffer_stages() | all_image_stages(); + unsafe { + cmb_raw.pipeline_barrier( + stages .. stages, + hal::memory::Dependencies::empty(), + src_barrier.into_iter().chain(dst_barrier), + ); + cmb_raw.copy_buffer_to_image( + &src_buffer.raw, + &dst_texture.raw, + dst_texture_state.1, + iter::once(region), + ); + } +} + +#[no_mangle] +pub extern "C" fn wgpu_command_buffer_copy_texture_to_buffer( + command_buffer_id: CommandBufferId, + source: &TextureCopyView, + destination: &BufferCopyView, + copy_size: Extent3d, +) { + let mut cmb_guard = HUB.command_buffers.write(); + let cmb = cmb_guard.get_mut(command_buffer_id); + let buffer_guard = HUB.buffers.read(); + let texture_guard = HUB.textures.read(); + + let (src_texture, src_usage) = cmb.texture_tracker + .get_with_replaced_usage( + &*texture_guard, + source.texture, + TextureUsageFlags::TRANSFER_SRC, + ) + .unwrap(); + let aspects = src_texture.full_range.aspects; + let src_texture_state = conv::map_texture_state(TextureUsageFlags::TRANSFER_SRC, aspects); + let src_barrier = src_usage.map(|old| hal::memory::Barrier::Image { + states: conv::map_texture_state(old, aspects) .. src_texture_state, + target: &src_texture.raw, + families: None, + range: src_texture.full_range.clone(), + }); + assert!(src_texture.swap_chain_link.is_none()); //TODO + + let (dst_buffer, dst_usage) = cmb.buffer_tracker + .get_with_replaced_usage( + &*buffer_guard, + destination.buffer, + BufferUsageFlags::TRANSFER_DST, + ) + .unwrap(); + let dst_barrier = dst_usage.map(|old| hal::memory::Barrier::Buffer { + states: conv::map_buffer_state(old) .. hal::buffer::Access::TRANSFER_WRITE, + target: &dst_buffer.raw, + families: None, + range: None .. None, + }); + + let bytes_per_texel = conv::map_texture_format(src_texture.format) + .surface_desc().bits as u32 / BITS_PER_BYTE; + let buffer_width = destination.row_pitch / bytes_per_texel; + assert_eq!(destination.row_pitch % bytes_per_texel, 0); + let region = hal::command::BufferImageCopy { + buffer_offset: destination.offset as hal::buffer::Offset, + buffer_width, + buffer_height: destination.image_height, + image_layers: hal::image::SubresourceLayers { + aspects, //TODO + level: source.level as hal::image::Level, + layers: source.slice as u16 .. source.slice as u16 + 1, + }, + image_offset: conv::map_origin(source.origin), + image_extent: conv::map_extent(copy_size), + }; + let cmb_raw = cmb.raw.last_mut().unwrap(); + let stages = all_buffer_stages() | all_image_stages(); + unsafe { + cmb_raw.pipeline_barrier( + stages .. stages, + hal::memory::Dependencies::empty(), + src_barrier.into_iter().chain(dst_barrier), + ); + cmb_raw.copy_image_to_buffer( + &src_texture.raw, + src_texture_state.1, + &dst_buffer.raw, + iter::once(region), + ); + } +} + +#[no_mangle] +pub extern "C" fn wgpu_command_buffer_copy_texture_to_texture( + command_buffer_id: CommandBufferId, + source: &TextureCopyView, + destination: &TextureCopyView, + copy_size: Extent3d, +) { + let mut cmb_guard = HUB.command_buffers.write(); + let cmb = cmb_guard.get_mut(command_buffer_id); + let texture_guard = HUB.textures.read(); + + let (src_texture, src_usage) = cmb.texture_tracker + .get_with_replaced_usage( + &*texture_guard, + source.texture, + TextureUsageFlags::TRANSFER_SRC, + ) + .unwrap(); + let (dst_texture, dst_usage) = cmb.texture_tracker + .get_with_replaced_usage( + &*texture_guard, + destination.texture, + TextureUsageFlags::TRANSFER_DST, + ) + .unwrap(); + + let aspects = src_texture.full_range.aspects & dst_texture.full_range.aspects; + let src_texture_state = conv::map_texture_state(TextureUsageFlags::TRANSFER_SRC, aspects); + let dst_texture_state = conv::map_texture_state(TextureUsageFlags::TRANSFER_DST, aspects); + + let src_barrier = src_usage.map(|old| hal::memory::Barrier::Image { + states: conv::map_texture_state(old, aspects) .. src_texture_state, + target: &src_texture.raw, + families: None, + range: src_texture.full_range.clone(), + }); + let dst_barrier = dst_usage.map(|old| hal::memory::Barrier::Image { + states: conv::map_texture_state(old, aspects) .. dst_texture_state, + target: &dst_texture.raw, + families: None, + range: dst_texture.full_range.clone(), + }); + + if let Some(ref link) = dst_texture.swap_chain_link { + cmb.swap_chain_links.push(SwapChainLink { + swap_chain_id: link.swap_chain_id.clone(), + epoch: *link.epoch.lock(), + image_index: link.image_index, + }); + } + + let region = hal::command::ImageCopy { + src_subresource: hal::image::SubresourceLayers { + aspects, + level: source.level as hal::image::Level, + layers: source.slice as u16 .. source.slice as u16 + 1, + }, + src_offset: conv::map_origin(source.origin), + dst_subresource: hal::image::SubresourceLayers { + aspects, + level: destination.level as hal::image::Level, + layers: destination.slice as u16 .. destination.slice as u16 + 1, + }, + dst_offset: conv::map_origin(destination.origin), + extent: conv::map_extent(copy_size), + }; + let cmb_raw = cmb.raw.last_mut().unwrap(); + unsafe { + cmb_raw.pipeline_barrier( + all_image_stages() .. all_image_stages(), + hal::memory::Dependencies::empty(), + src_barrier.into_iter().chain(dst_barrier), + ); + cmb_raw.copy_image( + &src_texture.raw, + src_texture_state.1, + &dst_texture.raw, + dst_texture_state.1, + iter::once(region), + ); + } +} diff --git a/wgpu-native/src/device.rs b/wgpu-native/src/device.rs index aed76415e..fff23b1c2 100644 --- a/wgpu-native/src/device.rs +++ b/wgpu-native/src/device.rs @@ -668,12 +668,11 @@ pub extern "C" fn wgpu_device_create_bind_group( for b in bindings { let descriptor = match b.resource { binding_model::BindingResource::Buffer(ref bb) => { - let (buffer, _) = used_buffers - .get_with_usage( + let buffer = used_buffers + .get_with_extended_usage( &*buffer_guard, bb.buffer, resource::BufferUsageFlags::UNIFORM, - TrackPermit::EXTEND, ) .unwrap(); let range = Some(bb.offset as u64) .. Some((bb.offset + bb.size) as u64); diff --git a/wgpu-native/src/track.rs b/wgpu-native/src/track.rs index 6b9cdace5..cddbd2587 100644 --- a/wgpu-native/src/track.rs +++ b/wgpu-native/src/track.rs @@ -190,7 +190,7 @@ impl + PartialE } impl + PartialEq> Tracker { - pub(crate) fn get_with_usage<'a, T: 'a + Borrow, V: Items>( + fn get_with_usage<'a, T: 'a + Borrow, V: Items>( &mut self, items: &'a V, id: Id, @@ -201,4 +201,31 @@ impl + PartialEq> Tracker { self.transit(id, item.borrow(), usage, permit) .map(|tracktion| (item, tracktion)) } + + pub(crate) fn get_with_extended_usage<'a, T: 'a + Borrow, V: Items>( + &mut self, + items: &'a V, + id: Id, + usage: U, + ) -> Result<&'a T, U> { + let item = items.get(id); + self.transit(id, item.borrow(), usage, TrackPermit::EXTEND) + .map(|_tracktion| item) + } + + pub(crate) fn get_with_replaced_usage<'a, T: 'a + Borrow, V: Items>( + &mut self, + items: &'a V, + id: Id, + usage: U, + ) -> Result<(&'a T, Option), U> { + let item = items.get(id); + self.transit(id, item.borrow(), usage, TrackPermit::REPLACE) + .map(|tracktion| (item, match tracktion { + Tracktion::Init | + Tracktion::Keep => None, + Tracktion::Extend { ..} => unreachable!(), + Tracktion::Replace { old } => Some(old), + })) + } } diff --git a/wgpu-rs/src/lib.rs b/wgpu-rs/src/lib.rs index 4b222569a..9905bf8e6 100644 --- a/wgpu-rs/src/lib.rs +++ b/wgpu-rs/src/lib.rs @@ -496,6 +496,24 @@ impl CommandBuffer { } } + pub fn copy_buffer_tobuffer( + &mut self, + source: &Buffer, + source_offset: u32, + destination: &Buffer, + destination_offset: u32, + copy_size: u32, + ) { + wgn::wgpu_command_buffer_copy_buffer_to_buffer( + self.id, + source.id, + source_offset, + destination.id, + destination_offset, + copy_size, + ); + } + pub fn copy_buffer_to_texture( &mut self, source: BufferCopyView, @@ -509,6 +527,34 @@ impl CommandBuffer { copy_size, ); } + + pub fn copy_texture_to_buffer( + &mut self, + source: TextureCopyView, + destination: BufferCopyView, + copy_size: Extent3d, + ) { + wgn::wgpu_command_buffer_copy_texture_to_buffer( + self.id, + &source.into_native(), + &destination.into_native(), + copy_size, + ); + } + + pub fn copy_texture_to_texture( + &mut self, + source: TextureCopyView, + destination: TextureCopyView, + copy_size: Extent3d, + ) { + wgn::wgpu_command_buffer_copy_texture_to_texture( + self.id, + &source.into_native(), + &destination.into_native(), + copy_size, + ); + } } impl<'a> RenderPass<'a> {