diff --git a/wgpu-native/src/track.rs b/wgpu-native/src/track.rs index 83c167f488..89395bacbf 100644 --- a/wgpu-native/src/track.rs +++ b/wgpu-native/src/track.rs @@ -18,10 +18,13 @@ use hal::backend::FastHashMap; use std::{ borrow::Borrow, + cmp::Ordering, collections::hash_map::{Entry, Iter}, + iter::Peekable, marker::PhantomData, mem, ops::{BitOr, Range}, + slice, vec::Drain, }; @@ -91,7 +94,7 @@ impl GenericUsage for DummyUsage { } /// A single unit of state tracking. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Unit { init: U, last: U, @@ -551,7 +554,7 @@ impl ResourceTracker { /// Merge another tacker into `self` by extending the current states /// without any transitions. pub fn merge_extend( - &mut self, other: &Self + &mut self, other: &Self, ) -> Result<(), PendingTransition> { for (&index, new) in other.map.iter() { match self.map.entry(index) { @@ -696,7 +699,7 @@ impl Default for RangedStates { } } -impl RangedStates { +impl RangedStates { fn isolate(&mut self, index: &Range, default: T) -> &mut [(Range, T)] { let start_pos = match self.ranges .iter() @@ -741,11 +744,99 @@ impl RangedStates { &mut self.ranges[start_pos .. pos] } + + fn coalesce(&mut self) { + let mut num_removed = 0; + let mut iter = self.ranges.iter_mut(); + let mut cur = match iter.next() { + Some(elem) => elem, + None => return, + }; + while let Some(next) = iter.next() { + if cur.0.end == next.0.start && cur.1 == next.1 { + num_removed += 1; + cur.0.end = next.0.end; + next.0.end = next.0.start; + } else { + cur = next; + } + } + if num_removed != 0 { + self.ranges.retain(|pair| pair.0.start != pair.0.end); + } + } +} + +struct Merge<'a, I, T> { + base: I, + sa: Peekable, T)>>, + sb: Peekable, T)>>, +} + +impl<'a, I: Copy + Ord, T: Copy> Iterator for Merge<'a, I, T> { + type Item = (Range, Range); + fn next(&mut self) -> Option { + match (self.sa.peek(), self.sb.peek()) { + // we have both streams + (Some(&(ref ra, va)), Some(&(ref rb, vb))) => { + let (range, usage) = if ra.start < self.base { // in the middle of the left stream + if self.base == rb.start { // right stream is starting + debug_assert!(self.base < ra.end); + (self.base .. ra.end.min(rb.end), *va .. *vb) + } else { // right hasn't started yet + debug_assert!(self.base < rb.start); + (self.base .. rb.start, *va .. *va) + } + } else if rb.start < self.base { // in the middle of the right stream + if self.base == ra.start { // left stream is starting + debug_assert!(self.base < rb.end); + (self.base .. ra.end.min(rb.end), *va .. *vb) + } else { // left hasn't started yet + debug_assert!(self.base < ra.start); + (self.base .. ra.start, *vb .. *vb) + } + } else { // no active streams + match ra.start.cmp(&rb.start) { + // both are starting + Ordering::Equal => (ra.start .. ra.end.min(rb.end), *va .. *vb), + // only left is starting + Ordering::Less => (ra.start .. rb.start, *va .. *va), + // only right is starting + Ordering::Greater => (rb.start .. ra.start, *vb .. *vb), + } + }; + self.base = range.end; + if ra.end == range.end { + let _ = self.sa.next(); + } + if rb.end == range.end { + let _ = self.sb.next(); + } + Some((range, usage)) + } + // only right stream + (None, Some(&(ref rb, vb))) => { + let range = self.base.max(rb.start) .. rb.end; + self.base = rb.end; + let _ = self.sb.next(); + Some((range, *vb .. *vb)) + } + // only left stream + (Some(&(ref ra, va)), None) => { + let range = self.base.max(ra.start) .. ra.end; + self.base = ra.end; + let _ = self.sa.next(); + Some((range, *va .. *va)) + } + // done + (None, None) => None, + } + } } type PlaneStates = RangedStates; -#[derive(Clone)] +#[derive(Clone, Copy, PartialEq)] struct DepthStencilState { depth: Unit, stencil: Unit, @@ -848,18 +939,161 @@ impl ResourceState for TextureStates { } } if selector.aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { - unimplemented!() //TODO + for level in selector.levels.clone() { + let ds_state = DepthStencilState { + depth: Unit::new(usage), + stencil: Unit::new(usage), + }; + for &mut (ref range, ref mut unit) in self.depth_stencil + .isolate(&selector.layers, ds_state) + { + //TODO: check if anything needs to be done when only one of the depth/stencil + // is selected? + if unit.depth.last != usage && selector.aspects.contains(hal::format::Aspects::DEPTH) { + let old = unit.depth.last; + let pending = PendingTransition { + id, + selector: hal::image::SubresourceRange { + aspects: hal::format::Aspects::DEPTH, + levels: level .. level + 1, + layers: range.clone(), + }, + usage: old .. usage, + }; + unit.depth.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 unit.stencil.last != usage && selector.aspects.contains(hal::format::Aspects::STENCIL) { + let old = unit.stencil.last; + let pending = PendingTransition { + id, + selector: hal::image::SubresourceRange { + aspects: hal::format::Aspects::STENCIL, + levels: level .. level + 1, + layers: range.clone(), + }, + usage: old .. usage, + }; + unit.stencil.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 + } + }; + } + } + } } Ok(()) } fn merge( &mut self, - _id: Self::Id, - _other: &Self, - _stitch: Stitch, - _output: Option<&mut Vec>>, + id: Self::Id, + other: &Self, + stitch: Stitch, + mut output: Option<&mut Vec>>, ) -> Result<(), PendingTransition> { + let mut temp_color = Vec::new(); + while self.color_mips.len() < other.color_mips.len() { + self.color_mips.push(PlaneStates::default()); + } + for (mip_id, (mip_self, mip_other)) in self.color_mips + .iter_mut() + .zip(&other.color_mips) + .enumerate() + { + temp_color.extend(Merge { + base: 0, + sa: mip_self.ranges.iter().peekable(), + sb: mip_other.ranges.iter().peekable(), + }); + mip_self.ranges.clear(); + for (layers, states) in temp_color.drain(..) { + let color_usage = states.start.last .. states.end.select(stitch); + if let Some(out) = output.as_mut() { + if color_usage.start != color_usage.end { + let level = mip_id as hal::image::Level; + out.push(PendingTransition { + id, + selector: hal::image::SubresourceRange { + aspects: hal::format::Aspects::COLOR, + levels: level .. level + 1, + layers: layers.clone(), + }, + usage: color_usage.clone(), + }); + } + } + mip_self.ranges.push((layers, Unit { + init: states.start.init, + last: color_usage.end, + })); + } + } + + let mut temp_ds = Vec::new(); + temp_ds.extend(Merge { + base: 0, + sa: self.depth_stencil.ranges.iter().peekable(), + sb: other.depth_stencil.ranges.iter().peekable(), + }); + self.depth_stencil.ranges.clear(); + for (layers, states) in temp_ds.drain(..) { + let usage_depth = states.start.depth.last .. states.end.depth.select(stitch); + let usage_stencil = states.start.stencil.last .. states.end.stencil.select(stitch); + if let Some(out) = output.as_mut() { + if usage_depth.start != usage_depth.end { + out.push(PendingTransition { + id, + selector: hal::image::SubresourceRange { + aspects: hal::format::Aspects::DEPTH, + levels: 0 .. 1, + layers: layers.clone(), + }, + usage: usage_depth.clone(), + }); + } + if usage_stencil.start != usage_stencil.end { + out.push(PendingTransition { + id, + selector: hal::image::SubresourceRange { + aspects: hal::format::Aspects::STENCIL, + levels: 0 .. 1, + layers: layers.clone(), + }, + usage: usage_stencil.clone(), + }); + } + } + self.depth_stencil.ranges.push((layers, DepthStencilState { + depth: Unit { + init: states.start.depth.init, + last: usage_depth.end, + }, + stencil: Unit { + init: states.start.stencil.init, + last: usage_stencil.end, + }, + })); + } + Ok(()) } }