No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RadeonRaysAPI.cs 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. using System;
  2. using System.IO;
  3. using System.Runtime.InteropServices;
  4. using Unity.Mathematics;
  5. namespace UnityEngine.Rendering.RadeonRays
  6. {
  7. enum IndexFormat { Int32 = 0, Int16 };
  8. internal struct MeshBuildInfo
  9. {
  10. public GraphicsBuffer vertices;
  11. public int verticesStartOffset; // in DWORD
  12. public uint vertexCount;
  13. public uint vertexStride; // in DWORD
  14. public int baseVertex;
  15. public GraphicsBuffer triangleIndices;
  16. public int indicesStartOffset; // in DWORD
  17. public int baseIndex;
  18. public IndexFormat indexFormat;
  19. public uint triangleCount;
  20. }
  21. internal struct MeshBuildMemoryRequirements
  22. {
  23. public ulong buildScratchSizeInDwords;
  24. public ulong resultSizeInDwords;
  25. }
  26. internal struct SceneBuildMemoryRequirements
  27. {
  28. public ulong buildScratchSizeInDwords;
  29. }
  30. internal class SceneMemoryRequirements
  31. {
  32. public ulong buildScratchSizeInDwords;
  33. public ulong[] bottomLevelBvhSizeInDwords;
  34. public uint[] bottomLevelBvhOffsetInNodes;
  35. public ulong totalBottomLevelBvhSizeInDwords;
  36. }
  37. [System.Flags]
  38. internal enum BuildFlags
  39. {
  40. None = 0,
  41. PreferFastBuild = 1 << 0,
  42. MinimizeMemory = 1 << 1
  43. }
  44. internal enum RayQueryType
  45. {
  46. ClosestHit,
  47. AnyHit
  48. }
  49. internal enum RayQueryOutputType
  50. {
  51. FullHitData,
  52. InstanceID
  53. }
  54. [StructLayout(LayoutKind.Sequential)]
  55. internal struct Transform
  56. {
  57. public float4 row0;
  58. public float4 row1;
  59. public float4 row2;
  60. public Transform(float4 row0, float4 row1, float4 row2)
  61. {
  62. this.row0 = row0;
  63. this.row1 = row1;
  64. this.row2 = row2;
  65. }
  66. public static Transform Identity()
  67. {
  68. return new Transform(
  69. new float4(1.0f, 0.0f, 0.0f, 0.0f),
  70. new float4(0.0f, 1.0f, 0.0f, 0.0f),
  71. new float4(0.0f, 0.0f, 1.0f, 0.0f));
  72. }
  73. public static Transform Translation(float3 translation)
  74. {
  75. return new Transform(
  76. new float4(1.0f, 0.0f, 0.0f, translation.x),
  77. new float4(0.0f, 1.0f, 0.0f, translation.y),
  78. new float4(0.0f, 0.0f, 1.0f, translation.z));
  79. }
  80. public static Transform Scale(float3 scale)
  81. {
  82. return new Transform(
  83. new float4(scale.x, 0.0f, 0.0f, 0.0f),
  84. new float4(0.0f, scale.y, 0.0f, 0.0f),
  85. new float4(0.0f, 0.0f, scale.z, 0.0f));
  86. }
  87. public static Transform TRS(float3 translation, float3 rotation, float3 scale)
  88. {
  89. var rot = float3x3.Euler(rotation);
  90. rot.c0 *= scale.x;
  91. rot.c1 *= scale.y;
  92. rot.c2 *= scale.z;
  93. return new Transform(
  94. new float4(rot.c0.x, rot.c1.x, rot.c2.x, translation.x),
  95. new float4(rot.c0.y, rot.c1.y, rot.c2.y, translation.y),
  96. new float4(rot.c0.z, rot.c1.z, rot.c2.z, translation.z));
  97. }
  98. public Transform Inverse()
  99. {
  100. float4x4 m = new float4x4();
  101. m[0] = new float4(row0.x, row1.x, row2.x, 0);
  102. m[1] = new float4(row0.y, row1.y, row2.y, 0);
  103. m[2] = new float4(row0.z, row1.z, row2.z, 0);
  104. m[3] = new float4(row0.w, row1.w, row2.w, 1);
  105. m = math.fastinverse(m);
  106. Transform res;
  107. res.row0 = new float4(m[0].x, m[1].x, m[2].x, m[3].x);
  108. res.row1 = new float4(m[0].y, m[1].y, m[2].y, m[3].y);
  109. res.row2 = new float4(m[0].z, m[1].z, m[2].z, m[3].z);
  110. return res;
  111. }
  112. }
  113. [StructLayout(LayoutKind.Sequential)]
  114. internal struct BvhNode
  115. {
  116. public uint child0;
  117. public uint child1;
  118. public uint parent;
  119. public uint update;
  120. public uint3 aabb0_min;
  121. public uint3 aabb0_max;
  122. public uint3 aabb1_min;
  123. public uint3 aabb1_max;
  124. }
  125. [StructLayout(LayoutKind.Sequential)]
  126. internal struct BvhHeader
  127. {
  128. public uint totalNodeCount;
  129. public uint leafNodeCount;
  130. public uint root;
  131. public uint unused;
  132. public uint3 unused1;
  133. public uint3 unused2;
  134. public uint3 unused3;
  135. public uint3 unused4;
  136. }
  137. internal struct Instance
  138. {
  139. public uint meshAccelStructOffset;
  140. public uint instanceMask;
  141. public uint vertexOffset;
  142. public uint indexOffset;
  143. public bool triangleCullingEnabled;
  144. public bool invertTriangleCulling;
  145. public uint userInstanceID;
  146. public Transform localToWorldTransform;
  147. }
  148. [StructLayout(LayoutKind.Sequential)]
  149. internal struct InstanceInfo
  150. {
  151. public int blasOffset;
  152. public int instanceMask;
  153. public int vertexOffset;
  154. public int indexOffset;
  155. public int triangleCullingEnabled;
  156. public int invertTriangleCulling;
  157. public uint userInstanceID;
  158. public int padding2;
  159. public Transform worldToLocalTransform;
  160. public Transform localToWorldTransform;
  161. }
  162. internal class RadeonRaysShaders
  163. {
  164. public ComputeShader bitHistogram;
  165. public ComputeShader blockReducePart;
  166. public ComputeShader blockScan;
  167. public ComputeShader buildHlbvh;
  168. public ComputeShader reorderTriangleIndices;
  169. public ComputeShader restructureBvh;
  170. public ComputeShader scatter;
  171. public ComputeShader topLevelIntersector;
  172. public ComputeShader intersector;
  173. #if UNITY_EDITOR
  174. public static RadeonRaysShaders LoadFromPath(string kernelFolderPath)
  175. {
  176. var res = new RadeonRaysShaders();
  177. res.bitHistogram = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(Path.Combine(kernelFolderPath, "bit_histogram.compute"));
  178. res.blockReducePart = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(Path.Combine(kernelFolderPath, "block_reduce_part.compute"));
  179. res.blockScan = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(Path.Combine(kernelFolderPath, "block_scan.compute"));
  180. res.buildHlbvh = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(Path.Combine(kernelFolderPath, "build_hlbvh.compute"));
  181. res.reorderTriangleIndices = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(Path.Combine(kernelFolderPath, "reorder_triangle_indices.compute"));
  182. res.restructureBvh = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(Path.Combine(kernelFolderPath, "restructure_bvh.compute"));
  183. res.scatter = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(Path.Combine(kernelFolderPath, "scatter.compute"));
  184. res.topLevelIntersector = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(Path.Combine(kernelFolderPath, "top_level_intersector.compute"));
  185. res.intersector = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(Path.Combine(kernelFolderPath, "intersector.compute"));
  186. return res;
  187. }
  188. #endif
  189. }
  190. internal class RadeonRaysAPI : IDisposable
  191. {
  192. private HlbvhBuilder buildBvh;
  193. private HlbvhTopLevelBuilder buildTopLevelBvh;
  194. private RestructureBvh restructureBvh;
  195. private TraceGeometry traceGeometry;
  196. private TraceScene traceScene;
  197. public const GraphicsBuffer.Target BufferTarget = GraphicsBuffer.Target.Structured;
  198. public RadeonRaysAPI(RadeonRaysShaders shaders)
  199. {
  200. buildBvh = new HlbvhBuilder(shaders);
  201. buildTopLevelBvh = new HlbvhTopLevelBuilder(shaders);
  202. restructureBvh = new RestructureBvh(shaders);
  203. traceGeometry = new TraceGeometry(shaders);
  204. traceScene = new TraceScene(shaders);
  205. }
  206. public void Dispose()
  207. {
  208. restructureBvh.Dispose();
  209. }
  210. static public int BvhNodeSizeInDwords() { return Marshal.SizeOf<BvhNode>() / 4; }
  211. static public int BvhNodeSizeInBytes() { return Marshal.SizeOf<BvhNode>(); }
  212. public void BuildMeshAccelStruct(
  213. CommandBuffer cmd,
  214. MeshBuildInfo buildInfo, BuildFlags buildFlags,
  215. GraphicsBuffer scratchBuffer,
  216. GraphicsBuffer accelStructBuffer, uint accelStructOffsetInNodes, uint accelStructSizeInNodes,
  217. Action<AsyncGPUReadbackRequest> callback = null)
  218. {
  219. if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal)
  220. buildFlags |= BuildFlags.PreferFastBuild;
  221. buildBvh.Execute(cmd,
  222. buildInfo.vertices, buildInfo.verticesStartOffset, buildInfo.vertexStride,
  223. buildInfo.triangleIndices, buildInfo.indicesStartOffset, buildInfo.triangleCount,
  224. scratchBuffer,
  225. accelStructBuffer, accelStructOffsetInNodes, accelStructSizeInNodes,
  226. (buildFlags & BuildFlags.MinimizeMemory) != 0 ? 2u : 0);
  227. if (callback != null && (buildFlags & BuildFlags.MinimizeMemory) != 0)
  228. cmd.RequestAsyncReadback(accelStructBuffer, 4*sizeof(uint), (int)accelStructOffsetInNodes*Marshal.SizeOf<BvhNode>(), callback);
  229. if ((buildFlags & BuildFlags.PreferFastBuild) == 0)
  230. {
  231. restructureBvh.Execute(cmd,
  232. buildInfo.vertices, buildInfo.verticesStartOffset, buildInfo.vertexStride,
  233. buildInfo.triangleIndices, buildInfo.indicesStartOffset, buildInfo.triangleCount,
  234. scratchBuffer, accelStructBuffer, accelStructOffsetInNodes);
  235. }
  236. }
  237. public MeshBuildMemoryRequirements GetMeshBuildMemoryRequirements(MeshBuildInfo buildInfo, BuildFlags buildFlags)
  238. {
  239. if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal)
  240. buildFlags |= BuildFlags.PreferFastBuild;
  241. var result = new MeshBuildMemoryRequirements();
  242. if ((buildFlags & BuildFlags.MinimizeMemory) != 0)
  243. result.resultSizeInDwords = buildBvh.GetResultDataSizeInDwordsPrediction(buildInfo.triangleCount);
  244. else
  245. result.resultSizeInDwords = buildBvh.GetResultDataSizeInDwords(buildInfo.triangleCount);
  246. result.buildScratchSizeInDwords = buildBvh.GetScratchDataSizeInDwords(buildInfo.triangleCount);
  247. ulong restructureScratchSize = ((buildFlags & BuildFlags.PreferFastBuild) == 0) ? restructureBvh.GetScratchDataSizeInDwords(buildInfo.triangleCount) : 0;
  248. result.buildScratchSizeInDwords = math.max(result.buildScratchSizeInDwords, restructureScratchSize);
  249. return result;
  250. }
  251. public TopLevelAccelStruct BuildSceneAccelStruct(
  252. CommandBuffer cmd,
  253. GraphicsBuffer meshAccelStructsBuffer,
  254. Instance[] instances, BuildFlags buildFlags,
  255. GraphicsBuffer scratchBuffer)
  256. {
  257. if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal)
  258. buildFlags |= BuildFlags.PreferFastBuild;
  259. var accelStruct = new TopLevelAccelStruct();
  260. if (instances.Length == 0)
  261. {
  262. buildTopLevelBvh.CreateEmpty(ref accelStruct);
  263. return accelStruct;
  264. }
  265. buildTopLevelBvh.AllocateResultBuffers((uint)instances.Length, ref accelStruct);
  266. var instancesInfos = new InstanceInfo[instances.Length];
  267. for (uint i = 0; i < instances.Length; ++i)
  268. {
  269. instancesInfos[i] = new InstanceInfo
  270. {
  271. blasOffset = (int)instances[i].meshAccelStructOffset,
  272. instanceMask = (int)instances[i].instanceMask,
  273. vertexOffset = (int)instances[i].vertexOffset,
  274. indexOffset = (int)instances[i].indexOffset,
  275. localToWorldTransform = instances[i].localToWorldTransform,
  276. triangleCullingEnabled = instances[i].triangleCullingEnabled ? 1 : 0,
  277. invertTriangleCulling = instances[i].invertTriangleCulling ? 1 : 0,
  278. userInstanceID = instances[i].userInstanceID
  279. // worldToLocal computed in the shader
  280. };
  281. }
  282. accelStruct.instanceInfos.SetData(instancesInfos);
  283. accelStruct.bottomLevelBvhs = meshAccelStructsBuffer;
  284. accelStruct.instanceCount = (uint)instances.Length;
  285. buildTopLevelBvh.Execute(cmd, scratchBuffer, ref accelStruct);
  286. return accelStruct;
  287. }
  288. public TopLevelAccelStruct CreateSceneAccelStructBuffers(
  289. GraphicsBuffer meshAccelStructsBuffer,
  290. uint tlasSizeInDwords,
  291. Instance[] instances)
  292. {
  293. var accelStruct = new TopLevelAccelStruct();
  294. if (instances.Length == 0)
  295. {
  296. buildTopLevelBvh.CreateEmpty(ref accelStruct);
  297. return accelStruct;
  298. }
  299. var instancesInfos = new InstanceInfo[instances.Length];
  300. for (uint i = 0; i < instances.Length; ++i)
  301. {
  302. instancesInfos[i] = new InstanceInfo
  303. {
  304. blasOffset = (int)instances[i].meshAccelStructOffset,
  305. instanceMask = (int)instances[i].instanceMask,
  306. vertexOffset = (int)instances[i].vertexOffset,
  307. indexOffset = (int)instances[i].indexOffset,
  308. localToWorldTransform = instances[i].localToWorldTransform,
  309. triangleCullingEnabled = instances[i].triangleCullingEnabled ? 1 : 0,
  310. invertTriangleCulling = instances[i].invertTriangleCulling ? 1 : 0,
  311. userInstanceID = instances[i].userInstanceID,
  312. worldToLocalTransform = instances[i].localToWorldTransform.Inverse()
  313. };
  314. }
  315. accelStruct.instanceInfos = new GraphicsBuffer(TopLevelAccelStruct.instanceInfoTarget, instances.Length, Marshal.SizeOf<InstanceInfo>());
  316. accelStruct.instanceInfos.SetData(instancesInfos);
  317. accelStruct.bottomLevelBvhs = meshAccelStructsBuffer;
  318. accelStruct.topLevelBvh = new GraphicsBuffer(TopLevelAccelStruct.topLevelBvhTarget, (int)tlasSizeInDwords / BvhNodeSizeInDwords(), Marshal.SizeOf<BvhNode>());
  319. accelStruct.instanceCount = (uint)instances.Length;
  320. return accelStruct;
  321. }
  322. public SceneBuildMemoryRequirements GetSceneBuildMemoryRequirements(uint instanceCount)
  323. {
  324. var result = new SceneBuildMemoryRequirements();
  325. result.buildScratchSizeInDwords = buildTopLevelBvh.GetScratchDataSizeInDwords(instanceCount);
  326. return result;
  327. }
  328. public SceneMemoryRequirements GetSceneMemoryRequirements(MeshBuildInfo[] buildInfos, BuildFlags buildFlags)
  329. {
  330. if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal)
  331. buildFlags |= BuildFlags.PreferFastBuild;
  332. var requirements = new SceneMemoryRequirements();
  333. requirements.bottomLevelBvhSizeInDwords = new ulong[buildInfos.Length];
  334. requirements.bottomLevelBvhOffsetInNodes = new uint[buildInfos.Length];
  335. requirements.buildScratchSizeInDwords = 0;
  336. requirements.totalBottomLevelBvhSizeInDwords = 0;
  337. int i = 0;
  338. uint offset = 0;
  339. foreach (var buildInfo in buildInfos)
  340. {
  341. var meshRequirements = GetMeshBuildMemoryRequirements(buildInfo, buildFlags);
  342. requirements.buildScratchSizeInDwords = math.max(requirements.buildScratchSizeInDwords, meshRequirements.buildScratchSizeInDwords);
  343. requirements.totalBottomLevelBvhSizeInDwords += meshRequirements.resultSizeInDwords;
  344. requirements.bottomLevelBvhSizeInDwords[i] = meshRequirements.resultSizeInDwords;
  345. requirements.bottomLevelBvhOffsetInNodes[i] = offset;
  346. offset += (uint)(meshRequirements.resultSizeInDwords / (ulong)RadeonRaysAPI.BvhNodeSizeInDwords());
  347. i++;
  348. }
  349. ulong topLevelScratchSize = buildTopLevelBvh.GetScratchDataSizeInDwords((uint)buildInfos.Length);
  350. requirements.buildScratchSizeInDwords = math.max(requirements.buildScratchSizeInDwords, topLevelScratchSize);
  351. return requirements;
  352. }
  353. static public ulong GetTraceMemoryRequirements(uint rayCount)
  354. {
  355. return math.max(TraceGeometry.GetScratchDataSizeInDwords(rayCount), TraceScene.GetScratchDataSizeInDwords(rayCount));
  356. }
  357. public void Intersect(
  358. CommandBuffer cmd,
  359. GraphicsBuffer raysBuffer, uint rayCount,
  360. RayQueryType queryType, RayQueryOutputType queryOutputType,
  361. GraphicsBuffer vertexBuffer, GraphicsBuffer indexBuffer,
  362. GraphicsBuffer accelStructBuffer, uint accelStructOffset, GraphicsBuffer scratchBuffer,
  363. GraphicsBuffer hitsBuffer)
  364. {
  365. traceGeometry.Execute(cmd, raysBuffer, rayCount, null, queryType, queryOutputType,
  366. vertexBuffer, indexBuffer, accelStructBuffer, accelStructOffset, scratchBuffer, hitsBuffer);
  367. }
  368. public void IntersectIndirect(
  369. CommandBuffer cmd,
  370. GraphicsBuffer raysBuffer, GraphicsBuffer indirectRayCount,
  371. RayQueryType queryType, RayQueryOutputType queryOutputType,
  372. GraphicsBuffer vertexBuffer, GraphicsBuffer indexBuffer,
  373. GraphicsBuffer accelStructBuffer, uint accelStructOffset, GraphicsBuffer scratchBuffer,
  374. GraphicsBuffer hitsBuffer)
  375. {
  376. traceGeometry.Execute(cmd, raysBuffer, 0, indirectRayCount, queryType, queryOutputType,
  377. vertexBuffer, indexBuffer, accelStructBuffer, accelStructOffset, scratchBuffer, hitsBuffer);
  378. }
  379. public void Intersect(
  380. CommandBuffer cmd,
  381. GraphicsBuffer raysBuffer, uint rayCount, GraphicsBuffer indirectRayCount,
  382. RayQueryType queryType, RayQueryOutputType queryOutputType,
  383. GraphicsBuffer vertexBuffer, int vertexStride, GraphicsBuffer indexBuffer,
  384. TopLevelAccelStruct accelStruct, GraphicsBuffer scratchBuffer,
  385. GraphicsBuffer hitsBuffer)
  386. {
  387. traceScene.Execute(
  388. cmd,
  389. raysBuffer, rayCount, indirectRayCount, queryType, queryOutputType,
  390. vertexBuffer, vertexStride, indexBuffer,
  391. accelStruct, scratchBuffer, hitsBuffer);
  392. }
  393. }
  394. }