Skip to content

Commit

Permalink
Add support for the debug utils extension in OpenXR
Browse files Browse the repository at this point in the history
  • Loading branch information
BastiaanOlij committed Aug 6, 2024
1 parent 3978628 commit 416e0da
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 0 deletions.
3 changes: 3 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2924,6 +2924,9 @@
<member name="xr/openxr/environment_blend_mode" type="int" setter="" getter="" default="&quot;0&quot;">
Specify how OpenXR should blend in the environment. This is specific to certain AR and passthrough devices where camera images are blended in by the XR compositor.
</member>
<member name="xr/openxr/extensions/debug_utils" type="int" setter="" getter="" default="&quot;0&quot;">
Enables debug utilities on XR runtimes that supports the debug utils extension. Sets the maximum severity being reported (0 = disabled, 1 = error, 2 = warning, 3 = info, 4 = verbose).
</member>
<member name="xr/openxr/extensions/eye_gaze_interaction" type="bool" setter="" getter="" default="false">
Specify whether to enable eye tracking for this project. Depending on the platform, additional export configuration may be needed.
</member>
Expand Down
1 change: 1 addition & 0 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2437,6 +2437,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_BASIC("xr/openxr/startup_alert", true);

// OpenXR project extensions settings.
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/extensions/debug_utils", PROPERTY_HINT_ENUM, "Disabled,Error,Warning,Info,Verbose"), "0");
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking", true);
GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/hand_interaction_profile", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/eye_gaze_interaction", false);
Expand Down
209 changes: 209 additions & 0 deletions modules/openxr/extensions/openxr_debug_utils_extension.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/**************************************************************************/
/* openxr_debug_utils_extension.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

#include "openxr_debug_utils_extension.h"

#include "../openxr_api.h"
#include "core/config/project_settings.h"
#include "core/string/print_string.h"

#include <openxr/openxr.h>

OpenXRDebugUtilsExtension *OpenXRDebugUtilsExtension::singleton = nullptr;

OpenXRDebugUtilsExtension *OpenXRDebugUtilsExtension::get_singleton() {
return singleton;
}

OpenXRDebugUtilsExtension::OpenXRDebugUtilsExtension() {
singleton = this;
}

OpenXRDebugUtilsExtension::~OpenXRDebugUtilsExtension() {
singleton = nullptr;
}

HashMap<String, bool *> OpenXRDebugUtilsExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;

request_extensions[XR_EXT_DEBUG_UTILS_EXTENSION_NAME] = &debug_utils_ext;

return request_extensions;
}

void OpenXRDebugUtilsExtension::on_instance_created(const XrInstance p_instance) {
if (debug_utils_ext) {
EXT_INIT_XR_FUNC(xrCreateDebugUtilsMessengerEXT);
EXT_INIT_XR_FUNC(xrDestroyDebugUtilsMessengerEXT);
EXT_INIT_XR_FUNC(xrSetDebugUtilsObjectNameEXT);

debug_utils_ext = xrCreateDebugUtilsMessengerEXT_ptr && xrDestroyDebugUtilsMessengerEXT_ptr && xrSetDebugUtilsObjectNameEXT_ptr;
}

// On successful init, setup our default messenger.
if (debug_utils_ext) {
int max_severity = GLOBAL_GET("xr/openxr/extensions/debug_utils");
XrDebugUtilsMessageSeverityFlagsEXT message_severities = 0;

if (max_severity >= 1) {
message_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
}
if (max_severity >= 2) {
message_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
}
if (max_severity >= 3) {
message_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
}
if (max_severity >= 4) {
message_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
}

XrDebugUtilsMessengerCreateInfoEXT callback_info = {
XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, // type
nullptr, // next
message_severities, // messageSeverities
XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT, // messageTypes
&OpenXRDebugUtilsExtension::_debug_callback, // userCallback
nullptr, // userData
};

XrResult result = xrCreateDebugUtilsMessengerEXT(p_instance, &callback_info, &default_messenger);
if (XR_FAILED(result)) {
ERR_PRINT("OpenXR: Failed to create debug callback [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
}
}
}

void OpenXRDebugUtilsExtension::on_instance_destroyed() {
if (default_messenger != XR_NULL_HANDLE) {
XrResult result = xrDestroyDebugUtilsMessengerEXT(default_messenger);
if (XR_FAILED(result)) {
ERR_PRINT("OpenXR: Failed to destroy debug callback [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
}

default_messenger = XR_NULL_HANDLE;
}

xrCreateDebugUtilsMessengerEXT_ptr = nullptr;
xrDestroyDebugUtilsMessengerEXT_ptr = nullptr;
xrSetDebugUtilsObjectNameEXT_ptr = nullptr;
debug_utils_ext = false;
}

bool OpenXRDebugUtilsExtension::get_active() {
return debug_utils_ext;
}

void OpenXRDebugUtilsExtension::set_object_name(XrObjectType p_object_type, uint64_t p_object_handle, const char *p_object_name) {
ERR_FAIL_COND(!debug_utils_ext);
ERR_FAIL_NULL(xrSetDebugUtilsObjectNameEXT_ptr);

const XrDebugUtilsObjectNameInfoEXT space_name_info = {
XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, // type
nullptr, // next
p_object_type, // objectType
p_object_handle, // objectHandle
p_object_name, // objectName
};

XrResult result = xrSetDebugUtilsObjectNameEXT_ptr(OpenXRAPI::get_singleton()->get_instance(), &space_name_info);
if (XR_FAILED(result)) {
ERR_PRINT("OpenXR: Failed to set object name [" + OpenXRAPI::get_singleton()->get_error_string(result) + "]");
}
}

XrBool32 OpenXRDebugUtilsExtension::_debug_callback(XrDebugUtilsMessageSeverityFlagsEXT p_message_severity, XrDebugUtilsMessageTypeFlagsEXT p_message_types, const XrDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data) {
OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();

if (debug_utils) {
return debug_utils->debug_callback(p_message_severity, p_message_types, p_callback_data, p_user_data);
}

return XR_FALSE;
}

XrBool32 OpenXRDebugUtilsExtension::debug_callback(XrDebugUtilsMessageSeverityFlagsEXT p_message_severity, XrDebugUtilsMessageTypeFlagsEXT p_message_types, const XrDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data) {
String msg;

ERR_FAIL_NULL_V(p_callback_data, XR_FALSE);

if (p_message_types == XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) {
msg = ", type: General";
} else if (p_message_types == XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) {
msg = ", type: Validation";
} else if (p_message_types == XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) {
msg = ", type: Performance";
} else if (p_message_types == XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT) {
msg = ", type: Conformance";
} else {
msg = ", type: Unknown (" + String::num_uint64(p_message_types) + ")";
}

if (p_callback_data->functionName) {
msg += ", function Name: " + String(p_callback_data->functionName);
}
if (p_callback_data->messageId) {
msg += "\nMessage ID: " + String(p_callback_data->messageId);
}
if (p_callback_data->message) {
msg += "\nMessage: " + String(p_callback_data->message);
}

if (p_callback_data->objectCount > 0) {
String objects;

for (uint32_t i = 0; i < p_callback_data->objectCount; i++) {
if (!objects.is_empty()) {
objects += ", ";
}
objects += p_callback_data->objects[i].objectName;
}

msg += "\nObjects: " + objects;
}
/*
TODO: add in:
uint32_t sessionLabelCount;
XrDebugUtilsLabelEXT* sessionLabels;
*/

if (p_message_severity == XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
ERR_PRINT("OpenXR: Severity: Error" + msg);
} else if (p_message_severity == XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
WARN_PRINT("OpenXR: Severity: Warning" + msg);
} else if (p_message_severity == XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
print_line("OpenXR: Severity: Info" + msg);
} else if (p_message_severity == XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
// This is a bit double because we won't output this unless verbose messaging in Godot is on.
print_verbose("OpenXR: Severity: Verbose" + msg);
}

return XR_FALSE;
}
70 changes: 70 additions & 0 deletions modules/openxr/extensions/openxr_debug_utils_extension.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**************************************************************************/
/* openxr_debug_utils_extension.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

#ifndef OPENXR_DEBUG_UTILS_EXTENSION_H
#define OPENXR_DEBUG_UTILS_EXTENSION_H

#include "../util.h"
#include "openxr_extension_wrapper.h"

class OpenXRDebugUtilsExtension : public OpenXRExtensionWrapper {
public:
static OpenXRDebugUtilsExtension *get_singleton();

OpenXRDebugUtilsExtension();
virtual ~OpenXRDebugUtilsExtension() override;

virtual HashMap<String, bool *> get_requested_extensions() override;
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void on_instance_destroyed() override;

bool get_active();

void set_object_name(XrObjectType p_object_type, uint64_t p_object_handle, const char *p_object_name);

private:
static OpenXRDebugUtilsExtension *singleton;

// related extensions
bool debug_utils_ext = false;

// debug handlers
XrDebugUtilsMessengerEXT default_messenger = XR_NULL_HANDLE;

static XrBool32 _debug_callback(XrDebugUtilsMessageSeverityFlagsEXT p_message_severity, XrDebugUtilsMessageTypeFlagsEXT p_message_types, const XrDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data);
XrBool32 debug_callback(XrDebugUtilsMessageSeverityFlagsEXT p_message_severity, XrDebugUtilsMessageTypeFlagsEXT p_message_types, const XrDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data);

// OpenXR API call wrappers
EXT_PROTO_XRRESULT_FUNC3(xrCreateDebugUtilsMessengerEXT, (XrInstance), p_instance, (const XrDebugUtilsMessengerCreateInfoEXT *), p_create_info, (XrDebugUtilsMessengerEXT *), p_messenger)
EXT_PROTO_XRRESULT_FUNC1(xrDestroyDebugUtilsMessengerEXT, (XrDebugUtilsMessengerEXT), p_messenger)
EXT_PROTO_XRRESULT_FUNC2(xrSetDebugUtilsObjectNameEXT, (XrInstance), p_instance, (const XrDebugUtilsObjectNameInfoEXT *), p_name_info)
};

#endif // OPENXR_DEBUG_UTILS_EXTENSION_H
31 changes: 31 additions & 0 deletions modules/openxr/openxr_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -316,6 +317,19 @@ 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 char *p_object_name) {
OpenXRDebugUtilsExtension *debug_utils = OpenXRDebugUtilsExtension::get_singleton();
if (!debug_utils) {
// Not enabled? Ignore.
return;
} else if (!debug_utils->get_active()) {
// Not active? Ignore.
return;
}

debug_utils->set_object_name(p_object_type, p_object_handle, p_object_name);
}

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) {
Expand Down Expand Up @@ -580,6 +594,9 @@ bool OpenXRAPI::create_instance() {
wrapper->on_instance_created(instance);
}

// We can't register this till now, only now our debug util is properly setup.
set_object_name(XR_OBJECT_TYPE_INSTANCE, uint64_t(instance), "Main Godot OpenXR Instance");

return true;
}

Expand Down Expand Up @@ -826,6 +843,8 @@ bool OpenXRAPI::create_session() {
return false;
}

set_object_name(XR_OBJECT_TYPE_SESSION, uint64_t(session), "Main Godot OpenXR Session");

for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_session_created(session);
}
Expand Down Expand Up @@ -916,6 +935,8 @@ bool OpenXRAPI::setup_play_space() {
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) {
Expand All @@ -931,6 +952,8 @@ bool OpenXRAPI::setup_play_space() {
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) {
Expand Down Expand Up @@ -972,6 +995,8 @@ bool OpenXRAPI::setup_play_space() {
play_space = new_play_space;
reference_space = new_reference_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;

Expand Down Expand Up @@ -1007,6 +1032,8 @@ bool OpenXRAPI::setup_view_space() {
return false;
}

set_object_name(XR_OBJECT_TYPE_SPACE, uint64_t(view_space), "View space");

return true;
}

Expand Down Expand Up @@ -1181,6 +1208,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:
Expand All @@ -1191,6 +1220,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_COLOR].get_swapchain()), "Main depth swapchain");
}

// We create our velocity swapchain if:
Expand Down
Loading

0 comments on commit 416e0da

Please sign in to comment.