參考官方文檔openxr-10-reference-guide
-
一個(gè)標(biāo)準(zhǔn)的openxr應(yīng)用包含方法調(diào)用滔金、對(duì)象創(chuàng)建、Session狀態(tài)變化痘昌、渲染循環(huán)等
- 以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钞艇。
- 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)