對(duì)OpenXR 的一些理解

參考官方文檔openxr-10-reference-guide

  • 一個(gè)標(biāo)準(zhǔn)的openxr應(yīng)用包含方法調(diào)用滔金、對(duì)象創(chuàng)建、Session狀態(tài)變化痘昌、渲染循環(huán)等


    image.png
  • 以monon的openxr runtime為例钥勋,主要涉及以下幾個(gè)大的模塊

1、連接方面辆苔,有藍(lán)牙設(shè)備算灸,和usb設(shè)備,涉及藍(lán)牙通信和HID通信
2驻啤、語言方面設(shè)計(jì)openxr 菲驴、vulkan、opengl等
3街佑、api方面有交換鏈谢翎、session會(huì)話捍靠、event隊(duì)列
4、ipc通信方面有soctet通信森逮、匿名共享內(nèi)存
5榨婆、渲染方面主要是vulkan 語法和 shader

  • monon的數(shù)據(jù)來源主要是獲取手機(jī)自帶的加速度和陀螺儀 模擬成3dof數(shù)據(jù)
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創(chuàng)建過程,
    1褒侧、有個(gè)宏控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語言支持?jǐn)U展

//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;  //指定交換鏈創(chuàng)建

    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)
{
//主要是初始化渲染相關(guān)的一些東西了
    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; 可以看出 調(diào)用到 xc->begin_session ,這里的xc 就是傳過來的
xrt_compositor_native 結(jié)構(gòu)體中的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 函數(shù)指針在 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;  //這里賦值疑俭,其他的幾個(gè)方法類似
    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 創(chuàng)建完成 婿失,特別記錄compositor_layer_commit 函數(shù)是應(yīng)用提交一幀后怎么繪制到屏幕的流程,下面是用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函數(shù)向圖像隊(duì)列提交命令緩沖區(qū)

  • runtime 迷惑的結(jié)構(gòu)體定義,我們看到這種comp_compositor 豪硅,c->base.base.base.begin_session 有三個(gè)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 結(jié)構(gòu)體

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; 里面主要是定義了一些函數(shù)指針

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);
  • 因?yàn)閛penxr的渲染部分是用vulkan實(shí)現(xiàn)的,最后可以再看下vulkan繪制出一個(gè)三角形流程可以從大的方面理解openxr的渲染流程
init_vulkan_instance();//創(chuàng)建Vulkan實(shí)例
 enumerate_vulkan_phy_devices();//獲取物理設(shè)備列表
create_vulkan_devices();//創(chuàng)建邏輯設(shè)備
create_vulkan_CommandBuffer();//創(chuàng)建命令緩沖
init_queue();//獲取設(shè)備中支持圖形工作的隊(duì)列
create_vulkan_swapChain();//初始化交換鏈
create_vulkan_DepthBuffer();//創(chuàng)建深度緩沖
create_render_pass();//創(chuàng)建渲染通道
create_frame_buffer();//創(chuàng)建幀緩沖
createDrawableObject();//創(chuàng)建繪制用的物體
initPipeline();//初始化渲染管線
createFence();//創(chuàng)建柵欄
initPresentInfo();//初始化呈現(xiàn)信息
initMatrix();//初始化基本變換矩陣砚著、攝像機(jī)矩陣次伶、投影矩陣
drawObject();//執(zhí)行繪制
destroyFence();//銷毀柵欄
destroyPipeline();//銷毀管線
destroyDrawableObject();//銷毀繪制用物體
destroy_frame_buffer();//銷毀幀緩沖
destroy_render_pass();//銷毀渲染通道相關(guān)
destroy_vulkan_DepthBuffer();//銷毀深度緩沖相關(guān)
destroy_vulkan_swapChain();//銷毀交換鏈相關(guān)
destroy_vulkan_CommandBuffer();//銷毀命令緩沖
destroy_vulkan_devices();//銷毀邏輯設(shè)備
destroy_vulkan_instance();//銷毀Vulkan 實(shí)例
  • 繪制一幀畫面要經(jīng)過
    1、從交換鏈獲取當(dāng)前幀索引
    2稽穆、為渲染通道設(shè)置當(dāng)前幀索引
    3学少、初始化命令緩沖,然后啟動(dòng)命令緩沖
    4秧骑、將當(dāng)前幀送入一直變量緩沖
    5、更新繪制用描述集
    6扣囊、繪制
    7乎折、結(jié)束渲染通道 結(jié)束命令緩沖 等待信號(hào)量
    8、提交命令緩沖
    9侵歇、等待渲染完畢
    10骂澄、為呈現(xiàn)信息指定當(dāng)前交換鏈索引
    11、呈現(xiàn)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載惕虑,如需轉(zhuǎn)載請(qǐng)通過簡(jiǎn)信或評(píng)論聯(lián)系作者坟冲。
  • 序言:七十年代末磨镶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子健提,更是在濱河造成了極大的恐慌琳猫,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件私痹,死亡現(xiàn)場(chǎng)離奇詭異脐嫂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)紊遵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門账千,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人暗膜,你說我怎么就攤上這事匀奏。” “怎么了学搜?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵娃善,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我恒水,道長(zhǎng)会放,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任钉凌,我火速辦了婚禮咧最,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘御雕。我一直安慰自己矢沿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布酸纲。 她就那樣靜靜地躺著捣鲸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闽坡。 梳的紋絲不亂的頭發(fā)上栽惶,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音疾嗅,去河邊找鬼外厂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛代承,可吹牛的內(nèi)容都是我干的汁蝶。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼掖棉!你這毒婦竟也來了墓律?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤幔亥,失蹤者是張志新(化名)和其女友劉穎耻讽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體紫谷,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡齐饮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了笤昨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祖驱。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瞒窒,靈堂內(nèi)的尸體忽然破棺而出捺僻,到底是詐尸還是另有隱情,我是刑警寧澤崇裁,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布匕坯,位于F島的核電站,受9級(jí)特大地震影響拔稳,放射性物質(zhì)發(fā)生泄漏葛峻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一巴比、第九天 我趴在偏房一處隱蔽的房頂上張望术奖。 院中可真熱鬧,春花似錦轻绞、人聲如沸采记。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唧龄。三九已至,卻和暖如春奸远,著一層夾襖步出監(jiān)牢的瞬間既棺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工懒叛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留援制,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓芍瑞,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親褐墅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拆檬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容