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)