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

TargetTests.cs 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. using System.Linq;
  2. using System.IO;
  3. using NUnit.Framework;
  4. using UnityEngine;
  5. using UnityEditor.Graphing;
  6. namespace UnityEditor.ShaderGraph.UnitTests
  7. {
  8. [TestFixture]
  9. class TargetTests
  10. {
  11. [OneTimeSetUp]
  12. public void RunBeforeAnyTests()
  13. {
  14. Debug.unityLogger.logHandler = new ConsoleLogHandler();
  15. }
  16. [Test]
  17. public void CanCreateBlankGraph()
  18. {
  19. GraphData graph = new GraphData();
  20. graph.AddContexts();
  21. Assert.IsNotNull(graph.activeTargets);
  22. Assert.AreEqual(0, graph.activeTargets.Count());
  23. }
  24. public static bool s_ForceVFXFakeTargetVisible = false;
  25. #if !VFX_GRAPH_10_0_0_OR_NEWER
  26. //A barebone VFXTarget for testing coverage.
  27. sealed class VFXTarget : UnityEditor.ShaderGraph.Target
  28. {
  29. public VFXTarget()
  30. {
  31. displayName = "Fake VFX Target"; //Should not be displayed outside the test runner.
  32. isHidden = !s_ForceVFXFakeTargetVisible;
  33. }
  34. public override void GetActiveBlocks(ref UnityEditor.ShaderGraph.TargetActiveBlockContext context)
  35. {
  36. context.AddBlock(ShaderGraph.BlockFields.SurfaceDescription.BaseColor);
  37. context.AddBlock(ShaderGraph.BlockFields.SurfaceDescription.Alpha);
  38. }
  39. public override void GetFields(ref TargetFieldContext context)
  40. {
  41. }
  42. public override void Setup(ref TargetSetupContext context)
  43. {
  44. }
  45. public override bool IsActive() => false;
  46. public override bool WorksWithSRP(UnityEngine.Rendering.RenderPipelineAsset scriptableRenderPipeline)
  47. {
  48. return false;
  49. }
  50. public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, System.Action onChange, System.Action<System.String> registerUndo)
  51. {
  52. }
  53. }
  54. #endif
  55. [Test]
  56. public void CanInitializeOutputTargets()
  57. {
  58. s_ForceVFXFakeTargetVisible = true;
  59. GraphData graph = new GraphData();
  60. graph.AddContexts();
  61. graph.InitializeOutputs(new[] { new VFXTarget() }, null);
  62. Assert.IsNotNull(graph.activeTargets);
  63. Assert.AreEqual(1, graph.activeTargets.Count());
  64. Assert.AreEqual(typeof(VFXTarget), graph.activeTargets.ElementAt(0).GetType());
  65. s_ForceVFXFakeTargetVisible = false;
  66. }
  67. [Test]
  68. public void CanAddTarget()
  69. {
  70. s_ForceVFXFakeTargetVisible = true;
  71. GraphData graph = new GraphData();
  72. graph.AddContexts();
  73. var vfxTarget = graph.allPotentialTargets.FirstOrDefault(x => x is VFXTarget);
  74. graph.SetTargetActive(vfxTarget);
  75. Assert.IsNotNull(graph.activeTargets);
  76. Assert.AreEqual(1, graph.activeTargets.Count());
  77. Assert.AreEqual(vfxTarget, graph.activeTargets.ElementAt(0));
  78. s_ForceVFXFakeTargetVisible = false;
  79. }
  80. [Test]
  81. public void ActiveTargetsArePotentialTargets()
  82. {
  83. s_ForceVFXFakeTargetVisible = true;
  84. GraphData graph = new GraphData();
  85. graph.AddContexts();
  86. var vfxTarget = new VFXTarget();
  87. graph.SetTargetActive(vfxTarget);
  88. Assert.IsTrue(graph.allPotentialTargets.Contains(vfxTarget));
  89. s_ForceVFXFakeTargetVisible = false;
  90. }
  91. [Test]
  92. public void GetTargetIndexWorks()
  93. {
  94. s_ForceVFXFakeTargetVisible = true;
  95. GraphData graph = new GraphData();
  96. graph.AddContexts();
  97. int targetIndex = graph.GetTargetIndexByKnownType(typeof(VFXTarget));
  98. Assert.IsTrue(targetIndex >= 0);
  99. var vfxTarget = new VFXTarget();
  100. graph.SetTargetActive(vfxTarget);
  101. var targetIndex2 = graph.GetTargetIndex(vfxTarget);
  102. Assert.AreEqual(targetIndex, targetIndex2);
  103. var nonActiveVFXTarget = new VFXTarget();
  104. Assert.AreEqual(-1, graph.GetTargetIndex(nonActiveVFXTarget));
  105. s_ForceVFXFakeTargetVisible = false;
  106. }
  107. [Test]
  108. public void CanRemoveTarget()
  109. {
  110. s_ForceVFXFakeTargetVisible = true;
  111. GraphData graph = new GraphData();
  112. graph.AddContexts();
  113. var vfxTarget = new VFXTarget();
  114. graph.InitializeOutputs(new[] { vfxTarget }, null);
  115. graph.SetTargetInactive(vfxTarget);
  116. Assert.IsNotNull(graph.activeTargets);
  117. Assert.AreEqual(0, graph.activeTargets.Count());
  118. s_ForceVFXFakeTargetVisible = false;
  119. }
  120. [Test]
  121. public void CanSetBlockActive()
  122. {
  123. s_ForceVFXFakeTargetVisible = true;
  124. GraphData graph = new GraphData();
  125. graph.AddContexts();
  126. graph.InitializeOutputs(new[] { new VFXTarget() }, new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.BaseColor, BlockFields.SurfaceDescription.NormalTS });
  127. // Block active state should match VFX Target's default GetActiveBlocks
  128. var blocks = graph.GetNodes<BlockNode>().ToList();
  129. Assert.AreEqual(2, blocks.Count);
  130. Assert.AreEqual(BlockFields.SurfaceDescription.BaseColor, blocks[0].descriptor);
  131. Assert.AreEqual(true, blocks[0].isActive);
  132. Assert.AreEqual(BlockFields.SurfaceDescription.NormalTS, blocks[1].descriptor);
  133. Assert.AreEqual(false, blocks[1].isActive);
  134. s_ForceVFXFakeTargetVisible = false;
  135. }
  136. [Test]
  137. public void CanUpdateBlockActiveState()
  138. {
  139. s_ForceVFXFakeTargetVisible = true;
  140. GraphData graph = new GraphData();
  141. graph.AddContexts();
  142. graph.InitializeOutputs(new[] { new VFXTarget() }, new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.BaseColor, BlockFields.SurfaceDescription.NormalTS });
  143. // Remove VFX target
  144. var vfxTarget = graph.allPotentialTargets.FirstOrDefault(x => x is VFXTarget);
  145. graph.SetTargetInactive(vfxTarget);
  146. var activeBlocks = graph.GetActiveBlocksForAllActiveTargets();
  147. graph.UpdateActiveBlocks(activeBlocks);
  148. // All blocks should be inactive as there are no active targets
  149. var blocks = graph.GetNodes<BlockNode>().ToList();
  150. Assert.AreEqual(2, blocks.Count);
  151. Assert.AreEqual(BlockFields.SurfaceDescription.BaseColor, blocks[0].descriptor);
  152. Assert.AreEqual(false, blocks[0].isActive);
  153. Assert.AreEqual(BlockFields.SurfaceDescription.NormalTS, blocks[1].descriptor);
  154. Assert.AreEqual(false, blocks[1].isActive);
  155. s_ForceVFXFakeTargetVisible = false;
  156. }
  157. abstract class TestShaderTarget : UnityEditor.ShaderGraph.Target
  158. {
  159. public override void GetActiveBlocks(ref UnityEditor.ShaderGraph.TargetActiveBlockContext context)
  160. {
  161. context.AddBlock(ShaderGraph.BlockFields.SurfaceDescription.BaseColor);
  162. context.AddBlock(ShaderGraph.BlockFields.SurfaceDescription.Alpha);
  163. }
  164. public override void GetFields(ref TargetFieldContext context)
  165. {
  166. }
  167. public static PassDescriptor BuildPass()
  168. {
  169. PassDescriptor pass = new PassDescriptor()
  170. {
  171. // Definition
  172. displayName = "DepthOnly",
  173. referenceName = "SHADERPASS_DEPTHONLY",
  174. lightMode = "DepthOnly",
  175. useInPreview = true,
  176. // Template
  177. passTemplatePath = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/Editor/ShaderGraph/Templates/ShaderPass.template",
  178. sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(),
  179. // Port Mask
  180. validVertexBlocks = new BlockFieldDescriptor[] { BlockFields.VertexDescription.Position, BlockFields.VertexDescription.Normal, BlockFields.VertexDescription.Tangent },
  181. validPixelBlocks = new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.Alpha, BlockFields.SurfaceDescription.AlphaClipThreshold },
  182. // Fields
  183. structs = new StructCollection { { Structs.Attributes }, { Structs.SurfaceDescriptionInputs }, { Structs.VertexDescriptionInputs } },
  184. fieldDependencies = FieldDependencies.Default,
  185. // Conditional State
  186. renderStates = null,
  187. pragmas = new PragmaCollection { { Pragma.Target(ShaderModel.Target30) }, { Pragma.MultiCompileInstancing }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") } },
  188. defines = null,
  189. keywords = null,
  190. includes = null,
  191. customInterpolators = null,
  192. };
  193. return pass;
  194. }
  195. public static SubShaderDescriptor BuildSubShader()
  196. {
  197. SubShaderDescriptor result = new SubShaderDescriptor()
  198. {
  199. pipelineTag = "TestPipeline",
  200. renderType = "Opaque",
  201. renderQueue = "Geometry",
  202. generatesPreview = true,
  203. passes = new PassCollection()
  204. };
  205. result.passes.Add(BuildPass());
  206. return result;
  207. }
  208. public override bool IsActive() => true;
  209. public override bool WorksWithSRP(UnityEngine.Rendering.RenderPipelineAsset scriptableRenderPipeline) => true;
  210. public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, System.Action onChange, System.Action<System.String> registerUndo)
  211. {
  212. }
  213. }
  214. sealed class MultiShaderTarget : TestShaderTarget
  215. {
  216. public MultiShaderTarget()
  217. {
  218. displayName = "MultiShader Test Target";
  219. isHidden = false;
  220. }
  221. public override void Setup(ref TargetSetupContext context)
  222. {
  223. context.AddSubShader(BuildSubShader()); // primary shader
  224. var ss2 = BuildSubShader();
  225. ss2.additionalShaderID = "{Name}-second";
  226. context.AddSubShader(ss2);
  227. }
  228. }
  229. [Test]
  230. public void CanBuildMultipleShaders()
  231. {
  232. GraphData graph = new GraphData();
  233. graph.AddContexts();
  234. var multiTarget = new MultiShaderTarget();
  235. graph.SetTargetActive(multiTarget);
  236. Assert.IsTrue(graph.allPotentialTargets.Contains(multiTarget));
  237. graph.OnEnable();
  238. graph.ValidateGraph();
  239. var generator = new Generator(graph, graph.outputNode, GenerationMode.ForReals, "MyTestShader");
  240. var generatedShaders = generator.allGeneratedShaders.ToList();
  241. Assert.AreEqual(2, generatedShaders.Count);
  242. Assert.IsTrue(generatedShaders[0].shaderName == "MyTestShader");
  243. Assert.IsTrue(generatedShaders[1].shaderName == "MyTestShader-second");
  244. Assert.IsTrue(generatedShaders[0].codeString.Contains("Shader \"MyTestShader\""));
  245. Assert.IsTrue(generatedShaders[1].codeString.Contains("Shader \"MyTestShader-second\""));
  246. // save graph to file on disk and import it...
  247. var path = AssetDatabase.GenerateUniqueAssetPath("Assets/multiShaderTest.ShaderGraph");
  248. FileUtilities.WriteShaderGraphToDisk(path, graph);
  249. AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate | ImportAssetOptions.DontDownloadFromCacheServer);
  250. // check that we actually have two shader assets in the import result
  251. // (they won't work, but they should exist)
  252. var assets = AssetDatabase.LoadAllAssetsAtPath(path);
  253. int shaderCount = assets.OfType<Shader>().Count();
  254. Assert.AreEqual(2, shaderCount);
  255. AssetDatabase.DeleteAsset(path);
  256. }
  257. sealed class DependencyShaderNameTarget : TestShaderTarget
  258. {
  259. public DependencyShaderNameTarget()
  260. {
  261. displayName = "DependencyShaderName Test Target";
  262. isHidden = false;
  263. }
  264. public override void Setup(ref TargetSetupContext context)
  265. {
  266. var ss = BuildSubShader();
  267. ss.shaderDependencies = new()
  268. {
  269. new ShaderDependency() { dependencyName = "TestDep1", shaderName = "Name-blah" },
  270. new ShaderDependency() { dependencyName = "TestDep2", shaderName = "{Name}-blah" }
  271. };
  272. context.AddSubShader(ss);
  273. }
  274. }
  275. [Test]
  276. public void ShaderNamesAreCorrectReplacedForDependencies()
  277. {
  278. GraphData graph = new GraphData();
  279. graph.AddContexts();
  280. var testTarget = new DependencyShaderNameTarget();
  281. graph.SetTargetActive(testTarget);
  282. graph.OnEnable();
  283. graph.ValidateGraph();
  284. var generator = new Generator(graph, graph.outputNode, GenerationMode.ForReals, "MyTestShader");
  285. var shaderCodeString = generator.generatedShader;
  286. Assert.IsTrue(shaderCodeString.Contains("Dependency \"TestDep1\" = \"Name-blah\""));
  287. Assert.IsTrue(shaderCodeString.Contains("Dependency \"TestDep2\" = \"MyTestShader-blah\""));
  288. }
  289. }
  290. }