Skip to content

Commit

Permalink
Dynamic loading of OpenXR Loader on Android
Browse files Browse the repository at this point in the history
This change implements dynamic loading of the OpenXR Loader library
on Android. If an OpenXR Loader library is not found,
Godot will still function with OpenXR disabled.

Also, on every platform, the OpenXR symbols are resolved at runtime
using xrGetInstanceProcAddr.

On Windows and Linux the OpenXR loader is included in the main
engine binary.

On Android, the OpenXR Loader is not built with the engine. Separately
distributed Android plugins will be provided with the correct loader
library for each device.

Co-authored-by: Gábor Pál Korom <[email protected]>
Co-authored-by: Gábor Koncz <[email protected]>
  • Loading branch information
3 people committed Sep 24, 2022
1 parent 240fb86 commit d5445c2
Show file tree
Hide file tree
Showing 10 changed files with 354 additions and 115 deletions.
61 changes: 33 additions & 28 deletions modules/openxr/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -18,56 +18,61 @@ env_openxr.Prepend(
thirdparty_dir + "/src",
thirdparty_dir + "/src/common",
thirdparty_dir + "/src/external/jsoncpp/include",
thirdparty_dir + "/src/loader",
]
)

# may need to check and set:
# - XR_USE_TIMESPEC

env_thirdparty = env_openxr.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"])

if env["platform"] == "android":
# may need to set OPENXR_ANDROID_VERSION_SUFFIX
env_thirdparty.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"])

# may need to include java parts of the openxr loader
elif env["platform"] == "linuxbsd":
env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_LINUX"])
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_LINUX"])

if env["x11"]:
env_thirdparty.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"])
env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"])

# FIXME: Review what needs to be set for Android and macOS.
env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
elif env["platform"] == "windows":
env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"])
env_openxr.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"])

env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c")
# may need to check and set:
# - XR_USE_TIMESPEC

# add in common files (hope these don't clash with us)
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/object_info.cpp")
env_thirdparty = env_openxr.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"])

if "-fno-exceptions" in env_thirdparty["CXXFLAGS"]:
env_thirdparty["CXXFLAGS"].remove("-fno-exceptions")
env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"])

# add in external jsoncpp dependency
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_reader.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_value.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_writer.cpp")

# add in load
if env["platform"] == "android":
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/android_utilities.cpp")

env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_core.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_instance.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/manifest_file.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp")
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp")
if env["platform"] != "android":
# On Android the openxr_loader is provided by separate plugins for each device
# Build the engine using object files
khrloader_obj = []
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c")

env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/object_info.cpp")

env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_core.cpp")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_instance.cpp")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp")
env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger.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/xr_generated_loader.cpp")
env.modules_sources += khrloader_obj

env.modules_sources += thirdparty_obj

Expand Down
4 changes: 1 addition & 3 deletions modules/openxr/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
def can_build(env, platform):
if (
platform == "linuxbsd" or platform == "windows"
): # or platform == "android" -- temporarily disabled android support
if platform in ("linuxbsd", "windows", "android"):
return env["openxr"]
else:
# not supported on these platforms
Expand Down
20 changes: 11 additions & 9 deletions modules/openxr/extensions/openxr_android_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
/*************************************************************************/

#include "openxr_android_extension.h"
#include "java_godot_wrapper.h"
#include "os_android.h"
#include "thread_jandroid.h"

#include <jni.h>
#include <modules/openxr/openxr_api.h>
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>

Expand All @@ -42,27 +47,24 @@ 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
}

// Initialize the loader
PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
result = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction *)(&xrInitializeLoaderKHR));
ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to retrieve pointer to xrInitializeLoaderKHR");
void OpenXRAndroidExtension::on_before_instance_created() {
EXT_INIT_XR_FUNC(xrInitializeLoaderKHR);

// TODO fix this code, this is still code from GDNative!
JNIEnv *env = android_api->godot_android_get_env();
JNIEnv *env = get_jni_env();
JavaVM *vm;
env->GetJavaVM(&vm);
jobject activity_object = env->NewGlobalRef(android_api->godot_android_get_activity());
jobject activity_object = env->NewGlobalRef(static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity());

XrLoaderInitInfoAndroidKHR loader_init_info_android = {
.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR,
.next = nullptr,
.applicationVM = vm,
.applicationContext = activity_object
};
xrInitializeLoaderKHR((const XrLoaderInitInfoBaseHeaderKHR *)&loader_init_info_android);
XrResult result = xrInitializeLoaderKHR((const XrLoaderInitInfoBaseHeaderKHR *)&loader_init_info_android);
ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to call xrInitializeLoaderKHR");
}

Expand Down
7 changes: 7 additions & 0 deletions modules/openxr/extensions/openxr_android_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,24 @@
#ifndef OPENXR_ANDROID_EXTENSION_H
#define OPENXR_ANDROID_EXTENSION_H

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

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

OpenXRAndroidExtension(OpenXRAPI *p_openxr_api);

virtual void on_before_instance_created() override;

virtual ~OpenXRAndroidExtension() override;

private:
static OpenXRAndroidExtension *singleton;

// Initialize the loader
EXT_PROTO_XRRESULT_FUNC1(xrInitializeLoaderKHR, (const XrLoaderInitInfoBaseHeaderKHR *), loaderInitInfo)
};

#endif // OPENXR_ANDROID_EXTENSION_H
1 change: 1 addition & 0 deletions modules/openxr/extensions/openxr_extension_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class OpenXRExtensionWrapper {
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 on_before_instance_created() {}
virtual void on_instance_created(const XrInstance p_instance) {}
virtual void on_instance_destroyed() {}
virtual void on_session_created(const XrSession p_instance) {}
Expand Down
67 changes: 5 additions & 62 deletions modules/openxr/extensions/openxr_vulkan_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,12 @@
#include "core/string/print_string.h"

#include "../extensions/openxr_vulkan_extension.h"
#include "../openxr_api.h"
#include "../openxr_util.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering_server.h"

// need to include Vulkan so we know of type definitions
#define XR_USE_GRAPHICS_API_VULKAN

#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

// include platform dependent structs
#include <openxr/openxr_platform.h>

PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR_ptr = nullptr;
PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR_ptr = nullptr;
PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR_ptr = nullptr;
PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR_ptr = nullptr;

OpenXRVulkanExtension::OpenXRVulkanExtension(OpenXRAPI *p_openxr_api) :
OpenXRGraphicsExtensionWrapper(p_openxr_api) {
VulkanContext::set_vulkan_hooks(this);
Expand All @@ -69,36 +51,15 @@ OpenXRVulkanExtension::~OpenXRVulkanExtension() {
}

void OpenXRVulkanExtension::on_instance_created(const XrInstance p_instance) {
XrResult result;

ERR_FAIL_NULL(openxr_api);

// Obtain pointers to functions we're accessing here, they are (not yet) part of core.
result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR_ptr);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to xrGetVulkanGraphicsRequirements2KHR entry point [", openxr_api->get_error_string(result), "]");
}

result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR_ptr);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to xrCreateVulkanInstanceKHR entry point [", openxr_api->get_error_string(result), "]");
}

result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsDevice2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR_ptr);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to xrGetVulkanGraphicsDevice2KHR entry point [", openxr_api->get_error_string(result), "]");
}

result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR_ptr);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to xrCreateVulkanDeviceKHR entry point [", openxr_api->get_error_string(result), "]");
}
}

XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements) {
ERR_FAIL_NULL_V(xrGetVulkanGraphicsRequirements2KHR_ptr, XR_ERROR_HANDLE_INVALID);

return (*xrGetVulkanGraphicsRequirements2KHR_ptr)(p_instance, p_system_id, p_graphics_requirements);
EXT_INIT_XR_FUNC(xrGetVulkanGraphicsRequirements2KHR);
EXT_INIT_XR_FUNC(xrCreateVulkanInstanceKHR);
EXT_INIT_XR_FUNC(xrGetVulkanGraphicsDevice2KHR);
EXT_INIT_XR_FUNC(xrCreateVulkanDeviceKHR);
EXT_INIT_XR_FUNC(xrEnumerateSwapchainImages);
}

bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_version) {
Expand Down Expand Up @@ -141,12 +102,6 @@ bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_versi
return true;
}

XrResult OpenXRVulkanExtension::xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result) {
ERR_FAIL_NULL_V(xrCreateVulkanInstanceKHR_ptr, XR_ERROR_HANDLE_INVALID);

return (*xrCreateVulkanInstanceKHR_ptr)(p_instance, p_create_info, r_vulkan_instance, r_vulkan_result);
}

bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) {
// get the vulkan version we are creating
uint32_t vulkan_version = p_vulkan_create_info->pApplicationInfo->apiVersion;
Expand Down Expand Up @@ -195,12 +150,6 @@ bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p
return true;
}

XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device) {
ERR_FAIL_NULL_V(xrGetVulkanGraphicsDevice2KHR_ptr, XR_ERROR_HANDLE_INVALID);

return (*xrGetVulkanGraphicsDevice2KHR_ptr)(p_instance, p_get_info, r_vulkan_physical_device);
}

bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) {
ERR_FAIL_NULL_V(openxr_api, false);

Expand All @@ -222,12 +171,6 @@ bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) {
return true;
}

XrResult OpenXRVulkanExtension::xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result) {
ERR_FAIL_NULL_V(xrCreateVulkanDeviceKHR_ptr, XR_ERROR_HANDLE_INVALID);

return (*xrCreateVulkanDeviceKHR_ptr)(p_instance, p_create_info, r_device, r_result);
}

bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) {
ERR_FAIL_NULL_V(openxr_api, false);

Expand Down
36 changes: 23 additions & 13 deletions modules/openxr/extensions/openxr_vulkan_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,25 @@

#include "drivers/vulkan/vulkan_context.h"

// Forward declare these so we don't need OpenXR headers where-ever this is included
// Including OpenXR at this point gives loads and loads of compile issues especially
// on Windows because windows.h is EVIL and really shouldn't be included outside of platform
// but we really don't have a choice in the matter
#include "../openxr_api.h"
#include "../util.h"

struct XrGraphicsRequirementsVulkanKHR;
struct XrVulkanInstanceCreateInfoKHR;
struct XrVulkanGraphicsDeviceGetInfoKHR;
struct XrVulkanDeviceCreateInfoKHR;
struct XrGraphicsBindingVulkanKHR;
// need to include Vulkan so we know of type definitions
#define XR_USE_GRAPHICS_API_VULKAN

#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 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 OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks {
public:
Expand Down Expand Up @@ -84,10 +93,11 @@ class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks
uint32_t vulkan_queue_family_index = 0;
uint32_t vulkan_queue_index = 0;

XrResult xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements);
XrResult xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result);
XrResult xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device);
XrResult xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result);
EXT_PROTO_XRRESULT_FUNC3(xrGetVulkanGraphicsRequirements2KHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsVulkanKHR *), p_graphics_requirements)
EXT_PROTO_XRRESULT_FUNC4(xrCreateVulkanInstanceKHR, (XrInstance), p_instance, (const XrVulkanInstanceCreateInfoKHR *), p_create_info, (VkInstance *), r_vulkan_instance, (VkResult *), r_vulkan_result)
EXT_PROTO_XRRESULT_FUNC3(xrGetVulkanGraphicsDevice2KHR, (XrInstance), p_instance, (const XrVulkanGraphicsDeviceGetInfoKHR *), p_get_info, (VkPhysicalDevice *), r_vulkan_physical_device)
EXT_PROTO_XRRESULT_FUNC4(xrCreateVulkanDeviceKHR, (XrInstance), p_instance, (const XrVulkanDeviceCreateInfoKHR *), p_create_info, (VkDevice *), r_device, (VkResult *), r_result)
EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainImages, (XrSwapchain), p_swapchain, (uint32_t), p_image_capacity_input, (uint32_t *), p_image_count_output, (XrSwapchainImageBaseHeader *), p_images)
};

#endif // OPENXR_VULKAN_EXTENSION_H
Loading

0 comments on commit d5445c2

Please sign in to comment.