using System;
using System.Linq;
using Unity.Collections;
using Unity.Simulation;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
namespace UnityEngine.Perception.GroundTruth
{
///
/// RenderTextureReader reads a RenderTexture from the GPU whenever Capture is called and passes the data back through a provided callback.
///
/// The type of the raw texture data to be provided.
class RenderTextureReader : IDisposable where T : struct
{
RenderTexture m_Source;
Texture2D m_CpuTexture;
///
/// Creates a new for the given , , and image readback callback
///
/// The to read from.
public RenderTextureReader(RenderTexture source)
{
m_Source = source;
}
public void Capture(ScriptableRenderContext context, Action, RenderTexture> imageReadCallback)
{
if (!GraphicsUtilities.SupportsAsyncReadback())
{
RenderTexture.active = m_Source;
if (m_CpuTexture == null || m_CpuTexture.width != m_Source.width || m_CpuTexture.height != m_Source.height)
{
if (m_CpuTexture != null)
m_CpuTexture.Resize(m_Source.width, m_Source.height);
m_CpuTexture = new Texture2D(m_Source.width, m_Source.height, m_Source.graphicsFormat, TextureCreationFlags.None);
}
m_CpuTexture.ReadPixels(new Rect(
Vector2.zero,
new Vector2(m_Source.width, m_Source.height)),
0, 0);
RenderTexture.active = null;
var data = m_CpuTexture.GetRawTextureData();
imageReadCallback(Time.frameCount, data, m_Source);
}
else
{
var commandBuffer = CommandBufferPool.Get("RenderTextureReader");
var frameCount = Time.frameCount;
commandBuffer.RequestAsyncReadback(m_Source, r => OnGpuReadback(r, frameCount, imageReadCallback));
context.ExecuteCommandBuffer(commandBuffer);
context.Submit();
CommandBufferPool.Release(commandBuffer);
}
}
void OnGpuReadback(AsyncGPUReadbackRequest request, int frameCount,
Action, RenderTexture> imageReadCallback)
{
if (request.hasError)
{
Debug.LogError("Error reading segmentation image from GPU");
}
else if (request.done && imageReadCallback != null)
{
imageReadCallback(frameCount, request.GetData(), m_Source);
}
}
///
/// Synchronously wait for all image requests to complete.
///
public void WaitForAllImages()
{
AsyncGPUReadback.WaitAllRequests();
}
///
/// Shut down the reader, waiting for all requests to return.
///
public void Dispose() => Dispose(true);
///
/// Shut down the reader, optionally waiting for all requests to return.
///
/// Whether this should block on waiting for asynchronous readbacks
public void Dispose(bool waitForAllImages)
{
WaitForAllImages();
if (m_CpuTexture != null)
{
Object.Destroy(m_CpuTexture);
m_CpuTexture = null;
}
}
}
}