Wwise SDK 2022.1.18
|
在默认情况下,Wwise 声音引擎在名为AK::EventManager
的专门线程中执行所有命令处理和音频渲染,该线程由AkPlatformInitSettings::threadLEngine 参数控制。调用 AK::SoundEngine::RenderAudio
表明游戏帧结束,线程可处理自上次调用 RenderAudio
以来的所有 API 命令。
将 AkInitSettings::bUseLEngineThread
设为 false
会禁用此线程,促使 RenderAudio
同步执行命令处理和音频渲染(如有必要)。音频输出的实际速度仍由音频终端控制。若 RenderAudio
调用间隔短于 AkInitSettings::uNumSamplesPerFrame
和输出采样率限定的缓冲周期,则有些 RenderAudio
调用将跳过音频渲染部分。相反,若 RenderAudio
调用间隔长于输出缓冲周期,则 RenderAudio
可能会一次处理多个缓冲区,导致出现 CPU 用量峰值,并可能最终造成音频卡顿。
启用离线渲染会禁止音频线程异步执行命令处理和音频渲染。每次调用 RenderAudio
时渲染的音频数量取决于发给 AK::SoundEngine::SetOfflineRenderingFrameTime
的非零正值。零值或负值会强制 RenderAudio
精准处理一个音频缓冲区。
注意: 在禁用音频渲染线程或启用离线渲染时,不得从 RenderAudio 调用方的同一线程同步调用 AK::SoundEngine::LoadBank 和 AK::SoundEngine::UnloadBank API。因为这些调用可能会阻塞线程,直到有音频缓冲区被渲染来完成 Stop 操作并释放 SoundBank 媒体(只有并发调用 RenderAudio 才能实现)。 |
在 Microsoft 平台上,由于使用了单线程单元 (STA) 并发模型,在将 AkInitSettings::bUseLEngineThread
设为 false
时,必须从调用 AK::SoundEngine::RenderAudio
的同一线程调用 CoInitializeEx()
。
有些 AK::SoundEngine::Query 函数可能会导致 CPU 用量突然增加。为了尽量避免浪费 CPU 时间并确保最佳性能,建议遵守以下准侧:
在默认情况下,Wwise 声音引擎会在音频渲染线程上依次执行其各种音频渲染任务(或称作业)。这些作业包括但不限于总线和声部处理任务。
您可以通过指定回调来允许 Wwise 声音引擎在游戏管理的线程上请求预留 CPU 时间以启用对音频作业的并行执行。在游戏通过 AkJobMgrSettings::fnRequestJobWorker
提供对此回调的实现时,会在 Wwise 声音引擎中启用并行执行。
备注: 在启动并行作业执行时,并行作业工作线程会生成部分 AK::SoundEngine 回调。有些插件可能不支持并行执行。 |
要理解声音引擎的 Job Manager 的工作机制,需先了解两个重要回调之间的区别:
备注: Wwise 声音引擎预计对于每个工作请求只会执行一次对工作函数的调用。比如,若调用工作请求函数一次来请求执行三项 AkJobType_AudioProcessing 类型的工作,然后再次调用来请求执行两项 AkJobType_Generic 类型的工作,则声音引擎预计游戏会针对 AkJobType_AudioProcessing 调用工作函数三次,并针对 AkJobType_Generic 调用两次。这些调用可从不同的线程按照任意顺序(依次或同时)发布。 |
在定义工作请求函数后,音频渲染线程会按照如下方式执行:
此流程可在一个音频渲染过程中重复多次,音频渲染线程会尝试执行尽可能多的任务。比如,在渲染总线通路图时,一旦完成对所有输入的处理,就会请求为给定总线预留处理时间,并且可独立于其他总线来运行。藉此,Job Manager 可确保将吞吐量最大化。
备注: 工作请求函数可从任何执行声音引擎代码的线程调用,而且必须以不影响线程安全的情况下运行。 |
Wwise 声音引擎的 Job Manager 可与现有作业调度程序结合使用来实现协同多任务处理。对于已经有作业调度程序的游戏引擎,在使用工作请求函数时,要确保在其现有作业系统内调度工作函数的执行。
在调用工作函数时,游戏引擎的作业调度程序可指定超时时限(毫秒)。这样可以避免声音引擎在调用线程上占用太多 CPU 时间。在超过此超时时限时,工作函数会停止并在有更多作业可执行时请求执行额外的工作。这样的话,就可在该线程上执行可能拥有更高优先级的其他游戏引擎工作。
备注: 在延迟执行工作函数或限制声音引擎工作执行时间时必须小心,因为这可能会导致出现声部匮乏。在将声音引擎作业集成到现有作业调度程序中时,建议将音频渲染作业视为高优先级工作。 |
对于还没有作业调度程序的游戏引擎,SDK/samples/SoundEngine/Common/AkJobWorkerMgr.[h,cpp]
下的 SDK 示例中提供了此类调度程序的实现示例。在此示例的基础上,可以更加清楚地了解如何并行执行音频渲染作业。除此之外,IntegrationDemo 还提供了代码来演示如何将该实现示例集成到实际的终端用户应用程序中。
下面列出了有关如何有效运用 Job Manager 的一些建议。
AK::MemoryMgr::InitForThread
和 AK::MemoryMgr::TermForThread
以确保正确地初始化和终止线程本地内存资源。另外,建议在运行工作函数后进入非活跃期时调用 AK::MemoryMgr::TrimForThread
以释放近期可能不会再使用的线程本地内存资源。AK::SoundEngine::SetJobMgrMaxActiveWorkers
. This can be useful to dynamically respond to changes in your title's operating conditions, or to more easily experiment and profile different configurations for multi-threaded work.您需要参考游戏的其他需求来对上述建议做出权衡。即便不遵从其中的有些建议,Job Manager 仍不失为一种增大声音引擎整体吞吐量的便捷方式。
“在分配作业时出现内存不足问题”被视为严重故障,因为音频渲染的逻辑流程会被中断并且无法恢复。这可能会导致不符合预期的结果和资源泄漏。
为了避免出现这种情况,Job Manager 会分配内存片。这些内存片会被保留并重复使用,直到声音引擎终止。其中的大部分内存片都在声音引擎初始化期间预先分配。不过,也可根据需要分配其他的内存片。
您可以通过 AkInitSettings::settingsJobManager
控制内存片的大小以及初始化时预先分配的内存片数量。
备注: 若 AK::MemoryMgr::Malloc 无法在渲染期间分配新的内存片,Job Manager 会一直尝试进行分配,直到成功为止。若发现声音引擎在内存不足的情况下挂起,请在初始化设置中增大预分配的内存片数。 |