ShaderAsset.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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/RPI.Reflect/Shader/ShaderAsset.h>
  9. #include <Atom/RPI.Reflect/Shader/ShaderCommonTypes.h>
  10. #include <AzCore/Asset/AssetSerializer.h>
  11. #include <AzCore/Casting/numeric_cast.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. #include <AzCore/std/algorithm.h>
  14. #include <Atom/RHI/Factory.h>
  15. #include <AzCore/Interface/Interface.h>
  16. #include <Atom/RPI.Reflect/Shader/IShaderVariantFinder.h>
  17. #include <Atom/RPI.Public/Shader/ShaderSystem.h>
  18. #include <Atom/RPI.Public/Shader/ShaderReloadDebugTracker.h>
  19. #include <Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h>
  20. DECLARE_EBUS_INSTANTIATION(RPI::ShaderVariantFinderNotification);
  21. namespace AZ
  22. {
  23. namespace RPI
  24. {
  25. const ShaderVariantStableId ShaderAsset::RootShaderVariantStableId{0};
  26. static constexpr uint32_t SubProductTypeBitPosition = 0;
  27. static constexpr uint32_t SubProductTypeNumBits = SupervariantIndexBitPosition - SubProductTypeBitPosition;
  28. [[maybe_unused]] static constexpr uint32_t SubProductTypeMaxValue = (1 << SubProductTypeNumBits) - 1;
  29. static_assert(RhiIndexMaxValue == RHI::Limits::APIType::PerPlatformApiUniqueIndexMax);
  30. uint32_t ShaderAsset::MakeProductAssetSubId(
  31. uint32_t rhiApiUniqueIndex, uint32_t supervariantIndex, uint32_t subProductType)
  32. {
  33. AZ_Assert(rhiApiUniqueIndex <= RhiIndexMaxValue, "Invalid rhiApiUniqueIndex [%u]", rhiApiUniqueIndex);
  34. AZ_Assert(supervariantIndex <= SupervariantIndexMaxValue, "Invalid supervariantIndex [%u]", supervariantIndex);
  35. AZ_Assert(subProductType <= SubProductTypeMaxValue, "Invalid subProductType [%u]", subProductType);
  36. const uint32_t assetProductSubId = (rhiApiUniqueIndex << RhiIndexBitPosition) |
  37. (supervariantIndex << SupervariantIndexBitPosition) | (subProductType << SubProductTypeBitPosition);
  38. return assetProductSubId;
  39. }
  40. SupervariantIndex ShaderAsset::GetSupervariantIndexFromProductAssetSubId(uint32_t assetProducSubId)
  41. {
  42. const uint32_t supervariantIndex = assetProducSubId >> SupervariantIndexBitPosition;
  43. return SupervariantIndex{supervariantIndex & SupervariantIndexMaxValue};
  44. }
  45. SupervariantIndex ShaderAsset::GetSupervariantIndexFromAssetId(const Data::AssetId& assetId)
  46. {
  47. return GetSupervariantIndexFromProductAssetSubId(assetId.m_subId);
  48. }
  49. void ShaderAsset::Supervariant::Reflect(AZ::ReflectContext* context)
  50. {
  51. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  52. {
  53. serializeContext->Class<Supervariant>()
  54. ->Version(1)
  55. ->Field("Name", &Supervariant::m_name)
  56. ->Field("SrgLayoutList", &Supervariant::m_srgLayoutList)
  57. ->Field("PipelineLayout", &Supervariant::m_pipelineLayoutDescriptor)
  58. ->Field("InputContract", &Supervariant::m_inputContract)
  59. ->Field("OutputContract", &Supervariant::m_outputContract)
  60. ->Field("RenderStates", &Supervariant::m_renderStates)
  61. ->Field("AttributeMapList", &Supervariant::m_attributeMaps)
  62. ->Field("RootVariantAsset", &Supervariant::m_rootShaderVariantAsset)
  63. ->Field("UseSpecializationConstants", &Supervariant::m_useSpecializationConstants)
  64. ;
  65. }
  66. }
  67. void ShaderAsset::ShaderApiDataContainer::Reflect(AZ::ReflectContext* context)
  68. {
  69. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  70. {
  71. serializeContext->Class<ShaderApiDataContainer>()
  72. ->Version(1)
  73. ->Field("APIType", &ShaderApiDataContainer::m_APIType)
  74. ->Field("Supervariants", &ShaderApiDataContainer::m_supervariants)
  75. ;
  76. }
  77. }
  78. void ShaderAsset::Reflect(ReflectContext* context)
  79. {
  80. Supervariant::Reflect(context);
  81. ShaderApiDataContainer::Reflect(context);
  82. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  83. {
  84. serializeContext->Class<ShaderAsset>()
  85. ->Version(2)
  86. ->Field("name", &ShaderAsset::m_name)
  87. ->Field("pipelineStateType", &ShaderAsset::m_pipelineStateType)
  88. ->Field("shaderOptionGroupLayout", &ShaderAsset::m_shaderOptionGroupLayout)
  89. ->Field("defaultShaderOptionValueOverrides", &ShaderAsset::m_defaultShaderOptionValueOverrides)
  90. ->Field("drawListName", &ShaderAsset::m_drawListName)
  91. ->Field("perAPIShaderData", &ShaderAsset::m_perAPIShaderData)
  92. ;
  93. }
  94. }
  95. ShaderAsset::~ShaderAsset()
  96. {
  97. ShaderVariantFinderNotificationBus::Handler::BusDisconnect();
  98. AssetInitBus::Handler::BusDisconnect();
  99. }
  100. const Name& ShaderAsset::GetName() const
  101. {
  102. return m_name;
  103. }
  104. RHI::PipelineStateType ShaderAsset::GetPipelineStateType() const
  105. {
  106. return m_pipelineStateType;
  107. }
  108. const ShaderOptionGroupLayout* ShaderAsset::GetShaderOptionGroupLayout() const
  109. {
  110. AZ_Assert(m_shaderOptionGroupLayout, "m_shaderOptionGroupLayout is null");
  111. return m_shaderOptionGroupLayout.get();
  112. }
  113. ShaderOptionGroup ShaderAsset::GetDefaultShaderOptions() const
  114. {
  115. // The m_shaderOptionGroupLayout has default values for each shader option, these come from shader source code.
  116. // The ShaderAsset can override these with its own default values, these come from the .shader file.
  117. ShaderOptionGroup shaderOptionGroup{m_shaderOptionGroupLayout, m_defaultShaderOptionValueOverrides};
  118. shaderOptionGroup.SetUnspecifiedToDefaultValues();
  119. return shaderOptionGroup;
  120. }
  121. const Name& ShaderAsset::GetDrawListName() const
  122. {
  123. return m_drawListName;
  124. }
  125. void ShaderAsset::SetReady()
  126. {
  127. m_status = AssetStatus::Ready;
  128. }
  129. SupervariantIndex ShaderAsset::GetSupervariantIndex(const AZ::Name& supervariantName) const
  130. {
  131. SupervariantIndex supervariantIndex = InvalidSupervariantIndex;
  132. // check for an RPI ShaderSystem supervariant
  133. RPI::ShaderSystemInterface* shaderSystemInterface = ShaderSystemInterface::Get();
  134. if (shaderSystemInterface && !shaderSystemInterface->GetSupervariantName().IsEmpty())
  135. {
  136. // search for the combined requested name and system supervariant name
  137. // Note: the shader may not support this supervariant, if it doesn't we will
  138. // fallback to the requested name below
  139. AZStd::string combinedName = supervariantName.GetCStr();
  140. combinedName.append(shaderSystemInterface->GetSupervariantName().GetCStr());
  141. supervariantIndex = GetSupervariantIndexInternal(AZ::Name(combinedName));
  142. }
  143. if (supervariantIndex == InvalidSupervariantIndex)
  144. {
  145. // search for the requested name
  146. supervariantIndex = GetSupervariantIndexInternal(supervariantName);
  147. }
  148. return supervariantIndex;
  149. }
  150. const AZ::Name& ShaderAsset::GetSupervariantName(SupervariantIndex supervariantIndex) const
  151. {
  152. const auto& supervariants = GetCurrentShaderApiData().m_supervariants;
  153. if (supervariantIndex.GetIndex() >= supervariants.size())
  154. {
  155. // Index 0 always exists, because the default supervariant always exists.
  156. return supervariants[0].m_name;
  157. }
  158. return supervariants[supervariantIndex.GetIndex()].m_name;
  159. }
  160. Data::Asset<ShaderVariantAsset> ShaderAsset::GetVariantAsset(
  161. const ShaderVariantId& shaderVariantId, SupervariantIndex supervariantIndex)
  162. {
  163. auto variantFinder = AZ::Interface<IShaderVariantFinder>::Get();
  164. AZ_Assert(variantFinder, "The IShaderVariantFinder doesn't exist");
  165. Data::Asset<ShaderAsset> thisAsset(this, Data::AssetLoadBehavior::Default);
  166. Data::Asset<ShaderVariantAsset> shaderVariantAsset =
  167. variantFinder->GetShaderVariantAssetByVariantId(thisAsset, shaderVariantId, supervariantIndex);
  168. if (!shaderVariantAsset && !IsFullySpecialized(supervariantIndex))
  169. {
  170. variantFinder->QueueLoadShaderVariantAssetByVariantId(thisAsset, shaderVariantId, supervariantIndex);
  171. }
  172. return shaderVariantAsset;
  173. }
  174. ShaderVariantSearchResult ShaderAsset::FindVariantStableId(const ShaderVariantId& shaderVariantId)
  175. {
  176. uint32_t dynamicOptionCount = aznumeric_cast<uint32_t>(GetShaderOptionGroupLayout()->GetShaderOptions().size());
  177. ShaderVariantSearchResult variantSearchResult{RootShaderVariantStableId, dynamicOptionCount };
  178. if (!dynamicOptionCount || m_isFullySpecialized)
  179. {
  180. // The shader has no options at all. There's nothing to search.
  181. return variantSearchResult;
  182. }
  183. auto variantFinder = AZ::Interface<IShaderVariantFinder>::Get();
  184. AZ_Assert(variantFinder, "The IShaderVariantFinder doesn't exist");
  185. {
  186. AZStd::shared_lock<decltype(m_variantTreeMutex)> lock(m_variantTreeMutex);
  187. if (m_shaderVariantTree)
  188. {
  189. return m_shaderVariantTree->FindVariantStableId(GetShaderOptionGroupLayout(), shaderVariantId);
  190. }
  191. }
  192. AZStd::unique_lock<decltype(m_variantTreeMutex)> lock(m_variantTreeMutex);
  193. if (!m_shaderVariantTree)
  194. {
  195. m_shaderVariantTree = variantFinder->GetShaderVariantTreeAsset(GetId());
  196. if (!m_shaderVariantTree)
  197. {
  198. if (!m_shaderVariantTreeLoadWasRequested)
  199. {
  200. variantFinder->QueueLoadShaderVariantTreeAsset(GetId());
  201. m_shaderVariantTreeLoadWasRequested = true;
  202. }
  203. // The variant tree could be under construction or simply doesn't exist at all.
  204. return variantSearchResult;
  205. }
  206. }
  207. return m_shaderVariantTree->FindVariantStableId(GetShaderOptionGroupLayout(), shaderVariantId);
  208. }
  209. Data::Asset<ShaderVariantAsset> ShaderAsset::GetVariantAsset(
  210. ShaderVariantStableId shaderVariantStableId, SupervariantIndex supervariantIndex) const
  211. {
  212. if (!shaderVariantStableId.IsValid() ||
  213. shaderVariantStableId == RootShaderVariantStableId ||
  214. IsFullySpecialized(supervariantIndex))
  215. {
  216. return GetRootVariantAsset(supervariantIndex);
  217. }
  218. auto variantFinder = AZ::Interface<IShaderVariantFinder>::Get();
  219. AZ_Assert(variantFinder, "No Variant Finder For shaderAsset with name [%s] and stableId [%u]", GetName().GetCStr(), shaderVariantStableId.GetIndex());
  220. Data::Asset<ShaderVariantAsset> variant =
  221. variantFinder->GetShaderVariantAsset(m_shaderVariantTree.GetId(), shaderVariantStableId, supervariantIndex);
  222. if (!variant.IsReady())
  223. {
  224. // Enqueue a request to load the variant, next time around the caller will get the asset.
  225. Data::AssetId variantTreeAssetId;
  226. {
  227. AZStd::shared_lock<decltype(m_variantTreeMutex)> lock(m_variantTreeMutex);
  228. if (m_shaderVariantTree)
  229. {
  230. variantTreeAssetId = m_shaderVariantTree.GetId();
  231. }
  232. }
  233. if (variantTreeAssetId.IsValid())
  234. {
  235. variantFinder->QueueLoadShaderVariantAsset(variantTreeAssetId, shaderVariantStableId, GetSupervariantName(supervariantIndex));
  236. }
  237. return GetRootVariantAsset(supervariantIndex);
  238. }
  239. return variant;
  240. }
  241. Data::Asset<ShaderVariantAsset> ShaderAsset::GetRootVariantAsset(SupervariantIndex supervariantIndex) const
  242. {
  243. auto supervariant = GetSupervariant(supervariantIndex);
  244. if (!supervariant)
  245. {
  246. return Data::Asset<ShaderVariantAsset>();
  247. }
  248. return supervariant->m_rootShaderVariantAsset;
  249. }
  250. const RHI::Ptr<RHI::ShaderResourceGroupLayout>& ShaderAsset::FindShaderResourceGroupLayout(
  251. const Name& shaderResourceGroupName, SupervariantIndex supervariantIndex) const
  252. {
  253. auto supervariant = GetSupervariant(supervariantIndex);
  254. if (!supervariant)
  255. {
  256. return RHI::NullSrgLayout;
  257. }
  258. const auto& srgLayoutList = supervariant->m_srgLayoutList;
  259. const auto findIt = AZStd::find_if(srgLayoutList.begin(), srgLayoutList.end(), [&](const RHI::Ptr<RHI::ShaderResourceGroupLayout>& layout)
  260. {
  261. return layout->GetName() == shaderResourceGroupName;
  262. });
  263. if (findIt != srgLayoutList.end())
  264. {
  265. return *findIt;
  266. }
  267. return RHI::NullSrgLayout;
  268. }
  269. const RHI::Ptr<RHI::ShaderResourceGroupLayout>& ShaderAsset::FindShaderResourceGroupLayout(const Name& shaderResourceGroupName) const
  270. {
  271. SupervariantIndex supervariantIndex = DefaultSupervariantIndex;
  272. // check for an RPI ShaderSystem specified supervariant
  273. // Note: we can just search for the system supervariant name, since the default supervariant is "", so no need to append
  274. RPI::ShaderSystemInterface* shaderSystemInterface = ShaderSystemInterface::Get();
  275. if (shaderSystemInterface && !shaderSystemInterface->GetSupervariantName().IsEmpty())
  276. {
  277. SupervariantIndex systemSupervariantIndex = GetSupervariantIndexInternal(shaderSystemInterface->GetSupervariantName());
  278. if (systemSupervariantIndex.IsValid())
  279. {
  280. supervariantIndex = systemSupervariantIndex;
  281. }
  282. }
  283. return FindShaderResourceGroupLayout(shaderResourceGroupName, supervariantIndex);
  284. }
  285. const RHI::Ptr<RHI::ShaderResourceGroupLayout>& ShaderAsset::FindShaderResourceGroupLayout(
  286. uint32_t bindingSlot, SupervariantIndex supervariantIndex) const
  287. {
  288. auto supervariant = GetSupervariant(supervariantIndex);
  289. if (!supervariant)
  290. {
  291. return RHI::NullSrgLayout;
  292. }
  293. const auto& srgLayoutList = supervariant->m_srgLayoutList;
  294. const auto findIt =
  295. AZStd::find_if(srgLayoutList.begin(), srgLayoutList.end(), [&](const RHI::Ptr<RHI::ShaderResourceGroupLayout>& layout)
  296. {
  297. return layout && layout->GetBindingSlot() == bindingSlot;
  298. });
  299. if (findIt != srgLayoutList.end())
  300. {
  301. return *findIt;
  302. }
  303. return RHI::NullSrgLayout;
  304. }
  305. const RHI::Ptr<RHI::ShaderResourceGroupLayout>& ShaderAsset::FindShaderResourceGroupLayout(uint32_t bindingSlot) const
  306. {
  307. SupervariantIndex supervariantIndex = DefaultSupervariantIndex;
  308. // check for an RPI ShaderSystem specified supervariant
  309. // Note: we can just search for the system supervariant name, since the default supervariant is "", so no need to append
  310. RPI::ShaderSystemInterface* shaderSystemInterface = ShaderSystemInterface::Get();
  311. if (shaderSystemInterface && !shaderSystemInterface->GetSupervariantName().IsEmpty())
  312. {
  313. SupervariantIndex systemSupervariantIndex = GetSupervariantIndexInternal(shaderSystemInterface->GetSupervariantName());
  314. if (systemSupervariantIndex.IsValid())
  315. {
  316. supervariantIndex = systemSupervariantIndex;
  317. }
  318. }
  319. return FindShaderResourceGroupLayout(bindingSlot, supervariantIndex);
  320. }
  321. const RHI::Ptr<RHI::ShaderResourceGroupLayout>& ShaderAsset::FindFallbackShaderResourceGroupLayout(
  322. SupervariantIndex supervariantIndex) const
  323. {
  324. auto supervariant = GetSupervariant(supervariantIndex);
  325. if (!supervariant)
  326. {
  327. return RHI::NullSrgLayout;
  328. }
  329. const auto& srgLayoutList = supervariant->m_srgLayoutList;
  330. const auto findIt =
  331. AZStd::find_if(srgLayoutList.begin(), srgLayoutList.end(), [&](const RHI::Ptr<RHI::ShaderResourceGroupLayout>& layout)
  332. {
  333. return layout && layout->HasShaderVariantKeyFallbackEntry();
  334. });
  335. if (findIt != srgLayoutList.end())
  336. {
  337. return *findIt;
  338. }
  339. return RHI::NullSrgLayout;
  340. }
  341. AZStd::span<const RHI::Ptr<RHI::ShaderResourceGroupLayout>> ShaderAsset::GetShaderResourceGroupLayouts(
  342. SupervariantIndex supervariantIndex) const
  343. {
  344. auto supervariant = GetSupervariant(supervariantIndex);
  345. if (!supervariant)
  346. {
  347. return {};
  348. }
  349. return supervariant->m_srgLayoutList;
  350. }
  351. const RHI::Ptr<RHI::ShaderResourceGroupLayout>& ShaderAsset::GetDrawSrgLayout(SupervariantIndex supervariantIndex) const
  352. {
  353. return FindShaderResourceGroupLayout(SrgBindingSlot::Draw, supervariantIndex);
  354. }
  355. const ShaderInputContract& ShaderAsset::GetInputContract(SupervariantIndex supervariantIndex) const
  356. {
  357. auto supervariant = GetSupervariant(supervariantIndex);
  358. return supervariant->m_inputContract;
  359. }
  360. const ShaderOutputContract& ShaderAsset::GetOutputContract(SupervariantIndex supervariantIndex) const
  361. {
  362. auto supervariant = GetSupervariant(supervariantIndex);
  363. return supervariant->m_outputContract;
  364. }
  365. const RHI::RenderStates& ShaderAsset::GetRenderStates(SupervariantIndex supervariantIndex) const
  366. {
  367. auto supervariant = GetSupervariant(supervariantIndex);
  368. return supervariant->m_renderStates;
  369. }
  370. const RHI::PipelineLayoutDescriptor* ShaderAsset::GetPipelineLayoutDescriptor(SupervariantIndex supervariantIndex) const
  371. {
  372. auto supervariant = GetSupervariant(supervariantIndex);
  373. if (!supervariant)
  374. {
  375. return nullptr;
  376. }
  377. AZ_Assert(supervariant->m_pipelineLayoutDescriptor, "m_pipelineLayoutDescriptor is null");
  378. return supervariant->m_pipelineLayoutDescriptor.get();
  379. }
  380. AZStd::optional<RHI::ShaderStageAttributeArguments> ShaderAsset::GetAttribute(const RHI::ShaderStage& shaderStage, const Name& attributeName,
  381. SupervariantIndex supervariantIndex) const
  382. {
  383. auto supervariant = GetSupervariant(supervariantIndex);
  384. if (!supervariant)
  385. {
  386. return AZStd::nullopt;
  387. }
  388. const auto stageIndex = static_cast<uint32_t>(shaderStage);
  389. AZ_Assert(stageIndex < RHI::ShaderStageCount, "Invalid shader stage specified!");
  390. const auto& attributeMaps = supervariant->m_attributeMaps;
  391. const auto& attrPair = attributeMaps[stageIndex].find(attributeName);
  392. if (attrPair == attributeMaps[stageIndex].end())
  393. {
  394. return AZStd::nullopt;
  395. }
  396. return attrPair->second;
  397. }
  398. bool ShaderAsset::UseSpecializationConstants(SupervariantIndex supervariantIndex) const
  399. {
  400. auto supervariant = GetSupervariant(supervariantIndex);
  401. if (!supervariant)
  402. {
  403. return false;
  404. }
  405. return supervariant->m_useSpecializationConstants;
  406. }
  407. bool ShaderAsset::IsFullySpecialized(SupervariantIndex supervariantIndex) const
  408. {
  409. return UseSpecializationConstants(supervariantIndex) && m_shaderOptionGroupLayout->IsFullySpecialized();
  410. }
  411. ShaderAsset::ShaderApiDataContainer& ShaderAsset::GetCurrentShaderApiData()
  412. {
  413. const size_t perApiShaderDataCount = m_perAPIShaderData.size();
  414. AZ_Assert(perApiShaderDataCount > 0, "Invalid m_perAPIShaderData");
  415. if (m_currentAPITypeIndex < perApiShaderDataCount)
  416. {
  417. return m_perAPIShaderData[m_currentAPITypeIndex];
  418. }
  419. // We may only endup here when running in a Builder context.
  420. return m_perAPIShaderData[0];
  421. }
  422. const ShaderAsset::ShaderApiDataContainer& ShaderAsset::GetCurrentShaderApiData() const
  423. {
  424. const size_t perApiShaderDataCount = m_perAPIShaderData.size();
  425. AZ_Assert(perApiShaderDataCount > 0, "Invalid m_perAPIShaderData");
  426. if (m_currentAPITypeIndex < perApiShaderDataCount)
  427. {
  428. return m_perAPIShaderData[m_currentAPITypeIndex];
  429. }
  430. // We may only endup here when running in a Builder context.
  431. return m_perAPIShaderData[0];
  432. }
  433. ShaderAsset::Supervariant* ShaderAsset::GetSupervariant(SupervariantIndex supervariantIndex)
  434. {
  435. auto& supervariants = GetCurrentShaderApiData().m_supervariants;
  436. auto index = supervariantIndex.GetIndex();
  437. if (index >= supervariants.size())
  438. {
  439. AZ_Error(
  440. "ShaderAsset", false, "Supervariant index = %u is invalid because there are only %zu supervariants", index,
  441. supervariants.size());
  442. return nullptr;
  443. }
  444. return &supervariants[index];
  445. }
  446. const ShaderAsset::Supervariant* ShaderAsset::GetSupervariant(SupervariantIndex supervariantIndex) const
  447. {
  448. const auto& supervariants = GetCurrentShaderApiData().m_supervariants;
  449. auto index = supervariantIndex.GetIndex();
  450. if (index >= supervariants.size())
  451. {
  452. AZ_Error(
  453. "ShaderAsset", false, "Supervariant index = %u is invalid because there are only %zu supervariants", index,
  454. supervariants.size());
  455. return nullptr;
  456. }
  457. return &supervariants[index];
  458. }
  459. SupervariantIndex ShaderAsset::GetSupervariantIndexInternal(AZ::Name supervariantName) const
  460. {
  461. const auto& supervariants = GetCurrentShaderApiData().m_supervariants;
  462. const uint32_t supervariantCount = static_cast<uint32_t>(supervariants.size());
  463. for (uint32_t index = 0; index < supervariantCount; ++index)
  464. {
  465. if (supervariants[index].m_name == supervariantName)
  466. {
  467. return SupervariantIndex{ index };
  468. }
  469. }
  470. return InvalidSupervariantIndex;
  471. }
  472. bool ShaderAsset::SelectShaderApiData()
  473. {
  474. // Use the current RHI that is active to select which shader data to use.
  475. // We don't assert if the Factory is not available because this method could be called during build time,
  476. // when no Factory is available. Some assets (like the material asset) need to load the ShaderAsset
  477. // in order to get some non API specific data (like a ShaderResourceGroup) during their build
  478. // process. If they try to access any RHI API specific data, an assert will be trigger because the
  479. // correct API index will not set.
  480. if (RHI::Factory::IsReady())
  481. {
  482. auto rhiType = RHI::Factory::Get().GetType();
  483. auto findIt = AZStd::find_if(m_perAPIShaderData.begin(), m_perAPIShaderData.end(), [&rhiType](const auto& shaderData)
  484. {
  485. return shaderData.m_APIType == rhiType;
  486. });
  487. if (findIt != m_perAPIShaderData.end())
  488. {
  489. m_currentAPITypeIndex = AZStd::distance(m_perAPIShaderData.begin(), findIt);
  490. }
  491. else
  492. {
  493. AZ_Error("ShaderAsset", false, "Could not find shader for API %s in shader %s", RHI::Factory::Get().GetName().GetCStr(), GetName().GetCStr());
  494. return false;
  495. }
  496. }
  497. m_isFullySpecialized = m_shaderOptionGroupLayout->IsFullySpecialized();
  498. // Common finalize check
  499. for (const auto& shaderApiData : m_perAPIShaderData)
  500. {
  501. const auto& supervariants = shaderApiData.m_supervariants;
  502. for (const auto& supervariant : supervariants)
  503. {
  504. m_isFullySpecialized &= supervariant.m_useSpecializationConstants;
  505. bool beTrue = supervariant.m_attributeMaps.size() == RHI::ShaderStageCount;
  506. if (!beTrue)
  507. {
  508. AZ_Error("ShaderAsset", false, "Unexpected number of shader stages at supervariant with name [%s]!", supervariant.m_name.GetCStr());
  509. return false;
  510. }
  511. }
  512. }
  513. return true;
  514. }
  515. bool ShaderAsset::PostLoadInit()
  516. {
  517. ShaderVariantFinderNotificationBus::Handler::BusConnect(GetId());
  518. AssetInitBus::Handler::BusDisconnect();
  519. return true;
  520. }
  521. ///////////////////////////////////////////////////////////////////
  522. /// ShaderVariantFinderNotificationBus overrides
  523. void ShaderAsset::OnShaderVariantTreeAssetReady(Data::Asset<ShaderVariantTreeAsset> shaderVariantTreeAsset, bool isError)
  524. {
  525. ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderAsset::OnShaderVariantTreeAssetReady %s", this, shaderVariantTreeAsset.GetHint().c_str());
  526. AZStd::unique_lock<decltype(m_variantTreeMutex)> lock(m_variantTreeMutex);
  527. if (isError)
  528. {
  529. m_shaderVariantTree = {}; //This will force to attempt to reload later.
  530. m_shaderVariantTreeLoadWasRequested = false;
  531. }
  532. else
  533. {
  534. m_shaderVariantTree = shaderVariantTreeAsset;
  535. }
  536. lock.unlock();
  537. }
  538. ///////////////////////////////////////////////////////////////////
  539. ///////////////////////////////////////////////////////////////////////
  540. // ShaderAssetHandler
  541. Data::AssetHandler::LoadResult ShaderAssetHandler::LoadAssetData(
  542. const Data::Asset<Data::AssetData>& asset,
  543. AZStd::shared_ptr<Data::AssetDataStream> stream,
  544. const Data::AssetFilterCB& assetLoadFilterCB)
  545. {
  546. if (Base::LoadAssetData(asset, stream, assetLoadFilterCB) == Data::AssetHandler::LoadResult::LoadComplete)
  547. {
  548. ShaderAsset* shaderAsset = asset.GetAs<ShaderAsset>();
  549. // The shader API selection must occur immediately ofter loading, on the same thread, rather than
  550. // deferring to AssetInitBus::PostLoadInit. Many functions in the ShaderAsset class are invalid
  551. // until after SelectShaderApiData() is called and some client code may need to access data in
  552. // the ShaderAsset before then.
  553. if (!shaderAsset->SelectShaderApiData())
  554. {
  555. return Data::AssetHandler::LoadResult::Error;
  556. }
  557. shaderAsset->AssetInitBus::Handler::BusConnect();
  558. return Data::AssetHandler::LoadResult::LoadComplete;
  559. }
  560. return Data::AssetHandler::LoadResult::Error;
  561. }
  562. ///////////////////////////////////////////////////////////////////////
  563. } // namespace RPI
  564. } // namespace AZ