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> {
type Item = (Range<I>, Range<T>);
type Item = (Range<I>, Range<Option<T>>);
fn next(&mut self) -> Option<Self::Item> {
match (self.sa.peek(), self.sb.peek()) {
// 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
if self.base == rb.start { // right stream is starting
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
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
if self.base == ra.start { // left stream is starting
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
debug_assert!(self.base < ra.start);
(self.base .. ra.start, *vb .. *vb)
(self.base .. ra.start, None .. Some(*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),
Ordering::Equal => (ra.start .. ra.end.min(rb.end), Some(*va) .. Some(*vb)),
// 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
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;
@ -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;
self.base = rb.end;
let _ = self.sb.next();
Some((range, *vb .. *vb))
Some((range, None .. Some(*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))
Some((range, Some(*va) .. None))
}
// done
(None, None) => None,
@ -247,7 +247,7 @@ mod test {
fn easy_merge<T: PartialEq + Copy + Debug>(
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()
}
@ -337,7 +337,7 @@ mod test {
],
),
vec![
(1..4, 0..2),
(1..4, Some(0)..Some(2)),
]
);
}
@ -353,7 +353,7 @@ mod test {
],
),
vec![
(1..2, 0..0),
(1..2, Some(0)..None),
]
);
assert_eq!(
@ -365,7 +365,7 @@ mod test {
],
),
vec![
(3..4, 1..1),
(3..4, None..Some(1)),
]
);
}
@ -383,9 +383,9 @@ mod test {
],
),
vec![
(1..2, 0..0),
(2..4, 2..2),
(5..6, 1..1),
(1..2, Some(0)..None),
(2..4, None..Some(2)),
(5..6, Some(1)..None),
]
);
}
@ -402,9 +402,9 @@ mod test {
],
),
vec![
(1..2, 0..0),
(2..4, 0..2),
(4..6, 0..0),
(1..2, Some(0)..None),
(2..4, Some(0)..Some(2)),
(4..6, Some(0)..None),
]
);
assert_eq!(
@ -417,8 +417,8 @@ mod test {
],
),
vec![
(1..2, 2..2),
(2..4, 0..2),
(1..2, None..Some(2)),
(2..4, Some(0)..Some(2)),
]
);
}
@ -437,13 +437,13 @@ mod test {
],
),
vec![
(1..2, 0..0),
(2..4, 0..2),
(4..5, 2..2),
(5..6, 1..2),
(6..7, 1..1),
(7..8, 1..3),
(8..9, 3..3),
(1..2, Some(0)..None),
(2..4, Some(0)..Some(2)),
(4..5, None..Some(2)),
(5..6, Some(1)..Some(2)),
(6..7, Some(1)..None),
(7..8, Some(1)..Some(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) {
for level in selector.levels.clone() {
//TODO: improve this, it's currently not tested enough and not sound
let ds_state = DepthStencilState {
depth: Unit::new(usage),
stencil: Unit::new(usage),
depth: Unit::new(
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)
{
//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) {
if ds.depth.last != usage && selector.aspects.contains(hal::format::Aspects::DEPTH) {
let pending = PendingTransition {
id,
selector: hal::image::SubresourceRange {
@ -152,11 +157,11 @@ impl ResourceState for TextureStates {
levels: level .. level + 1,
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 {
id,
selector: hal::image::SubresourceRange {
@ -164,9 +169,9 @@ impl ResourceState for TextureStates {
levels: level .. level + 1,
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));
mip_self.clear();
for (layers, states) in temp_color.drain(..) {
let mut color_usage = states.start.last .. states.end.select(stitch);
if color_usage.start != color_usage.end {
let level = mip_id as hal::image::Level;
let pending = PendingTransition {
id,
selector: hal::image::SubresourceRange {
aspects: hal::format::Aspects::COLOR,
levels: level .. level + 1,
layers: layers.clone(),
},
usage: color_usage.clone(),
};
color_usage.end = pending.record(output.as_mut())?;
}
mip_self.append(layers, Unit {
init: states.start.init,
last: color_usage.end,
});
let unit = match states {
Range { start: None, end: None } => unreachable!(),
Range { start: Some(start), end: None } => start,
Range { start: None, end: Some(end) } => Unit::new(end.select(stitch)),
Range { start: Some(start), end: Some(end) } => {
let mut final_usage = end.select(stitch);
if start.last != final_usage {
let level = mip_id as hal::image::Level;
let pending = PendingTransition {
id,
selector: hal::image::SubresourceRange {
aspects: hal::format::Aspects::COLOR,
levels: level .. level + 1,
layers: layers.clone(),
},
usage: start.last .. final_usage,
};
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));
self.depth_stencil.clear();
for (layers, states) in temp_ds.drain(..) {
let mut usage_depth = states.start.depth.last .. states.end.depth.select(stitch);
let mut usage_stencil = states.start.stencil.last .. states.end.stencil.select(stitch);
if usage_depth.start != usage_depth.end {
let pending = PendingTransition {
id,
selector: hal::image::SubresourceRange {
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,
let ds = match states {
Range { start: None, end: None } => unreachable!(),
Range { start: Some(start), end: None } => start,
Range { start: None, end: Some(end) } => DepthStencilState {
depth: Unit::new(end.depth.select(stitch)),
stencil: Unit::new(end.stencil.select(stitch)),
},
stencil: Unit {
init: states.start.stencil.init,
last: usage_stencil.end,
},
});
Range { start: Some(start), end: Some(end) } => {
let mut final_depth = end.depth.select(stitch);
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(())