Skip to content

Instantly share code, notes, and snippets.

@RamType0
Last active December 17, 2020 08:18
Show Gist options
  • Select an option

  • Save RamType0/3452cf68d8096e94536f95c1ca263a18 to your computer and use it in GitHub Desktop.

Select an option

Save RamType0/3452cf68d8096e94536f95c1ca263a18 to your computer and use it in GitHub Desktop.
ComputeBuffer.GetDataAsyncなどのメソッドを生やすAsyncGPUReadbackのUniTask向け拡張メソッド集。
using System;
using UnityEngine;
using Unity.Collections;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
namespace Cysharp.Threading.Tasks
{
public static class UniTaskAsyncGPUReadbackExtensions
{
#region AsyncGPUReadback.Request
public static UniTask<NativeArray<T>> GetDataAsync<T>(this ComputeBuffer src)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, callback);
return new UniTask<NativeArray<T>>(task, token);
}
public static unsafe UniTask<NativeArray<T>> GetDataAsync<T>(this ComputeBuffer src, int offset, int length)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, sizeof(T) * length, sizeof(T) * offset, callback);
return new UniTask<NativeArray<T>>(task, token);
}
#if UNITY_2019_4_OR_NEWER
public static UniTask<NativeArray<T>> GetDataAsync<T>(this GraphicsBuffer src)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, callback);
return new UniTask<NativeArray<T>>(task, token);
}
public static unsafe UniTask<NativeArray<T>> GetDataAsync<T>(this GraphicsBuffer src, int offset, int length)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, sizeof(T) * length, sizeof(T) * offset, callback);
return new UniTask<NativeArray<T>>(task, token);
}
#endif
public static UniTask<NativeArray<T>> GetDataAsync<T>(this Texture src, int mipIndex = 0)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, mipIndex, callback);
return new UniTask<NativeArray<T>>(task, token);
}
public static UniTask<NativeArray<T>> GetDataAsync<T>(this Texture src, int mipIndex, TextureFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, mipIndex, dstFormat, callback);
return new UniTask<NativeArray<T>>(task, token);
}
#if UNITY_2019_4_OR_NEWER
public static UniTask<NativeArray<T>> GetDataAsync<T>(this Texture src, int mipIndex, GraphicsFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, mipIndex, dstFormat, callback);
return new UniTask<NativeArray<T>>(task, token);
}
#endif
public static UniTask<NativeArray<T>> GetDataAsync<T>(this Texture src, int mipIndex, int x, int width, int y, int height, int z = 0)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, mipIndex, x, width, y, height, z, 1, callback);
return new UniTask<NativeArray<T>>(task, token);
}
public static UniTask<NativeArray<T>> GetDataAsync<T>(this Texture src, int mipIndex, int x, int width, int y, int height, int z, TextureFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, mipIndex, x, width, y, height, z, 1, dstFormat, callback);
return new UniTask<NativeArray<T>>(task, token);
}
#if UNITY_2019_4_OR_NEWER
public static UniTask<NativeArray<T>> GetDataAsync<T>(this Texture src, int mipIndex, int x, int width, int y, int height, int z, GraphicsFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackCompletionSource<T>.Create(out var token, out var callback);
AsyncGPUReadback.Request(src, mipIndex, x, width, y, height, z, 1, dstFormat, callback);
return new UniTask<NativeArray<T>>(task, token);
}
#endif
#endregion
internal sealed class AsyncGPUReadbackCompletionSource<T> : IUniTaskSource<NativeArray<T>>, ITaskPoolNode<AsyncGPUReadbackCompletionSource<T>>
where T : unmanaged
{
static TaskPool<AsyncGPUReadbackCompletionSource<T>> pool;
AsyncGPUReadbackCompletionSource<T> nextNode;
public ref AsyncGPUReadbackCompletionSource<T> NextNode => ref nextNode;
readonly Action<AsyncGPUReadbackRequest> onReadbackComplete;
UniTaskCompletionSourceCore<NativeArray<T>> core;
public AsyncGPUReadbackCompletionSource()
{
onReadbackComplete = OnReadbackComplete;
}
public static IUniTaskSource<NativeArray<T>> Create(out short token, out Action<AsyncGPUReadbackRequest> callback)
{
if (!pool.TryPop(out var result))
{
result = new AsyncGPUReadbackCompletionSource<T>();
}
TaskTracker.TrackActiveTask(result, 3);
token = result.core.Version;
callback = result.onReadbackComplete;
return result;
}
void OnReadbackComplete(AsyncGPUReadbackRequest readbackRequest)
{
if (readbackRequest.hasError)
{
core.TrySetException(new Exception("AsyncGPUReadbackRequest.hasError = true"));
}
else
{
core.TrySetResult(readbackRequest.GetData<T>());
}
}
public NativeArray<T> GetResult(short token)
{
try
{
return core.GetResult(token);
}
finally
{
TryReturn();
}
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
return pool.TryPush(this);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
}
#region AsyncGPUReadback.RequestIntoNativeArray
#if UNITY_2019_4_OR_NEWER
public static UniTask GetDataAsync<T>(this ComputeBuffer src, ref NativeArray<T> output)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeArray(ref output, src, callback);
return new UniTask(task, token);
}
public static unsafe UniTask GetDataAsync<T>(this ComputeBuffer src, ref NativeArray<T> output, int offset, int length)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeArray(ref output, src, sizeof(T) * length, sizeof(T) * offset, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this GraphicsBuffer src, ref NativeArray<T> output)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeArray(ref output, src, callback);
return new UniTask(task, token);
}
public static unsafe UniTask GetDataAsync<T>(this GraphicsBuffer src, ref NativeArray<T> output, int offset, int length)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeArray(ref output, src, sizeof(T) * length, sizeof(T) * offset, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeArray<T> output, int mipIndex = 0)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeArray(ref output, src, mipIndex, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeArray<T> output, int mipIndex, TextureFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeArray(ref output, src, mipIndex, dstFormat, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeArray<T> output, int mipIndex, GraphicsFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeArray(ref output, src, mipIndex, dstFormat, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeArray<T> output, int mipIndex, int x, int width, int y, int height, int z, int depth, TextureFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeArray(ref output, src, mipIndex, x, width, y, height, z, depth, dstFormat, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeArray<T> output, int mipIndex, int x, int width, int y, int height, int z, int depth, GraphicsFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeArray(ref output, src, mipIndex, x, width, y, height, z, depth, dstFormat, callback);
return new UniTask(task, token);
}
#endif
#endregion
#region AsyncGPUReadback.RequestIntoNativeSlice
#if UNITY_2020_2_OR_NEWER
public static UniTask GetDataAsync<T>(this ComputeBuffer src, ref NativeSlice<T> output)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeSlice(ref output, src, callback);
return new UniTask(task, token);
}
public static unsafe UniTask GetDataAsync<T>(this ComputeBuffer src, ref NativeSlice<T> output, int offset, int length)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeSlice(ref output, src, sizeof(T) * length, sizeof(T) * offset, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this GraphicsBuffer src, ref NativeSlice<T> output)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeSlice(ref output, src, callback);
return new UniTask(task, token);
}
public static unsafe UniTask GetDataAsync<T>(this GraphicsBuffer src, ref NativeSlice<T> output, int offset, int length)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeSlice(ref output, src, sizeof(T) * length, sizeof(T) * offset, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeSlice<T> output, int mipIndex = 0)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeSlice(ref output, src, mipIndex, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeSlice<T> output, int mipIndex, TextureFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeSlice(ref output, src, mipIndex, dstFormat, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeSlice<T> output, int mipIndex, GraphicsFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeSlice(ref output, src, mipIndex, dstFormat, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeSlice<T> output, int mipIndex, int x, int width, int y, int height, int z, int depth, TextureFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeSlice(ref output, src, mipIndex, x, width, y, height, z, depth, dstFormat, callback);
return new UniTask(task, token);
}
public static UniTask GetDataAsync<T>(this Texture src, ref NativeSlice<T> output, int mipIndex, int x, int width, int y, int height, int z, int depth, GraphicsFormat dstFormat)
where T : unmanaged
{
var task = AsyncGPUReadbackIntoNativeContainerCompletionSource.Create(out var token, out var callback);
AsyncGPUReadback.RequestIntoNativeSlice(ref output, src, mipIndex, x, width, y, height, z, depth, dstFormat, callback);
return new UniTask(task, token);
}
#endif
#endregion
#if UNITY_2019_4_OR_NEWER
internal sealed class AsyncGPUReadbackIntoNativeContainerCompletionSource : IUniTaskSource<AsyncUnit>, ITaskPoolNode<AsyncGPUReadbackIntoNativeContainerCompletionSource>
{
static TaskPool<AsyncGPUReadbackIntoNativeContainerCompletionSource> pool;
AsyncGPUReadbackIntoNativeContainerCompletionSource nextNode;
public ref AsyncGPUReadbackIntoNativeContainerCompletionSource NextNode => ref nextNode;
readonly Action<AsyncGPUReadbackRequest> onReadbackComplete;
UniTaskCompletionSourceCore<AsyncUnit> core;
public AsyncGPUReadbackIntoNativeContainerCompletionSource()
{
onReadbackComplete = OnReadbackComplete;
}
public static IUniTaskSource<AsyncUnit> Create(out short token, out Action<AsyncGPUReadbackRequest> callback)
{
if (!pool.TryPop(out var result))
{
result = new AsyncGPUReadbackIntoNativeContainerCompletionSource();
}
TaskTracker.TrackActiveTask(result, 3);
token = result.core.Version;
callback = result.onReadbackComplete;
return result;
}
void OnReadbackComplete(AsyncGPUReadbackRequest readbackRequest)
{
if (readbackRequest.hasError)
{
core.TrySetException(new Exception("AsyncGPUReadbackRequest.hasError = true"));
}
else
{
core.TrySetResult(default);
}
}
public AsyncUnit GetResult(short token)
{
try
{
return core.GetResult(token);
}
finally
{
TryReturn();
}
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
return pool.TryPush(this);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
}
#endif
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment