From 444220c6eb53aa5f703cec14d5326d08bf050cc6 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sun, 9 Jun 2019 00:00:17 -0400 Subject: [PATCH] Another iteration of internal tracking --- wgpu-native/src/track.rs | 626 ++++++++++++++++++++++++++++++++------- 1 file changed, 516 insertions(+), 110 deletions(-) diff --git a/wgpu-native/src/track.rs b/wgpu-native/src/track.rs index 226d55b90f..83c167f488 100644 --- a/wgpu-native/src/track.rs +++ b/wgpu-native/src/track.rs @@ -22,107 +22,9 @@ use std::{ marker::PhantomData, mem, ops::{BitOr, Range}, + vec::Drain, }; -#[derive(Clone, Debug)] -pub struct RangedStates { - ranges: Vec<(Range, T)>, -} - -pub type TextureLayerStates = RangedStates; -pub type TextureStates2 = RangedStates; - -impl RangedStates { - fn isolate(&mut self, index: Range) -> &mut T { - let mut pos = self.ranges - .iter() - .position(|&(ref range, _)| index.start >= range.start) - .unwrap(); - let base_range = self.ranges[pos].0.clone(); - assert!(index.end <= base_range.end); - if base_range.start < index.start { - let value = ((base_range.start .. index.start), self.ranges[pos].1.clone()); - self.ranges.insert(pos, value); - pos += 1; - self.ranges[pos].0.start = index.start; - } - if base_range.end > index.end { - let value = ((index.end .. base_range.end), self.ranges[pos].1.clone()); - self.ranges.insert(pos + 1, value); - self.ranges[pos].0.end = index.end; - } - &mut self.ranges[pos].1 - } -} - -impl TextureStates2 { - fn change_state( - &mut self, level: hal::image::Level, layer: hal::image::Layer, usage: TextureUsage - ) -> Option { - let layer_states = self.isolate(level .. level + 1); - let cur_usage = layer_states.isolate(layer .. layer + 1); - if *cur_usage != usage { - Some(mem::replace(cur_usage, usage)) - } else { - None - } - } -} - - -pub enum PlaneStates { - Single(T), - Multi(Vec<(Range, T)>), -} - -impl Default for PlaneStates { - fn default() -> Self { - PlaneStates::Multi(Vec::new()) - } -} - -pub struct DepthStencilState { - depth: TextureUsage, - stencil: TextureUsage, -} - -pub struct TextureStates { - color_mips: ArrayVec<[PlaneStates; MAX_MIP_LEVELS]>, - depth_stencil: PlaneStates, -} - -impl TextureStates { - fn change<'a>( - &mut self, - what: hal::image::SubresourceRange, - usage: TextureUsage, - permit: TrackPermit, - fun: impl FnMut(hal::image::SubresourceRange, Tracktion), - ) { - /*if what.aspects.contains(hal::format::Aspects::COLOR) { - for level in what.levels.clone() { - match self.color_mips[level as usize] { - PlaneStates::Single(ref mut cur_usage) => { - assert_eq!(what.layers, 0 .. 1); - if *cur_usage != usage { - let sub = hal::image::SubresourceRange { - aspects: hal::format::Aspects::COLOR, - levels: level .. level + 1, - layers: 0 .. 1, - }; - fun(sub, *cur_usage); - *cur_usage = usage; - } - } - PlaneStates::Multi(ref mut layers) => { - let pos = - } - } - } - }*/ - } -} - #[derive(Clone, Debug, PartialEq)] #[allow(unused)] @@ -189,7 +91,7 @@ impl GenericUsage for DummyUsage { } /// A single unit of state tracking. -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct Unit { init: U, last: U, @@ -228,14 +130,7 @@ impl + PartialEq + GenericUsage> Unit { } } -#[derive(Clone, Debug)] -struct Resource { - ref_count: RefCount, - state: S, - epoch: Epoch, -} - -//TODO: consider having `I` as an associated type of `U`? +//TODO: consider having `I` as an associated type of `S`? #[derive(Debug)] pub struct Tracker { /// An association of known resource indices with their tracked states. @@ -300,7 +195,7 @@ impl Tracker { } /// Remove an id from the tracked map. - pub(crate) fn remove(&mut self, id: I) -> bool { + pub fn remove(&mut self, id: I) -> bool { match self.map.remove(&id.index()) { Some(resource) => { assert_eq!(resource.epoch, id.epoch()); @@ -455,7 +350,6 @@ impl + PartialEq> } } - pub type BufferTracker = Tracker>; pub type TextureTracker = Tracker>; pub type TextureViewTracker = Tracker>; @@ -494,3 +388,515 @@ impl TrackerSet { self.bind_groups.consume_by_extend(&other.bind_groups).unwrap(); } } + + +pub trait ResourceState: Clone + Default { + type Id: Copy + TypedId; + type Selector; + type Usage; + + fn query( + &self, + selector: Self::Selector, + ) -> Option; + + fn change( + &mut self, + id: Self::Id, + selector: Self::Selector, + usage: Self::Usage, + output: Option<&mut Vec>>, + ) -> Result<(), PendingTransition>; + + fn merge( + &mut self, + id: Self::Id, + other: &Self, + stitch: Stitch, + output: Option<&mut Vec>>, + ) -> Result<(), PendingTransition>; +} + +#[derive(Clone, Debug)] +struct Resource { + ref_count: RefCount, + state: S, + epoch: Epoch, +} + +pub struct PendingTransition { + pub id: S::Id, + pub selector: S::Selector, + pub usage: Range, +} + +struct ResourceTracker { + /// An association of known resource indices with their tracked states. + map: FastHashMap>, + /// Temporary storage for collecting transitions. + temp: Vec>, +} + +impl ResourceTracker { + pub fn new() -> Self { + ResourceTracker { + map: FastHashMap::default(), + temp: Vec::new(), + } + } + + /// Remove an id from the tracked map. + pub fn remove(&mut self, id: S::Id) -> bool { + match self.map.remove(&id.index()) { + Some(resource) => { + assert_eq!(resource.epoch, id.epoch()); + true + } + None => false, + } + } + + /// Return an iterator over used resources keys. + pub fn used<'a>(&'a self) -> impl 'a + Iterator { + self.map + .iter() + .map(|(&index, resource)| S::Id::new(index, resource.epoch)) + } + + fn clear(&mut self) { + self.map.clear(); + } + + /// Initialize a resource to be used. + pub fn init( + &mut self, + id: S::Id, + ref_count: &RefCount, + selector: S::Selector, + default: S::Usage, + ) -> bool { + let mut state = S::default(); + let _ = state.change( + id, + selector, + default, + None, + ); + self.map + .insert(id.index(), Resource { + ref_count: ref_count.clone(), + state, + epoch: id.epoch(), + }) + .is_none() + } + + /// Query a resource selector. Returns `Some(Usage)` only if + /// this usage is consistent across the given selector. + pub fn query( + &mut self, + id: S::Id, + selector: S::Selector, + ) -> Option { + let res = self.map.get(&id.index())?; + assert_eq!(res.epoch, id.epoch()); + res.state.query(selector) + } + + fn grab<'a>( + map: &'a mut FastHashMap>, + id: S::Id, + ref_count: &RefCount, + ) -> &'a mut Resource { + match map.entry(id.index()) { + Entry::Vacant(e) => { + e.insert(Resource { + ref_count: ref_count.clone(), + state: S::default(), + epoch: id.epoch(), + }) + } + Entry::Occupied(e) => { + assert_eq!(e.get().epoch, id.epoch()); + e.into_mut() + } + } + } + + /// Extend the usage of a specified resource. + pub fn change_extend( + &mut self, + id: S::Id, + ref_count: &RefCount, + selector: S::Selector, + usage: S::Usage, + ) -> Result<(), PendingTransition> { + Self::grab(&mut self.map, id, ref_count) + .state.change(id, selector, usage, None) + } + + /// Replace the usage of a specified resource. + pub fn change_replace( + &mut self, + id: S::Id, + ref_count: &RefCount, + selector: S::Selector, + usage: S::Usage, + ) -> Result>, PendingTransition> { + let res = Self::grab(&mut self.map, id, ref_count); + res.state.change(id, selector, usage, Some(&mut self.temp))?; + Ok(self.temp.drain(..)) + } + + /// Merge another tacker into `self` by extending the current states + /// without any transitions. + pub fn merge_extend( + &mut self, other: &Self + ) -> Result<(), PendingTransition> { + for (&index, new) in other.map.iter() { + match self.map.entry(index) { + Entry::Vacant(e) => { + e.insert(new.clone()); + } + Entry::Occupied(e) => { + assert_eq!(e.get().epoch, new.epoch); + let id = S::Id::new(index, new.epoch); + e.into_mut().state.merge(id, &new.state, Stitch::Last, None)?; + } + } + } + Ok(()) + } + + /// Merge another tacker, adding it's transitions to `self`. + /// Transitions the current usage to the new one. + pub fn merge_replace<'a>( + &'a mut self, + other: &'a Self, + stitch: Stitch, + ) -> Result>, PendingTransition> { + for (&index, new) in other.map.iter() { + match self.map.entry(index) { + Entry::Vacant(e) => { + e.insert(new.clone()); + } + Entry::Occupied(e) => { + assert_eq!(e.get().epoch, new.epoch); + let id = S::Id::new(index, new.epoch); + e.into_mut().state.merge(id, &new.state, stitch, Some(&mut self.temp))?; + } + } + } + Ok(self.temp.drain(..)) + } + + pub fn use_extend<'a, T: 'a + Borrow>( + &mut self, + storage: &'a Storage, + id: S::Id, + selector: S::Selector, + usage: S::Usage, + ) -> Result<&'a T, S::Usage> { + let item = &storage[id]; + self.change_extend(id, item.borrow(), selector, usage) + .map(|()| item) + .map_err(|pending| pending.usage.start) + } + + pub fn use_replace<'a, T: 'a + Borrow>( + &mut self, + storage: &'a Storage, + id: S::Id, + selector: S::Selector, + usage: S::Usage, + ) -> Result<(&'a T, Drain>), S::Usage> { + let item = &storage[id]; + self.change_replace(id, item.borrow(), selector, usage) + .map(|drain| (item, drain)) + .map_err(|pending| pending.usage.start) + } +} + +pub type BufferState = Unit; + +impl Default for BufferState { + fn default() -> Self { + BufferState { + init: BufferUsage::empty(), + last: BufferUsage::empty(), + } + } +} + +impl ResourceState for BufferState { + type Id = BufferId; + type Selector = (); + type Usage = BufferUsage; + + fn query( + &self, + _selector: Self::Selector, + ) -> Option { + Some(self.last) + } + + fn change( + &mut self, + id: Self::Id, + _selector: Self::Selector, + usage: Self::Usage, + output: Option<&mut Vec>>, + ) -> Result<(), PendingTransition> { + let old = self.last; + if usage != old { + let pending = PendingTransition { + id, + selector: (), + usage: old .. usage, + }; + self.last = match output { + Some(transitions) => { + transitions.push(pending); + usage + } + None => { + if !old.is_empty() && BufferUsage::WRITE_ALL.intersects(old | usage) { + return Err(pending); + } + old | usage + } + }; + } + Ok(()) + } + + fn merge( + &mut self, + id: Self::Id, + other: &Self, + stitch: Stitch, + output: Option<&mut Vec>>, + ) -> Result<(), PendingTransition> { + let usage = other.select(stitch); + self.change(id, (), usage, output) + } +} + + +#[derive(Clone, Debug)] +pub struct RangedStates { + ranges: Vec<(Range, T)>, +} + +impl Default for RangedStates { + fn default() -> Self { + RangedStates { + ranges: Vec::new(), + } + } +} + +impl RangedStates { + fn isolate(&mut self, index: &Range, default: T) -> &mut [(Range, T)] { + let start_pos = match self.ranges + .iter() + .position(|pair| pair.0.end > index.start) + { + Some(pos) => pos, + None => { + let pos = self.ranges.len(); + self.ranges.push((index.clone(), default)); + return &mut self.ranges[pos ..]; + } + }; + + let mut pos = start_pos; + let mut range_pos = index.start; + loop { + let (range, unit) = self.ranges[pos].clone(); + if range.start >= index.end { + self.ranges.insert(pos, (range_pos .. index.end, default)); + pos += 1; + break; + } + if range.start > range_pos { + self.ranges.insert(pos, (range_pos .. range.start, default)); + pos += 1; + range_pos = range.start; + } + if range.end >= index.end { + self.ranges[pos].0.start = index.end; + self.ranges.insert(pos, (range_pos .. index.end, unit)); + pos += 1; + break; + } + pos += 1; + range_pos = range.end; + if pos == self.ranges.len() { + self.ranges.push((range_pos .. index.end, default)); + pos += 1; + break; + } + } + + &mut self.ranges[start_pos .. pos] + } +} + +type PlaneStates = RangedStates; + +#[derive(Clone)] +struct DepthStencilState { + depth: Unit, + stencil: Unit, +} + +#[derive(Clone, Default)] +struct TextureStates { + color_mips: ArrayVec<[PlaneStates>; MAX_MIP_LEVELS]>, + depth_stencil: PlaneStates, +} + +impl ResourceState for TextureStates { + type Id = TextureId; + type Selector = hal::image::SubresourceRange; + type Usage = TextureUsage; + + fn query( + &self, + selector: Self::Selector, + ) -> Option { + let mut usage = None; + if selector.aspects.contains(hal::format::Aspects::COLOR) { + let num_levels = self.color_mips.len(); + let layer_start = num_levels.min(selector.levels.start as usize); + let layer_end = num_levels.min(selector.levels.end as usize); + for layer in self.color_mips[layer_start .. layer_end].iter() { + for &(ref range, ref unit) in layer.ranges.iter() { + if range.end > selector.layers.start && range.start < selector.layers.end { + let old = usage.replace(unit.last); + if old.is_some() && old != usage { + return None + } + } + } + } + } + if selector.aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { + for &(ref range, ref ds) in self.depth_stencil.ranges.iter() { + if range.end > selector.layers.start && range.start < selector.layers.end { + if selector.aspects.contains(hal::format::Aspects::DEPTH) { + let old = usage.replace(ds.depth.last); + if old.is_some() && old != usage { + return None + } + } + if selector.aspects.contains(hal::format::Aspects::STENCIL) { + let old = usage.replace(ds.stencil.last); + if old.is_some() && old != usage { + return None + } + } + } + } + } + usage + } + + fn change( + &mut self, + id: Self::Id, + selector: Self::Selector, + usage: Self::Usage, + mut output: Option<&mut Vec>>, + ) -> Result<(), PendingTransition> { + if selector.aspects.contains(hal::format::Aspects::COLOR) { + while self.color_mips.len() < selector.levels.end as usize { + self.color_mips.push(PlaneStates::default()); + } + for level in selector.levels.clone() { + let layers = self + .color_mips[level as usize] + .isolate(&selector.layers, Unit::new(usage)); + for &mut (ref range, ref mut unit) in layers { + let old = unit.last; + if old == usage { + continue + } + let pending = PendingTransition { + id, + selector: hal::image::SubresourceRange { + aspects: hal::format::Aspects::COLOR, + levels: level .. level + 1, + layers: range.clone(), + }, + usage: old .. usage, + }; + unit.last = match output.as_mut() { + Some(out) => { + out.push(pending); + usage + } + None => { + if !old.is_empty() && TextureUsage::WRITE_ALL.intersects(old | usage) { + return Err(pending); + } + old | usage + } + }; + } + } + } + if selector.aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { + unimplemented!() //TODO + } + Ok(()) + } + + fn merge( + &mut self, + _id: Self::Id, + _other: &Self, + _stitch: Stitch, + _output: Option<&mut Vec>>, + ) -> Result<(), PendingTransition> { + Ok(()) + } +} + + +#[derive(Clone, Debug, Default)] +pub struct TextureViewState; + +impl ResourceState for TextureViewState { + type Id = TextureViewId; + type Selector = (); + type Usage = (); + + fn query( + &self, + _selector: Self::Selector, + ) -> Option { + Some(()) + } + + fn change( + &mut self, + _id: Self::Id, + _selector: Self::Selector, + _usage: Self::Usage, + _output: Option<&mut Vec>>, + ) -> Result<(), PendingTransition> { + Ok(()) + } + + fn merge( + &mut self, + _id: Self::Id, + _other: &Self, + _stitch: Stitch, + _output: Option<&mut Vec>>, + ) -> Result<(), PendingTransition> { + Ok(()) + } +}