mirror of https://git.suyu.dev/suyu/suyu
Merge pull request #11428 from Kelebek1/adsp_rework
Rework ADSP into a wrapper for appsmerge-requests/60/head
commit
69949e7964
@ -0,0 +1,18 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "audio_core/adsp/adsp.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
|
||||||
|
namespace AudioCore::ADSP {
|
||||||
|
|
||||||
|
ADSP::ADSP(Core::System& system, Sink::Sink& sink) {
|
||||||
|
audio_renderer =
|
||||||
|
std::make_unique<AudioRenderer::AudioRenderer>(system, system.ApplicationMemory(), sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioRenderer::AudioRenderer& ADSP::AudioRenderer() {
|
||||||
|
return *audio_renderer.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace AudioCore::ADSP
|
@ -0,0 +1,50 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "audio_core/adsp/apps/audio_renderer/audio_renderer.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
|
namespace AudioCore {
|
||||||
|
namespace Sink {
|
||||||
|
class Sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ADSP {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the ADSP embedded within the audio sysmodule.
|
||||||
|
* This is a 32-bit Linux4Tegra kernel from nVidia, which is launched with the sysmodule on boot.
|
||||||
|
*
|
||||||
|
* The kernel will run the apps you write for it, Nintendo have the following:
|
||||||
|
*
|
||||||
|
* Gmix - Responsible for mixing final audio and sending it out to hardware. This is last place all
|
||||||
|
* audio samples end up, and we skip it entirely, since we have very different backends and
|
||||||
|
* mixing is implicitly handled by the OS (but also due to lack of research/simplicity).
|
||||||
|
*
|
||||||
|
* AudioRenderer - Receives command lists generated by the audio render
|
||||||
|
* system on the host, processes them, and sends the samples to Gmix.
|
||||||
|
*
|
||||||
|
* OpusDecoder - Contains libopus, and decodes Opus audio packets into raw pcm data.
|
||||||
|
*
|
||||||
|
* Communication between the host and ADSP is done through mailboxes, and mapping of shared memory.
|
||||||
|
*/
|
||||||
|
class ADSP {
|
||||||
|
public:
|
||||||
|
explicit ADSP(Core::System& system, Sink::Sink& sink);
|
||||||
|
~ADSP() = default;
|
||||||
|
|
||||||
|
AudioRenderer::AudioRenderer& AudioRenderer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// AudioRenderer app
|
||||||
|
std::unique_ptr<AudioRenderer::AudioRenderer> audio_renderer{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ADSP
|
||||||
|
} // namespace AudioCore
|
@ -0,0 +1,115 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "audio_core/adsp/apps/audio_renderer/command_buffer.h"
|
||||||
|
#include "audio_core/adsp/apps/audio_renderer/command_list_processor.h"
|
||||||
|
#include "audio_core/adsp/mailbox.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/polyfill_thread.h"
|
||||||
|
#include "common/reader_writer_queue.h"
|
||||||
|
#include "common/thread.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
namespace Timing {
|
||||||
|
struct EventType;
|
||||||
|
}
|
||||||
|
namespace Memory {
|
||||||
|
class Memory;
|
||||||
|
}
|
||||||
|
class System;
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
|
namespace AudioCore {
|
||||||
|
namespace Sink {
|
||||||
|
class Sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ADSP::AudioRenderer {
|
||||||
|
|
||||||
|
enum Message : u32 {
|
||||||
|
Invalid = 0x00,
|
||||||
|
MapUnmap_Map = 0x01,
|
||||||
|
MapUnmap_MapResponse = 0x02,
|
||||||
|
MapUnmap_Unmap = 0x03,
|
||||||
|
MapUnmap_UnmapResponse = 0x04,
|
||||||
|
MapUnmap_InvalidateCache = 0x05,
|
||||||
|
MapUnmap_InvalidateCacheResponse = 0x06,
|
||||||
|
MapUnmap_Shutdown = 0x07,
|
||||||
|
MapUnmap_ShutdownResponse = 0x08,
|
||||||
|
InitializeOK = 0x16,
|
||||||
|
RenderResponse = 0x20,
|
||||||
|
Render = 0x2A,
|
||||||
|
Shutdown = 0x34,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AudioRenderer application running on the ADSP.
|
||||||
|
*/
|
||||||
|
class AudioRenderer {
|
||||||
|
public:
|
||||||
|
explicit AudioRenderer(Core::System& system, Core::Memory::Memory& memory, Sink::Sink& sink);
|
||||||
|
~AudioRenderer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the AudioRenderer.
|
||||||
|
*
|
||||||
|
* @param mailbox The mailbox to use for this session.
|
||||||
|
*/
|
||||||
|
void Start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the AudioRenderer.
|
||||||
|
*/
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
void Signal();
|
||||||
|
void Wait();
|
||||||
|
|
||||||
|
void Send(Direction dir, MailboxMessage message);
|
||||||
|
MailboxMessage Receive(Direction dir, bool block = true);
|
||||||
|
|
||||||
|
void SetCommandBuffer(s32 session_id, CommandBuffer& buffer) noexcept;
|
||||||
|
u32 GetRemainCommandCount(s32 session_id) const noexcept;
|
||||||
|
void ClearRemainCommandCount(s32 session_id) noexcept;
|
||||||
|
u64 GetRenderingStartTick(s32 session_id) const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Main AudioRenderer thread, responsible for processing the command lists.
|
||||||
|
*/
|
||||||
|
void Main(std::stop_token stop_token);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the streams which will receive the processed samples.
|
||||||
|
*/
|
||||||
|
void CreateSinkStreams();
|
||||||
|
|
||||||
|
/// Core system
|
||||||
|
Core::System& system;
|
||||||
|
/// Memory
|
||||||
|
Core::Memory::Memory& memory;
|
||||||
|
/// The output sink the AudioRenderer will use
|
||||||
|
Sink::Sink& sink;
|
||||||
|
/// The active mailbox
|
||||||
|
Mailbox mailbox;
|
||||||
|
/// Main thread
|
||||||
|
std::jthread main_thread{};
|
||||||
|
/// The current state
|
||||||
|
std::atomic<bool> running{};
|
||||||
|
std::array<CommandBuffer, MaxRendererSessions> command_buffers{};
|
||||||
|
/// The command lists to process
|
||||||
|
std::array<CommandListProcessor, MaxRendererSessions> command_list_processors{};
|
||||||
|
/// The streams which will receive the processed samples
|
||||||
|
std::array<Sink::SinkStream*, MaxRendererSessions> streams{};
|
||||||
|
u64 signalled_tick{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ADSP::AudioRenderer
|
||||||
|
} // namespace AudioCore
|
@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "audio_core/common/common.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace AudioCore::ADSP::AudioRenderer {
|
||||||
|
|
||||||
|
struct CommandBuffer {
|
||||||
|
// Set by the host
|
||||||
|
CpuAddr buffer{};
|
||||||
|
u64 size{};
|
||||||
|
u64 time_limit{};
|
||||||
|
u64 applet_resource_user_id{};
|
||||||
|
bool reset_buffer{};
|
||||||
|
// Set by the DSP
|
||||||
|
u32 remaining_command_count{};
|
||||||
|
u64 render_time_taken_us{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace AudioCore::ADSP::AudioRenderer
|
@ -0,0 +1,69 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/bounded_threadsafe_queue.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace AudioCore::ADSP {
|
||||||
|
|
||||||
|
enum class AppMailboxId : u32 {
|
||||||
|
Invalid = 0,
|
||||||
|
AudioRenderer = 50,
|
||||||
|
AudioRendererMemoryMapUnmap = 51,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Direction : u32 {
|
||||||
|
Host,
|
||||||
|
DSP,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MailboxMessage {
|
||||||
|
u32 msg;
|
||||||
|
std::span<u8> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Mailbox {
|
||||||
|
public:
|
||||||
|
void Initialize(AppMailboxId id_) {
|
||||||
|
Reset();
|
||||||
|
id = id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppMailboxId Id() const noexcept {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Send(Direction dir, MailboxMessage&& message) {
|
||||||
|
auto& queue = dir == Direction::Host ? host_queue : adsp_queue;
|
||||||
|
queue.EmplaceWait(std::move(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
MailboxMessage Receive(Direction dir, bool block = true) {
|
||||||
|
auto& queue = dir == Direction::Host ? host_queue : adsp_queue;
|
||||||
|
MailboxMessage t;
|
||||||
|
if (block) {
|
||||||
|
queue.PopWait(t);
|
||||||
|
} else {
|
||||||
|
queue.TryPop(t);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
id = AppMailboxId::Invalid;
|
||||||
|
MailboxMessage t;
|
||||||
|
while (host_queue.TryPop(t)) {
|
||||||
|
}
|
||||||
|
while (adsp_queue.TryPop(t)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AppMailboxId id{0};
|
||||||
|
Common::SPSCQueue<MailboxMessage> host_queue;
|
||||||
|
Common::SPSCQueue<MailboxMessage> adsp_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace AudioCore::ADSP
|
@ -1,117 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "audio_core/renderer/adsp/adsp.h"
|
|
||||||
#include "audio_core/renderer/adsp/command_buffer.h"
|
|
||||||
#include "audio_core/sink/sink.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/core_timing.h"
|
|
||||||
#include "core/memory.h"
|
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer::ADSP {
|
|
||||||
|
|
||||||
ADSP::ADSP(Core::System& system_, Sink::Sink& sink_)
|
|
||||||
: system{system_}, memory{system.ApplicationMemory()}, sink{sink_} {}
|
|
||||||
|
|
||||||
ADSP::~ADSP() {
|
|
||||||
ClearCommandBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
State ADSP::GetState() const {
|
|
||||||
if (running) {
|
|
||||||
return State::Started;
|
|
||||||
}
|
|
||||||
return State::Stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioRenderer_Mailbox* ADSP::GetRenderMailbox() {
|
|
||||||
return &render_mailbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ADSP::ClearRemainCount(const u32 session_id) {
|
|
||||||
render_mailbox.ClearRemainCount(session_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 ADSP::GetSignalledTick() const {
|
|
||||||
return render_mailbox.GetSignalledTick();
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 ADSP::GetTimeTaken() const {
|
|
||||||
return render_mailbox.GetRenderTimeTaken();
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 ADSP::GetRenderTimeTaken(const u32 session_id) {
|
|
||||||
return render_mailbox.GetCommandBuffer(session_id).render_time_taken;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 ADSP::GetRemainCommandCount(const u32 session_id) const {
|
|
||||||
return render_mailbox.GetRemainCommandCount(session_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ADSP::SendCommandBuffer(const u32 session_id, const CommandBuffer& command_buffer) {
|
|
||||||
render_mailbox.SetCommandBuffer(session_id, command_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 ADSP::GetRenderingStartTick(const u32 session_id) {
|
|
||||||
return render_mailbox.GetSignalledTick() +
|
|
||||||
render_mailbox.GetCommandBuffer(session_id).render_time_taken;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ADSP::Start() {
|
|
||||||
if (running) {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
running = true;
|
|
||||||
systems_active++;
|
|
||||||
audio_renderer = std::make_unique<AudioRenderer>(system);
|
|
||||||
audio_renderer->Start(&render_mailbox);
|
|
||||||
render_mailbox.HostSendMessage(RenderMessage::AudioRenderer_InitializeOK);
|
|
||||||
if (render_mailbox.HostWaitMessage() != RenderMessage::AudioRenderer_InitializeOK) {
|
|
||||||
LOG_ERROR(
|
|
||||||
Service_Audio,
|
|
||||||
"Host Audio Renderer -- Failed to receive initialize message response from ADSP!");
|
|
||||||
}
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ADSP::Stop() {
|
|
||||||
systems_active--;
|
|
||||||
if (running && systems_active == 0) {
|
|
||||||
{
|
|
||||||
std::scoped_lock l{mailbox_lock};
|
|
||||||
render_mailbox.HostSendMessage(RenderMessage::AudioRenderer_Shutdown);
|
|
||||||
if (render_mailbox.HostWaitMessage() != RenderMessage::AudioRenderer_Shutdown) {
|
|
||||||
LOG_ERROR(Service_Audio, "Host Audio Renderer -- Failed to receive shutdown "
|
|
||||||
"message response from ADSP!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
audio_renderer->Stop();
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ADSP::Signal() {
|
|
||||||
const auto signalled_tick{system.CoreTiming().GetClockTicks()};
|
|
||||||
render_mailbox.SetSignalledTick(signalled_tick);
|
|
||||||
render_mailbox.HostSendMessage(RenderMessage::AudioRenderer_Render);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ADSP::Wait() {
|
|
||||||
std::scoped_lock l{mailbox_lock};
|
|
||||||
auto response{render_mailbox.HostWaitMessage()};
|
|
||||||
if (response != RenderMessage::AudioRenderer_RenderResponse) {
|
|
||||||
LOG_ERROR(Service_Audio, "Invalid ADSP response message, expected 0x{:02X}, got 0x{:02X}",
|
|
||||||
static_cast<u32>(RenderMessage::AudioRenderer_RenderResponse),
|
|
||||||
static_cast<u32>(response));
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearCommandBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ADSP::ClearCommandBuffers() {
|
|
||||||
render_mailbox.ClearCommandBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace AudioCore::AudioRenderer::ADSP
|
|
@ -1,171 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include "audio_core/renderer/adsp/audio_renderer.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
namespace Memory {
|
|
||||||
class Memory;
|
|
||||||
}
|
|
||||||
class System;
|
|
||||||
} // namespace Core
|
|
||||||
|
|
||||||
namespace AudioCore {
|
|
||||||
namespace Sink {
|
|
||||||
class Sink;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace AudioRenderer::ADSP {
|
|
||||||
struct CommandBuffer;
|
|
||||||
|
|
||||||
enum class State {
|
|
||||||
Started,
|
|
||||||
Stopped,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the ADSP embedded within the audio sysmodule.
|
|
||||||
* This is a 32-bit Linux4Tegra kernel from nVidia, which is launched with the sysmodule on boot.
|
|
||||||
*
|
|
||||||
* The kernel will run apps you program for it, Nintendo have the following:
|
|
||||||
*
|
|
||||||
* Gmix - Responsible for mixing final audio and sending it out to hardware. This is last place all
|
|
||||||
* audio samples end up, and we skip it entirely, since we have very different backends and
|
|
||||||
* mixing is implicitly handled by the OS (but also due to lack of research/simplicity).
|
|
||||||
*
|
|
||||||
* AudioRenderer - Receives command lists generated by the audio render
|
|
||||||
* system, processes them, and sends the samples to Gmix.
|
|
||||||
*
|
|
||||||
* OpusDecoder - Contains libopus, and controls processing Opus audio and sends it to Gmix.
|
|
||||||
* Not much research done here, TODO if needed.
|
|
||||||
*
|
|
||||||
* We only implement the AudioRenderer for now.
|
|
||||||
*
|
|
||||||
* Communication for the apps is done through mailboxes, and some shared memory.
|
|
||||||
*/
|
|
||||||
class ADSP {
|
|
||||||
public:
|
|
||||||
explicit ADSP(Core::System& system, Sink::Sink& sink);
|
|
||||||
~ADSP();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the ADSP.
|
|
||||||
*
|
|
||||||
* @return True if started or already running, otherwise false.
|
|
||||||
*/
|
|
||||||
bool Start();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop the ADSP.
|
|
||||||
*/
|
|
||||||
void Stop();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the ADSP's state.
|
|
||||||
*
|
|
||||||
* @return Started or Stopped.
|
|
||||||
*/
|
|
||||||
State GetState() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the AudioRenderer mailbox to communicate with it.
|
|
||||||
*
|
|
||||||
* @return The AudioRenderer mailbox.
|
|
||||||
*/
|
|
||||||
AudioRenderer_Mailbox* GetRenderMailbox();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the tick the ADSP was signalled.
|
|
||||||
*
|
|
||||||
* @return The tick the ADSP was signalled.
|
|
||||||
*/
|
|
||||||
u64 GetSignalledTick() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the total time it took for the ADSP to run the last command lists (both command lists).
|
|
||||||
*
|
|
||||||
* @return The tick the ADSP was signalled.
|
|
||||||
*/
|
|
||||||
u64 GetTimeTaken() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the last time a given command list took to run.
|
|
||||||
*
|
|
||||||
* @param session_id - The session id to check (0 or 1).
|
|
||||||
* @return The time it took.
|
|
||||||
*/
|
|
||||||
u64 GetRenderTimeTaken(u32 session_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the remaining command count for a given session.
|
|
||||||
*
|
|
||||||
* @param session_id - The session id to check (0 or 1).
|
|
||||||
*/
|
|
||||||
void ClearRemainCount(u32 session_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the remaining number of commands left to process for a command list.
|
|
||||||
*
|
|
||||||
* @param session_id - The session id to check (0 or 1).
|
|
||||||
* @return The number of commands remaining.
|
|
||||||
*/
|
|
||||||
u32 GetRemainCommandCount(u32 session_id) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the last tick a command list started processing.
|
|
||||||
*
|
|
||||||
* @param session_id - The session id to check (0 or 1).
|
|
||||||
* @return The last tick the given command list started.
|
|
||||||
*/
|
|
||||||
u64 GetRenderingStartTick(u32 session_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a command buffer to be processed.
|
|
||||||
*
|
|
||||||
* @param session_id - The session id to check (0 or 1).
|
|
||||||
* @param command_buffer - The command buffer to process.
|
|
||||||
*/
|
|
||||||
void SendCommandBuffer(u32 session_id, const CommandBuffer& command_buffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the command buffers (does not clear the time taken or the remaining command count)
|
|
||||||
*/
|
|
||||||
void ClearCommandBuffers();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signal the AudioRenderer to begin processing.
|
|
||||||
*/
|
|
||||||
void Signal();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for the AudioRenderer to finish processing.
|
|
||||||
*/
|
|
||||||
void Wait();
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Core system
|
|
||||||
Core::System& system;
|
|
||||||
/// Core memory
|
|
||||||
Core::Memory::Memory& memory;
|
|
||||||
/// Number of systems active, used to prevent accidental shutdowns
|
|
||||||
u8 systems_active{0};
|
|
||||||
/// ADSP running state
|
|
||||||
std::atomic<bool> running{false};
|
|
||||||
/// Output sink used by the ADSP
|
|
||||||
Sink::Sink& sink;
|
|
||||||
/// AudioRenderer app
|
|
||||||
std::unique_ptr<AudioRenderer> audio_renderer{};
|
|
||||||
/// Communication for the AudioRenderer
|
|
||||||
AudioRenderer_Mailbox render_mailbox{};
|
|
||||||
/// Mailbox lock ffor the render mailbox
|
|
||||||
std::mutex mailbox_lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace AudioRenderer::ADSP
|
|
||||||
} // namespace AudioCore
|
|
@ -1,204 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <memory>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "audio_core/renderer/adsp/command_buffer.h"
|
|
||||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/polyfill_thread.h"
|
|
||||||
#include "common/reader_writer_queue.h"
|
|
||||||
#include "common/thread.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
namespace Timing {
|
|
||||||
struct EventType;
|
|
||||||
}
|
|
||||||
class System;
|
|
||||||
} // namespace Core
|
|
||||||
|
|
||||||
namespace AudioCore {
|
|
||||||
namespace Sink {
|
|
||||||
class Sink;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace AudioRenderer::ADSP {
|
|
||||||
|
|
||||||
enum class RenderMessage {
|
|
||||||
/* 0x00 */ Invalid,
|
|
||||||
/* 0x01 */ AudioRenderer_MapUnmap_Map,
|
|
||||||
/* 0x02 */ AudioRenderer_MapUnmap_MapResponse,
|
|
||||||
/* 0x03 */ AudioRenderer_MapUnmap_Unmap,
|
|
||||||
/* 0x04 */ AudioRenderer_MapUnmap_UnmapResponse,
|
|
||||||
/* 0x05 */ AudioRenderer_MapUnmap_InvalidateCache,
|
|
||||||
/* 0x06 */ AudioRenderer_MapUnmap_InvalidateCacheResponse,
|
|
||||||
/* 0x07 */ AudioRenderer_MapUnmap_Shutdown,
|
|
||||||
/* 0x08 */ AudioRenderer_MapUnmap_ShutdownResponse,
|
|
||||||
/* 0x16 */ AudioRenderer_InitializeOK = 0x16,
|
|
||||||
/* 0x20 */ AudioRenderer_RenderResponse = 0x20,
|
|
||||||
/* 0x2A */ AudioRenderer_Render = 0x2A,
|
|
||||||
/* 0x34 */ AudioRenderer_Shutdown = 0x34,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A mailbox for the AudioRenderer, allowing communication between the host and the AudioRenderer
|
|
||||||
* running on the ADSP.
|
|
||||||
*/
|
|
||||||
class AudioRenderer_Mailbox {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Send a message from the host to the AudioRenderer.
|
|
||||||
*
|
|
||||||
* @param message - The message to send to the AudioRenderer.
|
|
||||||
*/
|
|
||||||
void HostSendMessage(RenderMessage message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Host wait for a message from the AudioRenderer.
|
|
||||||
*
|
|
||||||
* @return The message returned from the AudioRenderer.
|
|
||||||
*/
|
|
||||||
RenderMessage HostWaitMessage();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message from the AudioRenderer to the host.
|
|
||||||
*
|
|
||||||
* @param message - The message to send to the host.
|
|
||||||
*/
|
|
||||||
void ADSPSendMessage(RenderMessage message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AudioRenderer wait for a message from the host.
|
|
||||||
*
|
|
||||||
* @return The message returned from the AudioRenderer.
|
|
||||||
*/
|
|
||||||
RenderMessage ADSPWaitMessage();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the command buffer with the given session id (0 or 1).
|
|
||||||
*
|
|
||||||
* @param session_id - The session id to get (0 or 1).
|
|
||||||
* @return The command buffer.
|
|
||||||
*/
|
|
||||||
CommandBuffer& GetCommandBuffer(u32 session_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the command buffer with the given session id (0 or 1).
|
|
||||||
*
|
|
||||||
* @param session_id - The session id to get (0 or 1).
|
|
||||||
* @param buffer - The command buffer to set.
|
|
||||||
*/
|
|
||||||
void SetCommandBuffer(u32 session_id, const CommandBuffer& buffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the total render time taken for the last command lists sent.
|
|
||||||
*
|
|
||||||
* @return Total render time taken for the last command lists.
|
|
||||||
*/
|
|
||||||
u64 GetRenderTimeTaken() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the tick the AudioRenderer was signalled.
|
|
||||||
*
|
|
||||||
* @return The tick the AudioRenderer was signalled.
|
|
||||||
*/
|
|
||||||
u64 GetSignalledTick() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the tick the AudioRenderer was signalled.
|
|
||||||
*
|
|
||||||
* @param tick - The tick the AudioRenderer was signalled.
|
|
||||||
*/
|
|
||||||
void SetSignalledTick(u64 tick);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the remaining command count.
|
|
||||||
*
|
|
||||||
* @param session_id - Index for which command list to clear (0 or 1).
|
|
||||||
*/
|
|
||||||
void ClearRemainCount(u32 session_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the remaining command count for a given command list.
|
|
||||||
*
|
|
||||||
* @param session_id - Index for which command list to clear (0 or 1).
|
|
||||||
* @return The remaining command count.
|
|
||||||
*/
|
|
||||||
u32 GetRemainCommandCount(u32 session_id) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the command buffers (does not clear the time taken or the remaining command count).
|
|
||||||
*/
|
|
||||||
void ClearCommandBuffers();
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Host signalling event
|
|
||||||
Common::Event host_event{};
|
|
||||||
/// AudioRenderer signalling event
|
|
||||||
Common::Event adsp_event{};
|
|
||||||
/// Host message queue
|
|
||||||
|
|
||||||
Common::ReaderWriterQueue<RenderMessage> host_messages{};
|
|
||||||
/// AudioRenderer message queue
|
|
||||||
|
|
||||||
Common::ReaderWriterQueue<RenderMessage> adsp_messages{};
|
|
||||||
/// Command buffers
|
|
||||||
|
|
||||||
std::array<CommandBuffer, MaxRendererSessions> command_buffers{};
|
|
||||||
/// Tick the AudioRnederer was signalled
|
|
||||||
u64 signalled_tick{};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The AudioRenderer application running on the ADSP.
|
|
||||||
*/
|
|
||||||
class AudioRenderer {
|
|
||||||
public:
|
|
||||||
explicit AudioRenderer(Core::System& system);
|
|
||||||
~AudioRenderer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the AudioRenderer.
|
|
||||||
*
|
|
||||||
* @param mailbox The mailbox to use for this session.
|
|
||||||
*/
|
|
||||||
void Start(AudioRenderer_Mailbox* mailbox);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop the AudioRenderer.
|
|
||||||
*/
|
|
||||||
void Stop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Main AudioRenderer thread, responsible for processing the command lists.
|
|
||||||
*/
|
|
||||||
void ThreadFunc(std::stop_token stop_token);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the streams which will receive the processed samples.
|
|
||||||
*/
|
|
||||||
void CreateSinkStreams();
|
|
||||||
|
|
||||||
/// Core system
|
|
||||||
Core::System& system;
|
|
||||||
/// Main thread
|
|
||||||
std::jthread thread{};
|
|
||||||
/// The current state
|
|
||||||
std::atomic<bool> running{};
|
|
||||||
/// The active mailbox
|
|
||||||
AudioRenderer_Mailbox* mailbox{};
|
|
||||||
/// The command lists to process
|
|
||||||
std::array<CommandListProcessor, MaxRendererSessions> command_list_processors{};
|
|
||||||
/// The output sink the AudioRenderer will use
|
|
||||||
Sink::Sink& sink;
|
|
||||||
/// The streams which will receive the processed samples
|
|
||||||
std::array<Sink::SinkStream*, MaxRendererSessions> streams;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace AudioRenderer::ADSP
|
|
||||||
} // namespace AudioCore
|
|
@ -1,21 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "audio_core/common/common.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer::ADSP {
|
|
||||||
|
|
||||||
struct CommandBuffer {
|
|
||||||
CpuAddr buffer;
|
|
||||||
u64 size;
|
|
||||||
u64 time_limit;
|
|
||||||
u32 remaining_command_count;
|
|
||||||
bool reset_buffers;
|
|
||||||
u64 applet_resource_user_id;
|
|
||||||
u64 render_time_taken;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace AudioCore::AudioRenderer::ADSP
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue