cvkg_render_gpu/kvasir/
graph.rs1use std::collections::{HashMap, VecDeque};
4
5use super::KvasirError;
6use super::resource::ResourceId;
7
8#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
10pub struct NodeKey(pub usize);
11
12#[derive(Clone, Debug)]
14pub struct Edge {
15 pub producer: NodeKey,
16 pub resource: ResourceId,
17 pub consumer: NodeKey,
18}
19
20#[derive(Default)]
23pub struct KvasirGraph {
24 nodes: Vec<Box<dyn super::node::KvasirNode>>,
25 edges: Vec<Edge>,
26 adjacency: HashMap<NodeKey, Vec<(ResourceId, NodeKey)>>,
28 reverse_adj: HashMap<NodeKey, Vec<NodeKey>>,
30 next_key: usize,
31}
32
33impl KvasirGraph {
34 pub fn new() -> Self {
35 Self::default()
36 }
37
38 pub fn add_node(&mut self, node: Box<dyn super::node::KvasirNode>) -> NodeKey {
40 let key = NodeKey(self.next_key);
41 self.next_key += 1;
42 self.nodes.push(node);
43 key
44 }
45
46 pub fn connect(&mut self, from: NodeKey, resource: ResourceId, to: NodeKey) {
48 self.edges.push(Edge {
49 producer: from,
50 resource,
51 consumer: to,
52 });
53 self.adjacency.entry(from).or_default().push((resource, to));
54 self.reverse_adj.entry(to).or_default().push(from);
55 }
56
57 pub fn topological_sort(&self) -> Result<Vec<NodeKey>, KvasirError> {
59 let n = self.nodes.len();
60 let mut in_degree: HashMap<NodeKey, usize> = HashMap::new();
61 for key in (0..n).map(NodeKey) {
62 in_degree.entry(key).or_insert(0);
63 }
64 for edge in &self.edges {
65 *in_degree.entry(edge.consumer).or_insert(0) += 1;
66 }
67
68 let mut queue: VecDeque<NodeKey> = in_degree
69 .iter()
70 .filter(|(_, d)| **d == 0)
71 .map(|(k, _)| *k)
72 .collect();
73 let mut order = Vec::with_capacity(n);
74
75 while let Some(node) = queue.pop_front() {
76 order.push(node);
77 if let Some(neighbors) = self.adjacency.get(&node) {
78 for (_, consumer) in neighbors {
79 let deg = in_degree
80 .get_mut(consumer)
81 .expect("Graph integrity violation: dangling consumer edge");
82 *deg -= 1;
83 if *deg == 0 {
84 queue.push_back(*consumer);
85 }
86 }
87 }
88 }
89
90 if order.len() != n {
91 let cycle_nodes: Vec<String> = in_degree
93 .iter()
94 .filter(|(_, d)| **d > 0)
95 .filter_map(|(k, _)| self.node(*k).map(|n| n.label().to_string()))
96 .collect();
97 return Err(KvasirError::CycleDetected(cycle_nodes));
98 }
99
100 Ok(order)
101 }
102
103 pub fn node(&self, key: NodeKey) -> Option<&dyn super::node::KvasirNode> {
105 self.nodes.get(key.0).map(|b| b.as_ref())
106 }
107
108 pub fn to_dot(&self) -> String {
110 let mut s = String::from("digraph Kvasir {\n");
111 for (i, node) in self.nodes.iter().enumerate() {
112 s.push_str(&format!(" n{} [label=\"{}\"];\n", i, node.label()));
113 }
114 for edge in &self.edges {
115 s.push_str(&format!(
116 " n{} -> n{} [label=\"{:?}\"];\n",
117 edge.producer.0, edge.consumer.0, edge.resource
118 ));
119 }
120 s.push_str("}\n");
121 s
122 }
123}
124
125pub struct GraphBuilder {
127 graph: KvasirGraph,
128}
129
130impl GraphBuilder {
131 pub fn new() -> Self {
132 Self {
133 graph: KvasirGraph::new(),
134 }
135 }
136
137 pub fn add_node(&mut self, node: Box<dyn super::node::KvasirNode>) -> NodeKey {
138 self.graph.add_node(node)
139 }
140
141 pub fn connect(&mut self, from: NodeKey, resource: ResourceId, to: NodeKey) {
142 self.graph.connect(from, resource, to);
143 }
144
145 pub fn build(self) -> KvasirGraph {
146 self.graph
147 }
148}
149
150impl Default for GraphBuilder {
151 fn default() -> Self {
152 Self::new()
153 }
154}