2
0

OpenXRVkSwapChain.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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/Vulkan/Conversion.h>
  9. #include <Atom/RHI.Reflect/Vulkan/XRVkDescriptors.h>
  10. #include <AzCore/Casting/numeric_cast.h>
  11. #include <AzCore/std/containers/set.h>
  12. #include <AzCore/std/containers/vector.h>
  13. #include <AzCore/Settings/SettingsRegistry.h>
  14. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  15. #include <OpenXRVk/OpenXRVkDevice.h>
  16. #include <OpenXRVk/OpenXRVkInstance.h>
  17. #include <OpenXRVk/OpenXRVkSession.h>
  18. #include <OpenXRVk/OpenXRVkSwapChain.h>
  19. #include <OpenXRVk/OpenXRVkUtils.h>
  20. #include <XR/XRFactory.h>
  21. namespace OpenXRVk
  22. {
  23. XR::Ptr<SwapChain> SwapChain::Create()
  24. {
  25. return aznew SwapChain;
  26. }
  27. XR::Ptr<SwapChain::Image> SwapChain::Image::Create()
  28. {
  29. return aznew SwapChain::Image;
  30. }
  31. XR::Ptr<SwapChain::View> SwapChain::View::Create()
  32. {
  33. return aznew SwapChain::View;
  34. }
  35. AZ::RHI::ResultCode SwapChain::View::Init(XrSwapchain handle, AZ::u32 width, AZ::u32 height)
  36. {
  37. m_handle = handle;
  38. m_width = width;
  39. m_height = height;
  40. return AZ::RHI::ResultCode::Success;
  41. }
  42. AZ::u32 SwapChain::View::GetCurrentImageIndex() const
  43. {
  44. return m_activeImageIndex;
  45. }
  46. AZ::RHI::ResultCode SwapChain::Image::Init(XrSwapchainImageVulkan2KHR swapchainImage)
  47. {
  48. m_swapchainImage = swapchainImage;
  49. return AZ::RHI::ResultCode::Success;
  50. }
  51. VkImage SwapChain::Image::GetNativeImage()
  52. {
  53. return m_swapchainImage.image;
  54. }
  55. XrSwapchain SwapChain::View::GetSwapChainHandle() const
  56. {
  57. return m_handle;
  58. }
  59. AZ::u32 SwapChain::View::GetWidth() const
  60. {
  61. return m_width;
  62. }
  63. AZ::u32 SwapChain::View::GetHeight() const
  64. {
  65. return m_height;
  66. }
  67. void SwapChain::View::Shutdown()
  68. {
  69. xrDestroySwapchain(m_handle);
  70. }
  71. AZ::RHI::ResultCode SwapChain::InitInternal()
  72. {
  73. Instance* xrVkInstance = static_cast<Instance*>(GetDescriptor().m_instance.get());
  74. Session* xrVkSession = static_cast<Session*>(GetDescriptor().m_session.get());
  75. XrInstance xrInstance = xrVkInstance->GetXRInstance();
  76. XrSystemId xrSystemId = xrVkInstance->GetXRSystemId();
  77. XrSession xrSession = xrVkSession->GetXrSession();
  78. // Read graphics properties for preferred swapchain length and logging.
  79. XrSystemProperties systemProperties{ XR_TYPE_SYSTEM_PROPERTIES };
  80. XrResult result = xrGetSystemProperties(xrInstance, xrSystemId, &systemProperties);
  81. WARN_IF_UNSUCCESSFUL(result);
  82. if(GetDescriptor().m_validationMode == AZ::RHI::ValidationMode::Enabled)
  83. {
  84. // Log system properties.
  85. AZ_Printf("OpenXRVk", "System Properties: Name=%s VendorId=%d\n", systemProperties.systemName, systemProperties.vendorId);
  86. AZ_Printf("OpenXRVk",
  87. "System Graphics Properties: MaxWidth=%d MaxHeight=%d MaxLayers=%d\n",
  88. systemProperties.graphicsProperties.maxSwapchainImageWidth, systemProperties.graphicsProperties.maxSwapchainImageHeight,
  89. systemProperties.graphicsProperties.maxLayerCount);
  90. AZ_Printf("OpenXRVk",
  91. "System Tracking Properties: OrientationTracking=%s PositionTracking=%s\n",
  92. systemProperties.trackingProperties.orientationTracking == XR_TRUE ? "True" : "False",
  93. systemProperties.trackingProperties.positionTracking == XR_TRUE ? "True" : "False");
  94. }
  95. m_numViews = xrVkInstance->GetViewCount();
  96. XrViewConfigurationType viewConfigType = xrVkInstance->GetViewConfigType();
  97. m_configViews.resize(m_numViews, { XR_TYPE_VIEW_CONFIGURATION_VIEW });
  98. result = xrEnumerateViewConfigurationViews(xrInstance, xrSystemId,
  99. viewConfigType, m_numViews, &m_numViews, m_configViews.data());
  100. WARN_IF_UNSUCCESSFUL(result);
  101. // Create the swapchain and get the images.
  102. if (m_numViews > 0)
  103. {
  104. // Select a swapchain format.
  105. uint32_t swapchainFormatCount = 0;
  106. result = xrEnumerateSwapchainFormats(xrSession, 0, &swapchainFormatCount, nullptr);
  107. AZStd::vector<int64_t> swapChainFormats(swapchainFormatCount);
  108. result = xrEnumerateSwapchainFormats(xrSession, aznumeric_cast<uint32_t>(swapChainFormats.size()),
  109. &swapchainFormatCount, swapChainFormats.data());
  110. WARN_IF_UNSUCCESSFUL(result);
  111. AZ_Assert(swapchainFormatCount == swapChainFormats.size(), "Size mismatch swapchainFormatCount %i swapChainFormats size %i", swapchainFormatCount, swapChainFormats.size());
  112. m_colorSwapChainFormat = SelectColorSwapChainFormat(swapChainFormats);
  113. // Print swapchain formats and the selected one.
  114. if (GetDescriptor().m_validationMode == AZ::RHI::ValidationMode::Enabled)
  115. {
  116. AZStd::string swapchainFormatsString;
  117. for (int64_t format : swapChainFormats)
  118. {
  119. const bool selected = format == static_cast<int64_t>(m_colorSwapChainFormat);
  120. swapchainFormatsString += " ";
  121. if (selected)
  122. {
  123. swapchainFormatsString += "[";
  124. }
  125. swapchainFormatsString += AZStd::string::format("%" PRId64, format);
  126. if (selected)
  127. {
  128. swapchainFormatsString += "]";
  129. }
  130. }
  131. AZ_Printf("OpenXRVk", "Swapchain Formats: %s\n", swapchainFormatsString.c_str());
  132. }
  133. double xrViewResolutionScale = 1.0;
  134. if (auto* settingsRegistry = AZ::SettingsRegistry::Get();
  135. settingsRegistry != nullptr)
  136. {
  137. AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, xrViewResolutionScale,
  138. "/O3DE/Atom/OpenXR", "ViewResolutionScale");
  139. }
  140. // Create a swapchain for each view.
  141. for (uint32_t i = 0; i < m_numViews; i++)
  142. {
  143. XrViewConfigurationView& configView = m_configViews[i];
  144. configView.recommendedImageRectWidth = static_cast<uint32_t>(static_cast<double>(configView.recommendedImageRectWidth) * xrViewResolutionScale);
  145. configView.recommendedImageRectHeight = static_cast<uint32_t>(static_cast<double>(configView.recommendedImageRectHeight) * xrViewResolutionScale);
  146. if (GetDescriptor().m_validationMode == AZ::RHI::ValidationMode::Enabled)
  147. {
  148. AZ_Printf("OpenXRVk",
  149. "Creating swapchain for view %d with dimensions Width=%d Height=%d SampleCount=%d\n", i,
  150. configView.recommendedImageRectWidth, configView.recommendedImageRectHeight, configView.recommendedSwapchainSampleCount);
  151. }
  152. XR::Ptr<XR::SwapChain::View> baseViewSwapChain = XR::Factory::Get().CreateSwapChainView();
  153. SwapChain::View* viewSwapChain = static_cast<SwapChain::View*>(baseViewSwapChain.get());
  154. if (viewSwapChain)
  155. {
  156. // Create the xr swapchain.
  157. XrSwapchainCreateInfo swapchainCreateInfo{ XR_TYPE_SWAPCHAIN_CREATE_INFO };
  158. swapchainCreateInfo.arraySize = m_arraySize;
  159. swapchainCreateInfo.format = static_cast<int64_t>(m_colorSwapChainFormat);
  160. swapchainCreateInfo.width = configView.recommendedImageRectWidth;
  161. swapchainCreateInfo.height = configView.recommendedImageRectHeight;
  162. swapchainCreateInfo.mipCount = m_mipCount;
  163. swapchainCreateInfo.faceCount = m_faceCount;
  164. swapchainCreateInfo.sampleCount = m_sampleCount;
  165. swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT |
  166. XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT |
  167. XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT |
  168. XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT |
  169. XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR
  170. ;
  171. XrSwapchain handle = XR_NULL_HANDLE;
  172. result = xrCreateSwapchain(xrSession, &swapchainCreateInfo, &handle);
  173. WARN_IF_UNSUCCESSFUL(result);
  174. AZ::RHI::ResultCode resultCode = viewSwapChain->Init(handle, swapchainCreateInfo.width, swapchainCreateInfo.height);
  175. if(resultCode == AZ::RHI::ResultCode::Success)
  176. {
  177. m_viewSwapchains.push_back(viewSwapChain);
  178. }
  179. }
  180. result = xrEnumerateSwapchainImages(viewSwapChain->GetSwapChainHandle(), 0, &viewSwapChain->m_numImages, nullptr);
  181. WARN_IF_UNSUCCESSFUL(result);
  182. viewSwapChain->m_swapChainImageHeaders.resize(viewSwapChain->m_numImages);
  183. viewSwapChain->m_swapchainImages.resize(viewSwapChain->m_numImages);
  184. for (AZ::u32 j = 0; j < viewSwapChain->m_numImages; ++j)
  185. {
  186. viewSwapChain->m_swapchainImages[j] = { XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR };
  187. viewSwapChain->m_swapChainImageHeaders[j] = reinterpret_cast<XrSwapchainImageBaseHeader*>(&viewSwapChain->m_swapchainImages[j]);
  188. }
  189. result = xrEnumerateSwapchainImages(viewSwapChain->GetSwapChainHandle(), viewSwapChain->m_numImages, &viewSwapChain->m_numImages, viewSwapChain->m_swapChainImageHeaders[0]);
  190. WARN_IF_UNSUCCESSFUL(result);
  191. for (uint32_t j = 0; j < viewSwapChain->m_numImages; ++j)
  192. {
  193. XR::Ptr<XR::SwapChain::Image> baseViewSwapChainImage = XR::Factory::Get().CreateSwapChainImage();
  194. SwapChain::Image* viewSwapChainImage = static_cast<SwapChain::Image*>(baseViewSwapChainImage.get());
  195. AZ::RHI::ResultCode resultCode = viewSwapChainImage->Init(viewSwapChain->m_swapchainImages[j]);
  196. if (resultCode == AZ::RHI::ResultCode::Success)
  197. {
  198. viewSwapChain->m_images.push_back(baseViewSwapChainImage);
  199. }
  200. }
  201. }
  202. }
  203. return AZ::RHI::ResultCode::Success;
  204. }
  205. VkFormat SwapChain::SelectColorSwapChainFormat(const AZStd::vector<int64_t>& runtimeFormats) const
  206. {
  207. // List of supported color swapchain formats.
  208. constexpr int64_t SupportedColorSwapchainFormats[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB };
  209. auto swapchainFormatIt =
  210. AZStd::find_first_of(runtimeFormats.begin(), runtimeFormats.end(), AZStd::begin(SupportedColorSwapchainFormats),
  211. AZStd::end(SupportedColorSwapchainFormats));
  212. if (swapchainFormatIt == runtimeFormats.end())
  213. {
  214. AZ_Error("OpenXRVk", false, "No runtime swapchain format supported for color swapchain");
  215. return VK_FORMAT_UNDEFINED;
  216. }
  217. return static_cast<VkFormat>(*swapchainFormatIt);
  218. }
  219. AZStd::vector<XrViewConfigurationView> SwapChain::GetViewConfigs() const
  220. {
  221. return m_configViews;
  222. }
  223. AZ::RHI::ResultCode SwapChain::GetSwapChainImage(AZ::RHI::XRSwapChainDescriptor* swapchainDescriptor) const
  224. {
  225. AZ::Vulkan::XRSwapChainDescriptor* xrSwapChainDescriptor = static_cast<AZ::Vulkan::XRSwapChainDescriptor*>(swapchainDescriptor);
  226. uint32_t swapChainIndex = xrSwapChainDescriptor->m_inputData.m_swapChainIndex;
  227. uint32_t swapChainImageIndex = xrSwapChainDescriptor->m_inputData.m_swapChainImageIndex;
  228. XR::SwapChain::View* viewSwapChain = GetView(swapChainIndex);
  229. SwapChain::Image* swapchainImage = static_cast<SwapChain::Image*>(viewSwapChain->m_images[swapChainImageIndex].get());
  230. xrSwapChainDescriptor->m_outputData.m_nativeImage = swapchainImage->GetNativeImage();
  231. return AZ::RHI::ResultCode::Success;
  232. }
  233. AZ::u32 SwapChain::GetSwapChainWidth(AZ::u32 viewIndex) const
  234. {
  235. return m_configViews[viewIndex].recommendedImageRectWidth;
  236. }
  237. AZ::u32 SwapChain::GetSwapChainHeight(AZ::u32 viewIndex) const
  238. {
  239. return m_configViews[viewIndex].recommendedImageRectHeight;
  240. }
  241. AZ::RHI::Format SwapChain::GetSwapChainFormat([[maybe_unused]] AZ::u32 viewIndex) const
  242. {
  243. return AZ::Vulkan::ConvertFormat(m_colorSwapChainFormat);
  244. }
  245. void SwapChain::ShutdownInternal()
  246. {
  247. for(XR::Ptr<XR::SwapChain::View> viewSwapChain : m_viewSwapchains)
  248. {
  249. viewSwapChain->Shutdown();
  250. }
  251. }
  252. }