ShaderAssetCreator.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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/RHI.Edit/ShaderPlatformInterface.h>
  9. #include <Atom/RPI.Reflect/Shader/ShaderAssetCreator.h>
  10. namespace AZ
  11. {
  12. namespace RPI
  13. {
  14. void ShaderAssetCreator::Begin(const Data::AssetId& assetId)
  15. {
  16. BeginCommon(assetId);
  17. }
  18. void ShaderAssetCreator::SetName(const Name& name)
  19. {
  20. if (ValidateIsReady())
  21. {
  22. m_asset->m_name = name;
  23. }
  24. }
  25. void ShaderAssetCreator::SetDrawListName(const Name& name)
  26. {
  27. if (ValidateIsReady())
  28. {
  29. m_asset->m_drawListName = name;
  30. }
  31. }
  32. void ShaderAssetCreator::SetShaderOptionGroupLayout(const Ptr<ShaderOptionGroupLayout>& shaderOptionGroupLayout)
  33. {
  34. if (ValidateIsReady())
  35. {
  36. m_asset->m_shaderOptionGroupLayout = shaderOptionGroupLayout;
  37. m_defaultShaderOptionGroup = ShaderOptionGroup{shaderOptionGroupLayout};
  38. }
  39. }
  40. void ShaderAssetCreator::SetShaderOptionDefaultValue(const Name& optionName, const Name& optionValue)
  41. {
  42. if (ValidateIsReady())
  43. {
  44. if (!m_defaultShaderOptionGroup.SetValue(optionName, optionValue))
  45. {
  46. ReportError("Could not set shader option '%s'.", optionName.GetCStr());
  47. }
  48. }
  49. }
  50. void ShaderAssetCreator::BeginAPI(RHI::APIType type)
  51. {
  52. if (ValidateIsReady())
  53. {
  54. ShaderAsset::ShaderApiDataContainer shaderData;
  55. shaderData.m_APIType = type;
  56. m_asset->m_currentAPITypeIndex = m_asset->m_perAPIShaderData.size();
  57. m_asset->m_perAPIShaderData.push_back(shaderData);
  58. }
  59. }
  60. void ShaderAssetCreator::BeginSupervariant(const Name& name)
  61. {
  62. if (!ValidateIsReady())
  63. {
  64. return;
  65. }
  66. if (m_currentSupervariant)
  67. {
  68. ReportError("Call EndSupervariant() before calling BeginSupervariant again.");
  69. return;
  70. }
  71. if (m_asset->m_currentAPITypeIndex == ShaderAsset::InvalidAPITypeIndex)
  72. {
  73. ReportError("Can not begin supervariant with name [%s] because this function must be called between BeginAPI()/EndAPI()", name.GetCStr());
  74. return;
  75. }
  76. if (m_asset->m_perAPIShaderData.empty())
  77. {
  78. ReportError("Can not add supervariant with name [%s] because there's no per API shader data", name.GetCStr());
  79. return;
  80. }
  81. ShaderAsset::ShaderApiDataContainer& perAPIShaderData = m_asset->m_perAPIShaderData[m_asset->m_perAPIShaderData.size() - 1];
  82. if (perAPIShaderData.m_supervariants.empty())
  83. {
  84. if (!name.IsEmpty())
  85. {
  86. ReportError("The first supervariant must be nameless. Name [%s] is invalid", name.GetCStr());
  87. return;
  88. }
  89. }
  90. else
  91. {
  92. if (name.IsEmpty())
  93. {
  94. ReportError(
  95. "Only the first supervariant can be nameless. So far there are %zu supervariants",
  96. perAPIShaderData.m_supervariants.size());
  97. return;
  98. }
  99. }
  100. perAPIShaderData.m_supervariants.push_back({});
  101. m_currentSupervariant = &perAPIShaderData.m_supervariants[perAPIShaderData.m_supervariants.size() - 1];
  102. m_currentSupervariant->m_name = name;
  103. }
  104. void ShaderAssetCreator::SetSrgLayoutList(const ShaderResourceGroupLayoutList& srgLayoutList)
  105. {
  106. if (!ValidateIsReady())
  107. {
  108. return;
  109. }
  110. if (!m_currentSupervariant)
  111. {
  112. ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
  113. return;
  114. }
  115. m_currentSupervariant->m_srgLayoutList = srgLayoutList;
  116. for (auto srgLayout : m_currentSupervariant->m_srgLayoutList)
  117. {
  118. if (!srgLayout->Finalize())
  119. {
  120. ReportError(
  121. "The current supervariant [%s], failed to finalize SRG Layout [%s]", m_currentSupervariant->m_name.GetCStr(),
  122. srgLayout->GetName().GetCStr());
  123. return;
  124. }
  125. }
  126. }
  127. //! [Required] Assigns the pipeline layout descriptor shared by all variants in the shader. Shader variants
  128. //! embedded in a single shader asset are required to use the same pipeline layout. It is not necessary to call
  129. //! Finalize() on the pipeline layout prior to assignment, but still permitted.
  130. void ShaderAssetCreator::SetPipelineLayout(RHI::Ptr<RHI::PipelineLayoutDescriptor> pipelineLayoutDescriptor)
  131. {
  132. if (!ValidateIsReady())
  133. {
  134. return;
  135. }
  136. if (!m_currentSupervariant)
  137. {
  138. ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
  139. return;
  140. }
  141. m_currentSupervariant->m_pipelineLayoutDescriptor = pipelineLayoutDescriptor;
  142. }
  143. //! Assigns the contract for inputs required by the shader.
  144. void ShaderAssetCreator::SetInputContract(const ShaderInputContract& contract)
  145. {
  146. if (!ValidateIsReady())
  147. {
  148. return;
  149. }
  150. if (!m_currentSupervariant)
  151. {
  152. ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
  153. return;
  154. }
  155. m_currentSupervariant->m_inputContract = contract;
  156. }
  157. //! Assigns the contract for outputs required by the shader.
  158. void ShaderAssetCreator::SetOutputContract(const ShaderOutputContract& contract)
  159. {
  160. if (!ValidateIsReady())
  161. {
  162. return;
  163. }
  164. if (!m_currentSupervariant)
  165. {
  166. ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
  167. return;
  168. }
  169. m_currentSupervariant->m_outputContract = contract;
  170. }
  171. //! Assigns the render states for the draw pipeline. Ignored for non-draw pipelines.
  172. void ShaderAssetCreator::SetRenderStates(const RHI::RenderStates& renderStates)
  173. {
  174. if (!ValidateIsReady())
  175. {
  176. return;
  177. }
  178. if (!m_currentSupervariant)
  179. {
  180. ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
  181. return;
  182. }
  183. m_currentSupervariant->m_renderStates = renderStates;
  184. }
  185. //! [Optional] Not all shaders have attributes before functions. Some attributes do not exist for all RHI::APIType either.
  186. void ShaderAssetCreator::SetShaderStageAttributeMapList(const RHI::ShaderStageAttributeMapList& shaderStageAttributeMapList)
  187. {
  188. if (!ValidateIsReady())
  189. {
  190. return;
  191. }
  192. if (!m_currentSupervariant)
  193. {
  194. ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
  195. return;
  196. }
  197. m_currentSupervariant->m_attributeMaps = shaderStageAttributeMapList;
  198. }
  199. //! [Required] There's always a root variant for each supervariant.
  200. void ShaderAssetCreator::SetRootShaderVariantAsset(Data::Asset<ShaderVariantAsset> shaderVariantAsset)
  201. {
  202. if (!ValidateIsReady())
  203. {
  204. return;
  205. }
  206. if (!m_currentSupervariant)
  207. {
  208. ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
  209. return;
  210. }
  211. if (!shaderVariantAsset)
  212. {
  213. ReportError("Invalid root variant");
  214. return;
  215. }
  216. m_currentSupervariant->m_rootShaderVariantAsset = shaderVariantAsset;
  217. }
  218. void ShaderAssetCreator::SetUseSpecializationConstants(bool value)
  219. {
  220. if (!ValidateIsReady())
  221. {
  222. return;
  223. }
  224. if (!m_currentSupervariant)
  225. {
  226. ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
  227. return;
  228. }
  229. m_currentSupervariant->m_useSpecializationConstants = value;
  230. }
  231. static RHI::PipelineStateType GetPipelineStateType(const Data::Asset<ShaderVariantAsset>& shaderVariantAsset)
  232. {
  233. if (shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Vertex) ||
  234. shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Geometry) ||
  235. shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Fragment))
  236. {
  237. return RHI::PipelineStateType::Draw;
  238. }
  239. if (shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Compute))
  240. {
  241. return RHI::PipelineStateType::Dispatch;
  242. }
  243. if (shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::RayTracing))
  244. {
  245. return RHI::PipelineStateType::RayTracing;
  246. }
  247. return RHI::PipelineStateType::Count;
  248. }
  249. bool ShaderAssetCreator::EndSupervariant()
  250. {
  251. if (!ValidateIsReady())
  252. {
  253. return false;
  254. }
  255. if (!m_currentSupervariant)
  256. {
  257. ReportError("Can not end a supervariant that has not started");
  258. return false;
  259. }
  260. if (!m_currentSupervariant->m_rootShaderVariantAsset.IsReady())
  261. {
  262. ReportError(
  263. "The current supervariant [%s], is missing the root ShaderVariantAsset", m_currentSupervariant->m_name.GetCStr());
  264. return false;
  265. }
  266. // Supervariant specific resources
  267. if (m_currentSupervariant->m_pipelineLayoutDescriptor)
  268. {
  269. if (!m_currentSupervariant->m_pipelineLayoutDescriptor->IsFinalized())
  270. {
  271. if (m_currentSupervariant->m_pipelineLayoutDescriptor->Finalize() != RHI::ResultCode::Success)
  272. {
  273. ReportError("Failed to finalize pipeline layout descriptor.");
  274. return false;
  275. }
  276. }
  277. }
  278. else
  279. {
  280. ReportError("PipelineLayoutDescriptor not specified.");
  281. return false;
  282. }
  283. const ShaderInputContract& shaderInputContract = m_currentSupervariant->m_inputContract;
  284. // Validate that each stream ID appears only once.
  285. for (const auto& channel : shaderInputContract.m_streamChannels)
  286. {
  287. int count = 0;
  288. for (const auto& searchChannel : shaderInputContract.m_streamChannels)
  289. {
  290. if (channel.m_semantic == searchChannel.m_semantic)
  291. {
  292. ++count;
  293. }
  294. }
  295. if (count > 1)
  296. {
  297. ReportError(
  298. "Input stream channel [%s] appears multiple times. For supervariant with name [%s]",
  299. channel.m_semantic.ToString().c_str(), m_currentSupervariant->m_name.GetCStr());
  300. return false;
  301. }
  302. }
  303. auto pipelineStateType = GetPipelineStateType(m_currentSupervariant->m_rootShaderVariantAsset);
  304. if (pipelineStateType == RHI::PipelineStateType::Count)
  305. {
  306. ReportError("Invalid pipelineStateType for supervariant [%s]", m_currentSupervariant->m_name.GetCStr());
  307. return false;
  308. }
  309. if (m_currentSupervariant->m_name.IsEmpty())
  310. {
  311. m_asset->m_pipelineStateType = pipelineStateType;
  312. }
  313. else
  314. {
  315. if (m_asset->m_pipelineStateType != pipelineStateType)
  316. {
  317. ReportError("All supervariants must be of the same pipelineStateType. Current pipelineStateType is [%d], but for supervariant [%s] the pipelineStateType is [%d]",
  318. m_asset->m_pipelineStateType, m_currentSupervariant->m_name.GetCStr(), pipelineStateType);
  319. return false;
  320. }
  321. }
  322. m_currentSupervariant->m_useSpecializationConstants =
  323. m_currentSupervariant->m_useSpecializationConstants && m_asset->m_shaderOptionGroupLayout->UseSpecializationConstants();
  324. m_currentSupervariant = nullptr;
  325. return true;
  326. }
  327. bool ShaderAssetCreator::EndAPI()
  328. {
  329. if (!ValidateIsReady())
  330. {
  331. return false;
  332. }
  333. if (m_currentSupervariant)
  334. {
  335. ReportError("EndSupervariant() must be called before calling EndAPI()");
  336. return false;
  337. }
  338. m_asset->m_currentAPITypeIndex = ShaderAsset::InvalidAPITypeIndex;
  339. return true;
  340. }
  341. bool ShaderAssetCreator::End(Data::Asset<ShaderAsset>& shaderAsset)
  342. {
  343. if (!ValidateIsReady())
  344. {
  345. return false;
  346. }
  347. if (m_asset->m_perAPIShaderData.empty())
  348. {
  349. ReportError("Empty shader data. Check that a valid RHI is enabled for this platform.");
  350. return false;
  351. }
  352. if (!m_asset->SelectShaderApiData())
  353. {
  354. ReportError("Failed to finalize the ShaderAsset.");
  355. return false;
  356. }
  357. m_asset->m_defaultShaderOptionValueOverrides = m_defaultShaderOptionGroup.GetShaderVariantId();
  358. m_asset->SetReady();
  359. return EndCommon(shaderAsset);
  360. }
  361. void ShaderAssetCreator::Clone(
  362. const Data::AssetId& assetId,
  363. const ShaderAsset& sourceShaderAsset,
  364. [[maybe_unused]] const ShaderSupervariants& supervariants,
  365. const AZStd::vector<RHI::ShaderPlatformInterface*>& platformInterfaces)
  366. {
  367. BeginCommon(assetId);
  368. m_asset->m_name = sourceShaderAsset.m_name;
  369. m_asset->m_pipelineStateType = sourceShaderAsset.m_pipelineStateType;
  370. m_asset->m_drawListName = sourceShaderAsset.m_drawListName;
  371. m_asset->m_shaderOptionGroupLayout = sourceShaderAsset.m_shaderOptionGroupLayout;
  372. // copy the perAPIShaderData
  373. for (auto& perAPIShaderData : sourceShaderAsset.m_perAPIShaderData)
  374. {
  375. // find the API in the list of supported APIs on this platform
  376. AZStd::vector<RHI::ShaderPlatformInterface*>::const_iterator itFoundAPI = AZStd::find_if(
  377. platformInterfaces.begin(),
  378. platformInterfaces.end(),
  379. [&perAPIShaderData](const RHI::ShaderPlatformInterface* shaderPlatformInterface)
  380. {
  381. return perAPIShaderData.m_APIType == shaderPlatformInterface->GetAPIType();
  382. });
  383. if (itFoundAPI == platformInterfaces.end())
  384. {
  385. // the API is not supported on this platform, skip this entry
  386. continue;
  387. }
  388. if (perAPIShaderData.m_supervariants.empty())
  389. {
  390. ReportWarning("Attempting to clone a shader asset that has no supervariants for API [%d]", perAPIShaderData.m_APIType);
  391. continue;
  392. }
  393. if (perAPIShaderData.m_supervariants.size() != supervariants.size())
  394. {
  395. ReportError("Incorrect number of supervariants provided to ShaderAssetCreator::Clone");
  396. return;
  397. }
  398. m_asset->m_perAPIShaderData.push_back(perAPIShaderData);
  399. // set the supervariants for this API
  400. for (auto& supervariant : m_asset->m_perAPIShaderData.back().m_supervariants)
  401. {
  402. // find the matching Supervariant by name from the incoming list
  403. ShaderSupervariants::const_iterator itFoundSuperVariant = AZStd::find_if(
  404. supervariants.begin(),
  405. supervariants.end(),
  406. [&supervariant](const ShaderSupervariant& shaderSupervariant)
  407. {
  408. return supervariant.m_name == shaderSupervariant.m_name;
  409. });
  410. if (itFoundSuperVariant == supervariants.end())
  411. {
  412. ReportError("Failed to find supervariant [%s]", supervariant.m_name.GetCStr());
  413. return;
  414. }
  415. // find the matching ShaderVariantAsset for this API
  416. ShaderRootVariantAssets::const_iterator itFoundRootShaderVariantAsset = AZStd::find_if(
  417. itFoundSuperVariant->m_rootVariantAssets.begin(),
  418. itFoundSuperVariant->m_rootVariantAssets.end(),
  419. [&perAPIShaderData](const ShaderRootVariantAssetPair& rootShaderVariantAsset)
  420. {
  421. return perAPIShaderData.m_APIType == rootShaderVariantAsset.first;
  422. });
  423. if (itFoundRootShaderVariantAsset == itFoundSuperVariant->m_rootVariantAssets.end())
  424. {
  425. ReportWarning("Failed to find root shader variant asset for API [%d] Supervariant [%s]", perAPIShaderData.m_APIType, supervariant.m_name.GetCStr());
  426. }
  427. else
  428. {
  429. supervariant.m_rootShaderVariantAsset = itFoundRootShaderVariantAsset->second;
  430. }
  431. }
  432. }
  433. }
  434. } // namespace RPI
  435. } // namespace AZ