A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using UnityEngine;
4
5namespace UnityEditor.ShaderGraph.Internal
6{
7 [Serializable]
8 public abstract class AbstractShaderProperty : ShaderInput
9 {
10 public abstract PropertyType propertyType { get; }
11
12 internal override ConcreteSlotValueType concreteShaderValueType => propertyType.ToConcreteShaderValueType();
13
14 // user selected precision setting
15 [SerializeField]
16 Precision m_Precision = Precision.Inherit;
17
18 [Obsolete("AbstractShaderProperty.gpuInstanced is no longer used")]
19 public bool gpuInstanced
20 {
21 get { return false; }
22 set { }
23 }
24
25 internal virtual string GetHLSLVariableName(bool isSubgraphProperty, GenerationMode mode)
26 {
27 if (mode == GenerationMode.VFX)
28 {
29 // Per-element exposed properties are provided by the properties structure filled by VFX.
30 if (overrideHLSLDeclaration && hlslDeclarationOverride != HLSLDeclaration.Global)
31 return $"PROP.{referenceName}";
32 // For un-exposed global properties, just read from the cbuffer.
33 else
34 return referenceName;
35 }
36
37 return referenceName;
38 }
39
40 internal string GetConnectionStateHLSLVariableName()
41 {
42 return GetConnectionStateVariableName(referenceName + "_" + objectId);
43 }
44
45 // NOTE: this does not tell you the HLSLDeclaration of the entire property...
46 // instead, it tells you what the DEFAULT HLSL Declaration would be, IF the property makes use of the default
47 // to check ACTUAL HLSL Declaration types, enumerate the HLSL Properties and check their HLSLDeclarations...
48 internal virtual HLSLDeclaration GetDefaultHLSLDeclaration()
49 {
50 if (overrideHLSLDeclaration)
51 return hlslDeclarationOverride;
52 // default Behavior switches between UnityPerMaterial and Global based on Exposed checkbox
53 if (generatePropertyBlock)
54 return HLSLDeclaration.UnityPerMaterial;
55 else
56 return HLSLDeclaration.Global;
57 }
58
59 // by default we disallow UI from choosing "DoNotDeclare"
60 // it needs a bit more UI support to disable property node output slots before we make it public
61 internal virtual bool AllowHLSLDeclaration(HLSLDeclaration decl) => (decl != HLSLDeclaration.DoNotDeclare);
62
63 [SerializeField]
64 internal bool overrideHLSLDeclaration = false;
65
66 [SerializeField]
67 internal HLSLDeclaration hlslDeclarationOverride;
68
69 override internal bool isExposed => base.isExposed && shouldForceExposed;
70
71 internal bool shouldForceExposed => (hlslDeclarationOverride == HLSLDeclaration.HybridPerInstance || GetDefaultHLSLDeclaration() == HLSLDeclaration.UnityPerMaterial) && isExposable;
72
73 internal Precision precision
74 {
75 get => m_Precision;
76 set => m_Precision = value;
77 }
78
79 ConcretePrecision m_ConcretePrecision = ConcretePrecision.Single;
80 public ConcretePrecision concretePrecision => m_ConcretePrecision;
81 internal void SetupConcretePrecision(ConcretePrecision defaultPrecision)
82 {
83 m_ConcretePrecision = precision.ToConcrete(defaultPrecision, defaultPrecision);
84 }
85
86 [SerializeField]
87 bool m_Hidden = false;
88 public bool hidden
89 {
90 get => m_Hidden;
91 set => m_Hidden = value;
92 }
93
94 internal string hideTagString => hidden || (shouldForceExposed && !isExposed) ? "[HideInInspector]" : "";
95
96 // reference names are the HLSL declaration name / property block ref name
97 internal virtual void GetPropertyReferenceNames(List<string> result)
98 {
99 result.Add(referenceName);
100 }
101
102 // display names are used as the UI name in the property block / show up in the Material Inspector
103 internal virtual void GetPropertyDisplayNames(List<string> result)
104 {
105 result.Add(displayName);
106 }
107
108 // the simple interface for simple properties
109 internal virtual string GetPropertyBlockString()
110 {
111 return string.Empty;
112 }
113
114 internal bool shouldGeneratePropertyBlock => (generatePropertyBlock || shouldForceExposed)
115 && GetDefaultHLSLDeclaration() != HLSLDeclaration.Global;
116
117 // the more complex interface for complex properties (defaulted for simple properties)
118 internal virtual void AppendPropertyBlockStrings(ShaderStringBuilder builder)
119 {
120 builder.AppendLine(GetPropertyBlockString());
121 }
122
123 internal abstract void ForeachHLSLProperty(Action<HLSLProperty> action);
124
125 internal virtual string GetPropertyAsArgumentStringForVFX(string precisionString)
126 {
127 return GetPropertyAsArgumentString(precisionString);
128 }
129
130 internal abstract string GetPropertyAsArgumentString(string precisionString);
131 internal abstract AbstractMaterialNode ToConcreteNode();
132 internal abstract PreviewProperty GetPreviewMaterialProperty();
133
134 public virtual string GetPropertyTypeString()
135 {
136 var typeString = propertyType.ToString();
137 if (sgVersion < latestVersion)
138 typeString = $"{typeString} (Legacy v{sgVersion})";
139 return typeString;
140 }
141 }
142
143 [Serializable]
144 public abstract class AbstractShaderProperty<T> : AbstractShaderProperty
145 {
146 [SerializeField]
147 T m_Value;
148
149 public virtual T value
150 {
151 get => m_Value;
152 set => m_Value = value;
153 }
154 }
155
156 // class for extracting deprecated data from older versions of AbstractShaderProperty
157 class LegacyShaderPropertyData
158 {
159 // indicates user wishes to support the HYBRID renderer GPU instanced path
160 [SerializeField]
161 public bool m_GPUInstanced = false;
162
163 // converts the old m_GPUInstanced data into the new override HLSLDeclaration system.
164 public static void UpgradeToHLSLDeclarationOverride(string json, AbstractShaderProperty property)
165 {
166 // this maintains the old behavior for versioned properties:
167 // old exposed GPUInstanced properties are declared hybrid (becomes override in new system)
168 // old unexposed GPUInstanced properties are declared global (becomes override in new system)
169 // old exposed properties are declared UnityPerMaterial (default behavior, no override necessary)
170 // old unexposed properties are declared Global (default behavior, no override necessary)
171 // moving forward, users can use the overrides directly to control what it does
172
173 var legacyShaderPropertyData = new LegacyShaderPropertyData();
174 JsonUtility.FromJsonOverwrite(json, legacyShaderPropertyData);
175 if (legacyShaderPropertyData.m_GPUInstanced)
176 {
177 property.overrideHLSLDeclaration = true;
178 if (property.generatePropertyBlock)
179 property.hlslDeclarationOverride = HLSLDeclaration.HybridPerInstance;
180 else
181 property.hlslDeclarationOverride = HLSLDeclaration.Global;
182 }
183 }
184 }
185
186 public enum HLSLType
187 {
188 // value types
189 _float,
190 _float2,
191 _float3,
192 _float4,
193 _matrix4x4,
194
195 // object types
196 FirstObjectType,
197 _Texture2D = FirstObjectType,
198 _Texture3D,
199 _TextureCube,
200 _Texture2DArray,
201 _SamplerState,
202
203 // custom type
204 _CUSTOM
205 }
206
207 // describes the different ways we can generate HLSL declarations
208 [Flags]
209 internal enum HLSLDeclaration
210 {
211 DoNotDeclare, // NOT declared in HLSL
212 Global, // declared in the global scope, mainly for use with state coming from Shader.SetGlobal*()
213 UnityPerMaterial, // declared in the UnityPerMaterial cbuffer, populated by Material or MaterialPropertyBlock
214 HybridPerInstance, // declared using HybridRenderer path (v1 or v2) to get DOTS GPU instancing
215 }
216
217 internal struct HLSLProperty
218 {
219 public string name;
220 public HLSLType type;
221 public ConcretePrecision precision;
222 public HLSLDeclaration declaration;
223 public Action<ShaderStringBuilder> customDeclaration;
224
225 public HLSLProperty(HLSLType type, string name, HLSLDeclaration declaration, ConcretePrecision precision = ConcretePrecision.Single)
226 {
227 this.type = type;
228 this.name = name;
229 this.declaration = declaration;
230 this.precision = precision;
231 this.customDeclaration = null;
232 }
233
234 public bool ValueEquals(HLSLProperty other)
235 {
236 if ((name != other.name) ||
237 (type != other.type) ||
238 (precision != other.precision) ||
239 (declaration != other.declaration) ||
240 ((customDeclaration == null) != (other.customDeclaration == null)))
241 {
242 return false;
243 }
244 else if (customDeclaration != null)
245 {
246 var ssb = new ShaderStringBuilder();
247 var ssbother = new ShaderStringBuilder();
248 customDeclaration(ssb);
249 other.customDeclaration(ssbother);
250 if (ssb.ToCodeBlock() != ssbother.ToCodeBlock())
251 return false;
252 }
253 return true;
254 }
255
256 static string[,] kValueTypeStrings = new string[(int)HLSLType.FirstObjectType, 2]
257 {
258 {"float", "half"},
259 {"float2", "half2"},
260 {"float3", "half3"},
261 {"float4", "half4"},
262 {"float4x4", "half4x4"}
263 };
264
265 static string[] kObjectTypeStrings = new string[(int)HLSLType._CUSTOM - (int)HLSLType.FirstObjectType]
266 {
267 "TEXTURE2D",
268 "TEXTURE3D",
269 "TEXTURECUBE",
270 "TEXTURE2D_ARRAY",
271 "SAMPLER",
272 };
273
274 public bool IsObjectType()
275 {
276 return type == HLSLType._SamplerState ||
277 type == HLSLType._Texture2D ||
278 type == HLSLType._Texture3D ||
279 type == HLSLType._TextureCube ||
280 type == HLSLType._Texture2DArray ||
281 type == HLSLType._CUSTOM;
282 }
283
284 public string GetValueTypeString()
285 {
286 if (type < HLSLType.FirstObjectType)
287 return kValueTypeStrings[(int)type, (int)precision];
288 return null;
289 }
290
291 public void AppendTo(ShaderStringBuilder ssb, Func<string, string> nameModifier = null)
292 {
293 var mName = nameModifier?.Invoke(name) ?? name;
294
295 if (type < HLSLType.FirstObjectType)
296 {
297 ssb.Append(kValueTypeStrings[(int)type, (int)precision]);
298 ssb.Append(" ");
299 ssb.Append(mName);
300 ssb.Append(";");
301 }
302 else if (type < HLSLType._CUSTOM)
303 {
304 ssb.Append(kObjectTypeStrings[type - HLSLType.FirstObjectType]);
305 ssb.Append("(");
306 ssb.Append(mName);
307 ssb.Append(");");
308 }
309 else
310 {
311 customDeclaration(ssb);
312 }
313 //ssb.Append(" // ");
314 //ssb.Append(declaration.ToString());
315 ssb.AppendNewLine();
316 }
317 }
318}