Skip to content

Commit 80ab22f

Browse files
PaulDemeulenaereEvergreen
authored andcommitted
[VFX] Missing Includes with CustomHLSL & SG
Issue introduced at https://github.cds.internal.unity3d.com/unity/unity/pull/40913 The support of `CustomHLSL` was partial and didn't consider custom HLSL and includes workflow. The exact repro was about usage in update leaking into output generated but the issue was reproducible actually using SG in output. ➕ Additionally, the `defines` wasn't applied in SG (but it doesn't have any effect, so far, only [FillAabbBuffer](https://github.cds.internal.unity3d.com/unity/unity/blob/05bbb1aacd661908468d5fe51f2a83f96c0649f2/Packages/com.unity.visualeffectgraph/Shaders/VFXBoundsUtils.hlsl#L194) and it isn't called in any vertex or pixel shader. I introduced the define declaration for consistency. ➕ Move the `VFXCommonOutput.hlsl` in case of SG because it wasn't consistent with builtin generated code.
1 parent 190c6d8 commit 80ab22f

File tree

4 files changed

+120
-25
lines changed

4 files changed

+120
-25
lines changed

Packages/com.unity.visualeffectgraph/Editor/Compiler/VFXCodeGenerator.cs

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -401,12 +401,19 @@ internal static Dictionary<VFXExpression, string> BuildExpressionToName(VFXConte
401401

402402
internal static void BuildContextBlocks(VFXContext context, VFXTaskCompiledData taskData, Dictionary<VFXExpression, string> expressionToName,
403403
out VFXShaderWriter blockFunction,
404-
out VFXShaderWriter blockCallFunction)
404+
out VFXShaderWriter blockCallFunction,
405+
out VFXShaderWriter blockIncludes,
406+
out VFXShaderWriter blockDefines)
405407
{
406408
//< Block processor
407409
blockFunction = new VFXShaderWriter();
408410
blockCallFunction = new VFXShaderWriter();
411+
blockIncludes = new VFXShaderWriter();
412+
blockDefines = new VFXShaderWriter();
413+
409414
var blockDeclared = new HashSet<string>();
415+
var includesProcessed = new HashSet<string>();
416+
var defineProcessed = new HashSet<string>();
410417

411418
int cpt = 0;
412419
foreach (var current in context.activeFlattenedChildrenWithImplicit)
@@ -415,14 +422,42 @@ internal static void BuildContextBlocks(VFXContext context, VFXTaskCompiledData
415422
if (current is IHLSLCodeHolder hlslCodeHolder)
416423
{
417424
blockFunction.Write(hlslCodeHolder.customCode);
425+
foreach (var includePath in hlslCodeHolder.includes)
426+
{
427+
if (includesProcessed.Add(includePath))
428+
{
429+
blockIncludes.WriteLine($"#include \"{includePath}\"");
430+
}
431+
}
432+
}
433+
434+
foreach (var define in current.defines)
435+
{
436+
if (defineProcessed.Add(define))
437+
{
438+
blockDefines.WriteLineFormat("#define {0}{1}", define, define.Contains(' ') ? "" : " 1");
439+
}
418440
}
419441
BuildBlock(taskData, blockFunction, blockCallFunction, blockDeclared, expressionToName, current, ref cpt);
420442
}
421443

422444
// Custom HLSL Operators
423-
foreach (var group in taskData.hlslCodeHolders.GroupBy(x => x.customCode.GetHashCode()))
445+
var customCodeProcessed = new HashSet<string>();
446+
foreach (var hlslCodeHolder in taskData.hlslCodeHolders)
424447
{
425-
blockFunction.Write(group.First().customCode);
448+
var customCode = hlslCodeHolder.customCode;
449+
if (customCodeProcessed.Add(customCode))
450+
{
451+
blockFunction.Write(customCode);
452+
}
453+
454+
foreach (var includePath in hlslCodeHolder.includes)
455+
{
456+
if (includesProcessed.Add(includePath))
457+
{
458+
blockIncludes.WriteLine($"#include \"{includePath}\"");
459+
}
460+
}
426461
}
427462
}
428463

@@ -681,7 +716,7 @@ static private StringBuilder Build(
681716
globalDeclaration.WriteEventBuffers(eventListOutName, taskData.linkedEventOut.Length);
682717

683718
var expressionToName = BuildExpressionToName(context, taskData);
684-
BuildContextBlocks(context, taskData, expressionToName, out var blockFunction, out var blockCallFunction);
719+
BuildContextBlocks(context, taskData, expressionToName, out var blockFunction, out var blockCallFunction, out var blockIncludes, out var blockDefines);
685720

686721
//< Final composition
687722
var globalIncludeContent = new VFXShaderWriter();
@@ -743,25 +778,8 @@ static private StringBuilder Build(
743778
{
744779
perPassIncludeContent.WriteLine("#include \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommonOutput.hlsl\"");
745780
}
746-
747-
// Per-block defines
748-
var defines = Enumerable.Empty<string>();
749-
foreach (var block in context.activeFlattenedChildrenWithImplicit)
750-
defines = defines.Concat(block.defines);
751-
var uniqueDefines = new HashSet<string>(defines);
752-
foreach (var define in uniqueDefines)
753-
globalIncludeContent.WriteLineFormat("#define {0}{1}", define, define.Contains(' ') ? "" : " 1");
754-
755-
// Per-block includes
756-
var includes = Enumerable.Empty<string>();
757-
foreach (var block in context.activeFlattenedChildrenWithImplicit.OfType<IHLSLCodeHolder>())
758-
includes = includes.Concat(block.includes);
759-
foreach (var hlslHolder in taskData.hlslCodeHolders)
760-
includes = includes.Concat(hlslHolder.includes);
761-
var uniqueIncludes = new HashSet<string>(includes);
762-
foreach (var includePath in uniqueIncludes)
763-
perPassIncludeContent.WriteLine(string.Format("#include \"{0}\"", includePath));
764-
781+
globalIncludeContent.Write(blockDefines.builder.ToString());
782+
perPassIncludeContent.Write(blockIncludes.builder.ToString());
765783

766784
ReplaceMultiline(stringBuilder, "${VFXGlobalInclude}", globalIncludeContent.builder);
767785
ReplaceMultiline(stringBuilder, "${VFXGlobalDeclaration}", globalDeclaration.builder);

Packages/com.unity.visualeffectgraph/Editor/ShaderGraph/Templates/VFXConfig.template.hlsl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,17 @@ UNITY_INSTANCING_BUFFER_END(PerInstance)
5656
#define VFX_GET_INSTANCE_ID(i) input.instanceID
5757
#endif
5858

59+
$splice(VFXPerBlockDefines)
60+
5961
$splice(VFXSRPCommonInclude)
6062
#include "Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.hlsl"
63+
$splice(VFXPerBlockIncludes)
64+
#include "Packages/com.unity.visualeffectgraph/Shaders/VFXCommonOutput.hlsl"
6165

6266
$splice(VFXParameterBuffer)
6367

6468
$splice(VFXGeneratedBlockFunction)
6569

66-
#include "Packages/com.unity.visualeffectgraph/Shaders/VFXCommonOutput.hlsl"
6770

6871
struct AttributesElement
6972
{

Packages/com.unity.visualeffectgraph/Editor/ShaderGraph/VFXSubTarget.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ static StructDescriptor GenerateVFXAttributesStruct(VFXContext context, VFXAttri
140140

141141
static void GenerateVFXAdditionalCommands(VFXContext context, VFXSRPBinder srp, VFXSRPBinder.ShaderGraphBinder shaderGraphBinder, VFXTaskCompiledData taskData,
142142
out AdditionalCommandDescriptor srpCommonInclude,
143+
out AdditionalCommandDescriptor perBlockDefines,
144+
out AdditionalCommandDescriptor perBlockIncludes,
143145
out AdditionalCommandDescriptor loadAttributeDescriptor,
144146
out AdditionalCommandDescriptor blockFunctionDescriptor,
145147
out AdditionalCommandDescriptor blockCallFunctionDescriptor,
@@ -177,7 +179,14 @@ static void GenerateVFXAdditionalCommands(VFXContext context, VFXSRPBinder srp,
177179

178180
// Graph Blocks
179181
var expressionToName = VFXCodeGenerator.BuildExpressionToName(context, taskData);
180-
VFXCodeGenerator.BuildContextBlocks(context, taskData, expressionToName, out var blockFunction, out var blockCallFunction);
182+
VFXCodeGenerator.BuildContextBlocks(context, taskData, expressionToName,
183+
out var blockFunction,
184+
out var blockCallFunction,
185+
out var blockIncludes,
186+
out var blockDefines);
187+
188+
perBlockDefines = new AdditionalCommandDescriptor("VFXPerBlockDefines", blockDefines.builder.ToString());
189+
perBlockIncludes = new AdditionalCommandDescriptor("VFXPerBlockIncludes", blockIncludes.builder.ToString());
181190

182191
blockFunctionDescriptor = new AdditionalCommandDescriptor("VFXGeneratedBlockFunction", blockFunction.builder.ToString());
183192
blockCallFunctionDescriptor = new AdditionalCommandDescriptor("VFXProcessBlocks", blockCallFunction.builder.ToString());
@@ -452,6 +461,8 @@ internal static SubShaderDescriptor PostProcessSubShader(SubShaderDescriptor sub
452461
GenerateVFXAdditionalCommands(
453462
context, srp, shaderGraphSRPInfo, data,
454463
out var srpCommonInclude,
464+
out var perBlockDefines,
465+
out var perBlockIncludes,
455466
out var loadAttributeDescriptor,
456467
out var blockFunctionDescriptor,
457468
out var blockCallFunctionDescriptor,
@@ -512,6 +523,8 @@ out var fragInputsDescriptor
512523
passDescriptor.additionalCommands = new AdditionalCommandCollection
513524
{
514525
srpCommonInclude,
526+
perBlockDefines,
527+
perBlockIncludes,
515528
loadAttributeDescriptor,
516529
blockFunctionDescriptor,
517530
blockCallFunctionDescriptor,

Tests/SRPTests/Projects/VisualEffectGraph_HDRP/Assets/AllTests/Editor/Tests/CustomHLSLOperatorTest.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,67 @@ public void Check_CustomHLSL_Operator_Use_Shader_File()
105105
Assert.AreEqual(expectedGeneratedCode, hlslExpression.customCode);
106106
}
107107

108+
[UnityTest, Description("Regression for UUM-69735")]
109+
public IEnumerator Check_CustomHLSL_Operator_Use_Shader_File_And_ShaderGraph()
110+
{
111+
var hlslCode = @"
112+
float3 GetCustomColor(in float3 vec)
113+
{
114+
return float3(0.1f, 0.2f, 0.3f);
115+
}";
116+
var shaderInclude = CustomHLSLBlockTest.CreateShaderFile(hlslCode, out var shaderIncludePath);
117+
118+
var hlslOperator = ScriptableObject.CreateInstance<CustomHLSL>();
119+
hlslOperator.SetSettingValue("m_HLSLCode", hlslCode);
120+
hlslOperator.SetSettingValue("m_ShaderFile", shaderInclude);
121+
hlslOperator.SetSettingValue("m_OperatorName", "GetCustomColor");
122+
MakeSimpleGraphWithCustomHLSL(hlslOperator, out var view, out var graph);
123+
124+
var vfxAsset = graph.GetResource().asset;
125+
var outputToReplace = graph.children.OfType<VFXContext>().First(o => o.contextType.HasFlag(VFXContextType.Output));
126+
var shaderGraphVariant = VFXLibrary.GetContexts().First(o => o.model is VFXComposedParticleOutput);
127+
128+
var newShaderGraphOutput = shaderGraphVariant.CreateInstance();
129+
graph.AddChild(newShaderGraphOutput);
130+
Assert.IsTrue(newShaderGraphOutput.GetSetting("shaderGraph").valid);
131+
132+
var tracker = "Find_Me_In_Generated_Name";
133+
newShaderGraphOutput.label = tracker;
134+
newShaderGraphOutput.LinkFrom(outputToReplace.inputFlowSlot[0].link.First().context);
135+
outputToReplace.UnlinkAll();
136+
graph.RemoveChild(outputToReplace);
137+
138+
var blockSetColor = ScriptableObject.CreateInstance<Block.SetAttribute>();
139+
blockSetColor.SetSettingValue("attribute", "color");
140+
newShaderGraphOutput.AddChild(blockSetColor);
141+
Assert.IsTrue(hlslOperator.outputSlots[0].Link(blockSetColor.inputSlots[0]));
142+
143+
var blockOrientCameraPlane = ScriptableObject.CreateInstance<Block.Orient>();
144+
blockOrientCameraPlane.SetSettingValue("faceRay", true);
145+
blockOrientCameraPlane.SetSettingValue("mode", Block.Orient.Mode.FaceCameraPlane);
146+
newShaderGraphOutput.AddChild(blockOrientCameraPlane);
147+
var defineToFind = blockOrientCameraPlane.defines.First();
148+
149+
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(vfxAsset));
150+
yield return null;
151+
152+
string source = null;
153+
for (int shaderIndex = 0; shaderIndex < graph.GetResource().GetShaderSourceCount(); shaderIndex++)
154+
{
155+
var name = graph.GetResource().GetShaderSourceName(shaderIndex);
156+
if (name.Contains(tracker))
157+
{
158+
source = graph.GetResource().GetShaderSource(shaderIndex);
159+
break;
160+
}
161+
}
162+
Assert.IsNotNull(source);
163+
Assert.IsTrue(source.Contains(shaderIncludePath, StringComparison.Ordinal));
164+
Assert.IsTrue(source.Contains(defineToFind, StringComparison.Ordinal));
165+
166+
yield return null;
167+
}
168+
108169
[UnityTest]
109170
public IEnumerator Check_CustomHLSL_Operator_Return_Type_Is_Void()
110171
{

0 commit comments

Comments
 (0)