LoaderContext.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. #define GLAD_VULKAN_IMPLEMENTATION
  9. #include <vulkan/vulkan.h>
  10. #include <Atom/RHI.Loader/LoaderContext.h>
  11. #include <AzCore/StringFunc/StringFunc.h>
  12. namespace AZ
  13. {
  14. namespace Vulkan
  15. {
  16. AZStd::unique_ptr<LoaderContext> LoaderContext::Create()
  17. {
  18. AZStd::unique_ptr<LoaderContext> loader(aznew LoaderContext());
  19. if (!loader->Preload())
  20. {
  21. return nullptr;
  22. }
  23. return loader;
  24. }
  25. LoaderContext::~LoaderContext()
  26. {
  27. Shutdown();
  28. }
  29. bool LoaderContext::Init(const LoaderContext::Descriptor& descriptor)
  30. {
  31. VkInstance instance = descriptor.m_instance;
  32. int result = gladLoaderLoadVulkanContext(&m_context, instance, descriptor.m_physicalDevice, descriptor.m_device);
  33. if (instance != VK_NULL_HANDLE)
  34. {
  35. LoadLayerExtensions(descriptor);
  36. }
  37. FilterAvailableExtensions(descriptor.m_device);
  38. return result != 0;
  39. }
  40. void LoaderContext::Shutdown()
  41. {
  42. gladLoaderUnloadVulkanContext(&m_context);
  43. }
  44. bool LoaderContext::Preload()
  45. {
  46. // Load functions from the dynamic library until we have a Vulkan instance or device.
  47. int result = gladLoaderLoadVulkanContext(&m_context, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE);
  48. FilterAvailableExtensions();
  49. return result != 0;
  50. }
  51. void LoaderContext::LoadLayerExtensions(const LoaderContext::Descriptor& descriptor)
  52. {
  53. // GLAD doesn't support loading extensions from layers yet, only from the driver.
  54. // On some platforms (e.g. Android) the EXT_debug_utils extension (we use it for receiving validation messages) is provided by
  55. // the validation layer instead of the driver. Because of this we manually load the function pointers for the EXT_debug_utils
  56. // extension (after checking that the extension was loaded by the Vulkan instance).
  57. VkInstance vkInstance = descriptor.m_instance;
  58. // Check if the EXT_debug_utils function pointers were already loaded from the driver.
  59. if (!VK_INSTANCE_EXTENSION_SUPPORTED(m_context, EXT_debug_utils))
  60. {
  61. // Check if the EXT_debug_utils extension was loaded when creating the VkInstance
  62. const AZStd::vector<const char*>& loadedExtensions = descriptor.m_loadedExtensions;
  63. auto findExtensionIter = AZStd::find_if(
  64. loadedExtensions.begin(),
  65. loadedExtensions.end(),
  66. [](const auto& extension)
  67. {
  68. return AZ::StringFunc::Equal(extension, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
  69. });
  70. if (findExtensionIter != loadedExtensions.end())
  71. {
  72. // EXT_debug_utils extension is loaded, so now we look for the layer that is providing the extension (since it was not
  73. // provided by the driver).
  74. const AZStd::vector<const char*>& loadedLayers = descriptor.m_loadedLayers;
  75. auto findLayerIter = AZStd::find_if(
  76. loadedLayers.begin(),
  77. loadedLayers.end(),
  78. [&](const auto& layer)
  79. {
  80. auto instanceExtensions = GetInstanceExtensionNames(layer);
  81. return AZStd::find(instanceExtensions.begin(), instanceExtensions.end(), *findExtensionIter) !=
  82. instanceExtensions.end();
  83. });
  84. if (findLayerIter != loadedLayers.end())
  85. {
  86. // Extension is loaded and provided by a layer that is also loaded.
  87. // We load the function pointers for the EXT_debug_utils extension manually.
  88. m_context.EXT_debug_utils = 1;
  89. if (vkInstance != VK_NULL_HANDLE)
  90. {
  91. m_context.CreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
  92. m_context.GetInstanceProcAddr(vkInstance, "vkCreateDebugUtilsMessengerEXT"));
  93. m_context.DestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(
  94. m_context.GetInstanceProcAddr(vkInstance, "vkDestroyDebugUtilsMessengerEXT"));
  95. m_context.SubmitDebugUtilsMessageEXT = reinterpret_cast<PFN_vkSubmitDebugUtilsMessageEXT>(
  96. m_context.GetInstanceProcAddr(vkInstance, "vkSubmitDebugUtilsMessageEXT"));
  97. }
  98. VkDevice device = descriptor.m_device;
  99. if (device != VK_NULL_HANDLE)
  100. {
  101. m_context.CmdBeginDebugUtilsLabelEXT = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(
  102. m_context.GetDeviceProcAddr(device, "vkCmdBeginDebugUtilsLabelEXT"));
  103. m_context.CmdEndDebugUtilsLabelEXT = reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(
  104. m_context.GetDeviceProcAddr(device, "vkCmdEndDebugUtilsLabelEXT"));
  105. m_context.CmdInsertDebugUtilsLabelEXT = reinterpret_cast<PFN_vkCmdInsertDebugUtilsLabelEXT>(
  106. m_context.GetDeviceProcAddr(device, "vkCmdInsertDebugUtilsLabelEXT"));
  107. m_context.QueueBeginDebugUtilsLabelEXT = reinterpret_cast<PFN_vkQueueBeginDebugUtilsLabelEXT>(
  108. m_context.GetDeviceProcAddr(device, "vkQueueBeginDebugUtilsLabelEXT"));
  109. m_context.QueueEndDebugUtilsLabelEXT = reinterpret_cast<PFN_vkQueueEndDebugUtilsLabelEXT>(
  110. m_context.GetDeviceProcAddr(device, "vkQueueEndDebugUtilsLabelEXT"));
  111. m_context.QueueInsertDebugUtilsLabelEXT = reinterpret_cast<PFN_vkQueueInsertDebugUtilsLabelEXT>(
  112. m_context.GetDeviceProcAddr(device, "vkQueueInsertDebugUtilsLabelEXT"));
  113. m_context.SetDebugUtilsObjectNameEXT = reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(
  114. m_context.GetDeviceProcAddr(device, "vkSetDebugUtilsObjectNameEXT"));
  115. m_context.SetDebugUtilsObjectTagEXT = reinterpret_cast<PFN_vkSetDebugUtilsObjectTagEXT>(
  116. m_context.GetDeviceProcAddr(device, "vkSetDebugUtilsObjectTagEXT"));
  117. }
  118. }
  119. }
  120. }
  121. }
  122. AZStd::vector<AZStd::string> LoaderContext::GetInstanceLayerNames() const
  123. {
  124. AZStd::vector<AZStd::string> layerNames;
  125. uint32_t layerPropertyCount = 0;
  126. VkResult result = m_context.EnumerateInstanceLayerProperties(&layerPropertyCount, nullptr);
  127. if (result != VK_SUCCESS || layerPropertyCount == 0)
  128. {
  129. return layerNames;
  130. }
  131. AZStd::vector<VkLayerProperties> layerProperties(layerPropertyCount);
  132. result = m_context.EnumerateInstanceLayerProperties(&layerPropertyCount, layerProperties.data());
  133. if (result != VK_SUCCESS)
  134. {
  135. return layerNames;
  136. }
  137. layerNames.reserve(layerNames.size() + layerProperties.size());
  138. for (uint32_t layerPropertyIndex = 0; layerPropertyIndex < layerPropertyCount; ++layerPropertyIndex)
  139. {
  140. layerNames.emplace_back(layerProperties[layerPropertyIndex].layerName);
  141. }
  142. return layerNames;
  143. }
  144. AZStd::vector<AZStd::string> LoaderContext::GetInstanceExtensionNames(const char* layerName /*= nullptr*/) const
  145. {
  146. AZStd::vector<AZStd::string> extensionNames;
  147. uint32_t extPropertyCount = 0;
  148. VkResult result = m_context.EnumerateInstanceExtensionProperties(layerName, &extPropertyCount, nullptr);
  149. if (result != VK_SUCCESS || extPropertyCount == 0)
  150. {
  151. return extensionNames;
  152. }
  153. AZStd::vector<VkExtensionProperties> extProperties;
  154. extProperties.resize(extPropertyCount);
  155. result = m_context.EnumerateInstanceExtensionProperties(layerName, &extPropertyCount, extProperties.data());
  156. if (result != VK_SUCCESS)
  157. {
  158. return extensionNames;
  159. }
  160. extensionNames.reserve(extensionNames.size() + extProperties.size());
  161. for (uint32_t extPropertyIndex = 0; extPropertyIndex < extPropertyCount; extPropertyIndex++)
  162. {
  163. extensionNames.emplace_back(extProperties[extPropertyIndex].extensionName);
  164. }
  165. return extensionNames;
  166. }
  167. GladVulkanContext& LoaderContext::GetContext()
  168. {
  169. return m_context;
  170. }
  171. const GladVulkanContext& LoaderContext::GetContext() const
  172. {
  173. return m_context;
  174. }
  175. void LoaderContext::FilterAvailableExtensions(const VkDevice device)
  176. {
  177. // In some cases (like when running with the GPU profiler on Quest2) the extension is reported as available
  178. // but the function pointers do not load. Disable the extension if that's the case.
  179. if (device != VK_NULL_HANDLE &&
  180. m_context.EXT_debug_utils &&
  181. !m_context.CmdBeginDebugUtilsLabelEXT)
  182. {
  183. m_context.EXT_debug_utils = 0;
  184. }
  185. }
  186. } // namespace Vulkan
  187. } // namespace AZ