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; } } } }