mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-25 20:16:05 -05:00
Merge pull request #1311 from Santarh/awaitcaller
Implements asynchronous AwaitCaller at runtime.
This commit is contained in:
3
Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller.meta
Normal file
3
Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea8ee11da1da4f82b988a3108a362c2f
|
||||
timeCreated: 1634202988
|
||||
@@ -32,26 +32,4 @@ namespace VRMShaders
|
||||
/// <returns></returns>
|
||||
Task<T> Run<T>(Func<T> action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同期実行
|
||||
/// </summary>
|
||||
public sealed class ImmediateCaller : IAwaitCaller
|
||||
{
|
||||
public Task NextFrame()
|
||||
{
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task Run(Action action)
|
||||
{
|
||||
action();
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task<T> Run<T>(Func<T> action)
|
||||
{
|
||||
return Task.FromResult(action());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VRMShaders
|
||||
{
|
||||
/// <summary>
|
||||
/// 同期実行
|
||||
/// </summary>
|
||||
public sealed class ImmediateCaller : IAwaitCaller
|
||||
{
|
||||
public Task NextFrame()
|
||||
{
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task Run(Action action)
|
||||
{
|
||||
action();
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task<T> Run<T>(Func<T> action)
|
||||
{
|
||||
return Task.FromResult(action());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30f43d5b7d6b4184fb775a315b835365
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace VRMShaders
|
||||
{
|
||||
internal sealed class NextFrameTaskScheduler
|
||||
{
|
||||
public bool IsSupported => Application.isPlaying;
|
||||
|
||||
public NextFrameTaskScheduler()
|
||||
{
|
||||
if (!IsSupported)
|
||||
{
|
||||
throw new NotSupportedException($"{nameof(NextFrameTaskScheduler)} is supported at runtime only.");
|
||||
}
|
||||
}
|
||||
|
||||
public bool Enqueue(Action action)
|
||||
{
|
||||
var currentFrame = Time.frameCount;
|
||||
|
||||
UnityLoopTaskScheduler.Instance.Scheduler.Enqueue(action, () => Time.frameCount != currentFrame);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private sealed class UnityLoopTaskScheduler : MonoBehaviour
|
||||
{
|
||||
private static UnityLoopTaskScheduler _instance;
|
||||
|
||||
public static UnityLoopTaskScheduler Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
var go = new GameObject("UniGLTF UnityThreadScheduler");
|
||||
Object.DontDestroyOnLoad(go);
|
||||
_instance = go.AddComponent<UnityLoopTaskScheduler>();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public TinyManagedTaskScheduler Scheduler { get; } = new TinyManagedTaskScheduler();
|
||||
|
||||
private void Update()
|
||||
{
|
||||
Scheduler.ManagedUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ce7defdc7144878a058274ae561d0be
|
||||
timeCreated: 1634203513
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VRMShaders
|
||||
{
|
||||
/// <summary>
|
||||
/// Runtime (Build 後と、Editor Playing) での非同期ロードを実現する AwaitCaller.
|
||||
/// NOTE: 簡便に実装されたものなので、最適化の余地はある.
|
||||
/// </summary>
|
||||
public sealed class RuntimeOnlyAwaitCaller : IAwaitCaller
|
||||
{
|
||||
private readonly NextFrameTaskScheduler _scheduler;
|
||||
|
||||
public RuntimeOnlyAwaitCaller()
|
||||
{
|
||||
_scheduler = new NextFrameTaskScheduler();
|
||||
}
|
||||
|
||||
public Task NextFrame()
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
_scheduler.Enqueue(() => tcs.SetResult(default));
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
public Task Run(Action action)
|
||||
{
|
||||
return Task.Run(action);
|
||||
}
|
||||
|
||||
public Task<T> Run<T>(Func<T> action)
|
||||
{
|
||||
return Task.Run(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4e64b1835ca4cd2b682a6bda572b8fb
|
||||
timeCreated: 1634203216
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace VRMShaders
|
||||
{
|
||||
internal sealed class TinyManagedTaskScheduler
|
||||
{
|
||||
private readonly ConcurrentQueue<(Action, Func<bool>)> _continuationQueue =
|
||||
new ConcurrentQueue<(Action, Func<bool>)>();
|
||||
private readonly ConcurrentQueue<(Action, Func<bool>)> _temporaryQueue =
|
||||
new ConcurrentQueue<(Action, Func<bool>)>();
|
||||
|
||||
public void ManagedUpdate()
|
||||
{
|
||||
while (_continuationQueue.TryDequeue(out var tuple))
|
||||
{
|
||||
var (continuation, canExecute) = tuple;
|
||||
|
||||
if (canExecute())
|
||||
{
|
||||
continuation();
|
||||
}
|
||||
else
|
||||
{
|
||||
_temporaryQueue.Enqueue(tuple);
|
||||
}
|
||||
}
|
||||
|
||||
while (_temporaryQueue.TryDequeue(out var tuple))
|
||||
{
|
||||
_continuationQueue.Enqueue(tuple);
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(Action continuation, Func<bool> canExecute)
|
||||
{
|
||||
_continuationQueue.Enqueue((continuation, canExecute));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c52ff07a0834bdc8f4c8d6c7f9a634f
|
||||
timeCreated: 1634203919
|
||||
Reference in New Issue
Block a user