Skip to content

Commit 8f42637

Browse files
YohannVaastUnityEvergreen
authored andcommitted
Render Graph - Fix support of Transient Textures & Buffers.
Transient resources support is broken in NRP RG. Reported initially here: https://forum.unity.com/threads/introduction-of-render-graph-in-the-universal-render-pipeline-urp.1500833/page-7#post-9768534 This PR fixes this behavior by removing the error in the console and adding the support of transient resources through the `transientResourceList`. Added some unit tests to verify transient resources works well / well created and are can't be shared between passes.
1 parent 360bc63 commit 8f42637

File tree

6 files changed

+124
-20
lines changed

6 files changed

+124
-20
lines changed

Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/Compiler/NativePassCompiler.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,34 @@ void BuildGraph()
284284

285285
ctxPass.numInputs++;
286286
}
287+
288+
var resourceTrans = inputPass.transientResourceList[type];
289+
var resourceTransCount = resourceTrans.Count;
290+
291+
for (var i = 0; i < resourceTransCount; ++i)
292+
{
293+
var resource = resourceTrans[i];
294+
295+
// Mark this pass as reading from this version of the resource
296+
ctx.resources[resource].RegisterReadingPass(ctx, resource, passId, ctxPass.numInputs);
297+
298+
ctx.inputData.Add(new PassInputData
299+
{
300+
resource = resource,
301+
});
302+
303+
ctxPass.numInputs++;
304+
305+
// Mark this pass as writing to this version of the resource
306+
ctx.resources[resource].SetWritingPass(ctx, resource, passId);
307+
308+
ctx.outputData.Add(new PassOutputData
309+
{
310+
resource = resource,
311+
});
312+
313+
ctxPass.numOutputs++;
314+
}
287315
}
288316
}
289317
}

Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ public bool nativeRenderPassesEnabled
371371
internal/*for tests*/ RenderGraphResourceRegistry m_Resources;
372372
RenderGraphObjectPool m_RenderGraphPool = new RenderGraphObjectPool();
373373
RenderGraphBuilders m_builderInstance = new RenderGraphBuilders();
374-
List<RenderGraphPass> m_RenderPasses = new List<RenderGraphPass>(64);
374+
internal/*for tests*/ List<RenderGraphPass> m_RenderPasses = new List<RenderGraphPass>(64);
375375
List<RendererListHandle> m_RendererLists = new List<RendererListHandle>(32);
376376
RenderGraphDebugParams m_DebugParameters = new RenderGraphDebugParams();
377377
RenderGraphLogger m_FrameInformationLogger = new RenderGraphLogger();

Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public struct RenderGraphBuilder : IDisposable
2525
/// <returns>An updated resource handle to the input resource.</returns>
2626
public TextureHandle UseColorBuffer(in TextureHandle input, int index)
2727
{
28-
CheckResource(input.handle, true);
28+
CheckResource(input.handle, false);
2929
m_Resources.IncrementWriteCount(input.handle);
3030
m_RenderPass.SetColorBuffer(input, index);
3131
return input;
@@ -39,7 +39,7 @@ public TextureHandle UseColorBuffer(in TextureHandle input, int index)
3939
/// <returns>An updated resource handle to the input resource.</returns>
4040
public TextureHandle UseDepthBuffer(in TextureHandle input, DepthAccess flags)
4141
{
42-
CheckResource(input.handle, true);
42+
CheckResource(input.handle, false);
4343

4444
if ((flags & DepthAccess.Write) != 0)
4545
m_Resources.IncrementWriteCount(input.handle);
@@ -320,15 +320,15 @@ void Dispose(bool disposing)
320320
}
321321

322322
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
323-
void CheckResource(in ResourceHandle res, bool dontCheckTransientReadWrite = false)
323+
void CheckResource(in ResourceHandle res, bool checkTransientReadWrite = true)
324324
{
325325
if(RenderGraph.enableValidityChecks)
326326
{
327327
if (res.IsValid())
328328
{
329329
int transientIndex = m_Resources.GetRenderGraphResourceTransientIndex(res);
330330
// We have dontCheckTransientReadWrite here because users may want to use UseColorBuffer/UseDepthBuffer API to benefit from render target auto binding. In this case we don't want to raise the error.
331-
if (transientIndex == m_RenderPass.index && !dontCheckTransientReadWrite)
331+
if (transientIndex == m_RenderPass.index && checkTransientReadWrite)
332332
{
333333
Debug.LogError($"Trying to read or write a transient resource at pass {m_RenderPass.name}.Transient resource are always assumed to be both read and written.");
334334
}

Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilders.cs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,31 +74,27 @@ public void EnableFoveatedRasterization(bool value)
7474
public BufferHandle CreateTransientBuffer(in BufferDesc desc)
7575
{
7676
var result = m_Resources.CreateBuffer(desc, m_RenderPass.index);
77-
m_RenderPass.AddTransientResource(result.handle);
77+
UseResource(result.handle, AccessFlags.Write | AccessFlags.Read, isTransient: true);
7878
return result;
7979
}
8080

8181
public BufferHandle CreateTransientBuffer(in BufferHandle computebuffer)
8282
{
8383
var desc = m_Resources.GetBufferResourceDesc(computebuffer.handle);
84-
var result = m_Resources.CreateBuffer(desc, m_RenderPass.index);
85-
m_RenderPass.AddTransientResource(result.handle);
86-
return result;
84+
return CreateTransientBuffer(desc);
8785
}
8886

8987
public TextureHandle CreateTransientTexture(in TextureDesc desc)
9088
{
9189
var result = m_Resources.CreateTexture(desc, m_RenderPass.index);
92-
m_RenderPass.AddTransientResource(result.handle);
90+
UseResource(result.handle, AccessFlags.Write | AccessFlags.Read, isTransient: true);
9391
return result;
9492
}
9593

9694
public TextureHandle CreateTransientTexture(in TextureHandle texture)
9795
{
9896
var desc = m_Resources.GetTextureResourceDesc(texture.handle);
99-
var result = m_Resources.CreateTexture(desc, m_RenderPass.index);
100-
m_RenderPass.AddTransientResource(result.handle);
101-
return result;
97+
return CreateTransientTexture(desc);
10298
}
10399

104100
public void Dispose()
@@ -188,7 +184,7 @@ private void ValidateWriteTo(in ResourceHandle handle)
188184
}
189185
}
190186

191-
private ResourceHandle UseResource(in ResourceHandle handle, AccessFlags flags)
187+
private ResourceHandle UseResource(in ResourceHandle handle, AccessFlags flags, bool isTransient = false)
192188
{
193189
CheckResource(handle);
194190

@@ -206,6 +202,12 @@ private ResourceHandle UseResource(in ResourceHandle handle, AccessFlags flags)
206202
versioned = handle;
207203
}
208204

205+
if (isTransient)
206+
{
207+
m_RenderPass.AddTransientResource(versioned);
208+
return GetLatestVersionHandle(handle);
209+
}
210+
209211
m_RenderPass.AddResourceRead(versioned);
210212

211213
if ((flags & AccessFlags.Read) == 0)
@@ -475,22 +477,22 @@ private ResourceHandle GetLatestVersionHandle(in ResourceHandle handle)
475477
}
476478

477479
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
478-
void CheckResource(in ResourceHandle res, bool dontCheckTransientReadWrite = false)
480+
void CheckResource(in ResourceHandle res, bool checkTransientReadWrite = false)
479481
{
480482
if(RenderGraph.enableValidityChecks)
481483
{
482484
if (res.IsValid())
483485
{
484486
int transientIndex = m_Resources.GetRenderGraphResourceTransientIndex(res);
485487
// We have dontCheckTransientReadWrite here because users may want to use UseColorBuffer/UseDepthBuffer API to benefit from render target auto binding. In this case we don't want to raise the error.
486-
if (transientIndex == m_RenderPass.index && !dontCheckTransientReadWrite)
488+
if (transientIndex == m_RenderPass.index && checkTransientReadWrite)
487489
{
488490
Debug.LogError($"Trying to read or write a transient resource at pass {m_RenderPass.name}.Transient resource are always assumed to be both read and written.");
489491
}
490492

491493
if (transientIndex != -1 && transientIndex != m_RenderPass.index)
492494
{
493-
throw new ArgumentException($"Trying to use a transient texture (pass index {transientIndex}) in a different pass (pass index {m_RenderPass.index}).");
495+
throw new ArgumentException($"Trying to use a transient {res.type} (pass index {transientIndex}) in a different pass (pass index {m_RenderPass.index}).");
494496
}
495497
}
496498
else

Packages/com.unity.render-pipelines.core/Tests/Editor/NativePassCompilerRenderGraphTests.cs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using NUnit.Framework;
2+
using System;
23
using System.Collections.Generic;
34
using UnityEngine.Experimental.Rendering;
45
using UnityEngine.Rendering.RenderGraphModule;
@@ -820,7 +821,6 @@ public void BuffersWork()
820821
Assert.AreEqual(1, lastUsedList.Length);
821822
Assert.AreEqual(buffer.handle.index, lastUsedList[0].index);
822823
Assert.AreEqual(RenderGraphResourceType.Buffer, lastUsedList[0].type);
823-
824824
}
825825

826826
[Test]
@@ -888,5 +888,79 @@ public void ResolveMSAAImportColor()
888888
// When discarding MSAA color, we only discard the MSAA buffers but keep the resolved texture
889889
Assert.AreEqual(RenderBufferStoreAction.Resolve, passes[0].attachments[1].storeAction);
890890
}
891+
892+
[Test]
893+
public void TransientTexturesCantBeReused()
894+
{
895+
var g = AllocateRenderGraph();
896+
var buffers = ImportAndCreateBuffers(g);
897+
var textureTransientHandle = TextureHandle.nullHandle;
898+
899+
// Render something to textureTransientHandle, created locally in the pass.
900+
// No exception and no error(s) should be thrown in the Console.
901+
{
902+
var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData);
903+
904+
var textDesc = new TextureDesc(Vector2.one, false, false)
905+
{
906+
width = 1920,
907+
height = 1080,
908+
colorFormat = GraphicsFormat.B10G11R11_UFloatPack32,
909+
clearBuffer = true,
910+
clearColor = Color.red,
911+
name = "Transient Texture"
912+
};
913+
textureTransientHandle = builder.CreateTransientTexture(textDesc);
914+
915+
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
916+
builder.Dispose();
917+
918+
Assert.IsTrue(g.m_RenderPasses.Count != 0);
919+
Assert.IsTrue(g.m_RenderPasses[^1].transientResourceList[(int)textureTransientHandle.handle.type].Count != 0);
920+
}
921+
922+
// Try to render something to textureTransientHandle, reusing the previous TextureHandle.
923+
// UseTexture should throw an exception.
924+
Assert.Throws<ArgumentException>(() =>
925+
{
926+
var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData);
927+
builder.UseTexture(textureTransientHandle, AccessFlags.Read | AccessFlags.Write);
928+
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
929+
builder.Dispose();
930+
});
931+
}
932+
933+
[Test]
934+
public void TransientBuffersCantBeReused()
935+
{
936+
var g = AllocateRenderGraph();
937+
var buffers = ImportAndCreateBuffers(g);
938+
var bufferTransientHandle = BufferHandle.nullHandle;
939+
940+
// Render something to textureTransientHandle, created locally in the pass.
941+
// No error(s) should be thrown in the Console.
942+
{
943+
var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData);
944+
945+
var prefixBuffer0Desc = new BufferDesc(1920 * 1080, 4, GraphicsBuffer.Target.Raw) { name = "prefixBuffer0" };
946+
bufferTransientHandle = builder.CreateTransientBuffer(prefixBuffer0Desc);
947+
948+
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
949+
builder.Dispose();
950+
951+
Assert.IsTrue(g.m_RenderPasses.Count != 0);
952+
Assert.IsTrue(g.m_RenderPasses[^1].transientResourceList[(int)bufferTransientHandle.handle.type].Count != 0);
953+
}
954+
955+
// Try to render something to textureTransientHandle, reusing the previous TextureHandle.
956+
// UseTexture should throw an exception.
957+
Assert.Throws<ArgumentException>(() =>
958+
{
959+
var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData);
960+
builder.UseBuffer(bufferTransientHandle, AccessFlags.Read | AccessFlags.Write);
961+
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
962+
builder.Dispose();
963+
});
964+
}
891965
}
892966
}

Packages/com.unity.render-pipelines.core/Tests/Editor/RenderGraphTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ public void TransientResourceNotCulled()
481481
}
482482

483483
[Test]
484-
public void AsyncPassWriteWaitOnGraphcisPipe()
484+
public void AsyncPassWriteWaitOnGraphicsPipe()
485485
{
486486
TextureHandle texture0;
487487
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
@@ -513,7 +513,7 @@ public void AsyncPassWriteWaitOnGraphcisPipe()
513513
}
514514

515515
[Test]
516-
public void AsyncPassReadWaitOnGraphcisPipe()
516+
public void AsyncPassReadWaitOnGraphicsPipe()
517517
{
518518
TextureHandle texture0;
519519
TextureHandle texture1;

0 commit comments

Comments
 (0)