OpenXRVkActionsManager.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. #pragma once
  9. #include <openxr/openxr.h>
  10. #include <OpenXRVk/OpenXRVkActionsInterface.h>
  11. #include <OpenXRVk/OpenXRVkActionSetsAsset.h>
  12. namespace OpenXRVk
  13. {
  14. // Class that will help manage XrActionSet/XrAction.
  15. // All XrActionSet and XrActions will be created from an
  16. // asset created by the developer where all actions of interest
  17. // are instantiated.
  18. class ActionsManager final :
  19. public OpenXRActionsInterface::Registrar,
  20. private AZ::Data::AssetBus::Handler
  21. {
  22. public:
  23. AZ_CLASS_ALLOCATOR(ActionsManager, AZ::SystemAllocator);
  24. AZ_RTTI(ActionsManager, "{79E2B285-073B-4042-93ED-B92E6C819CA6}", IOpenXRActions);
  25. static constexpr char LogName[] = "OpenXRVkActionsManager";
  26. ActionsManager() = default;
  27. ~ActionsManager();
  28. //! @returns True if it was able to start the initialization process by queueing
  29. //! asset loading of the Action Sets asset. This is a non-blocking call
  30. //! and the complete initialization will happend asynchronously but it
  31. //! will be transparent to the Session.
  32. bool Init(XrInstance xrInstance, XrSession xrSession);
  33. //! Called by the Session each tick.
  34. bool SyncActions(XrTime predictedDisplayTime);
  35. //! Called by the Session when the event XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED is
  36. //! received.
  37. void OnInteractionProfileChanged();
  38. /////////////////////////////////////////////////
  39. /// OpenXRActionsInterface overrides
  40. AZStd::vector<AZStd::string> GetAllActionSets() const override;
  41. AZ::Outcome<bool, AZStd::string> GetActionSetState(const AZStd::string& actionSetName) const override;
  42. AZ::Outcome<bool, AZStd::string> SetActionSetState(const AZStd::string& actionSetName, bool activate) override;
  43. IOpenXRActions::ActionHandle GetActionHandle(const AZStd::string& actionSetName, const AZStd::string& actionName) const override;
  44. AZ::Outcome<bool, AZStd::string> GetActionStateBoolean(ActionHandle actionHandle) const override;
  45. AZ::Outcome<float, AZStd::string> GetActionStateFloat(ActionHandle actionHandle) const override;
  46. AZ::Outcome<AZ::Vector2, AZStd::string> GetActionStateVector2(ActionHandle actionHandle) const override;
  47. AZ::Outcome<bool, AZStd::string> SetBaseReferenceSpaceForPoseActions(const AZStd::string& visualizedSpaceName) override;
  48. const AZStd::string& GetBaseReferenceSpaceForPoseActions() const override;
  49. AZ::Outcome<AZ::Transform, AZStd::string> GetActionStatePose(ActionHandle actionHandle) const override;
  50. AZ::Outcome<PoseWithVelocities, AZStd::string> GetActionStatePoseWithVelocities(ActionHandle actionHandle) const override;
  51. AZ::Outcome<bool, AZStd::string> ApplyHapticVibrationAction(ActionHandle actionHandle, uint64_t durationNanos, float frequencyHz, float amplitude) override;
  52. AZ::Outcome<bool, AZStd::string> StopHapticVibrationAction(ActionHandle actionHandle) override;
  53. /// OpenXRActionsInterface overrides
  54. /////////////////////////////////////////////////
  55. private:
  56. // The following struct will be used at initialization only.
  57. // All the bindings for all actions will be called
  58. struct SuggestedBindings
  59. {
  60. // Interaction Profile XrPath
  61. XrPath m_profileXrPath;
  62. // List of action bindings that will be registred for this profile.
  63. AZStd::vector<XrActionSuggestedBinding> m_suggestedBindingsList;
  64. };
  65. //! The key is the user friendly profile name.
  66. using SuggestedBindingsPerProfile = AZStd::unordered_map<AZStd::string, SuggestedBindings>;
  67. struct ActionInfo
  68. {
  69. AZStd::string m_name;
  70. XrActionType m_actionType = XR_ACTION_TYPE_MAX_ENUM;
  71. XrAction m_xrAction = XR_NULL_HANDLE;
  72. // Only valid if m_actionType is XR_ACTION_TYPE_POSE_INPUT
  73. XrSpace m_xrSpace = XR_NULL_HANDLE;
  74. };
  75. struct ActionSetInfo
  76. {
  77. AZStd::string m_name;
  78. XrActionSet m_xrActionSet;
  79. // The key is the name of the action.
  80. // The value is the index in @m_actions;
  81. AZStd::unordered_map<AZStd::string, IOpenXRActions::ActionHandle> m_actions;
  82. };
  83. // Called when m_actionSetAsset is ready.
  84. void InitInternal();
  85. //! Returns the Asset Cache relative product path of the
  86. //! ActionSets Asset.
  87. AZStd::string GetActionSetsAssetPath();
  88. //! Requests the Asset System to start loading the ActionSets Asset.
  89. //! @returns Success if the asset loading request was queued successfully.
  90. //! @remark Once OnAssetReady event is received, the XrActionSets and XrActions
  91. //! will be created, along with their bindings etc.
  92. bool LoadActionSetAssetAsync();
  93. //! This function is called by InitInternal() to instantiate an XrActionSet from an OpenXRActionSetDescriptor.
  94. //! Additionally all XrActions for the XrActionSet will also be instantiated.
  95. //! @param interactionProfilesAsset The interaction profiles asset that owns the XrPath string data
  96. //! that will be required to instantiate XrActions.
  97. //! @param actionSetDescriptor Contains all the data required to create an XrActionSet and all of its
  98. //! XrActions
  99. //! @param suggestedBindingsPerProfileOut In this dictionary, to be used later by InitInternal(),
  100. //! we collect all the Action Bindings for each Interaction Profile referenced by the
  101. //! OpenXRActionSetsAsset.
  102. bool InitActionSet(const OpenXRInteractionProfilesAsset& interactionProfilesAsset,
  103. const OpenXRActionSetDescriptor& actionSetDescriptor,
  104. SuggestedBindingsPerProfile& suggestedBindingsPerProfileOut);
  105. //! Called by InitActionSet(...)
  106. bool AddActionToActionSet(const OpenXRInteractionProfilesAsset& interactionProfilesAsset,
  107. ActionSetInfo& actionSetInfo,
  108. const OpenXRActionDescriptor& actionDescriptor,
  109. SuggestedBindingsPerProfile& suggestedBindingsPerProfile);
  110. //! Called by AddActionToActionSet(...)
  111. XrAction CreateXrActionAndXrSpace(const ActionSetInfo& actionSetInfo,
  112. const OpenXRActionDescriptor& actionDescriptor, const XrActionType actionType, XrSpace& newXrActionSpace) const;
  113. //! Called by AddActionToActionSet(...)
  114. uint32_t AppendActionBindings(const OpenXRInteractionProfilesAsset& interactionProfilesAsset,
  115. const OpenXRActionDescriptor& actionDescriptor,
  116. XrAction xrAction,
  117. SuggestedBindingsPerProfile& suggestedBindingsPerProfile) const;
  118. //! The application can selectively activate or deactivate Action Sets.
  119. //! This is possible thanks to the public method SetActionSetState().
  120. //! Each time an Action Set is activated or deactivated this function is called
  121. //! to keep @m_xrActiveActionSets up to date, which allow us to call xrSyncActions
  122. //! with the ActionSets that should be active for the current frame.
  123. void RecreateXrActiveActionSets();
  124. /////////////////////////////////////////////////
  125. /// AssetBus overrides
  126. //! The reason we don't care for OnAssetReloaded() is because in OpenXR
  127. //! once a group of ActionSets have been attached to the session, they become
  128. //! immutable. To have different action sets, the session would have to be recreated.
  129. void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
  130. void OnAssetError(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
  131. /// AssetBus overrides
  132. /////////////////////////////////////////////////
  133. XrInstance m_xrInstance = XR_NULL_HANDLE;
  134. XrSession m_xrSession = XR_NULL_HANDLE;
  135. //! Loaded Asynchronously. Once this asset is ready, the real initialization of the
  136. //! OpenXR Actions and ActionSets will occur.
  137. //! This asset is loaded once and never changes.
  138. AZ::Data::Asset<OpenXRActionSetsAsset> m_actionSetAsset;
  139. // Updated each time SyncActions is called.
  140. XrTime m_predictedDisplaytime;
  141. AZStd::string m_baseReferenceSpaceName;
  142. XrSpace m_xrBaseReferenceSpace = XR_NULL_HANDLE;
  143. //! Each actionSet in this list is guaranteed to contain at least one valid action.
  144. AZStd::vector<ActionSetInfo> m_actionSets;
  145. //! This is a flat list of all actions across all actionSets.
  146. //! An IOpenXRActions::ActionHandle is actually an index into this list.
  147. AZStd::vector<ActionInfo> m_actions;
  148. //! This set is only useful for debugging purposes, we keep track
  149. //! of all the top level user paths so we can call xrGetCurrentInteractionProfile
  150. //! each time the Session receives the event XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED.
  151. mutable AZStd::unordered_set<AZStd::string> m_topLevelUserPaths;
  152. //! 32 action sets should be enough
  153. static constexpr uint32_t MaxActionSets = 32;
  154. // Each time ChangeActionSetState or ChangeActionSetsState is called
  155. // the following lists are updated:
  156. //! Each bit is an index in @m_actionsSets
  157. AZStd::bitset<MaxActionSets> m_activeActionSets;
  158. //! Here we cache the list of OpenXR native handles for active action sets.
  159. //! This list is recreated each time RecreateXrActiveActionSets() is called.
  160. AZStd::vector<XrActiveActionSet> m_xrActiveActionSets;
  161. };
  162. }