GhostEngine Render Graph: major refactor & Unity RG ref

- Major architectural refactor for performance, extensibility, and feature completeness: resource pooling, pass culling, aliasing, and compilation caching.
- Introduces type-safe builder and context APIs, blackboard pattern, and unified resource management.
- Adds detailed documentation and cleans up obsolete files and APIs.
- Includes (commented) Unity Render Graph source for reference; not compiled, for parity and future extension.
This commit is contained in:
2026-01-11 23:43:17 +09:00
parent 87e315a588
commit 1fc9df1812
30 changed files with 7536 additions and 1545 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,598 @@
#if false
using System;
using System.Diagnostics;
using UnityEngine.Experimental.Rendering;
using static UnityEngine.Rendering.RenderGraphModule.RenderGraph;
namespace UnityEngine.Rendering.RenderGraphModule
{
// This is a class making it a struct wouldn't help as we pas it around as an interface which means it would be boxed/unboxed anyway
// Publicly this class has different faces to help the users with different pass types through type safety but internally
// we just have a single implementation for all builders
internal class RenderGraphBuilders : IBaseRenderGraphBuilder, IComputeRenderGraphBuilder, IRasterRenderGraphBuilder, IUnsafeRenderGraphBuilder
{
RenderGraphPass m_RenderPass;
RenderGraphResourceRegistry m_Resources;
RenderGraph m_RenderGraph;
bool m_Disposed;
public RenderGraphBuilders()
{
m_RenderPass = null;
m_Resources = null;
m_RenderGraph = null;
m_Disposed = true;
}
public void Setup(RenderGraphPass renderPass, RenderGraphResourceRegistry resources, RenderGraph renderGraph)
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
// If the object is not disposed yet this is an error as the pass is not finished (only in the dispose we register it with the rendergraph)
// This is likely cause by a user not doing a clean using and then forgetting to manually dispose the object.
if (m_Disposed != true)
{
throw new Exception(RenderGraph.RenderGraphExceptionMessages.k_UndisposedBuilderPreviousPass);
}
#endif
m_RenderPass = renderPass;
m_Resources = resources;
m_RenderGraph = renderGraph;
m_Disposed = false;
renderPass.useAllGlobalTextures = false;
if (renderPass.type == RenderGraphPassType.Raster)
{
CommandBuffer.ThrowOnSetRenderTarget = true;
}
}
public void EnableAsyncCompute(bool value)
{
m_RenderPass.EnableAsyncCompute(value);
}
public void AllowPassCulling(bool value)
{
// This pass cannot be culled if it allows global state modifications
if (value && m_RenderPass.allowGlobalState)
return;
m_RenderPass.AllowPassCulling(value);
}
public void AllowGlobalStateModification(bool value)
{
m_RenderPass.AllowGlobalState(value);
// This pass cannot be culled if it allows global state modifications
if (value)
{
AllowPassCulling(false);
}
}
/// <summary>
/// Enable foveated rendering for this pass.
/// </summary>
/// <param name="value">True to enable foveated rendering.</param>
public void EnableFoveatedRasterization(bool value)
{
m_RenderPass.EnableFoveatedRasterization(value);
}
public BufferHandle CreateTransientBuffer(in BufferDesc desc)
{
var result = m_Resources.CreateBuffer(desc, m_RenderPass.index);
UseTransientResource(result.handle);
return result;
}
public BufferHandle CreateTransientBuffer(in BufferHandle computebuffer)
{
ref readonly var desc = ref m_Resources.GetBufferResourceDesc(computebuffer.handle);
return CreateTransientBuffer(desc);
}
public TextureHandle CreateTransientTexture(in TextureDesc desc)
{
var result = m_Resources.CreateTexture(desc, m_RenderPass.index);
UseTransientResource(result.handle);
return result;
}
public TextureHandle CreateTransientTexture(in TextureHandle texture)
{
ref readonly var desc = ref m_Resources.GetTextureResourceDesc(texture.handle);
return CreateTransientTexture(desc);
}
public void GenerateDebugData(bool value)
{
m_RenderPass.GenerateDebugData(value);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (m_Disposed)
return;
try
{
if (disposing)
{
m_RenderGraph.RenderGraphState = RenderGraphState.RecordingGraph;
// Use all globals simply means this... we do a UseTexture on all globals so the pass has the correct dependencies.
// This of course goes to show how bad an idea shader-system wide globals really are dependency/lifetime tracking wise :-)
if (m_RenderPass.useAllGlobalTextures)
{
foreach (var texture in m_RenderGraph.AllGlobals())
{
if (texture.IsValid())
this.UseTexture(texture, AccessFlags.Read);
}
}
// Set globals on the graph fronted side so subsequent passes can have pass dependencies on these global texture handles
foreach (var t in m_RenderPass.setGlobalsList)
{
m_RenderGraph.SetGlobal(t.Item1, t.Item2);
}
}
}
finally
{
if (m_RenderPass.type == RenderGraphPassType.Raster)
{
CommandBuffer.ThrowOnSetRenderTarget = false;
}
m_RenderPass = null;
m_Resources = null;
m_RenderGraph = null;
m_Disposed = true;
}
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
private void CheckWriteTo(in ResourceHandle handle)
{
if (RenderGraph.enableValidityChecks)
{
// Write by design generates a new version of the resource. However
// you could in theory write to v2 of the resource while there is already
// a v3 so this write would then introduce a new v4 of the resource.
// This would mean a divergence in the versioning history subsequent versions based on v2 and other subsequent versions based on v3
// this would be very confusing as they are all still refered to by the same texture just different versions
// so we decide to disallow this. It can always be (at zero cost) handled by using a "Move" pass to move the divergent version
// so it's own texture resource which again has it's own single history of versions.
if (handle.IsVersioned)
{
var name = m_Resources.GetRenderGraphResourceName(handle);
throw new InvalidOperationException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {handle.type} at index {handle.index} - " + RenderGraph.RenderGraphExceptionMessages.k_WriteToVersionedResource);
}
if (m_RenderPass.IsWritten(handle))
{
// We bump the version and write count if you call USeResource with writing flags. So calling this several times
// would lead to the side effect of new versions for every call to UseResource leading to incorrect versions.
// In theory we could detect and ignore the second UseResource but we decided to just disallow is as it might also
// Stem from user confusion.
// It seems the most likely cause of such a situation would be something like:
// TextureHandle b = a;
// ...
// much much code in between, user lost track that a=b
// ...
// builder.WriteTexture(a)
// builder.WriteTexture(b)
// > Get this error they were probably thinking they were writing two separate outputs... but they are just two versions of resource 'a'
// where they can only differ between by careful management of versioned resources.
var name = m_Resources.GetRenderGraphResourceName(handle);
throw new InvalidOperationException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {handle.type} at index {handle.index} - " + RenderGraph.RenderGraphExceptionMessages.k_WriteToResourceTwice);
}
}
}
// Lifetime of a transient resource is one render graph pass
private ResourceHandle UseTransientResource(in ResourceHandle inputHandle)
{
CheckResource(inputHandle);
ResourceHandle versionedHandle = inputHandle.IsVersioned ? inputHandle : m_Resources.GetLatestVersionHandle(inputHandle);
// Transient resources are always considered written and read in the render graph pass where they are used
// Compiler will take it into account later, no need to add them to read and write lists
m_RenderPass.AddTransientResource(versionedHandle);
return versionedHandle;
}
private ResourceHandle UseResource(in ResourceHandle inputHandle, AccessFlags flags)
{
CheckResource(inputHandle);
bool discard = (flags & AccessFlags.Discard) != 0;
bool read = (flags & AccessFlags.Read) != 0;
bool write = (flags & AccessFlags.Write) != 0;
ResourceHandle versionedHandle = inputHandle.IsVersioned ? inputHandle : m_Resources.GetLatestVersionHandle(inputHandle);
// If we are not discarding the current version and its data, add a "read" dependency on it
// this is a bit of a misnomer it really means more like "Preserve existing content or read"
if (!discard)
{
m_Resources.IncrementReadCount(versionedHandle);
m_RenderPass.AddResourceRead(versionedHandle);
// Implicit read - not user-specified
if (!read)
{
m_RenderPass.implicitReadsList.Add(versionedHandle);
}
}
else
{
// We are discarding it but we still read it, so we add a dependency on version "0" of this resource
if (read)
{
var zeroVersionHandle = m_Resources.GetZeroVersionHandle(versionedHandle);
m_Resources.IncrementReadCount(zeroVersionHandle);
m_RenderPass.AddResourceRead(zeroVersionHandle);
}
}
if (write)
{
CheckWriteTo(inputHandle);
// New versioned written by this render graph pass
versionedHandle = m_Resources.IncrementWriteCount(inputHandle);
m_RenderPass.AddResourceWrite(versionedHandle);
}
return versionedHandle;
}
public BufferHandle UseBuffer(in BufferHandle input, AccessFlags flags)
{
UseResource(input.handle, flags);
return input;
}
// UseTexture and SetRenderAttachment are currently forced to be mutually exclusive in the same pass
// check this.
// We currently ignore the version. In theory there might be some cases that are actually allowed with versioning
// for ample UseTexture(myTexV1, read) UseFragment(myTexV2, ReadWrite) as they are different versions
// but for now we don't allow any of that.
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
private void CheckNotUseFragment(in TextureHandle tex)
{
if (RenderGraph.enableValidityChecks)
{
bool usedAsFragment = (m_RenderPass.depthAccess.textureHandle.IsValid() && m_RenderPass.depthAccess.textureHandle.handle.index == tex.handle.index);
if (!usedAsFragment)
{
for (int i = 0; i <= m_RenderPass.colorBufferMaxIndex; i++)
{
if (m_RenderPass.colorBufferAccess[i].textureHandle.IsValid() && m_RenderPass.colorBufferAccess[i].textureHandle.handle.index == tex.handle.index)
{
usedAsFragment = true;
break;
}
}
}
if (usedAsFragment)
{
var name = m_Resources.GetRenderGraphResourceName(tex.handle);
throw new ArgumentException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {tex.handle.type} at index {tex.handle.index} - " + RenderGraph.RenderGraphExceptionMessages.k_TextureAlreadyBeingUsedThroughSetAttachment);
}
}
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
private void CheckTextureUVOriginIsValid(in ResourceHandle handle, TextureResource texRes)
{
if (texRes.textureUVOrigin == TextureUVOriginSelection.TopLeft)
{
var name = m_Resources.GetRenderGraphResourceName(handle);
throw new ArgumentException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type `{handle.type}` at index `{handle.index}` - " + RenderGraph.RenderGraphExceptionMessages.IncompatibleTextureUVOriginUseTexture(texRes.textureUVOrigin));
}
}
public void UseTexture(in TextureHandle input, AccessFlags flags)
{
CheckNotUseFragment(input);
UseResource(input.handle, flags);
if ((flags & AccessFlags.Read) == AccessFlags.Read)
{
if (m_RenderGraph.renderTextureUVOriginStrategy == RenderTextureUVOriginStrategy.PropagateAttachmentOrientation)
{
TextureResource texRes = m_Resources.GetTextureResource(input.handle);
CheckTextureUVOriginIsValid(input.handle, texRes);
texRes.textureUVOrigin = TextureUVOriginSelection.BottomLeft;
}
}
}
public void UseGlobalTexture(int propertyId, AccessFlags flags)
{
var h = m_RenderGraph.GetGlobal(propertyId);
if (h.IsValid())
{
UseTexture(h, flags);
}
else
{
// rose test this path
var name = m_Resources.GetRenderGraphResourceName(h.handle);
throw new ArgumentException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {h.handle.type} at index {h.handle.index} - " + RenderGraph.RenderGraphExceptionMessages.NoGlobalTextureAtPropertyID(propertyId));
}
}
public void UseAllGlobalTextures(bool enable)
{
m_RenderPass.useAllGlobalTextures = enable;
}
public void SetGlobalTextureAfterPass(in TextureHandle input, int propertyId)
{
m_RenderPass.setGlobalsList.Add(ValueTuple.Create(input, propertyId));
}
// Shared validation between SetRenderAttachment/SetRenderAttachmentDepth
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
private void CheckUseFragment(in TextureHandle tex, bool isDepth)
{
if (RenderGraph.enableValidityChecks)
{
// We ignore the version as we don't allow mixing UseTexture/UseFragment between different versions
// even though it should theoretically work (and we might do so in the future) for now we're overly strict.
bool alreadyUsed = false;
//TODO: Check grab textures here and allow if it's grabbed. For now
// SetRenderAttachment()
// UseTexture(grab)
// will work but not the other way around
for (int i = 0; i < m_RenderPass.resourceReadLists[tex.handle.iType].Count; i++)
{
if (m_RenderPass.resourceReadLists[tex.handle.iType][i].index == tex.handle.index)
{
alreadyUsed = true;
break;
}
}
for (int i = 0; i < m_RenderPass.resourceWriteLists[tex.handle.iType].Count; i++)
{
if (m_RenderPass.resourceWriteLists[tex.handle.iType][i].index == tex.handle.index)
{
alreadyUsed = true;
break;
}
}
if (alreadyUsed)
{
var name = m_Resources.GetRenderGraphResourceName(tex.handle);
throw new InvalidOperationException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {tex.handle.type} at index {tex.handle.index} - " + RenderGraph.RenderGraphExceptionMessages.k_SetRenderAttachmentTextureAlreadyUsed);
}
m_Resources.GetRenderTargetInfo(tex.handle, out var info);
bool isDepthFormat = GraphicsFormatUtility.IsDepthFormat(info.format);
bool formatMismatch = isDepth != isDepthFormat;
if (formatMismatch)
{
var name = m_Resources.GetRenderGraphResourceName(tex.handle);
var errorMsg = isDepth
? RenderGraph.RenderGraphExceptionMessages.UseDepthWithColorFormat(info.format)
: RenderGraph.RenderGraphExceptionMessages.k_SetRenderAttachmentOnDepthTexture;
throw new InvalidOperationException(
$"In pass '{m_RenderPass.name}' when trying to use resource '{name}' " +
$"of type {tex.handle.type} at index {tex.handle.index} - {errorMsg}");
}
if (m_RenderGraph.renderTextureUVOriginStrategy == RenderTextureUVOriginStrategy.PropagateAttachmentOrientation)
{
var texResource = m_Resources.GetTextureResource(tex.handle);
TextureResource checkTexResource = null;
for (int i = 0; i < m_RenderPass.fragmentInputMaxIndex + 1; ++i)
{
if (m_RenderPass.fragmentInputAccess[i].textureHandle.IsValid())
{
ref readonly TextureHandle texCheck = ref m_RenderPass.fragmentInputAccess[i].textureHandle;
checkTexResource = m_Resources.GetTextureResource(texCheck.handle);
if (texResource.textureUVOrigin != TextureUVOriginSelection.Unknown && checkTexResource.textureUVOrigin != TextureUVOriginSelection.Unknown && texResource.textureUVOrigin != checkTexResource.textureUVOrigin)
{
var name = m_Resources.GetRenderGraphResourceName(tex.handle);
var checkName = m_Resources.GetRenderGraphResourceName(texCheck.handle);
throw new InvalidOperationException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {tex.handle.type} at index {tex.handle.index} - " + RenderGraph.RenderGraphExceptionMessages.IncompatibleTextureUVOrigin(texResource.textureUVOrigin, "input", checkName, texCheck.handle.type, texCheck.handle.index, checkTexResource.textureUVOrigin));
}
}
}
for (int i = 0; i < m_RenderPass.colorBufferMaxIndex + 1; ++i)
{
if (m_RenderPass.colorBufferAccess[i].textureHandle.IsValid())
{
ref readonly TextureHandle texCheck = ref m_RenderPass.colorBufferAccess[i].textureHandle;
checkTexResource = m_Resources.GetTextureResource(texCheck.handle);
if (texResource.textureUVOrigin != TextureUVOriginSelection.Unknown && checkTexResource.textureUVOrigin != TextureUVOriginSelection.Unknown && texResource.textureUVOrigin != checkTexResource.textureUVOrigin)
{
var name = m_Resources.GetRenderGraphResourceName(tex.handle);
var checkName = m_Resources.GetRenderGraphResourceName(texCheck.handle);
throw new InvalidOperationException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {tex.handle.type} at index {tex.handle.index} - " + RenderGraph.RenderGraphExceptionMessages.IncompatibleTextureUVOrigin(texResource.textureUVOrigin, "render", checkName, texCheck.handle.type, texCheck.handle.index, checkTexResource.textureUVOrigin));
}
}
}
if (!isDepth && m_RenderPass.depthAccess.textureHandle.IsValid())
{
TextureHandle texCheck = m_RenderPass.depthAccess.textureHandle;
checkTexResource = m_Resources.GetTextureResource(texCheck.handle);
if (texResource.textureUVOrigin != TextureUVOriginSelection.Unknown && checkTexResource.textureUVOrigin != TextureUVOriginSelection.Unknown && texResource.textureUVOrigin != checkTexResource.textureUVOrigin)
{
var name = m_Resources.GetRenderGraphResourceName(tex.handle);
var checkName = m_Resources.GetRenderGraphResourceName(texCheck.handle);
throw new InvalidOperationException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {tex.handle.type} at index {tex.handle.index} - " + RenderGraph.RenderGraphExceptionMessages.IncompatibleTextureUVOrigin(texResource.textureUVOrigin, "depth", checkName, texCheck.handle.type, texCheck.handle.index, checkTexResource.textureUVOrigin));
}
}
}
foreach (var globalTex in m_RenderPass.setGlobalsList)
{
if (globalTex.Item1.handle.index == tex.handle.index)
{
var name = m_Resources.GetRenderGraphResourceName(tex.handle);
throw new InvalidOperationException($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {tex.handle.type} at index {tex.handle.index} - " + RenderGraph.RenderGraphExceptionMessages.k_SetRenderAttachmentOnGlobalTexture);
}
}
}
}
public void SetRenderAttachment(TextureHandle tex, int index, AccessFlags flags, int mipLevel, int depthSlice)
{
CheckUseFragment(tex, false);
var versionedTextureHandle = new TextureHandle(UseResource(tex.handle, flags));
m_RenderPass.SetColorBufferRaw(versionedTextureHandle, index, flags, mipLevel, depthSlice);
}
public void SetInputAttachment(TextureHandle tex, int index, AccessFlags flags, int mipLevel, int depthSlice)
{
CheckFrameBufferFetchEmulationIsSupported(tex);
CheckUseFragment(tex, false);
var versionedTextureHandle = new TextureHandle(UseResource(tex.handle, flags));
m_RenderPass.SetFragmentInputRaw(versionedTextureHandle, index, flags, mipLevel, depthSlice);
}
public void SetRenderAttachmentDepth(TextureHandle tex, AccessFlags flags, int mipLevel, int depthSlice)
{
CheckUseFragment(tex, true);
var versionedTextureHandle = new TextureHandle(UseResource(tex.handle, flags));
m_RenderPass.SetDepthBufferRaw(versionedTextureHandle, flags, mipLevel, depthSlice);
}
public TextureHandle SetRandomAccessAttachment(TextureHandle input, int index, AccessFlags flags = AccessFlags.Read)
{
CheckNotUseFragment(input);
ResourceHandle result = UseResource(input.handle, flags);
m_RenderPass.SetRandomWriteResourceRaw(result, index, false, flags);
return input;
}
public void SetShadingRateImageAttachment(in TextureHandle tex)
{
CheckNotUseFragment(tex);
var versionedTextureHandle = new TextureHandle(UseResource(tex.handle, AccessFlags.Read));
m_RenderPass.SetShadingRateImageRaw(versionedTextureHandle);
}
public BufferHandle UseBufferRandomAccess(BufferHandle input, int index, AccessFlags flags = AccessFlags.Read)
{
var h = UseBuffer(input, flags);
m_RenderPass.SetRandomWriteResourceRaw(h.handle, index, true, flags);
return input;
}
public BufferHandle UseBufferRandomAccess(BufferHandle input, int index, bool preserveCounterValue, AccessFlags flags = AccessFlags.Read)
{
var h = UseBuffer(input, flags);
m_RenderPass.SetRandomWriteResourceRaw(h.handle, index, preserveCounterValue, flags);
return input;
}
public void SetRenderFunc<PassData>(BaseRenderFunc<PassData, ComputeGraphContext> renderFunc) where PassData : class, new()
{
((ComputeRenderGraphPass<PassData>)m_RenderPass).renderFunc = renderFunc;
}
public void SetRenderFunc<PassData>(BaseRenderFunc<PassData, RasterGraphContext> renderFunc) where PassData : class, new()
{
((RasterRenderGraphPass<PassData>)m_RenderPass).renderFunc = renderFunc;
}
public void SetRenderFunc<PassData>(BaseRenderFunc<PassData, UnsafeGraphContext> renderFunc) where PassData : class, new()
{
((UnsafeRenderGraphPass<PassData>)m_RenderPass).renderFunc = renderFunc;
}
public void UseRendererList(in RendererListHandle input)
{
m_RenderPass.UseRendererList(input);
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
void CheckResource(in ResourceHandle res, bool checkTransientReadWrite = false)
{
if (RenderGraph.enableValidityChecks)
{
if (res.IsValid())
{
int transientIndex = m_Resources.GetRenderGraphResourceTransientIndex(res);
// We have dontCheckTransientReadWrite here because users may want to use UseColorBuffer/UseDepthBuffer API to benefit from render target auto binding. In this case we don't want to raise the error.
if (transientIndex == m_RenderPass.index && checkTransientReadWrite)
{
var name = m_Resources.GetRenderGraphResourceName(res);
Debug.LogError($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {res.type} at index {res.index} - " + RenderGraph.RenderGraphExceptionMessages.k_ReadWriteTransient);
}
if (transientIndex != -1 && transientIndex != m_RenderPass.index)
{
var name = m_Resources.GetRenderGraphResourceName(res);
throw new ArgumentException(
$"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {res.type} at index {res.index} - " +
RenderGraph.RenderGraphExceptionMessages.UseTransientTextureInWrongPass(transientIndex));
}
}
else
{
var name = m_Resources.GetRenderGraphResourceName(res);
throw new Exception($"In pass '{m_RenderPass.name}' when trying to use resource '{name}' of type {res.type} at index {res.index} - " + RenderGraph.RenderGraphExceptionMessages.k_InvalidResource);
}
}
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
void CheckFrameBufferFetchEmulationIsSupported(in TextureHandle tex)
{
if (enableValidityChecks)
{
if (!Util.RenderGraphUtils.IsFramebufferFetchEmulationMSAASupportedOnCurrentPlatform())
{
var sourceInfo = m_RenderGraph.GetRenderTargetInfo(tex);
if (sourceInfo.bindMS)
throw new InvalidOperationException($"This API is not supported with MSAA attachments on the current platform: {SystemInfo.graphicsDeviceType}");
}
}
}
public void SetShadingRateFragmentSize(ShadingRateFragmentSize shadingRateFragmentSize)
{
m_RenderPass.SetShadingRateFragmentSize(shadingRateFragmentSize);
}
public void SetShadingRateCombiner(ShadingRateCombinerStage stage, ShadingRateCombiner combiner)
{
m_RenderPass.SetShadingRateCombiner(stage, combiner);
}
public void SetExtendedFeatureFlags(ExtendedFeatureFlags extendedFeatureFlags)
{
m_RenderPass.SetExtendedFeatureFlags(extendedFeatureFlags);
}
}
}
#endif

View File

@@ -0,0 +1,752 @@
#if false
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace UnityEngine.Rendering.RenderGraphModule
{
[DebuggerDisplay("RenderPass: {name} (Index:{index} Async:{enableAsyncCompute})")]
abstract class RenderGraphPass
{
public abstract void Execute(InternalRenderGraphContext renderGraphContext);
public abstract void Release(RenderGraphObjectPool pool);
public abstract bool HasRenderFunc();
public abstract int GetRenderFuncHash();
public string name { get; protected set; }
public int index { get; protected set; }
public RenderGraphPassType type { get; internal set; }
public ProfilingSampler customSampler { get; protected set; }
public bool enableAsyncCompute { get; protected set; }
public bool allowPassCulling { get; protected set; }
public bool allowGlobalState { get; protected set; }
public bool enableFoveatedRasterization { get; protected set; }
public ExtendedFeatureFlags extendedFeatureFlags { get; protected set; }
// Before using the AccessFlags use resourceHandle.isValid()
// to make sure that the data in the colorBuffer/fragmentInput/randomAccessResource buffers are up to date
public TextureAccess depthAccess { get; protected set; }
public TextureAccess[] colorBufferAccess { get; protected set; } = new TextureAccess[RenderGraph.kMaxMRTCount];
public int colorBufferMaxIndex { get; protected set; } = -1;
public bool hasShadingRateImage { get; protected set; }
public TextureAccess shadingRateAccess { get; protected set; }
public bool hasShadingRateStates { get; protected set; }
public ShadingRateFragmentSize shadingRateFragmentSize { get; protected set; }
public ShadingRateCombiner primitiveShadingRateCombiner { get; protected set; }
public ShadingRateCombiner fragmentShadingRateCombiner { get; protected set; }
// Used by native pass compiler only
public TextureAccess[] fragmentInputAccess { get; protected set; } = new TextureAccess[RenderGraph.kMaxMRTCount];
public int fragmentInputMaxIndex { get; protected set; } = -1;
public struct RandomWriteResourceInfo
{
public ResourceHandle h;
public bool preserveCounterValue;
}
// This list can contain both texture and buffer resources based on their binding index.
public RandomWriteResourceInfo[] randomAccessResource { get; protected set; } = new RandomWriteResourceInfo[RenderGraph.kMaxMRTCount];
public int randomAccessResourceMaxIndex { get; protected set; } = -1;
public bool generateDebugData { get; protected set; }
public bool allowRendererListCulling { get; protected set; }
public List<ResourceHandle>[] resourceReadLists = new List<ResourceHandle>[(int)RenderGraphResourceType.Count];
public List<ResourceHandle>[] resourceWriteLists = new List<ResourceHandle>[(int)RenderGraphResourceType.Count];
public List<ResourceHandle>[] transientResourceList = new List<ResourceHandle>[(int)RenderGraphResourceType.Count];
public List<RendererListHandle> usedRendererListList = new List<RendererListHandle>();
public List<ValueTuple<TextureHandle, int>> setGlobalsList = new List<ValueTuple<TextureHandle, int>>();
public bool useAllGlobalTextures;
public List<ResourceHandle> implicitReadsList = new List<ResourceHandle>();
#if UNITY_EDITOR || DEVELOPMENT_BUILD
public RenderGraph.DebugData.PassScriptInfo debugScriptInfo { get; set; }
#endif
public RenderGraphPass()
{
for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i)
{
resourceReadLists[i] = new List<ResourceHandle>();
resourceWriteLists[i] = new List<ResourceHandle>();
transientResourceList[i] = new List<ResourceHandle>();
}
}
public void Clear()
{
name = "";
index = -1;
customSampler = null;
for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i)
{
resourceReadLists[i].Clear();
resourceWriteLists[i].Clear();
transientResourceList[i].Clear();
}
usedRendererListList.Clear();
setGlobalsList.Clear();
useAllGlobalTextures = false;
implicitReadsList.Clear();
enableAsyncCompute = false;
allowPassCulling = true;
allowRendererListCulling = true;
allowGlobalState = false;
enableFoveatedRasterization = false;
generateDebugData = true;
// Invalidate the buffers without clearing them, as it is too costly
// Use IsValid() to make sure that the data in the colorBuffer/fragmentInput/randomAccessResource buffers are up to date
colorBufferMaxIndex = -1;
fragmentInputMaxIndex = -1;
randomAccessResourceMaxIndex = -1;
// We do not need to clear colorBufferAccess and fragmentInputAccess as we have the colorBufferMaxIndex and fragmentInputMaxIndex
// which are reset above so we only clear depthAccess here.
depthAccess = default(TextureAccess);
hasShadingRateImage = false;
hasShadingRateStates = false;
shadingRateFragmentSize = ShadingRateFragmentSize.FragmentSize1x1;
primitiveShadingRateCombiner = ShadingRateCombiner.Keep;
fragmentShadingRateCombiner = ShadingRateCombiner.Keep;
// Invalidate ExtendedFeatureFlags
extendedFeatureFlags = ExtendedFeatureFlags.None;
}
// Check if the pass has any render targets set-up
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasRenderAttachments()
{
return depthAccess.textureHandle.IsValid() || colorBufferAccess[0].textureHandle.IsValid() || colorBufferMaxIndex > 0;
}
// Checks if the resource is involved in this pass
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsTransient(in ResourceHandle res)
{
// Versioning doesn't matter much for transient resources as they are only used within a single pass
for (int i = 0; i < transientResourceList[res.iType].Count; i++)
{
if (transientResourceList[res.iType][i].index == res.index)
{
return true;
}
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsWritten(in ResourceHandle res)
{
// You can only ever write to the latest version so we ignore it when looking in the list
for (int i = 0; i < resourceWriteLists[res.iType].Count; i++)
{
if (resourceWriteLists[res.iType][i].index == res.index)
{
return true;
}
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsRead(in ResourceHandle res)
{
if (res.IsVersioned)
{
return resourceReadLists[res.iType].Contains(res);
}
else
{
// Just look if we are reading any version of this texture.
// Note that in theory this pass could read from several versions of the same texture
// e.g. ColorBuffer,v3 and ColorBuffer,v5 so this check is always conservative
for (int i = 0; i < resourceReadLists[res.iType].Count; i++)
{
if (resourceReadLists[res.iType][i].index == res.index)
{
return true;
}
}
return false;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsAttachment(in TextureHandle res)
{
// We ignore the version when checking, if any version is used it is considered a match
if (depthAccess.textureHandle.IsValid() && depthAccess.textureHandle.handle.index == res.handle.index) return true;
for (int i = 0; i < colorBufferAccess.Length; i++)
{
if (colorBufferAccess[i].textureHandle.IsValid() && colorBufferAccess[i].textureHandle.handle.index == res.handle.index) return true;
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddResourceWrite(in ResourceHandle res)
{
resourceWriteLists[res.iType].Add(res);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddResourceRead(in ResourceHandle res)
{
resourceReadLists[res.iType].Add(res);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddTransientResource(in ResourceHandle res)
{
transientResourceList[res.iType].Add(res);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UseRendererList(in RendererListHandle rendererList)
{
usedRendererListList.Add(rendererList);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnableAsyncCompute(bool value)
{
enableAsyncCompute = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AllowPassCulling(bool value)
{
allowPassCulling = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnableFoveatedRasterization(bool value)
{
enableFoveatedRasterization = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AllowRendererListCulling(bool value)
{
allowRendererListCulling = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AllowGlobalState(bool value)
{
allowGlobalState = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void GenerateDebugData(bool value)
{
generateDebugData = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetColorBuffer(in TextureHandle resource, int index)
{
Debug.Assert(index < RenderGraph.kMaxMRTCount && index >= 0);
colorBufferMaxIndex = Math.Max(colorBufferMaxIndex, index);
colorBufferAccess[index] = new TextureAccess(colorBufferAccess[index], resource);
AddResourceWrite(resource.handle);
}
// Sets up the color buffer for this pass but not any resource Read/Writes for it
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetColorBufferRaw(in TextureHandle resource, int index, AccessFlags accessFlags, int mipLevel, int depthSlice)
{
Debug.Assert(index < RenderGraph.kMaxMRTCount && index >= 0);
if (colorBufferAccess[index].textureHandle.handle.Equals(resource.handle) || !colorBufferAccess[index].textureHandle.IsValid())
{
colorBufferMaxIndex = Math.Max(colorBufferMaxIndex, index);
colorBufferAccess[index] = new TextureAccess(resource, accessFlags, mipLevel, depthSlice);
}
else
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
// You tried to do SetRenderAttachment(tex1, 1, ..); SetRenderAttachment(tex2, 1, ..); that is not valid for different textures on the same index
throw new InvalidOperationException(
$"In pass '{name}' when trying to call SetRenderAttachment with resource of type {resource.handle.type} at index {index} - " +
RenderGraph.RenderGraphExceptionMessages.k_MoreThanOneResourceForMRTIndex);
#endif
}
}
// Sets up the color buffer for this pass but not any resource Read/Writes for it
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetFragmentInputRaw(in TextureHandle resource, int index, AccessFlags accessFlags, int mipLevel, int depthSlice)
{
Debug.Assert(index < RenderGraph.kMaxMRTCount && index >= 0);
if (fragmentInputAccess[index].textureHandle.handle.Equals(resource.handle) || !fragmentInputAccess[index].textureHandle.IsValid())
{
fragmentInputMaxIndex = Math.Max(fragmentInputMaxIndex, index);
fragmentInputAccess[index] = new TextureAccess(resource, accessFlags, mipLevel, depthSlice);
}
else
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
// You tried to do SetRenderAttachment(tex1, 1, ..); SetRenderAttachment(tex2, 1, ..); that is not valid for different textures on the same index
throw new InvalidOperationException(
$"In pass '{name}' when trying to call SetInputAttachment with resource of type {resource.handle.type} at index {index} - " +
RenderGraph.RenderGraphExceptionMessages.k_MoreThanOneTextureForFragInputIndex);
#endif
}
}
// Sets up the color buffer for this pass but not any resource Read/Writes for it
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetRandomWriteResourceRaw(in ResourceHandle resource, int index, bool preserveCounterValue, AccessFlags accessFlags)
{
Debug.Assert(index < RenderGraph.kMaxMRTCount && index >= 0);
if (randomAccessResource[index].h.Equals(resource) || !randomAccessResource[index].h.IsValid())
{
randomAccessResourceMaxIndex = Math.Max(randomAccessResourceMaxIndex, index);
ref var info = ref randomAccessResource[index];
info.h = resource;
info.preserveCounterValue = preserveCounterValue;
}
else
{
// You tried to do SetRenderAttachment(tex1, 1, ..); SetRenderAttachment(tex2, 1, ..); that is not valid for different textures on the same index
throw new InvalidOperationException(
$"In pass '{name}' when trying to call SetRandomAccessAttachment/UseBufferRandomAccess with resource of type {resource.type} at index {index} - " +
RenderGraph.RenderGraphExceptionMessages.k_MoreThanOneTextureRandomWriteInputIndex);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetDepthBuffer(in TextureHandle resource, DepthAccess flags)
{
depthAccess = new TextureAccess(resource, (AccessFlags)flags, 0, 0);
if ((flags & DepthAccess.Read) != 0)
AddResourceRead(resource.handle);
if ((flags & DepthAccess.Write) != 0)
AddResourceWrite(resource.handle);
}
// Sets up the depth buffer for this pass but not any resource Read/Writes for it
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetDepthBufferRaw(in TextureHandle resource, AccessFlags accessFlags, int mipLevel, int depthSlice)
{
// If no depth buffer yet or if it is the same one as the previous one, allow the call otherwise log an error.
if (depthAccess.textureHandle.handle.Equals(resource.handle) || !depthAccess.textureHandle.IsValid())
{
depthAccess = new TextureAccess(resource, accessFlags, mipLevel, depthSlice);
}
#if DEVELOPMENT_BUILD || UNITY_EDITOR
else
{
throw new InvalidOperationException(
$"In pass '{name}' when trying to call SetRenderAttachmentDepth with resource of type {resource.handle.type} at index {index} - " +
RenderGraph.RenderGraphExceptionMessages.k_MultipleDepthTextures);
}
#endif
}
// Here we want to keep computation to a minimum and only hash what will influence NRP compiler: Pass merging, load/store actions etc.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void ComputeTextureHash(ref HashFNV1A32 generator, in ResourceHandle handle, RenderGraphResourceRegistry resources)
{
if (handle.index == 0)
return;
if (resources.IsRenderGraphResourceImported(handle))
{
var res = resources.GetTextureResource(handle);
var graphicsResource = res.graphicsResource;
ref readonly var desc = ref res.desc;
var externalTexture = graphicsResource.externalTexture;
if (externalTexture != null) // External texture
{
generator.Append((int) externalTexture.graphicsFormat);
generator.Append((int) externalTexture.dimension);
generator.Append(externalTexture.width);
generator.Append(externalTexture.height);
if (externalTexture is RenderTexture externalRT)
generator.Append(externalRT.antiAliasing);
}
else if (graphicsResource.rt != null) // Regular RTHandle
{
var rt = graphicsResource.rt;
generator.Append((int) rt.graphicsFormat);
generator.Append((int) rt.dimension);
generator.Append(rt.antiAliasing);
if (graphicsResource.useScaling)
if (graphicsResource.scaleFunc != null)
generator.Append(DelegateHashCodeUtils.GetFuncHashCode(graphicsResource.scaleFunc));
else
generator.Append(graphicsResource.scaleFactor);
else
{
generator.Append(rt.width);
generator.Append(rt.height);
}
}
else if (graphicsResource.nameID != default) // External RTI
{
// The only info we have is from the provided desc upon importing.
generator.Append((int) desc.format);
generator.Append((int) desc.dimension);
generator.Append((int) desc.msaaSamples);
generator.Append(desc.width);
generator.Append(desc.height);
}
// Add the clear/discard buffer flags to the hash (used in all the cases above)
generator.Append(desc.clearBuffer);
generator.Append(desc.discardBuffer);
}
else
{
ref readonly var desc = ref resources.GetTextureResourceDesc(handle);
generator.Append((int) desc.format);
generator.Append((int) desc.dimension);
generator.Append((int) desc.msaaSamples);
generator.Append(desc.clearBuffer);
generator.Append(desc.discardBuffer);
switch (desc.sizeMode)
{
case TextureSizeMode.Explicit:
generator.Append(desc.width);
generator.Append(desc.height);
break;
case TextureSizeMode.Scale:
generator.Append(desc.scale);
break;
case TextureSizeMode.Functor:
generator.Append(DelegateHashCodeUtils.GetFuncHashCode(desc.func));
break;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void ComputeHashForTextureAccess(ref HashFNV1A32 generator, in ResourceHandle handle, in TextureAccess textureAccess)
{
generator.Append(handle.index);
generator.Append((int) textureAccess.flags);
generator.Append(textureAccess.mipLevel);
generator.Append(textureAccess.depthSlice);
}
// This function is performance sensitive.
// Avoid mass function calls to get the hashCode and compute locally instead.
public void ComputeHash(ref HashFNV1A32 generator, RenderGraphResourceRegistry resources)
{
generator.Append((int) type);
generator.Append(enableAsyncCompute);
generator.Append(allowPassCulling);
generator.Append(allowGlobalState);
generator.Append(enableFoveatedRasterization);
generator.Append(extendedFeatureFlags);
var depthHandle = depthAccess.textureHandle.handle;
if (depthHandle.IsValid())
{
ComputeTextureHash(ref generator, depthHandle, resources);
ComputeHashForTextureAccess(ref generator, depthHandle, depthAccess);
}
for (int i = 0; i < colorBufferMaxIndex + 1; ++i)
{
var colorBufferAccessElement = colorBufferAccess[i];
var handle = colorBufferAccessElement.textureHandle.handle;
if (!handle.IsValid())
continue;
ComputeTextureHash(ref generator, handle, resources);
ComputeHashForTextureAccess(ref generator, handle, colorBufferAccessElement);
}
generator.Append(colorBufferMaxIndex);
generator.Append(hasShadingRateImage);
if (hasShadingRateImage)
{
var handle = shadingRateAccess.textureHandle.handle;
if (handle.IsValid())
{
ComputeTextureHash(ref generator, handle, resources);
ComputeHashForTextureAccess(ref generator, handle, shadingRateAccess);
}
}
generator.Append(hasShadingRateStates);
generator.Append((int)shadingRateFragmentSize);
generator.Append((int)primitiveShadingRateCombiner);
generator.Append((int)fragmentShadingRateCombiner);
for (int i = 0; i < fragmentInputMaxIndex + 1; ++i)
{
var fragmentInputAccessElement = fragmentInputAccess[i];
var handle = fragmentInputAccessElement.textureHandle.handle;
if (!handle.IsValid())
continue;
ComputeTextureHash(ref generator, handle, resources);
ComputeHashForTextureAccess(ref generator, handle, fragmentInputAccessElement);
}
for (int i = 0; i < randomAccessResourceMaxIndex + 1; ++i)
{
var rar = randomAccessResource[i];
if (!rar.h.IsValid())
continue;
generator.Append(rar.h.index);
generator.Append(rar.preserveCounterValue);
}
generator.Append(randomAccessResourceMaxIndex);
generator.Append(fragmentInputMaxIndex);
generator.Append(generateDebugData);
generator.Append(allowRendererListCulling);
for (int resType = 0; resType < (int)RenderGraphResourceType.Count; resType++)
{
var resourceReads = resourceReadLists[resType];
var resourceReadsCount = resourceReads.Count;
for (int i = 0; i < resourceReadsCount; ++i)
generator.Append(resourceReads[i].index);
var resourceWrites = resourceWriteLists[resType];
var resourceWritesCount = resourceWrites.Count;
for (int i = 0; i < resourceWritesCount; ++i)
generator.Append(resourceWrites[i].index);
var resourceTransient = transientResourceList[resType];
var resourceTransientCount = resourceTransient.Count;
for (int i = 0; i < resourceTransientCount; ++i)
generator.Append(resourceTransient[i].index);
}
var usedRendererListListCount = usedRendererListList.Count;
for (int i = 0; i < usedRendererListListCount; ++i)
generator.Append(usedRendererListList[i].handle);
var setGlobalsListCount = setGlobalsList.Count;
for (int i = 0; i < setGlobalsListCount; ++i)
{
var global = setGlobalsList[i];
generator.Append(global.Item1.handle.index);
generator.Append(global.Item2);
}
generator.Append(useAllGlobalTextures);
var implicitReadsListCount = implicitReadsList.Count;
for (int i = 0; i < implicitReadsListCount; ++i)
generator.Append(implicitReadsList[i].index);
generator.Append(GetRenderFuncHash());
}
public void SetShadingRateImageRaw(in TextureHandle shadingRateImage)
{
if (ShadingRateInfo.supportsPerImageTile)
{
hasShadingRateImage = true;
// shading rate image access flag is always read, only 1 mip and 1 slice
shadingRateAccess = new TextureAccess(shadingRateImage, AccessFlags.Read, 0, 0);
}
}
public void SetShadingRateImage(in TextureHandle shadingRateImage, AccessFlags accessFlags, int mipLevel, int depthSlice)
{
if (ShadingRateInfo.supportsPerImageTile)
{
hasShadingRateImage = true;
shadingRateAccess = new TextureAccess(shadingRateImage, accessFlags, mipLevel, depthSlice);
AddResourceRead(shadingRateAccess.textureHandle.handle);
}
}
public void SetShadingRateFragmentSize(ShadingRateFragmentSize shadingRateFragmentSize)
{
if (ShadingRateInfo.supportsPerDrawCall)
{
hasShadingRateStates = true;
this.shadingRateFragmentSize = shadingRateFragmentSize;
}
}
public void SetShadingRateCombiner(ShadingRateCombinerStage stage, ShadingRateCombiner combiner)
{
if (ShadingRateInfo.supportsPerImageTile)
{
switch (stage)
{
case ShadingRateCombinerStage.Primitive:
hasShadingRateStates = true;
primitiveShadingRateCombiner = combiner;
break;
case ShadingRateCombinerStage.Fragment:
hasShadingRateStates = true;
fragmentShadingRateCombiner = combiner;
break;
}
}
}
public void SetExtendedFeatureFlags(ExtendedFeatureFlags value)
{
extendedFeatureFlags |= value;
}
}
// This used to have an extra generic argument 'RenderGraphContext' abstracting the context and avoiding
// the RenderGraphPass/ComputeRenderGraphPass/RasterRenderGraphPass/UnsafeRenderGraphPass classes below
// but this confuses IL2CPP and causes garbage when boxing the context created (even though they are structs)
[DebuggerDisplay("RenderPass: {name} (Index:{index} Async:{enableAsyncCompute})")]
internal abstract class BaseRenderGraphPass<PassData, TRenderGraphContext> : RenderGraphPass
where PassData : class, new()
{
internal PassData data;
internal BaseRenderFunc<PassData, TRenderGraphContext> renderFunc;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Initialize(int passIndex, PassData passData, string passName, RenderGraphPassType passType, ProfilingSampler sampler)
{
Clear();
index = passIndex;
data = passData;
name = passName;
type = passType;
customSampler = sampler;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Release(RenderGraphObjectPool pool)
{
pool.Release(data);
data = null;
renderFunc = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool HasRenderFunc()
{
return renderFunc != null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetRenderFuncHash()
{
return renderFunc != null ? DelegateHashCodeUtils.GetFuncHashCode(renderFunc) : 0;
}
}
[DebuggerDisplay("RenderPass: {name} (Index:{index} Async:{enableAsyncCompute})")]
[Obsolete("RenderGraphPass is deprecated, use RasterRenderGraphPass/ComputeRenderGraphPass/UnsafeRenderGraphPass instead.")]
internal sealed class RenderGraphPass<PassData> : BaseRenderGraphPass<PassData, RenderGraphContext>
where PassData : class, new()
{
internal static RenderGraphContext c = new RenderGraphContext();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Execute(InternalRenderGraphContext renderGraphContext)
{
c.FromInternalContext(renderGraphContext);
renderFunc(data, c);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Release(RenderGraphObjectPool pool)
{
base.Release(pool);
// We need to do the release from here because we need the final type.
pool.Release(this);
}
}
[DebuggerDisplay("RenderPass: {name} (Index:{index} Async:{enableAsyncCompute})")]
internal sealed class ComputeRenderGraphPass<PassData> : BaseRenderGraphPass<PassData, ComputeGraphContext>
where PassData : class, new()
{
internal static ComputeGraphContext c = new ComputeGraphContext();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Execute(InternalRenderGraphContext renderGraphContext)
{
c.FromInternalContext(renderGraphContext);
renderFunc(data, c);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Release(RenderGraphObjectPool pool)
{
base.Release(pool);
// We need to do the release from here because we need the final type.
pool.Release(this);
}
}
[DebuggerDisplay("RenderPass: {name} (Index:{index} Async:{enableAsyncCompute})")]
internal sealed class RasterRenderGraphPass<PassData> : BaseRenderGraphPass<PassData, RasterGraphContext>
where PassData : class, new()
{
internal static RasterGraphContext c = new RasterGraphContext();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Execute(InternalRenderGraphContext renderGraphContext)
{
c.FromInternalContext(renderGraphContext);
renderFunc(data, c);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Release(RenderGraphObjectPool pool)
{
base.Release(pool);
// We need to do the release from here because we need the final type.
pool.Release(this);
}
}
[DebuggerDisplay("RenderPass: {name} (Index:{index} Async:{enableAsyncCompute})")]
internal sealed class UnsafeRenderGraphPass<PassData> : BaseRenderGraphPass<PassData, UnsafeGraphContext>
where PassData : class, new()
{
internal static UnsafeGraphContext c = new UnsafeGraphContext();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Execute(InternalRenderGraphContext renderGraphContext)
{
c.FromInternalContext(renderGraphContext);
renderFunc(data, c);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Release(RenderGraphObjectPool pool)
{
base.Release(pool);
// We need to do the release from here because we need the final type.
pool.Release(this);
}
}
}
#endif