OpenXR+Runtime:OpenXR SDK与Runtime的衔接

仍然以OpenXR SDK源码和Monado runtime源码来分析

以CreateSwapchains()函数为例来串一下,看看OpenXR SDK和runtime是怎么链接起来的

OpenXR SDK的源码里有一个hello_xr的sample code,

这个hello_xr 的main函数:void android_main(struct android_app* app)在 :

src\tests\hello_xr\main.cpp

/**
 * This is the main entry point of a native application that is using
 * android_native_app_glue.  It runs in its own thread, with its own
 * event loop for receiving input events and doing other things.
 */
void android_main(struct android_app* app) {
    try {
        JNIEnv* Env;
        app->activity->vm->AttachCurrentThread(&Env, nullptr);

        ...
        ...


        // Initialize the loader for this platform
        PFN_xrInitializeLoaderKHR initializeLoader = nullptr;
        if (XR_SUCCEEDED(
                xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)(&initializeLoader)))) {
            XrLoaderInitInfoAndroidKHR loaderInitInfoAndroid;
            memset(&loaderInitInfoAndroid, 0, sizeof(loaderInitInfoAndroid));
            loaderInitInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR;
            loaderInitInfoAndroid.next = NULL;
            loaderInitInfoAndroid.applicationVM = app->activity->vm;
            loaderInitInfoAndroid.applicationContext = app->activity->clazz;
            initializeLoader((const XrLoaderInitInfoBaseHeaderKHR*)&loaderInitInfoAndroid);
        }

        program->CreateInstance();
        program->InitializeSystem();
        program->InitializeSession();
        program->CreateSwapchains();

        ...
        ...
}

这里面会做很多事情,其中有一句:

program->CreateSwapchains();

CreateSwapchains()的定义在:

src\tests\hello_xr\openxr_program.cpp

void CreateSwapchains() override {
    ...
    ...    

        // Create a swapchain for each view.
        for (uint32_t i = 0; i < viewCount; i++) {
            const XrViewConfigurationView& vp = m_configViews[i];
            Log::Write(Log::Level::Info,
                       Fmt("Creating swapchain for view %d with dimensions Width=%d Height=%d SampleCount=%d", i,
                           vp.recommendedImageRectWidth, vp.recommendedImageRectHeight, vp.recommendedSwapchainSampleCount));

            // Create the swapchain.
            XrSwapchainCreateInfo swapchainCreateInfo{XR_TYPE_SWAPCHAIN_CREATE_INFO};
            swapchainCreateInfo.arraySize = 1;
            swapchainCreateInfo.format = m_colorSwapchainFormat;
            swapchainCreateInfo.width = vp.recommendedImageRectWidth;
            swapchainCreateInfo.height = vp.recommendedImageRectHeight;
            swapchainCreateInfo.mipCount = 1;
            swapchainCreateInfo.faceCount = 1;
            swapchainCreateInfo.sampleCount = m_graphicsPlugin->GetSupportedSwapchainSampleCount(vp);
            swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
            Swapchain swapchain;
            swapchain.width = swapchainCreateInfo.width;
            swapchain.height = swapchainCreateInfo.height;
            CHECK_XRCMD(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle));

            ...
            ...
        }
   ...
}

代码很多,其中有一句:

CHECK_XRCMD(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle));

注意这个xrCreateSwapchain(...)函数的三个参数:

XrSession m_session{XR_NULL_HANDLE};

XrSwapchainCreateInfo swapchainCreateInfo{XR_TYPE_SWAPCHAIN_CREATE_INFO};

struct Swapchain {
    XrSwapchain handle;
    int32_t width;
    int32_t height;
}; 实例的成员 XrSwapchain handle;

全局搜索xrCreateSwapchain(...)函数,

发现他在这两个文件中分别有包含

src\loader\openxr-loader.def

src\loader\openxr-loader.map

这两份文件中就包含了OpenXR SDK 和 Runtime 中需要进行衔接的Api:

OpenXR+Runtime:OpenXR SDK与Runtime的衔接_第1张图片

通过对openxr-loader.def 和 openxr-loader.map两个文件的全局查找可以看到

src\loader\CMakeLists.txt 里分别有如下两段:

if(DYNAMIC_LOADER) add_definitions(-DXRAPI_DLL_EXPORT)
    set(LIBRARY_TYPE SHARED)
    if(WIN32) list(APPEND openxr_loader_RESOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/openxr-loader.def) 
    endif() 
else() # build static lib 
    set(LIBRARY_TYPE STATIC) 
endif()
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") 
   target_compile_options( openxr_loader
        PRIVATE -Wextra
                -fno-strict-aliasing
                -fno-builtin-memcmp
                "$<$:-fno-rtti>"
                -ffunction-sections
                -fdata-sections )
    # Make build depend on the version script/export map
    target_sources(openxr_loader PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/openxr-loader.map) 
    # Add the linker flag.
    set_target_properties(openxr_loader PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/openxr-loader.map") 
   # For GCC version 7.1 or greater, we need to disable the implicit fallthrough warning since 
   # there's no consistent way to satisfy all compilers until they all accept the C++17 standard 
   if(CMAKE_COMPILER_IS_GNUCC AND NOT (CMAKE_CXX_COMPILER_VERSION LESS 7.1)) 
      target_compile_options(openxr_loader PRIVATE -Wimplicit-fallthrough=0) 
   endif() 
endif()

从这两段代码可以很明显的看到在编译时,

openxr-loader.def 和 openxr-loader.map会被加载,

openxr-loader.def 是被Win32位的系统加载。

再接着看monado runtime这边,是如何实现 xrCreateSwapchain(..)函数的

首先 src\external\openxr_includes\openxr\openxr_platform_defines.h 定义了很多宏,重点看看下面这段及其注释:

/* Platform-specific calling convention macros.
 *
 * Platforms should define these so that OpenXR clients call OpenXR functions
 * with the same calling conventions that the OpenXR implementation expects.
 *
 * XRAPI_ATTR - Placed before the return type in function declarations.
 *              Useful for C++11 and GCC/Clang-style function attribute syntax.
 * XRAPI_CALL - Placed after the return type in function declarations.
 *              Useful for MSVC-style calling convention syntax.
 * XRAPI_PTR  - Placed between the '(' and '*' in function pointer types.
 *
 * Function declaration:  XRAPI_ATTR void XRAPI_CALL xrFunction(void);
 * Function pointer type: typedef void (XRAPI_PTR *PFN_xrFunction)(void);
 */

#if defined(_WIN32)
#define XRAPI_ATTR
// On Windows, functions use the stdcall convention
#define XRAPI_CALL __stdcall
#define XRAPI_PTR XRAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
#error "API not supported for the 'armeabi' NDK ABI"
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
// On Android 32-bit ARM targets, functions use the "hardfloat"
// calling convention, i.e. float parameters are passed in registers. This
// is true even if the rest of the application passes floats on the stack,
// as it does by default when compiling for the armeabi-v7a NDK ABI.
#define XRAPI_ATTR __attribute__((pcs("aapcs-vfp")))
#define XRAPI_CALL
#define XRAPI_PTR XRAPI_ATTR
#else
// On other platforms, use the default calling convention
#define XRAPI_ATTR
#define XRAPI_CALL
#define XRAPI_PTR
#endif

src\external\openxr_includes\openxr\openxr.h

里对openxr-loader.map的每个函数都进行声明,同时还声明了很多结构体。

typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchain)(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain);

XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain(
    XrSession                                   session,
    const XrSwapchainCreateInfo*                createInfo,
    XrSwapchain*                                swapchain);

src\xrt\state_trackers\oxr\oxr_api_funcs.h 中,

同样对openxr-loader.map里的所有函数按照功能,分别进行了声明。

 * oxr_api_negotiate.c
 * oxr_api_instance.c
 * oxr_api_system.c
 * oxr_api_session.c
 * oxr_api_space.c

 * oxr_api_swapchain.c
//! OpenXR API function @ep{xrEnumerateSwapchainFormats}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrEnumerateSwapchainFormats(XrSession session,
                                uint32_t formatCapacityInput,
                                uint32_t *formatCountOutput,
                                int64_t *formats);

//! OpenXR API function @ep{xrCreateSwapchain}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrCreateSwapchain(XrSession session, const XrSwapchainCreateInfo *createInfo, XrSwapchain *swapchain);

//! OpenXR API function @ep{xrDestroySwapchain}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrDestroySwapchain(XrSwapchain swapchain);

//! OpenXR API function @ep{xrEnumerateSwapchainImages}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrEnumerateSwapchainImages(XrSwapchain swapchain,
                               uint32_t imageCapacityInput,
                               uint32_t *imageCountOutput,
                               XrSwapchainImageBaseHeader *images);

//! OpenXR API function @ep{xrAcquireSwapchainImage}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrAcquireSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageAcquireInfo *acquireInfo, uint32_t *index);

//! OpenXR API function @ep{xrWaitSwapchainImage}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrWaitSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageWaitInfo *waitInfo);

//! OpenXR API function @ep{xrReleaseSwapchainImage}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrReleaseSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageReleaseInfo *releaseInfo);

 * oxr_api_debug.c
 * oxr_api_action.c

并且在 src\xrt\state_trackers\oxr 目录下分别进行函数实现:

OpenXR+Runtime:OpenXR SDK与Runtime的衔接_第2张图片

src\xrt\state_trackers\oxr\CMakeLists.txt 里可以看到,Runtime中对OpenXR SDK需要衔接的函数实现,会编译成库的形式提供给OpenXR SDK使用。

OpenXR+Runtime:OpenXR SDK与Runtime的衔接_第3张图片

就目前来看,src\xrt\state_trackers\oxr\ 下以 oxr_api_ 为前缀的文件和CMakeLists.txt,才是对OpenXR SDK 中 openxr-loader.map 里函数的实现。

暂时不太清楚之前提到的 src\external\openxr_includes\openxr\ 这个目录里对 openxr-loader.map 的函数声明是做何用。

oxr_xrCreateSwapchain()函数在src\xrt\state_trackers\oxr\oxr_api_swapchain.c 中被具体定义实现:

XrResult
oxr_xrCreateSwapchain(XrSession session, const XrSwapchainCreateInfo *createInfo, XrSwapchain *out_swapchain)
{
	OXR_TRACE_MARKER();

	XrResult ret;
	struct oxr_session *sess;
	struct oxr_swapchain *sc;
	struct oxr_logger log;
	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrCreateSwapchain");
	if (sess->compositor == NULL) {
		return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "Is illegal in headless sessions");
	}

    ...    

	// Short hand.
	struct oxr_instance *inst = sess->sys->inst;

	XrSwapchainUsageFlags flags = 0;
	flags |= XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
	flags |= XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
	flags |= XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT;
	flags |= XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT;
	flags |= XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT;
	flags |= XR_SWAPCHAIN_USAGE_SAMPLED_BIT;
	flags |= XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT;
	if (inst->extensions.MND_swapchain_usage_input_attachment_bit ||
	    inst->extensions.KHR_swapchain_usage_input_attachment_bit) {
		// aliased to XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND
		flags |= XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR;
	}

    ...

	return oxr_session_success_result(sess);
}

这就是以 CreateSwapchains() 函数为例,OpenXR SDK 与 Monado Runtime的链接过程

你可能感兴趣的:(xr)