ShaderOptionGroup.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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/ShaderOptionGroup.h>
  9. #include <AzCore/Serialization/SerializeContext.h>
  10. namespace AZ
  11. {
  12. namespace RPI
  13. {
  14. const char* ShaderOptionGroup::DebugCategory = "ShaderOption";
  15. ShaderOptionGroup::ShaderOptionGroup(const ShaderOptionGroup& rhs)
  16. : m_layout(rhs.m_layout)
  17. , m_id{rhs.m_id}
  18. {
  19. }
  20. ShaderOptionGroup::ShaderOptionGroup(const ConstPtr<ShaderOptionGroupLayout>& shaderOptionGroupLayout)
  21. : m_layout{shaderOptionGroupLayout}
  22. {
  23. AZ_Assert(m_layout, "ShaderOptionGroup created with null layout!");
  24. Clear();
  25. }
  26. ShaderOptionGroup::ShaderOptionGroup(const ConstPtr<ShaderOptionGroupLayout>& shaderOptionGroupLayout, const ShaderVariantId& id)
  27. : m_layout{shaderOptionGroupLayout}
  28. , m_id{id}
  29. {
  30. AZ_Assert(m_layout, "ShaderOptionGroup created with null layout!");
  31. }
  32. void ShaderOptionGroup::Reflect(AZ::ReflectContext* context)
  33. {
  34. if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
  35. {
  36. behaviorContext->Class<ShaderOptionGroup>()
  37. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  38. ->Attribute(AZ::Script::Attributes::Category, "Shader")
  39. ->Attribute(AZ::Script::Attributes::Module, "shader")
  40. ->Method("GetValueByOptionName", static_cast<ShaderOptionValue (ShaderOptionGroup::*)(const Name&) const>(&ShaderOptionGroup::GetValue))
  41. ->Method("GetShaderOptionDescriptors", &ShaderOptionGroup::GetShaderOptionDescriptors)
  42. ->Method("GetShaderVariantId", &ShaderOptionGroup::GetShaderVariantId)
  43. ;
  44. }
  45. }
  46. void ShaderOptionGroup::Clear()
  47. {
  48. m_id.Reset();
  49. }
  50. ShaderOptionIndex ShaderOptionGroup::FindShaderOptionIndex(const Name& optionName) const
  51. {
  52. return m_layout->FindShaderOptionIndex(optionName);
  53. }
  54. bool ShaderOptionGroup::GetShaderOptionIndex(const Name& optionName, ShaderOptionIndex& optionIndex) const
  55. {
  56. optionIndex = FindShaderOptionIndex(optionName);
  57. if (!optionIndex.IsValid())
  58. {
  59. AZ_Error(DebugCategory, false, "ShaderOption '%s' does not exist", optionName.GetCStr());
  60. return false;
  61. }
  62. return true;
  63. }
  64. bool ShaderOptionGroup::ValidateIndex(const ShaderOptionIndex& optionIndex) const
  65. {
  66. if (!optionIndex.IsValid())
  67. {
  68. AZ_Error(DebugCategory, false, "Invalid ShaderOptionIndex");
  69. return false;
  70. }
  71. return true;
  72. }
  73. bool ShaderOptionGroup::SetValue(const Name& optionName, const Name& valueName)
  74. {
  75. ShaderOptionIndex index;
  76. if (GetShaderOptionIndex(optionName, index))
  77. {
  78. return SetValue(index, valueName);
  79. }
  80. else
  81. {
  82. return false;
  83. }
  84. }
  85. bool ShaderOptionGroup::SetValue(const Name& optionName, ShaderOptionValue valueIndex)
  86. {
  87. ShaderOptionIndex index;
  88. if (GetShaderOptionIndex(optionName, index))
  89. {
  90. return SetValue(index, valueIndex);
  91. }
  92. else
  93. {
  94. return false;
  95. }
  96. }
  97. ShaderOptionValue ShaderOptionGroup::GetValue(const Name& optionName) const
  98. {
  99. ShaderOptionIndex index;
  100. if (GetShaderOptionIndex(optionName, index))
  101. {
  102. return GetValue(index);
  103. }
  104. else
  105. {
  106. return ShaderOptionValue{};
  107. }
  108. }
  109. bool ShaderOptionGroup::SetValue(ShaderOptionIndex optionIndex, const Name& valueName)
  110. {
  111. if (ValidateIndex(optionIndex))
  112. {
  113. const ShaderOptionDescriptor& option = m_layout->GetShaderOption(optionIndex);
  114. if (!option.Set(*this, valueName))
  115. {
  116. return false;
  117. }
  118. return true;
  119. }
  120. else
  121. {
  122. return false;
  123. }
  124. }
  125. bool ShaderOptionGroup::SetValue(ShaderOptionIndex optionIndex, ShaderOptionValue valueIndex)
  126. {
  127. if (ValidateIndex(optionIndex))
  128. {
  129. const ShaderOptionDescriptor& option = m_layout->GetShaderOption(optionIndex);
  130. if (!option.Set(*this, valueIndex))
  131. {
  132. return false;
  133. }
  134. return true;
  135. }
  136. else
  137. {
  138. return false;
  139. }
  140. }
  141. ShaderOptionValue ShaderOptionGroup::GetValue(ShaderOptionIndex optionIndex) const
  142. {
  143. if (ValidateIndex(optionIndex))
  144. {
  145. const ShaderOptionDescriptor& option = m_layout->GetShaderOption(optionIndex);
  146. return option.Get(*this);
  147. }
  148. else
  149. {
  150. return ShaderOptionValue{};
  151. }
  152. }
  153. bool ShaderOptionGroup::ClearValue(const Name& optionName)
  154. {
  155. ShaderOptionIndex index;
  156. if (GetShaderOptionIndex(optionName, index))
  157. {
  158. return ClearValue(index);
  159. }
  160. else
  161. {
  162. return false;
  163. }
  164. }
  165. bool ShaderOptionGroup::ClearValue(ShaderOptionIndex optionIndex)
  166. {
  167. if (ValidateIndex(optionIndex))
  168. {
  169. const ShaderOptionDescriptor& option = m_layout->GetShaderOption(optionIndex);
  170. option.Clear(*this);
  171. return true;
  172. }
  173. return false;
  174. }
  175. void ShaderOptionGroup::SetAllToDefaultValues()
  176. {
  177. for (auto& option : m_layout->GetShaderOptions())
  178. {
  179. option.Set(*this, option.GetDefaultValue());
  180. }
  181. }
  182. void ShaderOptionGroup::SetUnspecifiedToDefaultValues()
  183. {
  184. for (auto& option : m_layout->GetShaderOptions())
  185. {
  186. if (!(m_id.m_mask & option.GetBitMask()).any())
  187. {
  188. option.Set(*this, option.GetDefaultValue());
  189. }
  190. }
  191. }
  192. bool ShaderOptionGroup::IsFullySpecified() const
  193. {
  194. for (auto& option : m_layout->GetShaderOptions())
  195. {
  196. if (!(m_id.m_mask & option.GetBitMask()).any())
  197. {
  198. return false;
  199. }
  200. }
  201. return true;
  202. }
  203. bool ShaderOptionGroup::IsEmpty() const
  204. {
  205. return m_id.IsEmpty();
  206. }
  207. ShaderVariantKey ShaderOptionGroup::GetShaderVariantKeyFallbackValue() const
  208. {
  209. // By default the fallback value is the search key
  210. auto fallbackValueKey = m_id.m_key;
  211. // However, we have to make sure that all options are set, opting for default values where missing
  212. for (auto& option : m_layout->GetShaderOptions())
  213. {
  214. if (!(m_id.m_mask & option.GetBitMask()).any())
  215. {
  216. const auto value = option.FindValue(option.GetDefaultValue());
  217. // This is an assert, not error, because the build system should have detected this situation earlier.
  218. AZ_Assert(value.IsValid(), "Default value for shader option '%s' is invalid.", option.GetName().GetCStr());
  219. option.Set(fallbackValueKey, value);
  220. }
  221. }
  222. return fallbackValueKey;
  223. }
  224. const ShaderVariantKey& ShaderOptionGroup::GetShaderVariantKey() const
  225. {
  226. return m_id.m_key;
  227. }
  228. const ShaderVariantKey& ShaderOptionGroup::GetShaderVariantMask() const
  229. {
  230. return m_id.m_mask;
  231. }
  232. const ShaderVariantId& ShaderOptionGroup::GetShaderVariantId() const
  233. {
  234. return m_id;
  235. }
  236. ShaderVariantKey& ShaderOptionGroup::GetShaderVariantKey()
  237. {
  238. return m_id.m_key;
  239. }
  240. ShaderVariantKey& ShaderOptionGroup::GetShaderVariantMask()
  241. {
  242. return m_id.m_mask;
  243. }
  244. const ShaderOptionGroupLayout* ShaderOptionGroup::GetShaderOptionLayout() const
  245. {
  246. return m_layout.get();
  247. }
  248. AZStd::string ShaderOptionGroup::ToString() const
  249. {
  250. AZStd::string s;
  251. for (int i = 0; i < GetShaderOptionLayout()->GetShaderOptionCount(); ++i)
  252. {
  253. ShaderOptionIndex index{i};
  254. const ShaderOptionDescriptor& option = GetShaderOptionLayout()->GetShaderOption(index);
  255. const ShaderOptionValue& value = GetValue(index);
  256. if (value.IsNull())
  257. {
  258. s += AZStd::string::format("%s=?, ", option.GetName().GetCStr());
  259. }
  260. else
  261. {
  262. //[GFX TODO][ATOM-3481] Report the names of enum options instead of numeric values. This depends on storing Names in NameIdReflectionMap.
  263. s += AZStd::string::format("%s=%d, ", option.GetName().GetCStr(), value.GetIndex());
  264. }
  265. }
  266. // Remove the trailing ", " from the last shader option in the string
  267. static const size_t separateLength = 2;
  268. if (s.size() >= separateLength)
  269. {
  270. s.resize(s.size() - separateLength);
  271. }
  272. return s;
  273. }
  274. const AZStd::vector<AZ::RPI::ShaderOptionDescriptor>& ShaderOptionGroup::GetShaderOptionDescriptors() const
  275. {
  276. return m_layout->GetShaderOptions();
  277. }
  278. } // namespace RPI
  279. } // namespace AZ