diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index b2897f0aa52..44c4a3bc033 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -85,6 +85,12 @@ If handtracking is enabled and motion range is supported, gets the currently configured motion range for [param hand]. + + + + Returns the current state of our OpenXR session. + + @@ -216,7 +222,7 @@ - Informs our OpenXR session now has focus. + Informs our OpenXR session now has focus, e.g. output is sent to our HMD and we're receiving XR input. @@ -229,13 +235,47 @@ Informs our OpenXR session is stopping. + + + Informs our OpenXR session has been synchronized. + + - Informs our OpenXR session is now visible (output is being sent to the HMD). + Informs our OpenXR session is now visible, e.g. output is being sent to the HMD but we don't receive XR input. + + The state of the session is unknown, we haven't tried setting up OpenXR yet. + + + The initial state after the OpenXR session is created or after the session is destroyed. + + + OpenXR is ready to begin our session. [signal session_begun] is emitted when we change to this state. + + + The application has synched its frame loop with the runtime but we're not rendering anything. [signal session_synchronized] is emitted when we change to this state. + + + The application has synched its frame loop with the runtime and we're rendering output to the user, however we receive no user input. [signal session_visible] is emitted when we change to this state. + [b]Note:[/b] This is the current state just before we get the focused state, whenever the user opens a system menu, switches to another application or takes off their headset. + + + The application has synched its frame loop with the runtime, we're rendering output to the user and we're receiving XR input. [signal session_focussed] is emitted when we change to this state. + [b]Note:[/b] This is the state OpenXR will be in when the user can fully interact with your game. + + + Our session is being stopped. [signal session_stopping] is emitted when we change to this state. + + + The session is about to be lost. [signal session_loss_pending] is emitted when we change to this state. + + + The OpenXR instance is about to be destroyed and we're existing. [signal instance_exiting] is emitted when we change to this state. + Left hand. diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 51a12e772cd..4383f09f809 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -1418,15 +1418,14 @@ bool OpenXRAPI::on_state_ready() { bool OpenXRAPI::on_state_synchronized() { print_verbose("On state synchronized"); - // Just in case, see if we already have active trackers... - for (const RID &tracker : tracker_owner.get_owned_list()) { - tracker_check_profile(tracker); - } - for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { wrapper->on_state_synchronized(); } + if (xr_interface) { + xr_interface->on_state_synchronized(); + } + return true; } @@ -2075,11 +2074,10 @@ bool OpenXRAPI::poll_events() { print_verbose("OpenXR EVENT: interaction profile changed!"); XrEventDataInteractionProfileChanged *event = (XrEventDataInteractionProfileChanged *)&runtimeEvent; - - for (const RID &tracker : tracker_owner.get_owned_list()) { - tracker_check_profile(tracker, event->session); + if (event->session == session) { + // Make sure we get our interaction profile change + interaction_profile_changed = true; } - } break; default: if (!handled) { @@ -3454,8 +3452,16 @@ bool OpenXRAPI::sync_action_sets(const Vector p_active_sets) { XrResult result = xrSyncActions(session, &sync_info); if (XR_FAILED(result)) { - print_line("OpenXR: failed to sync active action sets! [", get_error_string(result), "]"); - return false; + ERR_FAIL_V_MSG(false, "OpenXR: failed to sync active action sets! [" + get_error_string(result) + "]"); + } + + if (interaction_profile_changed) { + // Just in case, see if we already have active trackers... + for (const RID &tracker : tracker_owner.get_owned_list()) { + tracker_check_profile(tracker); + } + + interaction_profile_changed = false; } return true; diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 0ee9d8e9cdc..acfd519aa44 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -272,6 +272,7 @@ private: }; RID_Owner tracker_owner; RID get_tracker_rid(XrPath p_path); + bool interaction_profile_changed = true; // If true we need to check for updates to our active_profile_rid. struct ActionSet { // Action sets define a set of actions that can be enabled together String name; // Name for this action set (i.e. "godot_action_set") @@ -420,6 +421,7 @@ public: XrInstance get_instance() const { return instance; } XrSystemId get_system_id() const { return system_id; } XrSession get_session() const { return session; } + XrSessionState get_session_state() const { return session_state; } OpenXRGraphicsExtensionWrapper *get_graphics_extension() const { return graphics_extension; } String get_runtime_name() const { return runtime_name; } String get_runtime_version() const { return runtime_version; } diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 928a8704cac..88d53120bd6 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -44,6 +44,7 @@ void OpenXRInterface::_bind_methods() { // lifecycle signals ADD_SIGNAL(MethodInfo("session_begun")); ADD_SIGNAL(MethodInfo("session_stopping")); + ADD_SIGNAL(MethodInfo("session_synchronized")); ADD_SIGNAL(MethodInfo("session_focussed")); ADD_SIGNAL(MethodInfo("session_visible")); ADD_SIGNAL(MethodInfo("session_loss_pending")); @@ -54,6 +55,9 @@ void OpenXRInterface::_bind_methods() { ADD_SIGNAL(MethodInfo("cpu_level_changed", PropertyInfo(Variant::INT, "sub_domain"), PropertyInfo(Variant::INT, "from_level"), PropertyInfo(Variant::INT, "to_level"))); ADD_SIGNAL(MethodInfo("gpu_level_changed", PropertyInfo(Variant::INT, "sub_domain"), PropertyInfo(Variant::INT, "from_level"), PropertyInfo(Variant::INT, "to_level"))); + // State + ClassDB::bind_method(D_METHOD("get_session_state"), &OpenXRInterface::get_session_state); + // Display refresh rate ClassDB::bind_method(D_METHOD("get_display_refresh_rate"), &OpenXRInterface::get_display_refresh_rate); ClassDB::bind_method(D_METHOD("set_display_refresh_rate", "refresh_rate"), &OpenXRInterface::set_display_refresh_rate); @@ -116,6 +120,16 @@ void OpenXRInterface::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_min_radius", PROPERTY_HINT_RANGE, "1.0,100.0,1.0"), "set_vrs_min_radius", "get_vrs_min_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_strength", PROPERTY_HINT_RANGE, "0.1,10.0,0.1"), "set_vrs_strength", "get_vrs_strength"); + BIND_ENUM_CONSTANT(OPENXR_SESSION_STATE_UNKNOWN); + BIND_ENUM_CONSTANT(OPENXR_SESSION_STATE_IDLE); + BIND_ENUM_CONSTANT(OPENXR_SESSION_STATE_READY); + BIND_ENUM_CONSTANT(OPENXR_SESSION_STATE_SYNCHRONIZED); + BIND_ENUM_CONSTANT(OPENXR_SESSION_STATE_VISIBLE); + BIND_ENUM_CONSTANT(OPENXR_SESSION_STATE_FOCUSED); + BIND_ENUM_CONSTANT(OPENXR_SESSION_STATE_STOPPING); + BIND_ENUM_CONSTANT(OPENXR_SESSION_STATE_LOSS_PENDING); + BIND_ENUM_CONSTANT(OPENXR_SESSION_STATE_EXITING); + BIND_ENUM_CONSTANT(HAND_LEFT); BIND_ENUM_CONSTANT(HAND_RIGHT); BIND_ENUM_CONSTANT(HAND_MAX); @@ -1375,6 +1389,10 @@ void OpenXRInterface::on_state_visible() { emit_signal(SNAME("session_visible")); } +void OpenXRInterface::on_state_synchronized() { + emit_signal(SNAME("session_synchronized")); +} + void OpenXRInterface::on_state_focused() { emit_signal(SNAME("session_focussed")); } @@ -1399,6 +1417,14 @@ void OpenXRInterface::on_refresh_rate_changes(float p_new_rate) { emit_signal(SNAME("refresh_rate_changed"), p_new_rate); } +OpenXRInterface::OpenXrSessionState OpenXRInterface::get_session_state() { + if (openxr_api) { + return (OpenXrSessionState)openxr_api->get_session_state(); + } + + return OPENXR_SESSION_STATE_UNKNOWN; +} + /** Hand tracking. */ void OpenXRInterface::set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range) { ERR_FAIL_INDEX(p_hand, HAND_MAX); diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index 8705e796e90..a4d80891a83 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -209,6 +209,7 @@ public: void on_state_ready(); void on_state_visible(); void on_state_focused(); + void on_state_synchronized(); void on_state_stopping(); void on_state_loss_pending(); void on_state_exiting(); @@ -216,6 +217,21 @@ public: void on_refresh_rate_changes(float p_new_rate); void tracker_profile_changed(RID p_tracker, RID p_interaction_profile); + /** Session */ + enum OpenXrSessionState { // Should mirror XrSessionState + OPENXR_SESSION_STATE_UNKNOWN = 0, + OPENXR_SESSION_STATE_IDLE = 1, + OPENXR_SESSION_STATE_READY = 2, + OPENXR_SESSION_STATE_SYNCHRONIZED = 3, + OPENXR_SESSION_STATE_VISIBLE = 4, + OPENXR_SESSION_STATE_FOCUSED = 5, + OPENXR_SESSION_STATE_STOPPING = 6, + OPENXR_SESSION_STATE_LOSS_PENDING = 7, + OPENXR_SESSION_STATE_EXITING = 8, + }; + + OpenXrSessionState get_session_state(); + /** Hand tracking. */ enum Hand { HAND_LEFT, @@ -321,6 +337,7 @@ public: ~OpenXRInterface(); }; +VARIANT_ENUM_CAST(OpenXRInterface::OpenXrSessionState) VARIANT_ENUM_CAST(OpenXRInterface::Hand) VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange) VARIANT_ENUM_CAST(OpenXRInterface::HandTrackedSource)