Skip to content

Commit 5d73274

Browse files
alelievrEvergreen
authored andcommitted
Fix graphics corruption when enabling live subdivision
Fix this: ![image](https://media.github.cds.internal.unity3d.com/user/745/files/17568716-a6be-4a3a-8263-3f36e084ec42)
1 parent 3cbbde1 commit 5d73274

File tree

2 files changed

+28
-16
lines changed

2 files changed

+28
-16
lines changed

Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbePlacement.cs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ public class GPUSubdivisionContext : IDisposable
4444
public RenderTexture dummyRenderTarget;
4545

4646
public ComputeBuffer probeVolumesBuffer;
47+
public ComputeBuffer brickCountBuffer;
4748
public ComputeBuffer[] bricksBuffers;
48-
public ComputeBuffer[] readbackCountBuffers;
4949

5050
public Vector4[] brickPositions;
5151

@@ -91,14 +91,14 @@ public GPUSubdivisionContext(int probeVolumeCount, ProbeVolumeProfileInfo profil
9191
maxSubdivisionLevelInSubCell = Mathf.Min(maxSubdivisionLevel, k_MaxSubdivisionInSubCell);
9292
maxBrickCountPerAxisInSubCell = (int)Mathf.Pow(3, maxSubdivisionLevelInSubCell);
9393
bricksBuffers = new ComputeBuffer[maxSubdivisionLevelInSubCell + 1];
94-
readbackCountBuffers = new ComputeBuffer[maxSubdivisionLevelInSubCell + 1];
9594
for (int i = 0; i <= maxSubdivisionLevelInSubCell; i++)
9695
{
9796
int brickCountPerAxis = (int)Mathf.Pow(3, maxSubdivisionLevelInSubCell - i);
98-
bricksBuffers[i] = new ComputeBuffer(brickCountPerAxis * brickCountPerAxis * brickCountPerAxis, sizeof(float) * 4, ComputeBufferType.Append);
99-
readbackCountBuffers[i] = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);
97+
bricksBuffers[i] = new ComputeBuffer(brickCountPerAxis * brickCountPerAxis * brickCountPerAxis, sizeof(float) * 4, ComputeBufferType.Structured);
10098
}
10199

100+
brickCountBuffer = new ComputeBuffer(maxSubdivisionLevelInSubCell + 1, sizeof(uint), ComputeBufferType.Structured);
101+
102102
brickPositions = new Vector4[maxBrickCountPerAxisInSubCell * maxBrickCountPerAxisInSubCell * maxBrickCountPerAxisInSubCell];
103103
}
104104

@@ -108,16 +108,16 @@ public void Dispose()
108108
RenderTexture.ReleaseTemporary(sceneSDF2);
109109
RenderTexture.ReleaseTemporary(dummyRenderTarget);
110110
probeVolumesBuffer.Release();
111+
brickCountBuffer.Release();
111112

112113
for (int i = 0; i <= maxSubdivisionLevelInSubCell; i++)
113-
{
114114
bricksBuffers[i].Release();
115-
readbackCountBuffers[i].Release();
116-
}
117115
}
118116
}
119117

120118
static readonly int _BricksToClear = Shader.PropertyToID("_BricksToClear");
119+
static readonly int _BricksToClearCount = Shader.PropertyToID("_BricksToClearCount");
120+
static readonly int _BrickCountBuffer = Shader.PropertyToID("_BrickCountBuffer");
121121
static readonly int _Output = Shader.PropertyToID("_Output");
122122
static readonly int _OutputSize = Shader.PropertyToID("_OutputSize");
123123
static readonly int _VolumeWorldOffset = Shader.PropertyToID("_VolumeWorldOffset");
@@ -356,6 +356,9 @@ static void SubdivideSubCell(Bounds cellAABB, ProbeSubdivisionContext subdivisio
356356
var probeSubdivisionData = ctx.sceneSDF2;
357357
VoxelizeProbeVolumeData(cmd, cellAABB, probeVolumes, ctx);
358358

359+
// Clear the brick counter, equivalent to SetBufferCounterValue(0) but we can't use append buffers
360+
cmd.SetBufferData(ctx.brickCountBuffer, new int[ctx.maxSubdivisionLevelInSubCell + 1]);
361+
359362
// Find the maximum subdivision level we can have in this cell (avoid extra work if not needed)
360363
int globalMaxSubdiv = ProbeVolumeBakingSet.GetMaxSubdivision(ctx.maxSubdivisionLevel);
361364
int startSubdivisionLevel = Mathf.Max(0, ctx.maxSubdivisionLevelInSubCell - GetMaxSubdivision(ctx, probeVolumes.Max(p => p.component.GetMaxSubdivMultiplier(globalMaxSubdiv))));
@@ -364,22 +367,21 @@ static void SubdivideSubCell(Bounds cellAABB, ProbeSubdivisionContext subdivisio
364367
// Add the bricks from the probe volume min subdivision level:
365368
int brickCountPerAxis = (int)Mathf.Pow(3, ctx.maxSubdivisionLevelInSubCell - subdivisionLevel);
366369
var bricksBuffer = ctx.bricksBuffers[subdivisionLevel];
367-
var brickCountReadbackBuffer = ctx.readbackCountBuffers[subdivisionLevel];
368370

369371
using (new ProfilingScope(cmd, new ProfilingSampler("Clear Bricks Buffer")))
370372
{
371373
cmd.SetComputeBufferParam(subdivideSceneCS, s_ClearBufferKernel, _BricksToClear, bricksBuffer);
372-
DispatchCompute(cmd, s_ClearBufferKernel, brickCountPerAxis * brickCountPerAxis * brickCountPerAxis, 1);
373-
cmd.SetBufferCounterValue(bricksBuffer, 0);
374+
int count = brickCountPerAxis * brickCountPerAxis * brickCountPerAxis;
375+
cmd.SetComputeIntParam(subdivideSceneCS, _BricksToClearCount, count);
376+
DispatchCompute(cmd, s_ClearBufferKernel, count, 1);
374377
}
375378

376379
// Generate the list of bricks on the GPU
377-
SubdivideFromDistanceField(cmd, cellAABB, ctx, probeSubdivisionData, bricksBuffer, brickCountPerAxis, subdivisionLevel, minBrickSize, cellOffset);
380+
SubdivideFromDistanceField(cmd, cellAABB, ctx, probeSubdivisionData, bricksBuffer, ctx.brickCountBuffer, brickCountPerAxis, subdivisionLevel, minBrickSize, cellOffset);
378381

379-
cmd.CopyCounterValue(bricksBuffer, brickCountReadbackBuffer, 0);
380382
// Capture locally the subdivision level to use it inside the lambda
381383
int localSubdivLevel = subdivisionLevel;
382-
cmd.RequestAsyncReadback(brickCountReadbackBuffer, sizeof(int), 0, (data) => {
384+
cmd.RequestAsyncReadback(ctx.brickCountBuffer, sizeof(int), subdivisionLevel * sizeof(int), (data) => {
383385
int readbackBrickCount = data.GetData<int>()[0];
384386

385387
if (readbackBrickCount > 0)
@@ -394,11 +396,13 @@ static void SubdivideSubCell(Bounds cellAABB, ProbeSubdivisionContext subdivisio
394396
}
395397
});
396398
}
399+
// ExternalGPUProfiler.BeginGPUCapture();
397400

398401
cmd.WaitAllAsyncReadbackRequests();
399402
Graphics.ExecuteCommandBuffer(cmd);
400403
cmd.Clear();
401404
CommandBufferPool.Release(cmd);
405+
// ExternalGPUProfiler.EndGPUCapture();
402406
}
403407

404408
static bool RasterizeGeometry(CommandBuffer cmd, Bounds cellAABB, GPUSubdivisionContext ctx, GIContributors contributors)
@@ -633,7 +637,7 @@ static void VoxelizeProbeVolumeData(CommandBuffer cmd, Bounds cellAABB,
633637

634638
static void SubdivideFromDistanceField(
635639
CommandBuffer cmd, Bounds volume, GPUSubdivisionContext ctx, RenderTexture probeVolumeData,
636-
ComputeBuffer buffer, int brickCount, int subdivisionLevel, float minBrickSize, Vector3 cellOffset)
640+
ComputeBuffer buffer, ComputeBuffer brickCountBuffer, int brickCount, int subdivisionLevel, float minBrickSize, Vector3 cellOffset)
637641
{
638642
using (new ProfilingScope(cmd, new ProfilingSampler($"Subdivide Bricks at level {Mathf.Log(brickCount, 3)}")))
639643
{
@@ -642,6 +646,7 @@ static void SubdivideFromDistanceField(
642646
Vector3 volumeBrickPosition = (volume.center - volume.extents - cellOffset) / minBrickSize;
643647
cmd.SetComputeVectorParam(subdivideSceneCS, _VolumeOffsetInBricks, volumeBrickPosition);
644648
cmd.SetComputeBufferParam(subdivideSceneCS, s_SubdivideKernel, _Bricks, buffer);
649+
cmd.SetComputeBufferParam(subdivideSceneCS, s_SubdivideKernel, _BrickCountBuffer, brickCountBuffer);
645650
cmd.SetComputeVectorParam(subdivideSceneCS, _MaxBrickSize, Vector3.one * brickCount);
646651
cmd.SetComputeFloatParam(subdivideSceneCS, _SubdivisionLevel, subdivisionLevel);
647652
cmd.SetComputeFloatParam(subdivideSceneCS, _MaxSubdivisionLevel, ctx.maxSubdivisionLevelInSubCell);

Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeSubdivide.compute

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ RWTexture3D<float4> _Output;
1919
RWTexture3D<float4> _FinalOutput;
2020

2121
// Technically float3, but AppendBuffers stride must be a multiple of 4
22-
AppendStructuredBuffer<float4> _Bricks;
22+
RWStructuredBuffer<float4> _Bricks;
23+
RWStructuredBuffer<uint> _BrickCountBuffer;
2324
RWStructuredBuffer<float3> _BricksToClear;
2425

2526
StructuredBuffer<GPUProbeVolumeOBB> _ProbeVolumes;
@@ -37,6 +38,7 @@ float _SubdivisionLevel;
3738
float _MaxSubdivisionLevel;
3839
float _ProbeVolumeCount;
3940
float _ClearValue;
41+
uint _BricksToClearCount;
4042
CBUFFER_END
4143

4244
[numthreads(8,8,1)]
@@ -51,6 +53,9 @@ void Clear(uint3 id : SV_DispatchThreadID)
5153
[numthreads(64,1,1)]
5254
void ClearBuffer(uint3 id : SV_DispatchThreadID)
5355
{
56+
if (id.x >=_BricksToClearCount)
57+
return;
58+
5459
_BricksToClear[id.x] = 0;
5560
}
5661

@@ -264,6 +269,8 @@ void Subdivide(uint3 id : SV_DispatchThreadID)
264269
{
265270
// transform id to world position
266271
float3 positionInCell = _VolumeOffsetInBricks.xyz + (id / _MaxBrickSize.xyz) * _VolumeSizeInBricks.xyz;
267-
_Bricks.Append(float4(positionInCell, 0.0f));
272+
uint brickIndex;
273+
InterlockedAdd(_BrickCountBuffer[_SubdivisionLevel], 1, brickIndex);
274+
_Bricks[brickIndex] = float4(positionInCell, 0.0f);
268275
}
269276
}

0 commit comments

Comments
 (0)