#if false
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Scripting.APIUpdating;
// Typedef for the in-engine RendererList API (to avoid conflicts with the experimental version)
using CoreRendererListDesc = UnityEngine.Rendering.RendererUtils.RendererListDesc;
namespace UnityEngine.Rendering.RenderGraphModule
{
///
/// Sets the read and write access for the depth buffer.
///
[Flags][MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public enum DepthAccess
{
///Read Access.
Read = 1 << 0,
///Write Access.
Write = 1 << 1,
///Read and Write Access.
ReadWrite = Read | Write,
}
///
/// Express the operations the rendergraph pass will do on a resource.
///
[Flags][MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public enum AccessFlags
{
///The pass does not access the resource at all. Calling Use* functions with none has no effect.
None = 0,
///This pass will read data the resource. Data in the resource should never be written unless one of the write flags is also present. Writing to a read-only resource may lead to undefined results, significant performance penaties, and GPU crashes.
Read = 1 << 0,
///This pass will at least write some data to the resource. Data in the resource should never be read unless one of the read flags is also present. Reading from a write-only resource may lead to undefined results, significant performance penaties, and GPU crashes.
Write = 1 << 1,
///Previous data in the resource is not preserved. The resource will contain undefined data at the beginning of the pass.
Discard = 1 << 2,
///All data in the resource will be written by this pass. Data in the resource should never be read.
WriteAll = Write | Discard,
/// Shortcut for Read | Write
ReadWrite = Read | Write
}
///
/// Expresses additional pass properties that can be used to perform optimizations on some platforms.
///
[Flags]
public enum ExtendedFeatureFlags
{
///Default state with no extended features enabled.
None = 0,
///On Meta XR, this flag can be set for the pass that performs the most 3D rendering to achieve better performance.
TileProperties = 1 << 0,
///On XR, this flag can be set for passes that are compatible with Multiview Render Regions
MultiviewRenderRegionsCompatible = 1 << 1,
///On Meta XR, this flag can be set to use MSAA shader resolve in the last subpass of a render pass.
MultisampledShaderResolve = 1 << 2,
}
[Flags]
internal enum RenderGraphState
{
///
/// Render Graph is not doing anything.
///
Idle = 0,
///
/// Render Graph is recording the graph.
///
RecordingGraph = 1 << 0,
///
/// Render Graph is recording a low level pass.
///
RecordingPass = 1 << 1,
///
/// Render Graph is executing the graph.
///
Executing = 1 << 2,
///
/// Utility flag to check if the graph is active.
///
Active = RecordingGraph | RecordingPass | Executing
}
///
/// The strategy that the render pipeline should use to determine the UV origin of RenderTextures who have an Unknown TextureUVOrigin when rendering.
///
public enum RenderTextureUVOriginStrategy
{
/// RenderTextures are always treated as bottom left orientation.
BottomLeft,
/// RenderTextures may inherit the backbuffer attachment orientation if they are only used via attachment reads.
PropagateAttachmentOrientation
}
///
/// An object representing the internal context of a rendergraph pass execution.
/// This object is public for technical reasons only and should not be used.
///
[MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public class InternalRenderGraphContext
{
internal ScriptableRenderContext renderContext;
internal CommandBuffer cmd;
internal RenderGraphObjectPool renderGraphPool;
internal RenderGraphDefaultResources defaultResources;
internal RenderGraphPass executingPass;
internal NativeRenderPassCompiler.CompilerContextData compilerContext;
internal bool contextlessTesting;
internal bool forceResourceCreation;
}
// InternalRenderGraphContext is public (but all members are internal)
// only because the C# standard says that all interface member function implementations must be public.
// So below in for example the RasterGraphContext we can't implement the (internal) interface as
// internal void FromInternalContext(InternalRenderGraphContext context) { ... }
// So we have to make FromInternalContext public so InternalRenderGraphContext also becomes public.
// This seems an oversight in c# where Interfaces used as Generic constraints could very well be useful
// with internal only functions.
///
/// Interface implemented by the different render graph contexts provided at execution timeline (via SetRenderFunc())
///
internal interface IDerivedRendergraphContext
{
///
/// This function is only public for techical resons of the c# language and should not be called outside the package.
///
/// The context to convert
public void FromInternalContext(InternalRenderGraphContext context);
///
/// Retrieves the TextureUVOrigin of the Render Graph texture from its handle.
///
///
/// This function can only be called when using the Native Render Pass Compiler (enabled by default).
///
/// The texture handle to query.
/// The TextureUVOrigin of the texture.
public TextureUVOrigin GetTextureUVOrigin(in TextureHandle textureHandle);
}
///
/// This class declares the context object passed to the execute function of a raster render pass.
///
///
[MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public struct RasterGraphContext : IDerivedRendergraphContext
{
private InternalRenderGraphContext wrappedContext;
///Command Buffer used for rendering.
public RasterCommandBuffer cmd;
///Render Graph default resources.
public RenderGraphDefaultResources defaultResources { get => wrappedContext.defaultResources; }
///Render Graph pool used for temporary data.
public RenderGraphObjectPool renderGraphPool { get => wrappedContext.renderGraphPool; }
static internal RasterCommandBuffer rastercmd = new RasterCommandBuffer(null, null, false);
///
public void FromInternalContext(InternalRenderGraphContext context)
{
wrappedContext = context;
rastercmd.m_WrappedCommandBuffer = wrappedContext.cmd;
rastercmd.m_ExecutingPass = context.executingPass;
cmd = rastercmd;
}
///
public readonly TextureUVOrigin GetTextureUVOrigin(in TextureHandle textureHandle)
{
if (!SystemInfo.graphicsUVStartsAtTop)
return TextureUVOrigin.BottomLeft;
if (wrappedContext.compilerContext != null)
{
return wrappedContext.compilerContext.GetTextureUVOrigin(textureHandle);
}
return TextureUVOrigin.BottomLeft;
}
}
///
/// This class declares the context object passed to the execute function of a compute render pass.
///
///
[MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public class ComputeGraphContext : IDerivedRendergraphContext
{
private InternalRenderGraphContext wrappedContext;
///Command Buffer used for rendering.
public ComputeCommandBuffer cmd;
///Render Graph default resources.
public RenderGraphDefaultResources defaultResources { get => wrappedContext.defaultResources; }
///Render Graph pool used for temporary data.
public RenderGraphObjectPool renderGraphPool { get => wrappedContext.renderGraphPool; }
static internal ComputeCommandBuffer computecmd = new ComputeCommandBuffer(null, null, false);
///
public void FromInternalContext(InternalRenderGraphContext context)
{
wrappedContext = context;
computecmd.m_WrappedCommandBuffer = wrappedContext.cmd;
computecmd.m_ExecutingPass = context.executingPass;
cmd = computecmd;
}
///
public TextureUVOrigin GetTextureUVOrigin(in TextureHandle textureHandle)
{
if (!SystemInfo.graphicsUVStartsAtTop)
return TextureUVOrigin.BottomLeft;
if (wrappedContext.compilerContext != null)
{
return wrappedContext.compilerContext.GetTextureUVOrigin(textureHandle);
}
return TextureUVOrigin.BottomLeft;
}
}
///
/// This class declares the context object passed to the execute function of an unsafe render pass.
///
///
[MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public class UnsafeGraphContext : IDerivedRendergraphContext
{
private InternalRenderGraphContext wrappedContext;
///Unsafe Command Buffer used for rendering.
public UnsafeCommandBuffer cmd;
///Render Graph default resources.
public RenderGraphDefaultResources defaultResources { get => wrappedContext.defaultResources; }
///Render Graph pool used for temporary data.
public RenderGraphObjectPool renderGraphPool { get => wrappedContext.renderGraphPool; }
internal static UnsafeCommandBuffer unsCmd = new UnsafeCommandBuffer(null, null, false);
///
public void FromInternalContext(InternalRenderGraphContext context)
{
wrappedContext = context;
unsCmd.m_WrappedCommandBuffer = wrappedContext.cmd;
unsCmd.m_ExecutingPass = context.executingPass;
cmd = unsCmd;
}
///
public TextureUVOrigin GetTextureUVOrigin(in TextureHandle textureHandle)
{
if (!SystemInfo.graphicsUVStartsAtTop)
return TextureUVOrigin.BottomLeft;
if (wrappedContext.compilerContext != null)
{
return wrappedContext.compilerContext.GetTextureUVOrigin(textureHandle);
}
return TextureUVOrigin.BottomLeft;
}
}
///
/// This struct contains properties which control the execution of the Render Graph.
///
[MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public struct RenderGraphParameters
{
///Identifier for this render graph execution.
[Obsolete("Not used anymore. The debugging tools use the name of the object identified by executionId. #from(6000.3)")]
public string executionName;
///Identifier for this render graph execution (i.e. EntityId of the Camera rendering). Used for debugging tools.
public EntityId executionId;
///Whether the execution should generate debug data and be visible in Render Graph Viewer.
public bool generateDebugData;
///Index of the current frame being rendered.
public int currentFrameIndex;
/// Controls whether to enable Renderer List culling or not.
[Obsolete("Not supported anymore. Syncing with culling system brings performance regressions in most cases. #from(6000.5)")]
public bool rendererListCulling;
///Scriptable Render Context used by the render pipeline.
public ScriptableRenderContext scriptableRenderContext;
///Command Buffer used to execute graphic commands.
public CommandBuffer commandBuffer;
///When running tests indicate the context is intentionally invalid and all calls on it should just do nothing.
///This allows you to run tests that rely on code execution the way to the pass render functions
///This also changes some behaviours with exception handling and error logging so the test framework can act on exceptions to validate behaviour better.
internal bool invalidContextForTesting;
///The strategy that the rendergraph should use to determine the texture uv origin if Unknown of RenderTextures when rendering.
public RenderTextureUVOriginStrategy renderTextureUVOriginStrategy;
}
///
/// The Render Pass rendering delegate to use with typed contexts.
///
/// The type of the class used to provide data to the Render Pass.
/// The type of the context that will be passed to the render function.
/// Render Pass specific data.
/// Global Render Graph context.
[MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public delegate void BaseRenderFunc(PassData data, ContextType renderGraphContext) where PassData : class, new();
///
/// This class is the main entry point of the Render Graph system.
///
[MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public partial class RenderGraph
{
///Maximum number of MRTs supported by Render Graph.
public static readonly int kMaxMRTCount = 8;
///
/// Enable the use of the render pass API instead of the traditional SetRenderTarget workflow for AddRasterRenderPass() API. Enabled by default since 6000.3. No alternative since 6000.5.
///
///
/// When enabled, the render graph try to use render passes and supasses instead of relying on SetRendertarget. It
/// will try to aggressively optimize the number of BeginRenderPass+EndRenderPass calls as well as calls to NextSubPass.
/// This with the aim to maximize the time spent "on chip" on tile based renderers.
///
/// The Graph will automatically determine when to break render passes as well as the load and store actions to apply to these render passes.
/// To do this, the graph will analyze the use of textures. E.g. when a texture is used twice in a row as a active render target, the two
/// render graph passes will be merged in a single render pass with two surpasses. On the other hand if a render target is sampled as a texture in
/// a later pass this render target will be stored (and possibly resolved) and the render pass will be broken up.
///
/// When setting this setting to true some existing render graph API is no longer valid as it can't express detailed frame information needed to emit
/// native render pases. In particular:
/// - The ImportBackbuffer overload without a RenderTargetInfo argument.
/// - Any AddRenderPass overloads. The more specific AddRasterRenderPass/AddComputePass/AddUnsafePass functions should be used to register passes.
///
/// In addition to this, additional validation will be done on the correctness of arguments of existing API that was not previously done. This could lead
/// to new errors when using existing render graph code with nativeRenderPassesEnabled.
///
/// Note: that CommandBuffer.BeginRenderPass/EndRenderPass calls are different by design from SetRenderTarget so this could also have
/// effects outside of render graph (e.g. for code relying on the currently active render target as this will not be updated when using render passes).
///
[Obsolete("RenderGraph always enables native render pass support. #from(6000.5)")]
public bool nativeRenderPassesEnabled { get; set; } = true;
internal/*for tests*/ RenderGraphResourceRegistry m_Resources;
internal/*for tests*/ RenderGraphObjectPool m_RenderGraphPool = new RenderGraphObjectPool();
RenderGraphBuilders m_builderInstance = new RenderGraphBuilders();
internal/*for tests*/ List m_RenderPasses = new List(64);
List m_RendererLists = new List(32);
RenderGraphDebugParams m_DebugParameters = new RenderGraphDebugParams();
RenderGraphDefaultResources m_DefaultResources = new RenderGraphDefaultResources();
Dictionary m_DefaultProfilingSamplers = new Dictionary();
InternalRenderGraphContext m_RenderGraphContext = new InternalRenderGraphContext();
CommandBuffer m_PreviousCommandBuffer;
RenderGraphCompilationCache m_CompilationCache;
EntityId m_CurrentExecutionId;
bool m_CurrentExecutionCanGenerateDebugData;
int m_ExecutionCount;
int m_CurrentFrameIndex;
bool m_ExecutionExceptionWasRaised;
bool m_EnableCompilationCaching;
internal/*for tests*/ static bool? s_EnableCompilationCachingForTests;
RenderGraphState m_RenderGraphState;
RenderTextureUVOriginStrategy m_renderTextureUVOriginStrategy;
// Global container of registered render graphs, associated with the list of executions that have been registered for them.
// When a RenderGraph is created, an entry is added to this dictionary. When that RenderGraph renders something,
// and a debug session is active, an entry is added to the list of executions for that RenderGraph using the executionId
// as the key. So when you render multiple times with the same executionId, only one DebugExecutionItem is created.
static Dictionary> s_RegisteredExecutions = new ();
#region Public Interface
/// Name of the Render Graph.
public string name { get; private set; } = "RenderGraph";
internal RenderGraphState RenderGraphState
{
get { return m_RenderGraphState; }
set { m_RenderGraphState = value; }
}
/// The strategy the Render Graph will take for the uv origin of RenderTextures in the graph.
public RenderTextureUVOriginStrategy renderTextureUVOriginStrategy
{
get { return m_renderTextureUVOriginStrategy; }
internal set { m_renderTextureUVOriginStrategy = value; }
}
/// If true, the Render Graph Viewer is active.
public static bool isRenderGraphViewerActive => RenderGraphDebugSession.hasActiveDebugSession;
/// If true, the Render Graph will run its various validity checks while processing (not considered in release mode).
internal static bool enableValidityChecks { get; private set; }
///
/// Set of default resources usable in a pass rendering code.
///
public RenderGraphDefaultResources defaultResources
{
get
{
return m_DefaultResources;
}
}
///
/// Render Graph constructor.
///
/// Optional name used to identify the render graph instance.
public RenderGraph(string name = "RenderGraph")
{
this.name = name;
if (GraphicsSettings.TryGetRenderPipelineSettings(out var renderGraphGlobalSettings))
{
m_EnableCompilationCaching = renderGraphGlobalSettings.enableCompilationCaching;
enableValidityChecks = renderGraphGlobalSettings.enableValidityChecks;
}
else // No SRP pipeline is present/active, it can happen with unit tests
{
enableValidityChecks = true;
}
if (s_EnableCompilationCachingForTests.HasValue)
m_EnableCompilationCaching = s_EnableCompilationCachingForTests.Value;
if (m_EnableCompilationCaching)
m_CompilationCache = new RenderGraphCompilationCache();
m_Resources = new RenderGraphResourceRegistry(m_DebugParameters);
RegisterGraph();
m_RenderGraphState = RenderGraphState.Idle;
RenderGraph.RenderGraphExceptionMessages.enableCaller = true;
#if !UNITY_EDITOR && DEVELOPMENT_BUILD
if (RenderGraphDebugSession.currentDebugSession == null)
RenderGraphDebugSession.Create();
#endif
}
// Internal, only for testing
// Useful when we need to clean when calling
// internal functions in tests even if Render Graph is active
// This API shouldn't be called when the render graph is active!
internal void CleanupResourcesAndGraph()
{
// Usually done at the end of Execute step
// Also doing it here in case RG stopped before it
ClearCurrentCompiledGraph();
m_Resources.Cleanup();
m_DefaultResources.Cleanup();
m_RenderGraphPool.Cleanup();
nativeCompiler?.Cleanup();
m_CompilationCache?.Clear();
DelegateHashCodeUtils.ClearCache();
}
///
/// Free up all resources used internally by the Render Graph instance, and unregister it so it won't be visible in the Render Graph Viewer.
///
public void Cleanup()
{
CheckNotUsedWhenActive();
// Dispose of the compiled graphs left over in the cache
m_CompilationCache?.Cleanup();
CleanupResourcesAndGraph();
UnregisterGraph();
}
internal RenderGraphDebugParams debugParams => m_DebugParameters;
internal List GetWidgetList()
{
return m_DebugParameters.GetWidgetList(name);
}
internal bool areAnySettingsActive => m_DebugParameters.AreAnySettingsActive;
///
/// Register the render graph to the debug window.
///
///
/// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph().
///
/// Optional debug panel to which the render graph debug parameters will be registered.
public void RegisterDebug(DebugUI.Panel panel = null)
{
CheckNotUsedWhenActive();
m_DebugParameters.RegisterDebug(name, panel);
}
///
/// Unregister render graph from the debug window.
///
///
/// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph().
///
public void UnRegisterDebug()
{
CheckNotUsedWhenActive();
m_DebugParameters.UnRegisterDebug(this.name);
}
///
/// Get the list of all registered render graphs.
///
/// The list of all registered render graphs.
public static List GetRegisteredRenderGraphs()
{
return new List(s_RegisteredExecutions.Keys);
}
internal static Dictionary> GetRegisteredExecutions() => s_RegisteredExecutions;
///
/// End frame processing. Purge resources that have been used since last frame and resets internal states.
/// This need to be called once per frame.
///
///
/// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph().
///
public void EndFrame()
{
CheckNotUsedWhenActive();
m_Resources.PurgeUnusedGraphicsResources();
}
///
/// Import an external texture to the Render Graph.
/// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// External RTHandle that needs to be imported.
/// A new TextureHandle that represents the imported texture in the context of this rendergraph.
public TextureHandle ImportTexture(RTHandle rt)
{
CheckNotUsedWhenExecuting();
return m_Resources.ImportTexture(rt);
}
///
/// Import an external Variable Rate Shading (VRS) textures to the RenderGraph.
/// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled.
///
/// External shading rate image RTHandle that needs to be imported.
/// New TextureHandle that represents the imported shading rate images in the context of this rendergraph.
public TextureHandle ImportShadingRateImageTexture(RTHandle rt)
{
if (ShadingRateInfo.supportsPerImageTile)
return m_Resources.ImportTexture(rt);
return TextureHandle.nullHandle;
}
///
/// Import an external texture to the Render Graph.
/// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled.
///
/// Note: RTHandles that wrap RenderTargetIdentifier will fail to import using this overload as render graph can't derive the render texture's properties.
/// In that case the overload taking a RenderTargetInfo argument should be used instead.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// External RTHandle that needs to be imported.
/// Info describing the clear behavior of imported textures. Clearing textures using importParams may be more efficient than manually clearing the texture using `cmd.Clear` on some hardware.
/// A new TextureHandle that represents the imported texture in the context of this rendergraph.
public TextureHandle ImportTexture(RTHandle rt, ImportResourceParams importParams)
{
CheckNotUsedWhenExecuting();
return m_Resources.ImportTexture(rt, importParams);
}
///
/// Import an external texture to the Render Graph. This overload should be used for RTHandles wrapping a RenderTargetIdentifier.
/// If the RTHandle is wrapping a RenderTargetIdentifer, Rendergraph can't derive the render texture's properties so the user has to provide this info to the graph through RenderTargetInfo.
///
/// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled.
///
/// Note: To avoid inconsistencies between the passed in RenderTargetInfo and render texture this overload can only be used when the RTHandle is wrapping a RenderTargetIdentifier.
/// If this is not the case, the overload of ImportTexture without a RenderTargetInfo argument should be used instead.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// External RTHandle that needs to be imported.
/// The properties of the passed in RTHandle.
/// Info describing the clear behavior of imported textures. Clearing textures using importParams may be more efficient than manually clearing the texture using `cmd.Clear` on some hardware.
/// A new TextureHandle that represents the imported texture in the context of this rendergraph.
public TextureHandle ImportTexture(RTHandle rt, RenderTargetInfo info, ImportResourceParams importParams = new ImportResourceParams())
{
CheckNotUsedWhenExecuting();
return m_Resources.ImportTexture(rt, info, importParams);
}
///
/// Import an external texture to the Render Graph and set the handle as builtin handle. This can only happen from within the graph module
/// so it is internal.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// External RTHandle that needs to be imported.
/// The handle is a builtin handle managed by RenderGraph internally.
/// A new TextureHandle that represents the imported texture in the context of this rendergraph.
internal TextureHandle ImportTexture(RTHandle rt, bool isBuiltin)
{
CheckNotUsedWhenExecuting();
return m_Resources.ImportTexture(rt, isBuiltin);
}
///
/// Import the final backbuffer to render graph. The rendergraph can't derive the properties of a RenderTargetIdentifier as it is an opaque handle so the user has to pass them in through the info argument.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// Backbuffer render target identifier.
/// The properties of the passed in RTHandle.
/// Info describing the clear behavior of imported textures. Clearing textures using importParams may be more efficient than manually clearing the texture using `cmd.Clear` on some hardware.
/// A new TextureHandle that represents the imported texture in the context of this rendergraph.
public TextureHandle ImportBackbuffer(RenderTargetIdentifier rt, RenderTargetInfo info, ImportResourceParams importParams = new ImportResourceParams())
{
CheckNotUsedWhenExecuting();
return m_Resources.ImportBackbuffer(rt, info, importParams);
}
///
/// Create a new Render Graph Texture resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// Texture descriptor.
/// A new TextureHandle.
public TextureHandle CreateTexture(in TextureDesc desc)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateTexture(desc);
}
///
/// Create a new Render Graph Texture resource using the descriptor from another texture.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// Texture from which the descriptor should be used.
/// A new TextureHandle.
public TextureHandle CreateTexture(TextureHandle texture)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateTexture(in m_Resources.GetTextureResourceDesc(texture.handle));
}
///
/// Create a new Render Graph Texture resource using the descriptor from another texture.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// Texture from which the descriptor should be used.
/// The destination texture name.
/// Texture needs to be cleared on first use.
/// A new TextureHandle.
public TextureHandle CreateTexture(TextureHandle texture, string name, bool clear = false)
{
CheckNotUsedWhenExecuting();
var destinationDesc = GetTextureDesc(texture);
destinationDesc.name = name;
destinationDesc.clearBuffer = clear;
return m_Resources.CreateTexture(destinationDesc);
}
///
/// Create a new Render Graph Texture if the passed handle is invalid and use said handle as output.
/// If the passed handle is valid, no texture is created.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// Desc used to create the texture.
/// Texture from which the descriptor should be used.
public void CreateTextureIfInvalid(in TextureDesc desc, ref TextureHandle texture)
{
CheckNotUsedWhenExecuting();
if (!texture.IsValid())
texture = m_Resources.CreateTexture(desc);
}
///
/// Gets the descriptor of the specified Texture resource.
///
/// Texture resource from which the descriptor is requested.
/// The input texture descriptor.
public TextureDesc GetTextureDesc(in TextureHandle texture)
{
return m_Resources.GetTextureResourceDesc(texture.handle);
}
///
/// Gets the descriptor of the specified Texture resource.
///
/// Texture resource from which the descriptor is requested.
/// The input texture descriptor.
public RenderTargetInfo GetRenderTargetInfo(TextureHandle texture)
{
RenderTargetInfo info;
m_Resources.GetRenderTargetInfo(texture.handle, out info);
return info;
}
///
/// Creates a new Renderer List Render Graph resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// Renderer List descriptor.
/// A new RendererListHandle.
public RendererListHandle CreateRendererList(in CoreRendererListDesc desc)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateRendererList(desc);
}
///
/// Creates a new Renderer List Render Graph resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// Renderer List descriptor.
/// A new RendererListHandle.
public RendererListHandle CreateRendererList(in RendererListParams desc)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateRendererList(desc);
}
///
/// Creates a new Shadow Renderer List Render Graph resource.
///
/// DrawSettings that describe the shadow drawcall.
/// A new RendererListHandle.
public RendererListHandle CreateShadowRendererList(ref ShadowDrawingSettings shadowDrawingSettings)
{
return m_Resources.CreateShadowRendererList(m_RenderGraphContext.renderContext, ref shadowDrawingSettings);
}
///
/// Creates a new Gizmo Renderer List Render Graph resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// The camera that is used for rendering the Gizmo.
/// GizmoSubset that specifies whether gizmos render before or after postprocessing for a camera render.
/// A new RendererListHandle.
public RendererListHandle CreateGizmoRendererList(in Camera camera, in GizmoSubset gizmoSubset)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateGizmoRendererList(m_RenderGraphContext.renderContext, camera, gizmoSubset);
}
///
/// Creates a new UIOverlay Renderer List Render Graph resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// The camera that is used for rendering the full UIOverlay.
/// A new RendererListHandle.
public RendererListHandle CreateUIOverlayRendererList(in Camera camera)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateUIOverlayRendererList(m_RenderGraphContext.renderContext, camera, UISubset.All);
}
///
/// Creates a new UIOverlay Renderer List Render Graph resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// The camera that is used for rendering some subset of the UIOverlay.
/// Enum flag that specifies which subset to render.
/// A new RendererListHandle.
public RendererListHandle CreateUIOverlayRendererList(in Camera camera, in UISubset uiSubset)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateUIOverlayRendererList(m_RenderGraphContext.renderContext, camera, uiSubset);
}
///
/// Creates a new WireOverlay Renderer List Render Graph resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// The camera that is used for rendering the WireOverlay.
/// A new RendererListHandle.
public RendererListHandle CreateWireOverlayRendererList(in Camera camera)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateWireOverlayRendererList(m_RenderGraphContext.renderContext, camera);
}
///
/// Creates a new Skybox Renderer List Render Graph resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// The camera that is used for rendering the Skybox.
/// A new RendererListHandle.
public RendererListHandle CreateSkyboxRendererList(in Camera camera)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateSkyboxRendererList(m_RenderGraphContext.renderContext, camera);
}
///
/// Creates a new Skybox Renderer List Render Graph resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// The camera that is used for rendering the Skybox.
/// The projection matrix used during XR rendering of the skybox.
/// The view matrix used during XR rendering of the skybox.
/// A new RendererListHandle.
public RendererListHandle CreateSkyboxRendererList(in Camera camera, Matrix4x4 projectionMatrix, Matrix4x4 viewMatrix)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateSkyboxRendererList(m_RenderGraphContext.renderContext, camera, projectionMatrix, viewMatrix);
}
///
/// Creates a new Skybox Renderer List Render Graph resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// The camera that is used for rendering the Skybox.
/// The left eye projection matrix used during Legacy single pass XR rendering of the skybox.
/// The left eye view matrix used during Legacy single pass XR rendering of the skybox.
/// The right eye projection matrix used during Legacy single pass XR rendering of the skybox.
/// The right eye view matrix used during Legacy single pass XR rendering of the skybox.
/// A new RendererListHandle.
public RendererListHandle CreateSkyboxRendererList(in Camera camera, Matrix4x4 projectionMatrixL, Matrix4x4 viewMatrixL, Matrix4x4 projectionMatrixR, Matrix4x4 viewMatrixR)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateSkyboxRendererList(m_RenderGraphContext.renderContext, camera, projectionMatrixL, viewMatrixL, projectionMatrixR, viewMatrixR);
}
///
/// Import an external Graphics Buffer to the Render Graph.
/// Any pass writing to an imported graphics buffer will be considered having side effects and can't be automatically culled.
///
/// External Graphics Buffer that needs to be imported.
/// A new GraphicsBufferHandle.
public BufferHandle ImportBuffer(GraphicsBuffer graphicsBuffer)
{
CheckNotUsedWhenExecuting();
return m_Resources.ImportBuffer(graphicsBuffer);
}
///
/// Create a new Render Graph Graphics Buffer resource.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// Graphics Buffer descriptor.
/// A new GraphicsBufferHandle.
public BufferHandle CreateBuffer(in BufferDesc desc)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateBuffer(desc);
}
///
/// Create a new Render Graph Graphics Buffer resource using the descriptor from another graphics buffer.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// Graphics Buffer from which the descriptor should be used.
/// A new GraphicsBufferHandle.
public BufferHandle CreateBuffer(in BufferHandle graphicsBuffer)
{
CheckNotUsedWhenExecuting();
return m_Resources.CreateBuffer(in m_Resources.GetBufferResourceDesc(graphicsBuffer.handle));
}
///
/// Gets the descriptor of the specified Graphics Buffer resource.
///
/// Graphics Buffer resource from which the descriptor is requested.
/// The input graphics buffer descriptor.
public BufferDesc GetBufferDesc(in BufferHandle graphicsBuffer)
{
return m_Resources.GetBufferResourceDesc(graphicsBuffer.handle);
}
///
/// Import an external RayTracingAccelerationStructure to the Render Graph.
/// Any pass writing to (building) an imported RayTracingAccelerationStructure will be considered having side effects and can't be automatically culled.
///
///
/// This API cannot be called during the Render Graph execution, please call it outside of SetRenderFunc().
///
/// External RayTracingAccelerationStructure that needs to be imported.
/// Optional name for identifying the RayTracingAccelerationStructure in the Render Graph.
/// A new RayTracingAccelerationStructureHandle.
public RayTracingAccelerationStructureHandle ImportRayTracingAccelerationStructure(in RayTracingAccelerationStructure accelStruct, string name = null)
{
CheckNotUsedWhenExecuting();
return m_Resources.ImportRayTracingAccelerationStructure(accelStruct, name);
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
void CheckNotUsedWhenExecuting()
{
if (enableValidityChecks && m_RenderGraphState == RenderGraphState.Executing)
throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.Executing));
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
void CheckNotUsedWhenRecordingGraph()
{
if (enableValidityChecks && m_RenderGraphState == RenderGraphState.RecordingGraph)
throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.RecordingGraph));
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
void CheckNotUsedWhenRecordPassOrExecute()
{
if (enableValidityChecks && (m_RenderGraphState == RenderGraphState.RecordingPass || m_RenderGraphState == RenderGraphState.Executing))
throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.RecordingPass | RenderGraphState.Executing));
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
void CheckNotUsedWhenRecordingPass()
{
if (enableValidityChecks && m_RenderGraphState == RenderGraphState.RecordingPass)
throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.RecordingPass));
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
void CheckNotUsedWhenActive()
{
if (enableValidityChecks && (m_RenderGraphState & RenderGraphState.Active) != RenderGraphState.Idle)
throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.Active));
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
void CheckNotUsedWhenIdle()
{
if (enableValidityChecks && m_RenderGraphState == RenderGraphState.Idle)
throw new InvalidOperationException(RenderGraphExceptionMessages.GetExceptionMessage(RenderGraphState.Active));
}
///
/// Add a new Raster Render Pass to the Render Graph. Raster passes can execute rasterization workloads but cannot do other GPU work like copies or compute.
///
///
/// This API cannot be called when Render Graph records a pass, please call it within SetRenderFunc() or outside of AddUnsafePass()/AddComputePass()/AddRasterRenderPass().
///
/// Type of the class to use to provide data to the Render Pass.
/// Name of the new Render Pass (this is also be used to generate a GPU profiling marker).
/// Instance of PassData that is passed to the render function and you must fill.
/// File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// A new instance of a IRasterRenderGraphBuilder used to setup the new Rasterization Render Pass.
public IRasterRenderGraphBuilder AddRasterRenderPass(string passName, out PassData passData
#if !CORE_PACKAGE_DOCTOOLS
, [CallerFilePath] string file = "",
[CallerLineNumber] int line = 0) where PassData : class, new()
#endif
{
return AddRasterRenderPass(passName, out passData, GetDefaultProfilingSampler(passName), file, line);
}
///
/// Add a new Raster Render Pass to the Render Graph. Raster passes can execute rasterization workloads but cannot do other GPU work like copies or compute.
///
/// Type of the class to use to provide data to the Render Pass.
/// Name of the new Render Pass (this is also be used to generate a GPU profiling marker).
/// Instance of PassData that is passed to the render function and you must fill.
/// Profiling sampler used around the pass.
/// File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// A new instance of a IRasterRenderGraphBuilder used to setup the new Rasterization Render Pass.
public IRasterRenderGraphBuilder AddRasterRenderPass(string passName, out PassData passData, ProfilingSampler sampler
#if !CORE_PACKAGE_DOCTOOLS
,[CallerFilePath] string file = "",
[CallerLineNumber] int line = 0) where PassData : class, new()
#endif
{
CheckNotUsedWhenRecordingPass();
m_RenderGraphState = RenderGraphState.RecordingPass;
var renderPass = m_RenderGraphPool.Get>();
renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get(), passName, RenderGraphPassType.Raster, sampler);
AddPassDebugMetadata(renderPass, file, line);
passData = renderPass.data;
m_RenderPasses.Add(renderPass);
m_builderInstance.Setup(renderPass, m_Resources, this);
return m_builderInstance;
}
///
/// Add a new Compute Render Pass to the Render Graph. Raster passes can execute rasterization workloads but cannot do other GPU work like copies or compute.
///
///
/// This API cannot be called when Render Graph records a pass, please call it within SetRenderFunc() or outside of AddUnsafePass()/AddComputePass()/AddRasterRenderPass().
///
/// Type of the class to use to provide data to the Render Pass.
/// Name of the new Render Pass (this is also be used to generate a GPU profiling marker).
/// Instance of PassData that is passed to the render function and you must fill.
/// File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// A new instance of a IRasterRenderGraphBuilder used to setup the new Rasterization Render Pass.
public IComputeRenderGraphBuilder AddComputePass(string passName, out PassData passData
#if !CORE_PACKAGE_DOCTOOLS
, [CallerFilePath] string file = "",
[CallerLineNumber] int line = 0) where PassData : class, new()
#endif
{
return AddComputePass(passName, out passData, GetDefaultProfilingSampler(passName), file, line);
}
///
/// Add a new Compute Render Pass to the Render Graph. Compute passes can execute compute workloads but cannot do rasterization.
///
/// Type of the class to use to provide data to the Render Pass.
/// Name of the new Render Pass (this is also be used to generate a GPU profiling marker).
/// Instance of PassData that is passed to the render function and you must fill.
/// Profiling sampler used around the pass.
/// File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// A new instance of a IComputeRenderGraphBuilder used to setup the new Compute Render Pass.
public IComputeRenderGraphBuilder AddComputePass(string passName, out PassData passData, ProfilingSampler sampler
#if !CORE_PACKAGE_DOCTOOLS
,[CallerFilePath] string file = "",
[CallerLineNumber] int line = 0) where PassData : class, new()
#endif
{
CheckNotUsedWhenRecordingPass();
m_RenderGraphState = RenderGraphState.RecordingPass;
var renderPass = m_RenderGraphPool.Get>();
renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get(), passName, RenderGraphPassType.Compute, sampler);
AddPassDebugMetadata(renderPass, file, line);
passData = renderPass.data;
m_RenderPasses.Add(renderPass);
m_builderInstance.Setup(renderPass, m_Resources, this);
return m_builderInstance;
}
///
/// Add a new Unsafe Render Pass to the Render Graph. Unsafe passes can do certain operations compute/raster render passes cannot do and have
/// access to the full command buffer API. The unsafe API should be used sparingly as it has the following downsides:
/// - Limited automatic validation of the commands and resource dependencies. The user is responsible to ensure that all dependencies are correctly declared.
/// - All native render passes will be serialized out.
/// - In the future the render graph compiler may generate a sub-optimal command stream for unsafe passes.
/// When using a unsafe pass the graph will also not automatically set up graphics state like rendertargets. The pass should do this itself
/// using cmd.SetRenderTarget and related commands.
///
///
/// This API cannot be called when Render Graph records a pass, please call it within SetRenderFunc() or outside of AddUnsafePass()/AddComputePass()/AddRasterRenderPass().
///
/// Type of the class to use to provide data to the Render Pass.
/// Name of the new Render Pass (this is also be used to generate a GPU profiling marker).
/// Instance of PassData that is passed to the render function and you must fill.
/// File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// A new instance of a IUnsafeRenderGraphBuilder used to setup the new Unsafe Render Pass.
public IUnsafeRenderGraphBuilder AddUnsafePass(string passName, out PassData passData
#if !CORE_PACKAGE_DOCTOOLS
, [CallerFilePath] string file = "",
[CallerLineNumber] int line = 0) where PassData : class, new()
#endif
{
return AddUnsafePass(passName, out passData, GetDefaultProfilingSampler(passName), file, line);
}
///
/// Add a new unsafe Render Pass to the Render Graph. Unsafe passes can do certain operations compute/raster render passes cannot do and have
/// access to the full command buffer API. The unsafe API should be used sparingly as it has the following downsides:
/// - Limited automatic validation of the commands and resource dependencies. The user is responsible to ensure that all dependencies are correctly declared.
/// - All native render passes will be serialized out.
/// - In the future the render graph compiler may generate a sub-optimal command stream for unsafe passes.
/// When using an unsafe pass the graph will also not automatically set up graphics state like rendertargets. The pass should do this itself
/// using cmd.SetRenderTarget and related commands.
///
/// Type of the class to use to provide data to the Render Pass.
/// Name of the new Render Pass (this is also be used to generate a GPU profiling marker).
/// Instance of PassData that is passed to the render function and you must fill.
/// Profiling sampler used around the pass.
/// File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// A new instance of a IUnsafeRenderGraphBuilder used to setup the new unsafe Render Pass.
public IUnsafeRenderGraphBuilder AddUnsafePass(string passName, out PassData passData, ProfilingSampler sampler
#if !CORE_PACKAGE_DOCTOOLS
, [CallerFilePath] string file = "",
[CallerLineNumber] int line = 0) where PassData : class, new()
#endif
{
CheckNotUsedWhenRecordingPass();
m_RenderGraphState = RenderGraphState.RecordingPass;
var renderPass = m_RenderGraphPool.Get>();
renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get(), passName, RenderGraphPassType.Unsafe, sampler);
renderPass.AllowGlobalState(true);
AddPassDebugMetadata(renderPass, file, line);
passData = renderPass.data;
m_RenderPasses.Add(renderPass);
m_builderInstance.Setup(renderPass, m_Resources, this);
return m_builderInstance;
}
///
/// Starts the recording of the render graph.
/// This must be called before adding any pass to the render graph.
///
///
/// This API cannot be called when Render Graph is active, please call it outside of RecordRenderGraph().
///
/// Parameters necessary for the render graph execution.
///
/// Begin recording the Render Graph.
///
/// renderGraph.BeginRecording(parameters)
/// // Add your render graph passes here.
/// renderGraph.EndRecordingAndExecute()
///
///
public void BeginRecording(in RenderGraphParameters parameters)
{
CheckNotUsedWhenActive();
m_ExecutionExceptionWasRaised = false;
m_RenderGraphState = RenderGraphState.RecordingGraph;
m_CurrentFrameIndex = parameters.currentFrameIndex;
m_CurrentExecutionId = parameters.executionId;
// Ignore preview cameras and render requests for debug data generation. They would cause the same camera to
// be rendered twice with different render graphs, confusing users and causing the RG Viewer to constantly update.
m_CurrentExecutionCanGenerateDebugData = parameters.generateDebugData && parameters.executionId != EntityId.None;
m_renderTextureUVOriginStrategy = parameters.renderTextureUVOriginStrategy;
m_Resources.BeginRenderGraph(m_ExecutionCount++);
m_DefaultResources.InitializeForRendering(this);
m_RenderGraphContext.cmd = parameters.commandBuffer;
m_RenderGraphContext.renderContext = parameters.scriptableRenderContext;
m_RenderGraphContext.contextlessTesting = parameters.invalidContextForTesting;
m_RenderGraphContext.renderGraphPool = m_RenderGraphPool;
m_RenderGraphContext.defaultResources = m_DefaultResources;
// With the actual implementation of the Frame Debugger, we cannot re-use resources during the same frame
// or it breaks the rendering of the pass preview, since the FD copies the texture after the execution of the RG.
m_RenderGraphContext.forceResourceCreation =
#if UNITY_EDITOR || DEVELOPMENT_BUILD
FrameDebugger.enabled;
#else
false;
#endif
}
///
/// Ends the recording and executes the render graph.
/// This must be called once all passes have been added to the render graph.
///
public void EndRecordingAndExecute()
{
CheckNotUsedWhenRecordPassOrExecute();
Execute();
ClearCompiledGraph();
m_Resources.EndExecute();
InvalidateContext();
m_RenderGraphState = RenderGraphState.Idle;
}
///
/// Catches and logs exceptions that could happen during the graph recording or execution.
///
/// The exception thrown by the graph.
/// True if contexless testing is enabled, false otherwise.
public bool ResetGraphAndLogException(Exception e)
{
m_RenderGraphState = RenderGraphState.Idle;
if (!m_RenderGraphContext.contextlessTesting)
{
// If we're not testing log the exception and swallow it.
// TODO: Do we really want to swallow exceptions here? Not a very c# thing to do.
Debug.LogError(RenderGraphExceptionMessages.k_RenderGraphExecutionError);
if (!m_ExecutionExceptionWasRaised) // Already logged. TODO: There is probably a better way in C# to handle that.
{
Debug.LogException(e);
}
m_ExecutionExceptionWasRaised = true;
}
CommandBuffer.ThrowOnSetRenderTarget = false;
CleanupResourcesAndGraph();
// If there has been an error, we have to flush the command being built along the RG data structure,
// because otherwise the command might try to use resources we just deleted.
m_RenderGraphContext.cmd.Clear();
return m_RenderGraphContext.contextlessTesting;
}
///
/// Execute the Render Graph in its current state.
///
internal void Execute()
{
m_ExecutionExceptionWasRaised = false;
m_RenderGraphState = RenderGraphState.Executing;
#if DEVELOPMENT_BUILD || UNITY_EDITOR
if (m_RenderGraphContext.cmd == null)
throw new InvalidOperationException("RenderGraph.BeginRecording was not called before executing the render graph.");
ClearCacheIfNewActiveDebugSession();
#endif
int graphHash = m_EnableCompilationCaching ? ComputeGraphHash() : 0;
CompileNativeRenderGraph(graphHash);
// Must be set after compilation when the compiler has been initialized
m_RenderGraphContext.compilerContext = nativeCompiler?.contextData;
m_Resources.BeginExecute(m_CurrentFrameIndex);
#if UNITY_EDITOR || DEVELOPMENT_BUILD
// Feeding Render Graph Viewer before resource deallocation at pass execution
GenerateDebugData(graphHash);
#endif
ExecuteNativeRenderGraph();
// Clear the shader bindings for all global textures to make sure bindings don't leak outside the graph
ClearGlobalBindings();
}
class ProfilingScopePassData
{
public ProfilingSampler sampler;
}
const string k_BeginProfilingSamplerPassName = "BeginProfile";
const string k_EndProfilingSamplerPassName = "EndProfile";
///
/// Begin a profiling scope.
///
/// Sampler used for profiling.
/// File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
public void BeginProfilingSampler(ProfilingSampler sampler,
[CallerFilePath] string file = "",
[CallerLineNumber] int line = 0)
{
if (sampler == null)
return;
using (var builder = AddUnsafePass(k_BeginProfilingSamplerPassName, out var passData, (ProfilingSampler)null, file, line))
{
passData.sampler = sampler;
builder.AllowPassCulling(false);
builder.GenerateDebugData(false);
builder.SetRenderFunc(static (ProfilingScopePassData data, UnsafeGraphContext ctx) =>
{
data.sampler.Begin(CommandBufferHelpers.GetNativeCommandBuffer(ctx.cmd));
});
}
}
///
/// End a profiling scope.
///
/// Sampler used for profiling.
/// File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
/// File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.
public void EndProfilingSampler(ProfilingSampler sampler,
[CallerFilePath] string file = "",
[CallerLineNumber] int line = 0)
{
if (sampler == null)
return;
using (var builder = AddUnsafePass(k_EndProfilingSamplerPassName, out var passData, (ProfilingSampler)null, file, line))
{
passData.sampler = sampler;
builder.AllowPassCulling(false);
builder.GenerateDebugData(false);
builder.SetRenderFunc(static (ProfilingScopePassData data, UnsafeGraphContext ctx) =>
{
data.sampler.End(CommandBufferHelpers.GetNativeCommandBuffer(ctx.cmd));
});
}
}
#endregion
#region Internal Interface
// Internal for testing purpose only
internal void ClearCurrentCompiledGraph()
{
ClearCompiledGraph();
}
void ClearCompiledGraph()
{
ClearRenderPasses();
m_Resources.Clear(m_ExecutionExceptionWasRaised);
m_RendererLists.Clear();
registeredGlobals.Clear();
}
void InvalidateContext()
{
m_RenderGraphContext.cmd = null;
m_RenderGraphContext.renderGraphPool = null;
m_RenderGraphContext.defaultResources = null;
m_RenderGraphContext.compilerContext = null;
}
internal delegate void OnGraphRegisteredDelegate(string graphName);
internal static event OnGraphRegisteredDelegate onGraphRegistered;
internal static event OnGraphRegisteredDelegate onGraphUnregistered;
internal delegate void OnExecutionRegisteredDelegate(string graphName, EntityId executionId, string executionName);
internal static event OnExecutionRegisteredDelegate onExecutionRegistered;
#endregion
#region Private Interface
// Internal for testing purpose only.
internal int ComputeGraphHash()
{
using (new ProfilingScope(ProfilingSampler.Get(RenderGraphProfileId.ComputeHashRenderGraph)))
{
var hash128 = HashFNV1A32.Create();
for (int i = 0; i < m_RenderPasses.Count; ++i)
m_RenderPasses[i].ComputeHash(ref hash128, m_Resources);
return hash128.value;
}
}
internal bool GetImportedFallback(TextureDesc desc, out TextureHandle fallback)
{
fallback = TextureHandle.nullHandle;
// We don't have any fallback texture with MSAA
if (!desc.bindTextureMS)
{
if (desc.depthBufferBits != DepthBits.None)
{
fallback = defaultResources.whiteTexture;
}
else if (desc.clearColor == Color.black || desc.clearColor == default)
{
if (desc.dimension == TextureXR.dimension)
fallback = defaultResources.blackTextureXR;
else if (desc.dimension == TextureDimension.Tex3D)
fallback = defaultResources.blackTexture3DXR;
else if (desc.dimension == TextureDimension.Tex2D)
fallback = defaultResources.blackTexture;
}
else if (desc.clearColor == Color.white)
{
if (desc.dimension == TextureXR.dimension)
fallback = defaultResources.whiteTextureXR;
else if (desc.dimension == TextureDimension.Tex2D)
fallback = defaultResources.whiteTexture;
}
}
return fallback.IsValid();
}
void ClearRenderPasses()
{
foreach (var pass in m_RenderPasses)
pass.Release(m_RenderGraphPool);
m_RenderPasses.Clear();
}
ProfilingSampler GetDefaultProfilingSampler(string name)
{
// In non-dev builds, ProfilingSampler.Get returns null, so we'd always end up executing this.
// To avoid that we also ifdef the code out here.
#if DEVELOPMENT_BUILD || UNITY_EDITOR
int hash = name.GetHashCode();
if (!m_DefaultProfilingSamplers.TryGetValue(hash, out var sampler))
{
sampler = new ProfilingSampler(name);
m_DefaultProfilingSamplers.Add(hash, sampler);
}
return sampler;
#else
return null;
#endif
}
// Register the graph in the RenderGraph Viewer.
// Registered once on graph creation, indicates to the viewer that this render graph exists.
void RegisterGraph()
{
s_RegisteredExecutions.Add(this, new List());
onGraphRegistered?.Invoke(this.name);
}
// Unregister the graph from the render graph viewer.
// Should only be unregistered when it is destroyed, not before.
// Should not be called when an error happens because the existence of the graph doesn't depend on its state
// or whether it's been cleaned.
void UnregisterGraph()
{
s_RegisteredExecutions.Remove(this);
onGraphUnregistered?.Invoke(name);
}
// Note: obj.name allocates so make sure you only call this when debug tools / options are active
static string GetExecutionNameAllocates(EntityId entityId)
{
var obj = Resources.EntityIdToObject(entityId);
return obj != null ? obj.name : $"RenderGraphExecution ({entityId})";
}
static bool s_DebugSessionWasActive;
void ClearCacheIfNewActiveDebugSession()
{
if (RenderGraphDebugSession.hasActiveDebugSession && !s_DebugSessionWasActive)
{
// Invalidate cache whenever a debug session becomes active. This is because while the DebugSession is
// inactive, certain debug data (store/load/pass break audits) stored inside the compilation cache is
// not getting generated. Therefore we clear compilation cache to regenerate this debug data.
// This needs to be done before the compilation step.
m_CompilationCache?.Clear();
}
s_DebugSessionWasActive = RenderGraphDebugSession.hasActiveDebugSession;
}
void GenerateDebugData(int graphHash)
{
if (!RenderGraphDebugSession.hasActiveDebugSession || !m_CurrentExecutionCanGenerateDebugData || m_ExecutionExceptionWasRaised)
return;
var registeredExecutions = s_RegisteredExecutions[this];
// The reverse loop prunes deleted cameras and checks if the current camera needs to be registered.
bool alreadyRegistered = false;
using var deletedExecutionIdsDisposable = ListPool.Get(out var deletedExecutionIds);
for (int i = registeredExecutions.Count - 1; i >= 0; i--)
{
DebugExecutionItem executionItem = registeredExecutions[i];
if (Resources.EntityIdToObject(executionItem.id) == null)
{
registeredExecutions.RemoveAt(i);
deletedExecutionIds.Add(executionItem.id);
continue;
}
if (executionItem.id == m_CurrentExecutionId)
alreadyRegistered = true;
}
var currentExecutionName = GetExecutionNameAllocates(m_CurrentExecutionId);
if (!alreadyRegistered)
{
registeredExecutions.Add(new DebugExecutionItem(m_CurrentExecutionId, currentExecutionName));
}
if (deletedExecutionIds.Count > 0)
RenderGraphDebugSession.DeleteExecutionIds(name, deletedExecutionIds); // Clear stale debug data entries for deleted cameras
if (!alreadyRegistered)
{
onExecutionRegistered?.Invoke(name, m_CurrentExecutionId, currentExecutionName);
}
// When compilation caching is disabled, we don't hash the graph. In order to avoid UI needing to update every
// frame, we still want to use the hash to know if debug data should be updated, so compute the hash now.
if (!m_EnableCompilationCaching)
graphHash = ComputeGraphHash();
var debugData = RenderGraphDebugSession.GetDebugData(name, m_CurrentExecutionId);
bool cameraWasRenamed = debugData.executionName != currentExecutionName;
if (debugData.valid && debugData.graphHash == graphHash && !cameraWasRenamed)
return; // No need to update
debugData.Clear();
debugData.executionName = currentExecutionName;
debugData.graphHash = graphHash;
nativeCompiler.GenerateNativeCompilerDebugData(ref debugData);
debugData.valid = true;
RenderGraphDebugSession.SetDebugData(name, m_CurrentExecutionId, debugData);
}
#endregion
Dictionary registeredGlobals = new Dictionary();
internal void SetGlobal(in TextureHandle h, int globalPropertyId)
{
if (!h.IsValid())
throw new ArgumentException("Attempting to register an invalid texture handle as a global");
registeredGlobals[globalPropertyId] = h;
}
internal bool IsGlobal(int globalPropertyId)
{
return registeredGlobals.ContainsKey(globalPropertyId);
}
internal Dictionary.ValueCollection AllGlobals()
{
return registeredGlobals.Values;
}
internal TextureHandle GetGlobal(int globalPropertyId)
{
TextureHandle h;
registeredGlobals.TryGetValue(globalPropertyId, out h);
return h;
}
///
/// Clears the shader bindings associated with the registered globals in the graph
///
/// This prevents later rendering logic from accidentally relying on stale shader bindings that were set
/// earlier during graph execution.
///
internal void ClearGlobalBindings()
{
// Set all the global texture shader bindings to the default black texture.
// This doesn't technically "clear" the shader bindings, but it's the closest we can do.
foreach (var globalTex in registeredGlobals)
{
m_RenderGraphContext.cmd.SetGlobalTexture(globalTex.Key, defaultResources.blackTexture);
}
}
}
///
/// Render Graph Scoped Profiling markers
///
[MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
public struct RenderGraphProfilingScope : IDisposable
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
ProfilingSampler m_Sampler;
RenderGraph m_RenderGraph;
bool m_Disposed;
#endif
///
/// Profiling Scope constructor
///
/// Render Graph used for this scope.
/// Profiling Sampler to be used for this scope.
public RenderGraphProfilingScope(RenderGraph renderGraph, ProfilingSampler sampler)
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
m_RenderGraph = renderGraph;
m_Sampler = sampler;
m_Disposed = false;
renderGraph.BeginProfilingSampler(sampler);
#endif
}
///
/// Dispose pattern implementation
///
public void Dispose()
{
Dispose(true);
}
// Protected implementation of Dispose pattern.
void Dispose(bool disposing)
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
if (m_Disposed)
return;
// As this is a struct, it could have been initialized using an empty constructor so we
// need to make sure `cmd` isn't null to avoid a crash. Switching to a class would fix
// this but will generate garbage on every frame (and this struct is used quite a lot).
if (disposing)
{
m_RenderGraph.EndProfilingSampler(m_Sampler);
}
m_Disposed = true;
#endif
}
}
}
#endif