Netcode Bootstrap
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using static Rukhanka.AnimationProcessSystem;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Tests
|
||||
{
|
||||
public class AnimationProcessSystemTests
|
||||
{
|
||||
[Test]
|
||||
public void MuscleRangeToRadiansTest()
|
||||
{
|
||||
var r0 = ComputeBoneAnimationJob.MuscleRangeToRadians(new float3(-60, -30, -100), new float3(40, 60, 120), new float3(-0.5f, 0.0f, 0.5f));
|
||||
Assert.IsTrue(math.all(r0 == new float3(-30, 0, 60)));
|
||||
|
||||
var r1 = ComputeBoneAnimationJob.MuscleRangeToRadians(new float3(-60, -30, -100), new float3(40, 60, 120), new float3(0, 0, 0));
|
||||
Assert.IsTrue(math.all(r1 == new float3(0, 0, 0)));
|
||||
|
||||
var r2 = ComputeBoneAnimationJob.MuscleRangeToRadians(new float3(-91, -92, -93), new float3(94, 95, 96), new float3(1, 1, 1));
|
||||
Assert.IsTrue(math.all(r2 == new float3(94, 95, 96)));
|
||||
|
||||
var r3 = ComputeBoneAnimationJob.MuscleRangeToRadians(new float3(-91, -92, -93), new float3(94, 95, 96), new float3(-1, -1, -1));
|
||||
Assert.IsTrue(math.all(r3 == new float3(-91, -92, -93)));
|
||||
|
||||
var r4 = ComputeBoneAnimationJob.MuscleRangeToRadians(new float3(-60, -30, -100), new float3(40, 60, 120), new float3(-0.9f, 0.1f, 0.9f));
|
||||
Assert.IsTrue(math.all(r4 == new float3(-54, 6, 108)));
|
||||
|
||||
var r5 = ComputeBoneAnimationJob.MuscleRangeToRadians(new float3(-60, -30, -100), new float3(40, 60, 120), new float3(0.9f, -0.1f, -0.2f));
|
||||
Assert.IsTrue(math.all(r5 == new float3(36, -3, -20)));
|
||||
|
||||
var r6 = ComputeBoneAnimationJob.MuscleRangeToRadians(new float3(-12, -13, -14), new float3(12, 13, 14), new float3(-2, 3, -5.5f));
|
||||
Assert.IsTrue(math.all(r6 == new float3(-24, 39, -77)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8972ff72b5f18f438eb941e6ac95b51
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/AnimationProcessSystemTests.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,79 @@
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Mathematics;
|
||||
using static Rukhanka.AnimatorControllerSystemJobs;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Tests
|
||||
{
|
||||
public class AnimatorControllerTest
|
||||
{
|
||||
[Test]
|
||||
public void LoopAwareTransitionTimeTest()
|
||||
{
|
||||
var fn = TestToolbox.GetStaticPrivateMethod<StateMachineProcessJob>("GetLoopAwareTransitionExitTime");
|
||||
|
||||
var testData = new List<float2>();
|
||||
testData.Add(new float2(0, 0));
|
||||
testData.Add(new float2(1, 0));
|
||||
testData.Add(new float2(0, 1));
|
||||
testData.Add(new float2(1, 1));
|
||||
testData.Add(new float2(0, 2));
|
||||
testData.Add(new float2(1, 2));
|
||||
testData.Add(new float2(0, 3));
|
||||
testData.Add(new float2(1, 3));
|
||||
testData.Add(new float2(0, 3.5f));
|
||||
testData.Add(new float2(1, 3.5f));
|
||||
testData.Add(new float2(0, 6.99f));
|
||||
testData.Add(new float2(1, 6.99f));
|
||||
testData.Add(new float2(0, 7.01f));
|
||||
testData.Add(new float2(1, 7.01f));
|
||||
|
||||
UnityEngine.Random.InitState(DateTime.Now.Millisecond);
|
||||
|
||||
for (var i = 0; i < 100; ++i)
|
||||
{
|
||||
var exitTime = UnityEngine.Random.value;
|
||||
var normalizedStateTime = (UnityEngine.Random.value * 2 - 1) * 20;
|
||||
testData.Add(new float2(exitTime, normalizedStateTime));
|
||||
}
|
||||
|
||||
|
||||
// Test for exit time [0..1]
|
||||
foreach (var td in testData)
|
||||
{
|
||||
var exitTime = td.x;
|
||||
var normalizedStateTime = td.y;
|
||||
var t = StateMachineProcessJob.GetLoopAwareTransitionExitTime(exitTime, normalizedStateTime, math.sign(normalizedStateTime));
|
||||
var dt = t - normalizedStateTime;
|
||||
|
||||
//Debug.Log($"ET: {exitTime}, NT: {normalizedStateTime}, Transition Time: {t}");
|
||||
|
||||
if (math.sign(normalizedStateTime) > 0)
|
||||
{
|
||||
Assert.IsTrue(dt >= 0);
|
||||
Assert.IsTrue(dt <= 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsTrue(dt <= 0);
|
||||
Assert.IsTrue(dt >= -1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test for exit time >= 1
|
||||
for (var i = 0; i < 20; ++i)
|
||||
{
|
||||
var exitTime = UnityEngine.Random.value * 10 + 1;
|
||||
var normalizedStateTime = (UnityEngine.Random.value * 2 - 1) * 20;
|
||||
|
||||
var sgn = math.sign(normalizedStateTime);
|
||||
var t = StateMachineProcessJob.GetLoopAwareTransitionExitTime(exitTime, normalizedStateTime, sgn);
|
||||
|
||||
Assert.IsTrue(t == exitTime * sgn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06dc952934a081a44afa544c8bd18772
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/AnimatorControllerTest.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,142 @@
|
||||
using NUnit.Framework;
|
||||
using Rukhanka.Hybrid;
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Entities;
|
||||
using Random = Unity.Mathematics.Random;
|
||||
|
||||
#if RUKHANKA_WITH_TEST_PERFORMANCE
|
||||
using Unity.PerformanceTesting;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Tests
|
||||
{
|
||||
[BurstCompile]
|
||||
public class AnimatorParameterTest
|
||||
{
|
||||
#if RUKHANKA_WITH_TEST_PERFORMANCE
|
||||
[BurstCompile]
|
||||
static void ParameterAccessByLinearSearch(ref NativeSlice<AnimatorControllerParameterComponent> paramArr, int iterationCount, out int dummyResult)
|
||||
{
|
||||
var l = paramArr.Length;
|
||||
dummyResult = 0;
|
||||
for (int i = 0; i < iterationCount; ++i)
|
||||
{
|
||||
var idx = i % l;
|
||||
var p = paramArr[idx];
|
||||
|
||||
bool found = false;
|
||||
int k = 0;
|
||||
for (; k < paramArr.Length && !found; ++k)
|
||||
{
|
||||
var candidat = paramArr[k];
|
||||
found = candidat.hash == p.hash;
|
||||
}
|
||||
|
||||
dummyResult += paramArr[k - 1].value.intValue;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NativeArray<AnimatorControllerParameterComponent> CreateTestParamArray(int len)
|
||||
{
|
||||
var paramArr = new NativeArray<AnimatorControllerParameterComponent>(len, Allocator.Temp);
|
||||
var rng = new Random((uint)DateTime.Now.Millisecond + 1);
|
||||
|
||||
for (var i = 0; i < paramArr.Length; ++i)
|
||||
{
|
||||
var randomHash = rng.NextUInt();
|
||||
var acpc = new AnimatorControllerParameterComponent()
|
||||
{
|
||||
hash = randomHash,
|
||||
type = ControllerParameterType.Int,
|
||||
value = default
|
||||
};
|
||||
paramArr[i] = acpc;
|
||||
}
|
||||
return paramArr;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[Test, Performance]
|
||||
public void LinearSearchParameterAccess()
|
||||
{
|
||||
// Create test data
|
||||
var paramArr = CreateTestParamArray(200);
|
||||
|
||||
var iterationsCount = 1000000;
|
||||
|
||||
var testGroupSize = new int[] {2, 5, 10, 20, 50, 100};
|
||||
|
||||
foreach (var paramCount in testGroupSize)
|
||||
{
|
||||
var paramArrForTest = new NativeSlice<AnimatorControllerParameterComponent>(paramArr, 0, paramCount);
|
||||
Measure.Method(() =>
|
||||
{
|
||||
ParameterAccessByLinearSearch(ref paramArrForTest, iterationsCount, out var dummyResult);
|
||||
})
|
||||
.MeasurementCount(10)
|
||||
.SampleGroup($"Linear Parameter Access. Parameter count: {paramArrForTest.Length}, Searches count: {iterationsCount}")
|
||||
.Run();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
static unsafe void ParameterAccessHashLookup(ref NativeSlice<AnimatorControllerParameterComponent> paramArr, ref BlobAssetReference<PerfectHashTableBlob> pht, int iterationCount, out int dummyResult)
|
||||
{
|
||||
dummyResult = 0;
|
||||
var l = paramArr.Length;
|
||||
for (int i = 0; i < iterationCount; ++i)
|
||||
{
|
||||
var idx = i % l;
|
||||
var p = paramArr[idx];
|
||||
|
||||
var ps = new ReadOnlySpan<AnimatorControllerParameterComponent>(paramArr.GetUnsafePtr(), paramArr.Length);
|
||||
var pi = FastAnimatorParameter.GetRuntimeParameterIndex(p.hash, pht, ps);
|
||||
dummyResult += paramArr[pi].value.intValue;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[Test, Performance]
|
||||
public void HashTableParameterAccess()
|
||||
{
|
||||
// Create test data
|
||||
var paramArr = CreateTestParamArray(200);
|
||||
|
||||
var iterationsCount = 1000000;
|
||||
var testGroupSize = new int[] {2, 5, 10, 20, 50, 100};
|
||||
|
||||
foreach (var paramCount in testGroupSize)
|
||||
{
|
||||
var paramArrSlice = new NativeSlice<AnimatorControllerParameterComponent>(paramArr, 0, paramCount);
|
||||
var hashesArr = new NativeArray<uint>(paramCount, Allocator.Temp);
|
||||
for (int i = 0; i < hashesArr.Length; ++i)
|
||||
{
|
||||
hashesArr[i] = paramArr[i].hash;
|
||||
}
|
||||
|
||||
var perfectHashTableBlob = AnimatorControllerBaker.CreateParametersPerfectHashTableBlobInternal(hashesArr);
|
||||
Measure.Method(() =>
|
||||
{
|
||||
ParameterAccessHashLookup(ref paramArrSlice, ref perfectHashTableBlob, iterationsCount, out _);
|
||||
})
|
||||
.MeasurementCount(10)
|
||||
.SampleGroup($"Hash Table Parameter Access. Parameter count: {paramArrSlice.Length}, Searches count: {iterationsCount}")
|
||||
.Run();
|
||||
|
||||
perfectHashTableBlob.Dispose();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e01a62303845fcc4cb476467f1d8d7ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/AnimatorParameterTest.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,36 @@
|
||||
using NUnit.Framework;
|
||||
using Rukhanka.Toolbox;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using Random = Unity.Mathematics.Random;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Tests
|
||||
{
|
||||
public class BitFieldNTest
|
||||
{
|
||||
[Test]
|
||||
public unsafe void FunctionalityTest()
|
||||
{
|
||||
var rng = new Random((uint)(Time.time * 1000));
|
||||
var maxBitfieldSize = rng.NextInt(300, 1000);
|
||||
var bitFieldMem = stackalloc uint[maxBitfieldSize];
|
||||
|
||||
var numTests = rng.NextUInt(100);
|
||||
for (var i = 0; i < numTests; ++i)
|
||||
{
|
||||
var sz = rng.NextInt(1, maxBitfieldSize);
|
||||
var bf = new BitFieldN(bitFieldMem, sz);
|
||||
|
||||
var i0 = rng.NextInt(0, bf.Length);
|
||||
bf.Set(i0, true);
|
||||
Assert.IsTrue(bf.IsSet(i0));
|
||||
Assert.IsTrue(bf.TestAny());
|
||||
bf.Set(i0, false);
|
||||
Assert.IsFalse(bf.IsSet(i0));
|
||||
Assert.IsFalse(bf.TestAny());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c5ef6a217643ec4b90bf176a3c2fe96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/BitFieldNTest.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,148 @@
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using Rukhanka.Toolbox;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using Random = Unity.Mathematics.Random;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Tests
|
||||
{
|
||||
public class ComputeBufferToolsTests
|
||||
{
|
||||
[Test]
|
||||
public void ComputeBufferClearTest()
|
||||
{
|
||||
var bufferSize = 0xffff;
|
||||
var readbackData = new int[bufferSize];
|
||||
var srcData = new NativeArray<int>(bufferSize, Allocator.Temp);
|
||||
using var buf = new GraphicsBuffer(GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, bufferSize, sizeof(int));
|
||||
|
||||
var rng = new Random((uint)bufferSize);
|
||||
|
||||
// Fill buffer with random data
|
||||
for (var k = 0; k < bufferSize; ++k)
|
||||
{
|
||||
srcData[k] = rng.NextInt();
|
||||
}
|
||||
|
||||
var numIterations = 10;
|
||||
for (var i = 0; i < numIterations; ++i)
|
||||
{
|
||||
buf.SetData(srcData);
|
||||
|
||||
// Now clear portion of buffer and check result
|
||||
var startIndex = rng.NextUInt((uint)bufferSize - 1);
|
||||
var count = rng.NextUInt((uint)bufferSize - startIndex);
|
||||
var clearValue = rng.NextInt();
|
||||
ComputeBufferTools.Clear(buf, startIndex * 4, count * 4, (uint)clearValue);
|
||||
|
||||
buf.GetData(readbackData);
|
||||
|
||||
// Verify correctness
|
||||
for (var k = 0; k < bufferSize; ++k)
|
||||
{
|
||||
var v = readbackData[k];
|
||||
var srcV = srcData[k];
|
||||
if (k < startIndex || k >= startIndex + count)
|
||||
{
|
||||
Assert.IsTrue(v == srcV);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsTrue(v == clearValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[Test]
|
||||
public void ComputeBufferCopyTest()
|
||||
{
|
||||
var bufferSize = 0xffff;
|
||||
using var srcBuf = new GraphicsBuffer(GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, bufferSize, sizeof(int));
|
||||
var srcData = new NativeArray<int>(srcBuf.count, Allocator.Temp);
|
||||
using var dstBuf = new GraphicsBuffer(GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, bufferSize * 2, sizeof(int));
|
||||
var dstData = new NativeArray<int>(dstBuf.count, Allocator.Temp);
|
||||
var readbackData = new int[dstBuf.count];
|
||||
|
||||
var rng = new Random((uint)bufferSize);
|
||||
|
||||
// Fill buffer with random data
|
||||
for (var k = 0; k < srcData.Length; ++k)
|
||||
srcData[k] = rng.NextInt();
|
||||
|
||||
for (var k = 0; k < dstData.Length; ++k)
|
||||
dstData[k] = rng.NextInt();
|
||||
|
||||
var numIterations = 100;
|
||||
for (var i = 0; i < numIterations; ++i)
|
||||
{
|
||||
srcBuf.SetData(srcData);
|
||||
dstBuf.SetData(dstData);
|
||||
|
||||
var srcIndex = rng.NextUInt((uint)srcData.Length - 1);
|
||||
var copyCount = rng.NextUInt((uint)srcData.Length - srcIndex);
|
||||
var dstIndex = rng.NextUInt((uint)dstData.Length - copyCount);
|
||||
ComputeBufferTools.Copy(srcBuf, dstBuf, srcIndex * 4, dstIndex * 4, copyCount * 4);
|
||||
|
||||
dstBuf.GetData(readbackData);
|
||||
|
||||
// Verify correctness
|
||||
for (var k = 0; k < readbackData.Length; ++k)
|
||||
{
|
||||
var v = readbackData[k];
|
||||
var si = k - dstIndex;
|
||||
if (si < 0 || si >= copyCount)
|
||||
{
|
||||
var sv = dstData[k];
|
||||
Assert.IsTrue(v == sv);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sv = srcData[(int)(si + srcIndex)];
|
||||
Assert.IsTrue(v == sv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[Test]
|
||||
public void ComputeBufferResizeTest()
|
||||
{
|
||||
var srcBufferSize = 0xffff;
|
||||
var dstBufferSize = srcBufferSize * 2;
|
||||
var srcData = new NativeArray<int>(srcBufferSize, Allocator.Temp);
|
||||
|
||||
var rng = new Random((uint)srcBufferSize);
|
||||
|
||||
// Fill buffer with random data
|
||||
for (var k = 0; k < srcData.Length; ++k)
|
||||
srcData[k] = rng.NextInt();
|
||||
|
||||
var numIterations = 10;
|
||||
for (var i = 0; i < numIterations; ++i)
|
||||
{
|
||||
var srcBuf = new GraphicsBuffer(GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, srcBufferSize, sizeof(int));
|
||||
srcBuf.SetData(srcData);
|
||||
var newSize = rng.NextInt(dstBufferSize);
|
||||
using var newBuf = ComputeBufferTools.Resize(srcBuf, newSize);
|
||||
srcBuf.Release();
|
||||
var readbackBuf = new int[newSize];
|
||||
newBuf.GetData(readbackBuf);
|
||||
|
||||
var sz = math.min(newSize, srcData.Length);
|
||||
for (var k = 0; k < sz; ++k)
|
||||
{
|
||||
Assert.IsTrue(readbackBuf[k] == srcData[k]);
|
||||
}
|
||||
newBuf.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32a45c080cb803f418a4a8111296eb72
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/ComputeBufferToolsTest.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,45 @@
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using Rukhanka.Toolbox;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Tests
|
||||
{
|
||||
public class MathUtilsTest
|
||||
{
|
||||
[Test]
|
||||
public void ShuffleListTest()
|
||||
{
|
||||
var sz = 100;
|
||||
var srcArr = new NativeList<int>(128, Allocator.Temp);
|
||||
var refArr = new NativeList<int>(128, Allocator.Temp);
|
||||
|
||||
var rr = new Unity.Mathematics.Random(123);
|
||||
for (int i = 0; i < sz; ++i)
|
||||
{
|
||||
var v = rr.NextInt() % sz * 2;
|
||||
srcArr.Add(v);
|
||||
refArr.Add(v);
|
||||
}
|
||||
|
||||
var indexList = new NativeList<int>(srcArr.Length, Allocator.Temp);
|
||||
var shuffleList = new NativeList<int>(srcArr.Length, Allocator.Temp);
|
||||
for (int i = 0; i < sz; ++i) indexList.Add(i);
|
||||
|
||||
while (!indexList.IsEmpty)
|
||||
{
|
||||
var index = (int)(rr.NextUInt() % indexList.Length);
|
||||
shuffleList.Add(indexList[index]);
|
||||
indexList.RemoveAt(index);
|
||||
}
|
||||
|
||||
MathUtils.ShuffleArray(srcArr.AsArray().AsSpan(), shuffleList.AsArray());
|
||||
|
||||
for (int i = 0; i < sz; ++i)
|
||||
{
|
||||
Assert.IsTrue(srcArr[i] == refArr[shuffleList[i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abf96d770202cf64a98f590eca32fef9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/MathUtilsTest.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,168 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Rukhanka.Toolbox;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.PerformanceTesting;
|
||||
using UnityEngine;
|
||||
using Random = Unity.Mathematics.Random;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Tests
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
public class PerfectHashTest
|
||||
{
|
||||
[Test]
|
||||
public void PerfectHashValidationTest()
|
||||
{
|
||||
var numTests = 100;
|
||||
var seed = 123124u;
|
||||
var rng = new Random(seed);
|
||||
|
||||
for (var i = 0; i < numTests; ++i)
|
||||
{
|
||||
InternalHashFuncTest(rng.NextUInt(), math.abs(rng.NextInt() % 1000));
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe void InternalHashFuncTest(uint rngSeed, int numHashedValues)
|
||||
{
|
||||
var rng = new Random(rngSeed);
|
||||
|
||||
var hashArr = new NativeList<uint>(Allocator.Temp);
|
||||
for (int i = 0; i < numHashedValues; ++i)
|
||||
{
|
||||
hashArr.Add(rng.NextUInt());
|
||||
};
|
||||
Perfect2HashTable.Build(hashArr.AsArray(), out var pht, out var seed);
|
||||
|
||||
for (int i = 0; i < hashArr.Length; ++i)
|
||||
{
|
||||
var iHash = hashArr[i];
|
||||
var l = Perfect2HashTable.Query(iHash, seed, (uint2*)pht.GetUnsafePtr(), pht.Length);
|
||||
Assert.IsTrue(l == i);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
static void DummyUse(int s)
|
||||
{
|
||||
s += 1;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
static void HashSetQueryFunc(in NativeHashSet<uint> inSet, in NativeArray<uint> srcValues, int numIterations)
|
||||
{
|
||||
var sum = 0;
|
||||
for (int i = 0; i < numIterations; ++i)
|
||||
{
|
||||
var l = i * 12 % srcValues.Length;
|
||||
var k = inSet.Contains(srcValues[l]);
|
||||
sum += k ? 1 : 0;
|
||||
//BurstAssert.IsTrue(l == shuffleArr[k], "Does not match");
|
||||
}
|
||||
// Need to use sum somehow to keep query function body from stripping
|
||||
DummyUse(sum);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
static unsafe void PHT2QueryFunc(in NativeArray<uint2> pht, in NativeArray<uint> srcValues, uint seed, int numIterations)
|
||||
{
|
||||
var sum = 0;
|
||||
for (int i = 0; i < numIterations; ++i)
|
||||
{
|
||||
var l = i * 12 % srcValues.Length;
|
||||
var k = Perfect2HashTable.Query(srcValues[l], seed, (uint2*)pht.GetUnsafeReadOnlyPtr(), pht.Length);
|
||||
sum += (k >= 0) ? 1 : 0;
|
||||
//BurstAssert.IsTrue(k >= 0, "Does not match");
|
||||
}
|
||||
// Need to use sum somehow to keep query function body from stripping
|
||||
DummyUse(sum);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void NativeHashMapPerformanceSingleTest(NativeHashSet<uint> inSet, NativeArray<uint> srcValues, int numIterations)
|
||||
{
|
||||
Measure.Method(() =>
|
||||
{
|
||||
HashSetQueryFunc(inSet, srcValues, numIterations);
|
||||
})
|
||||
.MeasurementCount(10)
|
||||
.SampleGroup($"Native hash set query. Table size: {inSet.Count}, Queries count: {numIterations}")
|
||||
.Run();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PHT2_SingleTest(NativeArray<uint2> pht, NativeArray<uint> srcValues, uint seed, int numIterations)
|
||||
{
|
||||
Measure.Method(() =>
|
||||
{
|
||||
PHT2QueryFunc(pht, srcValues, seed, numIterations);
|
||||
})
|
||||
.MeasurementCount(10)
|
||||
.SampleGroup($"PHT2 query. Table size: {pht.Length}, Queries count: {numIterations}")
|
||||
.Run();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[Test, Performance]
|
||||
public void PerfectHashTableQueryPerformance()
|
||||
{
|
||||
var iterationsCount = 1000000;
|
||||
var rng = new Random((uint)(Time.time * 1000));
|
||||
|
||||
var testArraySizes = new [] { 10, 20, 50, 100, 200, 300 };
|
||||
|
||||
var maxElements = testArraySizes[^1];
|
||||
var hashArr = new NativeArray<uint>(maxElements, Allocator.Temp);
|
||||
var hashUniqCheck = new NativeHashSet<uint>(maxElements, Allocator.Temp);
|
||||
for (int i = 0; i < maxElements; ++i)
|
||||
{
|
||||
var v = rng.NextUInt();
|
||||
if (hashUniqCheck.Add(v))
|
||||
hashArr[i] = v;
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Generator collision!");
|
||||
i--;
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 0; i < testArraySizes.Length; ++i)
|
||||
{
|
||||
var h0 = hashArr.Slice(0, testArraySizes[i]).AsArray();
|
||||
Perfect2HashTable.Build(h0, out var pht, out var seed);
|
||||
PHT2_SingleTest(pht, h0, seed, iterationsCount);
|
||||
}
|
||||
|
||||
for (var i = 0; i < testArraySizes.Length; ++i)
|
||||
{
|
||||
var h0 = hashArr.Slice(0, testArraySizes[i]).AsArray();
|
||||
var hs = new NativeHashSet<uint>(h0.Length, Allocator.Temp);
|
||||
foreach (var v in h0)
|
||||
{
|
||||
hs.Add(v);
|
||||
}
|
||||
NativeHashMapPerformanceSingleTest(hs, h0, iterationsCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ff7f209bd6dd8f4f93c411f13e86b20
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/PerfectHashTest.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "Rukhanka.Tests",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:01e5f7c036964124aa192bf5e2d021ba",
|
||||
"GUID:69653bcfe095d1841bfa14a815f86dad",
|
||||
"GUID:3bd69b8470189e543a7984590f770554",
|
||||
"GUID:27619889b8ba8c24980f49ee34dbb44a",
|
||||
"GUID:0acc523941302664db1f4e527237feb3",
|
||||
"GUID:734d92eba21c94caba915361bd5ac177",
|
||||
"GUID:e0cd26848372d4e5c891c569017e11f1",
|
||||
"GUID:d8b63aba1907145bea998dd612889d6b",
|
||||
"GUID:c0dd0d10738d4ad4a9de57c559d0ca1b",
|
||||
"GUID:2665a8d13d1b3f18800f46e256720795",
|
||||
"GUID:8819f35a0fc84499b990e90a4ca1911f"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.test-framework.performance",
|
||||
"expression": "3.0.0-pre.2",
|
||||
"define": "RUKHANKA_WITH_TEST_PERFORMANCE"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af79188302ef8ac4694408b7b04e6709
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/Rukhanka.Tests.asmdef
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,173 @@
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.PerformanceTesting;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Tests
|
||||
{
|
||||
|
||||
[BurstCompile]
|
||||
public class SampleAnimationCurveTest
|
||||
{
|
||||
struct TestAnimationCurveBlob
|
||||
{
|
||||
public BlobArray<KeyFrame> animationCurve;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
static unsafe void SampleAnimationCurveLinearSearch(ref NativeArray<float> accumulator, in NativeArray<float> sampleTimes, in BlobAssetReference<TestAnimationCurveBlob> ba)
|
||||
{
|
||||
for (int i = 0; i < accumulator.Length; ++i)
|
||||
{
|
||||
var sum = 0.0f;
|
||||
for (int j = 0; j < sampleTimes.Length; ++j)
|
||||
{
|
||||
var arr = new ReadOnlySpan<KeyFrame>(ba.Value.animationCurve.GetUnsafePtr(), ba.Value.animationCurve.Length);
|
||||
var f = BlobCurve.SampleAnimationCurveLinearSearch(arr, sampleTimes[j]);
|
||||
sum += f;
|
||||
}
|
||||
accumulator[i] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
static unsafe void SampleAnimationCurveBinarySearch(ref NativeArray<float> accumulator, in NativeArray<float> sampleTimes, in BlobAssetReference<TestAnimationCurveBlob> ba)
|
||||
{
|
||||
for (int i = 0; i < accumulator.Length; ++i)
|
||||
{
|
||||
var sum = 0.0f;
|
||||
for (int j = 0; j < sampleTimes.Length; ++j)
|
||||
{
|
||||
var arr = new ReadOnlySpan<KeyFrame>(ba.Value.animationCurve.GetUnsafePtr(), ba.Value.animationCurve.Length);
|
||||
var f = BlobCurve.SampleAnimationCurveBinarySearch(arr, sampleTimes[j]);
|
||||
sum += f;
|
||||
}
|
||||
accumulator[i] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BlobAssetReference<TestAnimationCurveBlob> CreateTestBlob(int sz)
|
||||
{
|
||||
var bb = new BlobBuilder(Allocator.Temp);
|
||||
ref var cb = ref bb.ConstructRoot<TestAnimationCurveBlob>();
|
||||
var keyFramesArr = bb.Allocate(ref cb.animationCurve, sz);
|
||||
|
||||
var dt = 1.0f / keyFramesArr.Length;
|
||||
for (int i = 0; i < keyFramesArr.Length; ++i)
|
||||
{
|
||||
var kf = new KeyFrame()
|
||||
{
|
||||
time = dt * i,
|
||||
v = dt * i,
|
||||
inTan = 0.1f,
|
||||
outTan = 0.1f
|
||||
};
|
||||
keyFramesArr[i] = kf;
|
||||
}
|
||||
|
||||
var rv = bb.CreateBlobAssetReference<TestAnimationCurveBlob>(Allocator.Temp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[Test, Performance]
|
||||
public void SampleAnimationCurvePerformanceTests()
|
||||
{
|
||||
var acc = new NativeArray<float>(1000, Allocator.Temp);
|
||||
var sampleTimes = new NativeArray<float>(100, Allocator.Temp);
|
||||
var rr = new Unity.Mathematics.Random(123);
|
||||
|
||||
for (int i = 0; i < sampleTimes.Length; ++i)
|
||||
{
|
||||
sampleTimes[i] = rr.NextFloat();
|
||||
}
|
||||
|
||||
var testBlobAsset = CreateTestBlob(100);
|
||||
|
||||
Measure.Method(() =>
|
||||
{
|
||||
SampleAnimationCurveLinearSearch(ref acc, sampleTimes, testBlobAsset);
|
||||
})
|
||||
.MeasurementCount(10)
|
||||
.SampleGroup($"Linear key search")
|
||||
.Run();
|
||||
|
||||
Measure.Method(() =>
|
||||
{
|
||||
SampleAnimationCurveBinarySearch(ref acc, sampleTimes, testBlobAsset);
|
||||
})
|
||||
.MeasurementCount(10)
|
||||
.SampleGroup($"Binary key search")
|
||||
.Run();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe void ValidationTestBinarySearch(ref BlobArray<KeyFrame> ac)
|
||||
{
|
||||
var comparer = new FloatEqualityComparer(10e-6f);
|
||||
|
||||
var clip = new ReadOnlySpan<KeyFrame>(ac.GetUnsafePtr(), ac.Length);
|
||||
|
||||
var f = BlobCurve.SampleAnimationCurveBinarySearch(clip, 0);
|
||||
var refV = ac[0].v;
|
||||
Assert.That(f, Is.EqualTo(refV).Using(comparer));
|
||||
|
||||
f = BlobCurve.SampleAnimationCurveBinarySearch(clip, 1);
|
||||
refV = ac[ac.Length - 1].v;
|
||||
Assert.That(f, Is.EqualTo(refV).Using(comparer));
|
||||
|
||||
f = BlobCurve.SampleAnimationCurveBinarySearch(clip, -100);
|
||||
refV = ac[0].v;
|
||||
Assert.That(f, Is.EqualTo(refV).Using(comparer));
|
||||
|
||||
f = BlobCurve.SampleAnimationCurveBinarySearch(clip, 100);
|
||||
refV = ac[ac.Length - 1].v;
|
||||
Assert.That(f, Is.EqualTo(refV).Using(comparer));
|
||||
|
||||
var rr = new Unity.Mathematics.Random((uint)ac.Length);
|
||||
|
||||
var delta = 1.0f / ac.Length;
|
||||
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
var time = rr.NextFloat();
|
||||
f = BlobCurve.SampleAnimationCurveBinarySearch(clip, time);
|
||||
Assert.IsTrue(math.abs(f - time) < delta);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[Test]
|
||||
public void SampleAnimationCurveValidationTests()
|
||||
{
|
||||
var blob10 = CreateTestBlob(10);
|
||||
var blob2 = CreateTestBlob(2);
|
||||
var blob3 = CreateTestBlob(3);
|
||||
var blob7 = CreateTestBlob(7);
|
||||
var blob123 = CreateTestBlob(123);
|
||||
var blob321 = CreateTestBlob(321);
|
||||
|
||||
ValidationTestBinarySearch(ref blob10.Value.animationCurve);
|
||||
ValidationTestBinarySearch(ref blob2.Value.animationCurve);
|
||||
ValidationTestBinarySearch(ref blob3.Value.animationCurve);
|
||||
ValidationTestBinarySearch(ref blob7.Value.animationCurve);
|
||||
ValidationTestBinarySearch(ref blob123.Value.animationCurve);
|
||||
ValidationTestBinarySearch(ref blob321.Value.animationCurve);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15fba35ea76ae0b42a8d183f293ea08b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/SampleAnimationCurveTests.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,24 @@
|
||||
using NUnit.Framework;
|
||||
using System.Reflection;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Tests
|
||||
{
|
||||
public static class TestToolbox
|
||||
{
|
||||
public static MethodInfo GetStaticPrivateMethod<T>(string fnName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(fnName))
|
||||
Assert.Fail("Function name cannot be empty");
|
||||
|
||||
var classType = typeof(T);
|
||||
MethodInfo rv = classType.GetMethod(fnName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
if (rv == null)
|
||||
Assert.Fail(string.Format("{0} method not found", fnName));
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5dd31b777f2b6fc48a80550a59ff997d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Tests/TestToolbox.cs
|
||||
uploadId: 897522
|
||||
Reference in New Issue
Block a user