/******************************************************************************* The content of this file includes portions of the proprietary AUDIOKINETIC Wwise Technology released in source code form as part of the game integration package. The content of this file may not be used without valid licenses to the AUDIOKINETIC Wwise Technology. Note that the use of the game engine is subject to the Unreal(R) Engine End User License Agreement at https://www.unrealengine.com/en-US/eula/unreal License Usage Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use this file in accordance with the end user license agreement provided with the software or, alternatively, in accordance with the terms contained in a written agreement between you and Audiokinetic Inc. Copyright (c) 2023 Audiokinetic Inc. *******************************************************************************/ #include "AkJobWorkerScheduler.h" #include "AkAudioDevice.h" #include "Wwise/WwiseTask.h" #include "Wwise/API/WwiseMemoryMgrAPI.h" #define AK_DECLARE_JOB_TYPE(__job__, __desc__, __thread__) \ DECLARE_CYCLE_STAT(TEXT(__desc__), STAT_AkJob##__job__, STATGROUP_Audio); \ namespace AkJobWorkerSchedulerInternals \ { \ static const TCHAR* const Name##__job__ = TEXT(__desc__); \ static EWwiseTaskPriority Task##__job__ = __thread__; \ } #define AK_DEFINE_JOB_CASE(__job__) \ case AkJobType_##__job__: \ Name = AkJobWorkerSchedulerInternals::Name##__job__; \ StatId = GET_STATID(STAT_AkJob##__job__); \ TaskPriority = AkJobWorkerSchedulerInternals::Task##__job__ static_assert(AK_NUM_JOB_TYPES == 3, "Update the stat groups and switch cases below for new job types!"); AK_DECLARE_JOB_TYPE(Generic, "Wwise Generic Job", EWwiseTaskPriority::High) AK_DECLARE_JOB_TYPE(AudioProcessing, "Wwise Audio Processing Job", EWwiseTaskPriority::High) AK_DECLARE_JOB_TYPE(SpatialAudio, "Wwise Spatial Audio Job", EWwiseTaskPriority::High) static void OnJobWorkerRequest(AkJobWorkerFunc in_fnJobWorker, AkJobType in_jobType, AkUInt32 in_uNumWorkers, void* in_pUserData) { FAkJobWorkerScheduler* Scheduler = static_cast(in_pUserData); AkUInt32 MaxExecutionTime = Scheduler->uMaxExecutionTime; const TCHAR* Name; TStatId StatId; EWwiseTaskPriority TaskPriority; switch (in_jobType) { AK_DEFINE_JOB_CASE(AudioProcessing); break; AK_DEFINE_JOB_CASE(SpatialAudio); break; default: check(!"Unknown job type."); // Fall-through AK_DEFINE_JOB_CASE(Generic); } for (int i=0; i < (int)in_uNumWorkers; i++) { LaunchWwiseTask(Name, TaskPriority, [=]() { #if STATS #if UE_5_0_OR_LATER FScopeCycleCounter CycleCount(StatId, FStat_STAT_AkJobGeneric::GetFlags()); #else FScopeCycleCounter CycleCount(StatId); #endif #endif in_fnJobWorker(in_jobType, MaxExecutionTime); // After completion of the worker function, release any thread-local memory resources if (auto* MemoryManager = IWwiseMemoryMgrAPI::Get()) { MemoryManager->TrimForThread(); } }); } } #undef AK_DECLARE_JOB_TYPE #undef AK_DEFINE_JOB_TYPE void FAkJobWorkerScheduler::InstallJobWorkerScheduler(uint32 in_uMaxExecutionTime, uint32 in_uMaxWorkerCount, AkJobMgrSettings & out_settings) { if (!FTaskGraphInterface::Get().IsRunning()) { UE_LOG(LogAkAudio, Warning, TEXT("Multi-core rendering was requested, but Task Graph is not running. Multi-core rendering disabled.")); } else if (!FPlatformProcess::SupportsMultithreading()) { UE_LOG(LogAkAudio, Warning, TEXT("Multi-core rendering was requested, platform does not support multi-threading. Multi-core rendering disabled.")); } else { check(ENamedThreads::bHasHighPriorityThreads); uMaxExecutionTime = in_uMaxExecutionTime; AkUInt32 uNumWorkerThreads = FTaskGraphInterface::Get().GetNumWorkerThreads(); AkUInt32 uMaxActiveWorkers = FMath::Min(uNumWorkerThreads, in_uMaxWorkerCount); if (uMaxActiveWorkers > 0) { out_settings.fnRequestJobWorker = OnJobWorkerRequest; out_settings.pClientData = this; for (int i = 0; i < AK_NUM_JOB_TYPES; i++) { out_settings.uMaxActiveWorkers[i] = uMaxActiveWorkers; } } else { UE_LOG(LogAkAudio, Warning, TEXT("Multi-core rendering was requested, but Max Num Job Workers is set to 0. Multi-core rendering disabled.")); } } }