Skip to content

Commit 1798013

Browse files
authored
perf: Optimize RSE.LateUpdate by patching AudioSource ctor (#42)
Every frame, RocketSoundEnhancement makes a FindObjectsOfType call in order to discover any new AudioSources that have been created in the last frame. This is slow. This commit does away with that by: - Patching AudioSource::.ctor to add the newly created AudioSource object to a list (if there is currently an instance of RocketSoundEnhancement active). - Processing the new items in the list in LateUpdate instead of checking all available items. There might be some further simplifications that can be done here now that we know that we're only processing new AudioSources. None of them would have an effect on performance though, so I have left them in just to be safe. In my testing this change reduces the time spent in RSE.LateUpdate from 4.4s to 90ms over a 253s launch to orbit.
1 parent 74820f6 commit 1798013

File tree

5 files changed

+72
-28
lines changed

5 files changed

+72
-28
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ on:
1414
jobs:
1515
build:
1616
uses: KSPModdingLibs/KSPBuildTools/.github/workflows/[email protected]
17+
with:
18+
dependency-identifiers: Harmony2
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using HarmonyLib;
2+
using UnityEngine;
3+
using System;
4+
5+
namespace RocketSoundEnhancement.Patches
6+
{
7+
[HarmonyPatch(typeof(AudioSource), MethodType.Constructor, argumentTypes: new Type[0])]
8+
internal static class AudioSource_Ctor_Patch
9+
{
10+
static void Postfix(AudioSource __instance)
11+
{
12+
RocketSoundEnhancement.Instance?.newAudioSources?.Add(__instance);
13+
}
14+
}
15+
}
16+
17+

Source/RocketSoundEnhancement/RocketSoundEnhancement.cs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,16 @@ public static AudioMixer Mixer
5858
private float lastInteriorCutoffFreq;
5959

6060
private HashSet<int> managedSources = new HashSet<int>();
61+
internal readonly List<AudioSource> newAudioSources = new List<AudioSource>();
6162

6263
private bool gamePaused;
6364

6465
private void Awake()
6566
{
6667
if (instance != null) { Destroy(instance); }
6768

69+
// Get all the currently existing audio sources.
70+
newAudioSources.AddRange((AudioSource[])FindObjectsOfType(typeof(AudioSource)));
6871
instance = this;
6972
}
7073

@@ -162,27 +165,42 @@ public float WindModulation()
162165
return Mathf.Lerp(1, windModulation, Mathf.Clamp01((float)FlightGlobals.ActiveVessel.atmDensity));
163166
}
164167

168+
bool GetNextAudioSource(out AudioSource source)
169+
{
170+
if (newAudioSources.Count == 0)
171+
{
172+
source = null;
173+
return false;
174+
}
175+
176+
// This makes sure things still work even if a new audio source ends
177+
// up being created while we are running.
178+
source = newAudioSources[newAudioSources.Count - 1];
179+
newAudioSources.RemoveAt(newAudioSources.Count - 1);
180+
return true;
181+
}
182+
165183
public void LateUpdate()
166184
{
167185
if (gamePaused || !HighLogic.LoadedSceneIsFlight) return;
168186

169187
if (!Settings.EnableAudioEffects || Mixer == null)
170188
{
171-
// TODO: some kind of latch so this only runs once
172-
foreach (var sourceObj in FindObjectsOfType(typeof(AudioSource)))
189+
while (GetNextAudioSource(out var source))
173190
{
174-
AudioSource source = (AudioSource)sourceObj;
175-
if (source != null) source.outputAudioMixerGroup = null;
191+
if (source != null)
192+
source.outputAudioMixerGroup = null;
176193
}
194+
177195
managedSources.Clear();
178-
179196
return;
180197
}
181198

182199
// NOTE: the generic (strongly typed) version of FindObjectsOfType is slower!
183-
foreach (var sourceObj in FindObjectsOfType(typeof(AudioSource)))
200+
while (GetNextAudioSource(out var source))
184201
{
185-
AudioSource source = (AudioSource)sourceObj;
202+
if (source == null)
203+
continue;
186204

187205
int instanceID = source.GetInstanceID();
188206

Source/RocketSoundEnhancement/RocketSoundEnhancement.csproj

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,34 @@
77
<Publicize Include="Assembly-CSharp" IncludeCompilerGeneratedMembers="false" />
88
</ItemGroup>
99

10-
<PropertyGroup>
11-
<BinariesOutputRelativePath>GameData\RocketSoundEnhancement\Plugins</BinariesOutputRelativePath>
12-
<GenerateKSPAssemblyAttribute>true</GenerateKSPAssemblyAttribute>
13-
<GenerateKSPAssemblyDependencyAttributes>true</GenerateKSPAssemblyDependencyAttributes>
14-
</PropertyGroup>
10+
<PropertyGroup>
11+
<BinariesOutputRelativePath>GameData\RocketSoundEnhancement\Plugins</BinariesOutputRelativePath>
12+
<GenerateKSPAssemblyAttribute>true</GenerateKSPAssemblyAttribute>
13+
<GenerateKSPAssemblyDependencyAttributes>true</GenerateKSPAssemblyDependencyAttributes>
14+
</PropertyGroup>
1515

16-
<ItemGroup>
17-
<ProjectReference Include="..\RocketSoundEnhancement.Unity\RocketSoundEnhancement.Unity.csproj">
18-
<Project>{5dff0176-7ba8-49f4-8155-f5d9b37d7d3d}</Project>
19-
<Name>RocketSoundEnhancement.Unity</Name>
20-
<Private>False</Private>
21-
</ProjectReference>
22-
</ItemGroup>
16+
<ItemGroup>
17+
<ProjectReference
18+
Include="..\RocketSoundEnhancement.Unity\RocketSoundEnhancement.Unity.csproj">
19+
<Project>{5dff0176-7ba8-49f4-8155-f5d9b37d7d3d}</Project>
20+
<Name>RocketSoundEnhancement.Unity</Name>
21+
<Private>False</Private>
22+
</ProjectReference>
23+
</ItemGroup>
2324

2425
<ItemGroup>
2526
<PackageReference Include="Krafs.Publicizer" Version="2.3.0">
26-
<PrivateAssets>all</PrivateAssets>
27-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
27+
<PrivateAssets>all</PrivateAssets>
28+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2829
</PackageReference>
2930
<PackageReference Include="KSPBuildTools" Version="0.0.4" />
31+
32+
<Reference Include="HarmonyKSP">
33+
<HintPath>$(KSPRoot)/GameData/000_Harmony/0Harmony.dll</HintPath>
34+
<Private>false</Private>
35+
<KSPAssembly>HarmonyKSP</KSPAssembly>
36+
<KSPAssemblyVersion>2.2.1</KSPAssemblyVersion>
37+
</Reference>
3038
</ItemGroup>
3139

32-
</Project>
40+
</Project>
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
1+
using HarmonyLib;
62
using UnityEngine;
73

84
namespace RocketSoundEnhancement
@@ -15,14 +11,17 @@ void Awake()
1511
AudioConfiguration audioConfig = AudioSettings.GetConfiguration();
1612
audioConfig.numRealVoices = Settings.VoiceCount;
1713

18-
if(AudioSettings.Reset(audioConfig)) {
14+
if (AudioSettings.Reset(audioConfig)) {
1915
Debug.Log("[RSE]: Audio Settings Applied");
2016
Debug.Log("[RSE]: DSP Buffer Size : " + AudioSettings.GetConfiguration().dspBufferSize);
2117
Debug.Log("[RSE]: Real Voices : " + AudioSettings.GetConfiguration().numRealVoices);
2218
Debug.Log("[RSE]: Virtual Voices : " + AudioSettings.GetConfiguration().numVirtualVoices);
2319
Debug.Log("[RSE]: Samplerate : " + AudioSettings.GetConfiguration().sampleRate);
2420
Debug.Log("[RSE]: Spearker Mode : " + AudioSettings.GetConfiguration().speakerMode);
2521
}
22+
23+
Harmony harmony = new Harmony("RocketSoundEnhancement");
24+
harmony.PatchAll(typeof(Startup).Assembly);
2625
}
2726
}
2827
}

0 commit comments

Comments
 (0)