Skip to content

Commit e16eb1d

Browse files
committed
OpenXR add core support for Khronos loader
1 parent 6c9765d commit e16eb1d

File tree

3 files changed

+195
-1
lines changed

3 files changed

+195
-1
lines changed

modules/openxr/editor/openxr_editor_plugin.cpp

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,157 @@
3535
#include "editor/editor_command_palette.h"
3636
#include "editor/editor_node.h"
3737
#include "editor/gui/editor_bottom_panel.h"
38+
#include "platform/android/export/export_plugin.h"
39+
40+
#include <openxr/openxr.h>
41+
42+
////////////////////////////////////////////////////////////////////////////
43+
// OpenXRExportPlugin
44+
45+
bool OpenXRExportPlugin::supports_platform(const Ref<EditorExportPlatform> &p_export_platform) const {
46+
return p_export_platform->is_class(EditorExportPlatformAndroid::get_class_static());
47+
}
48+
49+
bool OpenXRExportPlugin::is_openxr_mode() const {
50+
int xr_mode_index = get_option("xr_features/xr_mode");
51+
52+
return xr_mode_index == XR_MODE_OPENXR;
53+
}
54+
55+
void OpenXRExportPlugin::_get_export_options(const Ref<EditorExportPlatform> &p_export_platform, List<EditorExportPlatform::ExportOption> *r_options) const {
56+
if (!supports_platform(p_export_platform)) {
57+
return;
58+
}
59+
60+
PropertyInfo openxr_version(Variant::STRING, "xr_features/custom_openxr_loader", PROPERTY_HINT_PLACEHOLDER_TEXT, "Custom OpenXR Loader [default if blank]");
61+
Variant default_value = "";
62+
bool update_visibility = true; // TODO only show openxr_version if xr_mode = XR_MODE_OPENXR
63+
r_options->push_back(EditorExportPlatform::ExportOption(openxr_version, default_value, update_visibility));
64+
}
65+
66+
Dictionary OpenXRExportPlugin::_get_export_options_overrides(const Ref<EditorExportPlatform> &p_export_platform) const {
67+
if (!supports_platform(p_export_platform)) {
68+
return Dictionary();
69+
}
70+
71+
Dictionary overrides;
72+
73+
if (!is_openxr_mode()) {
74+
// Creating an override will hide this property.
75+
overrides["xr_features/openxr_version"] = "disabled";
76+
}
77+
78+
return overrides;
79+
}
80+
81+
String OpenXRExportPlugin::_get_export_option_warning(const Ref<EditorExportPlatform> &p_export_platform, const String &p_option_name) const {
82+
if (!supports_platform(p_export_platform)) {
83+
return String();
84+
}
85+
86+
bool gradle_build = get_option("gradle_build/use_gradle_build");
87+
if (is_openxr_mode() && !gradle_build) {
88+
return "\"Use Gradle Build\" must be enabled when xr_mode is set to \"OpenXR\".";
89+
}
90+
91+
return String();
92+
}
93+
94+
PackedStringArray OpenXRExportPlugin::get_android_dependencies(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
95+
PackedStringArray ret;
96+
97+
if (!supports_platform(p_export_platform)) {
98+
return ret;
99+
}
100+
101+
if (is_openxr_mode()) {
102+
String openxr_loader = get_option("xr_features/custom_openxr_loader");
103+
104+
// If no loader is specified, match the openxr loader in our thirdparty folder.
105+
if (openxr_loader.is_empty()) {
106+
// Loader is always identified by the full API version even if we're initializing for OpenXR 1.0.
107+
int major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION);
108+
int minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION);
109+
int patch = XR_VERSION_PATCH(XR_CURRENT_API_VERSION);
110+
openxr_loader = "org.khronos.openxr:openxr_loader_for_android:" + String::num_int64(major) + "." + String::num_int64(minor) + "." + String::num_int64(patch);
111+
}
112+
113+
// We allow plugins to mark this as disabled as well if they introduce their own loader logic.
114+
if (openxr_loader != "disabled") {
115+
ret.push_back(openxr_loader);
116+
}
117+
}
118+
119+
return ret;
120+
}
121+
122+
PackedStringArray OpenXRExportPlugin::_get_export_features(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
123+
PackedStringArray features;
124+
125+
if (!supports_platform(p_export_platform) || !is_openxr_mode()) {
126+
return features;
127+
}
128+
129+
// Placeholder for now
130+
131+
return features;
132+
}
133+
134+
String OpenXRExportPlugin::get_android_manifest_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
135+
String contents;
136+
137+
if (!supports_platform(p_export_platform) || !is_openxr_mode()) {
138+
return contents;
139+
}
140+
141+
// Add in permissions.
142+
contents += " <uses-permission android:name=\"org.khronos.openxr.permission.OPENXR\" />\n";
143+
contents += " <uses-permission android:name=\"org.khronos.openxr.permission.OPENXR_SYSTEM\" />\n";
144+
145+
// Add in queries.
146+
contents += " <queries>\n";
147+
// To talk to the broker.
148+
contents += " <provider android:authorities=\"org.khronos.openxr.runtime_broker;org.khronos.openxr.system_runtime_broker\" />\n";
149+
150+
// So client-side code of runtime/layers can talk to their service sides
151+
contents += " <intent>\n";
152+
contents += " <action android:name=\"org.khronos.openxr.OpenXRRuntimeService\" />\n";
153+
contents += " </intent>\n";
154+
contents += " <intent>\n";
155+
contents += " <action android:name=\"org.khronos.openxr.OpenXRApiLayerService\" />\n";
156+
contents += " </intent>\n";
157+
158+
contents += " </queries>\n";
159+
160+
// Add in features.
161+
162+
// Indicates we support 6DOF tracking and as this is not required, also support 3DOF tracking.
163+
contents += " <uses-feature android:name=\"android.hardware.vr.headtracking\" android:required=\"false\" android:version=\"1\"/>\n";
164+
165+
return contents;
166+
}
167+
168+
String OpenXRExportPlugin::get_android_manifest_activity_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
169+
String contents;
170+
171+
if (!supports_platform(p_export_platform) || !is_openxr_mode()) {
172+
return contents;
173+
}
174+
175+
contents += " <intent-filter>\n";
176+
contents += " <action android:name=\"android.intent.action.MAIN\" />\n";
177+
178+
// OpenXR category tag to indicate the activity starts in an immersive OpenXR mode.
179+
// See https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#android-runtime-category.
180+
contents += " <category android:name=\"org.khronos.openxr.intent.category.IMMERSIVE_HMD\" />\n";
181+
182+
contents += " </intent-filter>\n";
183+
184+
return contents;
185+
}
186+
187+
////////////////////////////////////////////////////////////////////////////
188+
// OpenXREditorPlugin
38189

39190
void OpenXREditorPlugin::edit(Object *p_node) {
40191
if (Object::cast_to<OpenXRActionMap>(p_node)) {
@@ -64,3 +215,19 @@ OpenXREditorPlugin::OpenXREditorPlugin() {
64215
add_control_to_container(CONTAINER_TOOLBAR, select_runtime);
65216
#endif
66217
}
218+
219+
void OpenXREditorPlugin::_notification(int p_what) {
220+
switch (p_what) {
221+
case NOTIFICATION_ENTER_TREE: {
222+
// Initialize our export plugin
223+
openxr_export_plugin.instantiate();
224+
add_export_plugin(openxr_export_plugin);
225+
} break;
226+
case NOTIFICATION_EXIT_TREE: {
227+
// Clean up our export plugin
228+
remove_export_plugin(openxr_export_plugin);
229+
230+
openxr_export_plugin.unref();
231+
}
232+
}
233+
}

modules/openxr/editor/openxr_editor_plugin.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,29 @@
3434
#include "openxr_binding_modifier_editor.h"
3535
#include "openxr_select_runtime.h"
3636

37+
#include "editor/export/editor_export_plugin.h"
3738
#include "editor/plugins/editor_plugin.h"
3839

40+
class OpenXRExportPlugin : public EditorExportPlugin {
41+
GDCLASS(OpenXRExportPlugin, EditorExportPlugin)
42+
43+
public:
44+
virtual bool supports_platform(const Ref<EditorExportPlatform> &p_export_platform) const override;
45+
virtual PackedStringArray get_android_dependencies(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const override;
46+
47+
protected:
48+
virtual void _get_export_options(const Ref<EditorExportPlatform> &p_export_platform, List<EditorExportPlatform::ExportOption> *r_options) const override;
49+
virtual Dictionary _get_export_options_overrides(const Ref<EditorExportPlatform> &p_export_platform) const override;
50+
virtual String _get_export_option_warning(const Ref<EditorExportPlatform> &p_export_platform, const String &p_option_name) const override;
51+
52+
virtual PackedStringArray _get_export_features(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const override;
53+
virtual String get_android_manifest_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const override;
54+
virtual String get_android_manifest_activity_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const override;
55+
56+
private:
57+
bool is_openxr_mode() const;
58+
};
59+
3960
class OpenXREditorPlugin : public EditorPlugin {
4061
GDCLASS(OpenXREditorPlugin, EditorPlugin);
4162

@@ -53,4 +74,10 @@ class OpenXREditorPlugin : public EditorPlugin {
5374
virtual void make_visible(bool p_visible) override;
5475

5576
OpenXREditorPlugin();
77+
78+
protected:
79+
void _notification(int p_what);
80+
81+
private:
82+
Ref<OpenXRExportPlugin> openxr_export_plugin;
5683
};

platform/android/java/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ android {
161161
}
162162

163163
buildFeatures {
164-
buildConfig = true
164+
buildConfig = true
165165
}
166166

167167
buildTypes {

0 commit comments

Comments
 (0)