using System;
using System.Linq;
using Unity.Collections;
using Unity.Profiling;
using Unity.Simulation;
using UnityEngine.Assertions;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
namespace UnityEngine.Perception.Sensors
{
///
/// RenderTextureReader reads a RenderTexture from the GPU each frame and passes the data back through a provided callback.
///
public class RenderTextureReader : IDisposable where T : struct
{
RenderTexture m_Source;
Action, RenderTexture> m_ImageReadCallback;
int m_NextFrameToCapture;
Texture2D m_CpuTexture;
Camera m_CameraRenderingToSource;
ProfilerMarker m_WaitingForCompletionMarker = new ProfilerMarker("RenderTextureReader_WaitingForCompletion");
ReadbackMode m_ReadbackMode;
public RenderTextureReader(RenderTexture source, Camera cameraRenderingToSource, Action, RenderTexture> imageReadCallback, ReadbackMode readbackMode = ReadbackMode.Async)
{
this.m_Source = source;
this.m_ImageReadCallback = imageReadCallback;
this.m_CameraRenderingToSource = cameraRenderingToSource;
m_NextFrameToCapture = Time.frameCount;
m_ReadbackMode = readbackMode;
if (!GraphicsUtilities.SupportsAsyncReadback())
m_ReadbackMode = ReadbackMode.Synchronous;
if (m_ReadbackMode == ReadbackMode.Synchronous)
m_CpuTexture = new Texture2D(m_Source.width, m_Source.height, m_Source.graphicsFormat, TextureCreationFlags.None);
RenderPipelineManager.endFrameRendering += OnEndFrameRendering;
}
void OnEndFrameRendering(ScriptableRenderContext context, Camera[] cameras)
{
#if UNITY_EDITOR
if (UnityEditor.EditorApplication.isPaused)
return;
#endif
if (!cameras.Contains(m_CameraRenderingToSource))
return;
if (m_NextFrameToCapture > Time.frameCount)
return;
m_NextFrameToCapture = Time.frameCount + 1;
switch (m_ReadbackMode)
{
case ReadbackMode.Synchronous:
{
RenderTexture.active = m_Source;
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();
m_ImageReadCallback(Time.frameCount, data, m_Source);
break;
}
case ReadbackMode.Async:
{
var commandBuffer = CommandBufferPool.Get("RenderTextureReader");
var frameCount = Time.frameCount;
commandBuffer.RequestAsyncReadback(m_Source, r => OnGpuReadback(r, frameCount));
context.ExecuteCommandBuffer(commandBuffer);
context.Submit();
CommandBufferPool.Release(commandBuffer);
break;
}
}
}
void OnGpuReadback(AsyncGPUReadbackRequest request, int frameCount)
{
if (request.hasError)
{
Debug.LogError("Error reading segmentation image from GPU");
}
else if (request.done && m_ImageReadCallback != null)
{
m_ImageReadCallback(frameCount, request.GetData(), m_Source);
}
}
public void WaitForAllImages()
{
AsyncGPUReadback.WaitAllRequests();
}
public void Dispose()
{
WaitForAllImages();
RenderPipelineManager.endFrameRendering -= OnEndFrameRendering;
if (m_CpuTexture != null)
{
Object.Destroy(m_CpuTexture);
m_CpuTexture = null;
}
}
}
}