From ea8c01c72080f59df0714141649e57859ae2a10d Mon Sep 17 00:00:00 2001 From: Enderlook Date: Mon, 11 Nov 2024 20:50:51 -0300 Subject: [PATCH] [Unity] Improve perfomance by reducing memory allocations per frame and GC pressure when using FMOD engine In an scene test of mine, I had 158 SteamAudioSources. Without this commit, SteamAudioSource.Update() took 3.77 ms per frame (7.2% of CPU budget) and allocated 137 kb per frame. After this commit, it took 2.8 ms per frame (5.8%) and allocates 79.8 kb per frame. That is a ~25% perfomance improvement in CPU and ~41% less of garbage for the GC. For further improvement reflection should be eliminated. My tests show it can reduce time to 0.17 ms (0.3%) and 0 bytes of garbage, equivalent to ~95% perfomance improvement. Although it remains a question how to do that. --- .../Runtime/FMODStudioAudioEngineSource.cs | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/unity/src/project/SteamAudioUnity/Assets/Plugins/SteamAudio/Scripts/Runtime/FMODStudioAudioEngineSource.cs b/unity/src/project/SteamAudioUnity/Assets/Plugins/SteamAudio/Scripts/Runtime/FMODStudioAudioEngineSource.cs index 904e8958..53ddb731 100644 --- a/unity/src/project/SteamAudioUnity/Assets/Plugins/SteamAudio/Scripts/Runtime/FMODStudioAudioEngineSource.cs +++ b/unity/src/project/SteamAudioUnity/Assets/Plugins/SteamAudio/Scripts/Runtime/FMODStudioAudioEngineSource.cs @@ -30,6 +30,14 @@ public sealed class FMODStudioAudioEngineSource : AudioEngineSource SteamAudioSource mSteamAudioSource = null; int mHandle = -1; + static readonly object[] Array1 = new object[1]; + static readonly object[] Array2 = new object[2]; + static readonly object[] Array5 = new object[5]; + + static readonly object BoxedZero = (int)0; + static readonly object[] BoxedNumbers = new object[] { BoxedZero, (int)1, (int)2 }; + static readonly object BoxedSimulationOutputsParamIndex = kSimulationOutputsParamIndex; + static Type FMOD_DSP; static Type FMOD_ChannelGroup; static Type FMOD_Studio_EventInstance; @@ -74,8 +82,10 @@ public override void UpdateParameters(SteamAudioSource source) if (!mFoundDSP) return; - var index = kSimulationOutputsParamIndex; - FMOD_DSP_setParameterInt.Invoke(mDSP, new object[] { index++, mHandle }); + var args = Array2; + args[1] = mHandle; + args[0] = BoxedSimulationOutputsParamIndex; + FMOD_DSP_setParameterInt.Invoke(mDSP, args); } void CheckForChangedEventInstance() @@ -83,7 +93,7 @@ void CheckForChangedEventInstance() if (mEventEmitter != null) { var eventInstance = FMODUnity_StudioEventEmitter_EventInstance.GetValue(mEventEmitter, null); - if (!eventInstance.Equals(mEventInstance)) + if (eventInstance != mEventInstance) { // The event instance is different from the one we last used, which most likely means the // event-related objects were destroyed and re-created. Make sure we look for the DSP instance @@ -114,19 +124,23 @@ void FindDSP(GameObject gameObject) if (!((bool)FMOD_Studio_EventInstance_isValid.Invoke(mEventInstance, null))) return; - var channelGroup = Activator.CreateInstance(FMOD_ChannelGroup); + object channelGroup = null; - var getChannelGroupArgs = new object[] { channelGroup }; + var getChannelGroupArgs = Array1; + getChannelGroupArgs[0] = channelGroup; FMOD_Studio_EventInstance_getChannelGroup.Invoke(mEventInstance, getChannelGroupArgs); channelGroup = getChannelGroupArgs[0]; - var getNumDSPsArgs = new object[] { 0 }; + var getNumDSPsArgs = Array1; + getNumDSPsArgs[0] = BoxedZero; FMOD_ChannelGroup_getNumDSPs.Invoke(channelGroup, getNumDSPsArgs); int numDSPs = (int)getNumDSPsArgs[0]; for (var i = 0; i < numDSPs; ++i) { - var getDSPArgs = new object[] { i, mDSP }; + var getDSPArgs = Array2; + getDSPArgs[1] = mDSP; + getDSPArgs[0] = i < BoxedNumbers.Length ? BoxedNumbers[i] : i; FMOD_ChannelGroup_getDSP.Invoke(channelGroup, getDSPArgs); mDSP = getDSPArgs[1]; @@ -136,7 +150,12 @@ void FindDSP(GameObject gameObject) var dspConfigWidth = 0; var dspConfigHeight = 0; - var getInfoArgs = new object[] { dspName, dspVersion, dspNumChannels, dspConfigWidth, dspConfigHeight }; + var getInfoArgs = Array5; + getInfoArgs[4] = dspConfigHeight; + getInfoArgs[3] = dspConfigWidth; + getInfoArgs[2] = dspNumChannels; + getInfoArgs[1] = dspVersion; + getInfoArgs[0] = dspName; FMOD_DSP_getInfo.Invoke(mDSP, getInfoArgs); dspName = (string)getInfoArgs[0];