1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-25 15:37:42 +00:00

Merge pull request #106891 from BastiaanOlij/openxr_core_android_loader

OpenXR add core support for Khronos loader
This commit is contained in:
Thaddeus Crews
2025-11-20 16:47:00 -06:00
7 changed files with 213 additions and 16 deletions

View File

@@ -8,19 +8,16 @@ Import("env_modules")
env_openxr = env_modules.Clone() env_openxr = env_modules.Clone()
# Thirdparty source files # Thirdparty source files.
thirdparty_obj = [] thirdparty_obj = []
# Khronos OpenXR loader # Khronos OpenXR loader.
# Needs even for build against shared library, at least the defines used in public headers. # Needs even for build against shared library, at least the defines used in public headers.
if env["platform"] == "android": if env["platform"] == "android":
# may need to set OPENXR_ANDROID_VERSION_SUFFIX
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"]) env_openxr.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"])
env_openxr.AppendUnique(CPPDEFINES=[("JSON_USE_EXCEPTION", 0)]) env_openxr.AppendUnique(CPPDEFINES=[("JSON_USE_EXCEPTION", 0)])
# may need to include java parts of the openxr loader
elif env["platform"] == "linuxbsd": elif env["platform"] == "linuxbsd":
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_LINUX"]) env_openxr.AppendUnique(CPPDEFINES=["XR_OS_LINUX"])
@@ -31,7 +28,6 @@ elif env["platform"] == "linuxbsd":
env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_EGL", "XRDEPENDENCIES_USE_GLAD"]) env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_EGL", "XRDEPENDENCIES_USE_GLAD"])
env_openxr.Prepend(CPPPATH=["#thirdparty/glad"]) env_openxr.Prepend(CPPPATH=["#thirdparty/glad"])
# FIXME: Review what needs to be set for Android and macOS.
# FreeBSD uses non-standard getenv functions. # FreeBSD uses non-standard getenv functions.
if not sys.platform.startswith("freebsd"): if not sys.platform.startswith("freebsd"):
env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
@@ -40,12 +36,9 @@ elif env["platform"] == "windows":
elif env["platform"] == "macos": elif env["platform"] == "macos":
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_APPLE"]) env_openxr.AppendUnique(CPPDEFINES=["XR_OS_APPLE"])
# There does not seem to be a XR_USE_PLATFORM_XYZ for Apple # There does not seem to be a XR_USE_PLATFORM_XYZ for Apple.
# may need to check and set:
# - XR_USE_TIMESPEC
if env["builtin_openxr"]: if env["builtin_openxr"]:
thirdparty_dir = "#thirdparty/openxr" thirdparty_dir = "#thirdparty/openxr"
@@ -68,16 +61,15 @@ if env["builtin_openxr"]:
env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"]) env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"])
# add in external jsoncpp dependency # Add in external jsoncpp dependency.
thirdparty_jsoncpp_dir = thirdparty_dir + "/src/external/jsoncpp/src/lib_json/" thirdparty_jsoncpp_dir = thirdparty_dir + "/src/external/jsoncpp/src/lib_json/"
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_reader.cpp") env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_reader.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_value.cpp") env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_value.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_writer.cpp") env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_writer.cpp")
# add in load # Add in the OpenXR loader.
if env["platform"] != "android": if env["platform"] != "android":
# On Android the openxr_loader is provided by separate plugins for each device # On Android the OpenXR loader is handled by the configuration in 'platform/android/java/app/build.gradle'.
# Build the engine using object files
khrloader_obj = [] khrloader_obj = []
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table_core.c") env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table_core.c")
@@ -93,13 +85,12 @@ if env["builtin_openxr"]:
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_properties.cpp") env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_properties.cpp")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/manifest_file.cpp") env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/manifest_file.cpp")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp") env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp")
env.modules_sources += khrloader_obj env.modules_sources += khrloader_obj
env.modules_sources += thirdparty_obj env.modules_sources += thirdparty_obj
# Godot source files # Godot source files.
module_obj = [] module_obj = []

View File

@@ -35,6 +35,119 @@
#include "editor/editor_node.h" #include "editor/editor_node.h"
#include "editor/gui/editor_bottom_panel.h" #include "editor/gui/editor_bottom_panel.h"
#include "editor/settings/editor_command_palette.h" #include "editor/settings/editor_command_palette.h"
#include "platform/android/export/export_plugin.h"
#include <openxr/openxr.h>
////////////////////////////////////////////////////////////////////////////
// OpenXRExportPlugin
bool OpenXRExportPlugin::supports_platform(const Ref<EditorExportPlatform> &p_export_platform) const {
return p_export_platform->is_class(EditorExportPlatformAndroid::get_class_static());
}
bool OpenXRExportPlugin::is_openxr_mode() const {
int xr_mode_index = get_option("xr_features/xr_mode");
return xr_mode_index == XR_MODE_OPENXR;
}
String OpenXRExportPlugin::_get_export_option_warning(const Ref<EditorExportPlatform> &p_export_platform, const String &p_option_name) const {
if (!supports_platform(p_export_platform)) {
return String();
}
bool gradle_build = get_option("gradle_build/use_gradle_build");
if (is_openxr_mode() && !gradle_build) {
return "\"Use Gradle Build\" must be enabled when xr_mode is set to \"OpenXR\".";
}
return String();
}
PackedStringArray OpenXRExportPlugin::get_android_dependencies(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
PackedStringArray ret;
if (!supports_platform(p_export_platform)) {
return ret;
}
if (is_openxr_mode()) {
// Loader is always identified by the full API version even if we're initializing for OpenXR 1.0.
int major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION);
int minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION);
int patch = XR_VERSION_PATCH(XR_CURRENT_API_VERSION);
String openxr_loader = "org.khronos.openxr:openxr_loader_for_android:" + String::num_int64(major) + "." + String::num_int64(minor) + "." + String::num_int64(patch);
ret.push_back(openxr_loader);
}
return ret;
}
PackedStringArray OpenXRExportPlugin::_get_export_features(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
PackedStringArray features;
if (!supports_platform(p_export_platform) || !is_openxr_mode()) {
return features;
}
// Placeholder for now
return features;
}
String OpenXRExportPlugin::get_android_manifest_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
String contents;
if (!supports_platform(p_export_platform) || !is_openxr_mode()) {
return contents;
}
contents += R"n(
<uses-permission android:name="org.khronos.openxr.permission.OPENXR" />
<uses-permission android:name="org.khronos.openxr.permission.OPENXR_SYSTEM" />
<queries>
<provider android:authorities="org.khronos.openxr.runtime_broker;org.khronos.openxr.system_runtime_broker" />
<intent>
<action android:name="org.khronos.openxr.OpenXRRuntimeService" />
</intent>
<intent>
<action android:name="org.khronos.openxr.OpenXRApiLayerService" />
</intent>
</queries>
<uses-feature android:name="android.hardware.vr.headtracking" android:required="false" android:version="1" />
)n";
return contents;
}
String OpenXRExportPlugin::get_android_manifest_activity_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
String contents;
if (!supports_platform(p_export_platform) || !is_openxr_mode()) {
return contents;
}
contents += R"n(
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="org.khronos.openxr.intent.category.IMMERSIVE_HMD" />
</intent-filter>
)n";
return contents;
}
////////////////////////////////////////////////////////////////////////////
// OpenXREditorPlugin
void OpenXREditorPlugin::edit(Object *p_node) { void OpenXREditorPlugin::edit(Object *p_node) {
if (Object::cast_to<OpenXRActionMap>(p_node)) { if (Object::cast_to<OpenXRActionMap>(p_node)) {
@@ -64,3 +177,19 @@ OpenXREditorPlugin::OpenXREditorPlugin() {
add_control_to_container(CONTAINER_TOOLBAR, select_runtime); add_control_to_container(CONTAINER_TOOLBAR, select_runtime);
#endif #endif
} }
void OpenXREditorPlugin::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
// Initialize our export plugin
openxr_export_plugin.instantiate();
add_export_plugin(openxr_export_plugin);
} break;
case NOTIFICATION_EXIT_TREE: {
// Clean up our export plugin
remove_export_plugin(openxr_export_plugin);
openxr_export_plugin.unref();
}
}
}

View File

@@ -34,8 +34,27 @@
#include "openxr_binding_modifier_editor.h" #include "openxr_binding_modifier_editor.h"
#include "openxr_select_runtime.h" #include "openxr_select_runtime.h"
#include "editor/export/editor_export_plugin.h"
#include "editor/plugins/editor_plugin.h" #include "editor/plugins/editor_plugin.h"
class OpenXRExportPlugin : public EditorExportPlugin {
GDCLASS(OpenXRExportPlugin, EditorExportPlugin)
public:
virtual bool supports_platform(const Ref<EditorExportPlatform> &p_export_platform) const override;
virtual PackedStringArray get_android_dependencies(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const override;
protected:
virtual String _get_export_option_warning(const Ref<EditorExportPlatform> &p_export_platform, const String &p_option_name) const override;
virtual PackedStringArray _get_export_features(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const override;
virtual String get_android_manifest_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const override;
virtual String get_android_manifest_activity_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const override;
private:
bool is_openxr_mode() const;
};
class OpenXREditorPlugin : public EditorPlugin { class OpenXREditorPlugin : public EditorPlugin {
GDCLASS(OpenXREditorPlugin, EditorPlugin); GDCLASS(OpenXREditorPlugin, EditorPlugin);
@@ -53,4 +72,10 @@ public:
virtual void make_visible(bool p_visible) override; virtual void make_visible(bool p_visible) override;
OpenXREditorPlugin(); OpenXREditorPlugin();
protected:
void _notification(int p_what);
private:
Ref<OpenXRExportPlugin> openxr_export_plugin;
}; };

View File

@@ -299,6 +299,29 @@ task validateJavaVersion {
} }
} }
/*
* Older versions of our vendor plugin include a loader that we no longer need.
* This code ensures those are removed.
*/
tasks.withType( com.android.build.gradle.internal.tasks.MergeNativeLibsTask) {
doFirst {
externalLibNativeLibs.each { jniDir ->
if (jniDir.getCanonicalPath().contains("godot-openxr-") || jniDir.getCanonicalPath().contains("godotopenxr")) {
// Delete the 'libopenxr_loader.so' files from the vendors plugin so we only use the version from the
// openxr loader dependency.
File armFile = new File(jniDir, "arm64-v8a/libopenxr_loader.so")
if (armFile.exists()) {
armFile.delete()
}
File x86File = new File(jniDir, "x86_64/libopenxr_loader.so")
if (x86File.exists()) {
x86File.delete()
}
}
}
}
}
/* /*
When they're scheduled to run, the copy*AARToAppModule tasks generate dependencies for the 'app' When they're scheduled to run, the copy*AARToAppModule tasks generate dependencies for the 'app'
module, so we're ensuring the ':app:preBuild' task is set to run after those tasks. module, so we're ensuring the ':app:preBuild' task is set to run after those tasks.

View File

@@ -15,6 +15,8 @@ ext.versions = [
// Also update 'platform/android/detect.py#get_ndk_version()' when this is updated. // Also update 'platform/android/detect.py#get_ndk_version()' when this is updated.
ndkVersion : '28.1.13356709', ndkVersion : '28.1.13356709',
splashscreenVersion: '1.0.1', splashscreenVersion: '1.0.1',
// 'openxrLoaderVersion' should be set to XR_CURRENT_API_VERSION, see 'thirdparty/openxr'
openxrLoaderVersion: '1.1.53',
openxrVendorsVersion: '4.2.0-stable', openxrVendorsVersion: '4.2.0-stable',
junitVersion : '1.3.0', junitVersion : '1.3.0',
espressoCoreVersion: '3.7.0', espressoCoreVersion: '3.7.0',

View File

@@ -203,6 +203,8 @@ dependencies {
implementation "androidx.constraintlayout:constraintlayout:2.2.1" implementation "androidx.constraintlayout:constraintlayout:2.2.1"
implementation "org.bouncycastle:bcprov-jdk15to18:1.78" implementation "org.bouncycastle:bcprov-jdk15to18:1.78"
implementation "org.khronos.openxr:openxr_loader_for_android:$versions.openxrLoaderVersion"
// Android XR dependencies // Android XR dependencies
androidImplementation "org.godotengine:godot-openxr-vendors-androidxr:$versions.openxrVendorsVersion" androidImplementation "org.godotengine:godot-openxr-vendors-androidxr:$versions.openxrVendorsVersion"
// Meta dependencies // Meta dependencies
@@ -217,3 +219,26 @@ dependencies {
androidTestImplementation "androidx.test:runner:$versions.testRunnerVersion" androidTestImplementation "androidx.test:runner:$versions.testRunnerVersion"
androidTestUtil "androidx.test:orchestrator:$versions.testOrchestratorVersion" androidTestUtil "androidx.test:orchestrator:$versions.testOrchestratorVersion"
} }
/*
* Older versions of our vendor plugin include a loader that we no longer need.
* This code ensures those are removed.
*/
tasks.withType( com.android.build.gradle.internal.tasks.MergeNativeLibsTask) {
doFirst {
externalLibNativeLibs.each { jniDir ->
if (jniDir.getCanonicalPath().contains("godot-openxr-") || jniDir.getCanonicalPath().contains("godotopenxr")) {
// Delete the 'libopenxr_loader.so' files from the vendors plugin so we only use the version from the
// openxr loader dependency.
File armFile = new File(jniDir, "arm64-v8a/libopenxr_loader.so")
if (armFile.exists()) {
armFile.delete()
}
File x86File = new File(jniDir, "x86_64/libopenxr_loader.so")
if (x86File.exists()) {
x86File.delete()
}
}
}
}
}

View File

@@ -888,6 +888,8 @@ Exclude:
`*.{def,expsym,in,json,map,pom,rc,txt}` `*.{def,expsym,in,json,map,pom,rc,txt}`
- All dotfiles - All dotfiles
Additional:
- Update `openxrLoaderVersion` in `platform/android/java/app/config.gradle`
## pcre2 ## pcre2