system_manager.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <chrono>
  4. #include "audio_core/audio_core.h"
  5. #include "audio_core/renderer/adsp/adsp.h"
  6. #include "audio_core/renderer/system_manager.h"
  7. #include "common/microprofile.h"
  8. #include "common/thread.h"
  9. #include "core/core.h"
  10. #include "core/core_timing.h"
  11. MICROPROFILE_DEFINE(Audio_RenderSystemManager, "Audio", "Render System Manager",
  12. MP_RGB(60, 19, 97));
  13. namespace AudioCore::AudioRenderer {
  14. constexpr std::chrono::nanoseconds RENDER_TIME{5'000'000UL};
  15. SystemManager::SystemManager(Core::System& core_)
  16. : core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()},
  17. thread_event{Core::Timing::CreateEvent(
  18. "AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
  19. return ThreadFunc2(time);
  20. })} {
  21. core.CoreTiming().RegisterPauseCallback([this](bool paused) { PauseCallback(paused); });
  22. }
  23. SystemManager::~SystemManager() {
  24. Stop();
  25. }
  26. bool SystemManager::InitializeUnsafe() {
  27. if (!active) {
  28. if (adsp.Start()) {
  29. active = true;
  30. thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); });
  31. core.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), RENDER_TIME,
  32. thread_event);
  33. }
  34. }
  35. return adsp.GetState() == ADSP::State::Started;
  36. }
  37. void SystemManager::Stop() {
  38. if (!active) {
  39. return;
  40. }
  41. core.CoreTiming().UnscheduleEvent(thread_event, {});
  42. active = false;
  43. update.store(true);
  44. update.notify_all();
  45. thread.join();
  46. adsp.Stop();
  47. }
  48. bool SystemManager::Add(System& system_) {
  49. std::scoped_lock l2{mutex2};
  50. if (systems.size() + 1 > MaxRendererSessions) {
  51. LOG_ERROR(Service_Audio, "Maximum AudioRenderer Systems active, cannot add more!");
  52. return false;
  53. }
  54. {
  55. std::scoped_lock l{mutex1};
  56. if (systems.empty()) {
  57. if (!InitializeUnsafe()) {
  58. LOG_ERROR(Service_Audio, "Failed to start the AudioRenderer SystemManager");
  59. return false;
  60. }
  61. }
  62. }
  63. systems.push_back(&system_);
  64. return true;
  65. }
  66. bool SystemManager::Remove(System& system_) {
  67. std::scoped_lock l2{mutex2};
  68. {
  69. std::scoped_lock l{mutex1};
  70. if (systems.remove(&system_) == 0) {
  71. LOG_ERROR(Service_Audio,
  72. "Failed to remove a render system, it was not found in the list!");
  73. return false;
  74. }
  75. }
  76. if (systems.empty()) {
  77. Stop();
  78. }
  79. return true;
  80. }
  81. void SystemManager::ThreadFunc() {
  82. constexpr char name[]{"yuzu:AudioRenderSystemManager"};
  83. MicroProfileOnThreadCreate(name);
  84. Common::SetCurrentThreadName(name);
  85. Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
  86. while (active) {
  87. {
  88. std::scoped_lock l{mutex1};
  89. MICROPROFILE_SCOPE(Audio_RenderSystemManager);
  90. for (auto system : systems) {
  91. system->SendCommandToDsp();
  92. }
  93. }
  94. adsp.Signal();
  95. adsp.Wait();
  96. update.wait(false);
  97. update.store(false);
  98. }
  99. }
  100. std::optional<std::chrono::nanoseconds> SystemManager::ThreadFunc2(s64 time) {
  101. update.store(true);
  102. update.notify_all();
  103. return std::nullopt;
  104. }
  105. void SystemManager::PauseCallback(bool paused) {
  106. if (paused && core.IsPoweredOn() && core.IsShuttingDown()) {
  107. update.store(true);
  108. update.notify_all();
  109. }
  110. }
  111. } // namespace AudioCore::AudioRenderer