use smallvec::SmallVec; use std::{fmt, iter, ops::Range};
mod buffer; mod texture;
pub(crate) use buffer::{BufferInitTracker, BufferInitTrackerAction}; pub(crate) use texture::{
has_copy_partial_init_tracker_coverage, TextureInitRange, TextureInitTracker,
TextureInitTrackerAction,
};
#[derive(Debug, Clone, Copy)] pub(crate) enum MemoryInitKind { // The memory range is going to be written by an already initialized source, // thus doesn't need extra attention other than marking as initialized.
ImplicitlyInitialized, // The memory range is going to be read, therefore needs to ensure prior // initialization.
NeedsInitializedMemory,
}
// Most of the time a resource is either fully uninitialized (one element) or // initialized (zero elements). type UninitializedRangeVec<Idx> = SmallVec<[Range<Idx>; 1]>;
/// Tracks initialization status of a linear range from 0..size #[derive(Debug, Clone)] pub(crate) struct InitTracker<Idx: Ord + Copy + Default> { /// Non-overlapping list of all uninitialized ranges, sorted by /// range end.
uninitialized_ranges: UninitializedRangeVec<Idx>,
}
/// Checks for uninitialized ranges within a given query range. /// /// If `query_range` includes any uninitialized portions of this init /// tracker's resource, return the smallest subrange of `query_range` that /// covers all uninitialized regions. /// /// The returned range may be larger than necessary, to keep this function /// O(log n). pub(crate) fn check(&self, query_range: Range<Idx>) -> Option<Range<Idx>> { let index = self
.uninitialized_ranges
.partition_point(|r| r.end <= query_range.start); self.uninitialized_ranges
.get(index)
.and_then(|start_range| { if start_range.start < query_range.end { let start = start_range.start.max(query_range.start); matchself.uninitialized_ranges.get(index + 1) {
Some(next_range) => { if next_range.start < query_range.end { // Would need to keep iterating for more // accurate upper bound. Don't do that here.
Some(start..query_range.end)
} else {
Some(start..start_range.end.min(query_range.end))
}
}
None => Some(start..start_range.end.min(query_range.end)),
}
} else {
None
}
})
}
// Returns an iterator over the uninitialized ranges in a query range. pub(crate) fn uninitialized(&mutself, drain_range: Range<Idx>) -> UninitializedIter<Idx> { let index = self
.uninitialized_ranges
.partition_point(|r| r.end <= drain_range.start);
UninitializedIter {
drain_range,
uninitialized_ranges: &self.uninitialized_ranges,
next_index: index,
}
}
// Drains uninitialized ranges in a query range. pub(crate) fn drain(&mutself, drain_range: Range<Idx>) -> InitTrackerDrain<Idx> { let index = self
.uninitialized_ranges
.partition_point(|r| r.end <= drain_range.start);
InitTrackerDrain {
drain_range,
uninitialized_ranges: &mutself.uninitialized_ranges,
first_index: index,
next_index: index,
}
}
}
impl InitTracker<u32> { // Makes a single entry uninitialized if not already uninitialized #[allow(dead_code)] pub(crate) fn discard(&mutself, pos: u32) { // first range where end>=idx let r_idx = self.uninitialized_ranges.partition_point(|r| r.end < pos); iflet Some(r) = self.uninitialized_ranges.get(r_idx) { // Extend range at end if r.end == pos { // merge with next? iflet Some(right) = self.uninitialized_ranges.get(r_idx + 1) { if right.start == pos + 1 { self.uninitialized_ranges[r_idx] = r.start..right.end; self.uninitialized_ranges.remove(r_idx + 1); return;
}
} self.uninitialized_ranges[r_idx] = r.start..(pos + 1);
} elseif r.start > pos { // may still extend range at beginning if r.start == pos + 1 { self.uninitialized_ranges[r_idx] = pos..r.end;
} else { // previous range end must be smaller than idx, therefore no merge possible self.uninitialized_ranges.push(pos..(pos + 1));
}
}
} else { self.uninitialized_ranges.push(pos..(pos + 1));
}
}
}
#[test] fn check_for_partially_filled_tracker() { letmut tracker = Tracker::new(25); // Two regions of uninitialized memory
tracker.drain(0..5);
tracker.drain(10..15);
tracker.drain(20..25);
assert_eq!(tracker.check(0..25), Some(5..25)); // entire range
assert_eq!(tracker.check(0..5), None); // left non-overlapping
assert_eq!(tracker.check(3..8), Some(5..8)); // left overlapping region
assert_eq!(tracker.check(3..17), Some(5..17)); // left overlapping region + contained region
// right overlapping region + contained region (yes, doesn't fix range end!)
assert_eq!(tracker.check(8..22), Some(8..22)); // right overlapping region
assert_eq!(tracker.check(17..22), Some(17..20)); // right non-overlapping
assert_eq!(tracker.check(20..25), None);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.