aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/audio_core/renderer/system.h
blob: 3533a74efd25d71a6dc16babb1e385daacc0e3ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
// 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 KProcess;
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.
     * @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,
                      Kernel::KProcess* 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{};
    /// Process this audio render is operating within, used for memory reads/writes.
    Kernel::KProcess* 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