using System; using System.Collections.Generic; using System.Diagnostics; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler; namespace UnityEngine.Rendering.RenderGraphModule { public partial class RenderGraph { // Convenience class that wraps execution id and name for display purposes internal class DebugExecutionItem { public EntityId id { get; } public string name { get; } public DebugExecutionItem(EntityId id, string name) { this.id = id; this.name = name; } } /// /// Debug data interface shared by HDRP RG Compiler and NRP RG Compiler. /// Some data is optional, depending on the value of isNRPCompiler. /// [Serializable] internal class DebugData { public DebugData(string executionName) { this.executionName = executionName; } public string executionName; // Set to true when data has been set public bool valid = false; // Compilation hash of the render graph that produced this DebugData. public int graphHash; // If true, the data was output by NRP compiler, in which case PassData.nrpInfo is available. public bool isNRPCompiler; [Serializable] public class ResourceLists { [SerializeField] private List m_Textures = new(); [SerializeField] private List m_Buffers = new(); [SerializeField] private List m_AccelerationStructures = new(); // Indexer to access the lists by index public List this[int index] { get { return index switch { (int)RenderGraphResourceType.Texture => m_Textures, (int)RenderGraphResourceType.Buffer => m_Buffers, (int)RenderGraphResourceType.AccelerationStructure => m_AccelerationStructures, _ => throw new ArgumentOutOfRangeException(nameof(index)) }; } set { switch (index) { case (int)RenderGraphResourceType.Texture: m_Textures = value ?? new List(); break; case (int)RenderGraphResourceType.Buffer: m_Buffers = value ?? new List(); break; case (int)RenderGraphResourceType.AccelerationStructure: m_AccelerationStructures = value ?? new List(); break; default: throw new ArgumentOutOfRangeException(nameof(index)); } } } public void Clear() { for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i) { if (this[i] == null) this[i] = new List(); else this[i].Clear(); } } } // Debug data for passes. public List passList = new List(); // Debug data for resources. [Serializable] public class ResourceDataLists : ResourceLists { } public ResourceDataLists resourceLists = new(); // NOTE: Cannot use NativePassAttachment for DebugData directly because readonly fields are not serialized. // This class duplicates the relevant contents. [Serializable] public class SerializableNativePassAttachment { public RenderBufferLoadAction loadAction; public RenderBufferStoreAction storeAction; public bool memoryless; public int mipLevel; public int depthSlice; public SerializableNativePassAttachment(NativePassAttachment att) { loadAction = att.loadAction; storeAction = att.storeAction; memoryless = att.memoryless; mipLevel = att.mipLevel; depthSlice = att.depthSlice; } } [Serializable] [DebuggerDisplay("PassDebug: {name}")] public struct PassData { // Render pass name. public string name; // Render graph pass type. public RenderGraphPassType type; [Serializable] public class ResourceIdLists : ResourceLists {} // List of ResourceHandle.index's for each resource type read by this pass. public ResourceIdLists resourceReadLists; // List of ResourceHandle.index's for each resource type written by this pass. public ResourceIdLists resourceWriteLists; // Whether the pass was culled. public bool culled; // Whether the pass is an async compute pass. public bool async; // Native subpass index. public int nativeSubPassIndex; // Index of the pass that needs to be waited for. public int syncToPassIndex; // Smaller pass index that waits for this pass. public int syncFromPassIndex; // We have this member instead of removing the pass altogether because we need the full list of passes in // order to be able to remap them correctly when we remove them from display in the viewer. public bool generateDebugData; [Serializable] public class NRPInfo { [Serializable] public class NativeRenderPassInfo { [Serializable] public class AttachmentInfo { public string resourceName; public string loadReason; public string storeReason; public string storeMsaaReason; public int attachmentIndex; public SerializableNativePassAttachment attachment; } [Serializable] public struct PassCompatibilityInfo { public string message; public bool isCompatible; } public string passBreakReasoning; public List attachmentInfos; public SerializedDictionary passCompatibility; public List mergedPassIds; } // If this pass is part of a Native Render Pass, this is available, null otherwise. [SerializeReference] public NativeRenderPassInfo nativePassInfo; // List of ResourceHandle.index's for each texture resource that is accessed using framebuffer fetch. public List textureFBFetchList = new(); // List of ResourceHandle.index's for each texture resource that this pass called PostSetGlobalTexture() for. public List setGlobals = new(); // Fragment info public int width; public int height; public int volumeDepth; public int samples; public bool hasDepth; } // Only available when isNRPCompiler = true, null otherwise. [SerializeReference] public NRPInfo nrpInfo; // File path and line number where the render pass is defined. public PassScriptInfo scriptInfo; } [Serializable] public class BufferResourceData { // Number of elements in buffer. public int count; // Size of one element in the buffer. public int stride; // Buffer usage type. public GraphicsBuffer.Target target; // Buffer usage flags. public GraphicsBuffer.UsageFlags usage; } [Serializable] public class TextureResourceData { // Texture width & height. public int width; public int height; // Texture depth (volume texture). public int depth; // Whether the texture is bound with multi sampling. public bool bindMS; // Number of texture MSAA samples. public int samples; // Render texture graphics format. public GraphicsFormat format; // Whether texture is cleared on first use. public bool clearBuffer; } [Serializable] [DebuggerDisplay("ResourceDebug: {name} [{creationPassIndex}:{releasePassIndex}]")] public struct ResourceData { // Resource name. public string name; // Whether the resource is imported outside of render graph. public bool imported; // Pass that creates the resource (for imported resources, the first pass that uses the resource). public int creationPassIndex; // Pass that releases the resource (for imported resources, the last pass that uses the resource). public int releasePassIndex; // List of passes that read the resource. public List consumerList; // List of passes that write the resource. public List producerList; // Whether the resource is memoryless (i.e resources that are created/destroyed within the same native render pass). // Available if isNRPCompiler = true. public bool memoryless; // Texture-specific resource data. [SerializeReference] public TextureResourceData textureData; // Buffer-specific resource data. [SerializeReference] public BufferResourceData bufferData; } public void Clear() { passList.Clear(); resourceLists.Clear(); valid = false; } // Pass script metadata. [Serializable] public struct PassScriptInfo { public string filePath; public int line; } } [Conditional("UNITY_EDITOR"), Conditional("DEVELOPMENT_BUILD")] void AddPassDebugMetadata(RenderGraphPass renderPass, string file, int line) { #if UNITY_EDITOR || DEVELOPMENT_BUILD // Does nothing unless debug session is active. if (!RenderGraphDebugSession.hasActiveDebugSession) return; renderPass.debugScriptInfo = new DebugData.PassScriptInfo { filePath = file, line = line }; #endif } } }