You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
9.9 KiB
256 lines
9.9 KiB
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; |
|
|
|
[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); |
|
} |
|
} |
|
} |
|
}
|
|
|