3
0

ShaderOptionGroupLayout.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  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", static_cast<Name (ShaderOptionDescriptor::*)(ShaderOptionValue) const>(&ShaderOptionDescriptor::GetValueName))
  99. ->Method("FindValue", &ShaderOptionDescriptor::FindValue)
  100. ->Method("GetMinValue", &ShaderOptionDescriptor::GetMinValue)
  101. ->Method("GetMaxValue", &ShaderOptionDescriptor::GetMaxValue)
  102. ->Method("GetValuesCount", &ShaderOptionDescriptor::GetValuesCount)
  103. ->Method("GetType", &ShaderOptionDescriptor::GetType)
  104. ->Method("GetValueNameByIndex", static_cast<Name (ShaderOptionDescriptor::*)(uint32_t) const>(&ShaderOptionDescriptor::GetValueName))
  105. ;
  106. }
  107. }
  108. ShaderOptionDescriptor::ShaderOptionDescriptor(const Name& name,
  109. const ShaderOptionType& optionType,
  110. uint32_t bitOffset,
  111. uint32_t order,
  112. const ShaderOptionValues& nameIndexList,
  113. const Name& defaultValue)
  114. : m_name{name}
  115. , m_type{optionType}
  116. , m_bitOffset{bitOffset}
  117. , m_order{order}
  118. , m_defaultValue{defaultValue}
  119. {
  120. for (auto pair : nameIndexList)
  121. { // Registers the pair in the lookup table
  122. AddValue(pair.first, pair.second);
  123. if (m_defaultValue.IsEmpty())
  124. {
  125. m_defaultValue = pair.first;
  126. }
  127. }
  128. uint32_t numValues = (m_type == ShaderOptionType::IntegerRange) ? (m_maxValue.GetIndex() - m_minValue.GetIndex() + 1) : (uint32_t) nameIndexList.size();
  129. numValues = RHI::NextPowerOfTwo(numValues) - 1;
  130. m_bitCount = RHI::CountBitsSet(numValues);
  131. ShaderVariantKey bitMask;
  132. bitMask = AZ_BIT_MASK(m_bitCount);
  133. bitMask <<= m_bitOffset;
  134. m_bitMask = bitMask;
  135. m_bitMaskNot = ~bitMask;
  136. m_hash = TypeHash64(m_bitMask, static_cast<HashValue64>(m_name.GetHash()));
  137. }
  138. const Name& ShaderOptionDescriptor::GetName() const
  139. {
  140. return m_name;
  141. }
  142. uint32_t ShaderOptionDescriptor::GetBitOffset() const
  143. {
  144. return m_bitOffset;
  145. }
  146. uint32_t ShaderOptionDescriptor::GetBitCount() const
  147. {
  148. return m_bitCount;
  149. }
  150. uint32_t ShaderOptionDescriptor::GetOrder() const
  151. {
  152. return m_order;
  153. }
  154. ShaderVariantKey ShaderOptionDescriptor::GetBitMask() const
  155. {
  156. return m_bitMask;
  157. }
  158. ShaderVariantKey ShaderOptionDescriptor::GetBitMaskNot() const
  159. {
  160. return m_bitMaskNot;
  161. }
  162. HashValue64 ShaderOptionDescriptor::GetHash() const
  163. {
  164. return m_hash;
  165. }
  166. bool ShaderOptionDescriptor::Set(ShaderOptionGroup& group, const Name& valueName) const
  167. {
  168. auto valueIndex = FindValue(valueName);
  169. if (valueIndex.IsValid())
  170. {
  171. return Set(group, valueIndex);
  172. }
  173. else
  174. {
  175. AZ_Error(DebugCategory, false, "ShaderOption value '%s' does not exist", valueName.GetCStr());
  176. return false;
  177. }
  178. }
  179. bool ShaderOptionDescriptor::Set(ShaderOptionGroup& group, const ShaderOptionValue valueIndex) const
  180. {
  181. if (valueIndex.IsNull())
  182. {
  183. AZ_Error(DebugCategory, false, "Invalid ShaderOption value");
  184. return false;
  185. }
  186. if (m_type == ShaderOptionType::Unknown)
  187. {
  188. group.GetShaderVariantMask() &= m_bitMaskNot;
  189. }
  190. else
  191. {
  192. if (!(m_minValue.GetIndex() <= valueIndex.GetIndex() && valueIndex.GetIndex() <= m_maxValue.GetIndex()))
  193. {
  194. AZ_Error(DebugCategory, false, "%s ShaderOption value [%d] is out of range [%d,%d].",
  195. ToString(m_type), valueIndex.GetIndex(), m_minValue.GetIndex(), m_maxValue.GetIndex());
  196. return false;
  197. }
  198. EncodeBits(group.GetShaderVariantKey(), valueIndex.GetIndex() - m_minValue.GetIndex());
  199. group.GetShaderVariantMask() |= m_bitMask;
  200. }
  201. return true;
  202. }
  203. bool ShaderOptionDescriptor::Set(ShaderVariantKey& key, const ShaderOptionValue valueIndex) const
  204. {
  205. if (valueIndex.IsNull())
  206. {
  207. AZ_Error(DebugCategory, false, "Invalid ShaderOption value");
  208. return false;
  209. }
  210. if (m_type != ShaderOptionType::Unknown)
  211. {
  212. if (!(m_minValue.GetIndex() <= valueIndex.GetIndex() && valueIndex.GetIndex() <= m_maxValue.GetIndex()))
  213. {
  214. AZ_Error(DebugCategory, false, "%s ShaderOption value [%d] is out of range [%d,%d].",
  215. ToString(m_type), valueIndex.GetIndex(), m_minValue.GetIndex(), m_maxValue.GetIndex());
  216. return false;
  217. }
  218. EncodeBits(key, valueIndex.GetIndex() - m_minValue.GetIndex());
  219. }
  220. return true;
  221. }
  222. ShaderOptionValue ShaderOptionDescriptor::Get(const ShaderOptionGroup& group) const
  223. {
  224. if (group.GetShaderVariantMask().test(m_bitOffset))
  225. {
  226. return ShaderOptionValue(DecodeBits(group.GetShaderVariantKey()) + m_minValue.GetIndex());
  227. }
  228. return ShaderOptionValue();
  229. }
  230. void ShaderOptionDescriptor::Clear(ShaderOptionGroup& group) const
  231. {
  232. group.GetShaderVariantMask() &= m_bitMaskNot;
  233. }
  234. void ShaderOptionDescriptor::AddValue(const Name& valueName, const ShaderOptionValue valueIndex)
  235. {
  236. 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!");
  237. m_nameReflectionForValues.Insert(valueName, valueIndex);
  238. if (m_minValue.IsNull() || m_minValue.GetIndex() > valueIndex.GetIndex())
  239. {
  240. m_minValue = valueIndex;
  241. }
  242. if (m_maxValue.IsNull() || m_maxValue.GetIndex() < valueIndex.GetIndex())
  243. {
  244. m_maxValue = valueIndex;
  245. }
  246. }
  247. void ShaderOptionDescriptor::SetDefaultValue(const Name& valueName)
  248. {
  249. AZ_Assert(!valueName.IsEmpty(), "The default value cannot be empty!");
  250. auto valueIter = m_nameReflectionForValues.Find(valueName);
  251. if (valueIter.IsNull())
  252. {
  253. AZ_Assert(false, "ShaderOption [%s] has no member value [%s] so this cannot be the default!", m_name.GetCStr(), valueName.GetCStr());
  254. return;
  255. }
  256. m_defaultValue = valueName;
  257. }
  258. const Name& ShaderOptionDescriptor::GetDefaultValue() const
  259. {
  260. return m_defaultValue;
  261. }
  262. uint32_t ShaderOptionDescriptor::GetValuesCount() const
  263. {
  264. return static_cast<uint32_t>(m_maxValue.GetIndex() - m_minValue.GetIndex() + 1);
  265. }
  266. /// Sets the hint type for the shader option
  267. void ShaderOptionDescriptor::SetType(ShaderOptionType optionType)
  268. {
  269. m_type = optionType;
  270. }
  271. /// Gets the hint type for the shader option
  272. const ShaderOptionType& ShaderOptionDescriptor::GetType() const
  273. {
  274. return m_type;
  275. }
  276. ShaderOptionValue ShaderOptionDescriptor::GetMinValue() const
  277. {
  278. return m_minValue;
  279. }
  280. ShaderOptionValue ShaderOptionDescriptor::GetMaxValue() const
  281. {
  282. return m_maxValue;
  283. }
  284. ShaderOptionValue ShaderOptionDescriptor::FindValue(const Name& valueName) const
  285. {
  286. switch (m_type)
  287. {
  288. case ShaderOptionType::Boolean:
  289. // This is better than hardcoding True, or On, or Enabled:
  290. return m_nameReflectionForValues.Find(valueName);
  291. case ShaderOptionType::Enumeration:
  292. return m_nameReflectionForValues.Find(valueName);
  293. case ShaderOptionType::IntegerRange:
  294. {
  295. int asInt;
  296. if (AzFramework::StringFunc::LooksLikeInt(valueName.GetCStr(), &asInt))
  297. {
  298. if (aznumeric_cast<int64_t>(m_minValue.GetIndex()) <= asInt && asInt <= aznumeric_cast<int64_t>(m_maxValue.GetIndex()))
  299. {
  300. return ShaderOptionValue(asInt);
  301. }
  302. }
  303. }
  304. return ShaderOptionValue();
  305. default:
  306. AZ_Assert(false, "Unhandled case for ShaderOptionType! We should not break here!");
  307. }
  308. // Unreachable code
  309. return ShaderOptionValue();
  310. }
  311. Name ShaderOptionDescriptor::GetValueName(ShaderOptionValue value) const
  312. {
  313. if (m_type == ShaderOptionType::IntegerRange)
  314. {
  315. // We can just return the value here, as IntegerRange's values' ids must be equal to their numerical value, this had been checked in AddValue()
  316. // We can't use m_nameReflectionForValues, since it only contains min and max value
  317. uint32_t value_uint = value.GetIndex();
  318. if (m_minValue.GetIndex() <= value_uint && value_uint <= m_maxValue.GetIndex())
  319. {
  320. return Name(AZStd::to_string(value_uint));
  321. }
  322. else
  323. {
  324. // mimic the behavior of RHI::NameIdReflectionMap's Find function
  325. return {};
  326. }
  327. }
  328. auto name = m_nameReflectionForValues.Find(value);
  329. return name;
  330. }
  331. Name ShaderOptionDescriptor::GetValueName(uint32_t valueIndex) const
  332. {
  333. return GetValueName(ShaderOptionValue{ valueIndex });
  334. }
  335. void ShaderOptionDescriptor::EncodeBits(ShaderVariantKey& shaderVariantKey, uint32_t value) const
  336. {
  337. if (value < AZ_BIT(m_bitCount))
  338. {
  339. ShaderVariantKey valueBits = (value & AZ_BIT_MASK(m_bitCount));
  340. valueBits <<= m_bitOffset;
  341. shaderVariantKey &= m_bitMaskNot;
  342. shaderVariantKey |= valueBits;
  343. }
  344. else
  345. {
  346. AZ_Assert(false, "Exceeded maximum number of bits allocated for option.");
  347. }
  348. }
  349. uint32_t ShaderOptionDescriptor::DecodeBits(ShaderVariantKey shaderVariantKey) const
  350. {
  351. shaderVariantKey >>= m_bitOffset;
  352. shaderVariantKey &= AZ_BIT_MASK(m_bitCount);
  353. uint32_t value = static_cast<uint32_t>(shaderVariantKey.to_ulong());
  354. return value;
  355. }
  356. bool ShaderOptionDescriptor::operator==(const ShaderOptionDescriptor& rhs) const
  357. {
  358. return m_hash == rhs.m_hash;
  359. }
  360. bool ShaderOptionDescriptor::operator!=(const ShaderOptionDescriptor& rhs) const
  361. {
  362. return m_hash != rhs.m_hash;
  363. }
  364. bool ShaderOptionDescriptor::CompareOrder(const ShaderOptionDescriptor& first, const ShaderOptionDescriptor& second)
  365. {
  366. return first.GetOrder() < second.GetOrder();
  367. }
  368. bool ShaderOptionDescriptor::SameOrder(const ShaderOptionDescriptor& first, const ShaderOptionDescriptor& second)
  369. {
  370. return first.GetOrder() == second.GetOrder();
  371. }
  372. void ShaderOptionGroupLayout::Reflect(AZ::ReflectContext* context)
  373. {
  374. ShaderOptionIndex::Reflect(context);
  375. NameReflectionMapForOptions::Reflect(context);
  376. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  377. {
  378. serializeContext->Class<ShaderOptionGroupLayout>()
  379. ->Version(2)
  380. ->Field("m_bitMask", &ShaderOptionGroupLayout::m_bitMask)
  381. ->Field("m_options", &ShaderOptionGroupLayout::m_options)
  382. ->Field("m_nameReflectionForOptions", &ShaderOptionGroupLayout::m_nameReflectionForOptions)
  383. ->Field("m_hash", &ShaderOptionGroupLayout::m_hash)
  384. ;
  385. }
  386. if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
  387. {
  388. behaviorContext->Class<ShaderOptionGroupLayout>()
  389. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  390. ->Attribute(AZ::Script::Attributes::Category, "Shader")
  391. ->Attribute(AZ::Script::Attributes::Module, "shader")
  392. ->Method("GetShaderOptions", &ShaderOptionGroupLayout::GetShaderOptions)
  393. ;
  394. }
  395. }
  396. Ptr<ShaderOptionGroupLayout> ShaderOptionGroupLayout::Create()
  397. {
  398. return aznew ShaderOptionGroupLayout;
  399. }
  400. bool ShaderOptionGroupLayout::IsFinalized() const
  401. {
  402. return m_hash != HashValue64{ 0 };
  403. }
  404. HashValue64 ShaderOptionGroupLayout::GetHash() const
  405. {
  406. return m_hash;
  407. }
  408. void ShaderOptionGroupLayout::Clear()
  409. {
  410. m_options.clear();
  411. m_nameReflectionForOptions.Clear();
  412. m_bitMask = {};
  413. m_hash = HashValue64{ 0 };
  414. }
  415. void ShaderOptionGroupLayout::Finalize()
  416. {
  417. AZStd::sort(m_options.begin(), m_options.end(), ShaderOptionDescriptor::CompareOrder);
  418. // 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.
  419. HashValue64 hash = TypeHash64(m_options.size());
  420. for (const ShaderOptionDescriptor& option : m_options)
  421. {
  422. hash = TypeHash64(option.GetHash(), hash);
  423. }
  424. m_hash = hash;
  425. }
  426. bool ShaderOptionGroupLayout::ValidateIsFinalized() const
  427. {
  428. if (!IsFinalized())
  429. {
  430. AZ_Assert(false, "ShaderOptionGroupLayout is not finalized! This operation is only permitted on a finalized layout.");
  431. return false;
  432. }
  433. return true;
  434. }
  435. bool ShaderOptionGroupLayout::ValidateIsNotFinalized() const
  436. {
  437. if (IsFinalized())
  438. {
  439. AZ_Assert(false, "ShaderOptionGroupLayout is finalized! This operation is only permitted on a non-finalized layout.");
  440. return false;
  441. }
  442. return true;
  443. }
  444. bool ShaderOptionGroupLayout::AddShaderOption(const ShaderOptionDescriptor& option)
  445. {
  446. if (!ValidateIsNotFinalized())
  447. {
  448. return false;
  449. }
  450. const Name& optionName = option.GetName();
  451. const ShaderVariantKey bitMask = option.GetBitMask();
  452. if ((m_bitMask & bitMask).any())
  453. {
  454. AZ_Error(DebugCategory, false, "ShaderOptionBinding '%s': mask overlaps with previously added masks.", optionName.GetCStr());
  455. return false;
  456. }
  457. if (option.GetName().IsEmpty())
  458. {
  459. AZ_Error(DebugCategory, false, "ShaderOptionBinding added with empty name.");
  460. return false;
  461. }
  462. if (option.GetBitCount() == 0)
  463. {
  464. AZ_Error(DebugCategory, false, "ShaderOptionBinding '%s' has zero bits.", optionName.GetCStr());
  465. return false;
  466. }
  467. if (option.GetBitOffset() + option.GetBitCount() > bitMask.size())
  468. {
  469. AZ_Error(DebugCategory, false, "ShaderOptionBinding '%s' exceeds size of mask.", optionName.GetCStr());
  470. return false;
  471. }
  472. if (AZStd::any_of(m_options.begin(), m_options.end(),
  473. [&option](const ShaderOptionDescriptor& other) { return ShaderOptionDescriptor::SameOrder(option, other); }))
  474. {
  475. AZ_Error(DebugCategory, false, "ShaderOption '%s' has the same order (%d) as another shader option.", optionName.GetCStr(), option.GetOrder());
  476. return false;
  477. }
  478. if (!option.FindValue(option.GetDefaultValue()).IsValid())
  479. {
  480. AZ_Error(DebugCategory, false, "ShaderOption '%s' has invalid default value '%s'.", optionName.GetCStr(), option.GetDefaultValue().GetCStr());
  481. return false;
  482. }
  483. const ShaderOptionIndex optionIndex(m_options.size());
  484. if (!m_nameReflectionForOptions.Insert(optionName, optionIndex))
  485. {
  486. AZ_Error(DebugCategory, false, "ShaderOptionBinding '%s': name already exists.", optionName.GetCStr());
  487. return false;
  488. }
  489. m_bitMask |= bitMask;
  490. m_options.push_back(option);
  491. return true;
  492. }
  493. ShaderOptionIndex ShaderOptionGroupLayout::FindShaderOptionIndex(const Name& optionName) const
  494. {
  495. if (ValidateIsFinalized())
  496. {
  497. return m_nameReflectionForOptions.Find(optionName);
  498. }
  499. return {};
  500. }
  501. ShaderOptionValue ShaderOptionGroupLayout::FindValue(const Name& optionName, const Name& valueName) const
  502. {
  503. return FindValue(FindShaderOptionIndex(optionName), valueName);
  504. }
  505. ShaderOptionValue ShaderOptionGroupLayout::FindValue(const ShaderOptionIndex& optionIndex, const Name& valueName) const
  506. {
  507. if (optionIndex.IsValid() && optionIndex.GetIndex() < m_options.size())
  508. {
  509. return m_options[optionIndex.GetIndex()].FindValue(valueName);
  510. }
  511. else
  512. {
  513. return ShaderOptionValue{};
  514. }
  515. }
  516. uint32_t ShaderOptionGroupLayout::GetBitSize() const
  517. {
  518. if (m_options.empty())
  519. {
  520. return 0;
  521. }
  522. else
  523. {
  524. return m_options.back().GetBitOffset() + m_options.back().GetBitCount();
  525. }
  526. }
  527. const AZStd::vector<ShaderOptionDescriptor>& ShaderOptionGroupLayout::GetShaderOptions() const
  528. {
  529. return m_options;
  530. }
  531. const ShaderOptionDescriptor& ShaderOptionGroupLayout::GetShaderOption(ShaderOptionIndex optionIndex) const
  532. {
  533. return m_options[optionIndex.GetIndex()];
  534. }
  535. size_t ShaderOptionGroupLayout::GetShaderOptionCount() const
  536. {
  537. return m_options.size();
  538. }
  539. ShaderVariantKey ShaderOptionGroupLayout::GetBitMask() const
  540. {
  541. return m_bitMask;
  542. }
  543. bool ShaderOptionGroupLayout::IsValidShaderVariantKey(const ShaderVariantKey& shaderVariantKey) const
  544. {
  545. if (ValidateIsFinalized())
  546. {
  547. return (m_bitMask & shaderVariantKey) == shaderVariantKey;
  548. }
  549. return false;
  550. }
  551. } // namespace RPI
  552. } // namespace AZ