summaryrefslogtreecommitdiffstats
path: root/modules/openxr/openxr_api.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/openxr/openxr_api.cpp')
-rw-r--r--modules/openxr/openxr_api.cpp280
1 files changed, 188 insertions, 92 deletions
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 32512070d6..c67be5a2b3 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -54,6 +54,7 @@
#endif
#include "extensions/openxr_composition_layer_depth_extension.h"
+#include "extensions/openxr_debug_utils_extension.h"
#include "extensions/openxr_eye_gaze_interaction.h"
#include "extensions/openxr_fb_display_refresh_rate_extension.h"
#include "extensions/openxr_fb_foveation_extension.h"
@@ -270,17 +271,16 @@ OpenXRAPI *OpenXRAPI::singleton = nullptr;
Vector<OpenXRExtensionWrapper *> OpenXRAPI::registered_extension_wrappers;
bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) {
- // @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled"
-
- if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) {
- // Disabled for now, using XR inside of the editor we'll be working on during the coming months.
- return false;
- } else {
- if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
- return GLOBAL_GET("xr/openxr/enabled");
+ if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
+ if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) {
+ // For now, don't start OpenXR when the editor starts up. In the future, this may change
+ // if we want to integrate more XR features into the editor experience.
+ return false;
} else {
- return XRServer::get_xr_mode() == XRServer::XRMODE_ON;
+ return GLOBAL_GET("xr/openxr/enabled");
}
+ } else {
+ return XRServer::get_xr_mode() == XRServer::XRMODE_ON;
}
}
@@ -316,6 +316,46 @@ String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const {
return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format));
}
+void OpenXRAPI::set_object_name(XrObjectType p_object_type, uint64_t p_object_handle, const String &p_object_name) {
+ OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
+ if (!debug_utils || !debug_utils->get_active()) {
+ // Not enabled/active? Ignore.
+ return;
+ }
+
+ debug_utils->set_object_name(p_object_type, p_object_handle, p_object_name.utf8().get_data());
+}
+
+void OpenXRAPI::begin_debug_label_region(const String &p_label_name) {
+ OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
+ if (!debug_utils || !debug_utils->get_active()) {
+ // Not enabled/active? Ignore.
+ return;
+ }
+
+ debug_utils->begin_debug_label_region(p_label_name.utf8().get_data());
+}
+
+void OpenXRAPI::end_debug_label_region() {
+ OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
+ if (!debug_utils || !debug_utils->get_active()) {
+ // Not enabled/active? Ignore.
+ return;
+ }
+
+ debug_utils->end_debug_label_region();
+}
+
+void OpenXRAPI::insert_debug_label(const String &p_label_name) {
+ OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
+ if (!debug_utils || !debug_utils->get_active()) {
+ // Not enabled/active? Ignore.
+ return;
+ }
+
+ debug_utils->insert_debug_label(p_label_name.utf8().get_data());
+}
+
bool OpenXRAPI::load_layer_properties() {
// This queries additional layers that are available and can be initialized when we create our OpenXR instance
if (layer_properties != nullptr) {
@@ -516,16 +556,13 @@ bool OpenXRAPI::create_instance() {
extension_ptrs.push_back(enabled_extensions[i].get_data());
}
- // Get our project name
- String project_name = GLOBAL_GET("application/config/name");
-
// Create our OpenXR instance
XrApplicationInfo application_info{
- "", // applicationName, we'll set this down below
+ "Godot Engine", // applicationName, if we're running a game we'll update this down below.
1, // applicationVersion, we don't currently have this
- "Godot Game Engine", // engineName
+ "Godot Engine", // engineName
VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH, // engineVersion 4.0 -> 40000, 4.0.1 -> 40001, 4.1 -> 40100, etc.
- XR_CURRENT_API_VERSION // apiVersion
+ XR_API_VERSION_1_0 // apiVersion
};
void *next_pointer = nullptr;
@@ -547,7 +584,11 @@ bool OpenXRAPI::create_instance() {
extension_ptrs.ptr() // enabledExtensionNames
};
- copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE);
+ // Get our project name
+ String project_name = GLOBAL_GET("application/config/name");
+ if (!project_name.is_empty()) {
+ copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE);
+ }
XrResult result = xrCreateInstance(&instance_create_info, &instance);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "Failed to create XR instance.");
@@ -707,13 +748,6 @@ bool OpenXRAPI::load_supported_environmental_blend_modes() {
print_verbose(String("OpenXR: Found environmental blend mode ") + OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_modes[i]));
}
- // Check value we loaded at startup...
- if (!is_environment_blend_mode_supported(environment_blend_mode)) {
- print_verbose(String("OpenXR: ") + OpenXRUtil::get_environment_blend_mode_name(environment_blend_mode) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_modes[0]));
-
- environment_blend_mode = supported_environment_blend_modes[0];
- }
-
return true;
}
@@ -833,10 +867,21 @@ bool OpenXRAPI::create_session() {
return false;
}
+ set_object_name(XR_OBJECT_TYPE_SESSION, uint64_t(session), "Main Godot OpenXR Session");
+
+ begin_debug_label_region("Godot session active");
+
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_session_created(session);
}
+ // Check our environment blend mode. This needs to happen after we call `on_session_created()`
+ // on the extension wrappers, so they can emulate alpha blend mode.
+ if (!set_environment_blend_mode(environment_blend_mode)) {
+ print_verbose(String("OpenXR: ") + OpenXRUtil::get_environment_blend_mode_name(environment_blend_mode) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_modes[0]));
+ set_environment_blend_mode(supported_environment_blend_modes[0]);
+ }
+
return true;
}
@@ -902,6 +947,51 @@ bool OpenXRAPI::setup_play_space() {
new_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
will_emulate_local_floor = true;
+
+ if (local_floor_emulation.local_space == XR_NULL_HANDLE) {
+ XrReferenceSpaceCreateInfo create_info = {
+ XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
+ nullptr, // next
+ XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
+ identityPose, // poseInReferenceSpace
+ };
+
+ XrResult result = xrCreateReferenceSpace(session, &create_info, &local_floor_emulation.local_space);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to create LOCAL space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
+ will_emulate_local_floor = false;
+ }
+
+ set_object_name(XR_OBJECT_TYPE_SPACE, uint64_t(local_floor_emulation.local_space), "Emulation local space");
+ }
+
+ if (local_floor_emulation.stage_space == XR_NULL_HANDLE) {
+ XrReferenceSpaceCreateInfo create_info = {
+ XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
+ nullptr, // next
+ XR_REFERENCE_SPACE_TYPE_STAGE, // referenceSpaceType
+ identityPose, // poseInReferenceSpace
+ };
+
+ XrResult result = xrCreateReferenceSpace(session, &create_info, &local_floor_emulation.stage_space);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to create STAGE space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
+ will_emulate_local_floor = false;
+ }
+
+ set_object_name(XR_OBJECT_TYPE_SPACE, uint64_t(local_floor_emulation.stage_space), "Emulation stage space");
+ }
+
+ if (!will_emulate_local_floor) {
+ if (local_floor_emulation.local_space != XR_NULL_HANDLE) {
+ xrDestroySpace(local_floor_emulation.local_space);
+ local_floor_emulation.local_space = XR_NULL_HANDLE;
+ }
+ if (local_floor_emulation.stage_space != XR_NULL_HANDLE) {
+ xrDestroySpace(local_floor_emulation.stage_space);
+ local_floor_emulation.stage_space = XR_NULL_HANDLE;
+ }
+ }
} else {
// Fallback on LOCAL, which all OpenXR runtimes are required to support.
print_verbose(String("OpenXR: ") + OpenXRUtil::get_reference_space_name(requested_reference_space) + String(" isn't supported, defaulting to LOCAL space."));
@@ -931,16 +1021,13 @@ bool OpenXRAPI::setup_play_space() {
play_space = new_play_space;
reference_space = new_reference_space;
- emulating_local_floor = will_emulate_local_floor;
- if (emulating_local_floor) {
- // We'll use the STAGE space to get the floor height, but we can't do that until
- // after xrWaitFrame(), so just set this flag for now.
- // Render state will be updated then.
- should_reset_emulated_floor_height = true;
- } else {
- // Update render state so this play space is used rendering the upcoming frame.
- set_render_play_space(play_space);
- }
+ set_object_name(XR_OBJECT_TYPE_SPACE, uint64_t(play_space), "Play space");
+
+ local_floor_emulation.enabled = will_emulate_local_floor;
+ local_floor_emulation.should_reset_floor_height = will_emulate_local_floor;
+
+ // Update render state so this play space is used rendering the upcoming frame.
+ set_render_play_space(play_space);
return true;
}
@@ -971,67 +1058,45 @@ bool OpenXRAPI::setup_view_space() {
return false;
}
+ set_object_name(XR_OBJECT_TYPE_SPACE, uint64_t(view_space), "View space");
+
return true;
}
bool OpenXRAPI::reset_emulated_floor_height() {
- ERR_FAIL_COND_V(!emulating_local_floor, false);
-
- // This is based on the example code in the OpenXR spec which shows how to
- // emulate LOCAL_FLOOR if it's not supported.
- // See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_local_floor
+ ERR_FAIL_COND_V(!local_floor_emulation.enabled, false);
+ ERR_FAIL_COND_V(local_floor_emulation.local_space == XR_NULL_HANDLE, false);
+ ERR_FAIL_COND_V(local_floor_emulation.stage_space == XR_NULL_HANDLE, false);
XrResult result;
- XrPosef identityPose = {
- { 0.0, 0.0, 0.0, 1.0 },
- { 0.0, 0.0, 0.0 }
- };
-
- XrSpace local_space = XR_NULL_HANDLE;
- XrSpace stage_space = XR_NULL_HANDLE;
-
- XrReferenceSpaceCreateInfo create_info = {
- XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
- nullptr, // next
- XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
- identityPose, // poseInReferenceSpace
- };
-
- result = xrCreateReferenceSpace(session, &create_info, &local_space);
- if (XR_FAILED(result)) {
- print_line("OpenXR: Failed to create LOCAL space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
- return false;
- }
-
- create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
- result = xrCreateReferenceSpace(session, &create_info, &stage_space);
- if (XR_FAILED(result)) {
- print_line("OpenXR: Failed to create STAGE space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
- xrDestroySpace(local_space);
- return false;
- }
-
XrSpaceLocation stage_location = {
XR_TYPE_SPACE_LOCATION, // type
nullptr, // next
0, // locationFlags
- identityPose, // pose
+ { { 0.0, 0.0, 0.0, 1.0 }, { 0.0, 0.0, 0.0 } }, // pose
};
- result = xrLocateSpace(stage_space, local_space, get_predicted_display_time(), &stage_location);
-
- xrDestroySpace(local_space);
- xrDestroySpace(stage_space);
+ result = xrLocateSpace(local_floor_emulation.stage_space, local_floor_emulation.local_space, get_predicted_display_time(), &stage_location);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to locate STAGE space in LOCAL space, in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
return false;
}
+ XrPosef pose = {
+ { 0.0, 0.0, 0.0, 1.0 },
+ { 0.0, stage_location.pose.position.y, 0.0 }
+ };
+
+ XrReferenceSpaceCreateInfo create_info = {
+ XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
+ nullptr, // next
+ XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
+ pose, // poseInReferenceSpace
+ };
+
XrSpace new_play_space;
- create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
- create_info.poseInReferenceSpace.position.y = stage_location.pose.position.y;
result = xrCreateReferenceSpace(session, &create_info, &new_play_space);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to recreate emulated LOCAL_FLOOR play space with latest floor estimate [", get_error_string(result), "]");
@@ -1169,6 +1234,8 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) {
if (!render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].create(0, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, color_swapchain_format, render_state.main_swapchain_size.width, render_state.main_swapchain_size.height, sample_count, view_count)) {
return false;
}
+
+ set_object_name(XR_OBJECT_TYPE_SWAPCHAIN, uint64_t(render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain()), "Main color swapchain");
}
// We create our depth swapchain if:
@@ -1179,6 +1246,8 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) {
if (!render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].create(0, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, depth_swapchain_format, render_state.main_swapchain_size.width, render_state.main_swapchain_size.height, sample_count, view_count)) {
return false;
}
+
+ set_object_name(XR_OBJECT_TYPE_SWAPCHAIN, uint64_t(render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_swapchain()), "Main depth swapchain");
}
// We create our velocity swapchain if:
@@ -1220,6 +1289,10 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) {
}
};
+ for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
+ wrapper->on_main_swapchains_created();
+ }
+
return true;
};
@@ -1271,6 +1344,16 @@ void OpenXRAPI::destroy_session() {
xrDestroySpace(view_space);
view_space = XR_NULL_HANDLE;
}
+ if (local_floor_emulation.local_space != XR_NULL_HANDLE) {
+ xrDestroySpace(local_floor_emulation.local_space);
+ local_floor_emulation.local_space = XR_NULL_HANDLE;
+ }
+ if (local_floor_emulation.stage_space != XR_NULL_HANDLE) {
+ xrDestroySpace(local_floor_emulation.stage_space);
+ local_floor_emulation.stage_space = XR_NULL_HANDLE;
+ }
+ local_floor_emulation.enabled = false;
+ local_floor_emulation.should_reset_floor_height = false;
if (supported_reference_spaces != nullptr) {
// free previous results
@@ -1283,6 +1366,8 @@ void OpenXRAPI::destroy_session() {
wrapper->on_session_destroyed();
}
+ end_debug_label_region();
+
xrDestroySession(session);
session = XR_NULL_HANDLE;
}
@@ -1433,6 +1518,10 @@ void OpenXRAPI::set_form_factor(XrFormFactor p_form_factor) {
form_factor = p_form_factor;
}
+uint32_t OpenXRAPI::get_view_count() {
+ return view_count;
+}
+
void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configuration) {
ERR_FAIL_COND(is_initialized());
@@ -1707,8 +1796,12 @@ void OpenXRAPI::cleanup_extension_wrappers() {
XrHandTrackerEXT OpenXRAPI::get_hand_tracker(int p_hand_index) {
ERR_FAIL_INDEX_V(p_hand_index, OpenXRHandTrackingExtension::HandTrackedHands::OPENXR_MAX_TRACKED_HANDS, XR_NULL_HANDLE);
+
+ OpenXRHandTrackingExtension *hand_tracking = OpenXRHandTrackingExtension::get_singleton();
+ ERR_FAIL_NULL_V(hand_tracking, XR_NULL_HANDLE);
+
OpenXRHandTrackingExtension::HandTrackedHands hand = static_cast<OpenXRHandTrackingExtension::HandTrackedHands>(p_hand_index);
- return OpenXRHandTrackingExtension::get_singleton()->get_hand_tracker(hand)->hand_tracker;
+ return hand_tracking->get_hand_tracker(hand)->hand_tracker;
}
Size2 OpenXRAPI::get_recommended_target_size() {
@@ -1888,15 +1981,6 @@ bool OpenXRAPI::poll_events() {
// We probably didn't poll fast enough, just output warning
WARN_PRINT("OpenXR EVENT: " + itos(event->lostEventCount) + " event data lost!");
} break;
- case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR: {
- // XrEventDataVisibilityMaskChangedKHR *event = (XrEventDataVisibilityMaskChangedKHR *)&runtimeEvent;
-
- // TODO implement this in the future, we should call xrGetVisibilityMaskKHR to obtain a mask,
- // this will allow us to prevent rendering the part of our view which is never displayed giving us
- // a decent performance improvement.
-
- print_verbose("OpenXR EVENT: STUB: visibility mask changed");
- } break;
case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: {
XrEventDataInstanceLossPending *event = (XrEventDataInstanceLossPending *)&runtimeEvent;
@@ -1949,8 +2033,8 @@ bool OpenXRAPI::poll_events() {
XrEventDataReferenceSpaceChangePending *event = (XrEventDataReferenceSpaceChangePending *)&runtimeEvent;
print_verbose(String("OpenXR EVENT: reference space type ") + OpenXRUtil::get_reference_space_name(event->referenceSpaceType) + " change pending!");
- if (emulating_local_floor) {
- should_reset_emulated_floor_height = true;
+ if (local_floor_emulation.enabled) {
+ local_floor_emulation.should_reset_floor_height = true;
}
if (event->poseValid && xr_interface) {
xr_interface->on_pose_recentered();
@@ -2093,16 +2177,18 @@ bool OpenXRAPI::process() {
set_render_display_info(frame_state.predictedDisplayTime, frame_state.shouldRender);
+ // This is before setup_play_space() to ensure that it happens on the frame after
+ // the play space has been created.
+ if (unlikely(local_floor_emulation.should_reset_floor_height && !play_space_is_dirty)) {
+ reset_emulated_floor_height();
+ local_floor_emulation.should_reset_floor_height = false;
+ }
+
if (unlikely(play_space_is_dirty)) {
setup_play_space();
play_space_is_dirty = false;
}
- if (unlikely(should_reset_emulated_floor_height)) {
- reset_emulated_floor_height();
- should_reset_emulated_floor_height = false;
- }
-
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_process();
}
@@ -2188,6 +2274,9 @@ void OpenXRAPI::pre_render() {
}
}
+ // We should get our frame no from the rendering server, but this will do.
+ begin_debug_label_region(String("Session Frame ") + String::num_uint64(++render_state.frame));
+
// let's start our frame..
XrFrameBeginInfo frame_begin_info = {
XR_TYPE_FRAME_BEGIN_INFO, // type
@@ -2306,6 +2395,8 @@ void OpenXRAPI::end_frame() {
return;
}
+ end_debug_label_region(); // Session frame #
+
// neither eye is rendered
return;
}
@@ -2380,6 +2471,8 @@ void OpenXRAPI::end_frame() {
print_line("OpenXR: failed to end frame! [", get_error_string(result), "]");
return;
}
+
+ end_debug_label_region(); // Session frame #
}
float OpenXRAPI::get_display_refresh_rate() const {
@@ -2490,7 +2583,6 @@ OpenXRAPI::OpenXRAPI() {
if (Engine::get_singleton()->is_editor_hint()) {
// Enabled OpenXR in the editor? Adjust our settings for the editor
-
} else {
// Load settings from project settings
int form_factor_setting = GLOBAL_GET("xr/openxr/form_factor");
@@ -2795,6 +2887,8 @@ RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_n
return RID();
}
+ set_object_name(XR_OBJECT_TYPE_ACTION_SET, uint64_t(action_set.handle), p_name);
+
return action_set_owner.make_rid(action_set);
}
@@ -2970,6 +3064,8 @@ RID OpenXRAPI::action_create(RID p_action_set, const String p_name, const String
return RID();
}
+ set_object_name(XR_OBJECT_TYPE_ACTION, uint64_t(action.handle), p_name);
+
return action_owner.make_rid(action);
}