The open source OpenXR runtime

st/oxr: implement XR_EXT_plane_detection

Co-Authored-By: Christoph Haag <christoph.haag@collabora.com>
Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2439>

authored by

Simon Zeni
Christoph Haag
and committed by
Korcan Hussein
df047b54 f4c1b671

+503 -2
+2
CMakeLists.txt
··· 364 364 option(XRT_FEATURE_OPENXR_HEADLESS "Enable XR_MND_headless" ON) 365 365 option(XRT_FEATURE_OPENXR_OVERLAY "Enable XR_EXTX_overlay" ON) 366 366 option(XRT_FEATURE_OPENXR_PERFORMANCE_SETTINGS "Enable XR_EXT_performance_settings" OFF) 367 + option(XRT_FEATURE_OPENXR_PLANE_DETECTION "Enable XR_EXT_plane_detection" OFF) 367 368 option(XRT_FEATURE_OPENXR_VISIBILITY_MASK "Enable XR_KHR_visibility_mask" ON) 368 369 option(XRT_FEATURE_OPENXR_VULKAN_SWAPCHAIN_FORMAT_LIST "Enable XR_KHR_vulkan_swapchain_format_list" ON) 369 370 option(XRT_FEATURE_OPENXR_XDEV_SPACE "Enable XR_MNDX_xdev_space" ON) ··· 621 622 message(STATUS "# FEATURE_OPENXR_LAYER_FB_PASSTHROUGH: ${XRT_FEATURE_OPENXR_LAYER_FB_PASSTHROUGH}") 622 623 message(STATUS "# FEATURE_OPENXR_OVERLAY: ${XRT_FEATURE_OPENXR_OVERLAY}") 623 624 message(STATUS "# FEATURE_OPENXR_PERFORMANCE_SETTINGS: ${XRT_FEATURE_OPENXR_PERFORMANCE_SETTINGS}") 625 + message(STATUS "# FEATURE_OPENXR_PLANE_DETECTION: ${XRT_FEATURE_OPENXR_PLANE_DETECTION}") 624 626 message(STATUS "# FEATURE_OPENXR_SPACE_LOCAL_FLOOR: ${XRT_FEATURE_OPENXR_SPACE_LOCAL_FLOOR}") 625 627 message(STATUS "# FEATURE_OPENXR_SPACE_UNBOUNDED: ${XRT_FEATURE_OPENXR_SPACE_UNBOUNDED}") 626 628 message(STATUS "# FEATURE_OPENXR_VISIBILITY_MASK: ${XRT_FEATURE_OPENXR_VISIBILITY_MASK}")
+1
doc/changes/xrt/mr.2439.md
··· 1 + Adds support for XR_EXT_plane_detection extension
+1
scripts/generate_oxr_ext_support.py
··· 82 82 ['XR_HTC_facial_tracking', 'XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC'], 83 83 ['XR_META_touch_controller_plus', 'XRT_FEATURE_OPENXR_INTERACTION_TOUCH_PLUS'], 84 84 ['XR_ML_ml2_controller_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_ML2'], 85 + ['XR_EXT_plane_detection', 'XRT_FEATURE_OPENXR_PLANE_DETECTION'], 85 86 ['XR_MND_headless', 'XRT_FEATURE_OPENXR_HEADLESS'], 86 87 ['XR_MND_swapchain_usage_input_attachment_bit'], 87 88 ['XR_MSFT_hand_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_MSFT_HAND'],
+1
src/xrt/include/xrt/xrt_config_build.h.cmake_in
··· 66 66 #cmakedefine XRT_FEATURE_OPENXR_LAYER_FB_SETTINGS 67 67 #cmakedefine XRT_FEATURE_OPENXR_LAYER_FB_PASSTHROUGH 68 68 #cmakedefine XRT_FEATURE_OPENXR_OVERLAY 69 + #cmakedefine XRT_FEATURE_OPENXR_PLANE_DETECTION 69 70 #cmakedefine XRT_FEATURE_OPENXR_SPACE_LOCAL_FLOOR 70 71 #cmakedefine XRT_FEATURE_OPENXR_SPACE_UNBOUNDED 71 72 #cmakedefine XRT_FEATURE_OPENXR_VISIBILITY_MASK
+27 -2
src/xrt/state_trackers/oxr/oxr_api_funcs.h
··· 571 571 XRAPI_ATTR XrResult XRAPI_CALL 572 572 oxr_xrRequestDisplayRefreshRateFB(XrSession session, float displayRefreshRate); 573 573 574 - 575 574 //! OpenXR API function @ep{xrLocateSpacesKHR} 576 575 XRAPI_ATTR XrResult XRAPI_CALL 577 576 oxr_xrLocateSpacesKHR(XrSession session, const XrSpacesLocateInfoKHR *locateInfo, XrSpaceLocationsKHR *spaceLocations); ··· 579 578 //! OpenXR API function @ep{xrLocateSpaces} 580 579 XRAPI_ATTR XrResult XRAPI_CALL 581 580 oxr_xrLocateSpaces(XrSession session, const XrSpacesLocateInfo *locateInfo, XrSpaceLocations *spaceLocations); 581 + 582 + #ifdef OXR_HAVE_EXT_plane_detection 583 + XRAPI_ATTR XrResult XRAPI_CALL 584 + oxr_xrCreatePlaneDetectorEXT(XrSession session, 585 + const XrPlaneDetectorCreateInfoEXT *createInfo, 586 + XrPlaneDetectorEXT *planeDetector); 587 + 588 + XRAPI_ATTR XrResult XRAPI_CALL 589 + oxr_xrDestroyPlaneDetectorEXT(XrPlaneDetectorEXT planeDetector); 590 + 591 + XRAPI_ATTR XrResult XRAPI_CALL 592 + oxr_xrBeginPlaneDetectionEXT(XrPlaneDetectorEXT planeDetector, const XrPlaneDetectorBeginInfoEXT *beginInfo); 593 + 594 + XRAPI_ATTR XrResult XRAPI_CALL 595 + oxr_xrGetPlaneDetectionStateEXT(XrPlaneDetectorEXT planeDetector, XrPlaneDetectionStateEXT *state); 596 + 597 + XRAPI_ATTR XrResult XRAPI_CALL 598 + oxr_xrGetPlaneDetectionsEXT(XrPlaneDetectorEXT planeDetector, 599 + const XrPlaneDetectorGetInfoEXT *info, 600 + XrPlaneDetectorLocationsEXT *locations); 601 + 602 + XRAPI_ATTR XrResult XRAPI_CALL 603 + oxr_xrGetPlanePolygonBufferEXT(XrPlaneDetectorEXT planeDetector, 604 + uint64_t planeId, 605 + uint32_t polygonBufferIndex, 606 + XrPlaneDetectorPolygonBufferEXT *polygonBuffer); 607 + #endif // OXR_HAVE_EXT_plane_detection 582 608 583 609 /* 584 610 * ··· 707 733 XRAPI_ATTR XrResult XRAPI_CALL 708 734 oxr_xrCreateXDevSpaceMNDX(XrSession session, const XrCreateXDevSpaceInfoMNDX *createInfo, XrSpace *space); 709 735 #endif 710 - 711 736 712 737 /*! 713 738 * @}
+9
src/xrt/state_trackers/oxr/oxr_api_negotiate.c
··· 275 275 ENTRY_IF_EXT(xrPassthroughStartFB, FB_passthrough); 276 276 #endif // OXR_HAVE_FB_passthrough 277 277 278 + #ifdef OXR_HAVE_EXT_plane_detection 279 + ENTRY_IF_EXT(xrCreatePlaneDetectorEXT, EXT_plane_detection); 280 + ENTRY_IF_EXT(xrDestroyPlaneDetectorEXT, EXT_plane_detection); 281 + ENTRY_IF_EXT(xrBeginPlaneDetectionEXT, EXT_plane_detection); 282 + ENTRY_IF_EXT(xrGetPlaneDetectionStateEXT, EXT_plane_detection); 283 + ENTRY_IF_EXT(xrGetPlaneDetectionsEXT, EXT_plane_detection); 284 + ENTRY_IF_EXT(xrGetPlanePolygonBufferEXT, EXT_plane_detection); 285 + #endif 286 + 278 287 #ifdef OXR_HAVE_EXT_debug_utils 279 288 ENTRY_IF_EXT(xrSetDebugUtilsObjectNameEXT, EXT_debug_utils); 280 289 ENTRY_IF_EXT(xrCreateDebugUtilsMessengerEXT, EXT_debug_utils);
+376
src/xrt/state_trackers/oxr/oxr_api_session.c
··· 12 12 #include <stdlib.h> 13 13 #include <string.h> 14 14 15 + #include "math/m_space.h" 15 16 #include "xrt/xrt_compiler.h" 16 17 17 18 #include "util/u_debug.h" ··· 699 700 } 700 701 701 702 #endif 703 + 704 + #ifdef OXR_HAVE_EXT_plane_detection 705 + 706 + static XrResult 707 + oxr_plane_detector_destroy_cb(struct oxr_logger *log, struct oxr_handle_base *hb) 708 + { 709 + struct oxr_plane_detector_ext *pd = (struct oxr_plane_detector_ext *)hb; 710 + 711 + free(pd->xr_locations); 712 + 713 + if (pd->detection_id > 0) { 714 + enum xrt_result xret = xrt_device_destroy_plane_detection_ext(pd->xdev, pd->detection_id); 715 + if (xret != XRT_SUCCESS) { 716 + return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, 717 + "Internal error in xrDestroyPlaneDetectorEXT: %d", xret); 718 + } 719 + } 720 + 721 + xrt_plane_detections_ext_clear(&pd->detections); 722 + 723 + free(pd); 724 + 725 + return XR_SUCCESS; 726 + } 727 + 728 + XRAPI_ATTR XrResult XRAPI_CALL 729 + oxr_xrCreatePlaneDetectorEXT(XrSession session, 730 + const XrPlaneDetectorCreateInfoEXT *createInfo, 731 + XrPlaneDetectorEXT *planeDetector) 732 + { 733 + struct oxr_session *sess; 734 + struct oxr_logger log; 735 + OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrCreatePlaneDetectorEXT"); 736 + OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, createInfo, XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT); 737 + OXR_VERIFY_EXTENSION(&log, sess->sys->inst, EXT_plane_detection); 738 + 739 + //! @todo support planes on other devices 740 + struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head); 741 + if (!xdev->planes_supported) { 742 + return XR_ERROR_FEATURE_UNSUPPORTED; 743 + } 744 + 745 + if (createInfo->flags != 0 && createInfo->flags != XR_PLANE_DETECTOR_ENABLE_CONTOUR_BIT_EXT) { 746 + //! @todo: Disabled to allow Monado forks with internal extensions to have more values. 747 + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "Invalid plane detector creation flags: %lx", 748 + createInfo->flags); 749 + } 750 + 751 + struct oxr_plane_detector_ext *out_pd = NULL; 752 + OXR_ALLOCATE_HANDLE_OR_RETURN(&log, out_pd, OXR_XR_DEBUG_PLANEDET, oxr_plane_detector_destroy_cb, 753 + &sess->handle); 754 + 755 + out_pd->sess = sess; 756 + if ((createInfo->flags & XR_PLANE_DETECTOR_ENABLE_CONTOUR_BIT_EXT) != 0) { 757 + out_pd->flags |= XRT_PLANE_DETECTOR_FLAGS_CONTOUR_EXT; 758 + } 759 + 760 + out_pd->xdev = xdev; 761 + 762 + // no plane detection started on creation 763 + out_pd->state = XR_PLANE_DETECTION_STATE_NONE_EXT; 764 + 765 + out_pd->detection_id = 0; 766 + 767 + out_pd->xr_locations = NULL; 768 + 769 + *planeDetector = oxr_plane_detector_to_openxr(out_pd); 770 + 771 + return XR_SUCCESS; 772 + } 773 + 774 + XRAPI_ATTR XrResult XRAPI_CALL 775 + oxr_xrDestroyPlaneDetectorEXT(XrPlaneDetectorEXT planeDetector) 776 + { 777 + struct oxr_logger log; 778 + struct oxr_plane_detector_ext *pd; 779 + 780 + OXR_VERIFY_PLANE_DETECTOR_AND_INIT_LOG(&log, planeDetector, pd, "xrDestroyPlaneDetectorEXT"); 781 + 782 + return oxr_handle_destroy(&log, &pd->handle); 783 + } 784 + 785 + XRAPI_ATTR XrResult XRAPI_CALL 786 + oxr_xrBeginPlaneDetectionEXT(XrPlaneDetectorEXT planeDetector, const XrPlaneDetectorBeginInfoEXT *beginInfo) 787 + { 788 + struct oxr_logger log; 789 + struct oxr_plane_detector_ext *pd; 790 + struct oxr_space *spc; 791 + 792 + OXR_VERIFY_PLANE_DETECTOR_AND_INIT_LOG(&log, planeDetector, pd, "xrBeginPlaneDetectionEXT"); 793 + OXR_VERIFY_SPACE_NOT_NULL(&log, beginInfo->baseSpace, spc); 794 + OXR_VERIFY_ARG_NOT_ZERO(&log, beginInfo->maxPlanes); 795 + OXR_VERIFY_POSE(&log, beginInfo->boundingBoxPose); 796 + if (beginInfo->time < 1) { 797 + return oxr_error(&log, XR_ERROR_TIME_INVALID, "Time %" PRId64 " invalid", beginInfo->time); 798 + } 799 + 800 + if (!pd->xdev->planes_supported) { 801 + return XR_ERROR_FEATURE_UNSUPPORTED; 802 + } 803 + 804 + if (beginInfo->orientationCount > 0) { 805 + OXR_VERIFY_ARG_NOT_NULL(&log, beginInfo->orientations); 806 + } 807 + 808 + 809 + // BoundingBox, pose is relative to baseSpace spc 810 + struct xrt_pose T_base_bb = { 811 + .orientation = 812 + { 813 + .x = beginInfo->boundingBoxPose.orientation.x, 814 + .y = beginInfo->boundingBoxPose.orientation.y, 815 + .z = beginInfo->boundingBoxPose.orientation.z, 816 + .w = beginInfo->boundingBoxPose.orientation.w, 817 + }, 818 + .position = 819 + { 820 + .x = beginInfo->boundingBoxPose.position.x, 821 + .y = beginInfo->boundingBoxPose.position.y, 822 + .z = beginInfo->boundingBoxPose.position.z, 823 + }, 824 + }; 825 + 826 + // Get plane tracker xdev relation in bounding box baseSpc too. The inverse of this relation is the transform 827 + // from baseSpace spc to xdev space and can transform bounding box pose into xdev space. 828 + struct xrt_space_relation T_base_xdev; // What we get, xdev in base space. 829 + XrResult ret = oxr_space_locate_device(&log, pd->xdev, spc, beginInfo->time, &T_base_xdev); 830 + if (ret != XR_SUCCESS) { 831 + return ret; 832 + } 833 + 834 + if (T_base_xdev.relation_flags == 0) { 835 + return XR_ERROR_SPACE_NOT_LOCATABLE_EXT; 836 + } 837 + 838 + struct xrt_space_relation T_xdev_bb; // This is what we want, BoundingBox in xdev space. 839 + struct xrt_relation_chain xrc = {0}; 840 + m_relation_chain_push_pose_if_not_identity(&xrc, &T_base_bb); // T_base_bb 841 + m_relation_chain_push_inverted_relation(&xrc, &T_base_xdev); // T_xdev_base 842 + m_relation_chain_resolve(&xrc, &T_xdev_bb); 843 + 844 + if (T_xdev_bb.relation_flags == 0) { 845 + return XR_ERROR_SPACE_NOT_LOCATABLE_EXT; 846 + } 847 + 848 + struct xrt_plane_detector_begin_info_ext query; 849 + // the plane detector id is the raw handle (in our implementation: pointer to xrt_plane_detector) 850 + query.detector_flags = pd->flags; 851 + 852 + //! @todo be more graceful 853 + if (beginInfo->orientationCount > XRT_MAX_PLANE_ORIENTATIONS_EXT) { 854 + return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, "Too many plane orientations"); 855 + } 856 + 857 + if (beginInfo->semanticTypeCount > XRT_MAX_PLANE_SEMANTIC_TYPE_EXT) { 858 + return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, "Too many plane semantic types"); 859 + } 860 + 861 + query.orientation_count = beginInfo->orientationCount; 862 + for (uint32_t i = 0; i < beginInfo->orientationCount; i++) { 863 + // 1:1 mapped 864 + query.orientations[i] = (enum xrt_plane_detector_orientation_ext)beginInfo->orientations[i]; 865 + } 866 + 867 + query.semantic_type_count = beginInfo->semanticTypeCount; 868 + for (uint32_t i = 0; i < beginInfo->semanticTypeCount; i++) { 869 + // 1:1 mapped 870 + query.semantic_types[i] = (enum xrt_plane_detector_semantic_type_ext)beginInfo->semanticTypes[i]; 871 + } 872 + 873 + query.max_planes = beginInfo->maxPlanes; 874 + query.min_area = beginInfo->minArea; 875 + 876 + // extents are invariant under pose transforms 877 + query.bounding_box_extent.x = beginInfo->boundingBoxExtent.width; 878 + query.bounding_box_extent.y = beginInfo->boundingBoxExtent.height; 879 + query.bounding_box_extent.z = beginInfo->boundingBoxExtent.depth; 880 + 881 + query.bounding_box_pose = T_xdev_bb.pose; 882 + 883 + 884 + enum xrt_result xret; 885 + 886 + // The xrt backend tracks plane detections to be able to clean up when the client dies. 887 + // Because it tracks them as standalone objects, it can not know that this plane detection is replacing a 888 + // previous one. Therefore we need to explicitly destroy the previous detection. 889 + if (pd->detection_id > 0) { 890 + xret = xrt_device_destroy_plane_detection_ext(pd->xdev, pd->detection_id); 891 + if (xret != XRT_SUCCESS) { 892 + return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, 893 + "Internal error in xrBeginPlaneDetectionEXT: Failed to destroy previous plane " 894 + "detection: %d", 895 + xret); 896 + } 897 + } 898 + 899 + xret = xrt_device_begin_plane_detection_ext(pd->xdev, &query, pd->detection_id, &pd->detection_id); 900 + if (xret != XRT_SUCCESS) { 901 + return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, "Internal error in xrBeginPlaneDetectionEXT: %d", 902 + xret); 903 + } 904 + 905 + xrt_plane_detections_ext_clear(&pd->detections); 906 + 907 + // This makes sure a call to xrGetPlaneDetectionsEXT won't see a previous state, in particular a previous DONE. 908 + pd->state = XR_PLANE_DETECTION_STATE_PENDING_EXT; 909 + 910 + return XR_SUCCESS; 911 + } 912 + 913 + XRAPI_ATTR XrResult XRAPI_CALL 914 + oxr_xrGetPlaneDetectionStateEXT(XrPlaneDetectorEXT planeDetector, XrPlaneDetectionStateEXT *state) 915 + { 916 + struct oxr_logger log; 917 + struct oxr_plane_detector_ext *pd; 918 + enum xrt_result xret; 919 + 920 + OXR_VERIFY_PLANE_DETECTOR_AND_INIT_LOG(&log, planeDetector, pd, "xrGetPlaneDetectionsEXT"); 921 + 922 + enum xrt_plane_detector_state_ext xstate = 0; 923 + 924 + xret = xrt_device_get_plane_detection_state_ext(pd->xdev, pd->detection_id, &xstate); 925 + if (xret != XRT_SUCCESS) { 926 + return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, "Internal error in xrGetPlaneDetectionStateEXT: %d", 927 + xret); 928 + } 929 + 930 + *state = (XrPlaneDetectionStateEXT)xstate; // 1:1 mapped 931 + 932 + pd->state = *state; 933 + 934 + return XR_SUCCESS; 935 + } 936 + 937 + XRAPI_ATTR XrResult XRAPI_CALL 938 + oxr_xrGetPlaneDetectionsEXT(XrPlaneDetectorEXT planeDetector, 939 + const XrPlaneDetectorGetInfoEXT *info, 940 + XrPlaneDetectorLocationsEXT *locations) 941 + { 942 + struct oxr_logger log; 943 + struct oxr_plane_detector_ext *pd; 944 + struct oxr_space *spc; 945 + enum xrt_result xret; 946 + 947 + OXR_VERIFY_PLANE_DETECTOR_AND_INIT_LOG(&log, planeDetector, pd, "xrGetPlaneDetectionsEXT"); 948 + OXR_VERIFY_SPACE_NOT_NULL(&log, info->baseSpace, spc); 949 + if (info->time < 1) { 950 + return oxr_error(&log, XR_ERROR_TIME_INVALID, "Time %" PRId64 " invalid", info->time); 951 + } 952 + 953 + if (!pd->xdev->planes_supported) { 954 + return XR_ERROR_FEATURE_UNSUPPORTED; 955 + } 956 + 957 + if (pd->state != XR_PLANE_DETECTION_STATE_DONE_EXT) { 958 + locations->planeLocationCountOutput = 0; 959 + return XR_ERROR_CALL_ORDER_INVALID; 960 + } 961 + 962 + xret = xrt_device_get_plane_detections_ext(pd->xdev, pd->detection_id, &pd->detections); 963 + if (xret != XRT_SUCCESS) { 964 + return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, "Internal error in xrGetPlaneDetectionsEXT: %d", xret); 965 + } 966 + 967 + struct xrt_space_relation T_base_xdev; // What we get, xdev in base space. 968 + XrResult ret = oxr_space_locate_device(&log, pd->xdev, spc, info->time, &T_base_xdev); 969 + if (ret != XR_SUCCESS) { 970 + return ret; 971 + } 972 + 973 + if (T_base_xdev.relation_flags == 0) { 974 + return XR_ERROR_SPACE_NOT_LOCATABLE_EXT; 975 + } 976 + 977 + // create dynamic array for two call idiom 978 + U_ARRAY_REALLOC_OR_FREE(pd->xr_locations, XrPlaneDetectorLocationEXT, pd->detections.location_count); 979 + if (pd->detections.location_count == 0) { 980 + pd->xr_locations = NULL; 981 + } 982 + 983 + // populate pd->xr_locations from pd->detections.locations, also transform plane poses into baseSpace. 984 + for (uint32_t i = 0; i < pd->detections.location_count; i++) { 985 + pd->xr_locations[i].planeId = pd->detections.locations[i].planeId; 986 + pd->xr_locations[i].extents.width = pd->detections.locations[i].extents.x; 987 + pd->xr_locations[i].extents.height = pd->detections.locations[i].extents.y; 988 + // 1:1 mapped 989 + pd->xr_locations[i].orientation = 990 + (XrPlaneDetectorOrientationEXT)pd->detections.locations[i].orientation; 991 + pd->xr_locations[i].semanticType = 992 + (XrPlaneDetectorSemanticTypeEXT)pd->detections.locations[i].semantic_type; 993 + pd->xr_locations[i].polygonBufferCount = pd->detections.locations[i].polygon_buffer_count; 994 + 995 + 996 + // The plane poses are returned in the xdev's space. 997 + struct xrt_space_relation T_xdev_plane = pd->detections.locations[i].relation; 998 + 999 + // Get the plane pose in the base space. 1000 + struct xrt_space_relation T_base_plane; 1001 + struct xrt_relation_chain xrc = {0}; 1002 + m_relation_chain_push_relation(&xrc, &T_xdev_plane); 1003 + m_relation_chain_push_relation(&xrc, &T_base_xdev); 1004 + m_relation_chain_resolve(&xrc, &T_base_plane); 1005 + 1006 + OXR_XRT_POSE_TO_XRPOSEF(T_base_plane.pose, pd->xr_locations[i].pose); 1007 + 1008 + pd->xr_locations[i].locationFlags = 0; 1009 + if ((T_base_plane.relation_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) != 0) { 1010 + pd->xr_locations[i].locationFlags |= XR_SPACE_LOCATION_ORIENTATION_VALID_BIT; 1011 + } 1012 + if ((T_base_plane.relation_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) != 0) { 1013 + pd->xr_locations[i].locationFlags |= XR_SPACE_LOCATION_POSITION_VALID_BIT; 1014 + } 1015 + if ((T_base_plane.relation_flags & XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT) != 0) { 1016 + pd->xr_locations[i].locationFlags |= XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT; 1017 + } 1018 + if ((T_base_plane.relation_flags & XRT_SPACE_RELATION_POSITION_TRACKED_BIT) != 0) { 1019 + pd->xr_locations[i].locationFlags |= XR_SPACE_LOCATION_POSITION_TRACKED_BIT; 1020 + } 1021 + } 1022 + 1023 + 1024 + OXR_TWO_CALL_HELPER(&log, locations->planeLocationCapacityInput, &locations->planeLocationCountOutput, 1025 + locations->planeLocations, pd->detections.location_count, pd->xr_locations, XR_SUCCESS); 1026 + 1027 + return XR_SUCCESS; 1028 + } 1029 + 1030 + XRAPI_ATTR XrResult XRAPI_CALL 1031 + oxr_xrGetPlanePolygonBufferEXT(XrPlaneDetectorEXT planeDetector, 1032 + uint64_t planeId, 1033 + uint32_t polygonBufferIndex, 1034 + XrPlaneDetectorPolygonBufferEXT *polygonBuffer) 1035 + { 1036 + struct oxr_logger log; 1037 + struct oxr_plane_detector_ext *pd; 1038 + OXR_VERIFY_PLANE_DETECTOR_AND_INIT_LOG(&log, planeDetector, pd, "xrGetPlaneDetectionsEXT"); 1039 + 1040 + //! @todo can't reasonably retrieve a polygon without having retrieved plane data first. 1041 + if (pd->state != XR_PLANE_DETECTION_STATE_DONE_EXT) { 1042 + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, 1043 + "xrGetPlanePolygonBufferEXT called but plane detector state is %d", pd->state); 1044 + } 1045 + 1046 + // find the index of the plane in both pd->locations and pd->polygons_ptr arrays. 1047 + uint32_t plane_index = UINT32_MAX; 1048 + for (uint32_t i = 0; i < pd->detections.location_count; i++) { 1049 + if (pd->detections.locations[i].planeId == planeId) { 1050 + plane_index = i; 1051 + break; 1052 + } 1053 + } 1054 + 1055 + if (plane_index == UINT32_MAX) { 1056 + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "Invalid plane id %" PRId64, planeId); 1057 + } 1058 + 1059 + if (polygonBufferIndex + 1 > pd->detections.locations[plane_index].polygon_buffer_count) { 1060 + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "Invalid polygon buffer index %u (> %u)", 1061 + polygonBufferIndex, pd->detections.locations[plane_index].polygon_buffer_count - 1); 1062 + } 1063 + 1064 + uint32_t polygons_start_index = pd->detections.polygon_info_start_index[plane_index]; 1065 + uint32_t polygon_index = polygons_start_index + polygonBufferIndex; 1066 + 1067 + uint32_t vertices_start_index = pd->detections.polygon_infos[polygon_index].vertices_start_index; 1068 + // xrt_vec2 should mapped 1:1 to XrVector2f 1069 + XrVector2f *polygon_vertices = (XrVector2f *)&pd->detections.vertices[vertices_start_index]; 1070 + 1071 + uint32_t vertex_count = pd->detections.polygon_infos[polygon_index].vertex_count; 1072 + 1073 + OXR_TWO_CALL_HELPER(&log, polygonBuffer->vertexCapacityInput, &polygonBuffer->vertexCountOutput, 1074 + polygonBuffer->vertices, vertex_count, polygon_vertices, XR_SUCCESS); 1075 + } 1076 + 1077 + #endif // OXR_HAVE_EXT_plane_detection
+2
src/xrt/state_trackers/oxr/oxr_api_verify.h
··· 90 90 OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_body_tracker_fb, BTRACKER, name, new_thing->sess->sys->inst) 91 91 #define OXR_VERIFY_XDEVLIST_AND_INIT_LOG(log, thing, new_thing, name) \ 92 92 OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_xdev_list, XDEVLIST, name, new_thing->sess->sys->inst) 93 + #define OXR_VERIFY_PLANE_DETECTOR_AND_INIT_LOG(log, thing, new_thing, name) \ 94 + OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_plane_detector_ext, PLANEDET, name, new_thing->sess->sys->inst) 93 95 // clang-format on 94 96 95 97 #define OXR_VERIFY_INSTANCE_NOT_NULL(log, arg, new_arg) OXR_VERIFY_SET(log, arg, new_arg, oxr_instance, INSTANCE);
+2
src/xrt/state_trackers/oxr/oxr_defines.h
··· 32 32 // body tracker 33 33 #define OXR_XR_DEBUG_BTRACKER (*(uint64_t *)"oxrbtra\0") 34 34 #define OXR_XR_DEBUG_XDEVLIST (*(uint64_t *)"oxrxdli\0") 35 + // plane detection 36 + #define OXR_XR_DEBUG_PLANEDET (*(uint64_t *)"oxrplan\0") 35 37 // clang-format on 36 38 37 39 /*!
+12
src/xrt/state_trackers/oxr/oxr_extension_support.h
··· 578 578 579 579 580 580 /* 581 + * XR_EXT_plane_detection 582 + */ 583 + #if defined(XR_EXT_plane_detection) && defined(XRT_FEATURE_OPENXR_PLANE_DETECTION) 584 + #define OXR_HAVE_EXT_plane_detection 585 + #define OXR_EXTENSION_SUPPORT_EXT_plane_detection(_) _(EXT_plane_detection, EXT_PLANE_DETECTION) 586 + #else 587 + #define OXR_EXTENSION_SUPPORT_EXT_plane_detection(_) 588 + #endif 589 + 590 + 591 + /* 581 592 * XR_MND_headless 582 593 */ 583 594 #if defined(XR_MND_headless) && defined(XRT_FEATURE_OPENXR_HEADLESS) ··· 820 831 OXR_EXTENSION_SUPPORT_HTC_facial_tracking(_) \ 821 832 OXR_EXTENSION_SUPPORT_META_touch_controller_plus(_) \ 822 833 OXR_EXTENSION_SUPPORT_ML_ml2_controller_interaction(_) \ 834 + OXR_EXTENSION_SUPPORT_EXT_plane_detection(_) \ 823 835 OXR_EXTENSION_SUPPORT_MND_headless(_) \ 824 836 OXR_EXTENSION_SUPPORT_MND_swapchain_usage_input_attachment_bit(_) \ 825 837 OXR_EXTENSION_SUPPORT_MSFT_hand_interaction(_) \
+56
src/xrt/state_trackers/oxr/oxr_objects.h
··· 130 130 struct oxr_face_tracker2_fb; 131 131 struct oxr_body_tracker_fb; 132 132 struct oxr_xdev_list; 133 + struct oxr_plane_detector_ext; 133 134 134 135 #define XRT_MAX_HANDLE_CHILDREN 256 135 136 #define OXR_MAX_BINDINGS_PER_ACTION 32 ··· 380 381 { 381 382 return XRT_CAST_PTR_TO_OXR_HANDLE(XrHandTrackerEXT, hand_tracker); 382 383 } 384 + 385 + #ifdef OXR_HAVE_EXT_plane_detection 386 + /*! 387 + * To go back to a OpenXR object. 388 + * 389 + * @relates oxr_plane_detector 390 + */ 391 + static inline XrPlaneDetectorEXT 392 + oxr_plane_detector_to_openxr(struct oxr_plane_detector_ext *plane_detector) 393 + { 394 + return XRT_CAST_PTR_TO_OXR_HANDLE(XrPlaneDetectorEXT, plane_detector); 395 + } 396 + #endif // OXR_HAVE_EXT_plane_detection 383 397 384 398 /*! 385 399 * To go back to a OpenXR object. ··· 2838 2852 uint32_t device_count; 2839 2853 }; 2840 2854 #endif // OXR_HAVE_MNDX_xdev_space 2855 + 2856 + #ifdef OXR_HAVE_EXT_plane_detection 2857 + /*! 2858 + * A Plane Detector. 2859 + * 2860 + * Parent type/handle is @ref oxr_session 2861 + * 2862 + * 2863 + * @obj{XrPlaneDetectorEXT} 2864 + * @extends oxr_handle_base 2865 + */ 2866 + struct oxr_plane_detector_ext 2867 + { 2868 + //! Common structure for things referred to by OpenXR handles. 2869 + struct oxr_handle_base handle; 2870 + 2871 + //! Owner of this anchor. 2872 + struct oxr_session *sess; 2873 + 2874 + //! Plane detector flags. 2875 + enum xrt_plane_detector_flags_ext flags; 2876 + 2877 + //! The last known state of this plane detector. 2878 + XrPlaneDetectionStateEXT state; 2879 + 2880 + //! Whether the last DONE plane detection has been retrieved from the xdev. 2881 + bool retrieved; 2882 + 2883 + //! The device that this plane detector belongs to. 2884 + struct xrt_device *xdev; 2885 + 2886 + //! Detected planes. xrt_plane_detector_locations_ext::relation is kept in xdev space and not updated. 2887 + struct xrt_plane_detections_ext detections; 2888 + 2889 + //! Corresponds to xrt_plane_detections_ext::locations, but with OpenXR types and transformed into target space. 2890 + //! Enables two call idiom. 2891 + XrPlaneDetectorLocationEXT *xr_locations; 2892 + 2893 + //! A globally unique id for the current plane detection or 0, generated by the xrt_device. 2894 + uint64_t detection_id; 2895 + }; 2896 + #endif // OXR_HAVE_EXT_plane_detection 2841 2897 2842 2898 /*! 2843 2899 * @}
+14
src/xrt/state_trackers/oxr/oxr_system.c
··· 508 508 } 509 509 #endif // OXR_HAVE_MNDX_xdev_space 510 510 511 + #ifdef OXR_HAVE_EXT_plane_detection 512 + XrSystemPlaneDetectionPropertiesEXT *plane_detection_props = NULL; 513 + if (sys->inst->extensions.EXT_plane_detection) { 514 + plane_detection_props = OXR_GET_OUTPUT_FROM_CHAIN( 515 + properties, XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT, XrSystemPlaneDetectionPropertiesEXT); 516 + } 517 + 518 + if (plane_detection_props) { 519 + // for now these are mapped 1:1 520 + plane_detection_props->supportedFeatures = 521 + (XrPlaneDetectionCapabilityFlagsEXT)xdev->plane_capability_flags; 522 + } 523 + #endif // OXR_HAVE_EXT_plane_detection 524 + 511 525 return XR_SUCCESS; 512 526 } 513 527