ShaderOptionGroupLayout.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  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/ShaderOptionGroupLayout.h>
  9. #include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
  10. #include <Atom/RHI.Reflect/Bits.h>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <AzCore/std/string/conversions.h>
  13. #include <AzCore/std/sort.h>
  14. #include <AzCore/Utils/TypeHash.h>
  15. #include <AzFramework/StringFunc/StringFunc.h>
  16. namespace AZ
  17. {
  18. namespace RPI
  19. {
  20. const char* ShaderOptionDescriptor::DebugCategory = "ShaderOption";
  21. const char* ShaderOptionGroupLayout::DebugCategory = "ShaderOption";
  22. const char* ToString(ShaderOptionType shaderOptionType)
  23. {
  24. switch (shaderOptionType)
  25. {
  26. case ShaderOptionType::Boolean: return "Boolean";
  27. case ShaderOptionType::Enumeration: return "Enumeration";
  28. case ShaderOptionType::IntegerRange: return "IntegerRange";
  29. default: return "<Unknown>";
  30. }
  31. }
  32. ShaderOptionValues CreateEnumShaderOptionValues(AZStd::span<const AZStd::string_view> enumNames)
  33. {
  34. ShaderOptionValues values;
  35. values.reserve(enumNames.size());
  36. for (size_t i = 0; i < enumNames.size(); ++i)
  37. {
  38. values.emplace_back(Name{enumNames[i]}, i);
  39. }
  40. return values;
  41. }
  42. ShaderOptionValues CreateEnumShaderOptionValues(AZStd::initializer_list<AZStd::string_view> enumNames)
  43. {
  44. return CreateEnumShaderOptionValues(AZStd::span(enumNames.begin(), enumNames.end()));
  45. }
  46. ShaderOptionValues CreateBoolShaderOptionValues()
  47. {
  48. return CreateEnumShaderOptionValues({"False", "True"});
  49. }
  50. ShaderOptionValues CreateIntRangeShaderOptionValues(uint32_t min, uint32_t max)
  51. {
  52. AZStd::vector<RPI::ShaderOptionValuePair> intOptionRange;
  53. intOptionRange.push_back({Name{AZStd::string::format("%u", min)}, RPI::ShaderOptionValue{min}});
  54. intOptionRange.push_back({Name{AZStd::string::format("%u", max)}, RPI::ShaderOptionValue{max}});
  55. return intOptionRange;
  56. }
  57. void ShaderOptionGroupHints::Reflect(ReflectContext* context)
  58. {
  59. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  60. {
  61. serializeContext->Class<ShaderOptionGroupHints>()
  62. ->Version(4)
  63. ->Field("BakePrecedingVariants", &ShaderOptionGroupHints::m_bakePrecedingVariants)
  64. ->Field("BakeEmptyAsDefault", &ShaderOptionGroupHints::m_bakeEmptyAsDefault)
  65. ;
  66. }
  67. }
  68. void ShaderOptionDescriptor::Reflect(AZ::ReflectContext* context)
  69. {
  70. ShaderOptionValue::Reflect(context);
  71. NameReflectionMapForValues::Reflect(context);
  72. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  73. {
  74. serializeContext->Class<ShaderOptionDescriptor>()
  75. ->Version(4)
  76. ->Field("m_name", &ShaderOptionDescriptor::m_name)
  77. ->Field("m_type", &ShaderOptionDescriptor::m_type)
  78. ->Field("m_defaultValue", &ShaderOptionDescriptor::m_defaultValue)
  79. ->Field("m_minValue", &ShaderOptionDescriptor::m_minValue)
  80. ->Field("m_maxValue", &ShaderOptionDescriptor::m_maxValue)
  81. ->Field("m_bitOffset", &ShaderOptionDescriptor::m_bitOffset)
  82. ->Field("m_bitCount", &ShaderOptionDescriptor::m_bitCount)
  83. ->Field("m_bitMask", &ShaderOptionDescriptor::m_bitMask)
  84. ->Field("m_bitMaskNot", &ShaderOptionDescriptor::m_bitMaskNot)
  85. ->Field("m_hash", &ShaderOptionDescriptor::m_hash)
  86. ->Field("m_nameReflectionForValues", &ShaderOptionDescriptor::m_nameReflectionForValues)
  87. ;
  88. }
  89. if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
  90. {
  91. behaviorContext->Class<ShaderOptionDescriptor>()
  92. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  93. ->Attribute(AZ::Script::Attributes::Category, "Shader")
  94. ->Attribute(AZ::Script::Attributes::Module, "shader")
  95. ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::RuntimeOwn)
  96. ->Method("GetName", &ShaderOptionDescriptor::GetName)
  97. ->Method("GetDefaultValue", &ShaderOptionDescriptor::GetDefaultValue)
  98. ->Method("GetValueName", &ShaderOptionDescriptor::GetValueName)
  99. ->Method("FindValue", &ShaderOptionDescriptor::FindValue)
  100. ;
  101. }
  102. }
  103. ShaderOptionDescriptor::ShaderOptionDescriptor(const Name& name,
  104. const ShaderOptionType& optionType,
  105. uint32_t bitOffset,
  106. uint32_t order,
  107. const ShaderOptionValues& nameIndexList,
  108. const Name& defaultValue)
  109. : m_name{name}
  110. , m_type{optionType}
  111. , m_bitOffset{bitOffset}
  112. , m_order{order}
  113. , m_defaultValue{defaultValue}
  114. {
  115. for (auto pair : nameIndexList)
  116. { // Registers the pair in the lookup table
  117. AddValue(pair.first, pair.second);
  118. if (m_defaultValue.IsEmpty())
  119. {
  120. m_defaultValue = pair.first;
  121. }
  122. }
  123. uint32_t numValues = (m_type == ShaderOptionType::IntegerRange) ? (m_maxValue.GetIndex() - m_minValue.GetIndex() + 1) : (uint32_t) nameIndexList.size();
  124. numValues = RHI::NextPowerOfTwo(numValues) - 1;
  125. m_bitCount = RHI::CountBitsSet(numValues);
  126. ShaderVariantKey bitMask;
  127. bitMask = AZ_BIT_MASK(m_bitCount);
  128. bitMask <<= m_bitOffset;
  129. m_bitMask = bitMask;
  130. m_bitMaskNot = ~bitMask;
  131. m_hash = TypeHash64(m_bitMask, static_cast<HashValue64>(m_name.GetHash()));
  132. }
  133. const Name& ShaderOptionDescriptor::GetName() const
  134. {
  135. return m_name;
  136. }
  137. uint32_t ShaderOptionDescriptor::GetBitOffset() const
  138. {
  139. return m_bitOffset;
  140. }
  141. uint32_t ShaderOptionDescriptor::GetBitCount() const
  142. {
  143. return m_bitCount;
  144. }
  145. uint32_t ShaderOptionDescriptor::GetOrder() const
  146. {
  147. return m_order;
  148. }
  149. ShaderVariantKey ShaderOptionDescriptor::GetBitMask() const
  150. {
  151. return m_bitMask;
  152. }
  153. ShaderVariantKey ShaderOptionDescriptor::GetBitMaskNot() const
  154. {
  155. return m_bitMaskNot;
  156. }
  157. HashValue64 ShaderOptionDescriptor::GetHash() const
  158. {
  159. return m_hash;
  160. }
  161. bool ShaderOptionDescriptor::Set(ShaderOptionGroup& group, const Name& valueName) const
  162. {
  163. auto valueIndex = FindValue(valueName);
  164. if (valueIndex.IsValid())
  165. {
  166. return Set(group, valueIndex);
  167. }
  168. else
  169. {
  170. AZ_Error(DebugCategory, false, "ShaderOption value '%s' does not exist", valueName.GetCStr());
  171. return false;
  172. }
  173. }
  174. bool ShaderOptionDescriptor::Set(ShaderOptionGroup& group, const ShaderOptionValue valueIndex) const
  175. {
  176. if (valueIndex.IsNull())
  177. {
  178. AZ_Error(DebugCategory, false, "Invalid ShaderOption value");
  179. return false;
  180. }
  181. if (m_type == ShaderOptionType::Unknown)
  182. {
  183. group.GetShaderVariantMask() &= m_bitMaskNot;
  184. }
  185. else
  186. {
  187. if (!(m_minValue.GetIndex() <= valueIndex.GetIndex() && valueIndex.GetIndex() <= m_maxValue.GetIndex()))
  188. {
  189. AZ_Error(DebugCategory, false, "%s ShaderOption value [%d] is out of range [%d,%d].",
  190. ToString(m_type), valueIndex.GetIndex(), m_minValue.GetIndex(), m_maxValue.GetIndex());
  191. return false;
  192. }
  193. EncodeBits(group.GetShaderVariantKey(), valueIndex.GetIndex() - m_minValue.GetIndex());
  194. group.GetShaderVariantMask() |= m_bitMask;
  195. }
  196. return true;
  197. }
  198. bool ShaderOptionDescriptor::Set(ShaderVariantKey& key, const ShaderOptionValue valueIndex) const
  199. {
  200. if (valueIndex.IsNull())
  201. {
  202. AZ_Error(DebugCategory, false, "Invalid ShaderOption value");
  203. return false;
  204. }
  205. if (m_type != ShaderOptionType::Unknown)
  206. {
  207. if (!(m_minValue.GetIndex() <= valueIndex.GetIndex() && valueIndex.GetIndex() <= m_maxValue.GetIndex()))
  208. {
  209. AZ_Error(DebugCategory, false, "%s ShaderOption value [%d] is out of range [%d,%d].",
  210. ToString(m_type), valueIndex.GetIndex(), m_minValue.GetIndex(), m_maxValue.GetIndex());
  211. return false;
  212. }
  213. EncodeBits(key, valueIndex.GetIndex() - m_minValue.GetIndex());
  214. }
  215. return true;
  216. }
  217. ShaderOptionValue ShaderOptionDescriptor::Get(const ShaderOptionGroup& group) const
  218. {
  219. if (group.GetShaderVariantMask().test(m_bitOffset))
  220. {
  221. return ShaderOptionValue(DecodeBits(group.GetShaderVariantKey()) + m_minValue.GetIndex());
  222. }
  223. return ShaderOptionValue();
  224. }
  225. void ShaderOptionDescriptor::Clear(ShaderOptionGroup& group) const
  226. {
  227. group.GetShaderVariantMask() &= m_bitMaskNot;
  228. }
  229. void ShaderOptionDescriptor::AddValue(const Name& valueName, const ShaderOptionValue valueIndex)
  230. {
  231. AZ_Assert(m_type != ShaderOptionType::IntegerRange || valueIndex.GetIndex() == ShaderOptionValue((uint32_t)AZStd::stoll(AZStd::string{valueName.GetCStr()})).GetIndex(), "By convention, IntegerRange's values' ids must be equal to their numerical value!");
  232. m_nameReflectionForValues.Insert(valueName, valueIndex);
  233. if (m_minValue.IsNull() || m_minValue.GetIndex() > valueIndex.GetIndex())
  234. {
  235. m_minValue = valueIndex;
  236. }
  237. if (m_maxValue.IsNull() || m_maxValue.GetIndex() < valueIndex.GetIndex())
  238. {
  239. m_maxValue = valueIndex;
  240. }
  241. }
  242. void ShaderOptionDescriptor::SetDefaultValue(const Name& valueName)
  243. {
  244. AZ_Assert(!valueName.IsEmpty(), "The default value cannot be empty!");
  245. auto valueIter = m_nameReflectionForValues.Find(valueName);
  246. if (valueIter.IsNull())
  247. {
  248. AZ_Assert(false, "ShaderOption [%s] has no member value [%s] so this cannot be the default!", m_name.GetCStr(), valueName.GetCStr());
  249. return;
  250. }
  251. m_defaultValue = valueName;
  252. }
  253. const Name& ShaderOptionDescriptor::GetDefaultValue() const
  254. {
  255. return m_defaultValue;
  256. }
  257. uint32_t ShaderOptionDescriptor::GetValuesCount() const
  258. {
  259. return static_cast<uint32_t>(m_maxValue.GetIndex() - m_minValue.GetIndex() + 1);
  260. }
  261. /// Sets the hint type for the shader option
  262. void ShaderOptionDescriptor::SetType(ShaderOptionType optionType)
  263. {
  264. m_type = optionType;
  265. }
  266. /// Gets the hint type for the shader option
  267. const ShaderOptionType& ShaderOptionDescriptor::GetType() const
  268. {
  269. return m_type;
  270. }
  271. ShaderOptionValue ShaderOptionDescriptor::GetMinValue() const
  272. {
  273. return m_minValue;
  274. }
  275. ShaderOptionValue ShaderOptionDescriptor::GetMaxValue() const
  276. {
  277. return m_maxValue;
  278. }
  279. ShaderOptionValue ShaderOptionDescriptor::FindValue(const Name& valueName) const
  280. {
  281. switch (m_type)
  282. {
  283. case ShaderOptionType::Boolean:
  284. // This is better than hardcoding True, or On, or Enabled:
  285. return m_nameReflectionForValues.Find(valueName);
  286. case ShaderOptionType::Enumeration:
  287. return m_nameReflectionForValues.Find(valueName);
  288. case ShaderOptionType::IntegerRange:
  289. {
  290. int asInt;
  291. if (AzFramework::StringFunc::LooksLikeInt(valueName.GetCStr(), &asInt))
  292. {
  293. if (aznumeric_cast<int64_t>(m_minValue.GetIndex()) <= asInt && asInt <= aznumeric_cast<int64_t>(m_maxValue.GetIndex()))
  294. {
  295. return ShaderOptionValue(asInt);
  296. }
  297. }
  298. }
  299. return ShaderOptionValue();
  300. default:
  301. AZ_Assert(false, "Unhandled case for ShaderOptionType! We should not break here!");
  302. }
  303. // Unreachable code
  304. return ShaderOptionValue();
  305. }
  306. Name ShaderOptionDescriptor::GetValueName(ShaderOptionValue value) const
  307. {
  308. auto name = m_nameReflectionForValues.Find(value);
  309. return name;
  310. }
  311. void ShaderOptionDescriptor::EncodeBits(ShaderVariantKey& shaderVariantKey, uint32_t value) const
  312. {
  313. if (value < AZ_BIT(m_bitCount))
  314. {
  315. ShaderVariantKey valueBits = (value & AZ_BIT_MASK(m_bitCount));
  316. valueBits <<= m_bitOffset;
  317. shaderVariantKey &= m_bitMaskNot;
  318. shaderVariantKey |= valueBits;
  319. }
  320. else
  321. {
  322. AZ_Assert(false, "Exceeded maximum number of bits allocated for option.");
  323. }
  324. }
  325. uint32_t ShaderOptionDescriptor::DecodeBits(ShaderVariantKey shaderVariantKey) const
  326. {
  327. shaderVariantKey >>= m_bitOffset;
  328. shaderVariantKey &= AZ_BIT_MASK(m_bitCount);
  329. uint32_t value = static_cast<uint32_t>(shaderVariantKey.to_ulong());
  330. return value;
  331. }
  332. bool ShaderOptionDescriptor::operator==(const ShaderOptionDescriptor& rhs) const
  333. {
  334. return m_hash == rhs.m_hash;
  335. }
  336. bool ShaderOptionDescriptor::operator!=(const ShaderOptionDescriptor& rhs) const
  337. {
  338. return m_hash != rhs.m_hash;
  339. }
  340. bool ShaderOptionDescriptor::CompareOrder(const ShaderOptionDescriptor& first, const ShaderOptionDescriptor& second)
  341. {
  342. return first.GetOrder() < second.GetOrder();
  343. }
  344. bool ShaderOptionDescriptor::SameOrder(const ShaderOptionDescriptor& first, const ShaderOptionDescriptor& second)
  345. {
  346. return first.GetOrder() == second.GetOrder();
  347. }
  348. void ShaderOptionGroupLayout::Reflect(AZ::ReflectContext* context)
  349. {
  350. ShaderOptionIndex::Reflect(context);
  351. NameReflectionMapForOptions::Reflect(context);
  352. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  353. {
  354. serializeContext->Class<ShaderOptionGroupLayout>()
  355. ->Version(2)
  356. ->Field("m_bitMask", &ShaderOptionGroupLayout::m_bitMask)
  357. ->Field("m_options", &ShaderOptionGroupLayout::m_options)
  358. ->Field("m_nameReflectionForOptions", &ShaderOptionGroupLayout::m_nameReflectionForOptions)
  359. ->Field("m_hash", &ShaderOptionGroupLayout::m_hash)
  360. ;
  361. }
  362. if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
  363. {
  364. behaviorContext->Class<ShaderOptionGroupLayout>()
  365. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  366. ->Attribute(AZ::Script::Attributes::Category, "Shader")
  367. ->Attribute(AZ::Script::Attributes::Module, "shader")
  368. ->Method("GetShaderOptions", &ShaderOptionGroupLayout::GetShaderOptions)
  369. ;
  370. }
  371. }
  372. Ptr<ShaderOptionGroupLayout> ShaderOptionGroupLayout::Create()
  373. {
  374. return aznew ShaderOptionGroupLayout;
  375. }
  376. bool ShaderOptionGroupLayout::IsFinalized() const
  377. {
  378. return m_hash != HashValue64{ 0 };
  379. }
  380. HashValue64 ShaderOptionGroupLayout::GetHash() const
  381. {
  382. return m_hash;
  383. }
  384. void ShaderOptionGroupLayout::Clear()
  385. {
  386. m_options.clear();
  387. m_nameReflectionForOptions.Clear();
  388. m_bitMask = {};
  389. m_hash = HashValue64{ 0 };
  390. }
  391. void ShaderOptionGroupLayout::Finalize()
  392. {
  393. AZStd::sort(m_options.begin(), m_options.end(), ShaderOptionDescriptor::CompareOrder);
  394. // Start with a hash of the size so that m_hash!=0 will mean the group is finalized, even if the options list is empty.
  395. HashValue64 hash = TypeHash64(m_options.size());
  396. for (const ShaderOptionDescriptor& option : m_options)
  397. {
  398. hash = TypeHash64(option.GetHash(), hash);
  399. }
  400. m_hash = hash;
  401. }
  402. bool ShaderOptionGroupLayout::ValidateIsFinalized() const
  403. {
  404. if (!IsFinalized())
  405. {
  406. AZ_Assert(false, "ShaderOptionGroupLayout is not finalized! This operation is only permitted on a finalized layout.");
  407. return false;
  408. }
  409. return true;
  410. }
  411. bool ShaderOptionGroupLayout::ValidateIsNotFinalized() const
  412. {
  413. if (IsFinalized())
  414. {
  415. AZ_Assert(false, "ShaderOptionGroupLayout is finalized! This operation is only permitted on a non-finalized layout.");
  416. return false;
  417. }
  418. return true;
  419. }
  420. bool ShaderOptionGroupLayout::AddShaderOption(const ShaderOptionDescriptor& option)
  421. {
  422. if (!ValidateIsNotFinalized())
  423. {
  424. return false;
  425. }
  426. const Name& optionName = option.GetName();
  427. const ShaderVariantKey bitMask = option.GetBitMask();
  428. if ((m_bitMask & bitMask).any())
  429. {
  430. AZ_Error(DebugCategory, false, "ShaderOptionBinding '%s': mask overlaps with previously added masks.", optionName.GetCStr());
  431. return false;
  432. }
  433. if (option.GetName().IsEmpty())
  434. {
  435. AZ_Error(DebugCategory, false, "ShaderOptionBinding added with empty name.");
  436. return false;
  437. }
  438. if (option.GetBitCount() == 0)
  439. {
  440. AZ_Error(DebugCategory, false, "ShaderOptionBinding '%s' has zero bits.", optionName.GetCStr());
  441. return false;
  442. }
  443. if (option.GetBitOffset() + option.GetBitCount() > bitMask.size())
  444. {
  445. AZ_Error(DebugCategory, false, "ShaderOptionBinding '%s' exceeds size of mask.", optionName.GetCStr());
  446. return false;
  447. }
  448. if (AZStd::any_of(m_options.begin(), m_options.end(),
  449. [&option](const ShaderOptionDescriptor& other) { return ShaderOptionDescriptor::SameOrder(option, other); }))
  450. {
  451. AZ_Error(DebugCategory, false, "ShaderOption '%s' has the same order (%d) as another shader option.", optionName.GetCStr(), option.GetOrder());
  452. return false;
  453. }
  454. if (!option.FindValue(option.GetDefaultValue()).IsValid())
  455. {
  456. AZ_Error(DebugCategory, false, "ShaderOption '%s' has invalid default value '%s'.", optionName.GetCStr(), option.GetDefaultValue().GetCStr());
  457. return false;
  458. }
  459. const ShaderOptionIndex optionIndex(m_options.size());
  460. if (!m_nameReflectionForOptions.Insert(optionName, optionIndex))
  461. {
  462. AZ_Error(DebugCategory, false, "ShaderOptionBinding '%s': name already exists.", optionName.GetCStr());
  463. return false;
  464. }
  465. m_bitMask |= bitMask;
  466. m_options.push_back(option);
  467. return true;
  468. }
  469. ShaderOptionIndex ShaderOptionGroupLayout::FindShaderOptionIndex(const Name& optionName) const
  470. {
  471. if (ValidateIsFinalized())
  472. {
  473. return m_nameReflectionForOptions.Find(optionName);
  474. }
  475. return {};
  476. }
  477. ShaderOptionValue ShaderOptionGroupLayout::FindValue(const Name& optionName, const Name& valueName) const
  478. {
  479. return FindValue(FindShaderOptionIndex(optionName), valueName);
  480. }
  481. ShaderOptionValue ShaderOptionGroupLayout::FindValue(const ShaderOptionIndex& optionIndex, const Name& valueName) const
  482. {
  483. if (optionIndex.IsValid() && optionIndex.GetIndex() < m_options.size())
  484. {
  485. return m_options[optionIndex.GetIndex()].FindValue(valueName);
  486. }
  487. else
  488. {
  489. return ShaderOptionValue{};
  490. }
  491. }
  492. uint32_t ShaderOptionGroupLayout::GetBitSize() const
  493. {
  494. if (m_options.empty())
  495. {
  496. return 0;
  497. }
  498. else
  499. {
  500. return m_options.back().GetBitOffset() + m_options.back().GetBitCount();
  501. }
  502. }
  503. const AZStd::vector<ShaderOptionDescriptor>& ShaderOptionGroupLayout::GetShaderOptions() const
  504. {
  505. return m_options;
  506. }
  507. const ShaderOptionDescriptor& ShaderOptionGroupLayout::GetShaderOption(ShaderOptionIndex optionIndex) const
  508. {
  509. return m_options[optionIndex.GetIndex()];
  510. }
  511. size_t ShaderOptionGroupLayout::GetShaderOptionCount() const
  512. {
  513. return m_options.size();
  514. }
  515. ShaderVariantKey ShaderOptionGroupLayout::GetBitMask() const
  516. {
  517. return m_bitMask;
  518. }
  519. bool ShaderOptionGroupLayout::IsValidShaderVariantKey(const ShaderVariantKey& shaderVariantKey) const
  520. {
  521. if (ValidateIsFinalized())
  522. {
  523. return (m_bitMask & shaderVariantKey) == shaderVariantKey;
  524. }
  525. return false;
  526. }
  527. } // namespace RPI
  528. } // namespace AZ