美文网首页
对OpenXR 的一些理解

对OpenXR 的一些理解

作者: 赛非斯 | 来源:发表于2022-03-18 00:13 被阅读0次

参考官方文档openxr-10-reference-guide

  • 一个标准的openxr应用包含方法调用、对象创建、Session状态变化、渲染循环等


    image.png
  • 以monon的openxr runtime为例,主要涉及以下几个大的模块

1、连接方面,有蓝牙设备,和usb设备,涉及蓝牙通信和HID通信
2、语言方面设计openxr 、vulkan、opengl等
3、api方面有交换链、session会话、event队列
4、ipc通信方面有soctet通信、匿名共享内存
5、渲染方面主要是vulkan 语法和 shader

  • monon的数据来源主要是获取手机自带的加速度和陀螺仪 模拟成3dof数据
while (ASensorEventQueue_getEvents(d->event_queue, &event, 1) > 0) {

        switch (event.type) {
        case ASENSOR_TYPE_ACCELEROMETER: {
            accel.x = event.acceleration.y;
            accel.y = -event.acceleration.x;
            accel.z = event.acceleration.z;

            ANDROID_TRACE(d, "accel %ld %.2f %.2f %.2f", event.timestamp, accel.x, accel.y, accel.z);
            break;
        }
        case ASENSOR_TYPE_GYROSCOPE: {
            gyro.x = -event.data[1];
            gyro.y = event.data[0];
            gyro.z = event.data[2];

            ANDROID_TRACE(d, "gyro %ld %.2f %.2f %.2f", event.timestamp, gyro.x, gyro.y, gyro.z);

            // TODO: Make filter handle accelerometer
            struct xrt_vec3 null_accel;

            // Lock last and the fusion.
            os_mutex_lock(&d->lock);

            m_imu_3dof_update(&d->fusion, event.timestamp, &null_accel, &gyro);

            // Now done.
            os_mutex_unlock(&d->lock);
        }
        default: ANDROID_TRACE(d, "Unhandled event type %d", event.type);
        }
    }
  • monon的openxr Runingtime Session创建过程,
    1、有个宏控XR_USE_GRAPHICS_API_VULKAN 表示用vulkan作为图形库的语言。
//src/xrt/state_trackers/oxr/oxr_api_session.c
XrResult
oxr_xrCreateSession(XrInstance instance, const XrSessionCreateInfo *createInfo, XrSession *out_session)
{
    OXR_TRACE_MARKER();

      ret = oxr_session_create(&log, &inst->system, createInfo, &sess);
}
//src/xrt/state_trackers/oxr/oxr_session.c

XrResult
oxr_session_create(struct oxr_logger *log,
                   struct oxr_system *sys,
                   const XrSessionCreateInfo *createInfo,
                   struct oxr_session **out_session)
{
XrResult ret = oxr_session_create_impl(log, sys, createInfo, &xsi, &sess);

}

/* Just the allocation and populate part, so we can use early-returns to
 * simplify code flow and avoid weird if/else */
static XrResult
oxr_session_create_impl(struct oxr_logger *log,
                        struct oxr_system *sys,
                        const XrSessionCreateInfo *createInfo,
                        const struct xrt_session_info *xsi,
                        struct oxr_session **out_session){
#ifdef XR_USE_GRAPHICS_API_VULKAN
    XrGraphicsBindingVulkanKHR const *vulkan =
        OXR_GET_INPUT_FROM_CHAIN(createInfo, XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, XrGraphicsBindingVulkanKHR);
    if (vulkan != NULL) {
        OXR_VERIFY_ARG_NOT_ZERO(log, vulkan->instance);
        OXR_VERIFY_ARG_NOT_ZERO(log, vulkan->physicalDevice);
        if (vulkan->device == VK_NULL_HANDLE) {
            return oxr_error(log, XR_ERROR_GRAPHICS_DEVICE_INVALID, "VkDevice must not be VK_NULL_HANDLE");
        }

        if (!sys->gotten_requirements) {
            return oxr_error(log, XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING,
                             "Has not called "
                             "xrGetVulkanGraphicsRequirementsKHR");
        }

        if (sys->suggested_vulkan_physical_device == VK_NULL_HANDLE) {
            char *fn = sys->inst->extensions.KHR_vulkan_enable ? "xrGetVulkanGraphicsDeviceKHR"
                                                               : "xrGetVulkanGraphicsDevice2KHR";
            return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "Has not called %s", fn);
        }

        if (sys->suggested_vulkan_physical_device != vulkan->physicalDevice) {
            char *fn = sys->inst->extensions.KHR_vulkan_enable ? "xrGetVulkanGraphicsDeviceKHR"
                                                               : "xrGetVulkanGraphicsDevice2KHR";
            return oxr_error(
                log, XR_ERROR_VALIDATION_FAILURE,
                "XrGraphicsBindingVulkanKHR::physicalDevice %p must match device %p specified by %s",
                (void *)vulkan->physicalDevice, (void *)sys->suggested_vulkan_physical_device, fn);
        }

        OXR_SESSION_ALLOCATE(log, sys, *out_session);
        OXR_ALLOCATE_NATIVE_COMPOSITOR(log, xsi, *out_session);
        return oxr_session_populate_vk(log, sys, vulkan, *out_session);//这里表示用的是vk,还可以选择用opengl
    }
#endif
}

2、XrGraphicsBindingVulkanKHR 是xr图形绑定vulkan语言支持扩展

//src/xrt/state_trackers/oxr/oxr_session_gfx_vk.c
XrResult
oxr_session_populate_vk(struct oxr_logger *log,
                        struct oxr_system *sys,
                        XrGraphicsBindingVulkanKHR const *next,
                        struct oxr_session *sess)
{
struct xrt_compositor_native *xcn = sess->xcn;
    struct xrt_compositor_vk *xcvk = xrt_gfx_vk_provider_create( //
        xcn,                                                     //
        next->instance,                                          //
        vkGetInstanceProcAddr,                                   //
        next->physicalDevice,                                    //
        next->device,                                            //
        sess->sys->vk.timeline_semaphore_enabled,                //
        next->queueFamilyIndex,                                  //
        next->queueIndex);                                       //

    if (xcvk == NULL) {
        return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "Failed to create an vk client compositor");
    }

    sess->compositor = &xcvk->base;
    sess->create_swapchain = oxr_swapchain_vk_create;  //指定交换链创建

    return XR_SUCCESS;
}
//src/xrt/compositor/client/comp_vk_glue.c 
client_vk_compositor_create

//src/xrt/compositor/client/comp_vk_client.c
struct client_vk_compositor *
client_vk_compositor_create(struct xrt_compositor_native *xcn,
                            VkInstance instance,
                            PFN_vkGetInstanceProcAddr getProc,
                            VkPhysicalDevice physicalDevice,
                            VkDevice device,
                            bool timeline_semaphore_enabled,
                            uint32_t queueFamilyIndex,
                            uint32_t queueIndex)
{
//主要是初始化渲染相关的一些东西了
    c->base.base.create_swapchain = client_vk_swapchain_create;
    c->base.base.begin_session = client_vk_compositor_begin_session;
    c->base.base.end_session = client_vk_compositor_end_session;
    c->base.base.wait_frame = client_vk_compositor_wait_frame;
    c->base.base.begin_frame = client_vk_compositor_begin_frame;
    c->base.base.discard_frame = client_vk_compositor_discard_frame;
    c->base.base.layer_begin = client_vk_compositor_layer_begin;
    c->base.base.layer_stereo_projection = client_vk_compositor_layer_stereo_projection;
    c->base.base.layer_stereo_projection_depth = client_vk_compositor_layer_stereo_projection_depth;
    c->base.base.layer_quad = client_vk_compositor_layer_quad;
    c->base.base.layer_cube = client_vk_compositor_layer_cube;
    c->base.base.layer_cylinder = client_vk_compositor_layer_cylinder;
    c->base.base.layer_equirect1 = client_vk_compositor_layer_equirect1;
    c->base.base.layer_equirect2 = client_vk_compositor_layer_equirect2;
    c->base.base.layer_commit = client_vk_compositor_layer_commit;
    c->base.base.destroy = client_vk_compositor_destroy;
    c->base.base.poll_events = client_vk_compositor_poll_events;
}

3、client 里面的client_vk_compositor_create 中的c->base.base.begin_session = client_vk_compositor_begin_session; 可以看出 调用到 xc->begin_session ,这里的xc 就是传过来的
xrt_compositor_native 结构体中的base -->struct xrt_compositor base;

static xrt_result_t
client_vk_compositor_begin_session(struct xrt_compositor *xc, enum xrt_view_type type)
{
    COMP_TRACE_MARKER();

    struct client_vk_compositor *c = client_vk_compositor(xc);

    // Pipe down call into native compositor.
    return xrt_comp_begin_session(&c->xcn->base, type);//这里传过去的xrt_compositor_native 中的     
 xrt_compositor 
}

static inline xrt_result_t
xrt_comp_begin_session(struct xrt_compositor *xc, enum xrt_view_type view_type)
{
    return xc->begin_session(xc, view_type);
}

4、xrt_compositor_native 的xrt_compositor 的begin_session 函数指针在 src/xrt/compositor/main/comp_compositor.c 的xrt_gfx_provider_create_system 方法中被赋值

xrt_result_t
xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compositor **out_xsysc)
{
    struct comp_compositor *c = U_TYPED_CALLOC(struct comp_compositor);

    c->base.base.base.begin_session = compositor_begin_session;  //这里赋值,其他的几个方法类似
    c->base.base.base.end_session = compositor_end_session;
    c->base.base.base.predict_frame = compositor_predict_frame;
    c->base.base.base.mark_frame = compositor_mark_frame;
    c->base.base.base.begin_frame = compositor_begin_frame;
    c->base.base.base.discard_frame = compositor_discard_frame;
    c->base.base.base.layer_commit = compositor_layer_commit;
    c->base.base.base.poll_events = compositor_poll_events;
    c->base.base.base.destroy = compositor_destroy;
    c->frame.waited.id = -1;
    c->frame.rendering.id = -1;
    c->xdev = xdev;

5、至此compositor_begin_session 创建完成 ,特别记录compositor_layer_commit 函数是应用提交一帧后怎么绘制到屏幕的流程,下面是用perfetto抓取的trace。


image.png
  • monon的openxr渲染提交命令缓冲过程
src/xrt/compositor/main/comp_compositor.c
static xrt_result_t
compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_graphics_sync_handle_t sync_handle)
{
comp_renderer_draw(c->r);
}

//src/xrt/compositor/main/comp_renderer.c
void
comp_renderer_draw(struct comp_renderer *r)
{

comp_target_mark_begin(ct, c->frame.rendering.id, os_monotonic_get_ns());
if (use_compute) {
        dispatch_compute(r, &crc);
    } else {
        dispatch_graphics(r, &rr);
    }

    renderer_present_swapchain_image(r, c->frame.rendering.desired_present_time_ns,
                                     c->frame.rendering.present_slop_ns);

}


static void
dispatch_graphics(struct comp_renderer *r, struct comp_rendering *rr)
{
renderer_get_view_projection(r);
comp_layer_renderer_draw(r->lr);

renderer_build_rendering(r, rr, rtr, src_samplers, src_image_views, src_norm_rects);
renderer_submit_queue(r, rr->cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
}
//src/xrt/compositor/main/comp_layer_renderer.c
void
comp_layer_renderer_draw(struct comp_layer_renderer *self)
{
    COMP_TRACE_MARKER();

    struct vk_bundle *vk = self->vk;

    VkCommandBuffer cmd_buffer;
    if (vk_init_cmd_buffer(vk, &cmd_buffer) != VK_SUCCESS)
        return;
    os_mutex_lock(&vk->cmd_pool_mutex);
    if (self->layer_count == 0) {
        _render_stereo(self, vk, cmd_buffer, &background_color_idle);
    } else {
        _render_stereo(self, vk, cmd_buffer, &background_color_active);
    }
    os_mutex_unlock(&vk->cmd_pool_mutex);

    VkResult res = vk_submit_cmd_buffer(vk, cmd_buffer);
    vk_check_error("vk_submit_cmd_buffer", res, );
}

vk_submit_cmd_buffer 在 src/xrt/auxiliary/vk/vk_helpers.c 中
使用vkQueueSubmit函数向图像队列提交命令缓冲区

  • runtime 迷惑的结构体定义,我们看到这种comp_compositor ,c->base.base.base.begin_session 有三个base 分别代表啥呢
xrt_result_t
xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compositor **out_xsysc)
{
    struct comp_compositor *c = U_TYPED_CALLOC(struct comp_compositor);

    c->base.base.base.begin_session = compositor_begin_session;
    c->base.base.base.end_session = compositor_end_session;

1、comp_compositor 结构体

struct comp_compositor
{
    struct comp_base base;

    //! Renderer helper.
    struct comp_renderer *r;

    //! The target we are displaying to.
    struct comp_target *target;

    //! The device we are displaying to.
    struct xrt_device *xdev;

    //! The settings.
    struct comp_settings settings;

    //! Vulkan shaders that the compositor uses.
    struct comp_shaders shaders;

    //! Timestamp of last-rendered (immersive) frame.
    int64_t last_frame_time_ns;

    //! State for generating the correct set of events.
    enum comp_state state;

    /*!
     * @brief Data exclusive to the begin_frame/end_frame for computing an
     * estimate of the app's needs.
     */
    struct
    {
        int64_t last_begin;
        int64_t last_end;
    } app_profiling;

    struct
    {
        //! Current Index for times_ns.
        int index;

        //! Timestamps of last-rendered (immersive) frames.
        int64_t times_ns[NUM_FRAME_TIMES];

        //! Frametimes between last-rendered (immersive) frames.
        float timings_ms[NUM_FRAME_TIMES];

        //! Average FPS of last NUM_FRAME_TIMES rendered frames.
        float fps;

        struct u_var_timing *debug_var;
    } compositor_frame_times;

    struct
    {
        struct comp_frame waited;
        struct comp_frame rendering;
    } frame;

    struct
    {
        //! Temporarily disable ATW
        bool atw_off;
    } debug;

    struct comp_resources nr;
};

2、struct comp_base base; 主要封装了xrt_compositor_native 和 vulkan

struct comp_base
{
    //! Base native compositor.
    struct xrt_compositor_native base;

    //! Vulkan bundle of useful things, used by swapchain and fence.
    struct vk_bundle vk;

    //! For default @ref xrt_compositor::wait_frame.
    struct os_precise_sleeper sleeper;

    //! Swapchain garbage collector, used by swapchain, child class needs to call.
    struct comp_swapchain_gc cscgc;

    //! We only need to track a single slot.
    struct comp_layer_slot slot;
};

3、struct xrt_compositor_native base; 封装了xrt_compositor

struct xrt_compositor_native
{
    //! @public Base
    struct xrt_compositor base;
};

4、struct xrt_compositor base; 里面主要是定义了一些函数指针

struct xrt_compositor
{
    /*!
     * Capabilities and recommended values information.
     */
    struct xrt_compositor_info info;

    /*!
     * Create a swapchain with a set of images.
     *
     * The pointer pointed to by @p out_xsc has to either be NULL or a valid
     * @ref xrt_swapchain pointer. If there is a valid @ref xrt_swapchain
     * pointed by the pointed pointer it will have it reference decremented.
     */
    xrt_result_t (*create_swapchain)(struct xrt_compositor *xc,
                                     const struct xrt_swapchain_create_info *info,
                                     struct xrt_swapchain **out_xsc);
  • 因为openxr的渲染部分是用vulkan实现的,最后可以再看下vulkan绘制出一个三角形流程可以从大的方面理解openxr的渲染流程
init_vulkan_instance();//创建Vulkan实例
 enumerate_vulkan_phy_devices();//获取物理设备列表
create_vulkan_devices();//创建逻辑设备
create_vulkan_CommandBuffer();//创建命令缓冲
init_queue();//获取设备中支持图形工作的队列
create_vulkan_swapChain();//初始化交换链
create_vulkan_DepthBuffer();//创建深度缓冲
create_render_pass();//创建渲染通道
create_frame_buffer();//创建帧缓冲
createDrawableObject();//创建绘制用的物体
initPipeline();//初始化渲染管线
createFence();//创建栅栏
initPresentInfo();//初始化呈现信息
initMatrix();//初始化基本变换矩阵、摄像机矩阵、投影矩阵
drawObject();//执行绘制
destroyFence();//销毁栅栏
destroyPipeline();//销毁管线
destroyDrawableObject();//销毁绘制用物体
destroy_frame_buffer();//销毁帧缓冲
destroy_render_pass();//销毁渲染通道相关
destroy_vulkan_DepthBuffer();//销毁深度缓冲相关
destroy_vulkan_swapChain();//销毁交换链相关
destroy_vulkan_CommandBuffer();//销毁命令缓冲
destroy_vulkan_devices();//销毁逻辑设备
destroy_vulkan_instance();//销毁Vulkan 实例
  • 绘制一帧画面要经过
    1、从交换链获取当前帧索引
    2、为渲染通道设置当前帧索引
    3、初始化命令缓冲,然后启动命令缓冲
    4、将当前帧送入一直变量缓冲
    5、更新绘制用描述集
    6、绘制
    7、结束渲染通道 结束命令缓冲 等待信号量
    8、提交命令缓冲
    9、等待渲染完毕
    10、为呈现信息指定当前交换链索引
    11、呈现

相关文章

  • 对OpenXR 的一些理解

    参考官方文档openxr-10-reference-guide 一个标准的openxr应用包含方法调用、对象创建、...

  • 如何安装OpenXR运行时(Windows)

    1、下载openxr示例代码https://github.com/KhronosGroup/OpenXR-SDK-...

  • Monado&&openxr

    moado计划表image.png 首先介绍openxr官方网站OpenXR Overview - The Khr...

  • openxr的例子helloxr

    openxr的生命周期:image.png官方代码:https://github.com/KhronosGroup...

  • openxr DestroySwapchain流程

    1、oxr_xrDestroySwapchain 函数入口src/xrt/state_trackers/oxr/o...

  • 对递归的一些理解

    当一个函数的运行期间调用另一个函数的时候,在运行被调用的函数之前,系统会怎样操作呢: 1. 将所有的实参,以及接下...

  • 对一些歌词的理解

    关于感情的歌词最喜欢陈楚生 尤其是《经过》和《天长地久》。 若我爱你的方式已不同开始,不如我们变换下位置,看一看原...

  • 对NSCache的一些理解...

    对于NSCache的一些理解 对于有一定开发经验的iOS攻城狮来说,我们在对一个APP数据做存储和内存优化的时候,...

  • 对游戏的一些理解

    游戏的本质是什么?我知道什么?我不知道什么?我需要知道什么?游戏本质是一种精神娱乐产品,跟电影,电视节目,音乐,书...

  • 对炒股的一些理解

    炒股能赚钱是个多方面合力的结果,但大体上主要是以下几个方面:1.赚信息不对称的钱,如提前得到什么利空利好消息;2....

网友评论

      本文标题:对OpenXR 的一些理解

      本文链接:https://www.haomeiwen.com/subject/yvppdrtx.html