3
0

ShaderAssetCreator.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  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. static RHI::PipelineStateType GetPipelineStateType(const Data::Asset<ShaderVariantAsset>& shaderVariantAsset)
  219. {
  220. if (shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Vertex) ||
  221. shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Tessellation) ||
  222. shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Fragment))
  223. {
  224. return RHI::PipelineStateType::Draw;
  225. }
  226. if (shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Compute))
  227. {
  228. return RHI::PipelineStateType::Dispatch;
  229. }
  230. if (shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::RayTracing))
  231. {
  232. return RHI::PipelineStateType::RayTracing;
  233. }
  234. return RHI::PipelineStateType::Count;
  235. }
  236. bool ShaderAssetCreator::EndSupervariant()
  237. {
  238. if (!ValidateIsReady())
  239. {
  240. return false;
  241. }
  242. if (!m_currentSupervariant)
  243. {
  244. ReportError("Can not end a supervariant that has not started");
  245. return false;
  246. }
  247. if (!m_currentSupervariant->m_rootShaderVariantAsset.IsReady())
  248. {
  249. ReportError(
  250. "The current supervariant [%s], is missing the root ShaderVariantAsset", m_currentSupervariant->m_name.GetCStr());
  251. return false;
  252. }
  253. // Supervariant specific resources
  254. if (m_currentSupervariant->m_pipelineLayoutDescriptor)
  255. {
  256. if (!m_currentSupervariant->m_pipelineLayoutDescriptor->IsFinalized())
  257. {
  258. if (m_currentSupervariant->m_pipelineLayoutDescriptor->Finalize() != RHI::ResultCode::Success)
  259. {
  260. ReportError("Failed to finalize pipeline layout descriptor.");
  261. return false;
  262. }
  263. }
  264. }
  265. else
  266. {
  267. ReportError("PipelineLayoutDescriptor not specified.");
  268. return false;
  269. }
  270. const ShaderInputContract& shaderInputContract = m_currentSupervariant->m_inputContract;
  271. // Validate that each stream ID appears only once.
  272. for (const auto& channel : shaderInputContract.m_streamChannels)
  273. {
  274. int count = 0;
  275. for (const auto& searchChannel : shaderInputContract.m_streamChannels)
  276. {
  277. if (channel.m_semantic == searchChannel.m_semantic)
  278. {
  279. ++count;
  280. }
  281. }
  282. if (count > 1)
  283. {
  284. ReportError(
  285. "Input stream channel [%s] appears multiple times. For supervariant with name [%s]",
  286. channel.m_semantic.ToString().c_str(), m_currentSupervariant->m_name.GetCStr());
  287. return false;
  288. }
  289. }
  290. auto pipelineStateType = GetPipelineStateType(m_currentSupervariant->m_rootShaderVariantAsset);
  291. if (pipelineStateType == RHI::PipelineStateType::Count)
  292. {
  293. ReportError("Invalid pipelineStateType for supervariant [%s]", m_currentSupervariant->m_name.GetCStr());
  294. return false;
  295. }
  296. if (m_currentSupervariant->m_name.IsEmpty())
  297. {
  298. m_asset->m_pipelineStateType = pipelineStateType;
  299. }
  300. else
  301. {
  302. if (m_asset->m_pipelineStateType != pipelineStateType)
  303. {
  304. ReportError("All supervariants must be of the same pipelineStateType. Current pipelineStateType is [%d], but for supervariant [%s] the pipelineStateType is [%d]",
  305. m_asset->m_pipelineStateType, m_currentSupervariant->m_name.GetCStr(), pipelineStateType);
  306. return false;
  307. }
  308. }
  309. m_currentSupervariant = nullptr;
  310. return true;
  311. }
  312. bool ShaderAssetCreator::EndAPI()
  313. {
  314. if (!ValidateIsReady())
  315. {
  316. return false;
  317. }
  318. if (m_currentSupervariant)
  319. {
  320. ReportError("EndSupervariant() must be called before calling EndAPI()");
  321. return false;
  322. }
  323. m_asset->m_currentAPITypeIndex = ShaderAsset::InvalidAPITypeIndex;
  324. return true;
  325. }
  326. bool ShaderAssetCreator::End(Data::Asset<ShaderAsset>& shaderAsset)
  327. {
  328. if (!ValidateIsReady())
  329. {
  330. return false;
  331. }
  332. if (m_asset->m_perAPIShaderData.empty())
  333. {
  334. ReportError("Empty shader data. Check that a valid RHI is enabled for this platform.");
  335. return false;
  336. }
  337. if (!m_asset->SelectShaderApiData())
  338. {
  339. ReportError("Failed to finalize the ShaderAsset.");
  340. return false;
  341. }
  342. m_asset->m_defaultShaderOptionValueOverrides = m_defaultShaderOptionGroup.GetShaderVariantId();
  343. m_asset->SetReady();
  344. return EndCommon(shaderAsset);
  345. }
  346. void ShaderAssetCreator::Clone(
  347. const Data::AssetId& assetId,
  348. const ShaderAsset& sourceShaderAsset,
  349. [[maybe_unused]] const ShaderSupervariants& supervariants,
  350. const AZStd::vector<RHI::ShaderPlatformInterface*>& platformInterfaces)
  351. {
  352. BeginCommon(assetId);
  353. m_asset->m_name = sourceShaderAsset.m_name;
  354. m_asset->m_pipelineStateType = sourceShaderAsset.m_pipelineStateType;
  355. m_asset->m_drawListName = sourceShaderAsset.m_drawListName;
  356. m_asset->m_shaderOptionGroupLayout = sourceShaderAsset.m_shaderOptionGroupLayout;
  357. // copy the perAPIShaderData
  358. for (auto& perAPIShaderData : sourceShaderAsset.m_perAPIShaderData)
  359. {
  360. // find the API in the list of supported APIs on this platform
  361. AZStd::vector<RHI::ShaderPlatformInterface*>::const_iterator itFoundAPI = AZStd::find_if(
  362. platformInterfaces.begin(),
  363. platformInterfaces.end(),
  364. [&perAPIShaderData](const RHI::ShaderPlatformInterface* shaderPlatformInterface)
  365. {
  366. return perAPIShaderData.m_APIType == shaderPlatformInterface->GetAPIType();
  367. });
  368. if (itFoundAPI == platformInterfaces.end())
  369. {
  370. // the API is not supported on this platform, skip this entry
  371. continue;
  372. }
  373. if (perAPIShaderData.m_supervariants.empty())
  374. {
  375. ReportWarning("Attempting to clone a shader asset that has no supervariants for API [%d]", perAPIShaderData.m_APIType);
  376. continue;
  377. }
  378. if (perAPIShaderData.m_supervariants.size() != supervariants.size())
  379. {
  380. ReportError("Incorrect number of supervariants provided to ShaderAssetCreator::Clone");
  381. return;
  382. }
  383. m_asset->m_perAPIShaderData.push_back(perAPIShaderData);
  384. // set the supervariants for this API
  385. for (auto& supervariant : m_asset->m_perAPIShaderData.back().m_supervariants)
  386. {
  387. // find the matching Supervariant by name from the incoming list
  388. ShaderSupervariants::const_iterator itFoundSuperVariant = AZStd::find_if(
  389. supervariants.begin(),
  390. supervariants.end(),
  391. [&supervariant](const ShaderSupervariant& shaderSupervariant)
  392. {
  393. return supervariant.m_name == shaderSupervariant.m_name;
  394. });
  395. if (itFoundSuperVariant == supervariants.end())
  396. {
  397. ReportError("Failed to find supervariant [%s]", supervariant.m_name.GetCStr());
  398. return;
  399. }
  400. // find the matching ShaderVariantAsset for this API
  401. ShaderRootVariantAssets::const_iterator itFoundRootShaderVariantAsset = AZStd::find_if(
  402. itFoundSuperVariant->m_rootVariantAssets.begin(),
  403. itFoundSuperVariant->m_rootVariantAssets.end(),
  404. [&perAPIShaderData](const ShaderRootVariantAssetPair& rootShaderVariantAsset)
  405. {
  406. return perAPIShaderData.m_APIType == rootShaderVariantAsset.first;
  407. });
  408. if (itFoundRootShaderVariantAsset == itFoundSuperVariant->m_rootVariantAssets.end())
  409. {
  410. ReportWarning("Failed to find root shader variant asset for API [%d] Supervariant [%s]", perAPIShaderData.m_APIType, supervariant.m_name.GetCStr());
  411. }
  412. else
  413. {
  414. supervariant.m_rootShaderVariantAsset = itFoundRootShaderVariantAsset->second;
  415. }
  416. }
  417. }
  418. }
  419. } // namespace RPI
  420. } // namespace AZ