android上openxr sdk查找并加载runtime流程-爱代码爱编程 (2024)

OpenXR SDK地址为:GitHub - KhronosGroup/OpenXR-SDK-Source: Sources for OpenXR loader, basic API layers, and example code.

Monado runtime地址为:Monado / Monado · GitLab

system broker地址为:Ryan Pavlik / openxr-android-broker · GitLab

本文主要讲解openxr应用如何选择monado runtime的主要流程。

其完整流程图如下

android上openxr sdk查找并加载runtime流程-爱代码爱编程 (1)

由于图太大,有的地方不清晰,故将某些部分截图重新展示

CreateInstance流程如下

android上openxr sdk查找并加载runtime流程-爱代码爱编程 (2)

查找runtime流程如下

android上openxr sdk查找并加载runtime流程-爱代码爱编程 (3)

API layer load流程图如下

android上openxr sdk查找并加载runtime流程-爱代码爱编程 (4)

具体流程如下

目录

1.实例化OpenXrProgram

2.CreateOpenXrProgram

3. 实例化后会CreateInstance

4. LogLayersAndExtensions

5.xrEnumerateInstanceExtensionProperties

6.LoaderXrEnumerateInstanceExtensionProperties

7. RuntimeInterface::LoadRuntime-查找并加载runtime

8.RuntimeManifestFile::FindManifestFiles--查找runtime

9.GetPlatformRuntimeVirtualManifest--查找runtime-标志1

10.getActiveRuntimeVirtualManifest--查找runtime-标志1

11. PlatformGetGlobalRuntimeFileName--查找runtime-标志3

12.CreateIfValid-标志2

13.CreateIfValid-标志4

14. TryLoadingSingleRuntime--加载runtime-标志3

以SDK中的hello_xr应用为例,其入口在main.cpp中

1.实例化OpenXrProgram

main.cppvoid android_main(struct android_app* app) {...// Initialize the OpenXR program.//实例化OpenXrProgramstd::shared_ptr<IOpenXrProgram> program = CreateOpenXrProgram(options, platformPlugin, graphicsPlugin);// Initialize the loader for this platformPFN_xrInitializeLoaderKHR initializeLoader = nullptr;//将LoaderXrInitializeLoaderKHR方法指针赋值给initializeLoaderif (XR_SUCCEEDED( xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)(&initializeLoader)))) { XrLoaderInitInfoAndroidKHR loaderInitInfoAndroid = {XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR}; loaderInitInfoAndroid.applicationVM = app->activity->vm; loaderInitInfoAndroid.applicationContext = app->activity->clazz;//执行LoaderXrInitializeLoaderKHR方法 initializeLoader((const XrLoaderInitInfoBaseHeaderKHR*)&loaderInitInfoAndroid);}//CreateInstanceprogram->CreateInstance();program->InitializeSystem();...}

2.CreateOpenXrProgram

openxr_program.cpp

std::shared_ptr<IOpenXrProgram> CreateOpenXrProgram(const std::shared_ptr<Options>& options, const std::shared_ptr<IPlatformPlugin>& platformPlugin, const std::shared_ptr<IGraphicsPlugin>& graphicsPlugin) {//make_shared函数的主要功能是在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr;由于是通过shared_ptr管理内存,因此一种安全分配和使用动态内存的方法。 return std::make_shared<OpenXrProgram>(options, platformPlugin, graphicsPlugin);}
struct OpenXrProgram : IOpenXrProgram { OpenXrProgram(const std::shared_ptr<Options>& options, const std::shared_ptr<IPlatformPlugin>& platformPlugin, const std::shared_ptr<IGraphicsPlugin>& graphicsPlugin) : m_options(options),//赋值 m_platformPlugin(platformPlugin), m_graphicsPlugin(graphicsPlugin), m_acceptableBlendModes{XR_ENVIRONMENT_BLEND_MODE_OPAQUE, XR_ENVIRONMENT_BLEND_MODE_ADDITIVE, XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND} {}

3. 实例化后会CreateInstance

openxr_program.cppvoid CreateInstance() override { LogLayersAndExtensions(); CreateInstanceInternal(); LogInstanceInfo();}

4. LogLayersAndExtensions

openxr_program.cppstatic void LogLayersAndExtensions() { // Write out extension properties for a given layer. const auto logExtensions = [](const char* layerName, int indent = 0) { uint32_t instanceExtensionCount; //CHECK_XRCMD是用于判断函数是否执行FAILED //xrEnumerateInstanceExtensionProperties返回可用实例扩展的属性 CHECK_XRCMD(xrEnumerateInstanceExtensionProperties(layerName, 0, &instanceExtensionCount, nullptr));......}

5.xrEnumerateInstanceExtensionProperties

loader_core.cppLOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput, XrExtensionProperties *properties) { return LoaderXrEnumerateInstanceExtensionProperties(layerName, propertyCapacityInput, propertyCountOutput, properties);}

6.LoaderXrEnumerateInstanceExtensionProperties

loader_core.cppstatic XRAPI_ATTR XrResult XRAPI_CALLLoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput, XrExtensionProperties *properties) XRLOADER_ABI_TRY { ... // Get the layer extension properties result = ApiLayerInterface::GetInstanceExtensionProperties("xrEnumerateInstanceExtensionProperties", layerName, extension_properties); if (XR_SUCCEEDED(result) && !just_layer_properties) { // If not specific to a layer, get the runtime extension properties //如果不是特定于某个层,则获取运行时扩展属性 result = RuntimeInterface::LoadRuntime("xrEnumerateInstanceExtensionProperties"); if (XR_SUCCEEDED(result)) { RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties); ...}

7. RuntimeInterface::LoadRuntime-查找并加载runtime

runtime_interface.cppXrResult RuntimeInterface::LoadRuntime(const std::string& openxr_command) { // If something's already loaded, we're done here. //如果已经有Instance实例了,则return, 这代表一个APP只有一个Instance实例 if (GetInstance() != nullptr) { return XR_SUCCESS; }#ifdef XR_KHR_LOADER_INIT_SUPPORT if (!LoaderInitData::instance().initialized()) {//Instance没有成功初始化 LoaderLogger::LogErrorMessage( openxr_command, "RuntimeInterface::LoadRuntime cannot run because xrInitializeLoaderKHR was not successfully called."); return XR_ERROR_INITIALIZATION_FAILED; }#endif // XR_KHR_LOADER_INIT_SUPPORT std::vector<std::unique_ptr<RuntimeManifestFile>> runtime_manifest_files = {}; // Find the available runtimes which we may need to report information for. //查找可用的runtime,会对runtime_manifest_files赋值 XrResult last_error = RuntimeManifestFile::FindManifestFiles(runtime_manifest_files); if (XR_FAILED(last_error)) { LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - unknown error"); } else { last_error = XR_ERROR_RUNTIME_UNAVAILABLE; for (std::unique_ptr<RuntimeManifestFile>& manifest_file : runtime_manifest_files) { //加载runtime-----标志5 last_error = RuntimeInterface::TryLoadingSingleRuntime(openxr_command, manifest_file); if (XR_SUCCEEDED(last_error)) { break; } } } // Unsuccessful in loading any runtime, throw the runtime unavailable message. //如果没有加载到任何的runtime,会返回错误,且应用无法正常运转,表现大多为黑屏,或者卡在启动动画上 if (XR_FAILED(last_error)) { LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - failed to load a runtime"); last_error = XR_ERROR_RUNTIME_UNAVAILABLE; } return last_error;}

8.RuntimeManifestFile::FindManifestFiles--查找runtime

manifest_file.cpp// Find all manifest files in the appropriate search paths/registries for the given type.XrResult RuntimeManifestFile::FindManifestFiles(std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) {#if defined(XR_KHR_LOADER_INIT_SUPPORT) Json::Value virtualManifest; //获取runtime result = GetPlatformRuntimeVirtualManifest(virtualManifest);//标志1 if (XR_SUCCESS == result) { //将获取到的virtualManifest中的信息赋值给manifest_files RuntimeManifestFile::CreateIfValid(virtualManifest, "", manifest_files);//标志2 return result; }#endif // defined(XR_KHR_LOADER_INIT_SUPPORT)//如果上面通过GetPlatformRuntimeVirtualManifest没有找到runtime,则会通过PlatformGetGlobalRuntimeFileName继续查找 if (!PlatformGetGlobalRuntimeFileName(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), filename)) {//标志3 LoaderLogger::LogErrorMessage( "", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment"); return XR_ERROR_RUNTIME_UNAVAILABLE; } result = XR_SUCCESS; LoaderLogger::LogInfoMessage("", "RuntimeManifestFile::FindManifestFiles - using global runtime file " + filename);#endif }  //将filename文件中的信息赋值给manifest_files  RuntimeManifestFile::CreateIfValid(filename, manifest_files);//标志4...}

9.GetPlatformRuntimeVirtualManifest--查找runtime-标志1

runtime_interface.cpp#ifdef XR_USE_PLATFORM_ANDROIDXrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) { using wrap::android::content::Context; auto& initData = LoaderInitData::instance(); if (!initData.initialized()) { return XR_ERROR_INITIALIZATION_FAILED; } auto context = Context(reinterpret_cast<jobject>(initData.getData().applicationContext)); if (context.isNull()) { return XR_ERROR_INITIALIZATION_FAILED; } Json::Value virtualManifest; //即将通过Cursor要去查系统中的runtime了 if (0 != openxr_android::getActiveRuntimeVirtualManifest(context, virtualManifest)) { return XR_ERROR_INITIALIZATION_FAILED; } //virtualManifest赋值给out_manifest  out_manifest = virtualManifest; return XR_SUCCESS;}#endif // XR_USE_PLATFORM_ANDROID

10.getActiveRuntimeVirtualManifest--查找runtime-标志1

android_utilities.cpp

int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest) { jni::Array<std::string> projection = makeArray({active_runtime::Columns::PACKAGE_NAME,active_runtime::Columns::NATIVE_LIB_DIR, active_runtime::Columns::SO_FILENAME, active_runtime::Columns::HAS_FUNCTIONS}); // First, try getting the installable broker's provider bool systemBroker = false; Cursor cursor; //log输出:08-02 08:43:48.651 4294 4331 I OpenXR-Loader: getActiveRuntimeCursor: Querying URI: content://org.khronos.openxr.runtime_broker/openxr/1/abi/arm64-v8a/runtimes/active/0//非系统应用 if (!getActiveRuntimeCursor(context, projection, systemBroker, cursor)) { // OK, try the system broker as a fallback. //是系统应用,不是通过用户去安装的 systemBroker = true; getActiveRuntimeCursor(context, projection, systemBroker, cursor); //log输出:08-02 08:43:48.654 4294 4331 I OpenXR-Loader: getActiveRuntimeCursor: Querying URI: content://org.khronos.openxr.system_runtime_broker/openxr/1/abi/arm64-v8a/runtimes/active/0 } if (cursor.isNull()) { // Couldn't find either broker ALOGE("Could access neither the installable nor system runtime broker."); return -1; } cursor.moveToFirst();//通过cursor去查column对应的内容 auto filename = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::SO_FILENAME)); auto libDir = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::NATIVE_LIB_DIR)); auto packageName = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::PACKAGE_NAME)); auto hasFunctions = cursor.getInt(cursor.getColumnIndex(active_runtime::Columns::HAS_FUNCTIONS)) == 1; __android_log_print(ANDROID_LOG_INFO, TAG, "Got runtime: package: %s, so filename: %s, native lib dir: %s, has functions: %s", packageName.c_str(), filename.c_str(), libDir.c_str(), (hasFunctions ? "yes" : "no"));//log输出: 08-02 08:39:29.543 4425 4462 I OpenXR-Loader: Got runtime: package: org.freedesktop.monado.openxr_runtime.out_of_process, so filename: libopenxr_monado.so, native lib dir:/data/app/~~ZNtBhWeJzxYgOPuiZZVjgQ==/org.freedesktop.monado.openxr_runtime.out_of_process-PVkP76Im0S4PZZp5d2Gb5g==/lib/arm64, has functions: no//可以看到通过URI查出来的包名是org.freedesktop.monado.openxr_runtime.out_of_process, 对应的runtime so名字是libopenxr_monado.so auto lib_path = libDir + "/" + filename;//lib_path就是runtime so的全路径 cursor.close();//创建json文件,并将lib_path传入,root 名为runtime, lib_path为子节点 JsonManifestBuilder builder{"runtime", lib_path}; if (hasFunctions) { int result = populateFunctions(context, systemBroker, packageName, builder); if (result != 0) { return result; } }//json文件创建 virtualManifest = builder.build(); return 0;}} // namespace openxr_android

11. PlatformGetGlobalRuntimeFileName--查找runtime-标志3

platform_utils.hpp此函数会在"/product", "/odm", "/oem", "/vendor", "/system"目录下的/etc/openxr/下查找active_runtime.json文件// Intended to be only used as a fallback on Android, with a more open, "native" technique used in most casesstatic inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string& file_name) { // Prefix for the runtime JSON file name static const char* rt_dir_prefixes[] = {"/product", "/odm", "/oem", "/vendor", "/system"}; static const std::string rt_filename = "/active_runtime.json"; static const std::string subdir = "/etc/openxr/"; for (const auto prefix : rt_dir_prefixes) { auto path = prefix + subdir + std::to_string(major_version) + rt_filename; struct stat buf; if (0 == stat(path.c_str(), &buf)) { file_name = path;//返回active_runtime.json所在的目录 return true; } } return false;}

12.CreateIfValid-标志2

manifest_file.cppvoid RuntimeManifestFile::CreateIfValid(const Json::Value &root_node, const std::string &filename,std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) { std::ostringstream error_ss("RuntimeManifestFile::CreateIfValid "); JsonVersion file_version = {}; if (!ManifestFile::IsValidJson(root_node, file_version)) { error_ss << "isValidJson indicates " << filename << " is not a valid manifest file."; LoaderLogger::LogErrorMessage("", error_ss.str()); return; }// Json的root节点是runtime,子节点是library_path,如果有一个为空,则return const Json::Value &runtime_root_node = root_node["runtime"]; // The Runtime manifest file needs the "runtime" root as well as a sub-node for "library_path". If any of those aren't there, // fail. if (runtime_root_node.isNull() || runtime_root_node["library_path"].isNull() || !runtime_root_node["library_path"].isString()) { error_ss << filename << " is missing required fields. Verify all proper fields exist."; LoaderLogger::LogErrorMessage("", error_ss.str()); return; }//将子节点library_path的转化为string类型 std::string lib_path = runtime_root_node["library_path"].asString(); // If the library_path variable has no directory symbol, it's just a file name and should be accessible on the // global library path. if (lib_path.find('\\') != std::string::npos || lib_path.find('/') != std::string::npos) { // If the library_path is an absolute path, just use that if it exists//如果lib_path是绝对路径,如果存在则直接使用, 我们上面存的是绝对路径 if (FileSysUtilsIsAbsolutePath(lib_path)) { if (!FileSysUtilsPathExists(lib_path)) { error_ss << filename << " library " << lib_path << " does not appear to exist"; LoaderLogger::LogErrorMessage("", error_ss.str()); return; } } else { ... } } //add manifest files // Add this runtime manifest file manifest_files.emplace_back(new RuntimeManifestFile(filename, lib_path)); // Add any extensions to it after the fact. // Handle any renamed functions manifest_files.back()->ParseCommon(runtime_root_node);}

13.CreateIfValid-标志4

manifest_file.cppvoid RuntimeManifestFile::CreateIfValid(std::string const &filename , std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) { std::ifstream json_stream(filename, std::ifstream::in); LoaderLogger::LogInfoMessage("", "RuntimeManifestFile::CreateIfValid - attempting to load " + filename); std::ostringstream error_ss("RuntimeManifestFile::CreateIfValid "); if (!json_stream.is_open()) { error_ss << "failed to open " << filename << ". Does it exist?"; LoaderLogger::LogErrorMessage("", error_ss.str()); return; } Json::CharReaderBuilder builder; std::string errors; Json::Value root_node = Json::nullValue;...//会调用到12步 CreateIfValid(root_node, filename, manifest_files);}

14. TryLoadingSingleRuntime--加载runtime-标志5

runtime_interface.cppXrResult RuntimeInterface::TryLoadingSingleRuntime(const std::string& openxr_command, std::unique_ptr<RuntimeManifestFile>& manifest_file) { LoaderPlatformLibraryHandle runtime_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());//dlopen runtime so...#ifdef XR_KHR_LOADER_INIT_SUPPORT if (!LoaderInitData::instance().initialized()) { LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntime skipping manifest file " +manifest_file->Filename() +" because xrInitializeLoaderKHR was not yet called.");... // If we have xrInitializeLoaderKHR exposed as an export, forward call to it. const auto function_name = manifest_file->GetFunctionName("xrInitializeLoaderKHR"); auto initLoader = reinterpret_cast<PFN_xrInitializeLoaderKHR>(LoaderPlatformLibraryGetProcAddr(runtime_library, function_name));//dlsym if (initLoader != nullptr) {//initLoader为空... } }...// Get and settle on an runtime interface version (using any provided name if required).std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderRuntimeInterface");auto negotiate = reinterpret_cast<PFN_xrNegotiateLoaderRuntimeInterface>(LoaderPlatformLibraryGetProcAddr(runtime_library, function_name));//dlsym...// Skip calling the negotiate function and fail if the function pointer// could not get loadedXrResult res = XR_ERROR_RUNTIME_FAILURE;if (nullptr != negotiate) { //执行runtime中的xrNegotiateLoaderRuntimeInterface方法 //会对runtime_info结构体中的子变量getInstanceProcAddr赋值,赋值成了runtime中的方法,方法名为oxr_xrGetInstanceProcAddr res = negotiate(&loader_info, &runtime_info);}...#ifdef XR_KHR_LOADER_INIT_SUPPORT if (XR_SUCCEEDED(res) && !forwardedInitLoader) { // Forward initialize loader call, where possible and if we did not do so before. PFN_xrVoidFunction initializeVoid = nullptr; PFN_xrInitializeLoaderKHR initialize = nullptr; // Now we may try asking xrGetInstanceProcAddr //执行runtime中的oxr_xrGetInstanceProcAddr方法,会将xrInitializeLoaderKHR方法指针赋值为runtime中的oxr_xrInitializeLoaderKHR if (XR_SUCCEEDED(runtime_info.getInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", &initializeVoid))) {// if (initializeVoid == nullptr) { LoaderLogger::LogErrorMessage(openxr_command,"RuntimeInterface::LoadRuntime got success from xrGetInstanceProcAddr ""for xrInitializeLoaderKHR, but output a null pointer."); res = XR_ERROR_RUNTIME_FAILURE; } else {//将initializeVoid函数指针赋值给initialize  initialize = reinterpret_cast<PFN_xrInitializeLoaderKHR>(initializeVoid); } } if (initialize != nullptr) { // we found the entry point one way or another. LoaderLogger::LogInfoMessage(openxr_command,"RuntimeInterface::LoadRuntime forwarding xrInitializeLoaderKHR call to runtime after calling xrNegotiateLoaderRuntimeInterface.");//执行runtime中的oxr_xrInitializeLoaderKHR方法 res = initialize(LoaderInitData::instance().getParam()); if (!XR_SUCCEEDED(res)) {LoaderLogger::LogErrorMessage(openxr_command,"RuntimeInterface::LoadRuntime forwarded call to xrInitializeLoaderKHR failed."); } } }...// Use this runtime//使用这个runtime GetInstance().reset(new RuntimeInterface(runtime_library, runtime_info.getInstanceProcAddr));...}
android上openxr sdk查找并加载runtime流程-爱代码爱编程 (2024)

References

Top Articles
Latest Posts
Article information

Author: Terence Hammes MD

Last Updated:

Views: 5430

Rating: 4.9 / 5 (69 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Terence Hammes MD

Birthday: 1992-04-11

Address: Suite 408 9446 Mercy Mews, West Roxie, CT 04904

Phone: +50312511349175

Job: Product Consulting Liaison

Hobby: Jogging, Motor sports, Nordic skating, Jigsaw puzzles, Bird watching, Nordic skating, Sculpting

Introduction: My name is Terence Hammes MD, I am a inexpensive, energetic, jolly, faithful, cheerful, proud, rich person who loves writing and wants to share my knowledge and understanding with you.