Files
Jakob Bornecrantz 090f9688ae xrt: Change is_form_factor_supported to return xrt_result
Make all functions on xrt_device return a xft_result_t
so that ttings like IPC errors can be surfaced.

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2792>
2026-03-20 09:20:24 +00:00

1168 lines
32 KiB
C++

// Copyright 2025-2026, NVIDIA CORPORATION.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Tests for glue/g_device.hpp
* @author Jakob Bornecrantz <tbornecrantz@nvidia.com>
*/
#include "glue/g_device.hpp"
#include "util/u_device.h"
#include "util/u_device_ni.h"
#include "catch_amalgamated.hpp"
#include <cstring>
//! Test device with minimal functions
constexpr xrt::util::DeviceFunctions kMinimalFunctions = {};
//! Test device with hand tracking enabled
constexpr xrt::util::DeviceFunctions kHandTrackingFunctions = {
.hand_tracking = true,
};
//! Test device with HMD functions enabled
constexpr xrt::util::DeviceFunctions kHmdFunctions = {
.hmd = true,
};
//! Test device with body tracking enabled
constexpr xrt::util::DeviceFunctions kBodyTrackingFunctions = {
.body_tracking = true,
};
//! Test device with battery enabled
constexpr xrt::util::DeviceFunctions kBatteryFunctions = {
.battery = true,
};
//! Test device with brightness enabled
constexpr xrt::util::DeviceFunctions kBrightnessFunctions = {
.brightness = true,
};
//! Test device with all features enabled
constexpr xrt::util::DeviceFunctions kAllFunctions = {
.hmd = true,
.distortion = true,
.visibility_mask = true,
.update_inputs = true,
.output = true,
.output_limits = true,
.hand_tracking = true,
.face_tracking = true,
.face_calibration_android = true,
.body_tracking = true,
.plane_detection = true,
.presence = true,
.reference_space = true,
.battery = true,
.brightness = true,
.compositor_info = true,
.features = true,
};
/*!
* Minimal test device
*/
class MinimalTestDevice : public xrt::util::DeviceBase<MinimalTestDevice, kMinimalFunctions>
{
public:
bool destroyed = false;
MinimalTestDevice() : DeviceBase() {}
xrt_result_t
getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation)
{
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
return XRT_SUCCESS;
}
static void
destroyDevice(struct xrt_device *xdev)
{
auto *dev = MinimalTestDevice::fromXDev(xdev);
dev->destroyed = true;
}
};
/*!
* Hand tracking test device
*/
class HandTrackingTestDevice : public xrt::util::DeviceBase<HandTrackingTestDevice, kHandTrackingFunctions>
{
public:
bool destroyed = false;
int hand_tracking_call_count = 0;
HandTrackingTestDevice() : DeviceBase() {}
xrt_result_t
getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation)
{
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
return XRT_SUCCESS;
}
xrt_result_t
getHandTracking(enum xrt_input_name name,
int64_t desired_timestamp_ns,
struct xrt_hand_joint_set *out_value,
int64_t *out_timestamp_ns)
{
hand_tracking_call_count++;
return XRT_SUCCESS;
}
static void
destroyDevice(struct xrt_device *xdev)
{
auto *dev = HandTrackingTestDevice::fromXDev(xdev);
dev->destroyed = true;
}
};
/*!
* HMD test device
*/
class HmdTestDevice : public xrt::util::DeviceBase<HmdTestDevice, kHmdFunctions>
{
public:
bool destroyed = false;
int get_view_poses_call_count = 0;
int form_factor_call_count = 0;
HmdTestDevice() : DeviceBase() {}
xrt_result_t
getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation)
{
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
return XRT_SUCCESS;
}
xrt_result_t
getViewPoses(const struct xrt_vec3 *default_eye_relation,
int64_t at_timestamp_ns,
enum xrt_view_type view_type,
uint32_t view_count,
struct xrt_space_relation *out_head_relation,
struct xrt_fov *out_fovs,
struct xrt_pose *out_poses)
{
get_view_poses_call_count++;
return XRT_SUCCESS;
}
xrt_result_t
isFormFactorAvailable(enum xrt_form_factor form_factor, bool *out_available)
{
form_factor_call_count++;
*out_available = false;
return XRT_SUCCESS;
}
static void
destroyDevice(struct xrt_device *xdev)
{
auto *dev = HmdTestDevice::fromXDev(xdev);
dev->destroyed = true;
}
};
/*!
* Body tracking test device
*/
class BodyTrackingTestDevice : public xrt::util::DeviceBase<BodyTrackingTestDevice, kBodyTrackingFunctions>
{
public:
bool destroyed = false;
int get_body_skeleton_call_count = 0;
int get_body_joints_call_count = 0;
int reset_calibration_call_count = 0;
int set_calibration_call_count = 0;
BodyTrackingTestDevice() : DeviceBase() {}
xrt_result_t
getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation)
{
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
return XRT_SUCCESS;
}
xrt_result_t
getBodySkeleton(enum xrt_input_name body_tracking_type, struct xrt_body_skeleton *out_value)
{
get_body_skeleton_call_count++;
return XRT_SUCCESS;
}
xrt_result_t
getBodyJoints(enum xrt_input_name body_tracking_type,
int64_t desired_timestamp_ns,
struct xrt_body_joint_set *out_value)
{
get_body_joints_call_count++;
return XRT_SUCCESS;
}
xrt_result_t
resetBodyTrackingCalibrationMeta()
{
reset_calibration_call_count++;
return XRT_SUCCESS;
}
xrt_result_t
setBodyTrackingCalibrationOverrideMeta(float new_body_height)
{
set_calibration_call_count++;
return XRT_SUCCESS;
}
static void
destroyDevice(struct xrt_device *xdev)
{
auto *dev = BodyTrackingTestDevice::fromXDev(xdev);
dev->destroyed = true;
}
};
/*!
* Battery test device
*/
class BatteryTestDevice : public xrt::util::DeviceBase<BatteryTestDevice, kBatteryFunctions>
{
public:
bool destroyed = false;
int get_battery_call_count = 0;
BatteryTestDevice() : DeviceBase() {}
xrt_result_t
getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation)
{
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
return XRT_SUCCESS;
}
xrt_result_t
getBatteryStatus(bool *out_present, bool *out_charging, float *out_charge)
{
get_battery_call_count++;
*out_present = true;
*out_charging = false;
*out_charge = 0.75f;
return XRT_SUCCESS;
}
static void
destroyDevice(struct xrt_device *xdev)
{
auto *dev = BatteryTestDevice::fromXDev(xdev);
dev->destroyed = true;
}
};
/*!
* Brightness test device
*/
class BrightnessTestDevice : public xrt::util::DeviceBase<BrightnessTestDevice, kBrightnessFunctions>
{
public:
bool destroyed = false;
int get_brightness_call_count = 0;
int set_brightness_call_count = 0;
BrightnessTestDevice() : DeviceBase() {}
xrt_result_t
getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation)
{
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
return XRT_SUCCESS;
}
xrt_result_t
getBrightness(float *out_brightness)
{
get_brightness_call_count++;
*out_brightness = 0.5f;
return XRT_SUCCESS;
}
xrt_result_t
setBrightness(float brightness, bool relative)
{
set_brightness_call_count++;
return XRT_SUCCESS;
}
static void
destroyDevice(struct xrt_device *xdev)
{
auto *dev = BrightnessTestDevice::fromXDev(xdev);
dev->destroyed = true;
}
};
TEST_CASE("DeviceBase_MinimalDevice")
{
MinimalTestDevice dev;
auto *xdev = dev.getXDev();
SECTION("Basic properties")
{
REQUIRE(xdev != nullptr);
REQUIRE_FALSE(dev.destroyed);
}
SECTION("Function pointers are set")
{
REQUIRE(xdev->get_tracked_pose != nullptr);
REQUIRE(xdev->destroy != nullptr);
}
SECTION("Stub functions are set for disabled features")
{
REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses);
REQUIRE(xdev->is_form_factor_available == u_device_ni_is_form_factor_available);
REQUIRE(xdev->compute_distortion == u_device_ni_compute_distortion);
// @todo Fix when u_device function is fixed.
// REQUIRE(xdev->get_visibility_mask == u_device_ni_get_visibility_mask);
REQUIRE(xdev->update_inputs == u_device_noop_update_inputs);
REQUIRE(xdev->set_output == u_device_ni_set_output);
REQUIRE(xdev->get_output_limits == u_device_ni_get_output_limits);
REQUIRE(xdev->ref_space_usage == u_device_ni_ref_space_usage);
REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking);
REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking);
REQUIRE(xdev->get_body_skeleton == u_device_ni_get_body_skeleton);
REQUIRE(xdev->get_body_joints == u_device_ni_get_body_joints);
REQUIRE(xdev->reset_body_tracking_calibration_meta == u_device_ni_reset_body_tracking_calibration_meta);
REQUIRE(xdev->set_body_tracking_calibration_override_meta ==
u_device_ni_set_body_tracking_calibration_override_meta);
REQUIRE(xdev->get_presence == u_device_ni_get_presence);
REQUIRE(xdev->begin_plane_detection_ext == u_device_ni_begin_plane_detection_ext);
REQUIRE(xdev->destroy_plane_detection_ext == u_device_ni_destroy_plane_detection_ext);
REQUIRE(xdev->get_plane_detection_state_ext == u_device_ni_get_plane_detection_state_ext);
REQUIRE(xdev->get_plane_detections_ext == u_device_ni_get_plane_detections_ext);
REQUIRE(xdev->get_battery_status == u_device_ni_get_battery_status);
REQUIRE(xdev->get_brightness == u_device_ni_get_brightness);
REQUIRE(xdev->set_brightness == u_device_ni_set_brightness);
REQUIRE(xdev->begin_feature == u_device_ni_begin_feature);
REQUIRE(xdev->end_feature == u_device_ni_end_feature);
}
SECTION("fromXDev conversion works")
{
auto *retrieved = MinimalTestDevice::fromXDev(xdev);
REQUIRE(retrieved == &dev);
}
SECTION("getTrackedPose can be called")
{
xrt_space_relation relation;
memset(&relation, 0, sizeof(relation));
xrt_result_t result = xdev->get_tracked_pose(xdev, XRT_INPUT_GENERIC_HEAD_POSE, 0, &relation);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(relation.relation_flags == XRT_SPACE_RELATION_BITMASK_NONE);
}
SECTION("destroy calls destroyDevice")
{
REQUIRE_FALSE(dev.destroyed);
xdev->destroy(xdev);
REQUIRE(dev.destroyed);
}
}
TEST_CASE("DeviceBase_HandTrackingDevice")
{
HandTrackingTestDevice dev;
auto *xdev = dev.getXDev();
SECTION("Hand tracking function is set")
{
REQUIRE(xdev->get_hand_tracking != nullptr);
REQUIRE(xdev->get_hand_tracking != u_device_ni_get_hand_tracking);
}
SECTION("Other disabled features still use stubs")
{
REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses);
REQUIRE(xdev->is_form_factor_available == u_device_ni_is_form_factor_available);
REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking);
}
SECTION("Hand tracking can be called")
{
xrt_hand_joint_set joint_set;
int64_t timestamp;
REQUIRE(dev.hand_tracking_call_count == 0);
xrt_result_t result =
xdev->get_hand_tracking(xdev, XRT_INPUT_HT_UNOBSTRUCTED_LEFT, 0, &joint_set, &timestamp);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(dev.hand_tracking_call_count == 1);
}
SECTION("fromXDev conversion works")
{
auto *retrieved = HandTrackingTestDevice::fromXDev(xdev);
REQUIRE(retrieved == &dev);
}
}
TEST_CASE("DeviceBase_HmdDevice")
{
HmdTestDevice dev;
auto *xdev = dev.getXDev();
SECTION("HMD functions are set")
{
REQUIRE(xdev->get_view_poses != nullptr);
REQUIRE(xdev->get_view_poses != u_device_ni_get_view_poses);
REQUIRE(xdev->is_form_factor_available != nullptr);
REQUIRE(xdev->is_form_factor_available != u_device_ni_is_form_factor_available);
}
SECTION("Other disabled features still use stubs")
{
REQUIRE(xdev->compute_distortion == u_device_ni_compute_distortion);
REQUIRE(xdev->ref_space_usage == u_device_ni_ref_space_usage);
REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking);
REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking);
REQUIRE(xdev->get_body_skeleton == u_device_ni_get_body_skeleton);
REQUIRE(xdev->get_body_joints == u_device_ni_get_body_joints);
REQUIRE(xdev->get_presence == u_device_ni_get_presence);
REQUIRE(xdev->get_battery_status == u_device_ni_get_battery_status);
REQUIRE(xdev->get_output_limits == u_device_ni_get_output_limits);
}
SECTION("get_view_poses can be called")
{
xrt_vec3 default_eye_relation = {0.0f, 0.0f, 0.0f};
xrt_space_relation head_relation;
xrt_fov fovs[2];
xrt_pose poses[2];
REQUIRE(dev.get_view_poses_call_count == 0);
xrt_result_t result = xdev->get_view_poses(xdev, &default_eye_relation, 0, XRT_VIEW_TYPE_STEREO, 2,
&head_relation, fovs, poses);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(dev.get_view_poses_call_count == 1);
}
SECTION("is_form_factor_available can be called")
{
REQUIRE(dev.form_factor_call_count == 0);
bool available = false;
xrt_result_t result = xdev->is_form_factor_available(xdev, XRT_FORM_FACTOR_HMD, &available);
REQUIRE(result == XRT_SUCCESS);
REQUIRE_FALSE(available);
REQUIRE(dev.form_factor_call_count == 1);
}
SECTION("fromXDev conversion works")
{
auto *retrieved = HmdTestDevice::fromXDev(xdev);
REQUIRE(retrieved == &dev);
}
}
TEST_CASE("DeviceBase_MultipleInstances")
{
MinimalTestDevice dev1;
MinimalTestDevice dev2;
SECTION("Each device has its own xrt_device")
{
REQUIRE(dev1.getXDev() != dev2.getXDev());
}
SECTION("fromXDev returns correct instance")
{
auto *retrieved1 = MinimalTestDevice::fromXDev(dev1.getXDev());
auto *retrieved2 = MinimalTestDevice::fromXDev(dev2.getXDev());
REQUIRE(retrieved1 == &dev1);
REQUIRE(retrieved2 == &dev2);
REQUIRE(retrieved1 != retrieved2);
}
SECTION("Destroying one doesn't affect the other")
{
dev1.getXDev()->destroy(dev1.getXDev());
REQUIRE(dev1.destroyed);
REQUIRE_FALSE(dev2.destroyed);
}
}
TEST_CASE("DeviceBase_BodyTrackingDevice")
{
BodyTrackingTestDevice dev;
auto *xdev = dev.getXDev();
SECTION("Body tracking functions are set")
{
REQUIRE(xdev->get_body_skeleton != nullptr);
REQUIRE(xdev->get_body_joints != nullptr);
REQUIRE(xdev->reset_body_tracking_calibration_meta != nullptr);
REQUIRE(xdev->set_body_tracking_calibration_override_meta != nullptr);
}
SECTION("Other disabled features still use stubs")
{
REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses);
REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking);
REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking);
REQUIRE(xdev->get_presence == u_device_ni_get_presence);
REQUIRE(xdev->get_battery_status == u_device_ni_get_battery_status);
}
SECTION("get_body_skeleton can be called")
{
xrt_body_skeleton skeleton;
REQUIRE(dev.get_body_skeleton_call_count == 0);
xrt_result_t result = xdev->get_body_skeleton(xdev, XRT_INPUT_GENERIC_BODY_TRACKING, &skeleton);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(dev.get_body_skeleton_call_count == 1);
}
SECTION("get_body_joints can be called")
{
xrt_body_joint_set joint_set;
REQUIRE(dev.get_body_joints_call_count == 0);
xrt_result_t result = xdev->get_body_joints(xdev, XRT_INPUT_GENERIC_BODY_TRACKING, 0, &joint_set);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(dev.get_body_joints_call_count == 1);
}
SECTION("reset_body_tracking_calibration_meta can be called")
{
REQUIRE(dev.reset_calibration_call_count == 0);
xrt_result_t result = xdev->reset_body_tracking_calibration_meta(xdev);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(dev.reset_calibration_call_count == 1);
}
SECTION("set_body_tracking_calibration_override_meta can be called")
{
REQUIRE(dev.set_calibration_call_count == 0);
xrt_result_t result = xdev->set_body_tracking_calibration_override_meta(xdev, 1.75f);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(dev.set_calibration_call_count == 1);
}
SECTION("fromXDev conversion works")
{
auto *retrieved = BodyTrackingTestDevice::fromXDev(xdev);
REQUIRE(retrieved == &dev);
}
}
TEST_CASE("DeviceBase_BatteryDevice")
{
BatteryTestDevice dev;
auto *xdev = dev.getXDev();
SECTION("Battery function is set")
{
REQUIRE(xdev->get_battery_status != nullptr);
}
SECTION("Other disabled features still use stubs")
{
REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses);
REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking);
REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking);
REQUIRE(xdev->get_body_skeleton == u_device_ni_get_body_skeleton);
REQUIRE(xdev->get_presence == u_device_ni_get_presence);
REQUIRE(xdev->get_brightness == u_device_ni_get_brightness);
REQUIRE(xdev->set_brightness == u_device_ni_set_brightness);
}
SECTION("get_battery_status can be called")
{
bool present = false;
bool charging = false;
float charge = 0.0f;
REQUIRE(dev.get_battery_call_count == 0);
xrt_result_t result = xdev->get_battery_status(xdev, &present, &charging, &charge);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(present == true);
REQUIRE(charging == false);
REQUIRE(charge == 0.75f);
REQUIRE(dev.get_battery_call_count == 1);
}
SECTION("fromXDev conversion works")
{
auto *retrieved = BatteryTestDevice::fromXDev(xdev);
REQUIRE(retrieved == &dev);
}
}
TEST_CASE("DeviceBase_BrightnessDevice")
{
BrightnessTestDevice dev;
auto *xdev = dev.getXDev();
SECTION("Brightness functions are set")
{
REQUIRE(xdev->get_brightness != nullptr);
REQUIRE(xdev->set_brightness != nullptr);
}
SECTION("Other disabled features still use stubs")
{
REQUIRE(xdev->get_view_poses == u_device_ni_get_view_poses);
REQUIRE(xdev->get_hand_tracking == u_device_ni_get_hand_tracking);
REQUIRE(xdev->get_face_tracking == u_device_ni_get_face_tracking);
REQUIRE(xdev->get_body_skeleton == u_device_ni_get_body_skeleton);
REQUIRE(xdev->get_presence == u_device_ni_get_presence);
REQUIRE(xdev->get_battery_status == u_device_ni_get_battery_status);
}
SECTION("get_brightness can be called")
{
float brightness = 0.0f;
REQUIRE(dev.get_brightness_call_count == 0);
xrt_result_t result = xdev->get_brightness(xdev, &brightness);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(brightness == 0.5f);
REQUIRE(dev.get_brightness_call_count == 1);
}
SECTION("set_brightness can be called")
{
REQUIRE(dev.set_brightness_call_count == 0);
xrt_result_t result = xdev->set_brightness(xdev, 0.8f, false);
REQUIRE(result == XRT_SUCCESS);
REQUIRE(dev.set_brightness_call_count == 1);
}
SECTION("fromXDev conversion works")
{
auto *retrieved = BrightnessTestDevice::fromXDev(xdev);
REQUIRE(retrieved == &dev);
}
}
/*!
* Comprehensive test device with all features enabled
*/
class AllFeaturesTestDevice : public xrt::util::DeviceBase<AllFeaturesTestDevice, kAllFunctions>
{
public:
bool destroyed = false;
int update_inputs_count = 0;
int tracked_pose_count = 0;
int hand_tracking_count = 0;
int face_tracking_count = 0;
int face_calibration_android_count = 0;
int body_skeleton_count = 0;
int body_joints_count = 0;
int reset_body_calibration_count = 0;
int set_body_calibration_count = 0;
int set_output_count = 0;
int get_output_limits_count = 0;
int presence_count = 0;
int begin_plane_detection_count = 0;
int destroy_plane_detection_count = 0;
int get_plane_detection_state_count = 0;
int get_plane_detections_count = 0;
int get_view_poses_count = 0;
int compute_distortion_count = 0;
int get_visibility_mask_count = 0;
int ref_space_usage_count = 0;
int is_form_factor_available_count = 0;
int get_battery_status_count = 0;
int get_brightness_count = 0;
int set_brightness_count = 0;
int get_compositor_info_count = 0;
int begin_feature_count = 0;
int end_feature_count = 0;
AllFeaturesTestDevice() : DeviceBase() {}
xrt_result_t
updateInputs()
{
update_inputs_count++;
return XRT_SUCCESS;
}
xrt_result_t
getTrackedPose(enum xrt_input_name name, int64_t at_timestamp_ns, struct xrt_space_relation *out_relation)
{
tracked_pose_count++;
out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
return XRT_SUCCESS;
}
xrt_result_t
getHandTracking(enum xrt_input_name name,
int64_t desired_timestamp_ns,
struct xrt_hand_joint_set *out_value,
int64_t *out_timestamp_ns)
{
hand_tracking_count++;
return XRT_SUCCESS;
}
xrt_result_t
getFaceTracking(enum xrt_input_name facial_expression_type,
int64_t at_timestamp_ns,
struct xrt_facial_expression_set *out_value)
{
face_tracking_count++;
return XRT_SUCCESS;
}
xrt_result_t
getFaceCalibrationStateAndroid(bool *out_face_is_calibrated)
{
face_calibration_android_count++;
*out_face_is_calibrated = true;
return XRT_SUCCESS;
}
xrt_result_t
getBodySkeleton(enum xrt_input_name body_tracking_type, struct xrt_body_skeleton *out_value)
{
body_skeleton_count++;
return XRT_SUCCESS;
}
xrt_result_t
getBodyJoints(enum xrt_input_name body_tracking_type,
int64_t desired_timestamp_ns,
struct xrt_body_joint_set *out_value)
{
body_joints_count++;
return XRT_SUCCESS;
}
xrt_result_t
resetBodyTrackingCalibrationMeta()
{
reset_body_calibration_count++;
return XRT_SUCCESS;
}
xrt_result_t
setBodyTrackingCalibrationOverrideMeta(float new_body_height)
{
set_body_calibration_count++;
return XRT_SUCCESS;
}
xrt_result_t
setOutput(enum xrt_output_name name, const struct xrt_output_value *value)
{
set_output_count++;
return XRT_SUCCESS;
}
xrt_result_t
getOutputLimits(struct xrt_output_limits *limits)
{
get_output_limits_count++;
return XRT_SUCCESS;
}
xrt_result_t
getPresence(bool *out_presence)
{
presence_count++;
*out_presence = true;
return XRT_SUCCESS;
}
xrt_result_t
beginPlaneDetectionExt(const struct xrt_plane_detector_begin_info_ext *begin_info,
uint64_t plane_detection_id,
uint64_t *out_plane_detection_id)
{
begin_plane_detection_count++;
*out_plane_detection_id = 42;
return XRT_SUCCESS;
}
xrt_result_t
destroyPlaneDetectionExt(uint64_t plane_detection_id)
{
destroy_plane_detection_count++;
return XRT_SUCCESS;
}
xrt_result_t
getPlaneDetectionStateExt(uint64_t plane_detection_id, enum xrt_plane_detector_state_ext *out_state)
{
get_plane_detection_state_count++;
*out_state = XRT_PLANE_DETECTOR_STATE_DONE_EXT;
return XRT_SUCCESS;
}
xrt_result_t
getPlaneDetectionsExt(uint64_t plane_detection_id, struct xrt_plane_detections_ext *out_detections)
{
get_plane_detections_count++;
return XRT_SUCCESS;
}
xrt_result_t
getViewPoses(const struct xrt_vec3 *default_eye_relation,
int64_t at_timestamp_ns,
enum xrt_view_type view_type,
uint32_t view_count,
struct xrt_space_relation *out_head_relation,
struct xrt_fov *out_fovs,
struct xrt_pose *out_poses)
{
get_view_poses_count++;
return XRT_SUCCESS;
}
xrt_result_t
computeDistortion(uint32_t view, float u, float v, struct xrt_uv_triplet *out_result)
{
compute_distortion_count++;
return XRT_SUCCESS;
}
xrt_result_t
getVisibilityMask(enum xrt_visibility_mask_type type,
uint32_t view_index,
struct xrt_visibility_mask **out_mask)
{
get_visibility_mask_count++;
return XRT_SUCCESS;
}
xrt_result_t
refSpaceUsage(enum xrt_reference_space_type type, enum xrt_input_name name, bool used)
{
ref_space_usage_count++;
return XRT_SUCCESS;
}
xrt_result_t
isFormFactorAvailable(enum xrt_form_factor form_factor, bool *out_available)
{
is_form_factor_available_count++;
*out_available = true;
return XRT_SUCCESS;
}
xrt_result_t
getBatteryStatus(bool *out_present, bool *out_charging, float *out_charge)
{
get_battery_status_count++;
*out_present = true;
*out_charging = false;
*out_charge = 0.85f;
return XRT_SUCCESS;
}
xrt_result_t
getBrightness(float *out_brightness)
{
get_brightness_count++;
*out_brightness = 0.7f;
return XRT_SUCCESS;
}
xrt_result_t
setBrightness(float brightness, bool relative)
{
set_brightness_count++;
return XRT_SUCCESS;
}
xrt_result_t
getCompositorInfo(const struct xrt_device_compositor_mode *mode, struct xrt_device_compositor_info *out_info)
{
get_compositor_info_count++;
return XRT_SUCCESS;
}
xrt_result_t
beginFeature(enum xrt_device_feature_type type)
{
begin_feature_count++;
return XRT_SUCCESS;
}
xrt_result_t
endFeature(enum xrt_device_feature_type type)
{
end_feature_count++;
return XRT_SUCCESS;
}
static void
destroyDevice(struct xrt_device *xdev)
{
auto *dev = AllFeaturesTestDevice::fromXDev(xdev);
dev->destroyed = true;
}
};
TEST_CASE("DeviceBase_AllFeaturesDevice")
{
AllFeaturesTestDevice dev;
auto *xdev = dev.getXDev();
SECTION("All function pointers are set")
{
REQUIRE(xdev->update_inputs != nullptr);
REQUIRE(xdev->get_tracked_pose != nullptr);
REQUIRE(xdev->get_hand_tracking != nullptr);
REQUIRE(xdev->get_face_tracking != nullptr);
REQUIRE(xdev->get_face_calibration_state_android != nullptr);
REQUIRE(xdev->get_body_skeleton != nullptr);
REQUIRE(xdev->get_body_joints != nullptr);
REQUIRE(xdev->reset_body_tracking_calibration_meta != nullptr);
REQUIRE(xdev->set_body_tracking_calibration_override_meta != nullptr);
REQUIRE(xdev->set_output != nullptr);
REQUIRE(xdev->get_output_limits != nullptr);
REQUIRE(xdev->get_presence != nullptr);
REQUIRE(xdev->begin_plane_detection_ext != nullptr);
REQUIRE(xdev->destroy_plane_detection_ext != nullptr);
REQUIRE(xdev->get_plane_detection_state_ext != nullptr);
REQUIRE(xdev->get_plane_detections_ext != nullptr);
REQUIRE(xdev->get_view_poses != nullptr);
REQUIRE(xdev->compute_distortion != nullptr);
REQUIRE(xdev->get_visibility_mask != nullptr);
REQUIRE(xdev->ref_space_usage != nullptr);
REQUIRE(xdev->is_form_factor_available != nullptr);
REQUIRE(xdev->get_battery_status != nullptr);
REQUIRE(xdev->get_brightness != nullptr);
REQUIRE(xdev->set_brightness != nullptr);
REQUIRE(xdev->get_compositor_info != nullptr);
REQUIRE(xdev->begin_feature != nullptr);
REQUIRE(xdev->end_feature != nullptr);
REQUIRE(xdev->destroy != nullptr);
}
SECTION("All functions can be called and track call counts")
{
// Test update_inputs
REQUIRE(dev.update_inputs_count == 0);
xdev->update_inputs(xdev);
REQUIRE(dev.update_inputs_count == 1);
// Test get_tracked_pose
REQUIRE(dev.tracked_pose_count == 0);
xrt_space_relation relation;
xdev->get_tracked_pose(xdev, XRT_INPUT_GENERIC_HEAD_POSE, 0, &relation);
REQUIRE(dev.tracked_pose_count == 1);
// Test get_hand_tracking
REQUIRE(dev.hand_tracking_count == 0);
xrt_hand_joint_set hand_joints;
int64_t timestamp;
xdev->get_hand_tracking(xdev, XRT_INPUT_HT_UNOBSTRUCTED_LEFT, 0, &hand_joints, &timestamp);
REQUIRE(dev.hand_tracking_count == 1);
// Test get_face_tracking
REQUIRE(dev.face_tracking_count == 0);
xrt_facial_expression_set face_set;
xdev->get_face_tracking(xdev, XRT_INPUT_GENERIC_FACE_TRACKING, 0, &face_set);
REQUIRE(dev.face_tracking_count == 1);
// Test get_face_calibration_state_android
REQUIRE(dev.face_calibration_android_count == 0);
bool face_calibrated;
xdev->get_face_calibration_state_android(xdev, &face_calibrated);
REQUIRE(dev.face_calibration_android_count == 1);
REQUIRE(face_calibrated == true);
// Test get_body_skeleton
REQUIRE(dev.body_skeleton_count == 0);
xrt_body_skeleton skeleton;
xdev->get_body_skeleton(xdev, XRT_INPUT_GENERIC_BODY_TRACKING, &skeleton);
REQUIRE(dev.body_skeleton_count == 1);
// Test get_body_joints
REQUIRE(dev.body_joints_count == 0);
xrt_body_joint_set body_joints;
xdev->get_body_joints(xdev, XRT_INPUT_GENERIC_BODY_TRACKING, 0, &body_joints);
REQUIRE(dev.body_joints_count == 1);
// Test reset_body_tracking_calibration_meta
REQUIRE(dev.reset_body_calibration_count == 0);
xdev->reset_body_tracking_calibration_meta(xdev);
REQUIRE(dev.reset_body_calibration_count == 1);
// Test set_body_tracking_calibration_override_meta
REQUIRE(dev.set_body_calibration_count == 0);
xdev->set_body_tracking_calibration_override_meta(xdev, 1.8f);
REQUIRE(dev.set_body_calibration_count == 1);
// Test set_output
REQUIRE(dev.set_output_count == 0);
xrt_output_value output_value;
xdev->set_output(xdev, XRT_OUTPUT_NAME_SIMPLE_VIBRATION, &output_value);
REQUIRE(dev.set_output_count == 1);
// Test get_output_limits
REQUIRE(dev.get_output_limits_count == 0);
xrt_output_limits limits;
xdev->get_output_limits(xdev, &limits);
REQUIRE(dev.get_output_limits_count == 1);
// Test get_presence
REQUIRE(dev.presence_count == 0);
bool presence;
xdev->get_presence(xdev, &presence);
REQUIRE(dev.presence_count == 1);
REQUIRE(presence == true);
// Test begin_plane_detection_ext
REQUIRE(dev.begin_plane_detection_count == 0);
xrt_plane_detector_begin_info_ext begin_info = {};
uint64_t plane_detection_id;
xdev->begin_plane_detection_ext(xdev, &begin_info, 0, &plane_detection_id);
REQUIRE(dev.begin_plane_detection_count == 1);
REQUIRE(plane_detection_id == 42);
// Test get_plane_detection_state_ext
REQUIRE(dev.get_plane_detection_state_count == 0);
xrt_plane_detector_state_ext state;
xdev->get_plane_detection_state_ext(xdev, 42, &state);
REQUIRE(dev.get_plane_detection_state_count == 1);
REQUIRE(state == XRT_PLANE_DETECTOR_STATE_DONE_EXT);
// Test get_plane_detections_ext
REQUIRE(dev.get_plane_detections_count == 0);
xrt_plane_detections_ext detections;
xdev->get_plane_detections_ext(xdev, 42, &detections);
REQUIRE(dev.get_plane_detections_count == 1);
// Test destroy_plane_detection_ext
REQUIRE(dev.destroy_plane_detection_count == 0);
xdev->destroy_plane_detection_ext(xdev, 42);
REQUIRE(dev.destroy_plane_detection_count == 1);
// Test get_view_poses
REQUIRE(dev.get_view_poses_count == 0);
xrt_vec3 eye_relation = {0.0f, 0.0f, 0.0f};
xrt_space_relation head_relation;
xrt_fov fovs[2];
xrt_pose poses[2];
xdev->get_view_poses(xdev, &eye_relation, 0, XRT_VIEW_TYPE_STEREO, 2, &head_relation, fovs, poses);
REQUIRE(dev.get_view_poses_count == 1);
// Test compute_distortion
REQUIRE(dev.compute_distortion_count == 0);
xrt_uv_triplet triplet;
xdev->compute_distortion(xdev, 0, 0.5f, 0.5f, &triplet);
REQUIRE(dev.compute_distortion_count == 1);
// Test get_visibility_mask
REQUIRE(dev.get_visibility_mask_count == 0);
xrt_visibility_mask *mask;
xdev->get_visibility_mask(xdev, XRT_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH, 0, &mask);
REQUIRE(dev.get_visibility_mask_count == 1);
// Test ref_space_usage
REQUIRE(dev.ref_space_usage_count == 0);
xdev->ref_space_usage(xdev, XRT_SPACE_REFERENCE_TYPE_STAGE, XRT_INPUT_GENERIC_HEAD_POSE, true);
REQUIRE(dev.ref_space_usage_count == 1);
// Test is_form_factor_available
REQUIRE(dev.is_form_factor_available_count == 0);
bool form_factor_available = false;
xrt_result_t form_factor_result =
xdev->is_form_factor_available(xdev, XRT_FORM_FACTOR_HMD, &form_factor_available);
REQUIRE(form_factor_result == XRT_SUCCESS);
REQUIRE(dev.is_form_factor_available_count == 1);
REQUIRE(form_factor_available == true);
// Test get_battery_status
REQUIRE(dev.get_battery_status_count == 0);
bool battery_present, battery_charging;
float battery_charge;
xdev->get_battery_status(xdev, &battery_present, &battery_charging, &battery_charge);
REQUIRE(dev.get_battery_status_count == 1);
REQUIRE(battery_present == true);
REQUIRE(battery_charging == false);
REQUIRE(battery_charge == 0.85f);
// Test get_brightness
REQUIRE(dev.get_brightness_count == 0);
float brightness;
xdev->get_brightness(xdev, &brightness);
REQUIRE(dev.get_brightness_count == 1);
REQUIRE(brightness == 0.7f);
// Test set_brightness
REQUIRE(dev.set_brightness_count == 0);
xdev->set_brightness(xdev, 0.9f, false);
REQUIRE(dev.set_brightness_count == 1);
// Test get_compositor_info
REQUIRE(dev.get_compositor_info_count == 0);
xrt_device_compositor_mode mode = {};
xrt_device_compositor_info info;
xdev->get_compositor_info(xdev, &mode, &info);
REQUIRE(dev.get_compositor_info_count == 1);
// Test begin_feature
REQUIRE(dev.begin_feature_count == 0);
xdev->begin_feature(xdev, XRT_DEVICE_FEATURE_FACE_TRACKING);
REQUIRE(dev.begin_feature_count == 1);
// Test end_feature
REQUIRE(dev.end_feature_count == 0);
xdev->end_feature(xdev, XRT_DEVICE_FEATURE_FACE_TRACKING);
REQUIRE(dev.end_feature_count == 1);
// Test destroy
REQUIRE_FALSE(dev.destroyed);
xdev->destroy(xdev);
REQUIRE(dev.destroyed);
}
SECTION("fromXDev conversion works")
{
auto *retrieved = AllFeaturesTestDevice::fromXDev(xdev);
REQUIRE(retrieved == &dev);
}
}