UnityGame/Library/PackageCache/com.unity.rendering.light-transport/Runtime/UnifiedRayTracing/Compute/RadeonRays/HlbvhTopLevelBuilder.cs
2024-10-27 10:53:47 +03:00

188 lines
8.3 KiB
C#

using System;
using System.Runtime.InteropServices;
using Unity.Mathematics;
namespace UnityEngine.Rendering.RadeonRays
{
internal struct TopLevelAccelStruct : IDisposable
{
public const GraphicsBuffer.Target topLevelBvhTarget = GraphicsBuffer.Target.Structured;
public const GraphicsBuffer.Target instanceInfoTarget = GraphicsBuffer.Target.Structured;
public GraphicsBuffer topLevelBvh;
public GraphicsBuffer bottomLevelBvhs;
public GraphicsBuffer instanceInfos;
public uint instanceCount;
public void Dispose()
{
topLevelBvh?.Dispose();
instanceInfos?.Dispose();
}
}
internal class HlbvhTopLevelBuilder
{
readonly ComputeShader shaderBuildHlbvh;
readonly int kernelInit;
readonly int kernelCalculateAabb;
readonly int kernelCalculateMortonCodes;
readonly int kernelBuildTreeBottomUp;
readonly RadixSort radixSort;
const uint kTrianglesPerThread = 8u;
const uint kGroupSize = 256u;
const uint kTrianglesPerGroup = kTrianglesPerThread * kGroupSize;
public HlbvhTopLevelBuilder(RadeonRaysShaders shaders)
{
shaderBuildHlbvh = shaders.buildHlbvh;
kernelInit = shaderBuildHlbvh.FindKernel("Init");
kernelCalculateAabb = shaderBuildHlbvh.FindKernel("CalculateAabb");
kernelCalculateMortonCodes = shaderBuildHlbvh.FindKernel("CalculateMortonCodes");
kernelBuildTreeBottomUp = shaderBuildHlbvh.FindKernel("BuildTreeBottomUp");
radixSort = new RadixSort(shaders);
}
public ulong GetScratchDataSizeInDwords(uint instanceCount)
{
var scratchLayout = ScratchBufferLayout.Create(instanceCount);
return scratchLayout.TotalSize;
}
public static uint GetBvhNodeCount(uint leafCount)
{
return leafCount - 1;
}
public void AllocateResultBuffers(uint instanceCount, ref TopLevelAccelStruct accelStruct)
{
var bvhNodeCount = GetBvhNodeCount(instanceCount);
accelStruct.Dispose();
accelStruct.instanceInfos = new GraphicsBuffer(TopLevelAccelStruct.instanceInfoTarget, (int)instanceCount, Marshal.SizeOf<InstanceInfo>());
accelStruct.topLevelBvh = new GraphicsBuffer(TopLevelAccelStruct.topLevelBvhTarget, (int)bvhNodeCount + 1, Marshal.SizeOf<BvhNode>()); // plus one for header
}
public void CreateEmpty(ref TopLevelAccelStruct accelStruct)
{
accelStruct.Dispose();
accelStruct.topLevelBvh = new GraphicsBuffer(TopLevelAccelStruct.topLevelBvhTarget, 2, Marshal.SizeOf<BvhNode>());
accelStruct.instanceInfos = accelStruct.topLevelBvh;
accelStruct.bottomLevelBvhs = accelStruct.topLevelBvh;
accelStruct.instanceCount = 0;
var top = new BvhNode[2];
top[0].child0 = 0;
top[0].child1 = 0;
top[0].parent = 0;
top[1].child0 = 0;
top[1].child1 = 0;
top[1].parent = 0xFFFFFFFF;
top[1].update = 0;
top[1].aabb0_min = new float3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
top[1].aabb0_max = new float3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
top[1].aabb1_min = new float3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
top[1].aabb1_max = new float3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
accelStruct.topLevelBvh.SetData(top);
}
public void Execute(CommandBuffer cmd, GraphicsBuffer scratch, ref TopLevelAccelStruct accelStruct)
{
Common.EnableKeyword(cmd, shaderBuildHlbvh, "TOP_LEVEL", true);
Common.EnableKeyword(cmd, shaderBuildHlbvh, "UINT16_INDICES", false);
uint instanceCount = accelStruct.instanceCount;
var scratchLayout = ScratchBufferLayout.Create(instanceCount);
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_constants_vertex_stride, 0);
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_constants_triangle_count, (int)instanceCount);
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_bvh_offset, 0);
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_internal_node_range_offset, (int)scratchLayout.InternalNodeRange);
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_aabb_offset, (int)scratchLayout.Aabb);
BindKernelArguments(cmd, kernelInit, scratch, scratchLayout, accelStruct, false);
cmd.DispatchCompute(shaderBuildHlbvh, kernelInit, 1, 1, 1);
BindKernelArguments(cmd, kernelCalculateAabb, scratch, scratchLayout, accelStruct, false);
cmd.DispatchCompute(shaderBuildHlbvh, kernelCalculateAabb, (int)Common.CeilDivide(instanceCount, kTrianglesPerGroup), 1, 1);
BindKernelArguments(cmd, kernelCalculateMortonCodes, scratch, scratchLayout, accelStruct, false);
cmd.DispatchCompute(shaderBuildHlbvh, kernelCalculateMortonCodes, (int)Common.CeilDivide(instanceCount, kTrianglesPerGroup), 1, 1);
radixSort.Execute(cmd, scratch,
scratchLayout.MortonCodes, scratchLayout.SortedMortonCodes,
scratchLayout.PrimitiveRefs, scratchLayout.SortedPrimitiveRefs,
scratchLayout.SortMemory, instanceCount);
BindKernelArguments(cmd, kernelBuildTreeBottomUp, scratch, scratchLayout, accelStruct, true);
cmd.DispatchCompute(shaderBuildHlbvh, kernelBuildTreeBottomUp, (int)Common.CeilDivide(instanceCount, kTrianglesPerGroup), 1, 1);
}
struct ScratchBufferLayout
{
public uint Aabb;
public uint MortonCodes;
public uint PrimitiveRefs;
public uint SortedMortonCodes;
public uint SortedPrimitiveRefs;
public uint SortMemory;
public uint InternalNodeRange;
public uint TotalSize;
public static ScratchBufferLayout Create(uint instanceCount)
{
var result = new ScratchBufferLayout();
result.Aabb = result.Reserve(6);
result.MortonCodes = result.Reserve(instanceCount);
result.PrimitiveRefs = result.Reserve(instanceCount);
result.SortedMortonCodes = result.Reserve(instanceCount);
result.SortedPrimitiveRefs = result.Reserve(instanceCount);
result.SortMemory = result.Reserve((uint)RadixSort.GetScratchDataSizeInDwords(instanceCount));
// overlaps with MortonCodes and PrimitiveRefs
result.InternalNodeRange = result.MortonCodes;
return result;
}
uint Reserve(uint size)
{
var temp = TotalSize;
TotalSize += size;
return temp;
}
}
private void BindKernelArguments(
CommandBuffer cmd,
int kernel,
GraphicsBuffer scratch,
ScratchBufferLayout scratchLayout,
TopLevelAccelStruct accelStruct,
bool setSortedCodes)
{
cmd.SetComputeBufferParam(shaderBuildHlbvh, kernel, SID.g_scratch_buffer, scratch);
cmd.SetComputeBufferParam(shaderBuildHlbvh, kernel, SID.g_bvh, accelStruct.topLevelBvh);
cmd.SetComputeBufferParam(shaderBuildHlbvh, kernel, SID.g_bottom_bvhs, accelStruct.bottomLevelBvhs);
cmd.SetComputeBufferParam(shaderBuildHlbvh, kernel, SID.g_instance_infos, accelStruct.instanceInfos);
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_aabb_offset, (int)scratchLayout.Aabb);
if (setSortedCodes)
{
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_morton_codes_offset, (int)scratchLayout.SortedMortonCodes);
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_primitive_refs_offset, (int)scratchLayout.SortedPrimitiveRefs);
}
else
{
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_morton_codes_offset, (int)scratchLayout.MortonCodes);
cmd.SetComputeIntParam(shaderBuildHlbvh, SID.g_primitive_refs_offset, (int)scratchLayout.PrimitiveRefs);
}
}
}
}