This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
using NUnit.Framework;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Rendering;
namespace UnityEngine.Rendering.Tests
{
class BitArrayTests
{
BitArray8[] ba8;
BitArray16[] ba16;
BitArray32[] ba32;
BitArray64[] ba64;
BitArray128[] ba128;
BitArray256[] ba256;
static readonly uint[] aIndexes = new uint[] { 300, 200, 198, 100, 98, 60, 58, 30, 28, 10, 8, 4, 2, 0, 0 }; //double 0 entry to test double entry
static readonly uint[] bIndexes = new uint[] { 300, 200, 199, 100, 99, 60, 59, 30, 29, 10, 9, 8, 5, 1, 0 };
static readonly uint[] getSetTestedIndexes = new uint[] { 201, 200, 101, 100, 61, 60, 31, 30, 11, 10, 1, 0 }; // on a, odd value are false, even true
const string aHumanized = "00000000.00000000.00000000.00000000.00000000.00000000.00000001.01000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00010100.00000000.00000000.00000000.00000000.00010100.00000000.00000000.00000000.01010000.00000000.00000101.00010101";
const string bHumanized = "00000000.00000000.00000000.00000000.00000000.00000000.00000001.10000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00011000.00000000.00000000.00000000.00000000.00011000.00000000.00000000.00000000.01100000.00000000.00000111.00100011";
const string aAndBHumanized = "00000000.00000000.00000000.00000000.00000000.00000000.00000001.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00010000.00000000.00000000.00000000.00000000.00010000.00000000.00000000.00000000.01000000.00000000.00000101.00000001";
const string aOrBHumanized = "00000000.00000000.00000000.00000000.00000000.00000000.00000001.11000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00011100.00000000.00000000.00000000.00000000.00011100.00000000.00000000.00000000.01110000.00000000.00000111.00110111";
const string notAHumanized = "11111111.11111111.11111111.11111111.11111111.11111111.11111110.10111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11101011.11111111.11111111.11111111.11111111.11101011.11111111.11111111.11111111.10101111.11111111.11111010.11101010";
const string zeroHumanized = "00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000";
const string maxHumanized = "11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111.11111111";
[SetUp]
public void SetUpBitArray()
{
ba8 = new[] { new BitArray8(), new BitArray8(aIndexes), new BitArray8(bIndexes), new BitArray8(byte.MaxValue) };
ba16 = new[] { new BitArray16(), new BitArray16(aIndexes), new BitArray16(bIndexes), new BitArray16(ushort.MaxValue) };
ba32 = new[] { new BitArray32(), new BitArray32(aIndexes), new BitArray32(bIndexes), new BitArray32(uint.MaxValue) };
ba64 = new[] { new BitArray64(), new BitArray64(aIndexes), new BitArray64(bIndexes), new BitArray64(ulong.MaxValue) };
ba128 = new[] { new BitArray128(), new BitArray128(aIndexes), new BitArray128(bIndexes), new BitArray128(ulong.MaxValue, ulong.MaxValue) };
ba256 = new[] { new BitArray256(), new BitArray256(aIndexes), new BitArray256(bIndexes), new BitArray256(ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue) };
}
//[TearDown]
//nothing to do as they are non static struct
string GetLastHumanizedBits(string a, uint bitNumber) => a.Substring(a.Length - ((int)bitNumber + ((int)bitNumber - 1) / 8)); //handle '.' separators
void TestBitArrayMethods<T>(T[] ba, uint capacity)
where T : IBitArray
{
Assert.AreEqual(capacity, ba[0].capacity);
Assert.AreEqual(true, ba[0].allFalse);
Assert.AreEqual(false, ba[0].allTrue);
var trimmedZeroHumanized = GetLastHumanizedBits(zeroHumanized, capacity);
var humanized = ba[0].humanizedData;
Assert.AreEqual(trimmedZeroHumanized, humanized);
Assert.AreEqual(capacity, ba[1].capacity);
Assert.AreEqual(false, ba[1].allFalse);
Assert.AreEqual(false, ba[1].allTrue);
var trimmedAHumanized = GetLastHumanizedBits(aHumanized, capacity);
humanized = ba[1].humanizedData;
Assert.AreEqual(trimmedAHumanized, humanized);
Assert.AreEqual(capacity, ba[2].capacity);
Assert.AreEqual(false, ba[2].allFalse);
Assert.AreEqual(false, ba[2].allTrue);
var trimmedBHumanized = GetLastHumanizedBits(bHumanized, capacity);
humanized = ba[2].humanizedData;
Assert.AreEqual(trimmedBHumanized, humanized);
Assert.AreEqual(capacity, ba[3].capacity);
Assert.AreEqual(false, ba[3].allFalse);
Assert.AreEqual(true, ba[3].allTrue);
var trimmedMaxHumnized = GetLastHumanizedBits(maxHumanized, capacity);
humanized = ba[3].humanizedData;
Assert.AreEqual(trimmedMaxHumnized, humanized);
}
void TestBitArrayOperator<T>(T[] ba)
where T : IBitArray
{
//ensure we keep value type when refactoring
var ba_4 = ba[1];
Assert.AreEqual(ba_4, ba[1]);
Assert.AreNotSame(ba_4, ba[1]);
ba_4 = ba[2];
Assert.AreNotEqual(ba_4, ba[1]);
//test and
var bAndA = ba[2].BitAnd(ba[1]);
var aAndB = ba[1].BitAnd(ba[2]);
Assert.AreEqual(bAndA, aAndB);
Assert.AreEqual(bAndA.humanizedData, GetLastHumanizedBits(aAndBHumanized, ba[0].capacity));
//test or
var bOrA = ba[2].BitOr(ba[1]);
var aOrB = ba[1].BitOr(ba[2]);
Assert.AreEqual(bOrA, aOrB);
Assert.AreEqual(bOrA.humanizedData, GetLastHumanizedBits(aOrBHumanized, ba[0].capacity));
//test not
var notA = ba[1].BitNot();
Assert.AreEqual(notA.humanizedData, GetLastHumanizedBits(notAHumanized, ba[0].capacity));
//test indexer
foreach (uint index in getSetTestedIndexes.Where(i => i < ba[0].capacity))
{
//test get
Assert.AreEqual(ba[1][index], (index & 1) == 0); //on a, odd value are false and even true
//test set
var bai = ba[1];
bai[index] = ba[1][index];
Assert.AreEqual(ba[1], bai);
bai[index] = !ba[1][index];
Assert.AreNotEqual(ba[1], bai);
Assert.AreEqual(bai[index], !ba[1][index]);
}
}
[Test]
public void TestBitArray8()
{
TestBitArrayMethods(ba8, 8u);
TestBitArrayOperator(ba8);
}
[Test]
public void TestBitArray16()
{
TestBitArrayMethods(ba16, 16u);
TestBitArrayOperator(ba16);
}
[Test]
public void TestBitArray32()
{
TestBitArrayMethods(ba32, 32u);
TestBitArrayOperator(ba32);
}
[Test]
public void TestBitArray64()
{
TestBitArrayMethods(ba64, 64u);
TestBitArrayOperator(ba64);
}
[Test]
public void TestBitArray128()
{
TestBitArrayMethods(ba128, 128u);
TestBitArrayOperator(ba128);
}
[Test]
public void TestBitArray256()
{
TestBitArrayMethods(ba256, 256u);
TestBitArrayOperator(ba256);
}
}
}

View File

@@ -0,0 +1,139 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.Tests
{
unsafe class CoreUnsafeUtilsTests
{
public struct TestData : IEquatable<TestData>
{
public int intValue;
public float floatValue;
public bool Equals(TestData other)
{
return intValue == other.intValue && floatValue == other.floatValue;
}
public override bool Equals(object obj)
{
if (!(obj is TestData))
return false;
return Equals((TestData)obj);
}
public override int GetHashCode()
{
fixed(float* fptr = &floatValue)
return intValue ^ *(int*)fptr;
}
}
static object[][] s_CopyToList = new object[][]
{
new object[] { new List<TestData>
{
new TestData { floatValue = 2, intValue = 1 },
new TestData { floatValue = 3, intValue = 2 },
new TestData { floatValue = 4, intValue = 3 },
new TestData { floatValue = 5, intValue = 4 },
new TestData { floatValue = 6, intValue = 5 },
} }
};
[Test]
[TestCaseSource("s_CopyToList")]
public void CopyToList(List<TestData> datas)
{
var dest = stackalloc TestData[datas.Count];
datas.CopyTo(dest, datas.Count);
for (int i = 0; i < datas.Count; ++i)
Assert.AreEqual(datas[i], dest[i]);
}
static object[][] s_CopyToArray = new object[][]
{
new object[] { new TestData[]
{
new TestData { floatValue = 2, intValue = 1 },
new TestData { floatValue = 3, intValue = 2 },
new TestData { floatValue = 4, intValue = 3 },
new TestData { floatValue = 5, intValue = 4 },
new TestData { floatValue = 6, intValue = 5 },
} }
};
[Test]
[TestCaseSource("s_CopyToArray")]
public void CopyToArray(TestData[] datas)
{
var dest = stackalloc TestData[datas.Length];
datas.CopyTo(dest, datas.Length);
for (int i = 0; i < datas.Length; ++i)
Assert.AreEqual(datas[i], dest[i]);
}
static object[][] s_QuickSort = new object[][]
{
new object[] { new int[] { 0, 1 } },
new object[] { new int[] { 1, 0 } },
new object[] { new int[] { 0, 4, 2, 6, 3, 7, 1, 5 } }, // Test with unique set
new object[] { new int[] { 0, 4, 2, 6, 4, 7, 1, 5 } }, // Test with non unique set
};
[Test]
[TestCaseSource("s_QuickSort")]
public void QuickSort(int[] values)
{
// We must perform a copy to avoid messing the test data directly
var ptrValues = stackalloc int[values.Length];
values.CopyTo(ptrValues, values.Length);
CoreUnsafeUtils.QuickSort<int>(values.Length, ptrValues);
for (int i = 0; i < values.Length - 1; ++i)
Assert.LessOrEqual(ptrValues[i], ptrValues[i + 1]);
}
static object[][] s_QuickSortHash = new object[][]
{
new object[]
{
new Hash128[] { Hash128.Parse("78b27b84a9011b5403e836b9dfa51e33"), Hash128.Parse("c7417d322c083197631326bccf3f9ea0"), Hash128.Parse("dd27f0dc4ffe20b0f8ecc0e4fdf618fe") },
new Hash128[] { Hash128.Parse("dd27f0dc4ffe20b0f8ecc0e4fdf618fe"), Hash128.Parse("c7417d322c083197631326bccf3f9ea0"), Hash128.Parse("78b27b84a9011b5403e836b9dfa51e33") },
},
};
[Test]
[TestCaseSource("s_QuickSortHash")]
public void QuickSortHash(Hash128[] l, Hash128[] r)
{
var lPtr = stackalloc Hash128[l.Length];
var rPtr = stackalloc Hash128[r.Length];
for (int i = 0; i < l.Length; ++i)
{
lPtr[i] = l[i];
rPtr[i] = r[i];
}
CoreUnsafeUtils.QuickSort<Hash128>(l.Length, lPtr);
CoreUnsafeUtils.QuickSort<Hash128>(r.Length, rPtr);
for (int i = 0; i < l.Length - 1; ++i)
{
Assert.LessOrEqual(lPtr[i], lPtr[i + 1]);
Assert.LessOrEqual(rPtr[i], rPtr[i + 1]);
}
for (int i = 0; i < l.Length; ++i)
{
Assert.AreEqual(lPtr[i], rPtr[i]);
}
}
}
}

View File

@@ -0,0 +1,24 @@
using UnityEngine;
using UnityEditor;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;
class EditorExampleTest
{
[Test]
public void EditorSampleTestSimplePasses()
{
// Use the Assert class to test conditions.
}
// A UnityTest behaves like a coroutine in PlayMode
// and allows you to yield null to skip a frame in EditMode
[UnityTest]
public IEnumerator EditorSampleTestWithEnumeratorPasses()
{
// Use the Assert class to test conditions.
// yield to skip a frame
yield return null;
}
}

View File

@@ -0,0 +1,62 @@
using NUnit.Framework;
using System;
namespace UnityEngine.Rendering.Tests
{
unsafe class FixedBufferStringQueueTests
{
[Test]
public void PushAndPopInBufferRange()
{
const int size = 512;
var bufferStart = stackalloc byte[size];
var buffer = new CoreUnsafeUtils.FixedBufferStringQueue(bufferStart, size);
Assert.True(buffer.TryPush("Lorem ipsum dolor sit"));
Assert.True(buffer.TryPush("amet, consectetur adipiscing"));
Assert.True(buffer.TryPush("elit, sed do eiusmod"));
Assert.True(buffer.TryPush("tempor incididunt ut labore"));
Assert.AreEqual(4, buffer.Count);
Assert.True(buffer.TryPop(out string v) && v == "Lorem ipsum dolor sit");
Assert.True(buffer.TryPop(out v) && v == "amet, consectetur adipiscing");
Assert.True(buffer.TryPop(out v) && v == "elit, sed do eiusmod");
Assert.True(buffer.TryPop(out v) && v == "tempor incididunt ut labore");
}
[Test]
public void PushAndPopOutOfBufferRange()
{
const int size = 64;
var bufferStart = stackalloc byte[size];
var buffer = new CoreUnsafeUtils.FixedBufferStringQueue(bufferStart, size);
Assert.True(buffer.TryPush("Lorem ipsum dolor sit"));
Assert.False(buffer.TryPush("amet, consectetur adipiscing"));
Assert.AreEqual(1, buffer.Count);
}
[Test]
public void PushAndPopAndClear()
{
const int size = 128;
var bufferStart = stackalloc byte[size];
var buffer = new CoreUnsafeUtils.FixedBufferStringQueue(bufferStart, size);
Assert.True(buffer.TryPush("Lorem ipsum dolor sit"));
Assert.True(buffer.TryPush("amet, consectetur adipiscing"));
Assert.False(buffer.TryPush("elit, sed do eiusmod"));
Assert.AreEqual(2, buffer.Count);
buffer.Clear();
Assert.AreEqual(0, buffer.Count);
Assert.True(buffer.TryPush("elit, sed do eiusmod"));
Assert.True(buffer.TryPush("tempor incididunt ut labore"));
Assert.True(buffer.TryPop(out string v) && v == "elit, sed do eiusmod");
Assert.True(buffer.TryPop(out v) && v == "tempor incididunt ut labore");
}
}
}

View File

@@ -0,0 +1,79 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace UnityEngine.Rendering.Tests
{
public static class ReflectionUtils
{
/// <summary>
/// Calls a private method from a class
/// </summary>
/// <param name="methodName">The method name</param>
/// <param name="args">The arguments to pass to the method</param>
public static object Invoke(this object target, string methodName, params object[] args)
{
Assert.True(target != null, "The target could not be null");
Assert.IsNotEmpty(methodName, "The field to set could not be null");
var mi = target.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
Assert.True(mi != null, $"Could not find method `{methodName}` on object `{target}`");
return mi.Invoke(target, args);
}
private static FieldInfo FindField(this Type type, string fieldName)
{
FieldInfo fi = null;
while (type != null)
{
fi = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
if (fi != null) break;
type = type.BaseType;
}
Assert.True(fi != null, $"Could not find method `{fieldName}` on object `{type}`");
return fi;
}
/// <summary>
/// Sets a private field from a class
/// </summary>
/// <param name="fieldName">The field to change</param>
/// <param name="value">The new value</param>
public static void SetField(this object target, string fieldName, object value)
{
Assert.True(target != null, "The target could not be null");
Assert.IsNotEmpty(fieldName, "The field to set could not be null");
target.GetType().FindField(fieldName).SetValue(target, value);
}
/// <summary>
/// Gets the value of a private field from a class
/// </summary>
/// <param name="fieldName">The field to get</param>
public static object GetField(this object target, string fieldName)
{
Assert.True(target != null, "The target could not be null");
Assert.IsNotEmpty(fieldName, "The field to set could not be null");
return target.GetType().FindField(fieldName).GetValue(target);
}
/// <summary>
/// Gets all the fields from a class
/// </summary>
public static IEnumerable<FieldInfo> GetFields(this object target)
{
Assert.True(target != null, "The target could not be null");
return target.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.OrderBy(t => t.MetadataToken);
}
}
}

View File

@@ -0,0 +1,552 @@
using NUnit.Framework;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering.Tests
{
class RenderGraphTests
{
RenderGraph m_RenderGraph = new RenderGraph();
[SetUp]
public void SetupRenderGraph()
{
m_RenderGraph.ClearCompiledGraph();
}
class RenderGraphTestPassData
{
public TextureHandle[] textures = new TextureHandle[8];
public ComputeBufferHandle[] buffers = new ComputeBufferHandle[8];
}
// Final output (back buffer) of render graph needs to be explicitly imported in order to know that the chain of dependency should not be culled.
[Test]
public void WriteToBackBufferNotCulled()
{
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(1, compiledPasses.size);
Assert.AreEqual(false, compiledPasses[0].culled);
}
// If no back buffer is ever written to, everything should be culled.
[Test]
public void NoWriteToBackBufferCulled()
{
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(1, compiledPasses.size);
Assert.AreEqual(true, compiledPasses[0].culled);
}
// Writing to imported resource is considered as a side effect so passes should not be culled.
[Test]
public void WriteToImportedTextureNotCulled()
{
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
builder.WriteTexture(m_RenderGraph.ImportTexture(null));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(1, compiledPasses.size);
Assert.AreEqual(false, compiledPasses[0].culled);
}
[Test]
public void WriteToImportedComputeBufferNotCulled()
{
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
builder.WriteComputeBuffer(m_RenderGraph.ImportComputeBuffer(null));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(1, compiledPasses.size);
Assert.AreEqual(false, compiledPasses[0].culled);
}
// TODO RENDERGRAPH : Temporarily removed. See RenderGraph.cs pass culling
//// A pass not writing to anything is useless and should be culled.
//[Test]
//public void CullPassWithNoProduct()
//{
// // This pass reads an input but does not produce anything (no writes) so it should be culled.
// TextureHandle texture = m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm });
// using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
// {
// builder.ReadTexture(texture);
// builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { });
// }
// m_RenderGraph.CompileRenderGraph();
// var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
// Assert.AreEqual(1, compiledPasses.size);
// Assert.AreEqual(true, compiledPasses[0].culled);
//}
//// A series of passes with no final product should be culled.
//[Test]
//public void CullPassWithTextureDependenciesAndNoProduct()
//{
// // First pass produces an output that is read by second pass.
// // Second pass does not produce anything so it should be culled as well as all its unused dependencies.
// TextureHandle texture;
// using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
// {
// texture = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
// builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { });
// }
// using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
// {
// builder.ReadTexture(texture);
// builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { });
// }
// m_RenderGraph.CompileRenderGraph();
// var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
// Assert.AreEqual(2, compiledPasses.size);
// Assert.AreEqual(true, compiledPasses[0].culled);
// Assert.AreEqual(true, compiledPasses[1].culled);
//}
//// A series of passes with no final product should be culled.
//// Here first pass is not culled because Compute Buffer is imported.
//// TODO: Add test where compute buffer is created instead of imported once the API exists.
//[Test]
//public void CullPassWithBufferDependenciesAndNoProduct()
//{
// // First pass produces an output that is read by second pass.
// // Second pass does not produce anything so it should be culled as well as all its unused dependencies.
// ComputeBufferHandle computeBuffer;
// using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
// {
// computeBuffer = builder.WriteComputeBuffer(m_RenderGraph.ImportComputeBuffer(null));
// builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { });
// }
// using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
// {
// builder.ReadComputeBuffer(computeBuffer);
// builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => { });
// }
// m_RenderGraph.CompileRenderGraph();
// var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
// Assert.AreEqual(2, compiledPasses.size);
// Assert.AreEqual(false, compiledPasses[0].culled); // Not culled because writing to an imported resource is a side effect.
// Assert.AreEqual(true, compiledPasses[1].culled);
//}
[Test]
public void PassWriteResourcePartialNotReadAfterNotCulled()
{
// If a pass writes to a resource that is not unused globally by the graph but not read ever AFTER the pass then the pass should be culled unless it writes to another used resource.
TextureHandle texture0;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
TextureHandle texture1;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
{
builder.ReadTexture(texture0);
texture1 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
// This pass writes to texture0 which is used so will not be culled out.
// Since texture0 is never read after this pass, we should decrement refCount for this pass and potentially cull it.
// However, it also writes to texture1 which is used in the last pass so we mustn't cull it.
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
{
builder.WriteTexture(texture0);
builder.WriteTexture(texture1);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass3", out var passData))
{
builder.ReadTexture(texture1);
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(4, compiledPasses.size);
Assert.AreEqual(false, compiledPasses[0].culled);
Assert.AreEqual(false, compiledPasses[1].culled);
Assert.AreEqual(false, compiledPasses[2].culled);
Assert.AreEqual(false, compiledPasses[3].culled);
}
[Test]
public void PassDisallowCullingNotCulled()
{
// This pass does nothing so should be culled but we explicitly disallow it.
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
builder.AllowPassCulling(false);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(1, compiledPasses.size);
Assert.AreEqual(false, compiledPasses[0].culled);
}
// First pass produces two textures and second pass only read one of the two. Pass one should not be culled.
[Test]
public void PartialUnusedProductNotCulled()
{
TextureHandle texture;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
texture = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
{
builder.ReadTexture(texture);
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(2, compiledPasses.size);
Assert.AreEqual(false, compiledPasses[0].culled);
Assert.AreEqual(false, compiledPasses[1].culled);
}
// Simple cycle of create/release of a texture across multiple passes.
[Test]
public void SimpleCreateReleaseTexture()
{
TextureHandle texture;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
texture = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
// Add dummy passes
for (int i = 0; i < 2; ++i)
{
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
{
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
{
builder.ReadTexture(texture);
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(4, compiledPasses.size);
Assert.Contains(texture.handle.index, compiledPasses[0].resourceCreateList[(int)RenderGraphResourceType.Texture]);
Assert.Contains(texture.handle.index, compiledPasses[3].resourceReleaseList[(int)RenderGraphResourceType.Texture]);
}
[Test]
public void UseTransientOutsidePassRaiseException()
{
Assert.Catch<System.ArgumentException>(() =>
{
TextureHandle texture;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
texture = builder.CreateTransientTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm });
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
{
builder.ReadTexture(texture); // This is illegal (transient resource was created in previous pass)
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
});
}
[Test]
public void TransientCreateReleaseInSamePass()
{
TextureHandle texture;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
texture = builder.CreateTransientTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm });
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(1, compiledPasses.size);
Assert.Contains(texture.handle.index, compiledPasses[0].resourceCreateList[(int)RenderGraphResourceType.Texture]);
Assert.Contains(texture.handle.index, compiledPasses[0].resourceReleaseList[(int)RenderGraphResourceType.Texture]);
}
// Texture that should be released during an async pass should have their release delayed until the first pass that syncs with the compute pipe.
// Otherwise they may be reused by the graphics pipe even if the async pipe is not done executing.
[Test]
public void AsyncPassReleaseTextureOnGraphicsPipe()
{
TextureHandle texture0;
TextureHandle texture1;
TextureHandle texture2;
TextureHandle texture3;
// First pass creates and writes two textures.
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("Async_TestPass0", out var passData))
{
texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
texture1 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.EnableAsyncCompute(true);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
// Second pass creates a transient texture => Create/Release should happen in this pass but we want to delay the release until the first graphics pipe pass that sync with async queue.
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("Async_TestPass1", out var passData))
{
texture2 = builder.CreateTransientTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm });
builder.WriteTexture(texture0);
builder.EnableAsyncCompute(true);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
// This pass is the last to read texture0 => Release should happen in this pass but we want to delay the release until the first graphics pipe pass that sync with async queue.
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("Async_TestPass2", out var passData))
{
texture0 = builder.ReadTexture(texture0);
builder.WriteTexture(texture1);
builder.EnableAsyncCompute(true);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
// Just here to add "padding" to the number of passes to ensure resources are not released right at the first sync pass.
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass3", out var passData))
{
texture3 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.EnableAsyncCompute(false);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
// Pass prior to synchronization should be where textures are released.
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass4", out var passData))
{
builder.WriteTexture(texture3);
builder.EnableAsyncCompute(false);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
// Graphics pass that reads texture1. This will request a sync with compute pipe. The previous pass should be the one releasing async textures.
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass5", out var passData))
{
builder.ReadTexture(texture1);
builder.ReadTexture(texture3);
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.EnableAsyncCompute(false);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(6, compiledPasses.size);
Assert.Contains(texture0.handle.index, compiledPasses[4].resourceReleaseList[(int)RenderGraphResourceType.Texture]);
Assert.Contains(texture2.handle.index, compiledPasses[4].resourceReleaseList[(int)RenderGraphResourceType.Texture]);
}
[Test]
public void TransientResourceNotCulled()
{
TextureHandle texture0;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
{
builder.CreateTransientTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm });
builder.WriteTexture(texture0);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
// Graphics pass that reads texture1. This will request a sync with compute pipe. The previous pass should be the one releasing async textures.
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass5", out var passData))
{
builder.ReadTexture(texture0);
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.EnableAsyncCompute(false);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(3, compiledPasses.size);
Assert.AreEqual(false, compiledPasses[1].culled);
}
[Test]
public void AsyncPassWriteWaitOnGraphcisPipe()
{
TextureHandle texture0;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("Async_TestPass1", out var passData))
{
texture0 = builder.WriteTexture(texture0);
builder.EnableAsyncCompute(true);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
{
builder.ReadTexture(texture0);
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(3, compiledPasses.size);
Assert.AreEqual(0, compiledPasses[1].syncToPassIndex);
Assert.AreEqual(1, compiledPasses[2].syncToPassIndex);
}
[Test]
public void AsyncPassReadWaitOnGraphcisPipe()
{
TextureHandle texture0;
TextureHandle texture1;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass0", out var passData))
{
texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("Async_TestPass1", out var passData))
{
builder.ReadTexture(texture0);
texture1 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.EnableAsyncCompute(true);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass2", out var passData))
{
builder.ReadTexture(texture1);
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(3, compiledPasses.size);
Assert.AreEqual(0, compiledPasses[1].syncToPassIndex);
Assert.AreEqual(1, compiledPasses[2].syncToPassIndex);
}
[Test]
public void GraphicsPassWriteWaitOnAsyncPipe()
{
TextureHandle texture0;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("Async_TestPass0", out var passData))
{
texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.EnableAsyncCompute(true);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
{
builder.WriteTexture(texture0);
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(2, compiledPasses.size);
Assert.AreEqual(0, compiledPasses[1].syncToPassIndex);
}
[Test]
public void GraphicsPassReadWaitOnAsyncPipe()
{
TextureHandle texture0;
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("Async_TestPass0", out var passData))
{
texture0 = builder.WriteTexture(m_RenderGraph.CreateTexture(new TextureDesc(Vector2.one) { colorFormat = GraphicsFormat.R8G8B8A8_UNorm }));
builder.EnableAsyncCompute(true);
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
using (var builder = m_RenderGraph.AddRenderPass<RenderGraphTestPassData>("TestPass1", out var passData))
{
builder.ReadTexture(texture0);
builder.WriteTexture(m_RenderGraph.ImportBackbuffer(0)); // Needed for the passes to not be culled
builder.SetRenderFunc((RenderGraphTestPassData data, RenderGraphContext context) => {});
}
m_RenderGraph.CompileRenderGraph();
var compiledPasses = m_RenderGraph.GetCompiledPassInfos();
Assert.AreEqual(2, compiledPasses.size);
Assert.AreEqual(0, compiledPasses[1].syncToPassIndex);
}
}
}

View File

@@ -0,0 +1,23 @@
{
"name": "Unity.RenderPipelines.Core.Editor.Tests",
"references": [
"GUID:df380645f10b7bc4b97d4f5eb6303d95",
"GUID:3eae0364be2026648bf74846acb8a731",
"GUID:27619889b8ba8c24980f49ee34dbb44a",
"GUID:0acc523941302664db1f4e527237feb3"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": []
}

View File

@@ -0,0 +1,159 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.Rendering;
namespace UnityEngine.Rendering.Tests
{
public class VolumeComponentEditorTests
{
class VolumeComponentNoAdditionalAttributes : VolumeComponent
{
public MinFloatParameter parameter = new MinFloatParameter(0f, 0f);
}
class VolumeComponentAllAdditionalAttributes : VolumeComponent
{
[AdditionalProperty]
public MinFloatParameter parameter1 = new MinFloatParameter(0f, 0f);
[AdditionalProperty]
public FloatParameter parameter2 = new MinFloatParameter(0f, 0f);
}
class VolumeComponentMixedAdditionalAttributes : VolumeComponent
{
public MinFloatParameter parameter1 = new MinFloatParameter(0f, 0f);
[AdditionalProperty]
public FloatParameter parameter2 = new MinFloatParameter(0f, 0f);
public MinFloatParameter parameter3 = new MinFloatParameter(0f, 0f);
[AdditionalProperty]
public FloatParameter parameter4 = new MinFloatParameter(0f, 0f);
}
[Test]
public void TestOverridesChanges()
{
var component = ScriptableObject.CreateInstance<VolumeComponentMixedAdditionalAttributes>();
var editor = (VolumeComponentEditor)Activator.CreateInstance(typeof(VolumeComponentEditor));
editor.Invoke("Init", component, null);
component.SetAllOverridesTo(false);
bool allOverridesState = (bool)editor.Invoke("AreAllOverridesTo", false);
Assert.True(allOverridesState);
component.SetAllOverridesTo(true);
// Was the change correct?
allOverridesState = (bool)editor.Invoke("AreAllOverridesTo", true);
Assert.True(allOverridesState);
// Enable the advance mode on the editor
component.SetField("m_AdvancedMode", true);
// Everything is false
component.SetAllOverridesTo(false);
// Disable the advance mode on the editor
component.SetField("m_AdvancedMode", false);
// Now just set to true the overrides of non additional properties
editor.Invoke("SetOverridesTo", true);
// Check that the non additional properties must be false
allOverridesState = (bool)editor.Invoke("AreAllOverridesTo", true);
Assert.False(allOverridesState);
ScriptableObject.DestroyImmediate(component);
}
static TestCaseData[] s_AdditionalAttributesTestCaseDatas =
{
new TestCaseData(typeof(VolumeComponentNoAdditionalAttributes))
.Returns(Array.Empty<string>())
.SetName("VolumeComponentNoAdditionalAttributes"),
new TestCaseData(typeof(VolumeComponentAllAdditionalAttributes))
.Returns(new string[2] {"parameter1", "parameter2"})
.SetName("VolumeComponentAllAdditionalAttributes"),
new TestCaseData(typeof(VolumeComponentMixedAdditionalAttributes))
.Returns(new string[2] {"parameter2", "parameter4"})
.SetName("VolumeComponentMixedAdditionalAttributes"),
};
[Test, TestCaseSource(nameof(s_AdditionalAttributesTestCaseDatas))]
public string[] AdditionalProperties(Type volumeComponentType)
{
var component = (VolumeComponent)ScriptableObject.CreateInstance(volumeComponentType);
var editor = (VolumeComponentEditor)Activator.CreateInstance(typeof(VolumeComponentEditor));
editor.Invoke("Init", component, null);
var fields = component
.GetFields()
.Where(f => f.GetCustomAttribute<AdditionalPropertyAttribute>() != null)
.Select(f => f.Name)
.ToArray();
var notAdditionalParameters = editor.GetField("m_VolumeNotAdditionalParameters") as List<VolumeParameter>;
Assert.True(fields.Count() + notAdditionalParameters.Count == component.parameters.Count);
ScriptableObject.DestroyImmediate(component);
return fields;
}
#region Decorators Handling Test
class VolumeComponentDecorators : VolumeComponent
{
[Tooltip("Increase to make the noise texture appear bigger and less")]
public FloatParameter _NoiseTileSize = new FloatParameter(25.0f);
[InspectorName("Color")]
public ColorParameter _FogColor = new ColorParameter(Color.grey);
[InspectorName("Size and occurrence"), Tooltip("Increase to make patches SMALLER, and frequent")]
public ClampedFloatParameter _HighNoiseSpaceFreq = new ClampedFloatParameter(0.1f, 0.1f, 1f);
}
readonly (string displayName, string tooltip)[] k_ExpectedResults =
{
(string.Empty, "Increase to make the noise texture appear bigger and less"),
("Color", string.Empty),
("Size and occurrence", "Increase to make patches SMALLER, and frequent")
};
[Test]
public void TestHandleParameterDecorators()
{
var component = ScriptableObject.CreateInstance<VolumeComponentDecorators>();
var editor = (VolumeComponentEditor)Activator.CreateInstance(typeof(VolumeComponentEditor));
editor.Invoke("Init", component, null);
var parameters =
editor.GetField("m_Parameters") as List<(GUIContent displayName, int displayOrder,
SerializedDataParameter param)>;
Assert.True(parameters != null && parameters.Count() == k_ExpectedResults.Count());
for (int i = 0; i < k_ExpectedResults.Count(); ++i)
{
var property = parameters[i].param;
var title = new GUIContent(parameters[i].displayName);
editor.Invoke("HandleDecorators", property, title);
Assert.True(k_ExpectedResults[i].displayName == title.text);
Assert.True(k_ExpectedResults[i].tooltip == title.tooltip);
}
ScriptableObject.DestroyImmediate(component);
}
#endregion
}
}