OpenXRVkReferenceSpacesManager.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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 <AzCore/std/containers/array.h>
  9. #include <AzCore/std/utility/pair.h>
  10. #include <OpenXRVk/OpenXRVkUtils.h>
  11. #include "OpenXRVkReferenceSpacesManager.h"
  12. namespace OpenXRVk
  13. {
  14. bool ReferenceSpacesManager::Init(XrInstance xrInstance, XrSession xrSession, XrViewConfigurationType xrViewConfigurationType, uint32_t numEyeViews)
  15. {
  16. m_xrInstance = xrInstance;
  17. m_xrSession = xrSession;
  18. m_xrViewConfigurationType = xrViewConfigurationType;
  19. m_xrViews.resize(numEyeViews, { XR_TYPE_VIEW });
  20. m_eyeViewPoses.resize_no_construct(numEyeViews);
  21. m_eyeViewFovDatas.resize_no_construct(numEyeViews);
  22. m_viewSpacePose = AZ::Transform::Identity();
  23. for (uint32_t eyeViewIdx = 0; eyeViewIdx < numEyeViews; eyeViewIdx++)
  24. {
  25. m_eyeViewPoses[eyeViewIdx] = AZ::Transform::Identity();
  26. }
  27. const auto identityTm = AZ::Transform::CreateIdentity();
  28. AZStd::array<AZStd::pair<uint32_t, const char*>, 3> ReferenceSpaces = {
  29. {
  30. {IOpenXRReferenceSpaces::ReferenceSpaceIdView, IOpenXRReferenceSpaces::ReferenceSpaceNameView },
  31. {IOpenXRReferenceSpaces::ReferenceSpaceIdLocal, IOpenXRReferenceSpaces::ReferenceSpaceNameLocal },
  32. {IOpenXRReferenceSpaces::ReferenceSpaceIdStage, IOpenXRReferenceSpaces::ReferenceSpaceNameStage }
  33. }
  34. };
  35. for (const auto& refPair : ReferenceSpaces)
  36. {
  37. if (auto outcome = AddReferenceSpace(refPair.first, { refPair.second }, identityTm);
  38. !outcome.IsSuccess())
  39. {
  40. AZ_Error(LogName, false, "Failed to create default reference space [%s].Reason:\n%s\n",
  41. refPair.second, outcome.GetError().c_str());
  42. return false;
  43. }
  44. }
  45. // Set the default base space for View Space pose calculation.
  46. auto outcome = SetBaseSpaceForViewSpacePose({ IOpenXRReferenceSpaces::ReferenceSpaceNameLocal });
  47. AZ_Assert(outcome.IsSuccess(), "Failed to set the base space for View Space pose location");
  48. const auto& viewSpace = m_spaces.at(IOpenXRReferenceSpaces::ReferenceSpaceNameView);
  49. m_viewSpace = &viewSpace;
  50. return true;
  51. }
  52. bool ReferenceSpacesManager::SyncViews(XrTime predictedDisplayTime)
  53. {
  54. m_predictedDisplaytime = predictedDisplayTime;
  55. XrSpaceLocation xrSpaceLocation{ XR_TYPE_SPACE_LOCATION };
  56. auto result = xrLocateSpace(m_viewSpace->m_xrSpace, m_baseSpaceForViewSpace->m_xrSpace, m_predictedDisplaytime, &xrSpaceLocation);
  57. if (IsError(result))
  58. {
  59. PrintXrError(LogName, result, "Failed to locate View Space [%s] with base space [%s]",
  60. m_viewSpace->m_name.c_str(), m_baseSpaceForViewSpace->m_name.c_str());
  61. return false;
  62. }
  63. m_viewSpacePose = AzTransformFromXrPose(xrSpaceLocation.pose);
  64. ForceViewPosesCacheUpdate();
  65. return true;
  66. }
  67. void ReferenceSpacesManager::OnSessionReady()
  68. {
  69. // REMARK: On previous versions of the OpenXRVk::Spaces API it was necessary
  70. // to destroy and recreate the XrSpaces. But since the introduction of the
  71. // OpenXRVk::OpenXRActionsInterface and other architectural changes
  72. // that came with it, it appears that it is not ncessary anymore to recreate
  73. // the XrSpaces.
  74. // We are leaving this breadcrumb in case it becomes important in the future.
  75. AZ_Printf(LogName, "%s. For now, this function does nothing.\n", __FUNCTION__);
  76. }
  77. const AZStd::vector<XrView>& ReferenceSpacesManager::GetXrViews() const
  78. {
  79. return m_xrViews;
  80. }
  81. XrSpace ReferenceSpacesManager::GetViewSpaceXrSpace() const
  82. {
  83. return m_viewSpace->m_xrSpace;
  84. }
  85. /////////////////////////////////////////////////
  86. /// OpenXRReferenceSpacesInterface overrides
  87. AZStd::vector<AZStd::string> ReferenceSpacesManager::GetReferenceSpaceNames() const
  88. {
  89. AZStd::vector<AZStd::string> retList;
  90. for (auto const& pair : m_spaces) {
  91. retList.push_back(pair.first);
  92. }
  93. return retList;
  94. }
  95. AZ::Outcome<bool, AZStd::string> ReferenceSpacesManager::AddReferenceSpace(ReferenceSpaceId referenceSpaceType,
  96. const AZStd::string& spaceName, const AZ::Transform& poseInReferenceSpace)
  97. {
  98. if (m_spaces.contains(spaceName))
  99. {
  100. return AZ::Failure(
  101. AZStd::string::format("A space named [%s] already exists", spaceName.c_str())
  102. );
  103. }
  104. XrSpace newXrSpace = CreateXrSpace(XrReferenceSpaceType(referenceSpaceType), poseInReferenceSpace);
  105. if (XR_NULL_HANDLE == newXrSpace)
  106. {
  107. return AZ::Failure(
  108. AZStd::string::format("Failed to create new XrSpace for space named [%s] "
  109. "with reference space type [%u]", spaceName.c_str(), referenceSpaceType)
  110. );
  111. }
  112. ReferenceSpace visualizedSpace{ spaceName, poseInReferenceSpace, newXrSpace };
  113. m_spaces.emplace(spaceName, AZStd::move(visualizedSpace));
  114. return AZ::Success(true);
  115. }
  116. AZ::Outcome<bool, AZStd::string> ReferenceSpacesManager::RemoveReferenceSpace(const AZStd::string& spaceName)
  117. {
  118. static const AZStd::unordered_set<AZStd::string> defaultSystemSpaces {
  119. {IOpenXRReferenceSpaces::ReferenceSpaceNameView },
  120. {IOpenXRReferenceSpaces::ReferenceSpaceNameLocal},
  121. {IOpenXRReferenceSpaces::ReferenceSpaceNameStage}
  122. };
  123. if (defaultSystemSpaces.contains(spaceName))
  124. {
  125. return AZ::Failure(
  126. AZStd::string::format("Can not delete space [%s] because it is a system space.", spaceName.c_str())
  127. );
  128. }
  129. // If the space we are about to remove is currently the base space for View Space pose location, then we will fail too.
  130. if (m_baseSpaceForViewSpace &&
  131. (m_baseSpaceForViewSpace->m_name == spaceName))
  132. {
  133. return AZ::Failure(AZStd::string::format("Can not remove space [%s] because it is the base space to locate the [%s] space pose.",
  134. spaceName.c_str(), IOpenXRReferenceSpaces::ReferenceSpaceNameView));
  135. }
  136. auto itor = m_spaces.find(spaceName);
  137. if (itor == m_spaces.end())
  138. {
  139. AZ_Warning(LogName, false, "A space named [%s] doesn't exist.", spaceName.c_str());
  140. return AZ::Success(true);
  141. }
  142. xrDestroySpace(itor->second.m_xrSpace);
  143. m_spaces.erase(itor);
  144. return AZ::Success(true);
  145. }
  146. const void * ReferenceSpacesManager::GetReferenceSpaceNativeHandle(const AZStd::string& spaceName) const
  147. {
  148. const auto spaceItor = m_spaces.find(spaceName);
  149. if (spaceItor == m_spaces.end())
  150. {
  151. return nullptr;
  152. }
  153. return static_cast<void*>(spaceItor->second.m_xrSpace);
  154. }
  155. AZ::Outcome<AZ::Transform, AZStd::string> ReferenceSpacesManager::GetReferenceSpacePose(const AZStd::string& spaceName,
  156. const AZStd::string& baseSpaceName) const
  157. {
  158. const auto spaceItor = m_spaces.find(spaceName);
  159. if (spaceItor == m_spaces.end())
  160. {
  161. return AZ::Failure(AZStd::string::format("Space named [%s] doesn't exist.",
  162. spaceName.c_str()));
  163. }
  164. const auto baseSpaceItor = m_spaces.find(baseSpaceName);
  165. if (baseSpaceItor == m_spaces.end())
  166. {
  167. return AZ::Failure(AZStd::string::format("Base space named [%s] doesn't exist.",
  168. baseSpaceName.c_str()));
  169. }
  170. XrSpaceLocation xrSpaceLocation{ XR_TYPE_SPACE_LOCATION };
  171. auto result = xrLocateSpace(spaceItor->second.m_xrSpace, baseSpaceItor->second.m_xrSpace, m_predictedDisplaytime, &xrSpaceLocation);
  172. if (IsError(result))
  173. {
  174. return AZ::Failure(
  175. AZStd::string::format("Failed to locate visualized space [%s] with base space [%s]. Got Error:[%s].",
  176. spaceName.c_str(), baseSpaceName.c_str(), GetResultString(result))
  177. );
  178. }
  179. return AZ::Success(AzTransformFromXrPose(xrSpaceLocation.pose));
  180. }
  181. AZ::Outcome<bool, AZStd::string> ReferenceSpacesManager::SetBaseSpaceForViewSpacePose(const AZStd::string& spaceName)
  182. {
  183. const auto baseSpaceItor = m_spaces.find(spaceName);
  184. if (baseSpaceItor == m_spaces.end())
  185. {
  186. return AZ::Failure(
  187. AZStd::string::format("Can not set new base space named [%s] because it doesn't exist.",
  188. spaceName.c_str())
  189. );
  190. }
  191. m_baseSpaceForViewSpace = &(baseSpaceItor->second);
  192. return AZ::Success(true);
  193. }
  194. const AZStd::string& ReferenceSpacesManager::GetBaseSpaceForViewSpacePose() const
  195. {
  196. AZ_Assert(m_baseSpaceForViewSpace != nullptr, "A base space is always expected to exist!");
  197. return m_baseSpaceForViewSpace->m_name;
  198. }
  199. const AZ::Transform& ReferenceSpacesManager::GetViewSpacePose() const
  200. {
  201. return m_viewSpacePose;
  202. }
  203. uint32_t ReferenceSpacesManager::GetViewCount() const
  204. {
  205. return aznumeric_cast<uint32_t>(m_eyeViewPoses.size());
  206. }
  207. const AZ::Transform& ReferenceSpacesManager::GetViewPose(uint32_t eyeIndex) const
  208. {
  209. if (eyeIndex >= m_eyeViewPoses.size())
  210. {
  211. // Debug and Profile builds shoud crash here.
  212. AZ_Assert(false, "Can't get View Pose because [%u] is out of bounds", eyeIndex);
  213. // In Release build we'd see this message.
  214. AZ_Error(LogName, false, "Can't get View Pose because [%u] is out of bounds", eyeIndex);
  215. return AZ::Transform::Identity();
  216. }
  217. return m_eyeViewPoses[eyeIndex];
  218. }
  219. const AZ::RPI::FovData& ReferenceSpacesManager::GetViewFovData(uint32_t eyeIndex) const
  220. {
  221. if (eyeIndex >= m_eyeViewPoses.size())
  222. {
  223. // Debug and Profile builds shoud crash here.
  224. AZ_Assert(false, "Can't get View FovData because [%u] is out of bounds", eyeIndex);
  225. // In Release build we'd see this message.
  226. AZ_Error(LogName, false, "Can't get View FovData because [%u] is out of bounds", eyeIndex);
  227. static const AZ::RPI::FovData ZeroFovData{};
  228. return ZeroFovData;
  229. }
  230. return m_eyeViewFovDatas[eyeIndex];
  231. }
  232. const AZStd::vector<AZ::Transform>& ReferenceSpacesManager::GetViewPoses() const
  233. {
  234. return m_eyeViewPoses;
  235. }
  236. void ReferenceSpacesManager::ForceViewPosesCacheUpdate()
  237. {
  238. XrViewState viewState{ XR_TYPE_VIEW_STATE };
  239. uint32_t viewCapacityInput = aznumeric_cast<uint32_t>(m_xrViews.size());
  240. uint32_t viewCountOutput = 0;
  241. XrViewLocateInfo viewLocateInfo{ XR_TYPE_VIEW_LOCATE_INFO };
  242. viewLocateInfo.viewConfigurationType = m_xrViewConfigurationType;
  243. viewLocateInfo.displayTime = m_predictedDisplaytime;
  244. viewLocateInfo.space = m_viewSpace->m_xrSpace;
  245. XrResult result = xrLocateViews(m_xrSession, &viewLocateInfo, &viewState, viewCapacityInput, &viewCountOutput, m_xrViews.data());
  246. if (IsError(result) || (viewCapacityInput != viewCountOutput))
  247. {
  248. PrintXrError(LogName, result, "xrLocateViews failed with viewCapacityInput=%u, viewCountOutput=%u",
  249. viewCapacityInput, viewCountOutput);
  250. return;
  251. }
  252. AZ_Warning(LogName, (viewState.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT) != 0, "View poses position data won't be valid");
  253. AZ_Warning(LogName, (viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) != 0, "View poses orientation data won't be valid");
  254. for (size_t viewIdx = 0; viewIdx < m_xrViews.size(); viewIdx++)
  255. {
  256. m_eyeViewPoses[viewIdx] = AzTransformFromXrPose(m_xrViews[viewIdx].pose);
  257. auto& fovData = m_eyeViewFovDatas[viewIdx];
  258. const auto& xrFov = m_xrViews[viewIdx].fov;
  259. fovData.m_angleLeft = xrFov.angleLeft;
  260. fovData.m_angleRight = xrFov.angleRight;
  261. fovData.m_angleUp = xrFov.angleUp;
  262. fovData.m_angleDown = xrFov.angleDown;
  263. }
  264. }
  265. /// OpenXRReferenceSpacesInterface overrides
  266. /////////////////////////////////////////////////
  267. XrSpace ReferenceSpacesManager::CreateXrSpace(XrReferenceSpaceType referenceSpaceType, const AZ::Transform& relativePose)
  268. {
  269. XrReferenceSpaceCreateInfo referenceSpaceCreateInfo{ XR_TYPE_REFERENCE_SPACE_CREATE_INFO };
  270. referenceSpaceCreateInfo.poseInReferenceSpace = XrPoseFromAzTransform(relativePose);
  271. referenceSpaceCreateInfo.referenceSpaceType = referenceSpaceType;
  272. XrSpace newXrSpace = XR_NULL_HANDLE;
  273. XrResult result = xrCreateReferenceSpace(m_xrSession, &referenceSpaceCreateInfo, &newXrSpace);
  274. if (IsError(result))
  275. {
  276. PrintXrError(LogName, result, "Failed to create XrSpace using referenceSpaceType=%u.\n", referenceSpaceType);
  277. return XR_NULL_HANDLE;
  278. }
  279. return newXrSpace;
  280. }
  281. } // namespace OpenXRVk