Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Official Introduction of Render Graph in the Universal Render Pipeline (URP)

Discussion in 'Universal Render Pipeline' started by oliverschnabel, Oct 2, 2023.

  1. Neonage

    Neonage

    Joined:
    May 22, 2020
    Posts:
    288
    So I was able to get this asset working with RG via Unsafe pass
    https://github.com/mseonKim/URP-VolumetricFog-ForwardPlus
    upload_2024-3-22_23-50-39.png

    But to not change the actual execution code, I've had to make some internals public:
    m_WrappedCommandBuffer inside BaseCommandBuffer
    InternalRenderGraphContext wrappedContext inside UnsafeGraphContext
    ScriptableRenderContext renderContext inside InternalRenderGraphContext
    ContextContainer frameData inside RenderingData

    I did it like this:
    upload_2024-3-22_23-52-46.png

    upload_2024-3-22_23-53-13.png

    And had to comment out this line that used cameraColorTargetHandle:
    upload_2024-3-22_23-55-25.png

    So far it seems like the easiest way to get stuff working with RG in a matter of hour.
     
    Last edited: Mar 23, 2024
    D1234567890 and nasos_333 like this.
  2. Neonage

    Neonage

    Joined:
    May 22, 2020
    Posts:
    288
    Now I've got a question, is it possible to inject a pass after TAA/STP, but before any other post-processing?
    upload_2024-3-23_0-12-7.png
     
  3. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    297
    Here is a minimal example to reproduce, 6000.0.0b11:
    Code (CSharp):
    1. using UnityEngine.Rendering;
    2. using UnityEngine.Rendering.RenderGraphModule;
    3. using UnityEngine.Rendering.Universal;
    4.  
    5. namespace BugReport
    6. {
    7.     public class SomeBuggedRenderFeature : ScriptableRendererFeature
    8.     {
    9.         SomeBuggedRenderPass Pass;
    10.         public override void Create() => Pass = new SomeBuggedRenderPass();
    11.         public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) =>
    12.             renderer.EnqueuePass(Pass);
    13.     }
    14.  
    15.     public class SomeBuggedRenderPass : ScriptableRenderPass {
    16.         class PassData
    17.         {
    18.             public TextureHandle cameraColor;
    19.         }
    20.  
    21.         public SomeBuggedRenderPass() => renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
    22.  
    23.         public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
    24.         {
    25.             var resources = frameData.Get<UniversalResourceData>();
    26.             using (var builder = renderGraph.AddUnsafePass<PassData>(GetType().Name, out var passData))
    27.             {
    28.                 passData.cameraColor = resources.cameraColor;
    29.                 builder.AllowGlobalStateModification(true);
    30.                 builder.AllowPassCulling(false);
    31.                 builder.UseTexture(passData.cameraColor, AccessFlags.Read);
    32.                 builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => { });
    33.             }
    34.         }
    35.     }
    36. }

    Throws the following error when added to the renderer any time the inspector window draws (eg preview window when material is selected):
    Code (csharp):
    1. ArgumentException: Trying to use an invalid resource (pass SomeBuggedRenderPass).
    2. UnityEngine.Rendering.RenderGraphModule.RenderGraphBuilders.CheckResource (UnityEngine.Rendering.RenderGraphModule.ResourceHandle& res, System.Boolean dontCheckTransientReadWrite) (at ./Library/PackageCache/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs:500)
    3. UnityEngine.Rendering.RenderGraphModule.RenderGraphBuilders.UseResource (UnityEngine.Rendering.RenderGraphModule.ResourceHandle& handle, UnityEngine.Rendering.RenderGraphModule.AccessFlags flags) (at ./Library/PackageCache/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs:197)
    4. UnityEngine.Rendering.RenderGraphModule.RenderGraphBuilders.UseTexture (UnityEngine.Rendering.RenderGraphModule.TextureHandle& input, UnityEngine.Rendering.RenderGraphModule.AccessFlags flags) (at ./Library/PackageCache/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs:280)
    5. UnityEngine.Rendering.RenderGraphModule.RenderGraphBuilders.UnityEngine.Rendering.RenderGraphModule.IBaseRenderGraphBuilder.UseTexture (UnityEngine.Rendering.RenderGraphModule.TextureHandle& input, UnityEngine.Rendering.RenderGraphModule.AccessFlags flags) <0x2602ab4c040 + 0x00062> in <633f4713417f439596292740fbd11fac>:0
    6. BugReport.SomeBuggedRenderPass.RecordRenderGraph (UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, UnityEngine.Rendering.ContextContainer frameData) (at Assets/BuggedRenderFeature.cs:31)
    7. UnityEngine.Rendering.Universal.ScriptableRenderer.RecordCustomRenderGraphPasses (UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, UnityEngine.Rendering.Universal.RenderPassEvent injectionPoint) (at ./Library/PackageCache/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs:1180)
    8. UnityEngine.Rendering.Universal.UniversalRenderer.OnMainRendering (UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, UnityEngine.Rendering.ScriptableRenderContext context) (at ./Library/PackageCache/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs:1117)
    9. UnityEngine.Rendering.Universal.UniversalRenderer.OnRecordRenderGraph (UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, UnityEngine.Rendering.ScriptableRenderContext context) (at ./Library/PackageCache/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs:806)
    10. UnityEngine.Rendering.Universal.ScriptableRenderer.RecordRenderGraph (UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, UnityEngine.Rendering.ScriptableRenderContext context) (at ./Library/PackageCache/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs:1127)
    11. UnityEngine.Rendering.Universal.UniversalRenderPipeline.RecordRenderGraph (UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, UnityEngine.Rendering.ScriptableRenderContext context, UnityEngine.Rendering.Universal.ScriptableRenderer renderer) (at ./Library/PackageCache/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineRenderGraph.cs:9)
    12. UnityEngine.Rendering.Universal.UniversalRenderPipeline.RecordAndExecuteRenderGraph (UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, UnityEngine.Rendering.ScriptableRenderContext context, UnityEngine.Rendering.Universal.ScriptableRenderer renderer, UnityEngine.Rendering.CommandBuffer cmd, UnityEngine.Camera camera) (at ./Library/PackageCache/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineRenderGraph.cs:24)
    13. UnityEngine.Rendering.Universal.UniversalRenderPipeline.RenderSingleCamera ...
    (I had to remove the bottom of the error because it causes the code block to incorrectly render, you get the gist I hope)


    EDIT: It looks like what you need to do is use the backbuffer for preview cameras, eg:
    Code (CSharp):
    1. #if UNITY_2023_3_OR_NEWER
    2.         protected static TextureHandle CameraColorTexture(UniversalResourceData resource, UniversalCameraData camera) => camera.cameraType != CameraType.Preview ? resource.cameraColor : resource.backBufferColor;
    3.         protected static TextureHandle CameraDepthTexture(UniversalResourceData resource, UniversalCameraData camera) => camera.cameraType != CameraType.Preview ? resource.cameraDepth : resource.backBufferDepth;
    4. #endif
    If this is the case, I would say it was a counterintuitive part of the API that I can't use cameraColor/Depth when rendering a preview camera. Perhaps a bug?

    Thanks,
    Elliot
     
    Last edited: Mar 23, 2024
  4. ilcane87

    ilcane87

    Joined:
    Apr 29, 2022
    Posts:
    10
    Since one of the defining features of this upgrade is to allow access to previously 'internal' resources, I'd like to request access to 2D Light textures, which are currently computed by the internal 2D rendering passes but are disposed before they end, and there's no rendering event that allows to enqueue custom passes in-between their creation and disposal (which would also be desirable), making it effectively impossible to manually execute draw calls of sprites lit by them at any time within or outside the scope of the pipeline.

    Thank you very much and good luck with your endeavor.
     
    Last edited: Mar 25, 2024
    Gasimo likes this.
  5. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    297
    A note of appreciation how much easier it is to now reliably write to the cameraDepthTexture - no more writing to cameraDepthAttachment and hoping that you do it in time for the CopyDepth pass.
     
  6. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    297
    activeColor/DepthTarget after a UnsafeRenderPass

    I wondered about this while trying to redirect the rendering of a preview camera to a separate buffer. The DrawObjectsPass for opaque forward rendering uses the activeColorTexture and activeDepthTexture.

    https://github.com/Unity-Technologi...Runtime/UniversalRendererRenderGraph.cs#L1123

    My unsafe pass changes the color/depth targets at execution time, but this won't affect activeColorTexture/activeTexture at recording time. The activeColorTexture and activeDepthTexture resources are readonly, so we cannot set them ourselves at the recording stage. RasterRenderPass can use the SetAttachment methods at recording time, but what is the suggested way to make sure activeColorTexture and Depth are set properly after an UnsafeRenderPass? It seemed like using builder.UseTexture with Write flag enabled had no effect (and we can specify multiple of these).

    Cheers
     
  7. hyperdemented

    hyperdemented

    Joined:
    Sep 11, 2014
    Posts:
    7
    Hi, I have a question:

    I am currently trying to draw some renderers with a custom material using RasterCommandBuffer.DrawRendererList
    while following the guide from here: https://docs.unity3d.com/Packages/c...nual/render-graph-draw-objects-in-a-pass.html

    The problem I am facing is that I want to draw these renderers to a custom texture instead of the active color texture.
    But the guide says to "Set the texture to draw the objects onto. Set both the color texture and the depth texture so URP renders the objects correctly."

    So, if I try to set a custom texture as target, the renderers will not respect depth. And if I then add SetRenderAttachmentDepth with the active depth texture
    then the Editor will throw all kinds of error messages which makes me believe that this is not the way to do it.

    Does anyone have an idea how I should go about drawing selected renderers with a custom material to a custom texture?
     
  8. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Easy way is use a second camera and select layers there and use render objects with replacement shader.

    Since Unity breaks the backend constantly, this is also the only way to make sure will keep working in future.

    At this point if can avoid using the API i would 1000% do it that way.
     
  9. Neonage

    Neonage

    Joined:
    May 22, 2020
    Posts:
    288
    Copy depth from camera to your render texture, you could use CopyDepthPass for that.
     
  10. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    297
    There's still quite a few open questions in the thread. Given a mid April release date has been said previously, that puts us around 2 weeks off with spring week vacation in the mix. For assets you typically need to submit one week in advance because of asset store update queues. So for those of us hoping to support from day 1 to avoid bad reviews and embrace the tech, I'd be really grateful if someone from the URP team could answer some of the remaining questions.

    Cheers!
     
    oliverschnabel and Gasimo like this.
  11. oliverschnabel

    oliverschnabel

    Unity Technologies

    Joined:
    Mar 13, 2018
    Posts:
    49
    I am currently trying to collect the open questions and we will make sure to answer as many as possible of them next week.

    In the meantime, I wanted to highlight that we have recently published the first version of official docs on RenderGraph here: https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@17.0/manual/render-graph.html

    Let us know if you have feedback how we can improve it.
     
  12. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    I think trying to support this new system from day one can also bring many one star reviews, since a million things can go wrong with pre-Beta code as this in Render Graph, that is bound to change vastly every week until the Unity 6 release of later. This is just so early to have any real use or trust, especially since the years in making renderer features system was scrapped completely, even after a million users having it as standard.

    So imo adding a disclaimer that Unity 2023.3 new pipeline is not supported is the way to go to be sure that no one star reviews will go in. In my mind there is simply no way to avoid 1-star reviews given the complexity of the thing.

    DISCLAIMER: The support for Unity 2023.3 new pipeline URPRG (URGP - Universal Render Graph Pipeline) is on the way and will be soon available as a separate Beta download for anyone interested. All effects have already been converted internally and working at their base and remain to be refined and restore all possible variations of functionality for the official Unity 2023.3 release. Please visit our Discord, in Updates section, for checking on the availability for the assets for the new pipeline.

    Please note that this new pipeline is massively different than URP and all image effects had to be remade from scratch for the new system, thus can take a while to fully port to the new platform and test all cases. Also the new pipeline is very early and has not been tested yet, thus can be unstable and the code is expected to change very often, so it is recommended to not use it for some time for production until it is finalized and fully documented, hopefully by the end of 2024 or early 2025.
     
    Neonage likes this.
  13. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Hi,

    Is it possible to have an auto converter for current effects for the unsafe pass ?

    Something fully automatic for example so can have something working until adapt to the Graph, if that is needed, as most effects wont be making any use of it.

    Thanks
     
    Neonage likes this.
  14. AljoshaD

    AljoshaD

    Unity Technologies

    Joined:
    May 27, 2019
    Posts:
    282
    Unfortunately, it's not possible. It's something that we investigated and also discussed in this thread. Although the code is very similar when you use UnsafePass, facilitating the upgrading, it is not possible to create an automatic converter with a reliable, stable output.
     
    ElliotB likes this.
  15. AljoshaD

    AljoshaD

    Unity Technologies

    Joined:
    May 27, 2019
    Posts:
    282
    Do you mean your assets change vastly every week? U6/23.3 is in beta and the RG API itself does not change at this point.
     
    ElliotB likes this.
  16. AljoshaD

    AljoshaD

    Unity Technologies

    Joined:
    May 27, 2019
    Posts:
    282
    Thanks for sharing your proposal. Sounds like a good idea.
     
    nasos_333 likes this.
  17. Neonage

    Neonage

    Joined:
    May 22, 2020
    Posts:
    288
    As I posted above, the old code can be executed 'as is', with very little tweaking via Unsafe pass, but it required access to some internals to match with old APIs (direct access to wrapped CommandBuffer, ScriptableRenderContext from UnsafeGraphContext, ContextContainer from RenderingData, CameraData instead of UniversalCameraData, etc...)
    Please provide us with such APIs / utilities for an easy transition. Most people won't ever rewrite all their features to "pure RG way", so they'll look for workarounds to get the stuff working as fast as possible.
     
    D1234567890 and nasos_333 like this.
  18. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Indeed, that is one of the reasons i mentioned the automatic converter, but if at least can offer some extra public methods to do it faster manually would also be great and better than redo all in the Graph.

    The ideal would be a very fast conversion with unsafe pass with minimal code changes and adding the Graph option as option later, after properly having time to port and test and only if makes sense.
     
    Neonage likes this.
  19. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Hi,

    Is it possible to evaluate exposing the variables mentioned below by Neonage, so we can use the unsafe pass in a more streamlined way ?

    "make some internals public:
    m_WrappedCommandBuffer inside BaseCommandBuffer
    InternalRenderGraphContext wrappedContext inside UnsafeGraphContext
    ScriptableRenderContext renderContext inside InternalRenderGraphContext
    ContextContainer frameData inside RenderingData"

    For you is a few minutes to change to public, but for us could mean saving weeks of work and much less 1-star reviews.

    Also when is the tech release of Unity 6 planned, is for early April or later April ?

    Thanks

    Also would be great if those could come fast and before the release, please understand that publishers with many complex technical assets like mine (e.g. volume clouds, volume lighting, real time GI) are going in a bit of panic attack, as what you propose is to break all our effects for every single user using Unity 6 as a default, without any warning or excuse mentioned.

    It is king of apocalyptic event from our side and porting will take at least few more months, if all go well and performance is up to par and not have to reevaluate some of the effects stages, which then could take years to perfect.
     
    Last edited: Mar 29, 2024
    ElliotB and Neonage like this.
  20. Neonage

    Neonage

    Joined:
    May 22, 2020
    Posts:
    288
    nasos_333 likes this.
  21. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    sure, but if there is no confirmation that those changes are planned to be made would be lost work as could not work in the general case like that, so will start on such after a positive change on the above first :)

    It would just be so great if there was an easy way to port using unsafe pass, so we can take our time to port to Graph properly and after the API is easier and more streamlined in code requirements, my code right now for the conversions is 5-10x more lines for example and vastly harder to read.
     
  22. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    297
    Have you tried:
    Code (CSharp):
    1. CommandBuffer cmd = CommandBufferHelpers.GetNativeCommandBuffer(rgContext.cmd)
    I think some of the functionality you request is already there, but discoverability is hard. API change is probably not going to happen at this stage, but I think it would be reasonable to have some deeper examples of porting from non-RG to RG than blit; its a good starting point but it leaves a large surface of the api untouched. Disclaimer that I haven't checked out oliver's updated doc yet, so there might be more there.
     
  23. AljoshaD

    AljoshaD

    Unity Technologies

    Joined:
    May 27, 2019
    Posts:
    282
    At the earliest, end of April.
     
  24. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Hi,

    One question on grabbing Gbuffer in Forward Plus in graph mode

    Currently in non graph i do the below

    1. Configure the Gbuffer render targets

    Code (csharp):
    1.  
    2.  ConfigureTarget(new RTHandle[] {
    3.                 albedoHandle,
    4.                 specularHandle,
    5.                 worldPosHandle,
    6.                 depthNormalHandle,
    7.             });
    8.         ConfigureClear(ClearFlag.All, Color.black);
    9.  
    Then render the renderer list with the gbuffer entry

    Code (csharp):
    1.  
    2.  static readonly ShaderTagId gBufferShaderTag = new ShaderTagId("UniversalGBuffer");
    3.  
    4. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    5.     {
    6.         var cmd = CommandBufferPool.Get();
    7.         context.ExecuteCommandBuffer(cmd);
    8.         cmd.Clear();
    9.         using (new ProfilingScope(cmd, new ProfilingSampler("DeferredLights::GBufferPassRG")))
    10.         {
    11.             var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
    12.             var drawSettings = CreateDrawingSettings(gBufferShaderTag, ref renderingData, sortFlags);
    13.             drawSettings.enableDynamicBatching = true;
    14.             drawSettings.enableInstancing = true;
    15.             context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filteringSettings, ref renderStateBlock);
    16.            
    17.             cmd.SetGlobalTexture("_GBuffer0", albedoHandle.rt);
    18.             cmd.SetGlobalTexture("_GBuffer1", specularHandle.rt);
    19.             cmd.SetGlobalTexture("_GBuffer2", depthNormalHandle.rt);
    20.        
    21.         }
    22.         CoreUtils.SetRenderTarget(cmd, colorTarget, ClearFlag.All, Color.black);
    23.      
    24.         context.ExecuteCommandBuffer(cmd);
    25.         CommandBufferPool.Release(cmd);
    26.     }
    27.  
    Can we do something similar in Render Graph ?

    I tried create the render list with the Gbuffers tag, but i am not sure how to set the render targets correctly in the builder, e.g. how to replace the ConfigureTarget.

    Thanks
     
  25. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Exception: Pass 'Custom Render Pass' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass.

    How to fix this, i try to set a global variable and says that anything i import should not be set as a global variable.

    In RenderFunction i use

    context.cmd.SetGlobalTexture("_GBuffer0", data.gbuffer[0]);

    Thanks
     
    Last edited: Apr 1, 2024
  26. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    It has now been 3 days, day and night trying to get the gbuffer0-1-2 from Forward Plus in render graph.

    Also cant tell if is possible at all or simply Gbuffer is not available in the Graph case.

    Is it possible to have an example of extract the Gbuffers in Forward Plus and send them to a global shader variable ?

    Thanks a lot in advance
     
  27. Neonage

    Neonage

    Joined:
    May 22, 2020
    Posts:
    288
    nasos_333 likes this.
  28. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Hi, thanks, i already do create them in Forward plus in non Render Graph mode, this is trivial and works fine.

    The issue is that cant do the same with the render graph, tried with renderlist with the proper tag, grab from the mentioned gbuffer exposed struct etc

    Nothing seem to work out so far
     
  29. Neonage

    Neonage

    Joined:
    May 22, 2020
    Posts:
    288
    I was able to do it in UnsafePass, just needed to replace ConfigureTarget and ConfigureClear with cmd.SetRenderTarget and cmd.ClearRenderTarget.

    Also, I've made a small struct that can hold both RTHandle and TextureHandle to setup them separately in non-RG and RG passes. If rtHandle is not manually set - it means we are in RG pass and will get RTHandle from TextureHandle.
    Code (CSharp):
    1. public struct Handle
    2.     {
    3.         RTHandle rtHandle;
    4.         TextureHandle textureHandle;
    5.  
    6.         public RTHandle RT { [MethodImpl(256)] get => rtHandle ?? textureHandle; }
    7.  
    8.         [MethodImpl(256)] public static implicit operator Handle(RTHandle handle) => new Handle() { rtHandle = handle };
    9.         [MethodImpl(256)] public static implicit operator Handle(TextureHandle handle) => new Handle() { textureHandle = handle };
    10.  
    11.         [MethodImpl(256)] public static implicit operator RTHandle(Handle texture) => texture.RT;
    12.         [MethodImpl(256)] public static implicit operator TextureHandle(Handle texture) => texture.textureHandle;
    13.     }
    upload_2024-4-2_0-20-1.png
     
    D1234567890 and nasos_333 like this.
  30. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Nice, thanks a lot :), will try it out asap :)
     
  31. Neonage

    Neonage

    Joined:
    May 22, 2020
    Posts:
    288
    Here's my RGUtil that uses Reflection:
    Code (CSharp):
    1.  
    2. using System.Reflection;
    3. using UnityEngine;
    4. using UnityEngine.Rendering.Universal;
    5. using UnityEngine.Rendering;
    6. using System;
    7. using System.Runtime.CompilerServices;
    8. using UnityEngine.Rendering.RenderGraphModule;
    9.  
    10. public static class RGUtil
    11. {
    12.     public struct Handle
    13.     {
    14.         RTHandle rtHandle;
    15.         TextureHandle textureHandle;
    16.  
    17.         public RTHandle RT { [MethodImpl(256)] get => rtHandle ?? textureHandle; }
    18.  
    19.         [MethodImpl(256)] public static implicit operator Handle(RTHandle handle) => new Handle() { rtHandle = handle };
    20.         [MethodImpl(256)] public static implicit operator Handle(TextureHandle handle) => new Handle() { textureHandle = handle };
    21.  
    22.         [MethodImpl(256)] public static implicit operator RTHandle(Handle texture) => texture.RT;
    23.         [MethodImpl(256)] public static implicit operator TextureHandle(Handle texture) => texture.textureHandle;
    24.     }
    25.  
    26.     static FieldInfo R_s_RenderGraph = typeof(UniversalRenderPipeline).GetField("s_RenderGraph", BindingFlags.NonPublic | BindingFlags.Static);
    27.  
    28.     static FieldInfo R_renderContext = typeof(InternalRenderGraphContext).GetField("renderContext", BindingFlags.NonPublic | BindingFlags.Instance);
    29.     static FieldInfo R_InternalRenderGraphContext = typeof(UnsafeGraphContext).GetField("wrappedContext", BindingFlags.NonPublic | BindingFlags.Instance);
    30.     static FieldInfo R_RenderingData_frameData = typeof(RenderingData).GetField("frameData", BindingFlags.NonPublic | BindingFlags.Instance);
    31.     static FieldInfo R_CameraData_frameData = typeof(CameraData).GetField("frameData", BindingFlags.NonPublic | BindingFlags.Instance);
    32.     static MethodInfo R_GetGPUProjectionMatrix = typeof(UniversalCameraData).GetMethod("GetGPUProjectionMatrix", BindingFlags.NonPublic | BindingFlags.Instance,
    33.         null, new Type[] { typeof(bool), typeof(int) }, null);
    34.  
    35.     static object[] Args2 = new object[2];
    36.  
    37.  
    38.     [MethodImpl(256)]
    39.     public static void Get<T>(this ContextContainer frameData, out T data) where T : ContextItem, new()
    40.     {
    41.         data = frameData.Get<T>();
    42.     }
    43.  
    44.     public static void Alloc(ref RTHandle handle, in RenderTextureDescriptor desc, FilterMode filterMode = FilterMode.Point, TextureWrapMode wrapMode = TextureWrapMode.Repeat,
    45.         int anisoLevel = 1, float mipMapBias = 0, string name = "")
    46.     {
    47.         RenderingUtils.ReAllocateHandleIfNeeded(ref handle, desc, filterMode, wrapMode, anisoLevel, mipMapBias, name);
    48.     }
    49.  
    50.     // Use when want to ImportTexture during non-RG pass?
    51.     public static RenderGraph GetRenderGraph()
    52.     {
    53.         return (RenderGraph)R_s_RenderGraph.GetValue(null);
    54.     }
    55.  
    56.     static InternalRenderGraphContext GetInternalRenderGraphContext(this UnsafeGraphContext unsafeContext)
    57.     {
    58.         return (InternalRenderGraphContext)R_InternalRenderGraphContext.GetValue(unsafeContext);
    59.     }
    60.     public static ScriptableRenderContext GetRenderContext(this UnsafeGraphContext unsafeContext)
    61.     {
    62.         return (ScriptableRenderContext)R_renderContext.GetValue(GetInternalRenderGraphContext(unsafeContext));
    63.     }
    64.  
    65.     public static CommandBuffer GetCommandBuffer(this UnsafeGraphContext unsafeContext)
    66.     {
    67.         return CommandBufferHelpers.GetNativeCommandBuffer(unsafeContext.cmd);
    68.     }
    69.  
    70.     public static ContextContainer GetFrameData(this ref RenderingData renderingData)
    71.     {
    72.         return (ContextContainer)R_RenderingData_frameData.GetValue(renderingData);
    73.     }
    74.  
    75.     // Avoids a call to IsCameraProjectionMatrixFlipped that uses cameraColorTargetHandle, which is null during RG pass
    76.     public static Matrix4x4 GetGPUProjectionMatrix(this UniversalCameraData cameraData, bool flipped, int viewIndex = 0)
    77.     {
    78.         Args2[0] = flipped;
    79.         Args2[1] = viewIndex;
    80.         return (Matrix4x4)R_GetGPUProjectionMatrix.Invoke(cameraData, Args2);
    81.     }
    82.  
    83.     public static CameraData GetCameraData(this ContextContainer frameData)
    84.     {
    85.         object cameraDataBoxed = new CameraData();
    86.         R_CameraData_frameData.SetValue(cameraDataBoxed, frameData);
    87.         return (CameraData)cameraDataBoxed;
    88.     }
    89. }
    90.  
    And template code:
    Code (CSharp):
    1.  
    2. #pragma warning disable 612, 618 // suppress Obsolete warnings
    3.         class PassData
    4.         {
    5.             public UniversalCameraData cameraData;
    6.             public RGUtil.Handle colorTargetHandle;
    7.  
    8.             public void Init(ContextContainer frameData, IUnsafeRenderGraphBuilder builder = null)
    9.             {
    10.                 frameData.Get(out UniversalResourceData resources);
    11.                 frameData.Get(out cameraData);
    12.  
    13.                 if (builder == null) // non-RG pass
    14.                 {
    15.                     colorTargetHandle = cameraData.renderer.cameraColorTargetHandle;
    16.                 }
    17.                 else
    18.                 {
    19.                     colorTargetHandle = resources.activeColorTexture;
    20.                     builder.UseTexture(colorTargetHandle, AccessFlags.ReadWrite);
    21.                 }
    22.             }
    23.         }
    24.  
    25.         const string PassName = "Screen Space Reflections";
    26.  
    27.         public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
    28.         {
    29.             using (var builder = renderGraph.AddUnsafePass<PassData>(PassName, out var data))
    30.             {
    31.                 frameData.Get(out UniversalResourceData resources);
    32.  
    33.                 data.Init(frameData, builder);
    34.  
    35.                 builder.SetRenderFunc<PassData>((data, ctx) =>
    36.                 {
    37.                     var cmd = CommandBufferHelpers.GetNativeCommandBuffer(ctx.cmd);
    38.                     var renderContext = ctx.GetRenderContext();
    39.  
    40.                     OnSetup(cmd, data);
    41.                     ExecutePass(renderContext, cmd, data);
    42.                 });
    43.             }
    44.         }
    45.  
    46.         PassData passData = new PassData();
    47.  
    48.      
    49.         public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
    50.         {
    51.             var data = passData;
    52.             data.Init(renderingData.GetFrameData());
    53.          
    54.         }
    55.         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    56.         {
    57.             var data = passData;
    58.             data.Init(renderingData.GetFrameData());
    59.  
    60.             var cmd = CommandBufferPool.Get();
    61.             cmd.name = PassName;
    62.  
    63.             OnSetup(cmd, data);
    64.             ExecutePass(context, cmd, data);
    65.  
    66.             context.ExecuteCommandBuffer(cmd);
    67.             CommandBufferPool.Release(cmd);
    68.         }
    69. #pragma warning restore 612, 618
    70.  
     
  32. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    I see, great :), many thanks for the details, it is super useful
     
  33. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    upload_2024-4-2_11-23-14.png
    I wonder though, if since Gbuffer is mentioned as available in the manual, could have an example of how to grab it and make it globally available in Forward+ mode, that would be great if was done in the Graph natively.

    A complete example that works would be great to have in the official docs - samples as well.

    Thanks a lot in advance.
     
  34. AljoshaD

    AljoshaD

    Unity Technologies

    Joined:
    May 27, 2019
    Posts:
    282
    Certain Frame Resources are specific for a certain Renderer. If a user needs Gbuffers for effects then they need to use the Deferred Renderer. We won't add Gbuffer generation for other Renderers.
     
    ElliotB likes this.
  35. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539

    Oh i see, but in non Graph mode i could grab the Gbuffer using a renderer feature in Forward+.

    This is no longer possible with the Graph mode ?

    I mention the code above here. Using DrawRenderers with ShaderTagId "UniversalGBuffer".

    In any case would be great if could add a toggle to enable the pass, since having the Gbuffer can be useful in many ways in all modes. E.g. i get better performance when combine volumetric lighting and real time global illumination in Forward+ with Gbuffer use.

    Thanks
     
    Last edited: Apr 2, 2024
  36. AljoshaD

    AljoshaD

    Unity Technologies

    Joined:
    May 27, 2019
    Posts:
    282
    That's strange, the gbuffers should not be available when using Forward+. That seems like a bug.

    Why not use the Deferred Renderer in this case then if the gbuffers can offer a performance benefit? That seems more efficient.
     
    nasos_333 likes this.
  37. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Because the tiled rendering parsing of the lights in Forward+ seem more efficient when using volumetrics. The difference is 4-5ms and also a visible fluidity when many lights are used, versus Deferred.

    In all cases i dont see why not have an option to do the Gbuffer pass optionally.

    I saw the code in the pipeline where it happens, so i assume i could recreate it maybe, but would be much easier as a toggle.

    Another way could be if the light parsing could be tiled in Deferred also as another option, so Deferred comes to par with Forward+ performance. But not sure if that is possible, while enable the Gbufer pass is trivial.
     
  38. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    upload_2024-4-2_14-1-50.png
    upload_2024-4-2_14-1-58.png
    Here is a direct comparison between the two modes for reference.

    The difference also scales as light count goes up, so potentially Forward+ can be vastly faster.

    The only difference in the code is where lights are looped. Forward plus uses the specific iterator, while in Deferred i pass the light count from the light culling result and loop with that.

    Not sure how is all handled internally though. I will do some tests with iterating the lights in Forward+ using the culling result to see if that is the only reason Forward+ is so much faster.
     
  39. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Graph Deferred

    Non Graph Deferred

    Hi,

    I have an update, i managed to finish the conversion of the volume lights and real time GI in deferred mode.

    The issue is that in Deferred Graph mode i get 5ms more in processing than in non Graph, using the unsafe pass.

    Is this expected for Graph to be much slower or this is something addressed in Unity 6000 ? I use Unity 2023.3.0b4 to test now.

    Thanks
     
  40. AljoshaD

    AljoshaD

    Unity Technologies

    Joined:
    May 27, 2019
    Posts:
    282
    No this is not expected. There's a main thread CPU cost that is introduced by RenderGraph but in the latest beta patch versions this should have been optimized to the point that there is no difference. Some optimization work is still ongoing though.
     
    nasos_333 likes this.
  41. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Thanks for the feedback on this, so will be best to retest when the public versions with the latest patches is out to do the final performance tests.
     
  42. Kabinet13

    Kabinet13

    Joined:
    Jun 13, 2019
    Posts:
    154
    I'd be interested to see profiler (and gpu profiler) screenshots from both, I'm guessing some work is being doubled up somewhere or something. Because rendergraph shouldn't have 5ms of overhead, and if it does you've just found a serious bug.
     
    nasos_333 likes this.
  43. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    I have been working to optimize this and indeed seems was my fault afterall, it was a combination of leaving some extra log entries while the Graph was running and some other optimizations that had not yet gone in Graph version, now are almost on par. The video is from Graph version and run very fluidly in my 4050RTX Laptop now.
     
    Last edited: Apr 4, 2024
    ElliotB likes this.
  44. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    297
    What did you think of the Graph API after using it more?
     
  45. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    So far looks to do the same thing as the previous setup, cant see any difference, but i suppose if combine some of my effects that reuse resources, could potentially be faster.
     
  46. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    Hi,

    One question, where is the target texture for each of the renderer list results defined ?

    For example i want to render the Gbuffer group using "new ShaderTagId("UniversalGBuffer")" in the below textures

    ConfigureTarget(new RTHandle[] {
    albedoHandle,
    specularHandle,
    worldPosHandle,
    depthNormalHandle,
    });

    Thanks
     
  47. ilcane87

    ilcane87

    Joined:
    Apr 29, 2022
    Posts:
    10
    I'd like to add a question to the list.

    I've gone through the whole thread and based on the words of Unity staff such as these three posts, what I could gather is that you shouldn't use Render Graph unless all you'd like to do is a single Blit, or at most a few Blits but only if targeting render textures of the same size, otherwise you'd be compelled to create a separate pass for each Blit, and since those passes can't be merged you'd not only gain no GPU performance from it, but you'd also incur a higher CPU overhead for handling all the passes you had to create; so unless you can meet the specific requirements to take advantage of Render Graph, you should instead use Unsafe Pass.

    If I understood correctly so far, it seems to me that Unsafe Pass is the general purpose tool for custom render passes, while Render Graph is just for those edge cases where you can afford to get around its limitations for a performance boost.
    What's made me confused however is that I've also seen mentioned several times that using Render Graph would be more "future proof" than using Unsafe Pass, but as things stand I cannot imagine a future without Unsafe Pass unless Render Graph is improved to be able to tackle all those scenarios that are best handled with Unsafe Pass, with at least equal performance.

    So my question is: does Unity have such plans, or did I misunderstand what they meant with "future proof", and Unsafe Pass is going to live and be maintained beside Render Graph indefinitely?

    Thank you very much.
     
    Last edited: Apr 5, 2024
  48. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,539
    I think was mentioned that safe pass will always be an option, i asked the same question if i recall.
     
  49. ilcane87

    ilcane87

    Joined:
    Apr 29, 2022
    Posts:
    10
    That's what I would've normally expected, but even one of the posts that highlighted the importance of Unsafe Pass had this excerpt in it:
    Which I found a bit contradictory, hence my question.
     
  50. oliverschnabel

    oliverschnabel

    Unity Technologies

    Joined:
    Mar 13, 2018
    Posts:
    49
    In the file GBufferPass.cs in the Render() function you can see as a reference how we bind the GBuffer targets using the Renderer List (SetRenderAttachment). The Renderer List itself with "new ShaderTagId("UniversalGBuffer")" is created in InitRendererLists().

    Does this help for your case?
     
    nasos_333 likes this.