Skip to content

Commit b3a1243

Browse files
ludovic-theobaldEvergreen
authored andcommitted
[VFX][Optimisation] Merge buffers and group upload / dispatches
This PR consists in two main changes : 1. Merging some GPU Buffers together: - `instancingIndirect `& `instancingActiveIndirect `are merged into `instancingIndirectAndActiveIndirect` - `graphValuesBuffer`, `batchedInitParams `& `instancingContextData `are merged into `graphValuesBuffer` - `deadListIn`, `deadListCount`, and `deadListCountCopy `are merged into `deadList `: both the counter and the copy of the counter (that needs to be constant throughout the init compute) are stored at the beginning of the deadList buffer. - `eventsPrefixSum` and `spawnCountPrefixSum` are merged into `spawnBuffer` This enables to get below the buffer usage limit on some platforms (WebGPU, OpenGLES 3), but is not an optimization. 2. Uploads of these buffers are done at a fixed point in the frame : - `UploadBatchStepDataCommand` uploads `graphValuesBuffer`, the indirection buffers ( `instancingIndirectAndActiveIndirect` & `instancingPrefixSums`), and the initialize task buffers ( `spawnBuffer` and `sourceAttributeBuffer`) if they are needed. - `UploadOutputIndirectionBufferCommand` uploads the indirection buffers for the tasks in the rendering command list. This avoids having data uploads in-between dispatches, blocking any overlap between compute shader executions. To achieve this, the indirection lists for each split are stored contiguously in `instancingIndirectAndActiveIndirect` and `instancingPrefixSums` The PR also contains some other optimisations : - Caching of the instance step data, to avoid useless allocs/deallocs at each frame. - Moving the `CopyDeadListCount` command away from `BatchInitCommand` to favor compute overlap
1 parent 5668e70 commit b3a1243

File tree

31 files changed

+183
-231
lines changed

31 files changed

+183
-231
lines changed

Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Outputs/VFXVolumetricFogOutput.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ public override VFXContextCompiledData PrepareCompiledData()
320320
baseName = "maxSliceCount",
321321
size = 1,
322322
bufferSizeMode = VFXContextBufferSizeMode.FixedSize,
323-
bufferType = ComputeBufferType.Structured,
323+
bufferTarget = GraphicsBuffer.Target.Structured,
324324
stride = sizeof(uint),
325325
bufferCount = 1,
326326
});

Packages/com.unity.render-pipelines.high-definition/Editor/VFXGraph/Shaders/Templates/Volumetric/PassVolumetricFog.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ VertexToFragment Vert(vs_input i)
7676

7777
${VFXInitInstancing}
7878

79-
ContextData contextData = instancingContextData[instanceActiveIndex];
79+
${VFXLoadContextData}
8080
uint systemSeed = contextData.systemSeed;
8181
uint nbMax = contextData.maxParticleCount;
8282

Packages/com.unity.render-pipelines.universal/Editor/VFXGraph/Shaders/Templates/ParticleMeshesLit/Pass.template

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,18 @@ VFX_VARYING_PS_INPUTS vert(vs_input i)
4141
${VFXInitInstancing}
4242
${VFXLoadGraphValues}
4343

44-
ContextData contextData = instancingContextData[instanceActiveIndex];
44+
${VFXLoadContextData}
4545
uint systemSeed = contextData.systemSeed;
4646
uint nbMax = contextData.maxParticleCount;
47-
47+
4848
${VFXLoadAttributesOrCull}
4949
${VFXProcessBlocks}
50-
50+
5151
if (!attributes.alive)
5252
return o;
53-
53+
5454
o.VFX_VARYING_UV.xy = i.uv;
55-
55+
5656
#if VFX_SHADERGRAPH_HAS_UV1
5757
o.uv1 = i.uv1;
5858
#endif
@@ -65,9 +65,9 @@ VFX_VARYING_PS_INPUTS vert(vs_input i)
6565
#if VFX_SHADERGRAPH_HAS_COLOR
6666
o.vertexColor = i.vertexColor;
6767
#endif
68-
68+
6969
${VFXLoadSize}
70-
70+
7171
float3 inputVertexPosition = i.pos;
7272
float4x4 elementToVFX = GetElementToVFXMatrix(
7373
attributes.axisX,
@@ -77,19 +77,19 @@ VFX_VARYING_PS_INPUTS vert(vs_input i)
7777
float3(attributes.pivotX,attributes.pivotY,attributes.pivotZ),
7878
size3,
7979
attributes.position);
80-
80+
8181
float3 vPos = mul(elementToVFX,float4(inputVertexPosition,1.0f)).xyz;
8282
float4 csPos = TransformPositionVFXToClip(vPos);
8383
o.VFX_VARYING_POSCS = csPos;
84-
84+
8585
// TODO This is needed only if in local space (to handle non uniform scale) or if scale attributes are stored/written (no way to know atm)
8686
float3x3 elementToVFX_N = GetElementToVFXMatrixNormal(
8787
attributes.axisX,
8888
attributes.axisY,
8989
attributes.axisZ,
9090
float3(attributes.angleX,attributes.angleY,attributes.angleZ),
9191
size3);
92-
92+
9393
float3 normalWS = normalize(TransformNormalVFXToWorld(mul(elementToVFX_N, i.normal)));
9494
#ifdef VFX_VARYING_NORMAL
9595
o.VFX_VARYING_NORMAL = normalWS;
@@ -99,15 +99,15 @@ VFX_VARYING_PS_INPUTS vert(vs_input i)
9999
#endif
100100

101101
${VFXVertexComputeCurrentAndPreviousClipPos}
102-
102+
103103
${VFXVertexCommonProcess}
104-
104+
105105
${VFXVertexSetFlipbooksInterpolants}
106106

107107
${VFXVertexAdditionalProcess}
108-
108+
109109
${VFXAdditionalInterpolantsGeneration}
110-
110+
111111
return o;
112112
}
113113

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,13 @@ internal static void BuildFillGraphValues(VFXTaskCompiledData taskData, VFXDataP
603603
fillGraphValues = fillGraphValuesShaderWriter.ToString();
604604
}
605605

606+
internal static void BuildLoadContextData(VFXDataParticle.GraphValuesLayout graphValuesLayout, out string loadContextData)
607+
{
608+
var loadContextDataShaderWriter = new VFXShaderWriter();
609+
loadContextDataShaderWriter.GenerateLoadContextData(graphValuesLayout);
610+
loadContextData = loadContextDataShaderWriter.ToString();
611+
}
612+
606613
static private StringBuilder Build(
607614
VFXContext context,
608615
VFXTask task,
@@ -672,7 +679,7 @@ static private StringBuilder Build(
672679
globalDeclaration.WriteLine();
673680

674681
globalDeclaration.WriteEventBuffers(eventListOutName, taskData.linkedEventOut.Length);
675-
682+
676683
var expressionToName = BuildExpressionToName(context, taskData);
677684
BuildContextBlocks(context, taskData, expressionToName, out var blockFunction, out var blockCallFunction);
678685

@@ -764,6 +771,10 @@ static private StringBuilder Build(
764771
fillGraphValueStruct.GenerateFillGraphValuesStruct(taskData.uniformMapper, particleData.graphValuesLayout);
765772
ReplaceMultiline(stringBuilder, "${VFXLoadGraphValues}", fillGraphValueStruct.builder);
766773

774+
VFXShaderWriter loadContextData = new VFXShaderWriter();
775+
loadContextData.GenerateLoadContextData(particleData.graphValuesLayout);
776+
ReplaceMultiline(stringBuilder, "${VFXLoadContextData}", loadContextData.builder);
777+
767778
var mainParameters = taskData.gpuMapper.CollectExpression(-1).ToArray();
768779
foreach (var match in GetUniqueMatches("\\${VFXLoadParameter:{(.*?)}}", stringBuilder.ToString()))
769780
{
@@ -1049,12 +1060,12 @@ internal static IEnumerable<string> GetInstancingAdditionalDefines(VFXContext co
10491060
}
10501061
}
10511062

1052-
bool hasActiveIndirection = context.contextType == VFXContextType.Filter || context.contextType == VFXContextType.Output;
1053-
hasActiveIndirection = true; // TODO: how can we know if there are variable expressions with textures/buffers?
1063+
bool hasActiveIndirection = context.contextType != VFXContextType.Output;
1064+
// TODO: how can we know if there are variable expressions with textures/buffers?
10541065
if (hasActiveIndirection)
10551066
yield return "#define VFX_INSTANCING_ACTIVE_INDIRECTION 1";
10561067

1057-
bool hasBatchIndirection = true;
1068+
bool hasBatchIndirection = context.contextType != VFXContextType.Output;
10581069
if (hasBatchIndirection)
10591070
yield return "#define VFX_INSTANCING_BATCH_INDIRECTION 1";
10601071
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ struct VFXContextBufferDescriptor
2929
public string baseName;
3030
public VFXContextBufferSizeMode bufferSizeMode;
3131
public uint size;
32-
public ComputeBufferType bufferType;
32+
public GraphicsBuffer.Target bufferTarget;
3333
public bool includeInSystemMappings;
3434
public float capacityScaleMultiplier;
3535
}
@@ -51,7 +51,7 @@ public int AllocateIndirectBuffer(bool isPerCamera = true, uint stride = 4u, str
5151
isPerCamera = isPerCamera,
5252
stride = stride,
5353
bufferCount = bufferCount,
54-
bufferType = ComputeBufferType.Structured,
54+
bufferTarget = GraphicsBuffer.Target.Structured,
5555
includeInSystemMappings = true,
5656
});
5757

@@ -971,16 +971,15 @@ public void FillDependentBuffer(
971971
{
972972
stripBufferIndex = bufferDescs.Count;
973973
uint stripCapacity = (uint)data.GetSettingValue("stripCapacity");
974-
// 5 elements per strip + 1 for the total particle count
975-
bufferDescs.Add(new VFXGPUBufferDesc() { type = ComputeBufferType.Default, size = stripCapacity * 5 + 1, stride = 4 });
974+
bufferDescs.Add(new VFXGPUBufferDesc() { target = GraphicsBuffer.Target.Structured, size = stripCapacity * 5 + 1, stride = 4});
976975
}
977976
buffers.stripBuffers.Add(data, stripBufferIndex);
978977

979978
int boundsBufferIndex = -1;
980979
if (data.NeedsComputeBounds())
981980
{
982981
boundsBufferIndex = bufferDescs.Count;
983-
bufferDescs.Add(new VFXGPUBufferDesc() { type = ComputeBufferType.Default, size = 6, stride = 4 });
982+
bufferDescs.Add(new VFXGPUBufferDesc() { target = GraphicsBuffer.Target.Structured, size = 6, stride = 4});
984983
}
985984
buffers.boundsBuffers.Add(data, boundsBufferIndex);
986985
}
@@ -993,7 +992,7 @@ public void FillDependentBuffer(
993992
if (capacity > 0)
994993
{
995994
eventBufferIndex = bufferDescs.Count;
996-
bufferDescs.Add(new VFXGPUBufferDesc() { type = ComputeBufferType.Structured, size = capacity + 2, stride = 4 });
995+
bufferDescs.Add(new VFXGPUBufferDesc() { target = GraphicsBuffer.Target.Structured, size = capacity + 2, stride = 4 });
997996
}
998997
buffers.eventBuffers.Add(data, eventBufferIndex);
999998
}

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

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,6 @@ public bool WriteGraphValuesStruct(VFXUniformMapper contextUniformMapper)
381381
{
382382
bool needsGraphValueStruct = false;
383383
var contextUniforms = contextUniformMapper.uniforms;
384-
385384
if (contextUniforms.Any())
386385
{
387386
needsGraphValueStruct = true;
@@ -399,15 +398,28 @@ public bool WriteGraphValuesStruct(VFXUniformMapper contextUniformMapper)
399398
Deindent();
400399
WriteLine("};");
401400
}
402-
403-
if (needsGraphValueStruct)
404-
{
405-
WriteLine("ByteAddressBuffer graphValuesBuffer;");
406-
WriteLine();
407-
}
401+
WriteLine("ByteAddressBuffer graphValuesBuffer;");
402+
WriteLine();
408403
return needsGraphValueStruct;
409404
}
410405

406+
public void GenerateLoadContextData(VFXDataParticle.GraphValuesLayout graphValuesLayout)
407+
{
408+
uint structSize = graphValuesLayout.paddedSizeInBytes;
409+
WriteLine("struct ContextData");
410+
WriteLine("{");
411+
WriteLine(" uint maxParticleCount;");
412+
WriteLine(" uint systemSeed;");
413+
WriteLine(" uint initSpawnIndex;");
414+
WriteLine("};");
415+
416+
WriteLine("ContextData contextData;");
417+
WriteLine($"uint4 rawContextData = graphValuesBuffer.Load4(instanceActiveIndex * {structSize});");
418+
WriteLine($"contextData.maxParticleCount = rawContextData.x;");
419+
WriteLine($"contextData.systemSeed = rawContextData.y;");
420+
WriteLine($"contextData.initSpawnIndex = rawContextData.z;");
421+
}
422+
411423
public void GenerateFillGraphValuesStruct(VFXUniformMapper contextUniformMapper, VFXDataParticle.GraphValuesLayout graphValuesLayout)
412424
{
413425
uint structSize = graphValuesLayout.paddedSizeInBytes;
@@ -416,10 +428,8 @@ public void GenerateFillGraphValuesStruct(VFXUniformMapper contextUniformMapper,
416428
if (contextUniforms.Any())
417429
{
418430
contextUniforms = contextUniforms.OrderBy(o => nameToOffset[contextUniformMapper.GetName(o)]);
419-
420431
WriteLine("GraphValues graphValues;");
421432
WriteLine();
422-
423433
foreach (var value in contextUniforms)
424434
{
425435
string name = contextUniformMapper.GetName(value);

0 commit comments

Comments
 (0)