暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

PreviewManager.cs 62KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEditor.Graphing;
  6. using UnityEditor.Graphing.Util;
  7. using UnityEngine.Assertions;
  8. using UnityEngine.Rendering;
  9. using UnityEditor.ShaderGraph.Internal;
  10. using Debug = UnityEngine.Debug;
  11. using Object = UnityEngine.Object;
  12. using Unity.Profiling;
  13. namespace UnityEditor.ShaderGraph.Drawing
  14. {
  15. delegate void OnPrimaryMasterChanged();
  16. class PreviewManager : IDisposable
  17. {
  18. GraphData m_Graph;
  19. MessageManager m_Messenger;
  20. MaterialPropertyBlock m_SharedPreviewPropertyBlock; // stores preview properties (shared among ALL preview nodes)
  21. Dictionary<AbstractMaterialNode, PreviewRenderData> m_RenderDatas = new Dictionary<AbstractMaterialNode, PreviewRenderData>(); // stores all of the PreviewRendererData, mapped by node
  22. PreviewRenderData m_MasterRenderData; // ref to preview renderer data for the master node
  23. int m_MaxPreviewsCompiling = 2; // max preview shaders we want to async compile at once
  24. // state trackers
  25. HashSet<AbstractMaterialNode> m_NodesShaderChanged = new HashSet<AbstractMaterialNode>(); // nodes whose shader code has changed, this node and nodes that read from it are put into NeedRecompile
  26. HashSet<AbstractMaterialNode> m_NodesPropertyChanged = new HashSet<AbstractMaterialNode>(); // nodes whose property values have changed, the properties will need to be updated and all nodes that use that property re-rendered
  27. HashSet<PreviewRenderData> m_PreviewsNeedsRecompile = new HashSet<PreviewRenderData>(); // previews we need to recompile the preview shader
  28. HashSet<PreviewRenderData> m_PreviewsCompiling = new HashSet<PreviewRenderData>(); // previews currently being compiled
  29. HashSet<PreviewRenderData> m_PreviewsToDraw = new HashSet<PreviewRenderData>(); // previews to re-render the texture (either because shader compile changed or property changed)
  30. HashSet<PreviewRenderData> m_TimedPreviews = new HashSet<PreviewRenderData>(); // previews that are dependent on a time node -- i.e. animated / need to redraw every frame
  31. double m_LastTimedUpdateTime = 0.0f;
  32. bool m_TopologyDirty; // indicates topology changed, used to rebuild timed node list and preview type (2D/3D) inheritance.
  33. HashSet<BlockNode> m_MasterNodeTempBlocks = new HashSet<BlockNode>(); // temp blocks used by the most recent master node preview generation.
  34. // used to detect when texture assets have been modified
  35. HashSet<string> m_PreviewTextureGUIDs = new HashSet<string>();
  36. PreviewSceneResources m_SceneResources;
  37. Texture2D m_ErrorTexture;
  38. Vector2? m_NewMasterPreviewSize;
  39. const AbstractMaterialNode kMasterProxyNode = null;
  40. public PreviewRenderData masterRenderData
  41. {
  42. get { return m_MasterRenderData; }
  43. }
  44. public PreviewManager(GraphData graph, MessageManager messenger)
  45. {
  46. m_SharedPreviewPropertyBlock = new MaterialPropertyBlock();
  47. m_Graph = graph;
  48. m_Messenger = messenger;
  49. m_ErrorTexture = GenerateFourSquare(Color.magenta, Color.black);
  50. m_SceneResources = new PreviewSceneResources();
  51. foreach (var node in m_Graph.GetNodes<AbstractMaterialNode>())
  52. AddPreview(node);
  53. AddMasterPreview();
  54. }
  55. static Texture2D GenerateFourSquare(Color c1, Color c2)
  56. {
  57. var tex = new Texture2D(2, 2);
  58. tex.SetPixel(0, 0, c1);
  59. tex.SetPixel(0, 1, c2);
  60. tex.SetPixel(1, 0, c2);
  61. tex.SetPixel(1, 1, c1);
  62. tex.filterMode = FilterMode.Point;
  63. tex.Apply();
  64. return tex;
  65. }
  66. public void ResizeMasterPreview(Vector2 newSize)
  67. {
  68. m_NewMasterPreviewSize = newSize;
  69. }
  70. public PreviewRenderData GetPreviewRenderData(AbstractMaterialNode node)
  71. {
  72. PreviewRenderData result = null;
  73. if (node == kMasterProxyNode ||
  74. node is BlockNode ||
  75. node == m_Graph.outputNode) // the outputNode, if it exists, is mapped to master
  76. {
  77. result = m_MasterRenderData;
  78. }
  79. else
  80. {
  81. m_RenderDatas.TryGetValue(node, out result);
  82. }
  83. return result;
  84. }
  85. void AddMasterPreview()
  86. {
  87. m_MasterRenderData = new PreviewRenderData
  88. {
  89. previewName = "Master Preview",
  90. renderTexture =
  91. new RenderTexture(400, 400, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default)
  92. {
  93. hideFlags = HideFlags.HideAndDontSave
  94. },
  95. previewMode = PreviewMode.Preview3D,
  96. };
  97. m_MasterRenderData.renderTexture.Create();
  98. var shaderData = new PreviewShaderData
  99. {
  100. // even though a SubGraphOutputNode can be directly mapped to master (via m_Graph.outputNode)
  101. // we always keep master node associated with kMasterProxyNode instead
  102. // just easier if the association is always dynamic
  103. node = kMasterProxyNode,
  104. passesCompiling = 0,
  105. isOutOfDate = true,
  106. hasError = false,
  107. };
  108. m_MasterRenderData.shaderData = shaderData;
  109. m_PreviewsNeedsRecompile.Add(m_MasterRenderData);
  110. m_PreviewsToDraw.Add(m_MasterRenderData);
  111. m_TopologyDirty = true;
  112. }
  113. public void UpdateMasterPreview(ModificationScope scope)
  114. {
  115. if (scope == ModificationScope.Topological ||
  116. scope == ModificationScope.Graph)
  117. {
  118. // mark the master preview for recompile if it exists
  119. // if not, no need to do it here, because it is always marked for recompile on creation
  120. if (m_MasterRenderData != null)
  121. m_PreviewsNeedsRecompile.Add(m_MasterRenderData);
  122. m_TopologyDirty = true;
  123. }
  124. else if (scope == ModificationScope.Node)
  125. {
  126. if (m_MasterRenderData != null)
  127. m_PreviewsToDraw.Add(m_MasterRenderData);
  128. }
  129. }
  130. void AddPreview(AbstractMaterialNode node)
  131. {
  132. Assert.IsNotNull(node);
  133. // BlockNodes have no preview for themselves, but are mapped to the "Master" preview
  134. // SubGraphOutput nodes have their own previews, but will use the "Master" preview if they are the m_Graph.outputNode
  135. if (node is BlockNode)
  136. {
  137. node.RegisterCallback(OnNodeModified);
  138. UpdateMasterPreview(ModificationScope.Topological);
  139. m_NodesPropertyChanged.Add(node);
  140. return;
  141. }
  142. var renderData = new PreviewRenderData
  143. {
  144. previewName = node.name ?? "UNNAMED NODE",
  145. renderTexture =
  146. new RenderTexture(200, 200, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default)
  147. {
  148. hideFlags = HideFlags.HideAndDontSave
  149. }
  150. };
  151. renderData.renderTexture.Create();
  152. var shaderData = new PreviewShaderData
  153. {
  154. node = node,
  155. passesCompiling = 0,
  156. isOutOfDate = true,
  157. hasError = false,
  158. };
  159. renderData.shaderData = shaderData;
  160. m_RenderDatas.Add(node, renderData);
  161. node.RegisterCallback(OnNodeModified);
  162. m_PreviewsNeedsRecompile.Add(renderData);
  163. m_NodesPropertyChanged.Add(node);
  164. m_TopologyDirty = true;
  165. }
  166. void OnNodeModified(AbstractMaterialNode node, ModificationScope scope)
  167. {
  168. Assert.IsNotNull(node);
  169. if (scope == ModificationScope.Topological ||
  170. scope == ModificationScope.Graph)
  171. {
  172. m_NodesShaderChanged.Add(node); // shader code for this node changed, this will trigger m_PreviewsShaderChanged for all nodes downstream
  173. m_NodesPropertyChanged.Add(node); // properties could also have changed at the same time and need to be re-collected
  174. m_TopologyDirty = true;
  175. }
  176. else if (scope == ModificationScope.Node)
  177. {
  178. // if we only changed a constant on the node, we don't have to recompile the shader for it, just re-render it with the updated constant
  179. // should instead flag m_NodesConstantChanged
  180. m_NodesPropertyChanged.Add(node);
  181. }
  182. }
  183. // temp structures that are kept around statically to avoid GC churn (not thread safe)
  184. static Stack<AbstractMaterialNode> m_TempNodeWave = new Stack<AbstractMaterialNode>();
  185. static HashSet<AbstractMaterialNode> m_TempAddedToNodeWave = new HashSet<AbstractMaterialNode>();
  186. // cache the Action to avoid GC
  187. static Action<AbstractMaterialNode> AddNextLevelNodesToWave =
  188. nextLevelNode =>
  189. {
  190. if (!m_TempAddedToNodeWave.Contains(nextLevelNode))
  191. {
  192. m_TempNodeWave.Push(nextLevelNode);
  193. m_TempAddedToNodeWave.Add(nextLevelNode);
  194. }
  195. };
  196. internal enum PropagationDirection
  197. {
  198. Upstream,
  199. Downstream
  200. }
  201. // ADDs all nodes in sources, and all nodes in the given direction relative to them, into result
  202. // sources and result can be the same HashSet
  203. private static readonly ProfilerMarker PropagateNodesMarker = new ProfilerMarker("PropagateNodes");
  204. internal static void PropagateNodes(HashSet<AbstractMaterialNode> sources, PropagationDirection dir, HashSet<AbstractMaterialNode> result)
  205. {
  206. using (PropagateNodesMarker.Auto())
  207. if (sources.Count > 0)
  208. {
  209. // NodeWave represents the list of nodes we still have to process and add to result
  210. m_TempNodeWave.Clear();
  211. m_TempAddedToNodeWave.Clear();
  212. foreach (var node in sources)
  213. {
  214. m_TempNodeWave.Push(node);
  215. m_TempAddedToNodeWave.Add(node);
  216. }
  217. while (m_TempNodeWave.Count > 0)
  218. {
  219. var node = m_TempNodeWave.Pop();
  220. if (node == null)
  221. continue;
  222. result.Add(node);
  223. // grab connected nodes in propagation direction, add them to the node wave
  224. ForeachConnectedNode(node, dir, AddNextLevelNodesToWave);
  225. }
  226. // clean up any temp data
  227. m_TempNodeWave.Clear();
  228. m_TempAddedToNodeWave.Clear();
  229. }
  230. }
  231. static void ForeachConnectedNode(AbstractMaterialNode node, PropagationDirection dir, Action<AbstractMaterialNode> action)
  232. {
  233. using (var tempEdges = PooledList<IEdge>.Get())
  234. using (var tempSlots = PooledList<MaterialSlot>.Get())
  235. {
  236. // Loop through all nodes that the node feeds into.
  237. if (dir == PropagationDirection.Downstream)
  238. node.GetOutputSlots(tempSlots);
  239. else
  240. node.GetInputSlots(tempSlots);
  241. foreach (var slot in tempSlots)
  242. {
  243. // get the edges out of each slot
  244. tempEdges.Clear(); // and here we serialize another list, ouch!
  245. node.owner.GetEdges(slot.slotReference, tempEdges);
  246. foreach (var edge in tempEdges)
  247. {
  248. // We look at each node we feed into.
  249. var connectedSlot = (dir == PropagationDirection.Downstream) ? edge.inputSlot : edge.outputSlot;
  250. var connectedNode = connectedSlot.node;
  251. action(connectedNode);
  252. }
  253. }
  254. }
  255. // Custom Interpolator Blocks have implied connections to their Custom Interpolator Nodes...
  256. if (dir == PropagationDirection.Downstream && node is BlockNode bnode && bnode.isCustomBlock)
  257. {
  258. foreach (var cin in CustomInterpolatorUtils.GetCustomBlockNodeDependents(bnode))
  259. {
  260. action(cin);
  261. }
  262. }
  263. // ... Just as custom Interpolator Nodes have implied connections to their custom interpolator blocks
  264. if (dir == PropagationDirection.Upstream && node is CustomInterpolatorNode ciNode && ciNode.e_targetBlockNode != null)
  265. {
  266. action(ciNode.e_targetBlockNode);
  267. }
  268. }
  269. public void ReloadChangedFiles(string ChangedFileDependencyGUIDs)
  270. {
  271. if (m_PreviewTextureGUIDs.Contains(ChangedFileDependencyGUIDs))
  272. {
  273. // have to setup the textures on the MaterialPropertyBlock again
  274. // easiest is to just mark everything as needing property update
  275. m_NodesPropertyChanged.UnionWith(m_RenderDatas.Keys);
  276. }
  277. }
  278. public void HandleGraphChanges()
  279. {
  280. foreach (var node in m_Graph.addedNodes)
  281. {
  282. AddPreview(node);
  283. m_TopologyDirty = true;
  284. }
  285. foreach (var edge in m_Graph.addedEdges)
  286. {
  287. var node = edge.inputSlot.node;
  288. if (node != null)
  289. {
  290. if ((node is BlockNode) || (node is SubGraphOutputNode))
  291. UpdateMasterPreview(ModificationScope.Topological);
  292. else
  293. m_NodesShaderChanged.Add(node);
  294. m_TopologyDirty = true;
  295. }
  296. }
  297. foreach (var node in m_Graph.removedNodes)
  298. {
  299. DestroyPreview(node);
  300. m_TopologyDirty = true;
  301. }
  302. foreach (var edge in m_Graph.removedEdges)
  303. {
  304. var node = edge.inputSlot.node;
  305. if ((node is BlockNode) || (node is SubGraphOutputNode))
  306. {
  307. UpdateMasterPreview(ModificationScope.Topological);
  308. }
  309. m_NodesShaderChanged.Add(node);
  310. //When an edge gets deleted, if the node had the edge on creation, the properties would get out of sync and no value would get set.
  311. //Fix for https://fogbugz.unity3d.com/f/cases/1284033/
  312. m_NodesPropertyChanged.Add(node);
  313. m_TopologyDirty = true;
  314. }
  315. foreach (var edge in m_Graph.addedEdges)
  316. {
  317. var node = edge.inputSlot.node;
  318. if (node != null)
  319. {
  320. if ((node is BlockNode) || (node is SubGraphOutputNode))
  321. {
  322. UpdateMasterPreview(ModificationScope.Topological);
  323. }
  324. m_NodesShaderChanged.Add(node);
  325. m_TopologyDirty = true;
  326. }
  327. }
  328. // remove the nodes from the state trackers
  329. m_NodesShaderChanged.ExceptWith(m_Graph.removedNodes);
  330. m_NodesPropertyChanged.ExceptWith(m_Graph.removedNodes);
  331. m_Messenger.ClearNodesFromProvider(this, m_Graph.removedNodes);
  332. }
  333. private static readonly ProfilerMarker CollectPreviewPropertiesMarker = new ProfilerMarker("CollectPreviewProperties");
  334. void CollectPreviewProperties(IEnumerable<AbstractMaterialNode> nodesToCollect, PooledList<PreviewProperty> perMaterialPreviewProperties)
  335. {
  336. using (CollectPreviewPropertiesMarker.Auto())
  337. using (var tempPreviewProps = PooledList<PreviewProperty>.Get())
  338. {
  339. // collect from all of the changed nodes
  340. foreach (var propNode in nodesToCollect)
  341. propNode.CollectPreviewMaterialProperties(tempPreviewProps);
  342. // also grab all graph properties (they are updated every frame)
  343. foreach (var prop in m_Graph.properties)
  344. tempPreviewProps.Add(prop.GetPreviewMaterialProperty());
  345. foreach (var previewProperty in tempPreviewProps)
  346. {
  347. previewProperty.SetValueOnMaterialPropertyBlock(m_SharedPreviewPropertyBlock);
  348. // record guids for any texture properties
  349. if ((previewProperty.propType >= PropertyType.Texture2D) && (previewProperty.propType <= PropertyType.Cubemap))
  350. {
  351. if (previewProperty.propType != PropertyType.Cubemap)
  352. {
  353. if (previewProperty.textureValue != null)
  354. if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(previewProperty.textureValue, out string guid, out long localID))
  355. {
  356. // Note, this never gets cleared, so we accumulate texture GUIDs over time, if the user keeps changing textures
  357. m_PreviewTextureGUIDs.Add(guid);
  358. }
  359. }
  360. else
  361. {
  362. if (previewProperty.cubemapValue != null)
  363. if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(previewProperty.cubemapValue, out string guid, out long localID))
  364. {
  365. // Note, this never gets cleared, so we accumulate texture GUIDs over time, if the user keeps changing textures
  366. m_PreviewTextureGUIDs.Add(guid);
  367. }
  368. }
  369. }
  370. // virtual texture assignments must be pushed to the materials themselves (MaterialPropertyBlocks not supported)
  371. if ((previewProperty.propType == PropertyType.VirtualTexture) &&
  372. (previewProperty.vtProperty?.value?.layers != null))
  373. {
  374. perMaterialPreviewProperties.Add(previewProperty);
  375. }
  376. }
  377. }
  378. }
  379. void AssignPerMaterialPreviewProperties(Material mat, List<PreviewProperty> perMaterialPreviewProperties)
  380. {
  381. foreach (var prop in perMaterialPreviewProperties)
  382. {
  383. switch (prop.propType)
  384. {
  385. case PropertyType.VirtualTexture:
  386. // setup the VT textures on the material
  387. bool setAnyTextures = false;
  388. var vt = prop.vtProperty.value;
  389. for (int layer = 0; layer < vt.layers.Count; layer++)
  390. {
  391. var texture = vt.layers[layer].layerTexture?.texture;
  392. int propIndex = mat.shader.FindPropertyIndex(vt.layers[layer].layerRefName);
  393. if (propIndex != -1)
  394. {
  395. mat.SetTexture(vt.layers[layer].layerRefName, texture);
  396. setAnyTextures = true;
  397. }
  398. }
  399. // also put in a request for the VT tiles, since preview rendering does not have feedback enabled
  400. if (setAnyTextures)
  401. {
  402. #if ENABLE_VIRTUALTEXTURES
  403. int stackPropertyId = Shader.PropertyToID(prop.vtProperty.referenceName);
  404. try
  405. {
  406. // Ensure we always request the mip sized 256x256
  407. int width, height;
  408. UnityEngine.Rendering.VirtualTexturing.Streaming.GetTextureStackSize(mat, stackPropertyId, out width, out height);
  409. int textureMip = (int)Math.Max(Mathf.Log(width, 2f), Mathf.Log(height, 2f));
  410. const int baseMip = 8;
  411. int mip = Math.Max(textureMip - baseMip, 0);
  412. UnityEngine.Rendering.VirtualTexturing.Streaming.RequestRegion(mat, stackPropertyId, new Rect(0.0f, 0.0f, 1.0f, 1.0f), mip, UnityEngine.Rendering.VirtualTexturing.System.AllMips);
  413. }
  414. catch (InvalidOperationException)
  415. {
  416. // This gets thrown when the system is in an indeterminate state (like a material with no textures assigned which can obviously never have a texture stack streamed).
  417. // This is valid in this case as we're still authoring the material.
  418. }
  419. #endif // ENABLE_VIRTUALTEXTURES
  420. }
  421. break;
  422. }
  423. }
  424. }
  425. bool TimedNodesShouldUpdate(EditorWindow editorWindow)
  426. {
  427. // get current screen FPS, clamp to what we consider a valid range
  428. // this is probably not accurate for multi-monitor.. but should be relevant to at least one of the monitors
  429. double monitorFPS = Screen.currentResolution.refreshRateRatio.value;
  430. if (Double.IsInfinity(monitorFPS) || Double.IsNaN(monitorFPS))
  431. monitorFPS = 60.0f;
  432. monitorFPS = Math.Min(monitorFPS, 144.0);
  433. monitorFPS = Math.Max(monitorFPS, 30.0);
  434. var curTime = EditorApplication.timeSinceStartup;
  435. var deltaTime = curTime - m_LastTimedUpdateTime;
  436. bool isFocusedWindow = (EditorWindow.focusedWindow == editorWindow);
  437. // we throttle the update rate, based on whether the window is focused and if unity is active
  438. const double k_AnimatedFPS_WhenNotFocused = 10.0;
  439. const double k_AnimatedFPS_WhenInactive = 2.0;
  440. double maxAnimatedFPS =
  441. (UnityEditorInternal.InternalEditorUtility.isApplicationActive ?
  442. (isFocusedWindow ? monitorFPS : k_AnimatedFPS_WhenNotFocused) :
  443. k_AnimatedFPS_WhenInactive);
  444. bool update = (deltaTime > (1.0 / maxAnimatedFPS));
  445. if (update)
  446. m_LastTimedUpdateTime = curTime;
  447. return update;
  448. }
  449. private static readonly ProfilerMarker RenderPreviewsMarker = new ProfilerMarker("RenderPreviews");
  450. private static int k_spriteProps = Shader.PropertyToID("unity_SpriteProps");
  451. private static int k_spriteColor = Shader.PropertyToID("unity_SpriteColor");
  452. private static int k_rendererColor = Shader.PropertyToID("_RendererColor");
  453. public void RenderPreviews(EditorWindow editorWindow, bool requestShaders = true)
  454. {
  455. using (RenderPreviewsMarker.Auto())
  456. using (var renderList2D = PooledList<PreviewRenderData>.Get())
  457. using (var renderList3D = PooledList<PreviewRenderData>.Get())
  458. using (var nodesToDraw = PooledHashSet<AbstractMaterialNode>.Get())
  459. using (var perMaterialPreviewProperties = PooledList<PreviewProperty>.Get())
  460. {
  461. // update topology cached data
  462. // including list of time-dependent previews, and the preview mode (2d/3d)
  463. UpdateTopology();
  464. if (requestShaders)
  465. UpdateShaders();
  466. // Need to late capture custom interpolators because of how their type changes
  467. // can have downstream impacts on dynamic slots.
  468. HashSet<AbstractMaterialNode> customProps = new HashSet<AbstractMaterialNode>();
  469. PropagateNodes(
  470. new HashSet<AbstractMaterialNode>(m_NodesPropertyChanged.OfType<BlockNode>().Where(b => b.isCustomBlock)),
  471. PropagationDirection.Downstream,
  472. customProps);
  473. m_NodesPropertyChanged.UnionWith(customProps);
  474. // all nodes downstream of a changed property must be redrawn (to display the updated the property value)
  475. PropagateNodes(m_NodesPropertyChanged, PropagationDirection.Downstream, nodesToDraw);
  476. // always update properties from temporary blocks created by master node preview generation
  477. m_NodesPropertyChanged.UnionWith(m_MasterNodeTempBlocks);
  478. CollectPreviewProperties(m_NodesPropertyChanged, perMaterialPreviewProperties);
  479. m_NodesPropertyChanged.Clear();
  480. // timed nodes are animated, so they should be updated regularly (but not necessarily on every update)
  481. // (m_TimedPreviews has been pre-propagated downstream)
  482. // HOWEVER they do not need to collect properties. (the only property changing is time..)
  483. if (TimedNodesShouldUpdate(editorWindow))
  484. m_PreviewsToDraw.UnionWith(m_TimedPreviews);
  485. ForEachNodesPreview(nodesToDraw, p => m_PreviewsToDraw.Add(p));
  486. // redraw master when it is resized
  487. if (m_NewMasterPreviewSize.HasValue)
  488. m_PreviewsToDraw.Add(m_MasterRenderData);
  489. // apply filtering to determine what nodes really get drawn
  490. bool renderMasterPreview = false;
  491. int drawPreviewCount = 0;
  492. foreach (var preview in m_PreviewsToDraw)
  493. {
  494. Assert.IsNotNull(preview);
  495. { // skip if the node doesn't have a preview expanded (unless it's master)
  496. var node = preview.shaderData.node;
  497. if ((node != kMasterProxyNode) && (!node.hasPreview || !node.previewExpanded))
  498. continue;
  499. }
  500. // check that we've got shaders and materials generated
  501. // if not ,replace the rendered texture with null
  502. if ((preview.shaderData.shader == null) ||
  503. (preview.shaderData.mat == null))
  504. {
  505. // avoid calling NotifyPreviewChanged repeatedly
  506. if (preview.texture != null)
  507. {
  508. preview.texture = null;
  509. preview.NotifyPreviewChanged();
  510. }
  511. continue;
  512. }
  513. if (preview.shaderData.hasError)
  514. {
  515. preview.texture = m_ErrorTexture;
  516. preview.NotifyPreviewChanged();
  517. continue;
  518. }
  519. // skip rendering while a preview shader is being compiled
  520. if (m_PreviewsCompiling.Contains(preview))
  521. continue;
  522. // we want to render this thing, now categorize what kind of render it is
  523. if (preview == m_MasterRenderData)
  524. renderMasterPreview = true;
  525. else if (preview.previewMode == PreviewMode.Preview2D)
  526. renderList2D.Add(preview);
  527. else
  528. renderList3D.Add(preview);
  529. drawPreviewCount++;
  530. }
  531. // if we actually don't want to render anything at all, early out here
  532. if (drawPreviewCount <= 0)
  533. return;
  534. var time = Time.realtimeSinceStartup;
  535. var timeParameters = new Vector4(time, Mathf.Sin(time), Mathf.Cos(time), 0.0f);
  536. m_SharedPreviewPropertyBlock.SetVector("_TimeParameters", timeParameters);
  537. EditorUtility.SetCameraAnimateMaterialsTime(m_SceneResources.camera, time);
  538. m_SceneResources.light0.enabled = true;
  539. m_SceneResources.light0.intensity = 1.0f;
  540. m_SceneResources.light0.transform.rotation = Quaternion.Euler(50f, 50f, 0);
  541. m_SceneResources.light1.enabled = true;
  542. m_SceneResources.light1.intensity = 1.0f;
  543. m_SceneResources.camera.clearFlags = CameraClearFlags.Color;
  544. // Render 2D previews
  545. m_SceneResources.camera.transform.position = -Vector3.forward * 2;
  546. m_SceneResources.camera.transform.rotation = Quaternion.identity;
  547. m_SceneResources.camera.orthographicSize = 0.5f;
  548. m_SceneResources.camera.orthographic = true;
  549. foreach (var renderData in renderList2D)
  550. RenderPreview(renderData, m_SceneResources.quad, Matrix4x4.identity, perMaterialPreviewProperties);
  551. // Render 3D previews
  552. m_SceneResources.camera.transform.position = -Vector3.forward * 5;
  553. m_SceneResources.camera.transform.rotation = Quaternion.identity;
  554. m_SceneResources.camera.orthographic = false;
  555. foreach (var renderData in renderList3D)
  556. RenderPreview(renderData, m_SceneResources.sphere, Matrix4x4.identity, perMaterialPreviewProperties);
  557. if (renderMasterPreview)
  558. {
  559. if (m_NewMasterPreviewSize.HasValue)
  560. {
  561. if (masterRenderData.renderTexture != null)
  562. Object.DestroyImmediate(masterRenderData.renderTexture, true);
  563. masterRenderData.renderTexture = new RenderTexture((int)m_NewMasterPreviewSize.Value.x, (int)m_NewMasterPreviewSize.Value.y, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default) { hideFlags = HideFlags.HideAndDontSave };
  564. masterRenderData.renderTexture.Create();
  565. masterRenderData.texture = masterRenderData.renderTexture;
  566. m_NewMasterPreviewSize = null;
  567. }
  568. var mesh = m_Graph.previewData.serializedMesh.mesh;
  569. var preventRotation = m_Graph.previewData.preventRotation;
  570. if (!mesh)
  571. {
  572. var useSpritePreview =
  573. m_Graph.activeTargets.LastOrDefault(t => t.IsActive())?.prefersSpritePreview ?? false;
  574. mesh = useSpritePreview ? m_SceneResources.quad : m_SceneResources.sphere;
  575. preventRotation = useSpritePreview;
  576. }
  577. var previewTransform = preventRotation ? Matrix4x4.identity : Matrix4x4.Rotate(m_Graph.previewData.rotation);
  578. var scale = m_Graph.previewData.scale;
  579. previewTransform *= Matrix4x4.Scale(scale * Vector3.one * (Vector3.one).magnitude / mesh.bounds.size.magnitude);
  580. previewTransform *= Matrix4x4.Translate(-mesh.bounds.center);
  581. //bugfix for some variables that need to be setup for URP Sprite material previews. Want a better isolated place to put them,
  582. //but I dont believe such a place exists and would be too costly to add.
  583. masterRenderData.shaderData.mat.SetVector(k_spriteProps, new Vector4(1, 1, -1, 0));
  584. masterRenderData.shaderData.mat.SetVector(k_spriteColor, new Vector4(1, 1, 1, 1));
  585. masterRenderData.shaderData.mat.SetVector(k_rendererColor, new Vector4(1, 1, 1, 1));
  586. RenderPreview(masterRenderData, mesh, previewTransform, perMaterialPreviewProperties);
  587. }
  588. m_SceneResources.light0.enabled = false;
  589. m_SceneResources.light1.enabled = false;
  590. foreach (var renderData in renderList2D)
  591. renderData.NotifyPreviewChanged();
  592. foreach (var renderData in renderList3D)
  593. renderData.NotifyPreviewChanged();
  594. if (renderMasterPreview)
  595. masterRenderData.NotifyPreviewChanged();
  596. }
  597. }
  598. private static readonly ProfilerMarker ProcessCompletedShaderCompilationsMarker = new ProfilerMarker("ProcessCompletedShaderCompilations");
  599. private int compileFailRekicks = 0;
  600. void ProcessCompletedShaderCompilations()
  601. {
  602. // Check for shaders that finished compiling and set them to redraw
  603. using (ProcessCompletedShaderCompilationsMarker.Auto())
  604. using (var previewsCompiled = PooledHashSet<PreviewRenderData>.Get())
  605. {
  606. foreach (var preview in m_PreviewsCompiling)
  607. {
  608. {
  609. var node = preview.shaderData.node;
  610. Assert.IsFalse(node is BlockNode);
  611. }
  612. PreviewRenderData renderData = preview;
  613. PreviewShaderData shaderData = renderData.shaderData;
  614. // Assert.IsTrue(shaderData.passesCompiling > 0);
  615. if (shaderData.passesCompiling <= 0)
  616. {
  617. Debug.Log("Zero Passes: " + preview.previewName + " (" + shaderData.passesCompiling + " passes, " + renderData.shaderData.mat.passCount + " mat passes)");
  618. }
  619. if (shaderData.passesCompiling != renderData.shaderData.mat.passCount)
  620. {
  621. // attempt to re-kick the compilation a few times
  622. Debug.Log("Rekicking Compiling: " + preview.previewName + " (" + shaderData.passesCompiling + " passes, " + renderData.shaderData.mat.passCount + " mat passes)");
  623. compileFailRekicks++;
  624. if (compileFailRekicks <= 3)
  625. {
  626. shaderData.passesCompiling = 0;
  627. previewsCompiled.Add(renderData);
  628. m_PreviewsNeedsRecompile.Add(renderData);
  629. continue;
  630. }
  631. else if (compileFailRekicks == 4)
  632. {
  633. Debug.LogWarning("Unexpected error in compiling preview shaders: some previews might not update. You can try to re-open the Shader Graph window, or select <b>Help > Report a Bug</b> in the menu and report this bug.");
  634. }
  635. }
  636. // check that all passes have compiled
  637. var allPassesCompiled = true;
  638. for (var i = 0; i < renderData.shaderData.mat.passCount; i++)
  639. {
  640. if (!ShaderUtil.IsPassCompiled(renderData.shaderData.mat, i))
  641. {
  642. allPassesCompiled = false;
  643. break;
  644. }
  645. }
  646. if (!allPassesCompiled)
  647. {
  648. // keep waiting
  649. continue;
  650. }
  651. // Force the material to re-generate all it's shader properties, by reassigning the shader
  652. renderData.shaderData.mat.shader = renderData.shaderData.shader;
  653. renderData.shaderData.passesCompiling = 0;
  654. renderData.shaderData.isOutOfDate = false;
  655. CheckForErrors(renderData.shaderData);
  656. previewsCompiled.Add(renderData);
  657. }
  658. // removed compiled nodes from compiling list
  659. m_PreviewsCompiling.ExceptWith(previewsCompiled);
  660. // and add them to the draw list to display updated shader (note this will only redraw specifically this node, not any others)
  661. m_PreviewsToDraw.UnionWith(previewsCompiled);
  662. }
  663. }
  664. private static readonly ProfilerMarker KickOffShaderCompilationsMarker = new ProfilerMarker("KickOffShaderCompilations");
  665. void KickOffShaderCompilations()
  666. {
  667. // Start compilation for nodes that need to recompile
  668. using (KickOffShaderCompilationsMarker.Auto())
  669. using (var previewsToCompile = PooledHashSet<PreviewRenderData>.Get())
  670. {
  671. // master node compile is first in the priority list, as it takes longer than the other previews
  672. if (m_PreviewsCompiling.Count + previewsToCompile.Count < m_MaxPreviewsCompiling)
  673. {
  674. if (m_PreviewsNeedsRecompile.Contains(m_MasterRenderData) &&
  675. !m_PreviewsCompiling.Contains(m_MasterRenderData))
  676. {
  677. previewsToCompile.Add(m_MasterRenderData);
  678. m_PreviewsNeedsRecompile.Remove(m_MasterRenderData);
  679. }
  680. }
  681. // add each node to compile list if it needs a preview, is not already compiling, and we have room
  682. // (we don't want to double kick compiles, so wait for the first one to get back before kicking another)
  683. for (int i = 0; i < m_PreviewsNeedsRecompile.Count(); i++)
  684. {
  685. if (m_PreviewsCompiling.Count + previewsToCompile.Count >= m_MaxPreviewsCompiling)
  686. break;
  687. var preview = m_PreviewsNeedsRecompile.ElementAt(i);
  688. if (preview == m_MasterRenderData) // master preview is handled specially above
  689. continue;
  690. var node = preview.shaderData.node;
  691. Assert.IsNotNull(node);
  692. Assert.IsFalse(node is BlockNode);
  693. if (node.hasPreview && node.previewExpanded && !m_PreviewsCompiling.Contains(preview))
  694. {
  695. previewsToCompile.Add(preview);
  696. }
  697. }
  698. if (previewsToCompile.Count >= 0)
  699. using (var nodesToCompile = PooledHashSet<AbstractMaterialNode>.Get())
  700. {
  701. // remove the selected nodes from the recompile list
  702. m_PreviewsNeedsRecompile.ExceptWith(previewsToCompile);
  703. // Reset error states for the UI, the shader, and all render data for nodes we're recompiling
  704. nodesToCompile.UnionWith(previewsToCompile.Select(x => x.shaderData.node));
  705. nodesToCompile.Remove(null);
  706. // TODO: not sure if we need to clear BlockNodes when master gets rebuilt?
  707. m_Messenger.ClearNodesFromProvider(this, nodesToCompile);
  708. // Force async compile on
  709. var wasAsyncAllowed = ShaderUtil.allowAsyncCompilation;
  710. ShaderUtil.allowAsyncCompilation = true;
  711. // kick async compiles for all nodes in m_NodeToCompile
  712. foreach (var preview in previewsToCompile)
  713. {
  714. if (preview == m_MasterRenderData)
  715. {
  716. CompileMasterNodeShader();
  717. continue;
  718. }
  719. var node = preview.shaderData.node;
  720. Assert.IsNotNull(node); // master preview is handled above
  721. // Get shader code and compile
  722. var generator = new Generator(node.owner, node, GenerationMode.Preview, $"hidden/preview/{node.GetVariableNameForNode()}");
  723. BeginCompile(preview, generator.generatedShader);
  724. }
  725. ShaderUtil.allowAsyncCompilation = wasAsyncAllowed;
  726. }
  727. }
  728. }
  729. private static readonly ProfilerMarker UpdateShadersMarker = new ProfilerMarker("UpdateShaders");
  730. void UpdateShaders()
  731. {
  732. using (UpdateShadersMarker.Auto())
  733. {
  734. ProcessCompletedShaderCompilations();
  735. if (m_NodesShaderChanged.Count > 0)
  736. {
  737. // nodes with shader changes cause all downstream nodes to need recompilation
  738. // (since they presumably include the code for these nodes)
  739. using (var nodesToRecompile = PooledHashSet<AbstractMaterialNode>.Get())
  740. {
  741. PropagateNodes(m_NodesShaderChanged, PropagationDirection.Downstream, nodesToRecompile);
  742. ForEachNodesPreview(nodesToRecompile, p => m_PreviewsNeedsRecompile.Add(p));
  743. m_NodesShaderChanged.Clear();
  744. }
  745. }
  746. // if there's nothing to update, or if too many nodes are still compiling, then just return
  747. if ((m_PreviewsNeedsRecompile.Count == 0) || (m_PreviewsCompiling.Count >= m_MaxPreviewsCompiling))
  748. return;
  749. // flag all nodes in m_PreviewsNeedsRecompile as having out of date textures, and redraw them
  750. foreach (var preview in m_PreviewsNeedsRecompile)
  751. {
  752. Assert.IsNotNull(preview);
  753. if (!preview.shaderData.isOutOfDate)
  754. {
  755. preview.shaderData.isOutOfDate = true;
  756. preview.NotifyPreviewChanged();
  757. }
  758. }
  759. InitializeSRPIfNeeded(); // SRP must be initialized to compile master node previews
  760. KickOffShaderCompilations();
  761. }
  762. }
  763. private static readonly ProfilerMarker BeginCompileMarker = new ProfilerMarker("BeginCompile");
  764. void BeginCompile(PreviewRenderData renderData, string shaderStr)
  765. {
  766. using (BeginCompileMarker.Auto())
  767. {
  768. var shaderData = renderData.shaderData;
  769. // want to ensure this so we don't get confused with multiple compile versions in flight
  770. Assert.IsTrue(shaderData.passesCompiling == 0);
  771. if (shaderData.shader == null)
  772. {
  773. shaderData.shader = ShaderUtil.CreateShaderAsset(shaderStr, false);
  774. shaderData.shader.hideFlags = HideFlags.HideAndDontSave;
  775. }
  776. else
  777. {
  778. ShaderUtil.ClearCachedData(shaderData.shader);
  779. ShaderUtil.ClearShaderMessages(shaderData.shader);
  780. ShaderUtil.UpdateShaderAsset(shaderData.shader, shaderStr, false);
  781. }
  782. // Set up the material we use for the preview
  783. // Due to case 1259744, we have to re-create the material to update the preview material keywords
  784. Object.DestroyImmediate(shaderData.mat);
  785. {
  786. shaderData.mat = new Material(shaderData.shader) { hideFlags = HideFlags.HideAndDontSave };
  787. if (renderData == m_MasterRenderData)
  788. {
  789. // apply active target settings to the Material
  790. foreach (var target in m_Graph.activeTargets)
  791. {
  792. if (target.IsActive())
  793. target.ProcessPreviewMaterial(renderData.shaderData.mat);
  794. }
  795. }
  796. }
  797. int materialPassCount = shaderData.mat.passCount;
  798. if (materialPassCount <= 0)
  799. Debug.Log("Zero Passes ON COMPILE: " + shaderData.node.name + " (" + shaderData.passesCompiling + " passes, " + renderData.shaderData.mat.passCount + " mat passes)");
  800. else
  801. {
  802. shaderData.passesCompiling = materialPassCount;
  803. for (var i = 0; i < materialPassCount; i++)
  804. {
  805. ShaderUtil.CompilePass(shaderData.mat, i);
  806. }
  807. m_PreviewsCompiling.Add(renderData);
  808. }
  809. }
  810. }
  811. private void ForEachNodesPreview(
  812. IEnumerable<AbstractMaterialNode> nodes,
  813. Action<PreviewRenderData> action)
  814. {
  815. foreach (var node in nodes)
  816. {
  817. var preview = GetPreviewRenderData(node);
  818. if (preview != null) // some output nodes may have no preview
  819. action(preview);
  820. }
  821. }
  822. class NodeProcessor
  823. {
  824. // parameters
  825. GraphData graphData;
  826. Action<AbstractMaterialNode, IEnumerable<AbstractMaterialNode>> process;
  827. // node tracking state
  828. HashSet<AbstractMaterialNode> processing = new HashSet<AbstractMaterialNode>();
  829. HashSet<AbstractMaterialNode> processed = new HashSet<AbstractMaterialNode>();
  830. // iteration state stack
  831. Stack<AbstractMaterialNode> nodeStack = new Stack<AbstractMaterialNode>();
  832. Stack<int> childStartStack = new Stack<int>();
  833. Stack<int> curChildStack = new Stack<int>();
  834. Stack<int> stateStack = new Stack<int>();
  835. List<AbstractMaterialNode> allChildren = new List<AbstractMaterialNode>();
  836. public NodeProcessor(GraphData graphData, Action<AbstractMaterialNode, IEnumerable<AbstractMaterialNode>> process)
  837. {
  838. this.graphData = graphData;
  839. this.process = process;
  840. }
  841. public void ProcessInDependencyOrder(AbstractMaterialNode root)
  842. {
  843. // early out to skip a bit of work
  844. if (processed.Contains(root))
  845. return;
  846. // push root node in the initial state
  847. stateStack.Push(0);
  848. nodeStack.Push(root);
  849. while (nodeStack.Count > 0)
  850. {
  851. // check the state of the top of the stack
  852. switch (stateStack.Pop())
  853. {
  854. case 0: // node initial state (valid stacks: nodeStack)
  855. {
  856. var node = nodeStack.Peek();
  857. if (processed.Contains(node))
  858. {
  859. // finished with this node, pop it off the stack
  860. nodeStack.Pop();
  861. continue;
  862. }
  863. if (processing.Contains(node))
  864. {
  865. // not processed, but still processing.. means there was a circular dependency here
  866. throw new ArgumentException("ERROR: graph contains circular wire connections");
  867. }
  868. processing.Add(node);
  869. int childStart = allChildren.Count;
  870. childStartStack.Push(childStart);
  871. // add immediate children
  872. ForeachConnectedNode(node, PropagationDirection.Upstream, n => allChildren.Add(n));
  873. if (allChildren.Count == childStart)
  874. {
  875. // no children.. transition to state 2 (all children processed)
  876. stateStack.Push(2);
  877. }
  878. else
  879. {
  880. // transition to state 1 (processing children)
  881. stateStack.Push(1);
  882. curChildStack.Push(childStart);
  883. }
  884. }
  885. break;
  886. case 1: // processing children (valid stacks: nodeStack, childStartStack, curChildStack)
  887. {
  888. int curChild = curChildStack.Pop();
  889. // first update our state for when we return from the cur child
  890. int nextChild = curChild + 1;
  891. if (nextChild < allChildren.Count)
  892. {
  893. // we will process the next child
  894. stateStack.Push(1);
  895. curChildStack.Push(nextChild);
  896. }
  897. else
  898. {
  899. // we will be done iterating children, move to state 2
  900. stateStack.Push(2);
  901. }
  902. // then push the current child in state 0 to process it
  903. stateStack.Push(0);
  904. nodeStack.Push(allChildren[curChild]);
  905. }
  906. break;
  907. case 2: // all children processed (valid stacks: nodeStack, childStartStack)
  908. {
  909. // read state, popping all
  910. var node = nodeStack.Pop();
  911. int childStart = childStartStack.Pop();
  912. // process node
  913. process(node, allChildren.Slice(childStart, allChildren.Count));
  914. processed.Add(node);
  915. // remove the children that were added in state 0
  916. allChildren.RemoveRange(childStart, allChildren.Count - childStart);
  917. // terminate node, stacks are popped to state of parent node
  918. }
  919. break;
  920. }
  921. }
  922. }
  923. public void ProcessInDependencyOrderRecursive(AbstractMaterialNode node)
  924. {
  925. if (processed.Contains(node))
  926. return; // already processed
  927. if (processing.Contains(node))
  928. throw new ArgumentException("ERROR: graph contains circular wire connections");
  929. processing.Add(node);
  930. int childStart = allChildren.Count;
  931. // add immediate children
  932. ForeachConnectedNode(node, PropagationDirection.Upstream, n => allChildren.Add(n));
  933. // process children
  934. var children = allChildren.Slice(childStart, allChildren.Count);
  935. foreach (var child in children)
  936. ProcessInDependencyOrderRecursive(child);
  937. // process self
  938. process(node, children);
  939. processed.Add(node);
  940. // remove the children
  941. allChildren.RemoveRange(childStart, allChildren.Count - childStart);
  942. }
  943. }
  944. // Processes all the nodes in the upstream trees of rootNodes
  945. // Will only process each node once, even if the trees overlap
  946. // Processes a node ONLY after processing all of the nodes in its upstream subtree
  947. void ProcessUpstreamNodesInDependencyOrder(
  948. IEnumerable<AbstractMaterialNode> rootNodes, // root nodes can share subtrees, but cannot themselves exist in any others subtree
  949. Action<AbstractMaterialNode, IEnumerable<AbstractMaterialNode>> process) // process takes the node and it's list of immediate upstream children as parameters
  950. {
  951. if (rootNodes.Any())
  952. {
  953. NodeProcessor processor = new NodeProcessor(rootNodes.First().owner, process);
  954. foreach (var node in rootNodes)
  955. processor.ProcessInDependencyOrderRecursive(node);
  956. }
  957. }
  958. private static readonly ProfilerMarker UpdateTopologyMarker = new ProfilerMarker("UpdateTopology");
  959. void UpdateTopology()
  960. {
  961. if (!m_TopologyDirty)
  962. return;
  963. using (UpdateTopologyMarker.Auto())
  964. using (var timedNodes = PooledHashSet<AbstractMaterialNode>.Get())
  965. {
  966. timedNodes.UnionWith(m_Graph.GetNodes<AbstractMaterialNode>().Where(n => n.RequiresTime()));
  967. // we pre-propagate timed nodes downstream, to reduce amount of propagation we have to do per frame
  968. PropagateNodes(timedNodes, PropagationDirection.Downstream, timedNodes);
  969. m_TimedPreviews.Clear();
  970. ForEachNodesPreview(timedNodes, p => m_TimedPreviews.Add(p));
  971. }
  972. // Calculate the PreviewMode from upstream nodes
  973. ProcessUpstreamNodesInDependencyOrder(
  974. // we just pass all the nodes we care about as the roots
  975. m_RenderDatas.Values.Select(p => p.shaderData.node).Where(n => n != null),
  976. (node, children) =>
  977. {
  978. var preview = GetPreviewRenderData(node);
  979. // set preview mode based on node preference
  980. preview.previewMode = node.previewMode;
  981. // Inherit becomes 2D or 3D based on child state
  982. if (preview.previewMode == PreviewMode.Inherit)
  983. {
  984. if (children.Any(child => GetPreviewRenderData(child).previewMode == PreviewMode.Preview3D))
  985. preview.previewMode = PreviewMode.Preview3D;
  986. else
  987. preview.previewMode = PreviewMode.Preview2D;
  988. }
  989. });
  990. m_TopologyDirty = false;
  991. }
  992. private static readonly ProfilerMarker RenderPreviewMarker = new ProfilerMarker("RenderPreview");
  993. void RenderPreview(PreviewRenderData renderData, Mesh mesh, Matrix4x4 transform, PooledList<PreviewProperty> perMaterialPreviewProperties)
  994. {
  995. using (RenderPreviewMarker.Auto())
  996. {
  997. var wasAsyncAllowed = ShaderUtil.allowAsyncCompilation;
  998. ShaderUtil.allowAsyncCompilation = true;
  999. AssignPerMaterialPreviewProperties(renderData.shaderData.mat, perMaterialPreviewProperties);
  1000. var previousRenderTexture = RenderTexture.active;
  1001. //Temp workaround for alpha previews...
  1002. var temp = RenderTexture.GetTemporary(renderData.renderTexture.descriptor);
  1003. RenderTexture.active = temp;
  1004. Graphics.Blit(Texture2D.whiteTexture, temp, m_SceneResources.checkerboardMaterial);
  1005. // Mesh is invalid for VFXTarget
  1006. // We should handle this more gracefully
  1007. if (renderData != m_MasterRenderData || !m_Graph.isOnlyVFXTarget)
  1008. {
  1009. m_SceneResources.camera.targetTexture = temp;
  1010. Graphics.DrawMesh(mesh, transform, renderData.shaderData.mat, 1, m_SceneResources.camera, 0, m_SharedPreviewPropertyBlock, ShadowCastingMode.Off, false, null, false);
  1011. }
  1012. var previousUseSRP = Unsupported.useScriptableRenderPipeline;
  1013. Unsupported.useScriptableRenderPipeline = (renderData == m_MasterRenderData);
  1014. m_SceneResources.camera.Render();
  1015. Unsupported.useScriptableRenderPipeline = previousUseSRP;
  1016. Graphics.Blit(temp, renderData.renderTexture, m_SceneResources.blitNoAlphaMaterial);
  1017. RenderTexture.ReleaseTemporary(temp);
  1018. RenderTexture.active = previousRenderTexture;
  1019. renderData.texture = renderData.renderTexture;
  1020. m_PreviewsToDraw.Remove(renderData);
  1021. ShaderUtil.allowAsyncCompilation = wasAsyncAllowed;
  1022. }
  1023. }
  1024. void InitializeSRPIfNeeded()
  1025. {
  1026. if ((Shader.globalRenderPipeline != null) && (Shader.globalRenderPipeline.Length > 0))
  1027. {
  1028. return;
  1029. }
  1030. // issue a dummy SRP render to force SRP initialization, use the master node texture
  1031. PreviewRenderData renderData = m_MasterRenderData;
  1032. var previousRenderTexture = RenderTexture.active;
  1033. //Temp workaround for alpha previews...
  1034. var temp = RenderTexture.GetTemporary(renderData.renderTexture.descriptor);
  1035. RenderTexture.active = temp;
  1036. Graphics.Blit(Texture2D.whiteTexture, temp, m_SceneResources.checkerboardMaterial);
  1037. m_SceneResources.camera.targetTexture = temp;
  1038. var previousUseSRP = Unsupported.useScriptableRenderPipeline;
  1039. Unsupported.useScriptableRenderPipeline = true;
  1040. m_SceneResources.camera.Render();
  1041. Unsupported.useScriptableRenderPipeline = previousUseSRP;
  1042. RenderTexture.ReleaseTemporary(temp);
  1043. RenderTexture.active = previousRenderTexture;
  1044. }
  1045. void CheckForErrors(PreviewShaderData shaderData)
  1046. {
  1047. shaderData.hasError = ShaderUtil.ShaderHasError(shaderData.shader);
  1048. if (shaderData.hasError)
  1049. {
  1050. var messages = ShaderUtil.GetShaderMessages(shaderData.shader);
  1051. if (messages.Length > 0)
  1052. {
  1053. // TODO: Where to add errors to the stack??
  1054. if (shaderData.node == null)
  1055. return;
  1056. m_Messenger.AddOrAppendError(this, shaderData.node.objectId, messages[0]);
  1057. ShaderUtil.ClearShaderMessages(shaderData.shader);
  1058. }
  1059. }
  1060. }
  1061. void CompileMasterNodeShader()
  1062. {
  1063. var shaderData = masterRenderData?.shaderData;
  1064. // Skip generation for VFXTarget
  1065. if (!m_Graph.isOnlyVFXTarget)
  1066. {
  1067. var generator = new Generator(m_Graph, m_Graph.outputNode, GenerationMode.Preview, "Master");
  1068. shaderData.shaderString = generator.generatedShader;
  1069. // record the blocks temporarily created for missing stack blocks
  1070. m_MasterNodeTempBlocks.Clear();
  1071. foreach (var block in generator.temporaryBlocks)
  1072. {
  1073. m_MasterNodeTempBlocks.Add(block);
  1074. }
  1075. }
  1076. if (string.IsNullOrEmpty(shaderData.shaderString))
  1077. {
  1078. if (shaderData.shader != null)
  1079. {
  1080. ShaderUtil.ClearShaderMessages(shaderData.shader);
  1081. Object.DestroyImmediate(shaderData.shader, true);
  1082. shaderData.shader = null;
  1083. }
  1084. return;
  1085. }
  1086. BeginCompile(masterRenderData, shaderData.shaderString);
  1087. }
  1088. void DestroyRenderData(PreviewRenderData renderData)
  1089. {
  1090. if (renderData.shaderData != null)
  1091. {
  1092. if (renderData.shaderData.mat != null)
  1093. {
  1094. Object.DestroyImmediate(renderData.shaderData.mat, true);
  1095. }
  1096. if (renderData.shaderData.shader != null)
  1097. {
  1098. ShaderUtil.ClearShaderMessages(renderData.shaderData.shader);
  1099. Object.DestroyImmediate(renderData.shaderData.shader, true);
  1100. }
  1101. }
  1102. // Clear render textures
  1103. if (renderData.renderTexture != null)
  1104. Object.DestroyImmediate(renderData.renderTexture, true);
  1105. if(renderData.texture != null)
  1106. Object.DestroyImmediate(renderData.texture, true);
  1107. // Clear callbacks
  1108. renderData.onPreviewChanged = null;
  1109. if (renderData.shaderData != null && renderData.shaderData.node != null)
  1110. renderData.shaderData.node.UnregisterCallback(OnNodeModified);
  1111. }
  1112. void DestroyPreview(AbstractMaterialNode node)
  1113. {
  1114. if (node is BlockNode)
  1115. {
  1116. // block nodes don't have preview render data
  1117. Assert.IsFalse(m_RenderDatas.ContainsKey(node));
  1118. node.UnregisterCallback(OnNodeModified);
  1119. UpdateMasterPreview(ModificationScope.Topological);
  1120. return;
  1121. }
  1122. if (!m_RenderDatas.TryGetValue(node, out var renderData))
  1123. {
  1124. return;
  1125. }
  1126. m_PreviewsNeedsRecompile.Remove(renderData);
  1127. m_PreviewsCompiling.Remove(renderData);
  1128. m_PreviewsToDraw.Remove(renderData);
  1129. m_TimedPreviews.Remove(renderData);
  1130. DestroyRenderData(renderData);
  1131. m_RenderDatas.Remove(node);
  1132. }
  1133. void ReleaseUnmanagedResources()
  1134. {
  1135. if (m_ErrorTexture != null)
  1136. {
  1137. Object.DestroyImmediate(m_ErrorTexture);
  1138. m_ErrorTexture = null;
  1139. }
  1140. if (m_SceneResources != null)
  1141. {
  1142. m_SceneResources.Dispose();
  1143. m_SceneResources = null;
  1144. }
  1145. foreach (var renderData in m_RenderDatas.Values)
  1146. DestroyRenderData(renderData);
  1147. m_RenderDatas.Clear();
  1148. m_SharedPreviewPropertyBlock.Clear();
  1149. }
  1150. public void Dispose()
  1151. {
  1152. ReleaseUnmanagedResources();
  1153. GC.SuppressFinalize(this);
  1154. }
  1155. ~PreviewManager()
  1156. {
  1157. throw new Exception("PreviewManager was not disposed of properly.");
  1158. }
  1159. }
  1160. delegate void OnPreviewChanged();
  1161. class PreviewShaderData
  1162. {
  1163. public AbstractMaterialNode node;
  1164. public Shader shader;
  1165. public Material mat;
  1166. public string shaderString;
  1167. public int passesCompiling;
  1168. public bool isOutOfDate;
  1169. public bool hasError;
  1170. }
  1171. class PreviewRenderData
  1172. {
  1173. public string previewName;
  1174. public PreviewShaderData shaderData;
  1175. public RenderTexture renderTexture;
  1176. public Texture texture;
  1177. public PreviewMode previewMode;
  1178. public OnPreviewChanged onPreviewChanged;
  1179. public void NotifyPreviewChanged()
  1180. {
  1181. if (onPreviewChanged != null)
  1182. onPreviewChanged();
  1183. }
  1184. }
  1185. }