UnityGame/Library/PackageCache/com.unity.shadergraph/Editor/Data/SubGraph/SubGraphAsset.cs

258 lines
9.9 KiB
C#
Raw Normal View History

2024-10-27 10:53:47 +03:00
using System;
using System.Collections.Generic;
#if UNITY_2020_2_OR_NEWER
using UnityEditor.AssetImporters;
#else
using UnityEditor.Experimental.AssetImporters;
#endif
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph.Internal;
using UnityEditor.ShaderGraph.Serialization;
using UnityEngine;
namespace UnityEditor.ShaderGraph
{
[Serializable]
struct FunctionPair
{
public string key; // aka function name
public string value; // aka function code
public int graphPrecisionFlags; // Flags<GraphPrecision> indicating which precision variants are requested by the subgraph
public FunctionPair(string key, string value, int graphPrecisionFlags)
{
this.key = key;
this.value = value;
this.graphPrecisionFlags = graphPrecisionFlags;
}
}
[Serializable]
class SlotCapability
{
public string slotName;
public ShaderStageCapability capabilities = ShaderStageCapability.All;
}
[Serializable]
class SlotDependencyPair
{
public string inputSlotName;
public string outputSlotName;
}
/// Cached run-time information for slot dependency tracking within a sub-graph
class SlotDependencyInfo
{
internal string slotName;
internal ShaderStageCapability capabilities = ShaderStageCapability.All;
internal HashSet<string> dependencies = new HashSet<string>();
internal void AddDepencencySlotName(string slotName)
{
dependencies.Add(slotName);
}
internal bool ContainsSlot(MaterialSlot slot)
{
return dependencies.Contains(slot.RawDisplayName());
}
}
class SubGraphData : JsonObject
{
public List<JsonData<AbstractShaderProperty>> inputs = new List<JsonData<AbstractShaderProperty>>();
public List<JsonData<ShaderKeyword>> keywords = new List<JsonData<ShaderKeyword>>();
public List<JsonData<ShaderDropdown>> dropdowns = new List<JsonData<ShaderDropdown>>();
public List<JsonData<AbstractShaderProperty>> nodeProperties = new List<JsonData<AbstractShaderProperty>>();
public List<JsonData<MaterialSlot>> outputs = new List<JsonData<MaterialSlot>>();
public List<JsonData<Target>> unsupportedTargets = new List<JsonData<Target>>();
}
class SubGraphAsset : ScriptableObject, ISerializationCallbackReceiver
{
public bool isValid;
public long processedAt;
public string functionName;
public string inputStructName;
public string hlslName;
public string assetGuid;
public ShaderGraphRequirements requirements;
public string path;
public List<FunctionPair> functions = new List<FunctionPair>();
public IncludeCollection includes;
public List<string> vtFeedbackVariables = new List<string>();
private SubGraphData m_SubGraphData;
[HideInInspector]
[SerializeField]
private SerializationHelper.JSONSerializedElement m_SerializedSubGraphData;
public DataValueEnumerable<AbstractShaderProperty> inputs => m_SubGraphData.inputs.SelectValue();
public DataValueEnumerable<ShaderKeyword> keywords => m_SubGraphData.keywords.SelectValue();
public DataValueEnumerable<ShaderDropdown> dropdowns => m_SubGraphData.dropdowns.SelectValue();
public DataValueEnumerable<AbstractShaderProperty> nodeProperties => m_SubGraphData.nodeProperties.SelectValue();
public DataValueEnumerable<MaterialSlot> outputs => m_SubGraphData.outputs.SelectValue();
public DataValueEnumerable<Target> unsupportedTargets => m_SubGraphData.unsupportedTargets.SelectValue();
public List<string> children = new List<string>(); // guids of direct USED SUBGRAPH file dependencies
public List<string> descendents = new List<string>(); // guids of ALL file dependencies at any level, SHOULD LIST EVEN MISSING DESCENDENTS
public List<SlotCapability> inputCapabilities = new List<SlotCapability>();
public List<SlotCapability> outputCapabilities = new List<SlotCapability>();
// Every unique input/output dependency pair
public List<SlotDependencyPair> slotDependencies = new List<SlotDependencyPair>();
Dictionary<string, SlotDependencyInfo> m_InputDependencies = new Dictionary<string, SlotDependencyInfo>();
Dictionary<string, SlotDependencyInfo> m_OutputDependencies = new Dictionary<string, SlotDependencyInfo>();
public SlotDependencyInfo GetInputDependencies(string slotName)
{
m_InputDependencies.TryGetValue(slotName, out SlotDependencyInfo result);
return result;
}
public SlotDependencyInfo GetOutputDependencies(string slotName)
{
m_OutputDependencies.TryGetValue(slotName, out SlotDependencyInfo result);
return result;
}
// this is the precision that the entire subgraph is set to (indicates whether the graph is hard-coded or switchable)
public GraphPrecision subGraphGraphPrecision;
// this is the precision of the subgraph outputs
// NOTE: this may not be the same as subGraphGraphPrecision
// for example, a graph could allow switching precisions for internal calculations,
// but the output of the graph is always full float
// NOTE: we don't currently have a way to select the graph precision for EACH output
// there's a single shared precision for all of them
public GraphPrecision outputGraphPrecision;
public PreviewMode previewMode;
public void WriteData(IEnumerable<AbstractShaderProperty> inputs, IEnumerable<ShaderKeyword> keywords, IEnumerable<ShaderDropdown> dropdowns, IEnumerable<AbstractShaderProperty> nodeProperties, IEnumerable<MaterialSlot> outputs, IEnumerable<Target> unsupportedTargets)
{
if (m_SubGraphData == null)
{
m_SubGraphData = new SubGraphData();
m_SubGraphData.OverrideObjectId(assetGuid, "_subGraphData");
}
m_SubGraphData.inputs.Clear();
m_SubGraphData.keywords.Clear();
m_SubGraphData.dropdowns.Clear();
m_SubGraphData.nodeProperties.Clear();
m_SubGraphData.outputs.Clear();
m_SubGraphData.unsupportedTargets.Clear();
foreach (var input in inputs)
{
m_SubGraphData.inputs.Add(input);
}
foreach (var keyword in keywords)
{
m_SubGraphData.keywords.Add(keyword);
}
foreach (var dropdown in dropdowns)
{
m_SubGraphData.dropdowns.Add(dropdown);
}
foreach (var nodeProperty in nodeProperties)
{
m_SubGraphData.nodeProperties.Add(nodeProperty);
}
foreach (var output in outputs)
{
m_SubGraphData.outputs.Add(output);
}
foreach (var unsupportedTarget in unsupportedTargets)
{
m_SubGraphData.unsupportedTargets.Add(unsupportedTarget);
}
var json = MultiJson.Serialize(m_SubGraphData);
m_SerializedSubGraphData = new SerializationHelper.JSONSerializedElement() { JSONnodeData = json };
m_SubGraphData = null;
}
public void OnBeforeSerialize()
{
}
public void OnAfterDeserialize()
{
}
public void LoadGraphData()
{
m_SubGraphData = new SubGraphData();
if (!String.IsNullOrEmpty(m_SerializedSubGraphData.JSONnodeData))
{
MultiJson.Deserialize(m_SubGraphData, m_SerializedSubGraphData.JSONnodeData);
}
}
internal void LoadDependencyData()
{
m_InputDependencies.Clear();
m_OutputDependencies.Clear();
foreach (var capabilityInfo in inputCapabilities)
{
var dependencyInfo = new SlotDependencyInfo();
dependencyInfo.slotName = capabilityInfo.slotName;
dependencyInfo.capabilities = capabilityInfo.capabilities;
if (m_InputDependencies.ContainsKey(dependencyInfo.slotName))
{
Debug.LogWarning($"SubGraph '{hlslName}' has multiple input slots named '{dependencyInfo.slotName}', which is unsupported. Please assign the input slots unique names.");
continue;
}
m_InputDependencies.Add(dependencyInfo.slotName, dependencyInfo);
}
foreach (var capabilityInfo in outputCapabilities)
{
var dependencyInfo = new SlotDependencyInfo();
dependencyInfo.slotName = capabilityInfo.slotName;
dependencyInfo.capabilities = capabilityInfo.capabilities;
if (m_OutputDependencies.ContainsKey(dependencyInfo.slotName))
{
Debug.LogWarning($"SubGraph '{hlslName}' has multiple output slots named '{dependencyInfo.slotName}', which is unsupported. Please assign the output slots unique names.");
continue;
}
m_OutputDependencies.Add(dependencyInfo.slotName, dependencyInfo);
}
foreach (var slotDependency in slotDependencies)
{
// This shouldn't fail since every input/output must be in the above lists...
if (m_InputDependencies.ContainsKey(slotDependency.inputSlotName))
m_InputDependencies[slotDependency.inputSlotName].AddDepencencySlotName(slotDependency.outputSlotName);
if (m_OutputDependencies.ContainsKey(slotDependency.outputSlotName))
m_OutputDependencies[slotDependency.outputSlotName].AddDepencencySlotName(slotDependency.inputSlotName);
}
}
}
}