FactoryManagerSystemComponent.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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/Factory.h>
  9. #include <Atom/RHI/RHIUtils.h>
  10. #include <Atom/RHI/ValidationLayer.h>
  11. #include <RHI.Private/FactoryManagerSystemComponent.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. #include <AzCore/Serialization/EditContext.h>
  14. #include <AzCore/Settings/SettingsRegistry.h>
  15. #include <AzCore/std/containers/unordered_map.h>
  16. #include <AzCore/std/sort.h>
  17. #include <AzFramework/API/ApplicationAPI.h>
  18. #include <AzFramework/IO/LocalFileIO.h>
  19. namespace AZ::RHI
  20. {
  21. void FactoryManagerSystemComponent::Reflect(AZ::ReflectContext* context)
  22. {
  23. if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
  24. {
  25. serializeContext->Class<FactoryManagerSystemComponent, AZ::Component>()
  26. ->Version(1)
  27. ->Field("factoriesPriority", &FactoryManagerSystemComponent::m_factoriesPriority)
  28. ->Field("validationMode", &FactoryManagerSystemComponent::m_validationMode);
  29. if (AZ::EditContext* ec = serializeContext->GetEditContext())
  30. {
  31. ec->Class<FactoryManagerSystemComponent>("Atom RHI Manager", "Atom Renderer")
  32. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  33. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  34. ->DataElement(AZ::Edit::UIHandlers::Default, &FactoryManagerSystemComponent::m_factoriesPriority, "RHI Priority list", "Priorities for RHI Implementations")
  35. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &FactoryManagerSystemComponent::m_validationMode, "Validation Layer Mode", "Set the validation mode for the RHI. It only applies for non release builds")
  36. ->Attribute(AZ::Edit::Attributes::EnumValues,
  37. AZStd::vector<AZ::Edit::EnumConstant<RHI::ValidationMode>>
  38. {
  39. AZ::Edit::EnumConstant<RHI::ValidationMode>(RHI::ValidationMode::Disabled,
  40. "Disable - Disables any validation."),
  41. AZ::Edit::EnumConstant<RHI::ValidationMode>(RHI::ValidationMode::Enabled,
  42. "Enable - Enables warnings and errors validation messages."),
  43. AZ::Edit::EnumConstant<RHI::ValidationMode>(RHI::ValidationMode::Verbose,
  44. "Verbose - Enables warnings, error and information messages."),
  45. AZ::Edit::EnumConstant<RHI::ValidationMode>(RHI::ValidationMode::GPU,
  46. "GPU - Enables based validation."),
  47. });
  48. }
  49. }
  50. }
  51. void FactoryManagerSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  52. {
  53. provided.push_back(Factory::GetManagerComponentService());
  54. }
  55. void FactoryManagerSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  56. {
  57. incompatible.push_back(Factory::GetManagerComponentService());
  58. }
  59. void FactoryManagerSystemComponent::GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent)
  60. {
  61. dependent.push_back(AZ_CRC_CE("GraphicsProfilerService"));
  62. dependent.push_back(AZ_CRC_CE("DeviceAttributesSystemComponentService"));
  63. }
  64. void FactoryManagerSystemComponent::Activate()
  65. {
  66. UpdateValidationModeFromCommandline();
  67. FactoryManagerBus::Handler::BusConnect();
  68. }
  69. void FactoryManagerSystemComponent::Deactivate()
  70. {
  71. FactoryManagerBus::Handler::BusDisconnect();
  72. }
  73. void FactoryManagerSystemComponent::RegisterFactory(Factory* factory)
  74. {
  75. m_registeredFactories.push_back(factory);
  76. }
  77. void FactoryManagerSystemComponent::UnregisterFactory(Factory* factory)
  78. {
  79. auto findIt = AZStd::find(m_registeredFactories.begin(), m_registeredFactories.end(), factory);
  80. if (findIt != m_registeredFactories.end())
  81. {
  82. m_registeredFactories.erase(findIt);
  83. if (Factory::IsReady() && factory == &Factory::Get())
  84. {
  85. Factory::Unregister(factory);
  86. FactoryManagerNotificationBus::Broadcast(&FactoryManagerNotification::FactoryUnregistered);
  87. }
  88. }
  89. else
  90. {
  91. AZ_Error("FactoryManagerSystemComponent", false, "Trying to unregister invalid factory");
  92. }
  93. }
  94. void FactoryManagerSystemComponent::FactoryRegistrationFinalize()
  95. {
  96. // This will be called when all factories have finished registering.
  97. AZ_Assert(!m_registeredFactories.empty(), "No factories registered");
  98. // We first check if a factory was specified via command line.
  99. // If that fails we choose one from the registered factories.
  100. Factory* factory = GetFactoryFromCommandLine();
  101. if (!factory)
  102. {
  103. factory = SelectRegisteredFactory();
  104. }
  105. AZ_Assert(factory, "Could not select factory");
  106. Factory::Register(factory);
  107. FactoryManagerNotificationBus::Broadcast(&FactoryManagerNotification::FactoryRegistered);
  108. }
  109. Factory* FactoryManagerSystemComponent::GetFactoryFromCommandLine()
  110. {
  111. AZStd::string cmdLineFactory = RHI::GetCommandLineValue("rhi");
  112. if (!cmdLineFactory.empty())
  113. {
  114. RHI::APIType cmdLineFactoryType(cmdLineFactory.c_str());
  115. auto cmdLineFindIt = AZStd::find_if(m_registeredFactories.begin(), m_registeredFactories.end(), [&cmdLineFactoryType](const auto& element)
  116. {
  117. return element->GetType() == cmdLineFactoryType;
  118. });
  119. if (cmdLineFindIt != m_registeredFactories.end())
  120. {
  121. return *cmdLineFindIt;
  122. }
  123. else
  124. {
  125. AZ_Warning("FactoryManagerSystemComponent", false, "RHI %s provided by command line is not available. Ignoring argument.", cmdLineFactory.c_str());
  126. }
  127. }
  128. return nullptr;
  129. }
  130. Factory* FactoryManagerSystemComponent::SelectRegisteredFactory()
  131. {
  132. // If there's more that one factory registered then we need to decide which one to use.
  133. if (m_registeredFactories.size() > 1)
  134. {
  135. // Load factories priority list from the settings registry
  136. if (auto* registry = AZ::SettingsRegistry::Get(); registry != nullptr)
  137. {
  138. m_factoriesPriority.clear();
  139. if (registry->GetObject(m_factoriesPriority, "/O3DE/Atom/RHI/FactoryManager/factoriesPriority"))
  140. {
  141. AZ_Printf(
  142. "FactoryManagerSystemComponent",
  143. "User has provided a list of factories priority. This will override the default priorities");
  144. }
  145. }
  146. // Build a hash table to quickly check the user defined priority for a factory.
  147. AZStd::unordered_map<RHI::APIType, size_t> factoryToPriorityMap;
  148. for (size_t i = 0; i < m_factoriesPriority.size(); ++i)
  149. {
  150. factoryToPriorityMap[RHI::APIType(m_factoriesPriority[i].c_str())] = i;
  151. }
  152. AZStd::sort(m_registeredFactories.begin(), m_registeredFactories.end(), [&factoryToPriorityMap](Factory* lhs, Factory* rhs)
  153. {
  154. auto lhsFindPriority = factoryToPriorityMap.find(lhs->GetType());
  155. auto rhsFindPriority = factoryToPriorityMap.find(rhs->GetType());
  156. if (lhsFindPriority != factoryToPriorityMap.end() && rhsFindPriority != factoryToPriorityMap.end())
  157. {
  158. // Both factories have user defined priority, so we just compare them directly.
  159. return lhsFindPriority->second < rhsFindPriority->second;
  160. }
  161. else if (lhsFindPriority == factoryToPriorityMap.end() && rhsFindPriority == factoryToPriorityMap.end())
  162. {
  163. // None of the factories have user defined priorities, so we use the default priorities.
  164. return lhs->GetDefaultPriority() < rhs->GetDefaultPriority();
  165. }
  166. else
  167. {
  168. // If one of the factories has user defined priority, then we prefer that one.
  169. return lhsFindPriority == factoryToPriorityMap.end() ? false : true;
  170. }
  171. });
  172. }
  173. return m_registeredFactories.front();
  174. }
  175. AZ::RHI::ValidationMode FactoryManagerSystemComponent::DetermineValidationMode() const
  176. {
  177. return m_validationMode;
  178. }
  179. void FactoryManagerSystemComponent::UpdateValidationModeFromCommandline()
  180. {
  181. m_validationMode = AZ::RHI::ReadValidationMode();
  182. }
  183. void FactoryManagerSystemComponent::EnumerateFactories(AZStd::function<bool(Factory* factory)> callback)
  184. {
  185. for (auto& factory : m_registeredFactories)
  186. {
  187. if (!callback(factory))
  188. {
  189. break;
  190. }
  191. }
  192. }
  193. }