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

680 lines
28 KiB
C#

using System;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine.Assertions;
using UnityEngine.Rendering.RadeonRays;
#if UNITY_EDITOR
using UnityEditor.Embree;
#endif
namespace UnityEngine.Rendering.UnifiedRayTracing
{
internal class ComputeRayTracingAccelStruct : IRayTracingAccelStruct
{
internal ComputeRayTracingAccelStruct(
AccelerationStructureOptions options, RayTracingResources resources,
ReferenceCounter counter, int blasBufferInitialSizeBytes = 64 * 1024 * 1024)
{
m_CopyShader = resources.copyBuffer;
RadeonRaysShaders shaders = new RadeonRaysShaders();
shaders.bitHistogram = resources.bitHistogram;
shaders.blockReducePart = resources.blockReducePart;
shaders.blockScan = resources.blockScan;
shaders.buildHlbvh = resources.buildHlbvh;
shaders.restructureBvh = resources.restructureBvh;
shaders.scatter = resources.scatter;
m_RadeonRaysAPI = new RadeonRaysAPI(shaders);
m_BuildFlags = options.buildFlags;
#if UNITY_EDITOR
m_UseCpuBuild = options.useCPUBuild;
#endif
m_Blases = new Dictionary<(int mesh, int subMeshIndex), MeshBlas>();
var blasNodeCount = blasBufferInitialSizeBytes / RadeonRaysAPI.BvhInternalNodeSizeInBytes();
m_BlasBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, blasNodeCount, RadeonRaysAPI.BvhInternalNodeSizeInBytes());
m_BlasLeavesBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, blasNodeCount, RadeonRaysAPI.BvhLeafNodeSizeInBytes());
m_BlasPositions = new BLASPositionsPool(resources.copyPositions, resources.copyBuffer);
m_BlasAllocator = new BlockAllocator();
m_BlasAllocator.Initialize(blasNodeCount);
m_BlasLeavesAllocator = new BlockAllocator();
m_BlasLeavesAllocator.Initialize(blasNodeCount);
m_Counter = counter;
m_Counter.Inc();
}
internal GraphicsBuffer topLevelBvhBuffer { get { return m_TopLevelAccelStruct?.topLevelBvh; } }
internal GraphicsBuffer bottomLevelBvhBuffer { get { return m_TopLevelAccelStruct?.bottomLevelBvhs; } }
internal GraphicsBuffer instanceInfoBuffer { get { return m_TopLevelAccelStruct?.instanceInfos; } }
public void Dispose()
{
foreach (var blas in m_Blases.Values)
{
if (blas.buildInfo.triangleIndices != null)
blas.buildInfo.triangleIndices.Dispose();
}
m_Counter.Dec();
m_RadeonRaysAPI.Dispose();
m_BlasBuffer.Dispose();
m_BlasLeavesBuffer.Dispose();
m_BlasPositions.Dispose();
m_BlasAllocator.Dispose();
m_BlasLeavesAllocator.Dispose();
m_TopLevelAccelStruct?.Dispose();
}
public int AddInstance(MeshInstanceDesc meshInstance)
{
var blas = GetOrAllocateMeshBlas(meshInstance.mesh, meshInstance.subMeshIndex);
blas.IncRef();
FreeTopLevelAccelStruct();
int handle = NewHandle();
m_RadeonInstances.Add(handle, new RadeonRaysInstance
{
geomKey = (meshInstance.mesh.GetHashCode(), meshInstance.subMeshIndex),
blas = blas,
instanceMask = meshInstance.mask,
triangleCullingEnabled = meshInstance.enableTriangleCulling,
invertTriangleCulling = meshInstance.frontTriangleCounterClockwise,
userInstanceID = meshInstance.instanceID == 0xFFFFFFFF ? (uint)handle : meshInstance.instanceID,
localToWorldTransform = ConvertTranform(meshInstance.localToWorldMatrix)
});
return handle;
}
public void RemoveInstance(int instanceHandle)
{
ReleaseHandle(instanceHandle);
m_RadeonInstances.Remove(instanceHandle, out RadeonRaysInstance entry);
var meshBlas = entry.blas;
meshBlas.DecRef();
if (meshBlas.IsUnreferenced())
DeleteMeshBlas(entry.geomKey, meshBlas);
FreeTopLevelAccelStruct();
}
public void ClearInstances()
{
m_FreeHandles.Clear();
m_RadeonInstances.Clear();
foreach (var blas in m_Blases.Values)
{
if (blas.buildInfo.triangleIndices != null)
blas.buildInfo.triangleIndices.Dispose();
}
m_Blases.Clear();
m_BlasPositions.Clear();
var currentCapacity = m_BlasAllocator.capacity;
m_BlasAllocator.Dispose();
m_BlasAllocator = new BlockAllocator();
m_BlasAllocator.Initialize(currentCapacity);
currentCapacity = m_BlasLeavesAllocator.capacity;
m_BlasLeavesAllocator.Dispose();
m_BlasLeavesAllocator = new BlockAllocator();
m_BlasLeavesAllocator.Initialize(currentCapacity);
FreeTopLevelAccelStruct();
}
public void UpdateInstanceTransform(int instanceHandle, Matrix4x4 localToWorldMatrix)
{
m_RadeonInstances[instanceHandle].localToWorldTransform = ConvertTranform(localToWorldMatrix);
FreeTopLevelAccelStruct();
}
public void UpdateInstanceID(int instanceHandle, uint instanceID)
{
m_RadeonInstances[instanceHandle].userInstanceID = instanceID;
FreeTopLevelAccelStruct();
}
public void UpdateInstanceMask(int instanceHandle, uint mask)
{
m_RadeonInstances[instanceHandle].instanceMask = mask;
FreeTopLevelAccelStruct();
}
public void Build(CommandBuffer cmd, GraphicsBuffer scratchBuffer)
{
var requiredScratchSize = GetBuildScratchBufferRequiredSizeInBytes();
if (requiredScratchSize > 0 && (scratchBuffer == null || ((ulong)(scratchBuffer.count * scratchBuffer.stride) < requiredScratchSize)))
{
throw new System.ArgumentException("scratchBuffer size is too small");
}
if (requiredScratchSize > 0 && scratchBuffer.stride != 4)
{
throw new System.ArgumentException("scratchBuffer stride must be 4");
}
if (m_TopLevelAccelStruct != null)
return;
CreateBvh(cmd, scratchBuffer);
}
public ulong GetBuildScratchBufferRequiredSizeInBytes()
{
return GetBvhBuildScratchBufferSizeInDwords() * 4;
}
private void FreeTopLevelAccelStruct()
{
m_TopLevelAccelStruct?.Dispose();
m_TopLevelAccelStruct = null;
}
private MeshBlas GetOrAllocateMeshBlas(Mesh mesh, int subMeshIndex)
{
MeshBlas blas;
if (m_Blases.TryGetValue((mesh.GetHashCode(), subMeshIndex), out blas))
return blas;
blas = new MeshBlas();
AllocateBlas(mesh, subMeshIndex, blas);
m_Blases[(mesh.GetHashCode(), subMeshIndex)] = blas;
return blas;
}
void AllocateBlas(Mesh mesh, int submeshIndex, MeshBlas blas)
{
var bvhNodeSizeInDwords = RadeonRaysAPI.BvhInternalNodeSizeInDwords();
mesh.indexBufferTarget |= GraphicsBuffer.Target.Raw;
mesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
SubMeshDescriptor submeshDescriptor = mesh.GetSubMesh(submeshIndex);
using var vertexBuffer = LoadPositionBuffer(mesh, out int stride, out int offset);
GraphicsBuffer indexBuffer = null;
#if UNITY_EDITOR
if (!m_UseCpuBuild)
#endif
indexBuffer = LoadIndexBuffer(mesh);
var vertexBufferDesc = new VertexBufferChunk();
vertexBufferDesc.vertices = vertexBuffer;
vertexBufferDesc.verticesStartOffset = offset;
vertexBufferDesc.baseVertex = submeshDescriptor.baseVertex + submeshDescriptor.firstVertex;
vertexBufferDesc.vertexCount = (uint)submeshDescriptor.vertexCount;
vertexBufferDesc.vertexStride = (uint)stride;
m_BlasPositions.Add(vertexBufferDesc, out blas.blasVertices);
var meshBuildInfo = new MeshBuildInfo();
meshBuildInfo.vertices = m_BlasPositions.VertexBuffer;
meshBuildInfo.verticesStartOffset = blas.blasVertices.block.offset;
meshBuildInfo.baseVertex = 0;
meshBuildInfo.triangleIndices = indexBuffer;
meshBuildInfo.vertexCount = (uint)blas.blasVertices.block.count/3;
meshBuildInfo.triangleCount = (uint)submeshDescriptor.indexCount / 3;
meshBuildInfo.indicesStartOffset = submeshDescriptor.indexStart;
meshBuildInfo.baseIndex = -submeshDescriptor.firstVertex;
meshBuildInfo.indexFormat = mesh.indexFormat == IndexFormat.UInt32 ? RadeonRays.IndexFormat.Int32 : RadeonRays.IndexFormat.Int16;
meshBuildInfo.vertexStride = 3;
blas.buildInfo = meshBuildInfo;
#if UNITY_EDITOR
if (m_UseCpuBuild)
{
blas.indicesForCpuBuild = new List<int>();
mesh.GetTriangles(blas.indicesForCpuBuild, submeshIndex, false);
blas.baseIndexForCpuBuild = -submeshDescriptor.firstVertex;
blas.verticesForCpuBuild = new List<Vector3>();
mesh.GetVertices(blas.verticesForCpuBuild);
blas.bvhAlloc = BlockAllocator.Allocation.Invalid;
}
else
#endif
{
var requirements = m_RadeonRaysAPI.GetMeshBuildMemoryRequirements(meshBuildInfo, ConvertFlagsToGpuBuild(m_BuildFlags));
var allocationNodeCount = (int)(requirements.bvhSizeInDwords / (ulong)bvhNodeSizeInDwords);
blas.bvhAlloc = AllocateBlasInternalNodes(allocationNodeCount);
blas.bvhLeavesAlloc = AllocateBlasLeafNodes((int)meshBuildInfo.triangleCount);
if (!blas.bvhAlloc.valid || !blas.bvhLeavesAlloc.valid)
throw new UnifiedRayTracingException("Can't allocate a GraphicsBuffer bigger than 2GB", UnifiedRayTracingError.OutOfGraphicsBufferMemory);
}
}
private GraphicsBuffer LoadIndexBuffer(Mesh mesh)
{
Debug.Assert((mesh.indexBufferTarget & GraphicsBuffer.Target.Raw) != 0 || (mesh.GetIndices(0) != null && mesh.GetIndices(0).Length != 0),
"Cant use a mesh buffer that is not raw and has no CPU index information.");
return mesh.GetIndexBuffer();
}
GraphicsBuffer LoadPositionBuffer(Mesh mesh, out int stride, out int offset)
{
VertexAttribute attribute = VertexAttribute.Position;
Debug.Assert(mesh.HasVertexAttribute(attribute), "Cant use a mesh buffer that has no positions.");
int stream = mesh.GetVertexAttributeStream(attribute);
stride = mesh.GetVertexBufferStride(stream) / 4;
offset = mesh.GetVertexAttributeOffset(attribute) / 4;
return mesh.GetVertexBuffer(stream);
}
private void DeleteMeshBlas((int mesh, int subMeshIndex) geomKey, MeshBlas blas)
{
m_BlasAllocator.FreeAllocation(blas.bvhAlloc);
blas.bvhAlloc = BlockAllocator.Allocation.Invalid;
m_BlasLeavesAllocator.FreeAllocation(blas.bvhLeavesAlloc);
blas.bvhLeavesAlloc = BlockAllocator.Allocation.Invalid;
m_BlasPositions.Remove(ref blas.blasVertices);
if (blas.buildInfo.triangleIndices != null)
blas.buildInfo.triangleIndices.Dispose();
m_Blases.Remove(geomKey);
}
private ulong GetBvhBuildScratchBufferSizeInDwords()
{
#if UNITY_EDITOR
if (m_UseCpuBuild)
return 0;
#endif
var bvhNodeSizeInDwords = RadeonRaysAPI.BvhInternalNodeSizeInDwords();
ulong scratchBufferSize = 0;
foreach (var meshBlas in m_Blases)
{
if (meshBlas.Value.bvhBuilt)
continue;
var requirements = m_RadeonRaysAPI.GetMeshBuildMemoryRequirements(meshBlas.Value.buildInfo, ConvertFlagsToGpuBuild(m_BuildFlags));
Assert.AreEqual(requirements.bvhSizeInDwords / (ulong)bvhNodeSizeInDwords, (ulong)meshBlas.Value.bvhAlloc.block.count);
scratchBufferSize = math.max(scratchBufferSize, requirements.buildScratchSizeInDwords);
}
var topLevelScratchSize = m_RadeonRaysAPI.GetSceneBuildMemoryRequirements((uint)m_RadeonInstances.Count).buildScratchSizeInDwords;
scratchBufferSize = math.max(scratchBufferSize, topLevelScratchSize);
scratchBufferSize = math.max(4, scratchBufferSize);
return scratchBufferSize;
}
private void CreateBvh(CommandBuffer cmd, GraphicsBuffer scratchBuffer)
{
BuildMissingBottomLevelAccelStructs(cmd, scratchBuffer);
BuildTopLevelAccelStruct(cmd, scratchBuffer);
}
private void BuildMissingBottomLevelAccelStructs(CommandBuffer cmd, GraphicsBuffer scratchBuffer)
{
foreach (var meshBlas in m_Blases.Values)
{
if (meshBlas.bvhBuilt)
continue;
meshBlas.buildInfo.vertices = m_BlasPositions.VertexBuffer;
#if UNITY_EDITOR
if (m_UseCpuBuild)
{
CpuBuildForBottomLevelAccelStruct(cmd, meshBlas);
}
else
#endif
{
var blasDesc = new BottomLevelLevelAccelStruct(){
bvh = m_BlasBuffer,
bvhOffset = (uint)meshBlas.bvhAlloc.block.offset,
bvhLeaves = m_BlasLeavesBuffer,
bvhLeavesOffset = (uint)meshBlas.bvhLeavesAlloc.block.offset,
};
m_RadeonRaysAPI.BuildMeshAccelStruct(
cmd,
meshBlas.buildInfo, ConvertFlagsToGpuBuild(m_BuildFlags),
scratchBuffer, in blasDesc);
meshBlas.buildInfo.triangleIndices.Dispose();
meshBlas.buildInfo.triangleIndices = null;
}
meshBlas.bvhBuilt = true;
}
}
private void BuildTopLevelAccelStruct(CommandBuffer cmd, GraphicsBuffer scratchBuffer)
{
var radeonRaysInstances = new RadeonRays.Instance[m_RadeonInstances.Count];
int i = 0;
foreach (var instance in m_RadeonInstances.Values)
{
radeonRaysInstances[i].meshAccelStructOffset = (uint)instance.blas.bvhAlloc.block.offset;
radeonRaysInstances[i].localToWorldTransform = instance.localToWorldTransform;
radeonRaysInstances[i].instanceMask = instance.instanceMask;
radeonRaysInstances[i].vertexOffset = (uint)instance.blas.blasVertices.block.offset;
radeonRaysInstances[i].meshAccelStructLeavesOffset = (uint)instance.blas.bvhLeavesAlloc.block.offset;
radeonRaysInstances[i].triangleCullingEnabled = instance.triangleCullingEnabled;
radeonRaysInstances[i].invertTriangleCulling = instance.invertTriangleCulling;
radeonRaysInstances[i].userInstanceID = instance.userInstanceID;
i++;
}
m_TopLevelAccelStruct?.Dispose();
#if UNITY_EDITOR
if (m_UseCpuBuild)
m_TopLevelAccelStruct = CpuBuildForTopLevelAccelStruct(cmd, radeonRaysInstances);
else
#endif
m_TopLevelAccelStruct = m_RadeonRaysAPI.BuildSceneAccelStruct(cmd, m_BlasBuffer, radeonRaysInstances, scratchBuffer);
}
#if UNITY_EDITOR
void CpuBuildForBottomLevelAccelStruct(CommandBuffer cmd, MeshBlas blas)
{
var vertices = blas.verticesForCpuBuild;
var indices = blas.indicesForCpuBuild;
var prims = new GpuBvhPrimitiveDescriptor[blas.buildInfo.triangleCount];
for (int i = 0; i < blas.buildInfo.triangleCount; ++i)
{
var triangleIndices = GetFaceIndices(indices, i);
var triangle = GetTriangle(vertices, triangleIndices);
AABB aabb = new AABB();
aabb.Encapsulate(triangle.v0);
aabb.Encapsulate(triangle.v1);
aabb.Encapsulate(triangle.v2);
prims[i].primID = (uint)i;
prims[i].lowerBound = aabb.Min;
prims[i].upperBound = aabb.Max;
}
blas.indicesForCpuBuild = null;
blas.verticesForCpuBuild = null;
var options = ConvertFlagsToCpuBuild(m_BuildFlags, false);
var bvhBlob = GpuBvh.Build(options, prims);
var internalNodeCount = bvhBlob[0];
var leafNodeCount = bvhBlob[1];
var bvhSizeInDwords = RadeonRaysAPI.BvhInternalNodeSizeInDwords() * ((int)internalNodeCount + 1);
var bvhLeavesSizeInDwords = bvhBlob.Length - bvhSizeInDwords;
blas.bvhAlloc = AllocateBlasInternalNodes((int)internalNodeCount);
blas.bvhLeavesAlloc = AllocateBlasLeafNodes((int)leafNodeCount);
// Fill triangle indices in leaf nodes.
int leafOffset = bvhSizeInDwords;
for (int i = 0; i < leafNodeCount; ++i)
{
var triangleIndices = GetFaceIndices(indices,(int) bvhBlob[leafOffset+3]);
bvhBlob[leafOffset] = (uint)(triangleIndices.x + blas.baseIndexForCpuBuild);
bvhBlob[leafOffset+1] = (uint)(triangleIndices.y + blas.baseIndexForCpuBuild);
bvhBlob[leafOffset+2] = (uint)(triangleIndices.z + blas.baseIndexForCpuBuild);
leafOffset += 4;
}
var bvhStartInDwords = blas.bvhAlloc.block.offset * RadeonRaysAPI.BvhInternalNodeSizeInDwords();
cmd.SetBufferData(m_BlasBuffer, bvhBlob, 0, bvhStartInDwords, bvhSizeInDwords);
var bvhLeavesStartInDwords = blas.bvhLeavesAlloc.block.offset * RadeonRaysAPI.BvhLeafNodeSizeInDwords();
cmd.SetBufferData(m_BlasLeavesBuffer, bvhBlob, bvhSizeInDwords, bvhLeavesStartInDwords, bvhLeavesSizeInDwords);
// read mesh aabb from bvh header.
blas.aabbForCpuBuild = new AABB();
blas.aabbForCpuBuild.Min.x = math.asfloat(bvhBlob[4]);
blas.aabbForCpuBuild.Min.y = math.asfloat(bvhBlob[5]);
blas.aabbForCpuBuild.Min.z = math.asfloat(bvhBlob[6]);
blas.aabbForCpuBuild.Max.x = math.asfloat(bvhBlob[7]);
blas.aabbForCpuBuild.Max.y = math.asfloat(bvhBlob[8]);
blas.aabbForCpuBuild.Max.z = math.asfloat(bvhBlob[9]);
}
TopLevelAccelStruct CpuBuildForTopLevelAccelStruct(CommandBuffer cmd, RadeonRays.Instance[] radeonRaysInstances)
{
var prims = new GpuBvhPrimitiveDescriptor[m_RadeonInstances.Count];
int i = 0;
foreach (var instance in m_RadeonInstances.Values)
{
var blas = instance.blas;
AABB aabb = blas.aabbForCpuBuild;
var m = ConvertTranform(instance.localToWorldTransform);
var bounds = GeometryUtility.CalculateBounds(new Vector3[]
{ new Vector3(aabb.Min.x, aabb.Min.y, aabb.Max.z),
new Vector3(aabb.Min.x, aabb.Max.y, aabb.Min.z),
new Vector3(aabb.Min.x, aabb.Max.y, aabb.Max.z),
new Vector3(aabb.Max.x, aabb.Min.y, aabb.Max.z),
new Vector3(aabb.Max.x, aabb.Max.y, aabb.Min.z),
new Vector3(aabb.Max.x, aabb.Max.y, aabb.Max.z)
}, m);
prims[i].primID = (uint)i;
prims[i].lowerBound = bounds.min;
prims[i].upperBound = bounds.max;
i++;
}
if (m_RadeonInstances.Count != 0)
{
var options = ConvertFlagsToCpuBuild(m_BuildFlags, true);
var bvhBlob = GpuBvh.Build(options, prims);
var bvhSizeInDwords = bvhBlob.Length;
var result = m_RadeonRaysAPI.CreateSceneAccelStructBuffers(m_BlasBuffer, (uint)bvhSizeInDwords, radeonRaysInstances);
cmd.SetBufferData(result.topLevelBvh, bvhBlob);
return result;
}
else
{
return m_RadeonRaysAPI.CreateSceneAccelStructBuffers(m_BlasBuffer, 0, radeonRaysInstances);
}
}
GpuBvhBuildOptions ConvertFlagsToCpuBuild(BuildFlags flags, bool isTopLevel)
{
GpuBvhBuildQuality quality = GpuBvhBuildQuality.Medium;
if ((flags & BuildFlags.PreferFastBuild) != 0 && (flags & BuildFlags.PreferFastTrace) == 0)
quality = GpuBvhBuildQuality.Low;
else if ((flags & BuildFlags.PreferFastTrace) != 0 && (flags & BuildFlags.PreferFastBuild) == 0)
quality = GpuBvhBuildQuality.High;
return new GpuBvhBuildOptions
{
quality = quality,
minLeafSize = (flags & BuildFlags.MinimizeMemory) != 0 && !isTopLevel ? 4u : 1u,
maxLeafSize = isTopLevel ? 1u : 4u,
allowPrimitiveSplits = !isTopLevel && (flags & BuildFlags.MinimizeMemory) == 0,
isTopLevel = isTopLevel
};
}
#endif
RadeonRays.BuildFlags ConvertFlagsToGpuBuild(BuildFlags flags)
{
if ((flags & BuildFlags.PreferFastBuild) != 0 && (flags & BuildFlags.PreferFastTrace) == 0)
return RadeonRays.BuildFlags.PreferFastBuild;
else
return RadeonRays.BuildFlags.None;
}
public void Bind(CommandBuffer cmd, string name, IRayTracingShader shader)
{
shader.SetBufferParam(cmd, Shader.PropertyToID(name + "bvh"), topLevelBvhBuffer);
shader.SetBufferParam(cmd, Shader.PropertyToID(name + "bottomBvhs"), bottomLevelBvhBuffer);
shader.SetBufferParam(cmd, Shader.PropertyToID(name + "bottomBvhLeaves"), m_BlasLeavesBuffer);
shader.SetBufferParam(cmd, Shader.PropertyToID(name + "instanceInfos"), instanceInfoBuffer);
shader.SetBufferParam(cmd, Shader.PropertyToID(name + "vertexBuffer"), m_BlasPositions.VertexBuffer);
shader.SetIntParam(cmd, Shader.PropertyToID(name + "vertexStride"), 3);
}
static private RadeonRays.Transform ConvertTranform(Matrix4x4 input)
{
return new RadeonRays.Transform()
{
row0 = input.GetRow(0),
row1 = input.GetRow(1),
row2 = input.GetRow(2)
};
}
static private Matrix4x4 ConvertTranform(RadeonRays.Transform input)
{
var m = new Matrix4x4();
m.SetRow(0, input.row0);
m.SetRow(1, input.row1);
m.SetRow(2, input.row2);
m.SetRow(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
return m;
}
static int3 GetFaceIndices(List<int> indices, int triangleIdx)
{
return new int3(
indices[3 * triangleIdx],
indices[3 * triangleIdx + 1],
indices[3 * triangleIdx + 2]);
}
struct Triangle
{
public float3 v0;
public float3 v1;
public float3 v2;
};
static Triangle GetTriangle(List<Vector3> vertices, int3 idx)
{
Triangle tri;
tri.v0 = vertices[idx.x];
tri.v1 = vertices[idx.y];
tri.v2 = vertices[idx.z];
return tri;
}
BlockAllocator.Allocation AllocateBlasInternalNodes(int allocationNodeCount)
{
var allocation = m_BlasAllocator.Allocate(allocationNodeCount);
if (!allocation.valid)
{
allocation = m_BlasAllocator.GrowAndAllocate(allocationNodeCount, int.MaxValue / RadeonRaysAPI.BvhInternalNodeSizeInBytes(), out int oldCapacity, out int newCapacity);
if (!allocation.valid)
return allocation;
var newBlasBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, newCapacity, RadeonRaysAPI.BvhInternalNodeSizeInBytes());
GraphicsHelpers.CopyBuffer(m_CopyShader, m_BlasBuffer, 0, newBlasBuffer, 0, oldCapacity * RadeonRaysAPI.BvhInternalNodeSizeInDwords());
m_BlasBuffer.Dispose();
m_BlasBuffer = newBlasBuffer;
}
return allocation;
}
BlockAllocator.Allocation AllocateBlasLeafNodes(int allocationNodeCount)
{
var allocation = m_BlasLeavesAllocator.Allocate(allocationNodeCount);
if (!allocation.valid)
{
allocation = m_BlasLeavesAllocator.GrowAndAllocate(allocationNodeCount, int.MaxValue / RadeonRaysAPI.BvhLeafNodeSizeInBytes(), out int oldCapacity, out int newCapacity);
if (!allocation.valid)
return allocation;
var newBlasLeavesBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, newCapacity, RadeonRaysAPI.BvhLeafNodeSizeInBytes());
GraphicsHelpers.CopyBuffer(m_CopyShader, m_BlasLeavesBuffer, 0, newBlasLeavesBuffer, 0, oldCapacity * RadeonRaysAPI.BvhLeafNodeSizeInDwords());
m_BlasLeavesBuffer.Dispose();
m_BlasLeavesBuffer = newBlasLeavesBuffer;
}
return allocation;
}
readonly uint m_HandleObfuscation = (uint)Random.Range(int.MinValue, int.MaxValue);
int NewHandle()
{
if (m_FreeHandles.Count != 0)
return (int)(m_FreeHandles.Dequeue() ^ m_HandleObfuscation);
else
return (int)((uint)m_RadeonInstances.Count ^ m_HandleObfuscation);
}
void ReleaseHandle(int handle)
{
m_FreeHandles.Enqueue((uint)handle ^ m_HandleObfuscation);
}
readonly RadeonRaysAPI m_RadeonRaysAPI;
readonly BuildFlags m_BuildFlags;
#if UNITY_EDITOR
readonly bool m_UseCpuBuild;
#endif
readonly ReferenceCounter m_Counter;
readonly Dictionary<(int mesh, int subMeshIndex), MeshBlas> m_Blases;
BlockAllocator m_BlasAllocator;
GraphicsBuffer m_BlasBuffer;
BlockAllocator m_BlasLeavesAllocator;
GraphicsBuffer m_BlasLeavesBuffer;
readonly BLASPositionsPool m_BlasPositions;
TopLevelAccelStruct? m_TopLevelAccelStruct = null;
readonly ComputeShader m_CopyShader;
readonly Dictionary<int, RadeonRaysInstance> m_RadeonInstances = new ();
readonly Queue<uint> m_FreeHandles = new();
sealed class RadeonRaysInstance
{
public (int mesh, int subMeshIndex) geomKey;
public MeshBlas blas;
public uint instanceMask;
public bool triangleCullingEnabled;
public bool invertTriangleCulling;
public uint userInstanceID;
public RadeonRays.Transform localToWorldTransform;
}
sealed class MeshBlas
{
public MeshBuildInfo buildInfo;
public BlockAllocator.Allocation bvhAlloc;
public BlockAllocator.Allocation bvhLeavesAlloc;
public BlockAllocator.Allocation blasVertices;
#if UNITY_EDITOR
public AABB aabbForCpuBuild;
public List<int> indicesForCpuBuild;
public int baseIndexForCpuBuild;
public List<Vector3> verticesForCpuBuild;
#endif
public bool bvhBuilt = false;
private uint refCount = 0;
public void IncRef() { refCount++; }
public void DecRef() { refCount--; }
public bool IsUnreferenced() { return refCount == 0; }
}
}
}