3
0

IndirectBufferLayout.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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/RHI.Reflect/Base.h>
  9. #include <Atom/RHI.Reflect/IndirectBufferLayout.h>
  10. #include <AzCore/Utils/TypeHash.h>
  11. #include <AzCore/std/containers/unordered_set.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. namespace AZ::RHI
  14. {
  15. void IndirectBufferViewArguments::Reflect(ReflectContext* context)
  16. {
  17. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  18. {
  19. serializeContext->Class<IndirectBufferViewArguments>()
  20. ->Version(0)
  21. ->Field("m_slot", &IndirectBufferViewArguments::m_slot)
  22. ;
  23. }
  24. }
  25. void IndirectCommandDescriptor::Reflect(ReflectContext* context)
  26. {
  27. IndirectCommandIndex::Reflect(context);
  28. IndirectBufferViewArguments::Reflect(context);
  29. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  30. {
  31. serializeContext->Class<IndirectCommandDescriptor>()
  32. ->Version(0)
  33. ->Field("m_type", &IndirectCommandDescriptor::m_type)
  34. ->Field("m_vertexBufferArgs", &IndirectCommandDescriptor::m_vertexBufferArgs)
  35. ;
  36. }
  37. }
  38. HashValue64 IndirectCommandDescriptor::GetHash(HashValue64 seed /*= 0*/) const
  39. {
  40. return TypeHash64(*this, seed);
  41. }
  42. void IndirectBufferLayout::Reflect(AZ::ReflectContext* context)
  43. {
  44. IndirectCommandDescriptor::Reflect(context);
  45. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  46. {
  47. serializeContext->Class<IndirectBufferLayout>()
  48. ->Version(0)
  49. ->Field("m_commands", &IndirectBufferLayout::m_commands)
  50. ->Field("m_idReflectionForCommands", &IndirectBufferLayout::m_idReflectionForCommands)
  51. ->Field("m_type", &IndirectBufferLayout::m_type)
  52. ->Field("m_hash", &IndirectBufferLayout::m_hash)
  53. ;
  54. }
  55. }
  56. bool IndirectBufferLayout::IsFinalized() const
  57. {
  58. return m_hash != HashValue64{ 0 };
  59. }
  60. bool IndirectBufferLayout::Finalize()
  61. {
  62. if (!ValidateFinalizeState(ValidateFinalizeStateExpect::NotFinalized))
  63. {
  64. return false;
  65. }
  66. // Calculate the hash and get the main command type while
  67. // iterating through the commands.
  68. m_type = IndirectBufferLayoutType::Undefined;
  69. m_hash = HashValue64{ 0 };
  70. for (uint32_t i = 0; i < m_commands.size(); ++i)
  71. {
  72. const auto& commandDesc = m_commands[i];
  73. m_hash = TypeHash64(commandDesc.GetHash(), m_hash);
  74. m_idReflectionForCommands[static_cast<uint64_t>(commandDesc.GetHash())] = IndirectCommandIndex(i);
  75. bool result = true;
  76. switch (commandDesc.m_type)
  77. {
  78. case IndirectCommandType::Draw:
  79. result = SetType(IndirectBufferLayoutType::LinearDraw);
  80. break;
  81. case IndirectCommandType::DrawIndexed:
  82. result = SetType(IndirectBufferLayoutType::IndexedDraw);
  83. break;
  84. case IndirectCommandType::Dispatch:
  85. result = SetType(IndirectBufferLayoutType::Dispatch);
  86. break;
  87. case IndirectCommandType::DispatchRays:
  88. result = SetType(IndirectBufferLayoutType::DispatchRays);
  89. break;
  90. default:
  91. // Skip command
  92. break;
  93. }
  94. if (!result)
  95. {
  96. return false;
  97. }
  98. }
  99. m_hash = TypeHash64(m_type, m_hash);
  100. if (Validation::IsEnabled())
  101. {
  102. if (m_type == IndirectBufferLayoutType::Undefined)
  103. {
  104. AZ_Assert(false, "Missing Draw, DrawIndexed or Dispatch command in the layout.");
  105. return false;
  106. }
  107. }
  108. return true;
  109. }
  110. HashValue64 IndirectBufferLayout::GetHash([[maybe_unused]] HashValue64 seed) const
  111. {
  112. return m_hash;
  113. }
  114. bool IndirectBufferLayout::AddIndirectCommand(const IndirectCommandDescriptor& command)
  115. {
  116. if (!ValidateCommand(command))
  117. {
  118. return false;
  119. }
  120. m_commands.push_back(command);
  121. return true;
  122. }
  123. AZStd::span<const IndirectCommandDescriptor> IndirectBufferLayout::GetCommands() const
  124. {
  125. if (!ValidateFinalizeState(ValidateFinalizeStateExpect::Finalized))
  126. {
  127. return AZStd::span<const IndirectCommandDescriptor>();
  128. }
  129. return m_commands;
  130. }
  131. IndirectCommandIndex IndirectBufferLayout::FindCommandIndex(const IndirectCommandDescriptor& command) const
  132. {
  133. auto findIt = m_idReflectionForCommands.find(static_cast<uint64_t>(command.GetHash()));
  134. return findIt == m_idReflectionForCommands.end() ? IndirectCommandIndex::Null : findIt->second;
  135. }
  136. IndirectBufferLayoutType IndirectBufferLayout::GetType() const
  137. {
  138. return m_type;
  139. }
  140. bool IndirectBufferLayout::ValidateFinalizeState(ValidateFinalizeStateExpect expect) const
  141. {
  142. if (Validation::IsEnabled())
  143. {
  144. if (expect == ValidateFinalizeStateExpect::Finalized && !IsFinalized())
  145. {
  146. AZ_Assert(false, "IndirectBufferLayout must be finalized when calling this method.");
  147. return false;
  148. }
  149. else if (expect == ValidateFinalizeStateExpect::NotFinalized && IsFinalized())
  150. {
  151. AZ_Assert(false, "IndirectBufferLayout cannot be finalized when calling this method.");
  152. return false;
  153. }
  154. }
  155. return true;
  156. }
  157. bool IndirectBufferLayout::ValidateCommand(const IndirectCommandDescriptor& command) const
  158. {
  159. if (Validation::IsEnabled())
  160. {
  161. if (IsFinalized())
  162. {
  163. AZ_Assert(false, "Layout already finalized");
  164. return false;
  165. }
  166. switch (command.m_type)
  167. {
  168. case IndirectCommandType::Draw:
  169. case IndirectCommandType::DrawIndexed:
  170. case IndirectCommandType::Dispatch:
  171. case IndirectCommandType::DispatchRays:
  172. case IndirectCommandType::IndexBufferView:
  173. case IndirectCommandType::RootConstants:
  174. case IndirectCommandType::VertexBufferView:
  175. if (AZStd::find(m_commands.begin(), m_commands.end(), command) != m_commands.end())
  176. {
  177. AZ_Assert(false, "Duplicated command %d.", command.m_type);
  178. return false;
  179. }
  180. break;
  181. default:
  182. AZ_Assert(false, "Invalid command type %d.", command.m_type);
  183. return false;
  184. }
  185. }
  186. return true;
  187. }
  188. bool IndirectBufferLayout::SetType(IndirectBufferLayoutType type)
  189. {
  190. if (Validation::IsEnabled())
  191. {
  192. if (m_type != IndirectBufferLayoutType::Undefined)
  193. {
  194. AZ_Assert(false, "Trying to set a layout type (%d) when one is already set (%d)", type, m_type);
  195. return false;
  196. }
  197. }
  198. m_type = type;
  199. return true;
  200. }
  201. }