Improve texture state merging

This commit is contained in:
Dzmitry Malyshau 2019-06-13 23:11:09 -04:00
parent ef1c373887
commit 7c647a7d3c
2 changed files with 115 additions and 91 deletions

View File

@ -179,7 +179,7 @@ pub struct Merge<'a, I, T> {
} }
impl<'a, I: Copy + Debug + Ord, T: Copy + Debug> Iterator for Merge<'a, I, T> { impl<'a, I: Copy + Debug + Ord, T: Copy + Debug> Iterator for Merge<'a, I, T> {
type Item = (Range<I>, Range<T>); type Item = (Range<I>, Range<Option<T>>);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
match (self.sa.peek(), self.sb.peek()) { match (self.sa.peek(), self.sb.peek()) {
// we have both streams // we have both streams
@ -187,27 +187,27 @@ impl<'a, I: Copy + Debug + Ord, T: Copy + Debug> Iterator for Merge<'a, I, T> {
let (range, usage) = if ra.start < self.base { // in the middle of the left stream let (range, usage) = if ra.start < self.base { // in the middle of the left stream
if self.base == rb.start { // right stream is starting if self.base == rb.start { // right stream is starting
debug_assert!(self.base < ra.end); debug_assert!(self.base < ra.end);
(self.base .. ra.end.min(rb.end), *va .. *vb) (self.base .. ra.end.min(rb.end), Some(*va) .. Some(*vb))
} else { // right hasn't started yet } else { // right hasn't started yet
debug_assert!(self.base < rb.start); debug_assert!(self.base < rb.start);
(self.base .. rb.start, *va .. *va) (self.base .. rb.start, Some(*va) .. None)
} }
} else if rb.start < self.base { // in the middle of the right stream } else if rb.start < self.base { // in the middle of the right stream
if self.base == ra.start { // left stream is starting if self.base == ra.start { // left stream is starting
debug_assert!(self.base < rb.end); debug_assert!(self.base < rb.end);
(self.base .. ra.end.min(rb.end), *va .. *vb) (self.base .. ra.end.min(rb.end), Some(*va) .. Some(*vb))
} else { // left hasn't started yet } else { // left hasn't started yet
debug_assert!(self.base < ra.start); debug_assert!(self.base < ra.start);
(self.base .. ra.start, *vb .. *vb) (self.base .. ra.start, None .. Some(*vb))
} }
} else { // no active streams } else { // no active streams
match ra.start.cmp(&rb.start) { match ra.start.cmp(&rb.start) {
// both are starting // both are starting
Ordering::Equal => (ra.start .. ra.end.min(rb.end), *va .. *vb), Ordering::Equal => (ra.start .. ra.end.min(rb.end), Some(*va) .. Some(*vb)),
// only left is starting // only left is starting
Ordering::Less => (ra.start .. rb.start.min(ra.end), *va .. *va), Ordering::Less => (ra.start .. rb.start.min(ra.end), Some(*va) .. None),
// only right is starting // only right is starting
Ordering::Greater => (rb.start .. ra.start.min(rb.end), *vb .. *vb), Ordering::Greater => (rb.start .. ra.start.min(rb.end), None .. Some(*vb)),
} }
}; };
self.base = range.end; self.base = range.end;
@ -224,14 +224,14 @@ impl<'a, I: Copy + Debug + Ord, T: Copy + Debug> Iterator for Merge<'a, I, T> {
let range = self.base.max(rb.start) .. rb.end; let range = self.base.max(rb.start) .. rb.end;
self.base = rb.end; self.base = rb.end;
let _ = self.sb.next(); let _ = self.sb.next();
Some((range, *vb .. *vb)) Some((range, None .. Some(*vb)))
} }
// only left stream // only left stream
(Some(&(ref ra, va)), None) => { (Some(&(ref ra, va)), None) => {
let range = self.base.max(ra.start) .. ra.end; let range = self.base.max(ra.start) .. ra.end;
self.base = ra.end; self.base = ra.end;
let _ = self.sa.next(); let _ = self.sa.next();
Some((range, *va .. *va)) Some((range, Some(*va) .. None))
} }
// done // done
(None, None) => None, (None, None) => None,
@ -247,7 +247,7 @@ mod test {
fn easy_merge<T: PartialEq + Copy + Debug>( fn easy_merge<T: PartialEq + Copy + Debug>(
ra: Vec<(Range<usize>, T)>, rb: Vec<(Range<usize>, T)> ra: Vec<(Range<usize>, T)>, rb: Vec<(Range<usize>, T)>
) -> Vec<(Range<usize>, Range<T>)> { ) -> Vec<(Range<usize>, Range<Option<T>>)> {
RangedStates { ranges: ra }.merge(&RangedStates { ranges: rb }, 0).collect() RangedStates { ranges: ra }.merge(&RangedStates { ranges: rb }, 0).collect()
} }
@ -337,7 +337,7 @@ mod test {
], ],
), ),
vec![ vec![
(1..4, 0..2), (1..4, Some(0)..Some(2)),
] ]
); );
} }
@ -353,7 +353,7 @@ mod test {
], ],
), ),
vec![ vec![
(1..2, 0..0), (1..2, Some(0)..None),
] ]
); );
assert_eq!( assert_eq!(
@ -365,7 +365,7 @@ mod test {
], ],
), ),
vec![ vec![
(3..4, 1..1), (3..4, None..Some(1)),
] ]
); );
} }
@ -383,9 +383,9 @@ mod test {
], ],
), ),
vec![ vec![
(1..2, 0..0), (1..2, Some(0)..None),
(2..4, 2..2), (2..4, None..Some(2)),
(5..6, 1..1), (5..6, Some(1)..None),
] ]
); );
} }
@ -402,9 +402,9 @@ mod test {
], ],
), ),
vec![ vec![
(1..2, 0..0), (1..2, Some(0)..None),
(2..4, 0..2), (2..4, Some(0)..Some(2)),
(4..6, 0..0), (4..6, Some(0)..None),
] ]
); );
assert_eq!( assert_eq!(
@ -417,8 +417,8 @@ mod test {
], ],
), ),
vec![ vec![
(1..2, 2..2), (1..2, None..Some(2)),
(2..4, 0..2), (2..4, Some(0)..Some(2)),
] ]
); );
} }
@ -437,13 +437,13 @@ mod test {
], ],
), ),
vec![ vec![
(1..2, 0..0), (1..2, Some(0)..None),
(2..4, 0..2), (2..4, Some(0)..Some(2)),
(4..5, 2..2), (4..5, None..Some(2)),
(5..6, 1..2), (5..6, Some(1)..Some(2)),
(6..7, 1..1), (6..7, Some(1)..None),
(7..8, 1..3), (7..8, Some(1)..Some(3)),
(8..9, 3..3), (8..9, None..Some(3)),
] ]
); );
} }

View File

@ -135,16 +135,21 @@ impl ResourceState for TextureStates {
} }
if selector.aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { if selector.aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) {
for level in selector.levels.clone() { for level in selector.levels.clone() {
//TODO: improve this, it's currently not tested enough and not sound
let ds_state = DepthStencilState { let ds_state = DepthStencilState {
depth: Unit::new(usage), depth: Unit::new(
stencil: Unit::new(usage), if selector.aspects.contains(hal::format::Aspects::DEPTH) { usage } else { TextureUsage::empty() }
),
stencil: Unit::new(
if selector.aspects.contains(hal::format::Aspects::STENCIL) { usage } else { TextureUsage::empty() }
),
}; };
for &mut (ref range, ref mut unit) in self.depth_stencil for &mut (ref range, ref mut ds) in self.depth_stencil
.isolate(&selector.layers, ds_state) .isolate(&selector.layers, ds_state)
{ {
//TODO: check if anything needs to be done when only one of the depth/stencil //TODO: check if anything needs to be done when only one of the depth/stencil
// is selected? // is selected?
if unit.depth.last != usage && selector.aspects.contains(hal::format::Aspects::DEPTH) { if ds.depth.last != usage && selector.aspects.contains(hal::format::Aspects::DEPTH) {
let pending = PendingTransition { let pending = PendingTransition {
id, id,
selector: hal::image::SubresourceRange { selector: hal::image::SubresourceRange {
@ -152,11 +157,11 @@ impl ResourceState for TextureStates {
levels: level .. level + 1, levels: level .. level + 1,
layers: range.clone(), layers: range.clone(),
}, },
usage: unit.depth.last .. usage, usage: ds.depth.last .. usage,
}; };
unit.depth.last = pending.record(output.as_mut())?; ds.depth.last = pending.record(output.as_mut())?;
} }
if unit.stencil.last != usage && selector.aspects.contains(hal::format::Aspects::STENCIL) { if ds.stencil.last != usage && selector.aspects.contains(hal::format::Aspects::STENCIL) {
let pending = PendingTransition { let pending = PendingTransition {
id, id,
selector: hal::image::SubresourceRange { selector: hal::image::SubresourceRange {
@ -164,9 +169,9 @@ impl ResourceState for TextureStates {
levels: level .. level + 1, levels: level .. level + 1,
layers: range.clone(), layers: range.clone(),
}, },
usage: unit.stencil.last .. usage, usage: ds.stencil.last .. usage,
}; };
unit.stencil.last = pending.record(output.as_mut())?; ds.stencil.last = pending.record(output.as_mut())?;
} }
} }
} }
@ -193,24 +198,32 @@ impl ResourceState for TextureStates {
temp_color.extend(mip_self.merge(mip_other, 0)); temp_color.extend(mip_self.merge(mip_other, 0));
mip_self.clear(); mip_self.clear();
for (layers, states) in temp_color.drain(..) { for (layers, states) in temp_color.drain(..) {
let mut color_usage = states.start.last .. states.end.select(stitch); let unit = match states {
if color_usage.start != color_usage.end { Range { start: None, end: None } => unreachable!(),
let level = mip_id as hal::image::Level; Range { start: Some(start), end: None } => start,
let pending = PendingTransition { Range { start: None, end: Some(end) } => Unit::new(end.select(stitch)),
id, Range { start: Some(start), end: Some(end) } => {
selector: hal::image::SubresourceRange { let mut final_usage = end.select(stitch);
aspects: hal::format::Aspects::COLOR, if start.last != final_usage {
levels: level .. level + 1, let level = mip_id as hal::image::Level;
layers: layers.clone(), let pending = PendingTransition {
}, id,
usage: color_usage.clone(), selector: hal::image::SubresourceRange {
}; aspects: hal::format::Aspects::COLOR,
color_usage.end = pending.record(output.as_mut())?; levels: level .. level + 1,
} layers: layers.clone(),
mip_self.append(layers, Unit { },
init: states.start.init, usage: start.last .. final_usage,
last: color_usage.end, };
}); final_usage = pending.record(output.as_mut())?;
}
Unit {
init: start.init,
last: final_usage,
}
}
};
mip_self.append(layers, unit);
} }
} }
@ -218,42 +231,53 @@ impl ResourceState for TextureStates {
temp_ds.extend(self.depth_stencil.merge(&other.depth_stencil, 0)); temp_ds.extend(self.depth_stencil.merge(&other.depth_stencil, 0));
self.depth_stencil.clear(); self.depth_stencil.clear();
for (layers, states) in temp_ds.drain(..) { for (layers, states) in temp_ds.drain(..) {
let mut usage_depth = states.start.depth.last .. states.end.depth.select(stitch); let ds = match states {
let mut usage_stencil = states.start.stencil.last .. states.end.stencil.select(stitch); Range { start: None, end: None } => unreachable!(),
if usage_depth.start != usage_depth.end { Range { start: Some(start), end: None } => start,
let pending = PendingTransition { Range { start: None, end: Some(end) } => DepthStencilState {
id, depth: Unit::new(end.depth.select(stitch)),
selector: hal::image::SubresourceRange { stencil: Unit::new(end.stencil.select(stitch)),
aspects: hal::format::Aspects::DEPTH,
levels: 0 .. 1,
layers: layers.clone(),
},
usage: usage_depth.clone(),
};
usage_depth.end = pending.record(output.as_mut())?;
}
if usage_stencil.start != usage_stencil.end {
let pending = PendingTransition {
id,
selector: hal::image::SubresourceRange {
aspects: hal::format::Aspects::STENCIL,
levels: 0 .. 1,
layers: layers.clone(),
},
usage: usage_stencil.clone(),
};
usage_stencil.end = pending.record(output.as_mut())?;
}
self.depth_stencil.append(layers, DepthStencilState {
depth: Unit {
init: states.start.depth.init,
last: usage_depth.end,
}, },
stencil: Unit { Range { start: Some(start), end: Some(end) } => {
init: states.start.stencil.init, let mut final_depth = end.depth.select(stitch);
last: usage_stencil.end, let mut final_stencil = end.stencil.select(stitch);
}, if start.depth.last != final_depth {
}); let pending = PendingTransition {
id,
selector: hal::image::SubresourceRange {
aspects: hal::format::Aspects::DEPTH,
levels: 0 .. 1,
layers: layers.clone(),
},
usage: start.depth.last .. final_depth,
};
final_depth = pending.record(output.as_mut())?;
}
if start.stencil.last != final_stencil {
let pending = PendingTransition {
id,
selector: hal::image::SubresourceRange {
aspects: hal::format::Aspects::STENCIL,
levels: 0 .. 1,
layers: layers.clone(),
},
usage: start.stencil.last .. final_stencil,
};
final_stencil = pending.record(output.as_mut())?;
}
DepthStencilState {
depth: Unit {
init: start.depth.init,
last: final_depth,
},
stencil: Unit {
init: start.stencil.init,
last: final_stencil,
},
}
}
};
self.depth_stencil.append(layers, ds);
} }
Ok(()) Ok(())