diff options
Diffstat (limited to 'modules/openxr')
20 files changed, 642 insertions, 39 deletions
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index b5978ab134..84542be3b9 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -90,6 +90,8 @@ if env["platform"] == "android": env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp") if env["vulkan"]: env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp") +if env["opengl3"]: + env_openxr.add_source_files(module_obj, "extensions/openxr_opengl_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_depth_extension.cpp") diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp index 0fb4f0773f..7e02f0374d 100644 --- a/modules/openxr/action_map/openxr_action.cpp +++ b/modules/openxr/action_map/openxr_action.cpp @@ -42,7 +42,7 @@ void OpenXRAction::_bind_methods() { ClassDB::bind_method(D_METHOD("set_toplevel_paths", "toplevel_paths"), &OpenXRAction::set_toplevel_paths); ClassDB::bind_method(D_METHOD("get_toplevel_paths"), &OpenXRAction::get_toplevel_paths); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "toplevel_paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_toplevel_paths", "get_toplevel_paths"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "toplevel_paths"), "set_toplevel_paths", "get_toplevel_paths"); BIND_ENUM_CONSTANT(OPENXR_ACTION_BOOL); BIND_ENUM_CONSTANT(OPENXR_ACTION_FLOAT); diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index 185e44c29d..123f860ce9 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -224,7 +224,7 @@ void OpenXRActionMap::create_default_action_sets() { // Create our interaction profiles Ref<OpenXRInteractionProfile> profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/khr/simple_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); @@ -236,7 +236,7 @@ void OpenXRActionMap::create_default_action_sets() { // Create our Vive controller profile profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); @@ -257,7 +257,7 @@ void OpenXRActionMap::create_default_action_sets() { // Create our WMR controller profile profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/microsoft/motion_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); @@ -280,7 +280,7 @@ void OpenXRActionMap::create_default_action_sets() { // Create our Meta touch controller profile profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); @@ -305,7 +305,7 @@ void OpenXRActionMap::create_default_action_sets() { // Create our Valve index controller profile profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/valve/index_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); @@ -333,7 +333,7 @@ void OpenXRActionMap::create_default_action_sets() { // Create our HP MR controller profile profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); @@ -356,7 +356,7 @@ void OpenXRActionMap::create_default_action_sets() { // Create our Samsung Odyssey controller profile, // Note that this controller is only identified specifically on WMR, on SteamVR this is identified as a normal WMR controller. profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/samsung/odyssey_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); @@ -379,7 +379,7 @@ void OpenXRActionMap::create_default_action_sets() { // Create our Vive Cosmos controller profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); @@ -403,7 +403,7 @@ void OpenXRActionMap::create_default_action_sets() { // Note, Vive Focus 3 currently is not yet supported as a stand alone device // however HTC currently has a beta OpenXR runtime in testing we may support in the near future profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); @@ -427,7 +427,7 @@ void OpenXRActionMap::create_default_action_sets() { // Create our Huawei controller profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp index 99d7a17acf..abb714c3bb 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile.cpp @@ -38,7 +38,7 @@ void OpenXRIPBinding::_bind_methods() { ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count); ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths); ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_paths", "get_paths"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"), "set_paths", "get_paths"); ClassDB::bind_method(D_METHOD("has_path", "path"), &OpenXRIPBinding::has_path); ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path); diff --git a/modules/openxr/doc_classes/OpenXRAction.xml b/modules/openxr/doc_classes/OpenXRAction.xml index d1a2ce2d2e..a3a45ebb4c 100644 --- a/modules/openxr/doc_classes/OpenXRAction.xml +++ b/modules/openxr/doc_classes/OpenXRAction.xml @@ -6,7 +6,7 @@ <description> This resource defines an OpenXR action. Actions can be used both for inputs (buttons/joystick/trigger/etc) and outputs (haptics). OpenXR performs automatic conversion between action type and input type whenever possible. An analogue trigger bound to a boolean action will thus return [code]false[/code] if the trigger is depressed and [code]true[/code] if pressed fully. - Actions are not directly bound to specific devices, instead OpenXR recognises a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths. + Actions are not directly bound to specific devices, instead OpenXR recognizes a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths. Note that the name of the resource is used to register the action with. </description> <tutorials> @@ -16,7 +16,7 @@ The type of action. </member> <member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default=""""> - The localised description of this action. + The localized description of this action. </member> <member name="toplevel_paths" type="PackedStringArray" setter="set_toplevel_paths" getter="get_toplevel_paths" default="PackedStringArray()"> A collections of toplevel paths to which this action can be bound. diff --git a/modules/openxr/doc_classes/OpenXRActionSet.xml b/modules/openxr/doc_classes/OpenXRActionSet.xml index db3259ec07..39e518750a 100644 --- a/modules/openxr/doc_classes/OpenXRActionSet.xml +++ b/modules/openxr/doc_classes/OpenXRActionSet.xml @@ -36,7 +36,7 @@ Collection of actions for this action set. </member> <member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default=""""> - The localised name of this action set. + The localized name of this action set. </member> <member name="priority" type="int" setter="set_priority" getter="get_priority" default="0"> The priority for this action set. diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index f089fd066e..7251a4a9bd 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -5,7 +5,7 @@ </brief_description> <description> The OpenXR interface allows Godot to interact with OpenXR runtimes and make it possible to create XR experiences and games. - Due to the needs of OpenXR this interface works slightly different than other plugin based XR interfaces. It needs to be initialised when Godot starts. You need to enable OpenXR, settings for this can be found in your games project settings under the XR heading. You do need to mark a viewport for use with XR in order for Godot to know which render result should be output to the headset. + Due to the needs of OpenXR this interface works slightly different than other plugin based XR interfaces. It needs to be initialized when Godot starts. You need to enable OpenXR, settings for this can be found in your games project settings under the XR heading. You do need to mark a viewport for use with XR in order for Godot to know which render result should be output to the headset. </description> <tutorials> <link title="Setting up XR">$DOCS_URL/tutorials/xr/setting_up_xr.html</link> diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index 51c402d746..b5223e5903 100644 --- a/modules/openxr/editor/openxr_action_map_editor.cpp +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -128,7 +128,7 @@ void OpenXRActionMapEditor::_update_interaction_profiles() { interaction_profiles.remove_at(0); tabs->remove_child(interaction_profile); - interaction_profile->queue_delete(); + interaction_profile->queue_free(); } // in with the new... @@ -205,7 +205,7 @@ void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) { action_map->remove_action_set(action_set); actionsets_vb->remove_child(action_set_editor); - action_set_editor->queue_delete(); + action_set_editor->queue_free(); } void OpenXRActionMapEditor::_on_action_removed() { @@ -290,7 +290,7 @@ void OpenXRActionMapEditor::_on_tab_button_pressed(int p_tab) { action_map->remove_interaction_profile(interaction_profile); tabs->remove_child(profile_editor); - profile_editor->queue_delete(); + profile_editor->queue_free(); } void OpenXRActionMapEditor::open_action_map(String p_path) { @@ -364,7 +364,7 @@ OpenXRActionMapEditor::OpenXRActionMapEditor() { select_interaction_profile_dialog->connect("interaction_profile_selected", callable_mp(this, &OpenXRActionMapEditor::_on_interaction_profile_selected)); add_child(select_interaction_profile_dialog); - _load_action_map(ProjectSettings::get_singleton()->get("xr/openxr/default_action_map")); + _load_action_map(GLOBAL_GET("xr/openxr/default_action_map")); } OpenXRActionMapEditor::~OpenXRActionMapEditor() { diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp index 804808a6b9..3869146e8e 100644 --- a/modules/openxr/editor/openxr_action_set_editor.cpp +++ b/modules/openxr/editor/openxr_action_set_editor.cpp @@ -140,7 +140,7 @@ void OpenXRActionSetEditor::_on_remove_action(Object *p_action_editor) { // And remove it.... action_map->remove_action(action->get_name_with_set()); // remove it from the set and any interaction profile it relates to actions_vb->remove_child(action_editor); - action_editor->queue_delete(); + action_editor->queue_free(); // Let action map editor know so we can update our interaction profiles emit_signal("action_removed"); diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp index 8f6d5c28db..ea539f2053 100644 --- a/modules/openxr/extensions/openxr_android_extension.cpp +++ b/modules/openxr/extensions/openxr_android_extension.cpp @@ -47,7 +47,8 @@ OpenXRAndroidExtension *OpenXRAndroidExtension::get_singleton() { OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) : OpenXRExtensionWrapper(p_openxr_api) { singleton = this; - request_extensions[XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME] = nullptr; // must be available + request_extensions[XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME] = nullptr; // must be available + request_extensions[XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME] = &create_instance_extension_available; } void OpenXRAndroidExtension::on_before_instance_created() { @@ -68,6 +69,29 @@ void OpenXRAndroidExtension::on_before_instance_created() { ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to call xrInitializeLoaderKHR"); } +// We're keeping the Android create info struct here to avoid including openxr_platform.h in a header, which would break other extensions. +// This is reasonably safe as the struct is only used during intialization and the extension is a singleton. +static XrInstanceCreateInfoAndroidKHR instance_create_info; + +void *OpenXRAndroidExtension::set_instance_create_info_and_get_next_pointer(void *p_next_pointer) { + if (!create_instance_extension_available) { + return nullptr; + } + + JNIEnv *env = get_jni_env(); + JavaVM *vm; + env->GetJavaVM(&vm); + jobject activity_object = env->NewGlobalRef(static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity()); + + instance_create_info = { + .type = XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, + .next = p_next_pointer, + .applicationVM = vm, + .applicationActivity = activity_object + }; + return &instance_create_info; +} + OpenXRAndroidExtension::~OpenXRAndroidExtension() { singleton = nullptr; } diff --git a/modules/openxr/extensions/openxr_android_extension.h b/modules/openxr/extensions/openxr_android_extension.h index eda7022064..ca6011559a 100644 --- a/modules/openxr/extensions/openxr_android_extension.h +++ b/modules/openxr/extensions/openxr_android_extension.h @@ -41,12 +41,15 @@ public: OpenXRAndroidExtension(OpenXRAPI *p_openxr_api); virtual void on_before_instance_created() override; + virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) override; virtual ~OpenXRAndroidExtension() override; private: static OpenXRAndroidExtension *singleton; + bool create_instance_extension_available = false; + // Initialize the loader EXT_PROTO_XRRESULT_FUNC1(xrInitializeLoaderKHR, (const XrLoaderInitInfoBaseHeaderKHR *), loaderInitInfo) }; diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index c417c90d11..77b52ab355 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -65,6 +65,7 @@ public: virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } virtual void on_before_instance_created() {} virtual void on_instance_created(const XrInstance p_instance) {} diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp index 4b30965ce5..85e2ee4903 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -102,7 +102,7 @@ void OpenXRHandTrackingExtension::on_state_ready() { // Setup our hands and reset data for (int i = 0; i < MAX_OPENXR_TRACKED_HANDS; i++) { // we'll do this later - hand_trackers[i].is_initialised = false; + hand_trackers[i].is_initialized = false; hand_trackers[i].hand_tracker = XR_NULL_HANDLE; hand_trackers[i].aimState.aimPose = { { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }; @@ -144,7 +144,7 @@ void OpenXRHandTrackingExtension::on_process() { if (XR_FAILED(result)) { // not successful? then we do nothing. print_line("OpenXR: Failed to obtain hand tracking information [", openxr_api->get_error_string(result), "]"); - hand_trackers[i].is_initialised = false; + hand_trackers[i].is_initialized = false; } else { void *next_pointer = nullptr; if (hand_tracking_aim_state_ext) { @@ -172,11 +172,11 @@ void OpenXRHandTrackingExtension::on_process() { hand_trackers[i].locations.jointCount = XR_HAND_JOINT_COUNT_EXT; hand_trackers[i].locations.jointLocations = hand_trackers[i].joint_locations; - hand_trackers[i].is_initialised = true; + hand_trackers[i].is_initialized = true; } } - if (hand_trackers[i].is_initialised) { + if (hand_trackers[i].is_initialized) { void *next_pointer = nullptr; XrHandJointsMotionRangeInfoEXT motionRangeInfo; @@ -240,7 +240,7 @@ void OpenXRHandTrackingExtension::cleanup_hand_tracking() { if (hand_trackers[i].hand_tracker != XR_NULL_HANDLE) { xrDestroyHandTrackerEXT(hand_trackers[i].hand_tracker); - hand_trackers[i].is_initialised = false; + hand_trackers[i].is_initialized = false; hand_trackers[i].hand_tracker = XR_NULL_HANDLE; } } diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.h b/modules/openxr/extensions/openxr_hand_tracking_extension.h index f8c26339b0..0eca80bcfb 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.h +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.h @@ -40,7 +40,7 @@ class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper { public: struct HandTracker { - bool is_initialised = false; + bool is_initialized = false; XrHandJointsMotionRangeEXT motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT; XrHandTrackerEXT hand_tracker = XR_NULL_HANDLE; diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp index 4d996e6283..29208efb20 100644 --- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp +++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp @@ -91,8 +91,6 @@ bool OpenXRHTCViveTrackerExtension::is_path_supported(const String &p_path) { return available; } else if (p_path == "/user/vive_tracker_htcx/role/chest") { return available; - } else if (p_path == "/user/vive_tracker_htcx/role/chest") { - return available; } else if (p_path == "/user/vive_tracker_htcx/role/camera") { return available; } else if (p_path == "/user/vive_tracker_htcx/role/keyboard") { diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp new file mode 100644 index 0000000000..569030cc11 --- /dev/null +++ b/modules/openxr/extensions/openxr_opengl_extension.cpp @@ -0,0 +1,418 @@ +/*************************************************************************/ +/* openxr_opengl_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifdef GLES3_ENABLED + +#include "../extensions/openxr_opengl_extension.h" +#include "../openxr_util.h" +#include "drivers/gles3/effects/copy_effects.h" +#include "drivers/gles3/storage/texture_storage.h" +#include "servers/rendering/rendering_server_globals.h" +#include "servers/rendering_server.h" + +OpenXROpenGLExtension::OpenXROpenGLExtension(OpenXRAPI *p_openxr_api) : + OpenXRGraphicsExtensionWrapper(p_openxr_api) { +#ifdef ANDROID_ENABLED + request_extensions[XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME] = nullptr; +#else + request_extensions[XR_KHR_OPENGL_ENABLE_EXTENSION_NAME] = nullptr; +#endif + + ERR_FAIL_NULL(openxr_api); +} + +OpenXROpenGLExtension::~OpenXROpenGLExtension() { +} + +void OpenXROpenGLExtension::on_instance_created(const XrInstance p_instance) { + ERR_FAIL_NULL(openxr_api); + + // Obtain pointers to functions we're accessing here. + +#ifdef ANDROID_ENABLED + EXT_INIT_XR_FUNC(xrGetOpenGLESGraphicsRequirementsKHR); +#else + EXT_INIT_XR_FUNC(xrGetOpenGLGraphicsRequirementsKHR); +#endif + EXT_INIT_XR_FUNC(xrEnumerateSwapchainImages); +} + +bool OpenXROpenGLExtension::check_graphics_api_support(XrVersion p_desired_version) { + ERR_FAIL_NULL_V(openxr_api, false); + + XrSystemId system_id = openxr_api->get_system_id(); + XrInstance instance = openxr_api->get_instance(); + +#ifdef ANDROID_ENABLED + XrGraphicsRequirementsOpenGLESKHR opengl_requirements; + opengl_requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR; + opengl_requirements.next = nullptr; + + XrResult result = xrGetOpenGLESGraphicsRequirementsKHR(instance, system_id, &opengl_requirements); + if (!openxr_api->xr_result(result, "Failed to get OpenGL graphics requirements!")) { + return false; + } +#else + XrGraphicsRequirementsOpenGLKHR opengl_requirements; + opengl_requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR; + opengl_requirements.next = nullptr; + + XrResult result = xrGetOpenGLGraphicsRequirementsKHR(instance, system_id, &opengl_requirements); + if (!openxr_api->xr_result(result, "Failed to get OpenGL graphics requirements!")) { + return false; + } +#endif + + if (p_desired_version < opengl_requirements.minApiVersionSupported) { + print_line("OpenXR: Requested OpenGL version does not meet the minimum version this runtime supports."); + print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version)); + print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.minApiVersionSupported)); + print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.maxApiVersionSupported)); + return false; + } + + if (p_desired_version > opengl_requirements.maxApiVersionSupported) { + print_line("OpenXR: Requested OpenGL version exceeds the maximum version this runtime has been tested on and is known to support."); + print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version)); + print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.minApiVersionSupported)); + print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.maxApiVersionSupported)); + } + + return true; +} + +#ifdef WIN32 +XrGraphicsBindingOpenGLWin32KHR OpenXROpenGLExtension::graphics_binding_gl; +#elif ANDROID_ENABLED +XrGraphicsBindingOpenGLESAndroidKHR OpenXROpenGLExtension::graphics_binding_gl; +#else +XrGraphicsBindingOpenGLXlibKHR OpenXROpenGLExtension::graphics_binding_gl; +#endif + +void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) { + XrVersion desired_version = XR_MAKE_VERSION(3, 3, 0); + + if (!check_graphics_api_support(desired_version)) { + print_line("OpenXR: Trying to initialize with OpenGL anyway..."); + //return p_next_pointer; + } + + DisplayServer *display_server = DisplayServer::get_singleton(); + +#ifdef WIN32 + graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, + graphics_binding_gl.next = p_next_pointer; + + graphics_binding_gl.hDC = (HDC)display_server->window_get_native_handle(DisplayServer::WINDOW_VIEW); + graphics_binding_gl.hGLRC = (HGLRC)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT); +#elif ANDROID_ENABLED + graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR; + graphics_binding_gl.next = p_next_pointer; + + graphics_binding_gl.display = eglGetCurrentDisplay(); + graphics_binding_gl.config = (EGLConfig)0; // https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/tests/hello_xr/graphicsplugin_opengles.cpp#L122 + graphics_binding_gl.context = eglGetCurrentContext(); +#else + graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR; + graphics_binding_gl.next = p_next_pointer; + + void *display_handle = (void *)display_server->window_get_native_handle(DisplayServer::DISPLAY_HANDLE); + void *glxcontext_handle = (void *)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT); + void *glxdrawable_handle = (void *)display_server->window_get_native_handle(DisplayServer::WINDOW_HANDLE); + + graphics_binding_gl.xDisplay = (Display *)display_handle; + graphics_binding_gl.glxContext = (GLXContext)glxcontext_handle; + graphics_binding_gl.glxDrawable = (GLXDrawable)glxdrawable_handle; + + // spec says to use proper values but runtimes don't care + graphics_binding_gl.visualid = 0; + graphics_binding_gl.glxFBConfig = 0; +#endif + + return &graphics_binding_gl; +} + +void OpenXROpenGLExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) { + p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8); + p_usable_swap_chains.push_back(GL_RGBA8); +} + +void OpenXROpenGLExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_depth_formats) { + p_usable_depth_formats.push_back(GL_DEPTH_COMPONENT32F); + p_usable_depth_formats.push_back(GL_DEPTH24_STENCIL8); + p_usable_depth_formats.push_back(GL_DEPTH32F_STENCIL8); +} + +bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) { + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + ERR_FAIL_NULL_V(texture_storage, false); + + uint32_t swapchain_length; + XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchaim image count [", openxr_api->get_error_string(result), "]"); + return false; + } + +#ifdef ANDROID_ENABLED + XrSwapchainImageOpenGLESKHR *images = (XrSwapchainImageOpenGLESKHR *)memalloc(sizeof(XrSwapchainImageOpenGLESKHR) * swapchain_length); +#else + XrSwapchainImageOpenGLKHR *images = (XrSwapchainImageOpenGLKHR *)memalloc(sizeof(XrSwapchainImageOpenGLKHR) * swapchain_length); +#endif + ERR_FAIL_NULL_V_MSG(images, false, "OpenXR Couldn't allocate memory for swap chain image"); + + for (uint64_t i = 0; i < swapchain_length; i++) { +#ifdef ANDROID_ENABLED + images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR; +#else + images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR; +#endif + images[i].next = nullptr; + images[i].image = 0; + } + + result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to get swapchaim images [", openxr_api->get_error_string(result), "]"); + memfree(images); + return false; + } + + SwapchainGraphicsData *data = memnew(SwapchainGraphicsData); + if (data == nullptr) { + print_line("OpenXR: Failed to allocate memory for swapchain data"); + memfree(images); + return false; + } + *r_swapchain_graphics_data = data; + data->is_multiview = (p_array_size > 1); + + Image::Format format = Image::FORMAT_RGBA8; + + Vector<RID> texture_rids; + + for (uint64_t i = 0; i < swapchain_length; i++) { + RID texture_rid = texture_storage->texture_create_external( + p_array_size == 1 ? GLES3::Texture::TYPE_2D : GLES3::Texture::TYPE_LAYERED, + format, + images[i].image, + p_width, + p_height, + 1, + p_array_size); + + texture_rids.push_back(texture_rid); + } + + data->texture_rids = texture_rids; + + memfree(images); + + return true; +} + +bool OpenXROpenGLExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) { + XrMatrix4x4f matrix; + XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far); + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + r_camera_matrix.columns[j][i] = matrix.m[j * 4 + i]; + } + } + + return true; +} + +RID OpenXROpenGLExtension::get_texture(void *p_swapchain_graphics_data, int p_image_index) { + SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data; + ERR_FAIL_NULL_V(data, RID()); + + ERR_FAIL_INDEX_V(p_image_index, data->texture_rids.size(), RID()); + return data->texture_rids[p_image_index]; +} + +void OpenXROpenGLExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) { + if (*p_swapchain_graphics_data == nullptr) { + return; + } + + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + ERR_FAIL_NULL(texture_storage); + + SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data; + + for (int i = 0; i < data->texture_rids.size(); i++) { + texture_storage->texture_free(data->texture_rids[i]); + } + data->texture_rids.clear(); + + memdelete(data); + *p_swapchain_graphics_data = nullptr; +} + +#define ENUM_TO_STRING_CASE(e) \ + case e: { \ + return String(#e); \ + } break; + +String OpenXROpenGLExtension::get_swapchain_format_name(int64_t p_swapchain_format) const { + // These are somewhat different per platform, will need to weed some stuff out... + switch (p_swapchain_format) { +#ifdef ANDROID_ENABLED + // using definitions from GLES3/gl3.h + + ENUM_TO_STRING_CASE(GL_RGBA4) + ENUM_TO_STRING_CASE(GL_RGB5_A1) + ENUM_TO_STRING_CASE(GL_RGB565) + ENUM_TO_STRING_CASE(GL_RGB8) + ENUM_TO_STRING_CASE(GL_RGBA8) + ENUM_TO_STRING_CASE(GL_RGB10_A2) + ENUM_TO_STRING_CASE(GL_RGBA32F) + ENUM_TO_STRING_CASE(GL_RGB32F) + ENUM_TO_STRING_CASE(GL_RGBA16F) + ENUM_TO_STRING_CASE(GL_RGB16F) + ENUM_TO_STRING_CASE(GL_R11F_G11F_B10F) + ENUM_TO_STRING_CASE(GL_UNSIGNED_INT_10F_11F_11F_REV) + ENUM_TO_STRING_CASE(GL_RGB9_E5) + ENUM_TO_STRING_CASE(GL_UNSIGNED_INT_5_9_9_9_REV) + ENUM_TO_STRING_CASE(GL_RGBA32UI) + ENUM_TO_STRING_CASE(GL_RGB32UI) + ENUM_TO_STRING_CASE(GL_RGBA16UI) + ENUM_TO_STRING_CASE(GL_RGB16UI) + ENUM_TO_STRING_CASE(GL_RGBA8UI) + ENUM_TO_STRING_CASE(GL_RGB8UI) + ENUM_TO_STRING_CASE(GL_RGBA32I) + ENUM_TO_STRING_CASE(GL_RGB32I) + ENUM_TO_STRING_CASE(GL_RGBA16I) + ENUM_TO_STRING_CASE(GL_RGB16I) + ENUM_TO_STRING_CASE(GL_RGBA8I) + ENUM_TO_STRING_CASE(GL_RGB8I) + ENUM_TO_STRING_CASE(GL_RG) + ENUM_TO_STRING_CASE(GL_RG_INTEGER) + ENUM_TO_STRING_CASE(GL_R8) + ENUM_TO_STRING_CASE(GL_RG8) + ENUM_TO_STRING_CASE(GL_R16F) + ENUM_TO_STRING_CASE(GL_R32F) + ENUM_TO_STRING_CASE(GL_RG16F) + ENUM_TO_STRING_CASE(GL_RG32F) + ENUM_TO_STRING_CASE(GL_R8I) + ENUM_TO_STRING_CASE(GL_R8UI) + ENUM_TO_STRING_CASE(GL_R16I) + ENUM_TO_STRING_CASE(GL_R16UI) + ENUM_TO_STRING_CASE(GL_R32I) + ENUM_TO_STRING_CASE(GL_R32UI) + ENUM_TO_STRING_CASE(GL_RG8I) + ENUM_TO_STRING_CASE(GL_RG8UI) + ENUM_TO_STRING_CASE(GL_RG16I) + ENUM_TO_STRING_CASE(GL_RG16UI) + ENUM_TO_STRING_CASE(GL_RG32I) + ENUM_TO_STRING_CASE(GL_RG32UI) + ENUM_TO_STRING_CASE(GL_R8_SNORM) + ENUM_TO_STRING_CASE(GL_RG8_SNORM) + ENUM_TO_STRING_CASE(GL_RGB8_SNORM) + ENUM_TO_STRING_CASE(GL_RGBA8_SNORM) + ENUM_TO_STRING_CASE(GL_RGB10_A2UI) + ENUM_TO_STRING_CASE(GL_SRGB) + ENUM_TO_STRING_CASE(GL_SRGB8) + ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8) + ENUM_TO_STRING_CASE(GL_COMPRESSED_R11_EAC) + ENUM_TO_STRING_CASE(GL_COMPRESSED_SIGNED_R11_EAC) + ENUM_TO_STRING_CASE(GL_COMPRESSED_RG11_EAC) + ENUM_TO_STRING_CASE(GL_COMPRESSED_SIGNED_RG11_EAC) + ENUM_TO_STRING_CASE(GL_COMPRESSED_RGB8_ETC2) + ENUM_TO_STRING_CASE(GL_COMPRESSED_SRGB8_ETC2) + ENUM_TO_STRING_CASE(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2) + ENUM_TO_STRING_CASE(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) + ENUM_TO_STRING_CASE(GL_COMPRESSED_RGBA8_ETC2_EAC) + ENUM_TO_STRING_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT16) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT24) + ENUM_TO_STRING_CASE(GL_DEPTH24_STENCIL8) + +#else + // using definitions from GLAD + ENUM_TO_STRING_CASE(GL_R8_SNORM) + ENUM_TO_STRING_CASE(GL_RG8_SNORM) + ENUM_TO_STRING_CASE(GL_RGB8_SNORM) + ENUM_TO_STRING_CASE(GL_RGBA8_SNORM) + ENUM_TO_STRING_CASE(GL_R16_SNORM) + ENUM_TO_STRING_CASE(GL_RG16_SNORM) + ENUM_TO_STRING_CASE(GL_RGB16_SNORM) + ENUM_TO_STRING_CASE(GL_RGBA16_SNORM) + ENUM_TO_STRING_CASE(GL_RGB4) + ENUM_TO_STRING_CASE(GL_RGB5) + ENUM_TO_STRING_CASE(GL_RGB8) + ENUM_TO_STRING_CASE(GL_RGB10) + ENUM_TO_STRING_CASE(GL_RGB12) + ENUM_TO_STRING_CASE(GL_RGB16) + ENUM_TO_STRING_CASE(GL_RGBA2) + ENUM_TO_STRING_CASE(GL_RGBA4) + ENUM_TO_STRING_CASE(GL_RGB5_A1) + ENUM_TO_STRING_CASE(GL_RGBA8) + ENUM_TO_STRING_CASE(GL_RGB10_A2) + ENUM_TO_STRING_CASE(GL_RGBA12) + ENUM_TO_STRING_CASE(GL_RGBA16) + ENUM_TO_STRING_CASE(GL_RGBA32F) + ENUM_TO_STRING_CASE(GL_RGB32F) + ENUM_TO_STRING_CASE(GL_RGBA16F) + ENUM_TO_STRING_CASE(GL_RGB16F) + ENUM_TO_STRING_CASE(GL_RGBA32UI) + ENUM_TO_STRING_CASE(GL_RGB32UI) + ENUM_TO_STRING_CASE(GL_RGBA16UI) + ENUM_TO_STRING_CASE(GL_RGB16UI) + ENUM_TO_STRING_CASE(GL_RGBA8UI) + ENUM_TO_STRING_CASE(GL_RGB8UI) + ENUM_TO_STRING_CASE(GL_RGBA32I) + ENUM_TO_STRING_CASE(GL_RGB32I) + ENUM_TO_STRING_CASE(GL_RGBA16I) + ENUM_TO_STRING_CASE(GL_RGB16I) + ENUM_TO_STRING_CASE(GL_RGBA8I) + ENUM_TO_STRING_CASE(GL_RGB8I) + ENUM_TO_STRING_CASE(GL_RGB10_A2UI) + ENUM_TO_STRING_CASE(GL_SRGB) + ENUM_TO_STRING_CASE(GL_SRGB8) + ENUM_TO_STRING_CASE(GL_SRGB_ALPHA) + ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT16) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT24) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32) + ENUM_TO_STRING_CASE(GL_DEPTH24_STENCIL8) + ENUM_TO_STRING_CASE(GL_R11F_G11F_B10F) + ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32F) + ENUM_TO_STRING_CASE(GL_DEPTH32F_STENCIL8) +#endif + default: { + return String("Swapchain format 0x") + String::num_int64(p_swapchain_format, 16); + } break; + } +} + +#endif // GLES3_ENABLED diff --git a/modules/openxr/extensions/openxr_opengl_extension.h b/modules/openxr/extensions/openxr_opengl_extension.h new file mode 100644 index 0000000000..473c5157c0 --- /dev/null +++ b/modules/openxr/extensions/openxr_opengl_extension.h @@ -0,0 +1,119 @@ +/*************************************************************************/ +/* openxr_opengl_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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_OPENGL_EXTENSION_H +#define OPENXR_OPENGL_EXTENSION_H + +#ifdef GLES3_ENABLED + +#include "core/templates/vector.h" +#include "openxr_extension_wrapper.h" + +#include "../openxr_api.h" +#include "../util.h" + +#ifdef ANDROID_ENABLED +#define XR_USE_GRAPHICS_API_OPENGL_ES +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES3/gl3.h> +#include <GLES3/gl3ext.h> +#else +#define XR_USE_GRAPHICS_API_OPENGL +#endif + +#ifdef WINDOWS_ENABLED +// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform +// however due to the way the openxr headers are put together, we have no choice. +#include <windows.h> +#endif + +#ifdef X11_ENABLED +#include OPENGL_INCLUDE_H +#define GL_GLEXT_PROTOTYPES 1 +#define GL3_PROTOTYPES 1 +#include "thirdparty/glad/glad/gl.h" +#include "thirdparty/glad/glad/glx.h" +#include <X11/Xlib.h> +#endif + +#ifdef ANDROID_ENABLED +// The jobject type from jni.h is used by openxr_platform.h on Android. +#include <jni.h> +#endif + +// include platform dependent structs +#include <openxr/openxr_platform.h> + +class OpenXROpenGLExtension : public OpenXRGraphicsExtensionWrapper { +public: + OpenXROpenGLExtension(OpenXRAPI *p_openxr_api); + virtual ~OpenXROpenGLExtension() override; + + virtual void on_instance_created(const XrInstance p_instance) override; + virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override; + + virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override; + virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override; + virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override; + virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override; + virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override; + virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override; + virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override; + +private: + static OpenXROpenGLExtension *singleton; + +#ifdef WIN32 + static XrGraphicsBindingOpenGLWin32KHR graphics_binding_gl; +#elif ANDROID_ENABLED + static XrGraphicsBindingOpenGLESAndroidKHR graphics_binding_gl; +#else + static XrGraphicsBindingOpenGLXlibKHR graphics_binding_gl; +#endif + + struct SwapchainGraphicsData { + bool is_multiview; + Vector<RID> texture_rids; + }; + + bool check_graphics_api_support(XrVersion p_desired_version); + +#ifdef ANDROID_ENABLED + EXT_PROTO_XRRESULT_FUNC3(xrGetOpenGLESGraphicsRequirementsKHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsOpenGLESKHR *), p_graphics_requirements) +#else + EXT_PROTO_XRRESULT_FUNC3(xrGetOpenGLGraphicsRequirementsKHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsOpenGLKHR *), p_graphics_requirements) +#endif + EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainImages, (XrSwapchain), p_swapchain, (uint32_t), p_image_capacity_input, (uint32_t *), p_image_count_output, (XrSwapchainImageBaseHeader *), p_images) +}; + +#endif // GLES3_ENABLED + +#endif // OPENXR_OPENGL_EXTENSION_H diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 1ff1dac512..d6580ebfa6 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -45,10 +45,39 @@ #include "extensions/openxr_android_extension.h" #endif +// We need to have all the graphics API defines before the Vulkan or OpenGL +// extensions are included, otherwise we'll only get one graphics API. +#ifdef VULKAN_ENABLED +#define XR_USE_GRAPHICS_API_VULKAN +#endif +#ifdef GLES3_ENABLED +#ifdef ANDROID +#define XR_USE_GRAPHICS_API_OPENGL_ES +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES3/gl3.h> +#include <GLES3/gl3ext.h> +#else +#define XR_USE_GRAPHICS_API_OPENGL +#endif // ANDROID +#ifdef X11_ENABLED +#include OPENGL_INCLUDE_H +#define GL_GLEXT_PROTOTYPES 1 +#define GL3_PROTOTYPES 1 +#include "thirdparty/glad/glad/gl.h" +#include "thirdparty/glad/glad/glx.h" +#include <X11/Xlib.h> +#endif // X11_ENABLED +#endif // GLES_ENABLED + #ifdef VULKAN_ENABLED #include "extensions/openxr_vulkan_extension.h" #endif +#ifdef GLES3_ENABLED +#include "extensions/openxr_opengl_extension.h" +#endif + #include "extensions/openxr_composition_layer_depth_extension.h" #include "extensions/openxr_fb_display_refresh_rate_extension.h" #include "extensions/openxr_fb_passthrough_extension_wrapper.h" @@ -269,9 +298,17 @@ bool OpenXRAPI::create_instance() { XR_CURRENT_API_VERSION // apiVersion }; + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_instance_create_info_and_get_next_pointer(next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + XrInstanceCreateInfo instance_create_info = { XR_TYPE_INSTANCE_CREATE_INFO, // type - nullptr, // next + next_pointer, // next 0, // createFlags application_info, // applicationInfo 0, // enabledApiLayerCount, need to find out if we need support for this? @@ -691,7 +728,7 @@ bool OpenXRAPI::create_swapchains() { print_verbose(String("Using color swap chain format:") + get_swapchain_format_name(swapchain_format_to_use)); } - if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) { + if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) { return false; } } @@ -1142,9 +1179,8 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { #endif } else if (p_rendering_driver == "opengl3") { #ifdef GLES3_ENABLED - // graphics_extension = memnew(OpenXROpenGLExtension(this)); - // register_extension_wrapper(graphics_extension); - ERR_FAIL_V_MSG(false, "OpenXR: OpenGL is not supported at this time."); + graphics_extension = memnew(OpenXROpenGLExtension(this)); + register_extension_wrapper(graphics_extension); #else // shouldn't be possible... ERR_FAIL_V(false); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index bdf437b0b7..77660eb6f0 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -96,7 +96,7 @@ void OpenXRInterface::_load_action_map() { // This may seem a bit duplicitous to a little bit of background info here. // OpenXRActionMap (with all its sub resource classes) is a class that allows us to configure and store an action map in. - // This gives the user the ability to edit the action map in a UI and customise the actions. + // This gives the user the ability to edit the action map in a UI and customize the actions. // OpenXR however requires us to submit an action map and it takes over from that point and we can no longer change it. // This system does that push and we store the info needed to then work with this action map going forward. @@ -166,7 +166,7 @@ void OpenXRInterface::_load_action_map() { } } - // Only add our action if we have atleast one valid toplevel path + // Only add our action if we have at least one valid toplevel path if (trackers_for_action.size() > 0) { Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), trackers_for_action); if (action) { @@ -355,7 +355,7 @@ OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_tracker_ Ref<XRPositionalTracker> positional_tracker; positional_tracker.instantiate(); - // We have standardised some names to make things nicer to the user so lets recognise the toplevel paths related to these. + // We have standardized some names to make things nicer to the user so lets recognize the toplevel paths related to these. if (p_tracker_name == "/user/hand/left") { positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); positional_tracker->set_tracker_name("left_hand"); @@ -666,6 +666,7 @@ Transform3D OpenXRInterface::get_camera_transform() { Transform3D OpenXRInterface::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, Transform3D()); + ERR_FAIL_UNSIGNED_INDEX_V_MSG(p_view, get_view_count(), Transform3D(), "View index outside bounds."); Transform3D t; if (openxr_api && openxr_api->get_view_transform(p_view, t)) { @@ -685,6 +686,7 @@ Transform3D OpenXRInterface::get_transform_for_view(uint32_t p_view, const Trans Projection OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) { Projection cm; + ERR_FAIL_UNSIGNED_INDEX_V_MSG(p_view, get_view_count(), cm, "View index outside bounds."); if (openxr_api) { if (openxr_api->get_view_projection(p_view, p_z_near, p_z_far, cm)) { diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp index 2ae13a1026..588b818148 100644 --- a/modules/openxr/scene/openxr_hand.cpp +++ b/modules/openxr/scene/openxr_hand.cpp @@ -206,7 +206,7 @@ void OpenXRHand::_update_skeleton() { const OpenXRHandTrackingExtension::HandTracker *hand_tracker = hand_tracking_ext->get_hand_tracker(hand); const float ws = XRServer::get_singleton()->get_world_scale(); - if (hand_tracker->is_initialised && hand_tracker->locations.isActive) { + if (hand_tracker->is_initialized && hand_tracker->locations.isActive) { for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { confidences[i] = XRPose::XR_TRACKING_CONFIDENCE_NONE; quaternions[i] = Quaternion(); |