summaryrefslogtreecommitdiff
path: root/src/audio_core/renderer/nodes
diff options
context:
space:
mode:
authorGravatar Kelebek12022-07-16 23:48:45 +0100
committerGravatar Kelebek12022-07-22 01:11:32 +0100
commit458da8a94877677f086f06cdeecf959ec4283a33 (patch)
tree583166d77602ad90a0d552f37de8729ad80fd6c1 /src/audio_core/renderer/nodes
parentMerge pull request #8598 from Link4565/recv-dontwait (diff)
downloadyuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.gz
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.xz
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.zip
Project Andio
Diffstat (limited to 'src/audio_core/renderer/nodes')
-rw-r--r--src/audio_core/renderer/nodes/bit_array.h25
-rw-r--r--src/audio_core/renderer/nodes/edge_matrix.cpp38
-rw-r--r--src/audio_core/renderer/nodes/edge_matrix.h82
-rw-r--r--src/audio_core/renderer/nodes/node_states.cpp141
-rw-r--r--src/audio_core/renderer/nodes/node_states.h195
5 files changed, 481 insertions, 0 deletions
diff --git a/src/audio_core/renderer/nodes/bit_array.h b/src/audio_core/renderer/nodes/bit_array.h
new file mode 100644
index 000000000..b0d53cd51
--- /dev/null
+++ b/src/audio_core/renderer/nodes/bit_array.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <vector>
7
8#include "common/common_types.h"
9
10namespace AudioCore::AudioRenderer {
11/**
12 * Represents an array of bits used for nodes and edges for the mixing graph.
13 */
14struct BitArray {
15 void reset() {
16 buffer.assign(buffer.size(), false);
17 }
18
19 /// Bits
20 std::vector<bool> buffer{};
21 /// Size of the buffer
22 u32 size{};
23};
24
25} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/nodes/edge_matrix.cpp b/src/audio_core/renderer/nodes/edge_matrix.cpp
new file mode 100644
index 000000000..5573f33b9
--- /dev/null
+++ b/src/audio_core/renderer/nodes/edge_matrix.cpp
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/nodes/edge_matrix.h"
5
6namespace AudioCore::AudioRenderer {
7
8void EdgeMatrix::Initialize([[maybe_unused]] std::span<u8> buffer,
9 [[maybe_unused]] const u64 node_buffer_size, const u32 count_) {
10 count = count_;
11 edges.buffer.resize(count_ * count_);
12 edges.size = count_ * count_;
13 edges.reset();
14}
15
16bool EdgeMatrix::Connected(const u32 id, const u32 destination_id) const {
17 return edges.buffer[count * id + destination_id];
18}
19
20void EdgeMatrix::Connect(const u32 id, const u32 destination_id) {
21 edges.buffer[count * id + destination_id] = true;
22}
23
24void EdgeMatrix::Disconnect(const u32 id, const u32 destination_id) {
25 edges.buffer[count * id + destination_id] = false;
26}
27
28void EdgeMatrix::RemoveEdges(const u32 id) {
29 for (u32 dest = 0; dest < count; dest++) {
30 Disconnect(id, dest);
31 }
32}
33
34u32 EdgeMatrix::GetNodeCount() const {
35 return count;
36}
37
38} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/nodes/edge_matrix.h b/src/audio_core/renderer/nodes/edge_matrix.h
new file mode 100644
index 000000000..27a20e43e
--- /dev/null
+++ b/src/audio_core/renderer/nodes/edge_matrix.h
@@ -0,0 +1,82 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <span>
7
8#include "audio_core/renderer/nodes/bit_array.h"
9#include "common/alignment.h"
10#include "common/common_types.h"
11
12namespace AudioCore::AudioRenderer {
13/**
14 * An edge matrix, holding the connections for each node to every other node in the graph.
15 */
16class EdgeMatrix {
17public:
18 /**
19 * Calculate the size required for its workbuffer.
20 *
21 * @param count - The number of nodes in the graph.
22 * @return The required workbuffer size.
23 */
24 static u64 GetWorkBufferSize(u32 count) {
25 return Common::AlignUp(count * count, 0x40) / sizeof(u64);
26 }
27
28 /**
29 * Initialize this edge matrix.
30 *
31 * @param buffer - The workbuffer to use. Unused.
32 * @param node_buffer_size - The size of the workbuffer. Unused.
33 * @param count - The number of nodes in the graph.
34 */
35 void Initialize(std::span<u8> buffer, u64 node_buffer_size, u32 count);
36
37 /**
38 * Check if a node is connected to another.
39 *
40 * @param id - The node id to check.
41 * @param destination_id - Node id to check connection with.
42 */
43 bool Connected(u32 id, u32 destination_id) const;
44
45 /**
46 * Connect a node to another.
47 *
48 * @param id - The node id to connect.
49 * @param destination_id - Destination to connect it to.
50 */
51 void Connect(u32 id, u32 destination_id);
52
53 /**
54 * Disconnect a node from another.
55 *
56 * @param id - The node id to disconnect.
57 * @param destination_id - Destination to disconnect it from.
58 */
59 void Disconnect(u32 id, u32 destination_id);
60
61 /**
62 * Remove all connections for a given node.
63 *
64 * @param id - The node id to disconnect.
65 */
66 void RemoveEdges(u32 id);
67
68 /**
69 * Get the number of nodes in the graph.
70 *
71 * @return Number of nodes.
72 */
73 u32 GetNodeCount() const;
74
75private:
76 /// Edges for the current graph
77 BitArray edges;
78 /// Number of nodes (not edges) in the graph
79 u32 count;
80};
81
82} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/nodes/node_states.cpp b/src/audio_core/renderer/nodes/node_states.cpp
new file mode 100644
index 000000000..1821a51e6
--- /dev/null
+++ b/src/audio_core/renderer/nodes/node_states.cpp
@@ -0,0 +1,141 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/nodes/node_states.h"
5#include "common/logging/log.h"
6
7namespace AudioCore::AudioRenderer {
8
9void NodeStates::Initialize(std::span<u8> buffer_, [[maybe_unused]] const u64 node_buffer_size,
10 const u32 count) {
11 u64 num_blocks{Common::AlignUp(count, 0x40) / sizeof(u64)};
12 u64 offset{0};
13
14 node_count = count;
15
16 nodes_found.buffer.resize(count);
17 nodes_found.size = count;
18 nodes_found.reset();
19
20 offset += num_blocks;
21
22 nodes_complete.buffer.resize(count);
23 nodes_complete.size = count;
24 nodes_complete.reset();
25
26 offset += num_blocks;
27
28 results = {reinterpret_cast<u32*>(&buffer_[offset]), count};
29
30 offset += count * sizeof(u32);
31
32 stack.stack = {reinterpret_cast<u32*>(&buffer_[offset]), count * count};
33 stack.size = count * count;
34 stack.unk_10 = count * count;
35
36 offset += count * count * sizeof(u32);
37}
38
39bool NodeStates::Tsort(const EdgeMatrix& edge_matrix) {
40 return DepthFirstSearch(edge_matrix, stack);
41}
42
43bool NodeStates::DepthFirstSearch(const EdgeMatrix& edge_matrix, Stack& stack_) {
44 ResetState();
45
46 for (u32 node_id = 0; node_id < node_count; node_id++) {
47 if (GetState(node_id) == SearchState::Unknown) {
48 stack_.push(node_id);
49 }
50
51 while (stack_.Count() > 0) {
52 auto current_node{stack_.top()};
53 switch (GetState(current_node)) {
54 case SearchState::Unknown:
55 SetState(current_node, SearchState::Found);
56 break;
57 case SearchState::Found:
58 SetState(current_node, SearchState::Complete);
59 PushTsortResult(current_node);
60 stack_.pop();
61 continue;
62 case SearchState::Complete:
63 stack_.pop();
64 continue;
65 }
66
67 const auto edge_count{edge_matrix.GetNodeCount()};
68 for (u32 edge_id = 0; edge_id < edge_count; edge_id++) {
69 if (!edge_matrix.Connected(current_node, edge_id)) {
70 continue;
71 }
72
73 switch (GetState(edge_id)) {
74 case SearchState::Unknown:
75 stack_.push(edge_id);
76 break;
77 case SearchState::Found:
78 LOG_ERROR(Service_Audio,
79 "Cycle detected in the node graph, graph is not a DAG! "
80 "Bailing to avoid an infinite loop");
81 ResetState();
82 return false;
83 case SearchState::Complete:
84 break;
85 }
86 }
87 }
88 }
89
90 return true;
91}
92
93NodeStates::SearchState NodeStates::GetState(const u32 id) const {
94 if (nodes_found.buffer[id]) {
95 return SearchState::Found;
96 } else if (nodes_complete.buffer[id]) {
97 return SearchState::Complete;
98 }
99 return SearchState::Unknown;
100}
101
102void NodeStates::PushTsortResult(const u32 id) {
103 results[result_pos++] = id;
104}
105
106void NodeStates::SetState(const u32 id, const SearchState state) {
107 switch (state) {
108 case SearchState::Complete:
109 nodes_found.buffer[id] = false;
110 nodes_complete.buffer[id] = true;
111 break;
112 case SearchState::Found:
113 nodes_found.buffer[id] = true;
114 nodes_complete.buffer[id] = false;
115 break;
116 case SearchState::Unknown:
117 nodes_found.buffer[id] = false;
118 nodes_complete.buffer[id] = false;
119 break;
120 default:
121 LOG_ERROR(Service_Audio, "Unknown node SearchState {}", static_cast<u32>(state));
122 break;
123 }
124}
125
126void NodeStates::ResetState() {
127 nodes_found.reset();
128 nodes_complete.reset();
129 std::fill(results.begin(), results.end(), -1);
130 result_pos = 0;
131}
132
133u32 NodeStates::GetNodeCount() const {
134 return node_count;
135}
136
137std::vector<s32> NodeStates::GetSortedResuls() const {
138 return {results.rbegin(), results.rbegin() + result_pos};
139}
140
141} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/nodes/node_states.h b/src/audio_core/renderer/nodes/node_states.h
new file mode 100644
index 000000000..a1e0958a2
--- /dev/null
+++ b/src/audio_core/renderer/nodes/node_states.h
@@ -0,0 +1,195 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <span>
7#include <vector>
8
9#include "audio_core/renderer/nodes/edge_matrix.h"
10#include "common/alignment.h"
11#include "common/common_types.h"
12
13namespace AudioCore::AudioRenderer {
14/**
15 * Graph utility functions for sorting and getting results from the DAG.
16 */
17class NodeStates {
18 /**
19 * State of a node in the depth first search.
20 */
21 enum class SearchState {
22 Unknown,
23 Found,
24 Complete,
25 };
26
27 /**
28 * Stack used for a depth first search.
29 */
30 struct Stack {
31 /**
32 * Calculate the workbuffer size required for this stack.
33 *
34 * @param count - Maximum number of nodes for the stack.
35 * @return Required buffer size.
36 */
37 static u32 CalcBufferSize(u32 count) {
38 return count * sizeof(u32);
39 }
40
41 /**
42 * Reset the stack back to default.
43 *
44 * @param buffer_ - The new buffer to use.
45 * @param size_ - The size of the new buffer.
46 */
47 void Reset(u32* buffer_, u32 size_) {
48 stack = {buffer_, size_};
49 size = size_;
50 pos = 0;
51 unk_10 = size_;
52 }
53
54 /**
55 * Get the current stack position.
56 *
57 * @return The current stack position.
58 */
59 u32 Count() {
60 return pos;
61 }
62
63 /**
64 * Push a new node to the stack.
65 *
66 * @param data - The node to push.
67 */
68 void push(u32 data) {
69 stack[pos++] = data;
70 }
71
72 /**
73 * Pop a node from the stack.
74 *
75 * @return The node on the top of the stack.
76 */
77 u32 pop() {
78 return stack[--pos];
79 }
80
81 /**
82 * Get the top of the stack without popping.
83 *
84 * @return The node on the top of the stack.
85 */
86 u32 top() {
87 return stack[pos - 1];
88 }
89
90 /// Buffer for the stack
91 std::span<u32> stack{};
92 /// Size of the stack buffer
93 u32 size{};
94 /// Current stack position
95 u32 pos{};
96 /// Unknown
97 u32 unk_10{};
98 };
99
100public:
101 /**
102 * Calculate the workbuffer size required for the node states.
103 *
104 * @param count - The number of nodes.
105 * @return The required workbuffer size.
106 */
107 static u64 GetWorkBufferSize(u32 count) {
108 return (Common::AlignUp(count, 0x40) / sizeof(u64)) * 2 + count * sizeof(BitArray) +
109 count * Stack::CalcBufferSize(count);
110 }
111
112 /**
113 * Initialize the node states.
114 *
115 * @param buffer - The workbuffer to use. Unused.
116 * @param node_buffer_size - The size of the workbuffer. Unused.
117 * @param count - The number of nodes in the graph.
118 */
119 void Initialize(std::span<u8> nodes, u64 node_buffer_size, u32 count);
120
121 /**
122 * Sort the graph. Only calls DepthFirstSearch.
123 *
124 * @param edge_matrix - The edge matrix used to hold the connections between nodes.
125 * @return True if the sort was successful, otherwise false.
126 */
127 bool Tsort(const EdgeMatrix& edge_matrix);
128
129 /**
130 * Sort the graph via depth first search.
131 *
132 * @param edge_matrix - The edge matrix used to hold the connections between nodes.
133 * @param stack - The stack used for pushing and popping nodes.
134 * @return True if the sort was successful, otherwise false.
135 */
136 bool DepthFirstSearch(const EdgeMatrix& edge_matrix, Stack& stack);
137
138 /**
139 * Get the search state of a given node.
140 *
141 * @param id - The node id to check.
142 * @return The node's search state. See SearchState
143 */
144 SearchState GetState(u32 id) const;
145
146 /**
147 * Push a node id to the results buffer when found in the DFS.
148 *
149 * @param id - The node id to push.
150 */
151 void PushTsortResult(u32 id);
152
153 /**
154 * Set the state of a node.
155 *
156 * @param id - The node id to alter.
157 * @param state - The new search state.
158 */
159 void SetState(u32 id, SearchState state);
160
161 /**
162 * Reset the nodes found, complete and the results.
163 */
164 void ResetState();
165
166 /**
167 * Get the number of nodes in the graph.
168 *
169 * @return The number of nodes.
170 */
171 u32 GetNodeCount() const;
172
173 /**
174 * Get the sorted results from the DFS.
175 *
176 * @return Vector of nodes in reverse order.
177 */
178 std::vector<s32> GetSortedResuls() const;
179
180private:
181 /// Number of nodes in the graph
182 u32 node_count{};
183 /// Position in results buffer
184 u32 result_pos{};
185 /// List of nodes found
186 BitArray nodes_found{};
187 /// List of nodes completed
188 BitArray nodes_complete{};
189 /// List of results from the depth first search
190 std::span<u32> results{};
191 /// Stack used during the depth first search
192 Stack stack{};
193};
194
195} // namespace AudioCore::AudioRenderer