暫無描述
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.

ShaderGeneratorTests.cs 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. using System;
  2. using System.Globalization;
  3. using NUnit.Framework;
  4. using UnityEngine;
  5. using UnityEditor.Graphing;
  6. using UnityEditor.ShaderGraph;
  7. using UnityEditor.ShaderGraph.Internal;
  8. namespace UnityEditor.ShaderGraph.UnitTests
  9. {
  10. [TestFixture]
  11. class ShaderGeneratorTests
  12. {
  13. [OneTimeSetUp]
  14. public void RunBeforeAnyTests()
  15. {
  16. Debug.unityLogger.logHandler = new ConsoleLogHandler();
  17. }
  18. class TestNode : AbstractMaterialNode
  19. {
  20. public const int V1Out = 0;
  21. public const int V2Out = 1;
  22. public const int V3Out = 2;
  23. public const int V4Out = 3;
  24. public TestNode()
  25. {
  26. AddSlot(new Vector1MaterialSlot(V1Out, "V1Out", "V1Out", SlotType.Output, 0));
  27. AddSlot(new Vector2MaterialSlot(V2Out, "V2Out", "V2Out", SlotType.Output, Vector4.zero));
  28. AddSlot(new Vector3MaterialSlot(V3Out, "V3Out", "V3Out", SlotType.Output, Vector4.zero));
  29. AddSlot(new Vector4MaterialSlot(V4Out, "V4Out", "V4Out", SlotType.Output, Vector4.zero));
  30. }
  31. }
  32. [Test]
  33. public void AdaptNodeOutput1To1Works()
  34. {
  35. var node = new TestNode();
  36. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V1Out, ConcreteSlotValueType.Vector1);
  37. Assert.AreEqual(string.Format("{0}", node.GetVariableNameForSlot(TestNode.V1Out)), result);
  38. }
  39. [Test]
  40. public void AdaptNodeOutput1To2Works()
  41. {
  42. var node = new TestNode();
  43. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V1Out, ConcreteSlotValueType.Vector2);
  44. Assert.AreEqual(string.Format("({0}.xx)", node.GetVariableNameForSlot(TestNode.V1Out)), result);
  45. }
  46. [Test]
  47. public void AdaptNodeOutput1To3Works()
  48. {
  49. var node = new TestNode();
  50. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V1Out, ConcreteSlotValueType.Vector3);
  51. Assert.AreEqual(string.Format("({0}.xxx)", node.GetVariableNameForSlot(TestNode.V1Out)), result);
  52. }
  53. [Test]
  54. public void AdaptNodeOutput1To4Works()
  55. {
  56. var node = new TestNode();
  57. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V1Out, ConcreteSlotValueType.Vector4);
  58. Assert.AreEqual(string.Format("({0}.xxxx)", node.GetVariableNameForSlot(TestNode.V1Out)), result);
  59. }
  60. [Test]
  61. public void AdaptNodeOutput2To1Works()
  62. {
  63. var node = new TestNode();
  64. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V2Out, ConcreteSlotValueType.Vector1);
  65. Assert.AreEqual(string.Format("({0}).x", node.GetVariableNameForSlot(TestNode.V2Out)), result);
  66. }
  67. [Test]
  68. public void AdaptNodeOutput2To2Works()
  69. {
  70. var node = new TestNode();
  71. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V2Out, ConcreteSlotValueType.Vector2);
  72. Assert.AreEqual(string.Format("{0}", node.GetVariableNameForSlot(TestNode.V2Out)), result);
  73. }
  74. [Test]
  75. public void AdaptNodeOutput2To3Works()
  76. {
  77. var node = new TestNode();
  78. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V2Out, ConcreteSlotValueType.Vector3);
  79. Assert.AreEqual(string.Format("($precision3({0}, 0.0))", node.GetVariableNameForSlot(TestNode.V2Out)), result);
  80. }
  81. [Test]
  82. public void AdaptNodeOutput2To4Works()
  83. {
  84. var node = new TestNode();
  85. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V2Out, ConcreteSlotValueType.Vector4);
  86. Assert.AreEqual(string.Format("($precision4({0}, 0.0, 1.0))", node.GetVariableNameForSlot(TestNode.V2Out)), result);
  87. }
  88. [Test]
  89. public void AdaptNodeOutput3To1Works()
  90. {
  91. var node = new TestNode();
  92. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V3Out, ConcreteSlotValueType.Vector1);
  93. Assert.AreEqual(string.Format("({0}).x", node.GetVariableNameForSlot(TestNode.V3Out)), result);
  94. }
  95. [Test]
  96. public void AdaptNodeOutput3To2Works()
  97. {
  98. var node = new TestNode();
  99. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V3Out, ConcreteSlotValueType.Vector2);
  100. Assert.AreEqual(string.Format("({0}.xy)", node.GetVariableNameForSlot(TestNode.V3Out)), result);
  101. }
  102. [Test]
  103. public void AdaptNodeOutput3To3Works()
  104. {
  105. var node = new TestNode();
  106. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V3Out, ConcreteSlotValueType.Vector3);
  107. Assert.AreEqual(string.Format("{0}", node.GetVariableNameForSlot(TestNode.V3Out)), result);
  108. }
  109. [Test]
  110. public void AdaptNodeOutput3To4Fails()
  111. {
  112. var node = new TestNode();
  113. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V3Out, ConcreteSlotValueType.Vector4);
  114. Assert.AreEqual(string.Format("($precision4({0}, 1.0))", node.GetVariableNameForSlot(TestNode.V3Out)), result);
  115. }
  116. [Test]
  117. public void AdaptNodeOutput4To1Works()
  118. {
  119. var node = new TestNode();
  120. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V4Out, ConcreteSlotValueType.Vector1);
  121. Assert.AreEqual(string.Format("({0}).x", node.GetVariableNameForSlot(TestNode.V4Out)), result);
  122. }
  123. [Test]
  124. public void AdaptNodeOutput4To2Works()
  125. {
  126. var node = new TestNode();
  127. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V4Out, ConcreteSlotValueType.Vector2);
  128. Assert.AreEqual(string.Format("({0}.xy)", node.GetVariableNameForSlot(TestNode.V4Out)), result);
  129. }
  130. [Test]
  131. public void AdaptNodeOutput4To3Works()
  132. {
  133. var node = new TestNode();
  134. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V4Out, ConcreteSlotValueType.Vector3);
  135. Assert.AreEqual(string.Format("({0}.xyz)", node.GetVariableNameForSlot(TestNode.V4Out)), result);
  136. }
  137. [Test]
  138. public void AdaptNodeOutput4To4Works()
  139. {
  140. var node = new TestNode();
  141. var result = GenerationUtils.AdaptNodeOutput(node, TestNode.V4Out, ConcreteSlotValueType.Vector4);
  142. Assert.AreEqual(string.Format("{0}", node.GetVariableNameForSlot(TestNode.V4Out)), result);
  143. }
  144. [Test]
  145. public void AdaptNodeOutput1To4PreviewWorks()
  146. {
  147. var node = new TestNode();
  148. var result = GenerationUtils.AdaptNodeOutputForPreview(node, TestNode.V1Out);
  149. Assert.AreEqual(string.Format("half4({0}, {0}, {0}, 1.0)", node.GetVariableNameForSlot(TestNode.V1Out)), result);
  150. }
  151. [Test]
  152. public void AdaptNodeOutput2To4PreviewWorks()
  153. {
  154. var node = new TestNode();
  155. var expected = string.Format("half4({0}.x, {0}.y, 0.0, 1.0)", node.GetVariableNameForSlot(TestNode.V2Out));
  156. var result = GenerationUtils.AdaptNodeOutputForPreview(node, TestNode.V2Out);
  157. Assert.AreEqual(expected, result);
  158. }
  159. [Test]
  160. public void AdaptNodeOutput3To4PreviewWorks()
  161. {
  162. var node = new TestNode();
  163. var expected = string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", node.GetVariableNameForSlot(TestNode.V3Out));
  164. var result = GenerationUtils.AdaptNodeOutputForPreview(node, TestNode.V3Out);
  165. Assert.AreEqual(expected, result);
  166. }
  167. [Test]
  168. public void AdaptNodeOutput4To4PreviewWorks()
  169. {
  170. var node = new TestNode();
  171. var expected = string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", node.GetVariableNameForSlot(TestNode.V4Out));
  172. var result = GenerationUtils.AdaptNodeOutputForPreview(node, TestNode.V4Out);
  173. Assert.AreEqual(expected, result);
  174. }
  175. public struct PackingTestCase
  176. {
  177. internal string name;
  178. internal StructDescriptor inputStruct;
  179. internal StructDescriptor expectedOutputStruct;
  180. internal string expectedInterpolatorFunction;
  181. public override string ToString()
  182. {
  183. return name;
  184. }
  185. }
  186. public static readonly PackingTestCase[] s_PackingTestCase = new[]
  187. {
  188. new PackingTestCase()
  189. {
  190. name = "Simple_With_Semantic",
  191. inputStruct = new StructDescriptor()
  192. {
  193. name = "Input",
  194. packFields = false,
  195. fields = new []
  196. {
  197. new FieldDescriptor(tag: "Original", name: "position", define: string.Empty, type: ShaderValueType.Float4, semantic: "SV_POSITION", interpolation: "SV_POSITION_QUALIFIERS"),
  198. new FieldDescriptor(tag: "Original", name: "normalWS", define: string.Empty, type: ShaderValueType.Float3, semantic: "NORMAL_WS", interpolation: string.Empty),
  199. new FieldDescriptor(tag: "Original", name: "myFloatA", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  200. }
  201. },
  202. expectedOutputStruct = new StructDescriptor()
  203. {
  204. name = "PackedInput",
  205. packFields = true,
  206. fields = new []
  207. {
  208. new FieldDescriptor(tag: "Original", name: "position", define: string.Empty, type: ShaderValueType.Float4, semantic: "SV_POSITION", interpolation: "SV_POSITION_QUALIFIERS"),
  209. new FieldDescriptor(tag: "Original", name: "normalWS", define: string.Empty, type: ShaderValueType.Float3, semantic: "NORMAL_WS", interpolation: string.Empty),
  210. new FieldDescriptor(tag: "PackedInput", name: "myFloatA", define: string.Empty, type: "float1", semantic: "INTERP0", interpolation: string.Empty),
  211. }
  212. },
  213. expectedInterpolatorFunction = @"
  214. PackedInput PackInput (Input input)
  215. {
  216. PackedInput output;
  217. ZERO_INITIALIZE(PackedInput, output);
  218. output.position = input.position;
  219. output.normalWS = input.normalWS;
  220. output.myFloatA.x = input.myFloatA;
  221. return output;
  222. }
  223. Input UnpackInput (PackedInput input)
  224. {
  225. Input output;
  226. output.position = input.position;
  227. output.normalWS = input.normalWS;
  228. output.myFloatA = input.myFloatA.x;
  229. return output;
  230. }"
  231. },
  232. new PackingTestCase()
  233. {
  234. name = "Equivalent_Packing_F3F3F1F1_A",
  235. inputStruct = new StructDescriptor()
  236. {
  237. name = "Input",
  238. packFields = false,
  239. fields = new []
  240. {
  241. new FieldDescriptor(tag: "Original", name: "myVector3_A", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  242. new FieldDescriptor(tag: "Original", name: "myVector3_B", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  243. new FieldDescriptor(tag: "Original", name: "myFloat_A", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  244. new FieldDescriptor(tag: "Original", name: "myFloat_B", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  245. }
  246. },
  247. expectedOutputStruct = new StructDescriptor()
  248. {
  249. name = "PackedInput",
  250. packFields = true,
  251. fields = new []
  252. {
  253. new FieldDescriptor(tag: "PackedInput", name: "packed_myVector3_A_myFloat_A", define: string.Empty, type: "float4", semantic: "INTERP0", interpolation: string.Empty),
  254. new FieldDescriptor(tag: "PackedInput", name: "packed_myVector3_B_myFloat_B", define: string.Empty, type: "float4", semantic: "INTERP1", interpolation: string.Empty),
  255. }
  256. },
  257. expectedInterpolatorFunction = @"
  258. PackedInput PackInput (Input input)
  259. {
  260. PackedInput output;
  261. ZERO_INITIALIZE(PackedInput, output);
  262. output.packed_myVector3_A_myFloat_A.xyz = input.myVector3_A;
  263. output.packed_myVector3_A_myFloat_A.w = input.myFloat_A;
  264. output.packed_myVector3_B_myFloat_B.xyz = input.myVector3_B;
  265. output.packed_myVector3_B_myFloat_B.w = input.myFloat_B;
  266. return output;
  267. }
  268. Input UnpackInput (PackedInput input)
  269. {
  270. Input output;
  271. output.myVector3_A = input.packed_myVector3_A_myFloat_A.xyz;
  272. output.myFloat_A = input.packed_myVector3_A_myFloat_A.w;
  273. output.myVector3_B = input.packed_myVector3_B_myFloat_B.xyz;
  274. output.myFloat_B = input.packed_myVector3_B_myFloat_B.w;
  275. return output;
  276. }"
  277. },
  278. new PackingTestCase()
  279. {
  280. name = "Equivalent_Packing_F3F3F1F1_B",
  281. inputStruct = new StructDescriptor()
  282. {
  283. name = "Input",
  284. packFields = false,
  285. fields = new []
  286. {
  287. //This test insure the order of input packing doesn't fail the following packing
  288. new FieldDescriptor(tag: "Original", name: "myFloat_A", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  289. new FieldDescriptor(tag: "Original", name: "myFloat_B", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  290. new FieldDescriptor(tag: "Original", name: "myVector3_A", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  291. new FieldDescriptor(tag: "Original", name: "myVector3_B", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  292. }
  293. },
  294. expectedOutputStruct = new StructDescriptor()
  295. {
  296. name = "PackedInput",
  297. packFields = true,
  298. fields = new []
  299. {
  300. new FieldDescriptor(tag: "PackedInput", name: "packed_myVector3_A_myFloat_A", define: string.Empty, type: "float4", semantic: "INTERP0", interpolation: string.Empty),
  301. new FieldDescriptor(tag: "PackedInput", name: "packed_myVector3_B_myFloat_B", define: string.Empty, type: "float4", semantic: "INTERP1", interpolation: string.Empty),
  302. }
  303. },
  304. expectedInterpolatorFunction = @"
  305. PackedInput PackInput (Input input)
  306. {
  307. PackedInput output;
  308. ZERO_INITIALIZE(PackedInput, output);
  309. output.packed_myVector3_A_myFloat_A.xyz = input.myVector3_A;
  310. output.packed_myVector3_A_myFloat_A.w = input.myFloat_A;
  311. output.packed_myVector3_B_myFloat_B.xyz = input.myVector3_B;
  312. output.packed_myVector3_B_myFloat_B.w = input.myFloat_B;
  313. return output;
  314. }
  315. Input UnpackInput (PackedInput input)
  316. {
  317. Input output;
  318. output.myVector3_A = input.packed_myVector3_A_myFloat_A.xyz;
  319. output.myFloat_A = input.packed_myVector3_A_myFloat_A.w;
  320. output.myVector3_B = input.packed_myVector3_B_myFloat_B.xyz;
  321. output.myFloat_B = input.packed_myVector3_B_myFloat_B.w;
  322. return output;
  323. }"
  324. },
  325. new PackingTestCase()
  326. {
  327. name = "Packing_F3F3F2",
  328. inputStruct = new StructDescriptor()
  329. {
  330. name = "Input",
  331. packFields = false,
  332. fields = new []
  333. {
  334. new FieldDescriptor(tag: "Original", name: "myFloat_A", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  335. new FieldDescriptor(tag: "Original", name: "myFloat_B", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  336. new FieldDescriptor(tag: "Original", name: "myVector2", define: string.Empty, type: ShaderValueType.Float2, semantic: string.Empty, interpolation: string.Empty),
  337. }
  338. },
  339. expectedOutputStruct = new StructDescriptor()
  340. {
  341. name = "PackedInput",
  342. packFields = true,
  343. fields = new []
  344. {
  345. new FieldDescriptor(tag: "PackedInput", name: "packed_myFloat_A_myVector2x", define: string.Empty, type: "float4", semantic: "INTERP0", interpolation: string.Empty),
  346. new FieldDescriptor(tag: "PackedInput", name: "packed_myFloat_B_myVector2y", define: string.Empty, type: "float4", semantic: "INTERP1", interpolation: string.Empty),
  347. }
  348. },
  349. expectedInterpolatorFunction = @"
  350. PackedInput PackInput (Input input)
  351. {
  352. PackedInput output;
  353. ZERO_INITIALIZE(PackedInput, output);
  354. output.packed_myFloat_A_myVector2x.xyz = input.myFloat_A;
  355. output.packed_myFloat_A_myVector2x.w = input.myVector2.x;
  356. output.packed_myFloat_B_myVector2y.xyz = input.myFloat_B;
  357. output.packed_myFloat_B_myVector2y.w = input.myVector2.y;
  358. return output;
  359. }
  360. Input UnpackInput (PackedInput input)
  361. {
  362. Input output;
  363. output.myFloat_A = input.packed_myFloat_A_myVector2x.xyz;
  364. output.myVector2.x = input.packed_myFloat_A_myVector2x.w;
  365. output.myFloat_B = input.packed_myFloat_B_myVector2y.xyz;
  366. output.myVector2.y = input.packed_myFloat_B_myVector2y.w;
  367. return output;
  368. }
  369. "
  370. },
  371. new PackingTestCase()
  372. {
  373. name = "Packing_F3F3F3F3",
  374. inputStruct = new StructDescriptor()
  375. {
  376. name = "Input",
  377. packFields = false,
  378. fields = new []
  379. {
  380. new FieldDescriptor(tag: "Original", name: "myFloat3_A", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  381. new FieldDescriptor(tag: "Original", name: "myFloat3_B", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  382. new FieldDescriptor(tag: "Original", name: "myFloat3_C", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  383. new FieldDescriptor(tag: "Original", name: "myFloat3_D", define: string.Empty, type: ShaderValueType.Float3, semantic: string.Empty, interpolation: string.Empty),
  384. }
  385. },
  386. expectedOutputStruct = new StructDescriptor()
  387. {
  388. name = "PackedInput",
  389. packFields = true,
  390. fields = new []
  391. {
  392. new FieldDescriptor(tag: "PackedInput", name: "packed_myFloat3_A_myFloat3_Dx", define: string.Empty, type: "float4", semantic: "INTERP0", interpolation: string.Empty),
  393. new FieldDescriptor(tag: "PackedInput", name: "packed_myFloat3_B_myFloat3_Dy", define: string.Empty, type: "float4", semantic: "INTERP1", interpolation: string.Empty),
  394. new FieldDescriptor(tag: "PackedInput", name: "packed_myFloat3_C_myFloat3_Dz", define: string.Empty, type: "float4", semantic: "INTERP2", interpolation: string.Empty),
  395. }
  396. },
  397. expectedInterpolatorFunction = @"
  398. PackedInput PackInput (Input input)
  399. {
  400. PackedInput output;
  401. ZERO_INITIALIZE(PackedInput, output);
  402. output.packed_myFloat3_A_myFloat3_Dx.xyz = input.myFloat3_A;
  403. output.packed_myFloat3_A_myFloat3_Dx.w = input.myFloat3_D.x;
  404. output.packed_myFloat3_B_myFloat3_Dy.xyz = input.myFloat3_B;
  405. output.packed_myFloat3_B_myFloat3_Dy.w = input.myFloat3_D.y;
  406. output.packed_myFloat3_C_myFloat3_Dz.xyz = input.myFloat3_C;
  407. output.packed_myFloat3_C_myFloat3_Dz.w = input.myFloat3_D.z;
  408. return output;
  409. }
  410. Input UnpackInput (PackedInput input)
  411. {
  412. Input output;
  413. output.myFloat3_A = input.packed_myFloat3_A_myFloat3_Dx.xyz;
  414. output.myFloat3_D.x = input.packed_myFloat3_A_myFloat3_Dx.w;
  415. output.myFloat3_B = input.packed_myFloat3_B_myFloat3_Dy.xyz;
  416. output.myFloat3_D.y = input.packed_myFloat3_B_myFloat3_Dy.w;
  417. output.myFloat3_C = input.packed_myFloat3_C_myFloat3_Dz.xyz;
  418. output.myFloat3_D.z = input.packed_myFloat3_C_myFloat3_Dz.w;
  419. return output;
  420. }
  421. "
  422. },
  423. new PackingTestCase()
  424. {
  425. name = "Typical_Use_Case",
  426. inputStruct = new StructDescriptor()
  427. {
  428. name = "Input",
  429. packFields = false,
  430. fields = new []
  431. {
  432. new FieldDescriptor(tag: "Original", name: "position", define: string.Empty, type: ShaderValueType.Float4, semantic: "SV_POSITION", interpolation: "SV_POSITION_QUALIFIERS"),
  433. new FieldDescriptor(tag: "Original", name: "myIntA", define: string.Empty, type: ShaderValueType.Integer, semantic: string.Empty, interpolation: "nointerpolation"),
  434. new FieldDescriptor(tag: "Original", name: "myIntB", define: string.Empty, type: ShaderValueType.Integer, semantic: string.Empty, interpolation: "nointerpolation"),
  435. new FieldDescriptor(tag: "Original", name: "myFloatA", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: "nointerpolation"),
  436. new FieldDescriptor(tag: "Original", name: "myFloatB", define: string.Empty, type: ShaderValueType.Float2, semantic: string.Empty, interpolation: "nointerpolation"),
  437. new FieldDescriptor(tag: "Original", name: "myInterFloatA", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  438. new FieldDescriptor(tag: "Original", name: "myInterFloatB", define: string.Empty, type: ShaderValueType.Float2, semantic: string.Empty, interpolation: string.Empty),
  439. new FieldDescriptor(tag: "Original", name: "instanceID", define: string.Empty, type: ShaderValueType.Uint, semantic: "CUSTOM_INSTANCE_ID", preprocessor: "UNITY_ANY_INSTANCING_ENABLED")
  440. }
  441. },
  442. expectedOutputStruct = new StructDescriptor()
  443. {
  444. name = "PackedInput",
  445. packFields = true,
  446. fields = new[]
  447. {
  448. new FieldDescriptor(tag: "Original", name: "position", define: string.Empty, type: ShaderValueType.Float4, semantic: "SV_POSITION", interpolation: "SV_POSITION_QUALIFIERS"),
  449. new FieldDescriptor(tag: "PackedInput", name: "myIntA", define: string.Empty, type: ShaderValueType.Integer, semantic: "INTERP0", interpolation: "nointerpolation"),
  450. new FieldDescriptor(tag: "PackedInput", name: "myIntB", define: string.Empty, type: ShaderValueType.Integer, semantic: "INTERP1", interpolation: "nointerpolation"),
  451. new FieldDescriptor(tag: "PackedInput", name: "packed_myFloatB_myFloatA", define: string.Empty, type: "float3", semantic: "INTERP2", interpolation: "nointerpolation"),
  452. new FieldDescriptor(tag: "PackedInput", name: "packed_myInterFloatB_myInterFloatA", define: string.Empty, type: "float3", semantic: "INTERP3", interpolation: string.Empty),
  453. new FieldDescriptor(tag: "Original", name: "instanceID", define: string.Empty, type: ShaderValueType.Uint, semantic: "CUSTOM_INSTANCE_ID", preprocessor: "UNITY_ANY_INSTANCING_ENABLED")
  454. }
  455. },
  456. expectedInterpolatorFunction = @"
  457. PackedInput PackInput (Input input)
  458. {
  459. PackedInput output;
  460. ZERO_INITIALIZE(PackedInput, output);
  461. output.position = input.position;
  462. output.myIntA = input.myIntA;
  463. output.myIntB = input.myIntB;
  464. output.packed_myFloatB_myFloatA.xy = input.myFloatB;
  465. output.packed_myFloatB_myFloatA.z = input.myFloatA;
  466. output.packed_myInterFloatB_myInterFloatA.xy = input.myInterFloatB;
  467. output.packed_myInterFloatB_myInterFloatA.z = input.myInterFloatA;
  468. #if UNITY_ANY_INSTANCING_ENABLED
  469. output.instanceID = input.instanceID;
  470. #endif
  471. return output;
  472. }
  473. Input UnpackInput (PackedInput input)
  474. {
  475. Input output;
  476. output.position = input.position;
  477. output.myIntA = input.myIntA;
  478. output.myIntB = input.myIntB;
  479. output.myFloatB = input.packed_myFloatB_myFloatA.xy;
  480. output.myFloatA = input.packed_myFloatB_myFloatA.z;
  481. output.myInterFloatB = input.packed_myInterFloatB_myInterFloatA.xy;
  482. output.myInterFloatA = input.packed_myInterFloatB_myInterFloatA.z;
  483. #if UNITY_ANY_INSTANCING_ENABLED
  484. output.instanceID = input.instanceID;
  485. #endif
  486. return output;
  487. }"
  488. }
  489. };
  490. [Test]
  491. public void GenerationUtils_GeneratePackedStruct([ValueSource(nameof(s_PackingTestCase))] PackingTestCase testCase)
  492. {
  493. var activeFields = new ActiveFields();
  494. foreach (var field in testCase.inputStruct.fields)
  495. activeFields.all.AddAll(field);
  496. GenerationUtils.GeneratePackedStruct(testCase.inputStruct, activeFields, out var packedStruct);
  497. var expected = testCase.expectedOutputStruct;
  498. Assert.AreEqual(expected.name, packedStruct.name);
  499. Assert.AreEqual(expected.packFields, packedStruct.packFields);
  500. Assert.AreEqual(expected.fields.Length, packedStruct.fields.Length);
  501. for (int i = 0; i < expected.fields.Length; i++)
  502. {
  503. var currentField = packedStruct.fields[i];
  504. var expectedField = expected.fields[i];
  505. Assert.AreEqual(expectedField.tag, currentField.tag);
  506. Assert.AreEqual(expectedField.name, currentField.name);
  507. Assert.AreEqual(expectedField.define, currentField.define);
  508. Assert.AreEqual(expectedField.interpolation, currentField.interpolation);
  509. Assert.AreEqual(expectedField.type, currentField.type);
  510. Assert.AreEqual(expectedField.vectorCount, currentField.vectorCount);
  511. Assert.AreEqual(expectedField.semantic, currentField.semantic);
  512. Assert.AreEqual(expectedField.preprocessor, currentField.preprocessor);
  513. Assert.AreEqual(expectedField.subscriptOptions, currentField.subscriptOptions);
  514. }
  515. }
  516. [Test]
  517. public void GenerationUtils_GenerateInterpolatorFunctions([ValueSource(nameof(s_PackingTestCase))] PackingTestCase packingTestCase)
  518. {
  519. var activeFields = new ActiveFields();
  520. foreach (var field in packingTestCase.inputStruct.fields)
  521. activeFields.all.AddAll(field);
  522. GenerationUtils.GenerateInterpolatorFunctions(packingTestCase.inputStruct, activeFields.baseInstance, true, out var shaderFunction);
  523. var result = shaderFunction.ToString();
  524. int length = Math.Max(packingTestCase.expectedInterpolatorFunction.Length, result.Length);
  525. var compare = String.Compare(packingTestCase.expectedInterpolatorFunction, 0, result, 0, length, CultureInfo.InvariantCulture, CompareOptions.IgnoreSymbols);
  526. Assert.AreEqual(0, compare, "Unexpected generated function:\n" + result);
  527. }
  528. [Test]
  529. public void GenerationUtils_ActivationFields()
  530. {
  531. var inputStruct = new StructDescriptor()
  532. {
  533. name = "Input",
  534. packFields = false,
  535. fields = new[]
  536. {
  537. //This test insure the order of input packing doesn't fail the following packing
  538. new FieldDescriptor(tag: "Original", name: "myFloat_Cond_0", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  539. new FieldDescriptor(tag: "Original", name: "myFloat_Cond_1", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  540. new FieldDescriptor(tag: "Original", name: "myFloat_Cond_2", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  541. new FieldDescriptor(tag: "Original", name: "myFloat_Cond_ALL", define: string.Empty, type: ShaderValueType.Float, semantic: string.Empty, interpolation: string.Empty),
  542. }
  543. };
  544. var activeFields = new ActiveFields();
  545. foreach (var field in inputStruct.fields)
  546. {
  547. var index = field.name.EndsWith("0") ? 0 : field.name.EndsWith("1") ? 1 : field.name.EndsWith("2") ? 2 : -1;
  548. if (index != -1)
  549. {
  550. activeFields[index].Add(field);
  551. }
  552. else
  553. {
  554. activeFields.all.AddAll(field);
  555. }
  556. }
  557. GenerationUtils.GenerateInterpolatorFunctions(inputStruct, activeFields.baseInstance, true, out var shaderFunctionBuilder);
  558. GenerationUtils.GeneratePackedStruct(inputStruct, activeFields, out var packedStruct);
  559. GenerationUtils.GenerateShaderStruct(packedStruct, activeFields, true, out var structDeclarationBuilder);
  560. var expectedShaderFunction = @"
  561. PackedInput PackInput (Input input)
  562. {
  563. PackedInput output;
  564. ZERO_INITIALIZE(PackedInput, output);
  565. output.packed_myFloat_Cond_0_myFloat_Cond_1_myFloat_Cond_2_myFloat_Cond_ALL.x = input.myFloat_Cond_0;
  566. output.packed_myFloat_Cond_0_myFloat_Cond_1_myFloat_Cond_2_myFloat_Cond_ALL.y = input.myFloat_Cond_1;
  567. output.packed_myFloat_Cond_0_myFloat_Cond_1_myFloat_Cond_2_myFloat_Cond_ALL.z = input.myFloat_Cond_2;
  568. output.packed_myFloat_Cond_0_myFloat_Cond_1_myFloat_Cond_2_myFloat_Cond_ALL.w = input.myFloat_Cond_ALL;
  569. return output;
  570. }
  571. Input UnpackInput (PackedInput input)
  572. {
  573. Input output;
  574. output.myFloat_Cond_0 = input.packed_myFloat_Cond_0_myFloat_Cond_1_myFloat_Cond_2_myFloat_Cond_ALL.x;
  575. output.myFloat_Cond_1 = input.packed_myFloat_Cond_0_myFloat_Cond_1_myFloat_Cond_2_myFloat_Cond_ALL.y;
  576. output.myFloat_Cond_2 = input.packed_myFloat_Cond_0_myFloat_Cond_1_myFloat_Cond_2_myFloat_Cond_ALL.z;
  577. output.myFloat_Cond_ALL = input.packed_myFloat_Cond_0_myFloat_Cond_1_myFloat_Cond_2_myFloat_Cond_ALL.w;
  578. return output;
  579. }";
  580. var expectedStructDeclaration = @"
  581. struct PackedInput
  582. {
  583. #if defined(KEYWORD_PERMUTATION_0) || defined(KEYWORD_PERMUTATION_1) || defined(KEYWORD_PERMUTATION_2)
  584. float4 packed_myFloat_Cond_0_myFloat_Cond_1_myFloat_Cond_2_myFloat_Cond_ALL : INTERP0;
  585. #endif
  586. };";
  587. {
  588. var shaderFunction = shaderFunctionBuilder.ToString();
  589. var length = Math.Max(expectedShaderFunction.Length, shaderFunction.Length);
  590. var compare = String.Compare(expectedShaderFunction, 0, shaderFunction, 0, length, CultureInfo.InvariantCulture, CompareOptions.IgnoreSymbols);
  591. Assert.AreEqual(0, compare, "Unexpected generated function:\n" + shaderFunction);
  592. }
  593. {
  594. var structDeclaration = structDeclarationBuilder.ToString();
  595. var length = Math.Max(expectedStructDeclaration.Length, structDeclaration.Length);
  596. var compare = String.Compare(expectedStructDeclaration, 0, expectedStructDeclaration, 0, length, CultureInfo.InvariantCulture, CompareOptions.IgnoreSymbols);
  597. Assert.AreEqual(0, compare, "Unexpected generated function:\n" + structDeclaration);
  598. }
  599. }
  600. }
  601. }