diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c536e012..cd921fd3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}") diff --git a/scripts/generate_oxr_ext_support.py b/scripts/generate_oxr_ext_support.py index 2d59a950e..7c7b5920b 100755 --- a/scripts/generate_oxr_ext_support.py +++ b/scripts/generate_oxr_ext_support.py @@ -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'], diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h index 16fc8c600..d6c03ba45 100644 --- a/src/xrt/include/xrt/xrt_compositor.h +++ b/src/xrt/include/xrt/xrt_compositor.h @@ -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 * diff --git a/src/xrt/include/xrt/xrt_config_build.h.cmake_in b/src/xrt/include/xrt/xrt_config_build.h.cmake_in index aff267aeb..ce3c8f81a 100644 --- a/src/xrt/include/xrt/xrt_config_build.h.cmake_in +++ b/src/xrt/include/xrt/xrt_config_build.h.cmake_in @@ -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 diff --git a/src/xrt/include/xrt/xrt_defines.h b/src/xrt/include/xrt/xrt_defines.h index 2689faf65..0014a2461 100644 --- a/src/xrt/include/xrt/xrt_defines.h +++ b/src/xrt/include/xrt/xrt_defines.h @@ -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. diff --git a/src/xrt/include/xrt/xrt_session.h b/src/xrt/include/xrt/xrt_session.h index f107700ff..396174f2d 100644 --- a/src/xrt/include/xrt/xrt_session.h +++ b/src/xrt/include/xrt/xrt_session.h @@ -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; }; /*! diff --git a/src/xrt/state_trackers/oxr/CMakeLists.txt b/src/xrt/state_trackers/oxr/CMakeLists.txt index 6749a69d2..d3684ab91 100644 --- a/src/xrt/state_trackers/oxr/CMakeLists.txt +++ b/src/xrt/state_trackers/oxr/CMakeLists.txt @@ -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 diff --git a/src/xrt/state_trackers/oxr/oxr_api_funcs.h b/src/xrt/state_trackers/oxr/oxr_api_funcs.h index 2fa2a47e0..d9f136e4b 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_funcs.h +++ b/src/xrt/state_trackers/oxr/oxr_api_funcs.h @@ -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 /*! * @} */ diff --git a/src/xrt/state_trackers/oxr/oxr_api_negotiate.c b/src/xrt/state_trackers/oxr/oxr_api_negotiate.c index 5e3a7518e..c9fdff82c 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_negotiate.c +++ b/src/xrt/state_trackers/oxr/oxr_api_negotiate.c @@ -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); diff --git a/src/xrt/state_trackers/oxr/oxr_api_passthrough.c b/src/xrt/state_trackers/oxr/oxr_api_passthrough.c new file mode 100644 index 000000000..81cbead2a --- /dev/null +++ b/src/xrt/state_trackers/oxr/oxr_api_passthrough.c @@ -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 + * @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 +#include + +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; +} diff --git a/src/xrt/state_trackers/oxr/oxr_api_verify.h b/src/xrt/state_trackers/oxr/oxr_api_verify.h index e1b135621..517881ae9 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_verify.h +++ b/src/xrt/state_trackers/oxr/oxr_api_verify.h @@ -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) /* * diff --git a/src/xrt/state_trackers/oxr/oxr_defines.h b/src/xrt/state_trackers/oxr/oxr_defines.h index 0d7a9e74f..aa4e4e78d 100644 --- a/src/xrt/state_trackers/oxr/oxr_defines.h +++ b/src/xrt/state_trackers/oxr/oxr_defines.h @@ -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 /*! diff --git a/src/xrt/state_trackers/oxr/oxr_event.c b/src/xrt/state_trackers/oxr/oxr_event.c index 9943e7a97..d9b3dc8dc 100644 --- a/src/xrt/state_trackers/oxr/oxr_event.c +++ b/src/xrt/state_trackers/oxr/oxr_event.c @@ -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) { diff --git a/src/xrt/state_trackers/oxr/oxr_extension_support.h b/src/xrt/state_trackers/oxr/oxr_extension_support.h index cc60daf39..0145bab78 100644 --- a/src/xrt/state_trackers/oxr/oxr_extension_support.h +++ b/src/xrt/state_trackers/oxr/oxr_extension_support.h @@ -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(_) \ diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index ed14aa2a3..54d9d541a 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -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 + /*! * @} */ diff --git a/src/xrt/state_trackers/oxr/oxr_passthrough.c b/src/xrt/state_trackers/oxr/oxr_passthrough.c new file mode 100644 index 000000000..c30b1eb8d --- /dev/null +++ b/src/xrt/state_trackers/oxr/oxr_passthrough.c @@ -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 + * @ingroup oxr_main + */ + +#include +#include +#include + +#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; +} diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 3972da9e6..f7d7c7e01 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -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; } } diff --git a/src/xrt/state_trackers/oxr/oxr_session_frame_end.c b/src/xrt/state_trackers/oxr/oxr_session_frame_end.c index 32ce26b32..a339b796a 100644 --- a/src/xrt/state_trackers/oxr/oxr_session_frame_end.c +++ b/src/xrt/state_trackers/oxr/oxr_session_frame_end.c @@ -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"); } } diff --git a/src/xrt/state_trackers/oxr/oxr_system.c b/src/xrt/state_trackers/oxr/oxr_system.c index ad518186e..706c66328 100644 --- a/src/xrt/state_trackers/oxr/oxr_system.c +++ b/src/xrt/state_trackers/oxr/oxr_system.c @@ -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; }