OpenXRVkSwapChain.cpp 12 KB

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