ShaderCollection.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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 <AtomCore/std/containers/vector_set.h>
  9. #include <AzCore/Asset/AssetSerializer.h>
  10. #include <Atom/RPI.Reflect/Material/ShaderCollection.h>
  11. #include <Atom/RHI/RHISystemInterface.h>
  12. #include <Atom/RHI/DrawListTagRegistry.h>
  13. namespace AZ
  14. {
  15. namespace RPI
  16. {
  17. //! This allows ShaderCollection::Item to serialize only a ShaderVariantId rather than the ShaderOptionsGroup object,
  18. //! but still provide the corresponding ShaderOptionsGroup for use at runtime.
  19. //! RenderStates will be modified at runtime as well. It will be merged into the RenderStates stored in the corresponding ShaderVariant.
  20. class ShaderVariantReferenceSerializationEvents
  21. : public SerializeContext::IEventHandler
  22. {
  23. //! Called right before we start reading from the instance pointed by classPtr.
  24. void OnReadBegin(void* classPtr) override
  25. {
  26. ShaderCollection::Item* shaderVariantReference = reinterpret_cast<ShaderCollection::Item*>(classPtr);
  27. shaderVariantReference->m_shaderVariantId = shaderVariantReference->m_shaderOptionGroup.GetShaderVariantId();
  28. }
  29. //! Called right after we finish writing data to the instance pointed at by classPtr.
  30. void OnWriteEnd(void* classPtr) override
  31. {
  32. ShaderCollection::Item* shaderVariantReference = reinterpret_cast<ShaderCollection::Item*>(classPtr);
  33. if (shaderVariantReference->m_shaderAsset.IsReady())
  34. {
  35. shaderVariantReference->m_shaderOptionGroup = ShaderOptionGroup{
  36. shaderVariantReference->m_shaderAsset->GetShaderOptionGroupLayout(),
  37. shaderVariantReference->m_shaderVariantId
  38. };
  39. }
  40. else
  41. {
  42. // No worries, eventually the Material::Init will end up
  43. // calling InitializeShaderOptionGroup() and @m_shaderOptionGroup
  44. // will get proper data.
  45. shaderVariantReference->m_shaderOptionGroup = {};
  46. shaderVariantReference->m_shaderAsset.QueueLoad(); // Not necessary to call QueueLoad, but doesn't hurt either.
  47. }
  48. }
  49. };
  50. void ShaderCollection::Reflect(AZ::ReflectContext* context)
  51. {
  52. ShaderCollection::Item::Reflect(context);
  53. NameReflectionMapForIndex::Reflect(context);
  54. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  55. {
  56. serializeContext->Class<ShaderCollection>()
  57. ->Version(5)
  58. ->Field("ShaderItems", &ShaderCollection::m_shaderItems)
  59. ->Field("ShaderTagIndexMap", &ShaderCollection::m_shaderTagIndexMap)
  60. ;
  61. }
  62. }
  63. void ShaderCollection::Item::Reflect(AZ::ReflectContext* context)
  64. {
  65. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  66. {
  67. serializeContext->Class<ShaderCollection::Item>()
  68. ->Version(6)
  69. ->EventHandler<ShaderVariantReferenceSerializationEvents>()
  70. ->Field("ShaderAsset", &ShaderCollection::Item::m_shaderAsset)
  71. ->Field("ShaderVariantId", &ShaderCollection::Item::m_shaderVariantId)
  72. ->Field("Enabled", &ShaderCollection::Item::m_enabled)
  73. ->Field("OwnedShaderOptionIndices", &ShaderCollection::Item::m_ownedShaderOptionIndices)
  74. ->Field("ShaderTag", &ShaderCollection::Item::m_shaderTag)
  75. ;
  76. }
  77. if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
  78. {
  79. behaviorContext->Class<Item>("ShaderCollectionItem")
  80. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  81. ->Attribute(AZ::Script::Attributes::Category, "Shader")
  82. ->Attribute(AZ::Script::Attributes::Module, "shader")
  83. ->Method("GetShaderAsset", &Item::GetShaderAsset)
  84. ->Method("GetShaderAssetId", &Item::GetShaderAssetId)
  85. ->Method("GetShaderVariantId", &Item::GetShaderVariantId)
  86. ->Method("GetShaderOptionGroup", &Item::GetShaderOptionGroup)
  87. ->Method("MaterialOwnsShaderOption", static_cast<bool (Item::*)(const Name&) const>(&Item::MaterialOwnsShaderOption));
  88. }
  89. }
  90. size_t ShaderCollection::size() const
  91. {
  92. return m_shaderItems.size();
  93. }
  94. ShaderCollection::iterator ShaderCollection::begin()
  95. {
  96. return m_shaderItems.begin();
  97. }
  98. ShaderCollection::const_iterator ShaderCollection::begin() const
  99. {
  100. return m_shaderItems.begin();
  101. }
  102. ShaderCollection::iterator ShaderCollection::end()
  103. {
  104. return m_shaderItems.end();
  105. }
  106. ShaderCollection::const_iterator ShaderCollection::end() const
  107. {
  108. return m_shaderItems.end();
  109. }
  110. ShaderCollection::Item::Item()
  111. : m_renderStatesOverlay(RHI::GetInvalidRenderStates())
  112. {
  113. }
  114. ShaderCollection::Item& ShaderCollection::operator[](size_t i)
  115. {
  116. return m_shaderItems[i];
  117. }
  118. const ShaderCollection::Item& ShaderCollection::operator[](size_t i) const
  119. {
  120. return m_shaderItems[i];
  121. }
  122. ShaderCollection::Item& ShaderCollection::operator[](const AZ::Name& shaderTag)
  123. {
  124. return m_shaderItems[m_shaderTagIndexMap.Find(shaderTag).GetIndex()];
  125. }
  126. const ShaderCollection::Item& ShaderCollection::operator[](const AZ::Name& shaderTag) const
  127. {
  128. return m_shaderItems[m_shaderTagIndexMap.Find(shaderTag).GetIndex()];
  129. }
  130. bool ShaderCollection::HasShaderTag(const AZ::Name& shaderTag) const
  131. {
  132. return (m_shaderTagIndexMap.Find(shaderTag).IsValid());
  133. }
  134. void ShaderCollection::TryReplaceShaderAsset(const Data::Asset<ShaderAsset>& newShaderAsset)
  135. {
  136. for (auto& shaderItem : m_shaderItems)
  137. {
  138. shaderItem.TryReplaceShaderAsset(newShaderAsset);
  139. }
  140. }
  141. bool ShaderCollection::InitializeShaderOptionGroups()
  142. {
  143. for (auto& shaderItem : m_shaderItems)
  144. {
  145. if (!shaderItem.InitializeShaderOptionGroup())
  146. {
  147. return false;
  148. }
  149. }
  150. return true;
  151. }
  152. ShaderCollection::Item::Item(const Data::Asset<ShaderAsset>& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId)
  153. : m_renderStatesOverlay(RHI::GetInvalidRenderStates())
  154. , m_shaderAsset(shaderAsset)
  155. , m_shaderVariantId(variantId)
  156. , m_shaderTag(shaderTag)
  157. , m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId)
  158. {
  159. }
  160. ShaderCollection::Item::Item(Data::Asset<ShaderAsset>&& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId)
  161. : m_renderStatesOverlay(RHI::GetInvalidRenderStates())
  162. , m_shaderAsset(AZStd::move(shaderAsset))
  163. , m_shaderVariantId(variantId)
  164. , m_shaderTag(shaderTag)
  165. , m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId)
  166. {
  167. }
  168. const Data::Asset<ShaderAsset>& ShaderCollection::Item::GetShaderAsset() const
  169. {
  170. return m_shaderAsset;
  171. }
  172. const ShaderVariantId& ShaderCollection::Item::GetShaderVariantId() const
  173. {
  174. return m_shaderOptionGroup.GetShaderVariantId();
  175. }
  176. const ShaderOptionGroup* ShaderCollection::Item::GetShaderOptions() const
  177. {
  178. return &m_shaderOptionGroup;
  179. }
  180. ShaderOptionGroup* ShaderCollection::Item::GetShaderOptions()
  181. {
  182. return &m_shaderOptionGroup;
  183. }
  184. bool ShaderCollection::Item::MaterialOwnsShaderOption(const AZ::Name& shaderOptionName) const
  185. {
  186. return m_ownedShaderOptionIndices.contains(m_shaderOptionGroup.FindShaderOptionIndex(shaderOptionName));
  187. }
  188. bool ShaderCollection::Item::MaterialOwnsShaderOption(ShaderOptionIndex shaderOptionIndex) const
  189. {
  190. return m_ownedShaderOptionIndices.contains(shaderOptionIndex);
  191. }
  192. const RHI::RenderStates* ShaderCollection::Item::GetRenderStatesOverlay() const
  193. {
  194. return &m_renderStatesOverlay;
  195. }
  196. RHI::RenderStates* ShaderCollection::Item::GetRenderStatesOverlay()
  197. {
  198. return &m_renderStatesOverlay;
  199. }
  200. RHI::DrawListTag ShaderCollection::Item::GetDrawListTagOverride() const
  201. {
  202. return m_drawListTagOverride;
  203. }
  204. void ShaderCollection::Item::SetDrawListTagOverride(RHI::DrawListTag drawList)
  205. {
  206. m_drawListTagOverride = drawList;
  207. }
  208. void ShaderCollection::Item::SetDrawListTagOverride(const AZ::Name& drawListName)
  209. {
  210. if (drawListName.IsEmpty())
  211. {
  212. m_drawListTagOverride.Reset();
  213. return;
  214. }
  215. RHI::DrawListTagRegistry* drawListTagRegistry = RHI::RHISystemInterface::Get()->GetDrawListTagRegistry();
  216. // Note: we should use FindTag instead of AcquireTag to avoid occupy DrawListTag entries.
  217. RHI::DrawListTag newTag = drawListTagRegistry->FindTag(drawListName);
  218. if (newTag.IsNull())
  219. {
  220. AZ_Error("ShaderCollection", false, "Failed to set draw list with name: %s.", drawListName.GetCStr());
  221. return;
  222. }
  223. m_drawListTagOverride = newTag;
  224. }
  225. void ShaderCollection::Item::SetEnabled(bool enabled)
  226. {
  227. m_enabled = enabled;
  228. }
  229. bool ShaderCollection::Item::IsEnabled() const
  230. {
  231. return m_enabled;
  232. }
  233. const AZ::Name& ShaderCollection::Item::GetShaderTag() const
  234. {
  235. return m_shaderTag;
  236. }
  237. const Data::AssetId& ShaderCollection::Item::GetShaderAssetId() const
  238. {
  239. return m_shaderAsset->GetId();
  240. }
  241. const AZ::RPI::ShaderOptionGroup& ShaderCollection::Item::GetShaderOptionGroup() const
  242. {
  243. return m_shaderOptionGroup;
  244. }
  245. bool ShaderCollection::Item::InitializeShaderOptionGroup()
  246. {
  247. if (!m_shaderAsset.IsReady())
  248. {
  249. return false;
  250. }
  251. m_shaderOptionGroup = ShaderOptionGroup{
  252. m_shaderAsset->GetShaderOptionGroupLayout(),
  253. m_shaderVariantId };
  254. return true;
  255. }
  256. void ShaderCollection::Item::TryReplaceShaderAsset(const Data::Asset<ShaderAsset>& newShaderAsset)
  257. {
  258. if (newShaderAsset.GetId() != m_shaderAsset.GetId())
  259. {
  260. return;
  261. }
  262. m_shaderAsset = newShaderAsset;
  263. [[maybe_unused]] bool success = InitializeShaderOptionGroup();
  264. AZ_Assert(success, "Failed to InitializeShaderOptionGroup using shaderAsset with uuid=%s and hint=%s"
  265. , newShaderAsset.GetId().ToFixedString().c_str(), newShaderAsset.GetHint().c_str());
  266. }
  267. } // namespace RPI
  268. } // namespace AZ