OpenXR: Add access to session state and change interaction profile update.

This commit is contained in:
Bastiaan Olij 2025-06-17 17:36:38 +10:00
parent 46c495ca21
commit df06aa8392
5 changed files with 104 additions and 13 deletions

View file

@ -85,6 +85,12 @@
If handtracking is enabled and motion range is supported, gets the currently configured motion range for [param hand]. If handtracking is enabled and motion range is supported, gets the currently configured motion range for [param hand].
</description> </description>
</method> </method>
<method name="get_session_state">
<return type="int" enum="OpenXRInterface.OpenXrSessionState" />
<description>
Returns the current state of our OpenXR session.
</description>
</method>
<method name="is_action_set_active" qualifiers="const"> <method name="is_action_set_active" qualifiers="const">
<return type="bool" /> <return type="bool" />
<param index="0" name="name" type="String" /> <param index="0" name="name" type="String" />
@ -216,7 +222,7 @@
</signal> </signal>
<signal name="session_focussed"> <signal name="session_focussed">
<description> <description>
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.
</description> </description>
</signal> </signal>
<signal name="session_loss_pending"> <signal name="session_loss_pending">
@ -229,13 +235,47 @@
Informs our OpenXR session is stopping. Informs our OpenXR session is stopping.
</description> </description>
</signal> </signal>
<signal name="session_synchronized">
<description>
Informs our OpenXR session has been synchronized.
</description>
</signal>
<signal name="session_visible"> <signal name="session_visible">
<description> <description>
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.
</description> </description>
</signal> </signal>
</signals> </signals>
<constants> <constants>
<constant name="OPENXR_SESSION_STATE_UNKNOWN" value="0" enum="OpenXrSessionState">
The state of the session is unknown, we haven't tried setting up OpenXR yet.
</constant>
<constant name="OPENXR_SESSION_STATE_IDLE" value="1" enum="OpenXrSessionState">
The initial state after the OpenXR session is created or after the session is destroyed.
</constant>
<constant name="OPENXR_SESSION_STATE_READY" value="2" enum="OpenXrSessionState">
OpenXR is ready to begin our session. [signal session_begun] is emitted when we change to this state.
</constant>
<constant name="OPENXR_SESSION_STATE_SYNCHRONIZED" value="3" enum="OpenXrSessionState">
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.
</constant>
<constant name="OPENXR_SESSION_STATE_VISIBLE" value="4" enum="OpenXrSessionState">
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.
</constant>
<constant name="OPENXR_SESSION_STATE_FOCUSED" value="5" enum="OpenXrSessionState">
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.
</constant>
<constant name="OPENXR_SESSION_STATE_STOPPING" value="6" enum="OpenXrSessionState">
Our session is being stopped. [signal session_stopping] is emitted when we change to this state.
</constant>
<constant name="OPENXR_SESSION_STATE_LOSS_PENDING" value="7" enum="OpenXrSessionState">
The session is about to be lost. [signal session_loss_pending] is emitted when we change to this state.
</constant>
<constant name="OPENXR_SESSION_STATE_EXITING" value="8" enum="OpenXrSessionState">
The OpenXR instance is about to be destroyed and we're existing. [signal instance_exiting] is emitted when we change to this state.
</constant>
<constant name="HAND_LEFT" value="0" enum="Hand"> <constant name="HAND_LEFT" value="0" enum="Hand">
Left hand. Left hand.
</constant> </constant>

View file

@ -1418,15 +1418,14 @@ bool OpenXRAPI::on_state_ready() {
bool OpenXRAPI::on_state_synchronized() { bool OpenXRAPI::on_state_synchronized() {
print_verbose("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) { for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_state_synchronized(); wrapper->on_state_synchronized();
} }
if (xr_interface) {
xr_interface->on_state_synchronized();
}
return true; return true;
} }
@ -2075,11 +2074,10 @@ bool OpenXRAPI::poll_events() {
print_verbose("OpenXR EVENT: interaction profile changed!"); print_verbose("OpenXR EVENT: interaction profile changed!");
XrEventDataInteractionProfileChanged *event = (XrEventDataInteractionProfileChanged *)&runtimeEvent; XrEventDataInteractionProfileChanged *event = (XrEventDataInteractionProfileChanged *)&runtimeEvent;
if (event->session == session) {
for (const RID &tracker : tracker_owner.get_owned_list()) { // Make sure we get our interaction profile change
tracker_check_profile(tracker, event->session); interaction_profile_changed = true;
} }
} break; } break;
default: default:
if (!handled) { if (!handled) {
@ -3454,8 +3452,16 @@ bool OpenXRAPI::sync_action_sets(const Vector<RID> p_active_sets) {
XrResult result = xrSyncActions(session, &sync_info); XrResult result = xrSyncActions(session, &sync_info);
if (XR_FAILED(result)) { if (XR_FAILED(result)) {
print_line("OpenXR: failed to sync active action sets! [", get_error_string(result), "]"); ERR_FAIL_V_MSG(false, "OpenXR: failed to sync active action sets! [" + get_error_string(result) + "]");
return false; }
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; return true;

View file

@ -272,6 +272,7 @@ private:
}; };
RID_Owner<Tracker, true> tracker_owner; RID_Owner<Tracker, true> tracker_owner;
RID get_tracker_rid(XrPath p_path); 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 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") String name; // Name for this action set (i.e. "godot_action_set")
@ -420,6 +421,7 @@ public:
XrInstance get_instance() const { return instance; } XrInstance get_instance() const { return instance; }
XrSystemId get_system_id() const { return system_id; } XrSystemId get_system_id() const { return system_id; }
XrSession get_session() const { return session; } XrSession get_session() const { return session; }
XrSessionState get_session_state() const { return session_state; }
OpenXRGraphicsExtensionWrapper *get_graphics_extension() const { return graphics_extension; } OpenXRGraphicsExtensionWrapper *get_graphics_extension() const { return graphics_extension; }
String get_runtime_name() const { return runtime_name; } String get_runtime_name() const { return runtime_name; }
String get_runtime_version() const { return runtime_version; } String get_runtime_version() const { return runtime_version; }

View file

@ -44,6 +44,7 @@ void OpenXRInterface::_bind_methods() {
// lifecycle signals // lifecycle signals
ADD_SIGNAL(MethodInfo("session_begun")); ADD_SIGNAL(MethodInfo("session_begun"));
ADD_SIGNAL(MethodInfo("session_stopping")); ADD_SIGNAL(MethodInfo("session_stopping"));
ADD_SIGNAL(MethodInfo("session_synchronized"));
ADD_SIGNAL(MethodInfo("session_focussed")); ADD_SIGNAL(MethodInfo("session_focussed"));
ADD_SIGNAL(MethodInfo("session_visible")); ADD_SIGNAL(MethodInfo("session_visible"));
ADD_SIGNAL(MethodInfo("session_loss_pending")); 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("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"))); 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 // Display refresh rate
ClassDB::bind_method(D_METHOD("get_display_refresh_rate"), &OpenXRInterface::get_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); 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_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"); 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_LEFT);
BIND_ENUM_CONSTANT(HAND_RIGHT); BIND_ENUM_CONSTANT(HAND_RIGHT);
BIND_ENUM_CONSTANT(HAND_MAX); BIND_ENUM_CONSTANT(HAND_MAX);
@ -1375,6 +1389,10 @@ void OpenXRInterface::on_state_visible() {
emit_signal(SNAME("session_visible")); emit_signal(SNAME("session_visible"));
} }
void OpenXRInterface::on_state_synchronized() {
emit_signal(SNAME("session_synchronized"));
}
void OpenXRInterface::on_state_focused() { void OpenXRInterface::on_state_focused() {
emit_signal(SNAME("session_focussed")); 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); 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. */ /** Hand tracking. */
void OpenXRInterface::set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range) { void OpenXRInterface::set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range) {
ERR_FAIL_INDEX(p_hand, HAND_MAX); ERR_FAIL_INDEX(p_hand, HAND_MAX);

View file

@ -209,6 +209,7 @@ public:
void on_state_ready(); void on_state_ready();
void on_state_visible(); void on_state_visible();
void on_state_focused(); void on_state_focused();
void on_state_synchronized();
void on_state_stopping(); void on_state_stopping();
void on_state_loss_pending(); void on_state_loss_pending();
void on_state_exiting(); void on_state_exiting();
@ -216,6 +217,21 @@ public:
void on_refresh_rate_changes(float p_new_rate); void on_refresh_rate_changes(float p_new_rate);
void tracker_profile_changed(RID p_tracker, RID p_interaction_profile); 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. */ /** Hand tracking. */
enum Hand { enum Hand {
HAND_LEFT, HAND_LEFT,
@ -321,6 +337,7 @@ public:
~OpenXRInterface(); ~OpenXRInterface();
}; };
VARIANT_ENUM_CAST(OpenXRInterface::OpenXrSessionState)
VARIANT_ENUM_CAST(OpenXRInterface::Hand) VARIANT_ENUM_CAST(OpenXRInterface::Hand)
VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange) VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange)
VARIANT_ENUM_CAST(OpenXRInterface::HandTrackedSource) VARIANT_ENUM_CAST(OpenXRInterface::HandTrackedSource)