VFXGraphCompiledData.cs 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302
  1. using System;
  2. using System.Text;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using UnityEditor.VFX;
  6. using UnityEngine;
  7. using UnityEngine.VFX;
  8. using UnityEngine.Profiling;
  9. using UnityEngine.Rendering;
  10. using Object = UnityEngine.Object;
  11. using System.IO;
  12. using System.Collections.ObjectModel;
  13. namespace UnityEditor.VFX
  14. {
  15. struct VFXContextCompiledData
  16. {
  17. public VFXExpressionMapper cpuMapper;
  18. public VFXExpressionMapper gpuMapper;
  19. public VFXUniformMapper uniformMapper;
  20. public ReadOnlyDictionary<VFXExpression, Type> graphicsBufferUsage;
  21. public VFXMapping[] parameters;
  22. public int indexInShaderSource;
  23. }
  24. enum VFXCompilationMode
  25. {
  26. Edition,
  27. Runtime,
  28. }
  29. class VFXDependentBuffersData
  30. {
  31. public Dictionary<VFXData, int> attributeBuffers = new Dictionary<VFXData, int>();
  32. public Dictionary<VFXData, int> stripBuffers = new Dictionary<VFXData, int>();
  33. public Dictionary<VFXData, int> eventBuffers = new Dictionary<VFXData, int>();
  34. public Dictionary<VFXData, int> boundsBuffers = new Dictionary<VFXData, int>();
  35. }
  36. class VFXGraphCompiledData
  37. {
  38. // 3: Serialize material
  39. // 4: Bounds helper change
  40. public const uint compiledVersion = 4;
  41. public VFXGraphCompiledData(VFXGraph graph)
  42. {
  43. if (graph == null)
  44. throw new ArgumentNullException("VFXGraph cannot be null");
  45. m_Graph = graph;
  46. }
  47. private struct GeneratedCodeData
  48. {
  49. public VFXContext context;
  50. public bool computeShader;
  51. public System.Text.StringBuilder content;
  52. public VFXCompilationMode compilMode;
  53. }
  54. private static VFXExpressionObjectValueContainerDesc<T> CreateObjectValueDesc<T>(VFXExpression exp, int expIndex)
  55. {
  56. var desc = new VFXExpressionObjectValueContainerDesc<T>();
  57. desc.instanceID = exp.Get<int>();
  58. return desc;
  59. }
  60. private static VFXExpressionValueContainerDesc<T> CreateValueDesc<T>(VFXExpression exp, int expIndex)
  61. {
  62. var desc = new VFXExpressionValueContainerDesc<T>();
  63. desc.value = exp.Get<T>();
  64. return desc;
  65. }
  66. private void SetValueDesc<T>(VFXExpressionValueContainerDesc desc, VFXExpression exp)
  67. {
  68. ((VFXExpressionValueContainerDesc<T>)desc).value = exp.Get<T>();
  69. }
  70. private void SetObjectValueDesc<T>(VFXExpressionValueContainerDesc desc, VFXExpression exp)
  71. {
  72. ((VFXExpressionObjectValueContainerDesc<T>)desc).instanceID = exp.Get<int>();
  73. }
  74. public uint FindReducedExpressionIndexFromSlotCPU(VFXSlot slot)
  75. {
  76. if (m_ExpressionGraph == null)
  77. {
  78. return uint.MaxValue;
  79. }
  80. var targetExpression = slot.GetExpression();
  81. if (targetExpression == null)
  82. {
  83. return uint.MaxValue;
  84. }
  85. if (!m_ExpressionGraph.CPUExpressionsToReduced.ContainsKey(targetExpression))
  86. {
  87. return uint.MaxValue;
  88. }
  89. var ouputExpression = m_ExpressionGraph.CPUExpressionsToReduced[targetExpression];
  90. return (uint)m_ExpressionGraph.GetFlattenedIndex(ouputExpression);
  91. }
  92. private static void FillExpressionDescs(VFXExpressionGraph graph, List<VFXExpressionDesc> outExpressionCommonDescs, List<VFXExpressionDesc> outExpressionPerSpawnEventDescs, List<VFXExpressionValueContainerDesc> outValueDescs)
  93. {
  94. var flatGraph = graph.FlattenedExpressions;
  95. var numFlattenedExpressions = flatGraph.Count;
  96. var maxCommonExpressionIndex = (uint)numFlattenedExpressions;
  97. for (int i = 0; i < numFlattenedExpressions; ++i)
  98. {
  99. var exp = flatGraph[i];
  100. if (exp.Is(VFXExpression.Flags.PerSpawn) && maxCommonExpressionIndex == numFlattenedExpressions)
  101. maxCommonExpressionIndex = (uint)i;
  102. if (!exp.Is(VFXExpression.Flags.PerSpawn) && maxCommonExpressionIndex != numFlattenedExpressions)
  103. throw new InvalidOperationException("Not contiguous expression VFXExpression.Flags.PerSpawn detected");
  104. // Must match data in C++ expression
  105. if (exp.Is(VFXExpression.Flags.Value))
  106. {
  107. VFXExpressionValueContainerDesc value;
  108. switch (exp.valueType)
  109. {
  110. case VFXValueType.Float: value = CreateValueDesc<float>(exp, i); break;
  111. case VFXValueType.Float2: value = CreateValueDesc<Vector2>(exp, i); break;
  112. case VFXValueType.Float3: value = CreateValueDesc<Vector3>(exp, i); break;
  113. case VFXValueType.Float4: value = CreateValueDesc<Vector4>(exp, i); break;
  114. case VFXValueType.Int32: value = CreateValueDesc<int>(exp, i); break;
  115. case VFXValueType.Uint32: value = CreateValueDesc<uint>(exp, i); break;
  116. case VFXValueType.Texture2D:
  117. case VFXValueType.Texture2DArray:
  118. case VFXValueType.Texture3D:
  119. case VFXValueType.TextureCube:
  120. case VFXValueType.TextureCubeArray:
  121. value = CreateObjectValueDesc<Texture>(exp, i);
  122. break;
  123. case VFXValueType.CameraBuffer: value = CreateObjectValueDesc<Texture>(exp, i); break;
  124. case VFXValueType.Matrix4x4: value = CreateValueDesc<Matrix4x4>(exp, i); break;
  125. case VFXValueType.Curve: value = CreateValueDesc<AnimationCurve>(exp, i); break;
  126. case VFXValueType.ColorGradient: value = CreateValueDesc<Gradient>(exp, i); break;
  127. case VFXValueType.Mesh: value = CreateObjectValueDesc<Mesh>(exp, i); break;
  128. case VFXValueType.SkinnedMeshRenderer: value = CreateObjectValueDesc<SkinnedMeshRenderer>(exp, i); break;
  129. case VFXValueType.Boolean: value = CreateValueDesc<bool>(exp, i); break;
  130. case VFXValueType.Buffer: value = CreateValueDesc<GraphicsBuffer>(exp, i); break;
  131. default: throw new InvalidOperationException("Invalid type : " + exp.valueType);
  132. }
  133. value.expressionIndex = (uint)i;
  134. outValueDescs.Add(value);
  135. }
  136. var outExpressionsDesc = i >= maxCommonExpressionIndex ? outExpressionPerSpawnEventDescs : outExpressionCommonDescs;
  137. outExpressionsDesc.Add(new VFXExpressionDesc
  138. {
  139. op = exp.operation,
  140. data = exp.GetOperands(graph).ToArray(),
  141. });
  142. }
  143. }
  144. private static void CollectExposedDesc(List<VFXMapping> outExposedParameters, string name, VFXSlot slot, VFXExpressionGraph graph)
  145. {
  146. var expression = slot.valueType != VFXValueType.None ? slot.GetInExpression() : null;
  147. if (expression != null)
  148. {
  149. var exprIndex = graph.GetFlattenedIndex(expression);
  150. if (exprIndex == -1)
  151. throw new InvalidOperationException("Unable to retrieve value from exposed for " + name);
  152. outExposedParameters.Add(new VFXMapping()
  153. {
  154. name = name,
  155. index = exprIndex
  156. });
  157. }
  158. else
  159. {
  160. foreach (var child in slot.children)
  161. {
  162. CollectExposedDesc(outExposedParameters, name + "_" + child.name, child, graph);
  163. }
  164. }
  165. }
  166. private static void FillExposedDescs(List<VFXMapping> outExposedParameters, VFXExpressionGraph graph, IEnumerable<VFXParameter> parameters)
  167. {
  168. foreach (var parameter in parameters)
  169. {
  170. if (parameter.exposed && !parameter.isOutput)
  171. {
  172. CollectExposedDesc(outExposedParameters, parameter.exposedName, parameter.GetOutputSlot(0), graph);
  173. }
  174. }
  175. }
  176. class VFXSpawnContextLayer
  177. {
  178. public VFXContext context;
  179. public int depth;
  180. }
  181. private static List<VFXSpawnContextLayer> CollectContextParentRecursively(IEnumerable<VFXContext> inputList, ref SubgraphInfos subgraphContexts, int currentDepth = 0)
  182. {
  183. var contextEffectiveInputLinks = subgraphContexts.contextEffectiveInputLinks;
  184. var contextList = inputList.SelectMany(o => contextEffectiveInputLinks[o].SelectMany(t => t))
  185. .Select(t => t.context).Distinct()
  186. .Select(c => new VFXSpawnContextLayer()
  187. {
  188. context = c,
  189. depth = currentDepth
  190. }).ToList();
  191. if (contextList.Any(o => contextEffectiveInputLinks[o.context].Any()))
  192. {
  193. var parentContextList = CollectContextParentRecursively(contextList.Select(c => c.context), ref subgraphContexts, currentDepth + 1);
  194. foreach (var parentContextEntry in parentContextList)
  195. {
  196. var currentEntry = contextList.FirstOrDefault(o => o.context == parentContextEntry.context);
  197. if (currentEntry == null)
  198. {
  199. contextList.Add(parentContextEntry);
  200. }
  201. else if (parentContextEntry.depth > currentEntry.depth)
  202. {
  203. currentEntry.depth = parentContextEntry.depth;
  204. }
  205. }
  206. }
  207. return contextList;
  208. }
  209. private static VFXContext[] CollectSpawnersHierarchy(IEnumerable<VFXContext> vfxContext, ref SubgraphInfos subgraphContexts)
  210. {
  211. var initContext = vfxContext.Where(o => o.contextType == VFXContextType.Init || o.contextType == VFXContextType.OutputEvent).ToList();
  212. var spawnerHierarchy = CollectContextParentRecursively(initContext, ref subgraphContexts);
  213. var spawnerList = spawnerHierarchy.Where(o => o.context.contextType == VFXContextType.Spawner)
  214. .OrderByDescending(o => o.depth)
  215. .Select(o => o.context).ToArray();
  216. return spawnerList;
  217. }
  218. struct SpawnInfo
  219. {
  220. public int bufferIndex;
  221. public int systemIndex;
  222. }
  223. private static VFXCPUBufferData ComputeArrayOfStructureInitialData(IEnumerable<VFXLayoutElementDesc> layout)
  224. {
  225. var data = new VFXCPUBufferData();
  226. foreach (var element in layout)
  227. {
  228. var attribute = VFXAttribute.AllAttribute.FirstOrDefault(o => o.name == element.name);
  229. bool useAttribute = attribute.name == element.name;
  230. if (element.type == VFXValueType.Boolean)
  231. {
  232. var v = useAttribute ? attribute.value.Get<bool>() : default(bool);
  233. data.PushBool(v);
  234. }
  235. else if (element.type == VFXValueType.Float)
  236. {
  237. var v = useAttribute ? attribute.value.Get<float>() : default(float);
  238. data.PushFloat(v);
  239. }
  240. else if (element.type == VFXValueType.Float2)
  241. {
  242. var v = useAttribute ? attribute.value.Get<Vector2>() : default(Vector2);
  243. data.PushFloat(v.x);
  244. data.PushFloat(v.y);
  245. }
  246. else if (element.type == VFXValueType.Float3)
  247. {
  248. var v = useAttribute ? attribute.value.Get<Vector3>() : default(Vector3);
  249. data.PushFloat(v.x);
  250. data.PushFloat(v.y);
  251. data.PushFloat(v.z);
  252. }
  253. else if (element.type == VFXValueType.Float4)
  254. {
  255. var v = useAttribute ? attribute.value.Get<Vector4>() : default(Vector4);
  256. data.PushFloat(v.x);
  257. data.PushFloat(v.y);
  258. data.PushFloat(v.z);
  259. data.PushFloat(v.w);
  260. }
  261. else if (element.type == VFXValueType.Int32)
  262. {
  263. var v = useAttribute ? attribute.value.Get<int>() : default(int);
  264. data.PushInt(v);
  265. }
  266. else if (element.type == VFXValueType.Uint32)
  267. {
  268. var v = useAttribute ? attribute.value.Get<uint>() : default(uint);
  269. data.PushUInt(v);
  270. }
  271. else
  272. {
  273. throw new NotImplementedException();
  274. }
  275. }
  276. return data;
  277. }
  278. void RecursePutSubgraphParent(Dictionary<VFXSubgraphContext, VFXSubgraphContext> parents, List<VFXSubgraphContext> subgraphs, VFXSubgraphContext subgraph)
  279. {
  280. foreach (var subSubgraph in subgraph.subChildren.OfType<VFXSubgraphContext>().Where(t => t.subgraph != null))
  281. {
  282. subgraphs.Add(subSubgraph);
  283. parents[subSubgraph] = subgraph;
  284. RecursePutSubgraphParent(parents, subgraphs, subSubgraph);
  285. }
  286. }
  287. static List<VFXContextLink>[] ComputeContextEffectiveLinks(VFXContext context, ref SubgraphInfos subgraphInfos)
  288. {
  289. List<VFXContextLink>[] result = new List<VFXContextLink>[context.inputFlowSlot.Length];
  290. Dictionary<string, int> eventNameIndice = new Dictionary<string, int>();
  291. for (int i = 0; i < context.inputFlowSlot.Length; ++i)
  292. {
  293. result[i] = new List<VFXContextLink>();
  294. VFXSubgraphContext parentSubgraph = null;
  295. subgraphInfos.spawnerSubgraph.TryGetValue(context, out parentSubgraph);
  296. List<VFXContext> subgraphAncestors = new List<VFXContext>();
  297. subgraphAncestors.Add(context);
  298. while (parentSubgraph != null)
  299. {
  300. subgraphAncestors.Add(parentSubgraph);
  301. if (!subgraphInfos.subgraphParents.TryGetValue(parentSubgraph, out parentSubgraph))
  302. {
  303. parentSubgraph = null;
  304. }
  305. }
  306. List<List<int>> defaultEventPaths = new List<List<int>>();
  307. defaultEventPaths.Add(new List<int>(new int[] { i }));
  308. List<List<int>> newEventPaths = new List<List<int>>();
  309. var usedContexts = new List<VFXContext>();
  310. for (int j = 0; j < subgraphAncestors.Count; ++j)
  311. {
  312. var sg = subgraphAncestors[j];
  313. var nextSg = j < subgraphAncestors.Count - 1 ? subgraphAncestors[j + 1] as VFXSubgraphContext : null;
  314. foreach (var path in defaultEventPaths)
  315. {
  316. int currentFlowIndex = path.Last();
  317. var eventSlot = sg.inputFlowSlot[currentFlowIndex];
  318. var eventSlotSpawners = eventSlot.link.Where(t => !(t.context is VFXBasicEvent));
  319. if (eventSlotSpawners.Any())
  320. {
  321. foreach (var evt in eventSlotSpawners)
  322. {
  323. result[i].Add(evt);
  324. }
  325. }
  326. var eventSlotEvents = eventSlot.link.Where(t => t.context is VFXBasicEvent);
  327. if (eventSlotEvents.Any())
  328. {
  329. foreach (var evt in eventSlotEvents)
  330. {
  331. string eventName = (evt.context as VFXBasicEvent).eventName;
  332. switch (eventName)
  333. {
  334. case VisualEffectAsset.PlayEventName:
  335. if (nextSg != null)
  336. newEventPaths.Add(path.Concat(new int[] { 0 }).ToList());
  337. else
  338. result[i].Add(evt);
  339. break;
  340. case VisualEffectAsset.StopEventName:
  341. if (nextSg != null)
  342. newEventPaths.Add(path.Concat(new int[] { 1 }).ToList());
  343. else
  344. result[i].Add(evt);
  345. break;
  346. default:
  347. {
  348. if (nextSg != null)
  349. {
  350. int eventIndex = nextSg.GetInputFlowIndex(eventName);
  351. if (eventIndex != -1)
  352. newEventPaths.Add(path.Concat(new int[] { eventIndex }).ToList());
  353. }
  354. else
  355. {
  356. result[i].Add(evt);
  357. }
  358. }
  359. break;
  360. }
  361. }
  362. }
  363. else if (!eventSlot.link.Any())
  364. {
  365. if (!(sg is VFXSubgraphContext))
  366. {
  367. if (nextSg != null)
  368. {
  369. int fixedSlotIndex = currentFlowIndex > 1 ? currentFlowIndex : nextSg.GetInputFlowIndex(currentFlowIndex == 1 ? VisualEffectAsset.StopEventName : VisualEffectAsset.PlayEventName);
  370. if (fixedSlotIndex >= 0)
  371. newEventPaths.Add(path.Concat(new int[] { fixedSlotIndex }).ToList());
  372. }
  373. else
  374. newEventPaths.Add(path.Concat(new int[] { currentFlowIndex }).ToList());
  375. }
  376. else
  377. {
  378. var sgsg = sg as VFXSubgraphContext;
  379. var eventName = sgsg.GetInputFlowName(currentFlowIndex);
  380. var eventCtx = sgsg.GetEventContext(eventName);
  381. if (eventCtx != null)
  382. result[i].Add(new VFXContextLink() { slotIndex = 0, context = eventCtx });
  383. }
  384. }
  385. }
  386. defaultEventPaths.Clear();
  387. defaultEventPaths.AddRange(newEventPaths);
  388. newEventPaths.Clear();
  389. }
  390. }
  391. return result;
  392. }
  393. private static void CollectParentExpressionRecursively(VFXExpression entry, HashSet<VFXExpression> processed)
  394. {
  395. if (processed.Contains(entry))
  396. return;
  397. foreach (var parent in entry.parents)
  398. CollectParentExpressionRecursively(parent, processed);
  399. processed.Add(entry);
  400. }
  401. private class ProcessChunk
  402. {
  403. public int startIndex;
  404. public int endIndex;
  405. }
  406. static VFXMapping[] ComputePreProcessExpressionForSpawn(IEnumerable<VFXExpression> expressionPerSpawnToProcess, VFXExpressionGraph graph)
  407. {
  408. var allExpressions = new HashSet<VFXExpression>();
  409. foreach (var expression in expressionPerSpawnToProcess)
  410. CollectParentExpressionRecursively(expression, allExpressions);
  411. var expressionIndexes = allExpressions.
  412. Where(o => o.Is(VFXExpression.Flags.PerSpawn)) //Filter only per spawn part of graph
  413. .Select(o => graph.GetFlattenedIndex(o))
  414. .OrderBy(i => i);
  415. //Additional verification of appropriate expected expression index
  416. //In flatten expression, all common expressions are sorted first, then, we have chunk of additional preprocess
  417. //We aren't supposed to happen a chunk which is running common expression here.
  418. if (expressionIndexes.Any(i => i < graph.CommonExpressionCount))
  419. {
  420. var expressionInCommon = allExpressions
  421. .Where(o => graph.GetFlattenedIndex(o) < graph.CommonExpressionCount)
  422. .OrderBy(o => graph.GetFlattenedIndex(o));
  423. Debug.LogErrorFormat("Unexpected preprocess expression detected : {0} (count)", expressionInCommon.Count());
  424. }
  425. var processChunk = new List<ProcessChunk>();
  426. int previousIndex = int.MinValue;
  427. foreach (var indice in expressionIndexes)
  428. {
  429. if (indice != previousIndex + 1)
  430. processChunk.Add(new ProcessChunk()
  431. {
  432. startIndex = indice,
  433. endIndex = indice + 1
  434. });
  435. else
  436. processChunk.Last().endIndex = indice + 1;
  437. previousIndex = indice;
  438. }
  439. return processChunk.SelectMany((o, i) =>
  440. {
  441. var prefix = VFXCodeGeneratorHelper.GeneratePrefix((uint)i);
  442. return new[]
  443. {
  444. new VFXMapping
  445. {
  446. name = "start_" + prefix,
  447. index = o.startIndex
  448. },
  449. new VFXMapping
  450. {
  451. name = "end_" + prefix,
  452. index = o.endIndex
  453. }
  454. };
  455. }).ToArray();
  456. }
  457. private static VFXEditorTaskDesc[] BuildEditorTaksDescFromBlockSpawner(IEnumerable<VFXBlock> blocks, VFXContextCompiledData contextData, VFXExpressionGraph graph)
  458. {
  459. var taskDescList = new List<VFXEditorTaskDesc>();
  460. int index = 0;
  461. foreach (var b in blocks)
  462. {
  463. var spawnerBlock = b as VFXAbstractSpawner;
  464. if (spawnerBlock == null)
  465. {
  466. throw new InvalidCastException("Unexpected block type in spawnerContext");
  467. }
  468. if (spawnerBlock.spawnerType == VFXTaskType.CustomCallbackSpawner && spawnerBlock.customBehavior == null)
  469. {
  470. throw new InvalidOperationException("VFXAbstractSpawner excepts a custom behavior for custom callback type");
  471. }
  472. if (spawnerBlock.spawnerType != VFXTaskType.CustomCallbackSpawner && spawnerBlock.customBehavior != null)
  473. {
  474. throw new InvalidOperationException("VFXAbstractSpawner only expects a custom behavior for custom callback type");
  475. }
  476. var mappingList = new List<VFXMapping>();
  477. var expressionPerSpawnToProcess = new List<VFXExpression>();
  478. foreach (var namedExpression in contextData.cpuMapper.CollectExpression(index, false))
  479. {
  480. mappingList.Add(new VFXMapping()
  481. {
  482. index = graph.GetFlattenedIndex(namedExpression.exp),
  483. name = namedExpression.name
  484. });
  485. if (namedExpression.exp.Is(VFXExpression.Flags.PerSpawn))
  486. expressionPerSpawnToProcess.Add(namedExpression.exp);
  487. }
  488. if (expressionPerSpawnToProcess.Any())
  489. {
  490. var mappingPreProcess = ComputePreProcessExpressionForSpawn(expressionPerSpawnToProcess, graph);
  491. var preProcessTask = new VFXEditorTaskDesc
  492. {
  493. type = UnityEngine.VFX.VFXTaskType.EvaluateExpressionsSpawner,
  494. buffers = new VFXMapping[0],
  495. values = mappingPreProcess,
  496. parameters = contextData.parameters,
  497. externalProcessor = null
  498. };
  499. taskDescList.Add(preProcessTask);
  500. }
  501. Object processor = null;
  502. if (spawnerBlock.customBehavior != null)
  503. processor = spawnerBlock.customBehavior;
  504. taskDescList.Add(new VFXEditorTaskDesc
  505. {
  506. type = (UnityEngine.VFX.VFXTaskType)spawnerBlock.spawnerType,
  507. buffers = new VFXMapping[0],
  508. values = mappingList.ToArray(),
  509. parameters = contextData.parameters,
  510. externalProcessor = processor
  511. });
  512. index++;
  513. }
  514. return taskDescList.ToArray();
  515. }
  516. private static void FillSpawner(Dictionary<VFXContext, SpawnInfo> outContextSpawnToSpawnInfo,
  517. Dictionary<VFXContext, uint> outDataToSystemIndex,
  518. List<VFXCPUBufferDesc> outCpuBufferDescs,
  519. List<VFXEditorSystemDesc> outSystemDescs,
  520. IEnumerable<VFXContext> contexts,
  521. VFXExpressionGraph graph,
  522. Dictionary<VFXContext, VFXContextCompiledData> contextToCompiledData,
  523. ref SubgraphInfos subgraphInfos,
  524. VFXSystemNames systemNames = null)
  525. {
  526. var spawners = CollectSpawnersHierarchy(contexts, ref subgraphInfos);
  527. foreach (var it in spawners.Select((spawner, index) => new { spawner, index }))
  528. {
  529. outContextSpawnToSpawnInfo.Add(it.spawner, new SpawnInfo() { bufferIndex = outCpuBufferDescs.Count, systemIndex = it.index });
  530. outCpuBufferDescs.Add(new VFXCPUBufferDesc()
  531. {
  532. capacity = 1u,
  533. stride = graph.GlobalEventAttributes.First().offset.structure,
  534. layout = graph.GlobalEventAttributes.ToArray(),
  535. initialData = ComputeArrayOfStructureInitialData(graph.GlobalEventAttributes)
  536. });
  537. }
  538. foreach (var spawnContext in spawners)
  539. {
  540. var buffers = new List<VFXMapping>();
  541. buffers.Add(new VFXMapping()
  542. {
  543. index = outContextSpawnToSpawnInfo[spawnContext].bufferIndex,
  544. name = "spawner_output"
  545. });
  546. for (int indexSlot = 0; indexSlot < 2 && indexSlot < spawnContext.inputFlowSlot.Length; ++indexSlot)
  547. {
  548. foreach (var input in subgraphInfos.contextEffectiveInputLinks[spawnContext][indexSlot])
  549. {
  550. var inputContext = input.context;
  551. if (outContextSpawnToSpawnInfo.ContainsKey(inputContext))
  552. {
  553. buffers.Add(new VFXMapping()
  554. {
  555. index = outContextSpawnToSpawnInfo[inputContext].bufferIndex,
  556. name = "spawner_input_" + (indexSlot == 0 ? "OnPlay" : "OnStop")
  557. });
  558. }
  559. }
  560. }
  561. var contextData = contextToCompiledData[spawnContext];
  562. var contextExpressions = contextData.cpuMapper.CollectExpression(-1);
  563. var systemValueMappings = new List<VFXMapping>();
  564. var expressionPerSpawnToProcess = new List<VFXExpression>();
  565. foreach (var contextExpression in contextExpressions)
  566. {
  567. var expressionIndex = graph.GetFlattenedIndex(contextExpression.exp);
  568. systemValueMappings.Add(new VFXMapping(contextExpression.name, expressionIndex));
  569. if (contextExpression.exp.Is(VFXExpression.Flags.PerSpawn))
  570. {
  571. expressionPerSpawnToProcess.Add(contextExpression.exp);
  572. }
  573. }
  574. if (expressionPerSpawnToProcess.Any())
  575. {
  576. var addiionnalValues = ComputePreProcessExpressionForSpawn(expressionPerSpawnToProcess, graph);
  577. systemValueMappings.AddRange(addiionnalValues);
  578. }
  579. string nativeName = string.Empty;
  580. if (systemNames != null)
  581. nativeName = systemNames.GetUniqueSystemName(spawnContext);
  582. else
  583. throw new InvalidOperationException("system names manager cannot be null");
  584. outDataToSystemIndex.Add(spawnContext, (uint)outSystemDescs.Count);
  585. contextToCompiledData[spawnContext] = contextData;
  586. outSystemDescs.Add(new VFXEditorSystemDesc()
  587. {
  588. values = systemValueMappings.ToArray(),
  589. buffers = buffers.ToArray(),
  590. capacity = 0u,
  591. name = nativeName,
  592. flags = VFXSystemFlag.SystemDefault,
  593. layer = uint.MaxValue,
  594. tasks = BuildEditorTaksDescFromBlockSpawner(spawnContext.activeFlattenedChildrenWithImplicit, contextData, graph)
  595. });
  596. }
  597. }
  598. struct SubgraphInfos
  599. {
  600. public Dictionary<VFXSubgraphContext, VFXSubgraphContext> subgraphParents;
  601. public Dictionary<VFXContext, VFXSubgraphContext> spawnerSubgraph;
  602. public List<VFXSubgraphContext> subgraphs;
  603. public Dictionary<VFXContext, List<VFXContextLink>[]> contextEffectiveInputLinks;
  604. public List<VFXContextLink> GetContextEffectiveOutputLinks(VFXContext context, int slot)
  605. {
  606. List<VFXContextLink> effectiveOuts = new List<VFXContextLink>();
  607. foreach (var kv in contextEffectiveInputLinks)
  608. {
  609. for (int i = 0; i < kv.Value.Length; ++i)
  610. {
  611. foreach (var link in kv.Value[i])
  612. {
  613. if (link.context == context && link.slotIndex == slot)
  614. effectiveOuts.Add(new VFXContextLink() { context = kv.Key, slotIndex = i });
  615. }
  616. }
  617. }
  618. return effectiveOuts;
  619. }
  620. }
  621. private static void FillEvent(List<EventDesc> outEventDesc, Dictionary<VFXContext, SpawnInfo> contextSpawnToSpawnInfo, IEnumerable<VFXContext> contexts, IEnumerable<VFXData> compilableData, ref SubgraphInfos subgraphInfos)
  622. {
  623. var contextEffectiveInputLinks = subgraphInfos.contextEffectiveInputLinks;
  624. var allPlayNotLinked = contextSpawnToSpawnInfo.Where(o => !contextEffectiveInputLinks[o.Key][0].Any()).Select(o => o.Key).ToList();
  625. var allStopNotLinked = contextSpawnToSpawnInfo.Where(o => !contextEffectiveInputLinks[o.Key][1].Any()).Select(o => o.Key).ToList();
  626. var eventDescTemp = new EventDesc[]
  627. {
  628. new EventDesc() { name = VisualEffectAsset.PlayEventName, startSystems = allPlayNotLinked, stopSystems = new List<VFXContext>(), initSystems = new List<VFXContext>() },
  629. new EventDesc() { name = VisualEffectAsset.StopEventName, startSystems = new List<VFXContext>(), stopSystems = allStopNotLinked, initSystems = new List<VFXContext>() },
  630. }.ToList();
  631. var specialNames = new HashSet<string>(new string[] { VisualEffectAsset.PlayEventName, VisualEffectAsset.StopEventName });
  632. var events = contexts.Where(o => o.contextType == VFXContextType.Event);
  633. foreach (var evt in events)
  634. {
  635. var eventName = (evt as VFXBasicEvent).eventName;
  636. if (subgraphInfos.spawnerSubgraph.ContainsKey(evt) && specialNames.Contains(eventName))
  637. continue;
  638. List<VFXContextLink> effectiveOuts = subgraphInfos.GetContextEffectiveOutputLinks(evt, 0);
  639. foreach (var link in effectiveOuts)
  640. {
  641. var eventIndex = eventDescTemp.FindIndex(o => o.name == eventName);
  642. if (eventIndex == -1)
  643. {
  644. eventIndex = eventDescTemp.Count;
  645. eventDescTemp.Add(new EventDesc
  646. {
  647. name = eventName,
  648. startSystems = new List<VFXContext>(),
  649. stopSystems = new List<VFXContext>(),
  650. initSystems = new List<VFXContext>()
  651. });
  652. }
  653. var eventDesc = eventDescTemp[eventIndex];
  654. if (link.context.contextType == VFXContextType.Spawner)
  655. {
  656. if (contextSpawnToSpawnInfo.ContainsKey(link.context))
  657. {
  658. var startSystem = link.slotIndex == 0;
  659. if (startSystem)
  660. {
  661. eventDesc.startSystems.Add(link.context);
  662. }
  663. else
  664. {
  665. eventDesc.stopSystems.Add(link.context);
  666. }
  667. }
  668. }
  669. else if (link.context.contextType == VFXContextType.Init)
  670. {
  671. eventDesc.initSystems.Add(link.context);
  672. }
  673. else
  674. {
  675. throw new InvalidOperationException(string.Format("Unexpected link context : " + link.context.contextType));
  676. }
  677. }
  678. }
  679. outEventDesc.AddRange(eventDescTemp);
  680. }
  681. private void GenerateShaders(List<GeneratedCodeData> outGeneratedCodeData, VFXExpressionGraph graph, IEnumerable<VFXContext> contexts, Dictionary<VFXContext, VFXContextCompiledData> contextToCompiledData, VFXCompilationMode compilationMode, HashSet<string> dependencies)
  682. {
  683. Profiler.BeginSample("VFXEditor.GenerateShaders");
  684. try
  685. {
  686. foreach (var context in contexts)
  687. {
  688. var gpuMapper = graph.BuildGPUMapper(context);
  689. var uniformMapper = new VFXUniformMapper(gpuMapper, context.doesGenerateShader);
  690. // Add gpu and uniform mapper
  691. var contextData = contextToCompiledData[context];
  692. contextData.gpuMapper = gpuMapper;
  693. contextData.uniformMapper = uniformMapper;
  694. contextData.graphicsBufferUsage = graph.GraphicsBufferTypeUsage;
  695. contextToCompiledData[context] = contextData;
  696. if (context.doesGenerateShader)
  697. {
  698. var generatedContent = VFXCodeGenerator.Build(context, compilationMode, contextData, dependencies);
  699. if (generatedContent != null)
  700. {
  701. outGeneratedCodeData.Add(new GeneratedCodeData()
  702. {
  703. context = context,
  704. computeShader = context.codeGeneratorCompute,
  705. compilMode = compilationMode,
  706. content = generatedContent
  707. });
  708. }
  709. }
  710. }
  711. var resource = m_Graph.GetResource();
  712. }
  713. finally
  714. {
  715. Profiler.EndSample();
  716. }
  717. }
  718. private static VFXShaderSourceDesc[] SaveShaderFiles(VisualEffectResource resource,
  719. List<GeneratedCodeData> generatedCodeData,
  720. Dictionary<VFXContext, VFXContextCompiledData> contextToCompiledData,
  721. VFXSystemNames systemNames)
  722. {
  723. Profiler.BeginSample("VFXEditor.SaveShaderFiles");
  724. try
  725. {
  726. var descs = new VFXShaderSourceDesc[generatedCodeData.Count];
  727. var assetName = string.Empty;
  728. if (resource.asset != null)
  729. {
  730. assetName = resource.asset.name; //Most Common case, asset is already available
  731. }
  732. else
  733. {
  734. var assetPath = AssetDatabase.GetAssetPath(resource); //Can occur during Copy/Past or Rename
  735. if (!string.IsNullOrEmpty(assetPath))
  736. {
  737. assetName = Path.GetFileNameWithoutExtension(assetPath);
  738. }
  739. else if (resource.name != null) //Unable to retrieve asset path, last fallback use serialized resource name
  740. {
  741. assetName = resource.name;
  742. }
  743. }
  744. for (int i = 0; i < generatedCodeData.Count; ++i)
  745. {
  746. var generated = generatedCodeData[i];
  747. var systemName = systemNames.GetUniqueSystemName(generated.context.GetData());
  748. var contextLetter = generated.context.letter;
  749. var contextName = string.IsNullOrEmpty(generated.context.label) ? generated.context.libraryName : generated.context.label;
  750. var shaderName = string.Empty;
  751. var fileName = string.Empty;
  752. if (contextLetter == '\0')
  753. {
  754. fileName = string.Format("[{0}] [{1}] {2}", assetName, systemName, contextName);
  755. shaderName = string.Format("Hidden/VFX/{0}/{1}/{2}", assetName, systemName, contextName);
  756. }
  757. else
  758. {
  759. fileName = string.Format("[{0}] [{1}]{2} {3}", assetName, systemName, contextLetter, contextName);
  760. shaderName = string.Format("Hidden/VFX/{0}/{1}/{2}/{3}", assetName, systemName, contextLetter, contextName);
  761. }
  762. if (!generated.computeShader)
  763. {
  764. generated.content.Insert(0, "Shader \"" + shaderName + "\"\n");
  765. }
  766. descs[i].source = generated.content.ToString();
  767. descs[i].name = fileName;
  768. descs[i].compute = generated.computeShader;
  769. }
  770. for (int i = 0; i < generatedCodeData.Count; ++i)
  771. {
  772. var generated = generatedCodeData[i];
  773. var contextData = contextToCompiledData[generated.context];
  774. contextData.indexInShaderSource = i;
  775. contextToCompiledData[generated.context] = contextData;
  776. }
  777. return descs;
  778. }
  779. finally
  780. {
  781. Profiler.EndSample();
  782. }
  783. }
  784. public void FillDependentBuffer(
  785. IEnumerable<VFXData> compilableData,
  786. List<VFXGPUBufferDesc> bufferDescs,
  787. VFXDependentBuffersData buffers)
  788. {
  789. // TODO This should be in VFXDataParticle
  790. foreach (var data in compilableData.OfType<VFXDataParticle>())
  791. {
  792. int attributeBufferIndex = -1;
  793. if (data.attributeBufferSize > 0)
  794. {
  795. attributeBufferIndex = bufferDescs.Count;
  796. bufferDescs.Add(data.attributeBufferDesc);
  797. }
  798. buffers.attributeBuffers.Add(data, attributeBufferIndex);
  799. int stripBufferIndex = -1;
  800. if (data.hasStrip)
  801. {
  802. stripBufferIndex = bufferDescs.Count;
  803. uint stripCapacity = (uint)data.GetSettingValue("stripCapacity");
  804. bufferDescs.Add(new VFXGPUBufferDesc() { type = ComputeBufferType.Default, size = stripCapacity * 5, stride = 4 });
  805. }
  806. buffers.stripBuffers.Add(data, stripBufferIndex);
  807. int boundsBufferIndex = -1;
  808. if (data.NeedsComputeBounds())
  809. {
  810. boundsBufferIndex = bufferDescs.Count;
  811. bufferDescs.Add(new VFXGPUBufferDesc() { type = ComputeBufferType.Default, size = 6, stride = 4 });
  812. }
  813. buffers.boundsBuffers.Add(data, boundsBufferIndex); // TODO Ludovic : Fill the data index and stuff
  814. }
  815. //Prepare GPU event buffer
  816. foreach (var data in compilableData.SelectMany(o => o.dependenciesOut).Distinct().OfType<VFXDataParticle>())
  817. {
  818. var eventBufferIndex = -1;
  819. uint capacity = (uint)data.GetSettingValue("capacity");
  820. if (capacity > 0)
  821. {
  822. eventBufferIndex = bufferDescs.Count;
  823. bufferDescs.Add(new VFXGPUBufferDesc() { type = ComputeBufferType.Append, size = capacity, stride = 4 });
  824. }
  825. buffers.eventBuffers.Add(data, eventBufferIndex);
  826. }
  827. }
  828. VFXRendererSettings GetRendererSettings(VFXRendererSettings initialSettings, IEnumerable<IVFXSubRenderer> subRenderers)
  829. {
  830. var settings = initialSettings;
  831. settings.shadowCastingMode = subRenderers.Any(r => r.hasShadowCasting) ? ShadowCastingMode.On : ShadowCastingMode.Off;
  832. settings.motionVectorGenerationMode = subRenderers.Any(r => r.hasMotionVector) ? MotionVectorGenerationMode.Object : MotionVectorGenerationMode.Camera;
  833. return settings;
  834. }
  835. private class VFXImplicitContextOfExposedExpression : VFXContext
  836. {
  837. private VFXExpressionMapper mapper;
  838. public VFXImplicitContextOfExposedExpression() : base(VFXContextType.None, VFXDataType.None, VFXDataType.None) { }
  839. private static void CollectExposedExpression(List<VFXExpression> expressions, VFXSlot slot)
  840. {
  841. var expression = slot.valueType != VFXValueType.None ? slot.GetInExpression() : null;
  842. if (expression != null)
  843. expressions.Add(expression);
  844. else
  845. {
  846. foreach (var child in slot.children)
  847. CollectExposedExpression(expressions, child);
  848. }
  849. }
  850. public void FillExpression(VFXGraph graph)
  851. {
  852. var allExposedParameter = graph.children.OfType<VFXParameter>().Where(o => o.exposed);
  853. var expressionsList = new List<VFXExpression>();
  854. foreach (var parameter in allExposedParameter)
  855. CollectExposedExpression(expressionsList, parameter.outputSlots[0]);
  856. mapper = new VFXExpressionMapper();
  857. for (int i = 0; i < expressionsList.Count; ++i)
  858. mapper.AddExpression(expressionsList[i], "ImplicitExposedExpression", i);
  859. }
  860. public override VFXExpressionMapper GetExpressionMapper(VFXDeviceTarget target)
  861. {
  862. return target == VFXDeviceTarget.CPU ? mapper : null;
  863. }
  864. }
  865. void ComputeEffectiveInputLinks(ref SubgraphInfos subgraphInfos, IEnumerable<VFXContext> compilableContexts)
  866. {
  867. var contextEffectiveInputLinks = subgraphInfos.contextEffectiveInputLinks;
  868. foreach (var context in compilableContexts.Where(t => !(t is VFXSubgraphContext)))
  869. {
  870. contextEffectiveInputLinks[context] = ComputeContextEffectiveLinks(context, ref subgraphInfos);
  871. ComputeEffectiveInputLinks(ref subgraphInfos, contextEffectiveInputLinks[context].SelectMany(t => t).Select(t => t.context).Where(t => !contextEffectiveInputLinks.ContainsKey(t)));
  872. }
  873. }
  874. struct EventDesc
  875. {
  876. public string name;
  877. public List<VFXContext> startSystems;
  878. public List<VFXContext> stopSystems;
  879. public List<VFXContext> initSystems;
  880. }
  881. static IEnumerable<uint> ConvertDataToSystemIndex(IEnumerable<VFXContext> input, Dictionary<VFXContext, uint> contextToSystemIndex)
  882. {
  883. foreach (var data in input)
  884. if (contextToSystemIndex.TryGetValue(data, out var index))
  885. yield return index;
  886. }
  887. private void CleanRuntimeData()
  888. {
  889. if (m_Graph.visualEffectResource != null)
  890. m_Graph.visualEffectResource.ClearRuntimeData();
  891. m_ExpressionGraph = new VFXExpressionGraph();
  892. m_ExpressionValues = new VFXExpressionValueContainerDesc[] { };
  893. }
  894. public void Compile(VFXCompilationMode compilationMode, bool forceShaderValidation)
  895. {
  896. // Early out in case: (Not even displaying the popup)
  897. if (m_Graph.children.Count() < 1 || // Graph is empty
  898. VFXLibrary.currentSRPBinder == null) // One of supported SRPs is not current SRP
  899. {
  900. CleanRuntimeData();
  901. return;
  902. }
  903. Profiler.BeginSample("VFXEditor.CompileAsset");
  904. float nbSteps = 12.0f;
  905. string assetPath = AssetDatabase.GetAssetPath(visualEffectResource);
  906. string progressBarTitle = "Compiling " + assetPath;
  907. try
  908. {
  909. EditorUtility.DisplayProgressBar(progressBarTitle, "Collecting dependencies", 0 / nbSteps);
  910. var models = new HashSet<ScriptableObject>();
  911. m_Graph.CollectDependencies(models, false);
  912. var resource = m_Graph.GetResource();
  913. resource.ClearSourceDependencies();
  914. HashSet<string> sourceDependencies = new HashSet<string>();
  915. foreach (VFXModel model in models.Where(t => t is IVFXSlotContainer))
  916. {
  917. model.GetSourceDependentAssets(sourceDependencies);
  918. }
  919. var contexts = models.OfType<VFXContext>().ToArray();
  920. foreach (var c in contexts) // Unflag all contexts
  921. c.MarkAsCompiled(false);
  922. IEnumerable<VFXContext> compilableContexts = contexts.Where(c => c.CanBeCompiled()).ToArray();
  923. var compilableData = models.OfType<VFXData>().Where(d => d.CanBeCompiled());
  924. IEnumerable<VFXContext> implicitContexts = Enumerable.Empty<VFXContext>();
  925. foreach (var d in compilableData) // Flag compiled contexts
  926. implicitContexts = implicitContexts.Concat(d.InitImplicitContexts());
  927. compilableContexts = compilableContexts.Concat(implicitContexts.ToArray());
  928. foreach (var c in compilableContexts) // Flag compiled contexts
  929. c.MarkAsCompiled(true);
  930. EditorUtility.DisplayProgressBar(progressBarTitle, "Collecting attributes", 1 / nbSteps);
  931. foreach (var data in compilableData)
  932. data.CollectAttributes();
  933. EditorUtility.DisplayProgressBar(progressBarTitle, "Process dependencies", 2 / nbSteps);
  934. foreach (var data in compilableData)
  935. data.ProcessDependencies();
  936. EditorUtility.DisplayProgressBar(progressBarTitle, "Compiling expression Graph", 3 / nbSteps);
  937. m_ExpressionGraph = new VFXExpressionGraph();
  938. var exposedExpressionContext = ScriptableObject.CreateInstance<VFXImplicitContextOfExposedExpression>();
  939. exposedExpressionContext.FillExpression(m_Graph); //Force all exposed expression to be visible, only for registering in CompileExpressions
  940. var expressionContextOptions = compilationMode == VFXCompilationMode.Runtime ? VFXExpressionContextOption.ConstantFolding : VFXExpressionContextOption.Reduction;
  941. m_ExpressionGraph.CompileExpressions(compilableContexts.Concat(new VFXContext[] { exposedExpressionContext }), expressionContextOptions);
  942. EditorUtility.DisplayProgressBar(progressBarTitle, "Generating bytecode", 4 / nbSteps);
  943. var expressionDescs = new List<VFXExpressionDesc>();
  944. var expressionPerSpawnEventAttributesDescs = new List<VFXExpressionDesc>();
  945. var valueDescs = new List<VFXExpressionValueContainerDesc>();
  946. FillExpressionDescs(m_ExpressionGraph, expressionDescs, expressionPerSpawnEventAttributesDescs, valueDescs);
  947. Dictionary<VFXContext, VFXContextCompiledData> contextToCompiledData = new Dictionary<VFXContext, VFXContextCompiledData>();
  948. foreach (var context in compilableContexts)
  949. contextToCompiledData.Add(context, new VFXContextCompiledData() { indexInShaderSource = -1 });
  950. EditorUtility.DisplayProgressBar(progressBarTitle, "Generating mappings", 5 / nbSteps);
  951. foreach (var context in compilableContexts)
  952. {
  953. var cpuMapper = m_ExpressionGraph.BuildCPUMapper(context);
  954. var contextData = contextToCompiledData[context];
  955. contextData.cpuMapper = cpuMapper;
  956. contextData.parameters = context.additionalMappings.ToArray();
  957. contextToCompiledData[context] = contextData;
  958. }
  959. var exposedParameterDescs = new List<VFXMapping>();
  960. FillExposedDescs(exposedParameterDescs, m_ExpressionGraph, m_Graph.children.OfType<VFXParameter>());
  961. SubgraphInfos subgraphInfos;
  962. subgraphInfos.subgraphParents = new Dictionary<VFXSubgraphContext, VFXSubgraphContext>();
  963. subgraphInfos.subgraphs = new List<VFXSubgraphContext>();
  964. foreach (var subgraph in m_Graph.children.OfType<VFXSubgraphContext>().Where(t => t.subgraph != null))
  965. {
  966. subgraphInfos.subgraphs.Add(subgraph);
  967. RecursePutSubgraphParent(subgraphInfos.subgraphParents, subgraphInfos.subgraphs, subgraph);
  968. }
  969. subgraphInfos.spawnerSubgraph = new Dictionary<VFXContext, VFXSubgraphContext>();
  970. foreach (var subgraph in subgraphInfos.subgraphs)
  971. {
  972. foreach (var spawner in subgraph.subChildren.OfType<VFXContext>())
  973. subgraphInfos.spawnerSubgraph.Add(spawner, subgraph);
  974. }
  975. subgraphInfos.contextEffectiveInputLinks = new Dictionary<VFXContext, List<VFXContextLink>[]>();
  976. ComputeEffectiveInputLinks(ref subgraphInfos, compilableContexts.Where(o => o.contextType == VFXContextType.Init || o.contextType == VFXContextType.OutputEvent));
  977. EditorUtility.DisplayProgressBar(progressBarTitle, "Generating Attribute layouts", 6 / nbSteps);
  978. foreach (var data in compilableData)
  979. data.GenerateAttributeLayout(subgraphInfos.contextEffectiveInputLinks);
  980. var generatedCodeData = new List<GeneratedCodeData>();
  981. EditorUtility.DisplayProgressBar(progressBarTitle, "Generating shaders", 7 / nbSteps);
  982. GenerateShaders(generatedCodeData, m_ExpressionGraph, compilableContexts, contextToCompiledData, compilationMode, sourceDependencies);
  983. m_Graph.systemNames.Sync(m_Graph);
  984. EditorUtility.DisplayProgressBar(progressBarTitle, "Saving shaders", 8 / nbSteps);
  985. VFXShaderSourceDesc[] shaderSources = SaveShaderFiles(m_Graph.visualEffectResource, generatedCodeData, contextToCompiledData, m_Graph.systemNames);
  986. var bufferDescs = new List<VFXGPUBufferDesc>();
  987. var temporaryBufferDescs = new List<VFXTemporaryGPUBufferDesc>();
  988. var cpuBufferDescs = new List<VFXCPUBufferDesc>();
  989. var systemDescs = new List<VFXEditorSystemDesc>();
  990. EditorUtility.DisplayProgressBar(progressBarTitle, "Generating systems", 9 / nbSteps);
  991. cpuBufferDescs.Add(new VFXCPUBufferDesc()
  992. {
  993. //Global attribute descriptor, always first entry in cpuBufferDesc, it can be empty (stride == 0).
  994. capacity = 1u,
  995. layout = m_ExpressionGraph.GlobalEventAttributes.ToArray(),
  996. stride = m_ExpressionGraph.GlobalEventAttributes.Any() ? m_ExpressionGraph.GlobalEventAttributes.First().offset.structure : 0u,
  997. initialData = ComputeArrayOfStructureInitialData(m_ExpressionGraph.GlobalEventAttributes)
  998. });
  999. var contextSpawnToSpawnInfo = new Dictionary<VFXContext, SpawnInfo>();
  1000. var dataToSystemIndex = new Dictionary<VFXContext, uint>();
  1001. FillSpawner(contextSpawnToSpawnInfo, dataToSystemIndex, cpuBufferDescs, systemDescs, compilableContexts, m_ExpressionGraph, contextToCompiledData, ref subgraphInfos, m_Graph.systemNames);
  1002. var eventDescs = new List<EventDesc>();
  1003. FillEvent(eventDescs, contextSpawnToSpawnInfo, compilableContexts, compilableData, ref subgraphInfos);
  1004. var dependentBuffersData = new VFXDependentBuffersData();
  1005. FillDependentBuffer(compilableData, bufferDescs, dependentBuffersData);
  1006. var contextSpawnToBufferIndex = contextSpawnToSpawnInfo.Select(o => new { o.Key, o.Value.bufferIndex }).ToDictionary(o => o.Key, o => o.bufferIndex);
  1007. foreach (var data in compilableData)
  1008. {
  1009. if (data.type != VFXDataType.SpawnEvent)
  1010. {
  1011. //^ dataToSystemIndex have already been filled by FillSpawner
  1012. //TODO: Rework this approach and always use FillDescs after an appropriate ordering of compilableData
  1013. //TODO: We should identify context by its VFXData but connected spawn context are sharing the same VFXData (see VFXData.InnerSetData)
  1014. foreach (var context in data.owners)
  1015. dataToSystemIndex.Add(context, (uint)systemDescs.Count);
  1016. }
  1017. data.FillDescs(VFXGraph.compileReporter,
  1018. bufferDescs,
  1019. temporaryBufferDescs,
  1020. systemDescs,
  1021. m_ExpressionGraph,
  1022. contextToCompiledData,
  1023. contextSpawnToBufferIndex,
  1024. dependentBuffersData,
  1025. subgraphInfos.contextEffectiveInputLinks,
  1026. m_Graph.systemNames);
  1027. }
  1028. // Early check : OutputEvent should not be duplicated with same name
  1029. var outputEventNames = systemDescs.Where(o => o.type == VFXSystemType.OutputEvent).Select(o => o.name);
  1030. if (outputEventNames.Count() != outputEventNames.Distinct().Count())
  1031. {
  1032. throw new InvalidOperationException("There are duplicated entries in OutputEvent");
  1033. }
  1034. // Update transient renderer settings
  1035. ShadowCastingMode shadowCastingMode = compilableContexts.OfType<IVFXSubRenderer>().Any(r => r.hasShadowCasting) ? ShadowCastingMode.On : ShadowCastingMode.Off;
  1036. MotionVectorGenerationMode motionVectorGenerationMode = compilableContexts.OfType<IVFXSubRenderer>().Any(r => r.hasMotionVector) ? MotionVectorGenerationMode.Object : MotionVectorGenerationMode.Camera;
  1037. EditorUtility.DisplayProgressBar(progressBarTitle, "Setting up systems", 10 / nbSteps);
  1038. var expressionSheet = new VFXExpressionSheet();
  1039. expressionSheet.expressions = expressionDescs.ToArray();
  1040. expressionSheet.expressionsPerSpawnEventAttribute = expressionPerSpawnEventAttributesDescs.ToArray();
  1041. expressionSheet.values = valueDescs.OrderBy(o => o.expressionIndex).ToArray();
  1042. expressionSheet.exposed = exposedParameterDescs.OrderBy(o => o.name).ToArray();
  1043. var vfxEventDesc = eventDescs.Select(e =>
  1044. {
  1045. return new VFXEventDesc()
  1046. {
  1047. name = e.name,
  1048. initSystems = ConvertDataToSystemIndex(e.initSystems, dataToSystemIndex).ToArray(),
  1049. startSystems = ConvertDataToSystemIndex(e.startSystems, dataToSystemIndex).ToArray(),
  1050. stopSystems = ConvertDataToSystemIndex(e.stopSystems, dataToSystemIndex).ToArray()
  1051. };
  1052. }).Where(e =>
  1053. {
  1054. return e.initSystems.Length > 0 || e.startSystems.Length > 0 || e.stopSystems.Length > 0;
  1055. }).ToArray();
  1056. resource.SetRuntimeData(expressionSheet, systemDescs.ToArray(), vfxEventDesc, bufferDescs.ToArray(), cpuBufferDescs.ToArray(), temporaryBufferDescs.ToArray(), shaderSources, shadowCastingMode, motionVectorGenerationMode, compiledVersion);
  1057. m_ExpressionValues = expressionSheet.values;
  1058. foreach (var dep in sourceDependencies)
  1059. resource.AddSourceDependency(dep);
  1060. m_Graph.visualEffectResource.compileInitialVariants = forceShaderValidation;
  1061. }
  1062. catch (Exception e)
  1063. {
  1064. VisualEffectAsset asset = null;
  1065. if (m_Graph.visualEffectResource != null)
  1066. asset = m_Graph.visualEffectResource.asset;
  1067. Debug.LogError(string.Format("{2} : Exception while compiling expression graph: {0}: {1}", e, e.StackTrace, (asset != null) ? asset.name : "(Null Asset)"), asset);
  1068. CleanRuntimeData();
  1069. }
  1070. finally
  1071. {
  1072. Profiler.EndSample();
  1073. EditorUtility.ClearProgressBar();
  1074. }
  1075. m_Graph.onRuntimeDataChanged?.Invoke(m_Graph);
  1076. }
  1077. public void UpdateValues()
  1078. {
  1079. var flatGraph = m_ExpressionGraph.FlattenedExpressions;
  1080. var numFlattenedExpressions = flatGraph.Count;
  1081. int descIndex = 0;
  1082. for (int i = 0; i < numFlattenedExpressions; ++i)
  1083. {
  1084. var exp = flatGraph[i];
  1085. if (exp.Is(VFXExpression.Flags.Value))
  1086. {
  1087. var desc = m_ExpressionValues[descIndex++];
  1088. if (desc.expressionIndex != i)
  1089. throw new InvalidOperationException();
  1090. switch (exp.valueType)
  1091. {
  1092. case VFXValueType.Float: SetValueDesc<float>(desc, exp); break;
  1093. case VFXValueType.Float2: SetValueDesc<Vector2>(desc, exp); break;
  1094. case VFXValueType.Float3: SetValueDesc<Vector3>(desc, exp); break;
  1095. case VFXValueType.Float4: SetValueDesc<Vector4>(desc, exp); break;
  1096. case VFXValueType.Int32: SetValueDesc<int>(desc, exp); break;
  1097. case VFXValueType.Uint32: SetValueDesc<uint>(desc, exp); break;
  1098. case VFXValueType.Texture2D:
  1099. case VFXValueType.Texture2DArray:
  1100. case VFXValueType.Texture3D:
  1101. case VFXValueType.TextureCube:
  1102. case VFXValueType.TextureCubeArray:
  1103. SetObjectValueDesc<Texture>(desc, exp);
  1104. break;
  1105. case VFXValueType.CameraBuffer: SetObjectValueDesc<Texture>(desc, exp); break;
  1106. case VFXValueType.Matrix4x4: SetValueDesc<Matrix4x4>(desc, exp); break;
  1107. case VFXValueType.Curve: SetValueDesc<AnimationCurve>(desc, exp); break;
  1108. case VFXValueType.ColorGradient: SetValueDesc<Gradient>(desc, exp); break;
  1109. case VFXValueType.Mesh: SetObjectValueDesc<Mesh>(desc, exp); break;
  1110. case VFXValueType.SkinnedMeshRenderer: SetObjectValueDesc<SkinnedMeshRenderer>(desc, exp); break;
  1111. case VFXValueType.Boolean: SetValueDesc<bool>(desc, exp); break;
  1112. case VFXValueType.Buffer: break; //The GraphicsBuffer type isn't serialized
  1113. default: throw new InvalidOperationException("Invalid type");
  1114. }
  1115. }
  1116. }
  1117. m_Graph.visualEffectResource.SetValueSheet(m_ExpressionValues);
  1118. }
  1119. public VisualEffectResource visualEffectResource
  1120. {
  1121. get
  1122. {
  1123. if (m_Graph != null)
  1124. {
  1125. return m_Graph.visualEffectResource;
  1126. }
  1127. return null;
  1128. }
  1129. }
  1130. private VFXGraph m_Graph;
  1131. [NonSerialized]
  1132. private VFXExpressionGraph m_ExpressionGraph;
  1133. [NonSerialized]
  1134. private VFXExpressionValueContainerDesc[] m_ExpressionValues;
  1135. }
  1136. }