godot/modules/openxr/openxr_api.cpp

/**************************************************************************/
/*  openxr_api.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_api.h"

#include "extensions/openxr_extension_wrapper_extension.h"
#include "openxr_interface.h"
#include "openxr_util.h"

#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/os/memory.h"
#include "core/version.h"

#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
#endif

#include "openxr_platform_inc.h"

#ifdef VULKAN_ENABLED
#include "extensions/platform/openxr_vulkan_extension.h"
#endif

#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
#include "extensions/platform/openxr_opengl_extension.h"
#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"
#include "extensions/openxr_fb_update_swapchain_extension.h"
#include "extensions/openxr_hand_tracking_extension.h"

#ifdef ANDROID_ENABLED
#define OPENXR_LOADER_NAME
#endif

////////////////////////////////////
// OpenXRAPI::OpenXRSwapChainInfo

Vector<OpenXRAPI::OpenXRSwapChainInfo> OpenXRAPI::OpenXRSwapChainInfo::free_queue;

bool OpenXRAPI::OpenXRSwapChainInfo::create(XrSwapchainCreateFlags p_create_flags, XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size) {}

void OpenXRAPI::OpenXRSwapChainInfo::queue_free() {}

void OpenXRAPI::OpenXRSwapChainInfo::free_queued() {}

void OpenXRAPI::OpenXRSwapChainInfo::free() {}

bool OpenXRAPI::OpenXRSwapChainInfo::acquire(bool &p_should_render) {}

bool OpenXRAPI::OpenXRSwapChainInfo::release() {}

RID OpenXRAPI::OpenXRSwapChainInfo::get_image() {}

////////////////////////////////////
// OpenXRAPI

OpenXRAPI *OpenXRAPI::singleton =;
Vector<OpenXRExtensionWrapper *> OpenXRAPI::registered_extension_wrappers;

bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) {}

String OpenXRAPI::get_default_action_map_resource_name() {}

String OpenXRAPI::get_error_string(XrResult result) const {}

String OpenXRAPI::get_swapchain_format_name(int64_t p_swapchain_format) const {}

void OpenXRAPI::set_object_name(XrObjectType p_object_type, uint64_t p_object_handle, const String &p_object_name) {}

void OpenXRAPI::begin_debug_label_region(const String &p_label_name) {}

void OpenXRAPI::end_debug_label_region() {}

void OpenXRAPI::insert_debug_label(const String &p_label_name) {}

bool OpenXRAPI::load_layer_properties() {}

bool OpenXRAPI::load_supported_extensions() {}

bool OpenXRAPI::is_extension_supported(const String &p_extension) const {}

bool OpenXRAPI::is_extension_enabled(const String &p_extension) const {}

bool OpenXRAPI::is_top_level_path_supported(const String &p_toplevel_path) {}

bool OpenXRAPI::is_interaction_profile_supported(const String &p_ip_path) {}

bool OpenXRAPI::interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path) {}

void OpenXRAPI::copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len) {}

bool OpenXRAPI::create_instance() {}

bool OpenXRAPI::get_system_info() {}

bool OpenXRAPI::load_supported_view_configuration_types() {}

bool OpenXRAPI::load_supported_environmental_blend_modes() {}

bool OpenXRAPI::is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const {}

bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type) {}

void OpenXRAPI::destroy_instance() {}

bool OpenXRAPI::create_session() {}

bool OpenXRAPI::load_supported_reference_spaces() {}

bool OpenXRAPI::is_reference_space_supported(XrReferenceSpaceType p_reference_space) {}

bool OpenXRAPI::setup_play_space() {}

bool OpenXRAPI::setup_view_space() {}

bool OpenXRAPI::reset_emulated_floor_height() {}

bool OpenXRAPI::load_supported_swapchain_formats() {}

bool OpenXRAPI::is_swapchain_format_supported(int64_t p_swapchain_format) {}

bool OpenXRAPI::obtain_swapchain_formats() {}

bool OpenXRAPI::create_main_swapchains(Size2i p_size) {
	ERR_NOT_ON_RENDER_THREAD_V(false);
	ERR_FAIL_NULL_V(graphics_extension, false);
	ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);

	/*
		TODO: We need to improve on this, for now we're taking our old approach of creating our main swapchains and substituting
		those for the ones Godot normally creates.
		This however means we can only use swapchains for our main XR view.

		It would have been nicer if we could override the swapchain creation in Godot with ours but we have a timing issue here.
		We can't create XR swapchains until after our XR session is fully instantiated, yet Godot creates its swapchain much earlier.

		We only creates a swapchain for the main output here.
		Additional swapchains may be created through our composition layer extension.

		Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create,
		as we render 3D content into internal buffers that are copied into the swapchain, we do now have (basic) VRS support
	*/

	render_state.main_swapchain_size = p_size;
	uint32_t sample_count = 1;

	// We start with our color swapchain...
	if (color_swapchain_format != 0) {
		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:
	// - we've enabled submitting depth buffer
	// - we support our depth layer extension
	// - we have our spacewarp extension (not yet implemented)
	if (depth_swapchain_format != 0 && submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) {
		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:
	// - we have our spacewarp extension (not yet implemented)
	{
		// TBD
	}

	for (uint32_t i = 0; i < render_state.view_count; i++) {
		render_state.views[i].type = XR_TYPE_VIEW;
		render_state.views[i].next = nullptr;

		render_state.projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
		render_state.projection_views[i].next = nullptr;
		render_state.projection_views[i].subImage.swapchain = render_state.main_swapchains[OPENXR_SWAPCHAIN_COLOR].get_swapchain();
		render_state.projection_views[i].subImage.imageArrayIndex = i;
		render_state.projection_views[i].subImage.imageRect.offset.x = 0;
		render_state.projection_views[i].subImage.imageRect.offset.y = 0;
		render_state.projection_views[i].subImage.imageRect.extent.width = render_state.main_swapchain_size.width;
		render_state.projection_views[i].subImage.imageRect.extent.height = render_state.main_swapchain_size.height;

		if (render_state.submit_depth_buffer && OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && render_state.depth_views) {
			render_state.projection_views[i].next = &render_state.depth_views[i];

			render_state.depth_views[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR;
			render_state.depth_views[i].next = nullptr;
			render_state.depth_views[i].subImage.swapchain = render_state.main_swapchains[OPENXR_SWAPCHAIN_DEPTH].get_swapchain();
			render_state.depth_views[i].subImage.imageArrayIndex = i;
			render_state.depth_views[i].subImage.imageRect.offset.x = 0;
			render_state.depth_views[i].subImage.imageRect.offset.y = 0;
			render_state.depth_views[i].subImage.imageRect.extent.width = render_state.main_swapchain_size.width;
			render_state.depth_views[i].subImage.imageRect.extent.height = render_state.main_swapchain_size.height;
			// OpenXR spec says that: minDepth < maxDepth.
			render_state.depth_views[i].minDepth = 0.0;
			render_state.depth_views[i].maxDepth = 1.0;
			// But we can reverse near and far for reverse-Z.
			render_state.depth_views[i].nearZ = 100.0; // Near and far Z will be set to the correct values in fill_projection_matrix
			render_state.depth_views[i].farZ = 0.01;
		}
	};

	for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
		wrapper->on_main_swapchains_created();
	}

	return true;
};

void OpenXRAPI::destroy_session() {}

bool OpenXRAPI::on_state_idle() {}

bool OpenXRAPI::on_state_ready() {}

bool OpenXRAPI::on_state_synchronized() {}

bool OpenXRAPI::on_state_visible() {}

bool OpenXRAPI::on_state_focused() {}

bool OpenXRAPI::on_state_stopping() {}

bool OpenXRAPI::on_state_loss_pending() {}

bool OpenXRAPI::on_state_exiting() {}

void OpenXRAPI::set_form_factor(XrFormFactor p_form_factor) {}

uint32_t OpenXRAPI::get_view_count() {}

void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configuration) {}

bool OpenXRAPI::set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space) {}

void OpenXRAPI::set_submit_depth_buffer(bool p_submit_depth_buffer) {}

bool OpenXRAPI::is_initialized() {}

bool OpenXRAPI::is_running() {}

bool OpenXRAPI::openxr_loader_init() {}

bool OpenXRAPI::resolve_instance_openxr_symbols() {}

XrResult OpenXRAPI::try_get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) {}

XrResult OpenXRAPI::get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) {}

bool OpenXRAPI::initialize(const String &p_rendering_driver) {}

bool OpenXRAPI::initialize_session() {}

void OpenXRAPI::finish() {}

void OpenXRAPI::set_xr_interface(OpenXRInterface *p_xr_interface) {}

void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) {}

void OpenXRAPI::unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) {}

const Vector<OpenXRExtensionWrapper *> &OpenXRAPI::get_registered_extension_wrappers() {}

void OpenXRAPI::register_extension_metadata() {}

void OpenXRAPI::cleanup_extension_wrappers() {}

XrHandTrackerEXT OpenXRAPI::get_hand_tracker(int p_hand_index) {}

Size2 OpenXRAPI::get_recommended_target_size() {}

XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {}

bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) {}

bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, Projection &p_camera_matrix) {}

Vector2 OpenXRAPI::get_eye_focus(uint32_t p_view, float p_aspect) {}

bool OpenXRAPI::poll_events() {}

void OpenXRAPI::_allocate_view_buffers(uint32_t p_view_count, bool p_submit_depth_buffer) {}

void OpenXRAPI::_set_render_session_running(bool p_is_running) {}

void OpenXRAPI::_set_render_display_info(XrTime p_predicted_display_time, bool p_should_render) {}

void OpenXRAPI::_set_render_play_space(uint64_t p_play_space) {}

void OpenXRAPI::_set_render_state_multiplier(double p_render_target_size_multiplier) {}

bool OpenXRAPI::process() {}

void OpenXRAPI::free_main_swapchains() {}

void OpenXRAPI::pre_render() {}

bool OpenXRAPI::pre_draw_viewport(RID p_render_target) {}

XrSwapchain OpenXRAPI::get_color_swapchain() {}

RID OpenXRAPI::get_color_texture() {}

RID OpenXRAPI::get_depth_texture() {}

void OpenXRAPI::post_draw_viewport(RID p_render_target) {
	// Must be called from rendering thread!
	ERR_NOT_ON_RENDER_THREAD;

	if (instance == XR_NULL_HANDLE || session == XR_NULL_HANDLE || !render_state.running || !render_state.view_pose_valid || !render_state.should_render) {
		return;
	}

	for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
		wrapper->on_post_draw_viewport(p_render_target);
	}
};

void OpenXRAPI::end_frame() {}

float OpenXRAPI::get_display_refresh_rate() const {}

void OpenXRAPI::set_display_refresh_rate(float p_refresh_rate) {}

Array OpenXRAPI::get_available_display_refresh_rates() const {}

double OpenXRAPI::get_render_target_size_multiplier() const {}

void OpenXRAPI::set_render_target_size_multiplier(double multiplier) {}

bool OpenXRAPI::is_foveation_supported() const {}

int OpenXRAPI::get_foveation_level() const {}

void OpenXRAPI::set_foveation_level(int p_foveation_level) {}

bool OpenXRAPI::get_foveation_dynamic() const {}

void OpenXRAPI::set_foveation_dynamic(bool p_foveation_dynamic) {}

Size2 OpenXRAPI::get_play_space_bounds() const {}

OpenXRAPI::OpenXRAPI() {}

OpenXRAPI::~OpenXRAPI() {}

Transform3D OpenXRAPI::transform_from_pose(const XrPosef &p_pose) {}

template <typename T>
XRPose::TrackingConfidence _transform_from_location(const T &p_location, Transform3D &r_transform) {}

XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform) {}

XRPose::TrackingConfidence OpenXRAPI::transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform) {}

void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {}

bool OpenXRAPI::xr_result(XrResult result, const char *format, Array args) const {}

RID OpenXRAPI::get_tracker_rid(XrPath p_path) {}

RID OpenXRAPI::find_tracker(const String &p_name) {}

RID OpenXRAPI::tracker_create(const String p_name) {}

String OpenXRAPI::tracker_get_name(RID p_tracker) {}

void OpenXRAPI::tracker_check_profile(RID p_tracker, XrSession p_session) {}

void OpenXRAPI::tracker_free(RID p_tracker) {}

RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_name, const int p_priority) {}

String OpenXRAPI::action_set_get_name(RID p_action_set) {}

bool OpenXRAPI::attach_action_sets(const Vector<RID> &p_action_sets) {}

void OpenXRAPI::action_set_free(RID p_action_set) {}

RID OpenXRAPI::get_action_rid(XrAction p_action) {}

RID OpenXRAPI::find_action(const String &p_name) {}

RID OpenXRAPI::action_create(RID p_action_set, const String p_name, const String p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> &p_trackers) {}

String OpenXRAPI::action_get_name(RID p_action) {}

void OpenXRAPI::action_free(RID p_action) {}

RID OpenXRAPI::get_interaction_profile_rid(XrPath p_path) {}

XrPath OpenXRAPI::get_interaction_profile_path(RID p_interaction_profile) {}

RID OpenXRAPI::interaction_profile_create(const String p_name) {}

String OpenXRAPI::interaction_profile_get_name(RID p_interaction_profile) {}

void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) {}

bool OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) {}

bool OpenXRAPI::interaction_profile_suggest_bindings(RID p_interaction_profile) {}

void OpenXRAPI::interaction_profile_free(RID p_interaction_profile) {}

bool OpenXRAPI::sync_action_sets(const Vector<RID> p_active_sets) {}

bool OpenXRAPI::get_action_bool(RID p_action, RID p_tracker) {}

float OpenXRAPI::get_action_float(RID p_action, RID p_tracker) {}

Vector2 OpenXRAPI::get_action_vector2(RID p_action, RID p_tracker) {}

XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {}

bool OpenXRAPI::trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns) {}

void OpenXRAPI::register_composition_layer_provider(OpenXRCompositionLayerProvider *provider) {}

void OpenXRAPI::unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider) {}

const XrEnvironmentBlendMode *OpenXRAPI::get_supported_environment_blend_modes(uint32_t &count) {}

bool OpenXRAPI::is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const {}

bool OpenXRAPI::set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode) {}

void OpenXRAPI::set_emulate_environment_blend_mode_alpha_blend(bool p_enabled) {}

OpenXRAPI::OpenXRAlphaBlendModeSupport OpenXRAPI::is_environment_blend_mode_alpha_blend_supported() {}