mirror of https://github.com/Cysharp/UniTask
Add AsyncGPUReadbackRequest await support
parent
f0d2ee2beb
commit
1194c38568
|
@ -0,0 +1,139 @@
|
||||||
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks
|
||||||
|
{
|
||||||
|
public static partial class UnityAsyncExtensions
|
||||||
|
{
|
||||||
|
#region AsyncGPUReadbackRequest
|
||||||
|
|
||||||
|
public static UniTask<AsyncGPUReadbackRequest>.Awaiter GetAwaiter(this AsyncGPUReadbackRequest asyncOperation)
|
||||||
|
{
|
||||||
|
return ToUniTask(asyncOperation).GetAwaiter();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask<AsyncGPUReadbackRequest> WithCancellation(this AsyncGPUReadbackRequest asyncOperation, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
{
|
||||||
|
if (asyncOperation.done) return UniTask.FromResult(asyncOperation);
|
||||||
|
return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class AsyncGPUReadbackRequestAwaiterConfiguredSource : IUniTaskSource<AsyncGPUReadbackRequest>, IPlayerLoopItem, ITaskPoolNode<AsyncGPUReadbackRequestAwaiterConfiguredSource>
|
||||||
|
{
|
||||||
|
static TaskPool<AsyncGPUReadbackRequestAwaiterConfiguredSource> pool;
|
||||||
|
public AsyncGPUReadbackRequestAwaiterConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static AsyncGPUReadbackRequestAwaiterConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPool.RegisterSizeGetter(typeof(AsyncGPUReadbackRequestAwaiterConfiguredSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncGPUReadbackRequest asyncOperation;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
|
||||||
|
UniTaskCompletionSourceCore<AsyncGPUReadbackRequest> core;
|
||||||
|
|
||||||
|
AsyncGPUReadbackRequestAwaiterConfiguredSource()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return AutoResetUniTaskCompletionSource<AsyncGPUReadbackRequest>.CreateFromCanceled(cancellationToken, out token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AsyncGPUReadbackRequestAwaiterConfiguredSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.asyncOperation = asyncOperation;
|
||||||
|
result.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
|
token = result.core.Version;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncGPUReadbackRequest GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return core.GetResult(token);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUniTaskSource.GetResult(short token)
|
||||||
|
{
|
||||||
|
GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
return core.GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return core.UnsafeGetStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
core.OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
core.TrySetCanceled(cancellationToken);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asyncOperation.hasError)
|
||||||
|
{
|
||||||
|
core.TrySetException(new Exception("AsyncGPUReadbackRequest.hasError = true"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asyncOperation.done)
|
||||||
|
{
|
||||||
|
core.TrySetResult(asyncOperation);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryReturn()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
|
asyncOperation = default;
|
||||||
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 98f5fedb44749ab4688674d79126b46a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -15,6 +15,8 @@ using UnityEngine.LowLevel;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
|
||||||
// using DG.Tweening;
|
// using DG.Tweening;
|
||||||
|
@ -117,6 +119,8 @@ public class AsyncMessageBroker<T> : IDisposable
|
||||||
|
|
||||||
public class SandboxMain : MonoBehaviour
|
public class SandboxMain : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
public Camera camera;
|
||||||
|
|
||||||
public Button okButton;
|
public Button okButton;
|
||||||
public Button cancelButton;
|
public Button cancelButton;
|
||||||
|
|
||||||
|
@ -161,6 +165,9 @@ public class SandboxMain : MonoBehaviour
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//setHp = Hp.GetSetter();
|
//setHp = Hp.GetSetter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,10 +185,6 @@ public class SandboxMain : MonoBehaviour
|
||||||
public Button button;
|
public Button button;
|
||||||
|
|
||||||
|
|
||||||
void Start2()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -437,29 +440,37 @@ public class SandboxMain : MonoBehaviour
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async void Nanika()
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
Debug.Log("Here");
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
PlayerLoopInfo.Inject();
|
||||||
|
PrepareCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async UniTaskVoid Start()
|
async UniTaskVoid Start()
|
||||||
{
|
{
|
||||||
//_ = Foo(); // unhandled.
|
|
||||||
//Go();
|
|
||||||
var cts = new CancellationTokenSource();
|
|
||||||
|
|
||||||
okButton.onClick.AddListener(() =>
|
okButton.onClick.AddListener(() =>
|
||||||
{
|
{
|
||||||
cts.Cancel();
|
ShootAsync().Forget();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Nanika();
|
||||||
UnityEngine.Debug.Log("Start:" + PlayerLoopInfo.CurrentLoopType);
|
|
||||||
|
|
||||||
var token = UniTask.Delay(TimeSpan.FromSeconds(3), DelayType.Realtime).ToCancellationToken(cts.Token);
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
UnityEngine.Debug.Log("in loop");
|
|
||||||
await UniTask.Yield();
|
|
||||||
}
|
|
||||||
UnityEngine.Debug.Log("end");
|
|
||||||
|
|
||||||
|
|
||||||
|
await UniTask.Yield();
|
||||||
// this.GetCancellationTokenOnDestroy()
|
// this.GetCancellationTokenOnDestroy()
|
||||||
|
|
||||||
//PlayerLoopInfo.Inject();
|
//PlayerLoopInfo.Inject();
|
||||||
|
@ -974,6 +985,62 @@ public class SandboxMain : MonoBehaviour
|
||||||
// e.SetObserved();
|
// e.SetObserved();
|
||||||
// or other custom write code.
|
// or other custom write code.
|
||||||
UnityEngine.Debug.LogError("Unobserved:" + e.Exception.ToString());
|
UnityEngine.Debug.LogError("Unobserved:" + e.Exception.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GPU Screenshot Sample
|
||||||
|
|
||||||
|
void PrepareCamera()
|
||||||
|
{
|
||||||
|
Debug.Log("Support AsyncGPUReadback:" + SystemInfo.supportsAsyncGPUReadback);
|
||||||
|
|
||||||
|
var width = 480;
|
||||||
|
var height = 240;
|
||||||
|
var depth = 24;
|
||||||
|
|
||||||
|
camera.targetTexture = new RenderTexture(width, height, depth, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default)
|
||||||
|
{
|
||||||
|
antiAliasing = 8
|
||||||
|
};
|
||||||
|
camera.enabled = true;
|
||||||
|
|
||||||
|
//myRenderTexture = new RenderTexture(width, height, depth, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default)
|
||||||
|
//{
|
||||||
|
// antiAliasing = 8
|
||||||
|
//};
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderTexture myRenderTexture;
|
||||||
|
|
||||||
|
async UniTask ShootAsync()
|
||||||
|
{
|
||||||
|
var rt = camera.targetTexture;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var req = await AsyncGPUReadback.Request(rt, 0);
|
||||||
|
|
||||||
|
Debug.Log("GPU Readback done?:" + req.done);
|
||||||
|
|
||||||
|
var rawByteArray = req.GetData<byte>().ToArray();
|
||||||
|
var graphicsFormat = rt.graphicsFormat;
|
||||||
|
var width = (uint)rt.width;
|
||||||
|
var height = (uint)rt.height;
|
||||||
|
|
||||||
|
Debug.Log("BytesSize:" + rawByteArray.Length);
|
||||||
|
|
||||||
|
|
||||||
|
var imageBytes = ImageConversion.EncodeArrayToPNG(rawByteArray, graphicsFormat, width, height);
|
||||||
|
|
||||||
|
|
||||||
|
File.WriteAllBytes("my_screenshot.png", imageBytes); // test
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,80 @@ CanvasRenderer:
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 16537670}
|
m_GameObject: {fileID: 16537670}
|
||||||
m_CullTransparentMesh: 0
|
m_CullTransparentMesh: 0
|
||||||
|
--- !u!1 &518730348
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 518730350}
|
||||||
|
- component: {fileID: 518730349}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Camera
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!20 &518730349
|
||||||
|
Camera:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 518730348}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ClearFlags: 1
|
||||||
|
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||||
|
m_projectionMatrixMode: 1
|
||||||
|
m_GateFitMode: 2
|
||||||
|
m_FOVAxisMode: 0
|
||||||
|
m_SensorSize: {x: 36, y: 24}
|
||||||
|
m_LensShift: {x: 0, y: 0}
|
||||||
|
m_FocalLength: 50
|
||||||
|
m_NormalizedViewPortRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
near clip plane: 0.3
|
||||||
|
far clip plane: 1000
|
||||||
|
field of view: 60
|
||||||
|
orthographic: 0
|
||||||
|
orthographic size: 5
|
||||||
|
m_Depth: 0
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingPath: -1
|
||||||
|
m_TargetTexture: {fileID: 0}
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
m_TargetEye: 3
|
||||||
|
m_HDR: 1
|
||||||
|
m_AllowMSAA: 1
|
||||||
|
m_AllowDynamicResolution: 0
|
||||||
|
m_ForceIntoRT: 0
|
||||||
|
m_OcclusionCulling: 1
|
||||||
|
m_StereoConvergence: 10
|
||||||
|
m_StereoSeparation: 0.022
|
||||||
|
--- !u!4 &518730350
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 518730348}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 488, y: 418, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 1
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &519420028
|
--- !u!1 &519420028
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
@ -278,9 +352,11 @@ MonoBehaviour:
|
||||||
m_Script: {fileID: 11500000, guid: f0bc6c75abb2e0b47a25aa49bfd488ed, type: 3}
|
m_Script: {fileID: 11500000, guid: f0bc6c75abb2e0b47a25aa49bfd488ed, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
|
camera: {fileID: 518730349}
|
||||||
okButton: {fileID: 16537672}
|
okButton: {fileID: 16537672}
|
||||||
cancelButton: {fileID: 628393011}
|
cancelButton: {fileID: 628393011}
|
||||||
text: {fileID: 2101290655}
|
text: {fileID: 2101290655}
|
||||||
|
button: {fileID: 0}
|
||||||
--- !u!20 &519420031
|
--- !u!20 &519420031
|
||||||
Camera:
|
Camera:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
@ -597,7 +673,7 @@ Transform:
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 1
|
m_RootOrder: 2
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &1556045504
|
--- !u!1 &1556045504
|
||||||
GameObject:
|
GameObject:
|
||||||
|
@ -693,7 +769,7 @@ RectTransform:
|
||||||
- {fileID: 628393010}
|
- {fileID: 628393010}
|
||||||
- {fileID: 2101290654}
|
- {fileID: 2101290654}
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 2
|
m_RootOrder: 3
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 0, y: 0}
|
m_AnchorMax: {x: 0, y: 0}
|
||||||
|
|
Loading…
Reference in New Issue