summaryrefslogtreecommitdiff
path: root/src/audio_core/renderer/adsp
diff options
context:
space:
mode:
authorGravatar Kelebek12023-08-31 15:09:15 +0100
committerGravatar Kelebek12023-09-04 17:12:16 +0100
commitebd19dec99d9809a669f63294745d7c8facc6d31 (patch)
treecd1f34cac0c091c2ffd16c429ac33b8fe133e06e /src/audio_core/renderer/adsp
parentMerge pull request #11420 from t895/long-install-fix (diff)
downloadyuzu-ebd19dec99d9809a669f63294745d7c8facc6d31.tar.gz
yuzu-ebd19dec99d9809a669f63294745d7c8facc6d31.tar.xz
yuzu-ebd19dec99d9809a669f63294745d7c8facc6d31.zip
Rework ADSP into a wrapper for apps
Diffstat (limited to 'src/audio_core/renderer/adsp')
-rw-r--r--src/audio_core/renderer/adsp/adsp.cpp117
-rw-r--r--src/audio_core/renderer/adsp/adsp.h171
-rw-r--r--src/audio_core/renderer/adsp/audio_renderer.cpp225
-rw-r--r--src/audio_core/renderer/adsp/audio_renderer.h204
-rw-r--r--src/audio_core/renderer/adsp/command_buffer.h21
-rw-r--r--src/audio_core/renderer/adsp/command_list_processor.cpp108
-rw-r--r--src/audio_core/renderer/adsp/command_list_processor.h119
7 files changed, 0 insertions, 965 deletions
diff --git a/src/audio_core/renderer/adsp/adsp.cpp b/src/audio_core/renderer/adsp/adsp.cpp
deleted file mode 100644
index b1db31e93..000000000
--- a/src/audio_core/renderer/adsp/adsp.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/adsp/adsp.h"
5#include "audio_core/renderer/adsp/command_buffer.h"
6#include "audio_core/sink/sink.h"
7#include "common/logging/log.h"
8#include "core/core.h"
9#include "core/core_timing.h"
10#include "core/memory.h"
11
12namespace AudioCore::AudioRenderer::ADSP {
13
14ADSP::ADSP(Core::System& system_, Sink::Sink& sink_)
15 : system{system_}, memory{system.ApplicationMemory()}, sink{sink_} {}
16
17ADSP::~ADSP() {
18 ClearCommandBuffers();
19}
20
21State ADSP::GetState() const {
22 if (running) {
23 return State::Started;
24 }
25 return State::Stopped;
26}
27
28AudioRenderer_Mailbox* ADSP::GetRenderMailbox() {
29 return &render_mailbox;
30}
31
32void ADSP::ClearRemainCount(const u32 session_id) {
33 render_mailbox.ClearRemainCount(session_id);
34}
35
36u64 ADSP::GetSignalledTick() const {
37 return render_mailbox.GetSignalledTick();
38}
39
40u64 ADSP::GetTimeTaken() const {
41 return render_mailbox.GetRenderTimeTaken();
42}
43
44u64 ADSP::GetRenderTimeTaken(const u32 session_id) {
45 return render_mailbox.GetCommandBuffer(session_id).render_time_taken;
46}
47
48u32 ADSP::GetRemainCommandCount(const u32 session_id) const {
49 return render_mailbox.GetRemainCommandCount(session_id);
50}
51
52void ADSP::SendCommandBuffer(const u32 session_id, const CommandBuffer& command_buffer) {
53 render_mailbox.SetCommandBuffer(session_id, command_buffer);
54}
55
56u64 ADSP::GetRenderingStartTick(const u32 session_id) {
57 return render_mailbox.GetSignalledTick() +
58 render_mailbox.GetCommandBuffer(session_id).render_time_taken;
59}
60
61bool ADSP::Start() {
62 if (running) {
63 return running;
64 }
65
66 running = true;
67 systems_active++;
68 audio_renderer = std::make_unique<AudioRenderer>(system);
69 audio_renderer->Start(&render_mailbox);
70 render_mailbox.HostSendMessage(RenderMessage::AudioRenderer_InitializeOK);
71 if (render_mailbox.HostWaitMessage() != RenderMessage::AudioRenderer_InitializeOK) {
72 LOG_ERROR(
73 Service_Audio,
74 "Host Audio Renderer -- Failed to receive initialize message response from ADSP!");
75 }
76 return running;
77}
78
79void ADSP::Stop() {
80 systems_active--;
81 if (running && systems_active == 0) {
82 {
83 std::scoped_lock l{mailbox_lock};
84 render_mailbox.HostSendMessage(RenderMessage::AudioRenderer_Shutdown);
85 if (render_mailbox.HostWaitMessage() != RenderMessage::AudioRenderer_Shutdown) {
86 LOG_ERROR(Service_Audio, "Host Audio Renderer -- Failed to receive shutdown "
87 "message response from ADSP!");
88 }
89 }
90 audio_renderer->Stop();
91 running = false;
92 }
93}
94
95void ADSP::Signal() {
96 const auto signalled_tick{system.CoreTiming().GetClockTicks()};
97 render_mailbox.SetSignalledTick(signalled_tick);
98 render_mailbox.HostSendMessage(RenderMessage::AudioRenderer_Render);
99}
100
101void ADSP::Wait() {
102 std::scoped_lock l{mailbox_lock};
103 auto response{render_mailbox.HostWaitMessage()};
104 if (response != RenderMessage::AudioRenderer_RenderResponse) {
105 LOG_ERROR(Service_Audio, "Invalid ADSP response message, expected 0x{:02X}, got 0x{:02X}",
106 static_cast<u32>(RenderMessage::AudioRenderer_RenderResponse),
107 static_cast<u32>(response));
108 }
109
110 ClearCommandBuffers();
111}
112
113void ADSP::ClearCommandBuffers() {
114 render_mailbox.ClearCommandBuffers();
115}
116
117} // namespace AudioCore::AudioRenderer::ADSP
diff --git a/src/audio_core/renderer/adsp/adsp.h b/src/audio_core/renderer/adsp/adsp.h
deleted file mode 100644
index f7a2f25e4..000000000
--- a/src/audio_core/renderer/adsp/adsp.h
+++ /dev/null
@@ -1,171 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <mutex>
8
9#include "audio_core/renderer/adsp/audio_renderer.h"
10#include "common/common_types.h"
11
12namespace Core {
13namespace Memory {
14class Memory;
15}
16class System;
17} // namespace Core
18
19namespace AudioCore {
20namespace Sink {
21class Sink;
22}
23
24namespace AudioRenderer::ADSP {
25struct CommandBuffer;
26
27enum class State {
28 Started,
29 Stopped,
30};
31
32/**
33 * Represents the ADSP embedded within the audio sysmodule.
34 * This is a 32-bit Linux4Tegra kernel from nVidia, which is launched with the sysmodule on boot.
35 *
36 * The kernel will run apps you program for it, Nintendo have the following:
37 *
38 * Gmix - Responsible for mixing final audio and sending it out to hardware. This is last place all
39 * audio samples end up, and we skip it entirely, since we have very different backends and
40 * mixing is implicitly handled by the OS (but also due to lack of research/simplicity).
41 *
42 * AudioRenderer - Receives command lists generated by the audio render
43 * system, processes them, and sends the samples to Gmix.
44 *
45 * OpusDecoder - Contains libopus, and controls processing Opus audio and sends it to Gmix.
46 * Not much research done here, TODO if needed.
47 *
48 * We only implement the AudioRenderer for now.
49 *
50 * Communication for the apps is done through mailboxes, and some shared memory.
51 */
52class ADSP {
53public:
54 explicit ADSP(Core::System& system, Sink::Sink& sink);
55 ~ADSP();
56
57 /**
58 * Start the ADSP.
59 *
60 * @return True if started or already running, otherwise false.
61 */
62 bool Start();
63
64 /**
65 * Stop the ADSP.
66 */
67 void Stop();
68
69 /**
70 * Get the ADSP's state.
71 *
72 * @return Started or Stopped.
73 */
74 State GetState() const;
75
76 /**
77 * Get the AudioRenderer mailbox to communicate with it.
78 *
79 * @return The AudioRenderer mailbox.
80 */
81 AudioRenderer_Mailbox* GetRenderMailbox();
82
83 /**
84 * Get the tick the ADSP was signalled.
85 *
86 * @return The tick the ADSP was signalled.
87 */
88 u64 GetSignalledTick() const;
89
90 /**
91 * Get the total time it took for the ADSP to run the last command lists (both command lists).
92 *
93 * @return The tick the ADSP was signalled.
94 */
95 u64 GetTimeTaken() const;
96
97 /**
98 * Get the last time a given command list took to run.
99 *
100 * @param session_id - The session id to check (0 or 1).
101 * @return The time it took.
102 */
103 u64 GetRenderTimeTaken(u32 session_id);
104
105 /**
106 * Clear the remaining command count for a given session.
107 *
108 * @param session_id - The session id to check (0 or 1).
109 */
110 void ClearRemainCount(u32 session_id);
111
112 /**
113 * Get the remaining number of commands left to process for a command list.
114 *
115 * @param session_id - The session id to check (0 or 1).
116 * @return The number of commands remaining.
117 */
118 u32 GetRemainCommandCount(u32 session_id) const;
119
120 /**
121 * Get the last tick a command list started processing.
122 *
123 * @param session_id - The session id to check (0 or 1).
124 * @return The last tick the given command list started.
125 */
126 u64 GetRenderingStartTick(u32 session_id);
127
128 /**
129 * Set a command buffer to be processed.
130 *
131 * @param session_id - The session id to check (0 or 1).
132 * @param command_buffer - The command buffer to process.
133 */
134 void SendCommandBuffer(u32 session_id, const CommandBuffer& command_buffer);
135
136 /**
137 * Clear the command buffers (does not clear the time taken or the remaining command count)
138 */
139 void ClearCommandBuffers();
140
141 /**
142 * Signal the AudioRenderer to begin processing.
143 */
144 void Signal();
145
146 /**
147 * Wait for the AudioRenderer to finish processing.
148 */
149 void Wait();
150
151private:
152 /// Core system
153 Core::System& system;
154 /// Core memory
155 Core::Memory::Memory& memory;
156 /// Number of systems active, used to prevent accidental shutdowns
157 u8 systems_active{0};
158 /// ADSP running state
159 std::atomic<bool> running{false};
160 /// Output sink used by the ADSP
161 Sink::Sink& sink;
162 /// AudioRenderer app
163 std::unique_ptr<AudioRenderer> audio_renderer{};
164 /// Communication for the AudioRenderer
165 AudioRenderer_Mailbox render_mailbox{};
166 /// Mailbox lock ffor the render mailbox
167 std::mutex mailbox_lock;
168};
169
170} // namespace AudioRenderer::ADSP
171} // namespace AudioCore
diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp
deleted file mode 100644
index 9ca716b60..000000000
--- a/src/audio_core/renderer/adsp/audio_renderer.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <array>
5#include <chrono>
6
7#include "audio_core/audio_core.h"
8#include "audio_core/common/common.h"
9#include "audio_core/renderer/adsp/audio_renderer.h"
10#include "audio_core/sink/sink.h"
11#include "common/logging/log.h"
12#include "common/microprofile.h"
13#include "common/thread.h"
14#include "core/core.h"
15#include "core/core_timing.h"
16
17MICROPROFILE_DEFINE(Audio_Renderer, "Audio", "DSP", MP_RGB(60, 19, 97));
18
19namespace AudioCore::AudioRenderer::ADSP {
20
21void AudioRenderer_Mailbox::HostSendMessage(RenderMessage message_) {
22 adsp_messages.enqueue(message_);
23 adsp_event.Set();
24}
25
26RenderMessage AudioRenderer_Mailbox::HostWaitMessage() {
27 host_event.Wait();
28 RenderMessage msg{RenderMessage::Invalid};
29 if (!host_messages.try_dequeue(msg)) {
30 LOG_ERROR(Service_Audio, "Failed to dequeue host message!");
31 }
32 return msg;
33}
34
35void AudioRenderer_Mailbox::ADSPSendMessage(const RenderMessage message_) {
36 host_messages.enqueue(message_);
37 host_event.Set();
38}
39
40RenderMessage AudioRenderer_Mailbox::ADSPWaitMessage() {
41 adsp_event.Wait();
42 RenderMessage msg{RenderMessage::Invalid};
43 if (!adsp_messages.try_dequeue(msg)) {
44 LOG_ERROR(Service_Audio, "Failed to dequeue ADSP message!");
45 }
46 return msg;
47}
48
49CommandBuffer& AudioRenderer_Mailbox::GetCommandBuffer(const u32 session_id) {
50 return command_buffers[session_id];
51}
52
53void AudioRenderer_Mailbox::SetCommandBuffer(const u32 session_id, const CommandBuffer& buffer) {
54 command_buffers[session_id] = buffer;
55}
56
57u64 AudioRenderer_Mailbox::GetRenderTimeTaken() const {
58 return command_buffers[0].render_time_taken + command_buffers[1].render_time_taken;
59}
60
61u64 AudioRenderer_Mailbox::GetSignalledTick() const {
62 return signalled_tick;
63}
64
65void AudioRenderer_Mailbox::SetSignalledTick(const u64 tick) {
66 signalled_tick = tick;
67}
68
69void AudioRenderer_Mailbox::ClearRemainCount(const u32 session_id) {
70 command_buffers[session_id].remaining_command_count = 0;
71}
72
73u32 AudioRenderer_Mailbox::GetRemainCommandCount(const u32 session_id) const {
74 return command_buffers[session_id].remaining_command_count;
75}
76
77void AudioRenderer_Mailbox::ClearCommandBuffers() {
78 command_buffers[0].buffer = 0;
79 command_buffers[0].size = 0;
80 command_buffers[0].reset_buffers = false;
81 command_buffers[1].buffer = 0;
82 command_buffers[1].size = 0;
83 command_buffers[1].reset_buffers = false;
84}
85
86AudioRenderer::AudioRenderer(Core::System& system_)
87 : system{system_}, sink{system.AudioCore().GetOutputSink()} {
88 CreateSinkStreams();
89}
90
91AudioRenderer::~AudioRenderer() {
92 Stop();
93 for (auto& stream : streams) {
94 if (stream) {
95 sink.CloseStream(stream);
96 }
97 stream = nullptr;
98 }
99}
100
101void AudioRenderer::Start(AudioRenderer_Mailbox* mailbox_) {
102 if (running) {
103 return;
104 }
105
106 mailbox = mailbox_;
107 thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(stop_token); });
108 running = true;
109}
110
111void AudioRenderer::Stop() {
112 if (!running) {
113 return;
114 }
115
116 for (auto& stream : streams) {
117 stream->Stop();
118 }
119 thread.join();
120 running = false;
121}
122
123void AudioRenderer::CreateSinkStreams() {
124 u32 channels{sink.GetDeviceChannels()};
125 for (u32 i = 0; i < MaxRendererSessions; i++) {
126 std::string name{fmt::format("ADSP_RenderStream-{}", i)};
127 streams[i] =
128 sink.AcquireSinkStream(system, channels, name, ::AudioCore::Sink::StreamType::Render);
129 streams[i]->SetRingSize(4);
130 }
131}
132
133void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
134 static constexpr char name[]{"AudioRenderer"};
135 MicroProfileOnThreadCreate(name);
136 Common::SetCurrentThreadName(name);
137 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
138 if (mailbox->ADSPWaitMessage() != RenderMessage::AudioRenderer_InitializeOK) {
139 LOG_ERROR(Service_Audio,
140 "ADSP Audio Renderer -- Failed to receive initialize message from host!");
141 return;
142 }
143
144 mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_InitializeOK);
145
146 // 0.12 seconds (2304000 / 19200000)
147 constexpr u64 max_process_time{2'304'000ULL};
148
149 while (!stop_token.stop_requested()) {
150 auto message{mailbox->ADSPWaitMessage()};
151 switch (message) {
152 case RenderMessage::AudioRenderer_Shutdown:
153 mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_Shutdown);
154 return;
155
156 case RenderMessage::AudioRenderer_Render: {
157 if (system.IsShuttingDown()) [[unlikely]] {
158 std::this_thread::sleep_for(std::chrono::milliseconds(5));
159 mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_RenderResponse);
160 continue;
161 }
162 std::array<bool, MaxRendererSessions> buffers_reset{};
163 std::array<u64, MaxRendererSessions> render_times_taken{};
164 const auto start_time{system.CoreTiming().GetClockTicks()};
165
166 for (u32 index = 0; index < 2; index++) {
167 auto& command_buffer{mailbox->GetCommandBuffer(index)};
168 auto& command_list_processor{command_list_processors[index]};
169
170 // Check this buffer is valid, as it may not be used.
171 if (command_buffer.buffer != 0) {
172 // If there are no remaining commands (from the previous list),
173 // this is a new command list, initialize it.
174 if (command_buffer.remaining_command_count == 0) {
175 command_list_processor.Initialize(system, command_buffer.buffer,
176 command_buffer.size, streams[index]);
177 }
178
179 if (command_buffer.reset_buffers && !buffers_reset[index]) {
180 streams[index]->ClearQueue();
181 buffers_reset[index] = true;
182 }
183
184 u64 max_time{max_process_time};
185 if (index == 1 && command_buffer.applet_resource_user_id ==
186 mailbox->GetCommandBuffer(0).applet_resource_user_id) {
187 max_time = max_process_time - render_times_taken[0];
188 if (render_times_taken[0] > max_process_time) {
189 max_time = 0;
190 }
191 }
192
193 max_time = std::min(command_buffer.time_limit, max_time);
194 command_list_processor.SetProcessTimeMax(max_time);
195
196 streams[index]->WaitFreeSpace(stop_token);
197
198 // Process the command list
199 {
200 MICROPROFILE_SCOPE(Audio_Renderer);
201 render_times_taken[index] =
202 command_list_processor.Process(index) - start_time;
203 }
204
205 const auto end_time{system.CoreTiming().GetClockTicks()};
206
207 command_buffer.remaining_command_count =
208 command_list_processor.GetRemainingCommandCount();
209 command_buffer.render_time_taken = end_time - start_time;
210 }
211 }
212
213 mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_RenderResponse);
214 } break;
215
216 default:
217 LOG_WARNING(Service_Audio,
218 "ADSP AudioRenderer received an invalid message, msg={:02X}!",
219 static_cast<u32>(message));
220 break;
221 }
222 }
223}
224
225} // namespace AudioCore::AudioRenderer::ADSP
diff --git a/src/audio_core/renderer/adsp/audio_renderer.h b/src/audio_core/renderer/adsp/audio_renderer.h
deleted file mode 100644
index 88e558183..000000000
--- a/src/audio_core/renderer/adsp/audio_renderer.h
+++ /dev/null
@@ -1,204 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <memory>
8#include <thread>
9
10#include "audio_core/renderer/adsp/command_buffer.h"
11#include "audio_core/renderer/adsp/command_list_processor.h"
12#include "common/common_types.h"
13#include "common/polyfill_thread.h"
14#include "common/reader_writer_queue.h"
15#include "common/thread.h"
16
17namespace Core {
18namespace Timing {
19struct EventType;
20}
21class System;
22} // namespace Core
23
24namespace AudioCore {
25namespace Sink {
26class Sink;
27}
28
29namespace AudioRenderer::ADSP {
30
31enum class RenderMessage {
32 /* 0x00 */ Invalid,
33 /* 0x01 */ AudioRenderer_MapUnmap_Map,
34 /* 0x02 */ AudioRenderer_MapUnmap_MapResponse,
35 /* 0x03 */ AudioRenderer_MapUnmap_Unmap,
36 /* 0x04 */ AudioRenderer_MapUnmap_UnmapResponse,
37 /* 0x05 */ AudioRenderer_MapUnmap_InvalidateCache,
38 /* 0x06 */ AudioRenderer_MapUnmap_InvalidateCacheResponse,
39 /* 0x07 */ AudioRenderer_MapUnmap_Shutdown,
40 /* 0x08 */ AudioRenderer_MapUnmap_ShutdownResponse,
41 /* 0x16 */ AudioRenderer_InitializeOK = 0x16,
42 /* 0x20 */ AudioRenderer_RenderResponse = 0x20,
43 /* 0x2A */ AudioRenderer_Render = 0x2A,
44 /* 0x34 */ AudioRenderer_Shutdown = 0x34,
45};
46
47/**
48 * A mailbox for the AudioRenderer, allowing communication between the host and the AudioRenderer
49 * running on the ADSP.
50 */
51class AudioRenderer_Mailbox {
52public:
53 /**
54 * Send a message from the host to the AudioRenderer.
55 *
56 * @param message - The message to send to the AudioRenderer.
57 */
58 void HostSendMessage(RenderMessage message);
59
60 /**
61 * Host wait for a message from the AudioRenderer.
62 *
63 * @return The message returned from the AudioRenderer.
64 */
65 RenderMessage HostWaitMessage();
66
67 /**
68 * Send a message from the AudioRenderer to the host.
69 *
70 * @param message - The message to send to the host.
71 */
72 void ADSPSendMessage(RenderMessage message);
73
74 /**
75 * AudioRenderer wait for a message from the host.
76 *
77 * @return The message returned from the AudioRenderer.
78 */
79 RenderMessage ADSPWaitMessage();
80
81 /**
82 * Get the command buffer with the given session id (0 or 1).
83 *
84 * @param session_id - The session id to get (0 or 1).
85 * @return The command buffer.
86 */
87 CommandBuffer& GetCommandBuffer(u32 session_id);
88
89 /**
90 * Set the command buffer with the given session id (0 or 1).
91 *
92 * @param session_id - The session id to get (0 or 1).
93 * @param buffer - The command buffer to set.
94 */
95 void SetCommandBuffer(u32 session_id, const CommandBuffer& buffer);
96
97 /**
98 * Get the total render time taken for the last command lists sent.
99 *
100 * @return Total render time taken for the last command lists.
101 */
102 u64 GetRenderTimeTaken() const;
103
104 /**
105 * Get the tick the AudioRenderer was signalled.
106 *
107 * @return The tick the AudioRenderer was signalled.
108 */
109 u64 GetSignalledTick() const;
110
111 /**
112 * Set the tick the AudioRenderer was signalled.
113 *
114 * @param tick - The tick the AudioRenderer was signalled.
115 */
116 void SetSignalledTick(u64 tick);
117
118 /**
119 * Clear the remaining command count.
120 *
121 * @param session_id - Index for which command list to clear (0 or 1).
122 */
123 void ClearRemainCount(u32 session_id);
124
125 /**
126 * Get the remaining command count for a given command list.
127 *
128 * @param session_id - Index for which command list to clear (0 or 1).
129 * @return The remaining command count.
130 */
131 u32 GetRemainCommandCount(u32 session_id) const;
132
133 /**
134 * Clear the command buffers (does not clear the time taken or the remaining command count).
135 */
136 void ClearCommandBuffers();
137
138private:
139 /// Host signalling event
140 Common::Event host_event{};
141 /// AudioRenderer signalling event
142 Common::Event adsp_event{};
143 /// Host message queue
144
145 Common::ReaderWriterQueue<RenderMessage> host_messages{};
146 /// AudioRenderer message queue
147
148 Common::ReaderWriterQueue<RenderMessage> adsp_messages{};
149 /// Command buffers
150
151 std::array<CommandBuffer, MaxRendererSessions> command_buffers{};
152 /// Tick the AudioRnederer was signalled
153 u64 signalled_tick{};
154};
155
156/**
157 * The AudioRenderer application running on the ADSP.
158 */
159class AudioRenderer {
160public:
161 explicit AudioRenderer(Core::System& system);
162 ~AudioRenderer();
163
164 /**
165 * Start the AudioRenderer.
166 *
167 * @param mailbox The mailbox to use for this session.
168 */
169 void Start(AudioRenderer_Mailbox* mailbox);
170
171 /**
172 * Stop the AudioRenderer.
173 */
174 void Stop();
175
176private:
177 /**
178 * Main AudioRenderer thread, responsible for processing the command lists.
179 */
180 void ThreadFunc(std::stop_token stop_token);
181
182 /**
183 * Creates the streams which will receive the processed samples.
184 */
185 void CreateSinkStreams();
186
187 /// Core system
188 Core::System& system;
189 /// Main thread
190 std::jthread thread{};
191 /// The current state
192 std::atomic<bool> running{};
193 /// The active mailbox
194 AudioRenderer_Mailbox* mailbox{};
195 /// The command lists to process
196 std::array<CommandListProcessor, MaxRendererSessions> command_list_processors{};
197 /// The output sink the AudioRenderer will use
198 Sink::Sink& sink;
199 /// The streams which will receive the processed samples
200 std::array<Sink::SinkStream*, MaxRendererSessions> streams;
201};
202
203} // namespace AudioRenderer::ADSP
204} // namespace AudioCore
diff --git a/src/audio_core/renderer/adsp/command_buffer.h b/src/audio_core/renderer/adsp/command_buffer.h
deleted file mode 100644
index 880b279d8..000000000
--- a/src/audio_core/renderer/adsp/command_buffer.h
+++ /dev/null
@@ -1,21 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/common/common.h"
7#include "common/common_types.h"
8
9namespace AudioCore::AudioRenderer::ADSP {
10
11struct CommandBuffer {
12 CpuAddr buffer;
13 u64 size;
14 u64 time_limit;
15 u32 remaining_command_count;
16 bool reset_buffers;
17 u64 applet_resource_user_id;
18 u64 render_time_taken;
19};
20
21} // namespace AudioCore::AudioRenderer::ADSP
diff --git a/src/audio_core/renderer/adsp/command_list_processor.cpp b/src/audio_core/renderer/adsp/command_list_processor.cpp
deleted file mode 100644
index 3a0f1ae38..000000000
--- a/src/audio_core/renderer/adsp/command_list_processor.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <string>
5
6#include "audio_core/renderer/adsp/command_list_processor.h"
7#include "audio_core/renderer/command/command_list_header.h"
8#include "audio_core/renderer/command/commands.h"
9#include "common/settings.h"
10#include "core/core.h"
11#include "core/core_timing.h"
12#include "core/memory.h"
13
14namespace AudioCore::AudioRenderer::ADSP {
15
16void CommandListProcessor::Initialize(Core::System& system_, CpuAddr buffer, u64 size,
17 Sink::SinkStream* stream_) {
18 system = &system_;
19 memory = &system->ApplicationMemory();
20 stream = stream_;
21 header = reinterpret_cast<CommandListHeader*>(buffer);
22 commands = reinterpret_cast<u8*>(buffer + sizeof(CommandListHeader));
23 commands_buffer_size = size;
24 command_count = header->command_count;
25 sample_count = header->sample_count;
26 target_sample_rate = header->sample_rate;
27 mix_buffers = header->samples_buffer;
28 buffer_count = header->buffer_count;
29 processed_command_count = 0;
30}
31
32void CommandListProcessor::SetProcessTimeMax(const u64 time) {
33 max_process_time = time;
34}
35
36u32 CommandListProcessor::GetRemainingCommandCount() const {
37 return command_count - processed_command_count;
38}
39
40void CommandListProcessor::SetBuffer(const CpuAddr buffer, const u64 size) {
41 commands = reinterpret_cast<u8*>(buffer + sizeof(CommandListHeader));
42 commands_buffer_size = size;
43}
44
45Sink::SinkStream* CommandListProcessor::GetOutputSinkStream() const {
46 return stream;
47}
48
49u64 CommandListProcessor::Process(u32 session_id) {
50 const auto start_time_{system->CoreTiming().GetClockTicks()};
51 const auto command_base{CpuAddr(commands)};
52
53 if (processed_command_count > 0) {
54 current_processing_time += start_time_ - end_time;
55 } else {
56 start_time = start_time_;
57 current_processing_time = 0;
58 }
59
60 std::string dump{fmt::format("\nSession {}\n", session_id)};
61
62 for (u32 index = 0; index < command_count; index++) {
63 auto& command{*reinterpret_cast<ICommand*>(commands)};
64
65 if (command.magic != 0xCAFEBABE) {
66 LOG_ERROR(Service_Audio, "Command has invalid magic! Expected 0xCAFEBABE, got {:08X}",
67 command.magic);
68 return system->CoreTiming().GetClockTicks() - start_time_;
69 }
70
71 auto current_offset{CpuAddr(commands) - command_base};
72
73 if (current_offset + command.size > commands_buffer_size) {
74 LOG_ERROR(Service_Audio,
75 "Command exceeded command buffer, buffer size {:08X}, command ends at {:08X}",
76 commands_buffer_size,
77 CpuAddr(commands) + command.size - sizeof(CommandListHeader));
78 return system->CoreTiming().GetClockTicks() - start_time_;
79 }
80
81 if (Settings::values.dump_audio_commands) {
82 command.Dump(*this, dump);
83 }
84
85 if (!command.Verify(*this)) {
86 break;
87 }
88
89 if (command.enabled) {
90 command.Process(*this);
91 } else {
92 dump += fmt::format("\tDisabled!\n");
93 }
94
95 processed_command_count++;
96 commands += command.size;
97 }
98
99 if (Settings::values.dump_audio_commands && dump != last_dump) {
100 LOG_WARNING(Service_Audio, "{}", dump);
101 last_dump = dump;
102 }
103
104 end_time = system->CoreTiming().GetClockTicks();
105 return end_time - start_time_;
106}
107
108} // namespace AudioCore::AudioRenderer::ADSP
diff --git a/src/audio_core/renderer/adsp/command_list_processor.h b/src/audio_core/renderer/adsp/command_list_processor.h
deleted file mode 100644
index d78269e1d..000000000
--- a/src/audio_core/renderer/adsp/command_list_processor.h
+++ /dev/null
@@ -1,119 +0,0 @@
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/common/common.h"
9#include "common/common_types.h"
10
11namespace Core {
12namespace Memory {
13class Memory;
14}
15class System;
16} // namespace Core
17
18namespace AudioCore {
19namespace Sink {
20class SinkStream;
21}
22
23namespace AudioRenderer {
24struct CommandListHeader;
25
26namespace ADSP {
27
28/**
29 * A processor for command lists given to the AudioRenderer.
30 */
31class CommandListProcessor {
32public:
33 /**
34 * Initialize the processor.
35 *
36 * @param system - The core system.
37 * @param buffer - The command buffer to process.
38 * @param size - The size of the buffer.
39 * @param stream - The stream to be used for sending the samples.
40 */
41 void Initialize(Core::System& system, CpuAddr buffer, u64 size, Sink::SinkStream* stream);
42
43 /**
44 * Set the maximum processing time for this command list.
45 *
46 * @param time - The maximum process time.
47 */
48 void SetProcessTimeMax(u64 time);
49
50 /**
51 * Get the remaining command count for this list.
52 *
53 * @return The remaining command count.
54 */
55 u32 GetRemainingCommandCount() const;
56
57 /**
58 * Set the command buffer.
59 *
60 * @param buffer - The buffer to use.
61 * @param size - The size of the buffer.
62 */
63 void SetBuffer(CpuAddr buffer, u64 size);
64
65 /**
66 * Get the stream for this command list.
67 *
68 * @return The stream associated with this command list.
69 */
70 Sink::SinkStream* GetOutputSinkStream() const;
71
72 /**
73 * Process the command list.
74 *
75 * @param session_id - Session ID for the commands being processed.
76 *
77 * @return The time taken to process.
78 */
79 u64 Process(u32 session_id);
80
81 /// Core system
82 Core::System* system{};
83 /// Core memory
84 Core::Memory::Memory* memory{};
85 /// Stream for the processed samples
86 Sink::SinkStream* stream{};
87 /// Header info for this command list
88 CommandListHeader* header{};
89 /// The command buffer
90 u8* commands{};
91 /// The command buffer size
92 u64 commands_buffer_size{};
93 /// The maximum processing time allotted
94 u64 max_process_time{};
95 /// The number of commands in the buffer
96 u32 command_count{};
97 /// The target sample count for output
98 u32 sample_count{};
99 /// The target sample rate for output
100 u32 target_sample_rate{};
101 /// The mixing buffers used by the commands
102 std::span<s32> mix_buffers{};
103 /// The number of mix buffers
104 u32 buffer_count{};
105 /// The number of processed commands so far
106 u32 processed_command_count{};
107 /// The processing start time of this list
108 u64 start_time{};
109 /// The current processing time for this list
110 u64 current_processing_time{};
111 /// The end processing time for this list
112 u64 end_time{};
113 /// Last command list string generated, used for dumping audio commands to console
114 std::string last_dump{};
115};
116
117} // namespace ADSP
118} // namespace AudioRenderer
119} // namespace AudioCore