// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <mutex>
#include <span>
#include "audio_core/renderer/behavior/behavior_info.h"
#include "audio_core/renderer/command/command_processing_time_estimator.h"
#include "audio_core/renderer/effect/effect_context.h"
#include "audio_core/renderer/memory/memory_pool_info.h"
#include "audio_core/renderer/mix/mix_context.h"
#include "audio_core/renderer/performance/performance_manager.h"
#include "audio_core/renderer/sink/sink_context.h"
#include "audio_core/renderer/splitter/splitter_context.h"
#include "audio_core/renderer/upsampler/upsampler_manager.h"
#include "audio_core/renderer/voice/voice_context.h"
#include "common/thread.h"
#include "core/hle/service/audio/errors.h"
namespace Core {
namespace Memory {
class Memory;
}
class System;
} // namespace Core
namespace Kernel {
class KEvent;
class KTransferMemory;
} // namespace Kernel
namespace AudioCore {
struct AudioRendererParameterInternal;
namespace ADSP {
class ADSP;
namespace AudioRenderer {
class AudioRenderer;
}
} // namespace ADSP
namespace Renderer {
using namespace ::AudioCore::ADSP;
class CommandBuffer;
/**
* Audio Renderer System, the main worker for audio rendering.
*/
class System {
enum class State {
Started = 0,
Stopped = 2,
};
public:
explicit System(Core::System& core, Kernel::KEvent* adsp_rendered_event);
/**
* Calculate the total size required for all audio render workbuffers.
*
* @param params - Input parameters with the numbers of voices/mixes/sinks/etc.
* @return Size (in bytes) required for the audio renderer.
*/
static u64 GetWorkBufferSize(const AudioRendererParameterInternal& params);
/**
* Initialize the renderer system.
* Allocates workbuffers and initializes everything to a default state, ready to receive a
* RequestUpdate.
*
* @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused.
* @param process_handle - Process handle, also used for memory. Unused.
* @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer.
* @return Result code.
*/
Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle, u64 applet_resource_user_id, s32 session_id);
/**
* Finalize the system.
*/
void Finalize();
/**
* Start the system.
*/
void Start();
/**
* Stop the system.
*/
void Stop();
/**
* Update the system.
*
* @param input - Inout buffer containing the update data.
* @param performance - Optional buffer for writing back performance metrics.
* @param output - Output information from rendering.
* @return Result code.
*/
Result Update(std::span<const u8> input, std::span<u8> performance, std::span<u8> output);
/**
* Get the time limit (percent) for rendering
*
* @return Time limit as a percent.
*/
u32 GetRenderingTimeLimit() const;
/**
* Set the time limit (percent) for rendering
*
* @param limit - New time limit.
*/
void SetRenderingTimeLimit(u32 limit);
/**
* Get the session id for this system.
*
* @return Session id of this system.
*/
u32 GetSessionId() const;
/**
* Get the sample rate of this system.
*
* @return Sample rate of this system.
*/
u32 GetSampleRate() const;
/**
* Get the sample count of this system.
*
* @return Sample count of this system.
*/
u32 GetSampleCount() const;
/**
* Get the number of mix buffers for this system.
*
* @return Number of mix buffers in the system.
*/
u32 GetMixBufferCount() const;
/**
* Get the execution mode of this system.
* Note: Only Auto is implemented.
*
* @return Execution mode for this system.
*/
ExecutionMode GetExecutionMode() const;
/**
* Get the rendering device for this system.
* This is unused.
*
* @return Rendering device for this system.
*/
u32 GetRenderingDevice() const;
/**
* Check if this system is currently active.
*
* @return True if active, otherwise false.
*/
bool IsActive() const;
/**
* Prepare and generate a list of commands for the AudioRenderer based on current state,
* signalling the buffer event when all processed.
*/
void SendCommandToDsp();
/**
* Generate a list of commands for the AudioRenderer based on current state.
*
* @param command_buffer - Buffer for commands to be written to.
* @param command_buffer_size - Size of the command_buffer.
*
* @return Number of bytes written.
*/
u64 GenerateCommand(std::span<u8> command_buffer, u64 command_buffer_size);
/**
* Try to drop some voices if the AudioRenderer fell behind.
*
* @param command_buffer - Command buffer to drop voices from.
* @param estimated_process_time - Current estimated processing time of all commands.
* @param time_limit - Time limit for rendering, voices are dropped if estimated
* exceeds this.
*
* @return Number of voices dropped.
*/
u32 DropVoices(CommandBuffer& command_buffer, u32 estimated_process_time, u32 time_limit);
/**
* Get the current voice drop parameter.
*
* @return The current voice drop.
*/
f32 GetVoiceDropParameter() const;
/**
* Set the voice drop parameter.
*
* @param The new voice drop.
*/
void SetVoiceDropParameter(f32 voice_drop);
private:
/// Core system
Core::System& core;
/// Reference to the ADSP's AudioRenderer for communication
::AudioCore::ADSP::AudioRenderer::AudioRenderer& audio_renderer;
/// Is this system initialized?
bool initialized{};
/// Is this system currently active?
std::atomic<bool> active{};
/// State of the system
State state{State::Stopped};
/// Sample rate for the system
u32 sample_rate{};
/// Sample count of the system
u32 sample_count{};
/// Number of mix buffers in use by the system
s16 mix_buffer_count{};
/// Workbuffer for mix buffers, used by the AudioRenderer
std::span<s32> samples_workbuffer{};
/// Depop samples for depopping commands
std::span<s32> depop_buffer{};
/// Number of memory pools in the buffer
u32 memory_pool_count{};
/// Workbuffer for memory pools
std::span<MemoryPoolInfo> memory_pool_workbuffer{};
/// System memory pool info
MemoryPoolInfo memory_pool_info{};
/// Workbuffer that commands will be generated into
std::span<u8> command_workbuffer{};
/// Size of command workbuffer
u64 command_workbuffer_size{};
/// Number of commands in the workbuffer
u64 command_buffer_size{};
/// Manager for upsamplers
UpsamplerManager* upsampler_manager{};
/// Upsampler workbuffer
std::span<UpsamplerInfo> upsampler_infos{};
/// Number of upsamplers in the workbuffer
u32 upsampler_count{};
/// Holds and controls all voices
VoiceContext voice_context{};
/// Holds and controls all mixes
MixContext mix_context{};
/// Holds and controls all effects
EffectContext effect_context{};
/// Holds and controls all sinks
SinkContext sink_context{};
/// Holds and controls all splitters
SplitterContext splitter_context{};
/// Estimates the time taken for each command
std::unique_ptr<ICommandProcessingTimeEstimator> command_processing_time_estimator{};
/// Session id of this system
s32 session_id{};
/// Number of channels in use by voices
s32 voice_channels{};
/// Event to be called when the AudioRenderer processes a command list
Kernel::KEvent* adsp_rendered_event{};
/// Event signalled on system terminate
Common::Event terminate_event{};
/// Does what locks do
std::mutex lock{};
/// Handle for the process for this system, unused
u32 process_handle{};
/// Applet resource id for this system, unused
u64 applet_resource_user_id{};
/// Controls performance input and output
PerformanceManager performance_manager{};
/// Workbuffer for performance metrics
std::span<u8> performance_workbuffer{};
/// Main workbuffer, from which all other workbuffers here allocate into
std::unique_ptr<u8[]> workbuffer{};
/// Size of the main workbuffer
u64 workbuffer_size{};
/// Unknown buffer/marker
std::span<u8> unk_2A8{};
/// Size of the above unknown buffer/marker
u64 unk_2B0{};
/// Rendering time limit (percent)
u32 render_time_limit_percent{};
/// Should any voices be dropped?
bool drop_voice{};
/// Should the backend stream have its buffers flushed?
bool reset_command_buffers{};
/// Execution mode of this system, only Auto is supported
ExecutionMode execution_mode{ExecutionMode::Auto};
/// Render device, unused
u32 render_device{};
/// Behaviour to check which features are supported by the user revision
BehaviorInfo behavior{};
/// Total ticks the audio system has been running
u64 total_ticks_elapsed{};
/// Ticks the system has spent in updates
u64 ticks_spent_updating{};
/// Number of times a command list was generated
u64 num_command_lists_generated{};
/// Number of times the system has updated
u64 num_times_updated{};
/// Number of frames generated, written back to the game
std::atomic<u64> frames_elapsed{};
/// Is the AudioRenderer running too slow?
bool adsp_behind{};
/// Number of voices dropped
u32 num_voices_dropped{};
/// Tick that rendering started
u64 render_start_tick{};
/// Parameter to control the threshold for dropping voices if the audio graph gets too large
f32 drop_voice_param{1.0f};
};
} // namespace Renderer
} // namespace AudioCore