Пример #1
0
        public static int GetKeywordPermutationCount(this GraphData graph)
        {
            // Gather all unique keywords from the Graph including Sub Graphs
            IEnumerable <ShaderKeyword> allKeywords = graph.keywords;
            var subGraphNodes = graph.GetNodes <SubGraphNode>();

            foreach (SubGraphNode subGraphNode in subGraphNodes)
            {
                if (subGraphNode.asset == null)
                {
                    continue;
                }
                allKeywords = allKeywords.Union(subGraphNode.asset.keywords);
            }
            allKeywords = allKeywords.Distinct();

            // Get permutation count for all Keywords
            int permutationCount = 1;

            foreach (ShaderKeyword keyword in allKeywords)
            {
                if (keyword.keywordType == KeywordType.Boolean)
                {
                    permutationCount *= 2;
                }
                else
                {
                    permutationCount *= keyword.entries.Count;
                }
            }

            return(permutationCount);
        }
Пример #2
0
        static void CollectInputCapabilities(SubGraphAsset asset, GraphData graph)
        {
            // Collect each input's capabilities. There can be multiple property nodes
            // contributing to the same input, so we cache these in a map while building
            var inputCapabilities = new Dictionary <string, SlotCapability>();

            // Walk all property node output slots, computing and caching the capabilities for that slot
            var propertyNodes = graph.GetNodes <PropertyNode>();

            foreach (var propertyNode in propertyNodes)
            {
                foreach (var slot in propertyNode.GetOutputSlots <MaterialSlot>())
                {
                    var            slotName = slot.RawDisplayName();
                    SlotCapability capabilityInfo;
                    if (!inputCapabilities.TryGetValue(slotName, out capabilityInfo))
                    {
                        capabilityInfo          = new SlotCapability();
                        capabilityInfo.slotName = slotName;
                        inputCapabilities.Add(propertyNode.property.displayName, capabilityInfo);
                    }
                    capabilityInfo.capabilities &= NodeUtils.GetEffectiveShaderStageCapability(slot, false);
                }
            }
            asset.inputCapabilities.AddRange(inputCapabilities.Values);
        }
Пример #3
0
            public static void ApplyActionLeafFirst(GraphData graph, Action <AbstractMaterialNode> action)
            {
                var temporaryMarks = PooledHashSet <string> .Get();

                var permanentMarks = PooledHashSet <string> .Get();

                var slots = ListPool <MaterialSlot> .Get();

                // Make sure we process a node's children before the node itself.
                var stack = StackPool <AbstractMaterialNode> .Get();

                foreach (var node in graph.GetNodes <AbstractMaterialNode>())
                {
                    stack.Push(node);
                }
                while (stack.Count > 0)
                {
                    var node = stack.Pop();
                    if (permanentMarks.Contains(node.objectId))
                    {
                        continue;
                    }

                    if (temporaryMarks.Contains(node.objectId))
                    {
                        action.Invoke(node);
                        permanentMarks.Add(node.objectId);
                    }
                    else
                    {
                        temporaryMarks.Add(node.objectId);
                        stack.Push(node);
                        node.GetInputSlots(slots);
                        foreach (var inputSlot in slots)
                        {
                            var nodeEdges = graph.GetEdges(inputSlot.slotReference);
                            foreach (var edge in nodeEdges)
                            {
                                var fromSocketRef = edge.outputSlot;
                                var childNode     = fromSocketRef.node;
                                if (childNode != null)
                                {
                                    stack.Push(childNode);
                                }
                            }
                        }
                        slots.Clear();
                    }
                }

                StackPool <AbstractMaterialNode> .Release(stack);

                ListPool <MaterialSlot> .Release(slots);

                temporaryMarks.Dispose();
                permanentMarks.Dispose();
            }
Пример #4
0
            public static void ConcretizeProperties(GraphData graph)
            {
                var propertyNodes = graph.GetNodes <PropertyNode>().Where(n => !graph.m_Properties.Any(p => p.guid == n.propertyGuid)).ToArray();

                foreach (var pNode in propertyNodes)
                {
                    graph.ReplacePropertyNodeWithConcreteNodeNoValidate(pNode);
                }
            }
Пример #5
0
        void Generate(GenerationMode mode, string name, AssetCollection assetCollection, Target[] targets)
        {
            m_Mode = mode;
            m_Name = name;

            m_Builder            = new ShaderStringBuilder();
            m_ConfiguredTextures = new List <PropertyCollector.TextureInfo>();
            m_assetCollection    = assetCollection;

            m_ActiveBlocks    = m_GraphData.GetNodes <BlockNode>().ToList();
            m_TemporaryBlocks = new List <BlockNode>();
            m_Targets         = targets;
            BuildShader();
        }
        internal static void SendShaderGraphEvent(string assetGuid, GraphData graph)
        {
            //The event shouldn't be able to report if this is disabled but if we know we're not going to report
            //Lets early out and not waste time gathering all the data
            if (!EditorAnalytics.enabled)
            {
                return;
            }

            if (!EnableAnalytics())
            {
                return;
            }

            Dictionary <string, int> nodeTypeAndCount = new Dictionary <string, int>();
            var nodes = graph.GetNodes <AbstractMaterialNode>();

            int subgraphCount = 0;

            foreach (var materialNode in nodes)
            {
                string nType = materialNode.GetType().ToString().Split('.').Last();

                if (nType == "SubGraphNode")
                {
                    subgraphCount += 1;
                }

                if (!nodeTypeAndCount.ContainsKey(nType))
                {
                    nodeTypeAndCount[nType] = 1;
                }
                else
                {
                    nodeTypeAndCount[nType] += 1;
                }
            }
            var jsonRepr = DictionaryToJson(nodeTypeAndCount);

            var data = new AnalyticsData()
            {
                nodes          = jsonRepr,
                node_count     = nodes.Count(),
                asset_guid     = assetGuid,
                subgraph_count = subgraphCount
            };

            EditorAnalytics.SendEventWithLimit(k_EventName, data);
        }
Пример #7
0
        public Generator(GraphData graphData, AbstractMaterialNode outputNode, GenerationMode mode, string name, AssetCollection assetCollection)
        {
            m_GraphData  = graphData;
            m_OutputNode = outputNode;
            m_Mode       = mode;
            m_Name       = name;

            m_Builder            = new ShaderStringBuilder();
            m_ConfiguredTextures = new List <PropertyCollector.TextureInfo>();
            m_assetCollection    = assetCollection;

            m_Blocks = graphData.GetNodes <BlockNode>().ToList();
            GetTargetImplementations();
            BuildShader();
        }
Пример #8
0
        static string GetShaderText(string path, out List <PropertyCollector.TextureInfo> configuredTextures, List <string> sourceAssetDependencyPaths, out GraphData graph)
        {
            graph = null;
            string shaderString = null;
            var    shaderName   = Path.GetFileNameWithoutExtension(path);

            try
            {
                var textGraph = File.ReadAllText(path, Encoding.UTF8);
                graph = JsonUtility.FromJson <GraphData>(textGraph);
                graph.messageManager = new MessageManager();
                graph.assetGuid      = AssetDatabase.AssetPathToGUID(path);
                graph.OnEnable();
                graph.ValidateGraph();

                if (!string.IsNullOrEmpty(graph.path))
                {
                    shaderName = graph.path + "/" + shaderName;
                }
                shaderString = ((IMasterNode)graph.outputNode).GetShader(GenerationMode.ForReals, shaderName, out configuredTextures, sourceAssetDependencyPaths);

                if (sourceAssetDependencyPaths != null)
                {
                    foreach (var node in graph.GetNodes <AbstractMaterialNode>())
                    {
                        node.GetSourceAssetDependencies(sourceAssetDependencyPaths);
                    }
                }

                if (graph.messageManager.nodeMessagesChanged)
                {
                    shaderString = null;
                }
            }
            catch (Exception)
            {
                configuredTextures = new List <PropertyCollector.TextureInfo>();

                // ignored
            }

            return(shaderString ?? k_ErrorShader.Replace("Hidden/GraphErrorShader2", shaderName));
        }
Пример #9
0
        public void ReplaceWith(GraphData other)
        {
            if (other == null)
            {
                throw new ArgumentException("Can only replace with another AbstractMaterialGraph", "other");
            }

            using (var removedPropertiesPooledObject = ListPool <Guid> .GetDisposable())
            {
                var removedPropertyGuids = removedPropertiesPooledObject.value;
                foreach (var property in m_Properties)
                {
                    removedPropertyGuids.Add(property.guid);
                }
                foreach (var propertyGuid in removedPropertyGuids)
                {
                    RemoveShaderPropertyNoValidate(propertyGuid);
                }
            }
            foreach (var otherProperty in other.properties)
            {
                if (!properties.Any(p => p.guid == otherProperty.guid))
                {
                    AddShaderProperty(otherProperty);
                }
            }

            other.ValidateGraph();
            ValidateGraph();

            // Current tactic is to remove all nodes and edges and then re-add them, such that depending systems
            // will re-initialize with new references.

            using (var removedGroupsPooledObject = ListPool <GroupData> .GetDisposable())
            {
                var removedGroupDatas = removedGroupsPooledObject.value;
                removedGroupDatas.AddRange(m_Groups);
                foreach (var groupData in removedGroupDatas)
                {
                    RemoveGroupNoValidate(groupData);
                }
            }

            using (var pooledList = ListPool <IEdge> .GetDisposable())
            {
                var removedNodeEdges = pooledList.value;
                removedNodeEdges.AddRange(m_Edges);
                foreach (var edge in removedNodeEdges)
                {
                    RemoveEdgeNoValidate(edge);
                }
            }

            using (var removedNodesPooledObject = ListPool <Guid> .GetDisposable())
            {
                var removedNodeGuids = removedNodesPooledObject.value;
                removedNodeGuids.AddRange(m_Nodes.Where(n => n != null).Select(n => n.guid));
                foreach (var nodeGuid in removedNodeGuids)
                {
                    RemoveNodeNoValidate(m_NodeDictionary[nodeGuid]);
                }
            }

            ValidateGraph();

            foreach (GroupData groupData in other.groups)
            {
                AddGroup(groupData);
            }

            foreach (var node in other.GetNodes <AbstractMaterialNode>())
            {
                AddNodeNoValidate(node);
            }

            foreach (var edge in other.edges)
            {
                ConnectNoValidate(edge.outputSlot, edge.inputSlot);
            }

            ValidateGraph();
        }
Пример #10
0
        public override void OnImportAsset(AssetImportContext ctx)
        {
            var currentTime = DateTime.Now.Ticks;

            if (ctx.assetPath != path)
            {
                ctx.LogImportError("The sgpostsubgraph extension may only be used internally by Shader Graph.");
                return;
            }

            if (SubGraphDatabase.instance == null)
            {
                SubGraphDatabase.instance = ScriptableObject.CreateInstance <SubGraphDatabase>();
            }
            var database = SubGraphDatabase.instance;

            var allSubGraphGuids = AssetDatabase.FindAssets($"t:{nameof(SubGraphAsset)}").ToList();

            allSubGraphGuids.Sort();
            var subGraphMap  = new Dictionary <string, SubGraphData>();
            var graphDataMap = new Dictionary <string, GraphData>();

            foreach (var subGraphData in database.subGraphs)
            {
                if (allSubGraphGuids.BinarySearch(subGraphData.assetGuid) >= 0)
                {
                    subGraphMap.Add(subGraphData.assetGuid, subGraphData);
                }
            }

            var dirtySubGraphGuids = new List <string>();

            foreach (var subGraphGuid in allSubGraphGuids)
            {
                var subGraphAsset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(subGraphGuid));
                if (!subGraphMap.TryGetValue(subGraphGuid, out var subGraphData))
                {
                    subGraphData = new SubGraphData();
                }

                if (subGraphAsset.importedAt > subGraphData.processedAt)
                {
                    dirtySubGraphGuids.Add(subGraphGuid);
                    subGraphData.Reset();
                    subGraphData.processedAt = currentTime;
                    var subGraphPath = AssetDatabase.GUIDToAssetPath(subGraphGuid);
                    var textGraph    = File.ReadAllText(subGraphPath, Encoding.UTF8);
                    var graphData    = new GraphData {
                        isSubGraph = true, assetGuid = subGraphGuid
                    };
                    JsonUtility.FromJsonOverwrite(textGraph, graphData);
                    subGraphData.children.AddRange(graphData.GetNodes <SubGraphNode>().Select(x => x.subGraphGuid).Distinct());
                    subGraphData.assetGuid     = subGraphGuid;
                    subGraphMap[subGraphGuid]  = subGraphData;
                    graphDataMap[subGraphGuid] = graphData;
                }
                else
                {
                    subGraphData.ancestors.Clear();
                    subGraphData.descendents.Clear();
                    subGraphData.isRecursive = false;
                }
            }

            database.subGraphs.Clear();
            database.subGraphs.AddRange(subGraphMap.Values);
            database.subGraphs.Sort((s1, s2) => s1.assetGuid.CompareTo(s2.assetGuid));
            database.subGraphGuids.Clear();
            database.subGraphGuids.AddRange(database.subGraphs.Select(x => x.assetGuid));

            var permanentMarks = new HashSet <string>();
            var stack          = new Stack <string>(allSubGraphGuids.Count);

            // Detect recursion, and populate `ancestors` and `descendents` per sub graph.
            foreach (var rootSubGraphData in database.subGraphs)
            {
                var rootSubGraphGuid = rootSubGraphData.assetGuid;
                stack.Push(rootSubGraphGuid);
                while (stack.Count > 0)
                {
                    var subGraphGuid = stack.Pop();
                    if (!permanentMarks.Add(subGraphGuid))
                    {
                        continue;
                    }

                    var subGraphData = subGraphMap[subGraphGuid];
                    if (subGraphData != rootSubGraphData)
                    {
                        subGraphData.ancestors.Add(rootSubGraphGuid);
                        rootSubGraphData.descendents.Add(subGraphGuid);
                    }
                    foreach (var childSubGraphGuid in subGraphData.children)
                    {
                        if (childSubGraphGuid == rootSubGraphGuid)
                        {
                            rootSubGraphData.isRecursive = true;
                        }
                        else if (subGraphMap.ContainsKey(childSubGraphGuid))
                        {
                            stack.Push(childSubGraphGuid);
                        }
                    }
                }
                permanentMarks.Clear();
            }

            // Next up we build a list of sub graphs to be processed, which will later be sorted topologically.
            var sortedSubGraphs = new List <SubGraphData>();

            foreach (var subGraphGuid in dirtySubGraphGuids)
            {
                var subGraphData = subGraphMap[subGraphGuid];
                if (permanentMarks.Add(subGraphGuid))
                {
                    sortedSubGraphs.Add(subGraphData);
                }

                // Note that we're traversing up the graph via ancestors rather than descendents, because all Sub Graphs using the current sub graph needs to be re-processed.
                foreach (var ancestorGuid in subGraphData.ancestors)
                {
                    if (permanentMarks.Add(ancestorGuid))
                    {
                        var ancestorSubGraphData = subGraphMap[ancestorGuid];
                        sortedSubGraphs.Add(ancestorSubGraphData);
                    }
                }
            }
            permanentMarks.Clear();

            // Sort topologically. At this stage we can assume there are no loops because all recursive sub graphs have been filtered out.
            sortedSubGraphs.Sort((s1, s2) => s1.descendents.Contains(s2.assetGuid) ? 1 : s2.descendents.Contains(s1.assetGuid) ? -1 : 0);

            // Finally process the topologically sorted sub graphs without recursion.
            var registry       = new FunctionRegistry(new ShaderStringBuilder(), true);
            var messageManager = new MessageManager();

            foreach (var subGraphData in sortedSubGraphs)
            {
                try
                {
                    var subGraphPath = AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid);
                    if (!graphDataMap.TryGetValue(subGraphData.assetGuid, out var graphData))
                    {
                        var textGraph = File.ReadAllText(subGraphPath, Encoding.UTF8);
                        graphData = new GraphData {
                            isSubGraph = true, assetGuid = subGraphData.assetGuid
                        };
                        JsonUtility.FromJsonOverwrite(textGraph, graphData);
                    }

                    graphData.messageManager = messageManager;
                    ProcessSubGraph(subGraphMap, registry, subGraphData, graphData);
                    if (messageManager.nodeMessagesChanged)
                    {
                        var subGraphAsset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid));
                        foreach (var pair in messageManager.GetNodeMessages())
                        {
                            var node = graphData.GetNodeFromTempId(pair.Key);
                            foreach (var message in pair.Value)
                            {
                                MessageManager.Log(node, subGraphPath, message, subGraphAsset);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    subGraphData.isValid = false;
                    var subGraphAsset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid));
                    Debug.LogException(e, subGraphAsset);
                }
                finally
                {
                    subGraphData.processedAt = currentTime;
                    messageManager.ClearAll();
                }
            }

            // Carry over functions used by sub-graphs that were not re-processed in this import.
            foreach (var subGraphData in database.subGraphs)
            {
                foreach (var functionName in subGraphData.functionNames)
                {
                    if (!registry.sources.ContainsKey(functionName))
                    {
                        registry.sources.Add(functionName, database.functionSources[database.functionNames.BinarySearch(functionName)]);
                    }
                }
            }

            var functions = registry.sources.ToList();

            functions.Sort((p1, p2) => p1.Key.CompareTo(p2.Key));
            database.functionNames.Clear();
            database.functionSources.Clear();
            foreach (var pair in functions)
            {
                database.functionNames.Add(pair.Key);
                database.functionSources.Add(pair.Value);
            }

            ctx.AddObjectToAsset("MainAsset", database);
            ctx.SetMainObject(database);

            SubGraphDatabase.instance = null;
        }