Skip to content

Commit a22dba4

Browse files
UnityAljoshaEvergreen
authored andcommitted
fix UUM-68261 URP ignores resourceData.cameraColor when set in a user pass AfterRenderPostProcessing
fix [UUM-68261](https://jira.unity3d.com/browse/UUM-68261) URP ignores resourceData.cameraColor when set in a user pass AfterRenderPostProcessing Update the RenderGraph blit with material sample to cover this scenario, and demonstrate how to use the ResourceData to avoid a copy blit back to the resource. This update also fixes bugs in the sample.
1 parent 5c58d14 commit a22dba4

File tree

6 files changed

+166
-123
lines changed

6 files changed

+166
-123
lines changed

Packages/com.unity.render-pipelines.universal/Runtime/Passes/FinalBlitPass.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ private void InitPassData(UniversalCameraData cameraData, ref PassData passData,
259259
passData.blitMaterialData = m_BlitMaterialData[(int)blitType];
260260
}
261261

262-
internal void Render(RenderGraph renderGraph, UniversalCameraData cameraData, TextureHandle src, TextureHandle dest, TextureHandle overlayUITexture)
262+
internal void Render(RenderGraph renderGraph, UniversalCameraData cameraData, in TextureHandle src, in TextureHandle dest, TextureHandle overlayUITexture)
263263
{
264264
using (var builder = renderGraph.AddRasterRenderPass<PassData>("Final Blit", out var passData, base.profilingSampler))
265265
{

Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,9 +1272,7 @@ private void OnAfterRendering(RenderGraph renderGraph)
12721272

12731273
bool resolvePostProcessingToCameraTarget = !hasCaptureActions && !hasPassesAfterPostProcessing && !applyFinalPostProcessing;
12741274
bool needsColorEncoding = DebugHandler == null || !DebugHandler.HDRDebugViewIsActive(cameraData.resolveFinalTarget);
1275-
1276-
TextureHandle cameraColor = resourceData.cameraColor;
1277-
1275+
12781276
DebugHandler debugHandler = ScriptableRenderPass.GetActiveDebugHandler(cameraData);
12791277
bool resolveToDebugScreen = debugHandler != null && debugHandler.WriteToDebugScreenTexture(cameraData.resolveFinalTarget);
12801278
// Allocate debug screen texture if the debug mode needs it.
@@ -1316,13 +1314,12 @@ private void OnAfterRendering(RenderGraph renderGraph)
13161314
// that the post processing output is rendered to a properly sized target. Any rendering performed beyond this point will also use the upscaled targets.
13171315
if (cameraData.IsSTPEnabled())
13181316
m_UseUpscaledColorHandle = true;
1319-
1320-
cameraColor = renderGraph.ImportTexture(nextRenderGraphCameraColorHandle, importColorParams);
1321-
resourceData.cameraColor = cameraColor;
1317+
1318+
resourceData.cameraColor = renderGraph.ImportTexture(nextRenderGraphCameraColorHandle, importColorParams);
13221319
}
13231320

13241321
// Desired target for post-processing pass.
1325-
var target = isTargetBackbuffer ? backbuffer : cameraColor;
1322+
var target = isTargetBackbuffer ? backbuffer : resourceData.cameraColor;
13261323

13271324
// but we may actually render to an intermediate texture if debug views are enabled.
13281325
// In that case, DebugHandler will eventually blit DebugScreenTexture into AfterPostProcessColor.
@@ -1362,7 +1359,9 @@ private void OnAfterRendering(RenderGraph renderGraph)
13621359
target = resourceData.debugScreenColor;
13631360
}
13641361

1365-
m_PostProcessPasses.finalPostProcessPass.RenderFinalPassRenderGraph(renderGraph, frameData, in cameraColor, in overlayUITexture, in target, needsColorEncoding);
1362+
// make sure we are accessing the proper camera color in case it was replaced by injected passes
1363+
var source = resourceData.cameraColor;
1364+
m_PostProcessPasses.finalPostProcessPass.RenderFinalPassRenderGraph(renderGraph, frameData, in source, in overlayUITexture, in target, needsColorEncoding);
13661365

13671366
resourceData.activeColorID = UniversalResourceData.ActiveID.BackBuffer;
13681367
resourceData.activeDepthID = UniversalResourceData.ActiveID.BackBuffer;
@@ -1395,11 +1394,11 @@ private void OnAfterRendering(RenderGraph renderGraph)
13951394
}
13961395

13971396
// make sure we are accessing the proper camera color in case it was replaced by injected passes
1398-
cameraColor = resourceData.cameraColor;
1397+
var source = resourceData.cameraColor;
13991398

14001399
debugHandler?.UpdateShaderGlobalPropertiesForFinalValidationPass(renderGraph, cameraData, !resolveToDebugScreen);
14011400

1402-
m_FinalBlitPass.Render(renderGraph, cameraData, cameraColor, target, overlayUITexture);
1401+
m_FinalBlitPass.Render(renderGraph, cameraData, source, target, overlayUITexture);
14031402
resourceData.activeColorID = UniversalResourceData.ActiveID.BackBuffer;
14041403
resourceData.activeDepthID = UniversalResourceData.ActiveID.BackBuffer;
14051404
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
using UnityEngine;
2+
using UnityEngine.Rendering.RenderGraphModule;
3+
using UnityEngine.Rendering;
4+
using UnityEngine.Rendering.Universal;
5+
6+
//This example blits the active CameraColor to a new texture. It shows how to do a blit with material, and how to use the ResourceData to avoid another blit back to the active color target.
7+
//This example is for API demonstrative purposes.
8+
9+
public class BlitAndSwapColorRendererFeature : ScriptableRendererFeature
10+
{
11+
12+
// This pass blits the whole screen for a given material to a temp texture, and swaps the UniversalResourceData.cameraColor to this temp texture.
13+
// Therefor, the next pass that references the cameraColor will reference this new temp texture as the cameraColor, saving us a blit.
14+
// Using the ResourceData, you can manage swapping of resources yourself and don't need a bespoke API like the SwapColorBuffer API that was specific for the cameraColor.
15+
// This allows you to write more decoupled passes without the added costs of avoidable copies/blits.
16+
class BlitAndSwapColorPass : ScriptableRenderPass
17+
{
18+
const string m_PassName = "BlitAndSwapColorPass";
19+
20+
// The data we want to transfer to the render function after recording.
21+
class PassData
22+
{
23+
// For the blit operation we will need the source and destination of the color attachments.
24+
public TextureHandle source;
25+
public TextureHandle destination;
26+
// We will also need a material to transform the color attachment when making a blit operation.
27+
public Material material;
28+
}
29+
30+
// Scale bias is used to blit from source to distination given a 2d scale in the x and y parameters
31+
// and an offset in the z and w parameters.
32+
static Vector4 scaleBias = new Vector4(1f, 1f, 0f, 0f);
33+
34+
// Material used in the blit operation.
35+
Material m_BlitMaterial;
36+
37+
// Function used to transfer the material from the renderer feature to the render pass.
38+
public void Setup(Material mat)
39+
{
40+
m_BlitMaterial = mat;
41+
}
42+
43+
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
44+
{
45+
var resourceData = frameData.Get<UniversalResourceData>();
46+
47+
//This should never happen since we set m_Pass.requiresIntermediateTexture = true;
48+
//Unless you set the render event to AfterRendering, where we only have the BackBuffer.
49+
if (resourceData.isActiveTargetBackBuffer)
50+
{
51+
Debug.LogError($"Skipping render pass. BlitAndSwapColorRendererFeature requires an intermediate ColorTexture, we can't use the BackBuffer as a texture input.");
52+
return;
53+
}
54+
55+
56+
// Starts the recording of the render graph pass given the name of the pass
57+
// and outputting the data used to pass data to the execution of the render function.
58+
using (var builder = renderGraph.AddRasterRenderPass<PassData>(m_PassName, out var passData))
59+
{
60+
// Initialize the pass data
61+
InitPassData(renderGraph, frameData, ref passData);
62+
63+
// Sets input.
64+
builder.UseTexture(passData.source);
65+
66+
// Sets output.
67+
builder.SetRenderAttachment(passData.destination, 0);
68+
69+
// Sets the render function.
70+
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => ExecutePass(data, rgContext));
71+
72+
73+
//FrameData allows to get and set internal pipeline buffers. Here we update the CameraColorBuffer to the texture that we just wrote to in this pass.
74+
//Because RenderGraph manages the pipeline resources and dependencies, following up passes will correctly use the right color buffer.
75+
//This optimization has some caveats. You have to be careful when the color buffer is persistent across frames and between different cameras, such as in camera stacking.
76+
//In those cases you need to make sure your texture is an RTHandle and that you properly manage the lifecycle of it.
77+
resourceData.cameraColor = passData.destination;
78+
}
79+
}
80+
81+
// ExecutePass is the render function for each of the blit render graph recordings.
82+
// This is good practice to avoid using variables outside of the lambda it is called from.
83+
// It is static to avoid using member variables which could cause unintended behaviour.
84+
static void ExecutePass(PassData data, RasterGraphContext rgContext)
85+
{
86+
// We can use blit with or without a material both using the static scaleBias to avoid reallocations.
87+
if (data.material == null)
88+
Blitter.BlitTexture(rgContext.cmd, data.source, scaleBias, 0, false);
89+
else
90+
Blitter.BlitTexture(rgContext.cmd, data.source, scaleBias, data.material, 0);
91+
}
92+
93+
private void InitPassData(RenderGraph renderGraph, ContextContainer frameData, ref PassData passData)
94+
{
95+
// Fill up the passData with the data needed by the passes
96+
97+
// UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures
98+
// The active color and depth textures are the main color and depth buffers that the camera renders into
99+
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
100+
101+
// The destination texture is created here,
102+
// the texture is created with the same dimensions as the active color texture, but with no depth buffer, being a copy of the color texture
103+
104+
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
105+
RenderTextureDescriptor desc = cameraData.cameraTargetDescriptor;
106+
desc.depthBufferBits = 0;
107+
108+
TextureHandle destination = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, $"CameraTarget-{m_PassName}", false);
109+
110+
passData.source = resourceData.activeColorTexture;
111+
passData.destination = destination;
112+
passData.material = m_BlitMaterial;
113+
}
114+
}
115+
116+
117+
[Tooltip("The material used when making the blit operation.")]
118+
public Material material;
119+
120+
[Tooltip("The event where to inject the pass.")]
121+
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
122+
123+
BlitAndSwapColorPass m_Pass;
124+
125+
// Here you can create passes and do the initialization of them. This is called everytime serialization happens.
126+
public override void Create()
127+
{
128+
m_Pass = new BlitAndSwapColorPass();
129+
130+
// Configures where the render pass should be injected.
131+
m_Pass.renderPassEvent = renderPassEvent;
132+
}
133+
134+
// Here you can inject one or multiple render passes in the renderer.
135+
// This method is called when setting up the renderer once per-camera.
136+
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
137+
{
138+
// Early exit if there are no materials.
139+
if (material == null)
140+
{
141+
Debug.LogWarning("BlitAndSwapColorRendererFeature material is null and will be skipped.");
142+
return;
143+
}
144+
145+
m_Pass.Setup(material);
146+
renderer.EnqueuePass(m_Pass);
147+
148+
//The pass will read the current color texture. That needs to be an intermediate texture. It's not supported to use the BackBuffer as input texture.
149+
//By setting this property, URP will automatically create an intermediate texture.
150+
m_Pass.requiresIntermediateTexture = true;
151+
}
152+
}
153+
154+

Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitAndSwapColorRendererFeature.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterialRenderFeature.cs

Lines changed: 0 additions & 110 deletions
This file was deleted.

Packages/com.unity.render-pipelines.universal/Samples~/URPRenderGraphSamples/BlitWithMaterial/BlitWithMaterialRenderFeature.cs.meta

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)