Another iteration of internal tracking

This commit is contained in:
Dzmitry Malyshau 2019-06-09 00:00:17 -04:00
parent 0dcd0c449d
commit 444220c6eb

View File

@ -22,107 +22,9 @@ use std::{
marker::PhantomData,
mem,
ops::{BitOr, Range},
vec::Drain,
};
#[derive(Clone, Debug)]
pub struct RangedStates<I, T> {
ranges: Vec<(Range<I>, T)>,
}
pub type TextureLayerStates = RangedStates<hal::image::Layer, TextureUsage>;
pub type TextureStates2 = RangedStates<hal::image::Level, TextureLayerStates>;
impl<I: Copy + PartialOrd, T: Clone> RangedStates<I, T> {
fn isolate(&mut self, index: Range<I>) -> &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<TextureUsage> {
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<T> {
Single(T),
Multi(Vec<(Range<hal::image::Layer>, T)>),
}
impl<T> Default for PlaneStates<T> {
fn default() -> Self {
PlaneStates::Multi(Vec::new())
}
}
pub struct DepthStencilState {
depth: TextureUsage,
stencil: TextureUsage,
}
pub struct TextureStates {
color_mips: ArrayVec<[PlaneStates<TextureUsage>; MAX_MIP_LEVELS]>,
depth_stencil: PlaneStates<DepthStencilState>,
}
impl TextureStates {
fn change<'a>(
&mut self,
what: hal::image::SubresourceRange,
usage: TextureUsage,
permit: TrackPermit,
fun: impl FnMut(hal::image::SubresourceRange, Tracktion<TextureUsage>),
) {
/*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<U> {
init: U,
last: U,
@ -228,14 +130,7 @@ impl<U: Copy + BitOr<Output=U> + PartialEq + GenericUsage> Unit<U> {
}
}
#[derive(Clone, Debug)]
struct Resource<S> {
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<I, S> {
/// An association of known resource indices with their tracked states.
@ -300,7 +195,7 @@ impl<I: TypedId, S> Tracker<I, S> {
}
/// 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<I: Copy + TypedId, U: Copy + GenericUsage + BitOr<Output = U> + PartialEq>
}
}
pub type BufferTracker = Tracker<BufferId, Unit<BufferUsage>>;
pub type TextureTracker = Tracker<TextureId, Unit<TextureUsage>>;
pub type TextureViewTracker = Tracker<TextureViewId, Unit<DummyUsage>>;
@ -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<Self::Usage>;
fn change(
&mut self,
id: Self::Id,
selector: Self::Selector,
usage: Self::Usage,
output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>>;
fn merge(
&mut self,
id: Self::Id,
other: &Self,
stitch: Stitch,
output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>>;
}
#[derive(Clone, Debug)]
struct Resource<S> {
ref_count: RefCount,
state: S,
epoch: Epoch,
}
pub struct PendingTransition<S: ResourceState> {
pub id: S::Id,
pub selector: S::Selector,
pub usage: Range<S::Usage>,
}
struct ResourceTracker<S: ResourceState> {
/// An association of known resource indices with their tracked states.
map: FastHashMap<Index, Resource<S>>,
/// Temporary storage for collecting transitions.
temp: Vec<PendingTransition<S>>,
}
impl<S: ResourceState> ResourceTracker<S> {
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<Item = S::Id> {
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<S::Usage> {
let res = self.map.get(&id.index())?;
assert_eq!(res.epoch, id.epoch());
res.state.query(selector)
}
fn grab<'a>(
map: &'a mut FastHashMap<Index, Resource<S>>,
id: S::Id,
ref_count: &RefCount,
) -> &'a mut Resource<S> {
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<S>> {
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<Drain<PendingTransition<S>>, PendingTransition<S>> {
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<S>> {
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<Drain<PendingTransition<S>>, PendingTransition<S>> {
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<RefCount>>(
&mut self,
storage: &'a Storage<T, S::Id>,
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<RefCount>>(
&mut self,
storage: &'a Storage<T, S::Id>,
id: S::Id,
selector: S::Selector,
usage: S::Usage,
) -> Result<(&'a T, Drain<PendingTransition<S>>), 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<BufferUsage>;
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<Self::Usage> {
Some(self.last)
}
fn change(
&mut self,
id: Self::Id,
_selector: Self::Selector,
usage: Self::Usage,
output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
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<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
let usage = other.select(stitch);
self.change(id, (), usage, output)
}
}
#[derive(Clone, Debug)]
pub struct RangedStates<I, T> {
ranges: Vec<(Range<I>, T)>,
}
impl<I, T> Default for RangedStates<I, T> {
fn default() -> Self {
RangedStates {
ranges: Vec::new(),
}
}
}
impl<I: Copy + PartialOrd, T: Copy> RangedStates<I, T> {
fn isolate(&mut self, index: &Range<I>, default: T) -> &mut [(Range<I>, 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<T> = RangedStates<hal::image::Layer, T>;
#[derive(Clone)]
struct DepthStencilState {
depth: Unit<TextureUsage>,
stencil: Unit<TextureUsage>,
}
#[derive(Clone, Default)]
struct TextureStates {
color_mips: ArrayVec<[PlaneStates<Unit<TextureUsage>>; MAX_MIP_LEVELS]>,
depth_stencil: PlaneStates<DepthStencilState>,
}
impl ResourceState for TextureStates {
type Id = TextureId;
type Selector = hal::image::SubresourceRange;
type Usage = TextureUsage;
fn query(
&self,
selector: Self::Selector,
) -> Option<Self::Usage> {
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<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
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<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
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<Self::Usage> {
Some(())
}
fn change(
&mut self,
_id: Self::Id,
_selector: Self::Selector,
_usage: Self::Usage,
_output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
Ok(())
}
fn merge(
&mut self,
_id: Self::Id,
_other: &Self,
_stitch: Stitch,
_output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
Ok(())
}
}