可能的性能优化

This commit is contained in:
2026-03-20 18:48:11 +08:00
parent 41e38311f0
commit 27d57a28a9
7 changed files with 90 additions and 67 deletions
@@ -62,19 +62,12 @@ namespace OCES.Audio
{
ContainerPlayHandle outgoing = this.m_fader.CurrentHandle;
float outgoingVolume = this.m_fader.CurrentVolume;
float fadeOutOffSet = transition?.FadeOutOffset ?? 0f;
float fadeOutTime = transition?.FadeOutTime ?? 0f;
float fadeInOffSet = transition?.FadeInOffset ?? 0f;
float fadeInTime = transition?.FadeInTime ?? 0f;
// ContainerPlayHandle outgoingHandle = this.m_currentHandle;
// float outgoingVolume = this.m_currentVolume;
this.m_coroutineHost.StartCoroutine(
this.m_fader.FadeOutBranch(outgoing, outgoingVolume,fadeOutOffSet, fadeOutTime));
this.m_fader.FadeOutBranch(outgoing, outgoingVolume, transition));
yield return this.m_coroutineHost.StartCoroutine(
this.m_fader.FadeInBranch(newContainerId, fadeInOffSet, fadeInTime));
this.m_fader.FadeInBranch(newContainerId, transition));
}
// ─────────────────────────────────────────────
@@ -18,11 +18,15 @@ namespace OCES.Audio
readonly Dictionary<uint, int> m_clipConcurrentCount = new();
readonly List<ActiveSound> m_activeSounds = new();
// 复用列表,避免 TryPlay 每帧分配临时 List(原 LINQ .Where().ToList()
readonly List<ActiveSound> m_tempSameObject = new();
readonly List<ActiveSound> m_tempSameGroup = new();
readonly List<ActiveSound> m_tempLowerPriority = new();
AudioGroupConfig m_groupConfig;
AudioMixerGroup m_sfxGroup;
AudioMixerGroup m_musicGroup;
AudioMixerGroup m_voiceGroup;
AudioMixerGroup m_ambienceGroup;
AudioSourcePool m_pool;
AudioContainerSelector m_containerSelector;
PitchStepManager m_pitchStepManager;
@@ -60,8 +64,6 @@ namespace OCES.Audio
AudioMixerGroup[] sfx = Find("Master/SFX");
if (sfx.Length > 0) this.m_sfxGroup = sfx[0];
AudioMixerGroup[] ambience = Find("Master/SFX/Ambience");
if (ambience.Length > 0) this.m_ambienceGroup = ambience[0];
AudioMixerGroup[] voice = Find("Master/Voice");
if (voice.Length > 0) this.m_voiceGroup = voice[0];
return;
@@ -87,15 +89,20 @@ namespace OCES.Audio
// 第二层:单 AudioObject/Clip 并发控制
if (audioObject.ThrottleCount != 0)
{ // TODO 这里和下面的组控制,每次都会分配新List,可以考虑做成成员变量,每次用完clear
// TODO Linq表达式好用但是GC性能差。如果性能有问题可以考虑换成普通表达
List<ActiveSound> sameObject = this.m_activeSounds
.Where(a => a.AudioObject.Id == audioObject.Id)
.ToList();
{
this.m_tempSameObject.Clear();
foreach (ActiveSound activeSound in this.m_activeSounds)
{
if (activeSound.AudioObject.Id == audioObject.Id)
{
this.m_tempSameObject.Add(activeSound);
}
}
if (sameObject.Count >= audioObject.ThrottleCount &&
!TryKill(sameObject, audioObject.KillMode, $"[Object] {audioObject.Name[0]}"))
if (this.m_tempSameObject.Count >= audioObject.ThrottleCount &&
!TryKill(this.m_tempSameObject, audioObject.KillMode, $"[Object] {audioObject.Name[0]}"))
return;
}
// 第三层:Group 并发控制
@@ -105,18 +112,28 @@ namespace OCES.Audio
groupConfig = this.m_groupConfig.QueryById(1);
Debug.Log($"未找到{audioObject.Id}对应的组文件,已使用默认配置组1。");
}
List<ActiveSound> sameGroup = this.m_activeSounds
.Where(a => a.AudioObject.Group == audioObject.Group)
.ToList();
if (sameGroup.Count >= groupConfig.GroupThrottleCount)
this.m_tempSameGroup.Clear();
foreach (ActiveSound activeSound in this.m_activeSounds)
{
List<ActiveSound> lowerPriority = sameGroup
.Where(a => a.AudioObject.Priority > audioObject.Priority)
.ToList();
if (activeSound.AudioObject.Group == audioObject.Group)
{
this.m_tempSameGroup.Add(activeSound);
}
}
List<ActiveSound> killCandidates = lowerPriority.Count > 0 ? lowerPriority : sameGroup;
KillMode killMode = lowerPriority.Count > 0 ? groupConfig.KillMode : audioObject.KillMode;
if (this.m_tempSameGroup.Count >= groupConfig.GroupThrottleCount)
{
this.m_tempLowerPriority.Clear();
foreach (ActiveSound activeSound in this.m_tempSameGroup)
{
if (activeSound.AudioObject.Priority > audioObject.Priority)
{
this.m_tempLowerPriority.Add(activeSound);
}
}
List<ActiveSound> killCandidates = this.m_tempLowerPriority.Count > 0 ? this.m_tempLowerPriority : this.m_tempSameGroup;
KillMode killMode = this.m_tempLowerPriority.Count > 0 ? groupConfig.KillMode : audioObject.KillMode;
if (!TryKill(killCandidates, killMode, $"[Group] {audioObject.Name[0]}"))
return;
@@ -125,11 +142,16 @@ namespace OCES.Audio
// 第四层:全局并发控制
if (this.m_activeSounds.Count >= k_maxGlobalConcurrent)
{
List<ActiveSound> lowerPriority = this.m_activeSounds
.Where(a => a.AudioObject.Priority > audioObject.Priority)
.ToList();
this.m_tempLowerPriority.Clear();
foreach (ActiveSound activeSound in this.m_activeSounds)
{
if (activeSound.AudioObject.Priority > audioObject.Priority)
{
this.m_tempLowerPriority.Add(activeSound);
}
}
if (lowerPriority.Count == 0 || !TryKill(lowerPriority, KillMode.Oldest, "[Global]"))
if (this.m_tempLowerPriority.Count == 0 || !TryKill(this.m_tempLowerPriority, KillMode.Oldest, "[Global]"))
return;
}
@@ -46,19 +46,19 @@ namespace OCES.Audio
/// <summary>
/// 淡出分支:fire-and-forget,由调用方 StartCoroutine
/// </summary>
internal IEnumerator FadeOutBranch(ContainerPlayHandle outgoingHandle, float outgoingVolume, float fadeOutOffset, float fadeOutTime)
internal IEnumerator FadeOutBranch(ContainerPlayHandle outgoingHandle, float outgoingVolume, ITransitionConfig transition)
{
if (outgoingHandle == null) yield break;
if (fadeOutOffset > 0f)
if (transition?.FadeOutOffset > 0f)
{
Debug.Log($"Waiting for {fadeOutOffset} to fade out.");
yield return new WaitForSeconds(fadeOutOffset);
Debug.Log($"Waiting for {transition.FadeOutOffset} to fade out.");
yield return new WaitForSeconds(transition.FadeOutOffset);
}
if (fadeOutTime > 0f )
if (transition?.FadeOutTime > 0f )
yield return this.m_coroutineHost.StartCoroutine(
FadeOut(outgoingHandle, outgoingVolume, fadeOutTime));
FadeOut(outgoingHandle, outgoingVolume, transition.FadeOutTime));
else
StopHandle(outgoingHandle);
}
@@ -67,12 +67,12 @@ namespace OCES.Audio
/// 淡入分支:等待 FadeInOffset 后启动新音乐并淡入。
/// 主协程 yield return 此分支,以便 DoTransition 在新音乐就绪后才结束。
/// </summary>
internal IEnumerator FadeInBranch(uint newContainerId, float fadeInOffset, float fadeInTime, Action onContainerStarted = null)
internal IEnumerator FadeInBranch(uint newContainerId, ITransitionConfig transition, Action onContainerStarted = null)
{
if (fadeInOffset > 0f)
if (transition?.FadeOutOffset > 0f)
{
Debug.Log($"Waiting {fadeInOffset} to fade in.");
yield return new WaitForSeconds(fadeInOffset);
Debug.Log($"Waiting {transition.FadeInOffset} to fade in.");
yield return new WaitForSeconds(transition.FadeInOffset);
}
if (newContainerId == 0)
@@ -82,13 +82,13 @@ namespace OCES.Audio
yield break;
}
float startVolume = fadeInTime > 0f ? 0f : 1f;
float startVolume = transition?.FadeOutOffset > 0f ? 0f : 1f;
StartNew(newContainerId, startVolume);
if (fadeInTime > 0f )
if (transition?.FadeOutOffset > 0f)
{
yield return this.m_coroutineHost.StartCoroutine(
FadeIn(CurrentHandle, fadeInTime));
FadeIn(CurrentHandle, transition.FadeInTime));
}
}
@@ -62,4 +62,31 @@ namespace OCES.Audio
void DeSerialize(BinaryReader reader);
void Serialize(BinaryWriter writer);
}
// ─────────────────────────────────────────────
// 辅助接口,让泛型方法同时处理 MusicPath 和 AmbiencePath
// ─────────────────────────────────────────────
public interface IPathEntry
{
uint Id { get; }
string Path { get; }
uint ContainerId { get; }
int Priority { get; }
}
public interface ITransitionConfig
{
float FadeOutOffset { get; }
float FadeOutTime { get; }
float FadeInOffset { get; }
float FadeInTime { get; }
}
public partial class MusicTransition : ITransitionConfig { }
public partial class AmbienceTransition : ITransitionConfig { }
public partial class MusicPath : IPathEntry { }
public partial class AmbiencePath : IPathEntry { }
}
@@ -89,16 +89,12 @@ namespace OCES.Audio
// ── 2 & 3. 淡出与淡入并行:两条分支从同一时刻起算各自的 Offset,互不等待 ──
ContainerPlayHandle outgoing = this.m_fader.CurrentHandle;
float outVol = this.m_fader.CurrentVolume;
float fadeOutOffset = transition?.FadeOutOffset ?? 0f;
float fadeOutTime = transition?.FadeOutTime ?? 0f;
float fadeInOffset = transition?.FadeInOffset ?? 0f;
float fadeInTime = transition?.FadeInTime ?? 0f;
this.m_coroutineHost.StartCoroutine(
this.m_fader.FadeOutBranch(outgoing, outVol, fadeOutOffset, fadeOutTime));
this.m_fader.FadeOutBranch(outgoing, outVol, transition));
yield return this.m_coroutineHost.StartCoroutine(
this.m_fader.FadeInBranch(newContainerId, fadeInOffset, fadeInTime,
this.m_fader.FadeInBranch(newContainerId, transition,
onContainerStarted: () =>
{
// Music 独有:记录新 container 和播放起始时间
@@ -136,19 +136,4 @@ namespace OCES.Audio
return -1;
}
}
// ─────────────────────────────────────────────
// 辅助接口,让泛型方法同时处理 MusicPath 和 AmbiencePath
// ─────────────────────────────────────────────
public interface IPathEntry
{
uint Id { get; }
string Path { get; }
uint ContainerId { get; }
int Priority { get; }
}
public partial class MusicPath : IPathEntry { }
public partial class AmbiencePath : IPathEntry { }
}