Add new pseudo method NextFrameIfTimedOut to RuntimeOnlyAwaitCaller

This change adds (pseudo) method RuntimeOnlyAwaitCaller.NextFrameIfTimedOut()
which invokes NextFrame() if given time is elapsed.  Otherwise, it does nothing.

We'll be able to utilize this (pseudo) method to ease possible cause of spikes.

For example:

----
public class VRMImporterContext : ImporterContext {
  protected override async Task OnLoadHierarchy(IAwaitCaller awaitCaller, ...) {
    ...
    var blendShapeList = VRM.blendShapeMaster.blendShapeGroups;
    if (blendShapeList != null && blendShapeList.Count > 0) {
      foreach (var x in blendShapeList) {
        await awaitCaller.NextFrameIfTimeout();
        BlendShapeAvatar.Clips.Add(await LoadBlendShapeBind(awaitCaller, x, transformMeshTable));
      }
    }
    ...
  }
}
----

Note that this change doesn't add NextFrameIfTimeout() to IAwaitCaller to avoid
breaking change.  This limitation introduces extra (maybe unnecessarily) complexity.
This commit is contained in:
Takayuki Matsuoka
2022-09-07 17:51:10 +09:00
parent 6b41e34071
commit 935afcb80d

View File

@@ -32,5 +32,51 @@ namespace VRMShaders
{
return Task.Run(action);
}
/// <summary>
/// 指定した時間が経過している場合のみ、NextFrame() を使って1フレーム待つ
/// </summary>
/// <param name="timeOutInMilliseconds">タイムアウト時間(ミリ秒単位)</param>
/// <returns>タイムアウト時はNextFrame()を呼び出す。そうではない場合、Task.CompletedTaskを返す</returns>
public Task NextFrameIfTimedOut_(float timeOutInMilliseconds = 1f)
{
if (!CheckTimeOut(timeOutInMilliseconds))
{
return Task.CompletedTask;
}
_lastBaseTime = 0f;
return NextFrame();
}
private bool CheckTimeOut(float timeOutInMilliseconds)
{
float t = UnityEngine.Time.realtimeSinceStartup;
if (_lastBaseTime == 0f)
{
// Reset base time
_lastBaseTime = t;
}
return (t - _lastBaseTime) >= timeOutInMilliseconds * (1f / 1000f);
}
private float _lastBaseTime;
}
}
internal static class RuntimeOnlyAwaitCallerHelper
{
/// <summary>
/// 指定した時間が経過している場合のみ、NextFrame() を使って1フレーム待つ
/// </summary>
/// <param name="iAwaitCaller">IAwaitCallerのインスタンス</param>
/// <param name="timeOutInMilliseconds">タイムアウト時間(ミリ秒単位)</param>
/// <returns>タイムアウト時はNextFrame()を呼び出す。そうではない場合、Task.CompletedTaskを返す</returns>
internal static Task NextFrameIfTimedOut(this IAwaitCaller iAwaitCaller, float timeOutInMilliseconds)
{
if (iAwaitCaller is RuntimeOnlyAwaitCaller runtimeOnlyAwaitCaller)
{
return runtimeOnlyAwaitCaller.NextFrameIfTimedOut_(timeOutInMilliseconds);
}
return Task.CompletedTask;
}
}
}