WwiseConcurrencyModuleImpl.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*******************************************************************************
  2. The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
  3. Technology released in source code form as part of the game integration package.
  4. The content of this file may not be used without valid licenses to the
  5. AUDIOKINETIC Wwise Technology.
  6. Note that the use of the game engine is subject to the Unreal(R) Engine End User
  7. License Agreement at https://www.unrealengine.com/en-US/eula/unreal
  8. License Usage
  9. Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
  10. this file in accordance with the end user license agreement provided with the
  11. software or, alternatively, in accordance with the terms contained
  12. in a written agreement between you and Audiokinetic Inc.
  13. Copyright (c) 2023 Audiokinetic Inc.
  14. *******************************************************************************/
  15. #include "Wwise/WwiseConcurrencyModuleImpl.h"
  16. #include "Wwise/WwiseGlobalCallbacks.h"
  17. #include "Wwise/Stats/Concurrency.h"
  18. IMPLEMENT_MODULE(FWwiseConcurrencyModule, WwiseConcurrency)
  19. FWwiseConcurrencyModule::FWwiseConcurrencyModule()
  20. {
  21. }
  22. void FWwiseConcurrencyModule::StartupModule()
  23. {
  24. UE_LOG(LogWwiseConcurrency, Display, TEXT("Initializing default Concurrency."));
  25. ExecutionQueueLock.WriteLock();
  26. if (!ExecutionQueueThreadPool)
  27. {
  28. InitializeExecutionQueueThreadPool();
  29. }
  30. ExecutionQueueLock.WriteUnlock();
  31. GlobalCallbacksLock.WriteLock();
  32. if (!GlobalCallbacks)
  33. {
  34. InitializeGlobalCallbacks();
  35. }
  36. GlobalCallbacksLock.WriteUnlock();
  37. IWwiseConcurrencyModule::StartupModule();
  38. }
  39. void FWwiseConcurrencyModule::ShutdownModule()
  40. {
  41. UE_LOG(LogWwiseConcurrency, Display, TEXT("Shutting down default Concurrency."));
  42. GlobalCallbacksLock.WriteLock();
  43. TerminateGlobalCallbacks();
  44. GlobalCallbacksLock.WriteUnlock();
  45. ExecutionQueueLock.WriteLock();
  46. TerminateExecutionQueueThreadPool();
  47. ExecutionQueueLock.WriteUnlock();
  48. IWwiseConcurrencyModule::ShutdownModule();
  49. }
  50. FQueuedThreadPool* FWwiseConcurrencyModule::GetExecutionQueueThreadPool()
  51. {
  52. ExecutionQueueLock.ReadLock();
  53. if (LIKELY(ExecutionQueueThreadPool))
  54. {
  55. ExecutionQueueLock.ReadUnlock();
  56. return ExecutionQueueThreadPool;
  57. }
  58. ExecutionQueueLock.ReadUnlock();
  59. ExecutionQueueLock.WriteLock();
  60. if (UNLIKELY(ExecutionQueueThreadPool))
  61. {
  62. ExecutionQueueLock.WriteUnlock();
  63. return ExecutionQueueThreadPool;
  64. }
  65. InitializeExecutionQueueThreadPool();
  66. ExecutionQueueLock.WriteUnlock();
  67. return ExecutionQueueThreadPool;
  68. }
  69. FWwiseGlobalCallbacks* FWwiseConcurrencyModule::GetGlobalCallbacks()
  70. {
  71. GlobalCallbacksLock.ReadLock();
  72. if (LIKELY(GlobalCallbacks))
  73. {
  74. GlobalCallbacksLock.ReadUnlock();
  75. return GlobalCallbacks;
  76. }
  77. GlobalCallbacksLock.ReadUnlock();
  78. GlobalCallbacksLock.WriteLock();
  79. if (UNLIKELY(GlobalCallbacks))
  80. {
  81. GlobalCallbacksLock.WriteUnlock();
  82. return GlobalCallbacks;
  83. }
  84. InitializeGlobalCallbacks();
  85. GlobalCallbacksLock.WriteUnlock();
  86. return GlobalCallbacks;
  87. }
  88. int32 FWwiseConcurrencyModule::NumberOfExecutionQueueThreadsToSpawn()
  89. {
  90. if (UNLIKELY(!FPlatformProcess::SupportsMultithreading()))
  91. {
  92. return 1;
  93. }
  94. static constexpr int32 ClampMin = 2;
  95. static constexpr int32 ClampMax = 8;
  96. // Unreal Platform gives a curated value based on the possible number of cores available. Some platforms have 3, some have 13.
  97. // In our case, we don't want that many threads, don't want to tax systems, but don't want the app to wait for us.
  98. // A square root gives a good correlation for most, and for everyone else, it's possible to override this class.
  99. // 4 cores = 2 threads, 9 cores = 3 threads, 16 cores = 4 threads.
  100. const auto PlatformWorkersToSpawn = FPlatformMisc::NumberOfWorkerThreadsToSpawn();
  101. const auto WorkersToSpawn = FMath::Sqrt(static_cast<float>(PlatformWorkersToSpawn));
  102. return FMath::Min(ClampMax, FMath::Max(ClampMin, static_cast<int32>(WorkersToSpawn)));
  103. }
  104. void FWwiseConcurrencyModule::InitializeExecutionQueueThreadPool()
  105. {
  106. static constexpr int32 StackSize = 128 * 1024;
  107. ExecutionQueueThreadPool = FQueuedThreadPool::Allocate();
  108. const int32 NumThreadsInThreadPool = NumberOfExecutionQueueThreadsToSpawn();
  109. verify(ExecutionQueueThreadPool->Create(NumThreadsInThreadPool, StackSize, TPri_Normal, TEXT("Wwise ExecutionQueue Pool")));
  110. }
  111. void FWwiseConcurrencyModule::InitializeGlobalCallbacks()
  112. {
  113. if (!ExecutionQueueThreadPool)
  114. {
  115. InitializeExecutionQueueThreadPool();
  116. }
  117. GlobalCallbacks = new FWwiseGlobalCallbacks;
  118. // GlobalCallbacks->Initialize(); Initialization requires memory allocation that is only available in AkInitializationSettings.
  119. }
  120. void FWwiseConcurrencyModule::TerminateExecutionQueueThreadPool()
  121. {
  122. if (ExecutionQueueThreadPool)
  123. {
  124. ExecutionQueueThreadPool->Destroy();
  125. ExecutionQueueThreadPool = nullptr;
  126. }
  127. }
  128. void FWwiseConcurrencyModule::TerminateGlobalCallbacks()
  129. {
  130. if (GlobalCallbacks)
  131. {
  132. GlobalCallbacks->Terminate();
  133. delete GlobalCallbacks;
  134. GlobalCallbacks = nullptr;
  135. }
  136. }