A game about forced loneliness, made by TACStudios
1using NUnit.Framework;
2using System;
3using System.Collections.Generic;
4using UnityEngine.Experimental.Rendering;
5using UnityEngine.Rendering.RenderGraphModule;
6using UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler;
7
8namespace UnityEngine.Rendering.Tests
9{
10 class NativePassCompilerRenderGraphTests
11 {
12 class RenderGraphTestPassData
13 {
14 public TextureHandle[] textures = new TextureHandle[8];
15 public BufferHandle[] buffers = new BufferHandle[8];
16 }
17
18 TextureDesc SimpleTextureDesc(string name, int w, int h, int samples)
19 {
20 TextureDesc result = new TextureDesc(w, h);
21 result.msaaSamples = (MSAASamples)samples;
22 result.format = GraphicsFormat.R8G8B8A8_UNorm;
23 result.name = name;
24 return result;
25 }
26
27 class TestBuffers
28 {
29 public TextureHandle backBuffer;
30 public TextureHandle depthBuffer;
31 public TextureHandle[] extraBuffers = new TextureHandle[10];
32 public TextureHandle extraDepthBuffer;
33 };
34
35 TestBuffers ImportAndCreateBuffers(RenderGraph g)
36 {
37 TestBuffers result = new TestBuffers();
38 var backBuffer = BuiltinRenderTextureType.CameraTarget;
39 var backBufferHandle = RTHandles.Alloc(backBuffer, "Backbuffer Color");
40 var depthBuffer = BuiltinRenderTextureType.Depth;
41 var depthBufferHandle = RTHandles.Alloc(depthBuffer, "Backbuffer Depth");
42 var extraDepthBufferHandle = RTHandles.Alloc(depthBuffer, "Extra Depth Buffer");
43
44 RenderTargetInfo importInfo = new RenderTargetInfo();
45 RenderTargetInfo importInfoDepth = new RenderTargetInfo();
46 importInfo.width = 1024;
47 importInfo.height = 768;
48 importInfo.volumeDepth = 1;
49 importInfo.msaaSamples = 1;
50 importInfo.format = GraphicsFormat.R16G16B16A16_SFloat;
51 result.backBuffer = g.ImportTexture(backBufferHandle, importInfo);
52
53 importInfoDepth = importInfo;
54 importInfoDepth.format = GraphicsFormat.D32_SFloat_S8_UInt;
55 result.depthBuffer = g.ImportTexture(depthBufferHandle, importInfoDepth);
56
57 importInfo.format = GraphicsFormat.D24_UNorm;
58 result.extraDepthBuffer = g.ImportTexture(extraDepthBufferHandle, importInfoDepth);
59
60 for (int i = 0; i < result.extraBuffers.Length; i++)
61 {
62 result.extraBuffers[i] = g.CreateTexture(SimpleTextureDesc("ExtraBuffer" + i, 1024, 768, 1));
63 }
64
65 return result;
66 }
67
68 RenderGraph AllocateRenderGraph()
69 {
70 RenderGraph g = new RenderGraph();
71 g.nativeRenderPassesEnabled = true;
72 return g;
73 }
74
75 [Test]
76 public void SimpleMergePasses()
77 {
78 var g = AllocateRenderGraph();
79
80 var buffers = ImportAndCreateBuffers(g);
81
82 // Render something to 0,1
83 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
84 {
85 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
86 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
87 builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
88 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
89 }
90
91 // Render extra bits to 1
92 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
93 {
94 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
95 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
96 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
97 }
98 // Render to final buffer
99 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
100 {
101 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
102 builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
103 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
104 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
105 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
106 }
107
108 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
109 var passes = result.contextData.GetNativePasses();
110
111 Assert.AreEqual(1, passes.Count);
112 Assert.AreEqual(4, passes[0].attachments.size);
113 Assert.AreEqual(3, passes[0].numGraphPasses);
114
115 ref var firstAttachment = ref passes[0].attachments[0];
116 Assert.AreEqual(RenderBufferLoadAction.Load, firstAttachment.loadAction);
117
118 ref var secondAttachment = ref passes[0].attachments[1];
119 Assert.AreEqual(RenderBufferLoadAction.Clear, secondAttachment.loadAction);
120
121 ref var thirdAttachment = ref passes[0].attachments[2];
122 Assert.AreEqual(RenderBufferLoadAction.Clear, thirdAttachment.loadAction);
123
124 ref var fourthAttachment = ref passes[0].attachments[3];
125 Assert.AreEqual(RenderBufferLoadAction.Load, fourthAttachment.loadAction);
126 }
127
128 /*[Test]
129 public void MergeNonRenderPasses()
130 {
131 RenderGraph g = new RenderGraph();
132
133 var buffers = ImportAndCreateBuffers(g);
134
135 // Render something to 0,1
136 {
137 var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData);
138 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
139 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
140 builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
141 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
142 builder.Dispose();
143 }
144
145 // Render extra bits to 1
146 {
147 var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData);
148 // This does something like CommandBufffer.SetGlobal or something that doesn't do any rendering
149 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
150 builder.AllowPassCulling(false);
151 builder.Dispose();
152 }
153 // Render to final buffer
154 {
155 var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData);
156 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
157 builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
158 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
159 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
160 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
161 builder.Dispose();
162 }
163
164 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
165 var passes = result.contextData.GetNativePasses();
166
167 Assert.AreEqual(1, passes.Count);
168 Assert.AreEqual(4, passes[0].attachments.size);
169 Assert.AreEqual(3, passes[0].numGraphPasses);
170 Assert.AreEqual(2, passes[0].numNativeSubPasses);
171 }*/
172
173 [Test]
174 public void MergeDepthPassWithNoDepthPass()
175 {
176 var g = AllocateRenderGraph();
177 var buffers = ImportAndCreateBuffers(g);
178
179 // depth
180 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
181 {
182 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
183 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
184 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
185 }
186
187 // with no depth
188 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
189 {
190 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
191 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
192 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
193 }
194
195 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
196 var passes = result.contextData.GetNativePasses();
197
198 Assert.AreEqual(1, passes.Count);
199 Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.EndOfGraph, passes[0].breakAudit.reason);
200 }
201
202 [Test]
203 public void MergeNoDepthPassWithDepthPass()
204 {
205 var g = AllocateRenderGraph();
206 var buffers = ImportAndCreateBuffers(g);
207
208 // no depth
209 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
210 {
211 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
212 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
213 }
214
215 // with depth
216 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
217 {
218 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
219 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
220 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
221 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
222 }
223
224 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
225 var passes = result.contextData.GetNativePasses();
226
227 Assert.AreEqual(1, passes.Count);
228 Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.EndOfGraph, passes[0].breakAudit.reason);
229 }
230
231 [Test]
232 public void MergeMultiplePassesDifferentDepth()
233 {
234 var g = AllocateRenderGraph();
235 var buffers = ImportAndCreateBuffers(g);
236
237 // no depth
238 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
239 {
240 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
241 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
242 }
243
244 // with depth
245 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
246 {
247 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
248 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
249 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
250 }
251
252 // with no depth
253 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
254 {
255 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
256 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
257 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
258 }
259
260 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
261 var passes = result.contextData.GetNativePasses();
262
263 Assert.AreEqual(1, passes.Count);
264 Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.EndOfGraph, passes[0].breakAudit.reason);
265 }
266
267 [Test]
268 public void MergeDifferentDepthFormatsBreaksPass()
269 {
270 var g = AllocateRenderGraph();
271 var buffers = ImportAndCreateBuffers(g);
272
273 // depth
274 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
275 {
276 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
277 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
278 }
279
280 // with different depth
281 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
282 {
283 builder.SetRenderAttachmentDepth(buffers.extraDepthBuffer, AccessFlags.Write);
284 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
285 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
286 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
287 }
288
289 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
290 var passes = result.contextData.GetNativePasses();
291
292 Assert.AreEqual(2, passes.Count);
293 Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.DifferentDepthTextures, passes[0].breakAudit.reason);
294 }
295
296 [Test]
297 public void VerifyMergeStateAfterMergingPasses()
298 {
299 var g = AllocateRenderGraph();
300 var buffers = ImportAndCreateBuffers(g);
301
302 // First pass, not culled.
303 {
304 var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData);
305 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
306 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
307 builder.AllowPassCulling(false);
308 builder.Dispose();
309 }
310
311 // Second pass, culled.
312 {
313 var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData);
314 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
315 builder.AllowPassCulling(true);
316 builder.Dispose();
317 }
318
319 // Third pass, not culled.
320 {
321 var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData);
322 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
323 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
324 builder.AllowPassCulling(false);
325 builder.Dispose();
326 }
327
328 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
329 var passes = result.contextData.GetNativePasses();
330
331 Assert.IsTrue(passes != null && passes.Count > 0);
332 var firstNativePass = passes[0];
333
334 var firstGraphPass = result.contextData.passData.ElementAt(firstNativePass.firstGraphPass);
335 var lastGraphPass = result.contextData.passData.ElementAt(firstNativePass.lastGraphPass);
336 var middleGraphPass = result.contextData.passData.ElementAt(firstNativePass.lastGraphPass - 1);
337
338 // Only 2 passes since one have been culled
339 Assert.IsTrue(firstNativePass.numGraphPasses == 2);
340
341 // All 3 passes including the culled one. We need to add +1 to obtain the correct passes count
342 // e.g lastGraphPass index = 2, firstGraphPass index = 0, so 2 - 0 = 2 passes, but we have 3 passes to consider
343 // (index 0, 1 and 2) so we add +1 for the correct count.
344 Assert.IsTrue(firstNativePass.lastGraphPass - firstNativePass.firstGraphPass + 1 == 3);
345
346 Assert.IsTrue(firstGraphPass.mergeState == PassMergeState.Begin);
347 Assert.IsTrue(lastGraphPass.mergeState == PassMergeState.End);
348 Assert.IsTrue(middleGraphPass.mergeState == PassMergeState.None);
349 }
350
351 [Test]
352 public void NonFragmentUseBreaksPass()
353 {
354 var g = AllocateRenderGraph();
355 var buffers = ImportAndCreateBuffers(g);
356
357 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
358 {
359 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
360 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
361 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
362 }
363
364 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
365 {
366 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
367 builder.UseTexture(buffers.extraBuffers[0], AccessFlags.Read);
368 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
369 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
370 }
371
372 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
373 var passes = result.contextData.GetNativePasses();
374
375 Assert.AreEqual(2, passes.Count);
376 Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.NextPassReadsTexture, passes[0].breakAudit.reason);
377 }
378
379 [Test]
380 public void NonRasterBreaksPass()
381 {
382 var g = AllocateRenderGraph();
383
384 var buffers = ImportAndCreateBuffers(g);
385
386 // No depth
387 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
388 {
389 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
390 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
391 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
392 }
393
394 // Compute touches extraBuffers[0]
395 using (var builder = g.AddComputePass<RenderGraphTestPassData>("ComputePass", out var passData))
396 {
397 builder.UseTexture(buffers.extraBuffers[0], AccessFlags.ReadWrite);
398 builder.SetRenderFunc((RenderGraphTestPassData data, ComputeGraphContext context) => { });
399 }
400
401 // With depth
402 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
403 {
404 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
405 builder.SetRenderAttachment(buffers.extraBuffers[0], 1, AccessFlags.Read);
406 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
407 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
408 }
409
410 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
411 var passes = result.contextData.GetNativePasses();
412
413 Assert.AreEqual(2, passes.Count);
414 Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.NonRasterPass, passes[0].breakAudit.reason);
415 }
416
417 [Test]
418 public void TooManyAttachmentsBreaksPass()
419 {
420 var g = AllocateRenderGraph();
421 var buffers = ImportAndCreateBuffers(g);
422
423 // 8 attachments
424 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
425 {
426 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
427 for (int i = 0; i < 6; i++)
428 {
429 builder.SetRenderAttachment(buffers.extraBuffers[i], i, AccessFlags.Write);
430 }
431 builder.SetRenderAttachment(buffers.backBuffer, 7, AccessFlags.Write);
432 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
433 }
434
435 // 2 additional attachments
436 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
437 {
438 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
439 for (int i = 0; i < 2; i++)
440 {
441 builder.SetRenderAttachment(buffers.extraBuffers[i + 6], i, AccessFlags.Write);
442 }
443 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
444 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
445 }
446
447 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
448 var passes = result.contextData.GetNativePasses();
449
450 Assert.AreEqual(2, passes.Count);
451 Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.AttachmentLimitReached, passes[0].breakAudit.reason);
452 }
453
454 [Test]
455 public void NativeSubPassesLimitNotExceeded()
456 {
457 var g = AllocateRenderGraph();
458 var buffers = ImportAndCreateBuffers(g);
459
460 // Native subpasses limit is 8 so go above
461 for (int i = 0; i < Rendering.RenderGraphModule.NativeRenderPassCompiler.NativePassCompiler.k_MaxSubpass + 2; i++)
462 {
463 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>($"TestPass_{i}", out var passData))
464 {
465 builder.SetInputAttachment(buffers.extraBuffers[1 - i % 2], 0);
466 builder.SetRenderAttachmentDepth(buffers.depthBuffer);
467 builder.SetRenderAttachment(buffers.extraBuffers[i % 2], 1);
468 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
469 }
470 }
471
472 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
473 var passes = result.contextData.GetNativePasses();
474
475 Assert.AreEqual(2, passes.Count);
476 Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.NativePassCompiler.k_MaxSubpass, passes[0].numGraphPasses);
477 Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.SubPassLimitReached, passes[0].breakAudit.reason);
478 }
479
480 [Test]
481 public void AllocateFreeInMergedPassesWorks()
482 {
483 var g = AllocateRenderGraph();
484
485 var buffers = ImportAndCreateBuffers(g);
486
487 // Render something to extra 0
488 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
489 {
490 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
491 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
492 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
493 }
494
495 // Render extra bits to extra 1, this causes 1 to be allocated in pass 1 which will be the first sub pass of the merged native pass
496 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
497 {
498 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
499 builder.SetRenderAttachment(buffers.extraBuffers[1], 0, AccessFlags.Write);
500 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
501 }
502
503 // Render extra bits to extra 2, this causes 2 to be allocated in pass 2 which will be the second sub pass of the merged native pass
504 // It's also the last time extra 1 is used so it gets freed
505 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
506 {
507 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
508 builder.SetRenderAttachment(buffers.extraBuffers[1], 0, AccessFlags.ReadWrite);
509 builder.SetRenderAttachment(buffers.extraBuffers[2], 1, AccessFlags.Write);
510 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
511 }
512
513 // Render to final buffer
514 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
515 {
516 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
517 builder.SetRenderAttachment(buffers.extraBuffers[2], 1, AccessFlags.Write);
518 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
519 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
520 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
521 }
522
523 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
524 var passes = result.contextData.GetNativePasses();
525
526 Assert.AreEqual(1, passes.Count);
527 Assert.AreEqual(5, passes[0].attachments.size); //3 extra + color + depth
528 Assert.AreEqual(4, passes[0].numGraphPasses);
529
530 // Pass 1 first used = {extra 1}
531 List<ResourceHandle> firstUsed = new List<ResourceHandle>();
532 ref var pass1Data = ref result.contextData.passData.ElementAt(1);
533 foreach (ref readonly var res in pass1Data.FirstUsedResources(result.contextData))
534 firstUsed.Add(res);
535
536 Assert.AreEqual(1, firstUsed.Count);
537 Assert.AreEqual(buffers.extraBuffers[1].handle.index, firstUsed[0].index);
538
539 // Pass 2 last used = {
540 List<ResourceHandle> lastUsed = new List<ResourceHandle>();
541 ref var pass2Data = ref result.contextData.passData.ElementAt(2);
542 foreach (ref readonly var res in pass2Data.LastUsedResources(result.contextData))
543 lastUsed.Add(res);
544
545 Assert.AreEqual(1, lastUsed.Count);
546 Assert.AreEqual(buffers.extraBuffers[1].handle.index, lastUsed[0].index);
547
548 }
549
550 [Test]
551 public void MemorylessWorks()
552 {
553 var g = AllocateRenderGraph();
554
555 var buffers = ImportAndCreateBuffers(g);
556
557 // Render something to extra 0
558 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
559 {
560 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
561 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
562 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
563 }
564
565 // Render to final buffer
566 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
567 {
568 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
569 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.ReadWrite);
570 builder.SetRenderAttachment(buffers.backBuffer, 1, AccessFlags.Write);
571 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
572 }
573
574 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
575 var passes = result.contextData.GetNativePasses();
576
577 Assert.AreEqual(1, passes.Count);
578 Assert.AreEqual(3, passes[0].attachments.size); //1 extra + color + depth
579 Assert.AreEqual(2, passes[0].numGraphPasses);
580
581 // Pass 0 : first used = {depthBuffer, extraBuffers[0]}
582 List<ResourceHandle> firstUsed = new List<ResourceHandle>();
583 ref var pass0Data = ref result.contextData.passData.ElementAt(0);
584 foreach (ref readonly var res in pass0Data.FirstUsedResources(result.contextData))
585 firstUsed.Add(res);
586
587 //Extra buffer 0 should be memoryless
588 Assert.AreEqual(2, firstUsed.Count);
589 Assert.AreEqual(buffers.extraBuffers[0].handle.index, firstUsed[1].index);
590 ref var info = ref result.contextData.UnversionedResourceData(firstUsed[1]);
591 Assert.AreEqual(true, info.memoryLess);
592
593 // Pass 1 : last used = {depthBuffer, extraBuffers[0], backBuffer}
594 List<ResourceHandle> lastUsed = new List<ResourceHandle>();
595 ref var pass1Data = ref result.contextData.passData.ElementAt(1);
596 foreach (var res in pass1Data.LastUsedResources(result.contextData))
597 lastUsed.Add(res);
598
599 Assert.AreEqual(3, lastUsed.Count);
600 Assert.AreEqual(buffers.extraBuffers[0].handle.index, lastUsed[1].index);
601 }
602
603 [Test]
604 public void InputAttachmentsWork()
605 {
606 var g = AllocateRenderGraph();
607
608 var buffers = ImportAndCreateBuffers(g);
609
610 // Render something to extra 0,1,2
611 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
612 {
613 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
614 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
615 builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
616 builder.SetRenderAttachment(buffers.extraBuffers[2], 2, AccessFlags.Write);
617 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
618 }
619
620 // Render to final buffer using extra 0 as attachment
621 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
622 {
623 builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.ReadWrite);
624 builder.SetRenderAttachment(buffers.backBuffer, 1, AccessFlags.Write);
625 builder.SetInputAttachment(buffers.extraBuffers[0], 0, AccessFlags.Read);
626 builder.SetInputAttachment(buffers.extraBuffers[1], 1, AccessFlags.Read);
627 builder.SetInputAttachment(buffers.extraBuffers[2], 2, AccessFlags.Read);
628 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
629 }
630
631 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
632 var nativePasses = result.contextData.GetNativePasses();
633
634 Assert.AreEqual(1, nativePasses.Count);
635 Assert.AreEqual(5, nativePasses[0].attachments.size); //3 extra + color + depth
636 Assert.AreEqual(2, nativePasses[0].numGraphPasses);
637
638 // Validate attachments
639 Assert.AreEqual(buffers.depthBuffer.handle.index, nativePasses[0].attachments[0].handle.index);
640 Assert.AreEqual(buffers.extraBuffers[0].handle.index, nativePasses[0].attachments[1].handle.index);
641 Assert.AreEqual(buffers.extraBuffers[1].handle.index, nativePasses[0].attachments[2].handle.index);
642 Assert.AreEqual(buffers.extraBuffers[2].handle.index, nativePasses[0].attachments[3].handle.index);
643 Assert.AreEqual(buffers.backBuffer.handle.index, nativePasses[0].attachments[4].handle.index);
644
645 // Sub Pass 0
646 ref var subPass = ref result.contextData.nativeSubPassData.ElementAt(nativePasses[0].firstNativeSubPass);
647 Assert.AreEqual(0, subPass.inputs.Length);
648
649 Assert.AreEqual(3, subPass.colorOutputs.Length);
650 Assert.AreEqual(1, subPass.colorOutputs[0]);
651 Assert.AreEqual(2, subPass.colorOutputs[1]);
652 Assert.AreEqual(3, subPass.colorOutputs[2]);
653
654 // Sub Pass 1
655 ref var subPass2 = ref result.contextData.nativeSubPassData.ElementAt(nativePasses[0].firstNativeSubPass + 1);
656 Assert.AreEqual(3, subPass2.inputs.Length);
657 Assert.AreEqual(1, subPass2.inputs[0]);
658 Assert.AreEqual(2, subPass2.inputs[1]);
659 Assert.AreEqual(3, subPass2.inputs[2]);
660
661 Assert.AreEqual(1, subPass2.colorOutputs.Length);
662 Assert.AreEqual(4, subPass2.colorOutputs[0]);
663 }
664
665 [Test]
666 public void ImportParametersWork()
667 {
668 var g = AllocateRenderGraph();
669 var buffers = ImportAndCreateBuffers(g);
670
671 // Import with parameters
672 var backBuffer = BuiltinRenderTextureType.CameraTarget;
673 var backBufferHandle = RTHandles.Alloc(backBuffer, "Test Import");
674
675 RenderTargetInfo importInfo = new RenderTargetInfo();
676 importInfo.width = 1024;
677 importInfo.height = 768;
678 importInfo.msaaSamples = 1;
679 importInfo.volumeDepth = 1;
680 importInfo.format = GraphicsFormat.R16G16B16A16_SFloat;
681
682 ImportResourceParams importResourceParams = new ImportResourceParams();
683 importResourceParams.clearOnFirstUse = true;
684 importResourceParams.discardOnLastUse = true;
685 var importedTexture = g.ImportTexture(backBufferHandle, importInfo, importResourceParams);
686
687 // Render something to importedTexture
688 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
689 {
690 builder.SetRenderAttachment(importedTexture, 0, AccessFlags.Write);
691 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
692 }
693
694 // Compute does something or other
695 using (var builder = g.AddComputePass<RenderGraphTestPassData>("ComputePass", out var passData))
696 {
697 builder.UseTexture(buffers.extraBuffers[0], AccessFlags.ReadWrite);
698 builder.SetRenderFunc((RenderGraphTestPassData data, ComputeGraphContext context) => { });
699 }
700
701 // Render to final buffer
702 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
703 {
704 builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
705 builder.SetRenderAttachment(importedTexture, 1, AccessFlags.Write);
706 builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
707 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
708 }
709
710 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
711 var passes = result.contextData.GetNativePasses();
712
713 // Validate nr pass 0
714 Assert.AreEqual(2, passes.Count);
715 Assert.AreEqual(1, passes[0].attachments.size);
716 Assert.AreEqual(1, passes[0].numGraphPasses);
717
718 // Clear on first use
719 ref var firstAttachment = ref passes[0].attachments[0];
720 Assert.AreEqual(RenderBufferLoadAction.Clear, firstAttachment.loadAction);
721
722 // Validate nr pass 1
723 Assert.AreEqual(3, passes[1].attachments.size);
724 Assert.AreEqual(1, passes[1].numGraphPasses);
725
726 // Discard on last use
727 Assert.AreEqual(RenderBufferStoreAction.DontCare, passes[1].attachments[1].storeAction);
728 // Regular imports do a full load/store
729 Assert.AreEqual(RenderBufferLoadAction.Load, passes[1].attachments[2].loadAction);
730 Assert.AreEqual(RenderBufferStoreAction.Store, passes[1].attachments[2].storeAction);
731 }
732
733 [Test]
734 public void FencesWork()
735 {
736 var g = AllocateRenderGraph();
737 var buffers = ImportAndCreateBuffers(g);
738
739 // Pass #1: Render pass writing to backbuffer
740 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("#1 RenderPass", out _))
741 {
742 builder.UseTexture(buffers.backBuffer, AccessFlags.Write);
743 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
744 }
745
746 // Pass #2: Async compute pass writing to back buffer
747 using (var builder = g.AddComputePass<RenderGraphTestPassData>("#2 AsyncComputePass", out _))
748 {
749 builder.EnableAsyncCompute(true);
750 builder.UseTexture(buffers.backBuffer, AccessFlags.Write);
751 builder.SetRenderFunc((RenderGraphTestPassData data, ComputeGraphContext context) => { });
752 }
753
754 // Pass #3: Render pass writing to backbuffer
755 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("#3 RenderPass", out _))
756 {
757 builder.UseTexture(buffers.backBuffer, AccessFlags.Write);
758 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
759 }
760
761 // Pass #4: Render pass writing to backbuffer
762 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("#4 RenderPass", out _))
763 {
764 builder.UseTexture(buffers.backBuffer, AccessFlags.Write);
765 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
766 }
767
768 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
769 var passData = result.contextData.passData;
770
771 // #1 waits for nothing, inserts a fence
772 Assert.AreEqual(-1, passData[0].waitOnGraphicsFencePassId);
773 Assert.True(passData[0].insertGraphicsFence);
774
775 // #2 (async compute) pass waits on #1, inserts a fence
776 Assert.AreEqual(0, passData[1].waitOnGraphicsFencePassId);
777 Assert.True(passData[1].insertGraphicsFence);
778
779 // #3 waits on #2 (async compute) pass, doesn't insert a fence
780 Assert.AreEqual(1, passData[2].waitOnGraphicsFencePassId);
781 Assert.False(passData[2].insertGraphicsFence);
782
783 // #4 waits for nothing, doesn't insert a fence
784 Assert.AreEqual(-1, passData[3].waitOnGraphicsFencePassId);
785 Assert.False(passData[3].insertGraphicsFence);
786 }
787
788 [Test]
789 public void BuffersWork()
790 {
791 var g = AllocateRenderGraph();
792 var rendertargets = ImportAndCreateBuffers(g);
793
794 var desc = new BufferDesc(1024, 16);
795 var buffer = g.CreateBuffer(desc);
796
797 // Render something to extra 0 and write uav
798 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
799 {
800 builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Write);
801 builder.SetRenderAttachment(rendertargets.extraBuffers[0], 0, AccessFlags.Write);
802 builder.UseBufferRandomAccess(buffer, 1, AccessFlags.ReadWrite);
803 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
804 }
805
806 // Render extra bits to 0 reading from the uav
807 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
808 {
809 builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Write);
810 builder.SetRenderAttachment(rendertargets.extraBuffers[0], 0, AccessFlags.Write);
811 builder.UseBuffer(buffer, AccessFlags.Read);
812 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
813 }
814
815 // Render to final buffer
816 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
817 {
818 builder.UseTexture(rendertargets.extraBuffers[0]);
819 builder.SetRenderAttachment(rendertargets.backBuffer, 2, AccessFlags.Write);
820 builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Write);
821 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
822 }
823
824 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
825 var passes = result.contextData.GetNativePasses();
826
827 // Validate Pass 0 : uav is first used and created
828 ref var pass0Data = ref result.contextData.passData.ElementAt(0);
829 var firstUsedList = pass0Data.FirstUsedResources(result.contextData).ToArray();
830
831 Assert.AreEqual(3, firstUsedList.Length);
832 Assert.AreEqual(rendertargets.depthBuffer.handle.index, firstUsedList[0].index);
833 Assert.AreEqual(RenderGraphResourceType.Texture, firstUsedList[0].type);
834 Assert.AreEqual(rendertargets.extraBuffers[0].handle.index, firstUsedList[1].index);
835 Assert.AreEqual(RenderGraphResourceType.Texture, firstUsedList[1].type);
836 Assert.AreEqual(buffer.handle.index, firstUsedList[2].index);
837 Assert.AreEqual(RenderGraphResourceType.Buffer, firstUsedList[2].type);
838
839 var randomAccessList = pass0Data.RandomWriteTextures(result.contextData).ToArray();
840 Assert.AreEqual(1, randomAccessList.Length);
841 Assert.AreEqual(buffer.handle.index, randomAccessList[0].resource.index);
842 Assert.AreEqual(RenderGraphResourceType.Buffer, randomAccessList[0].resource.type);
843 Assert.AreEqual(1, randomAccessList[0].index); // we asked for it to be at index 1 in the builder
844 Assert.AreEqual(true, randomAccessList[0].preserveCounterValue); // preserve is default
845
846 // Validate Pass 1 : uav buffer is last used and destroyed
847 ref var pass1Data = ref result.contextData.passData.ElementAt(1);
848 var lastUsedList = pass1Data.LastUsedResources(result.contextData).ToArray();
849
850 Assert.AreEqual(1, lastUsedList.Length);
851 Assert.AreEqual(buffer.handle.index, lastUsedList[0].index);
852 Assert.AreEqual(RenderGraphResourceType.Buffer, lastUsedList[0].type);
853 }
854
855 [Test]
856 public void ResolveMSAAImportColor()
857 {
858 var g = AllocateRenderGraph();
859 var buffers = ImportAndCreateBuffers(g);
860
861 // Import with parameters
862 // Depth
863 var depthBuffer = BuiltinRenderTextureType.Depth;
864 var depthBufferHandle = RTHandles.Alloc(depthBuffer, "Test Import Depth");
865
866 RenderTargetInfo importInfoDepth = new RenderTargetInfo();
867 importInfoDepth.width = 1024;
868 importInfoDepth.height = 768;
869 importInfoDepth.msaaSamples = 4;
870 importInfoDepth.volumeDepth = 1;
871 importInfoDepth.format = GraphicsFormat.D32_SFloat_S8_UInt;
872
873 ImportResourceParams importResourceParams = new ImportResourceParams();
874 importResourceParams.clearOnFirstUse = true;
875 importResourceParams.discardOnLastUse = true;
876
877 var importedDepth = g.ImportTexture(depthBufferHandle, importInfoDepth, importResourceParams);
878
879 // Color
880 var backBuffer = BuiltinRenderTextureType.CameraTarget;
881 var backBufferHandle = RTHandles.Alloc(backBuffer, "Test Import Color");
882
883 RenderTargetInfo importInfoColor = new RenderTargetInfo();
884 importInfoColor.width = 1024;
885 importInfoColor.height = 768;
886 importInfoColor.msaaSamples = 4;
887 importInfoColor.volumeDepth = 1;
888 importInfoColor.format = GraphicsFormat.R16G16B16A16_SFloat;
889
890 var importedColor = g.ImportTexture(backBufferHandle, importInfoColor, importResourceParams);
891
892 // Render something to importedColor and importedDepth
893 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass", out var passData))
894 {
895 builder.SetRenderAttachmentDepth(importedDepth, AccessFlags.Write);
896 builder.SetRenderAttachment(importedColor, 1, AccessFlags.Write);
897 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
898 }
899
900 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
901 var passes = result.contextData.GetNativePasses();
902
903 // Validate nr pass
904 Assert.AreEqual(1, passes.Count);
905 Assert.AreEqual(2, passes[0].attachments.size);
906 Assert.AreEqual(1, passes[0].numGraphPasses);
907
908 // Clear on first use
909 ref var firstAttachment = ref passes[0].attachments[0];
910 Assert.AreEqual(RenderBufferLoadAction.Clear, firstAttachment.loadAction);
911 ref var secondAttachment = ref passes[0].attachments[1];
912 Assert.AreEqual(RenderBufferLoadAction.Clear, secondAttachment.loadAction);
913
914 // Discard on last use
915 Assert.AreEqual(RenderBufferStoreAction.DontCare, passes[0].attachments[0].storeAction);
916 // When discarding MSAA color, we only discard the MSAA buffers but keep the resolved texture
917 Assert.AreEqual(RenderBufferStoreAction.Resolve, passes[0].attachments[1].storeAction);
918 }
919
920 [Test]
921 public void TransientTexturesCantBeReused()
922 {
923 var g = AllocateRenderGraph();
924 var buffers = ImportAndCreateBuffers(g);
925 var textureTransientHandle = TextureHandle.nullHandle;
926
927 // Render something to textureTransientHandle, created locally in the pass.
928 // No exception and no error(s) should be thrown in the Console.
929 {
930 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
931 {
932 var textDesc = new TextureDesc(Vector2.one, false, false)
933 {
934 width = 1920,
935 height = 1080,
936 format = GraphicsFormat.B10G11R11_UFloatPack32,
937 clearBuffer = true,
938 clearColor = Color.red,
939 name = "Transient Texture"
940 };
941 textureTransientHandle = builder.CreateTransientTexture(textDesc);
942
943 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
944 }
945
946 Assert.IsTrue(g.m_RenderPasses.Count != 0);
947 Assert.IsTrue(g.m_RenderPasses[^1].transientResourceList[(int)textureTransientHandle.handle.type].Count != 0);
948 }
949
950 // Try to render something to textureTransientHandle, reusing the previous TextureHandle.
951 // UseTexture should throw an exception.
952 Assert.Throws<ArgumentException>(() =>
953 {
954 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
955 {
956 builder.UseTexture(textureTransientHandle, AccessFlags.Read | AccessFlags.Write);
957 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
958 }
959 });
960 }
961
962 [Test]
963 public void TransientBuffersCantBeReused()
964 {
965 var g = AllocateRenderGraph();
966 var buffers = ImportAndCreateBuffers(g);
967 var bufferTransientHandle = BufferHandle.nullHandle;
968
969 // Render something to textureTransientHandle, created locally in the pass.
970 // No error(s) should be thrown in the Console.
971 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
972 {
973 var prefixBuffer0Desc = new BufferDesc(1920 * 1080, 4, GraphicsBuffer.Target.Raw) { name = "prefixBuffer0" };
974 bufferTransientHandle = builder.CreateTransientBuffer(prefixBuffer0Desc);
975
976 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
977
978 Assert.IsTrue(g.m_RenderPasses.Count != 0);
979 Assert.IsTrue(g.m_RenderPasses[^1].transientResourceList[(int)bufferTransientHandle.handle.type].Count != 0);
980 }
981
982 // Try to render something to textureTransientHandle, reusing the previous TextureHandle.
983 // UseTexture should throw an exception.
984 Assert.Throws<ArgumentException>(() =>
985 {
986 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
987 {
988 builder.UseBuffer(bufferTransientHandle, AccessFlags.Read | AccessFlags.Write);
989 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
990 }
991 });
992 }
993
994 [Test]
995 public void ChangingGlobalStateDisablesCulling()
996 {
997 var g = AllocateRenderGraph();
998 var buffers = ImportAndCreateBuffers(g);
999
1000 // First pass ; culling should be set to false after calling AllowGlobalStateModification.
1001 {
1002 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
1003 {
1004 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
1005 builder.AllowPassCulling(true);
1006 builder.AllowGlobalStateModification(true);
1007 }
1008 }
1009
1010 // Second pass ; culling should be set to false even if we are setting it to true after calling AllowGlobalStateModification.
1011 {
1012 using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
1013 {
1014 builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
1015 builder.AllowGlobalStateModification(true);
1016 builder.AllowPassCulling(true);
1017 }
1018 }
1019
1020 var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
1021 var passes = result.contextData.GetNativePasses();
1022
1023 Assert.IsTrue(passes != null && passes.Count > 0);
1024 var firstNativePass = passes[0];
1025
1026 Assert.IsTrue(firstNativePass.numGraphPasses == 2);
1027 }
1028 }
1029}