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