chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
79 / 84
94.0%
Branches:
50 / 54
92.6%
Functions:
8 / 9
88.9%

graph/graph.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/graph/graph.h"
3
4 #include <algorithm>
5 #include <cstring>
6
7 #include "chrono_batch_render/util/error.h"
8 #include "chrono_batch_render/util/text.h"
9
10 namespace chrono::batch_render::graph {
11
12 442 uint32_t Graph::Add(uint32_t kind) {
13
1/1
✓ Branch 1 taken 442 times.
442 m_nodes.push_back({.kind = kind});
14 442 return uint32_t(m_nodes.size() - 1);
15 }
16
17 320 void Graph::Connect(uint32_t node, uint32_t input, uint32_t source, uint32_t output) {
18
3/4
✓ Branch 0 taken 320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 319 times.
320 if (node >= m_nodes.size() || source >= m_nodes.size()) {
19
1/1
✓ Branch 2 taken 1 time.
1 throw Error("Connecting node {} to node {} of a graph of {}", node, source, m_nodes.size());
20 }
21 319 std::vector<Edge>& inputs = m_nodes[node].inputs;
22
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 318 times.
319 if (std::ranges::find(inputs, input, &Edge::input) != inputs.end()) {
23
1/1
✓ Branch 2 taken 1 time.
1 throw Error("Node {}'s input {} is already connected", node, input);
24 }
25 318 inputs.push_back({input, source, output});
26 318 }
27
28 122 Ordering Graph::Order() const {
29 122 enum class Mark : uint8_t { None, Open, Done };
30 122 std::vector<Mark> marks(m_nodes.size(), Mark::None);
31 122 std::vector<uint32_t> path;
32 122 Ordering ordering;
33
34 122 struct Frame {
35 uint32_t node;
36 uint32_t next;
37 };
38
39 122 std::vector<Frame> stack;
40
2/2
✓ Branch 0 taken 424 times.
✓ Branch 1 taken 119 times.
543 for (uint32_t root = 0; root < m_nodes.size(); ++root) {
41
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 381 times.
424 if (marks[root] != Mark::None) {
42 43 continue;
43 }
44
1/1
✓ Branch 1 taken 381 times.
381 stack.push_back({root, 0});
45
1/1
✓ Branch 1 taken 381 times.
381 marks[root] = Mark::Open;
46
1/1
✓ Branch 1 taken 381 times.
381 path.push_back(root);
47
2/2
✓ Branch 0 taken 733 times.
✓ Branch 1 taken 378 times.
1111 while (!stack.empty()) {
48 733 Frame& frame = stack.back();
49
2/2
✓ Branch 0 taken 421 times.
✓ Branch 1 taken 312 times.
733 const std::vector<Edge>& inputs = m_nodes[frame.node].inputs;
50
2/2
✓ Branch 0 taken 421 times.
✓ Branch 1 taken 312 times.
733 if (frame.next == inputs.size()) {
51
1/1
✓ Branch 1 taken 421 times.
421 marks[frame.node] = Mark::Done;
52
1/1
✓ Branch 1 taken 421 times.
421 ordering.order.push_back(frame.node);
53 421 path.pop_back();
54 421 stack.pop_back();
55 421 continue;
56 }
57
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 309 times.
312 const uint32_t source = inputs[frame.next++].source;
58
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 309 times.
312 if (marks[source] == Mark::Open) {
59
1/1
✓ Branch 2 taken 3 times.
3 ordering.cycle.assign(std::ranges::find(path, source), path.end());
60 3 ordering.order.clear();
61 3 return ordering;
62 }
63
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 261 times.
309 if (marks[source] == Mark::None) {
64 48 marks[source] = Mark::Open;
65
1/1
✓ Branch 1 taken 48 times.
48 path.push_back(source);
66
1/1
✓ Branch 1 taken 48 times.
48 stack.push_back({source, 0});
67 }
68 }
69 }
70 119 return ordering;
71 122 }
72
73 116 uint64_t ShapeKey::Hash() const {
74 116 return Fnv1a(m_bytes);
75 }
76
77 2834 void ShapeWriter::Add(uint32_t value) {
78 2834 char bytes[sizeof(value)];
79 2834 std::memcpy(bytes, &value, sizeof(value));
80 2834 m_key.m_bytes.append(bytes, sizeof(bytes));
81 2834 }
82
83 514 void ShapeWriter::Add(std::string_view text) {
84 514 Add(uint32_t(text.size()));
85 514 m_key.m_bytes.append(text);
86 514 }
87
88 ✗ void ShapeWriter::Add(std::span<const std::byte> bytes) {
89 ✗ Add(uint32_t(bytes.size()));
90 ✗ m_key.m_bytes.append(reinterpret_cast<const char*>(bytes.data()), bytes.size());
91 ✗ }
92
93 117 ShapeKey ShapeWriter::Finish() && {
94 117 return std::move(m_key);
95 }
96
97 102 ShapeKey GraphShape(const Graph& graph, std::span<const uint32_t> order,
98 const NodeUniforms& uniforms) {
99 102 std::vector<uint32_t> positions(graph.Nodes().size(), kNoNode);
100
2/2
✓ Branch 0 taken 394 times.
✓ Branch 1 taken 102 times.
496 for (uint32_t position = 0; position < order.size(); ++position) {
101 394 positions[order[position]] = position;
102 }
103
1/1
✓ Branch 1 taken 102 times.
102 ShapeWriter writer;
104
1/1
✓ Branch 1 taken 102 times.
102 writer.Add(uint32_t(order.size()));
105
2/2
✓ Branch 0 taken 394 times.
✓ Branch 1 taken 102 times.
496 for (const uint32_t node : order) {
106
1/1
✓ Branch 1 taken 394 times.
394 const Node& each = graph[node];
107
1/1
✓ Branch 1 taken 394 times.
394 writer.Add(each.kind);
108
1/1
✓ Branch 1 taken 394 times.
394 std::vector<Edge> inputs = each.inputs;
109 394 std::ranges::sort(inputs, {}, &Edge::input);
110
1/1
✓ Branch 1 taken 394 times.
394 writer.Add(uint32_t(inputs.size()));
111
2/2
✓ Branch 0 taken 294 times.
✓ Branch 1 taken 394 times.
688 for (const Edge& edge : inputs) {
112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294 times.
294 if (positions[edge.source] == kNoNode) {
113
0/1
✗ Branch 2 not taken.
✗ throw Error("Node {} reads node {}, which the order leaves out", node, edge.source);
114 }
115
1/1
✓ Branch 1 taken 294 times.
294 writer.Add(edge.input);
116
1/1
✓ Branch 1 taken 294 times.
294 writer.Add(positions[edge.source]);
117
1/1
✓ Branch 1 taken 294 times.
294 writer.Add(edge.output);
118 }
119
1/2
✓ Branch 0 taken 394 times.
✗ Branch 1 not taken.
394 if (uniforms) {
120
1/1
✓ Branch 1 taken 394 times.
394 uniforms(node, writer);
121 }
122 394 }
123 204 return std::move(writer).Finish();
124 102 }
125
126 }
127