st/oxr: Add extension XR_FB_passthrough

This commit is contained in:
dengkail 2024-02-29 11:15:37 +08:00
parent 6876de1da6
commit c57976c2af
19 changed files with 864 additions and 0 deletions

View file

@ -422,6 +422,9 @@ endif()
if(NOT DEFINED XRT_FEATURE_OPENXR_LAYER_FB_DEPTH_TEST)
set(XRT_FEATURE_OPENXR_LAYER_FB_DEPTH_TEST OFF)
endif()
if(NOT DEFINED XRT_FEATURE_OPENXR_LAYER_PASSTHROUGH)
set(XRT_FEATURE_OPENXR_LAYER_PASSTHROUGH OFF)
endif()
# Defaults for OpenXR spaces
if(NOT DEFINED XRT_FEATURE_OPENXR_SPACE_LOCAL_FLOOR)
@ -632,6 +635,7 @@ message(STATUS "# FEATURE_OPENXR_LAYER_DEPTH: ${XRT_FEATURE
message(STATUS "# FEATURE_OPENXR_LAYER_EQUIRECT1: ${XRT_FEATURE_OPENXR_LAYER_EQUIRECT1}")
message(STATUS "# FEATURE_OPENXR_LAYER_EQUIRECT2: ${XRT_FEATURE_OPENXR_LAYER_EQUIRECT2}")
message(STATUS "# FEATURE_OPENXR_LAYER_FB_ALPHA_BLEND: ${XRT_FEATURE_OPENXR_LAYER_FB_ALPHA_BLEND}")
message(STATUS "# FEATURE_OPENXR_LAYER_PASSTHROUGH: ${XRT_FEATURE_OPENXR_LAYER_PASSTHROUGH}")
message(STATUS "# FEATURE_OPENXR_LAYER_FB_IMAGE_LAYOUT ${XRT_FEATURE_OPENXR_LAYER_FB_IMAGE_LAYOUT}")
message(STATUS "# FEATURE_OPENXR_LAYER_FB_SETTINGS: ${XRT_FEATURE_OPENXR_LAYER_FB_SETTINGS}")
message(STATUS "# FEATURE_OPENXR_LAYER_FB_DEPTH_TEST: ${XRT_FEATURE_OPENXR_LAYER_FB_DEPTH_TEST}")

View file

@ -70,6 +70,7 @@ EXTENSIONS = (
['XR_FB_composition_layer_settings', 'XRT_FEATURE_OPENXR_LAYER_FB_SETTINGS'],
['XR_FB_composition_layer_depth_test', 'XRT_FEATURE_OPENXR_LAYER_FB_DEPTH_TEST'],
['XR_FB_display_refresh_rate', 'XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE'],
['XR_FB_passthrough', 'XRT_FEATURE_OPENXR_LAYER_PASSTHROUGH'],
['XR_ML_ml2_controller_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_ML2'],
['XR_MND_headless', 'XRT_FEATURE_OPENXR_HEADLESS'],
['XR_MND_swapchain_usage_input_attachment_bit'],

View file

@ -82,6 +82,7 @@ enum xrt_layer_type
XRT_LAYER_CYLINDER,
XRT_LAYER_EQUIRECT1,
XRT_LAYER_EQUIRECT2,
XRT_LAYER_PASSTHROUGH
};
/*!
@ -355,6 +356,34 @@ struct xrt_layer_equirect2_data
float lower_vertical_angle;
};
/*!
* @interface xrt_passthrough
*/
struct xrt_passthrough
{
bool paused;
};
/*!
* @interface xrt_passthrough_layer
*/
struct xrt_passthrough_layer
{
bool paused;
};
/*!
* All the pure data values associated with a passthrough layer.
*
* The @ref xrt_swapchain references and @ref xrt_device are provided outside of
* this struct.
*/
struct xrt_layer_passthrough_data
{
struct xrt_passthrough xrt_pt;
struct xrt_passthrough_layer xrt_pl;
};
/*!
* All the pure data values associated with a composition layer.
*
@ -436,6 +465,7 @@ struct xrt_layer_data
struct xrt_layer_cylinder_data cylinder;
struct xrt_layer_equirect1_data equirect1;
struct xrt_layer_equirect2_data equirect2;
struct xrt_layer_passthrough_data passthrough;
};
};
@ -861,6 +891,23 @@ struct xrt_swapchain_create_info
uint32_t formats[XRT_MAX_SWAPCHAIN_CREATE_INFO_FORMAT_LIST_COUNT];
};
/*!
* Passthrough creation info.
*/
struct xrt_passthrough_create_info
{
enum xrt_passthrough_create_flags create;
};
/*!
* Passthrough layer creation info.
*/
struct xrt_passthrough_layer_create_info
{
enum xrt_passthrough_create_flags create;
enum xrt_passthrough_purpose_flags purpose;
};
/*!
* Struct used to negotiate properties of a swapchain that is created outside
* of the compositor. Often used by a client compositor or IPC layer to allocate
@ -991,6 +1038,22 @@ struct xrt_compositor
struct xrt_compositor_semaphore **out_xcsem);
/*! @} */
/*!
* Create a passthrough.
*/
xrt_result_t (*create_passthrough)(struct xrt_compositor *xc, const struct xrt_passthrough_create_info *info);
/*!
* Create a passthrough layer.
*/
xrt_result_t (*create_passthrough_layer)(struct xrt_compositor *xc,
const struct xrt_passthrough_layer_create_info *info);
/*!
* Destroy a passthrough.
*/
xrt_result_t (*destroy_passthrough)(struct xrt_compositor *xc);
/*!
* @name Function pointers for session functions
* @{
@ -1256,6 +1319,19 @@ struct xrt_compositor
struct xrt_swapchain *xsc,
const struct xrt_layer_data *data);
/*!
* Adds a passthrough layer for submission.
*
* @param xc Self pointer
* @param xdev The device the layer is relative to.
* @param data All of the pure data bits (not pointers/handles),
* including what part of the supplied swapchain
* object to use.
*/
xrt_result_t (*layer_passthrough)(struct xrt_compositor *xc,
struct xrt_device *xdev,
const struct xrt_layer_data *data);
/*!
* @brief Commits all of the submitted layers.
*
@ -1419,6 +1495,44 @@ xrt_comp_create_semaphore(struct xrt_compositor *xc,
/*! @} */
/*!
* @copydoc xrt_compositor::create_passthrough
*
* Helper for calling through the function pointer.
*
* @public @memberof xrt_compositor
*/
static inline xrt_result_t
xrt_comp_create_passthrough(struct xrt_compositor *xc, const struct xrt_passthrough_create_info *info)
{
return xc->create_passthrough(xc, info);
}
/*!
* @copydoc xrt_compositor::create_passthrough_layer
*
* Helper for calling through the function pointer.
*
* @public @memberof xrt_compositor
*/
static inline xrt_result_t
xrt_comp_create_passthrough_layer(struct xrt_compositor *xc, const struct xrt_passthrough_layer_create_info *info)
{
return xc->create_passthrough_layer(xc, info);
}
/*!
* @copydoc xrt_compositor::destroy_passthrough
*
* Helper for calling through the function pointer.
*
* @public @memberof xrt_compositor
*/
static inline xrt_result_t
xrt_comp_destroy_passthrough(struct xrt_compositor *xc)
{
return xc->destroy_passthrough(xc);
}
/*!
* @name Session methods
@ -1681,6 +1795,19 @@ xrt_comp_layer_equirect2(struct xrt_compositor *xc,
return xc->layer_equirect2(xc, xdev, xsc, data);
}
/*!
* @copydoc xrt_compositor::layer_passthrough
*
* Helper for calling through the function pointer.
*
* @public @memberof xrt_compositor
*/
static inline xrt_result_t
xrt_comp_layer_passthrough(struct xrt_compositor *xc, struct xrt_device *xdev, const struct xrt_layer_data *data)
{
return xc->layer_passthrough(xc, xdev, data);
}
/*!
* @copydoc xrt_compositor::layer_commit
*

View file

@ -47,6 +47,7 @@
#cmakedefine XRT_FEATURE_OPENXR_LAYER_EQUIRECT1
#cmakedefine XRT_FEATURE_OPENXR_LAYER_EQUIRECT2
#cmakedefine XRT_FEATURE_OPENXR_LAYER_FB_ALPHA_BLEND
#cmakedefine XRT_FEATURE_OPENXR_LAYER_PASSTHROUGH
#cmakedefine XRT_FEATURE_OPENXR_LAYER_FB_IMAGE_LAYOUT
#cmakedefine XRT_FEATURE_OPENXR_LAYER_FB_SETTINGS
#cmakedefine XRT_FEATURE_OPENXR_LAYER_FB_DEPTH_TEST

View file

@ -115,6 +115,47 @@ enum xrt_blend_mode
#define XRT_MAX_DEVICE_BLEND_MODES 3
/*!
* Special flags for creating passthrough.
*/
enum xrt_passthrough_create_flags
{
//! Start the passthrough on creation
XRT_PASSTHROUGH_IS_RUNNING_AT_CREATION = (1 << 0),
//! Our compositor just ignores this bit.
XRT_PASSTHROUGH_LAYER_DEPTH = (1 << 1),
};
/*!
* Specify additional state change behavior.
*/
enum xrt_passthrough_state
{
//! Passthrough system requires reinitialization.
XRT_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT = (1 << 0),
//! Non-recoverable error has occurred.
XRT_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT = (1 << 1),
//! A recoverable error has occurred.
XRT_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT = (1 << 2),
//! The runtime has recovered from a previous error and is functioning normally.
XRT_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT = (1 << 3),
};
/*!
* Specify the kind of passthrough behavior the layer provides.
*/
enum xrt_passthrough_purpose_flags
{
//! Fullscreen layer
XRT_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION = (1 << 0),
//! Projected layer.
XRT_PASSTHROUGH_LAYER_PURPOSE_PROJECTED = (1 << 1),
//! Provided by XR_FB_passthrough_keyboard_hands
XRT_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS = 1000203001,
//! Provided by XR_FB_passthrough_keyboard_hands
XRT_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS = 1000203002,
};
/*!
* Which distortion model does the device expose,
* used both as a bitfield and value.

View file

@ -58,6 +58,9 @@ enum xrt_session_event_type
//! The performance of the session has changed
XRT_SESSION_EVENT_PERFORMANCE_CHANGE = 7,
//! The passthrough state of the session has changed
XRT_SESSION_EVENT_PASSTHRU_STATE_CHANGE = 8,
};
/*!
@ -152,6 +155,15 @@ struct xrt_session_event_perf_change
enum xrt_perf_notify_level to_level;
};
/*!
* Passthrough state change event.
*/
struct xrt_session_event_passthrough_state_change
{
enum xrt_session_event_type type;
enum xrt_passthrough_state state;
};
/*!
* Union of all session events, used to return multiple events through one call.
* Each event struct must start with a @ref xrt_session_event_type field.
@ -168,6 +180,7 @@ union xrt_session_event {
struct xrt_session_event_display_refresh_rate_change display;
struct xrt_session_event_reference_space_change_pending ref_change;
struct xrt_session_event_perf_change performance;
struct xrt_session_event_passthrough_state_change passthru;
};
/*!

View file

@ -104,6 +104,10 @@ if(WIN32)
target_compile_definitions(st_oxr PRIVATE XR_USE_PLATFORM_WIN32)
endif()
if(XRT_FEATURE_OPENXR_LAYER_PASSTHROUGH)
target_sources(st_oxr PRIVATE oxr_api_passthrough.c oxr_passthrough.c)
endif()
target_link_libraries(
st_oxr
PRIVATE

View file

@ -570,6 +570,44 @@ oxr_xrGetDisplayRefreshRateFB(XrSession session, float *displayRefreshRate);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrRequestDisplayRefreshRateFB(XrSession session, float displayRefreshRate);
/*
*
* oxr_api_passthrough.c
*
*/
#ifdef OXR_HAVE_FB_passthrough
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrCreateGeometryInstanceFB(XrSession session,
const XrGeometryInstanceCreateInfoFB *createInfo,
XrGeometryInstanceFB *outGeometryInstance);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrCreatePassthroughFB(XrSession session,
const XrPassthroughCreateInfoFB *createInfo,
XrPassthroughFB *outPassthrough);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrCreatePassthroughLayerFB(XrSession session,
const XrPassthroughLayerCreateInfoFB *createInfo,
XrPassthroughLayerFB *outLayer);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrDestroyGeometryInstanceFB(XrGeometryInstanceFB instance);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrDestroyPassthroughFB(XrPassthroughFB passthrough);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrDestroyPassthroughLayerFB(XrPassthroughLayerFB layer);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrGeometryInstanceSetTransformFB(XrGeometryInstanceFB instance,
const XrGeometryInstanceTransformFB *transformation);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrPassthroughLayerPauseFB(XrPassthroughLayerFB layer);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrPassthroughLayerResumeFB(XrPassthroughLayerFB layer);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrPassthroughLayerSetStyleFB(XrPassthroughLayerFB layer, const XrPassthroughStyleFB *style);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrPassthroughPauseFB(XrPassthroughFB passthrough);
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrPassthroughStartFB(XrPassthroughFB passthrough);
#endif
/*!
* @}
*/

View file

@ -246,6 +246,21 @@ handle_non_null(struct oxr_instance *inst, struct oxr_logger *log, const char *n
ENTRY_IF_EXT(xrRequestDisplayRefreshRateFB, FB_display_refresh_rate);
#endif
#ifdef OXR_HAVE_FB_passthrough
ENTRY_IF_EXT(xrCreateGeometryInstanceFB, FB_passthrough);
ENTRY_IF_EXT(xrCreatePassthroughFB, FB_passthrough);
ENTRY_IF_EXT(xrCreatePassthroughLayerFB, FB_passthrough);
ENTRY_IF_EXT(xrDestroyGeometryInstanceFB, FB_passthrough);
ENTRY_IF_EXT(xrDestroyPassthroughFB, FB_passthrough);
ENTRY_IF_EXT(xrDestroyPassthroughLayerFB, FB_passthrough);
ENTRY_IF_EXT(xrGeometryInstanceSetTransformFB, FB_passthrough);
ENTRY_IF_EXT(xrPassthroughLayerPauseFB, FB_passthrough);
ENTRY_IF_EXT(xrPassthroughLayerResumeFB, FB_passthrough);
ENTRY_IF_EXT(xrPassthroughLayerSetStyleFB, FB_passthrough);
ENTRY_IF_EXT(xrPassthroughPauseFB, FB_passthrough);
ENTRY_IF_EXT(xrPassthroughStartFB, FB_passthrough);
#endif // OXR_HAVE_FB_passthrough
#ifdef OXR_HAVE_EXT_debug_utils
ENTRY_IF_EXT(xrSetDebugUtilsObjectNameEXT, EXT_debug_utils);
ENTRY_IF_EXT(xrCreateDebugUtilsMessengerEXT, EXT_debug_utils);

View file

@ -0,0 +1,205 @@
// Copyright 2023-2024, Qualcomm Innovation Center, Inc.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief passthrough related API entrypoint functions.
* @author Knox Liu <quic_dengkail@qti.qualcomm.com>
* @ingroup oxr_api
*/
#include "oxr_objects.h"
#include "oxr_logger.h"
#include "oxr_handle.h"
#include "util/u_debug.h"
#include "util/u_trace_marker.h"
#include "oxr_api_funcs.h"
#include "oxr_api_verify.h"
#include "oxr_chain.h"
#include "oxr_subaction.h"
#include <stdio.h>
#include <inttypes.h>
XrResult
oxr_xrCreateGeometryInstanceFB(XrSession session,
const XrGeometryInstanceCreateInfoFB *createInfo,
XrGeometryInstanceFB *outGeometryInstance)
{
OXR_TRACE_MARKER();
struct oxr_logger log;
oxr_log_init(&log, "oxr_xrCreateGeometryInstanceFB");
return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
}
XrResult
oxr_xrCreatePassthroughFB(XrSession session,
const XrPassthroughCreateInfoFB *createInfo,
XrPassthroughFB *outPassthrough)
{
OXR_TRACE_MARKER();
struct oxr_session *sess;
struct oxr_logger log;
OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "oxr_xrCreatePassthroughFB");
OXR_VERIFY_SESSION_NOT_LOST(&log, sess);
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, createInfo, XR_TYPE_PASSTHROUGH_CREATE_INFO_FB);
OXR_VERIFY_PASSTHROUGH_FLAGS(&log, createInfo->flags);
struct oxr_passthrough *passthrough;
XrResult ret = oxr_passthrough_create(&log, sess, createInfo, &passthrough);
if (ret != XR_SUCCESS) {
return ret;
}
*outPassthrough = oxr_passthrough_to_openxr(passthrough);
return oxr_session_success_result(sess);
}
XrResult
oxr_xrCreatePassthroughLayerFB(XrSession session,
const XrPassthroughLayerCreateInfoFB *createInfo,
XrPassthroughLayerFB *outLayer)
{
OXR_TRACE_MARKER();
struct oxr_session *sess;
struct oxr_logger log;
OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "oxr_xrCreatePassthroughLayerFB");
OXR_VERIFY_SESSION_NOT_LOST(&log, sess);
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, createInfo, XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB);
OXR_VERIFY_ARG_NOT_NULL(&log, createInfo->passthrough);
OXR_VERIFY_PASSTHROUGH_FLAGS(&log, createInfo->flags);
OXR_VERIFY_PASSTHROUGH_LAYER_PURPOSE(&log, createInfo->purpose);
struct oxr_passthrough_layer *passthroughLayer;
XrResult ret = oxr_passthrough_layer_create(&log, sess, createInfo, &passthroughLayer);
if (ret != XR_SUCCESS) {
return ret;
}
*outLayer = oxr_passthrough_layer_to_openxr(passthroughLayer);
return oxr_session_success_result(sess);
}
XrResult
oxr_xrDestroyGeometryInstanceFB(XrGeometryInstanceFB instance)
{
OXR_TRACE_MARKER();
struct oxr_logger log;
oxr_log_init(&log, "oxr_xrDestroyGeometryInstanceFB");
return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
}
XrResult
oxr_xrDestroyPassthroughFB(XrPassthroughFB passthrough)
{
OXR_TRACE_MARKER();
struct oxr_passthrough *pt;
struct oxr_logger log;
OXR_VERIFY_PASSTHROUGH_AND_INIT_LOG(&log, passthrough, pt, "oxr_xrDestroyPassthroughFB");
xrt_comp_destroy_passthrough(pt->sess->compositor);
return oxr_handle_destroy(&log, &pt->handle);
}
XrResult
oxr_xrDestroyPassthroughLayerFB(XrPassthroughLayerFB layer)
{
OXR_TRACE_MARKER();
struct oxr_passthrough_layer *pl;
struct oxr_logger log;
OXR_VERIFY_PASSTHROUGH_LAYER_AND_INIT_LOG(&log, layer, pl, "oxr_xrDestroyPassthroughLayerFB");
return oxr_handle_destroy(&log, &pl->handle);
}
XrResult
oxr_xrGeometryInstanceSetTransformFB(XrGeometryInstanceFB instance, const XrGeometryInstanceTransformFB *transformation)
{
OXR_TRACE_MARKER();
struct oxr_logger log;
oxr_log_init(&log, "oxr_xrGeometryInstanceSetTransformFB");
return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
}
XrResult
oxr_xrPassthroughLayerPauseFB(XrPassthroughLayerFB layer)
{
OXR_TRACE_MARKER();
struct oxr_passthrough_layer *pl;
struct oxr_logger log;
OXR_VERIFY_PASSTHROUGH_LAYER_AND_INIT_LOG(&log, layer, pl, "oxr_xrPassthroughLayerPauseFB");
pl->paused = true;
return XR_SUCCESS;
}
XrResult
oxr_xrPassthroughLayerResumeFB(XrPassthroughLayerFB layer)
{
OXR_TRACE_MARKER();
struct oxr_passthrough_layer *pl;
struct oxr_logger log;
OXR_VERIFY_PASSTHROUGH_LAYER_AND_INIT_LOG(&log, layer, pl, "oxr_xrPassthroughLayerResumeFB");
pl->paused = false;
return XR_SUCCESS;
}
XrResult
oxr_xrPassthroughLayerSetStyleFB(XrPassthroughLayerFB layer, const XrPassthroughStyleFB *style)
{
OXR_TRACE_MARKER();
struct oxr_passthrough_layer *pl;
struct oxr_logger log;
OXR_VERIFY_PASSTHROUGH_LAYER_AND_INIT_LOG(&log, layer, pl, "oxr_xrPassthroughLayerResumeFB");
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, style, XR_TYPE_PASSTHROUGH_STYLE_FB);
OXR_VERIFY_PASSTHROUGH_LAYER_STYLE(&log, style);
pl->style = *style;
XrPassthroughStyleFB *next = (XrPassthroughStyleFB *)style->next;
while (next) {
switch (next->type) {
case XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB:
pl->brightnessContrastSaturation = *(XrPassthroughBrightnessContrastSaturationFB *)next;
break;
case XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB:
pl->monoToMono = *(XrPassthroughColorMapMonoToMonoFB *)next;
break;
case XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB:
pl->monoToRgba = *(XrPassthroughColorMapMonoToRgbaFB *)next;
break;
}
next = (XrPassthroughStyleFB *)next->next;
}
return XR_SUCCESS;
}
XrResult
oxr_xrPassthroughPauseFB(XrPassthroughFB passthrough)
{
OXR_TRACE_MARKER();
struct oxr_passthrough *pt;
struct oxr_logger log;
OXR_VERIFY_PASSTHROUGH_AND_INIT_LOG(&log, passthrough, pt, "oxr_xrPassthroughPauseFB");
pt->paused = true;
return XR_SUCCESS;
}
XrResult
oxr_xrPassthroughStartFB(XrPassthroughFB passthrough)
{
OXR_TRACE_MARKER();
struct oxr_passthrough *pt;
struct oxr_logger log;
OXR_VERIFY_PASSTHROUGH_AND_INIT_LOG(&log, passthrough, pt, "oxr_xrPassthroughStartFB");
pt->paused = false;
return XR_SUCCESS;
}

View file

@ -67,6 +67,10 @@ extern "C" {
OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_hand_tracker, HTRACKER, name, new_thing->sess->sys->inst)
#define OXR_VERIFY_FORCE_FEEDBACK_AND_INIT_LOG(log, thing, new_thing, name) \
OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_force_feedback, FFB, name, new_thing->sess->sys->inst)
#define OXR_VERIFY_PASSTHROUGH_AND_INIT_LOG(log, thing, new_thing, name) \
OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_passthrough, PASSTHROUGH, name, new_thing->sess->sys->inst)
#define OXR_VERIFY_PASSTHROUGH_LAYER_AND_INIT_LOG(log, thing, new_thing, name) \
OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_passthrough_layer, PASSTHROUGH_LAYER, name, new_thing->sess->sys->inst)
// clang-format on
#define OXR_VERIFY_INSTANCE_NOT_NULL(log, arg, new_arg) OXR_VERIFY_SET(log, arg, new_arg, oxr_instance, INSTANCE);
@ -229,6 +233,37 @@ extern "C" {
} \
} while (false)
#define OXR_VERIFY_PASSTHROUGH_FLAGS(log, flags) \
if (flags == 0 || \
(flags & (XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB | XR_PASSTHROUGH_LAYER_DEPTH_BIT_FB)) == 0) \
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, \
"flags is not a valid combination of XrPassthroughFlagBitsFB values");
#define OXR_VERIFY_PASSTHROUGH_LAYER_PURPOSE(log, purpose) \
if ((purpose != XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB && \
purpose != XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB && \
purpose != XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB && \
purpose != XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB)) \
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, \
"purpose is not a valid XrPassthroughLayerPurposeFB value");
#define OXR_VERIFY_PASSTHROUGH_LAYER_STYLE(log, style) \
do { \
uint32_t duplicate_check = 0; \
const XrPassthroughStyleFB *next = style->next; \
while (next) { \
if (next->type != XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB && \
next->type != XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB && \
next->type != XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB) \
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, \
"style next structure chain contains invalid pointers"); \
if ((next->type & duplicate_check) != 0) \
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, \
"style next structure chain contains duplicate items"); \
duplicate_check |= next->type; \
next = (const XrPassthroughStyleFB *)next->next; \
} \
} while (false)
/*
*

View file

@ -25,6 +25,8 @@
#define OXR_XR_DEBUG_SOURCESET (*(uint64_t *)"oxrsrcs\0")
#define OXR_XR_DEBUG_SOURCE (*(uint64_t *)"oxrsrc_\0")
#define OXR_XR_DEBUG_HTRACKER (*(uint64_t *)"oxrhtra\0")
#define OXR_XR_DEBUG_PASSTHROUGH (*(uint64_t *)"oxrpass\0")
#define OXR_XR_DEBUG_PASSTHROUGH_LAYER (*(uint64_t *)"oxrptla\0")
// clang-format on
/*!

View file

@ -296,6 +296,28 @@ oxr_event_push_XrEventDataPerfSettingsEXTX(struct oxr_logger *log,
}
#endif // OXR_HAVE_EXT_performance_settings
#ifdef OXR_HAVE_FB_passthrough
XrResult
oxr_event_push_XrEventDataPassthroughStateChangedFB(struct oxr_logger *log,
struct oxr_session *sess,
XrPassthroughStateChangedFlagsFB flags)
{
struct oxr_instance *inst = sess->sys->inst;
XrEventDataPassthroughStateChangedFB *changed;
struct oxr_event *event = NULL;
ALLOC(log, inst, &event, &changed);
changed->type = XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB;
changed->flags = flags;
event->result = XR_SUCCESS;
lock(inst);
push(inst, event);
unlock(inst);
return XR_SUCCESS;
}
#endif // OXR_HAVE_FB_passthrough
XrResult
oxr_event_remove_session_events(struct oxr_logger *log, struct oxr_session *sess)
{

View file

@ -439,6 +439,15 @@
#define OXR_EXTENSION_SUPPORT_FB_display_refresh_rate(_)
#endif
/*
* XR_FB_passthrough
*/
#if defined(XR_FB_passthrough) && defined(XRT_FEATURE_OPENXR_LAYER_PASSTHROUGH)
#define OXR_HAVE_FB_passthrough
#define OXR_EXTENSION_SUPPORT_FB_passthrough(_) _(FB_passthrough, FB_PASSTHROUGH)
#else
#define OXR_EXTENSION_SUPPORT_FB_passthrough(_)
#endif
/*
* XR_ML_ml2_controller_interaction
@ -648,6 +657,7 @@
OXR_EXTENSION_SUPPORT_FB_composition_layer_settings(_) \
OXR_EXTENSION_SUPPORT_FB_composition_layer_depth_test(_) \
OXR_EXTENSION_SUPPORT_FB_display_refresh_rate(_) \
OXR_EXTENSION_SUPPORT_FB_passthrough(_) \
OXR_EXTENSION_SUPPORT_ML_ml2_controller_interaction(_) \
OXR_EXTENSION_SUPPORT_MND_headless(_) \
OXR_EXTENSION_SUPPORT_MND_swapchain_usage_input_attachment_bit(_) \

View file

@ -2477,6 +2477,70 @@ struct oxr_hand_tracker
XrHandJointSetEXT hand_joint_set;
};
#ifdef OXR_HAVE_FB_passthrough
struct oxr_passthrough
{
struct oxr_handle_base handle;
struct oxr_session *sess;
XrPassthroughFlagsFB flags;
bool paused;
};
struct oxr_passthrough_layer
{
struct oxr_handle_base handle;
struct oxr_session *sess;
XrPassthroughFB passthrough;
XrPassthroughFlagsFB flags;
XrPassthroughLayerPurposeFB purpose;
bool paused;
XrPassthroughStyleFB style;
XrPassthroughColorMapMonoToRgbaFB monoToRgba;
XrPassthroughColorMapMonoToMonoFB monoToMono;
XrPassthroughBrightnessContrastSaturationFB brightnessContrastSaturation;
};
XrResult
oxr_passthrough_create(struct oxr_logger *log,
struct oxr_session *sess,
const XrPassthroughCreateInfoFB *createInfo,
struct oxr_passthrough **out_passthrough);
XrResult
oxr_passthrough_layer_create(struct oxr_logger *log,
struct oxr_session *sess,
const XrPassthroughLayerCreateInfoFB *createInfo,
struct oxr_passthrough_layer **out_layer);
static inline XrPassthroughFB
oxr_passthrough_to_openxr(struct oxr_passthrough *passthrough)
{
return XRT_CAST_PTR_TO_OXR_HANDLE(XrPassthroughFB, passthrough);
}
static inline XrPassthroughLayerFB
oxr_passthrough_layer_to_openxr(struct oxr_passthrough_layer *passthroughLayer)
{
return XRT_CAST_PTR_TO_OXR_HANDLE(XrPassthroughLayerFB, passthroughLayer);
}
XrResult
oxr_event_push_XrEventDataPassthroughStateChangedFB(struct oxr_logger *log,
struct oxr_session *sess,
XrPassthroughStateChangedFlagsFB flags);
#endif // OXR_HAVE_FB_passthrough
/*!
* @}
*/

View file

@ -0,0 +1,144 @@
// Copyright 2023-2024, Qualcomm Innovation Center, Inc.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief passthrough related API entrypoint functions.
* @author Knox Liu <quic_dengkail@qti.qualcomm.com>
* @ingroup oxr_main
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "math/m_api.h"
#include "math/m_space.h"
#include "util/u_debug.h"
#include "util/u_misc.h"
#include "oxr_objects.h"
#include "oxr_logger.h"
#include "oxr_handle.h"
#include "oxr_input_transform.h"
#include "oxr_chain.h"
#include "oxr_pretty_print.h"
/*
*
* XR_FB_passthrough
*
*/
static enum xrt_passthrough_create_flags
convert_create_flags(XrPassthroughFlagsFB xr_flags)
{
enum xrt_passthrough_create_flags flags = 0;
if ((xr_flags & XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB) != 0) {
flags |= XRT_PASSTHROUGH_IS_RUNNING_AT_CREATION;
}
if ((xr_flags & XR_PASSTHROUGH_LAYER_DEPTH_BIT_FB) != 0) {
flags |= XRT_PASSTHROUGH_LAYER_DEPTH;
}
return flags;
}
static enum xrt_passthrough_purpose_flags
convert_purpose_flags(XrPassthroughLayerPurposeFB xr_flags)
{
enum xrt_passthrough_purpose_flags flags = 0;
if ((xr_flags & XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB) != 0) {
flags |= XRT_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION;
}
if ((xr_flags & XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB) != 0) {
flags |= XRT_PASSTHROUGH_LAYER_PURPOSE_PROJECTED;
}
if ((xr_flags & XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB) != 0) {
flags |= XRT_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS;
}
if ((xr_flags & XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB) != 0) {
flags |= XRT_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS;
}
return flags;
}
static XrResult
oxr_passthrough_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
{
struct oxr_passthrough *passthrough = (struct oxr_passthrough *)hb;
free(passthrough);
return XR_SUCCESS;
}
static XrResult
oxr_passthrough_layer_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
{
struct oxr_passthrough_layer *passthroughLayer = (struct oxr_passthrough_layer *)hb;
free(passthroughLayer);
return XR_SUCCESS;
}
XrResult
oxr_passthrough_create(struct oxr_logger *log,
struct oxr_session *sess,
const XrPassthroughCreateInfoFB *createInfo,
struct oxr_passthrough **out_passthrough)
{
struct oxr_instance *inst = sess->sys->inst;
struct oxr_passthrough *passthrough = NULL;
OXR_ALLOCATE_HANDLE_OR_RETURN(log, passthrough, OXR_XR_DEBUG_PASSTHROUGH, oxr_passthrough_destroy,
&sess->handle);
passthrough->sess = sess;
passthrough->flags = createInfo->flags;
xrt_result_t xret = XRT_SUCCESS;
struct xrt_passthrough_create_info info;
info.create = convert_create_flags(createInfo->flags);
xret = xrt_comp_create_passthrough(sess->compositor, &info);
if (xret != XRT_SUCCESS) {
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to create passthrough");
}
*out_passthrough = passthrough;
return XR_SUCCESS;
}
XrResult
oxr_passthrough_layer_create(struct oxr_logger *log,
struct oxr_session *sess,
const XrPassthroughLayerCreateInfoFB *createInfo,
struct oxr_passthrough_layer **out_layer)
{
struct oxr_instance *inst = sess->sys->inst;
struct oxr_passthrough_layer *passthroughLayer = NULL;
OXR_ALLOCATE_HANDLE_OR_RETURN(log, passthroughLayer, OXR_XR_DEBUG_PASSTHROUGH_LAYER,
oxr_passthrough_layer_destroy, &sess->handle);
passthroughLayer->sess = sess;
passthroughLayer->passthrough = createInfo->passthrough;
passthroughLayer->flags = createInfo->flags;
passthroughLayer->purpose = createInfo->purpose;
xrt_result_t xret = XRT_SUCCESS;
struct xrt_passthrough_layer_create_info info;
info.create = convert_create_flags(createInfo->flags);
info.purpose = convert_purpose_flags(createInfo->purpose);
xret = xrt_comp_create_passthrough_layer(sess->compositor, &info);
if (xret != XRT_SUCCESS) {
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to create passthrough layer");
}
*out_layer = passthroughLayer;
return XR_SUCCESS;
}

View file

@ -314,6 +314,27 @@ oxr_session_request_exit(struct oxr_logger *log, struct oxr_session *sess)
return oxr_session_success_result(sess);
}
#ifdef OXR_HAVE_FB_passthrough
static inline XrPassthroughStateChangedFlagsFB
xrt_to_passthrough_state_flags(enum xrt_passthrough_state state)
{
XrPassthroughStateChangedFlagsFB res = 0;
if (state & XRT_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT) {
res |= XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB;
}
if (state & XRT_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT) {
res |= XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB;
}
if (state & XRT_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT) {
res |= XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB;
}
if (state & XRT_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT) {
res |= XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB;
}
return res;
}
#endif
XrResult
oxr_session_poll(struct oxr_logger *log, struct oxr_session *sess)
{
@ -370,6 +391,12 @@ oxr_session_poll(struct oxr_logger *log, struct oxr_session *sess)
xse.performance.to_level);
#endif // OXR_HAVE_EXT_performance_settings
break;
case XRT_SESSION_EVENT_PASSTHRU_STATE_CHANGE:
#ifdef OXR_HAVE_FB_passthrough
oxr_event_push_XrEventDataPassthroughStateChangedFB(
log, sess, xrt_to_passthrough_state_flags(xse.passthru.state));
#endif // OXR_HAVE_FB_passthrough
break;
default: U_LOG_W("unhandled event type! %d", xse.type); break;
}
}

View file

@ -313,6 +313,25 @@ fill_in_depth_test(struct oxr_session *sess, const XrCompositionLayerBaseHeader
#endif // OXR_HAVE_FB_composition_layer_depth_test
}
static void
fill_in_passthrough(struct oxr_session *sess, const XrCompositionLayerBaseHeader *layer, struct xrt_layer_data *data)
{
#ifdef OXR_HAVE_FB_passthrough
// Is the extension enabled?
if (!sess->sys->inst->extensions.FB_passthrough) {
return;
}
const XrCompositionLayerPassthroughFB *passthrough = OXR_GET_INPUT_FROM_CHAIN(
layer, (XrStructureType)XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB, XrCompositionLayerPassthroughFB);
struct oxr_passthrough_layer *layer_handle =
XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_passthrough_layer *, passthrough->layerHandle);
data->passthrough.xrt_pl.paused = layer_handle->paused;
struct oxr_passthrough *passthrough_handle =
XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_passthrough *, layer_handle->passthrough);
data->passthrough.xrt_pt.paused = passthrough_handle->paused;
#endif
}
/*
*
* Verify functions.
@ -1066,6 +1085,45 @@ verify_equirect2_layer(struct oxr_session *sess,
#endif // OXR_HAVE_KHR_composition_layer_equirect2
}
static XrResult
verify_passthrough_layer(struct xrt_compositor *xc,
struct oxr_logger *log,
uint32_t layer_index,
const XrCompositionLayerPassthroughFB *passthrough,
struct xrt_device *head,
uint64_t timestamp)
{
#ifndef OXR_HAVE_FB_passthrough
return oxr_error(log, XR_ERROR_LAYER_INVALID,
"(frameEndInfo->layers[%u]->type) layer type XrCompositionLayerPassthroughFB not supported",
layer_index);
#else
if (passthrough->flags == 0 || (passthrough->flags & (XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT |
XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT |
XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT)) == 0) {
return oxr_error(log, XR_ERROR_LAYER_INVALID,
"(frameEndInfo->layers[%u]->flags) layer flags is not a valid combination of "
"XrCompositionLayerFlagBits values",
layer_index);
}
if (passthrough->space) {
XrResult ret = verify_space(log, layer_index, passthrough->space);
if (ret != XR_SUCCESS) {
return ret;
}
}
struct oxr_passthrough_layer *pl =
XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_passthrough_layer *, passthrough->layerHandle);
if (pl == NULL) {
return oxr_error(log, XR_ERROR_LAYER_INVALID,
"(frameEndInfo->layers[%u]->layerHandle) layerHandle is NULL!", layer_index);
}
return XR_SUCCESS;
#endif
}
/*
*
@ -1526,6 +1584,33 @@ submit_equirect2_layer(struct oxr_session *sess,
return XR_SUCCESS;
}
static XrResult
submit_passthrough_layer(struct oxr_session *sess,
struct xrt_compositor *xc,
struct oxr_logger *log,
const XrCompositionLayerPassthroughFB *passthrough,
struct xrt_device *head,
struct xrt_pose *inv_offset,
uint64_t oxr_timestamp,
uint64_t xrt_timestamp)
{
enum xrt_layer_composition_flags flags = convert_layer_flags(passthrough->flags);
struct xrt_layer_data data;
U_ZERO(&data);
data.type = XRT_LAYER_PASSTHROUGH;
data.name = XRT_INPUT_GENERIC_HEAD_POSE;
data.timestamp = xrt_timestamp;
data.flags = flags;
fill_in_passthrough(sess, (XrCompositionLayerBaseHeader *)passthrough, &data);
fill_in_blend_factors(sess, (XrCompositionLayerBaseHeader *)passthrough, &data);
xrt_result_t xret = xrt_comp_layer_passthrough(xc, head, &data);
OXR_CHECK_XRET(log, sess, xret, xrt_comp_layer_passthrough);
return XR_SUCCESS;
}
XrResult
oxr_session_frame_end(struct oxr_logger *log, struct oxr_session *sess, const XrFrameEndInfo *frameEndInfo)
{
@ -1655,6 +1740,10 @@ oxr_session_frame_end(struct oxr_logger *log, struct oxr_session *sess, const Xr
res = verify_equirect2_layer(sess, xc, log, i, (XrCompositionLayerEquirect2KHR *)layer, xdev,
frameEndInfo->displayTime);
break;
case XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB:
res = verify_passthrough_layer(xc, log, i, (XrCompositionLayerPassthroughFB *)layer, xdev,
frameEndInfo->displayTime);
break;
default:
return oxr_error(log, XR_ERROR_LAYER_INVALID,
"(frameEndInfo->layers[%u]->type) layer type not supported (%u)", i,
@ -1716,6 +1805,10 @@ oxr_session_frame_end(struct oxr_logger *log, struct oxr_session *sess, const Xr
submit_equirect2_layer(sess, xc, log, (XrCompositionLayerEquirect2KHR *)layer, xdev,
&inv_offset, frameEndInfo->displayTime, xrt_display_time_ns);
break;
case XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB:
submit_passthrough_layer(sess, xc, log, (XrCompositionLayerPassthroughFB *)layer, xdev,
&inv_offset, frameEndInfo->displayTime, xrt_display_time_ns);
break;
default: assert(false && "invalid layer type");
}
}

View file

@ -329,6 +329,24 @@ oxr_system_get_properties(struct oxr_logger *log, struct oxr_system *sys, XrSyst
}
#endif
#ifdef OXR_HAVE_FB_passthrough
XrSystemPassthroughPropertiesFB *passthrough_props = NULL;
XrSystemPassthroughProperties2FB *passthrough_props2 = NULL;
if (sys->inst->extensions.FB_passthrough) {
passthrough_props = OXR_GET_OUTPUT_FROM_CHAIN(properties, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB,
XrSystemPassthroughPropertiesFB);
if (passthrough_props) {
passthrough_props->supportsPassthrough = true;
}
passthrough_props2 = OXR_GET_OUTPUT_FROM_CHAIN(properties, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB,
XrSystemPassthroughProperties2FB);
if (passthrough_props2) {
passthrough_props2->capabilities = XR_PASSTHROUGH_CAPABILITY_BIT_FB;
}
}
#endif
return XR_SUCCESS;
}