Merge pull request #496 from Cysharp/hadashiA/awaitable

Add EndOfFrame implementation using `UnityEngine.Awaitable`
master
hadashiA 2023-09-14 16:26:40 +09:00 committed by GitHub
commit acc71550c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 1 deletions

View File

@ -84,8 +84,13 @@ async UniTask<string> DemoAsync()
await UniTask.Yield(); await UniTask.Yield();
await UniTask.NextFrame(); await UniTask.NextFrame();
// replacement of WaitForEndOfFrame(requires MonoBehaviour(CoroutineRunner)) // replacement of WaitForEndOfFrame
#if UNITY_2023_1_OR_NEWER
await UniTask.WaitForEndOfFrame();
#else
// requires MonoBehaviour(CoroutineRunner))
await UniTask.WaitForEndOfFrame(this); // this is MonoBehaviour await UniTask.WaitForEndOfFrame(this); // this is MonoBehaviour
#endif
// replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate)) // replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))
await UniTask.WaitForFixedUpdate(); await UniTask.WaitForFixedUpdate();
@ -497,6 +502,8 @@ It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.
`PlayerLoopTiming.Update` is similar to `yield return null` in a coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar to `WaitForFixedUpdate`. `PlayerLoopTiming.Update` is similar to `yield return null` in a coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar to `WaitForFixedUpdate`.
> `PlayerLoopTiming.LastPostLateUpdate` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`Texture2D.ReadPixels`, `ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, pass MonoBehaviour(coroutine runnner) to `UniTask.WaitForEndOfFrame`. For example, `await UniTask.WaitForEndOfFrame(this);` is lightweight allocation free alternative of `yield return new WaitForEndOfFrame()`. > `PlayerLoopTiming.LastPostLateUpdate` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`Texture2D.ReadPixels`, `ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, pass MonoBehaviour(coroutine runnner) to `UniTask.WaitForEndOfFrame`. For example, `await UniTask.WaitForEndOfFrame(this);` is lightweight allocation free alternative of `yield return new WaitForEndOfFrame()`.
>
> Note: In Unity 2023.1 or newer, `await UniTask.WaitForEndOfFrame();` no longer requires MonoBehaviour. It uses `UnityEngine.Awaitable.EndOfFrameAsync`.
`yield return null` and `UniTask.Yield` are similar but different. `yield return null` always returns next frame but `UniTask.Yield` returns next called. That is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` guarantees return next frame, you can expect this to behave exactly the same as `yield return null`. `yield return null` and `UniTask.Yield` are similar but different. `yield return null` always returns next frame but `UniTask.Yield` returns next called. That is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` guarantees return next frame, you can expect this to behave exactly the same as `yield return null`.

View File

@ -75,6 +75,12 @@ namespace Cysharp.Threading.Tasks
return new UniTask(NextFramePromise.Create(timing, cancellationToken, out var token), token); return new UniTask(NextFramePromise.Create(timing, cancellationToken, out var token), token);
} }
#if UNITY_2023_1_OR_NEWER
public static async UniTask WaitForEndOfFrame(CancellationToken cancellationToken = default)
{
await Awaitable.EndOfFrameAsync(cancellationToken);
}
#else
[Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")] [Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
public static YieldAwaitable WaitForEndOfFrame() public static YieldAwaitable WaitForEndOfFrame()
{ {
@ -86,6 +92,7 @@ namespace Cysharp.Threading.Tasks
{ {
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken); return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken);
} }
#endif
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner, CancellationToken cancellationToken = default) public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner, CancellationToken cancellationToken = default)
{ {