You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1638 lines
80 KiB
1638 lines
80 KiB
using NUnit.Framework;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using UnityEngine.Profiling;
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
using UnityEngine.Rendering.RenderGraphModule.NativeRenderPassCompiler;
|
|
|
|
namespace UnityEngine.Rendering.Tests
|
|
{
|
|
class NativePassCompilerRenderGraphTests
|
|
{
|
|
static Recorder gcAllocRecorder = Recorder.Get("GC.Alloc");
|
|
|
|
class RenderGraphTestPassData
|
|
{
|
|
public TextureHandle[] textures = new TextureHandle[8];
|
|
public BufferHandle[] buffers = new BufferHandle[8];
|
|
}
|
|
|
|
TextureDesc SimpleTextureDesc(string name, int w, int h, int samples)
|
|
{
|
|
TextureDesc result = new TextureDesc(w, h);
|
|
result.msaaSamples = (MSAASamples)samples;
|
|
result.format = GraphicsFormat.R8G8B8A8_UNorm;
|
|
result.name = name;
|
|
return result;
|
|
}
|
|
|
|
class TestBuffers
|
|
{
|
|
public TextureHandle backBuffer;
|
|
public TextureHandle depthBuffer;
|
|
public TextureHandle[] extraBuffers = new TextureHandle[10];
|
|
public TextureHandle extraDepthBuffer;
|
|
};
|
|
|
|
TestBuffers ImportAndCreateBuffers(RenderGraph g)
|
|
{
|
|
TestBuffers result = new TestBuffers();
|
|
var backBuffer = BuiltinRenderTextureType.CameraTarget;
|
|
var backBufferHandle = RTHandles.Alloc(backBuffer, "Backbuffer Color");
|
|
var depthBuffer = BuiltinRenderTextureType.Depth;
|
|
var depthBufferHandle = RTHandles.Alloc(depthBuffer, "Backbuffer Depth");
|
|
var extraDepthBufferHandle = RTHandles.Alloc(depthBuffer, "Extra Depth Buffer");
|
|
|
|
RenderTargetInfo importInfo = new RenderTargetInfo();
|
|
RenderTargetInfo importInfoDepth = new RenderTargetInfo();
|
|
importInfo.width = 1024;
|
|
importInfo.height = 768;
|
|
importInfo.volumeDepth = 1;
|
|
importInfo.msaaSamples = 1;
|
|
importInfo.format = GraphicsFormat.R16G16B16A16_SFloat;
|
|
result.backBuffer = g.ImportTexture(backBufferHandle, importInfo);
|
|
|
|
importInfoDepth = importInfo;
|
|
importInfoDepth.format = GraphicsFormat.D32_SFloat_S8_UInt;
|
|
result.depthBuffer = g.ImportTexture(depthBufferHandle, importInfoDepth);
|
|
|
|
importInfo.format = GraphicsFormat.D24_UNorm;
|
|
result.extraDepthBuffer = g.ImportTexture(extraDepthBufferHandle, importInfoDepth);
|
|
|
|
for (int i = 0; i < result.extraBuffers.Length; i++)
|
|
{
|
|
result.extraBuffers[i] = g.CreateTexture(SimpleTextureDesc("ExtraBuffer" + i, 1024, 768, 1));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
RenderGraph AllocateRenderGraph()
|
|
{
|
|
RenderGraph g = new RenderGraph();
|
|
g.nativeRenderPassesEnabled = true;
|
|
return g;
|
|
}
|
|
|
|
[Test]
|
|
public void SimpleMergePasses()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Render something to 0,1
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render extra bits to 1
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
// Render to final buffer
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(4, passes[0].attachments.size);
|
|
Assert.AreEqual(3, passes[0].numGraphPasses);
|
|
|
|
ref var firstAttachment = ref passes[0].attachments[0];
|
|
Assert.AreEqual(RenderBufferLoadAction.Load, firstAttachment.loadAction);
|
|
|
|
ref var secondAttachment = ref passes[0].attachments[1];
|
|
Assert.AreEqual(RenderBufferLoadAction.Clear, secondAttachment.loadAction);
|
|
|
|
ref var thirdAttachment = ref passes[0].attachments[2];
|
|
Assert.AreEqual(RenderBufferLoadAction.Clear, thirdAttachment.loadAction);
|
|
|
|
ref var fourthAttachment = ref passes[0].attachments[3];
|
|
Assert.AreEqual(RenderBufferLoadAction.Load, fourthAttachment.loadAction);
|
|
}
|
|
|
|
/*[Test]
|
|
public void MergeNonRenderPasses()
|
|
{
|
|
RenderGraph g = new RenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Render something to 0,1
|
|
{
|
|
var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData);
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.Dispose();
|
|
}
|
|
|
|
// Render extra bits to 1
|
|
{
|
|
var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData);
|
|
// This does something like CommandBufffer.SetGlobal or something that doesn't do any rendering
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
builder.Dispose();
|
|
}
|
|
// Render to final buffer
|
|
{
|
|
var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.Dispose();
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(4, passes[0].attachments.size);
|
|
Assert.AreEqual(3, passes[0].numGraphPasses);
|
|
Assert.AreEqual(2, passes[0].numNativeSubPasses);
|
|
}*/
|
|
|
|
[Test]
|
|
public void MergeDepthPassWithNoDepthPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// with no depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.EndOfGraph, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void MergeNoDepthPassWithDepthPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// no depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// with depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.EndOfGraph, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void MergeMultiplePassesDifferentDepth()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// no depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// with depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// with no depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.EndOfGraph, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void MergeDifferentDepthFormatsBreaksPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// with different depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.extraDepthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(2, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.DifferentDepthTextures, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void MergePassWithWriteAllPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Render something to depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
// Merge pass, render with WriteAll in extra 0
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.WriteAll);
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(2, passes[0].numGraphPasses);
|
|
|
|
// Validate attachments
|
|
Assert.AreEqual(buffers.depthBuffer.handle.index, passes[0].attachments[0].handle.index);
|
|
Assert.AreEqual(buffers.extraBuffers[0].handle.index, passes[0].attachments[1].handle.index);
|
|
|
|
ref var depthAttachment = ref passes[0].attachments[0];
|
|
Assert.AreEqual(RenderBufferLoadAction.Load, depthAttachment.loadAction);
|
|
|
|
ref var extraAttachment = ref passes[0].attachments[1];
|
|
Assert.AreEqual(RenderBufferLoadAction.DontCare, extraAttachment.loadAction);
|
|
}
|
|
|
|
[Test]
|
|
public void MergeWriteAllPassWithReadPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Render something to extra 0
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.WriteAll);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
// Read from extra 0
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetInputAttachment(buffers.extraBuffers[0], 0, AccessFlags.Read);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(2, passes[0].numGraphPasses);
|
|
|
|
// Validate attachments
|
|
Assert.AreEqual(buffers.depthBuffer.handle.index, passes[0].attachments[0].handle.index);
|
|
Assert.AreEqual(buffers.extraBuffers[0].handle.index, passes[0].attachments[1].handle.index);
|
|
|
|
ref var depthAttachment = ref passes[0].attachments[0];
|
|
Assert.AreEqual(RenderBufferLoadAction.Load, depthAttachment.loadAction);
|
|
|
|
ref var extraAttachment = ref passes[0].attachments[1];
|
|
Assert.AreEqual(RenderBufferLoadAction.DontCare, extraAttachment.loadAction);
|
|
}
|
|
|
|
[Test]
|
|
public void MergeReadPassWithWriteAllPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Render something to 0,1
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Read);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
// Render to final buffer
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.WriteAll);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(2, passes[0].numGraphPasses);
|
|
|
|
// Validate attachments
|
|
Assert.AreEqual(buffers.depthBuffer.handle.index, passes[0].attachments[0].handle.index);
|
|
Assert.AreEqual(buffers.extraBuffers[0].handle.index, passes[0].attachments[1].handle.index);
|
|
|
|
ref var depthAttachment = ref passes[0].attachments[0];
|
|
Assert.AreEqual(RenderBufferLoadAction.Load, depthAttachment.loadAction);
|
|
|
|
// LoadAction is Clear because it was not used by another pass before, in other case it should be Load
|
|
ref var extraAttachment = ref passes[0].attachments[1];
|
|
Assert.AreEqual(RenderBufferLoadAction.Clear, extraAttachment.loadAction);
|
|
}
|
|
|
|
[Test]
|
|
public void MergeDiscardPassWithWrite()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Discard extra 0
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Discard);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
// Read extra 0
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Read);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
// Write to extra 0
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
// break pass using another depth, Read extra 0
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.extraDepthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Read);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(2, passes.Count);
|
|
Assert.AreEqual(3, passes[0].numGraphPasses);
|
|
|
|
// Validate attachments
|
|
Assert.AreEqual(buffers.depthBuffer.handle.index, passes[0].attachments[0].handle.index);
|
|
Assert.AreEqual(buffers.extraBuffers[0].handle.index, passes[0].attachments[1].handle.index);
|
|
Assert.AreEqual(buffers.extraBuffers[0].handle.index, passes[1].attachments[1].handle.index);
|
|
|
|
ref var depthAttachment = ref passes[0].attachments[0];
|
|
Assert.AreEqual(RenderBufferLoadAction.Load, depthAttachment.loadAction);
|
|
|
|
// As we have a discard flag in the pass the LoadAction is DontCare, but as it has also a Write flag it should Store the result for the next pass
|
|
ref var extraAttachmentPass0 = ref passes[0].attachments[1];
|
|
Assert.AreEqual(RenderBufferLoadAction.DontCare, extraAttachmentPass0.loadAction);
|
|
Assert.AreEqual(RenderBufferStoreAction.Store, extraAttachmentPass0.storeAction);
|
|
|
|
ref var extraAttachmentPass1 = ref passes[1].attachments[1];
|
|
Assert.AreEqual(RenderBufferLoadAction.Load, extraAttachmentPass1.loadAction);
|
|
|
|
}
|
|
|
|
[Test]
|
|
public void VerifyMergeStateAfterMergingPasses()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// First pass, not culled.
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
builder.Dispose();
|
|
}
|
|
|
|
// Second pass, culled.
|
|
{
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(true);
|
|
builder.Dispose();
|
|
}
|
|
|
|
// Third pass, not culled.
|
|
{
|
|
var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData);
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
builder.Dispose();
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.IsTrue(passes != null && passes.Count > 0);
|
|
var firstNativePass = passes[0];
|
|
|
|
var firstGraphPass = result.contextData.passData.ElementAt(firstNativePass.firstGraphPass);
|
|
var lastGraphPass = result.contextData.passData.ElementAt(firstNativePass.lastGraphPass);
|
|
var middleGraphPass = result.contextData.passData.ElementAt(firstNativePass.lastGraphPass - 1);
|
|
|
|
// Only 2 passes since one have been culled
|
|
Assert.IsTrue(firstNativePass.numGraphPasses == 2);
|
|
|
|
// All 3 passes including the culled one. We need to add +1 to obtain the correct passes count
|
|
// e.g lastGraphPass index = 2, firstGraphPass index = 0, so 2 - 0 = 2 passes, but we have 3 passes to consider
|
|
// (index 0, 1 and 2) so we add +1 for the correct count.
|
|
Assert.IsTrue(firstNativePass.lastGraphPass - firstNativePass.firstGraphPass + 1 == 3);
|
|
|
|
Assert.IsTrue(firstGraphPass.mergeState == PassMergeState.Begin);
|
|
Assert.IsTrue(lastGraphPass.mergeState == PassMergeState.End);
|
|
Assert.IsTrue(middleGraphPass.mergeState == PassMergeState.None);
|
|
}
|
|
|
|
[Test]
|
|
public void NonFragmentSamplingBreaksPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.UseTexture(buffers.extraBuffers[0], AccessFlags.Read);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(2, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.NextPassReadsTexture, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void FragmentAfterSamplingWithInputAttachmentBreaksPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.UseTexture(buffers.extraBuffers[0], AccessFlags.Read);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetInputAttachment(buffers.extraBuffers[1], 1, AccessFlags.Read);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(2, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.NextPassTargetsTexture, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void FragmentAfterSamplingBreaksPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.UseTexture(buffers.extraBuffers[0], AccessFlags.Read);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[2], 1, AccessFlags.Read);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(2, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.NextPassTargetsTexture, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void NonRasterBreaksPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// No depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Compute touches extraBuffers[0]
|
|
using (var builder = g.AddComputePass<RenderGraphTestPassData>("ComputePass", out var passData))
|
|
{
|
|
builder.UseTexture(buffers.extraBuffers[0], AccessFlags.ReadWrite);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, ComputeGraphContext context) => { });
|
|
}
|
|
|
|
// With depth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 1, AccessFlags.Read);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(2, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.NonRasterPass, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void TooManyAttachmentsBreaksPass()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// 8 attachments
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[i], i, AccessFlags.Write);
|
|
}
|
|
builder.SetRenderAttachment(buffers.backBuffer, 7, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// 2 additional attachments
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[i + 6], i, AccessFlags.Write);
|
|
}
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(2, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.AttachmentLimitReached, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void NativeSubPassesLimitNotExceeded()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Native subpasses limit is 8 so go above
|
|
for (int i = 0; i < Rendering.RenderGraphModule.NativeRenderPassCompiler.NativePassCompiler.k_MaxSubpass + 2; i++)
|
|
{
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>($"TestPass_{i}", out var passData))
|
|
{
|
|
builder.SetInputAttachment(buffers.extraBuffers[1 - i % 2], 0);
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[i % 2], 1);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(2, passes.Count);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.NativePassCompiler.k_MaxSubpass, passes[0].numGraphPasses);
|
|
Assert.AreEqual(Rendering.RenderGraphModule.NativeRenderPassCompiler.PassBreakReason.SubPassLimitReached, passes[0].breakAudit.reason);
|
|
}
|
|
|
|
[Test]
|
|
public void AllocateFreeInMergedPassesWorks()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Render something to extra 0
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// 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
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// 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
|
|
// It's also the last time extra 1 is used so it gets freed
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 0, AccessFlags.ReadWrite);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[2], 1, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render to final buffer
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[2], 1, AccessFlags.Write);
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(5, passes[0].attachments.size); //3 extra + color + depth
|
|
Assert.AreEqual(4, passes[0].numGraphPasses);
|
|
|
|
// Pass 1 first used = {extra 1}
|
|
List<ResourceHandle> firstUsed = new List<ResourceHandle>();
|
|
ref var pass1Data = ref result.contextData.passData.ElementAt(1);
|
|
foreach (ref readonly var res in pass1Data.FirstUsedResources(result.contextData))
|
|
firstUsed.Add(res);
|
|
|
|
Assert.AreEqual(1, firstUsed.Count);
|
|
Assert.AreEqual(buffers.extraBuffers[1].handle.index, firstUsed[0].index);
|
|
|
|
// Pass 2 last used = {
|
|
List<ResourceHandle> lastUsed = new List<ResourceHandle>();
|
|
ref var pass2Data = ref result.contextData.passData.ElementAt(2);
|
|
foreach (ref readonly var res in pass2Data.LastUsedResources(result.contextData))
|
|
lastUsed.Add(res);
|
|
|
|
Assert.AreEqual(1, lastUsed.Count);
|
|
Assert.AreEqual(buffers.extraBuffers[1].handle.index, lastUsed[0].index);
|
|
|
|
}
|
|
|
|
[Test]
|
|
public void MemorylessWorks()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Render something to extra 0
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render to final buffer
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.ReadWrite);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 1, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(3, passes[0].attachments.size); //1 extra + color + depth
|
|
Assert.AreEqual(2, passes[0].numGraphPasses);
|
|
|
|
// Pass 0 : first used = {depthBuffer, extraBuffers[0]}
|
|
List<ResourceHandle> firstUsed = new List<ResourceHandle>();
|
|
ref var pass0Data = ref result.contextData.passData.ElementAt(0);
|
|
foreach (ref readonly var res in pass0Data.FirstUsedResources(result.contextData))
|
|
firstUsed.Add(res);
|
|
|
|
//Extra buffer 0 should be memoryless
|
|
Assert.AreEqual(2, firstUsed.Count);
|
|
Assert.AreEqual(buffers.extraBuffers[0].handle.index, firstUsed[1].index);
|
|
ref var info = ref result.contextData.UnversionedResourceData(firstUsed[1]);
|
|
Assert.AreEqual(true, info.memoryLess);
|
|
|
|
// Pass 1 : last used = {depthBuffer, extraBuffers[0], backBuffer}
|
|
List<ResourceHandle> lastUsed = new List<ResourceHandle>();
|
|
ref var pass1Data = ref result.contextData.passData.ElementAt(1);
|
|
foreach (var res in pass1Data.LastUsedResources(result.contextData))
|
|
lastUsed.Add(res);
|
|
|
|
Assert.AreEqual(3, lastUsed.Count);
|
|
Assert.AreEqual(buffers.extraBuffers[0].handle.index, lastUsed[1].index);
|
|
}
|
|
|
|
[Test]
|
|
public void InputAttachmentsWork()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Render something to extra 0,1,2
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 1, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[2], 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render to final buffer using extra 0 as attachment
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.ReadWrite);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 1, AccessFlags.Write);
|
|
builder.SetInputAttachment(buffers.extraBuffers[0], 0, AccessFlags.Read);
|
|
builder.SetInputAttachment(buffers.extraBuffers[1], 1, AccessFlags.Read);
|
|
builder.SetInputAttachment(buffers.extraBuffers[2], 2, AccessFlags.Read);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var nativePasses = result.contextData.GetNativePasses();
|
|
|
|
Assert.AreEqual(1, nativePasses.Count);
|
|
Assert.AreEqual(5, nativePasses[0].attachments.size); //3 extra + color + depth
|
|
Assert.AreEqual(2, nativePasses[0].numGraphPasses);
|
|
|
|
// Validate attachments
|
|
Assert.AreEqual(buffers.depthBuffer.handle.index, nativePasses[0].attachments[0].handle.index);
|
|
Assert.AreEqual(buffers.extraBuffers[0].handle.index, nativePasses[0].attachments[1].handle.index);
|
|
Assert.AreEqual(buffers.extraBuffers[1].handle.index, nativePasses[0].attachments[2].handle.index);
|
|
Assert.AreEqual(buffers.extraBuffers[2].handle.index, nativePasses[0].attachments[3].handle.index);
|
|
Assert.AreEqual(buffers.backBuffer.handle.index, nativePasses[0].attachments[4].handle.index);
|
|
|
|
// Sub Pass 0
|
|
ref var subPass = ref result.contextData.nativeSubPassData.ElementAt(nativePasses[0].firstNativeSubPass);
|
|
Assert.AreEqual(0, subPass.inputs.Length);
|
|
|
|
Assert.AreEqual(3, subPass.colorOutputs.Length);
|
|
Assert.AreEqual(1, subPass.colorOutputs[0]);
|
|
Assert.AreEqual(2, subPass.colorOutputs[1]);
|
|
Assert.AreEqual(3, subPass.colorOutputs[2]);
|
|
|
|
// Sub Pass 1
|
|
ref var subPass2 = ref result.contextData.nativeSubPassData.ElementAt(nativePasses[0].firstNativeSubPass + 1);
|
|
Assert.AreEqual(3, subPass2.inputs.Length);
|
|
Assert.AreEqual(1, subPass2.inputs[0]);
|
|
Assert.AreEqual(2, subPass2.inputs[1]);
|
|
Assert.AreEqual(3, subPass2.inputs[2]);
|
|
|
|
Assert.AreEqual(1, subPass2.colorOutputs.Length);
|
|
Assert.AreEqual(4, subPass2.colorOutputs[0]);
|
|
}
|
|
|
|
[Test]
|
|
public void ImportParametersWork()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Import with parameters
|
|
var backBuffer = BuiltinRenderTextureType.CameraTarget;
|
|
var backBufferHandle = RTHandles.Alloc(backBuffer, "Test Import");
|
|
|
|
RenderTargetInfo importInfo = new RenderTargetInfo();
|
|
importInfo.width = 1024;
|
|
importInfo.height = 768;
|
|
importInfo.msaaSamples = 1;
|
|
importInfo.volumeDepth = 1;
|
|
importInfo.format = GraphicsFormat.R16G16B16A16_SFloat;
|
|
|
|
ImportResourceParams importResourceParams = new ImportResourceParams();
|
|
importResourceParams.clearOnFirstUse = true;
|
|
importResourceParams.discardOnLastUse = true;
|
|
var importedTexture = g.ImportTexture(backBufferHandle, importInfo, importResourceParams);
|
|
|
|
// Render something to importedTexture
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(importedTexture, 0, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Compute does something or other
|
|
using (var builder = g.AddComputePass<RenderGraphTestPassData>("ComputePass", out var passData))
|
|
{
|
|
builder.UseTexture(buffers.extraBuffers[0], AccessFlags.ReadWrite);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, ComputeGraphContext context) => { });
|
|
}
|
|
|
|
// Render to final buffer
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.SetRenderAttachment(importedTexture, 1, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
// Validate nr pass 0
|
|
Assert.AreEqual(2, passes.Count);
|
|
Assert.AreEqual(1, passes[0].attachments.size);
|
|
Assert.AreEqual(1, passes[0].numGraphPasses);
|
|
|
|
// Clear on first use
|
|
ref var firstAttachment = ref passes[0].attachments[0];
|
|
Assert.AreEqual(RenderBufferLoadAction.Clear, firstAttachment.loadAction);
|
|
|
|
// Validate nr pass 1
|
|
Assert.AreEqual(3, passes[1].attachments.size);
|
|
Assert.AreEqual(1, passes[1].numGraphPasses);
|
|
|
|
// Discard on last use
|
|
Assert.AreEqual(RenderBufferStoreAction.DontCare, passes[1].attachments[1].storeAction);
|
|
// Regular imports do a full load/store
|
|
Assert.AreEqual(RenderBufferLoadAction.Load, passes[1].attachments[2].loadAction);
|
|
Assert.AreEqual(RenderBufferStoreAction.Store, passes[1].attachments[2].storeAction);
|
|
}
|
|
|
|
[Test]
|
|
public void FencesWork()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Pass #1: Render pass writing to backbuffer
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("#1 RenderPass", out _))
|
|
{
|
|
builder.UseTexture(buffers.backBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Pass #2: Async compute pass writing to back buffer
|
|
using (var builder = g.AddComputePass<RenderGraphTestPassData>("#2 AsyncComputePass", out _))
|
|
{
|
|
builder.EnableAsyncCompute(true);
|
|
builder.UseTexture(buffers.backBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, ComputeGraphContext context) => { });
|
|
}
|
|
|
|
// Pass #3: Render pass writing to backbuffer
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("#3 RenderPass", out _))
|
|
{
|
|
builder.UseTexture(buffers.backBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Pass #4: Render pass writing to backbuffer
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("#4 RenderPass", out _))
|
|
{
|
|
builder.UseTexture(buffers.backBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passData = result.contextData.passData;
|
|
|
|
// #1 waits for nothing, inserts a fence
|
|
Assert.AreEqual(-1, passData[0].waitOnGraphicsFencePassId);
|
|
Assert.True(passData[0].insertGraphicsFence);
|
|
|
|
// #2 (async compute) pass waits on #1, inserts a fence
|
|
Assert.AreEqual(0, passData[1].waitOnGraphicsFencePassId);
|
|
Assert.True(passData[1].insertGraphicsFence);
|
|
|
|
// #3 waits on #2 (async compute) pass, doesn't insert a fence
|
|
Assert.AreEqual(1, passData[2].waitOnGraphicsFencePassId);
|
|
Assert.False(passData[2].insertGraphicsFence);
|
|
|
|
// #4 waits for nothing, doesn't insert a fence
|
|
Assert.AreEqual(-1, passData[3].waitOnGraphicsFencePassId);
|
|
Assert.False(passData[3].insertGraphicsFence);
|
|
}
|
|
|
|
[Test]
|
|
public void MaxReadersAndMaxVersionsAreCorrectForBuffers()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var rendertargets = ImportAndCreateBuffers(g);
|
|
|
|
var desc = new BufferDesc(1024, 16);
|
|
var buffer = g.CreateBuffer(desc);
|
|
var buffer2 = g.CreateBuffer(desc);
|
|
|
|
// Render something to extra 0 and write uav
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.UseBufferRandomAccess(buffer, 0, AccessFlags.Write);
|
|
builder.UseBufferRandomAccess(buffer2, 1, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render extra bits to 0 reading from the uav
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.UseBuffer(buffer, AccessFlags.Read);
|
|
builder.UseBufferRandomAccess(buffer2, 1, AccessFlags.ReadWrite);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
|
|
// The resource with the biggest MaxReaders is buffer2:
|
|
// 1 implicit read (TestPass0) + 1 explicit read (TestPass1) + 1 for the offset.
|
|
Assert.AreEqual(result.contextData.resources.MaxReaders, 3);
|
|
|
|
// The resource with the biggest MaxVersion is buffer2:
|
|
// 1 explicit write (TestPass0) + 1 explicit readwrite (TestPass1) + 1 for the offset
|
|
Assert.AreEqual(result.contextData.resources.MaxVersions, 3);
|
|
}
|
|
|
|
[Test]
|
|
public void MaxReadersAndMaxVersionsAreCorrectForTextures()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var rendertargets = ImportAndCreateBuffers(g);
|
|
|
|
// Render something to extra 0 and write uav
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Write);
|
|
builder.UseTexture(rendertargets.extraBuffers[0], AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render extra bits to 0 reading from the uav
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Read);
|
|
builder.UseTexture(rendertargets.extraBuffers[0], AccessFlags.ReadWrite);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render extra bits to 0 reading from the uav
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.AllowPassCulling(false);
|
|
builder.UseTexture(rendertargets.extraBuffers[0], AccessFlags.Read);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
|
|
// Resources with the biggest MaxReaders are extraBuffers[0] and depthBuffer (both being equal):
|
|
// 1 implicit read (TestPass0) + 2 explicit read (TestPass1 & TestPass2) + 1 for the offset
|
|
Assert.AreEqual(result.contextData.resources.MaxReaders, 4);
|
|
|
|
// The resource with the biggest MaxVersion is extraBuffers[0]:
|
|
// 1 explicit write (TestPass0) + 1 explicit read-write (TestPass1) + 1 for the offset
|
|
Assert.AreEqual(result.contextData.resources.MaxVersions, 3);
|
|
}
|
|
|
|
[Test]
|
|
public void MaxReadersAndMaxVersionsAreCorrectForBuffersMultiplePasses()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var rendertargets = ImportAndCreateBuffers(g);
|
|
|
|
var desc = new BufferDesc(1024, 16);
|
|
var buffer = g.CreateBuffer(desc);
|
|
var buffer2 = g.CreateBuffer(desc);
|
|
|
|
int indexName = 0;
|
|
|
|
for (int i = 0; i < 5; ++i)
|
|
{
|
|
// Render something to extra 0 and write uav
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass" + indexName++, out var passData))
|
|
{
|
|
builder.UseBufferRandomAccess(buffer, 0, AccessFlags.Write);
|
|
builder.UseBufferRandomAccess(buffer2, 1, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render extra bits to 0 reading from the uav
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass" + indexName++, out var passData))
|
|
{
|
|
builder.UseBuffer(buffer, AccessFlags.Read);
|
|
builder.UseBufferRandomAccess(buffer2, 1, AccessFlags.ReadWrite);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
|
|
// The resource with the biggest MaxReaders is buffer2:
|
|
// 5 implicit read (TestPass0-2-4-6-8) + 5 explicit read (TestPass1-3-5-7-9) + 1 for the offset.
|
|
Assert.AreEqual(result.contextData.resources.MaxReaders, 11);
|
|
|
|
// The resource with the biggest MaxVersion is buffer2:
|
|
// 5 explicit write (TestPass0-2-4-6-8) + 5 explicit readwrite (TestPass1-3-5-7-9) + 1 for the offset
|
|
Assert.AreEqual(result.contextData.resources.MaxVersions, 11);
|
|
}
|
|
|
|
[Test]
|
|
public void BuffersWork()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var rendertargets = ImportAndCreateBuffers(g);
|
|
|
|
var desc = new BufferDesc(1024, 16);
|
|
var buffer = g.CreateBuffer(desc);
|
|
|
|
// Render something to extra 0 and write uav
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(rendertargets.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.UseBufferRandomAccess(buffer, 1, AccessFlags.ReadWrite);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render extra bits to 0 reading from the uav
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(rendertargets.extraBuffers[0], 0, AccessFlags.Write);
|
|
builder.UseBuffer(buffer, AccessFlags.Read);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
// Render to final buffer
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.UseTexture(rendertargets.extraBuffers[0]);
|
|
builder.SetRenderAttachment(rendertargets.backBuffer, 2, AccessFlags.Write);
|
|
builder.SetRenderAttachmentDepth(rendertargets.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
// Validate Pass 0 : uav is first used and created
|
|
ref var pass0Data = ref result.contextData.passData.ElementAt(0);
|
|
var firstUsedList = pass0Data.FirstUsedResources(result.contextData).ToArray();
|
|
|
|
Assert.AreEqual(3, firstUsedList.Length);
|
|
Assert.AreEqual(rendertargets.depthBuffer.handle.index, firstUsedList[0].index);
|
|
Assert.AreEqual(RenderGraphResourceType.Texture, firstUsedList[0].type);
|
|
Assert.AreEqual(rendertargets.extraBuffers[0].handle.index, firstUsedList[1].index);
|
|
Assert.AreEqual(RenderGraphResourceType.Texture, firstUsedList[1].type);
|
|
Assert.AreEqual(buffer.handle.index, firstUsedList[2].index);
|
|
Assert.AreEqual(RenderGraphResourceType.Buffer, firstUsedList[2].type);
|
|
|
|
var randomAccessList = pass0Data.RandomWriteTextures(result.contextData).ToArray();
|
|
Assert.AreEqual(1, randomAccessList.Length);
|
|
Assert.AreEqual(buffer.handle.index, randomAccessList[0].resource.index);
|
|
Assert.AreEqual(RenderGraphResourceType.Buffer, randomAccessList[0].resource.type);
|
|
Assert.AreEqual(1, randomAccessList[0].index); // we asked for it to be at index 1 in the builder
|
|
Assert.AreEqual(true, randomAccessList[0].preserveCounterValue); // preserve is default
|
|
|
|
// Validate Pass 1 : uav buffer is last used and destroyed
|
|
ref var pass1Data = ref result.contextData.passData.ElementAt(1);
|
|
var lastUsedList = pass1Data.LastUsedResources(result.contextData).ToArray();
|
|
|
|
Assert.AreEqual(1, lastUsedList.Length);
|
|
Assert.AreEqual(buffer.handle.index, lastUsedList[0].index);
|
|
Assert.AreEqual(RenderGraphResourceType.Buffer, lastUsedList[0].type);
|
|
}
|
|
|
|
[Test]
|
|
public void ResolveMSAAImportColor()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Import with parameters
|
|
// Depth
|
|
var depthBuffer = BuiltinRenderTextureType.Depth;
|
|
var depthBufferHandle = RTHandles.Alloc(depthBuffer, "Test Import Depth");
|
|
|
|
RenderTargetInfo importInfoDepth = new RenderTargetInfo();
|
|
importInfoDepth.width = 1024;
|
|
importInfoDepth.height = 768;
|
|
importInfoDepth.msaaSamples = 4;
|
|
importInfoDepth.volumeDepth = 1;
|
|
importInfoDepth.format = GraphicsFormat.D32_SFloat_S8_UInt;
|
|
|
|
ImportResourceParams importResourceParams = new ImportResourceParams();
|
|
importResourceParams.clearOnFirstUse = true;
|
|
importResourceParams.discardOnLastUse = true;
|
|
|
|
var importedDepth = g.ImportTexture(depthBufferHandle, importInfoDepth, importResourceParams);
|
|
|
|
// Color
|
|
var backBuffer = BuiltinRenderTextureType.CameraTarget;
|
|
var backBufferHandle = RTHandles.Alloc(backBuffer, "Test Import Color");
|
|
|
|
RenderTargetInfo importInfoColor = new RenderTargetInfo();
|
|
importInfoColor.width = 1024;
|
|
importInfoColor.height = 768;
|
|
importInfoColor.msaaSamples = 4;
|
|
importInfoColor.volumeDepth = 1;
|
|
importInfoColor.format = GraphicsFormat.R16G16B16A16_SFloat;
|
|
|
|
var importedColor = g.ImportTexture(backBufferHandle, importInfoColor, importResourceParams);
|
|
|
|
// Render something to importedColor and importedDepth
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass", out var passData))
|
|
{
|
|
builder.SetRenderAttachmentDepth(importedDepth, AccessFlags.Write);
|
|
builder.SetRenderAttachment(importedColor, 1, AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
// Validate nr pass
|
|
Assert.AreEqual(1, passes.Count);
|
|
Assert.AreEqual(2, passes[0].attachments.size);
|
|
Assert.AreEqual(1, passes[0].numGraphPasses);
|
|
|
|
// Clear on first use
|
|
ref var firstAttachment = ref passes[0].attachments[0];
|
|
Assert.AreEqual(RenderBufferLoadAction.Clear, firstAttachment.loadAction);
|
|
ref var secondAttachment = ref passes[0].attachments[1];
|
|
Assert.AreEqual(RenderBufferLoadAction.Clear, secondAttachment.loadAction);
|
|
|
|
// Discard on last use
|
|
Assert.AreEqual(RenderBufferStoreAction.DontCare, passes[0].attachments[0].storeAction);
|
|
// When discarding MSAA color, we only discard the MSAA buffers but keep the resolved texture
|
|
Assert.AreEqual(RenderBufferStoreAction.Resolve, passes[0].attachments[1].storeAction);
|
|
}
|
|
|
|
[Test]
|
|
public void TransientTexturesCantBeReused()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
var textureTransientHandle = TextureHandle.nullHandle;
|
|
|
|
// Render something to textureTransientHandle, created locally in the pass.
|
|
// No exception and no error(s) should be thrown in the Console.
|
|
{
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
var textDesc = new TextureDesc(Vector2.one, false, false)
|
|
{
|
|
width = 1920,
|
|
height = 1080,
|
|
format = GraphicsFormat.B10G11R11_UFloatPack32,
|
|
clearBuffer = true,
|
|
clearColor = Color.red,
|
|
name = "Transient Texture"
|
|
};
|
|
textureTransientHandle = builder.CreateTransientTexture(textDesc);
|
|
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
|
|
Assert.IsTrue(g.m_RenderPasses.Count != 0);
|
|
Assert.IsTrue(g.m_RenderPasses[^1].transientResourceList[(int)textureTransientHandle.handle.type].Count != 0);
|
|
}
|
|
|
|
// Try to render something to textureTransientHandle, reusing the previous TextureHandle.
|
|
// UseTexture should throw an exception.
|
|
Assert.Throws<ArgumentException>(() =>
|
|
{
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.UseTexture(textureTransientHandle, AccessFlags.Read | AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void TransientBuffersCantBeReused()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
var bufferTransientHandle = BufferHandle.nullHandle;
|
|
|
|
// Render something to textureTransientHandle, created locally in the pass.
|
|
// No error(s) should be thrown in the Console.
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
var prefixBuffer0Desc = new BufferDesc(1920 * 1080, 4, GraphicsBuffer.Target.Raw) { name = "prefixBuffer0" };
|
|
bufferTransientHandle = builder.CreateTransientBuffer(prefixBuffer0Desc);
|
|
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
|
|
Assert.IsTrue(g.m_RenderPasses.Count != 0);
|
|
Assert.IsTrue(g.m_RenderPasses[^1].transientResourceList[(int)bufferTransientHandle.handle.type].Count != 0);
|
|
}
|
|
|
|
// Try to render something to textureTransientHandle, reusing the previous TextureHandle.
|
|
// UseTexture should throw an exception.
|
|
Assert.Throws<ArgumentException>(() =>
|
|
{
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.UseBuffer(bufferTransientHandle, AccessFlags.Read | AccessFlags.Write);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
}
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void ChangingGlobalStateDisablesCulling()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// First pass ; culling should be set to false after calling AllowGlobalStateModification.
|
|
{
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(true);
|
|
builder.AllowGlobalStateModification(true);
|
|
}
|
|
}
|
|
|
|
// Second pass ; culling should be set to false even if we are setting it to true after calling AllowGlobalStateModification.
|
|
{
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowGlobalStateModification(true);
|
|
builder.AllowPassCulling(true);
|
|
}
|
|
}
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
Assert.IsTrue(passes != null && passes.Count > 0);
|
|
var firstNativePass = passes[0];
|
|
|
|
Assert.IsTrue(firstNativePass.numGraphPasses == 2);
|
|
}
|
|
|
|
[Test]
|
|
public void DecreaseResourceVersionIfLastPassIsCulled()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
// Bumping version of extraBuffer within RG to 1 as we write to it in first pass
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
|
|
// Bumping version of extraBuffer within RG to 2 as we write to it in second pass
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(true);
|
|
}
|
|
|
|
// First pass is preserved as requested but second pass is culled
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
// Second pass has been culled
|
|
Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 1);
|
|
// extraBuffer version has decreased to 1 as it is only used by the first pass
|
|
Assert.AreEqual(passes[0].attachments[0].handle.version, 1);
|
|
}
|
|
|
|
[Test]
|
|
public void GraphPassesDoesNotAlloc()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
|
|
{
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass1_Culled", out var passData))
|
|
{
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(true);
|
|
}
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
|
|
{
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
|
|
// First pass is preserved as requested but second pass is culled
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
// Second pass has been culled
|
|
Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 2);
|
|
// Goes into possible alloc path
|
|
Assert.IsFalse(passes[0].lastGraphPass - passes[0].firstGraphPass + 1 == passes[0].numGraphPasses);
|
|
|
|
|
|
ValidateNoGCAllocs(() =>
|
|
{
|
|
passes[0].GraphPasses(result.contextData);
|
|
});
|
|
|
|
// From RenderPassCullingTests.cs
|
|
void ValidateNoGCAllocs(Action action)
|
|
{
|
|
// Warmup - this will catch static c'tors etc.
|
|
CountGCAllocs(action);
|
|
|
|
// Actual test.
|
|
var count = CountGCAllocs(action);
|
|
if (count != 0)
|
|
throw new AssertionException($"Expected 0 GC allocations but there were {count}");
|
|
}
|
|
|
|
int CountGCAllocs(Action action)
|
|
{
|
|
gcAllocRecorder.FilterToCurrentThread();
|
|
gcAllocRecorder.enabled = true;
|
|
|
|
action();
|
|
|
|
gcAllocRecorder.enabled = false;
|
|
return gcAllocRecorder.sampleBlockCount;
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void UpdateSubpassAttachmentIndices_WhenDepthAttachmentIsAdded()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("NoDepth0_Subpass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
|
|
// Render Pass
|
|
// attachments: [extraBuffers[0]]
|
|
// subpass 0: color outputs : [0]
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("NoDepth1_Subpass0", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[0], 0);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
|
|
// Render Pass
|
|
// attachments: [extraBuffers[0]]
|
|
// subpass 0: color outputs : [0]
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("NoDepth2_Subpass1", out var passData))
|
|
{
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 0);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
|
|
// Render Pass
|
|
// attachments: [extraBuffers[0], extraBuffers[1]]
|
|
// subpass 0: color outputs : [0]
|
|
// subpass 1: color outputs : [1]
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("NoDepth3_Subpass2", out var passData))
|
|
{
|
|
builder.SetInputAttachment(buffers.extraBuffers[0], 0);
|
|
builder.SetInputAttachment(buffers.extraBuffers[1], 1);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[2], 0);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
|
|
// Render Pass
|
|
// attachments: [extraBuffers[0], extraBuffers[1], extraBuffers[2]]
|
|
// subpass 0: color outputs : [0]
|
|
// subpass 1: color outputs : [1]
|
|
// subpass 2: color outputs : [2], inputs : [0, 1]
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("Depth_Subpass3", out var passData))
|
|
{
|
|
builder.SetInputAttachment(buffers.extraBuffers[0], 0);
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[3], 0);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
|
|
// Render Pass
|
|
// attachments: [depthBuffer, extraBuffers[1], extraBuffers[2], extraBuffers[0], extraBuffers[3]]
|
|
// subpass 0: color outputs : [0 -> 3]
|
|
// subpass 1: color outputs : [1]
|
|
// subpass 2: color outputs : [2], inputs : [0 -> 3, 1]
|
|
// subpass 3: color outputs : [4], inputs : [3]
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
// All graph passes are merged in the same render pass
|
|
Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 5 && passes[0].numNativeSubPasses == 4);
|
|
|
|
// Depth is the first attachment
|
|
Assert.IsTrue(passes[0].attachments[0].handle.index == buffers.depthBuffer.handle.index);
|
|
Assert.IsTrue(passes[0].attachments[1].handle.index == buffers.extraBuffers[1].handle.index);
|
|
Assert.IsTrue(passes[0].attachments[2].handle.index == buffers.extraBuffers[2].handle.index);
|
|
Assert.IsTrue(passes[0].attachments[3].handle.index == buffers.extraBuffers[0].handle.index);
|
|
Assert.IsTrue(passes[0].attachments[4].handle.index == buffers.extraBuffers[3].handle.index);
|
|
|
|
// Check first subpass is correctly updated
|
|
ref var subPassDesc0 = ref result.contextData.nativeSubPassData.ElementAt(0);
|
|
Assert.IsTrue(subPassDesc0.colorOutputs.Length == 1);
|
|
Assert.IsTrue(subPassDesc0.colorOutputs[0] == 3);
|
|
|
|
// Check second subpass is correctly updated
|
|
ref var subPassDesc1 = ref result.contextData.nativeSubPassData.ElementAt(1);
|
|
Assert.IsTrue(subPassDesc1.colorOutputs.Length == 1);
|
|
Assert.IsTrue(subPassDesc1.colorOutputs[0] == 1);
|
|
|
|
// Check third subpass is correctly updated
|
|
ref var subPassDesc2 = ref result.contextData.nativeSubPassData.ElementAt(2);
|
|
Assert.IsTrue(subPassDesc2.colorOutputs.Length == 1);
|
|
Assert.IsTrue(subPassDesc2.colorOutputs[0] == 2);
|
|
Assert.IsTrue(subPassDesc2.inputs.Length == 2);
|
|
Assert.IsTrue(subPassDesc2.inputs[0] == 3);
|
|
Assert.IsTrue(subPassDesc2.inputs[1] == 1);
|
|
|
|
// Check fourth subpass with depth is correct
|
|
ref var subPassDesc3 = ref result.contextData.nativeSubPassData.ElementAt(3);
|
|
Assert.IsTrue(subPassDesc3.colorOutputs.Length == 1);
|
|
Assert.IsTrue(subPassDesc3.colorOutputs[0] == 4);
|
|
Assert.IsTrue(subPassDesc3.inputs.Length == 1);
|
|
Assert.IsTrue(subPassDesc3.inputs[0] == 3);
|
|
}
|
|
|
|
/* //VRS bug. It seems that there is a bug with VRS forcing pass breaking between passes using the same shading rate image where it shouldn't: UUM-102113.
|
|
[Test]
|
|
public void UpdateShadingRateImageIndex_WhenDepthAttachmentIsAdded()
|
|
{
|
|
var g = AllocateRenderGraph();
|
|
var buffers = ImportAndCreateBuffers(g);
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("NoDepth_Subpass0", out var passData))
|
|
{
|
|
builder.SetShadingRateImageAttachment(buffers.extraBuffers[0]);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[1], 0);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
|
|
// Render Pass
|
|
// attachments: [extraBuffers[0], extraBuffers[1]]
|
|
// shading rate image : [0]
|
|
// subpass 0: color outputs : [1]
|
|
|
|
using (var builder = g.AddRasterRenderPass<RenderGraphTestPassData>("Depth_Subpass1", out var passData))
|
|
{
|
|
builder.SetShadingRateImageAttachment(buffers.extraBuffers[0]);
|
|
builder.SetRenderAttachmentDepth(buffers.depthBuffer, AccessFlags.Write);
|
|
builder.SetRenderAttachment(buffers.extraBuffers[2], 0);
|
|
builder.SetRenderFunc((RenderGraphTestPassData data, RasterGraphContext context) => { });
|
|
builder.AllowPassCulling(false);
|
|
}
|
|
|
|
// Render Pass
|
|
// attachments: [depthBuffer, extraBuffers[1], extraBuffers[0], extraBuffers[2]]
|
|
// shading rate image : [0 -> 2]
|
|
// subpass 0: color outputs : [1]
|
|
// subpass 1: color outputs : [3]
|
|
|
|
var result = g.CompileNativeRenderGraph(g.ComputeGraphHash());
|
|
var passes = result.contextData.GetNativePasses();
|
|
|
|
// All graph passes are merged in the same render pass
|
|
Assert.IsTrue(passes != null && passes.Count == 1 && passes[0].numGraphPasses == 2 && passes[0].numNativeSubPasses == 2);
|
|
|
|
// Depth is the first attachment
|
|
Assert.IsTrue(passes[0].attachments[0].handle.index == buffers.depthBuffer.handle.index);
|
|
Assert.IsTrue(passes[0].attachments[1].handle.index == buffers.extraBuffers[1].handle.index);
|
|
Assert.IsTrue(passes[0].attachments[2].handle.index == buffers.extraBuffers[0].handle.index);
|
|
Assert.IsTrue(passes[0].attachments[3].handle.index == buffers.extraBuffers[2].handle.index);
|
|
|
|
// Check Shading Rate Image index is correctly updated
|
|
Assert.IsTrue(passes[0].shadingRateImageIndex == buffers.extraBuffers[0].handle.index);
|
|
}
|
|
*/
|
|
}
|
|
}
|