OpenXR+Runtime:xrSession和xrSwapchain创建流程

废话不多说,上源码

注释:src\xrt\state_trackers\oxr
//! OpenXR API function @ep{xrCreateSession}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrCreateSession(XrInstance instance, const XrSessionCreateInfo *createInfo, XrSession *session);

注释:注意,最后一个参数 XrSession *out_session 是作为输出的 out put param
注释:src\xrt\state_trackers\oxr\oxr_objects.h
#define XRT_CAST_PTR_TO_OXR_HANDLE(HANDLE_TYPE, PTR) ((HANDLE_TYPE)(uint64_t)(uintptr_t)(PTR))

static inline XrSession
oxr_session_to_openxr(struct oxr_session *sess)
{
	return XRT_CAST_PTR_TO_OXR_HANDLE(XrSession, sess);
}


注释:src\xrt\state_trackers\oxr\oxr_api_session.c
XrResult
oxr_xrCreateSession(XrInstance instance, const XrSessionCreateInfo *createInfo, XrSession *out_session)
{
	OXR_TRACE_MARKER();

	XrResult ret;
	struct oxr_instance *inst;
	struct oxr_session *sess, **link;
	struct oxr_logger log;
	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrCreateSession");

    注释:XrSessionCreateInfo 指针往下传递
	ret = oxr_verify_XrSessionCreateInfo(&log, inst, createInfo);
	if (ret != XR_SUCCESS) {
		return ret;
	}

    注释:将创建的oxr_session指针往下传
	ret = oxr_session_create(&log, &inst->system, createInfo, &sess);
	if (ret != XR_SUCCESS) {
		return ret;
	}

    注释:参看上面两个函数的注释,这里只是作了一个强制类型转换,
         将oxr中的类型强制转换成openxr中对应类型,作为output param输出给openxr
         防止编译Warning,并没有具体的赋值操作。
	*out_session = oxr_session_to_openxr(sess);

	/* Add to session list */
	link = &inst->sessions;
	while (*link) {
		link = &(*link)->next;
	}
	*link = sess;

	return XR_SUCCESS;
}
注释: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)
{
    注释:创建一个空的oxr_session指针
	struct oxr_session *sess = NULL;

	struct xrt_session_info xsi = {0};
	const XrSessionCreateInfoOverlayEXTX *overlay_info = OXR_GET_INPUT_FROM_CHAIN(
	    createInfo, XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX, XrSessionCreateInfoOverlayEXTX);
	if (overlay_info) {
		xsi.is_overlay = true;
		xsi.flags = overlay_info->createFlags;
		xsi.z_order = overlay_info->sessionLayersPlacement;
	}

	/* Try allocating and populating. */
    注释:注意上面这行注释,将创建的oxr_session指针往下传递进行内存分配和填充(也就是赋值)
	XrResult ret = oxr_session_create_impl(log, sys, createInfo, &xsi, &sess);
	if (ret != XR_SUCCESS) {
		if (sess != NULL) {
			/* clean up allocation first */
			XrResult cleanup_result = oxr_handle_destroy(log, &sess->handle);
			assert(cleanup_result == XR_SUCCESS);
			(void)cleanup_result;
		}
		return ret;
	}

	// Init the begin/wait frame semaphore.
	os_semaphore_init(&sess->sem, 1);

    注释:sess经过oxr_session_create_impl()函数填充之后,再接着进行下面这些数据赋值
         可以看到,主要是赋值ipd,帧spew,帧wait_sleep,以及初始状态时间等
	sess->active_wait_frames = 0;
	os_mutex_init(&sess->active_wait_frames_lock);

	sess->ipd_meters = debug_get_num_option_ipd() / 1000.0f;
	sess->frame_timing_spew = debug_get_bool_option_frame_timing_spew();
	sess->frame_timing_wait_sleep_ms = debug_get_num_option_wait_frame_sleep();

	oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE);
	oxr_session_change_state(log, sess, XR_SESSION_STATE_READY);

	u_hashmap_int_create(&sess->act_sets_attachments_by_key);
	u_hashmap_int_create(&sess->act_attachments_by_key);

    注释:赋值给传入进来的*out_session
	*out_session = sess;

	return ret;
}

接着跟oxr_session_create_impl(log, sys, createInfo, &xsi, &sess)函数,看看到底对 sess 作了哪些数据填充

注释:src\xrt\state_trackers\oxr\oxr_session.c
/* 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

        ...        

		OXR_SESSION_ALLOCATE(log, sys, *out_session);
		OXR_ALLOCATE_NATIVE_COMPOSITOR(log, xsi, *out_session);

        注释:这个函数里用不同的宏定义了不同的平台渲染方式
             monado runtime使用的是vulkan,所以只关注宏 XR_USE_GRAPHICS_API_VULKAN
             传进来的*out_session接着往下传递
		return oxr_session_populate_vk(log, sys, vulkan, *out_session);
	}
#endif

...

}
注释:src\xrt\state_trackers\oxr\oxr_objects.h
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和create_swapchain赋值
         compositor 结构体指针
         create_swapchain 函数指针
	sess->compositor = &xcvk->base;
	sess->create_swapchain = oxr_swapchain_vk_create;

	return XR_SUCCESS;
}

注释:compositor由xrt_gfx_vk_provider_create()创建的xrt_compositor_vk指针的成员xcvk->base赋值接下来,先跟函数xrt_gfx_vk_provider_create(),回头再来跟oxr_swapchain_vk_create
注释:src\xrt\compositor\client\comp_vk_glue.c
struct xrt_compositor_vk *
xrt_gfx_vk_provider_create(struct xrt_compositor_native *xcn,
                           VkInstance instance,
                           PFN_vkGetInstanceProcAddr get_instance_proc_addr,
                           VkPhysicalDevice physical_device,
                           VkDevice device,
                           bool timeline_semaphore_enabled,
                           uint32_t queue_family_index,
                           uint32_t queue_index)
{
	struct client_vk_compositor *vcc = client_vk_compositor_create( //
	    xcn,                                                        //
	    instance,                                                   //
	    get_instance_proc_addr,                                     //
	    physical_device,                                            //
	    device,                                                     //
	    timeline_semaphore_enabled,                                 //
	    queue_family_index,                                         //
	    queue_index);                                               //

    注释:这里就是上一段代码中获取到的返回值
         在源码中可以很清晰的看到,vcc的base成员就是下面的xrt_compositor结构体
	return &vcc->base;
}


注释:src\xrt\include\xrt\xrt_compositor.h
struct xrt_compositor_vk
{
	//! @public Base
	struct xrt_compositor base;
};


注释:再接着看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)
{
	COMP_TRACE_MARKER();

	xrt_result_t xret;
	VkResult ret;
	struct client_vk_compositor *c = U_TYPED_CALLOC(struct client_vk_compositor);

	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;

	c->xcn = xcn;
	// passthrough our formats from the native compositor to the client
	for (uint32_t i = 0; i < xcn->base.info.format_count; i++) {
		c->base.base.info.formats[i] = xcn->base.info.formats[i];
	}

	c->base.base.info.format_count = xcn->base.info.format_count;

	// Default to info.
	enum u_logging_level log_level = U_LOGGING_INFO;

	ret = vk_init_from_given(       //
	    &c->vk,                     // vk_bundle
	    getProc,                    // vkGetInstanceProcAddr
	    instance,                   // instance
	    physicalDevice,             // physical_device
	    device,                     // device
	    queueFamilyIndex,           // queue_family_index
	    queueIndex,                 // queue_index
	    timeline_semaphore_enabled, // timeline_semaphore_enabled
	    log_level);                 // log_level
	if (ret != VK_SUCCESS) {
		goto err_free;
	}

	ret = vk_init_mutex(&c->vk);
	if (ret != VK_SUCCESS) {
		goto err_free;
	}

#ifdef VK_KHR_timeline_semaphore
	if (c->vk.features.timeline_semaphore) {
		xret = setup_semaphore(c);
		if (xret != XRT_SUCCESS) {
			goto err_mutex;
		}
	}
#endif

	return c;


err_mutex:
	vk_deinit_mutex(&c->vk);
err_free:
	free(c);

	return NULL;
}

可以看到这两句:

    c->base.base.create_swapchain = client_vk_swapchain_create;
    c->base.base.begin_session = client_vk_compositor_begin_session;

先看看swap_chain:

直接点击client_vk_swapchain_create()就能跳转到其完整实现:

注释:src\xrt\compositor\client\comp_vk_client.c

static xrt_result_t
client_vk_swapchain_create(struct xrt_compositor *xc,
                           const struct xrt_swapchain_create_info *info,
                           struct xrt_swapchain **out_xsc)
{
	COMP_TRACE_MARKER();

	struct client_vk_compositor *c = client_vk_compositor(xc);
	struct vk_bundle *vk = &c->vk;
	VkCommandBuffer cmd_buffer;
	VkResult ret;
	xrt_result_t xret;

	struct xrt_swapchain_native *xscn = NULL; // Has to be NULL.
	xret = xrt_comp_native_create_swapchain(c->xcn, info, &xscn);

	if (xret != XRT_SUCCESS) {
		return xret;
	}
	assert(xscn != NULL);

	struct xrt_swapchain *xsc = &xscn->base;

	ret = vk_init_cmd_buffer(vk, &cmd_buffer);
	if (ret != VK_SUCCESS) {
		return XRT_ERROR_VULKAN;
	}

	VkAccessFlags barrier_access_mask = vk_csci_get_barrier_access_mask(info->bits);
	VkImageLayout barrier_optimal_layout = vk_csci_get_barrier_optimal_layout(info->format);
	VkImageAspectFlags barrier_aspect_mask = vk_csci_get_barrier_aspect_mask(info->format);

	VkImageSubresourceRange subresource_range = {
	    .aspectMask = barrier_aspect_mask,
	    .baseMipLevel = 0,
	    .levelCount = VK_REMAINING_MIP_LEVELS,
	    .baseArrayLayer = 0,
	    .layerCount = VK_REMAINING_ARRAY_LAYERS,
	};

	struct client_vk_swapchain *sc = U_TYPED_CALLOC(struct client_vk_swapchain);
	sc->base.base.destroy = client_vk_swapchain_destroy;
	sc->base.base.acquire_image = client_vk_swapchain_acquire_image;
	sc->base.base.wait_image = client_vk_swapchain_wait_image;
	sc->base.base.release_image = client_vk_swapchain_release_image;
	sc->base.base.reference.count = 1;
	sc->base.base.image_count = xsc->image_count; // Fetch the number of images from the native swapchain.
	sc->c = c;
	sc->xscn = xscn;

	for (uint32_t i = 0; i < xsc->image_count; i++) {
		ret = vk_create_image_from_native(vk, info, &xscn->images[i], &sc->base.images[i], &sc->mems[i]);


		if (ret != VK_SUCCESS) {
			return XRT_ERROR_VULKAN;
		}

		/*
		 * This is only to please the validation layer, that may or may
		 * not be a bug in the validation layer. That may or may not be
		 * fixed in the future version of the validation layer.
		 */
		vk_set_image_layout(                 //
		    vk,                              // vk_bundle
		    cmd_buffer,                      // cmd_buffer
		    sc->base.images[i],              // image
		    0,                               // src_access_mask
		    barrier_access_mask,             // dst_access_mask
		    VK_IMAGE_LAYOUT_UNDEFINED,       // old_layout
		    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // new_layout
		    subresource_range);              // subresource_range
	}

	ret = vk_submit_cmd_buffer(vk, cmd_buffer);
	if (ret != VK_SUCCESS) {
		return XRT_ERROR_FAILED_TO_SUBMIT_VULKAN_COMMANDS;
	}

	// Prerecord command buffers for swapchain image ownership/layout transitions
	for (uint32_t i = 0; i < xsc->image_count; i++) {
		ret = vk_init_cmd_buffer(vk, &sc->acquire[i]);
		if (ret != VK_SUCCESS) {
			return XRT_ERROR_VULKAN;
		}
		ret = vk_init_cmd_buffer(vk, &sc->release[i]);
		if (ret != VK_SUCCESS) {
			return XRT_ERROR_VULKAN;
		}

		VkImageSubresourceRange subresource_range = {
		    .aspectMask = barrier_aspect_mask,
		    .baseMipLevel = 0,
		    .levelCount = VK_REMAINING_MIP_LEVELS,
		    .baseArrayLayer = 0,
		    .layerCount = VK_REMAINING_ARRAY_LAYERS,
		};

		VkImageMemoryBarrier acquire = {
		    .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
		    .srcAccessMask = 0,
		    .dstAccessMask = barrier_access_mask,
		    .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
		    .newLayout = barrier_optimal_layout,
		    .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
		    .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
		    .image = sc->base.images[i],
		    .subresourceRange = subresource_range,
		};

		VkImageMemoryBarrier release = {
		    .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
		    .srcAccessMask = barrier_access_mask,
		    .dstAccessMask = 0,
		    .oldLayout = barrier_optimal_layout,
		    .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
		    .srcQueueFamilyIndex = vk->queue_family_index,
		    .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
		    .image = sc->base.images[i],
		    .subresourceRange = subresource_range,
		};

		//! @todo less conservative pipeline stage masks based on usage
		vk->vkCmdPipelineBarrier(               //
		    sc->acquire[i],                     // commandBuffer
		    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,  // srcStageMask
		    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // dstStageMask
		    0,                                  // dependencyFlags
		    0,                                  // memoryBarrierCount
		    NULL,                               // pMemoryBarriers
		    0,                                  // bufferMemoryBarrierCount
		    NULL,                               // pBufferMemoryBarriers
		    1,                                  // imageMemoryBarrierCount
		    &acquire);                          // pImageMemoryBarriers

		vk->vkCmdPipelineBarrier(                 //
		    sc->release[i],                       // commandBuffer
		    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,   // srcStageMask
		    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // dstStageMask
		    0,                                    // dependencyFlags
		    0,                                    // memoryBarrierCount
		    NULL,                                 // pMemoryBarriers
		    0,                                    // bufferMemoryBarrierCount
		    NULL,                                 // pBufferMemoryBarriers
		    1,                                    // imageMemoryBarrierCount
		    &release);                            // pImageMemoryBarriers

		ret = vk->vkEndCommandBuffer(sc->acquire[i]);
		if (ret != VK_SUCCESS) {
			VK_ERROR(vk, "vkEndCommandBuffer: %s", vk_result_string(ret));
			return XRT_ERROR_VULKAN;
		}
		ret = vk->vkEndCommandBuffer(sc->release[i]);
		if (ret != VK_SUCCESS) {
			VK_ERROR(vk, "vkEndCommandBuffer: %s", vk_result_string(ret));
			return XRT_ERROR_VULKAN;
		}
	}

    注释:swapchain创建完成,在此返回output输出
	*out_xsc = &sc->base.base;

	return XRT_SUCCESS;
}

swapchain在此创建完成,并在最后作为output param输出,一路返回

xrSession则需要继续跟函数client_vk_compositor_begin_session 

注释:src\xrt\compositor\client\comp_vk_client.c
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);
}
注释:src\xrt\include\xrt\xrt_compositor.h
/*!
 * @copydoc xrt_compositor::begin_session
 *
 * Helper for calling through the function pointer.
 *
 * @public @memberof 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);
}


注释:点击begin_session,会跳转到其声明的地方,是xrt_compositor结构体中的函数指针
     src\xrt\include\xrt\xrt_compositor.h
struct xrt_compositor{
    ...

    /*!
	 * See xrBeginSession.
	 */
	xrt_result_t (*begin_session)(struct xrt_compositor *xc, enum xrt_view_type view_type);
    
    ...
}

注释:需要接着跟踪begin_session被赋值的地方

 begin_session赋值在这里:

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

     注意看下面函数体里面的c->base.base.base.begin_session

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;

    ...
    ...

	return comp_multi_create_system_compositor(&c->base.base, sys_info, out_xsysc);
}

到此,compositor_begin_seesion也就是xrSession的创建过程也完成。

猜你喜欢

转载自blog.csdn.net/geyichongchujianghu/article/details/124131842