3
0

ShaderOptionGroupLayout.cpp 25 KB

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