system.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <chrono>
  4. #include <span>
  5. #include "audio_core/adsp/apps/audio_renderer/audio_renderer.h"
  6. #include "audio_core/adsp/apps/audio_renderer/command_buffer.h"
  7. #include "audio_core/audio_core.h"
  8. #include "audio_core/common/audio_renderer_parameter.h"
  9. #include "audio_core/common/common.h"
  10. #include "audio_core/common/feature_support.h"
  11. #include "audio_core/common/workbuffer_allocator.h"
  12. #include "audio_core/renderer/behavior/info_updater.h"
  13. #include "audio_core/renderer/command/command_buffer.h"
  14. #include "audio_core/renderer/command/command_generator.h"
  15. #include "audio_core/renderer/command/command_list_header.h"
  16. #include "audio_core/renderer/effect/effect_info_base.h"
  17. #include "audio_core/renderer/effect/effect_result_state.h"
  18. #include "audio_core/renderer/memory/memory_pool_info.h"
  19. #include "audio_core/renderer/memory/pool_mapper.h"
  20. #include "audio_core/renderer/mix/mix_info.h"
  21. #include "audio_core/renderer/nodes/edge_matrix.h"
  22. #include "audio_core/renderer/nodes/node_states.h"
  23. #include "audio_core/renderer/sink/sink_info_base.h"
  24. #include "audio_core/renderer/system.h"
  25. #include "audio_core/renderer/upsampler/upsampler_info.h"
  26. #include "audio_core/renderer/voice/voice_channel_resource.h"
  27. #include "audio_core/renderer/voice/voice_info.h"
  28. #include "audio_core/renderer/voice/voice_state.h"
  29. #include "common/alignment.h"
  30. #include "core/core.h"
  31. #include "core/core_timing.h"
  32. #include "core/hle/kernel/k_event.h"
  33. #include "core/hle/kernel/k_process.h"
  34. #include "core/hle/kernel/k_transfer_memory.h"
  35. #include "core/memory.h"
  36. namespace AudioCore::Renderer {
  37. u64 System::GetWorkBufferSize(const AudioRendererParameterInternal& params) {
  38. BehaviorInfo behavior;
  39. behavior.SetUserLibRevision(params.revision);
  40. u64 size{0};
  41. size += Common::AlignUp(params.mixes * sizeof(s32), 0x40);
  42. size += params.sub_mixes * MaxEffects * sizeof(s32);
  43. size += (params.sub_mixes + 1) * sizeof(MixInfo);
  44. size += params.voices * (sizeof(VoiceInfo) + sizeof(VoiceChannelResource) + sizeof(VoiceState));
  45. size += Common::AlignUp((params.sub_mixes + 1) * sizeof(MixInfo*), 0x10);
  46. size += Common::AlignUp(params.voices * sizeof(VoiceInfo*), 0x10);
  47. size += Common::AlignUp(((params.sinks + params.sub_mixes) * TargetSampleCount * sizeof(s32) +
  48. params.sample_count * sizeof(s32)) *
  49. (params.mixes + MaxChannels),
  50. 0x40);
  51. if (behavior.IsSplitterSupported()) {
  52. const auto node_size{NodeStates::GetWorkBufferSize(params.sub_mixes + 1)};
  53. const auto edge_size{EdgeMatrix::GetWorkBufferSize(params.sub_mixes + 1)};
  54. size += Common::AlignUp(node_size + edge_size, 0x10);
  55. }
  56. size += SplitterContext::CalcWorkBufferSize(behavior, params);
  57. size += (params.effects + params.voices * MaxWaveBuffers) * sizeof(MemoryPoolInfo);
  58. if (behavior.IsEffectInfoVersion2Supported()) {
  59. size += params.effects * sizeof(EffectResultState);
  60. }
  61. size += 0x50;
  62. size = Common::AlignUp(size, 0x40);
  63. size += (params.sinks + params.sub_mixes) * sizeof(UpsamplerInfo);
  64. size += params.effects * sizeof(EffectInfoBase);
  65. size += Common::AlignUp(params.voices * sizeof(VoiceState), 0x40);
  66. size += params.sinks * sizeof(SinkInfoBase);
  67. if (behavior.IsEffectInfoVersion2Supported()) {
  68. size += params.effects * sizeof(EffectResultState);
  69. }
  70. if (params.perf_frames > 0) {
  71. auto perf_size{PerformanceManager::GetRequiredBufferSizeForPerformanceMetricsPerFrame(
  72. behavior, params)};
  73. size += Common::AlignUp(perf_size * (params.perf_frames + 1) + 0xC0, 0x100);
  74. }
  75. if (behavior.IsVariadicCommandBufferSizeSupported()) {
  76. size += CommandGenerator::CalculateCommandBufferSize(behavior, params) + (0x40 - 1) * 2;
  77. } else {
  78. size += 0x18000 + (0x40 - 1) * 2;
  79. }
  80. size = Common::AlignUp(size, 0x1000);
  81. return size;
  82. }
  83. System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_)
  84. : core{core_}, audio_renderer{core.AudioCore().ADSP().AudioRenderer()},
  85. adsp_rendered_event{adsp_rendered_event_} {}
  86. Result System::Initialize(const AudioRendererParameterInternal& params,
  87. Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
  88. Kernel::KProcess* process_handle_, u64 applet_resource_user_id_,
  89. s32 session_id_) {
  90. if (!CheckValidRevision(params.revision)) {
  91. return Service::Audio::ResultInvalidRevision;
  92. }
  93. if (GetWorkBufferSize(params) > transfer_memory_size) {
  94. return Service::Audio::ResultInsufficientBuffer;
  95. }
  96. if (process_handle_ == 0) {
  97. return Service::Audio::ResultInvalidHandle;
  98. }
  99. behavior.SetUserLibRevision(params.revision);
  100. process_handle = process_handle_;
  101. applet_resource_user_id = applet_resource_user_id_;
  102. session_id = session_id_;
  103. sample_rate = params.sample_rate;
  104. sample_count = params.sample_count;
  105. mix_buffer_count = static_cast<s16>(params.mixes);
  106. voice_channels = MaxChannels;
  107. upsampler_count = params.sinks + params.sub_mixes;
  108. memory_pool_count = params.effects + params.voices * MaxWaveBuffers;
  109. render_device = params.rendering_device;
  110. execution_mode = params.execution_mode;
  111. process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(),
  112. transfer_memory_size);
  113. // Note: We're not actually using the transfer memory because it's a pain to code for.
  114. // Allocate the memory normally instead and hope the game doesn't try to read anything back
  115. workbuffer = std::make_unique<u8[]>(transfer_memory_size);
  116. workbuffer_size = transfer_memory_size;
  117. PoolMapper pool_mapper(process_handle, false);
  118. pool_mapper.InitializeSystemPool(memory_pool_info, workbuffer.get(), workbuffer_size);
  119. WorkbufferAllocator allocator({workbuffer.get(), workbuffer_size}, workbuffer_size);
  120. samples_workbuffer =
  121. allocator.Allocate<s32>((voice_channels + mix_buffer_count) * sample_count, 0x10);
  122. if (samples_workbuffer.empty()) {
  123. return Service::Audio::ResultInsufficientBuffer;
  124. }
  125. auto upsampler_workbuffer{allocator.Allocate<s32>(
  126. (voice_channels + mix_buffer_count) * TargetSampleCount * upsampler_count, 0x10)};
  127. if (upsampler_workbuffer.empty()) {
  128. return Service::Audio::ResultInsufficientBuffer;
  129. }
  130. depop_buffer =
  131. allocator.Allocate<s32>(Common::AlignUp(static_cast<u32>(mix_buffer_count), 0x40), 0x40);
  132. if (depop_buffer.empty()) {
  133. return Service::Audio::ResultInsufficientBuffer;
  134. }
  135. // invalidate samples_workbuffer DSP cache
  136. auto voice_infos{allocator.Allocate<VoiceInfo>(params.voices, 0x10)};
  137. for (auto& voice_info : voice_infos) {
  138. std::construct_at<VoiceInfo>(&voice_info);
  139. }
  140. if (voice_infos.empty()) {
  141. return Service::Audio::ResultInsufficientBuffer;
  142. }
  143. auto sorted_voice_infos{allocator.Allocate<VoiceInfo*>(params.voices, 0x10)};
  144. if (sorted_voice_infos.empty()) {
  145. return Service::Audio::ResultInsufficientBuffer;
  146. }
  147. std::memset(sorted_voice_infos.data(), 0, sorted_voice_infos.size_bytes());
  148. auto voice_channel_resources{allocator.Allocate<VoiceChannelResource>(params.voices, 0x10)};
  149. u32 i{0};
  150. for (auto& voice_channel_resource : voice_channel_resources) {
  151. std::construct_at<VoiceChannelResource>(&voice_channel_resource, i++);
  152. }
  153. if (voice_channel_resources.empty()) {
  154. return Service::Audio::ResultInsufficientBuffer;
  155. }
  156. auto voice_cpu_states{allocator.Allocate<VoiceState>(params.voices, 0x10)};
  157. if (voice_cpu_states.empty()) {
  158. return Service::Audio::ResultInsufficientBuffer;
  159. }
  160. for (auto& voice_state : voice_cpu_states) {
  161. voice_state = {};
  162. }
  163. auto mix_infos{allocator.Allocate<MixInfo>(params.sub_mixes + 1, 0x10)};
  164. if (mix_infos.empty()) {
  165. return Service::Audio::ResultInsufficientBuffer;
  166. }
  167. u32 effect_process_order_count{0};
  168. std::span<s32> effect_process_order_buffer{};
  169. if (params.effects > 0) {
  170. effect_process_order_count = params.effects * (params.sub_mixes + 1);
  171. effect_process_order_buffer = allocator.Allocate<s32>(effect_process_order_count, 0x10);
  172. if (effect_process_order_buffer.empty()) {
  173. return Service::Audio::ResultInsufficientBuffer;
  174. }
  175. }
  176. i = 0;
  177. for (auto& mix_info : mix_infos) {
  178. std::construct_at<MixInfo>(
  179. &mix_info, effect_process_order_buffer.subspan(i * params.effects, params.effects),
  180. params.effects, this->behavior);
  181. i++;
  182. }
  183. auto sorted_mix_infos{allocator.Allocate<MixInfo*>(params.sub_mixes + 1, 0x10)};
  184. if (sorted_mix_infos.empty()) {
  185. return Service::Audio::ResultInsufficientBuffer;
  186. }
  187. std::memset(sorted_mix_infos.data(), 0, sorted_mix_infos.size_bytes());
  188. if (behavior.IsSplitterSupported()) {
  189. u64 node_state_size{NodeStates::GetWorkBufferSize(params.sub_mixes + 1)};
  190. u64 edge_matrix_size{EdgeMatrix::GetWorkBufferSize(params.sub_mixes + 1)};
  191. auto node_states_workbuffer{allocator.Allocate<u8>(node_state_size, 1)};
  192. auto edge_matrix_workbuffer{allocator.Allocate<u8>(edge_matrix_size, 1)};
  193. if (node_states_workbuffer.empty() || edge_matrix_workbuffer.size() == 0) {
  194. return Service::Audio::ResultInsufficientBuffer;
  195. }
  196. mix_context.Initialize(sorted_mix_infos, mix_infos, params.sub_mixes + 1,
  197. effect_process_order_buffer, effect_process_order_count,
  198. node_states_workbuffer, node_state_size, edge_matrix_workbuffer,
  199. edge_matrix_size);
  200. } else {
  201. mix_context.Initialize(sorted_mix_infos, mix_infos, params.sub_mixes + 1,
  202. effect_process_order_buffer, effect_process_order_count, {}, 0, {},
  203. 0);
  204. }
  205. upsampler_manager = allocator.Allocate<UpsamplerManager>(1, 0x10).data();
  206. if (upsampler_manager == nullptr) {
  207. return Service::Audio::ResultInsufficientBuffer;
  208. }
  209. memory_pool_workbuffer = allocator.Allocate<MemoryPoolInfo>(memory_pool_count, 0x10);
  210. for (auto& memory_pool : memory_pool_workbuffer) {
  211. std::construct_at<MemoryPoolInfo>(&memory_pool, MemoryPoolInfo::Location::DSP);
  212. }
  213. if (memory_pool_workbuffer.empty() && memory_pool_count > 0) {
  214. return Service::Audio::ResultInsufficientBuffer;
  215. }
  216. if (!splitter_context.Initialize(behavior, params, allocator)) {
  217. return Service::Audio::ResultInsufficientBuffer;
  218. }
  219. std::span<EffectResultState> effect_result_states_cpu{};
  220. if (behavior.IsEffectInfoVersion2Supported() && params.effects > 0) {
  221. effect_result_states_cpu = allocator.Allocate<EffectResultState>(params.effects, 0x10);
  222. if (effect_result_states_cpu.empty()) {
  223. return Service::Audio::ResultInsufficientBuffer;
  224. }
  225. std::memset(effect_result_states_cpu.data(), 0, effect_result_states_cpu.size_bytes());
  226. }
  227. allocator.Align(0x40);
  228. unk_2B0 = allocator.GetSize() - allocator.GetCurrentOffset();
  229. unk_2A8 = {&workbuffer[allocator.GetCurrentOffset()], unk_2B0};
  230. upsampler_infos = allocator.Allocate<UpsamplerInfo>(upsampler_count, 0x40);
  231. for (auto& upsampler_info : upsampler_infos) {
  232. std::construct_at<UpsamplerInfo>(&upsampler_info);
  233. }
  234. std::construct_at<UpsamplerManager>(upsampler_manager, upsampler_count, upsampler_infos,
  235. upsampler_workbuffer);
  236. if (upsampler_infos.empty()) {
  237. return Service::Audio::ResultInsufficientBuffer;
  238. }
  239. auto effect_infos{allocator.Allocate<EffectInfoBase>(params.effects, 0x40)};
  240. for (auto& effect_info : effect_infos) {
  241. std::construct_at<EffectInfoBase>(&effect_info);
  242. }
  243. if (effect_infos.empty() && params.effects > 0) {
  244. return Service::Audio::ResultInsufficientBuffer;
  245. }
  246. std::span<EffectResultState> effect_result_states_dsp{};
  247. if (behavior.IsEffectInfoVersion2Supported() && params.effects > 0) {
  248. effect_result_states_dsp = allocator.Allocate<EffectResultState>(params.effects, 0x40);
  249. if (effect_result_states_dsp.empty()) {
  250. return Service::Audio::ResultInsufficientBuffer;
  251. }
  252. std::memset(effect_result_states_dsp.data(), 0, effect_result_states_dsp.size_bytes());
  253. }
  254. effect_context.Initialize(effect_infos, params.effects, effect_result_states_cpu,
  255. effect_result_states_dsp, effect_result_states_dsp.size());
  256. auto sinks{allocator.Allocate<SinkInfoBase>(params.sinks, 0x10)};
  257. for (auto& sink : sinks) {
  258. std::construct_at<SinkInfoBase>(&sink);
  259. }
  260. if (sinks.empty()) {
  261. return Service::Audio::ResultInsufficientBuffer;
  262. }
  263. sink_context.Initialize(sinks, params.sinks);
  264. auto voice_dsp_states{allocator.Allocate<VoiceState>(params.voices, 0x40)};
  265. if (voice_dsp_states.empty()) {
  266. return Service::Audio::ResultInsufficientBuffer;
  267. }
  268. for (auto& voice_state : voice_dsp_states) {
  269. voice_state = {};
  270. }
  271. voice_context.Initialize(sorted_voice_infos, voice_infos, voice_channel_resources,
  272. voice_cpu_states, voice_dsp_states, params.voices);
  273. if (params.perf_frames > 0) {
  274. const auto perf_workbuffer_size{
  275. PerformanceManager::GetRequiredBufferSizeForPerformanceMetricsPerFrame(behavior,
  276. params) *
  277. (params.perf_frames + 1) +
  278. 0xC};
  279. performance_workbuffer = allocator.Allocate<u8>(perf_workbuffer_size, 0x40);
  280. if (performance_workbuffer.empty()) {
  281. return Service::Audio::ResultInsufficientBuffer;
  282. }
  283. std::memset(performance_workbuffer.data(), 0, performance_workbuffer.size_bytes());
  284. performance_manager.Initialize(performance_workbuffer, performance_workbuffer.size_bytes(),
  285. params, behavior, memory_pool_info);
  286. }
  287. render_time_limit_percent = 100;
  288. drop_voice = params.voice_drop_enabled && params.execution_mode == ExecutionMode::Auto;
  289. drop_voice_param = 1.0f;
  290. num_voices_dropped = 0;
  291. allocator.Align(0x40);
  292. command_workbuffer_size = allocator.GetRemainingSize();
  293. command_workbuffer = allocator.Allocate<u8>(command_workbuffer_size, 0x40);
  294. if (command_workbuffer.empty()) {
  295. return Service::Audio::ResultInsufficientBuffer;
  296. }
  297. command_buffer_size = 0;
  298. reset_command_buffers = true;
  299. // nn::audio::dsp::FlushDataCache(transferMemory, transferMemorySize);
  300. if (behavior.IsCommandProcessingTimeEstimatorVersion5Supported()) {
  301. command_processing_time_estimator =
  302. std::make_unique<CommandProcessingTimeEstimatorVersion5>(sample_count,
  303. mix_buffer_count);
  304. } else if (behavior.IsCommandProcessingTimeEstimatorVersion4Supported()) {
  305. command_processing_time_estimator =
  306. std::make_unique<CommandProcessingTimeEstimatorVersion4>(sample_count,
  307. mix_buffer_count);
  308. } else if (behavior.IsCommandProcessingTimeEstimatorVersion3Supported()) {
  309. command_processing_time_estimator =
  310. std::make_unique<CommandProcessingTimeEstimatorVersion3>(sample_count,
  311. mix_buffer_count);
  312. } else if (behavior.IsCommandProcessingTimeEstimatorVersion2Supported()) {
  313. command_processing_time_estimator =
  314. std::make_unique<CommandProcessingTimeEstimatorVersion2>(sample_count,
  315. mix_buffer_count);
  316. } else {
  317. command_processing_time_estimator =
  318. std::make_unique<CommandProcessingTimeEstimatorVersion1>(sample_count,
  319. mix_buffer_count);
  320. }
  321. initialized = true;
  322. return ResultSuccess;
  323. }
  324. void System::Finalize() {
  325. if (!initialized) {
  326. return;
  327. }
  328. if (active) {
  329. Stop();
  330. }
  331. applet_resource_user_id = 0;
  332. PoolMapper pool_mapper(process_handle, false);
  333. pool_mapper.Unmap(memory_pool_info);
  334. if (process_handle) {
  335. pool_mapper.ClearUseState(memory_pool_workbuffer, memory_pool_count);
  336. for (auto& memory_pool : memory_pool_workbuffer) {
  337. if (memory_pool.IsMapped()) {
  338. pool_mapper.Unmap(memory_pool);
  339. }
  340. }
  341. // dsp::ProcessCleanup
  342. // close handle
  343. }
  344. initialized = false;
  345. }
  346. void System::Start() {
  347. std::scoped_lock l{lock};
  348. frames_elapsed = 0;
  349. state = State::Started;
  350. active = true;
  351. }
  352. void System::Stop() {
  353. {
  354. std::scoped_lock l{lock};
  355. state = State::Stopped;
  356. active = false;
  357. }
  358. if (execution_mode == ExecutionMode::Auto) {
  359. terminate_event.Wait();
  360. }
  361. }
  362. Result System::Update(std::span<const u8> input, std::span<u8> performance, std::span<u8> output) {
  363. std::scoped_lock l{lock};
  364. const auto start_time{core.CoreTiming().GetGlobalTimeNs().count()};
  365. std::memset(output.data(), 0, output.size());
  366. InfoUpdater info_updater(input, output, process_handle, behavior);
  367. auto result{info_updater.UpdateBehaviorInfo(behavior)};
  368. if (result.IsError()) {
  369. LOG_ERROR(Service_Audio, "Failed to update BehaviorInfo!");
  370. return result;
  371. }
  372. result = info_updater.UpdateMemoryPools(memory_pool_workbuffer, memory_pool_count);
  373. if (result.IsError()) {
  374. LOG_ERROR(Service_Audio, "Failed to update MemoryPools!");
  375. return result;
  376. }
  377. result = info_updater.UpdateVoiceChannelResources(voice_context);
  378. if (result.IsError()) {
  379. LOG_ERROR(Service_Audio, "Failed to update VoiceChannelResources!");
  380. return result;
  381. }
  382. result = info_updater.UpdateVoices(voice_context, memory_pool_workbuffer, memory_pool_count);
  383. if (result.IsError()) {
  384. LOG_ERROR(Service_Audio, "Failed to update Voices!");
  385. return result;
  386. }
  387. result = info_updater.UpdateEffects(effect_context, active, memory_pool_workbuffer,
  388. memory_pool_count);
  389. if (result.IsError()) {
  390. LOG_ERROR(Service_Audio, "Failed to update Effects!");
  391. return result;
  392. }
  393. if (behavior.IsSplitterSupported()) {
  394. result = info_updater.UpdateSplitterInfo(splitter_context);
  395. if (result.IsError()) {
  396. LOG_ERROR(Service_Audio, "Failed to update SplitterInfo!");
  397. return result;
  398. }
  399. }
  400. result =
  401. info_updater.UpdateMixes(mix_context, mix_buffer_count, effect_context, splitter_context);
  402. if (result.IsError()) {
  403. LOG_ERROR(Service_Audio, "Failed to update Mixes!");
  404. return result;
  405. }
  406. result = info_updater.UpdateSinks(sink_context, memory_pool_workbuffer, memory_pool_count);
  407. if (result.IsError()) {
  408. LOG_ERROR(Service_Audio, "Failed to update Sinks!");
  409. return result;
  410. }
  411. PerformanceManager* perf_manager{nullptr};
  412. if (performance_manager.IsInitialized()) {
  413. perf_manager = &performance_manager;
  414. }
  415. result =
  416. info_updater.UpdatePerformanceBuffer(performance, performance.size_bytes(), perf_manager);
  417. if (result.IsError()) {
  418. LOG_ERROR(Service_Audio, "Failed to update PerformanceBuffer!");
  419. return result;
  420. }
  421. result = info_updater.UpdateErrorInfo(behavior);
  422. if (result.IsError()) {
  423. LOG_ERROR(Service_Audio, "Failed to update ErrorInfo!");
  424. return result;
  425. }
  426. if (behavior.IsElapsedFrameCountSupported()) {
  427. result = info_updater.UpdateRendererInfo(frames_elapsed);
  428. if (result.IsError()) {
  429. LOG_ERROR(Service_Audio, "Failed to update RendererInfo!");
  430. return result;
  431. }
  432. }
  433. result = info_updater.CheckConsumedSize();
  434. if (result.IsError()) {
  435. LOG_ERROR(Service_Audio, "Invalid consume size!");
  436. return result;
  437. }
  438. adsp_rendered_event->Clear();
  439. num_times_updated++;
  440. const auto end_time{core.CoreTiming().GetGlobalTimeNs().count()};
  441. ticks_spent_updating += end_time - start_time;
  442. return ResultSuccess;
  443. }
  444. u32 System::GetRenderingTimeLimit() const {
  445. return render_time_limit_percent;
  446. }
  447. void System::SetRenderingTimeLimit(u32 limit) {
  448. render_time_limit_percent = limit;
  449. }
  450. u32 System::GetSessionId() const {
  451. return session_id;
  452. }
  453. u32 System::GetSampleRate() const {
  454. return sample_rate;
  455. }
  456. u32 System::GetSampleCount() const {
  457. return sample_count;
  458. }
  459. u32 System::GetMixBufferCount() const {
  460. return mix_buffer_count;
  461. }
  462. ExecutionMode System::GetExecutionMode() const {
  463. return execution_mode;
  464. }
  465. u32 System::GetRenderingDevice() const {
  466. return render_device;
  467. }
  468. bool System::IsActive() const {
  469. return active;
  470. }
  471. void System::SendCommandToDsp() {
  472. std::scoped_lock l{lock};
  473. if (initialized) {
  474. if (active) {
  475. terminate_event.Reset();
  476. const auto remaining_command_count{audio_renderer.GetRemainCommandCount(session_id)};
  477. u64 command_size{0};
  478. if (remaining_command_count) {
  479. adsp_behind = true;
  480. command_size = command_buffer_size;
  481. } else {
  482. command_size = GenerateCommand(command_workbuffer, command_workbuffer_size);
  483. }
  484. auto translated_addr{
  485. memory_pool_info.Translate(CpuAddr(command_workbuffer.data()), command_size)};
  486. auto time_limit_percent{70.0f};
  487. if (behavior.IsAudioRendererProcessingTimeLimit80PercentSupported()) {
  488. time_limit_percent = 80.0f;
  489. } else if (behavior.IsAudioRendererProcessingTimeLimit75PercentSupported()) {
  490. time_limit_percent = 75.0f;
  491. } else {
  492. // result ignored and 70 is used anyway
  493. behavior.IsAudioRendererProcessingTimeLimit70PercentSupported();
  494. time_limit_percent = 70.0f;
  495. }
  496. auto time_limit{
  497. static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
  498. (static_cast<f32>(render_time_limit_percent) / 100.0f))};
  499. audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
  500. applet_resource_user_id, process_handle,
  501. reset_command_buffers);
  502. reset_command_buffers = false;
  503. command_buffer_size = command_size;
  504. if (remaining_command_count == 0) {
  505. adsp_rendered_event->Signal();
  506. }
  507. } else {
  508. audio_renderer.ClearRemainCommandCount(session_id);
  509. terminate_event.Set();
  510. }
  511. }
  512. }
  513. u64 System::GenerateCommand(std::span<u8> in_command_buffer,
  514. [[maybe_unused]] u64 command_buffer_size_) {
  515. PoolMapper::ClearUseState(memory_pool_workbuffer, memory_pool_count);
  516. const auto start_time{core.CoreTiming().GetGlobalTimeNs().count()};
  517. auto command_list_header{reinterpret_cast<CommandListHeader*>(in_command_buffer.data())};
  518. command_list_header->buffer_count = static_cast<s16>(voice_channels + mix_buffer_count);
  519. command_list_header->sample_count = sample_count;
  520. command_list_header->sample_rate = sample_rate;
  521. command_list_header->samples_buffer = samples_workbuffer;
  522. const auto performance_initialized{performance_manager.IsInitialized()};
  523. if (performance_initialized) {
  524. performance_manager.TapFrame(adsp_behind, num_voices_dropped, render_start_tick);
  525. adsp_behind = false;
  526. num_voices_dropped = 0;
  527. render_start_tick = 0;
  528. }
  529. s8 channel_count{2};
  530. if (execution_mode == ExecutionMode::Auto) {
  531. const auto& sink{core.AudioCore().GetOutputSink()};
  532. channel_count = static_cast<s8>(sink.GetDeviceChannels());
  533. }
  534. AudioRendererSystemContext render_context{
  535. .session_id{session_id},
  536. .channels{channel_count},
  537. .mix_buffer_count{mix_buffer_count},
  538. .behavior{&behavior},
  539. .depop_buffer{depop_buffer},
  540. .upsampler_manager{upsampler_manager},
  541. .memory_pool_info{&memory_pool_info},
  542. };
  543. CommandBuffer command_buffer{
  544. .command_list{in_command_buffer},
  545. .sample_count{sample_count},
  546. .sample_rate{sample_rate},
  547. .size{sizeof(CommandListHeader)},
  548. .count{0},
  549. .estimated_process_time{0},
  550. .memory_pool{&memory_pool_info},
  551. .time_estimator{command_processing_time_estimator.get()},
  552. .behavior{&behavior},
  553. };
  554. PerformanceManager* perf_manager{nullptr};
  555. if (performance_initialized) {
  556. perf_manager = &performance_manager;
  557. }
  558. CommandGenerator command_generator{command_buffer, *command_list_header, render_context,
  559. voice_context, mix_context, effect_context,
  560. sink_context, splitter_context, perf_manager};
  561. voice_context.SortInfo();
  562. command_generator.GenerateVoiceCommands();
  563. const auto start_estimated_time{drop_voice_param *
  564. static_cast<f32>(command_buffer.estimated_process_time)};
  565. command_generator.GenerateSubMixCommands();
  566. command_generator.GenerateFinalMixCommands();
  567. command_generator.GenerateSinkCommands();
  568. if (drop_voice) {
  569. f32 time_limit_percent{70.0f};
  570. if (render_context.behavior->IsAudioRendererProcessingTimeLimit80PercentSupported()) {
  571. time_limit_percent = 80.0f;
  572. } else if (render_context.behavior
  573. ->IsAudioRendererProcessingTimeLimit75PercentSupported()) {
  574. time_limit_percent = 75.0f;
  575. } else {
  576. // result is ignored
  577. render_context.behavior->IsAudioRendererProcessingTimeLimit70PercentSupported();
  578. time_limit_percent = 70.0f;
  579. }
  580. const auto end_estimated_time{drop_voice_param *
  581. static_cast<f32>(command_buffer.estimated_process_time)};
  582. const auto dsp_time_limit{((time_limit_percent / 100.0f) * 2'880'000.0f) *
  583. (static_cast<f32>(render_time_limit_percent) / 100.0f)};
  584. const auto estimated_time{start_estimated_time - end_estimated_time};
  585. const auto time_limit{static_cast<u32>(std::max(dsp_time_limit + estimated_time, 0.0f))};
  586. num_voices_dropped =
  587. DropVoices(command_buffer, static_cast<u32>(start_estimated_time), time_limit);
  588. }
  589. command_list_header->buffer_size = command_buffer.size;
  590. command_list_header->command_count = command_buffer.count;
  591. voice_context.UpdateStateByDspShared();
  592. if (render_context.behavior->IsEffectInfoVersion2Supported()) {
  593. effect_context.UpdateStateByDspShared();
  594. }
  595. const auto end_time{core.CoreTiming().GetGlobalTimeNs().count()};
  596. total_ticks_elapsed += end_time - start_time;
  597. num_command_lists_generated++;
  598. render_start_tick = audio_renderer.GetRenderingStartTick(session_id);
  599. frames_elapsed++;
  600. return command_buffer.size;
  601. }
  602. f32 System::GetVoiceDropParameter() const {
  603. return drop_voice_param;
  604. }
  605. void System::SetVoiceDropParameter(f32 voice_drop_) {
  606. drop_voice_param = voice_drop_;
  607. }
  608. u32 System::DropVoices(CommandBuffer& command_buffer, u32 estimated_process_time, u32 time_limit) {
  609. u32 i{0};
  610. auto command_list{command_buffer.command_list.data() + sizeof(CommandListHeader)};
  611. ICommand* cmd{nullptr};
  612. // Find a first valid voice to drop
  613. while (i < command_buffer.count) {
  614. cmd = reinterpret_cast<ICommand*>(command_list);
  615. if (cmd->type == CommandId::Performance ||
  616. cmd->type == CommandId::DataSourcePcmInt16Version1 ||
  617. cmd->type == CommandId::DataSourcePcmInt16Version2 ||
  618. cmd->type == CommandId::DataSourcePcmFloatVersion1 ||
  619. cmd->type == CommandId::DataSourcePcmFloatVersion2 ||
  620. cmd->type == CommandId::DataSourceAdpcmVersion1 ||
  621. cmd->type == CommandId::DataSourceAdpcmVersion2) {
  622. break;
  623. }
  624. command_list += cmd->size;
  625. i++;
  626. }
  627. if (cmd == nullptr || command_buffer.count == 0 || i >= command_buffer.count) {
  628. return 0;
  629. }
  630. auto voices_dropped{0};
  631. while (i < command_buffer.count) {
  632. const auto node_id{cmd->node_id};
  633. const auto node_id_type{cmd->node_id >> 28};
  634. const auto node_id_base{(cmd->node_id >> 16) & 0xFFF};
  635. // If the new estimated process time falls below the limit, we're done dropping.
  636. if (estimated_process_time <= time_limit) {
  637. break;
  638. }
  639. if (node_id_type != 1) {
  640. break;
  641. }
  642. // Don't drop voices marked with the highest priority.
  643. auto& voice_info{voice_context.GetInfo(node_id_base)};
  644. if (voice_info.priority == HighestVoicePriority) {
  645. break;
  646. }
  647. voices_dropped++;
  648. voice_info.voice_dropped = true;
  649. // First iteration should drop the voice, and then iterate through all of the commands tied
  650. // to the voice. We don't need reverb on a voice which we've just removed, for example.
  651. // Depops can't be removed otherwise we'll introduce audio popping, and we don't
  652. // remove perf commands. Lower the estimated time for each command dropped.
  653. while (i < command_buffer.count && cmd->node_id == node_id) {
  654. if (cmd->type == CommandId::DepopPrepare) {
  655. cmd->enabled = true;
  656. } else if (cmd->enabled && cmd->type != CommandId::Performance) {
  657. cmd->enabled = false;
  658. estimated_process_time -= static_cast<u32>(
  659. drop_voice_param * static_cast<f32>(cmd->estimated_process_time));
  660. }
  661. command_list += cmd->size;
  662. cmd = reinterpret_cast<ICommand*>(command_list);
  663. i++;
  664. }
  665. i++;
  666. }
  667. return voices_dropped;
  668. }
  669. } // namespace AudioCore::Renderer