137 lines
6.1 KiB
C#
137 lines
6.1 KiB
C#
|
using System;
|
||
|
using System.IO;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using Unity.Mathematics;
|
||
|
|
||
|
namespace UnityEngine.Rendering.RadeonRays
|
||
|
{
|
||
|
internal sealed class RestructureBvh : IDisposable
|
||
|
{
|
||
|
readonly ComputeShader shader;
|
||
|
readonly int kernelInitPrimitiveCounts;
|
||
|
readonly int kernelFindTreeletRoots;
|
||
|
readonly int kernelRestructure;
|
||
|
readonly int kernelPrepareTreeletsDispatchSize;
|
||
|
const int numIterations = 3;
|
||
|
readonly GraphicsBuffer treeletDispatchIndirectBuffer;
|
||
|
|
||
|
const uint kGroupSize = 256u;
|
||
|
const uint kTrianglesPerThread = 8u;
|
||
|
const uint kTrianglesPerGroup = kTrianglesPerThread * kGroupSize;
|
||
|
const uint kMinPrimitivesPerTreelet = 64u;
|
||
|
const int kMaxThreadGroupsPerDispatch = 65535;
|
||
|
|
||
|
public RestructureBvh(RadeonRaysShaders shaders)
|
||
|
{
|
||
|
shader = shaders.restructureBvh;
|
||
|
kernelInitPrimitiveCounts = shader.FindKernel("InitPrimitiveCounts");
|
||
|
kernelFindTreeletRoots = shader.FindKernel("FindTreeletRoots");
|
||
|
kernelRestructure = shader.FindKernel("Restructure");
|
||
|
kernelPrepareTreeletsDispatchSize = shader.FindKernel("PrepareTreeletsDispatchSize");
|
||
|
|
||
|
treeletDispatchIndirectBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, 6, sizeof(uint));
|
||
|
}
|
||
|
public void Dispose()
|
||
|
{
|
||
|
treeletDispatchIndirectBuffer.Dispose();
|
||
|
}
|
||
|
|
||
|
public ulong GetScratchDataSizeInDwords(uint triangleCount)
|
||
|
{
|
||
|
var scratchLayout = ScratchBufferLayout.Create(triangleCount);
|
||
|
return scratchLayout.TotalSize;
|
||
|
}
|
||
|
|
||
|
public static uint GetBvhNodeCount(uint leafCount)
|
||
|
{
|
||
|
return leafCount - 1;
|
||
|
}
|
||
|
|
||
|
public void Execute(
|
||
|
CommandBuffer cmd,
|
||
|
GraphicsBuffer vertices, int verticesOffset, uint vertexStride, uint triangleCount,
|
||
|
GraphicsBuffer scratch, in BottomLevelLevelAccelStruct result)
|
||
|
{
|
||
|
var scratchLayout = ScratchBufferLayout.Create(triangleCount);
|
||
|
Common.EnableKeyword(cmd, shader, "TOP_LEVEL", false);
|
||
|
|
||
|
cmd.SetComputeIntParam(shader, SID.g_vertices_offset, verticesOffset);
|
||
|
cmd.SetComputeIntParam(shader, SID.g_constants_vertex_stride, (int)vertexStride);
|
||
|
cmd.SetComputeIntParam(shader, SID.g_constants_triangle_count, (int)triangleCount);
|
||
|
cmd.SetComputeIntParam(shader, SID.g_treelet_count_offset, (int)scratchLayout.TreeletCount);
|
||
|
cmd.SetComputeIntParam(shader, SID.g_treelet_roots_offset, (int)scratchLayout.TreeletRoots);
|
||
|
cmd.SetComputeIntParam(shader, SID.g_primitive_counts_offset, (int)scratchLayout.PrimitiveCounts);
|
||
|
cmd.SetComputeIntParam(shader, SID.g_leaf_parents_offset, (int)scratchLayout.LeafParents);
|
||
|
cmd.SetComputeIntParam(shader, SID.g_bvh_offset, (int)result.bvhOffset);
|
||
|
cmd.SetComputeIntParam(shader, SID.g_bvh_leaves_offset, (int)result.bvhLeavesOffset);
|
||
|
|
||
|
uint minPrimitivePerTreelet = kMinPrimitivesPerTreelet;
|
||
|
for (int i = 0; i < numIterations; ++i)
|
||
|
{
|
||
|
cmd.SetComputeIntParam(shader, SID.g_constants_min_prims_per_treelet, (int)minPrimitivePerTreelet);
|
||
|
|
||
|
BindKernelArguments(cmd, kernelInitPrimitiveCounts, vertices, scratch, result);
|
||
|
cmd.DispatchCompute(shader, kernelInitPrimitiveCounts, (int)Common.CeilDivide(kTrianglesPerGroup, kGroupSize), 1, 1);
|
||
|
|
||
|
BindKernelArguments(cmd, kernelFindTreeletRoots, vertices, scratch, result);
|
||
|
cmd.DispatchCompute(shader, kernelFindTreeletRoots, (int)Common.CeilDivide(kTrianglesPerGroup, kGroupSize), 1, 1);
|
||
|
|
||
|
BindKernelArguments(cmd, kernelPrepareTreeletsDispatchSize, vertices, scratch, result);
|
||
|
cmd.DispatchCompute(shader, kernelPrepareTreeletsDispatchSize, 1, 1, 1);
|
||
|
|
||
|
BindKernelArguments(cmd, kernelRestructure, vertices, scratch, result);
|
||
|
cmd.SetComputeIntParam(shader, SID.g_remainder_treelets, 0);
|
||
|
cmd.DispatchCompute(shader, kernelRestructure, treeletDispatchIndirectBuffer, 0);
|
||
|
|
||
|
if (Common.CeilDivide(triangleCount, minPrimitivePerTreelet) > kMaxThreadGroupsPerDispatch)
|
||
|
{
|
||
|
cmd.SetComputeIntParam(shader, SID.g_remainder_treelets, 1);
|
||
|
cmd.DispatchCompute(shader, kernelRestructure, treeletDispatchIndirectBuffer, 3 * sizeof(uint));
|
||
|
}
|
||
|
|
||
|
minPrimitivePerTreelet *= 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void BindKernelArguments(
|
||
|
CommandBuffer cmd, int kernel,
|
||
|
GraphicsBuffer vertices,
|
||
|
GraphicsBuffer scratch, BottomLevelLevelAccelStruct result)
|
||
|
{
|
||
|
cmd.SetComputeBufferParam(shader, kernel, SID.g_vertices, vertices);
|
||
|
cmd.SetComputeBufferParam(shader, kernel, SID.g_scratch_buffer, scratch);
|
||
|
cmd.SetComputeBufferParam(shader, kernel, SID.g_bvh, result.bvh);
|
||
|
cmd.SetComputeBufferParam(shader, kernel, SID.g_bvh_leaves, result.bvhLeaves);
|
||
|
cmd.SetComputeBufferParam(shader, kernel, SID.g_treelet_dispatch_buffer, treeletDispatchIndirectBuffer);
|
||
|
}
|
||
|
|
||
|
struct ScratchBufferLayout
|
||
|
{
|
||
|
public uint LeafParents;
|
||
|
public uint TreeletCount;
|
||
|
public uint TreeletRoots;
|
||
|
public uint PrimitiveCounts;
|
||
|
public uint TotalSize;
|
||
|
|
||
|
public static ScratchBufferLayout Create(uint triangleCount)
|
||
|
{
|
||
|
var result = new ScratchBufferLayout();
|
||
|
result.LeafParents = result.Reserve(triangleCount);
|
||
|
result.TreeletCount = result.Reserve(1);
|
||
|
result.TreeletRoots = result.Reserve(triangleCount);
|
||
|
result.PrimitiveCounts = result.Reserve(GetBvhNodeCount(triangleCount));
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
uint Reserve(uint size)
|
||
|
{
|
||
|
var temp = TotalSize;
|
||
|
TotalSize += size;
|
||
|
return temp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|