fewer btrees
This commit is contained in:
parent
6a41cccf8b
commit
51a2e69f74
|
|
@ -1,5 +1,6 @@
|
|||
use std::{
|
||||
collections::{BTreeMap, BTreeSet, HashMap},
|
||||
cmp::Reverse,
|
||||
collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, VecDeque},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
|
|
@ -103,9 +104,11 @@ impl ResourceInterference {
|
|||
|
||||
/// Deterministic Kahn topological-sort state for command dependencies.
|
||||
struct Kahn {
|
||||
edges: Vec<BTreeSet<usize>>,
|
||||
edges: Vec<Vec<usize>>,
|
||||
indegree: Vec<usize>,
|
||||
ready: BTreeSet<usize>,
|
||||
ready: BinaryHeap<Reverse<usize>>,
|
||||
// TODO: bitvec
|
||||
is_ready: Vec<bool>,
|
||||
emitted: usize,
|
||||
total: usize,
|
||||
}
|
||||
|
|
@ -113,23 +116,34 @@ struct Kahn {
|
|||
impl Kahn {
|
||||
fn new(node_count: usize) -> Self {
|
||||
Self {
|
||||
edges: vec![BTreeSet::new(); node_count],
|
||||
edges: vec![Vec::new(); node_count],
|
||||
indegree: vec![0; node_count],
|
||||
ready: (0..node_count).collect(),
|
||||
ready: (0..node_count).map(Reverse).collect(),
|
||||
is_ready: vec![true; node_count],
|
||||
emitted: 0,
|
||||
total: node_count,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_edge(&mut self, from: usize, to: usize) {
|
||||
if self.edges[from].insert(to) {
|
||||
let edges = &mut self.edges[from];
|
||||
if let Err(index) = edges.binary_search(&to) {
|
||||
edges.insert(index, to);
|
||||
self.indegree[to] += 1;
|
||||
self.ready.remove(&to);
|
||||
if self.is_ready[to] {
|
||||
self.is_ready[to] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_ready(&mut self) -> Option<usize> {
|
||||
self.ready.pop_first()
|
||||
while let Some(Reverse(node)) = self.ready.pop() {
|
||||
if self.is_ready[node] {
|
||||
self.is_ready[node] = false;
|
||||
return Some(node);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn complete(&mut self, node: usize) {
|
||||
|
|
@ -137,7 +151,8 @@ impl Kahn {
|
|||
for &dependent in &self.edges[node] {
|
||||
self.indegree[dependent] -= 1;
|
||||
if self.indegree[dependent] == 0 {
|
||||
self.ready.insert(dependent);
|
||||
self.is_ready[dependent] = true;
|
||||
self.ready.push(Reverse(dependent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -149,7 +164,7 @@ impl Kahn {
|
|||
|
||||
pub struct RenderGraph {
|
||||
next_id: u64,
|
||||
resources: BTreeMap<ResourceId, ResourceDesc>,
|
||||
resources: Vec<ResourceDesc>,
|
||||
pub commands: CommandList,
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +172,7 @@ impl RenderGraph {
|
|||
pub fn new() -> Self {
|
||||
Self {
|
||||
next_id: 0,
|
||||
resources: BTreeMap::new(),
|
||||
resources: Vec::new(),
|
||||
commands: CommandList::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -165,7 +180,7 @@ impl RenderGraph {
|
|||
fn add_resource(&mut self, desc: ResourceDesc) -> ResourceId {
|
||||
let id = ResourceId(self.next_id);
|
||||
self.next_id = self.next_id.checked_add(1).expect("resource id overflow");
|
||||
self.resources.insert(id, desc);
|
||||
self.resources.push(desc);
|
||||
id
|
||||
}
|
||||
|
||||
|
|
@ -225,14 +240,14 @@ impl RenderGraph {
|
|||
}
|
||||
|
||||
struct GraphCompiler<'a> {
|
||||
resources: &'a BTreeMap<ResourceId, ResourceDesc>,
|
||||
resources: &'a [ResourceDesc],
|
||||
accesses: &'a [Vec<crate::recorder::ResourceAccess>],
|
||||
command_count: usize,
|
||||
}
|
||||
|
||||
impl<'a> GraphCompiler<'a> {
|
||||
fn new(
|
||||
resources: &'a BTreeMap<ResourceId, ResourceDesc>,
|
||||
resources: &'a [ResourceDesc],
|
||||
accesses: &'a [Vec<crate::recorder::ResourceAccess>],
|
||||
command_count: usize,
|
||||
) -> Self {
|
||||
|
|
@ -277,7 +292,7 @@ impl<'a> GraphCompiler<'a> {
|
|||
fn validate_resources(&self) -> Result<(), GraphError> {
|
||||
for command_accesses in self.accesses {
|
||||
for access in command_accesses {
|
||||
if !self.resources.contains_key(&access.resource) {
|
||||
if access.resource.index() >= self.resources.len() {
|
||||
return Err(GraphError::UnknownResource(access.resource));
|
||||
}
|
||||
}
|
||||
|
|
@ -313,7 +328,7 @@ impl<'a> GraphCompiler<'a> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let desc = &self.resources[¤t.resource];
|
||||
let desc = &self.resources[current.resource.0 as usize];
|
||||
let initial = desc.initial_state();
|
||||
let (old_layout, new_layout) = Self::layouts_from_state(initial, current.scope);
|
||||
let layout_transition = old_layout != new_layout && new_layout.is_some();
|
||||
|
|
@ -397,12 +412,13 @@ impl<'a> GraphCompiler<'a> {
|
|||
ids.sort_by_key(|id| lifetimes[id].first_command);
|
||||
for id in ids {
|
||||
let lifetime = lifetimes.get_mut(&id).expect("lifetime key exists");
|
||||
let size = match &self.resources[&id] {
|
||||
let desc = &self.resources[id.0 as usize];
|
||||
let size = match desc {
|
||||
ResourceDesc::CreatedBuffer(desc) => desc.size,
|
||||
ResourceDesc::CreatedTexture(desc) => texture_size_estimate(desc),
|
||||
ResourceDesc::ImportedBuffer { .. } | ResourceDesc::ImportedTexture { .. } => 0,
|
||||
};
|
||||
if self.resources[&id].is_created()
|
||||
if desc.is_created()
|
||||
&& let Some((offset, last_use, capacity)) = slots
|
||||
.iter_mut()
|
||||
.find(|(_, last, cap)| !interference.interferes(*last, id) && *cap >= size)
|
||||
|
|
@ -412,7 +428,7 @@ impl<'a> GraphCompiler<'a> {
|
|||
let _ = capacity;
|
||||
} else {
|
||||
lifetime.memory_offset = next_offset;
|
||||
if self.resources[&id].is_created() {
|
||||
if desc.is_created() {
|
||||
slots.push((next_offset, id, size));
|
||||
next_offset = next_offset.saturating_add(size);
|
||||
}
|
||||
|
|
@ -429,7 +445,7 @@ impl Default for RenderGraph {
|
|||
}
|
||||
|
||||
pub struct CompiledGraph {
|
||||
resources: BTreeMap<ResourceId, ResourceDesc>,
|
||||
resources: Vec<ResourceDesc>,
|
||||
resolved: HashMap<ResourceId, ResolvedResource>,
|
||||
commands: CommandList,
|
||||
order: Vec<CommandIndex>,
|
||||
|
|
@ -464,7 +480,8 @@ impl CompiledGraph {
|
|||
/// of a Vulkan device, while command recording requires this resolution step
|
||||
/// for any created resources used by commands.
|
||||
pub fn resolve(&mut self, device: &Device) -> renderer_resources::Result<()> {
|
||||
for (&id, desc) in &self.resources {
|
||||
for (index, desc) in self.resources.iter().enumerate() {
|
||||
let id = ResourceId(index as u64);
|
||||
if self.resolved.contains_key(&id) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -529,7 +546,8 @@ impl CompiledGraph {
|
|||
&mut self,
|
||||
recorder: &mut CommandRecorder<'_>,
|
||||
) -> Result<(), RecordError> {
|
||||
for (&id, desc) in &self.resources {
|
||||
for (index, desc) in self.resources.iter().enumerate() {
|
||||
let id = ResourceId(index as u64);
|
||||
if !self.lifetimes.contains_key(&id) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -801,6 +819,7 @@ mod tests {
|
|||
fn kahn_emits_dag_in_deterministic_order() {
|
||||
let mut kahn = Kahn::new(4);
|
||||
kahn.add_edge(0, 2);
|
||||
kahn.add_edge(0, 2);
|
||||
kahn.add_edge(1, 2);
|
||||
kahn.add_edge(2, 3);
|
||||
|
||||
|
|
@ -867,29 +886,20 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn aliasing_reuses_non_interfering_slot_and_separates_interfering_resources() {
|
||||
let resources = BTreeMap::from([
|
||||
(
|
||||
ResourceId(0),
|
||||
let resources = vec![
|
||||
ResourceDesc::CreatedBuffer(GraphBufferDesc {
|
||||
size: 8,
|
||||
..Default::default()
|
||||
}),
|
||||
),
|
||||
(
|
||||
ResourceId(1),
|
||||
ResourceDesc::CreatedBuffer(GraphBufferDesc {
|
||||
size: 8,
|
||||
..Default::default()
|
||||
}),
|
||||
),
|
||||
(
|
||||
ResourceId(2),
|
||||
ResourceDesc::CreatedBuffer(GraphBufferDesc {
|
||||
size: 8,
|
||||
..Default::default()
|
||||
}),
|
||||
),
|
||||
]);
|
||||
];
|
||||
let accesses = vec![
|
||||
vec![resource_access_for(ResourceId(0))],
|
||||
vec![
|
||||
|
|
|
|||
|
|
@ -72,6 +72,12 @@ impl Default for GraphTextureDesc {
|
|||
#[repr(transparent)]
|
||||
pub struct ResourceId(pub u64);
|
||||
|
||||
impl ResourceId {
|
||||
pub(crate) fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Buffer(pub ResourceId);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue