RayTracingFeatureProcessor.cpp 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Atom/Feature/RayTracing/RayTracingPass.h>
  9. #include <Atom/RHI/Factory.h>
  10. #include <Atom/RHI/RHISystemInterface.h>
  11. #include <Atom/RHI/RayTracingAccelerationStructure.h>
  12. #include <Atom/RHI/RayTracingCompactionQueryPool.h>
  13. #include <Atom/RPI.Public/Pass/PassFilter.h>
  14. #include <Atom/RPI.Public/Scene.h>
  15. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  16. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  17. #include <CoreLights/CapsuleLightFeatureProcessor.h>
  18. #include <CoreLights/DirectionalLightFeatureProcessor.h>
  19. #include <CoreLights/DiskLightFeatureProcessor.h>
  20. #include <CoreLights/PointLightFeatureProcessor.h>
  21. #include <CoreLights/QuadLightFeatureProcessor.h>
  22. #include <CoreLights/SimplePointLightFeatureProcessor.h>
  23. #include <CoreLights/SimpleSpotLightFeatureProcessor.h>
  24. #include <ImageBasedLights/ImageBasedLightFeatureProcessor.h>
  25. #include <RayTracing/RayTracingFeatureProcessor.h>
  26. namespace AZ
  27. {
  28. namespace Render
  29. {
  30. void RayTracingFeatureProcessor::Reflect(ReflectContext* context)
  31. {
  32. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  33. {
  34. serializeContext
  35. ->Class<RayTracingFeatureProcessor, FeatureProcessor>()
  36. ->Version(1);
  37. }
  38. }
  39. void RayTracingFeatureProcessor::Activate()
  40. {
  41. auto deviceMask{RHI::RHISystemInterface::Get()->GetRayTracingSupport()};
  42. m_rayTracingEnabled = (deviceMask != RHI::MultiDevice::NoDevices);
  43. if (!m_rayTracingEnabled)
  44. {
  45. return;
  46. }
  47. m_transformServiceFeatureProcessor = GetParentScene()->GetFeatureProcessor<TransformServiceFeatureProcessorInterface>();
  48. // initialize the ray tracing buffer pools
  49. m_bufferPools = aznew RHI::RayTracingBufferPools;
  50. m_bufferPools->Init(deviceMask);
  51. auto deviceCount = RHI::RHISystemInterface::Get()->GetDeviceCount();
  52. for (auto deviceIndex{0}; deviceIndex < deviceCount; ++deviceIndex)
  53. {
  54. if ((AZStd::to_underlying(deviceMask) >> deviceIndex) & 1)
  55. {
  56. m_meshBufferIndices[deviceIndex] = {};
  57. m_materialTextureIndices[deviceIndex] = {};
  58. m_meshInfos[deviceIndex] = {};
  59. m_materialInfos[deviceIndex] = {};
  60. m_proceduralGeometryMaterialInfos[deviceIndex] = {};
  61. }
  62. }
  63. // create TLAS attachmentId
  64. AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString<AZStd::string>();
  65. m_tlasAttachmentId = RHI::AttachmentId(AZStd::string::format("RayTracingTlasAttachmentId_%s", uuidString.c_str()));
  66. // create the TLAS object
  67. m_tlas = aznew RHI::RayTracingTlas;
  68. // load the RayTracingSrg asset asset
  69. m_rayTracingSrgAsset = RPI::AssetUtils::LoadCriticalAsset<RPI::ShaderAsset>("shaderlib/atom/features/rayTracing/raytracingsrgs.azshader");
  70. if (!m_rayTracingSrgAsset.IsReady())
  71. {
  72. AZ_Assert(false, "Failed to load RayTracingSrg asset");
  73. return;
  74. }
  75. // create the RayTracingSceneSrg
  76. m_rayTracingSceneSrg = RPI::ShaderResourceGroup::Create(m_rayTracingSrgAsset, Name("RayTracingSceneSrg"));
  77. AZ_Assert(m_rayTracingSceneSrg, "Failed to create RayTracingSceneSrg");
  78. // create the RayTracingMaterialSrg
  79. const AZ::Name rayTracingMaterialSrgName("RayTracingMaterialSrg");
  80. m_rayTracingMaterialSrg = RPI::ShaderResourceGroup::Create(m_rayTracingSrgAsset, Name("RayTracingMaterialSrg"));
  81. AZ_Assert(m_rayTracingMaterialSrg, "Failed to create RayTracingMaterialSrg");
  82. // Setup RayTracingCompactionQueryPool
  83. {
  84. auto rpiDesc = RPI::RPISystemInterface::Get()->GetDescriptor();
  85. RHI::RayTracingCompactionQueryPoolDescriptor desc;
  86. desc.m_deviceMask = RHI::RHISystemInterface::Get()->GetRayTracingSupport();
  87. desc.m_budget = rpiDesc.m_rayTracingSystemDescriptor.m_rayTracingCompactionQueryPoolSize;
  88. desc.m_readbackBufferPool = AZ::RPI::BufferSystemInterface::Get()->GetCommonBufferPool(RPI::CommonBufferPoolType::ReadBack);
  89. desc.m_copyBufferPool = AZ::RPI::BufferSystemInterface::Get()->GetCommonBufferPool(RPI::CommonBufferPoolType::ReadWrite);
  90. m_compactionQueryPool = aznew RHI::RayTracingCompactionQueryPool;
  91. m_compactionQueryPool->Init(desc);
  92. }
  93. EnableSceneNotification();
  94. }
  95. void RayTracingFeatureProcessor::Deactivate()
  96. {
  97. DisableSceneNotification();
  98. }
  99. RayTracingFeatureProcessor::ProceduralGeometryTypeHandle RayTracingFeatureProcessor::RegisterProceduralGeometryType(
  100. const AZStd::string& name,
  101. const Data::Instance<RPI::Shader>& intersectionShader,
  102. const AZStd::string& intersectionShaderName,
  103. const AZStd::unordered_map<int, uint32_t>& bindlessBufferIndices)
  104. {
  105. ProceduralGeometryTypeHandle geometryTypeHandle;
  106. {
  107. ProceduralGeometryType proceduralGeometryType;
  108. proceduralGeometryType.m_name = AZ::Name(name);
  109. proceduralGeometryType.m_intersectionShader = intersectionShader;
  110. proceduralGeometryType.m_intersectionShaderName = AZ::Name(intersectionShaderName);
  111. proceduralGeometryType.m_bindlessBufferIndices = bindlessBufferIndices;
  112. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  113. geometryTypeHandle = m_proceduralGeometryTypes.insert(proceduralGeometryType);
  114. }
  115. m_proceduralGeometryTypeRevision++;
  116. return geometryTypeHandle;
  117. }
  118. void RayTracingFeatureProcessor::SetProceduralGeometryTypeBindlessBufferIndex(
  119. ProceduralGeometryTypeWeakHandle geometryTypeHandle, const AZStd::unordered_map<int, uint32_t>& bindlessBufferIndices)
  120. {
  121. if (!m_rayTracingEnabled)
  122. {
  123. return;
  124. }
  125. geometryTypeHandle->m_bindlessBufferIndices = bindlessBufferIndices;
  126. m_proceduralGeometryInfoBufferNeedsUpdate = true;
  127. }
  128. void RayTracingFeatureProcessor::AddProceduralGeometry(
  129. ProceduralGeometryTypeWeakHandle geometryTypeHandle,
  130. const Uuid& uuid,
  131. const Aabb& aabb,
  132. const SubMeshMaterial& material,
  133. RHI::RayTracingAccelerationStructureInstanceInclusionMask instanceMask,
  134. uint32_t localInstanceIndex)
  135. {
  136. if (!m_rayTracingEnabled)
  137. {
  138. return;
  139. }
  140. RHI::Ptr<AZ::RHI::RayTracingBlas> rayTracingBlas = aznew AZ::RHI::RayTracingBlas;
  141. RHI::RayTracingBlasDescriptor blasDescriptor;
  142. blasDescriptor.m_aabb = aabb;
  143. rayTracingBlas->CreateBuffers(m_deviceMask, &blasDescriptor, *m_bufferPools);
  144. ProceduralGeometry proceduralGeometry;
  145. proceduralGeometry.m_uuid = uuid;
  146. proceduralGeometry.m_typeHandle = geometryTypeHandle;
  147. proceduralGeometry.m_aabb = aabb;
  148. proceduralGeometry.m_instanceMask = static_cast<uint32_t>(instanceMask);
  149. proceduralGeometry.m_blas = rayTracingBlas;
  150. proceduralGeometry.m_localInstanceIndex = localInstanceIndex;
  151. MeshBlasInstance meshBlasInstance;
  152. meshBlasInstance.m_count = 1;
  153. SubMeshBlasInstance subMeshBlasInstance;
  154. subMeshBlasInstance.m_blas = rayTracingBlas;
  155. meshBlasInstance.m_subMeshes.push_back(AZStd::move(subMeshBlasInstance));
  156. MaterialInfo materialInfo;
  157. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  158. m_proceduralGeometryLookup.emplace(uuid, m_proceduralGeometry.size());
  159. m_proceduralGeometry.push_back(proceduralGeometry);
  160. auto deviceCount = RHI::RHISystemInterface::Get()->GetDeviceCount();
  161. for (auto deviceIndex{0}; deviceIndex < deviceCount; ++deviceIndex)
  162. {
  163. m_proceduralGeometryMaterialInfos[deviceIndex].emplace_back();
  164. ConvertMaterial(m_proceduralGeometryMaterialInfos[deviceIndex].back(), material, deviceIndex);
  165. }
  166. m_blasInstanceMap.emplace(Data::AssetId(uuid), meshBlasInstance);
  167. RHI::MultiDeviceObject::IterateDevices(
  168. m_deviceMask,
  169. [&](int deviceIndex)
  170. {
  171. m_blasToBuild[deviceIndex].insert(Data::AssetId(uuid));
  172. return true;
  173. });
  174. geometryTypeHandle->m_instanceCount++;
  175. m_revision++;
  176. m_proceduralGeometryInfoBufferNeedsUpdate = true;
  177. m_materialInfoBufferNeedsUpdate = true;
  178. m_indexListNeedsUpdate = true;
  179. }
  180. void RayTracingFeatureProcessor::SetProceduralGeometryTransform(
  181. const Uuid& uuid, const Transform& transform, const Vector3& nonUniformScale)
  182. {
  183. if (!m_rayTracingEnabled)
  184. {
  185. return;
  186. }
  187. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  188. if (auto it = m_proceduralGeometryLookup.find(uuid); it != m_proceduralGeometryLookup.end())
  189. {
  190. m_proceduralGeometry[it->second].m_transform = transform;
  191. m_proceduralGeometry[it->second].m_nonUniformScale = nonUniformScale;
  192. }
  193. m_revision++;
  194. }
  195. void RayTracingFeatureProcessor::SetProceduralGeometryLocalInstanceIndex(const Uuid& uuid, uint32_t localInstanceIndex)
  196. {
  197. if (!m_rayTracingEnabled)
  198. {
  199. return;
  200. }
  201. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  202. if (auto it = m_proceduralGeometryLookup.find(uuid); it != m_proceduralGeometryLookup.end())
  203. {
  204. m_proceduralGeometry[it->second].m_localInstanceIndex = localInstanceIndex;
  205. }
  206. m_proceduralGeometryInfoBufferNeedsUpdate = true;
  207. }
  208. void RayTracingFeatureProcessor::SetProceduralGeometryMaterial(
  209. const Uuid& uuid, const RayTracingFeatureProcessor::SubMeshMaterial& material)
  210. {
  211. if (!m_rayTracingEnabled)
  212. {
  213. return;
  214. }
  215. auto deviceCount = RHI::RHISystemInterface::Get()->GetDeviceCount();
  216. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  217. for (auto deviceIndex{0}; deviceIndex < deviceCount; ++deviceIndex)
  218. {
  219. if (auto it = m_proceduralGeometryLookup.find(uuid); it != m_proceduralGeometryLookup.end())
  220. {
  221. ConvertMaterial(m_proceduralGeometryMaterialInfos[deviceIndex][it->second], material, deviceIndex);
  222. }
  223. }
  224. m_materialInfoBufferNeedsUpdate = true;
  225. }
  226. void RayTracingFeatureProcessor::RemoveProceduralGeometry(const Uuid& uuid)
  227. {
  228. if (!m_rayTracingEnabled)
  229. {
  230. return;
  231. }
  232. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  233. size_t materialInfoIndex = m_proceduralGeometryLookup[uuid];
  234. m_proceduralGeometry[materialInfoIndex].m_typeHandle->m_instanceCount--;
  235. if (materialInfoIndex < m_proceduralGeometry.size() - 1)
  236. {
  237. m_proceduralGeometryLookup[m_proceduralGeometry.back().m_uuid] = m_proceduralGeometryLookup[uuid];
  238. m_proceduralGeometry[materialInfoIndex] = m_proceduralGeometry.back();
  239. for (auto& [deviceIndex, materialInfos] : m_proceduralGeometryMaterialInfos)
  240. {
  241. materialInfos[materialInfoIndex] = materialInfos.back();
  242. }
  243. }
  244. m_proceduralGeometry.pop_back();
  245. for (auto& [deviceIndex, materialInfos] : m_proceduralGeometryMaterialInfos)
  246. {
  247. materialInfos.pop_back();
  248. }
  249. m_proceduralGeometryLookup.erase(uuid);
  250. RemoveBlasInstance(uuid);
  251. m_revision++;
  252. m_proceduralGeometryInfoBufferNeedsUpdate = true;
  253. m_materialInfoBufferNeedsUpdate = true;
  254. m_indexListNeedsUpdate = true;
  255. }
  256. int RayTracingFeatureProcessor::GetProceduralGeometryCount(ProceduralGeometryTypeWeakHandle geometryTypeHandle) const
  257. {
  258. return geometryTypeHandle->m_instanceCount;
  259. }
  260. void RayTracingFeatureProcessor::AddMesh(const AZ::Uuid& uuid, const Mesh& rayTracingMesh, const SubMeshVector& subMeshes)
  261. {
  262. if (!m_rayTracingEnabled)
  263. {
  264. return;
  265. }
  266. // lock the mutex to protect the mesh and BLAS lists
  267. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  268. // check to see if we already have this mesh
  269. MeshMap::iterator itMesh = m_meshes.find(uuid);
  270. if (itMesh != m_meshes.end())
  271. {
  272. AZ_Assert(false, "AddMesh called on an existing Mesh, call RemoveMesh first");
  273. return;
  274. }
  275. // add the mesh
  276. m_meshes.insert(AZStd::make_pair(uuid, rayTracingMesh));
  277. Mesh& mesh = m_meshes[uuid];
  278. // add the subMeshes to the end of the global subMesh vector
  279. // Note 1: the MeshInfo and MaterialInfo vectors are parallel with the subMesh vector
  280. // Note 2: the list of indices for the subMeshes in the global vector are stored in the parent Mesh
  281. IndexVector subMeshIndices;
  282. uint32_t subMeshGlobalIndex = aznumeric_cast<uint32_t>(m_subMeshes.size());
  283. for (uint32_t subMeshIndex = 0; subMeshIndex < subMeshes.size(); ++subMeshIndex, ++subMeshGlobalIndex)
  284. {
  285. SubMesh& subMesh = m_subMeshes.emplace_back(subMeshes[subMeshIndex]);
  286. subMesh.m_mesh = &mesh;
  287. subMesh.m_subMeshIndex = subMeshIndex;
  288. subMesh.m_globalIndex = subMeshGlobalIndex;
  289. // add to the list of global subMeshIndices, which will be stored in the Mesh
  290. subMeshIndices.push_back(subMeshGlobalIndex);
  291. // add MeshInfo and MaterialInfo entries
  292. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  293. {
  294. meshInfos.emplace_back();
  295. }
  296. for (auto& [deviceIndex, materialInfos] : m_materialInfos)
  297. {
  298. materialInfos.emplace_back();
  299. }
  300. }
  301. mesh.m_subMeshIndices = subMeshIndices;
  302. // search for an existing BLAS instance entry for this mesh using the assetId
  303. BlasInstanceMap::iterator itMeshBlasInstance = m_blasInstanceMap.find(mesh.m_assetId);
  304. if (itMeshBlasInstance == m_blasInstanceMap.end())
  305. {
  306. // make a new BLAS map entry for this mesh
  307. MeshBlasInstance meshBlasInstance;
  308. meshBlasInstance.m_count = 1;
  309. meshBlasInstance.m_subMeshes.reserve(mesh.m_subMeshIndices.size());
  310. meshBlasInstance.m_isSkinnedMesh = mesh.m_isSkinnedMesh;
  311. itMeshBlasInstance = m_blasInstanceMap.insert({ mesh.m_assetId, meshBlasInstance }).first;
  312. // Note: the build flags are set to be the same for each BLAS created for the mesh
  313. RHI::RayTracingAccelerationStructureBuildFlags buildFlags =
  314. CreateRayTracingAccelerationStructureBuildFlags(mesh.m_isSkinnedMesh);
  315. auto rpiDesc = RPI::RPISystemInterface::Get()->GetDescriptor();
  316. if (mesh.m_subMeshIndices.size() > rpiDesc.m_rayTracingSystemDescriptor.m_rayTracingCompactionQueryPoolSize)
  317. {
  318. AZ_Warning(
  319. "RaytracingFeatureProcessor",
  320. false,
  321. "CompactionQueryPool is not large enough for model %s.\n"
  322. "Pool size: %d\n"
  323. "Num meshes in model: %d\n"
  324. "Raytracing Acceleration Structure Compaction will be disabled for this model\n"
  325. "Consider increasing the size of the pool through the registry setting "
  326. "O3DE/Atom/RPI/Initialization/RayTracingSystemDescriptor/RayTracingCompactionQueryPoolSize",
  327. mesh.m_assetId.ToFixedString().c_str(),
  328. rpiDesc.m_rayTracingSystemDescriptor.m_rayTracingCompactionQueryPoolSize,
  329. mesh.m_subMeshIndices.size());
  330. buildFlags = buildFlags & ~RHI::RayTracingAccelerationStructureBuildFlags::ENABLE_COMPACTION;
  331. }
  332. for (uint32_t subMeshIndex = 0; subMeshIndex < mesh.m_subMeshIndices.size(); ++subMeshIndex)
  333. {
  334. const SubMesh& subMesh = m_subMeshes[mesh.m_subMeshIndices[subMeshIndex]];
  335. SubMeshBlasInstance subMeshBlasInstance;
  336. RHI::RayTracingBlasDescriptor& blasDescriptor = subMeshBlasInstance.m_blasDescriptor;
  337. blasDescriptor.m_buildFlags = buildFlags;
  338. RHI::RayTracingGeometry& blasGeometry = blasDescriptor.m_geometries.emplace_back();
  339. blasGeometry.m_vertexFormat = subMesh.m_positionFormat;
  340. blasGeometry.m_vertexBuffer = subMesh.m_positionVertexBufferView;
  341. blasGeometry.m_indexBuffer = subMesh.m_indexBufferView;
  342. itMeshBlasInstance->second.m_subMeshes.push_back(subMeshBlasInstance);
  343. }
  344. m_blasToCreate.insert(mesh.m_assetId);
  345. }
  346. else
  347. {
  348. itMeshBlasInstance->second.m_count++;
  349. AZ_Assert(itMeshBlasInstance->second.m_subMeshes.size() == mesh.m_subMeshIndices.size(), "");
  350. }
  351. for (uint32_t subMeshIndex = 0; subMeshIndex < mesh.m_subMeshIndices.size(); ++subMeshIndex)
  352. {
  353. m_subMeshes[mesh.m_subMeshIndices[subMeshIndex]].m_blasInstanceId = { mesh.m_assetId, subMeshIndex };
  354. }
  355. AZ::Transform noScaleTransform = mesh.m_transform;
  356. noScaleTransform.ExtractUniformScale();
  357. AZ::Matrix3x3 rotationMatrix = Matrix3x3::CreateFromTransform(noScaleTransform);
  358. rotationMatrix = rotationMatrix.GetInverseFull().GetTranspose();
  359. Matrix3x4 worldInvTranspose3x4 = Matrix3x4::CreateFromMatrix3x3(rotationMatrix);
  360. Matrix3x4 reflectionProbeModelToWorld3x4 = Matrix3x4::CreateFromTransform(mesh.m_reflectionProbe.m_modelToWorld);
  361. // store the mesh buffers and material textures in the resource lists
  362. for (uint32_t subMeshIndex : mesh.m_subMeshIndices)
  363. {
  364. SubMesh& subMesh = m_subMeshes[subMeshIndex];
  365. AZ_Assert(subMesh.m_indexShaderBufferView.get(), "RayTracing Mesh IndexBuffer cannot be null");
  366. AZ_Assert(subMesh.m_positionShaderBufferView.get(), "RayTracing Mesh PositionBuffer cannot be null");
  367. AZ_Assert(subMesh.m_normalShaderBufferView.get(), "RayTracing Mesh NormalBuffer cannot be null");
  368. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  369. {
  370. MeshInfo& meshInfo = meshInfos[subMesh.m_globalIndex];
  371. worldInvTranspose3x4.StoreToRowMajorFloat12(meshInfo.m_worldInvTranspose.data());
  372. meshInfo.m_bufferFlags = subMesh.m_bufferFlags;
  373. meshInfo.m_indexByteOffset = subMesh.m_indexBufferView.GetByteOffset();
  374. meshInfo.m_positionByteOffset = subMesh.m_positionVertexBufferView.GetByteOffset();
  375. meshInfo.m_normalByteOffset = subMesh.m_normalVertexBufferView.GetByteOffset();
  376. meshInfo.m_tangentByteOffset =
  377. subMesh.m_tangentShaderBufferView ? subMesh.m_tangentVertexBufferView.GetByteOffset() : 0;
  378. meshInfo.m_bitangentByteOffset =
  379. subMesh.m_bitangentShaderBufferView ? subMesh.m_bitangentVertexBufferView.GetByteOffset() : 0;
  380. meshInfo.m_uvByteOffset = subMesh.m_uvShaderBufferView ? subMesh.m_uvVertexBufferView.GetByteOffset() : 0;
  381. auto& materialInfos{ m_materialInfos[deviceIndex] };
  382. MaterialInfo& materialInfo = materialInfos[subMesh.m_globalIndex];
  383. ConvertMaterial(materialInfo, subMesh.m_material, deviceIndex);
  384. auto& meshBufferIndices = m_meshBufferIndices[deviceIndex];
  385. // add mesh buffers
  386. meshInfo.m_bufferStartIndex = meshBufferIndices.AddEntry(
  387. {
  388. #if USE_BINDLESS_SRG
  389. subMesh.m_indexShaderBufferView.get() ? subMesh.m_indexShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  390. subMesh.m_positionShaderBufferView.get() ? subMesh.m_positionShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  391. subMesh.m_normalShaderBufferView.get() ? subMesh.m_normalShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  392. subMesh.m_tangentShaderBufferView.get() ? subMesh.m_tangentShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  393. subMesh.m_bitangentShaderBufferView.get() ? subMesh.m_bitangentShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  394. subMesh.m_uvShaderBufferView.get() ? subMesh.m_uvShaderBufferView->GetDeviceBufferView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex
  395. #else
  396. m_meshBuffers.AddResource(subMesh.m_indexShaderBufferView.get()),
  397. m_meshBuffers.AddResource(subMesh.m_positionShaderBufferView.get()),
  398. m_meshBuffers.AddResource(subMesh.m_normalShaderBufferView.get()),
  399. m_meshBuffers.AddResource(subMesh.m_tangentShaderBufferView.get()),
  400. m_meshBuffers.AddResource(subMesh.m_bitangentShaderBufferView.get()),
  401. m_meshBuffers.AddResource(subMesh.m_uvShaderBufferView.get())
  402. #endif
  403. });
  404. // add reflection probe data
  405. if (mesh.m_reflectionProbe.m_reflectionProbeCubeMap.get())
  406. {
  407. materialInfo.m_reflectionProbeCubeMapIndex = mesh.m_reflectionProbe.m_reflectionProbeCubeMap->GetImageView()->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex();
  408. if (materialInfo.m_reflectionProbeCubeMapIndex != InvalidIndex)
  409. {
  410. reflectionProbeModelToWorld3x4.StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorld.data());
  411. reflectionProbeModelToWorld3x4.GetInverseFull().StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorldInverse.data());
  412. mesh.m_reflectionProbe.m_outerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_outerObbHalfLengths.data());
  413. mesh.m_reflectionProbe.m_innerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_innerObbHalfLengths.data());
  414. materialInfo.m_reflectionProbeData.m_useReflectionProbe = true;
  415. materialInfo.m_reflectionProbeData.m_useParallaxCorrection = mesh.m_reflectionProbe.m_useParallaxCorrection;
  416. materialInfo.m_reflectionProbeData.m_exposure = mesh.m_reflectionProbe.m_exposure;
  417. }
  418. }
  419. }
  420. }
  421. m_revision++;
  422. m_subMeshCount += aznumeric_cast<uint32_t>(subMeshes.size());
  423. m_meshInfoBufferNeedsUpdate = true;
  424. m_materialInfoBufferNeedsUpdate = true;
  425. m_indexListNeedsUpdate = true;
  426. }
  427. void RayTracingFeatureProcessor::RemoveMesh(const AZ::Uuid& uuid)
  428. {
  429. if (!m_rayTracingEnabled)
  430. {
  431. return;
  432. }
  433. // lock the mutex to protect the mesh and BLAS lists
  434. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  435. MeshMap::iterator itMesh = m_meshes.find(uuid);
  436. if (itMesh != m_meshes.end())
  437. {
  438. Mesh& mesh = itMesh->second;
  439. // decrement the count from the BLAS instances, and check to see if we can remove them
  440. BlasInstanceMap::iterator itBlas = m_blasInstanceMap.find(mesh.m_assetId);
  441. if (itBlas != m_blasInstanceMap.end())
  442. {
  443. itBlas->second.m_count--;
  444. if (itBlas->second.m_count == 0)
  445. {
  446. if (itBlas->second.m_isSkinnedMesh)
  447. {
  448. --m_skinnedMeshCount;
  449. }
  450. RemoveBlasInstance(mesh.m_assetId);
  451. }
  452. }
  453. // remove the SubMeshes
  454. for (auto& subMeshIndex : mesh.m_subMeshIndices)
  455. {
  456. SubMesh& subMesh = m_subMeshes[subMeshIndex];
  457. uint32_t globalIndex = subMesh.m_globalIndex;
  458. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  459. {
  460. MeshInfo& meshInfo = meshInfos[globalIndex];
  461. auto& meshBufferIndices = m_meshBufferIndices[deviceIndex];
  462. meshBufferIndices.RemoveEntry(meshInfo.m_bufferStartIndex);
  463. }
  464. for (auto& [deviceIndex, materialTextureIndices] : m_materialTextureIndices)
  465. {
  466. MaterialInfo& materialInfo = m_materialInfos[deviceIndex][globalIndex];
  467. materialTextureIndices.RemoveEntry(materialInfo.m_textureStartIndex);
  468. }
  469. #if !USE_BINDLESS_SRG
  470. m_meshBuffers.RemoveResource(subMesh.m_indexShaderBufferView.get());
  471. m_meshBuffers.RemoveResource(subMesh.m_positionShaderBufferView.get());
  472. m_meshBuffers.RemoveResource(subMesh.m_normalShaderBufferView.get());
  473. m_meshBuffers.RemoveResource(subMesh.m_tangentShaderBufferView.get());
  474. m_meshBuffers.RemoveResource(subMesh.m_bitangentShaderBufferView.get());
  475. m_meshBuffers.RemoveResource(subMesh.m_uvShaderBufferView.get());
  476. m_materialTextures.RemoveResource(subMesh.m_material.m_baseColorImageView.get());
  477. m_materialTextures.RemoveResource(subMesh.m_material.m_normalImageView.get());
  478. m_materialTextures.RemoveResource(subMesh.m_material.m_metallicImageView.get());
  479. m_materialTextures.RemoveResource(subMesh.m_material.m_roughnessImageView.get());
  480. m_materialTextures.RemoveResource(subMesh.m_material.m_emissiveImageView.get());
  481. #endif
  482. if (globalIndex < m_subMeshes.size() - 1)
  483. {
  484. // the subMesh we're removing is in the middle of the global lists, remove by swapping the last element to its position in the list
  485. m_subMeshes[globalIndex] = m_subMeshes.back();
  486. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  487. {
  488. auto& materialInfos{ m_materialInfos[deviceIndex] };
  489. meshInfos[globalIndex] = meshInfos.back();
  490. materialInfos[globalIndex] = materialInfos.back();
  491. }
  492. // update the global index for the swapped subMesh
  493. m_subMeshes[globalIndex].m_globalIndex = globalIndex;
  494. // update the global index in the parent Mesh' subMesh list
  495. Mesh* swappedSubMeshParent = m_subMeshes[globalIndex].m_mesh;
  496. uint32_t swappedSubMeshIndex = m_subMeshes[globalIndex].m_subMeshIndex;
  497. swappedSubMeshParent->m_subMeshIndices[swappedSubMeshIndex] = globalIndex;
  498. }
  499. m_subMeshes.pop_back();
  500. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  501. {
  502. auto& materialInfos{ m_materialInfos[deviceIndex] };
  503. meshInfos.pop_back();
  504. materialInfos.pop_back();
  505. }
  506. }
  507. // remove from the Mesh list
  508. m_subMeshCount -= aznumeric_cast<uint32_t>(mesh.m_subMeshIndices.size());
  509. m_meshes.erase(itMesh);
  510. m_revision++;
  511. // reset all data structures if all meshes were removed (i.e., empty scene)
  512. if (m_subMeshCount == 0)
  513. {
  514. m_meshes.clear();
  515. m_subMeshes.clear();
  516. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  517. {
  518. meshInfos.clear();
  519. }
  520. for (auto& [deviceIndex, materialInfos] : m_materialInfos)
  521. {
  522. materialInfos.clear();
  523. }
  524. for (auto& [deviceIndex, meshBufferIndices] : m_meshBufferIndices)
  525. {
  526. meshBufferIndices.Reset();
  527. }
  528. for (auto& [deviceIndex, materialTextureIndices] : m_materialTextureIndices)
  529. {
  530. materialTextureIndices.Reset();
  531. }
  532. #if !USE_BINDLESS_SRG
  533. m_meshBuffers.Reset();
  534. m_materialTextures.Reset();
  535. #endif
  536. }
  537. }
  538. m_meshInfoBufferNeedsUpdate = true;
  539. m_materialInfoBufferNeedsUpdate = true;
  540. m_indexListNeedsUpdate = true;
  541. }
  542. void RayTracingFeatureProcessor::SetMeshTransform(const AZ::Uuid& uuid, const AZ::Transform transform, const AZ::Vector3 nonUniformScale)
  543. {
  544. if (!m_rayTracingEnabled)
  545. {
  546. return;
  547. }
  548. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  549. MeshMap::iterator itMesh = m_meshes.find(uuid);
  550. if (itMesh != m_meshes.end())
  551. {
  552. Mesh& mesh = itMesh->second;
  553. mesh.m_transform = transform;
  554. mesh.m_nonUniformScale = nonUniformScale;
  555. m_revision++;
  556. // create a world inverse transpose 3x4 matrix
  557. AZ::Transform noScaleTransform = mesh.m_transform;
  558. noScaleTransform.ExtractUniformScale();
  559. AZ::Matrix3x3 rotationMatrix = Matrix3x3::CreateFromTransform(noScaleTransform);
  560. rotationMatrix = rotationMatrix.GetInverseFull().GetTranspose();
  561. Matrix3x4 worldInvTranspose3x4 = Matrix3x4::CreateFromMatrix3x3(rotationMatrix);
  562. // update all MeshInfos for this Mesh with the new transform
  563. for (const auto& subMeshIndex : mesh.m_subMeshIndices)
  564. {
  565. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  566. {
  567. MeshInfo& meshInfo = meshInfos[subMeshIndex];
  568. worldInvTranspose3x4.StoreToRowMajorFloat12(meshInfo.m_worldInvTranspose.data());
  569. }
  570. }
  571. m_meshInfoBufferNeedsUpdate = true;
  572. }
  573. }
  574. void RayTracingFeatureProcessor::SetMeshReflectionProbe(const AZ::Uuid& uuid, const Mesh::ReflectionProbe& reflectionProbe)
  575. {
  576. if (!m_rayTracingEnabled)
  577. {
  578. return;
  579. }
  580. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  581. MeshMap::iterator itMesh = m_meshes.find(uuid);
  582. if (itMesh != m_meshes.end())
  583. {
  584. Mesh& mesh = itMesh->second;
  585. // update the Mesh reflection probe data
  586. mesh.m_reflectionProbe = reflectionProbe;
  587. // update all of the subMeshes
  588. const Data::Instance<RPI::Image>& reflectionProbeCubeMap = reflectionProbe.m_reflectionProbeCubeMap;
  589. Matrix3x4 reflectionProbeModelToWorld3x4 = Matrix3x4::CreateFromTransform(mesh.m_reflectionProbe.m_modelToWorld);
  590. for (auto& subMeshIndex : mesh.m_subMeshIndices)
  591. {
  592. SubMesh& subMesh = m_subMeshes[subMeshIndex];
  593. uint32_t globalIndex = subMesh.m_globalIndex;
  594. for (auto& [deviceIndex, materialInfos] : m_materialInfos)
  595. {
  596. MaterialInfo& materialInfo = materialInfos[globalIndex];
  597. materialInfo.m_reflectionProbeCubeMapIndex = reflectionProbeCubeMap.get()
  598. ? reflectionProbeCubeMap->GetImageView()->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex()
  599. : InvalidIndex;
  600. if (materialInfo.m_reflectionProbeCubeMapIndex != InvalidIndex)
  601. {
  602. reflectionProbeModelToWorld3x4.StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorld.data());
  603. reflectionProbeModelToWorld3x4.GetInverseFull().StoreToRowMajorFloat12(materialInfo.m_reflectionProbeData.m_modelToWorldInverse.data());
  604. mesh.m_reflectionProbe.m_outerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_outerObbHalfLengths.data());
  605. mesh.m_reflectionProbe.m_innerObbHalfLengths.StoreToFloat3(materialInfo.m_reflectionProbeData.m_innerObbHalfLengths.data());
  606. materialInfo.m_reflectionProbeData.m_useReflectionProbe = true;
  607. materialInfo.m_reflectionProbeData.m_useParallaxCorrection = mesh.m_reflectionProbe.m_useParallaxCorrection;
  608. materialInfo.m_reflectionProbeData.m_exposure = mesh.m_reflectionProbe.m_exposure;
  609. }
  610. else
  611. {
  612. materialInfo.m_reflectionProbeData.m_useReflectionProbe = false;
  613. }
  614. }
  615. }
  616. m_materialInfoBufferNeedsUpdate = true;
  617. }
  618. }
  619. void RayTracingFeatureProcessor::SetMeshMaterials(const AZ::Uuid& uuid, const SubMeshMaterialVector& subMeshMaterials)
  620. {
  621. if (!m_rayTracingEnabled)
  622. {
  623. return;
  624. }
  625. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  626. MeshMap::iterator itMesh = m_meshes.find(uuid);
  627. if (itMesh != m_meshes.end())
  628. {
  629. Mesh& mesh = itMesh->second;
  630. AZ_Assert(
  631. subMeshMaterials.size() == mesh.m_subMeshIndices.size(),
  632. "The size of subMeshes in SetMeshMaterial must be the same as in AddMesh");
  633. for (auto& subMeshIndex : mesh.m_subMeshIndices)
  634. {
  635. const SubMesh& subMesh = m_subMeshes[subMeshIndex];
  636. for (auto& [deviceIndex, materialInfos] : m_materialInfos)
  637. {
  638. ConvertMaterial(materialInfos[subMesh.m_globalIndex], subMeshMaterials[subMesh.m_subMeshIndex], deviceIndex);
  639. }
  640. }
  641. m_materialInfoBufferNeedsUpdate = true;
  642. m_indexListNeedsUpdate = true;
  643. }
  644. }
  645. void RayTracingFeatureProcessor::Render(const RenderPacket&)
  646. {
  647. m_frameIndex++;
  648. }
  649. void RayTracingFeatureProcessor::BeginFrame()
  650. {
  651. if (m_updatedFrameIndex == m_frameIndex)
  652. {
  653. // Make sure the update is only called once per frame
  654. // When multiple devices are present a RayTracingAccelerationStructurePass is created per device
  655. // Thus this function is called once for each device
  656. return;
  657. }
  658. m_updatedFrameIndex = m_frameIndex;
  659. m_compactionQueryPool->BeginFrame(m_frameIndex);
  660. UpdateBlasInstances();
  661. if (m_tlasRevision != m_revision)
  662. {
  663. m_tlasRevision = m_revision;
  664. // create the TLAS descriptor
  665. RHI::RayTracingTlasDescriptor tlasDescriptor;
  666. uint32_t instanceIndex = 0;
  667. for (auto& subMesh : m_subMeshes)
  668. {
  669. const auto& blasInstance =
  670. m_blasInstanceMap.at(subMesh.m_blasInstanceId.first).m_subMeshes[subMesh.m_blasInstanceId.second];
  671. auto& blas = blasInstance.m_compactBlas ? blasInstance.m_compactBlas : blasInstance.m_blas;
  672. if (blas)
  673. {
  674. RHI::RayTracingTlasInstance& tlasInstance = tlasDescriptor.m_instances.emplace_back();
  675. tlasInstance.m_instanceID = instanceIndex;
  676. tlasInstance.m_instanceMask = subMesh.m_mesh->m_instanceMask;
  677. tlasInstance.m_hitGroupIndex = 0;
  678. tlasInstance.m_blas = blas;
  679. tlasInstance.m_transform = subMesh.m_mesh->m_transform;
  680. tlasInstance.m_nonUniformScale = subMesh.m_mesh->m_nonUniformScale;
  681. tlasInstance.m_transparent = subMesh.m_material.m_irradianceColor.GetA() < 1.0f;
  682. }
  683. instanceIndex++;
  684. }
  685. unsigned proceduralHitGroupIndex = 1; // Hit group 0 is used for normal meshes
  686. AZStd::unordered_map<Name, unsigned> geometryTypeMap;
  687. geometryTypeMap.reserve(m_proceduralGeometryTypes.size());
  688. for (auto it = m_proceduralGeometryTypes.cbegin(); it != m_proceduralGeometryTypes.cend(); ++it)
  689. {
  690. geometryTypeMap[it->m_name] = proceduralHitGroupIndex++;
  691. }
  692. for (const auto& proceduralGeometry : m_proceduralGeometry)
  693. {
  694. RHI::RayTracingTlasInstance& tlasInstance = tlasDescriptor.m_instances.emplace_back();
  695. tlasInstance.m_instanceID = instanceIndex;
  696. tlasInstance.m_instanceMask = proceduralGeometry.m_instanceMask;
  697. tlasInstance.m_hitGroupIndex = geometryTypeMap[proceduralGeometry.m_typeHandle->m_name];
  698. tlasInstance.m_blas = proceduralGeometry.m_blas;
  699. tlasInstance.m_transform = proceduralGeometry.m_transform;
  700. tlasInstance.m_nonUniformScale = proceduralGeometry.m_nonUniformScale;
  701. instanceIndex++;
  702. }
  703. // create the TLAS buffers based on the descriptor
  704. RHI::Ptr<RHI::RayTracingTlas>& rayTracingTlas = m_tlas;
  705. rayTracingTlas->CreateBuffers(m_deviceMask, &tlasDescriptor, *m_bufferPools);
  706. }
  707. // update and compile the RayTracingSceneSrg and RayTracingMaterialSrg
  708. // Note: the timing of this update is very important, it needs to be updated after the TLAS is allocated so it can
  709. // be set on the RayTracingSceneSrg for this frame, and the ray tracing mesh data in the RayTracingSceneSrg must
  710. // exactly match the TLAS. Any mismatch in this data may result in a TDR.
  711. UpdateRayTracingSrgs();
  712. }
  713. void RayTracingFeatureProcessor::UpdateRayTracingSrgs()
  714. {
  715. AZ_PROFILE_SCOPE(AzRender, "RayTracingFeatureProcessor::UpdateRayTracingSrgs");
  716. if (!m_tlas->GetTlasBuffer())
  717. {
  718. return;
  719. }
  720. if (m_rayTracingSceneSrg->IsQueuedForCompile() || m_rayTracingMaterialSrg->IsQueuedForCompile())
  721. {
  722. //[GFX TODO][ATOM-14792] AtomSampleViewer: Reset scene and feature processors before switching to sample
  723. return;
  724. }
  725. // lock the mutex to protect the mesh and BLAS lists
  726. AZStd::unique_lock<AZStd::mutex> lock(m_mutex);
  727. if (HasMeshGeometry())
  728. {
  729. UpdateMeshInfoBuffer();
  730. }
  731. if (HasProceduralGeometry())
  732. {
  733. UpdateProceduralGeometryInfoBuffer();
  734. }
  735. if (HasGeometry())
  736. {
  737. UpdateMaterialInfoBuffer();
  738. UpdateIndexLists();
  739. }
  740. UpdateRayTracingSceneSrg();
  741. UpdateRayTracingMaterialSrg();
  742. }
  743. const void RayTracingFeatureProcessor::MarkBlasInstanceForCompaction(int deviceIndex, Data::AssetId assetId)
  744. {
  745. AZStd::unique_lock lock(m_queueMutex);
  746. auto it = m_blasInstanceMap.find(assetId);
  747. if (RHI::Validation::IsEnabled())
  748. {
  749. if (it != m_blasInstanceMap.end())
  750. {
  751. for ([[maybe_unused]] auto& subMeshInstance : it->second.m_subMeshes)
  752. {
  753. AZ_Assert(
  754. subMeshInstance.m_compactionSizeQuery, "Enqueuing a Blas without an compaction size query for compaction");
  755. }
  756. }
  757. }
  758. m_blasEnqueuedForCompact[assetId].m_frameIndex = static_cast<int>(m_frameIndex + RHI::Limits::Device::FrameCountMax);
  759. m_blasEnqueuedForCompact[assetId].m_deviceMask = RHI::SetBit(m_blasEnqueuedForCompact[assetId].m_deviceMask, deviceIndex);
  760. }
  761. const void RayTracingFeatureProcessor::MarkBlasInstanceAsCompactionEnqueued(int deviceIndex, Data::AssetId assetId)
  762. {
  763. AZStd::unique_lock lock(m_queueMutex);
  764. auto it = m_blasInstanceMap.find(assetId);
  765. if (RHI::Validation::IsEnabled())
  766. {
  767. if (it != m_blasInstanceMap.end())
  768. {
  769. for ([[maybe_unused]] auto& subMeshInstance : it->second.m_subMeshes)
  770. {
  771. AZ_Assert(subMeshInstance.m_compactBlas, "Marking a Blas without a compacted Blas as enqueued for compaction");
  772. }
  773. }
  774. }
  775. m_uncompactedBlasEnqueuedForDeletion[assetId].m_frameIndex =
  776. static_cast<int>(m_frameIndex + RHI::Limits::Device::FrameCountMax);
  777. m_uncompactedBlasEnqueuedForDeletion[assetId].m_deviceMask =
  778. RHI::SetBit(m_uncompactedBlasEnqueuedForDeletion[assetId].m_deviceMask, deviceIndex);
  779. }
  780. void RayTracingFeatureProcessor::UpdateBlasInstances()
  781. {
  782. bool changed = false;
  783. auto rpiDesc = RPI::RPISystemInterface::Get()->GetDescriptor();
  784. {
  785. uint32_t numModelBlasCreated = 0;
  786. uint32_t numCompactionQueriesEnqueued = 0;
  787. AZStd::unordered_set<Data::AssetId> toRemoveFromCreateList;
  788. for (auto assetId : m_blasToCreate)
  789. {
  790. auto it = m_blasInstanceMap.find(assetId);
  791. if (it == m_blasInstanceMap.end())
  792. {
  793. toRemoveFromCreateList.insert(assetId);
  794. continue;
  795. }
  796. auto& instance = it->second;
  797. {
  798. int numSubmeshesWithCompactionQuery = 0;
  799. for (auto& subMeshInstance : instance.m_subMeshes)
  800. {
  801. // create the BLAS object and store it in the BLAS list
  802. if (RHI::CheckBitsAny(
  803. subMeshInstance.m_blasDescriptor.m_buildFlags,
  804. RHI::RayTracingAccelerationStructureBuildFlags::ENABLE_COMPACTION))
  805. {
  806. numSubmeshesWithCompactionQuery++;
  807. }
  808. }
  809. if (numCompactionQueriesEnqueued + numSubmeshesWithCompactionQuery >
  810. rpiDesc.m_rayTracingSystemDescriptor.m_rayTracingCompactionQueryPoolSize)
  811. {
  812. break;
  813. }
  814. }
  815. for (auto& subMeshInstance : instance.m_subMeshes)
  816. {
  817. // create the BLAS object and store it in the BLAS list
  818. RHI::Ptr<RHI::RayTracingBlas> rayTracingBlas = aznew RHI::RayTracingBlas;
  819. if (RHI::CheckBitsAny(
  820. subMeshInstance.m_blasDescriptor.m_buildFlags,
  821. RHI::RayTracingAccelerationStructureBuildFlags::ENABLE_COMPACTION))
  822. {
  823. subMeshInstance.m_compactionSizeQuery = aznew RHI::RayTracingCompactionQuery;
  824. m_compactionQueryPool->InitQuery(subMeshInstance.m_compactionSizeQuery.get());
  825. numCompactionQueriesEnqueued++;
  826. }
  827. subMeshInstance.m_blas = rayTracingBlas;
  828. // create the buffers from the BLAS descriptor
  829. subMeshInstance.m_blas->CreateBuffers(m_deviceMask, &subMeshInstance.m_blasDescriptor, *m_bufferPools);
  830. }
  831. if (instance.m_isSkinnedMesh)
  832. {
  833. ++m_skinnedMeshCount;
  834. m_skinnedBlasIds.insert(assetId);
  835. }
  836. else
  837. {
  838. RHI::MultiDeviceObject::IterateDevices(
  839. RHI::RHISystemInterface::Get()->GetRayTracingSupport(),
  840. [&](int deviceIndex)
  841. {
  842. m_blasToBuild[deviceIndex].insert(assetId);
  843. return true;
  844. });
  845. }
  846. toRemoveFromCreateList.insert(assetId);
  847. changed = true;
  848. numModelBlasCreated++;
  849. if (rpiDesc.m_rayTracingSystemDescriptor.m_maxBlasCreatedPerFrame > 0 &&
  850. numModelBlasCreated >= static_cast<uint32_t>(rpiDesc.m_rayTracingSystemDescriptor.m_maxBlasCreatedPerFrame))
  851. {
  852. break;
  853. }
  854. }
  855. for (auto toRemove : toRemoveFromCreateList)
  856. {
  857. m_blasToCreate.erase(toRemove);
  858. }
  859. }
  860. // Check which Blas are ready for compaction and create compacted acceleration structures for them
  861. {
  862. AZStd::unordered_set<Data::AssetId> toDelete;
  863. for (const auto& [assetId, frameEvent] : m_blasEnqueuedForCompact)
  864. {
  865. if (frameEvent.m_frameIndex <= m_frameIndex)
  866. {
  867. auto it = m_blasInstanceMap.find(assetId);
  868. if (it != m_blasInstanceMap.end())
  869. {
  870. // Limit the number of blas we enqueue per frame to the size of the compaction query pool
  871. for (int subMeshIdx = 0; subMeshIdx < it->second.m_subMeshes.size(); subMeshIdx++)
  872. {
  873. auto& subMeshInstance = it->second.m_subMeshes[subMeshIdx];
  874. AZ_Assert(!subMeshInstance.m_compactBlas, "Trying to compact a Blas twice");
  875. AZ_Assert(
  876. frameEvent.m_deviceMask == m_deviceMask,
  877. "All device Blas of a SubMesh must be compacted in the same frame");
  878. AZStd::unordered_map<int, uint64_t> sizes;
  879. RHI::MultiDeviceObject::IterateDevices(
  880. frameEvent.m_deviceMask,
  881. [&](int deviceIndex)
  882. {
  883. sizes[deviceIndex] =
  884. subMeshInstance.m_compactionSizeQuery->GetDeviceRayTracingCompactionQuery(deviceIndex)
  885. ->GetResult();
  886. return true;
  887. });
  888. subMeshInstance.m_compactBlas = aznew RHI::RayTracingBlas;
  889. subMeshInstance.m_compactBlas->CreateCompactedBuffers(*subMeshInstance.m_blas, sizes, *m_bufferPools);
  890. subMeshInstance.m_compactionSizeQuery = {};
  891. changed = true;
  892. }
  893. RHI::MultiDeviceObject::IterateDevices(
  894. m_deviceMask,
  895. [&, assetId = assetId](int deviceIndex)
  896. {
  897. m_blasToCompact[deviceIndex].insert(assetId);
  898. return true;
  899. });
  900. }
  901. toDelete.insert(assetId);
  902. }
  903. }
  904. for (auto assetId : toDelete)
  905. {
  906. m_blasEnqueuedForCompact.erase(assetId);
  907. }
  908. }
  909. // Check which uncompacted Blas can be deleted, and delete them
  910. {
  911. AZStd::unordered_set<Data::AssetId> toDelete;
  912. for (const auto& [assetId, frameEvent] : m_uncompactedBlasEnqueuedForDeletion)
  913. {
  914. if (frameEvent.m_frameIndex <= m_frameIndex)
  915. {
  916. auto it = m_blasInstanceMap.find(assetId);
  917. if (it != m_blasInstanceMap.end())
  918. {
  919. for (auto& subMeshInstance : it->second.m_subMeshes)
  920. {
  921. AZ_Assert(
  922. subMeshInstance.m_compactBlas, "Deleting a uncompacted Blas from a submesh without a compacted one");
  923. // We assume here that all device Blas are handled at the same frame for all devices
  924. subMeshInstance.m_blas = {};
  925. changed = true;
  926. }
  927. }
  928. toDelete.insert(assetId);
  929. }
  930. }
  931. for (auto assetId : toDelete)
  932. {
  933. m_uncompactedBlasEnqueuedForDeletion.erase(assetId);
  934. }
  935. }
  936. if (changed)
  937. {
  938. m_revision++;
  939. }
  940. }
  941. void RayTracingFeatureProcessor::UpdateMeshInfoBuffer()
  942. {
  943. if (m_meshInfoBufferNeedsUpdate)
  944. {
  945. AZStd::unordered_map<int, const void*> rawMeshInfos;
  946. for (auto& [deviceIndex, meshInfos] : m_meshInfos)
  947. {
  948. rawMeshInfos[deviceIndex] = meshInfos.data();
  949. }
  950. size_t meshInfoByteCount = m_meshInfos.begin()->second.size() * sizeof(MeshInfo);
  951. m_meshInfoGpuBuffer.AdvanceCurrentBufferAndUpdateData(rawMeshInfos, meshInfoByteCount);
  952. m_meshInfoBufferNeedsUpdate = false;
  953. }
  954. }
  955. void RayTracingFeatureProcessor::UpdateProceduralGeometryInfoBuffer()
  956. {
  957. if (!m_proceduralGeometryInfoBufferNeedsUpdate)
  958. {
  959. return;
  960. }
  961. AZStd::unordered_map<int, AZStd::vector<uint32_t>> proceduralGeometryInfos;
  962. for (const auto& proceduralGeometry : m_proceduralGeometry)
  963. {
  964. for (auto& [deviceIndex, bindlessBufferIndex] : proceduralGeometry.m_typeHandle->m_bindlessBufferIndices)
  965. {
  966. auto& proceduralGeometryInfo = proceduralGeometryInfos[deviceIndex];
  967. if (proceduralGeometryInfo.empty())
  968. {
  969. proceduralGeometryInfo.reserve(m_proceduralGeometry.size() * 2);
  970. }
  971. proceduralGeometryInfo.push_back(bindlessBufferIndex);
  972. proceduralGeometryInfo.push_back(proceduralGeometry.m_localInstanceIndex);
  973. }
  974. }
  975. AZStd::unordered_map<int, const void*> rawProceduralGeometryInfos;
  976. for (auto& [deviceIndex, proceduralGeometryInfo] : proceduralGeometryInfos)
  977. {
  978. rawProceduralGeometryInfos[deviceIndex] = proceduralGeometryInfo.data();
  979. }
  980. m_proceduralGeometryInfoGpuBuffer.AdvanceCurrentBufferAndUpdateData(
  981. rawProceduralGeometryInfos, m_proceduralGeometry.size() * 2 * sizeof(uint32_t));
  982. m_proceduralGeometryInfoBufferNeedsUpdate = false;
  983. }
  984. void RayTracingFeatureProcessor::UpdateMaterialInfoBuffer()
  985. {
  986. if (m_materialInfoBufferNeedsUpdate)
  987. {
  988. m_materialInfoGpuBuffer.AdvanceCurrentElement();
  989. m_materialInfoGpuBuffer.CreateOrResizeCurrentBufferWithElementCount<MaterialInfo>(
  990. m_subMeshCount + m_proceduralGeometryMaterialInfos.begin()->second.size());
  991. m_materialInfoGpuBuffer.UpdateCurrentBufferData(m_materialInfos);
  992. m_materialInfoGpuBuffer.UpdateCurrentBufferData(m_proceduralGeometryMaterialInfos, m_subMeshCount);
  993. m_materialInfoBufferNeedsUpdate = false;
  994. }
  995. }
  996. void RayTracingFeatureProcessor::UpdateIndexLists()
  997. {
  998. if (m_indexListNeedsUpdate)
  999. {
  1000. #if !USE_BINDLESS_SRG
  1001. // resolve to the true indices using the indirection list
  1002. // Note: this is done on the CPU to avoid double-indirection in the shader
  1003. AZStd::unordered_map<int, IndexVector> resolvedMeshBufferIndicesMap;
  1004. for (const auto& [deviceIndex, meshBufferIndices] : m_meshBufferIndices)
  1005. {
  1006. IndexVector& resolvedMeshBufferIndices = resolvedMeshBufferIndicesMap[deviceIndex];
  1007. resolvedMeshBufferIndices.resize(meshBufferIndices.GetIndexList().size());
  1008. uint32_t resolvedMeshBufferIndex = 0;
  1009. for (auto& meshBufferIndex : meshBufferIndices.GetIndexList())
  1010. {
  1011. if (!meshBufferIndices.IsValidIndex(meshBufferIndex))
  1012. {
  1013. resolvedMeshBufferIndices[resolvedMeshBufferIndex++] = InvalidIndex;
  1014. }
  1015. else
  1016. {
  1017. resolvedMeshBufferIndices[resolvedMeshBufferIndex++] = m_meshBuffers.GetIndirectionList()[meshBufferIndex];
  1018. }
  1019. }
  1020. }
  1021. m_meshBufferIndicesGpuBuffer.AdvanceCurrentBufferAndUpdateData(resolvedMeshBufferIndicesMap);
  1022. #else
  1023. AZStd::unordered_map<int, const void*> rawMeshData;
  1024. for (auto& [deviceIndex, meshBufferIndices] : m_meshBufferIndices)
  1025. {
  1026. rawMeshData[deviceIndex] = meshBufferIndices.GetIndexList().data();
  1027. }
  1028. size_t newMeshBufferIndicesByteCount = m_meshBufferIndices.begin()->second.GetIndexList().size() * sizeof(uint32_t);
  1029. m_meshBufferIndicesGpuBuffer.AdvanceCurrentBufferAndUpdateData(rawMeshData, newMeshBufferIndicesByteCount);
  1030. #endif
  1031. #if !USE_BINDLESS_SRG
  1032. // resolve to the true indices using the indirection list
  1033. // Note: this is done on the CPU to avoid double-indirection in the shader
  1034. AZStd::unordered_map<int, IndexVector> resolvedMaterialTextureIndicesMap;
  1035. for (const auto& [deviceIndex, materialTextureIndices] : m_materialTextureIndices)
  1036. {
  1037. IndexVector& resolvedMaterialTextureIndices = resolvedMaterialTextureIndicesMap[deviceIndex];
  1038. resolvedMaterialTextureIndices.resize(materialTextureIndices.GetIndexList().size());
  1039. uint32_t resolvedMaterialTextureIndex = 0;
  1040. for (auto& materialTextureIndex : materialTextureIndices.GetIndexList())
  1041. {
  1042. if (!materialTextureIndices.IsValidIndex(materialTextureIndex))
  1043. {
  1044. resolvedMaterialTextureIndices[resolvedMaterialTextureIndex++] = InvalidIndex;
  1045. }
  1046. else
  1047. {
  1048. resolvedMaterialTextureIndices[resolvedMaterialTextureIndex++] = m_materialTextures.GetIndirectionList()[materialTextureIndex];
  1049. }
  1050. }
  1051. }
  1052. m_materialTextureIndicesGpuBuffer.AdvanceCurrentBufferAndUpdateData(resolvedMaterialTextureIndicesMap);
  1053. #else
  1054. AZStd::unordered_map<int, const void*> rawMaterialData;
  1055. for (auto& [deviceIndex, materialTextureIndices] : m_materialTextureIndices)
  1056. {
  1057. rawMaterialData[deviceIndex] = materialTextureIndices.GetIndexList().data();
  1058. }
  1059. size_t newMaterialTextureIndicesByteCount = m_materialTextureIndices.begin()->second.GetIndexList().size() * sizeof(uint32_t);
  1060. m_materialTextureIndicesGpuBuffer.AdvanceCurrentBufferAndUpdateData(rawMaterialData, newMaterialTextureIndicesByteCount);
  1061. #endif
  1062. m_indexListNeedsUpdate = false;
  1063. }
  1064. }
  1065. void RayTracingFeatureProcessor::UpdateRayTracingSceneSrg()
  1066. {
  1067. const RHI::ShaderResourceGroupLayout* srgLayout = m_rayTracingSceneSrg->GetLayout();
  1068. RHI::ShaderInputImageIndex imageIndex;
  1069. RHI::ShaderInputBufferIndex bufferIndex;
  1070. RHI::ShaderInputConstantIndex constantIndex;
  1071. // TLAS
  1072. uint32_t tlasBufferByteCount = aznumeric_cast<uint32_t>(m_tlas->GetTlasBuffer()->GetDescriptor().m_byteCount);
  1073. RHI::BufferViewDescriptor bufferViewDescriptor = RHI::BufferViewDescriptor::CreateRayTracingTLAS(tlasBufferByteCount);
  1074. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_scene"));
  1075. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_tlas->GetTlasBuffer()->GetBufferView(bufferViewDescriptor).get());
  1076. // directional lights
  1077. const auto directionalLightFP = GetParentScene()->GetFeatureProcessor<DirectionalLightFeatureProcessor>();
  1078. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_directionalLights"));
  1079. m_rayTracingSceneSrg->SetBufferView(
  1080. bufferIndex,
  1081. directionalLightFP->GetLightBuffer()->GetBufferView());
  1082. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_directionalLightCount"));
  1083. m_rayTracingSceneSrg->SetConstant(constantIndex, directionalLightFP->GetLightCount());
  1084. // simple point lights
  1085. const auto simplePointLightFP = GetParentScene()->GetFeatureProcessor<SimplePointLightFeatureProcessor>();
  1086. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_simplePointLights"));
  1087. m_rayTracingSceneSrg->SetBufferView(
  1088. bufferIndex,
  1089. simplePointLightFP->GetLightBuffer()->GetBufferView());
  1090. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_simplePointLightCount"));
  1091. m_rayTracingSceneSrg->SetConstant(constantIndex, simplePointLightFP->GetLightCount());
  1092. // simple spot lights
  1093. const auto simpleSpotLightFP = GetParentScene()->GetFeatureProcessor<SimpleSpotLightFeatureProcessor>();
  1094. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_simpleSpotLights"));
  1095. m_rayTracingSceneSrg->SetBufferView(
  1096. bufferIndex,
  1097. simpleSpotLightFP->GetLightBuffer()->GetBufferView());
  1098. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_simpleSpotLightCount"));
  1099. m_rayTracingSceneSrg->SetConstant(constantIndex, simpleSpotLightFP->GetLightCount());
  1100. // point lights (sphere)
  1101. const auto pointLightFP = GetParentScene()->GetFeatureProcessor<PointLightFeatureProcessor>();
  1102. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_pointLights"));
  1103. m_rayTracingSceneSrg->SetBufferView(
  1104. bufferIndex,
  1105. pointLightFP->GetLightBuffer()->GetBufferView());
  1106. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_pointLightCount"));
  1107. m_rayTracingSceneSrg->SetConstant(constantIndex, pointLightFP->GetLightCount());
  1108. // disk lights
  1109. const auto diskLightFP = GetParentScene()->GetFeatureProcessor<DiskLightFeatureProcessor>();
  1110. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_diskLights"));
  1111. m_rayTracingSceneSrg->SetBufferView(
  1112. bufferIndex,
  1113. diskLightFP->GetLightBuffer()->GetBufferView());
  1114. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_diskLightCount"));
  1115. m_rayTracingSceneSrg->SetConstant(constantIndex, diskLightFP->GetLightCount());
  1116. // capsule lights
  1117. const auto capsuleLightFP = GetParentScene()->GetFeatureProcessor<CapsuleLightFeatureProcessor>();
  1118. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_capsuleLights"));
  1119. m_rayTracingSceneSrg->SetBufferView(
  1120. bufferIndex,
  1121. capsuleLightFP->GetLightBuffer()->GetBufferView());
  1122. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_capsuleLightCount"));
  1123. m_rayTracingSceneSrg->SetConstant(constantIndex, capsuleLightFP->GetLightCount());
  1124. // quad lights
  1125. const auto quadLightFP = GetParentScene()->GetFeatureProcessor<QuadLightFeatureProcessor>();
  1126. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_quadLights"));
  1127. m_rayTracingSceneSrg->SetBufferView(
  1128. bufferIndex,
  1129. quadLightFP->GetLightBuffer()->GetBufferView());
  1130. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_quadLightCount"));
  1131. m_rayTracingSceneSrg->SetConstant(constantIndex, quadLightFP->GetLightCount());
  1132. // diffuse environment map for sky hits
  1133. ImageBasedLightFeatureProcessor* imageBasedLightFeatureProcessor = GetParentScene()->GetFeatureProcessor<ImageBasedLightFeatureProcessor>();
  1134. if (imageBasedLightFeatureProcessor)
  1135. {
  1136. imageIndex = srgLayout->FindShaderInputImageIndex(AZ::Name("m_diffuseEnvMap"));
  1137. m_rayTracingSceneSrg->SetImage(imageIndex, imageBasedLightFeatureProcessor->GetDiffuseImage());
  1138. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_iblOrientation"));
  1139. m_rayTracingSceneSrg->SetConstant(constantIndex, imageBasedLightFeatureProcessor->GetOrientation());
  1140. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_iblExposure"));
  1141. m_rayTracingSceneSrg->SetConstant(constantIndex, imageBasedLightFeatureProcessor->GetExposure());
  1142. }
  1143. if (m_meshInfoGpuBuffer.IsCurrentBufferValid())
  1144. {
  1145. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_meshInfo"));
  1146. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_meshInfoGpuBuffer.GetCurrentBufferView());
  1147. }
  1148. constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_meshInfoCount"));
  1149. m_rayTracingSceneSrg->SetConstant(constantIndex, m_subMeshCount);
  1150. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_meshBufferIndices"));
  1151. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_meshBufferIndicesGpuBuffer.GetCurrentBufferView());
  1152. if (m_proceduralGeometryInfoGpuBuffer.IsCurrentBufferValid())
  1153. {
  1154. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_proceduralGeometryInfo"));
  1155. m_rayTracingSceneSrg->SetBufferView(bufferIndex, m_proceduralGeometryInfoGpuBuffer.GetCurrentBufferView());
  1156. }
  1157. #if !USE_BINDLESS_SRG
  1158. RHI::ShaderInputBufferUnboundedArrayIndex bufferUnboundedArrayIndex = srgLayout->FindShaderInputBufferUnboundedArrayIndex(AZ::Name("m_meshBuffers"));
  1159. m_rayTracingSceneSrg->SetBufferViewUnboundedArray(bufferUnboundedArrayIndex, m_meshBuffers.GetResourceList());
  1160. #endif
  1161. m_rayTracingSceneSrg->Compile();
  1162. }
  1163. void RayTracingFeatureProcessor::UpdateRayTracingMaterialSrg()
  1164. {
  1165. const RHI::ShaderResourceGroupLayout* srgLayout = m_rayTracingMaterialSrg->GetLayout();
  1166. RHI::ShaderInputBufferIndex bufferIndex;
  1167. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_materialInfo"));
  1168. m_rayTracingMaterialSrg->SetBufferView(bufferIndex, m_materialInfoGpuBuffer.GetCurrentBufferView());
  1169. bufferIndex = srgLayout->FindShaderInputBufferIndex(AZ::Name("m_materialTextureIndices"));
  1170. m_rayTracingMaterialSrg->SetBufferView(bufferIndex, m_materialTextureIndicesGpuBuffer.GetCurrentBufferView());
  1171. #if !USE_BINDLESS_SRG
  1172. RHI::ShaderInputImageUnboundedArrayIndex textureUnboundedArrayIndex = srgLayout->FindShaderInputImageUnboundedArrayIndex(AZ::Name("m_materialTextures"));
  1173. m_rayTracingMaterialSrg->SetImageViewUnboundedArray(textureUnboundedArrayIndex, m_materialTextures.GetResourceList());
  1174. #endif
  1175. m_rayTracingMaterialSrg->Compile();
  1176. }
  1177. void RayTracingFeatureProcessor::OnRenderPipelineChanged(
  1178. [[maybe_unused]] RPI::RenderPipeline* renderPipeline,
  1179. [[maybe_unused]] RPI::SceneNotification::RenderPipelineChangeType changeType)
  1180. {
  1181. if (!m_rayTracingEnabled)
  1182. {
  1183. return;
  1184. }
  1185. // Find out which devices have a RayTracingAccelerationStructurePass
  1186. // We then only build the BLAS and TLAS objects on these devices
  1187. AZ::RPI::PassFilter passFilter = AZ::RPI::PassFilter::CreateWithTemplateName(
  1188. AZ_NAME_LITERAL("RayTracingAccelerationStructurePassTemplate"), renderPipeline->GetScene());
  1189. AZ::RPI::PassSystemInterface::Get()->ForEachPass(
  1190. passFilter,
  1191. [this](AZ::RPI::Pass* pass) -> AZ::RPI::PassFilterExecutionFlow
  1192. {
  1193. auto deviceIndex = pass->GetDeviceIndex();
  1194. if (deviceIndex == AZ::RHI::MultiDevice::InvalidDeviceIndex)
  1195. {
  1196. // We assume that the whole pipelines runs on device 0 here
  1197. // Pipelines that might be scheduled on other devices have to take care to set the device index of RTAS passes
  1198. deviceIndex = 0;
  1199. }
  1200. if (m_blasInstanceMap.empty())
  1201. {
  1202. m_deviceMask = AZ::RHI::SetBit(m_deviceMask, deviceIndex);
  1203. }
  1204. else
  1205. {
  1206. // Adding new RTAS passes when a scene is already loaded is currently not supported
  1207. // We would need to build all current BLAS on this new device
  1208. // Additionally we would need to find a way to have a compacted BLAS on one device and an uncompacted on another
  1209. [[maybe_unused]] auto newDeviceMask = AZ::RHI::SetBit(m_deviceMask, deviceIndex);
  1210. AZ_Assert(
  1211. newDeviceMask == m_deviceMask,
  1212. "RaytracingAccelerationStructurePasses cannot be added while the scene already contains objects");
  1213. }
  1214. AZ_Assert(
  1215. RHI::CheckBit(RHI::RHISystemInterface::Get()->GetRayTracingSupport(), deviceIndex),
  1216. "Pass %s does not run on a raytracing capable device",
  1217. pass->GetName().GetCStr());
  1218. return AZ::RPI::ContinueVisitingPasses;
  1219. });
  1220. }
  1221. void RayTracingFeatureProcessor::RemoveBlasInstance(Data::AssetId id)
  1222. {
  1223. m_blasInstanceMap.erase(id);
  1224. m_blasToCreate.erase(id);
  1225. m_skinnedBlasIds.erase(id);
  1226. for (auto& [deviceIndex, entries] : m_blasToBuild)
  1227. {
  1228. entries.erase(id);
  1229. }
  1230. for (auto& [deviceIndex, entries] : m_blasToCompact)
  1231. {
  1232. entries.erase(id);
  1233. }
  1234. m_blasEnqueuedForCompact.erase(id);
  1235. m_uncompactedBlasEnqueuedForDeletion.erase(id);
  1236. }
  1237. AZ::RHI::RayTracingAccelerationStructureBuildFlags RayTracingFeatureProcessor::CreateRayTracingAccelerationStructureBuildFlags(bool isSkinnedMesh)
  1238. {
  1239. AZ::RHI::RayTracingAccelerationStructureBuildFlags buildFlags;
  1240. if (isSkinnedMesh)
  1241. {
  1242. buildFlags = AZ::RHI::RayTracingAccelerationStructureBuildFlags::ENABLE_UPDATE | AZ::RHI::RayTracingAccelerationStructureBuildFlags::FAST_BUILD;
  1243. }
  1244. else
  1245. {
  1246. buildFlags = AZ::RHI::RayTracingAccelerationStructureBuildFlags::FAST_TRACE;
  1247. auto rpiDesc = RPI::RPISystemInterface::Get()->GetDescriptor();
  1248. if (rpiDesc.m_rayTracingSystemDescriptor.m_enableBlasCompaction)
  1249. {
  1250. buildFlags = buildFlags | RHI::RayTracingAccelerationStructureBuildFlags::ENABLE_COMPACTION;
  1251. }
  1252. }
  1253. return buildFlags;
  1254. }
  1255. void RayTracingFeatureProcessor::ConvertMaterial(MaterialInfo& materialInfo, const SubMeshMaterial& subMeshMaterial, int deviceIndex)
  1256. {
  1257. subMeshMaterial.m_baseColor.StoreToFloat4(materialInfo.m_baseColor.data());
  1258. subMeshMaterial.m_emissiveColor.StoreToFloat4(materialInfo.m_emissiveColor.data());
  1259. subMeshMaterial.m_irradianceColor.StoreToFloat4(materialInfo.m_irradianceColor.data());
  1260. materialInfo.m_metallicFactor = subMeshMaterial.m_metallicFactor;
  1261. materialInfo.m_roughnessFactor = subMeshMaterial.m_roughnessFactor;
  1262. materialInfo.m_textureFlags = subMeshMaterial.m_textureFlags;
  1263. if (materialInfo.m_textureStartIndex != InvalidIndex)
  1264. {
  1265. m_materialTextureIndices[deviceIndex].RemoveEntry(materialInfo.m_textureStartIndex);
  1266. #if !USE_BINDLESS_SRG
  1267. m_materialTextures.RemoveResource(subMeshMaterial.m_baseColorImageView.get());
  1268. m_materialTextures.RemoveResource(subMeshMaterial.m_normalImageView.get());
  1269. m_materialTextures.RemoveResource(subMeshMaterial.m_metallicImageView.get());
  1270. m_materialTextures.RemoveResource(subMeshMaterial.m_roughnessImageView.get());
  1271. m_materialTextures.RemoveResource(subMeshMaterial.m_emissiveImageView.get());
  1272. #endif
  1273. }
  1274. materialInfo.m_textureStartIndex = m_materialTextureIndices[deviceIndex].AddEntry({
  1275. #if USE_BINDLESS_SRG
  1276. subMeshMaterial.m_baseColorImageView.get() ? subMeshMaterial.m_baseColorImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  1277. subMeshMaterial.m_normalImageView.get() ? subMeshMaterial.m_normalImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  1278. subMeshMaterial.m_metallicImageView.get() ? subMeshMaterial.m_metallicImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  1279. subMeshMaterial.m_roughnessImageView.get() ? subMeshMaterial.m_roughnessImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex,
  1280. subMeshMaterial.m_emissiveImageView.get() ? subMeshMaterial.m_emissiveImageView->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidIndex
  1281. #else
  1282. m_materialTextures.AddResource(subMeshMaterial.m_baseColorImageView.get()),
  1283. m_materialTextures.AddResource(subMeshMaterial.m_normalImageView.get()),
  1284. m_materialTextures.AddResource(subMeshMaterial.m_metallicImageView.get()),
  1285. m_materialTextures.AddResource(subMeshMaterial.m_roughnessImageView.get()),
  1286. m_materialTextures.AddResource(subMeshMaterial.m_emissiveImageView.get())
  1287. #endif
  1288. });
  1289. }
  1290. } // namespace Render
  1291. }