From 5462690c4aef840ef521143a4d0f09c42423fb7b Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 18 Oct 2018 16:27:35 -0400 Subject: [PATCH 1/6] Chain multiple native command buffers per logical one --- wgpu-native/src/command/allocator.rs | 84 ++++++++++++++++++---------- wgpu-native/src/command/compute.rs | 3 +- wgpu-native/src/command/mod.rs | 17 ++++-- wgpu-native/src/command/render.rs | 16 +++++- wgpu-native/src/device.rs | 14 ++--- 5 files changed, 87 insertions(+), 47 deletions(-) diff --git a/wgpu-native/src/command/allocator.rs b/wgpu-native/src/command/allocator.rs index 6c45be2c2..899c0ad00 100644 --- a/wgpu-native/src/command/allocator.rs +++ b/wgpu-native/src/command/allocator.rs @@ -12,14 +12,37 @@ use std::thread; struct CommandPool { raw: B::CommandPool, - available: Vec>, + available: Vec, +} + +impl CommandPool { + fn allocate(&mut self) -> B::CommandBuffer { + if self.available.is_empty() { + let extra = self.raw.allocate(20, hal::command::RawLevel::Primary); + self.available.extend(extra); + } + + self.available.pop().unwrap() + } } struct Inner { pools: HashMap>, + fences: Vec, pending: Vec>, } +impl Inner { + fn recycle(&mut self, cmd_buf: CommandBuffer) { + let pool = self.pools.get_mut(&cmd_buf.recorded_thread_id).unwrap(); + for mut raw in cmd_buf.raw { + raw.reset(false); + pool.available.push(raw); + } + self.fences.push(cmd_buf.fence); + } +} + pub struct CommandAllocator { queue_family: hal::queue::QueueFamilyId, inner: Mutex>, @@ -31,6 +54,7 @@ impl CommandAllocator { queue_family, inner: Mutex::new(Inner { pools: HashMap::new(), + fences: Vec::new(), pending: Vec::new(), }), } @@ -41,6 +65,17 @@ impl CommandAllocator { ) -> CommandBuffer { let thread_id = thread::current().id(); let mut inner = self.inner.lock().unwrap(); + + let fence = match inner.fences.pop() { + Some(fence) => { + device.reset_fence(&fence); + fence + } + None => { + device.create_fence(false) + } + }; + let pool = inner.pools.entry(thread_id).or_insert_with(|| CommandPool { raw: device.create_command_pool( self.queue_family, @@ -48,21 +83,25 @@ impl CommandAllocator { ), available: Vec::new(), }); + let init = pool.allocate(); - if let Some(cmd_buf) = pool.available.pop() { - assert_eq!(device_id, cmd_buf.device_id.0); - device.reset_fence(&cmd_buf.fence); - return cmd_buf; + CommandBuffer { + raw: vec![init], + fence, + recorded_thread_id: thread_id, + device_id: Stored(device_id), + } + } + + pub fn extend(&self, cmd_buf: &CommandBuffer) -> B::CommandBuffer { + let mut inner = self.inner.lock().unwrap(); + let pool = inner.pools.get_mut(&cmd_buf.recorded_thread_id).unwrap(); + + if pool.available.is_empty() { + let extra = pool.raw.allocate(20, hal::command::RawLevel::Primary); + pool.available.extend(extra); } - for cmbuf in pool.raw.allocate(20, hal::command::RawLevel::Primary) { - pool.available.push(CommandBuffer { - raw: Some(cmbuf), - fence: device.create_fence(false), - recorded_thread_id: thread_id, - device_id: Stored(device_id), - }); - } pool.available.pop().unwrap() } @@ -70,16 +109,8 @@ impl CommandAllocator { self.inner.lock().unwrap().pending.push(cmd_buf); } - pub fn recycle(&self, mut cmd_buf: CommandBuffer) { - cmd_buf.raw.as_mut().unwrap().reset(false); - self.inner - .lock() - .unwrap() - .pools - .get_mut(&cmd_buf.recorded_thread_id) - .unwrap() - .available - .push(cmd_buf); + pub fn recycle(&self, cmd_buf: CommandBuffer) { + self.inner.lock().unwrap().recycle(cmd_buf); } pub fn maintain(&self, device: &B::Device) { @@ -87,12 +118,7 @@ impl CommandAllocator { for i in (0..inner.pending.len()).rev() { if device.get_fence_status(&inner.pending[i].fence) { let cmd_buf = inner.pending.swap_remove(i); - inner - .pools - .get_mut(&cmd_buf.recorded_thread_id) - .unwrap() - .available - .push(cmd_buf); + inner.recycle(cmd_buf); } } } diff --git a/wgpu-native/src/command/compute.rs b/wgpu-native/src/command/compute.rs index 3f96a1774..05bcc7703 100644 --- a/wgpu-native/src/command/compute.rs +++ b/wgpu-native/src/command/compute.rs @@ -35,7 +35,8 @@ pub extern "C" fn wgpu_compute_pass_end_pass( HUB.command_buffers .lock() .get_mut(pass.cmb_id.0) - .raw = Some(pass.raw); + .raw + .push(pass.raw); pass.cmb_id.0 } diff --git a/wgpu-native/src/command/mod.rs b/wgpu-native/src/command/mod.rs index 25c44a745..695a10277 100644 --- a/wgpu-native/src/command/mod.rs +++ b/wgpu-native/src/command/mod.rs @@ -72,7 +72,7 @@ pub struct TextureCopyView { } pub struct CommandBuffer { - pub(crate) raw: Option, + pub(crate) raw: Vec, fence: B::Fence, recorded_thread_id: ThreadId, device_id: Stored, @@ -89,10 +89,11 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass( let mut cmb_guard = HUB.command_buffers.lock(); let cmb = cmb_guard.get_mut(command_buffer_id); - let raw = cmb.raw.take().unwrap(); - let device_guard = HUB.devices.lock(); - let _device = &device_guard.get(cmb.device_id.0).raw; + let device = device_guard.get(cmb.device_id.0); + + let transit_comb = cmb.raw.pop().unwrap(); + let current_comb = device.com_allocator.extend(cmb); //let render_pass = device.create_render_pass(); //let framebuffer = device.create_framebuffer(); @@ -108,7 +109,11 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass( HUB.render_passes .lock() - .register(RenderPass::new(raw, command_buffer_id)) + .register(RenderPass::new( + current_comb, + transit_comb, + command_buffer_id, + )) } #[no_mangle] @@ -118,7 +123,7 @@ pub extern "C" fn wgpu_command_buffer_begin_compute_pass( let mut cmb_guard = HUB.command_buffers.lock(); let cmb = cmb_guard.get_mut(command_buffer_id); - let raw = cmb.raw.take().unwrap(); + let raw = cmb.raw.pop().unwrap(); HUB.compute_passes .lock() diff --git a/wgpu-native/src/command/render.rs b/wgpu-native/src/command/render.rs index 79dcd91da..3e221d662 100644 --- a/wgpu-native/src/command/render.rs +++ b/wgpu-native/src/command/render.rs @@ -7,16 +7,24 @@ use { use hal; use hal::command::RawCommandBuffer; +use std::iter; + pub struct RenderPass { raw: B::CommandBuffer, + parent: B::CommandBuffer, cmb_id: Stored, } impl RenderPass { - pub fn new(raw: B::CommandBuffer, cmb_id: CommandBufferId) -> Self { + pub fn new( + raw: B::CommandBuffer, + parent: B::CommandBuffer, + cmb_id: CommandBufferId, + ) -> Self { RenderPass { raw, + parent, cmb_id: Stored(cmb_id), } } @@ -31,9 +39,13 @@ pub extern "C" fn wgpu_render_pass_end_pass( .take(pass_id); pass.raw.end_render_pass(); + let combs = iter::once(pass.parent) + .chain(iter::once(pass.raw)); HUB.command_buffers .lock() .get_mut(pass.cmb_id.0) - .raw = Some(pass.raw); + .raw + .extend(combs); + pass.cmb_id.0 } diff --git a/wgpu-native/src/device.rs b/wgpu-native/src/device.rs index d2185a235..fd3716dc1 100644 --- a/wgpu-native/src/device.rs +++ b/wgpu-native/src/device.rs @@ -17,7 +17,7 @@ pub struct Device { pub(crate) raw: B::Device, queue_group: hal::QueueGroup, mem_allocator: Heaps, - com_allocator: command::CommandAllocator, + pub(crate) com_allocator: command::CommandAllocator, mem_props: hal::MemoryProperties, } @@ -219,7 +219,7 @@ pub extern "C" fn wgpu_device_create_command_buffer( let device = device_guard.get_mut(device_id); let mut cmd_buf = device.com_allocator.allocate(device_id, &device.raw); - cmd_buf.raw.as_mut().unwrap().begin( + cmd_buf.raw.last_mut().unwrap().begin( hal::command::CommandBufferFlags::ONE_TIME_SUBMIT, hal::command::CommandBufferInheritanceInfo::default(), ); @@ -249,7 +249,7 @@ pub extern "C" fn wgpu_queue_submit( command_buffer_guard .get_mut(cmb_id) .raw - .as_mut() + .last_mut() .unwrap() .finish(); } @@ -259,12 +259,8 @@ pub extern "C" fn wgpu_queue_submit( let submission = hal::queue::RawSubmission { cmd_buffers: command_buffer_ids .iter() - .map(|&cmb_id| { - command_buffer_guard - .get(cmb_id) - .raw - .as_ref() - .unwrap() + .flat_map(|&cmb_id| { + &command_buffer_guard.get(cmb_id).raw }), wait_semaphores: &[], signal_semaphores: &[], From 0fca6930d90beb24c1d650d764a8b5d8d0b3069e Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 19 Oct 2018 10:34:19 -0400 Subject: [PATCH 2/6] Basic resource tracking --- wgpu-native/src/command/render.rs | 3 ++ wgpu-native/src/conv.rs | 40 ++++++++------- wgpu-native/src/device.rs | 15 ++++-- wgpu-native/src/lib.rs | 3 +- wgpu-native/src/resource.rs | 35 +++++++------ wgpu-native/src/track.rs | 85 +++++++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 41 deletions(-) create mode 100644 wgpu-native/src/track.rs diff --git a/wgpu-native/src/command/render.rs b/wgpu-native/src/command/render.rs index 3e221d662..4c4dd1b45 100644 --- a/wgpu-native/src/command/render.rs +++ b/wgpu-native/src/command/render.rs @@ -1,4 +1,5 @@ use registry::{HUB, Items, Registry}; +use track::{Tracker}; use { Stored, CommandBufferId, RenderPassId, @@ -14,6 +15,7 @@ pub struct RenderPass { raw: B::CommandBuffer, parent: B::CommandBuffer, cmb_id: Stored, + tracker: Tracker, } impl RenderPass { @@ -26,6 +28,7 @@ impl RenderPass { raw, parent, cmb_id: Stored(cmb_id), + tracker: Tracker::default(), } } } diff --git a/wgpu-native/src/conv.rs b/wgpu-native/src/conv.rs index 4708c7464..204ae14d6 100644 --- a/wgpu-native/src/conv.rs +++ b/wgpu-native/src/conv.rs @@ -244,7 +244,9 @@ fn checked_u32_as_u16(value: u32) -> u16 { value as u16 } -pub(crate) fn map_texture_dimension_size(dimension: resource::TextureDimension, size: Extent3d) -> hal::image::Kind { +pub(crate) fn map_texture_dimension_size( + dimension: resource::TextureDimension, size: Extent3d +) -> hal::image::Kind { use hal::image::Kind as H; use resource::TextureDimension::*; let Extent3d { width, height, depth } = size; @@ -258,30 +260,30 @@ pub(crate) fn map_texture_dimension_size(dimension: resource::TextureDimension, } } -pub(crate) fn map_texture_usage_flags(flags: u32, format: hal::format::Format) -> hal::image::Usage { - use hal::image::Usage as H; - use resource::{ - TextureUsageFlags_TRANSFER_SRC, TextureUsageFlags_TRANSFER_DST, TextureUsageFlags_SAMPLED, - TextureUsageFlags_STORAGE, TextureUsageFlags_OUTPUT_ATTACHMENT, - }; - let mut value = H::empty(); - if 0 != flags & TextureUsageFlags_TRANSFER_SRC { - value |= H::TRANSFER_SRC; +pub(crate) fn map_texture_usage_flags( + flags: resource::TextureUsageFlags, format: hal::format::Format +) -> hal::image::Usage { + use hal::image::Usage as U; + use resource::TextureUsageFlags as W; + + let mut value = U::empty(); + if flags.contains(W::TRANSFER_SRC) { + value |= U::TRANSFER_SRC; } - if 0 != flags & TextureUsageFlags_TRANSFER_DST { - value |= H::TRANSFER_DST; + if flags.contains(W::TRANSFER_DST) { + value |= U::TRANSFER_DST; } - if 0 != flags & TextureUsageFlags_SAMPLED { - value |= H::SAMPLED; + if flags.contains(W::SAMPLED) { + value |= U::SAMPLED; } - if 0 != flags & TextureUsageFlags_STORAGE { - value |= H::STORAGE; + if flags.contains(W::STORAGE) { + value |= U::STORAGE; } - if 0 != flags & TextureUsageFlags_OUTPUT_ATTACHMENT { + if flags.contains(W::OUTPUT_ATTACHMENT) { if format.surface_desc().aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { - value |= H::DEPTH_STENCIL_ATTACHMENT; + value |= U::DEPTH_STENCIL_ATTACHMENT; } else { - value |= H::COLOR_ATTACHMENT; + value |= U::COLOR_ATTACHMENT; } } // Note: TextureUsageFlags::Present does not need to be handled explicitly diff --git a/wgpu-native/src/device.rs b/wgpu-native/src/device.rs index fd3716dc1..3a5245317 100644 --- a/wgpu-native/src/device.rs +++ b/wgpu-native/src/device.rs @@ -1,6 +1,8 @@ use {back, binding_model, command, conv, pipeline, resource}; use registry::{HUB, Items, Registry}; +use track::{Tracker, UsePermit}; use { + Stored, AttachmentStateId, BindGroupLayoutId, BlendStateId, CommandBufferId, DepthStencilStateId, DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId, TextureId, }; @@ -18,6 +20,7 @@ pub struct Device { queue_group: hal::QueueGroup, mem_allocator: Heaps, pub(crate) com_allocator: command::CommandAllocator, + tracker: Tracker, mem_props: hal::MemoryProperties, } @@ -53,6 +56,7 @@ impl Device { mem_allocator, com_allocator: command::CommandAllocator::new(queue_group.family()), queue_group, + tracker: Tracker::default(), mem_props, } } @@ -101,11 +105,16 @@ pub extern "C" fn wgpu_device_create_texture( .raw .bind_image_memory(&image_memory, 0, image_unbound) .unwrap(); - HUB.textures + + let id = HUB.textures .lock() .register(resource::Texture { raw: bound_image, - }) + }); + device.tracker.use_texture(Stored(id), resource::TextureUsageFlags::empty(), UsePermit::empty()) + .expect("Resource somehow is already registered"); + + id } #[no_mangle] @@ -216,7 +225,7 @@ pub extern "C" fn wgpu_device_create_command_buffer( _desc: &command::CommandBufferDescriptor, ) -> CommandBufferId { let mut device_guard = HUB.devices.lock(); - let device = device_guard.get_mut(device_id); + let device = device_guard.get(device_id); let mut cmd_buf = device.com_allocator.allocate(device_id, &device.raw); cmd_buf.raw.last_mut().unwrap().begin( diff --git a/wgpu-native/src/lib.rs b/wgpu-native/src/lib.rs index 9d3248aa5..5445b4989 100644 --- a/wgpu-native/src/lib.rs +++ b/wgpu-native/src/lib.rs @@ -29,6 +29,7 @@ mod instance; mod pipeline; mod registry; mod resource; +mod track; pub use self::binding_model::*; pub use self::command::*; @@ -40,7 +41,7 @@ pub use self::resource::*; use back::Backend as B; use registry::Id; -#[derive(Debug, PartialEq)] +#[derive(Debug, Hash, PartialEq, Eq)] struct Stored(T); #[cfg(not(feature = "remote"))] unsafe impl Sync for Stored {} diff --git a/wgpu-native/src/resource.rs b/wgpu-native/src/resource.rs index 884a1d3a3..6a6f40ee5 100644 --- a/wgpu-native/src/resource.rs +++ b/wgpu-native/src/resource.rs @@ -1,11 +1,11 @@ +use {Extent3d}; + use hal; -use Extent3d; bitflags! { #[repr(transparent)] pub struct BufferUsageFlags: u32 { - const NONE = 0; const MAP_READ = 1; const MAP_WRITE = 2; const TRANSFER_SRC = 4; @@ -14,6 +14,8 @@ bitflags! { const VERTEX = 32; const UNIFORM = 64; const STORAGE = 128; + const NONE = 0; + const WRITE_ALL = 2 + 8 + 128; } } @@ -50,22 +52,19 @@ pub enum TextureFormat { D32FloatS8Uint = 3, } -// TODO: bitflags -pub type TextureUsageFlags = u32; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_NONE: u32 = 0; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_TRANSFER_SRC: u32 = 1; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_TRANSFER_DST: u32 = 2; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_SAMPLED: u32 = 4; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_STORAGE: u32 = 8; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_OUTPUT_ATTACHMENT: u32 = 16; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_PRESENT: u32 = 32; +bitflags! { + #[repr(transparent)] + pub struct TextureUsageFlags: u32 { + const TRANSFER_SRC = 1; + const TRANSFER_DST = 2; + const SAMPLED = 4; + const STORAGE = 8; + const OUTPUT_ATTACHMENT = 16; + const PRESENT = 32; + const NONE = 0; + const WRITE_ALL = 2 + 8 + 16; + } +} #[repr(C)] pub struct TextureDescriptor { diff --git a/wgpu-native/src/track.rs b/wgpu-native/src/track.rs new file mode 100644 index 000000000..7f72a1f2e --- /dev/null +++ b/wgpu-native/src/track.rs @@ -0,0 +1,85 @@ +use {Stored, BufferId, TextureId}; +use resource::{BufferUsageFlags, TextureUsageFlags}; + +use std::collections::hash_map::{Entry, HashMap}; +use std::ops::Range; +use std::sync::Mutex; + + +#[derive(Clone, Debug, PartialEq)] +pub enum UseAction { + Init, + Keep, + Extend { old: T }, + Replace { old: T }, +} + +bitflags! { + pub struct UsePermit: u32 { + const EXTEND = 1; + const REPLACE = 2; + } +} + + +#[derive(Default)] +pub struct Tracker { + buffers: Mutex, Range>>, + textures: Mutex, Range>>, +} + +impl Tracker { + pub(crate) fn use_buffer( + &self, id: Stored, usage: BufferUsageFlags, permit: UsePermit, + ) -> Result, BufferUsageFlags> { + match self.buffers.lock().unwrap().entry(id) { + Entry::Vacant(e) => { + e.insert(usage .. usage); + Ok(UseAction::Init) + } + Entry::Occupied(mut e) => { + let old = e.get().end; + if usage == old { + Ok(UseAction::Keep) + } else if permit.contains(UsePermit::EXTEND) && + !BufferUsageFlags::WRITE_ALL.intersects(old | usage) + { + e.get_mut().end |= usage; + Ok(UseAction::Extend { old }) + } else if permit.contains(UsePermit::REPLACE) { + e.get_mut().end = usage; + Ok(UseAction::Replace { old }) + } else { + Err(old) + } + } + } + } + + pub(crate) fn use_texture( + &self, id: Stored, usage: TextureUsageFlags, permit: UsePermit, + ) -> Result, TextureUsageFlags> { + match self.textures.lock().unwrap().entry(id) { + Entry::Vacant(e) => { + e.insert(usage .. usage); + Ok(UseAction::Init) + } + Entry::Occupied(mut e) => { + let old = e.get().end; + if usage == old { + Ok(UseAction::Keep) + } else if permit.contains(UsePermit::EXTEND) && + !TextureUsageFlags::WRITE_ALL.intersects(old | usage) + { + e.get_mut().end |= usage; + Ok(UseAction::Extend { old }) + } else if permit.contains(UsePermit::REPLACE) { + e.get_mut().end = usage; + Ok(UseAction::Replace { old }) + } else { + Err(old) + } + } + } + } +} From f9cd55ed59cbecf9da36f8412390e292871c1e86 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 19 Oct 2018 10:45:11 -0400 Subject: [PATCH 3/6] Share use_xxx implementations in the tracker --- wgpu-native/src/command/mod.rs | 2 - wgpu-native/src/command/render.rs | 7 +-- wgpu-native/src/track.rs | 76 +++++++++++++++---------------- 3 files changed, 39 insertions(+), 46 deletions(-) diff --git a/wgpu-native/src/command/mod.rs b/wgpu-native/src/command/mod.rs index 695a10277..d4dd5658b 100644 --- a/wgpu-native/src/command/mod.rs +++ b/wgpu-native/src/command/mod.rs @@ -92,7 +92,6 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass( let device_guard = HUB.devices.lock(); let device = device_guard.get(cmb.device_id.0); - let transit_comb = cmb.raw.pop().unwrap(); let current_comb = device.com_allocator.extend(cmb); //let render_pass = device.create_render_pass(); @@ -111,7 +110,6 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass( .lock() .register(RenderPass::new( current_comb, - transit_comb, command_buffer_id, )) } diff --git a/wgpu-native/src/command/render.rs b/wgpu-native/src/command/render.rs index 4c4dd1b45..2c5892738 100644 --- a/wgpu-native/src/command/render.rs +++ b/wgpu-native/src/command/render.rs @@ -13,7 +13,6 @@ use std::iter; pub struct RenderPass { raw: B::CommandBuffer, - parent: B::CommandBuffer, cmb_id: Stored, tracker: Tracker, } @@ -21,12 +20,10 @@ pub struct RenderPass { impl RenderPass { pub fn new( raw: B::CommandBuffer, - parent: B::CommandBuffer, cmb_id: CommandBufferId, ) -> Self { RenderPass { raw, - parent, cmb_id: Stored(cmb_id), tracker: Tracker::default(), } @@ -42,13 +39,11 @@ pub extern "C" fn wgpu_render_pass_end_pass( .take(pass_id); pass.raw.end_render_pass(); - let combs = iter::once(pass.parent) - .chain(iter::once(pass.raw)); HUB.command_buffers .lock() .get_mut(pass.cmb_id.0) .raw - .extend(combs); + .push(pass.raw); pass.cmb_id.0 } diff --git a/wgpu-native/src/track.rs b/wgpu-native/src/track.rs index 7f72a1f2e..d3584bb51 100644 --- a/wgpu-native/src/track.rs +++ b/wgpu-native/src/track.rs @@ -2,7 +2,8 @@ use {Stored, BufferId, TextureId}; use resource::{BufferUsageFlags, TextureUsageFlags}; use std::collections::hash_map::{Entry, HashMap}; -use std::ops::Range; +use std::hash::Hash; +use std::ops::BitOr; use std::sync::Mutex; @@ -22,33 +23,47 @@ bitflags! { } +trait GenericUsage { + fn is_exclusive(&self) -> bool; +} +impl GenericUsage for BufferUsageFlags { + fn is_exclusive(&self) -> bool { + BufferUsageFlags::WRITE_ALL.intersects(*self) + } +} +impl GenericUsage for TextureUsageFlags { + fn is_exclusive(&self) -> bool { + TextureUsageFlags::WRITE_ALL.intersects(*self) + } +} + #[derive(Default)] pub struct Tracker { - buffers: Mutex, Range>>, - textures: Mutex, Range>>, + buffers: Mutex, BufferUsageFlags>>, + textures: Mutex, TextureUsageFlags>>, } impl Tracker { - pub(crate) fn use_buffer( - &self, id: Stored, usage: BufferUsageFlags, permit: UsePermit, - ) -> Result, BufferUsageFlags> { - match self.buffers.lock().unwrap().entry(id) { + fn use_impl( + map: &mut HashMap, id: I, usage: U, permit: UsePermit + ) -> Result, U> + where + I: Hash + Eq, + U: Copy + GenericUsage + BitOr + PartialEq, + { + match map.entry(id) { Entry::Vacant(e) => { - e.insert(usage .. usage); + e.insert(usage); Ok(UseAction::Init) } Entry::Occupied(mut e) => { - let old = e.get().end; + let old = *e.get(); if usage == old { Ok(UseAction::Keep) - } else if permit.contains(UsePermit::EXTEND) && - !BufferUsageFlags::WRITE_ALL.intersects(old | usage) - { - e.get_mut().end |= usage; - Ok(UseAction::Extend { old }) + } else if permit.contains(UsePermit::EXTEND) && !(old | usage).is_exclusive() { + Ok(UseAction::Extend { old: e.insert(old | usage) }) } else if permit.contains(UsePermit::REPLACE) { - e.get_mut().end = usage; - Ok(UseAction::Replace { old }) + Ok(UseAction::Replace { old: e.insert(usage) }) } else { Err(old) } @@ -56,30 +71,15 @@ impl Tracker { } } + pub(crate) fn use_buffer( + &self, id: Stored, usage: BufferUsageFlags, permit: UsePermit, + ) -> Result, BufferUsageFlags> { + Self::use_impl(&mut *self.buffers.lock().unwrap(), id, usage, permit) + } + pub(crate) fn use_texture( &self, id: Stored, usage: TextureUsageFlags, permit: UsePermit, ) -> Result, TextureUsageFlags> { - match self.textures.lock().unwrap().entry(id) { - Entry::Vacant(e) => { - e.insert(usage .. usage); - Ok(UseAction::Init) - } - Entry::Occupied(mut e) => { - let old = e.get().end; - if usage == old { - Ok(UseAction::Keep) - } else if permit.contains(UsePermit::EXTEND) && - !TextureUsageFlags::WRITE_ALL.intersects(old | usage) - { - e.get_mut().end |= usage; - Ok(UseAction::Extend { old }) - } else if permit.contains(UsePermit::REPLACE) { - e.get_mut().end = usage; - Ok(UseAction::Replace { old }) - } else { - Err(old) - } - } - } + Self::use_impl(&mut *self.textures.lock().unwrap(), id, usage, permit) } } From b27650bfcded3608d4695b4727710c338240e8cc Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 19 Oct 2018 12:07:07 -0400 Subject: [PATCH 4/6] Buffer transitions for a render pass --- wgpu-native/src/command/allocator.rs | 3 ++ wgpu-native/src/command/mod.rs | 4 ++ wgpu-native/src/command/render.rs | 44 ++++++++++++++----- wgpu-native/src/conv.rs | 48 +++++++++++++++++---- wgpu-native/src/device.rs | 21 ++++++---- wgpu-native/src/lib.rs | 1 + wgpu-native/src/registry/mod.rs | 3 +- wgpu-native/src/resource.rs | 10 ++--- wgpu-native/src/track.rs | 63 +++++++++++++--------------- 9 files changed, 130 insertions(+), 67 deletions(-) diff --git a/wgpu-native/src/command/allocator.rs b/wgpu-native/src/command/allocator.rs index 899c0ad00..d37b4e5e4 100644 --- a/wgpu-native/src/command/allocator.rs +++ b/wgpu-native/src/command/allocator.rs @@ -1,5 +1,6 @@ use super::CommandBuffer; use {DeviceId, Stored}; +use track::{Tracker}; use hal::command::RawCommandBuffer; use hal::pool::RawCommandPool; @@ -90,6 +91,8 @@ impl CommandAllocator { fence, recorded_thread_id: thread_id, device_id: Stored(device_id), + buffer_tracker: Tracker::new(), + texture_tracker: Tracker::new(), } } diff --git a/wgpu-native/src/command/mod.rs b/wgpu-native/src/command/mod.rs index d4dd5658b..14bdbcf89 100644 --- a/wgpu-native/src/command/mod.rs +++ b/wgpu-native/src/command/mod.rs @@ -13,9 +13,11 @@ use { BufferId, CommandBufferId, ComputePassId, DeviceId, RenderPassId, TextureId, TextureViewId, }; use registry::{HUB, Items, Registry}; +use track::{BufferTracker, TextureTracker}; use std::thread::ThreadId; + #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub enum LoadOp { @@ -76,6 +78,8 @@ pub struct CommandBuffer { fence: B::Fence, recorded_thread_id: ThreadId, device_id: Stored, + buffer_tracker: BufferTracker, + texture_tracker: TextureTracker, } #[repr(C)] diff --git a/wgpu-native/src/command/render.rs b/wgpu-native/src/command/render.rs index 2c5892738..3ee3f7d1d 100644 --- a/wgpu-native/src/command/render.rs +++ b/wgpu-native/src/command/render.rs @@ -1,5 +1,6 @@ +use conv; use registry::{HUB, Items, Registry}; -use track::{Tracker}; +use track::{BufferTracker, TextureTracker, Tracktion, TrackPermit}; use { Stored, CommandBufferId, RenderPassId, @@ -8,13 +9,12 @@ use { use hal; use hal::command::RawCommandBuffer; -use std::iter; - pub struct RenderPass { raw: B::CommandBuffer, cmb_id: Stored, - tracker: Tracker, + buffer_tracker: BufferTracker, + texture_tracker: TextureTracker, } impl RenderPass { @@ -25,7 +25,8 @@ impl RenderPass { RenderPass { raw, cmb_id: Stored(cmb_id), - tracker: Tracker::default(), + buffer_tracker: BufferTracker::new(), + texture_tracker: TextureTracker::new(), } } } @@ -39,11 +40,34 @@ pub extern "C" fn wgpu_render_pass_end_pass( .take(pass_id); pass.raw.end_render_pass(); - HUB.command_buffers - .lock() - .get_mut(pass.cmb_id.0) - .raw - .push(pass.raw); + let buffer_guard = HUB.buffers.lock(); + //let texture_guard = HUB.textures.lock(); + let mut cmb_guard = HUB.command_buffers.lock(); + let cmb = cmb_guard.get_mut(pass.cmb_id.0); + let cmb_buffers = &mut cmb.buffer_tracker; + let buffer_barriers = pass.buffer_tracker + .finish() + .into_iter() + .flat_map(|(id, new)| { + match cmb_buffers.track(id.0, new, TrackPermit::REPLACE) { + Ok(Tracktion::Init) => None, + Ok(Tracktion::Keep) => None, + Ok(Tracktion::Replace { old }) => Some(hal::memory::Barrier::Buffer { + states: conv::map_buffer_state(old) .. conv::map_buffer_state(new), + target: &buffer_guard.get(id.0).raw, + }), + Ok(Tracktion::Extend { .. }) | + Err(_) => panic!("Unable to do the resource transition for a pass"), + } + }); + + pass.raw.pipeline_barrier( + hal::pso::PipelineStage::TOP_OF_PIPE .. hal::pso::PipelineStage::BOTTOM_OF_PIPE, + hal::memory::Dependencies::empty(), + buffer_barriers, + ); + + cmb.raw.push(pass.raw); pass.cmb_id.0 } diff --git a/wgpu-native/src/conv.rs b/wgpu-native/src/conv.rs index 204ae14d6..38818f2f7 100644 --- a/wgpu-native/src/conv.rs +++ b/wgpu-native/src/conv.rs @@ -2,7 +2,8 @@ use hal; use {Extent3d, binding_model, pipeline, resource}; -pub(crate) fn map_buffer_usage( + +pub fn map_buffer_usage( usage: resource::BufferUsageFlags, ) -> (hal::buffer::Usage, hal::memory::Properties) { use hal::buffer::Usage as U; @@ -40,7 +41,7 @@ pub(crate) fn map_buffer_usage( (hal_usage, hal_memory) } -pub(crate) fn map_binding_type( +pub fn map_binding_type( binding_ty: binding_model::BindingType, ) -> hal::pso::DescriptorType { use binding_model::BindingType::*; @@ -53,7 +54,7 @@ pub(crate) fn map_binding_type( } } -pub(crate) fn map_shader_stage_flags( +pub fn map_shader_stage_flags( shader_stage_flags: binding_model::ShaderStageFlags, ) -> hal::pso::ShaderStageFlags { use binding_model::{ @@ -73,7 +74,7 @@ pub(crate) fn map_shader_stage_flags( value } -pub(crate) fn map_primitive_topology( +pub fn map_primitive_topology( primitive_topology: pipeline::PrimitiveTopology, ) -> hal::Primitive { use hal::Primitive as H; @@ -87,7 +88,7 @@ pub(crate) fn map_primitive_topology( } } -pub(crate) fn map_blend_state_descriptor( +pub fn map_blend_state_descriptor( desc: &pipeline::BlendStateDescriptor, ) -> hal::pso::ColorBlendDesc { let color_mask = desc.write_mask; @@ -164,7 +165,7 @@ fn map_blend_factor(blend_factor: pipeline::BlendFactor) -> hal::pso::Factor { } } -pub(crate) fn map_depth_stencil_state( +pub fn map_depth_stencil_state( desc: &pipeline::DepthStencilStateDescriptor, ) -> hal::pso::DepthStencilDesc { hal::pso::DepthStencilDesc { @@ -228,7 +229,7 @@ fn map_stencil_operation(stencil_operation: pipeline::StencilOperation) -> hal:: } } -pub(crate) fn map_texture_format(texture_format: resource::TextureFormat) -> hal::format::Format { +pub fn map_texture_format(texture_format: resource::TextureFormat) -> hal::format::Format { use hal::format::Format as H; use resource::TextureFormat::*; match texture_format { @@ -244,7 +245,7 @@ fn checked_u32_as_u16(value: u32) -> u16 { value as u16 } -pub(crate) fn map_texture_dimension_size( +pub fn map_texture_dimension_size( dimension: resource::TextureDimension, size: Extent3d ) -> hal::image::Kind { use hal::image::Kind as H; @@ -260,7 +261,7 @@ pub(crate) fn map_texture_dimension_size( } } -pub(crate) fn map_texture_usage_flags( +pub fn map_texture_usage( flags: resource::TextureUsageFlags, format: hal::format::Format ) -> hal::image::Usage { use hal::image::Usage as U; @@ -290,3 +291,32 @@ pub(crate) fn map_texture_usage_flags( // TODO: HAL Transient Attachment, HAL Input Attachment value } + +pub fn map_buffer_state( + usage: resource::BufferUsageFlags, +) -> hal::buffer::State { + use hal::buffer::Access as A; + use resource::BufferUsageFlags as W; + + let mut access = A::empty(); + if usage.contains(W::TRANSFER_SRC) { + access |= A::TRANSFER_READ; + } + if usage.contains(W::TRANSFER_DST) { + access |= A::TRANSFER_WRITE; + } + if usage.contains(W::INDEX) { + access |= A::INDEX_BUFFER_READ; + } + if usage.contains(W::VERTEX) { + access |= A::VERTEX_BUFFER_READ; + } + if usage.contains(W::UNIFORM) { + access |= A::CONSTANT_BUFFER_READ | A::SHADER_READ; + } + if usage.contains(W::STORAGE) { + access |= A::SHADER_WRITE; + } + + access +} diff --git a/wgpu-native/src/device.rs b/wgpu-native/src/device.rs index 3a5245317..fb40e4017 100644 --- a/wgpu-native/src/device.rs +++ b/wgpu-native/src/device.rs @@ -1,8 +1,7 @@ use {back, binding_model, command, conv, pipeline, resource}; use registry::{HUB, Items, Registry}; -use track::{Tracker, UsePermit}; +use track::{BufferTracker, TextureTracker, TrackPermit}; use { - Stored, AttachmentStateId, BindGroupLayoutId, BlendStateId, CommandBufferId, DepthStencilStateId, DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId, TextureId, }; @@ -10,9 +9,10 @@ use { use hal::command::RawCommandBuffer; use hal::queue::RawCommandQueue; use hal::{self, Device as _Device}; +use rendy_memory::{allocator, Config, Heaps}; use std::{ffi, slice}; -use rendy_memory::{allocator, Config, Heaps}; +use std::sync::Mutex; pub struct Device { @@ -20,7 +20,8 @@ pub struct Device { queue_group: hal::QueueGroup, mem_allocator: Heaps, pub(crate) com_allocator: command::CommandAllocator, - tracker: Tracker, + buffer_tracker: Mutex, + texture_tracker: Mutex, mem_props: hal::MemoryProperties, } @@ -56,7 +57,8 @@ impl Device { mem_allocator, com_allocator: command::CommandAllocator::new(queue_group.family()), queue_group, - tracker: Tracker::default(), + buffer_tracker: Mutex::new(BufferTracker::new()), + texture_tracker: Mutex::new(TextureTracker::new()), mem_props, } } @@ -73,7 +75,7 @@ pub extern "C" fn wgpu_device_create_texture( ) -> TextureId { let kind = conv::map_texture_dimension_size(desc.dimension, desc.size); let format = conv::map_texture_format(desc.format); - let usage = conv::map_texture_usage_flags(desc.usage, format); + let usage = conv::map_texture_usage(desc.usage, format); let device_guard = HUB.devices.lock(); let device = &device_guard.get(device_id); let image_unbound = device @@ -111,7 +113,10 @@ pub extern "C" fn wgpu_device_create_texture( .register(resource::Texture { raw: bound_image, }); - device.tracker.use_texture(Stored(id), resource::TextureUsageFlags::empty(), UsePermit::empty()) + device.texture_tracker + .lock() + .unwrap() + .track(id, resource::TextureUsageFlags::empty(), TrackPermit::empty()) .expect("Resource somehow is already registered"); id @@ -224,7 +229,7 @@ pub extern "C" fn wgpu_device_create_command_buffer( device_id: DeviceId, _desc: &command::CommandBufferDescriptor, ) -> CommandBufferId { - let mut device_guard = HUB.devices.lock(); + let device_guard = HUB.devices.lock(); let device = device_guard.get(device_id); let mut cmd_buf = device.com_allocator.allocate(device_id, &device.raw); diff --git a/wgpu-native/src/lib.rs b/wgpu-native/src/lib.rs index 5445b4989..f1705c5bb 100644 --- a/wgpu-native/src/lib.rs +++ b/wgpu-native/src/lib.rs @@ -96,6 +96,7 @@ pub type DeviceId = Id; type DeviceHandle = Device; pub type QueueId = Id; pub type BufferId = Id; +type BufferHandle = Buffer; // Resource pub type TextureViewId = Id; diff --git a/wgpu-native/src/registry/mod.rs b/wgpu-native/src/registry/mod.rs index ca9a32b5c..935732323 100644 --- a/wgpu-native/src/registry/mod.rs +++ b/wgpu-native/src/registry/mod.rs @@ -13,7 +13,7 @@ use { BlendStateHandle, CommandBufferHandle, DepthStencilStateHandle, DeviceHandle, InstanceHandle, RenderPassHandle, ComputePassHandle, PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle, - TextureHandle, + BufferHandle, TextureHandle, }; @@ -48,6 +48,7 @@ pub struct Hub { pub(crate) compute_pipelines: ConcreteRegistry, pub(crate) render_passes: ConcreteRegistry, pub(crate) compute_passes: ConcreteRegistry, + pub(crate) buffers: ConcreteRegistry, pub(crate) textures: ConcreteRegistry, } diff --git a/wgpu-native/src/resource.rs b/wgpu-native/src/resource.rs index 6a6f40ee5..6517e01d1 100644 --- a/wgpu-native/src/resource.rs +++ b/wgpu-native/src/resource.rs @@ -25,9 +25,9 @@ pub struct BufferDescriptor { pub usage: BufferUsageFlags, } -pub struct Buffer { - pub(crate) raw: B::UnboundBuffer, - pub(crate) memory_properties: hal::memory::Properties, +pub(crate) struct Buffer { + pub raw: B::UnboundBuffer, + pub memory_properties: hal::memory::Properties, // TODO: mapping, unmap() } @@ -75,8 +75,8 @@ pub struct TextureDescriptor { pub usage: TextureUsageFlags, } -pub struct Texture { - pub(crate) raw: B::Image, +pub(crate) struct Texture { + pub raw: B::Image, } #[repr(C)] diff --git a/wgpu-native/src/track.rs b/wgpu-native/src/track.rs index d3584bb51..4e5b3bb55 100644 --- a/wgpu-native/src/track.rs +++ b/wgpu-native/src/track.rs @@ -4,11 +4,10 @@ use resource::{BufferUsageFlags, TextureUsageFlags}; use std::collections::hash_map::{Entry, HashMap}; use std::hash::Hash; use std::ops::BitOr; -use std::sync::Mutex; #[derive(Clone, Debug, PartialEq)] -pub enum UseAction { +pub enum Tracktion { Init, Keep, Extend { old: T }, @@ -16,14 +15,14 @@ pub enum UseAction { } bitflags! { - pub struct UsePermit: u32 { + pub struct TrackPermit: u32 { const EXTEND = 1; const REPLACE = 2; } } -trait GenericUsage { +pub trait GenericUsage { fn is_exclusive(&self) -> bool; } impl GenericUsage for BufferUsageFlags { @@ -37,33 +36,37 @@ impl GenericUsage for TextureUsageFlags { } } -#[derive(Default)] -pub struct Tracker { - buffers: Mutex, BufferUsageFlags>>, - textures: Mutex, TextureUsageFlags>>, -} -impl Tracker { - fn use_impl( - map: &mut HashMap, id: I, usage: U, permit: UsePermit - ) -> Result, U> - where - I: Hash + Eq, - U: Copy + GenericUsage + BitOr + PartialEq, - { - match map.entry(id) { +pub struct Tracker { + map: HashMap, U>, +} +pub type BufferTracker = Tracker; +pub type TextureTracker = Tracker; + +impl< + I: Hash + Eq, + U: Copy + GenericUsage + BitOr + PartialEq, +> Tracker { + pub fn new() -> Self { + Tracker { + map: HashMap::new(), + } + } + + pub fn track(&mut self, id: I, usage: U, permit: TrackPermit) -> Result, U> { + match self.map.entry(Stored(id)) { Entry::Vacant(e) => { e.insert(usage); - Ok(UseAction::Init) + Ok(Tracktion::Init) } Entry::Occupied(mut e) => { let old = *e.get(); if usage == old { - Ok(UseAction::Keep) - } else if permit.contains(UsePermit::EXTEND) && !(old | usage).is_exclusive() { - Ok(UseAction::Extend { old: e.insert(old | usage) }) - } else if permit.contains(UsePermit::REPLACE) { - Ok(UseAction::Replace { old: e.insert(usage) }) + Ok(Tracktion::Keep) + } else if permit.contains(TrackPermit::EXTEND) && !(old | usage).is_exclusive() { + Ok(Tracktion::Extend { old: e.insert(old | usage) }) + } else if permit.contains(TrackPermit::REPLACE) { + Ok(Tracktion::Replace { old: e.insert(usage) }) } else { Err(old) } @@ -71,15 +74,7 @@ impl Tracker { } } - pub(crate) fn use_buffer( - &self, id: Stored, usage: BufferUsageFlags, permit: UsePermit, - ) -> Result, BufferUsageFlags> { - Self::use_impl(&mut *self.buffers.lock().unwrap(), id, usage, permit) - } - - pub(crate) fn use_texture( - &self, id: Stored, usage: TextureUsageFlags, permit: UsePermit, - ) -> Result, TextureUsageFlags> { - Self::use_impl(&mut *self.textures.lock().unwrap(), id, usage, permit) + pub(crate) fn finish(self) -> HashMap, U> { + self.map } } From 0cad1f5d5661add054ccf618a26cff20949bbc3b Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 19 Oct 2018 12:31:36 -0400 Subject: [PATCH 5/6] Basic texture transitions --- wgpu-native/src/command/render.rs | 43 ++++++++----- wgpu-native/src/conv.rs | 100 +++++++++++++++++++++--------- wgpu-native/src/device.rs | 4 +- wgpu-native/src/resource.rs | 1 + wgpu-native/src/track.rs | 16 +++-- 5 files changed, 111 insertions(+), 53 deletions(-) diff --git a/wgpu-native/src/command/render.rs b/wgpu-native/src/command/render.rs index 3ee3f7d1d..88aa3310b 100644 --- a/wgpu-native/src/command/render.rs +++ b/wgpu-native/src/command/render.rs @@ -1,6 +1,6 @@ use conv; use registry::{HUB, Items, Registry}; -use track::{BufferTracker, TextureTracker, Tracktion, TrackPermit}; +use track::{BufferTracker, TextureTracker}; use { Stored, CommandBufferId, RenderPassId, @@ -41,31 +41,40 @@ pub extern "C" fn wgpu_render_pass_end_pass( pass.raw.end_render_pass(); let buffer_guard = HUB.buffers.lock(); - //let texture_guard = HUB.textures.lock(); + let texture_guard = HUB.textures.lock(); let mut cmb_guard = HUB.command_buffers.lock(); let cmb = cmb_guard.get_mut(pass.cmb_id.0); - let cmb_buffers = &mut cmb.buffer_tracker; - let buffer_barriers = pass.buffer_tracker - .finish() - .into_iter() - .flat_map(|(id, new)| { - match cmb_buffers.track(id.0, new, TrackPermit::REPLACE) { - Ok(Tracktion::Init) => None, - Ok(Tracktion::Keep) => None, - Ok(Tracktion::Replace { old }) => Some(hal::memory::Barrier::Buffer { - states: conv::map_buffer_state(old) .. conv::map_buffer_state(new), - target: &buffer_guard.get(id.0).raw, - }), - Ok(Tracktion::Extend { .. }) | - Err(_) => panic!("Unable to do the resource transition for a pass"), + let buffer_barriers = cmb.buffer_tracker + .consume(pass.buffer_tracker) + .map(|(id, transit)| { + let b = buffer_guard.get(id); + hal::memory::Barrier::Buffer { + states: conv::map_buffer_state(transit.start) .. + conv::map_buffer_state(transit.end), + target: &b.raw, + } + }); + let texture_barriers = cmb.texture_tracker + .consume(pass.texture_tracker) + .map(|(id, transit)| { + let t = texture_guard.get(id); + hal::memory::Barrier::Image { + states: conv::map_texture_state(transit.start, t.aspects) .. + conv::map_texture_state(transit.end, t.aspects), + target: &t.raw, + range: hal::image::SubresourceRange { //TODO! + aspects: t.aspects, + levels: 0 .. 1, + layers: 0 .. 1, + }, } }); pass.raw.pipeline_barrier( hal::pso::PipelineStage::TOP_OF_PIPE .. hal::pso::PipelineStage::BOTTOM_OF_PIPE, hal::memory::Dependencies::empty(), - buffer_barriers, + buffer_barriers.chain(texture_barriers), ); cmb.raw.push(pass.raw); diff --git a/wgpu-native/src/conv.rs b/wgpu-native/src/conv.rs index 38818f2f7..c266e1e8f 100644 --- a/wgpu-native/src/conv.rs +++ b/wgpu-native/src/conv.rs @@ -41,6 +41,37 @@ pub fn map_buffer_usage( (hal_usage, hal_memory) } +pub fn map_texture_usage( + usage: resource::TextureUsageFlags, aspects: hal::format::Aspects +) -> hal::image::Usage { + use hal::image::Usage as U; + use resource::TextureUsageFlags as W; + + let mut value = U::empty(); + if usage.contains(W::TRANSFER_SRC) { + value |= U::TRANSFER_SRC; + } + if usage.contains(W::TRANSFER_DST) { + value |= U::TRANSFER_DST; + } + if usage.contains(W::SAMPLED) { + value |= U::SAMPLED; + } + if usage.contains(W::STORAGE) { + value |= U::STORAGE; + } + if usage.contains(W::OUTPUT_ATTACHMENT) { + if aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { + value |= U::DEPTH_STENCIL_ATTACHMENT; + } else { + value |= U::COLOR_ATTACHMENT; + } + } + // Note: TextureUsageFlags::Present does not need to be handled explicitly + // TODO: HAL Transient Attachment, HAL Input Attachment + value +} + pub fn map_binding_type( binding_ty: binding_model::BindingType, ) -> hal::pso::DescriptorType { @@ -261,37 +292,6 @@ pub fn map_texture_dimension_size( } } -pub fn map_texture_usage( - flags: resource::TextureUsageFlags, format: hal::format::Format -) -> hal::image::Usage { - use hal::image::Usage as U; - use resource::TextureUsageFlags as W; - - let mut value = U::empty(); - if flags.contains(W::TRANSFER_SRC) { - value |= U::TRANSFER_SRC; - } - if flags.contains(W::TRANSFER_DST) { - value |= U::TRANSFER_DST; - } - if flags.contains(W::SAMPLED) { - value |= U::SAMPLED; - } - if flags.contains(W::STORAGE) { - value |= U::STORAGE; - } - if flags.contains(W::OUTPUT_ATTACHMENT) { - if format.surface_desc().aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { - value |= U::DEPTH_STENCIL_ATTACHMENT; - } else { - value |= U::COLOR_ATTACHMENT; - } - } - // Note: TextureUsageFlags::Present does not need to be handled explicitly - // TODO: HAL Transient Attachment, HAL Input Attachment - value -} - pub fn map_buffer_state( usage: resource::BufferUsageFlags, ) -> hal::buffer::State { @@ -320,3 +320,41 @@ pub fn map_buffer_state( access } + +pub fn map_texture_state( + usage: resource::TextureUsageFlags, + aspects: hal::format::Aspects, +) -> hal::image::State { + use hal::image::{Access as A, Layout as L}; + use resource::TextureUsageFlags as W; + + let is_color = aspects.contains(hal::format::Aspects::COLOR); + let layout = match usage { + W::TRANSFER_SRC => L::TransferSrcOptimal, + W::TRANSFER_DST => L::TransferDstOptimal, + W::SAMPLED => L::ShaderReadOnlyOptimal, + W::OUTPUT_ATTACHMENT if is_color => L::ColorAttachmentOptimal, + W::OUTPUT_ATTACHMENT => L::DepthStencilAttachmentOptimal, //TODO: read-only depth/stencil + _ => L::General, + }; + + let mut access = A::empty(); + if usage.contains(W::TRANSFER_SRC) { + access |= A::TRANSFER_READ; + } + if usage.contains(W::TRANSFER_DST) { + access |= A::TRANSFER_WRITE; + } + if usage.contains(W::SAMPLED) { + access |= A::SHADER_READ; + } + if usage.contains(W::STORAGE) { + access |= A::SHADER_WRITE; + } + if usage.contains(W::OUTPUT_ATTACHMENT) { + //TODO: read-only attachments + access |= if is_color { A::COLOR_ATTACHMENT_WRITE } else { A::DEPTH_STENCIL_ATTACHMENT_WRITE }; + } + + (access, layout) +} diff --git a/wgpu-native/src/device.rs b/wgpu-native/src/device.rs index fb40e4017..3c7c4e6ad 100644 --- a/wgpu-native/src/device.rs +++ b/wgpu-native/src/device.rs @@ -75,7 +75,8 @@ pub extern "C" fn wgpu_device_create_texture( ) -> TextureId { let kind = conv::map_texture_dimension_size(desc.dimension, desc.size); let format = conv::map_texture_format(desc.format); - let usage = conv::map_texture_usage(desc.usage, format); + let aspects = format.surface_desc().aspects; + let usage = conv::map_texture_usage(desc.usage, aspects); let device_guard = HUB.devices.lock(); let device = &device_guard.get(device_id); let image_unbound = device @@ -112,6 +113,7 @@ pub extern "C" fn wgpu_device_create_texture( .lock() .register(resource::Texture { raw: bound_image, + aspects, }); device.texture_tracker .lock() diff --git a/wgpu-native/src/resource.rs b/wgpu-native/src/resource.rs index 6517e01d1..f91a93a78 100644 --- a/wgpu-native/src/resource.rs +++ b/wgpu-native/src/resource.rs @@ -77,6 +77,7 @@ pub struct TextureDescriptor { pub(crate) struct Texture { pub raw: B::Image, + pub aspects: hal::format::Aspects, } #[repr(C)] diff --git a/wgpu-native/src/track.rs b/wgpu-native/src/track.rs index 4e5b3bb55..752e06116 100644 --- a/wgpu-native/src/track.rs +++ b/wgpu-native/src/track.rs @@ -3,7 +3,7 @@ use resource::{BufferUsageFlags, TextureUsageFlags}; use std::collections::hash_map::{Entry, HashMap}; use std::hash::Hash; -use std::ops::BitOr; +use std::ops::{BitOr, Range}; #[derive(Clone, Debug, PartialEq)] @@ -44,7 +44,7 @@ pub type BufferTracker = Tracker; pub type TextureTracker = Tracker; impl< - I: Hash + Eq, + I: Clone + Hash + Eq, U: Copy + GenericUsage + BitOr + PartialEq, > Tracker { pub fn new() -> Self { @@ -74,7 +74,15 @@ impl< } } - pub(crate) fn finish(self) -> HashMap, U> { - self.map + pub(crate) fn consume<'a>(&'a mut self, other: Self) -> impl 'a + Iterator)> { + other.map + .into_iter() + .flat_map(move |(id, new)| match self.track(id.0.clone(), new, TrackPermit::REPLACE) { + Ok(Tracktion::Init) | + Ok(Tracktion::Keep) => None, + Ok(Tracktion::Replace { old }) => Some((id.0, old .. new)), + Ok(Tracktion::Extend { .. }) | + Err(_) => panic!("Unable to consume a resource transition!"), + }) } } From 32b92afa5c2f846a4b4373dd67bcd0df5e5f98b5 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 22 Oct 2018 10:46:13 -0400 Subject: [PATCH 6/6] Root Makefile --- Cargo.lock | 6 +-- Makefile | 63 ++++++++++++++++++++++++++++++++ examples/hello_triangle_c/main.c | 4 +- wgpu-bindings/Cargo.toml | 2 +- wgpu-bindings/src/main.rs | 9 +++-- wgpu-bindings/wgpu.h | 42 ++++++++++++++------- wgpu-native/src/resource.rs | 3 +- 7 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 Makefile diff --git a/Cargo.lock b/Cargo.lock index 61de9c0b3..bfb3cbad4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,7 +82,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cbindgen" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1033,7 +1033,7 @@ dependencies = [ name = "wgpu-bindings" version = "0.1.0" dependencies = [ - "cbindgen 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cbindgen 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1139,7 +1139,7 @@ dependencies = [ "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" -"checksum cbindgen 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "33dfad88cda0bab90ef91c4ae338f132ba6934ea59b6e352eb96f558b5a879d7" +"checksum cbindgen 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "660a462ad3acdc79f83dcc84161d9e87f01cb29754b7ab5196785e1f0c11f714" "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..d5d3ab0db --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +RUST_BACKTRACE:=1 +EXCLUDES:= +FEATURE_RUST:= +FEATURE_NATIVE:= + +ifeq (,$(TARGET)) + CHECK_TARGET_FLAG= +else + CHECK_TARGET_FLAG=--target $(TARGET) +endif + +ifeq ($(OS),Windows_NT) + ifeq ($(TARGET),x86_64-pc-windows-gnu) + FEATURE_RUST=vulkan + FEATURE_NATIVE=gfx-backend-vulkan + else + FEATURE_RUST=dx12 + FEATURE_NATIVE=gfx-backend-dx12 + endif +else + UNAME_S:=$(shell uname -s) + ifeq ($(UNAME_S),Linux) + FEATURE_RUST=vulkan + FEATURE_NATIVE=gfx-backend-vulkan + endif + ifeq ($(UNAME_S),Darwin) + FEATURE_RUST=metal + FEATURE_NATIVE=gfx-backend-metal + endif +endif + + +.PHONY: all check test doc clear lib-native lib-rust examples-native examples-rust + +all: examples-native examples-rust + +check: + cargo check --all + +test: + cargo test --all --features "$(FEATURE_NATIVE) $(FEATURE_RUST)" + +doc: + cargo doc --all + +clear: + cargo clear + rm wgpu-bindings/wgpu.h + +lib-native: Cargo.lock wgpu-native/Cargo.toml $(wildcard wgpu-native/**/*.rs) + cargo build --manifest-path wgpu-native/Cargo.toml --features $(FEATURE_NATIVE) + +lib-rust: Cargo.lock wgpu-rs/Cargo.toml $(wildcard wgpu-rs/**/*.rs) + cargo build --manifest-path wgpu-rs/Cargo.toml --features $(FEATURE_RUST) + +wgpu-bindings/wgpu.h: Cargo.lock wgpu-bindings/src/*.rs lib-native + cargo +nightly run --manifest-path wgpu-bindings/Cargo.toml + +examples-native: lib-native wgpu-bindings/wgpu.h $(wildcard wgpu-native/**/*.c) + $(MAKE) -C examples + +examples-rust: lib-rust examples/Cargo.toml $(wildcard wgpu-native/**/*.rs) + cargo build --manifest-path examples/Cargo.toml --bin hello_triangle --features $(FEATURE_RUST) diff --git a/examples/hello_triangle_c/main.c b/examples/hello_triangle_c/main.c index 6b9f534c7..1765fdcf6 100644 --- a/examples/hello_triangle_c/main.c +++ b/examples/hello_triangle_c/main.c @@ -40,7 +40,7 @@ int main() .bindings_length = 0, }; WGPUBindGroupLayoutId _bind_group_layout = wgpu_device_create_bind_group_layout(device, &bind_group_layout_desc); - + WGPUPipelineLayoutDescriptor pipeline_layout_desc = { .bind_group_layouts = NULL, .bind_group_layouts_length = 0, @@ -116,7 +116,7 @@ int main() .formats_length = FORMATS_LENGTH, }; WGPUAttachmentStateId attachment_state = wgpu_device_create_attachment_state(device, &attachment_state_desc); - + WGPURenderPipelineDescriptor render_pipeline_desc = { .layout = layout, .stages = stages, diff --git a/wgpu-bindings/Cargo.toml b/wgpu-bindings/Cargo.toml index 7ab66cfdb..a2eb27916 100644 --- a/wgpu-bindings/Cargo.toml +++ b/wgpu-bindings/Cargo.toml @@ -10,4 +10,4 @@ authors = [ default = [] [dependencies] -cbindgen = "0.6.3" +cbindgen = "0.6.6" diff --git a/wgpu-bindings/src/main.rs b/wgpu-bindings/src/main.rs index 42a5d402f..02f719a07 100644 --- a/wgpu-bindings/src/main.rs +++ b/wgpu-bindings/src/main.rs @@ -11,8 +11,8 @@ const HEADER: &str = " "; fn main() { - let mut crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - crate_dir.push("../wgpu-native"); + let crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let source_dir = crate_dir.parent().unwrap().join("wgpu-native"); let config = cbindgen::Config { header: Some(String::from(HEADER.trim())), @@ -33,9 +33,10 @@ fn main() { }; cbindgen::Builder::new() - .with_crate(crate_dir) + .with_crate(source_dir) .with_config(config) + .with_parse_expand(&["wgpu-native"]) .generate() .unwrap() - .write_to_file("wgpu.h"); + .write_to_file(crate_dir.join("wgpu.h")); } diff --git a/wgpu-bindings/wgpu.h b/wgpu-bindings/wgpu.h index 11fc5b373..bfa5e1530 100644 --- a/wgpu-bindings/wgpu.h +++ b/wgpu-bindings/wgpu.h @@ -28,20 +28,6 @@ #define WGPUShaderStageFlags_VERTEX 1 -#define WGPUTextureUsageFlags_NONE 0 - -#define WGPUTextureUsageFlags_OUTPUT_ATTACHMENT 16 - -#define WGPUTextureUsageFlags_PRESENT 32 - -#define WGPUTextureUsageFlags_SAMPLED 4 - -#define WGPUTextureUsageFlags_STORAGE 8 - -#define WGPUTextureUsageFlags_TRANSFER_DST 2 - -#define WGPUTextureUsageFlags_TRANSFER_SRC 1 - typedef enum { WGPUBindingType_UniformBuffer = 0, WGPUBindingType_Sampler = 1, @@ -276,12 +262,40 @@ typedef struct { #define WGPUBLUE (Color){ .r = 0, .g = 0, .b = 1, .a = 1 } +#define WGPUEXTEND (TrackPermit){ .bits = 1 } + #define WGPUGREEN (Color){ .r = 0, .g = 1, .b = 0, .a = 1 } +#define WGPUINDEX (BufferUsageFlags){ .bits = 16 } + +#define WGPUMAP_READ (BufferUsageFlags){ .bits = 1 } + +#define WGPUMAP_WRITE (BufferUsageFlags){ .bits = 2 } + +#define WGPUNONE (BufferUsageFlags){ .bits = 0 } + +#define WGPUOUTPUT_ATTACHMENT (TextureUsageFlags){ .bits = 16 } + +#define WGPUPRESENT (TextureUsageFlags){ .bits = 32 } + #define WGPURED (Color){ .r = 1, .g = 0, .b = 0, .a = 1 } +#define WGPUREPLACE (TrackPermit){ .bits = 2 } + +#define WGPUSAMPLED (TextureUsageFlags){ .bits = 4 } + +#define WGPUSTORAGE (BufferUsageFlags){ .bits = 128 } + +#define WGPUTRANSFER_DST (BufferUsageFlags){ .bits = 8 } + +#define WGPUTRANSFER_SRC (BufferUsageFlags){ .bits = 4 } + #define WGPUTRANSPARENT (Color){ .r = 0, .g = 0, .b = 0, .a = 0 } +#define WGPUUNIFORM (BufferUsageFlags){ .bits = 64 } + +#define WGPUVERTEX (BufferUsageFlags){ .bits = 32 } + #define WGPUWHITE (Color){ .r = 1, .g = 1, .b = 1, .a = 1 } WGPUDeviceId wgpu_adapter_create_device(WGPUAdapterId adapter_id, diff --git a/wgpu-native/src/resource.rs b/wgpu-native/src/resource.rs index f91a93a78..14df48e7a 100644 --- a/wgpu-native/src/resource.rs +++ b/wgpu-native/src/resource.rs @@ -26,7 +26,8 @@ pub struct BufferDescriptor { } pub(crate) struct Buffer { - pub raw: B::UnboundBuffer, + //pub raw: B::UnboundBuffer, + pub raw: B::Buffer, pub memory_properties: hal::memory::Properties, // TODO: mapping, unmap() }