summaryrefslogtreecommitdiff
path: root/src/audio_core/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/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/adsp')
-rw-r--r--src/audio_core/adsp/adsp.cpp18
-rw-r--r--src/audio_core/adsp/adsp.h50
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp215
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/audio_renderer.h115
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/command_buffer.h23
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/command_list_processor.cpp108
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/command_list_processor.h120
-rw-r--r--src/audio_core/adsp/mailbox.h69
8 files changed, 718 insertions, 0 deletions
diff --git a/src/audio_core/adsp/adsp.cpp b/src/audio_core/adsp/adsp.cpp
new file mode 100644
index 000000000..0580990f5
--- /dev/null
+++ b/src/audio_core/adsp/adsp.cpp
@@ -0,0 +1,18 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/adsp/adsp.h"
5#include "core/core.h"
6
7namespace AudioCore::ADSP {
8
9ADSP::ADSP(Core::System& system, Sink::Sink& sink) {
10 audio_renderer =
11 std::make_unique<AudioRenderer::AudioRenderer>(system, system.ApplicationMemory(), sink);
12}
13
14AudioRenderer::AudioRenderer& ADSP::AudioRenderer() {
15 return *audio_renderer.get();
16}
17
18} // namespace AudioCore::ADSP
diff --git a/src/audio_core/adsp/adsp.h b/src/audio_core/adsp/adsp.h
new file mode 100644
index 000000000..bd5bcc63b
--- /dev/null
+++ b/src/audio_core/adsp/adsp.h
@@ -0,0 +1,50 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/adsp/apps/audio_renderer/audio_renderer.h"
7#include "common/common_types.h"
8
9namespace Core {
10class System;
11} // namespace Core
12
13namespace AudioCore {
14namespace Sink {
15class Sink;
16}
17
18namespace ADSP {
19
20/**
21 * Represents the ADSP embedded within the audio sysmodule.
22 * This is a 32-bit Linux4Tegra kernel from nVidia, which is launched with the sysmodule on boot.
23 *
24 * The kernel will run the apps you write for it, Nintendo have the following:
25 *
26 * Gmix - Responsible for mixing final audio and sending it out to hardware. This is last place all
27 * audio samples end up, and we skip it entirely, since we have very different backends and
28 * mixing is implicitly handled by the OS (but also due to lack of research/simplicity).
29 *
30 * AudioRenderer - Receives command lists generated by the audio render
31 * system on the host, processes them, and sends the samples to Gmix.
32 *
33 * OpusDecoder - Contains libopus, and decodes Opus audio packets into raw pcm data.
34 *
35 * Communication between the host and ADSP is done through mailboxes, and mapping of shared memory.
36 */
37class ADSP {
38public:
39 explicit ADSP(Core::System& system, Sink::Sink& sink);
40 ~ADSP() = default;
41
42 AudioRenderer::AudioRenderer& AudioRenderer();
43
44private:
45 /// AudioRenderer app
46 std::unique_ptr<AudioRenderer::AudioRenderer> audio_renderer{};
47};
48
49} // namespace ADSP
50} // namespace AudioCore
diff --git a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp
new file mode 100644
index 000000000..3da342ea3
--- /dev/null
+++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp
@@ -0,0 +1,215 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <array>
5#include <chrono>
6
7#include "audio_core/adsp/apps/audio_renderer/audio_renderer.h"
8#include "audio_core/audio_core.h"
9#include "audio_core/common/common.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::ADSP::AudioRenderer {
20
21AudioRenderer::AudioRenderer(Core::System& system_, Core::Memory::Memory& memory_,
22 Sink::Sink& sink_)
23 : system{system_}, memory{memory_}, sink{sink_} {}
24
25AudioRenderer::~AudioRenderer() {
26 Stop();
27}
28
29void AudioRenderer::Start() {
30 CreateSinkStreams();
31
32 mailbox.Initialize(AppMailboxId::AudioRenderer);
33
34 main_thread = std::jthread([this](std::stop_token stop_token) { Main(stop_token); });
35
36 mailbox.Send(Direction::DSP, {Message::InitializeOK, {}});
37 if (mailbox.Receive(Direction::Host).msg != Message::InitializeOK) {
38 LOG_ERROR(Service_Audio, "Host Audio Renderer -- Failed to receive shutdown "
39 "message response from ADSP!");
40 return;
41 }
42 running = true;
43}
44
45void AudioRenderer::Stop() {
46 if (!running) {
47 return;
48 }
49
50 mailbox.Send(Direction::DSP, {Message::Shutdown, {}});
51 if (mailbox.Receive(Direction::Host).msg != Message::Shutdown) {
52 LOG_ERROR(Service_Audio, "Host Audio Renderer -- Failed to receive shutdown "
53 "message response from ADSP!");
54 }
55 main_thread.request_stop();
56 main_thread.join();
57
58 for (auto& stream : streams) {
59 if (stream) {
60 stream->Stop();
61 sink.CloseStream(stream);
62 stream = nullptr;
63 }
64 }
65 running = false;
66}
67
68void AudioRenderer::Signal() {
69 signalled_tick = system.CoreTiming().GetGlobalTimeNs().count();
70 Send(Direction::DSP, {Message::Render, {}});
71}
72
73void AudioRenderer::Wait() {
74 auto received = Receive(Direction::Host);
75 if (received.msg != Message::RenderResponse) {
76 LOG_ERROR(Service_Audio,
77 "Did not receive the expected render response from the AudioRenderer! Expected "
78 "{}, got {}",
79 Message::RenderResponse, received.msg);
80 }
81}
82
83void AudioRenderer::Send(Direction dir, MailboxMessage message) {
84 mailbox.Send(dir, std::move(message));
85}
86
87MailboxMessage AudioRenderer::Receive(Direction dir, bool block) {
88 return mailbox.Receive(dir, block);
89}
90
91void AudioRenderer::SetCommandBuffer(s32 session_id, CommandBuffer& buffer) noexcept {
92 command_buffers[session_id] = buffer;
93}
94
95u32 AudioRenderer::GetRemainCommandCount(s32 session_id) const noexcept {
96 return command_buffers[session_id].remaining_command_count;
97}
98
99void AudioRenderer::ClearRemainCommandCount(s32 session_id) noexcept {
100 command_buffers[session_id].remaining_command_count = 0;
101}
102
103u64 AudioRenderer::GetRenderingStartTick(s32 session_id) const noexcept {
104 return (1000 * command_buffers[session_id].render_time_taken_us) + signalled_tick;
105}
106
107void AudioRenderer::CreateSinkStreams() {
108 u32 channels{sink.GetDeviceChannels()};
109 for (u32 i = 0; i < MaxRendererSessions; i++) {
110 std::string name{fmt::format("ADSP_RenderStream-{}", i)};
111 streams[i] =
112 sink.AcquireSinkStream(system, channels, name, ::AudioCore::Sink::StreamType::Render);
113 streams[i]->SetRingSize(4);
114 }
115}
116
117void AudioRenderer::Main(std::stop_token stop_token) {
118 static constexpr char name[]{"AudioRenderer"};
119 MicroProfileOnThreadCreate(name);
120 Common::SetCurrentThreadName(name);
121 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
122
123 // TODO: Create buffer map/unmap thread + mailbox
124 // TODO: Create gMix devices, initialize them here
125
126 if (mailbox.Receive(Direction::DSP).msg != Message::InitializeOK) {
127 LOG_ERROR(Service_Audio,
128 "ADSP Audio Renderer -- Failed to receive initialize message from host!");
129 return;
130 }
131
132 mailbox.Send(Direction::Host, {Message::InitializeOK, {}});
133
134 // 0.12 seconds (2,304,000 / 19,200,000)
135 constexpr u64 max_process_time{2'304'000ULL};
136
137 while (!stop_token.stop_requested()) {
138 auto received{mailbox.Receive(Direction::DSP)};
139 switch (received.msg) {
140 case Message::Shutdown:
141 mailbox.Send(Direction::Host, {Message::Shutdown, {}});
142 return;
143
144 case Message::Render: {
145 if (system.IsShuttingDown()) [[unlikely]] {
146 std::this_thread::sleep_for(std::chrono::milliseconds(5));
147 mailbox.Send(Direction::Host, {Message::RenderResponse, {}});
148 continue;
149 }
150 std::array<bool, MaxRendererSessions> buffers_reset{};
151 std::array<u64, MaxRendererSessions> render_times_taken{};
152 const auto start_time{system.CoreTiming().GetGlobalTimeUs().count()};
153
154 for (u32 index = 0; index < MaxRendererSessions; index++) {
155 auto& command_buffer{command_buffers[index]};
156 auto& command_list_processor{command_list_processors[index]};
157
158 // Check this buffer is valid, as it may not be used.
159 if (command_buffer.buffer != 0) {
160 // If there are no remaining commands (from the previous list),
161 // this is a new command list, initialize it.
162 if (command_buffer.remaining_command_count == 0) {
163 command_list_processor.Initialize(system, command_buffer.buffer,
164 command_buffer.size, streams[index]);
165 }
166
167 if (command_buffer.reset_buffer && !buffers_reset[index]) {
168 streams[index]->ClearQueue();
169 buffers_reset[index] = true;
170 }
171
172 u64 max_time{max_process_time};
173 if (index == 1 && command_buffer.applet_resource_user_id ==
174 command_buffers[0].applet_resource_user_id) {
175 max_time = max_process_time - render_times_taken[0];
176 if (render_times_taken[0] > max_process_time) {
177 max_time = 0;
178 }
179 }
180
181 max_time = std::min(command_buffer.time_limit, max_time);
182 command_list_processor.SetProcessTimeMax(max_time);
183
184 if (index == 0) {
185 streams[index]->WaitFreeSpace(stop_token);
186 }
187
188 // Process the command list
189 {
190 MICROPROFILE_SCOPE(Audio_Renderer);
191 render_times_taken[index] =
192 command_list_processor.Process(index) - start_time;
193 }
194
195 const auto end_time{system.CoreTiming().GetGlobalTimeUs().count()};
196
197 command_buffer.remaining_command_count =
198 command_list_processor.GetRemainingCommandCount();
199 command_buffer.render_time_taken_us = end_time - start_time;
200 }
201 }
202
203 mailbox.Send(Direction::Host, {Message::RenderResponse, {}});
204 } break;
205
206 default:
207 LOG_WARNING(Service_Audio,
208 "ADSP AudioRenderer received an invalid message, msg={:02X}!",
209 received.msg);
210 break;
211 }
212 }
213}
214
215} // namespace AudioCore::ADSP::AudioRenderer
diff --git a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h
new file mode 100644
index 000000000..b225e10fb
--- /dev/null
+++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h
@@ -0,0 +1,115 @@
1// SPDX-FileCopyrightText: Copyright 2023 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/adsp/apps/audio_renderer/command_buffer.h"
11#include "audio_core/adsp/apps/audio_renderer/command_list_processor.h"
12#include "audio_core/adsp/mailbox.h"
13#include "common/common_types.h"
14#include "common/polyfill_thread.h"
15#include "common/reader_writer_queue.h"
16#include "common/thread.h"
17
18namespace Core {
19class System;
20namespace Timing {
21struct EventType;
22}
23namespace Memory {
24class Memory;
25}
26class System;
27} // namespace Core
28
29namespace AudioCore {
30namespace Sink {
31class Sink;
32}
33
34namespace ADSP::AudioRenderer {
35
36enum Message : u32 {
37 Invalid = 0x00,
38 MapUnmap_Map = 0x01,
39 MapUnmap_MapResponse = 0x02,
40 MapUnmap_Unmap = 0x03,
41 MapUnmap_UnmapResponse = 0x04,
42 MapUnmap_InvalidateCache = 0x05,
43 MapUnmap_InvalidateCacheResponse = 0x06,
44 MapUnmap_Shutdown = 0x07,
45 MapUnmap_ShutdownResponse = 0x08,
46 InitializeOK = 0x16,
47 RenderResponse = 0x20,
48 Render = 0x2A,
49 Shutdown = 0x34,
50};
51
52/**
53 * The AudioRenderer application running on the ADSP.
54 */
55class AudioRenderer {
56public:
57 explicit AudioRenderer(Core::System& system, Core::Memory::Memory& memory, Sink::Sink& sink);
58 ~AudioRenderer();
59
60 /**
61 * Start the AudioRenderer.
62 *
63 * @param mailbox The mailbox to use for this session.
64 */
65 void Start();
66
67 /**
68 * Stop the AudioRenderer.
69 */
70 void Stop();
71
72 void Signal();
73 void Wait();
74
75 void Send(Direction dir, MailboxMessage message);
76 MailboxMessage Receive(Direction dir, bool block = true);
77
78 void SetCommandBuffer(s32 session_id, CommandBuffer& buffer) noexcept;
79 u32 GetRemainCommandCount(s32 session_id) const noexcept;
80 void ClearRemainCommandCount(s32 session_id) noexcept;
81 u64 GetRenderingStartTick(s32 session_id) const noexcept;
82
83private:
84 /**
85 * Main AudioRenderer thread, responsible for processing the command lists.
86 */
87 void Main(std::stop_token stop_token);
88
89 /**
90 * Creates the streams which will receive the processed samples.
91 */
92 void CreateSinkStreams();
93
94 /// Core system
95 Core::System& system;
96 /// Memory
97 Core::Memory::Memory& memory;
98 /// The output sink the AudioRenderer will use
99 Sink::Sink& sink;
100 /// The active mailbox
101 Mailbox mailbox;
102 /// Main thread
103 std::jthread main_thread{};
104 /// The current state
105 std::atomic<bool> running{};
106 std::array<CommandBuffer, MaxRendererSessions> command_buffers{};
107 /// The command lists to process
108 std::array<CommandListProcessor, MaxRendererSessions> command_list_processors{};
109 /// The streams which will receive the processed samples
110 std::array<Sink::SinkStream*, MaxRendererSessions> streams{};
111 u64 signalled_tick{0};
112};
113
114} // namespace ADSP::AudioRenderer
115} // namespace AudioCore
diff --git a/src/audio_core/adsp/apps/audio_renderer/command_buffer.h b/src/audio_core/adsp/apps/audio_renderer/command_buffer.h
new file mode 100644
index 000000000..3fd1b09dc
--- /dev/null
+++ b/src/audio_core/adsp/apps/audio_renderer/command_buffer.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2023 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::ADSP::AudioRenderer {
10
11struct CommandBuffer {
12 // Set by the host
13 CpuAddr buffer{};
14 u64 size{};
15 u64 time_limit{};
16 u64 applet_resource_user_id{};
17 bool reset_buffer{};
18 // Set by the DSP
19 u32 remaining_command_count{};
20 u64 render_time_taken_us{};
21};
22
23} // namespace AudioCore::ADSP::AudioRenderer
diff --git a/src/audio_core/adsp/apps/audio_renderer/command_list_processor.cpp b/src/audio_core/adsp/apps/audio_renderer/command_list_processor.cpp
new file mode 100644
index 000000000..acbc9100c
--- /dev/null
+++ b/src/audio_core/adsp/apps/audio_renderer/command_list_processor.cpp
@@ -0,0 +1,108 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <string>
5
6#include "audio_core/adsp/apps/audio_renderer/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::ADSP::AudioRenderer {
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<Renderer::CommandListHeader*>(buffer);
22 commands = reinterpret_cast<u8*>(buffer + sizeof(Renderer::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(Renderer::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().GetGlobalTimeUs().count()};
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<Renderer::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().GetGlobalTimeUs().count() - 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(Renderer::CommandListHeader));
78 return system->CoreTiming().GetGlobalTimeUs().count() - 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().GetGlobalTimeUs().count();
105 return end_time - start_time_;
106}
107
108} // namespace AudioCore::ADSP::AudioRenderer
diff --git a/src/audio_core/adsp/apps/audio_renderer/command_list_processor.h b/src/audio_core/adsp/apps/audio_renderer/command_list_processor.h
new file mode 100644
index 000000000..9d6fe1851
--- /dev/null
+++ b/src/audio_core/adsp/apps/audio_renderer/command_list_processor.h
@@ -0,0 +1,120 @@
1// SPDX-FileCopyrightText: Copyright 2023 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 "audio_core/renderer/command/command_list_header.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 SinkStream;
22}
23
24namespace Renderer {
25struct CommandListHeader;
26}
27
28namespace ADSP::AudioRenderer {
29
30/**
31 * A processor for command lists given to the AudioRenderer.
32 */
33class CommandListProcessor {
34public:
35 /**
36 * Initialize the processor.
37 *
38 * @param system - The core system.
39 * @param buffer - The command buffer to process.
40 * @param size - The size of the buffer.
41 * @param stream - The stream to be used for sending the samples.
42 */
43 void Initialize(Core::System& system, CpuAddr buffer, u64 size, Sink::SinkStream* stream);
44
45 /**
46 * Set the maximum processing time for this command list.
47 *
48 * @param time - The maximum process time.
49 */
50 void SetProcessTimeMax(u64 time);
51
52 /**
53 * Get the remaining command count for this list.
54 *
55 * @return The remaining command count.
56 */
57 u32 GetRemainingCommandCount() const;
58
59 /**
60 * Set the command buffer.
61 *
62 * @param buffer - The buffer to use.
63 * @param size - The size of the buffer.
64 */
65 void SetBuffer(CpuAddr buffer, u64 size);
66
67 /**
68 * Get the stream for this command list.
69 *
70 * @return The stream associated with this command list.
71 */
72 Sink::SinkStream* GetOutputSinkStream() const;
73
74 /**
75 * Process the command list.
76 *
77 * @param session_id - Session ID for the commands being processed.
78 *
79 * @return The time taken to process.
80 */
81 u64 Process(u32 session_id);
82
83 /// Core system
84 Core::System* system{};
85 /// Core memory
86 Core::Memory::Memory* memory{};
87 /// Stream for the processed samples
88 Sink::SinkStream* stream{};
89 /// Header info for this command list
90 Renderer::CommandListHeader* header{};
91 /// The command buffer
92 u8* commands{};
93 /// The command buffer size
94 u64 commands_buffer_size{};
95 /// The maximum processing time allotted
96 u64 max_process_time{};
97 /// The number of commands in the buffer
98 u32 command_count{};
99 /// The target sample count for output
100 u32 sample_count{};
101 /// The target sample rate for output
102 u32 target_sample_rate{};
103 /// The mixing buffers used by the commands
104 std::span<s32> mix_buffers{};
105 /// The number of mix buffers
106 u32 buffer_count{};
107 /// The number of processed commands so far
108 u32 processed_command_count{};
109 /// The processing start time of this list
110 u64 start_time{};
111 /// The current processing time for this list
112 u64 current_processing_time{};
113 /// The end processing time for this list
114 u64 end_time{};
115 /// Last command list string generated, used for dumping audio commands to console
116 std::string last_dump{};
117};
118
119} // namespace ADSP::AudioRenderer
120} // namespace AudioCore
diff --git a/src/audio_core/adsp/mailbox.h b/src/audio_core/adsp/mailbox.h
new file mode 100644
index 000000000..c31b73717
--- /dev/null
+++ b/src/audio_core/adsp/mailbox.h
@@ -0,0 +1,69 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/bounded_threadsafe_queue.h"
7#include "common/common_types.h"
8
9namespace AudioCore::ADSP {
10
11enum class AppMailboxId : u32 {
12 Invalid = 0,
13 AudioRenderer = 50,
14 AudioRendererMemoryMapUnmap = 51,
15};
16
17enum class Direction : u32 {
18 Host,
19 DSP,
20};
21
22struct MailboxMessage {
23 u32 msg;
24 std::span<u8> data;
25};
26
27class Mailbox {
28public:
29 void Initialize(AppMailboxId id_) {
30 Reset();
31 id = id_;
32 }
33
34 AppMailboxId Id() const noexcept {
35 return id;
36 }
37
38 void Send(Direction dir, MailboxMessage&& message) {
39 auto& queue = dir == Direction::Host ? host_queue : adsp_queue;
40 queue.EmplaceWait(std::move(message));
41 }
42
43 MailboxMessage Receive(Direction dir, bool block = true) {
44 auto& queue = dir == Direction::Host ? host_queue : adsp_queue;
45 MailboxMessage t;
46 if (block) {
47 queue.PopWait(t);
48 } else {
49 queue.TryPop(t);
50 }
51 return t;
52 }
53
54 void Reset() {
55 id = AppMailboxId::Invalid;
56 MailboxMessage t;
57 while (host_queue.TryPop(t)) {
58 }
59 while (adsp_queue.TryPop(t)) {
60 }
61 }
62
63private:
64 AppMailboxId id{0};
65 Common::SPSCQueue<MailboxMessage> host_queue;
66 Common::SPSCQueue<MailboxMessage> adsp_queue;
67};
68
69} // namespace AudioCore::ADSP