Ei kuvausta
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.

PlaymodeTest.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. using System.Collections;
  2. using NUnit.Framework;
  3. using Unity.Burst;
  4. using UnityEngine;
  5. using Unity.Jobs.LowLevel.Unsafe;
  6. using UnityEngine.TestTools;
  7. using System;
  8. using Unity.Jobs;
  9. [TestFixture]
  10. public class PlaymodeTest
  11. {
  12. // [UnityTest]
  13. public IEnumerator CheckBurstJobEnabledDisabled()
  14. {
  15. BurstCompiler.Options.EnableBurstCompileSynchronously = true;
  16. foreach(var item in CheckBurstJobDisabled()) yield return item;
  17. foreach(var item in CheckBurstJobEnabled()) yield return item;
  18. }
  19. private IEnumerable CheckBurstJobEnabled()
  20. {
  21. BurstCompiler.Options.EnableBurstCompilation = true;
  22. yield return null;
  23. using (var jobTester = new BurstJobTester2())
  24. {
  25. var result = jobTester.Calculate();
  26. Assert.AreNotEqual(0.0f, result);
  27. }
  28. }
  29. private IEnumerable CheckBurstJobDisabled()
  30. {
  31. BurstCompiler.Options.EnableBurstCompilation = false;
  32. yield return null;
  33. using (var jobTester = new BurstJobTester2())
  34. {
  35. var result = jobTester.Calculate();
  36. Assert.AreEqual(0.0f, result);
  37. }
  38. }
  39. [BurstCompile(CompileSynchronously = true)]
  40. private struct ThrowingJob : IJob
  41. {
  42. public int I;
  43. public void Execute()
  44. {
  45. if (I < 0)
  46. {
  47. throw new System.Exception("Some Exception!");
  48. }
  49. }
  50. }
  51. [Test]
  52. public void NoSafetyCheckExceptionWarningInEditor()
  53. {
  54. var job = new ThrowingJob { I = 42 };
  55. job.Schedule().Complete();
  56. // UNITY_BURST_DEBUG enables additional logging which messes with our check.
  57. var debuggingStr = Environment.GetEnvironmentVariable("UNITY_BURST_DEBUG");
  58. if (debuggingStr == null || !int.TryParse(debuggingStr, out var debugLevel) || debugLevel == 0)
  59. {
  60. LogAssert.NoUnexpectedReceived();
  61. }
  62. }
  63. private struct MyKey { public struct MySubKey0 { } public struct MySubKey1 { } }
  64. private struct SomeGenericStruct<T> {}
  65. private static readonly SharedStatic<int> SharedStaticOneType = SharedStatic<int>.GetOrCreate<MyKey>();
  66. private static readonly SharedStatic<double> SharedStaticTwoTypes0 = SharedStatic<double>.GetOrCreate<MyKey, MyKey.MySubKey0>();
  67. private static readonly SharedStatic<double> SharedStaticTwoTypes1 = SharedStatic<double>.GetOrCreate<MyKey, MyKey.MySubKey1>();
  68. private struct MyGenericContainingStruct<T>
  69. {
  70. public static readonly SharedStatic<int> Data0 = SharedStatic<int>.GetOrCreate<T>();
  71. public static readonly SharedStatic<int> Data1 = SharedStatic<int>.GetOrCreate<SomeGenericStruct<MyKey>, T>();
  72. public static readonly SharedStatic<int> Data2 = SharedStatic<int>.GetOrCreate<SomeGenericStruct<T>, MyKey>();
  73. }
  74. private static readonly SharedStatic<int> SharedStaticWithSystemTypes0 = SharedStatic<int>.GetOrCreate<IntPtr>();
  75. private static readonly SharedStatic<int> SharedStaticWithSystemTypes1 = SharedStatic<int>.GetOrCreate<IntPtr, MyKey>();
  76. private static readonly SharedStatic<int> SharedStaticWithSystemTypes2 = SharedStatic<int>.GetOrCreate<MyKey, IntPtr>();
  77. private static readonly SharedStatic<int> SharedStaticWithSystemTypes3 = SharedStatic<int>.GetOrCreate<IntPtr, IntPtr>();
  78. [Test]
  79. public unsafe void SharedStaticPostProcessedTests()
  80. {
  81. var oneType = SharedStatic<int>.GetOrCreate(typeof(MyKey));
  82. Assert.AreEqual((IntPtr)oneType.UnsafeDataPointer, (IntPtr)SharedStaticOneType.UnsafeDataPointer);
  83. Assert.AreNotEqual((IntPtr)oneType.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes0.UnsafeDataPointer);
  84. Assert.AreNotEqual((IntPtr)oneType.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes1.UnsafeDataPointer);
  85. var twoTypes0 = SharedStatic<double>.GetOrCreate(typeof(MyKey), typeof(MyKey.MySubKey0));
  86. Assert.AreEqual((IntPtr)twoTypes0.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes0.UnsafeDataPointer);
  87. Assert.AreNotEqual((IntPtr)twoTypes0.UnsafeDataPointer, (IntPtr)SharedStaticOneType.UnsafeDataPointer);
  88. Assert.AreNotEqual((IntPtr)twoTypes0.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes1.UnsafeDataPointer);
  89. var twoTypes1 = SharedStatic<double>.GetOrCreate(typeof(MyKey), typeof(MyKey.MySubKey1));
  90. Assert.AreEqual((IntPtr)twoTypes1.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes1.UnsafeDataPointer);
  91. Assert.AreNotEqual((IntPtr)twoTypes1.UnsafeDataPointer, (IntPtr)SharedStaticOneType.UnsafeDataPointer);
  92. Assert.AreNotEqual((IntPtr)twoTypes1.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes0.UnsafeDataPointer);
  93. // A shared static in a generic struct, that uses the same type for `GetOrCreate`, will resolve to the same shared static.
  94. Assert.AreEqual((IntPtr)oneType.UnsafeDataPointer, (IntPtr)MyGenericContainingStruct<MyKey>.Data0.UnsafeDataPointer);
  95. // These two test partial evaluations of shared statics (where we can evaluate one of the template arguments at ILPP time
  96. // but not both).
  97. Assert.AreEqual(
  98. (IntPtr)MyGenericContainingStruct<MyKey>.Data1.UnsafeDataPointer,
  99. (IntPtr)MyGenericContainingStruct<MyKey>.Data2.UnsafeDataPointer);
  100. // Check that system type evaluations all match up.
  101. Assert.AreEqual(
  102. (IntPtr)SharedStatic<int>.GetOrCreate(typeof(IntPtr)).UnsafeDataPointer,
  103. (IntPtr)SharedStaticWithSystemTypes0.UnsafeDataPointer);
  104. Assert.AreEqual(
  105. (IntPtr)SharedStatic<int>.GetOrCreate(typeof(IntPtr), typeof(MyKey)).UnsafeDataPointer,
  106. (IntPtr)SharedStaticWithSystemTypes1.UnsafeDataPointer);
  107. Assert.AreEqual(
  108. (IntPtr)SharedStatic<int>.GetOrCreate(typeof(MyKey), typeof(IntPtr)).UnsafeDataPointer,
  109. (IntPtr)SharedStaticWithSystemTypes2.UnsafeDataPointer);
  110. Assert.AreEqual(
  111. (IntPtr)SharedStatic<int>.GetOrCreate(typeof(IntPtr), typeof(IntPtr)).UnsafeDataPointer,
  112. (IntPtr)SharedStaticWithSystemTypes3.UnsafeDataPointer);
  113. }
  114. [BurstCompile]
  115. public struct SomeFunctionPointers
  116. {
  117. [BurstDiscard]
  118. private static void MessWith(ref int a) => a += 13;
  119. [BurstCompile]
  120. public static int A(int a, int b)
  121. {
  122. MessWith(ref a);
  123. return a + b;
  124. }
  125. [BurstCompile(DisableDirectCall = true)]
  126. public static int B(int a, int b)
  127. {
  128. MessWith(ref a);
  129. return a - b;
  130. }
  131. [BurstCompile(CompileSynchronously = true)]
  132. public static int C(int a, int b)
  133. {
  134. MessWith(ref a);
  135. return a * b;
  136. }
  137. [BurstCompile(CompileSynchronously = true, DisableDirectCall = true)]
  138. public static int D(int a, int b)
  139. {
  140. MessWith(ref a);
  141. return a / b;
  142. }
  143. public delegate int Delegate(int a, int b);
  144. }
  145. [Test]
  146. public void TestDirectCalls()
  147. {
  148. Assert.IsTrue(BurstCompiler.IsEnabled);
  149. // a can either be (42 + 13) + 53 or 42 + 53 (depending on whether it was burst compiled).
  150. var a = SomeFunctionPointers.A(42, 53);
  151. Assert.IsTrue((a == ((42 + 13) + 53)) || (a == (42 + 53)));
  152. // b can only be (42 + 13) - 53, because direct call is disabled and so we always call the managed method.
  153. var b = SomeFunctionPointers.B(42, 53);
  154. Assert.AreEqual((42 + 13) - 53, b);
  155. // c can only be 42 * 53, because synchronous compilation is enabled.
  156. var c = SomeFunctionPointers.C(42, 53);
  157. Assert.AreEqual(42 * 53, c);
  158. // d can only be (42 + 13) / 53, because even though synchronous compilation is enabled, direct call is disabled.
  159. var d = SomeFunctionPointers.D(42, 53);
  160. Assert.AreEqual((42 + 13) / 53, d);
  161. }
  162. [Test]
  163. public void TestDirectCallInNamespacedClass()
  164. {
  165. void onCompileILPPMethod2()
  166. {
  167. Assert.Fail("BurstCompiler.CompileILPPMethod2 should not have been called at this time");
  168. }
  169. // We expect BurstCompiler.CompileILPPMethod2 to have been called at startup, via
  170. // [InitializeOnLoad] or [RuntimeInitializeOnLoadMethod]. If it's called when we invoke
  171. // N.C.A(), then something has gone wrong.
  172. try
  173. {
  174. BurstCompiler.OnCompileILPPMethod2 += onCompileILPPMethod2;
  175. var result = N.C.A();
  176. Assert.AreEqual(42, result);
  177. }
  178. finally
  179. {
  180. BurstCompiler.OnCompileILPPMethod2 -= onCompileILPPMethod2;
  181. }
  182. }
  183. [Test]
  184. public void TestFunctionPointers()
  185. {
  186. Assert.IsTrue(BurstCompiler.IsEnabled);
  187. var A = BurstCompiler.CompileFunctionPointer<SomeFunctionPointers.Delegate>(SomeFunctionPointers.A);
  188. var B = BurstCompiler.CompileFunctionPointer<SomeFunctionPointers.Delegate>(SomeFunctionPointers.B);
  189. var C = BurstCompiler.CompileFunctionPointer<SomeFunctionPointers.Delegate>(SomeFunctionPointers.C);
  190. var D = BurstCompiler.CompileFunctionPointer<SomeFunctionPointers.Delegate>(SomeFunctionPointers.D);
  191. // a can either be (42 + 13) + 53 or 42 + 53 (depending on whether it was burst compiled).
  192. var a = A.Invoke(42, 53);
  193. Assert.IsTrue((a == ((42 + 13) + 53)) || (a == (42 + 53)));
  194. // b can either be (42 + 13) - 53 or 42 - 53 (depending on whether it was burst compiled).
  195. var b = B.Invoke(42, 53);
  196. Assert.IsTrue((b == ((42 + 13) - 53)) || (b == (42 - 53)));
  197. // c can only be 42 * 53, because synchronous compilation is enabled.
  198. var c = C.Invoke(42, 53);
  199. Assert.AreEqual(42 * 53, c);
  200. // d can only be 42 / 53, because synchronous compilation is enabled.
  201. var d = D.Invoke(42, 53);
  202. Assert.AreEqual(42 / 53, d);
  203. }
  204. [BurstCompile]
  205. public static class GenericClass<T>
  206. {
  207. [BurstCompile]
  208. public static int ConcreteMethod() => 3;
  209. }
  210. public delegate int NoArgsIntReturnDelegate();
  211. [Test]
  212. public void TestGenericClassConcreteMethodFunctionPointer()
  213. {
  214. Assert.IsTrue(BurstCompiler.IsEnabled);
  215. var F = BurstCompiler.CompileFunctionPointer<NoArgsIntReturnDelegate>(GenericClass<int>.ConcreteMethod);
  216. Assert.AreEqual(3, F.Invoke());
  217. }
  218. }
  219. // This test class is intentionally in a namespace to ensure that our
  220. // direct-call [RuntimeInitializeOnLoadMethod] works correctly in that
  221. // scenario.
  222. namespace N
  223. {
  224. [BurstCompile]
  225. internal static class C
  226. {
  227. public static int A() => B();
  228. [BurstCompile(CompileSynchronously = true)]
  229. private static int B()
  230. {
  231. var x = 42;
  232. DiscardedMethod(ref x);
  233. return x;
  234. }
  235. [BurstDiscard]
  236. private static void DiscardedMethod(ref int x)
  237. {
  238. x += 1;
  239. }
  240. }
  241. }