diff --git a/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/9x_Other/9700_CustomPass_FullScreen.unity b/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/9x_Other/9700_CustomPass_FullScreen.unity index d8a50c2b3a5..967397708db 100644 --- a/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/9x_Other/9700_CustomPass_FullScreen.unity +++ b/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/9x_Other/9700_CustomPass_FullScreen.unity @@ -321,7 +321,7 @@ PrefabInstance: - target: {fileID: 114995348509370400, guid: c07ace9ab142ca9469fa377877c2f1e7, type: 3} propertyPath: renderGraphCompatible - value: 0 + value: 1 objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: c07ace9ab142ca9469fa377877c2f1e7, type: 3} diff --git a/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/9x_Other/9701_CustomPass_DrawRenderers.unity b/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/9x_Other/9701_CustomPass_DrawRenderers.unity index 054b0799b05..9b4a10a1036 100644 --- a/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/9x_Other/9701_CustomPass_DrawRenderers.unity +++ b/TestProjects/HDRP_Tests/Assets/GraphicTests/Scenes/9x_Other/9701_CustomPass_DrawRenderers.unity @@ -326,7 +326,7 @@ PrefabInstance: - target: {fileID: 114995348509370400, guid: c07ace9ab142ca9469fa377877c2f1e7, type: 3} propertyPath: renderGraphCompatible - value: 0 + value: 1 objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: c07ace9ab142ca9469fa377877c2f1e7, type: 3} @@ -397,6 +397,7 @@ MonoBehaviour: m_EnableSpotReflector: 0 m_LuxAtDistance: 1 m_InnerSpotPercent: 0 + m_SpotIESCutoffPercent: 100 m_LightDimmer: 1 m_VolumetricDimmer: 1 m_LightUnit: 0 @@ -415,6 +416,8 @@ MonoBehaviour: m_ApplyRangeAttenuation: 1 m_DisplayAreaLightEmissiveMesh: 0 m_AreaLightCookie: {fileID: 0} + m_IESPoint: {fileID: 0} + m_IESSpot: {fileID: 0} m_AreaLightShadowCone: 120 m_UseScreenSpaceShadows: 0 m_InteractsWithSky: 1 @@ -2741,6 +2744,7 @@ MonoBehaviour: m_EnableSpotReflector: 0 m_LuxAtDistance: 1 m_InnerSpotPercent: 0 + m_SpotIESCutoffPercent: 100 m_LightDimmer: 1 m_VolumetricDimmer: 1 m_LightUnit: 0 @@ -2759,6 +2763,8 @@ MonoBehaviour: m_ApplyRangeAttenuation: 1 m_DisplayAreaLightEmissiveMesh: 0 m_AreaLightCookie: {fileID: 0} + m_IESPoint: {fileID: 0} + m_IESSpot: {fileID: 0} m_AreaLightShadowCone: 120 m_UseScreenSpaceShadows: 0 m_InteractsWithSky: 1 @@ -3954,6 +3960,7 @@ MonoBehaviour: serializedVersion: 2 m_Bits: 4294967295 hasPersistentHistory: 0 + exposureTarget: {fileID: 0} m_RenderingPathCustomFrameSettings: bitDatas: data1: 72198260625768269 @@ -4389,6 +4396,7 @@ MonoBehaviour: serializedVersion: 2 m_Bits: 4294967295 hasPersistentHistory: 0 + exposureTarget: {fileID: 0} m_RenderingPathCustomFrameSettings: bitDatas: data1: 72198260625768268 diff --git a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs index 7559a39daf4..66b2f157838 100644 --- a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs +++ b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs @@ -22,7 +22,7 @@ public enum DepthAccess /// /// This struct specifies the context given to every render pass. /// - public ref struct RenderGraphContext + public class RenderGraphContext { ///Scriptable Render Context used for rendering. public ScriptableRenderContext renderContext; @@ -197,6 +197,7 @@ public void Reset(RenderGraphPass pass) RenderGraphDefaultResources m_DefaultResources = new RenderGraphDefaultResources(); Dictionary m_DefaultProfilingSamplers = new Dictionary(); bool m_ExecutionExceptionWasRaised; + RenderGraphContext m_RenderGraphContext = new RenderGraphContext(); // Compiled Render Graph info. DynamicArray[] m_CompiledResourcesInfos = new DynamicArray[(int)RenderGraphResourceType.Count]; @@ -810,12 +811,11 @@ internal void CompileRenderGraph() // Execute the compiled render graph void ExecuteRenderGraph(ScriptableRenderContext renderContext, CommandBuffer cmd) { - RenderGraphContext rgContext = new RenderGraphContext(); - rgContext.cmd = cmd; - rgContext.renderContext = renderContext; - rgContext.renderGraphPool = m_RenderGraphPool; - rgContext.resources = m_Resources; - rgContext.defaultResources = m_DefaultResources; + m_RenderGraphContext.cmd = cmd; + m_RenderGraphContext.renderContext = renderContext; + m_RenderGraphContext.renderGraphPool = m_RenderGraphPool; + m_RenderGraphContext.resources = m_Resources; + m_RenderGraphContext.defaultResources = m_DefaultResources; for (int passIndex = 0; passIndex < m_CompiledPassInfos.size; ++passIndex) { @@ -830,14 +830,14 @@ void ExecuteRenderGraph(ScriptableRenderContext renderContext, CommandBuffer cmd try { - using (new ProfilingScope(rgContext.cmd, passInfo.pass.customSampler)) + using (new ProfilingScope(m_RenderGraphContext.cmd, passInfo.pass.customSampler)) { LogRenderPassBegin(passInfo); using (new RenderGraphLogIndent(m_Logger)) { - PreRenderPassExecute(passInfo, ref rgContext); - passInfo.pass.Execute(rgContext); - PostRenderPassExecute(cmd, ref passInfo, ref rgContext); + PreRenderPassExecute(passInfo, m_RenderGraphContext); + passInfo.pass.Execute(m_RenderGraphContext); + PostRenderPassExecute(cmd, ref passInfo, m_RenderGraphContext); } } } @@ -895,7 +895,7 @@ void PreRenderPassSetRenderTargets(in CompiledPassInfo passInfo, RenderGraphCont } } - void PreRenderPassExecute(in CompiledPassInfo passInfo, ref RenderGraphContext rgContext) + void PreRenderPassExecute(in CompiledPassInfo passInfo, RenderGraphContext rgContext) { // TODO RENDERGRAPH merge clear and setup here if possible RenderGraphPass pass = passInfo.pass; @@ -930,7 +930,7 @@ void PreRenderPassExecute(in CompiledPassInfo passInfo, ref RenderGraphContext r } } - void PostRenderPassExecute(CommandBuffer mainCmd, ref CompiledPassInfo passInfo, ref RenderGraphContext rgContext) + void PostRenderPassExecute(CommandBuffer mainCmd, ref CompiledPassInfo passInfo, RenderGraphContext rgContext) { RenderGraphPass pass = passInfo.pass; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs index ba09b19cd92..3644b2f14a7 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using UnityEngine.Experimental.Rendering; using UnityEngine.Experimental.Rendering.RenderGraphModule; @@ -135,7 +136,14 @@ void BindMotionVectorPassColorBuffers(in RenderGraphBuilder builder, in PrepassO } } - PrepassOutput RenderPrepass(RenderGraph renderGraph, TextureHandle colorbuffer, TextureHandle sssBuffer, CullingResults cullingResults, HDCamera hdCamera) + PrepassOutput RenderPrepass(RenderGraph renderGraph, + TextureHandle colorBuffer, + TextureHandle sssBuffer, + CullingResults cullingResults, + CullingResults customPassCullingResults, + HDCamera hdCamera, + AOVRequestData aovRequest, + List aovBuffers) { m_IsDepthBufferCopyValid = false; @@ -150,20 +158,14 @@ PrepassOutput RenderPrepass(RenderGraph renderGraph, TextureHandle colorbuffer, result.motionVectorsBuffer = CreateMotionVectorBuffer(renderGraph, msaa, clearMotionVectors); result.depthBuffer = CreateDepthBuffer(renderGraph, msaa); - RenderXROcclusionMeshes(renderGraph, hdCamera, colorbuffer, result.depthBuffer); + RenderXROcclusionMeshes(renderGraph, hdCamera, colorBuffer, result.depthBuffer); using (new XRSinglePassScope(renderGraph, hdCamera)) { - //// Bind the custom color/depth before the first custom pass - //if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.CustomPass)) - //{ - // if (m_CustomPassColorBuffer.IsValueCreated) - // cmd.SetGlobalTexture(HDShaderIDs._CustomColorTexture, m_CustomPassColorBuffer.Value); - // if (m_CustomPassDepthBuffer.IsValueCreated) - // cmd.SetGlobalTexture(HDShaderIDs._CustomDepthTexture, m_CustomPassDepthBuffer.Value); - //} + // Bind the custom color/depth before the first custom pass + BindCustomPassBuffers(renderGraph, hdCamera); - //RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforeRendering, aovRequest, aovCustomPassBuffers); + RenderCustomPass(renderGraph, hdCamera, colorBuffer, result.depthBuffer, result.normalBuffer, customPassCullingResults, CustomPassInjectionPoint.BeforeRendering, aovRequest, aovBuffers); //RenderRayTracingPrepass(cullingResults, hdCamera, renderContext, cmd, false); @@ -192,7 +194,7 @@ PrepassOutput RenderPrepass(RenderGraph renderGraph, TextureHandle colorbuffer, RenderCameraMotionVectors(renderGraph, hdCamera, result.depthBuffer, result.motionVectorsBuffer); } - PreRenderSky(renderGraph, hdCamera, colorbuffer, result.depthBuffer, result.normalBuffer); + PreRenderSky(renderGraph, hdCamera, colorBuffer, result.depthBuffer, result.normalBuffer); // At this point in forward all objects have been rendered to the prepass (depth/normal/motion vectors) so we can resolve them ResolvePrepassBuffers(renderGraph, hdCamera, ref result); @@ -201,16 +203,14 @@ PrepassOutput RenderPrepass(RenderGraph renderGraph, TextureHandle colorbuffer, RenderGBuffer(renderGraph, sssBuffer, ref result, probeVolumeListOutput, cullingResults, hdCamera); - DecalNormalPatch(renderGraph, hdCamera, ref result); - // TODO RENDERGRAPH - //// After Depth and Normals/roughness including decals - //bool depthBufferModified = RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.AfterOpaqueDepthAndNormal, aovRequest, aovCustomPassBuffers); + // After Depth and Normals/roughness including decals + bool depthBufferModified = RenderCustomPass(renderGraph, hdCamera, colorBuffer, result.depthBuffer, result.normalBuffer, customPassCullingResults, CustomPassInjectionPoint.AfterOpaqueDepthAndNormal, aovRequest, aovBuffers); - //// If the depth was already copied in RenderDBuffer, we force the copy again because the custom pass modified the depth. - //if (depthBufferModified) - // m_IsDepthBufferCopyValid = false; + // If the depth was already copied in RenderDBuffer, we force the copy again because the custom pass modified the depth. + if (depthBufferModified) + m_IsDepthBufferCopyValid = false; // In both forward and deferred, everything opaque should have been rendered at this point so we can safely copy the depth buffer for later processing. GenerateDepthPyramid(renderGraph, hdCamera, ref result); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs index 9c9d5f0ce74..8b73d64d0aa 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using UnityEngine.Experimental.Rendering; using UnityEngine.Experimental.Rendering.RenderGraphModule; @@ -9,6 +10,9 @@ public partial class HDRenderPipeline { class TempPassData { }; + // Needed only because of custom pass. See comment at ResolveMSAAColor. + TextureHandle m_NonMSAAColorBuffer; + void ExecuteWithRenderGraph( RenderRequest renderRequest, AOVRequestData aovRequest, List aovBuffers, @@ -18,6 +22,7 @@ void ExecuteWithRenderGraph( RenderRequest renderRequest, var hdCamera = renderRequest.hdCamera; var camera = hdCamera.camera; var cullingResults = renderRequest.cullingResults.cullingResults; + var customPassCullingResults = renderRequest.cullingResults.customPassCullingResults ?? cullingResults; bool msaa = hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA); var target = renderRequest.target; @@ -28,13 +33,14 @@ void ExecuteWithRenderGraph( RenderRequest renderRequest, TextureHandle backBuffer = m_RenderGraph.ImportBackbuffer(target.id); TextureHandle colorBuffer = CreateColorBuffer(m_RenderGraph, hdCamera, msaa); + m_NonMSAAColorBuffer = CreateColorBuffer(m_RenderGraph, hdCamera, false); TextureHandle currentColorPyramid = m_RenderGraph.ImportTexture(hdCamera.GetCurrentFrameRT((int)HDCameraFrameHistoryType.ColorBufferMipChain), HDShaderIDs._ColorPyramidTexture); LightingBuffers lightingBuffers = new LightingBuffers(); lightingBuffers.diffuseLightingBuffer = CreateDiffuseLightingBuffer(m_RenderGraph, msaa); lightingBuffers.sssBuffer = CreateSSSBuffer(m_RenderGraph, msaa); - var prepassOutput = RenderPrepass(m_RenderGraph, colorBuffer, lightingBuffers.sssBuffer, cullingResults, hdCamera); + var prepassOutput = RenderPrepass(m_RenderGraph, colorBuffer, lightingBuffers.sssBuffer, cullingResults, customPassCullingResults, hdCamera, aovRequest, aovBuffers); // Need this during debug render at the end outside of the main loop scope. // Once render graph move is implemented, we can probably remove the branch and this. @@ -173,7 +179,7 @@ void ExecuteWithRenderGraph( RenderRequest renderRequest, // No need for old stencil values here since from transparent on different features are tagged ClearStencilBuffer(m_RenderGraph, colorBuffer, prepassOutput.depthBuffer); - colorBuffer = RenderTransparency(m_RenderGraph, hdCamera, colorBuffer, currentColorPyramid, gpuLightListOutput, ref prepassOutput, shadowResult, cullingResults); + colorBuffer = RenderTransparency(m_RenderGraph, hdCamera, colorBuffer, currentColorPyramid, gpuLightListOutput, ref prepassOutput, shadowResult, cullingResults, customPassCullingResults, aovRequest, aovBuffers); if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.TransparentsWriteMotionVector)) { @@ -212,8 +218,7 @@ void ExecuteWithRenderGraph( RenderRequest renderRequest, // At this point, the color buffer has been filled by either debug views are regular rendering so we can push it here. var colorPickerTexture = PushColorPickerDebugTexture(m_RenderGraph, colorBuffer); - // TODO RENDERGRAPH - //RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforePostProcess, aovRequest, aovCustomPassBuffers); + RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.depthBuffer, prepassOutput.normalBuffer, customPassCullingResults, CustomPassInjectionPoint.BeforePostProcess, aovRequest, aovBuffers); aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.Color, hdCamera, colorBuffer, aovBuffers); @@ -227,8 +232,7 @@ void ExecuteWithRenderGraph( RenderRequest renderRequest, //} //PushFullScreenExposureDebugTexture(cmd, m_IntermediateAfterPostProcessBuffer); - // TODO RENDERGRAPH - //RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.AfterPostProcess, aovRequest, aovCustomPassBuffers); + RenderCustomPass(m_RenderGraph, hdCamera, postProcessDest, prepassOutput.depthBuffer, prepassOutput.normalBuffer, customPassCullingResults, CustomPassInjectionPoint.AfterPostProcess, aovRequest, aovBuffers); // TODO RENDERGRAPH //// Copy and rescale depth buffer for XR devices @@ -745,7 +749,10 @@ TextureHandle RenderTransparency( RenderGraph renderGraph, in BuildGPULightListOutput lightLists, ref PrepassOutput prepassOutput, ShadowResult shadowResult, - CullingResults cullingResults) + CullingResults cullingResults, + CullingResults customPassCullingResults, + AOVRequestData aovRequest, + List aovBuffers) { RenderTransparentDepthPrepass(renderGraph, hdCamera, prepassOutput, cullingResults); @@ -757,25 +764,25 @@ TextureHandle RenderTransparency( RenderGraph renderGraph, // TODO RENDERGRAPH //// To allow users to fetch the current color buffer, we temporarily bind the camera color buffer //cmd.SetGlobalTexture(HDShaderIDs._ColorPyramidTexture, m_CameraColorBuffer); - //RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforePreRefraction, aovRequest, aovCustomPassBuffers); + + RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.depthBuffer, prepassOutput.normalBuffer, customPassCullingResults, CustomPassInjectionPoint.BeforePreRefraction, aovRequest, aovBuffers); // Render pre-refraction objects RenderForwardTransparent(renderGraph, hdCamera, colorBuffer, prepassOutput.motionVectorsBuffer, prepassOutput.depthBuffer, ssrLightingBuffer, null, lightLists, shadowResult, cullingResults, true); if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.Refraction)) { - var resolvedColorBuffer = ResolveMSAAColor(renderGraph, hdCamera, colorBuffer); + var resolvedColorBuffer = ResolveMSAAColor(renderGraph, hdCamera, colorBuffer, m_NonMSAAColorBuffer); GenerateColorPyramid(renderGraph, hdCamera, resolvedColorBuffer, currentColorPyramid, true); } - // TODO RENDERGRAPH - //// We don't have access to the color pyramid with transparent if rough refraction is disabled - //RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforeTransparent, aovRequest, aovCustomPassBuffers); + // We don't have access to the color pyramid with transparent if rough refraction is disabled + RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.depthBuffer, prepassOutput.normalBuffer, customPassCullingResults, CustomPassInjectionPoint.BeforeTransparent, aovRequest, aovBuffers); // Render all type of transparent forward (unlit, lit, complex (hair...)) to keep the sorting between transparent objects. RenderForwardTransparent(renderGraph, hdCamera, colorBuffer, prepassOutput.motionVectorsBuffer, prepassOutput.depthBuffer, ssrLightingBuffer, currentColorPyramid, lightLists, shadowResult, cullingResults, false); - colorBuffer = ResolveMSAAColor(renderGraph, hdCamera, colorBuffer); + colorBuffer = ResolveMSAAColor(renderGraph, hdCamera, colorBuffer, m_NonMSAAColorBuffer); // Render All forward error RenderForwardError(renderGraph, hdCamera, colorBuffer, prepassOutput.depthBuffer, cullingResults); @@ -1060,6 +1067,10 @@ void GenerateColorPyramid(RenderGraph renderGraph, HDCamera hdCamera, TextureHan var colorPyramid = context.resources.GetTexture(data.colorPyramid); var inputTexture = context.resources.GetTexture(data.inputColor); data.hdCamera.colorPyramidHistoryMipCount = data.mipGenerator.RenderColorGaussianPyramid(context.cmd, pyramidSize, inputTexture, colorPyramid); + + // TODO RENDERGRAPH: We'd like to avoid SetGlobals like this but it's required by custom passes currently. + // We will probably be able to remove those once we push custom passes fully to render graph. + context.cmd.SetGlobalTexture(HDShaderIDs._ColorPyramidTexture, colorPyramid); }); } @@ -1181,21 +1192,35 @@ class ResolveColorData } TextureHandle ResolveMSAAColor(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle input) + { + var outputDesc = renderGraph.GetTextureDesc(input); + outputDesc.enableMSAA = false; + outputDesc.enableRandomWrite = true; + outputDesc.bindTextureMS = false; + // Can't do that because there is NO way to concatenate strings without allocating. + // We're stuck with subpar debug name in the meantime... + //outputDesc.name = string.Format("{0}Resolved", outputDesc.name); + + var output = renderGraph.CreateTexture(outputDesc); + + return ResolveMSAAColor(renderGraph, hdCamera, input, output); + } + + // TODO RENDERGRAPH: + // In theory we should never need to specify the output. The function can create the output texture on its own (see function above). + // This way when doing an msaa resolve, we can return the right texture regardless of msaa being enabled or not (either the new texture or the input directly). + // This allows client code to not have to worry about managing the texture at all. + // Now, because Custom Passes allow to do an MSAA resolve for the main color buffer but are implemented outside of render graph, we need an explicit msaa/nonMsaa separation for the main color buffer. + // Having this function here allows us to do that by having the main color non msaa texture created outside and passed to both ResolveMSAAColor and the custom passes. + // When Custom Pass correctly use render graph we'll be able to remove that. + TextureHandle ResolveMSAAColor(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle input, TextureHandle output) { if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA)) { using (var builder = renderGraph.AddRenderPass("ResolveColor", out var passData)) { - var outputDesc = renderGraph.GetTextureDesc(input); - outputDesc.enableMSAA = false; - outputDesc.enableRandomWrite = true; - outputDesc.bindTextureMS = false; - // Can't do that because there is NO way to concatenate strings without allocating. - // We're stuck with subpar debug name in the meantime... - //outputDesc.name = string.Format("{0}Resolved", outputDesc.name); - passData.input = builder.ReadTexture(input); - passData.output = builder.UseColorBuffer(renderGraph.CreateTexture(outputDesc), 0); + passData.output = builder.UseColorBuffer(output, 0); passData.resolveMaterial = m_ColorResolveMaterial; passData.passIndex = SampleCountToPassIndex(m_MSAASamples); @@ -1324,6 +1349,81 @@ void RenderGizmos(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colo #endif } + bool RenderCustomPass( RenderGraph renderGraph, + HDCamera hdCamera, + TextureHandle colorBuffer, + TextureHandle depthBuffer, + TextureHandle normalBuffer, + CullingResults cullingResults, + CustomPassInjectionPoint injectionPoint, + AOVRequestData aovRequest, + List aovCustomPassBuffers) + { + if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.CustomPass)) + return false; + + bool executed = false; + CustomPassVolume.GetActivePassVolumes(injectionPoint, m_ActivePassVolumes); + foreach (var customPass in m_ActivePassVolumes) + { + if (customPass == null) + return false; + + var customPassTargets = new CustomPass.RenderTargets + { + useRenderGraph = true, + + // Set to null to make sure we don't use them by mistake. + cameraColorMSAABuffer = null, + cameraColorBuffer = null, + // TODO RENDERGRAPH: we can't replace the Lazy buffers with RenderGraph resource because they are part of the current public API. + // To replace them correctly we need users to actually write render graph passes and explicit whether or not they want to use those buffers. + // We'll do it when we switch fully to render graph for custom passes. + customColorBuffer = m_CustomPassColorBuffer, + customDepthBuffer = m_CustomPassDepthBuffer, + + // Render Graph Specific textures + colorBufferRG = colorBuffer, + nonMSAAColorBufferRG = m_NonMSAAColorBuffer, + depthBufferRG = depthBuffer, + normalBufferRG = normalBuffer, + }; + executed |= customPass.Execute(renderGraph, hdCamera, cullingResults, customPassTargets); + } + + // Push the custom pass buffer, in case it was requested in the AOVs + aovRequest.PushCustomPassTexture(renderGraph, injectionPoint, colorBuffer, m_CustomPassColorBuffer, aovCustomPassBuffers); + + return executed; + } + + class BindCustomPassBuffersPassData + { + public Lazy customColorTexture; + public Lazy customDepthTexture; + } + + void BindCustomPassBuffers(RenderGraph renderGraph, HDCamera hdCamera) + { + if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.CustomPass)) + { + using (var builder = renderGraph.AddRenderPass("Bind Custom Pass Buffers", out BindCustomPassBuffersPassData passData)) + { + passData.customColorTexture = m_CustomPassColorBuffer; + passData.customDepthTexture = m_CustomPassDepthBuffer; + + builder.SetRenderFunc( + (BindCustomPassBuffersPassData data, RenderGraphContext ctx) => + { + if (data.customColorTexture.IsValueCreated) + ctx.cmd.SetGlobalTexture(HDShaderIDs._CustomColorTexture, data.customColorTexture.Value); + if (data.customDepthTexture.IsValueCreated) + ctx.cmd.SetGlobalTexture(HDShaderIDs._CustomDepthTexture, data.customDepthTexture.Value); + }); + } + } + } + #if UNITY_EDITOR class RenderWireOverlayPassData { diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index f8dabcad66b..8c5714b9d71 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -517,6 +517,10 @@ public HDRenderPipeline(HDRenderPipelineAsset asset, HDRenderPipelineAsset defau InitializeRenderTextures(); + // TODO RENDERGRAPH: Moved those out of InitializeRenderTexture as they are still needed in render graph and would be deallocated otherwise when switching it on. + m_CustomPassColorBuffer = new Lazy(() => RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GetCustomBufferFormat(), enableRandomWrite: true, useDynamicScale: true, name: "CustomPassColorBuffer")); + m_CustomPassDepthBuffer = new Lazy(() => RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GraphicsFormat.R32_UInt, useDynamicScale: true, name: "CustomPassDepthBuffer", depthBufferBits: DepthBits.Depth32)); + // For debugging MousePositionDebug.instance.Build(); @@ -703,9 +707,6 @@ void InitializeRenderTextures() m_OpaqueAtmosphericScatteringBuffer = RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GetColorBufferFormat(), enableRandomWrite: true, useMipMap: false, useDynamicScale: true, name: "OpaqueAtmosphericScattering"); m_CameraSssDiffuseLightingBuffer = RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GraphicsFormat.B10G11R11_UFloatPack32, enableRandomWrite: true, useDynamicScale: true, name: "CameraSSSDiffuseLighting"); - m_CustomPassColorBuffer = new Lazy(() => RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GetCustomBufferFormat(), enableRandomWrite: true, useDynamicScale: true, name: "CustomPassColorBuffer")); - m_CustomPassDepthBuffer = new Lazy(() => RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GraphicsFormat.R32_UInt, useDynamicScale: true, name: "CustomPassDepthBuffer", depthBufferBits: DepthBits.Depth32)); - m_DistortionBuffer = RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: Builtin.GetDistortionBufferFormat(), useDynamicScale: true, name: "Distortion"); m_ContactShadowBuffer = RTHandles.Alloc(Vector2.one, TextureXR.slices, dimension: TextureXR.dimension, colorFormat: GraphicsFormat.R32_UInt, enableRandomWrite: true, useDynamicScale: true, name: "ContactShadowsBuffer"); @@ -768,11 +769,6 @@ void DestroyRenderTextures() RTHandles.Release(m_OpaqueAtmosphericScatteringBuffer); RTHandles.Release(m_CameraSssDiffuseLightingBuffer); - if (m_CustomPassColorBuffer.IsValueCreated) - RTHandles.Release(m_CustomPassColorBuffer.Value); - if (m_CustomPassDepthBuffer.IsValueCreated) - RTHandles.Release(m_CustomPassDepthBuffer.Value); - RTHandles.Release(m_DistortionBuffer); RTHandles.Release(m_ContactShadowBuffer); @@ -1131,6 +1127,12 @@ protected override void Dispose(bool disposing) m_MipGenerator.Release(); DestroyRenderTextures(); + + if (m_CustomPassColorBuffer.IsValueCreated) + RTHandles.Release(m_CustomPassColorBuffer.Value); + if (m_CustomPassDepthBuffer.IsValueCreated) + RTHandles.Release(m_CustomPassDepthBuffer.Value); + CullingGroupManager.instance.Cleanup(); m_DbufferManager.ReleaseResolutionDependentBuffers(); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestData.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestData.cs index 8dc863829f2..ddb949175bd 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestData.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestData.cs @@ -182,6 +182,44 @@ List targets HDUtils.BlitCameraTexture(cmd, source, targets[index]); } + class PushCameraTexturePassData + { + public TextureHandle source; + // Not super clean to not use TextureHandles here. In practice it's ok because those texture are never passed back to any other render pass. + public RTHandle target; + } + + internal void PushCameraTexture( + RenderGraph renderGraph, + AOVBuffers aovBufferId, + HDCamera camera, + TextureHandle source, + List targets + ) + { + if (!isValid || m_RequestedAOVBuffers == null) + return; + + Assert.IsNotNull(m_RequestedAOVBuffers); + Assert.IsNotNull(targets); + + var index = Array.IndexOf(m_RequestedAOVBuffers, aovBufferId); + if (index == -1) + return; + + using (var builder = renderGraph.AddRenderPass("Push AOV Camera Texture", out var passData)) + { + passData.source = builder.ReadTexture(source); + passData.target = targets[index]; + + builder.SetRenderFunc( + (PushCameraTexturePassData data, RenderGraphContext ctx) => + { + HDUtils.BlitCameraTexture(ctx.cmd, ctx.resources.GetTexture(data.source), data.target); + }); + } + } + internal void PushCustomPassTexture( CommandBuffer cmd, CustomPassInjectionPoint injectionPoint, @@ -221,42 +259,60 @@ List targets } } - class PushCameraTexturePassData + class PushCustomPassTexturePassData { - public int requestIndex; - public TextureHandle source; + public TextureHandle source; + public RTHandle customPassSource; // Not super clean to not use TextureHandles here. In practice it's ok because those texture are never passed back to any other render pass. - public List targets; + public RTHandle target; } - internal void PushCameraTexture( - RenderGraph renderGraph, - AOVBuffers aovBufferId, - HDCamera camera, - TextureHandle source, - List targets + internal void PushCustomPassTexture( + RenderGraph renderGraph, + CustomPassInjectionPoint injectionPoint, + TextureHandle cameraSource, + Lazy customPassSource, + List targets ) { - if (!isValid || m_RequestedAOVBuffers == null) + if (!isValid || m_CustomPassAOVBuffers == null) return; - Assert.IsNotNull(m_RequestedAOVBuffers); Assert.IsNotNull(targets); - var index = Array.IndexOf(m_RequestedAOVBuffers, aovBufferId); + int index = -1; + for (int i = 0; i < m_CustomPassAOVBuffers.Length; ++i) + { + if (m_CustomPassAOVBuffers[i].injectionPoint == injectionPoint) + { + index = i; + break; + } + } + if (index == -1) return; - using (var builder = renderGraph.AddRenderPass("Push AOV Camera Texture", out var passData)) + using (var builder = renderGraph.AddRenderPass("Push Custom Pass Texture", out var passData)) { - passData.requestIndex = index; - passData.source = builder.ReadTexture(source); - passData.targets = targets; + if (m_CustomPassAOVBuffers[index].outputType == CustomPassAOVBuffers.OutputType.Camera) + { + passData.source = builder.ReadTexture(cameraSource); + passData.customPassSource = null; + } + else + { + passData.customPassSource = customPassSource.Value; + } + passData.target = targets[index]; builder.SetRenderFunc( - (PushCameraTexturePassData data, RenderGraphContext ctx) => + (PushCustomPassTexturePassData data, RenderGraphContext ctx) => { - HDUtils.BlitCameraTexture(ctx.cmd, ctx.resources.GetTexture(data.source), data.targets[data.requestIndex]); + if (data.customPassSource != null) + HDUtils.BlitCameraTexture(ctx.cmd, data.customPassSource, data.target); + else + HDUtils.BlitCameraTexture(ctx.cmd, ctx.resources.GetTexture(data.source), data.target); }); } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs index 9054fb9eb7d..ee7019aa0df 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPass.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System; using UnityEngine.Serialization; +using UnityEngine.Experimental.Rendering.RenderGraphModule; namespace UnityEngine.Rendering.HighDefinition { @@ -65,6 +66,8 @@ internal ProfilingSampler profilingSampler CustomPassVolume owner; SharedRTManager currentRTManager; HDCamera currentHDCamera; + // This is a bit dirty but necessary as users may call function that need it but they don't have the instance to pass on. + RenderGraphContext currentRenderGraphContext; MaterialPropertyBlock userMaterialPropertyBlock; @@ -129,10 +132,19 @@ public enum RenderQueueType internal struct RenderTargets { + public bool useRenderGraph; + public RTHandle cameraColorMSAABuffer; public RTHandle cameraColorBuffer; public Lazy customColorBuffer; public Lazy customDepthBuffer; + + // Render graph specific + // TODO RENDERGRAPH cleanup the other ones when we only have the render graph path. + public TextureHandle colorBufferRG; + public TextureHandle nonMSAAColorBufferRG; + public TextureHandle depthBufferRG; + public TextureHandle normalBufferRG; } enum Version @@ -199,6 +211,92 @@ internal void ExecuteInternal(ScriptableRenderContext renderContext, CommandBuff } } + class ExecutePassData + { + public CustomPass customPass; + public CullingResults cullingResult; + public HDCamera hdCamera; + } + + RenderTargets ReadRenderTargets(in RenderGraphBuilder builder, in RenderTargets targets) + { + RenderTargets output = new RenderTargets(); + + output.useRenderGraph = true; + + // Copy over builtin textures. + output.customColorBuffer = targets.customColorBuffer; + output.customDepthBuffer = targets.customDepthBuffer; + + // TODO RENDERGRAPH + // For now we assume that all "outside" textures are both read and written. + // We can change that once we properly integrate render graph into custom passes. + // Problem with that is that it will extend the lifetime of any of those textures to the last custom pass that is executed... + output.colorBufferRG = builder.ReadTexture(builder.WriteTexture(targets.colorBufferRG)); + output.nonMSAAColorBufferRG = builder.ReadTexture(builder.WriteTexture(targets.nonMSAAColorBufferRG)); + output.depthBufferRG = builder.ReadTexture(builder.WriteTexture(targets.depthBufferRG)); + output.normalBufferRG = builder.ReadTexture(builder.WriteTexture(targets.normalBufferRG)); + + return output; + } + + internal void ExecuteInternal(RenderGraph renderGraph, HDCamera hdCamera, CullingResults cullingResult, in RenderTargets targets, CustomPassVolume owner) + { + this.owner = owner; + this.currentRTManager = null; + this.currentRenderTarget = targets; + this.currentHDCamera = hdCamera; + + using (var builder = renderGraph.AddRenderPass(name, out ExecutePassData passData, m_ProfilingSampler)) + { + passData.customPass = this; + passData.cullingResult = cullingResult; + passData.hdCamera = hdCamera; + + this.currentRenderTarget = ReadRenderTargets(builder, targets); + + builder.SetRenderFunc( + (ExecutePassData data, RenderGraphContext ctx) => + { + var customPass = data.customPass; + customPass.currentRenderGraphContext = ctx; + + if (!customPass.isSetup) + { + customPass.Setup(ctx.renderContext, ctx.cmd); + customPass.isSetup = true; + // TODO RENDERGRAPH: We still need to allocate this otherwise it would be null when switching off render graph (because isSetup stays true). + // We can remove the member altogether when we remove the non render graph code path. + userMaterialPropertyBlock = new MaterialPropertyBlock(); + } + + customPass.SetCustomPassTarget(ctx.cmd); + + var outputColorBuffer = ctx.resources.GetTexture(customPass.currentRenderTarget.colorBufferRG); + + // Create the custom pass context: + CustomPassContext customPassCtx = new CustomPassContext( + ctx.renderContext, ctx.cmd, data.hdCamera, + data.cullingResult, + outputColorBuffer, + ctx.resources.GetTexture(customPass.currentRenderTarget.depthBufferRG), + ctx.resources.GetTexture(customPass.currentRenderTarget.normalBufferRG), + customPass.currentRenderTarget.customColorBuffer, + customPass.currentRenderTarget.customDepthBuffer, + ctx.renderGraphPool.GetTempMaterialPropertyBlock() + ); + + customPass.isExecuting = true; + customPass.Execute(customPassCtx); + customPass.isExecuting = false; + + // Set back the camera color buffer if we were using a custom buffer as target + if (customPass.targetDepthBuffer != TargetBuffer.Camera) + CoreUtils.SetRenderTarget(ctx.cmd, outputColorBuffer); + }); + } + } + internal void InternalAggregateCullingParameters(ref ScriptableCullingParameters cullingParameters, HDCamera hdCamera) => AggregateCullingParameters(ref cullingParameters, hdCamera); /// @@ -234,12 +332,22 @@ void SetCustomPassTarget(CommandBuffer cmd) if (targetColorBuffer == TargetBuffer.None && targetDepthBuffer == TargetBuffer.None) return; - bool msaa = IsMSAAEnabled(currentHDCamera); - var cameraColorBuffer = msaa ? currentRenderTarget.cameraColorMSAABuffer : currentRenderTarget.cameraColorBuffer; - var cameraDepthBuffer = currentRTManager.GetDepthStencilBuffer(msaa); + RTHandle colorBuffer, depthBuffer; - RTHandle colorBuffer = (targetColorBuffer == TargetBuffer.Custom) ? currentRenderTarget.customColorBuffer.Value : cameraColorBuffer; - RTHandle depthBuffer = (targetDepthBuffer == TargetBuffer.Custom) ? currentRenderTarget.customDepthBuffer.Value : cameraDepthBuffer; + if (!currentRenderTarget.useRenderGraph) + { + bool msaa = IsMSAAEnabled(currentHDCamera); + var cameraColorBuffer = msaa ? currentRenderTarget.cameraColorMSAABuffer : currentRenderTarget.cameraColorBuffer; + var cameraDepthBuffer = currentRTManager.GetDepthStencilBuffer(msaa); + + colorBuffer = (targetColorBuffer == TargetBuffer.Custom) ? currentRenderTarget.customColorBuffer.Value : cameraColorBuffer; + depthBuffer = (targetDepthBuffer == TargetBuffer.Custom) ? currentRenderTarget.customDepthBuffer.Value : cameraDepthBuffer; + } + else + { + colorBuffer = (targetColorBuffer == TargetBuffer.Custom) ? currentRenderTarget.customColorBuffer.Value : currentRenderGraphContext.resources.GetTexture(currentRenderTarget.colorBufferRG); + depthBuffer = (targetDepthBuffer == TargetBuffer.Custom) ? currentRenderTarget.customDepthBuffer.Value : currentRenderGraphContext.resources.GetTexture(currentRenderTarget.depthBufferRG); + } if (targetColorBuffer == TargetBuffer.None && targetDepthBuffer != TargetBuffer.None) CoreUtils.SetRenderTarget(cmd, depthBuffer, clearFlags); @@ -305,10 +413,22 @@ protected void SetCameraRenderTarget(CommandBuffer cmd, bool bindDepth = true, C if (!isExecuting) throw new Exception("SetCameraRenderTarget can only be called inside the CustomPass.Execute function"); + RTHandle colorBuffer, depthBuffer; + if (currentRenderTarget.useRenderGraph) + { + colorBuffer = currentRenderGraphContext.resources.GetTexture(currentRenderTarget.colorBufferRG); + depthBuffer = currentRenderGraphContext.resources.GetTexture(currentRenderTarget.depthBufferRG); + } + else + { + colorBuffer = currentRenderTarget.cameraColorBuffer; + depthBuffer = currentRTManager.GetDepthStencilBuffer(IsMSAAEnabled(currentHDCamera)); + } + if (bindDepth) - CoreUtils.SetRenderTarget(cmd, currentRenderTarget.cameraColorBuffer, currentRTManager.GetDepthStencilBuffer(IsMSAAEnabled(currentHDCamera)), clearFlags); + CoreUtils.SetRenderTarget(cmd, colorBuffer, depthBuffer, clearFlags); else - CoreUtils.SetRenderTarget(cmd, currentRenderTarget.cameraColorBuffer, clearFlags); + CoreUtils.SetRenderTarget(cmd, colorBuffer, clearFlags); } /// @@ -345,9 +465,25 @@ protected void ResolveMSAAColorBuffer(CommandBuffer cmd, HDCamera hdCamera) if (!isExecuting) throw new Exception("ResolveMSAAColorBuffer can only be called inside the CustomPass.Execute function"); + // TODO RENDERGRAPH + // See how to implement this correctly... + // When running with render graph, the design was to have both msaa/non-msaa textures at the same time, which makes a lot of the code simpler. + // This pattern here breaks this. if (IsMSAAEnabled(hdCamera)) { - currentRTManager.ResolveMSAAColor(cmd, hdCamera, currentRenderTarget.cameraColorMSAABuffer, currentRenderTarget.cameraColorBuffer); + RTHandle input, output; + if (currentRenderTarget.useRenderGraph) + { + input = currentRenderGraphContext.resources.GetTexture(currentRenderTarget.colorBufferRG); + output = currentRenderGraphContext.resources.GetTexture(currentRenderTarget.nonMSAAColorBufferRG); + } + else + { + input = currentRenderTarget.cameraColorMSAABuffer; + output = currentRenderTarget.cameraColorBuffer; + } + + currentRTManager.ResolveMSAAColor(cmd, hdCamera, input, output); } } @@ -369,8 +505,16 @@ protected void GetCameraBuffers(out RTHandle colorBuffer, out RTHandle depthBuff throw new Exception("GetCameraBuffers can only be called inside the CustomPass.Execute function"); bool msaa = IsMSAAEnabled(currentHDCamera); - colorBuffer = msaa ? currentRenderTarget.cameraColorMSAABuffer : currentRenderTarget.cameraColorBuffer; - depthBuffer = currentRTManager.GetDepthStencilBuffer(msaa); + if (currentRenderTarget.useRenderGraph) + { + colorBuffer = currentRenderGraphContext.resources.GetTexture(currentRenderTarget.colorBufferRG); + depthBuffer = currentRenderGraphContext.resources.GetTexture(currentRenderTarget.depthBufferRG); + } + else + { + colorBuffer = msaa ? currentRenderTarget.cameraColorMSAABuffer : currentRenderTarget.cameraColorBuffer; + depthBuffer = currentRTManager.GetDepthStencilBuffer(msaa); + } } /// @@ -398,7 +542,10 @@ protected RTHandle GetNormalBuffer() if (!isExecuting) throw new Exception("GetNormalBuffer can only be called inside the CustomPass.Execute function"); - return currentRTManager.GetNormalBuffer(IsMSAAEnabled(currentHDCamera)); + if (currentRenderTarget.useRenderGraph) + return currentRenderGraphContext.resources.GetTexture(currentRenderTarget.normalBufferRG); + else + return currentRTManager.GetNormalBuffer(IsMSAAEnabled(currentHDCamera)); } /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassVolume.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassVolume.cs index d1f2e2d08ee..323b3f55b5d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassVolume.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassVolume.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using UnityEngine.Rendering; +using UnityEngine.Experimental.Rendering.RenderGraphModule; using System.Linq; using System; @@ -101,6 +101,28 @@ internal bool Execute(ScriptableRenderContext renderContext, CommandBuffer cmd, return executed; } + internal bool Execute(RenderGraph renderGraph, HDCamera hdCamera, CullingResults cullingResult, in CustomPass.RenderTargets targets) + { + bool executed = false; + + // We never execute volume if the layer is not within the culling layers of the camera + if ((hdCamera.volumeLayerMask & (1 << gameObject.layer)) == 0) + return false; + + Shader.SetGlobalFloat(HDShaderIDs._CustomPassInjectionPoint, (float)injectionPoint); + + foreach (var pass in customPasses) + { + if (pass != null && pass.WillBeExecuted(hdCamera)) + { + pass.ExecuteInternal(renderGraph, hdCamera, cullingResult, targets, this); + executed = true; + } + } + + return executed; + } + internal bool WillExecuteInjectionPoint(HDCamera hdCamera) { bool executed = false; @@ -227,7 +249,7 @@ internal void AggregateCullingParameters(ref ScriptableCullingParameters culling // TODO: cache the results per camera in the HDRenderPipeline so it's not executed twice per camera Update(hdCamera); - // For each injection points, we gather the culling results for + // For each injection points, we gather the culling results for hdCamera.camera.TryGetCullingParameters(out var cullingParameters); // By default we don't want the culling to return any objects