From e4b0e6282d460347068601107fc30eae36c219c6 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Sun, 24 Jan 2021 22:49:50 +0100 Subject: [PATCH 001/883] d/vive: Factor out config into separate struct --- src/xrt/drivers/vive/vive.h | 10 +-- src/xrt/drivers/vive/vive_config.c | 6 +- src/xrt/drivers/vive/vive_config.h | 89 ++++++++++++++++++++++++- src/xrt/drivers/vive/vive_device.c | 101 +++++++++++++++-------------- src/xrt/drivers/vive/vive_device.h | 73 +-------------------- 5 files changed, 149 insertions(+), 130 deletions(-) diff --git a/src/xrt/drivers/vive/vive.h b/src/xrt/drivers/vive/vive.h index 7c6e65777..84f5196ab 100644 --- a/src/xrt/drivers/vive/vive.h +++ b/src/xrt/drivers/vive/vive.h @@ -16,8 +16,8 @@ * */ -#define VIVE_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->ll, __VA_ARGS__) -#define VIVE_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->ll, __VA_ARGS__) -#define VIVE_INFO(d, ...) U_LOG_XDEV_IFL_I(&d->base, d->ll, __VA_ARGS__) -#define VIVE_WARN(d, ...) U_LOG_XDEV_IFL_W(&d->base, d->ll, __VA_ARGS__) -#define VIVE_ERROR(d, ...) U_LOG_XDEV_IFL_E(&d->base, d->ll, __VA_ARGS__) +#define VIVE_TRACE(d, ...) U_LOG_IFL_T(d->ll, __VA_ARGS__) +#define VIVE_DEBUG(d, ...) U_LOG_IFL_D(d->ll, __VA_ARGS__) +#define VIVE_INFO(d, ...) U_LOG_IFL_I(d->ll, __VA_ARGS__) +#define VIVE_WARN(d, ...) U_LOG_IFL_W(d->ll, __VA_ARGS__) +#define VIVE_ERROR(d, ...) U_LOG_IFL_E(d->ll, __VA_ARGS__) diff --git a/src/xrt/drivers/vive/vive_config.c b/src/xrt/drivers/vive/vive_config.c index c7e58b3d1..5e616e9a2 100644 --- a/src/xrt/drivers/vive/vive_config.c +++ b/src/xrt/drivers/vive/vive_config.c @@ -56,7 +56,7 @@ _get_pose_from_pos_x_z(const cJSON *obj, struct xrt_pose *pose) } static void -_get_distortion_properties(struct vive_device *d, const cJSON *eye_transform_json, uint8_t eye) +_get_distortion_properties(struct vive_config *d, const cJSON *eye_transform_json, uint8_t eye) { const cJSON *eye_json = cJSON_GetArrayItem(eye_transform_json, eye); if (eye_json == NULL) { @@ -97,7 +97,7 @@ _get_distortion_properties(struct vive_device *d, const cJSON *eye_transform_jso } static void -_get_lighthouse(struct vive_device *d, const cJSON *json) +_get_lighthouse(struct vive_config *d, const cJSON *json) { const cJSON *lh = cJSON_GetObjectItemCaseSensitive(json, "lighthouse_config"); if (lh == NULL) { @@ -177,7 +177,7 @@ _print_vec3(const char *title, struct xrt_vec3 *vec) } bool -vive_config_parse(struct vive_device *d, char *json_string) +vive_config_parse(struct vive_config *d, char *json_string) { VIVE_DEBUG(d, "JSON config:\n%s", json_string); diff --git a/src/xrt/drivers/vive/vive_config.h b/src/xrt/drivers/vive/vive_config.h index aa7943601..02e9e29ef 100644 --- a/src/xrt/drivers/vive/vive_config.h +++ b/src/xrt/drivers/vive/vive_config.h @@ -11,10 +11,95 @@ #include -struct vive_device; +#include "xrt/xrt_defines.h" +#include "util/u_logging.h" +#include "util/u_distortion_mesh.h" + +enum VIVE_VARIANT +{ + VIVE_UNKNOWN = 0, + VIVE_VARIANT_VIVE, + VIVE_VARIANT_PRO, + VIVE_VARIANT_INDEX +}; + +/*! + * A single lighthouse senosor point and normal, in IMU space. + */ +struct lh_sensor +{ + struct xrt_vec3 pos; + uint32_t _pad0; + struct xrt_vec3 normal; + uint32_t _pad1; +}; + +/*! + * A lighthouse consisting of sensors. + * + * All sensors are placed in IMU space. + */ +struct lh_model +{ + struct lh_sensor *sensors; + size_t num_sensors; +}; + +struct vive_config +{ + //! log level accessed by the config parser + enum u_logging_level ll; + + enum VIVE_VARIANT variant; + + struct + { + double acc_range; + double gyro_range; + struct xrt_vec3 acc_bias; + struct xrt_vec3 acc_scale; + struct xrt_vec3 gyro_bias; + struct xrt_vec3 gyro_scale; + + //! IMU position in tracking space. + struct xrt_pose trackref; + } imu; + + struct + { + double lens_separation; + double persistence; + int eye_target_height_in_pixels; + int eye_target_width_in_pixels; + + struct xrt_quat rot[2]; + + //! Head position in tracking space. + struct xrt_pose trackref; + //! Head position in IMU space. + struct xrt_pose imuref; + } display; + + struct + { + uint32_t display_firmware_version; + uint32_t firmware_version; + uint8_t hardware_revision; + uint8_t hardware_version_micro; + uint8_t hardware_version_minor; + uint8_t hardware_version_major; + char mb_serial_number[32]; + char model_number[32]; + char device_serial_number[32]; + } firmware; + + struct u_vive_values distortion[2]; + + struct lh_model lh; +}; bool -vive_config_parse(struct vive_device *d, char *json_string); +vive_config_parse(struct vive_config *d, char *json_string); struct vive_controller_device; diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index 6da1c6964..939ff2194 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -26,7 +26,6 @@ #include "vive.h" #include "vive_device.h" #include "vive_protocol.h" -#include "vive_config.h" #define VIVE_CLOCK_FREQ 48e6 // 48 MHz @@ -71,10 +70,10 @@ vive_device_destroy(struct xrt_device *xdev) d->watchman_dev = NULL; } - if (d->lh.sensors != NULL) { - free(d->lh.sensors); - d->lh.sensors = NULL; - d->lh.num_sensors = 0; + if (d->config.lh.sensors != NULL) { + free(d->config.lh.sensors); + d->config.lh.sensors = NULL; + d->config.lh.num_sensors = 0; } // Remove the variable tracking. @@ -137,7 +136,7 @@ vive_device_get_view_pose(struct xrt_device *xdev, struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; bool adjust = view_index == 0; - pose.orientation = d->display.rot[view_index]; + pose.orientation = d->config.display.rot[view_index]; pose.position.x = eye_relation->x / 2.0f; pose.position.y = eye_relation->y / 2.0f; pose.position.z = eye_relation->z / 2.0f; @@ -178,11 +177,11 @@ vive_mainboard_get_device_info(struct vive_device *d) edid_vid = __be16_to_cpu(report.edid_vid); - d->firmware.display_firmware_version = __le32_to_cpu(report.display_firmware_version); + d->config.firmware.display_firmware_version = __le32_to_cpu(report.display_firmware_version); VIVE_INFO(d, "EDID Manufacturer ID: %c%c%c, Product code: 0x%04x", '@' + (edid_vid >> 10), '@' + ((edid_vid >> 5) & 0x1f), '@' + (edid_vid & 0x1f), __le16_to_cpu(report.edid_pid)); - VIVE_INFO(d, "Display firmware version: %u", d->firmware.display_firmware_version); + VIVE_INFO(d, "Display firmware version: %u", d->config.firmware.display_firmware_version); return 0; } @@ -316,11 +315,11 @@ update_imu(struct vive_device *d, const void *buffer) (int16_t)__le16_to_cpu(sample->acc[2]), }; - scale = (float)d->imu.acc_range / 32768.0f; + scale = (float)d->config.imu.acc_range / 32768.0f; struct xrt_vec3 acceleration = { - scale * d->imu.acc_scale.x * acc[0] - d->imu.acc_bias.x, - scale * d->imu.acc_scale.y * acc[1] - d->imu.acc_bias.y, - scale * d->imu.acc_scale.z * acc[2] - d->imu.acc_bias.z, + scale * d->config.imu.acc_scale.x * acc[0] - d->config.imu.acc_bias.x, + scale * d->config.imu.acc_scale.y * acc[1] - d->config.imu.acc_bias.y, + scale * d->config.imu.acc_scale.z * acc[2] - d->config.imu.acc_bias.z, }; int16_t gyro[3] = { @@ -329,11 +328,11 @@ update_imu(struct vive_device *d, const void *buffer) (int16_t)__le16_to_cpu(sample->gyro[2]), }; - scale = (float)d->imu.gyro_range / 32768.0f; + scale = (float)d->config.imu.gyro_range / 32768.0f; struct xrt_vec3 angular_velocity = { - scale * d->imu.gyro_scale.x * gyro[0] - d->imu.gyro_bias.x, - scale * d->imu.gyro_scale.y * gyro[1] - d->imu.gyro_bias.y, - scale * d->imu.gyro_scale.z * gyro[2] - d->imu.gyro_bias.z, + scale * d->config.imu.gyro_scale.x * gyro[0] - d->config.imu.gyro_bias.x, + scale * d->config.imu.gyro_scale.y * gyro[1] - d->config.imu.gyro_bias.y, + scale * d->config.imu.gyro_scale.z * gyro[2] - d->config.imu.gyro_bias.z, }; VIVE_TRACE(d, "ACC %f %f %f", acceleration.x, acceleration.y, acceleration.z); @@ -720,29 +719,29 @@ vive_sensors_run_thread(void *ptr) void vive_init_defaults(struct vive_device *d) { - d->display.eye_target_width_in_pixels = 1080; - d->display.eye_target_height_in_pixels = 1200; + d->config.display.eye_target_width_in_pixels = 1080; + d->config.display.eye_target_height_in_pixels = 1200; - d->display.rot[0].w = 1.0f; - d->display.rot[1].w = 1.0f; + d->config.display.rot[0].w = 1.0f; + d->config.display.rot[1].w = 1.0f; - d->imu.gyro_range = 8.726646f; - d->imu.acc_range = 39.226600f; + d->config.imu.gyro_range = 8.726646f; + d->config.imu.acc_range = 39.226600f; - d->imu.acc_scale.x = 1.0f; - d->imu.acc_scale.y = 1.0f; - d->imu.acc_scale.z = 1.0f; + d->config.imu.acc_scale.x = 1.0f; + d->config.imu.acc_scale.y = 1.0f; + d->config.imu.acc_scale.z = 1.0f; - d->imu.gyro_scale.x = 1.0f; - d->imu.gyro_scale.y = 1.0f; - d->imu.gyro_scale.z = 1.0f; + d->config.imu.gyro_scale.x = 1.0f; + d->config.imu.gyro_scale.y = 1.0f; + d->config.imu.gyro_scale.z = 1.0f; d->rot_filtered.w = 1.0f; for (int view = 0; view < 2; view++) { - d->distortion[view].aspect_x_over_y = 0.89999997615814209f; - d->distortion[view].grow_for_undistort = 0.5f; - d->distortion[view].undistort_r2_cutoff = 1.0f; + d->config.distortion[view].aspect_x_over_y = 0.89999997615814209f; + d->config.distortion[view].grow_for_undistort = 0.5f; + d->config.distortion[view].undistort_r2_cutoff = 1.0f; } } @@ -751,7 +750,7 @@ static bool compute_distortion(struct xrt_device *xdev, int view, float u, float v, struct xrt_uv_triplet *result) { struct vive_device *d = vive_device(xdev); - return u_compute_distortion_vive(&d->distortion[view], u, v, result); + return u_compute_distortion_vive(&d->config.distortion[view], u, v, result); } struct vive_device * @@ -794,9 +793,9 @@ vive_device_create(struct os_hid_device *mainboard_dev, vive_mainboard_power_on(d); vive_mainboard_get_device_info(d); } - vive_read_firmware(d->sensors_dev, &d->firmware.firmware_version, &d->firmware.hardware_revision, - &d->firmware.hardware_version_micro, &d->firmware.hardware_version_minor, - &d->firmware.hardware_version_major); + vive_read_firmware(d->sensors_dev, &d->config.firmware.firmware_version, &d->config.firmware.hardware_revision, + &d->config.firmware.hardware_version_micro, &d->config.firmware.hardware_version_minor, + &d->config.firmware.hardware_version_major); /* VIVE_INFO(d, "Firmware version %u %s@%s FPGA %u.%u", @@ -804,18 +803,22 @@ vive_device_create(struct os_hid_device *mainboard_dev, report.fpga_version_major, report.fpga_version_minor); */ - VIVE_INFO(d, "Firmware version %u", d->firmware.firmware_version); - VIVE_INFO(d, "Hardware revision: %d rev %d.%d.%d", d->firmware.hardware_revision, - d->firmware.hardware_version_major, d->firmware.hardware_version_minor, - d->firmware.hardware_version_micro); + VIVE_INFO(d, "Firmware version %u", d->config.firmware.firmware_version); + VIVE_INFO(d, "Hardware revision: %d rev %d.%d.%d", d->config.firmware.hardware_revision, + d->config.firmware.hardware_version_major, d->config.firmware.hardware_version_minor, + d->config.firmware.hardware_version_micro); - vive_get_imu_range_report(d->sensors_dev, &d->imu.gyro_range, &d->imu.acc_range); - VIVE_INFO(d, "Vive gyroscope range %f", d->imu.gyro_range); - VIVE_INFO(d, "Vive accelerometer range %f", d->imu.acc_range); + vive_get_imu_range_report(d->sensors_dev, &d->config.imu.gyro_range, &d->config.imu.acc_range); + VIVE_INFO(d, "Vive gyroscope range %f", d->config.imu.gyro_range); + VIVE_INFO(d, "Vive accelerometer range %f", d->config.imu.acc_range); char *config = vive_read_config(d->sensors_dev); + + d->config.ll = d->ll; + // usb connected HMD variant is known because of USB id, config parsing relies on it. + d->config.variant = d->variant; if (config != NULL) { - vive_config_parse(d, config); + vive_config_parse(&d->config, config); free(config); } @@ -825,8 +828,8 @@ vive_device_create(struct os_hid_device *mainboard_dev, double lens_horizontal_separation = 0.057863; double eye_to_screen_distance = 0.023226876441867737; - uint32_t w_pixels = d->display.eye_target_width_in_pixels; - uint32_t h_pixels = d->display.eye_target_height_in_pixels; + uint32_t w_pixels = d->config.display.eye_target_width_in_pixels; + uint32_t h_pixels = d->config.display.eye_target_height_in_pixels; // Main display. d->base.hmd->screens[0].w_pixels = (int)w_pixels * 2; @@ -882,10 +885,10 @@ vive_device_create(struct os_hid_device *mainboard_dev, u_var_add_root(d, "Vive Device", true); u_var_add_gui_header(d, &d->gui.calibration, "Calibration"); - u_var_add_vec3_f32(d, &d->imu.acc_scale, "acc_scale"); - u_var_add_vec3_f32(d, &d->imu.acc_bias, "acc_bias"); - u_var_add_vec3_f32(d, &d->imu.gyro_scale, "gyro_scale"); - u_var_add_vec3_f32(d, &d->imu.gyro_bias, "gyro_bias"); + u_var_add_vec3_f32(d, &d->config.imu.acc_scale, "acc_scale"); + u_var_add_vec3_f32(d, &d->config.imu.acc_bias, "acc_bias"); + u_var_add_vec3_f32(d, &d->config.imu.gyro_scale, "gyro_scale"); + u_var_add_vec3_f32(d, &d->config.imu.gyro_bias, "gyro_bias"); u_var_add_gui_header(d, &d->gui.last, "Last data"); u_var_add_vec3_f32(d, &d->last.acc, "acc"); u_var_add_vec3_f32(d, &d->last.gyro, "gyro"); diff --git a/src/xrt/drivers/vive/vive_device.h b/src/xrt/drivers/vive/vive_device.h index eef5121be..09e95a6dd 100644 --- a/src/xrt/drivers/vive/vive_device.h +++ b/src/xrt/drivers/vive/vive_device.h @@ -16,42 +16,12 @@ #include "util/u_distortion_mesh.h" #include "vive_lighthouse.h" +#include "vive_config.h" #ifdef __cplusplus extern "C" { #endif - -/*! - * A lighthouse consisting of sensors. - * - * All sensors are placed in IMU space. - */ -struct lh_model -{ - struct lh_sensor *sensors; - size_t num_sensors; -}; - -/*! - * A single lighthouse senosor point and normal, in IMU space. - */ -struct lh_sensor -{ - struct xrt_vec3 pos; - uint32_t _pad0; - struct xrt_vec3 normal; - uint32_t _pad1; -}; - -enum VIVE_VARIANT -{ - VIVE_UNKNOWN = 0, - VIVE_VARIANT_VIVE, - VIVE_VARIANT_PRO, - VIVE_VARIANT_INDEX -}; - /*! * @implements xrt_device */ @@ -70,22 +40,11 @@ struct vive_device struct os_thread_helper watchman_thread; struct os_thread_helper mainboard_thread; - struct lh_model lh; - struct { uint64_t time_ns; uint8_t sequence; uint32_t last_sample_time_raw; - double acc_range; - double gyro_range; - struct xrt_vec3 acc_bias; - struct xrt_vec3 acc_scale; - struct xrt_vec3 gyro_bias; - struct xrt_vec3 gyro_scale; - - //! IMU position in tracking space. - struct xrt_pose trackref; } imu; struct m_imu_3dof fusion; @@ -96,21 +55,6 @@ struct vive_device struct xrt_vec3 gyro; } last; - struct - { - double lens_separation; - double persistence; - int eye_target_height_in_pixels; - int eye_target_width_in_pixels; - - struct xrt_quat rot[2]; - - //! Head position in tracking space. - struct xrt_pose trackref; - //! Head position in IMU space. - struct xrt_pose imuref; - } display; - struct { uint16_t ipd; @@ -119,19 +63,6 @@ struct vive_device uint8_t button; } board; - struct - { - uint32_t display_firmware_version; - uint32_t firmware_version; - uint8_t hardware_revision; - uint8_t hardware_version_micro; - uint8_t hardware_version_minor; - uint8_t hardware_version_major; - char mb_serial_number[32]; - char model_number[32]; - char device_serial_number[32]; - } firmware; - struct xrt_quat rot_filtered; enum u_logging_level ll; @@ -143,7 +74,7 @@ struct vive_device bool last; } gui; - struct u_vive_values distortion[2]; + struct vive_config config; }; struct vive_device * From a2e7e1c3d9adea3bd6e24869531ed1d4573fea77 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Sun, 24 Jan 2021 23:02:55 +0100 Subject: [PATCH 002/883] d/vive: Factor out controller config into separate struct --- src/xrt/drivers/vive/vive_config.c | 2 +- src/xrt/drivers/vive/vive_config.h | 44 ++++++++++++++++++- src/xrt/drivers/vive/vive_controller.c | 59 ++++++++++++++------------ src/xrt/drivers/vive/vive_controller.h | 37 +++------------- 4 files changed, 82 insertions(+), 60 deletions(-) diff --git a/src/xrt/drivers/vive/vive_config.c b/src/xrt/drivers/vive/vive_config.c index 5e616e9a2..65e54f7bd 100644 --- a/src/xrt/drivers/vive/vive_config.c +++ b/src/xrt/drivers/vive/vive_config.c @@ -287,7 +287,7 @@ vive_config_parse(struct vive_config *d, char *json_string) } bool -vive_config_parse_controller(struct vive_controller_device *d, char *json_string) +vive_config_parse_controller(struct vive_controller_config *d, char *json_string) { VIVE_DEBUG(d, "JSON config:\n%s", json_string); diff --git a/src/xrt/drivers/vive/vive_config.h b/src/xrt/drivers/vive/vive_config.h index 02e9e29ef..49add8b64 100644 --- a/src/xrt/drivers/vive/vive_config.h +++ b/src/xrt/drivers/vive/vive_config.h @@ -23,6 +23,16 @@ enum VIVE_VARIANT VIVE_VARIANT_INDEX }; +enum VIVE_CONTROLLER_VARIANT +{ + CONTROLLER_VIVE_WAND, + CONTROLLER_INDEX_LEFT, + CONTROLLER_INDEX_RIGHT, + CONTROLLER_TRACKER_GEN1, + CONTROLLER_TRACKER_GEN2, + CONTROLLER_UNKNOWN +}; + /*! * A single lighthouse senosor point and normal, in IMU space. */ @@ -98,6 +108,38 @@ struct vive_config struct lh_model lh; }; +struct vive_controller_config +{ + enum u_logging_level ll; + + enum VIVE_CONTROLLER_VARIANT variant; + + struct + { + uint32_t firmware_version; + uint8_t hardware_revision; + uint8_t hardware_version_micro; + uint8_t hardware_version_minor; + uint8_t hardware_version_major; + char mb_serial_number[32]; + char model_number[32]; + char device_serial_number[32]; + } firmware; + + struct + { + double acc_range; + double gyro_range; + struct xrt_vec3 acc_bias; + struct xrt_vec3 acc_scale; + struct xrt_vec3 gyro_bias; + struct xrt_vec3 gyro_scale; + + //! IMU position in tracking space. + struct xrt_pose trackref; + } imu; +}; + bool vive_config_parse(struct vive_config *d, char *json_string); @@ -105,4 +147,4 @@ vive_config_parse(struct vive_config *d, char *json_string); struct vive_controller_device; bool -vive_config_parse_controller(struct vive_controller_device *d, char *json_string); +vive_config_parse_controller(struct vive_controller_config *d, char *json_string); diff --git a/src/xrt/drivers/vive/vive_controller.c b/src/xrt/drivers/vive/vive_controller.c index 4137215c2..74539bc6c 100644 --- a/src/xrt/drivers/vive/vive_controller.c +++ b/src/xrt/drivers/vive/vive_controller.c @@ -543,18 +543,18 @@ vive_controller_handle_imu_sample(struct vive_controller_device *d, struct watch __le16_to_cpu(sample->gyro[2]), }; - float scale = (float)d->imu.acc_range / 32768.0f; + float scale = (float)d->config.imu.acc_range / 32768.0f; struct xrt_vec3 acceleration = { - scale * d->imu.acc_scale.x * acc[0] - d->imu.acc_bias.x, - scale * d->imu.acc_scale.y * acc[1] - d->imu.acc_bias.y, - scale * d->imu.acc_scale.z * acc[2] - d->imu.acc_bias.z, + scale * d->config.imu.acc_scale.x * acc[0] - d->config.imu.acc_bias.x, + scale * d->config.imu.acc_scale.y * acc[1] - d->config.imu.acc_bias.y, + scale * d->config.imu.acc_scale.z * acc[2] - d->config.imu.acc_bias.z, }; - scale = (float)d->imu.gyro_range / 32768.0f; + scale = (float)d->config.imu.gyro_range / 32768.0f; struct xrt_vec3 angular_velocity = { - scale * d->imu.gyro_scale.x * gyro[0] - d->imu.gyro_bias.x, - scale * d->imu.gyro_scale.y * gyro[1] - d->imu.gyro_bias.y, - scale * d->imu.gyro_scale.z * gyro[2] - d->imu.gyro_bias.z, + scale * d->config.imu.gyro_scale.x * gyro[0] - d->config.imu.gyro_bias.x, + scale * d->config.imu.gyro_scale.y * gyro[1] - d->config.imu.gyro_bias.y, + scale * d->config.imu.gyro_scale.z * gyro[2] - d->config.imu.gyro_bias.z, }; VIVE_TRACE(d, "ACC %f %f %f", acceleration.x, acceleration.y, acceleration.z); @@ -1030,22 +1030,22 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w m_imu_3dof_init(&d->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); /* default values, will be queried from device */ - d->imu.gyro_range = 8.726646f; - d->imu.acc_range = 39.226600f; + d->config.imu.gyro_range = 8.726646f; + d->config.imu.acc_range = 39.226600f; - d->imu.acc_scale.x = 1.0f; - d->imu.acc_scale.y = 1.0f; - d->imu.acc_scale.z = 1.0f; - d->imu.gyro_scale.x = 1.0f; - d->imu.gyro_scale.y = 1.0f; - d->imu.gyro_scale.z = 1.0f; + d->config.imu.acc_scale.x = 1.0f; + d->config.imu.acc_scale.y = 1.0f; + d->config.imu.acc_scale.z = 1.0f; + d->config.imu.gyro_scale.x = 1.0f; + d->config.imu.gyro_scale.y = 1.0f; + d->config.imu.gyro_scale.z = 1.0f; - d->imu.acc_bias.x = 0.0f; - d->imu.acc_bias.y = 0.0f; - d->imu.acc_bias.z = 0.0f; - d->imu.gyro_bias.x = 0.0f; - d->imu.gyro_bias.y = 0.0f; - d->imu.gyro_bias.z = 0.0f; + d->config.imu.acc_bias.x = 0.0f; + d->config.imu.acc_bias.y = 0.0f; + d->config.imu.acc_bias.z = 0.0f; + d->config.imu.gyro_bias.x = 0.0f; + d->config.imu.gyro_bias.y = 0.0f; + d->config.imu.gyro_bias.z = 0.0f; d->controller_hid = controller_hid; @@ -1058,19 +1058,22 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w d->index = controller_num; //! @todo: reading range report fails for powered off controller - if (vive_get_imu_range_report(d->controller_hid, &d->imu.gyro_range, &d->imu.acc_range) != 0) { + if (vive_get_imu_range_report(d->controller_hid, &d->config.imu.gyro_range, &d->config.imu.acc_range) != 0) { VIVE_ERROR(d, "Could not get watchman IMU range packet!"); free(d); return 0; } - VIVE_DEBUG(d, "Vive controller gyroscope range %f", d->imu.gyro_range); - VIVE_DEBUG(d, "Vive controller accelerometer range %f", d->imu.acc_range); + VIVE_DEBUG(d, "Vive controller gyroscope range %f", d->config.imu.gyro_range); + VIVE_DEBUG(d, "Vive controller accelerometer range %f", d->config.imu.acc_range); // successful config parsing determines d->variant char *config = vive_read_config(d->controller_hid); + + d->config.ll = d->ll; + if (config != NULL) { - vive_config_parse_controller(d, config); + vive_config_parse_controller(&d->config, config); free(config); } else { VIVE_ERROR(d, "Could not get Vive controller config\n"); @@ -1078,6 +1081,10 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w return 0; } + // watchman rf connected device variant is read from config json + //! @todo usb connected controllers + d->variant = d->config.variant; + if (d->variant == CONTROLLER_VIVE_WAND) { d->base.name = XRT_DEVICE_VIVE_WAND; diff --git a/src/xrt/drivers/vive/vive_controller.h b/src/xrt/drivers/vive/vive_controller.h index 387998cd8..4228c814c 100644 --- a/src/xrt/drivers/vive/vive_controller.h +++ b/src/xrt/drivers/vive/vive_controller.h @@ -20,6 +20,8 @@ #include "util/u_hand_tracking.h" +#include "vive_config.h" + #ifdef __cplusplus extern "C" { #endif @@ -36,16 +38,6 @@ enum watchman_gen WATCHMAN_GEN_UNKNOWN }; -enum controller_variant -{ - CONTROLLER_VIVE_WAND, - CONTROLLER_INDEX_LEFT, - CONTROLLER_INDEX_RIGHT, - CONTROLLER_TRACKER_GEN1, - CONTROLLER_TRACKER_GEN2, - CONTROLLER_UNKNOWN -}; - /*! * A Vive Controller device, representing just a single controller. * @@ -63,15 +55,6 @@ struct vive_controller_device { uint64_t time_ns; uint32_t last_sample_time_raw; - double acc_range; - double gyro_range; - struct xrt_vec3 acc_bias; - struct xrt_vec3 acc_scale; - struct xrt_vec3 gyro_bias; - struct xrt_vec3 gyro_scale; - - //! IMU position in tracking space. - struct xrt_pose trackref; } imu; struct m_imu_3dof fusion; @@ -113,22 +96,12 @@ struct vive_controller_device uint8_t battery; } state; - struct - { - uint32_t firmware_version; - uint8_t hardware_revision; - uint8_t hardware_version_micro; - uint8_t hardware_version_minor; - uint8_t hardware_version_major; - char mb_serial_number[32]; - char model_number[32]; - char device_serial_number[32]; - } firmware; - enum watchman_gen watchman_gen; - enum controller_variant variant; + enum VIVE_CONTROLLER_VARIANT variant; struct u_hand_tracking hand_tracking; + + struct vive_controller_config config; }; struct vive_controller_device * From 721b1593128bb1b73dd670d03283e077e7720a7b Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Sun, 24 Jan 2021 23:15:57 +0100 Subject: [PATCH 003/883] build/meson: make vive_config lib and link to vive, libsurvive --- src/xrt/drivers/meson.build | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/xrt/drivers/meson.build b/src/xrt/drivers/meson.build index 848b9faf1..1a2d41adb 100644 --- a/src/xrt/drivers/meson.build +++ b/src/xrt/drivers/meson.build @@ -154,6 +154,20 @@ lib_drv_v4l2 = static_library( build_by_default: 'v4l2' in drivers, ) +lib_vive_config = static_library( + 'vive_config', + files( + 'vive/vive_config.c', + 'vive/vive_config.h', + ), + include_directories: [ + xrt_include, + cjson_include, + ], + dependencies: [aux, zlib], + build_by_default: 'vive' in drivers or 'survive' in drivers, +) + lib_drv_vive = static_library( 'drv_vive', files( @@ -165,8 +179,6 @@ lib_drv_vive = static_library( 'vive/vive_prober.c', 'vive/vive_controller.c', 'vive/vive_controller.h', - 'vive/vive_config.c', - 'vive/vive_config.h', 'vive/vive_lighthouse.c', 'vive/vive_lighthouse.h', ), @@ -176,6 +188,7 @@ lib_drv_vive = static_library( ], dependencies: [aux, zlib], build_by_default: 'vive' in drivers, + link_with: lib_vive_config ) lib_drv_survive = static_library( @@ -184,7 +197,7 @@ lib_drv_survive = static_library( 'survive/survive_driver.c', 'survive/survive_interface.h', 'survive/survive_wrap.c', - 'survive/survive_wrap.h' + 'survive/survive_wrap.h', ), include_directories: [ xrt_include, @@ -192,6 +205,7 @@ lib_drv_survive = static_library( ], dependencies: [aux, zlib, survive], build_by_default: 'survive' in drivers, + link_with: lib_vive_config ) lib_drv_daydream = static_library( From b2da8dfd07e7a993c0508ab25b1410739f058dbb Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Sun, 24 Jan 2021 23:19:21 +0100 Subject: [PATCH 004/883] build/cmake: make vive_config lib and link to vive, libsurvive --- src/xrt/drivers/CMakeLists.txt | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index 65617a9b8..bec8b2a6a 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -160,8 +160,8 @@ if(XRT_BUILD_DRIVER_REMOTE) list(APPEND ENABLED_HEADSET_DRIVERS remote) endif() -if(XRT_BUILD_DRIVER_VIVE) - set(VIVE_SOURCE_FILES +if (XRT_BUILD_DRIVER_VIVE OR XRT_BUILD_DRIVER_SURVIVE) + set(VIVE_CONFIG_SOURCE_FILES vive/vive_device.h vive/vive_device.c vive/vive_prober.h @@ -175,9 +175,28 @@ if(XRT_BUILD_DRIVER_VIVE) vive/vive_lighthouse.h vive/vive_lighthouse.c ) + add_library(vive_config STATIC ${VIVE_CONFIG_SOURCE_FILES}) + target_link_libraries(vive_config PRIVATE xrt-interfaces aux_util aux_math xrt-external-cjson) + target_link_libraries(vive_config PRIVATE ${ZLIB_LIBRARIES}) + target_include_directories(vive_config PRIVATE ${ZLIB_INCLUDE_DIRS}) +endif() + +if(XRT_BUILD_DRIVER_VIVE) + set(VIVE_SOURCE_FILES + vive/vive_device.h + vive/vive_device.c + vive/vive_prober.h + vive/vive_prober.c + vive/vive_protocol.c + vive/vive_protocol.h + vive/vive_controller.h + vive/vive_controller.c + vive/vive_lighthouse.h + vive/vive_lighthouse.c + ) add_library(drv_vive STATIC ${VIVE_SOURCE_FILES}) - target_link_libraries(drv_vive PRIVATE xrt-interfaces aux_os aux_util aux_math xrt-external-cjson) + target_link_libraries(drv_vive PRIVATE xrt-interfaces aux_os aux_util aux_math xrt-external-cjson vive_config) target_link_libraries(drv_vive PRIVATE ${ZLIB_LIBRARIES}) target_include_directories(drv_vive PRIVATE ${ZLIB_INCLUDE_DIRS}) list(APPEND ENABLED_HEADSET_DRIVERS vive) @@ -214,7 +233,7 @@ if (XRT_BUILD_DRIVER_SURVIVE) ) add_library(drv_survive STATIC ${SURVIVE_SOURCE_FILES}) - target_link_libraries(drv_survive PRIVATE xrt-interfaces aux_os aux_util aux_math PkgConfig::SURVIVE) + target_link_libraries(drv_survive PRIVATE xrt-interfaces aux_os aux_util aux_math vive_config PkgConfig::SURVIVE) list(APPEND ENABLED_HEADSET_DRIVERS survive) endif() @@ -254,4 +273,4 @@ if(ENABLED_HEADSET_DRIVERS) message(STATUS "Enabled drivers: ${ENABLED_DRIVERS}") else() message(FATAL_ERROR "You must enable at least one headset driver to build Monado.") -endif() \ No newline at end of file +endif() From e8ac9ecee439a9b31e923662d50ce0ace0904085 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Sun, 24 Jan 2021 23:23:08 +0100 Subject: [PATCH 005/883] build/meson: Add vive_config include dir to survive --- src/xrt/drivers/meson.build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/xrt/drivers/meson.build b/src/xrt/drivers/meson.build index 1a2d41adb..ff5eda7e1 100644 --- a/src/xrt/drivers/meson.build +++ b/src/xrt/drivers/meson.build @@ -154,6 +154,7 @@ lib_drv_v4l2 = static_library( build_by_default: 'v4l2' in drivers, ) +vive_config_include = include_directories('vive') lib_vive_config = static_library( 'vive_config', files( @@ -185,6 +186,7 @@ lib_drv_vive = static_library( include_directories: [ xrt_include, cjson_include, + vive_config_include, ], dependencies: [aux, zlib], build_by_default: 'vive' in drivers, @@ -202,6 +204,7 @@ lib_drv_survive = static_library( include_directories: [ xrt_include, cjson_include, + vive_config_include, ], dependencies: [aux, zlib, survive], build_by_default: 'survive' in drivers, From 152587d728adcfd10198df64cdf974eff0c32343 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Sun, 24 Jan 2021 23:27:09 +0100 Subject: [PATCH 006/883] build/cmake: Add vive_config include dir to survive --- src/xrt/drivers/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index bec8b2a6a..1f1916087 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -181,6 +181,7 @@ if (XRT_BUILD_DRIVER_VIVE OR XRT_BUILD_DRIVER_SURVIVE) target_include_directories(vive_config PRIVATE ${ZLIB_INCLUDE_DIRS}) endif() +set(VIVE_CONFIG_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/vive") if(XRT_BUILD_DRIVER_VIVE) set(VIVE_SOURCE_FILES vive/vive_device.h @@ -198,7 +199,7 @@ if(XRT_BUILD_DRIVER_VIVE) add_library(drv_vive STATIC ${VIVE_SOURCE_FILES}) target_link_libraries(drv_vive PRIVATE xrt-interfaces aux_os aux_util aux_math xrt-external-cjson vive_config) target_link_libraries(drv_vive PRIVATE ${ZLIB_LIBRARIES}) - target_include_directories(drv_vive PRIVATE ${ZLIB_INCLUDE_DIRS}) + target_include_directories(drv_vive PRIVATE ${ZLIB_INCLUDE_DIRS} ${VIVE_CONFIG_INCLUDE}) list(APPEND ENABLED_HEADSET_DRIVERS vive) endif() @@ -233,6 +234,7 @@ if (XRT_BUILD_DRIVER_SURVIVE) ) add_library(drv_survive STATIC ${SURVIVE_SOURCE_FILES}) + target_include_directories(drv_survive PRIVATE ${VIVE_CONFIG_INCLUDE}) target_link_libraries(drv_survive PRIVATE xrt-interfaces aux_os aux_util aux_math vive_config PkgConfig::SURVIVE) list(APPEND ENABLED_HEADSET_DRIVERS survive) endif() From b87c7d5e617dac9a04f62ffd3ad481564641cef3 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 25 Jan 2021 00:15:54 +0100 Subject: [PATCH 007/883] d/survive: Port to vive_config parsing --- src/xrt/drivers/survive/survive_driver.c | 368 +++++------------------ src/xrt/drivers/vive/vive_config.c | 29 ++ src/xrt/drivers/vive/vive_config.h | 8 + src/xrt/drivers/vive/vive_device.c | 32 -- 4 files changed, 117 insertions(+), 320 deletions(-) diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index b90d3abb5..02dee3566 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -41,17 +41,11 @@ #include "math/m_predict.h" +#include "vive_config.h" + // typically HMD config is available at around 2 seconds after init #define WAIT_TIMEOUT 5.0 -// public documentation -//! @todo move to vive_protocol -#define INDEX_MIN_IPD 0.058 -#define INDEX_MAX_IPD 0.07 - -#define DEFAULT_HAPTIC_FREQ 150.0f -#define MIN_HAPTIC_DURATION 0.05f - #define SURVIVE_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->sys->ll, __VA_ARGS__) #define SURVIVE_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->sys->ll, __VA_ARGS__) #define SURVIVE_INFO(d, ...) U_LOG_XDEV_IFL_I(&d->base, d->sys->ll, __VA_ARGS__) @@ -105,19 +99,6 @@ typedef enum static bool survive_already_initialized = false; -enum VIVE_VARIANT -{ - VIVE_UNKNOWN = 0, - VIVE_VARIANT_VIVE, - VIVE_VARIANT_PRO, - VIVE_VARIANT_VALVE_INDEX, - VIVE_VARIANT_HTC_VIVE_CONTROLLER, - VIVE_VARIANT_VALVE_INDEX_LEFT_CONTROLLER, - VIVE_VARIANT_VALVE_INDEX_RIGHT_CONTROLLER, - VIVE_VARIANT_TRACKER_V1, - VIVE_VARIANT_TRACKER_v2 -}; - /*! * @implements xrt_device */ @@ -131,14 +112,15 @@ struct survive_device int num; - enum VIVE_VARIANT variant; union { struct { float proximity; // [0,1] float ipd; - struct xrt_quat rot[2]; + + enum VIVE_VARIANT variant; + struct vive_config config; } hmd; struct @@ -146,9 +128,11 @@ struct survive_device float curl[XRT_FINGER_COUNT]; uint64_t curl_ts[XRT_FINGER_COUNT]; struct u_hand_tracking hand_tracking; + + enum VIVE_CONTROLLER_VARIANT variant; + struct vive_controller_config config; } ctrl; }; - struct u_vive_values distortion[2]; }; //! @todo support more devices (trackers, ...) @@ -447,7 +431,7 @@ survive_controller_get_hand_tracking(struct xrt_device *xdev, } - bool left = survive->variant == VIVE_VARIANT_VALVE_INDEX_LEFT_CONTROLLER; + bool left = survive->ctrl.variant == CONTROLLER_INDEX_LEFT; enum xrt_hand hand = left ? XRT_HAND_LEFT : XRT_HAND_RIGHT; float thumb_curl = 0.0f; @@ -489,7 +473,7 @@ survive_device_get_view_pose(struct xrt_device *xdev, bool adjust = view_index == 0; struct survive_device *survive = (struct survive_device *)xdev; - pose.orientation = survive->hmd.rot[view_index]; + pose.orientation = survive->hmd.config.display.rot[view_index]; pose.position.x = eye_relation->x / 2.0f; pose.position.y = eye_relation->y / 2.0f; pose.position.z = eye_relation->z / 2.0f; @@ -831,130 +815,11 @@ wait_for_device_config(const struct SurviveSimpleObject *sso) return false; } -void -print_vec3(const char *title, struct xrt_vec3 *vec) -{ - U_LOG_D("%s = %f %f %f", title, (double)vec->x, (double)vec->y, (double)vec->z); -} - -static long long -_json_to_int(const cJSON *item) -{ - if (item != NULL) { - return item->valueint; - } else { - return 0; - } -} - -static bool -_json_get_matrix_3x3(const cJSON *json, const char *name, struct xrt_matrix_3x3 *result) -{ - const cJSON *vec3_arr = cJSON_GetObjectItemCaseSensitive(json, name); - - // Some sanity checking. - if (vec3_arr == NULL || cJSON_GetArraySize(vec3_arr) != 3) { - return false; - } - - size_t total = 0; - const cJSON *vec = NULL; - cJSON_ArrayForEach(vec, vec3_arr) - { - assert(cJSON_GetArraySize(vec) == 3); - const cJSON *elem = NULL; - cJSON_ArrayForEach(elem, vec) - { - // Just in case. - if (total >= 9) { - break; - } - - assert(cJSON_IsNumber(elem)); - result->v[total++] = (float)elem->valuedouble; - } - } - - return true; -} - -static float -_json_get_float(const cJSON *json, const char *name) -{ - const cJSON *item = cJSON_GetObjectItemCaseSensitive(json, name); - return (float)item->valuedouble; -} - -static long long -_json_get_int(const cJSON *json, const char *name) -{ - const cJSON *item = cJSON_GetObjectItemCaseSensitive(json, name); - return _json_to_int(item); -} - -static void -_get_color_coeffs(struct u_vive_values *values, const cJSON *coeffs, uint8_t eye, uint8_t channel) -{ - // For Vive this is 8 with only 3 populated. - // For Index this is 4 with all values populated. - const cJSON *item = NULL; - size_t i = 0; - cJSON_ArrayForEach(item, coeffs) - { - values->coefficients[channel][i] = (float)item->valuedouble; - ++i; - if (i == 4) { - break; - } - } -} - -static void -get_distortion_properties(struct survive_device *d, const cJSON *eye_transform_json, uint8_t eye) -{ - const cJSON *eye_json = cJSON_GetArrayItem(eye_transform_json, eye); - if (eye_json == NULL) { - return; - } - - struct xrt_matrix_3x3 rot = {0}; - if (_json_get_matrix_3x3(eye_json, "eye_to_head", &rot)) { - math_quat_from_matrix_3x3(&rot, &d->hmd.rot[eye]); - } - - // TODO: store grow_for_undistort per eye - // clang-format off - d->distortion[eye].grow_for_undistort = _json_get_float(eye_json, "grow_for_undistort"); - d->distortion[eye].undistort_r2_cutoff = _json_get_float(eye_json, "undistort_r2_cutoff"); - // clang-format on - - const char *names[3] = { - "distortion_red", - "distortion", - "distortion_blue", - }; - - for (int i = 0; i < 3; i++) { - const cJSON *distortion = cJSON_GetObjectItemCaseSensitive(eye_json, names[i]); - if (distortion == NULL) { - continue; - } - - d->distortion[eye].center[i].x = _json_get_float(distortion, "center_x"); - d->distortion[eye].center[i].y = _json_get_float(distortion, "center_y"); - - const cJSON *coeffs = cJSON_GetObjectItemCaseSensitive(distortion, "coeffs"); - if (coeffs != NULL) { - _get_color_coeffs(&d->distortion[eye], coeffs, eye, i); - } - } -} - static bool compute_distortion(struct xrt_device *xdev, int view, float u, float v, struct xrt_uv_triplet *result) { struct survive_device *d = (struct survive_device *)xdev; - return u_compute_distortion_vive(&d->distortion[view], u, v, result); + return u_compute_distortion_vive(&d->hmd.config.distortion[view], u, v, result); } static bool @@ -965,10 +830,11 @@ _create_hmd_device(struct survive_system *sys, enum VIVE_VARIANT variant, const int outputs = 0; struct survive_device *survive = U_DEVICE_ALLOCATE(struct survive_device, flags, inputs, outputs); + sys->hmd = survive; survive->sys = sys; survive->survive_obj = sso; - survive->variant = variant; + survive->hmd.variant = variant; survive->base.name = XRT_DEVICE_GENERIC_HMD; snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive HMD"); @@ -983,78 +849,39 @@ _create_hmd_device(struct survive_system *sys, enum VIVE_VARIANT variant, const survive->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; char *json_string = survive_get_json_config(survive->survive_obj); - cJSON *json = cJSON_Parse(json_string); - if (!cJSON_IsObject(json)) { - SURVIVE_ERROR(survive, "Could not parse JSON data."); - return false; - } + survive->hmd.config.ll = survive->sys->ll; + // usb connected HMD variant is known because of USB id, config parsing relies on it. + survive->hmd.config.variant = survive->hmd.variant; + vive_config_parse(&survive->hmd.config, json_string); // TODO: Replace hard coded values from OpenHMD with config double w_meters = 0.122822 / 2.0; double h_meters = 0.068234; double lens_horizontal_separation = 0.057863; double eye_to_screen_distance = 0.023226876441867737; - if (survive->variant == VIVE_VARIANT_VALVE_INDEX) { - lens_horizontal_separation = 0.06; - h_meters = 0.07; - // eye relief knob adjusts this around [0.0255(near)-0.275(far)] - eye_to_screen_distance = 0.0255; - } + uint32_t w_pixels = survive->hmd.config.display.eye_target_width_in_pixels; + uint32_t h_pixels = survive->hmd.config.display.eye_target_height_in_pixels; - double fov = 2 * atan2(w_meters - lens_horizontal_separation / 2.0, eye_to_screen_distance); - - for (int view = 0; view < 2; view++) { - survive->distortion[view].aspect_x_over_y = 0.89999997615814209f; - survive->distortion[view].grow_for_undistort = 0.5f; - survive->distortion[view].undistort_r2_cutoff = 1.0f; - } - - survive->hmd.rot[0].w = 1.0f; - survive->hmd.rot[1].w = 1.0f; - - //! @todo: use IPD for FOV - survive->hmd.ipd = 0.063; - survive->hmd.proximity = 0; - - uint16_t w_pixels = 1080; - uint16_t h_pixels = 1200; - const cJSON *device_json = cJSON_GetObjectItemCaseSensitive(json, "device"); - if (device_json) { - if (survive->variant != VIVE_VARIANT_VALVE_INDEX) { - survive->distortion[0].aspect_x_over_y = - _json_get_float(device_json, "physical_aspect_x_over_y"); - survive->distortion[1].aspect_x_over_y = survive->distortion[0].aspect_x_over_y; - - //! @todo: fov calculation needs to be fixed, only works - //! with hardcoded value - // lens_horizontal_separation = _json_get_double(json, - // "lens_separation"); - } - h_pixels = (uint16_t)_json_get_int(device_json, "eye_target_height_in_pixels"); - w_pixels = (uint16_t)_json_get_int(device_json, "eye_target_width_in_pixels"); - } - - const cJSON *eye_transform_json = cJSON_GetObjectItemCaseSensitive(json, "tracking_to_eye_transform"); - if (eye_transform_json) { - for (uint8_t eye = 0; eye < 2; eye++) { - get_distortion_properties(survive, eye_transform_json, eye); - } - } - - SURVIVE_INFO(survive, "Survive eye resolution %dx%d", w_pixels, h_pixels); - - cJSON_Delete(json); + SURVIVE_DEBUG(survive, "display: %dx%d", w_pixels, h_pixels); // Main display. survive->base.hmd->screens[0].w_pixels = (int)w_pixels * 2; survive->base.hmd->screens[0].h_pixels = (int)h_pixels; - if (survive->variant == VIVE_VARIANT_VALVE_INDEX) + if (survive->hmd.variant == VIVE_VARIANT_INDEX) { + lens_horizontal_separation = 0.06; + h_meters = 0.07; + // eye relief knob adjusts this around [0.0255(near)-0.275(far)] + eye_to_screen_distance = 0.0255; + survive->base.hmd->screens[0].nominal_frame_interval_ns = (uint64_t)time_s_to_ns(1.0f / 144.0f); - else + } else { survive->base.hmd->screens[0].nominal_frame_interval_ns = (uint64_t)time_s_to_ns(1.0f / 90.0f); + } + + double fov = 2 * atan2(w_meters - lens_horizontal_separation / 2.0, eye_to_screen_distance); struct xrt_vec2 lens_center[2]; @@ -1160,43 +987,54 @@ static struct xrt_binding_profile binding_profiles_vive[1] = { } while (0) static bool -_create_controller_device(struct survive_system *sys, const SurviveSimpleObject *sso, enum VIVE_VARIANT variant) +_create_controller_device(struct survive_system *sys, + const SurviveSimpleObject *sso, + struct vive_controller_config *config) { + enum VIVE_CONTROLLER_VARIANT variant = config->variant; + + int idx = -1; + if (variant == CONTROLLER_VIVE_WAND) { + if (sys->controllers[SURVIVE_LEFT_CONTROLLER] == NULL) { + idx = SURVIVE_LEFT_CONTROLLER; + } else if (sys->controllers[SURVIVE_RIGHT_CONTROLLER] == NULL) { + idx = SURVIVE_RIGHT_CONTROLLER; + } else { + U_LOG_IFL_E(sys->ll, "Only creating 2 controllers!"); + return false; + } + } else if (variant == CONTROLLER_INDEX_LEFT) { + if (sys->controllers[SURVIVE_LEFT_CONTROLLER] == NULL) { + idx = SURVIVE_LEFT_CONTROLLER; + } else { + U_LOG_IFL_E(sys->ll, "Only creating 1 left controller!"); + return false; + } + } else if (variant == CONTROLLER_INDEX_RIGHT) { + if (sys->controllers[SURVIVE_RIGHT_CONTROLLER] == NULL) { + idx = SURVIVE_RIGHT_CONTROLLER; + } else { + U_LOG_IFL_E(sys->ll, "Only creating 1 right controller!"); + return false; + } + } + + if (idx == -1) { + U_LOG_IFL_E(sys->ll, "Skipping survive device we couldn't assign: %s!", config->firmware.model_number); + return false; + } + enum u_device_alloc_flags flags = 0; int inputs = VIVE_CONTROLLER_MAX_INDEX; int outputs = 1; struct survive_device *survive = U_DEVICE_ALLOCATE(struct survive_device, flags, inputs, outputs); + survive->ctrl.config = *config; - int idx = -1; - if (variant == VIVE_VARIANT_HTC_VIVE_CONTROLLER) { - if (sys->controllers[SURVIVE_LEFT_CONTROLLER] == NULL) { - idx = SURVIVE_LEFT_CONTROLLER; - } else if (sys->controllers[SURVIVE_RIGHT_CONTROLLER] == NULL) { - idx = SURVIVE_RIGHT_CONTROLLER; - } else { - SURVIVE_ERROR(survive, "Only creating 2 controllers!"); - return false; - } - } else if (variant == VIVE_VARIANT_VALVE_INDEX_LEFT_CONTROLLER) { - if (sys->controllers[SURVIVE_LEFT_CONTROLLER] == NULL) { - idx = SURVIVE_LEFT_CONTROLLER; - } else { - SURVIVE_ERROR(survive, "Only creating 1 left controller!"); - return false; - } - } else if (variant == VIVE_VARIANT_VALVE_INDEX_RIGHT_CONTROLLER) { - if (sys->controllers[SURVIVE_RIGHT_CONTROLLER] == NULL) { - idx = SURVIVE_RIGHT_CONTROLLER; - } else { - SURVIVE_ERROR(survive, "Only creating 1 right controller!"); - return false; - } - } sys->controllers[idx] = survive; survive->sys = sys; - survive->variant = variant; + survive->ctrl.variant = variant; survive->survive_obj = sso; survive->num = idx; @@ -1209,8 +1047,7 @@ _create_controller_device(struct survive_system *sys, const SurviveSimpleObject //! @todo: May use Vive Wands + Index HMDs or Index Controllers + Vive //! HMD - if (variant == VIVE_VARIANT_VALVE_INDEX_LEFT_CONTROLLER || - variant == VIVE_VARIANT_VALVE_INDEX_RIGHT_CONTROLLER) { + if (variant == CONTROLLER_INDEX_LEFT || variant == CONTROLLER_INDEX_RIGHT) { survive->base.name = XRT_DEVICE_INDEX_CONTROLLER; snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Valve Index Controller %d", idx); @@ -1236,10 +1073,10 @@ _create_controller_device(struct survive_system *sys, const SurviveSimpleObject SET_INDEX_INPUT(AIM_POSE, AIM_POSE); SET_INDEX_INPUT(GRIP_POSE, GRIP_POSE); - if (variant == VIVE_VARIANT_VALVE_INDEX_LEFT_CONTROLLER) { + if (variant == CONTROLLER_INDEX_LEFT) { survive->base.device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; survive->base.inputs[VIVE_CONTROLLER_HAND_TRACKING].name = XRT_INPUT_GENERIC_HAND_TRACKING_LEFT; - } else if (variant == VIVE_VARIANT_VALVE_INDEX_RIGHT_CONTROLLER) { + } else if (variant == CONTROLLER_INDEX_RIGHT) { survive->base.device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER; survive->base.inputs[VIVE_CONTROLLER_HAND_TRACKING].name = XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT; @@ -1260,7 +1097,7 @@ _create_controller_device(struct survive_system *sys, const SurviveSimpleObject survive->base.hand_tracking_supported = true; - } else if (survive->variant == VIVE_VARIANT_HTC_VIVE_CONTROLLER) { + } else if (survive->ctrl.variant == CONTROLLER_VIVE_WAND) { survive->base.name = XRT_DEVICE_VIVE_WAND; snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Vive Wand Controller %d", idx); @@ -1300,50 +1137,11 @@ _product_to_variant(uint16_t product_id) switch (product_id) { case VIVE_PID: return VIVE_VARIANT_VIVE; case VIVE_PRO_MAINBOARD_PID: return VIVE_VARIANT_PRO; - case VIVE_PRO_LHR_PID: return VIVE_VARIANT_VALVE_INDEX; + case VIVE_PRO_LHR_PID: return VIVE_VARIANT_INDEX; default: U_LOG_W("No product ids matched %.4x", product_id); return VIVE_UNKNOWN; } } -#define JSON_STRING(a, b, c) u_json_get_string_into_array(u_json_get(a, b), c, sizeof(c)) - -static enum VIVE_VARIANT -get_variant_from_json(struct survive_system *ss, cJSON *json) -{ - char model_number[32]; - - if (u_json_get(json, "model_number")) { - JSON_STRING(json, "model_number", model_number); - } else { - JSON_STRING(json, "model_name", model_number); - } - - enum VIVE_VARIANT variant = VIVE_UNKNOWN; - - if (strcmp(model_number, "Vive. Controller MV") == 0) { - variant = VIVE_VARIANT_HTC_VIVE_CONTROLLER; - U_LOG_D("Found Vive Wand controller"); - } else if (strcmp(model_number, "Knuckles Right") == 0) { - variant = VIVE_VARIANT_VALVE_INDEX_RIGHT_CONTROLLER; - U_LOG_D("Found Knuckles Right controller"); - } else if (strcmp(model_number, "Knuckles Left") == 0) { - variant = VIVE_VARIANT_VALVE_INDEX_LEFT_CONTROLLER; - U_LOG_D("Found Knuckles Left controller"); - } else if (strcmp(model_number, "Vive Tracker PVT") == 0) { - variant = VIVE_VARIANT_TRACKER_V1; - U_LOG_D("Found Gen 1 tracker."); - } else if (strcmp(model_number, "VIVE Tracker Pro MV") == 0) { - variant = VIVE_VARIANT_TRACKER_v2; - U_LOG_D("Found Gen 2 tracker."); - } else if (strcmp(model_number, "Utah MP") == 0) { - U_LOG_W("Found Utah MP (Index HMD), not a controller!"); - } else { - U_LOG_E("Failed to parse controller variant: %s", model_number); - } - - return variant; -} - int survive_found(struct xrt_prober *xp, struct xrt_prober_device **devices, @@ -1414,28 +1212,22 @@ survive_found(struct xrt_prober *xp, _create_hmd_device(ss, variant, it); } else if (type == SurviveSimpleObject_OBJECT) { char *json_string = survive_get_json_config(it); - cJSON *json = cJSON_Parse(json_string); - if (!cJSON_IsObject(json)) { - U_LOG_IFL_E(ss->ll, "Could not parse JSON data."); - cJSON_Delete(json); - continue; - } - enum VIVE_VARIANT variant = get_variant_from_json(ss, json); + struct vive_controller_config config = {.ll = ss->ll}; + vive_config_parse_controller(&config, json_string); - switch (variant) { - case VIVE_VARIANT_HTC_VIVE_CONTROLLER: - case VIVE_VARIANT_VALVE_INDEX_LEFT_CONTROLLER: - case VIVE_VARIANT_VALVE_INDEX_RIGHT_CONTROLLER: + switch (config.variant) { + case CONTROLLER_VIVE_WAND: + case CONTROLLER_INDEX_LEFT: + case CONTROLLER_INDEX_RIGHT: U_LOG_IFL_D(ss->ll, "Adding controller."); - _create_controller_device(ss, it, variant); + _create_controller_device(ss, it, &config); break; default: U_LOG_IFL_D(ss->ll, "Skip non controller obj."); U_LOG_IFL_T(ss->ll, "json: %s", json_string); break; } - cJSON_Delete(json); } else { U_LOG_IFL_D(ss->ll, "Skip non OBJECT obj."); } diff --git a/src/xrt/drivers/vive/vive_config.c b/src/xrt/drivers/vive/vive_config.c index 65e54f7bd..dfd0440b3 100644 --- a/src/xrt/drivers/vive/vive_config.c +++ b/src/xrt/drivers/vive/vive_config.c @@ -176,9 +176,38 @@ _print_vec3(const char *title, struct xrt_vec3 *vec) U_LOG_D("%s = %f %f %f", title, (double)vec->x, (double)vec->y, (double)vec->z); } +static void +vive_init_defaults(struct vive_config *d) +{ + d->display.eye_target_width_in_pixels = 1080; + d->display.eye_target_height_in_pixels = 1200; + + d->display.rot[0].w = 1.0f; + d->display.rot[1].w = 1.0f; + + d->imu.gyro_range = 8.726646f; + d->imu.acc_range = 39.226600f; + + d->imu.acc_scale.x = 1.0f; + d->imu.acc_scale.y = 1.0f; + d->imu.acc_scale.z = 1.0f; + + d->imu.gyro_scale.x = 1.0f; + d->imu.gyro_scale.y = 1.0f; + d->imu.gyro_scale.z = 1.0f; + + for (int view = 0; view < 2; view++) { + d->distortion[view].aspect_x_over_y = 0.89999997615814209f; + d->distortion[view].grow_for_undistort = 0.5f; + d->distortion[view].undistort_r2_cutoff = 1.0f; + } +} + bool vive_config_parse(struct vive_config *d, char *json_string) { + vive_init_defaults(d); + VIVE_DEBUG(d, "JSON config:\n%s", json_string); cJSON *json = cJSON_Parse(json_string); diff --git a/src/xrt/drivers/vive/vive_config.h b/src/xrt/drivers/vive/vive_config.h index 49add8b64..584b75863 100644 --- a/src/xrt/drivers/vive/vive_config.h +++ b/src/xrt/drivers/vive/vive_config.h @@ -15,6 +15,14 @@ #include "util/u_logging.h" #include "util/u_distortion_mesh.h" +// public documentation +#define INDEX_MIN_IPD 0.058 +#define INDEX_MAX_IPD 0.07 + +// arbitrary default values +#define DEFAULT_HAPTIC_FREQ 150.0f +#define MIN_HAPTIC_DURATION 0.05f + enum VIVE_VARIANT { VIVE_UNKNOWN = 0, diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index 939ff2194..9d6a7d76e 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -716,36 +716,6 @@ vive_sensors_run_thread(void *ptr) return NULL; } -void -vive_init_defaults(struct vive_device *d) -{ - d->config.display.eye_target_width_in_pixels = 1080; - d->config.display.eye_target_height_in_pixels = 1200; - - d->config.display.rot[0].w = 1.0f; - d->config.display.rot[1].w = 1.0f; - - d->config.imu.gyro_range = 8.726646f; - d->config.imu.acc_range = 39.226600f; - - d->config.imu.acc_scale.x = 1.0f; - d->config.imu.acc_scale.y = 1.0f; - d->config.imu.acc_scale.z = 1.0f; - - d->config.imu.gyro_scale.x = 1.0f; - d->config.imu.gyro_scale.y = 1.0f; - d->config.imu.gyro_scale.z = 1.0f; - - d->rot_filtered.w = 1.0f; - - for (int view = 0; view < 2; view++) { - d->config.distortion[view].aspect_x_over_y = 0.89999997615814209f; - d->config.distortion[view].grow_for_undistort = 0.5f; - d->config.distortion[view].undistort_r2_cutoff = 1.0f; - } -} - - static bool compute_distortion(struct xrt_device *xdev, int view, float u, float v, struct xrt_uv_triplet *result) { @@ -780,8 +750,6 @@ vive_device_create(struct os_hid_device *mainboard_dev, d->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_COMPUTE; d->base.compute_distortion = compute_distortion; - vive_init_defaults(d); - switch (variant) { case VIVE_VARIANT_VIVE: snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "HTC Vive"); break; case VIVE_VARIANT_PRO: snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "HTC Vive Pro"); break; From bec70c476c0e2687671ed2249378ec2d3426ee5d Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 28 Jan 2021 16:37:41 +0100 Subject: [PATCH 008/883] doc: Add changelog for MR 674 --- doc/changes/drivers/mr.674.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/drivers/mr.674.md diff --git a/doc/changes/drivers/mr.674.md b/doc/changes/drivers/mr.674.md new file mode 100644 index 000000000..93b361979 --- /dev/null +++ b/doc/changes/drivers/mr.674.md @@ -0,0 +1 @@ +vive: Factor out json config parser and reuse it in survive driver. From 58531038204740f2a0c98fee178c371256f07ab2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 1 Feb 2021 15:39:44 +0000 Subject: [PATCH 009/883] d/vive: Refactor out vive config code into auxiliary library fix vive_config.h include for survive --- src/xrt/auxiliary/CMakeLists.txt | 11 ++++++++ src/xrt/auxiliary/meson.build | 20 ++++++++++++- .../{drivers => auxiliary}/vive/vive_config.c | 10 +++++-- .../{drivers => auxiliary}/vive/vive_config.h | 0 src/xrt/drivers/CMakeLists.txt | 28 ++----------------- src/xrt/drivers/meson.build | 25 +++-------------- src/xrt/drivers/survive/survive_driver.c | 2 +- src/xrt/drivers/vive/vive_controller.c | 2 +- src/xrt/drivers/vive/vive_controller.h | 3 +- src/xrt/drivers/vive/vive_device.h | 2 +- 10 files changed, 48 insertions(+), 55 deletions(-) rename src/xrt/{drivers => auxiliary}/vive/vive_config.c (97%) rename src/xrt/{drivers => auxiliary}/vive/vive_config.h (100%) diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index 56f1f7875..3edac2547 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -234,6 +234,17 @@ if(XRT_HAVE_OPENCV) target_link_libraries(aux_tracking PUBLIC ${OpenCV_LIBRARIES}) endif() +if (XRT_BUILD_DRIVER_VIVE OR XRT_BUILD_DRIVER_SURVIVE) + set(VIVE_CONFIG_SOURCE_FILES + vive/vive_config.h + vive/vive_config.c + ) + add_library(aux_vive STATIC ${VIVE_CONFIG_SOURCE_FILES}) + target_link_libraries(aux_vive PRIVATE xrt-interfaces aux_util aux_math xrt-external-cjson) + target_link_libraries(aux_vive PRIVATE ${ZLIB_LIBRARIES}) + target_include_directories(aux_vive PRIVATE ${ZLIB_INCLUDE_DIRS}) +endif() + if(XRT_HAVE_VULKAN) # Vulkan library. add_library(aux_vk STATIC ${VK_SOURCE_FILES}) diff --git a/src/xrt/auxiliary/meson.build b/src/xrt/auxiliary/meson.build index 2ced9ea8e..5b7a0e940 100644 --- a/src/xrt/auxiliary/meson.build +++ b/src/xrt/auxiliary/meson.build @@ -217,6 +217,24 @@ aux_tracking = declare_dependency( link_with: lib_aux_tracking, ) +lib_aux_vive = static_library( + 'aux_vive', + files( + 'vive/vive_config.c', + 'vive/vive_config.h', + ), + include_directories: [ + xrt_include, + cjson_include, + ], + dependencies: [zlib], +) + +aux_vive = declare_dependency( + include_directories: aux_include, + link_with: lib_aux_vive, +) + lib_aux_vk = static_library( 'aux_vk', files( @@ -237,6 +255,6 @@ aux_vk = declare_dependency( ) -all_aux = [aux_util, aux_os, aux_math, aux_tracking, aux_generated_bindings] +all_aux = [aux_util, aux_os, aux_math, aux_tracking, aux_generated_bindings, aux_vive] aux = declare_dependency(dependencies: all_aux) diff --git a/src/xrt/drivers/vive/vive_config.c b/src/xrt/auxiliary/vive/vive_config.c similarity index 97% rename from src/xrt/drivers/vive/vive_config.c rename to src/xrt/auxiliary/vive/vive_config.c index dfd0440b3..5b203f288 100644 --- a/src/xrt/drivers/vive/vive_config.c +++ b/src/xrt/auxiliary/vive/vive_config.c @@ -11,14 +11,18 @@ #include "vive_config.h" +#include "util/u_misc.h" #include "util/u_json.h" #include "util/u_distortion_mesh.h" #include "math/m_api.h" -#include "vive.h" -#include "vive_device.h" -#include "vive_controller.h" + +#define VIVE_TRACE(d, ...) U_LOG_IFL_T(d->ll, __VA_ARGS__) +#define VIVE_DEBUG(d, ...) U_LOG_IFL_D(d->ll, __VA_ARGS__) +#define VIVE_INFO(d, ...) U_LOG_IFL_I(d->ll, __VA_ARGS__) +#define VIVE_WARN(d, ...) U_LOG_IFL_W(d->ll, __VA_ARGS__) +#define VIVE_ERROR(d, ...) U_LOG_IFL_E(d->ll, __VA_ARGS__) #define JSON_INT(a, b, c) u_json_get_int(u_json_get(a, b), c) #define JSON_FLOAT(a, b, c) u_json_get_float(u_json_get(a, b), c) diff --git a/src/xrt/drivers/vive/vive_config.h b/src/xrt/auxiliary/vive/vive_config.h similarity index 100% rename from src/xrt/drivers/vive/vive_config.h rename to src/xrt/auxiliary/vive/vive_config.h diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index 1f1916087..383c3f509 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -160,27 +160,6 @@ if(XRT_BUILD_DRIVER_REMOTE) list(APPEND ENABLED_HEADSET_DRIVERS remote) endif() -if (XRT_BUILD_DRIVER_VIVE OR XRT_BUILD_DRIVER_SURVIVE) - set(VIVE_CONFIG_SOURCE_FILES - vive/vive_device.h - vive/vive_device.c - vive/vive_prober.h - vive/vive_prober.c - vive/vive_protocol.c - vive/vive_protocol.h - vive/vive_controller.h - vive/vive_controller.c - vive/vive_config.h - vive/vive_config.c - vive/vive_lighthouse.h - vive/vive_lighthouse.c - ) - add_library(vive_config STATIC ${VIVE_CONFIG_SOURCE_FILES}) - target_link_libraries(vive_config PRIVATE xrt-interfaces aux_util aux_math xrt-external-cjson) - target_link_libraries(vive_config PRIVATE ${ZLIB_LIBRARIES}) - target_include_directories(vive_config PRIVATE ${ZLIB_INCLUDE_DIRS}) -endif() - set(VIVE_CONFIG_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/vive") if(XRT_BUILD_DRIVER_VIVE) set(VIVE_SOURCE_FILES @@ -197,9 +176,9 @@ if(XRT_BUILD_DRIVER_VIVE) ) add_library(drv_vive STATIC ${VIVE_SOURCE_FILES}) - target_link_libraries(drv_vive PRIVATE xrt-interfaces aux_os aux_util aux_math xrt-external-cjson vive_config) + target_link_libraries(drv_vive PRIVATE xrt-interfaces aux_os aux_util aux_math xrt-external-cjson aux_vive) target_link_libraries(drv_vive PRIVATE ${ZLIB_LIBRARIES}) - target_include_directories(drv_vive PRIVATE ${ZLIB_INCLUDE_DIRS} ${VIVE_CONFIG_INCLUDE}) + target_include_directories(drv_vive PRIVATE ${ZLIB_INCLUDE_DIRS}) list(APPEND ENABLED_HEADSET_DRIVERS vive) endif() @@ -234,8 +213,7 @@ if (XRT_BUILD_DRIVER_SURVIVE) ) add_library(drv_survive STATIC ${SURVIVE_SOURCE_FILES}) - target_include_directories(drv_survive PRIVATE ${VIVE_CONFIG_INCLUDE}) - target_link_libraries(drv_survive PRIVATE xrt-interfaces aux_os aux_util aux_math vive_config PkgConfig::SURVIVE) + target_link_libraries(drv_survive PRIVATE xrt-interfaces aux_os aux_util aux_math aux_vive PkgConfig::SURVIVE) list(APPEND ENABLED_HEADSET_DRIVERS survive) endif() diff --git a/src/xrt/drivers/meson.build b/src/xrt/drivers/meson.build index ff5eda7e1..5c47ea854 100644 --- a/src/xrt/drivers/meson.build +++ b/src/xrt/drivers/meson.build @@ -154,21 +154,6 @@ lib_drv_v4l2 = static_library( build_by_default: 'v4l2' in drivers, ) -vive_config_include = include_directories('vive') -lib_vive_config = static_library( - 'vive_config', - files( - 'vive/vive_config.c', - 'vive/vive_config.h', - ), - include_directories: [ - xrt_include, - cjson_include, - ], - dependencies: [aux, zlib], - build_by_default: 'vive' in drivers or 'survive' in drivers, -) - lib_drv_vive = static_library( 'drv_vive', files( @@ -185,12 +170,11 @@ lib_drv_vive = static_library( ), include_directories: [ xrt_include, + aux_include, cjson_include, - vive_config_include, ], - dependencies: [aux, zlib], + dependencies: [aux, zlib, aux_vive], build_by_default: 'vive' in drivers, - link_with: lib_vive_config ) lib_drv_survive = static_library( @@ -203,12 +187,11 @@ lib_drv_survive = static_library( ), include_directories: [ xrt_include, + aux_include, cjson_include, - vive_config_include, ], - dependencies: [aux, zlib, survive], + dependencies: [aux, zlib, survive, aux_vive], build_by_default: 'survive' in drivers, - link_with: lib_vive_config ) lib_drv_daydream = static_library( diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index 02dee3566..c58638d2d 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -41,7 +41,7 @@ #include "math/m_predict.h" -#include "vive_config.h" +#include "vive/vive_config.h" // typically HMD config is available at around 2 seconds after init #define WAIT_TIMEOUT 5.0 diff --git a/src/xrt/drivers/vive/vive_controller.c b/src/xrt/drivers/vive/vive_controller.c index 74539bc6c..8b35351b2 100644 --- a/src/xrt/drivers/vive/vive_controller.c +++ b/src/xrt/drivers/vive/vive_controller.c @@ -30,11 +30,11 @@ #include "os/os_hid.h" #include "os/os_threading.h" #include "os/os_time.h" +#include "vive/vive_config.h" #include "vive.h" #include "vive_protocol.h" #include "vive_controller.h" -#include "vive_config.h" #ifdef XRT_OS_LINUX #include diff --git a/src/xrt/drivers/vive/vive_controller.h b/src/xrt/drivers/vive/vive_controller.h index 4228c814c..abd027353 100644 --- a/src/xrt/drivers/vive/vive_controller.h +++ b/src/xrt/drivers/vive/vive_controller.h @@ -17,10 +17,9 @@ #include "os/os_threading.h" #include "math/m_imu_3dof.h" #include "util/u_logging.h" - #include "util/u_hand_tracking.h" +#include "vive/vive_config.h" -#include "vive_config.h" #ifdef __cplusplus extern "C" { diff --git a/src/xrt/drivers/vive/vive_device.h b/src/xrt/drivers/vive/vive_device.h index 09e95a6dd..a70194c48 100644 --- a/src/xrt/drivers/vive/vive_device.h +++ b/src/xrt/drivers/vive/vive_device.h @@ -14,9 +14,9 @@ #include "os/os_threading.h" #include "util/u_logging.h" #include "util/u_distortion_mesh.h" +#include "vive/vive_config.h" #include "vive_lighthouse.h" -#include "vive_config.h" #ifdef __cplusplus extern "C" { From 35da4a51ea688941211326a6b7063d9997055e18 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 1 Feb 2021 19:04:39 +0000 Subject: [PATCH 010/883] d/vf: Refactor code to add videotestsrc capability and break out gstreamer detection --- CMakeLists.txt | 5 +- src/xrt/drivers/CMakeLists.txt | 2 +- src/xrt/drivers/vf/vf_driver.c | 139 ++++++++++++------ src/xrt/drivers/vf/vf_interface.h | 17 ++- src/xrt/include/xrt/meson.build | 4 - .../include/xrt/xrt_config_have.h.cmake_in | 2 +- src/xrt/state_trackers/prober/p_prober.c | 6 +- src/xrt/targets/common/CMakeLists.txt | 2 +- 8 files changed, 113 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dcf94ab0..e639db3fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,7 +128,6 @@ cmake_dependent_option(XRT_HAVE_OPENGL "Enable OpenGL Graphics API support" ON " cmake_dependent_option(XRT_HAVE_OPENGLES "Enable OpenGL-ES Graphics API support" ON "OpenGLES_FOUND" OFF) cmake_dependent_option(XRT_HAVE_EGL "Enable OpenGL on EGL Graphics API support" ON "EGL_FOUND; XRT_HAVE_OPENGL OR XRT_HAVE_OPENGLES" OFF) cmake_dependent_option(XRT_HAVE_DBUS "Enable dbus support (for BLE support)" ON "DBUS_FOUND" OFF) -cmake_dependent_option(XRT_HAVE_VF "Enable gstreamer support (for video file support)" ON "GST_FOUND" OFF) cmake_dependent_option(XRT_FEATURE_COMPOSITOR_MAIN "Build main compositor host functionality" ON "XRT_HAVE_VULKAN; XRT_HAVE_WAYLAND OR XRT_HAVE_XCB OR ANDROID OR WIN32" OFF) cmake_dependent_option(XRT_FEATURE_OPENXR "Build OpenXR runtime target" ON "XRT_FEATURE_COMPOSITOR_MAIN" OFF) cmake_dependent_option(XRT_FEATURE_SERVICE "Enable separate service module for OpenXR runtime" ON "NOT WIN32" OFF) @@ -172,6 +171,7 @@ cmake_dependent_option(XRT_HAVE_LIBUVC "Enable libuvc video driver" ON "LIBUVC_F cmake_dependent_option(XRT_HAVE_FFMPEG "Enable ffmpeg testing video driver" ON "FFMPEG_FOUND" OFF) cmake_dependent_option(XRT_HAVE_SDL2 "Enable use of SDL2" ON "SDL2_FOUND AND XRT_HAVE_OPENGL" OFF) cmake_dependent_option(XRT_HAVE_SYSTEM_CJSON "Enable cJSON from system, instead of bundled source" ON "CJSON_FOUND" OFF) +cmake_dependent_option(XRT_HAVE_GST "Enable gstreamer" ON "GST_FOUND" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_PSVR "Enable PSVR HMD driver" ON "HIDAPI_FOUND" OFF) @@ -191,6 +191,7 @@ cmake_dependent_option(XRT_BUILD_DRIVER_HDK "Enable HDK driver" ON "XRT_HAVE_INT cmake_dependent_option(XRT_BUILD_DRIVER_PSMV "Enable Playstation Move driver" ON "XRT_HAVE_INTERNAL_HID" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_HYDRA "Enable Hydra driver" ON "XRT_HAVE_INTERNAL_HID" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_NS "Enable North Star driver" ON "XRT_HAVE_INTERNAL_HID" OFF) +cmake_dependent_option(XRT_BUILD_DRIVER_VF "Build video frame driver (for video file support, uses gstreamer)" ON "XRT_HAVE_GST" OFF) # This one defaults to off, even if we find the deps. cmake_dependent_option(XRT_BUILD_DRIVER_SURVIVE "Enable libsurvive driver" ON "SURVIVE_FOUND" OFF) @@ -216,6 +217,7 @@ list(APPEND AVAILABLE_DRIVERS "REMOTE" "SURVIVE" "V4L2" + "VF" "VIVE" ) @@ -348,5 +350,6 @@ message(STATUS "# DRIVER_PSVR: ${XRT_BUILD_DRIVER_PSVR}") message(STATUS "# DRIVER_RS: ${XRT_BUILD_DRIVER_RS}") message(STATUS "# DRIVER_REMOTE: ${XRT_BUILD_DRIVER_REMOTE}") message(STATUS "# DRIVER_SURVIVE: ${XRT_BUILD_DRIVER_SURVIVE}") +message(STATUS "# DRIVER_VF: ${XRT_BUILD_DRIVER_VF}") message(STATUS "# DRIVER_VIVE: ${XRT_BUILD_DRIVER_VIVE}") message(STATUS "#####----- Config -----#####") diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index 383c3f509..fb1f02c3c 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -192,7 +192,7 @@ if(XRT_HAVE_V4L2) list(APPEND ENABLED_DRIVERS v4l2) endif() -if(XRT_HAVE_VF) +if(XRT_BUILD_DRIVER_VF) set(VF_SOURCE_FILES vf/vf_driver.c ) diff --git a/src/xrt/drivers/vf/vf_driver.c b/src/xrt/drivers/vf/vf_driver.c index c5d9225c4..0210f8980 100644 --- a/src/xrt/drivers/vf/vf_driver.c +++ b/src/xrt/drivers/vf/vf_driver.c @@ -61,7 +61,6 @@ struct vf_fs struct os_thread_helper play_thread; - const char *path; GMainLoop *loop; GstElement *source; GstElement *testsink; @@ -280,7 +279,7 @@ on_new_sample_from_sink(GstElement *elt, struct vf_fs *vid) gst_structure_get_int(structure, "width", &width); gst_structure_get_int(structure, "height", &height); - VF_DEBUG(vid, "video size is %dx%d\n", width, height); + VF_DEBUG(vid, "video size is %dx%d", width, height); vid->got_sample = true; vid->width = width; vid->height = height; @@ -303,8 +302,8 @@ print_gst_error(GstMessage *message) gchar *dbg_info = NULL; gst_message_parse_error(message, &err, &dbg_info); - U_LOG_E("ERROR from element %s: %s\n", GST_OBJECT_NAME(message->src), err->message); - U_LOG_E("Debugging info: %s\n", (dbg_info) ? dbg_info : "none"); + U_LOG_E("ERROR from element %s: %s", GST_OBJECT_NAME(message->src), err->message); + U_LOG_E("Debugging info: %s", (dbg_info) ? dbg_info : "none"); g_error_free(err); g_free(dbg_info); } @@ -315,11 +314,11 @@ on_source_message(GstBus *bus, GstMessage *message, struct vf_fs *vid) /* nil */ switch (GST_MESSAGE_TYPE(message)) { case GST_MESSAGE_EOS: - VF_DEBUG(vid, "Finished playback\n"); + VF_DEBUG(vid, "Finished playback."); g_main_loop_quit(vid->loop); break; case GST_MESSAGE_ERROR: - VF_ERROR(vid, "Received error\n"); + VF_ERROR(vid, "Received error."); print_gst_error(message); g_main_loop_quit(vid->loop); break; @@ -333,9 +332,9 @@ run_play_thread(void *ptr) { struct vf_fs *vid = (struct vf_fs *)ptr; - VF_DEBUG(vid, "Let's run!\n"); + VF_DEBUG(vid, "Let's run!"); g_main_loop_run(vid->loop); - VF_DEBUG(vid, "Going out\n"); + VF_DEBUG(vid, "Going out!"); gst_object_unref(vid->testsink); gst_element_set_state(vid->source, GST_STATE_NULL); @@ -347,56 +346,35 @@ run_play_thread(void *ptr) return NULL; } -struct xrt_fs * -vf_fs_create(struct xrt_frame_context *xfctx, const char *path) +static struct xrt_fs * +alloc_and_init_common(struct xrt_frame_context *xfctx, // + enum xrt_format format, // + enum xrt_stereo_format stereo_format, // + gchar *pipeline_string) // { - if (path == NULL) { - U_LOG_E("No path given"); - return NULL; - } - - struct vf_fs *vid = U_TYPED_CALLOC(struct vf_fs); - vid->path = path; vid->got_sample = false; + vid->format = format; + vid->stereo_format = stereo_format; - gchar *loop = "false"; - - gchar *string = NULL; GstBus *bus = NULL; - - gst_init(0, NULL); - - if (!g_file_test(path, G_FILE_TEST_EXISTS)) { - VF_ERROR(vid, "File %s does not exist\n", path); + int ret = os_thread_helper_init(&vid->play_thread); + if (ret < 0) { + VF_ERROR(vid, "Failed to init thread"); + g_free(pipeline_string); + free(vid); return NULL; } vid->loop = g_main_loop_new(NULL, FALSE); + VF_DEBUG(vid, "Pipeline: %s", pipeline_string); -#if 0 - const gchar *caps = "video/x-raw,format=RGB"; - vid->format = XRT_FORMAT_R8G8B8; - vid->stereo_format = XRT_STEREO_FORMAT_SBS; -#endif - -#if 1 - const gchar *caps = "video/x-raw,format=YUY2"; - vid->format = XRT_FORMAT_YUYV422; - vid->stereo_format = XRT_STEREO_FORMAT_SBS; -#endif - - string = g_strdup_printf( - "multifilesrc location=\"%s\" loop=%s ! decodebin ! videoconvert ! " - "appsink caps=\"%s\" name=testsink", - path, loop, caps); - VF_DEBUG(vid, "Pipeline: %s\n", string); - vid->source = gst_parse_launch(string, NULL); - g_free(string); + vid->source = gst_parse_launch(pipeline_string, NULL); + g_free(pipeline_string); if (vid->source == NULL) { - VF_ERROR(vid, "Bad source\n"); + VF_ERROR(vid, "Bad source"); g_main_loop_unref(vid->loop); free(vid); return NULL; @@ -410,16 +388,21 @@ vf_fs_create(struct xrt_frame_context *xfctx, const char *path) gst_bus_add_watch(bus, (GstBusFunc)on_source_message, vid); gst_object_unref(bus); - int ret = os_thread_helper_start(&vid->play_thread, run_play_thread, vid); - if (!ret) { - VF_ERROR(vid, "Failed to start thread"); + ret = os_thread_helper_start(&vid->play_thread, run_play_thread, vid); + if (ret != 0) { + VF_ERROR(vid, "Failed to start thread '%i'", ret); + g_main_loop_unref(vid->loop); + free(vid); + return NULL; } - // we need one sample to determine frame size + // We need one sample to determine frame size. + VF_DEBUG(vid, "Waiting for frame"); gst_element_set_state(vid->source, GST_STATE_PLAYING); while (!vid->got_sample) { os_nanosleep(100 * 1000 * 1000); } + VF_DEBUG(vid, "Got first sample"); gst_element_set_state(vid->source, GST_STATE_PAUSED); vid->base.enumerate_modes = vf_fs_enumerate_modes; @@ -443,3 +426,61 @@ vf_fs_create(struct xrt_frame_context *xfctx, const char *path) return &(vid->base); } + +struct xrt_fs * +vf_fs_videotestsource(struct xrt_frame_context *xfctx, uint32_t width, uint32_t height) +{ + gst_init(0, NULL); + + enum xrt_format format = XRT_FORMAT_R8G8B8; + enum xrt_stereo_format stereo_format = XRT_STEREO_FORMAT_NONE; + + gchar *pipeline_string = g_strdup_printf( + "videotestsrc name=source ! " + "videoconvert ! " + "videoscale ! " + "video/x-raw,format=RGB,width=%u,height=%u ! " + "appsink name=testsink", + width, height); + + return alloc_and_init_common(xfctx, format, stereo_format, pipeline_string); +} + +struct xrt_fs * +vf_fs_open_file(struct xrt_frame_context *xfctx, const char *path) +{ + if (path == NULL) { + U_LOG_E("No path given"); + return NULL; + } + + gst_init(0, NULL); + + if (!g_file_test(path, G_FILE_TEST_EXISTS)) { + U_LOG_E("File %s does not exist", path); + return NULL; + } + +#if 0 + const gchar *caps = "video/x-raw,format=RGB"; + enum xrt_format format = XRT_FORMAT_R8G8B8; + enum xrt_stereo_format stereo_format = XRT_STEREO_FORMAT_NONE; +#endif + +#if 1 + const gchar *caps = "video/x-raw,format=YUY2"; + enum xrt_format format = XRT_FORMAT_YUYV422; + enum xrt_stereo_format stereo_format = XRT_STEREO_FORMAT_SBS; +#endif + + gchar *loop = "false"; + + gchar *pipeline_string = g_strdup_printf( + "multifilesrc location=\"%s\" loop=%s ! " + "decodebin ! " + "videoconvert ! " + "appsink caps=\"%s\" name=testsink", + path, loop, caps); + + return alloc_and_init_common(xfctx, format, stereo_format, pipeline_string); +} diff --git a/src/xrt/drivers/vf/vf_interface.h b/src/xrt/drivers/vf/vf_interface.h index 7919f83db..4f0ef1b2e 100644 --- a/src/xrt/drivers/vf/vf_interface.h +++ b/src/xrt/drivers/vf/vf_interface.h @@ -1,4 +1,4 @@ -// Copyright 2029, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -11,6 +11,7 @@ #include "xrt/xrt_frameserver.h" + #ifdef __cplusplus extern "C" { #endif @@ -23,14 +24,22 @@ extern "C" { */ /*! - * Create a vf frameserver + * Create a vf frameserver by opening a video file. * * @ingroup drv_vf */ struct xrt_fs * -vf_fs_create(struct xrt_frame_context *xfctx, const char *path); +vf_fs_open_file(struct xrt_frame_context *xfctx, const char *path); + +/*! + * Create a vf frameserver that uses the videotestsource. + * + * @ingroup drv_vf + */ +struct xrt_fs * +vf_fs_videotestsource(struct xrt_frame_context *xfctx, uint32_t width, uint32_t height); + #ifdef __cplusplus } - #endif diff --git a/src/xrt/include/xrt/meson.build b/src/xrt/include/xrt/meson.build index edb000a8f..4abefaa95 100644 --- a/src/xrt/include/xrt/meson.build +++ b/src/xrt/include/xrt/meson.build @@ -68,10 +68,6 @@ if has_v4l2_header and 'v4l2' in drivers have_conf.set('XRT_HAVE_V4L2', true) endif -if 'vf' in drivers - have_conf.set('XRT_HAVE_VF', true) -endif - if true have_conf.set('XRT_HAVE_VULKAN', true) endif diff --git a/src/xrt/include/xrt/xrt_config_have.h.cmake_in b/src/xrt/include/xrt/xrt_config_have.h.cmake_in index fa3637f68..e490a0f82 100644 --- a/src/xrt/include/xrt/xrt_config_have.h.cmake_in +++ b/src/xrt/include/xrt/xrt_config_have.h.cmake_in @@ -10,9 +10,9 @@ #pragma once #cmakedefine XRT_HAVE_DBUS -#cmakedefine XRT_HAVE_VF #cmakedefine XRT_HAVE_EGL #cmakedefine XRT_HAVE_FFMPEG +#cmakedefine XRT_HAVE_GST #cmakedefine XRT_HAVE_JPEG #cmakedefine XRT_HAVE_LIBUDEV #cmakedefine XRT_HAVE_LIBUSB diff --git a/src/xrt/state_trackers/prober/p_prober.c b/src/xrt/state_trackers/prober/p_prober.c index 1fc0f2455..76383e7e7 100644 --- a/src/xrt/state_trackers/prober/p_prober.c +++ b/src/xrt/state_trackers/prober/p_prober.c @@ -20,7 +20,7 @@ #include "v4l2/v4l2_interface.h" #endif -#ifdef XRT_HAVE_VF +#ifdef XRT_BUILD_DRIVER_VF #include "vf/vf_interface.h" #endif @@ -742,10 +742,10 @@ open_video_device(struct xrt_prober *xp, { XRT_MAYBE_UNUSED struct prober_device *pdev = (struct prober_device *)xpdev; -#if defined(XRT_HAVE_VF) +#if defined(XRT_BUILD_DRIVER_VF) const char *path = debug_get_option_vf_path(); if (path != NULL) { - struct xrt_fs *xfs = vf_fs_create(xfctx, path); + struct xrt_fs *xfs = vf_fs_open_file(xfctx, path); if (xfs) { *out_xfs = xfs; return 0; diff --git a/src/xrt/targets/common/CMakeLists.txt b/src/xrt/targets/common/CMakeLists.txt index a44fa9027..0bdd0e997 100644 --- a/src/xrt/targets/common/CMakeLists.txt +++ b/src/xrt/targets/common/CMakeLists.txt @@ -72,7 +72,7 @@ if(XRT_HAVE_V4L2) target_link_libraries(target_lists PRIVATE drv_v4l2) endif() -if(XRT_HAVE_VF) +if(XRT_BUILD_DRIVER_VF) target_link_libraries(target_lists PRIVATE drv_vf) endif() From f8941fe5ee9c7021c399c0f0496d0bea9911627f Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 1 Feb 2021 20:05:42 +0000 Subject: [PATCH 011/883] d/vf: Declare dependency to avoid build issues --- src/xrt/drivers/meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xrt/drivers/meson.build b/src/xrt/drivers/meson.build index 5c47ea854..e50807f40 100644 --- a/src/xrt/drivers/meson.build +++ b/src/xrt/drivers/meson.build @@ -144,6 +144,11 @@ lib_drv_vf = static_library( build_by_default: 'vf' in drivers, ) +drv_vf = declare_dependency( + include_directories: drv_include, + link_with: lib_drv_vf, +) + lib_drv_v4l2 = static_library( 'drv_v4l2', files( From 2fcce7380f08fad53fed4a75cbb488836d337ee4 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 3 Feb 2021 00:19:15 +0100 Subject: [PATCH 012/883] build/cmake: Don't use PythonInterp on old cmake It literally does not work to find python 3. https://cmake.org/cmake/help/latest/module/FindPythonInterp.html > Note > A call to find_package(PythonInterp ${V}) for python version V may find a python executable > with no version suffix. In this case no attempt is made to avoid python executables from other > versions. Use FindPython3, FindPython2 or FindPython instead. Fixes build on Ubuntu 18.04 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e639db3fc..5965db999 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,7 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.12) find_package(Python3 REQUIRED Interpreter) set(PYTHON_EXECUTABLE Python3::Interpreter) else() - find_package(PythonInterp REQUIRED VERSION 3) + find_program(PYTHON_EXECUTABLE python3) if(PYTHON_EXECUTABLE MATCHES "WindowsApps") # If you hit this error, you will have to install Python 3 or try harder to tell CMake where it is. message(FATAL_ERROR "Found WindowsApps alias for Python. Make sure Python3 is installed, then choose 'Manage App Execution Aliases' in Start and disable the aliases for Python.") From 00ef7243922b85f997d570103d4b1a0a745533c0 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 3 Feb 2021 01:32:16 +0100 Subject: [PATCH 013/883] aux/vk: Add trace info when memory type is unsupported --- src/xrt/auxiliary/vk/vk_helpers.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/vk/vk_helpers.c b/src/xrt/auxiliary/vk/vk_helpers.c index 35820fb98..06e3273f5 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.c +++ b/src/xrt/auxiliary/vk/vk_helpers.c @@ -170,19 +170,33 @@ bool vk_get_memory_type(struct vk_bundle *vk, uint32_t type_bits, VkMemoryPropertyFlags memory_props, uint32_t *out_type_id) { + uint32_t i_supported = type_bits; for (uint32_t i = 0; i < vk->device_memory_props.memoryTypeCount; i++) { uint32_t propertyFlags = vk->device_memory_props.memoryTypes[i].propertyFlags; - if ((type_bits & 1) == 1) { + if ((i_supported & 1) == 1) { if ((propertyFlags & memory_props) == memory_props) { *out_type_id = i; return true; } } - type_bits >>= 1; + i_supported >>= 1; } VK_DEBUG(vk, "Could not find memory type!"); + VK_TRACE(vk, "Requested flags: %d (type bits %d with %d memory types)", memory_props, type_bits, + vk->device_memory_props.memoryTypeCount); + + i_supported = type_bits; + VK_TRACE(vk, "Supported flags:"); + for (uint32_t i = 0; i < vk->device_memory_props.memoryTypeCount; i++) { + uint32_t propertyFlags = vk->device_memory_props.memoryTypes[i].propertyFlags; + if ((i_supported & 1) == 1) { + VK_TRACE(vk, " %d", propertyFlags); + } + i_supported >>= 1; + } + return false; } From f5abb144223a38b034f9f644261c8ee1dd7d142b Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 3 Feb 2021 02:24:35 +0100 Subject: [PATCH 014/883] comp: Don't allocate ubos with VK_MEMORY_PROPERTY_HOST_CACHED_BIT On Tegra the only supported combinations for VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT are * VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT * VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT * VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT This article agrees that we do not need host cached memory here: https://zeux.io/2020/02/27/writing-an-efficient-vulkan-renderer/ --- src/xrt/compositor/main/comp_layer.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/xrt/compositor/main/comp_layer.c b/src/xrt/compositor/main/comp_layer.c index 83e82fe84..bb57ca70f 100644 --- a/src/xrt/compositor/main/comp_layer.c +++ b/src/xrt/compositor/main/comp_layer.c @@ -52,8 +52,7 @@ static bool _init_ubos(struct comp_render_layer *self) { VkBufferUsageFlags usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; for (uint32_t i = 0; i < 2; i++) { math_matrix_4x4_identity(&self->transformation[i].mvp); @@ -77,8 +76,7 @@ static bool _init_equirect1_ubo(struct comp_render_layer *self) { VkBufferUsageFlags usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; if (!vk_buffer_init(self->vk, sizeof(struct layer_transformation), usage, properties, &self->equirect1_ubo.handle, &self->equirect1_ubo.memory)) @@ -98,8 +96,7 @@ static bool _init_equirect2_ubo(struct comp_render_layer *self) { VkBufferUsageFlags usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; if (!vk_buffer_init(self->vk, sizeof(struct layer_transformation), usage, properties, &self->equirect2_ubo.handle, &self->equirect2_ubo.memory)) From 850cb96e872a34a76f77546ddfeee41a9fb8419b Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 3 Feb 2021 02:44:17 +0100 Subject: [PATCH 015/883] doc: Add mr 677 changelog --- doc/changes/compositor/mr.677.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/compositor/mr.677.md diff --git a/doc/changes/compositor/mr.677.md b/doc/changes/compositor/mr.677.md new file mode 100644 index 000000000..d73ea57ba --- /dev/null +++ b/doc/changes/compositor/mr.677.md @@ -0,0 +1 @@ +comp: Fix layer submission on nvidia tegra. From 6e6a7291238e545ed0c825a776626bf9dc8beba0 Mon Sep 17 00:00:00 2001 From: zhibinw Date: Thu, 28 Jan 2021 15:51:09 +0800 Subject: [PATCH 016/883] aux/android: Make MonadoView not focusable/touchable --- .../java/org/freedesktop/monado/auxiliary/MonadoView.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java index e8dd1f28e..982a79451 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java @@ -81,9 +81,12 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); WindowManager windowManager = activity.getWindowManager(); - windowManager.addView(this, new WindowManager.LayoutParams(WindowManager.LayoutParams.FLAG_FULLSCREEN)); + WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); + lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN | + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + windowManager.addView(this, lp); - requestFocus(); SurfaceHolder surfaceHolder = getHolder(); surfaceHolder.addCallback(this); Log.i(TAG, "Registered callbacks!"); From 14532aceae278730c204942973a6049adf9d99ba Mon Sep 17 00:00:00 2001 From: zhibinw Date: Tue, 9 Feb 2021 16:31:59 +0800 Subject: [PATCH 017/883] aux/android: Make MonadoView focusable optional --- .../monado/auxiliary/MonadoView.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java index 982a79451..7a4d08fbb 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java @@ -73,8 +73,13 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S this(activity); nativeCounterpart = new NativeCounterpart(nativePointer); } - private void createSurface() { + createSurface(false); + } + /** + * @param focusable Indicates MonadoView should be focusable or not + */ + private void createSurface(boolean focusable) { Log.i(TAG, "Starting to add a new surface!"); activity.runOnUiThread(() -> { Log.i(TAG, "Starting runOnUiThread"); @@ -82,11 +87,20 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S WindowManager windowManager = activity.getWindowManager(); WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); - lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN | - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + if (focusable) { + lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN; + } else { + // There are 2 problems if view is focusable on all-in-one device: + // 1. Navigation bar won't go away because view gets focus. + // 2. Underlying activity lost focus and can not receive input. + lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN | + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + } windowManager.addView(this, lp); - + if (focusable) { + requestFocus(); + } SurfaceHolder surfaceHolder = getHolder(); surfaceHolder.addCallback(this); Log.i(TAG, "Registered callbacks!"); From a5913c7b4f0993ee67e03810fec630cddd9c4304 Mon Sep 17 00:00:00 2001 From: zhibinw Date: Tue, 9 Feb 2021 16:48:15 +0800 Subject: [PATCH 018/883] aux/android:add blank line between functions --- .../main/java/org/freedesktop/monado/auxiliary/MonadoView.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java index 7a4d08fbb..692485f78 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java @@ -73,9 +73,11 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S this(activity); nativeCounterpart = new NativeCounterpart(nativePointer); } + private void createSurface() { createSurface(false); } + /** * @param focusable Indicates MonadoView should be focusable or not */ From cfab11355db17d09ffe583f408f4312872f00528 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 10 Feb 2021 02:56:46 +0100 Subject: [PATCH 019/883] u/hand_tracking: Hand Joint flags can only be as valid as hand flags --- src/xrt/auxiliary/util/u_hand_tracking.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xrt/auxiliary/util/u_hand_tracking.c b/src/xrt/auxiliary/util/u_hand_tracking.c index 8019f9b0c..d78e1d930 100644 --- a/src/xrt/auxiliary/util/u_hand_tracking.c +++ b/src/xrt/auxiliary/util/u_hand_tracking.c @@ -667,6 +667,10 @@ u_hand_joints_set_out_data(struct u_hand_tracking *set, m_space_graph_add_relation(&graph, &data->relation); m_space_graph_add_pose(&graph, hand_offset); m_space_graph_resolve(&graph, &l[i].relation); + + // joint relations can not be "more valid" than the hand relation + // after space graph to make sure flags are not "upgraded" + l[i].relation.relation_flags &= hand_relation->relation_flags; } out_value->hand_pose = *hand_relation; From c4108035ea0c01a5f727565eb18481ae7ff71bab Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 1 Feb 2021 11:34:08 -0600 Subject: [PATCH 020/883] ipc: Fix doc warning --- src/xrt/ipc/client/ipc_client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/ipc/client/ipc_client.h b/src/xrt/ipc/client/ipc_client.h index c73bc7d42..9e26af84a 100644 --- a/src/xrt/ipc/client/ipc_client.h +++ b/src/xrt/ipc/client/ipc_client.h @@ -74,7 +74,7 @@ struct ipc_connection * @param xina Optional native image allocator for client-side allocation. Takes * ownership if one is supplied. * @param xdev Taken in but not used currently @todo remove this param? - * @param[out] out_xcn Pointer to receive the created xrt_system_compositor. + * @param[out] out_xcs Pointer to receive the created xrt_system_compositor. */ int ipc_client_create_system_compositor(struct ipc_connection *ipc_c, From 84508320f4c3619743efcf61062fda7b98b3b57b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 2 Feb 2021 09:37:01 -0600 Subject: [PATCH 021/883] ipc: Fix typo in comment --- src/xrt/ipc/server/ipc_server_process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index 02bf580d1..bf8479df2 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -585,7 +585,7 @@ init_all(struct ipc_server *s) } #endif - // Init all of the render riming helpers. + // Init all of the render timing helpers. for (size_t i = 0; i < ARRAY_SIZE(s->threads); i++) { u_rt_helper_init((struct u_rt_helper *)&s->threads[i].ics.urth); } From 51704bc2e55ee565f888434803eb3e78cab9b81e Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 8 Feb 2021 14:18:17 -0600 Subject: [PATCH 022/883] math: Fix doc warnings --- src/xrt/auxiliary/math/m_predict.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/math/m_predict.h b/src/xrt/auxiliary/math/m_predict.h index 04891e256..628ee93f1 100644 --- a/src/xrt/auxiliary/math/m_predict.h +++ b/src/xrt/auxiliary/math/m_predict.h @@ -19,7 +19,7 @@ * Assumes that angular velocity is relative to the space the relation is in, * not relative to relation::pose. * - * @aux_math + * @ingroup aux_math */ void m_predict_relation(const struct xrt_space_relation *rel, double delta_s, struct xrt_space_relation *out_rel); From ee81edfe48fd373117c5f462f984712c41039926 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 8 Feb 2021 12:34:35 -0600 Subject: [PATCH 023/883] t/oxr_android: Fix gradle build for release 21. --- src/xrt/targets/openxr_android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/targets/openxr_android/build.gradle b/src/xrt/targets/openxr_android/build.gradle index 1f8a7b59d..a02b569b6 100644 --- a/src/xrt/targets/openxr_android/build.gradle +++ b/src/xrt/targets/openxr_android/build.gradle @@ -17,7 +17,7 @@ plugins { androidGitVersion { tagPattern(/^v[0-9]+.*/) - codeFormat = 'MNNPPPBBB' + codeFormat = 'MMNNPPBBB' format = '%tag%%-count%%-gcommit%%-dirty%' } From a1aa5611fe46daca2bddb023ad163f150821e1d5 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 8 Feb 2021 12:51:36 -0600 Subject: [PATCH 024/883] gradle: Update to android-gradle-plugin 4.1.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 91a25088f..72c84403f 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.1' + classpath 'com.android.tools.build:gradle:4.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${latestAboutLibsRelease}" classpath 'com.quittle:svg-2-android-vector:0.0.5' From c65ce85fe1d3a44471440cf296c0d3eb8aef4be8 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 9 Feb 2021 15:32:55 -0600 Subject: [PATCH 025/883] ipc/android: Clean up MonadoService --- .../freedesktop/monado/ipc/MonadoService.kt | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.kt b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.kt index 7bebdedfd..fcd1943c0 100644 --- a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.kt +++ b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.kt @@ -53,23 +53,27 @@ class MonadoService : Service() { } private fun handleStart() { - val pendingShutdownIntent = PendingIntent.getForegroundService(this, - 0, - Intent(BuildConfig.SHUTDOWN_ACTION).setPackage(packageName), - 0) + val pendingShutdownIntent = PendingIntent.getForegroundService( + this, + 0, + Intent(BuildConfig.SHUTDOWN_ACTION).setPackage(packageName), + 0 + ) val notification = serviceNotification.buildNotification(this, pendingShutdownIntent) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - startForeground(serviceNotification.getNotificationId(), - notification, - ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST) + startForeground( + serviceNotification.getNotificationId(), + notification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST + ) } else { - startForeground(serviceNotification.getNotificationId(), - notification) + startForeground( + serviceNotification.getNotificationId(), + notification + ) } - } companion object { From 8f0c20093c02cee93287bfef899e26417c30e4b6 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 9 Feb 2021 16:39:30 -0600 Subject: [PATCH 026/883] ipc/android: Specify full qualified service name --- src/xrt/ipc/android/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/ipc/android/src/main/AndroidManifest.xml b/src/xrt/ipc/android/src/main/AndroidManifest.xml index b28f47840..691c56c56 100644 --- a/src/xrt/ipc/android/src/main/AndroidManifest.xml +++ b/src/xrt/ipc/android/src/main/AndroidManifest.xml @@ -7,7 +7,7 @@ From cc81174b709356b68120f83759e613ad2ec3391e Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 10 Feb 2021 21:57:58 +0100 Subject: [PATCH 027/883] comp: Fix VkDisplayKHR direct mode build without libx11-xcb --- src/xrt/auxiliary/vk/vk_helpers.h | 17 +++++++++-------- src/xrt/compositor/CMakeLists.txt | 6 +++++- src/xrt/compositor/main/comp_window_direct.c | 4 ++++ src/xrt/compositor/main/comp_window_direct.h | 4 ++++ src/xrt/compositor/meson.build | 15 +++++++++------ 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/xrt/auxiliary/vk/vk_helpers.h b/src/xrt/auxiliary/vk/vk_helpers.h index e3e930bf2..b2ecc4ec9 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.h +++ b/src/xrt/auxiliary/vk/vk_helpers.h @@ -81,19 +81,20 @@ struct vk_bundle #endif #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT - PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; - PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; - - // This doesn't strictly require VK_USE_PLATFORM_XLIB_XRANDR_EXT, - // but it's only used in the NVIDIA X direct mode path that does require it. - PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; - PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; - PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT; PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT; PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT; #endif +#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) || defined(VK_USE_PLATFORM_DISPLAY_KHR) + PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; + PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; + + PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; + PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; + PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +#endif + #ifdef VK_USE_PLATFORM_ANDROID_KHR PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; #endif diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index 94fcfa548..ae5b9ae40 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -109,7 +109,6 @@ if(XRT_FEATURE_COMPOSITOR_MAIN) endif() if(XRT_HAVE_XCB AND XRT_HAVE_XLIB) list(APPEND MAIN_SOURCE_FILES - main/comp_window_direct.c main/comp_window_direct_randr.c main/comp_window_direct_nvidia.c ) @@ -124,6 +123,11 @@ if(XRT_FEATURE_COMPOSITOR_MAIN) main/comp_window_vk_display.c ) endif() + if (VK_USE_PLATFORM_DISPLAY_KHR OR XRT_HAVE_XCB) + list(APPEND MAIN_SOURCE_FILES + main/comp_window_direct.c + ) + endif() # generate wayland protocols if(XRT_HAVE_WAYLAND) diff --git a/src/xrt/compositor/main/comp_window_direct.c b/src/xrt/compositor/main/comp_window_direct.c index 8b5cec0c8..be1af5e33 100644 --- a/src/xrt/compositor/main/comp_window_direct.c +++ b/src/xrt/compositor/main/comp_window_direct.c @@ -205,6 +205,8 @@ comp_window_direct_create_surface(struct comp_target_swapchain *cts, return result; } +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT + int comp_window_direct_connect(struct comp_target_swapchain *cts, Display **dpy) { @@ -258,3 +260,5 @@ comp_window_direct_init_swapchain( return true; } + +#endif diff --git a/src/xrt/compositor/main/comp_window_direct.h b/src/xrt/compositor/main/comp_window_direct.h index 2608e0229..d1c37bfe0 100644 --- a/src/xrt/compositor/main/comp_window_direct.h +++ b/src/xrt/compositor/main/comp_window_direct.h @@ -25,6 +25,8 @@ comp_window_direct_create_surface(struct comp_target_swapchain *cts, uint32_t width, uint32_t height); +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT + int comp_window_direct_connect(struct comp_target_swapchain *cts, Display **dpy); @@ -35,6 +37,8 @@ bool comp_window_direct_init_swapchain( struct comp_target_swapchain *cts, Display *dpy, VkDisplayKHR display, uint32_t width, uint32_t height); +#endif + #ifdef __cplusplus } #endif diff --git a/src/xrt/compositor/meson.build b/src/xrt/compositor/meson.build index 3ff8b758a..0651299a1 100644 --- a/src/xrt/compositor/meson.build +++ b/src/xrt/compositor/meson.build @@ -36,22 +36,25 @@ compositor_srcs = [ compile_args = [] -if build_vk_khr_display - compositor_srcs += ['main/comp_window_vk_display.c'] -endif - if build_xcb compositor_srcs += ['main/comp_window_xcb.c'] compositor_deps += [xcb] endif +if build_vk_khr_display + compositor_srcs += ['main/comp_window_vk_display.c'] +endif + if build_xcb_xrandr_direct - compositor_srcs += ['main/comp_window_direct.c', - 'main/comp_window_direct_randr.c', + compositor_srcs += ['main/comp_window_direct_randr.c', 'main/comp_window_direct_nvidia.c'] compositor_deps += [xcb_randr, x11_xcb] endif +if build_vk_khr_display or build_xcb_xrandr_direct + compositor_srcs += ['main/comp_window_direct.c'] +endif + if build_opengl or build_opengles compositor_srcs += [ 'client/comp_gl_client.c', From d8aad83932b635e7db9bbaac473cb6d5ab5147de Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 11 Feb 2021 09:28:12 -0600 Subject: [PATCH 028/883] d/ht: Fix mistaken 2029 copyright date. --- src/xrt/drivers/ht/ht_interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/ht/ht_interface.h b/src/xrt/drivers/ht/ht_interface.h index 4593a6b67..f47439990 100644 --- a/src/xrt/drivers/ht/ht_interface.h +++ b/src/xrt/drivers/ht/ht_interface.h @@ -1,4 +1,4 @@ -// Copyright 2029, Collabora, Ltd. +// Copyright 2020, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file From 268738c45deb043e30369c2180448526bf70ca6a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 11 Feb 2021 09:43:08 -0600 Subject: [PATCH 029/883] doc: Cleanup howto-release --- doc/howto-release.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/howto-release.md b/doc/howto-release.md index 828b004e9..0c483d20a 100644 --- a/doc/howto-release.md +++ b/doc/howto-release.md @@ -1,5 +1,10 @@ # How to release + + These instructions assumes that the version you are making is `21.0.0`. ## Generate changelog @@ -17,7 +22,6 @@ git commit -m"doc: Update CHANGELOG.md" doc/CHANGELOG.md git commit -m"doc: Remove old changelog fragments" doc/changes ``` - ## Update versions Edit the files @@ -32,7 +36,6 @@ See previous commits for exact places. git commit -a -m"monado: Update version" ``` - ## Tag the code Do the tagging from git, do **not** do it from gitlab, also make sure to prefix @@ -42,7 +45,6 @@ the version with `v` so that `21.0.0` becomes `v21.0.0`. git tag v21.0.0 -m"v21.0.0" ``` - ## Do gitlab release The Gitlab UI has a friendly interface, just follow the guide there. From 1d9ea3f1959d6bc4bdebd1942947bd5672bb98d2 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 11 Feb 2021 09:43:22 -0600 Subject: [PATCH 030/883] external/flexkalman: Add some missing copyright/license headers --- src/external/flexkalman/.clang-format | 3 +++ src/external/flexkalman/flexkalman/README.md | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/external/flexkalman/.clang-format b/src/external/flexkalman/.clang-format index 72b5e5320..370746784 100644 --- a/src/external/flexkalman/.clang-format +++ b/src/external/flexkalman/.clang-format @@ -1,4 +1,7 @@ --- +# Copyright 2015, 2016, Sensics, Inc. +# Copyright 2019, Collabora, Ltd. +# SPDX-License-Identifier: Apache-2.0 Language: Cpp BasedOnStyle: LLVM Standard: Auto diff --git a/src/external/flexkalman/flexkalman/README.md b/src/external/flexkalman/flexkalman/README.md index 74b8e2d55..aaa67ce8d 100644 --- a/src/external/flexkalman/flexkalman/README.md +++ b/src/external/flexkalman/flexkalman/README.md @@ -1,5 +1,11 @@ # FlexibleKalmanFilter + + ## About This is a C++ template-based header library for building Kalman-style filters, using [Eigen](http://eigen.tuxfamily.org) linear algebra data types and algorithms. From a702b42439dc6346d5f16e309e9dc6e241edd3b8 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 11 Feb 2021 09:45:01 -0600 Subject: [PATCH 031/883] ext/openxr: Update headers to 1.0.14 --- .../openxr/loader_interfaces.h | 18 ++----- src/external/openxr_includes/openxr/openxr.h | 5 +- .../openxr_includes/openxr/openxr_platform.h | 23 +++++++- .../openxr/openxr_platform_defines.h | 2 +- .../openxr/openxr_reflection.h | 54 +++++++++++-------- 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/src/external/openxr_includes/openxr/loader_interfaces.h b/src/external/openxr_includes/openxr/loader_interfaces.h index bf0a4ea16..695f4c089 100644 --- a/src/external/openxr_includes/openxr/loader_interfaces.h +++ b/src/external/openxr_includes/openxr/loader_interfaces.h @@ -1,22 +1,10 @@ -// Copyright (c) 2017-2020 The Khronos Group Inc. +// Copyright (c) 2017-2021, The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // -// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: Apache-2.0 OR MIT // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: Mark Young +// Initial Author: Mark Young // #pragma once diff --git a/src/external/openxr_includes/openxr/openxr.h b/src/external/openxr_includes/openxr/openxr.h index 04595ee14..92e92316b 100644 --- a/src/external/openxr_includes/openxr/openxr.h +++ b/src/external/openxr_includes/openxr/openxr.h @@ -2,7 +2,7 @@ #define OPENXR_H_ 1 /* -** Copyright (c) 2017-2020 The Khronos Group Inc. +** Copyright (c) 2017-2021, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -25,7 +25,7 @@ extern "C" { ((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL)) // OpenXR current version number. -#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 13) +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 14) #define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL) #define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL) @@ -306,6 +306,7 @@ typedef enum XrStructureType { XR_TYPE_CONTROLLER_MODEL_STATE_MSFT = 1000055004, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC = 1000059000, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT = 1000063000, + XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB = 1000070000, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE = 1000079000, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR = 1000089000, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR = 1000090000, diff --git a/src/external/openxr_includes/openxr/openxr_platform.h b/src/external/openxr_includes/openxr/openxr_platform.h index e29598db5..f7e633806 100644 --- a/src/external/openxr_includes/openxr/openxr_platform.h +++ b/src/external/openxr_includes/openxr/openxr_platform.h @@ -2,7 +2,7 @@ #define OPENXR_PLATFORM_H_ 1 /* -** Copyright (c) 2017-2020 The Khronos Group Inc. +** Copyright (c) 2017-2021, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -510,6 +510,27 @@ typedef struct XrHolographicWindowAttachmentMSFT { #endif /* XR_USE_PLATFORM_WIN32 */ +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_FB_android_surface_swapchain_create 1 +#define XR_FB_android_surface_swapchain_create_SPEC_VERSION 1 +#define XR_FB_ANDROID_SURFACE_SWAPCHAIN_CREATE_EXTENSION_NAME "XR_FB_android_surface_swapchain_create" +typedef XrFlags64 XrAndroidSurfaceSwapchainFlagsFB; + +// Flag bits for XrAndroidSurfaceSwapchainFlagsFB +static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB = 0x00000001; +static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB = 0x00000002; + +#ifdef XR_USE_PLATFORM_ANDROID +typedef struct XrAndroidSurfaceSwapchainCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAndroidSurfaceSwapchainFlagsFB createFlags; +} XrAndroidSurfaceSwapchainCreateInfoFB; +#endif // XR_USE_PLATFORM_ANDROID + +#endif /* XR_USE_PLATFORM_ANDROID */ + #ifdef __cplusplus } #endif diff --git a/src/external/openxr_includes/openxr/openxr_platform_defines.h b/src/external/openxr_includes/openxr/openxr_platform_defines.h index 45ccf0e37..a7ffcb459 100644 --- a/src/external/openxr_includes/openxr/openxr_platform_defines.h +++ b/src/external/openxr_includes/openxr/openxr_platform_defines.h @@ -1,5 +1,5 @@ /* -** Copyright (c) 2017-2020 The Khronos Group Inc. +** Copyright (c) 2017-2021, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ diff --git a/src/external/openxr_includes/openxr/openxr_reflection.h b/src/external/openxr_includes/openxr/openxr_reflection.h index 7249f72e8..61db0068f 100644 --- a/src/external/openxr_includes/openxr/openxr_reflection.h +++ b/src/external/openxr_includes/openxr/openxr_reflection.h @@ -2,7 +2,7 @@ #define OPENXR_REFLECTION_H_ 1 /* -** Copyright (c) 2017-2020 The Khronos Group Inc. +** Copyright (c) 2017-2021, The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -209,6 +209,7 @@ XR_ENUM_STR(XrResult); _(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT, 1000055004) \ _(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC, 1000059000) \ _(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT, 1000063000) \ + _(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB, 1000070000) \ _(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE, 1000079000) \ _(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, 1000089000) \ _(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, 1000090000) \ @@ -446,6 +447,10 @@ XR_ENUM_STR(XrResult); #define XR_LIST_BITS_XrOverlayMainSessionFlagsEXTX(_) \ _(XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX, 0x00000001) \ +#define XR_LIST_BITS_XrAndroidSurfaceSwapchainFlagsFB(_) \ + _(XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB, 0x00000001) \ + _(XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB, 0x00000002) \ + #define XR_LIST_STRUCT_XrApiLayerProperties(_) \ _(type) \ _(next) \ @@ -1399,6 +1404,11 @@ XR_ENUM_STR(XrResult); _(holographicSpace) \ _(coreWindow) \ +#define XR_LIST_STRUCT_XrAndroidSurfaceSwapchainCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + #define XR_LIST_STRUCT_XrInteractionProfileAnalogThresholdVALVE(_) \ _(type) \ _(next) \ @@ -1573,15 +1583,6 @@ XR_ENUM_STR(XrResult); #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) #endif -#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XCB) -#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ - _(XrGraphicsBindingOpenGLXcbKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) \ - - -#else -#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) -#endif - #if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XLIB) #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ _(XrGraphicsBindingOpenGLXlibKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) \ @@ -1601,15 +1602,6 @@ XR_ENUM_STR(XrResult); #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) #endif -#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) && defined(XR_USE_PLATFORM_ANDROID) -#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ - _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ - - -#else -#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) -#endif - #if defined(XR_USE_GRAPHICS_API_VULKAN) #define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ _(XrVulkanSwapchainFormatListCreateInfoKHR, XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) \ @@ -1629,12 +1621,22 @@ XR_ENUM_STR(XrResult); #define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ _(XrInstanceCreateInfoAndroidKHR, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) \ _(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ + _(XrAndroidSurfaceSwapchainCreateInfoFB, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) \ #else #define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) #endif +#if defined(XR_USE_PLATFORM_ANDROID) && defined(XR_USE_GRAPHICS_API_OPENGL_ES) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ + _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID_XR_USE_GRAPHICS_API_OPENGL_ES(_) +#endif + #if defined(XR_USE_PLATFORM_EGL) #define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ _(XrGraphicsBindingEGLMNDX, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) \ @@ -1653,6 +1655,15 @@ XR_ENUM_STR(XrResult); #define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) #endif +#if defined(XR_USE_PLATFORM_XCB) && defined(XR_USE_GRAPHICS_API_OPENGL) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_XCB_XR_USE_GRAPHICS_API_OPENGL(_) \ + _(XrGraphicsBindingOpenGLXcbKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_XCB_XR_USE_GRAPHICS_API_OPENGL(_) +#endif + #define XR_LIST_STRUCTURE_TYPES(_) \ XR_LIST_STRUCTURE_TYPES_CORE(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) \ @@ -1660,14 +1671,14 @@ XR_ENUM_STR(XrResult); XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) \ - XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ - XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_XCB_XR_USE_GRAPHICS_API_OPENGL(_) \ #define XR_LIST_EXTENSIONS(_) \ @@ -1713,6 +1724,7 @@ XR_ENUM_STR(XrResult); _(XR_EPIC_view_configuration_fov, 60) \ _(XR_MSFT_holographic_window_attachment, 64) \ _(XR_HUAWEI_controller_interaction, 70) \ + _(XR_FB_android_surface_swapchain_create, 71) \ _(XR_VALVE_analog_threshold, 80) \ _(XR_KHR_loader_init, 89) \ _(XR_KHR_loader_init_android, 90) \ From 55fd787397bb6e43a6cfcab946644345daf41620 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 11 Feb 2021 09:45:43 -0600 Subject: [PATCH 032/883] reuse: Update dep5 file --- .reuse/dep5 | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/.reuse/dep5 b/.reuse/dep5 index 8616e6669..291b59df3 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -10,17 +10,10 @@ Files: doc/changes/drivers/* doc/changes/xrt/* doc/changes/auxiliary/* doc/changes/compositor/* -Copyright: 2020, Collabora, Ltd. and the Monado contributors +Copyright: 2020-2021, Collabora, Ltd. and the Monado contributors License: CC0-1.0 Comment: Prevents needing a license header per fragment between releases. -Files: src/external/flexkalman/.clang-format - src/external/flexkalman/flexkalman/README.md -Copyright: 2015, 2016, Sensics, Inc. - 2019, Collabora, Ltd. -License: Apache-2.0 -Comment: Copyright statement and license identifier missing. - Files: src/external/cjson/* Copyright: 2009-2017, Dave Gamble and cJSON contributors License: MIT @@ -32,14 +25,6 @@ Copyright: 2020, Two Blue Cubes Ltd. License: BSL-1.0 Comment: SPDX-License-Identifier missing. -Files: src/external/openxr_includes/loader_interfaces.h -Copyright: 2017, LunarG, Inc. - 2017, Valve Corporation - 2017-2019, The Khronos Group Inc. -License: Apache-2.0 -Comment: SPDX-License-Identifier missing. - - Files: src/external/jnipp/* Copyright: 2016-2020, Mitchell Dowd 2020, Collabora, Ltd. @@ -52,6 +37,11 @@ Copyright: 2016, mcximing License: BSD-2-Clause Comment: SPDX-License-Identifier missing. +Files: src/external/openvr_includes/* +Copyright: 2015-2020, Valve Corporation +License: BSD-3-Clause +Comment: License identifier missing. + Files: src/external/imgui/imgui* src/external/imgui/imconfig.h Copyright: 2014-2020, Omar Cornut From e8058034a37d46f296d8b0366e74dd61ccd14dc5 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 11 Feb 2021 09:45:58 -0600 Subject: [PATCH 033/883] readme: Clarify clang-format usage/version --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b9cc6765..0e849669b 100644 --- a/README.md +++ b/README.md @@ -241,8 +241,11 @@ scripts/format-project.sh You can optionally put something like `CLANG_FORMAT=clang-format-7` before that command if your clang-format binary isn't named `clang-format`. -Note that you'll typically prefer to use something like `git clang-format` +**Note that you'll typically prefer** to use something like `git clang-format` to just re-format your changes, in case version differences in tools result in overall format changes. +The CI "style" job currently runs on Debian Buster, so it has clang-format-7. +We will probably update that job to Bullseye or Ubuntu 20.10, which will allow +using clang-format-11 by default, soon. [OpenHMD]: http://openhmd.net [drm-lease]: https://haagch.frickel.club/#!drmlease%2Emd From 2d814dab574a495a0f3d6a8736a0494de3b144a2 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Fri, 5 Feb 2021 16:56:38 +0100 Subject: [PATCH 034/883] aux/vive: Parse hmd variant and add various model strings Model strings collected from libsurvive, survive_default_devices.c --- src/xrt/auxiliary/vive/vive_config.c | 39 +++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/xrt/auxiliary/vive/vive_config.c b/src/xrt/auxiliary/vive/vive_config.c index 5b203f288..4f17bd987 100644 --- a/src/xrt/auxiliary/vive/vive_config.c +++ b/src/xrt/auxiliary/vive/vive_config.c @@ -220,6 +220,28 @@ vive_config_parse(struct vive_config *d, char *json_string) return false; } + if (u_json_get(json, "model_number")) { + JSON_STRING(json, "model_number", d->firmware.model_number); + } else { + JSON_STRING(json, "model_name", d->firmware.model_number); + } + + VIVE_DEBUG(d, "Parsing model number: %s", d->firmware.model_number); + + if (strcmp(d->firmware.model_number, "Utah MP") == 0) { + d->variant = VIVE_VARIANT_INDEX; + VIVE_DEBUG(d, "Found Valve Index HMD"); + } else if (strcmp(d->firmware.model_number, "Vive MV") == 0 || + strcmp(d->firmware.model_number, "Vive. MV") == 0) { + d->variant = VIVE_VARIANT_VIVE; + VIVE_DEBUG(d, "Found HTC Vive HMD"); + } else if (strcmp(d->firmware.model_number, "Vive_Pro MV") == 0) { + d->variant = VIVE_VARIANT_PRO; + VIVE_DEBUG(d, "Found HTC Vive Pro HMD"); + } else { + VIVE_ERROR(d, "Failed to parse Vive HMD variant"); + } + switch (d->variant) { case VIVE_VARIANT_VIVE: JSON_VEC3(json, "acc_bias", &d->imu.acc_bias); @@ -258,8 +280,6 @@ vive_config_parse(struct vive_config *d, char *json_string) default: VIVE_ERROR(d, "Unknown Vive variant."); return false; } - JSON_STRING(json, "model_number", d->firmware.model_number); - if (d->variant != VIVE_VARIANT_INDEX) { JSON_STRING(json, "mb_serial_number", d->firmware.mb_serial_number); } @@ -337,16 +357,23 @@ vive_config_parse_controller(struct vive_controller_config *d, char *json_string JSON_STRING(json, "model_name", d->firmware.model_number); } - if (strcmp(d->firmware.model_number, "Vive. Controller MV") == 0) { + VIVE_DEBUG(d, "Parsing model number: %s", d->firmware.model_number); + + if (strcmp(d->firmware.model_number, "Vive. Controller MV") == 0 || + strcmp(d->firmware.model_number, "Vive Controller MV") == 0) { d->variant = CONTROLLER_VIVE_WAND; VIVE_DEBUG(d, "Found Vive Wand controller"); - } else if (strcmp(d->firmware.model_number, "Knuckles Right") == 0) { + } else if (strcmp(d->firmware.model_number, "Knuckles Right") == 0 || + strcmp(d->firmware.model_number, "Knuckles EV3.0 Right") == 0) { d->variant = CONTROLLER_INDEX_RIGHT; VIVE_DEBUG(d, "Found Knuckles Right controller"); - } else if (strcmp(d->firmware.model_number, "Knuckles Left") == 0) { + } else if (strcmp(d->firmware.model_number, "Knuckles Left") == 0 || + strcmp(d->firmware.model_number, "Knuckles EV3.0 Left") == 0) { d->variant = CONTROLLER_INDEX_LEFT; VIVE_DEBUG(d, "Found Knuckles Left controller"); - } else if (strcmp(d->firmware.model_number, "Vive Tracker PVT") == 0) { + } else if (strcmp(d->firmware.model_number, "Vive Tracker PVT") == 0 || + strcmp(d->firmware.model_number, "Vive. Tracker MV") == 0 || + strcmp(d->firmware.model_number, "Vive Tracker MV") == 0) { d->variant = CONTROLLER_TRACKER_GEN1; VIVE_DEBUG(d, "Found Gen 1 tracker."); } else if (strcmp(d->firmware.model_number, "VIVE Tracker Pro MV") == 0) { From f93209a1eddfcad38d57543ba70b7a9707b18f73 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Fri, 5 Feb 2021 16:59:27 +0100 Subject: [PATCH 035/883] d/vive: Remove vive_device::variant and use variant from config --- src/xrt/drivers/vive/vive_device.c | 13 ++----------- src/xrt/drivers/vive/vive_device.h | 2 -- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index 9d6a7d76e..ff4f0735b 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -339,7 +339,7 @@ update_imu(struct vive_device *d, const void *buffer) VIVE_TRACE(d, "GYRO %f %f %f", angular_velocity.x, angular_velocity.y, angular_velocity.z); - switch (d->variant) { + switch (d->config.variant) { case VIVE_VARIANT_VIVE: // flip all except x axis acceleration.x = +acceleration.x; @@ -744,19 +744,11 @@ vive_device_create(struct os_hid_device *mainboard_dev, d->sensors_dev = sensors_dev; d->ll = debug_get_log_option_vive_log(); d->watchman_dev = watchman_dev; - d->variant = variant; d->base.hmd->distortion.models = XRT_DISTORTION_MODEL_COMPUTE; d->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_COMPUTE; d->base.compute_distortion = compute_distortion; - switch (variant) { - case VIVE_VARIANT_VIVE: snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "HTC Vive"); break; - case VIVE_VARIANT_PRO: snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "HTC Vive Pro"); break; - case VIVE_VARIANT_INDEX: snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "Valve Index"); break; - default: snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "Unknown Vive device"); - } - if (d->mainboard_dev) { vive_mainboard_power_on(d); vive_mainboard_get_device_info(d); @@ -784,7 +776,6 @@ vive_device_create(struct os_hid_device *mainboard_dev, d->config.ll = d->ll; // usb connected HMD variant is known because of USB id, config parsing relies on it. - d->config.variant = d->variant; if (config != NULL) { vive_config_parse(&d->config, config); free(config); @@ -803,7 +794,7 @@ vive_device_create(struct os_hid_device *mainboard_dev, d->base.hmd->screens[0].w_pixels = (int)w_pixels * 2; d->base.hmd->screens[0].h_pixels = (int)h_pixels; - if (d->variant == VIVE_VARIANT_INDEX) { + if (d->config.variant == VIVE_VARIANT_INDEX) { lens_horizontal_separation = 0.06; h_meters = 0.07; // eye relief knob adjusts this around [0.0255(near)-0.275(far)] diff --git a/src/xrt/drivers/vive/vive_device.h b/src/xrt/drivers/vive/vive_device.h index a70194c48..65a9b430e 100644 --- a/src/xrt/drivers/vive/vive_device.h +++ b/src/xrt/drivers/vive/vive_device.h @@ -34,8 +34,6 @@ struct vive_device struct lighthouse_watchman watchman; - enum VIVE_VARIANT variant; - struct os_thread_helper sensors_thread; struct os_thread_helper watchman_thread; struct os_thread_helper mainboard_thread; From 3a02610e7719533b291d3c4385a1bd96fec851bd Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 8 Feb 2021 13:54:53 +0100 Subject: [PATCH 036/883] d/vive: Remove vive_controller_device::variant and use variant from config --- src/xrt/drivers/vive/vive_controller.c | 33 ++++++++++++-------------- src/xrt/drivers/vive/vive_controller.h | 1 - 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/xrt/drivers/vive/vive_controller.c b/src/xrt/drivers/vive/vive_controller.c index 8b35351b2..f1c9321ea 100644 --- a/src/xrt/drivers/vive/vive_controller.c +++ b/src/xrt/drivers/vive/vive_controller.c @@ -308,7 +308,7 @@ vive_controller_get_hand_tracking(struct xrt_device *xdev, return; } - enum xrt_hand hand = d->variant == CONTROLLER_INDEX_LEFT ? XRT_HAND_LEFT : XRT_HAND_RIGHT; + enum xrt_hand hand = d->config.variant == CONTROLLER_INDEX_LEFT ? XRT_HAND_LEFT : XRT_HAND_RIGHT; float thumb_curl = 0.0f; //! @todo place thumb preciely on the button that is touched/pressed @@ -562,21 +562,21 @@ vive_controller_handle_imu_sample(struct vive_controller_device *d, struct watch /* */ - if (d->variant == CONTROLLER_VIVE_WAND) { + if (d->config.variant == CONTROLLER_VIVE_WAND) { struct xrt_vec3 fixed_acceleration = {.x = -acceleration.x, .y = -acceleration.z, .z = -acceleration.y}; acceleration = fixed_acceleration; struct xrt_vec3 fixed_angular_velocity = { .x = -angular_velocity.x, .y = -angular_velocity.z, .z = -angular_velocity.y}; angular_velocity = fixed_angular_velocity; - } else if (d->variant == CONTROLLER_INDEX_RIGHT) { + } else if (d->config.variant == CONTROLLER_INDEX_RIGHT) { struct xrt_vec3 fixed_acceleration = {.x = acceleration.z, .y = -acceleration.y, .z = acceleration.x}; acceleration = fixed_acceleration; struct xrt_vec3 fixed_angular_velocity = { .x = angular_velocity.z, .y = -angular_velocity.y, .z = angular_velocity.x}; angular_velocity = fixed_angular_velocity; - } else if (d->variant == CONTROLLER_INDEX_LEFT) { + } else if (d->config.variant == CONTROLLER_INDEX_LEFT) { struct xrt_vec3 fixed_acceleration = {.x = -acceleration.z, .y = acceleration.x, .z = -acceleration.y}; acceleration = fixed_acceleration; @@ -1023,7 +1023,7 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w d->ll = debug_get_log_option_vive_log(); d->watchman_gen = WATCHMAN_GEN_UNKNOWN; - d->variant = CONTROLLER_UNKNOWN; + d->config.variant = CONTROLLER_UNKNOWN; d->watchman_gen = watchman_gen; @@ -1067,7 +1067,7 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w VIVE_DEBUG(d, "Vive controller gyroscope range %f", d->config.imu.gyro_range); VIVE_DEBUG(d, "Vive controller accelerometer range %f", d->config.imu.acc_range); - // successful config parsing determines d->variant + // successful config parsing determines d->config.variant char *config = vive_read_config(d->controller_hid); d->config.ll = d->ll; @@ -1081,11 +1081,7 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w return 0; } - // watchman rf connected device variant is read from config json - //! @todo usb connected controllers - d->variant = d->config.variant; - - if (d->variant == CONTROLLER_VIVE_WAND) { + if (d->config.variant == CONTROLLER_VIVE_WAND) { d->base.name = XRT_DEVICE_VIVE_WAND; SET_WAND_INPUT(SYSTEM_CLICK, SYSTEM_CLICK); @@ -1108,7 +1104,7 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w d->base.num_binding_profiles = ARRAY_SIZE(binding_profiles_vive); d->base.device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER; - } else if (d->variant == CONTROLLER_INDEX_LEFT || d->variant == CONTROLLER_INDEX_RIGHT) { + } else if (d->config.variant == CONTROLLER_INDEX_LEFT || d->config.variant == CONTROLLER_INDEX_RIGHT) { d->base.name = XRT_DEVICE_INDEX_CONTROLLER; SET_INDEX_INPUT(SYSTEM_CLICK, SYSTEM_CLICK); @@ -1139,25 +1135,25 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w d->base.get_hand_tracking = vive_controller_get_hand_tracking; - enum xrt_hand hand = d->variant == CONTROLLER_INDEX_LEFT ? XRT_HAND_LEFT : XRT_HAND_RIGHT; + enum xrt_hand hand = d->config.variant == CONTROLLER_INDEX_LEFT ? XRT_HAND_LEFT : XRT_HAND_RIGHT; u_hand_joints_init_default_set(&d->hand_tracking, hand, XRT_HAND_TRACKING_MODEL_FINGERL_CURL, 1.0); d->base.binding_profiles = binding_profiles_index; d->base.num_binding_profiles = ARRAY_SIZE(binding_profiles_index); - if (d->variant == CONTROLLER_INDEX_LEFT) { + if (d->config.variant == CONTROLLER_INDEX_LEFT) { d->base.device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; d->base.inputs[VIVE_CONTROLLER_HAND_TRACKING].name = XRT_INPUT_GENERIC_HAND_TRACKING_LEFT; - } else if (d->variant == CONTROLLER_INDEX_RIGHT) { + } else if (d->config.variant == CONTROLLER_INDEX_RIGHT) { d->base.device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER; d->base.inputs[VIVE_CONTROLLER_HAND_TRACKING].name = XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT; } - } else if (d->variant == CONTROLLER_TRACKER_GEN1) { + } else if (d->config.variant == CONTROLLER_TRACKER_GEN1) { d->base.name = XRT_DEVICE_VIVE_TRACKER_GEN1; d->base.update_inputs = _update_tracker_inputs; d->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER; - } else if (d->variant == CONTROLLER_TRACKER_GEN2) { + } else if (d->config.variant == CONTROLLER_TRACKER_GEN2) { d->base.name = XRT_DEVICE_VIVE_TRACKER_GEN2; d->base.update_inputs = _update_tracker_inputs; d->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER; @@ -1179,7 +1175,8 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w VIVE_DEBUG(d, "Opened vive controller!\n"); d->base.orientation_tracking_supported = true; d->base.position_tracking_supported = false; - d->base.hand_tracking_supported = d->variant == CONTROLLER_INDEX_LEFT || d->variant == CONTROLLER_INDEX_RIGHT; + d->base.hand_tracking_supported = + d->config.variant == CONTROLLER_INDEX_LEFT || d->config.variant == CONTROLLER_INDEX_RIGHT; return d; } diff --git a/src/xrt/drivers/vive/vive_controller.h b/src/xrt/drivers/vive/vive_controller.h index abd027353..c30cdf0ae 100644 --- a/src/xrt/drivers/vive/vive_controller.h +++ b/src/xrt/drivers/vive/vive_controller.h @@ -96,7 +96,6 @@ struct vive_controller_device } state; enum watchman_gen watchman_gen; - enum VIVE_CONTROLLER_VARIANT variant; struct u_hand_tracking hand_tracking; From 7e1408787aad73c85661bc2016486dac045068d0 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 8 Feb 2021 15:22:09 +0100 Subject: [PATCH 037/883] d/survive: Update to new API and clean up * Remove survive_device.{ctrl,hmd}::variant and use variant from config * Use SurviveSimpleEventType_ConfigEvent to find connected devices * Use SurviveSimpleEventType_PoseUpdateEvent for pose updates --- src/xrt/drivers/CMakeLists.txt | 2 - src/xrt/drivers/meson.build | 2 - src/xrt/drivers/survive/survive_driver.c | 455 +++++++++++------------ src/xrt/drivers/survive/survive_wrap.c | 43 --- src/xrt/drivers/survive/survive_wrap.h | 21 -- 5 files changed, 209 insertions(+), 314 deletions(-) delete mode 100644 src/xrt/drivers/survive/survive_wrap.c delete mode 100644 src/xrt/drivers/survive/survive_wrap.h diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index fb1f02c3c..36d274f57 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -208,8 +208,6 @@ if (XRT_BUILD_DRIVER_SURVIVE) set(SURVIVE_SOURCE_FILES survive/survive_driver.c survive/survive_interface.h - survive/survive_wrap.c - survive/survive_wrap.h ) add_library(drv_survive STATIC ${SURVIVE_SOURCE_FILES}) diff --git a/src/xrt/drivers/meson.build b/src/xrt/drivers/meson.build index e50807f40..bb35a5000 100644 --- a/src/xrt/drivers/meson.build +++ b/src/xrt/drivers/meson.build @@ -187,8 +187,6 @@ lib_drv_survive = static_library( files( 'survive/survive_driver.c', 'survive/survive_interface.h', - 'survive/survive_wrap.c', - 'survive/survive_wrap.h', ), include_directories: [ xrt_include, diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index c58638d2d..7c32202ef 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -32,8 +32,6 @@ #include "survive_api.h" -#include "survive_wrap.h" - #include "util/u_json.h" #include "util/u_hand_tracking.h" @@ -43,8 +41,19 @@ #include "vive/vive_config.h" -// typically HMD config is available at around 2 seconds after init -#define WAIT_TIMEOUT 5.0 +// reading usb config takes libsurvive about 50ms per device +// to be safe, we wait 500 ms after the last device has been initialized +#define WAIT_TIMEOUT 0.5f + +// index in sys->controllers[] array +#define SURVIVE_LEFT_CONTROLLER_INDEX 0 +#define SURVIVE_RIGHT_CONTROLLER_INDEX 1 + +//! excl HMD we support 16 devices (controllers, trackers, ...) +#define MAX_TRACKED_DEVICE_COUNT 16 + +// initializing survive_driver once creates xrt_devices for all connected devices +static bool survive_already_initialized = false; #define SURVIVE_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->sys->ll, __VA_ARGS__) #define SURVIVE_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->sys->ll, __VA_ARGS__) @@ -89,16 +98,6 @@ enum input_index VIVE_CONTROLLER_MAX_INDEX, }; -// also used as index in sys->controllers[] array -typedef enum -{ - SURVIVE_LEFT_CONTROLLER = 0, - SURVIVE_RIGHT_CONTROLLER = 1, - SURVIVE_HMD = 2, -} SurviveDeviceType; - -static bool survive_already_initialized = false; - /*! * @implements xrt_device */ @@ -109,9 +108,7 @@ struct survive_device const SurviveSimpleObject *survive_obj; struct xrt_space_relation last_relation; - - int num; - + timepoint_ns last_relation_ts; union { struct @@ -119,7 +116,6 @@ struct survive_device float proximity; // [0,1] float ipd; - enum VIVE_VARIANT variant; struct vive_config config; } hmd; @@ -129,15 +125,11 @@ struct survive_device uint64_t curl_ts[XRT_FINGER_COUNT]; struct u_hand_tracking hand_tracking; - enum VIVE_CONTROLLER_VARIANT variant; struct vive_controller_config config; } ctrl; }; }; -//! @todo support more devices (trackers, ...) -#define CONTROLLER_COUNT 2 - /*! * @extends xrt_tracking_origin */ @@ -146,7 +138,7 @@ struct survive_system struct xrt_tracking_origin base; SurviveSimpleContext *ctx; struct survive_device *hmd; - struct survive_device *controllers[CONTROLLER_COUNT]; + struct survive_device *controllers[MAX_TRACKED_DEVICE_COUNT]; enum u_logging_level ll; }; @@ -158,13 +150,29 @@ survive_device_destroy(struct xrt_device *xdev) if (survive == survive->sys->hmd) survive->sys->hmd = NULL; - if (survive == survive->sys->controllers[SURVIVE_LEFT_CONTROLLER]) - survive->sys->controllers[SURVIVE_LEFT_CONTROLLER] = NULL; - if (survive == survive->sys->controllers[SURVIVE_RIGHT_CONTROLLER]) - survive->sys->controllers[SURVIVE_RIGHT_CONTROLLER] = NULL; - if (survive->sys->hmd == NULL && survive->sys->controllers[SURVIVE_LEFT_CONTROLLER] == NULL && - survive->sys->controllers[SURVIVE_RIGHT_CONTROLLER] == NULL) { + for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) { + if (survive == survive->sys->controllers[i]) { + survive->sys->controllers[i] = NULL; + } + } + + //! @todo: For now tear libsurvive down without expliclity destroying trackers + bool all_null = true; + if (survive->sys->controllers[CONTROLLER_INDEX_LEFT] != NULL) { + all_null = false; + } + if (survive->sys->controllers[CONTROLLER_INDEX_RIGHT] != NULL) { + all_null = false; + } + + if (survive->sys->hmd == NULL && all_null) { + + //! @todo we don't explicitly destroy trackers yet + for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) { + survive->sys->controllers[i] = 0; + } + U_LOG_D("Tearing down libsurvive context"); survive_simple_close(survive->sys->ctx); @@ -184,50 +192,24 @@ survive_timecode_now_s() return ((double)tv.tv_usec) / 1000000. + (tv.tv_sec); } -static void -_get_survive_pose(struct survive_device *survive, uint64_t at_timestamp_ns, struct xrt_space_relation *out_relation) +static timepoint_ns +survive_timecode_to_monotonic(double timecode) { - const SurviveSimpleObject *survive_object = survive->survive_obj; - - out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE; - - if (survive_simple_object_get_type(survive_object) != SurviveSimpleObject_OBJECT && - survive_simple_object_get_type(survive_object) != SurviveSimpleObject_HMD) { - return; - } - - // Initially pose can be zeroed. That's okay, we report it without - // orientation etc. valid flag then. - SurvivePose pose; - SurviveVelocity vel; - - // "device time" in seconds - double timecode_s = survive_simple_object_get_latest_pose(survive_object, &pose); - - double vel_timecode_s = survive_simple_object_get_latest_velocity(survive_object, &vel); - (void)vel_timecode_s; - - // do calculations in ns due to large numbers - timepoint_ns timecode_ns = time_s_to_ns(timecode_s); - - timepoint_ns monotonic_now_ns = os_monotonic_get_ns(); - timepoint_ns remaining_ns = at_timestamp_ns - monotonic_now_ns; - + timepoint_ns timecode_ns = time_s_to_ns(timecode); timepoint_ns survive_now_ns = time_s_to_ns(survive_timecode_now_s()); - timepoint_ns survive_pose_age_ns = survive_now_ns - timecode_ns; - timepoint_ns prediction_ns = remaining_ns + survive_pose_age_ns; + timepoint_ns timecode_age_ns = survive_now_ns - timecode_ns; - double prediction_s = time_ns_to_s(prediction_ns); + timepoint_ns now = os_monotonic_get_ns(); + timepoint_ns timestamp = now - timecode_age_ns; - SURVIVE_TRACE(survive, - "dev %s At %ldns: Pose requested for +%ldns (%ldns). " - "Libsurvive Pose Timecode: %ldns, Pose gotten at -%ldns " - "from now (%ldns), predicting %ldns", - survive->base.str, monotonic_now_ns, remaining_ns, at_timestamp_ns, timecode_ns, - survive_pose_age_ns, survive_now_ns, prediction_ns); + return timestamp; +} - struct xrt_quat out_rot = {.x = pose.Rot[1], .y = pose.Rot[2], .z = pose.Rot[3], .w = pose.Rot[0]}; +static void +pose_to_relation(const SurvivePose *pose, const SurviveVelocity *vel, struct xrt_space_relation *out_relation) +{ + struct xrt_quat out_rot = {.x = pose->Rot[1], .y = pose->Rot[2], .z = pose->Rot[3], .w = pose->Rot[0]}; /* libsurvive looks down when it should be looking forward, so * rotate the quat. @@ -245,18 +227,17 @@ _get_survive_pose(struct survive_device *survive, uint64_t at_timestamp_ns, stru // just to be sure math_quat_normalize(&out_rot); - - out_relation->pose.orientation = out_rot; /* switch -y, z axes to go from libsurvive coordinate system to ours */ - out_relation->pose.position.x = pose.Pos[0]; - out_relation->pose.position.y = pose.Pos[2]; - out_relation->pose.position.z = -pose.Pos[1]; + out_relation->pose.position.x = pose->Pos[0]; + out_relation->pose.position.y = pose->Pos[2]; + out_relation->pose.position.z = -pose->Pos[1]; - struct xrt_vec3 linear_vel = {.x = vel.Pos[0], .y = vel.Pos[2], .z = -vel.Pos[1]}; + struct xrt_vec3 linear_vel = {.x = vel->Pos[0], .y = vel->Pos[2], .z = -vel->Pos[1]}; - struct xrt_vec3 angular_vel = {.x = vel.AxisAngleRot[0], .y = vel.AxisAngleRot[2], .z = -vel.AxisAngleRot[1]}; + struct xrt_vec3 angular_vel = { + .x = vel->AxisAngleRot[0], .y = vel->AxisAngleRot[2], .z = -vel->AxisAngleRot[1]}; if (math_quat_validate(&out_rot)) { out_relation->relation_flags |= @@ -280,57 +261,21 @@ _get_survive_pose(struct survive_device *survive, uint64_t at_timestamp_ns, stru out_relation->relation_flags |= XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT; } } - - SURVIVE_TRACE(survive, "Predicting %fs for %s", prediction_s, survive->base.str); - - struct xrt_space_relation rel = *out_relation; - m_predict_relation(&rel, prediction_s, out_relation); } -//! @todo: Hotplugging, with get_variant_from_json() -#if 0 -static bool -_update_survive_devices(struct survive_system *sys) +static void +_predict_pose(struct survive_device *survive, uint64_t at_timestamp_ns, struct xrt_space_relation *out_relation) { - //! @todo better method + timepoint_ns prediction_ns = at_timestamp_ns - survive->last_relation_ts; + double prediction_s = time_ns_to_s(prediction_ns); - if (sys->hmd->survive_obj && sys->controllers[0]->survive_obj && - sys->controllers[1]->survive_obj) - return true; + timepoint_ns monotonic_now_ns = os_monotonic_get_ns(); + timepoint_ns remaining_ns = at_timestamp_ns - monotonic_now_ns; + SURVIVE_TRACE(survive, "dev %s At %ldns: Pose requested for +%ldns (%ldns), predicting %ldns", + survive->base.str, monotonic_now_ns, remaining_ns, at_timestamp_ns, prediction_ns); - SurviveSimpleContext *ctx = sys->ctx; - - for (const SurviveSimpleObject *it = - survive_simple_get_first_object(ctx); - it != 0; it = survive_simple_get_next_object(ctx, it)) { - const char *codename = survive_simple_object_name(it); - - enum SurviveSimpleObject_type type = - survive_simple_object_get_type(it); - if (type == SurviveSimpleObject_HMD && - sys->hmd->survive_obj == NULL) { - U_LOG_D("Found HMD: %s", codename); - sys->hmd->survive_obj = it; - } - if (type == SurviveSimpleObject_OBJECT) { - for (int i = 0; i < CONTROLLER_COUNT; i++) { - if (sys->controllers[i]->survive_obj == it) { - break; - } - - if (sys->controllers[i]->survive_obj == NULL) { - U_LOG_D("Found Controller %d: %s", i, - codename); - sys->controllers[i]->survive_obj = it; - break; - } - } - } - } - - return true; + m_predict_relation(&survive->last_relation, prediction_s, out_relation); } -#endif static void survive_device_get_tracked_pose(struct xrt_device *xdev, @@ -348,16 +293,12 @@ survive_device_get_tracked_pose(struct xrt_device *xdev, return; } - //_update_survive_devices(survive->sys); if (!survive->survive_obj) { // U_LOG_D("Obj not set for %p", (void*)survive); return; } - - _get_survive_pose(survive, at_timestamp_ns, out_relation); - - survive->last_relation = *out_relation; + _predict_pose(survive, at_timestamp_ns, out_relation); struct xrt_pose *p = &out_relation->pose; SURVIVE_TRACE(survive, "GET_POSITION (%f %f %f) GET_ORIENTATION (%f, %f, %f, %f)", p->position.x, p->position.y, @@ -414,9 +355,6 @@ survive_controller_device_set_output(struct xrt_device *xdev, enum xrt_output_na } } -#define PI 3.14159265358979323846 -#define DEG_TO_RAD(DEG) (DEG * PI / 180.) - static void survive_controller_get_hand_tracking(struct xrt_device *xdev, enum xrt_input_name name, @@ -431,7 +369,7 @@ survive_controller_get_hand_tracking(struct xrt_device *xdev, } - bool left = survive->ctrl.variant == CONTROLLER_INDEX_LEFT; + bool left = survive->ctrl.config.variant == CONTROLLER_INDEX_LEFT; enum xrt_hand hand = left ? XRT_HAND_LEFT : XRT_HAND_RIGHT; float thumb_curl = 0.0f; @@ -505,7 +443,7 @@ struct Axis enum InputComponent comp; }; -struct Axis axes[255] = { +static struct Axis axes[255] = { [SURVIVE_AXIS_TRIGGER] = { .input = VIVE_CONTROLLER_TRIGGER_VALUE, @@ -596,7 +534,7 @@ struct Button buttons[255] = { }; static bool -update_button(struct survive_device *survive, const struct SurviveSimpleButtonEvent *e, uint64_t now) +update_button(struct survive_device *survive, const struct SurviveSimpleButtonEvent *e, timepoint_ns ts) { if (e->event_type == SURVIVE_INPUT_EVENT_NONE) { return true; @@ -610,22 +548,22 @@ update_button(struct survive_device *survive, const struct SurviveSimpleButtonEv enum input_index index = buttons[btn_id].click; struct xrt_input *input = &survive->base.inputs[index]; input->value.boolean = false; - input->timestamp = now; + input->timestamp = ts; } else if (e_type == SURVIVE_INPUT_EVENT_BUTTON_DOWN) { enum input_index index = buttons[btn_id].click; struct xrt_input *input = &survive->base.inputs[index]; input->value.boolean = true; - input->timestamp = now; + input->timestamp = ts; } else if (e_type == SURVIVE_INPUT_EVENT_TOUCH_UP) { enum input_index index = buttons[btn_id].touch; struct xrt_input *input = &survive->base.inputs[index]; input->value.boolean = false; - input->timestamp = now; + input->timestamp = ts; } else if (e_type == SURVIVE_INPUT_EVENT_TOUCH_DOWN) { enum input_index index = buttons[btn_id].touch; struct xrt_input *input = &survive->base.inputs[index]; input->value.boolean = true; - input->timestamp = now; + input->timestamp = ts; } return true; @@ -643,29 +581,31 @@ _calculate_squeeze_value(struct survive_device *survive) } static void -_process_button_event(struct survive_device *survive, const struct SurviveSimpleButtonEvent *e, int64_t now) +_process_button_event(struct survive_device *survive, const struct SurviveSimpleButtonEvent *e) { + timepoint_ns ts = survive_timecode_to_monotonic(e->time); + ; if (e->event_type == SURVIVE_INPUT_EVENT_AXIS_CHANGED) { for (int i = 0; i < e->axis_count; i++) { struct Axis *axis = &axes[e->axis_ids[i]]; float val = e->axis_val[i]; - if (update_axis(survive, axis, e, i, now)) { + if (update_axis(survive, axis, e, i, ts)) { } else if (e->axis_ids[i] == SURVIVE_AXIS_TRIGGER_FINGER_PROXIMITY) { survive->ctrl.curl[XRT_FINGER_INDEX] = val; - survive->ctrl.curl_ts[XRT_FINGER_INDEX] = now; + survive->ctrl.curl_ts[XRT_FINGER_INDEX] = ts; } else if (e->axis_ids[i] == SURVIVE_AXIS_MIDDLE_FINGER_PROXIMITY) { survive->ctrl.curl[XRT_FINGER_MIDDLE] = val; - survive->ctrl.curl_ts[XRT_FINGER_MIDDLE] = now; + survive->ctrl.curl_ts[XRT_FINGER_MIDDLE] = ts; } else if (e->axis_ids[i] == SURVIVE_AXIS_RING_FINGER_PROXIMITY) { survive->ctrl.curl[XRT_FINGER_RING] = val; - survive->ctrl.curl_ts[XRT_FINGER_RING] = now; + survive->ctrl.curl_ts[XRT_FINGER_RING] = ts; } else if (e->axis_ids[i] == SURVIVE_AXIS_PINKY_FINGER_PROXIMITY) { survive->ctrl.curl[XRT_FINGER_LITTLE] = val; - survive->ctrl.curl_ts[XRT_FINGER_LITTLE] = now; + survive->ctrl.curl_ts[XRT_FINGER_LITTLE] = ts; } else { SURVIVE_DEBUG(survive, "axis id: %d val %f", e->axis_ids[i], e->axis_val[i]); } @@ -675,15 +615,15 @@ _process_button_event(struct survive_device *survive, const struct SurviveSimple float squeeze_value = _calculate_squeeze_value(survive); if (prev_squeeze_value != squeeze_value) { squeeze_value_in->value.vec1.x = squeeze_value; - squeeze_value_in->timestamp = now; + squeeze_value_in->timestamp = ts; } } - update_button(survive, e, now); + update_button(survive, e, ts); } static void -_process_hmd_button_event(struct survive_device *survive, const struct SurviveSimpleButtonEvent *e, int64_t now) +_process_hmd_button_event(struct survive_device *survive, const struct SurviveSimpleButtonEvent *e) { if (e->event_type == SURVIVE_INPUT_EVENT_AXIS_CHANGED) { for (int i = 0; i < e->axis_count; i++) { @@ -735,7 +675,7 @@ get_device_by_object(struct survive_system *sys, const SurviveSimpleObject *obje return sys->hmd; } - for (int i = 0; i < CONTROLLER_COUNT; i++) { + for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) { if (sys->controllers[i] == NULL) { continue; } @@ -748,15 +688,26 @@ get_device_by_object(struct survive_system *sys, const SurviveSimpleObject *obje } static void -_process_event(struct survive_device *survive, struct SurviveSimpleEvent *event, int64_t now) +add_device(struct survive_system *ss, const struct SurviveSimpleConfigEvent *e); + +static void +_process_pose_event(struct survive_device *survive, const struct SurviveSimplePoseUpdatedEvent *e) +{ + pose_to_relation(&e->pose, &e->velocity, &survive->last_relation); + survive->last_relation_ts = survive_timecode_to_monotonic(e->time); +} + +static void +_process_event(struct survive_system *ss, struct survive_device *survive, struct SurviveSimpleEvent *event) { switch (event->event_type) { case SurviveSimpleEventType_ButtonEvent: { const struct SurviveSimpleButtonEvent *e = survive_simple_get_button_event(event); - struct survive_device *event_device = survive; - - if (e->object != survive->survive_obj) { + struct survive_device *event_device = NULL; + if (e->object == survive->survive_obj) { + event_device = survive; + } else { event_device = get_device_by_object(survive->sys, e->object); } @@ -767,13 +718,40 @@ _process_event(struct survive_device *survive, struct SurviveSimpleEvent *event, // hmd & controller axes have overlapping enum indices if (event_device == survive->sys->hmd) { - _process_hmd_button_event(event_device, e, now); + _process_hmd_button_event(event_device, e); } else { - _process_button_event(event_device, e, now); + _process_button_event(event_device, e); } break; } + case SurviveSimpleEventType_ConfigEvent: { + const struct SurviveSimpleConfigEvent *e = survive_simple_get_config_event(event); + add_device(ss, e); + break; + } + case SurviveSimpleEventType_PoseUpdateEvent: { + const struct SurviveSimplePoseUpdatedEvent *e = survive_simple_get_pose_updated_event(event); + + struct survive_device *event_device = NULL; + if (e->object == survive->survive_obj) { + event_device = survive; + } else { + event_device = get_device_by_object(survive->sys, e->object); + } + + if (event_device == NULL) { + SURVIVE_ERROR(survive, "Pose Event for unknown object not handled"); + return; + } + + _process_pose_event(event_device, e); + break; + } + case SurviveSimpleEventType_DeviceAdded: { + SURVIVE_WARN(survive, "Device added event, but hotplugging not implemented yet"); + break; + } case SurviveSimpleEventType_None: break; default: SURVIVE_ERROR(survive, "Unknown event %d", event->event_type); } @@ -785,36 +763,15 @@ survive_device_update_inputs(struct xrt_device *xdev) { struct survive_device *survive = (struct survive_device *)xdev; - uint64_t now = os_monotonic_get_ns(); - /* one event queue for all devices. _process_events() updates all devices, not just this survive device. */ struct SurviveSimpleEvent event = {0}; while (survive_simple_next_event(survive->sys->ctx, &event) != SurviveSimpleEventType_None) { - _process_event(survive, &event, now); + _process_event(NULL, survive, &event); } } -static bool -wait_for_device_config(const struct SurviveSimpleObject *sso) -{ - // if not backed by a survive object, we will never get a config - if (!survive_has_obj(sso)) { - return false; - } - - double start = time_ns_to_s(os_monotonic_get_ns()); - do { - if (survive_config_ready(sso)) { - return true; - } - os_nanosleep(1000 * 1000 * 100); - } while (time_ns_to_s(os_monotonic_get_ns()) - start < WAIT_TIMEOUT); - - return false; -} - static bool compute_distortion(struct xrt_device *xdev, int view, float u, float v, struct xrt_uv_triplet *result) { @@ -823,7 +780,7 @@ compute_distortion(struct xrt_device *xdev, int view, float u, float v, struct x } static bool -_create_hmd_device(struct survive_system *sys, enum VIVE_VARIANT variant, const SurviveSimpleObject *sso) +_create_hmd_device(struct survive_system *sys, const struct SurviveSimpleObject *sso, struct vive_config *config) { enum u_device_alloc_flags flags = (enum u_device_alloc_flags)U_DEVICE_ALLOC_HMD; int inputs = 1; @@ -834,7 +791,6 @@ _create_hmd_device(struct survive_system *sys, enum VIVE_VARIANT variant, const sys->hmd = survive; survive->sys = sys; survive->survive_obj = sso; - survive->hmd.variant = variant; survive->base.name = XRT_DEVICE_GENERIC_HMD; snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive HMD"); @@ -848,12 +804,7 @@ _create_hmd_device(struct survive_system *sys, enum VIVE_VARIANT variant, const survive->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; - char *json_string = survive_get_json_config(survive->survive_obj); - - survive->hmd.config.ll = survive->sys->ll; - // usb connected HMD variant is known because of USB id, config parsing relies on it. - survive->hmd.config.variant = survive->hmd.variant; - vive_config_parse(&survive->hmd.config, json_string); + survive->hmd.config = *config; // TODO: Replace hard coded values from OpenHMD with config double w_meters = 0.122822 / 2.0; @@ -870,7 +821,7 @@ _create_hmd_device(struct survive_system *sys, enum VIVE_VARIANT variant, const survive->base.hmd->screens[0].w_pixels = (int)w_pixels * 2; survive->base.hmd->screens[0].h_pixels = (int)h_pixels; - if (survive->hmd.variant == VIVE_VARIANT_INDEX) { + if (survive->hmd.config.variant == VIVE_VARIANT_INDEX) { lens_horizontal_separation = 0.06; h_meters = 0.07; // eye relief knob adjusts this around [0.0255(near)-0.275(far)] @@ -996,24 +947,24 @@ _create_controller_device(struct survive_system *sys, int idx = -1; if (variant == CONTROLLER_VIVE_WAND) { - if (sys->controllers[SURVIVE_LEFT_CONTROLLER] == NULL) { - idx = SURVIVE_LEFT_CONTROLLER; - } else if (sys->controllers[SURVIVE_RIGHT_CONTROLLER] == NULL) { - idx = SURVIVE_RIGHT_CONTROLLER; + if (sys->controllers[SURVIVE_LEFT_CONTROLLER_INDEX] == NULL) { + idx = SURVIVE_LEFT_CONTROLLER_INDEX; + } else if (sys->controllers[SURVIVE_RIGHT_CONTROLLER_INDEX] == NULL) { + idx = SURVIVE_RIGHT_CONTROLLER_INDEX; } else { U_LOG_IFL_E(sys->ll, "Only creating 2 controllers!"); return false; } } else if (variant == CONTROLLER_INDEX_LEFT) { - if (sys->controllers[SURVIVE_LEFT_CONTROLLER] == NULL) { - idx = SURVIVE_LEFT_CONTROLLER; + if (sys->controllers[SURVIVE_LEFT_CONTROLLER_INDEX] == NULL) { + idx = SURVIVE_LEFT_CONTROLLER_INDEX; } else { U_LOG_IFL_E(sys->ll, "Only creating 1 left controller!"); return false; } } else if (variant == CONTROLLER_INDEX_RIGHT) { - if (sys->controllers[SURVIVE_RIGHT_CONTROLLER] == NULL) { - idx = SURVIVE_RIGHT_CONTROLLER; + if (sys->controllers[SURVIVE_RIGHT_CONTROLLER_INDEX] == NULL) { + idx = SURVIVE_RIGHT_CONTROLLER_INDEX; } else { U_LOG_IFL_E(sys->ll, "Only creating 1 right controller!"); return false; @@ -1034,10 +985,8 @@ _create_controller_device(struct survive_system *sys, sys->controllers[idx] = survive; survive->sys = sys; - survive->ctrl.variant = variant; survive->survive_obj = sso; - survive->num = idx; survive->base.tracking_origin = &sys->base; survive->base.destroy = survive_device_destroy; @@ -1086,7 +1035,7 @@ _create_controller_device(struct survive_system *sys, survive->base.get_hand_tracking = survive_controller_get_hand_tracking; - enum xrt_hand hand = idx == SURVIVE_LEFT_CONTROLLER ? XRT_HAND_LEFT : XRT_HAND_RIGHT; + enum xrt_hand hand = idx == SURVIVE_LEFT_CONTROLLER_INDEX ? XRT_HAND_LEFT : XRT_HAND_RIGHT; u_hand_joints_init_default_set(&survive->ctrl.hand_tracking, hand, XRT_HAND_TRACKING_MODEL_FINGERL_CURL, 1.0); @@ -1097,7 +1046,7 @@ _create_controller_device(struct survive_system *sys, survive->base.hand_tracking_supported = true; - } else if (survive->ctrl.variant == CONTROLLER_VIVE_WAND) { + } else if (survive->ctrl.config.variant == CONTROLLER_VIVE_WAND) { survive->base.name = XRT_DEVICE_VIVE_WAND; snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Vive Wand Controller %d", idx); @@ -1131,17 +1080,70 @@ _create_controller_device(struct survive_system *sys, DEBUG_GET_ONCE_LOG_OPTION(survive_log, "SURVIVE_LOG", U_LOGGING_WARN) -static enum VIVE_VARIANT -_product_to_variant(uint16_t product_id) +static void +add_device(struct survive_system *ss, const struct SurviveSimpleConfigEvent *e) { - switch (product_id) { - case VIVE_PID: return VIVE_VARIANT_VIVE; - case VIVE_PRO_MAINBOARD_PID: return VIVE_VARIANT_PRO; - case VIVE_PRO_LHR_PID: return VIVE_VARIANT_INDEX; - default: U_LOG_W("No product ids matched %.4x", product_id); return VIVE_UNKNOWN; + struct SurviveSimpleObject *sso = e->object; + + U_LOG_IFL_D(ss->ll, "Got device config from survive"); + + enum SurviveSimpleObject_type type = survive_simple_object_get_type(sso); + + char *conf_str = (char *)survive_simple_json_config(sso); + + if (type == SurviveSimpleObject_HMD) { + + struct vive_config config = {.ll = ss->ll}; + vive_config_parse(&config, conf_str); + _create_hmd_device(ss, sso, &config); + + } else if (type == SurviveSimpleObject_OBJECT) { + struct vive_controller_config config = {.ll = ss->ll}; + vive_config_parse_controller(&config, conf_str); + + switch (config.variant) { + case CONTROLLER_VIVE_WAND: + case CONTROLLER_INDEX_LEFT: + case CONTROLLER_INDEX_RIGHT: + U_LOG_IFL_D(ss->ll, "Adding controller."); + _create_controller_device(ss, sso, &config); + break; + default: + U_LOG_IFL_D(ss->ll, "Skip non controller obj."); + U_LOG_IFL_T(ss->ll, "json: %s", conf_str); + break; + } + } else { + U_LOG_IFL_D(ss->ll, "Skip non OBJECT obj."); } } +static bool +add_connected_devices(struct survive_system *ss) +{ + timepoint_ns start = os_monotonic_get_ns(); + + while (true) { + struct SurviveSimpleEvent event = {0}; + while (survive_simple_next_event(ss->ctx, &event) != SurviveSimpleEventType_None) { + if (event.event_type == SurviveSimpleEventType_ConfigEvent) { + _process_event(ss, NULL, &event); + + // libsurvive processes sequentially, restart timeout + start = os_monotonic_get_ns(); + } else { + U_LOG_IFL_D(ss->ll, "Skipping event\n"); + } + } + + if (time_ns_to_s(os_monotonic_get_ns() - start) > WAIT_TIMEOUT) { + break; + } + os_nanosleep(1000); + } + return true; +} + int survive_found(struct xrt_prober *xp, struct xrt_prober_device **devices, @@ -1177,8 +1179,6 @@ survive_found(struct xrt_prober *xp, struct survive_system *ss = U_TYPED_CALLOC(struct survive_system); - struct xrt_prober_device *dev = devices[index]; - survive_simple_start_thread(actx); ss->ctx = actx; @@ -1191,46 +1191,9 @@ survive_found(struct xrt_prober *xp, ss->ll = debug_get_log_option_survive_log(); - /* iterate over all devices, if SurviveSimpleObject_OBJECT parse config - * and if controller, add it with variant from config. - */ - for (const SurviveSimpleObject *it = survive_simple_get_first_object(ss->ctx); it != 0; - it = survive_simple_get_next_object(ss->ctx, it)) { - - if (!wait_for_device_config(it)) { - U_LOG_IFL_E(ss->ll, "Failed to get device config from survive"); - continue; - } - - U_LOG_IFL_D(ss->ll, "Got device config from survive"); - - enum SurviveSimpleObject_type type = survive_simple_object_get_type(it); - - if (type == SurviveSimpleObject_HMD) { - enum VIVE_VARIANT variant = _product_to_variant(dev->product_id); - U_LOG_I("survive HMD: Assuming variant %d", variant); - _create_hmd_device(ss, variant, it); - } else if (type == SurviveSimpleObject_OBJECT) { - char *json_string = survive_get_json_config(it); - - struct vive_controller_config config = {.ll = ss->ll}; - vive_config_parse_controller(&config, json_string); - - switch (config.variant) { - case CONTROLLER_VIVE_WAND: - case CONTROLLER_INDEX_LEFT: - case CONTROLLER_INDEX_RIGHT: - U_LOG_IFL_D(ss->ll, "Adding controller."); - _create_controller_device(ss, it, &config); - break; - default: - U_LOG_IFL_D(ss->ll, "Skip non controller obj."); - U_LOG_IFL_T(ss->ll, "json: %s", json_string); - break; - } - } else { - U_LOG_IFL_D(ss->ll, "Skip non OBJECT obj."); - } + while (!add_connected_devices(ss)) { + U_LOG_IFL_E(ss->ll, "Failed to get device config from survive"); + continue; } // U_LOG_D("Survive HMD %p, controller %p %p", (void *)ss->hmd, @@ -1246,11 +1209,11 @@ survive_found(struct xrt_prober *xp, if (ss->hmd) { out_xdevs[out_idx++] = &ss->hmd->base; } - if (&ss->controllers[SURVIVE_LEFT_CONTROLLER]) { - out_xdevs[out_idx++] = &ss->controllers[SURVIVE_LEFT_CONTROLLER]->base; + if (&ss->controllers[SURVIVE_LEFT_CONTROLLER_INDEX]) { + out_xdevs[out_idx++] = &ss->controllers[SURVIVE_LEFT_CONTROLLER_INDEX]->base; } - if (&ss->controllers[SURVIVE_LEFT_CONTROLLER]) { - out_xdevs[out_idx++] = &ss->controllers[SURVIVE_RIGHT_CONTROLLER]->base; + if (&ss->controllers[SURVIVE_LEFT_CONTROLLER_INDEX]) { + out_xdevs[out_idx++] = &ss->controllers[SURVIVE_RIGHT_CONTROLLER_INDEX]->base; } survive_already_initialized = true; diff --git a/src/xrt/drivers/survive/survive_wrap.c b/src/xrt/drivers/survive/survive_wrap.c deleted file mode 100644 index a58f4586b..000000000 --- a/src/xrt/drivers/survive/survive_wrap.c +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2020, Collabora, Ltd. -// SPDX-License-Identifier: BSL-1.0 -/*! - * @file - * @brief low level libsurvive wrapper - * @author Christoph Haag - * @ingroup drv_survive - */ - -#define SURVIVE_ENABLE_FULL_API 1 -#include "survive_api.h" - -#include "survive_wrap.h" - - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wignored-qualifiers" - -// TODO: expose config values we need through actual survive API -#include "survive.h" - -#pragma GCC diagnostic pop - -bool -survive_has_obj(const SurviveSimpleObject *sso) -{ - SurviveObject *so = survive_simple_get_survive_object(sso); - return so != NULL; -} - -bool -survive_config_ready(const SurviveSimpleObject *sso) -{ - SurviveObject *so = survive_simple_get_survive_object(sso); - return so && so->conf != 0; -} - -char * -survive_get_json_config(const SurviveSimpleObject *sso) -{ - SurviveObject *so = survive_simple_get_survive_object(sso); - return so->conf; -} diff --git a/src/xrt/drivers/survive/survive_wrap.h b/src/xrt/drivers/survive/survive_wrap.h deleted file mode 100644 index 9bf69e28b..000000000 --- a/src/xrt/drivers/survive/survive_wrap.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2020, Collabora, Ltd. -// SPDX-License-Identifier: BSL-1.0 -/*! - * @file - * @brief low level libsurvive wrapper - * @author Christoph Haag - * @ingroup drv_survive - */ - -#pragma once - -#include "survive_api.h" - -bool -survive_has_obj(const SurviveSimpleObject *sso); - -bool -survive_config_ready(const SurviveSimpleObject *sso); - -char * -survive_get_json_config(const SurviveSimpleObject *sso); From 47ed26a5e89746de467933b84c0a449eb718949b Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 8 Feb 2021 22:33:05 +0100 Subject: [PATCH 038/883] xrt: Add XRT_INPUT_GENERIC_TRACKER_POSE --- src/xrt/include/xrt/xrt_defines.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xrt/include/xrt/xrt_defines.h b/src/xrt/include/xrt/xrt_defines.h index 04d8cf6c8..61523d0ae 100644 --- a/src/xrt/include/xrt/xrt_defines.h +++ b/src/xrt/include/xrt/xrt_defines.h @@ -508,6 +508,7 @@ enum xrt_input_name XRT_INPUT_GENERIC_HEAD_DETECT = XRT_INPUT_NAME(0x0001, BOOLEAN), XRT_INPUT_GENERIC_HAND_TRACKING_LEFT = XRT_INPUT_NAME(0x0002, HAND_TRACKING), XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT = XRT_INPUT_NAME(0x0004, HAND_TRACKING), + XRT_INPUT_GENERIC_TRACKER_POSE = XRT_INPUT_NAME(0x0005, POSE), XRT_INPUT_SIMPLE_SELECT_CLICK = XRT_INPUT_NAME(0x0010, BOOLEAN), XRT_INPUT_SIMPLE_MENU_CLICK = XRT_INPUT_NAME(0x0011, BOOLEAN), From 9760f6d123d637b8a049fb86e992e0d5bf51a0b6 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 8 Feb 2021 22:35:02 +0100 Subject: [PATCH 039/883] d/survive: Create devices for trackers They can not be queried yet. --- src/xrt/drivers/survive/survive_driver.c | 85 +++++++++++++++++------- 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index 7c32202ef..2977236a6 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -48,6 +48,7 @@ // index in sys->controllers[] array #define SURVIVE_LEFT_CONTROLLER_INDEX 0 #define SURVIVE_RIGHT_CONTROLLER_INDEX 1 +#define SURVIVE_NON_CONTROLLER_START 2 //! excl HMD we support 16 devices (controllers, trackers, ...) #define MAX_TRACKED_DEVICE_COUNT 16 @@ -95,9 +96,17 @@ enum input_index VIVE_CONTROLLER_HAND_TRACKING, + VIVE_TRACKER_POSE, + VIVE_CONTROLLER_MAX_INDEX, }; +enum DeviceType +{ + DEVICE_TYPE_HMD, + DEVICE_TYPE_CONTROLLER +}; + /*! * @implements xrt_device */ @@ -110,6 +119,8 @@ struct survive_device struct xrt_space_relation last_relation; timepoint_ns last_relation_ts; + enum DeviceType device_type; + union { struct { @@ -157,22 +168,14 @@ survive_device_destroy(struct xrt_device *xdev) } } - //! @todo: For now tear libsurvive down without expliclity destroying trackers bool all_null = true; - if (survive->sys->controllers[CONTROLLER_INDEX_LEFT] != NULL) { - all_null = false; - } - if (survive->sys->controllers[CONTROLLER_INDEX_RIGHT] != NULL) { - all_null = false; + for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) { + if (survive->sys->controllers[i] != 0) { + all_null = false; + } } if (survive->sys->hmd == NULL && all_null) { - - //! @todo we don't explicitly destroy trackers yet - for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) { - survive->sys->controllers[i] = 0; - } - U_LOG_D("Tearing down libsurvive context"); survive_simple_close(survive->sys->ctx); @@ -277,6 +280,20 @@ _predict_pose(struct survive_device *survive, uint64_t at_timestamp_ns, struct x m_predict_relation(&survive->last_relation, prediction_s, out_relation); } +static bool +verify_device_name(struct survive_device *survive, enum xrt_input_name name) +{ + + switch (survive->device_type) { + case DEVICE_TYPE_HMD: return name == XRT_INPUT_GENERIC_HEAD_POSE; + case DEVICE_TYPE_CONTROLLER: + return name == XRT_INPUT_INDEX_AIM_POSE || name == XRT_INPUT_INDEX_GRIP_POSE || + name == XRT_INPUT_VIVE_AIM_POSE || name == XRT_INPUT_VIVE_GRIP_POSE || + name == XRT_INPUT_GENERIC_TRACKER_POSE; + }; + return false; +} + static void survive_device_get_tracked_pose(struct xrt_device *xdev, enum xrt_input_name name, @@ -284,11 +301,7 @@ survive_device_get_tracked_pose(struct xrt_device *xdev, struct xrt_space_relation *out_relation) { struct survive_device *survive = (struct survive_device *)xdev; - if ((survive == survive->sys->hmd && name != XRT_INPUT_GENERIC_HEAD_POSE) || - ((survive == survive->sys->controllers[0] || survive == survive->sys->controllers[1]) && - (name != XRT_INPUT_INDEX_AIM_POSE && name != XRT_INPUT_INDEX_GRIP_POSE) && - (name != XRT_INPUT_VIVE_AIM_POSE && name != XRT_INPUT_VIVE_GRIP_POSE))) { - + if (!verify_device_name(survive, name)) { SURVIVE_ERROR(survive, "unknown input name"); return; } @@ -695,6 +708,7 @@ _process_pose_event(struct survive_device *survive, const struct SurviveSimplePo { pose_to_relation(&e->pose, &e->velocity, &survive->last_relation); survive->last_relation_ts = survive_timecode_to_monotonic(e->time); + SURVIVE_TRACE(survive, "Process pose event for %s", survive->base.str); } static void @@ -791,6 +805,7 @@ _create_hmd_device(struct survive_system *sys, const struct SurviveSimpleObject sys->hmd = survive; survive->sys = sys; survive->survive_obj = sso; + survive->device_type = DEVICE_TYPE_HMD; survive->base.name = XRT_DEVICE_GENERIC_HMD; snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive HMD"); @@ -969,6 +984,13 @@ _create_controller_device(struct survive_system *sys, U_LOG_IFL_E(sys->ll, "Only creating 1 right controller!"); return false; } + } else if (variant == CONTROLLER_TRACKER_GEN1 || variant == CONTROLLER_TRACKER_GEN2) { + for (int i = SURVIVE_NON_CONTROLLER_START; i < MAX_TRACKED_DEVICE_COUNT; i++) { + if (sys->controllers[i] == NULL) { + idx = i; + break; + } + } } if (idx == -1) { @@ -986,6 +1008,7 @@ _create_controller_device(struct survive_system *sys, sys->controllers[idx] = survive; survive->sys = sys; survive->survive_obj = sso; + survive->device_type = DEVICE_TYPE_CONTROLLER; survive->base.tracking_origin = &sys->base; @@ -1068,6 +1091,18 @@ _create_controller_device(struct survive_system *sys, survive->base.num_binding_profiles = ARRAY_SIZE(binding_profiles_vive); survive->base.device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER; + } else if (survive->ctrl.config.variant == CONTROLLER_TRACKER_GEN1 || + survive->ctrl.config.variant == CONTROLLER_TRACKER_GEN2) { + if (survive->ctrl.config.variant == CONTROLLER_TRACKER_GEN1) { + survive->base.name = XRT_DEVICE_VIVE_TRACKER_GEN1; + } else if (survive->ctrl.config.variant == CONTROLLER_TRACKER_GEN2) { + survive->base.name = XRT_DEVICE_VIVE_TRACKER_GEN2; + } + snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Vive Tracker %d", idx); + + survive->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER; + + survive->base.inputs[VIVE_TRACKER_POSE].name = XRT_INPUT_GENERIC_TRACKER_POSE; } survive->base.orientation_tracking_supported = true; @@ -1105,11 +1140,13 @@ add_device(struct survive_system *ss, const struct SurviveSimpleConfigEvent *e) case CONTROLLER_VIVE_WAND: case CONTROLLER_INDEX_LEFT: case CONTROLLER_INDEX_RIGHT: - U_LOG_IFL_D(ss->ll, "Adding controller."); + case CONTROLLER_TRACKER_GEN1: + case CONTROLLER_TRACKER_GEN2: + U_LOG_IFL_D(ss->ll, "Adding controller: %s.", config.firmware.model_number); _create_controller_device(ss, sso, &config); break; default: - U_LOG_IFL_D(ss->ll, "Skip non controller obj."); + U_LOG_IFL_D(ss->ll, "Skip non controller obj %s.", config.firmware.model_number); U_LOG_IFL_T(ss->ll, "json: %s", conf_str); break; } @@ -1209,11 +1246,11 @@ survive_found(struct xrt_prober *xp, if (ss->hmd) { out_xdevs[out_idx++] = &ss->hmd->base; } - if (&ss->controllers[SURVIVE_LEFT_CONTROLLER_INDEX]) { - out_xdevs[out_idx++] = &ss->controllers[SURVIVE_LEFT_CONTROLLER_INDEX]->base; - } - if (&ss->controllers[SURVIVE_LEFT_CONTROLLER_INDEX]) { - out_xdevs[out_idx++] = &ss->controllers[SURVIVE_RIGHT_CONTROLLER_INDEX]->base; + + for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) { + if (ss->controllers[i] != NULL) { + out_xdevs[out_idx++] = &ss->controllers[i]->base; + } } survive_already_initialized = true; From ea6d6bfb3f1f38fdd5449f48adf90c7b142f4c62 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 8 Feb 2021 22:44:13 +0100 Subject: [PATCH 040/883] d/rs: Use XRT_INPUT_GENERIC_TRACKER_POSE instead of XRT_INPUT_GENERIC_HEAD_POSE --- src/xrt/drivers/north_star/ns_hmd.c | 12 ++++++------ src/xrt/drivers/realsense/rs_6dof.c | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/xrt/drivers/north_star/ns_hmd.c b/src/xrt/drivers/north_star/ns_hmd.c index a3c080367..c67c43e7d 100644 --- a/src/xrt/drivers/north_star/ns_hmd.c +++ b/src/xrt/drivers/north_star/ns_hmd.c @@ -86,15 +86,15 @@ ns_hmd_get_tracked_pose(struct xrt_device *xdev, { struct ns_hmd *ns = ns_hmd(xdev); - - // If the tracking device is created use it. - if (ns->tracker != NULL) { - xrt_device_get_tracked_pose(ns->tracker, name, at_timestamp_ns, out_relation); + if (name != XRT_INPUT_GENERIC_HEAD_POSE) { + NS_ERROR(ns, "unknown input name"); return; } - if (name != XRT_INPUT_GENERIC_HEAD_POSE) { - NS_ERROR(ns, "unknown input name"); + // If the tracking device is created use it. + if (ns->tracker != NULL) { + enum xrt_input_name tracker_name = XRT_INPUT_GENERIC_TRACKER_POSE; + xrt_device_get_tracked_pose(ns->tracker, tracker_name, at_timestamp_ns, out_relation); return; } diff --git a/src/xrt/drivers/realsense/rs_6dof.c b/src/xrt/drivers/realsense/rs_6dof.c index 67d5265fe..3ab9e1dbe 100644 --- a/src/xrt/drivers/realsense/rs_6dof.c +++ b/src/xrt/drivers/realsense/rs_6dof.c @@ -324,7 +324,7 @@ rs_6dof_get_tracked_pose(struct xrt_device *xdev, { struct rs_6dof *rs = rs_6dof(xdev); - if (name != XRT_INPUT_GENERIC_HEAD_POSE) { + if (name != XRT_INPUT_GENERIC_TRACKER_POSE) { U_LOG_E("unknown input name"); return; } @@ -386,8 +386,7 @@ rs_6dof_create(void) // Print name. snprintf(rs->base.str, XRT_DEVICE_NAME_LEN, "Intel RealSense 6-DOF"); - // Setup input, this is a lie. - rs->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; + rs->base.inputs[0].name = XRT_INPUT_GENERIC_TRACKER_POSE; // Thread and other state. ret = os_thread_helper_init(&rs->oth); From c67a6ccd3498a1cceea974645fd6440edad9c74e Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Tue, 9 Feb 2021 01:15:55 +0100 Subject: [PATCH 041/883] xrt: Add xrt_device::serial for uniquely identifying devices if possible d: Make controller serials unique by appending number For drivers that do not (yet) know a persistent unique id per device. --- src/xrt/drivers/android/android_sensors.c | 1 + src/xrt/drivers/arduino/arduino_device.c | 4 ++++ src/xrt/drivers/daydream/daydream_device.c | 4 ++++ src/xrt/drivers/dummy/dummy_hmd.c | 1 + src/xrt/drivers/hdk/hdk_device.cpp | 1 + src/xrt/drivers/ht/ht_driver.c | 4 +++- src/xrt/drivers/hydra/hydra_driver.c | 1 + src/xrt/drivers/illixr/illixr_device.cpp | 1 + src/xrt/drivers/north_star/ns_hmd.c | 1 + src/xrt/drivers/ohmd/oh_device.c | 1 + src/xrt/drivers/psmv/psmv_driver.c | 3 +++ src/xrt/drivers/psvr/psvr_device.c | 1 + src/xrt/drivers/realsense/rs_6dof.c | 1 + src/xrt/drivers/remote/r_device.c | 1 + src/xrt/drivers/remote/r_hmd.c | 1 + src/xrt/drivers/survive/survive_driver.c | 10 +++++++++- src/xrt/drivers/vive/vive_controller.c | 3 ++- src/xrt/drivers/vive/vive_device.c | 3 +++ src/xrt/include/xrt/xrt_device.h | 3 +++ src/xrt/targets/cli/cli_cmd_probe.c | 2 +- 20 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/xrt/drivers/android/android_sensors.c b/src/xrt/drivers/android/android_sensors.c index bad38b5b7..00159a809 100644 --- a/src/xrt/drivers/android/android_sensors.c +++ b/src/xrt/drivers/android/android_sensors.c @@ -225,6 +225,7 @@ android_device_create() d->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; d->base.device_type = XRT_DEVICE_TYPE_HMD; snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "Android Sensors"); + snprintf(d->base.serial, XRT_DEVICE_NAME_LEN, "Android Sensors"); d->ll = debug_get_log_option_android_log(); diff --git a/src/xrt/drivers/arduino/arduino_device.c b/src/xrt/drivers/arduino/arduino_device.c index 125764a14..53a2c5242 100644 --- a/src/xrt/drivers/arduino/arduino_device.c +++ b/src/xrt/drivers/arduino/arduino_device.c @@ -390,6 +390,10 @@ arduino_device_create(struct os_ble_device *ble) ad->base.binding_profiles = binding_profiles; ad->base.num_binding_profiles = ARRAY_SIZE(binding_profiles); + static int controller_num = 0; + snprintf(ad->base.str, XRT_DEVICE_NAME_LEN, "Arduino"); + snprintf(ad->base.serial, XRT_DEVICE_NAME_LEN, "Arduino %d", controller_num++); + ad->ble = ble; ad->ll = debug_get_log_option_arduino_log(); diff --git a/src/xrt/drivers/daydream/daydream_device.c b/src/xrt/drivers/daydream/daydream_device.c index 0fc221cf6..3e6ac9dcc 100644 --- a/src/xrt/drivers/daydream/daydream_device.c +++ b/src/xrt/drivers/daydream/daydream_device.c @@ -370,6 +370,10 @@ daydream_device_create(struct os_ble_device *ble) dd->base.binding_profiles = binding_profiles; dd->base.num_binding_profiles = ARRAY_SIZE(binding_profiles); + static int controller_num = 0; + snprintf(dd->base.str, XRT_DEVICE_NAME_LEN, "Daydream"); + snprintf(dd->base.serial, XRT_DEVICE_NAME_LEN, "Daydream %d", controller_num++); + dd->ble = ble; dd->ll = debug_get_log_option_daydream_log(); diff --git a/src/xrt/drivers/dummy/dummy_hmd.c b/src/xrt/drivers/dummy/dummy_hmd.c index babe5bb68..ad4b030b1 100644 --- a/src/xrt/drivers/dummy/dummy_hmd.c +++ b/src/xrt/drivers/dummy/dummy_hmd.c @@ -165,6 +165,7 @@ dummy_hmd_create(void) // Print name. snprintf(dh->base.str, XRT_DEVICE_NAME_LEN, "Dummy HMD"); + snprintf(dh->base.serial, XRT_DEVICE_NAME_LEN, "Dummy HMD"); // Setup input. dh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; diff --git a/src/xrt/drivers/hdk/hdk_device.cpp b/src/xrt/drivers/hdk/hdk_device.cpp index 90f3e6efb..b30751e52 100644 --- a/src/xrt/drivers/hdk/hdk_device.cpp +++ b/src/xrt/drivers/hdk/hdk_device.cpp @@ -326,6 +326,7 @@ hdk_device_create(struct os_hid_device *dev, enum HDK_VARIANT variant) hd->ll = debug_get_log_option_hdk_log(); snprintf(hd->base.str, XRT_DEVICE_NAME_LEN, "OSVR HDK-family Device"); + snprintf(hd->base.serial, XRT_DEVICE_NAME_LEN, "OSVR HDK-family Device"); if (variant == HDK_UNKNOWN) { HDK_ERROR(hd, "Don't know which HDK variant this is."); diff --git a/src/xrt/drivers/ht/ht_driver.c b/src/xrt/drivers/ht/ht_driver.c index 9df1a716f..ec1406060 100644 --- a/src/xrt/drivers/ht/ht_driver.c +++ b/src/xrt/drivers/ht/ht_driver.c @@ -12,6 +12,7 @@ #include "util/u_var.h" #include "util/u_debug.h" #include +#include struct ht_device { @@ -118,7 +119,8 @@ ht_device_create(struct xrt_auto_prober *xap, cJSON *attached_data, struct xrt_p htd->base.get_hand_tracking = ht_device_get_hand_tracking; htd->base.destroy = ht_device_destroy; - strncpy(htd->base.str, "Camera based Hand Tracker", XRT_DEVICE_NAME_LEN); + snprintf(htd->base.str, XRT_DEVICE_NAME_LEN, "Camera based Hand Tracker"); + snprintf(htd->base.serial, XRT_DEVICE_NAME_LEN, "Camera based Hand Tracker"); htd->base.inputs[0].name = XRT_INPUT_GENERIC_HAND_TRACKING_LEFT; htd->base.inputs[1].name = XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT; diff --git a/src/xrt/drivers/hydra/hydra_driver.c b/src/xrt/drivers/hydra/hydra_driver.c index 40d3d7b2d..174d82bdf 100644 --- a/src/xrt/drivers/hydra/hydra_driver.c +++ b/src/xrt/drivers/hydra/hydra_driver.c @@ -625,6 +625,7 @@ hydra_found(struct xrt_prober *xp, // hs->base.set_output = hydra_device_set_output; hd->base.name = XRT_DEVICE_HYDRA; snprintf(hd->base.str, XRT_DEVICE_NAME_LEN, "%s %i", "Razer Hydra Controller", (int)(i + 1)); + snprintf(hd->base.serial, XRT_DEVICE_NAME_LEN, "%s %i", "Razer Hydra Controller", (int)(i + 1)); SET_INPUT(1_CLICK); SET_INPUT(2_CLICK); SET_INPUT(3_CLICK); diff --git a/src/xrt/drivers/illixr/illixr_device.cpp b/src/xrt/drivers/illixr/illixr_device.cpp index 81b22f8ac..2e69b31b7 100644 --- a/src/xrt/drivers/illixr/illixr_device.cpp +++ b/src/xrt/drivers/illixr/illixr_device.cpp @@ -186,6 +186,7 @@ illixr_hmd_create(const char *path_in, const char *comp_in) // Print name. snprintf(dh->base.str, XRT_DEVICE_NAME_LEN, "ILLIXR"); + snprintf(dh->base.serial, XRT_DEVICE_NAME_LEN, "ILLIXR"); // Setup input. dh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; diff --git a/src/xrt/drivers/north_star/ns_hmd.c b/src/xrt/drivers/north_star/ns_hmd.c index c67c43e7d..1b9efa7c5 100644 --- a/src/xrt/drivers/north_star/ns_hmd.c +++ b/src/xrt/drivers/north_star/ns_hmd.c @@ -501,6 +501,7 @@ ns_hmd_create(const char *config_path) // Print name. snprintf(ns->base.str, XRT_DEVICE_NAME_LEN, "North Star"); + snprintf(ns->base.serial, XRT_DEVICE_NAME_LEN, "North Star"); // Setup input. ns->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c index 9c1f93a18..0aefc4c4d 100644 --- a/src/xrt/drivers/ohmd/oh_device.c +++ b/src/xrt/drivers/ohmd/oh_device.c @@ -511,6 +511,7 @@ oh_device_create(ohmd_context *ctx, ohmd_device *dev, const char *prod) ohd->enable_finite_difference = debug_get_bool_option_ohmd_finite_diff(); snprintf(ohd->base.str, XRT_DEVICE_NAME_LEN, "%s (OpenHMD)", prod); + snprintf(ohd->base.serial, XRT_DEVICE_NAME_LEN, "%s (OpenHMD)", prod); const struct device_info info = get_info(ohd, prod); diff --git a/src/xrt/drivers/psmv/psmv_driver.c b/src/xrt/drivers/psmv/psmv_driver.c index 96098dda3..639754eb7 100644 --- a/src/xrt/drivers/psmv/psmv_driver.c +++ b/src/xrt/drivers/psmv/psmv_driver.c @@ -1034,7 +1034,10 @@ psmv_found(struct xrt_prober *xp, psmv->log_level = debug_get_log_option_psmv_log(); psmv->pid = devices[index]->product_id; psmv->hid = hid; + + static int controller_num = 0; snprintf(psmv->base.str, XRT_DEVICE_NAME_LEN, "%s", "PS Move Controller"); + snprintf(psmv->base.serial, XRT_DEVICE_NAME_LEN, "PS Move Controller %d", controller_num++); m_imu_pre_filter_init(&psmv->calibration.prefilter, 1.f, 1.f); diff --git a/src/xrt/drivers/psvr/psvr_device.c b/src/xrt/drivers/psvr/psvr_device.c index 6918b4aaa..f5b45a15f 100644 --- a/src/xrt/drivers/psvr/psvr_device.c +++ b/src/xrt/drivers/psvr/psvr_device.c @@ -1012,6 +1012,7 @@ psvr_device_create(struct hid_device_info *sensor_hid_info, #endif snprintf(psvr->base.str, XRT_DEVICE_NAME_LEN, "PS VR Headset"); + snprintf(psvr->base.serial, XRT_DEVICE_NAME_LEN, "PS VR Headset"); ret = open_hid(psvr, sensor_hid_info, &psvr->hid_sensor); if (ret != 0) { diff --git a/src/xrt/drivers/realsense/rs_6dof.c b/src/xrt/drivers/realsense/rs_6dof.c index 3ab9e1dbe..e341072b3 100644 --- a/src/xrt/drivers/realsense/rs_6dof.c +++ b/src/xrt/drivers/realsense/rs_6dof.c @@ -385,6 +385,7 @@ rs_6dof_create(void) // Print name. snprintf(rs->base.str, XRT_DEVICE_NAME_LEN, "Intel RealSense 6-DOF"); + snprintf(rs->base.serial, XRT_DEVICE_NAME_LEN, "Intel RealSense 6-DOF"); rs->base.inputs[0].name = XRT_INPUT_GENERIC_TRACKER_POSE; diff --git a/src/xrt/drivers/remote/r_device.c b/src/xrt/drivers/remote/r_device.c index 4dc89c223..91f0008e5 100644 --- a/src/xrt/drivers/remote/r_device.c +++ b/src/xrt/drivers/remote/r_device.c @@ -195,6 +195,7 @@ r_device_create(struct r_hub *r, bool is_left) // Print name. snprintf(rd->base.str, sizeof(rd->base.str), "Remote %s Controller", is_left ? "Left" : "Right"); + snprintf(rd->base.serial, sizeof(rd->base.str), "Remote %s Controller", is_left ? "Left" : "Right"); // Inputs and outputs. rd->base.inputs[0].name = XRT_INPUT_SIMPLE_SELECT_CLICK; diff --git a/src/xrt/drivers/remote/r_hmd.c b/src/xrt/drivers/remote/r_hmd.c index cc5202a83..1aa1df9ff 100644 --- a/src/xrt/drivers/remote/r_hmd.c +++ b/src/xrt/drivers/remote/r_hmd.c @@ -148,6 +148,7 @@ r_hmd_create(struct r_hub *r) // Print name. snprintf(rh->base.str, sizeof(rh->base.str), "Remote HMD"); + snprintf(rh->base.serial, sizeof(rh->base.serial), "Remote HMD"); // Setup info. struct u_device_simple_info info; diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index 2977236a6..db899128b 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -808,7 +808,6 @@ _create_hmd_device(struct survive_system *sys, const struct SurviveSimpleObject survive->device_type = DEVICE_TYPE_HMD; survive->base.name = XRT_DEVICE_GENERIC_HMD; - snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive HMD"); survive->base.destroy = survive_device_destroy; survive->base.update_inputs = survive_device_update_inputs; survive->base.get_tracked_pose = survive_device_get_tracked_pose; @@ -821,6 +820,9 @@ _create_hmd_device(struct survive_system *sys, const struct SurviveSimpleObject survive->hmd.config = *config; + snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive HMD"); + snprintf(survive->base.serial, XRT_DEVICE_NAME_LEN, "%s", survive->hmd.config.firmware.device_serial_number); + // TODO: Replace hard coded values from OpenHMD with config double w_meters = 0.122822 / 2.0; double h_meters = 0.068234; @@ -1022,6 +1024,8 @@ _create_controller_device(struct survive_system *sys, if (variant == CONTROLLER_INDEX_LEFT || variant == CONTROLLER_INDEX_RIGHT) { survive->base.name = XRT_DEVICE_INDEX_CONTROLLER; snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Valve Index Controller %d", idx); + snprintf(survive->base.serial, XRT_DEVICE_NAME_LEN, "%s", + survive->ctrl.config.firmware.device_serial_number); SET_INDEX_INPUT(SYSTEM_CLICK, SYSTEM_CLICK); SET_INDEX_INPUT(A_CLICK, A_CLICK); @@ -1072,6 +1076,8 @@ _create_controller_device(struct survive_system *sys, } else if (survive->ctrl.config.variant == CONTROLLER_VIVE_WAND) { survive->base.name = XRT_DEVICE_VIVE_WAND; snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Vive Wand Controller %d", idx); + snprintf(survive->base.serial, XRT_DEVICE_NAME_LEN, "%s", + survive->ctrl.config.firmware.device_serial_number); SET_WAND_INPUT(SYSTEM_CLICK, SYSTEM_CLICK); SET_WAND_INPUT(SQUEEZE_CLICK, SQUEEZE_CLICK); @@ -1099,6 +1105,8 @@ _create_controller_device(struct survive_system *sys, survive->base.name = XRT_DEVICE_VIVE_TRACKER_GEN2; } snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Vive Tracker %d", idx); + snprintf(survive->base.serial, XRT_DEVICE_NAME_LEN, "%s", + survive->ctrl.config.firmware.device_serial_number); survive->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER; diff --git a/src/xrt/drivers/vive/vive_controller.c b/src/xrt/drivers/vive/vive_controller.c index f1c9321ea..b92204127 100644 --- a/src/xrt/drivers/vive/vive_controller.c +++ b/src/xrt/drivers/vive/vive_controller.c @@ -1054,7 +1054,6 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w d->base.set_output = vive_controller_device_set_output; snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "%s %i", "Vive Controller", (int)(controller_num)); - d->index = controller_num; //! @todo: reading range report fails for powered off controller @@ -1081,6 +1080,8 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w return 0; } + snprintf(d->base.serial, XRT_DEVICE_NAME_LEN, "%s", d->config.firmware.device_serial_number); + if (d->config.variant == CONTROLLER_VIVE_WAND) { d->base.name = XRT_DEVICE_VIVE_WAND; diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index ff4f0735b..5726969bd 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -877,6 +877,9 @@ vive_device_create(struct os_hid_device *mainboard_dev, d->base.position_tracking_supported = false; d->base.device_type = XRT_DEVICE_TYPE_HMD; + snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "Vive HMD"); + snprintf(d->base.serial, XRT_DEVICE_NAME_LEN, "%s", d->config.firmware.device_serial_number); + ret = os_thread_helper_start(&d->sensors_thread, vive_sensors_run_thread, d); if (ret != 0) { VIVE_ERROR(d, "Failed to start sensors thread!"); diff --git a/src/xrt/include/xrt/xrt_device.h b/src/xrt/include/xrt/xrt_device.h index 47ea18d7e..d42aed082 100644 --- a/src/xrt/include/xrt/xrt_device.h +++ b/src/xrt/include/xrt/xrt_device.h @@ -226,6 +226,9 @@ struct xrt_device //! A string describing the device. char str[XRT_DEVICE_NAME_LEN]; + //! A unique identifier. Persistent across configurations, if possible. + char serial[XRT_DEVICE_NAME_LEN]; + //! Null if this device does not interface with the users head. struct xrt_hmd_parts *hmd; diff --git a/src/xrt/targets/cli/cli_cmd_probe.c b/src/xrt/targets/cli/cli_cmd_probe.c index cc8ac652d..eec3d84e9 100644 --- a/src/xrt/targets/cli/cli_cmd_probe.c +++ b/src/xrt/targets/cli/cli_cmd_probe.c @@ -122,7 +122,7 @@ cli_cmd_probe(int argc, const char **argv) continue; } - printf("\tDestroying '%s'\n", xdevs[i]->str); + printf("\tDestroying '%s' [%s]\n", xdevs[i]->str, xdevs[i]->serial); xrt_device_destroy(&xdevs[i]); } From c66aea33115d9f93646cba4f7a33290ea553e6ce Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 11 Feb 2021 21:42:29 +0100 Subject: [PATCH 042/883] d/survive: Improve device naming scheme --- src/xrt/drivers/survive/survive_driver.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index db899128b..6b756d981 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -1018,14 +1018,10 @@ _create_controller_device(struct survive_system *sys, survive->base.update_inputs = survive_device_update_inputs; survive->base.get_tracked_pose = survive_device_get_tracked_pose; survive->base.set_output = survive_controller_device_set_output; + snprintf(survive->base.serial, XRT_DEVICE_NAME_LEN, "%s", survive->ctrl.config.firmware.device_serial_number); - //! @todo: May use Vive Wands + Index HMDs or Index Controllers + Vive - //! HMD if (variant == CONTROLLER_INDEX_LEFT || variant == CONTROLLER_INDEX_RIGHT) { survive->base.name = XRT_DEVICE_INDEX_CONTROLLER; - snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Valve Index Controller %d", idx); - snprintf(survive->base.serial, XRT_DEVICE_NAME_LEN, "%s", - survive->ctrl.config.firmware.device_serial_number); SET_INDEX_INPUT(SYSTEM_CLICK, SYSTEM_CLICK); SET_INDEX_INPUT(A_CLICK, A_CLICK); @@ -1052,12 +1048,12 @@ _create_controller_device(struct survive_system *sys, if (variant == CONTROLLER_INDEX_LEFT) { survive->base.device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; survive->base.inputs[VIVE_CONTROLLER_HAND_TRACKING].name = XRT_INPUT_GENERIC_HAND_TRACKING_LEFT; + snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Valve Index Left Controller (libsurvive)"); } else if (variant == CONTROLLER_INDEX_RIGHT) { survive->base.device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER; survive->base.inputs[VIVE_CONTROLLER_HAND_TRACKING].name = XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT; - } else { - survive->base.device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER; + snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Valve Index Right Controller (libsurvive)"); } survive->base.get_hand_tracking = survive_controller_get_hand_tracking; @@ -1075,9 +1071,7 @@ _create_controller_device(struct survive_system *sys, } else if (survive->ctrl.config.variant == CONTROLLER_VIVE_WAND) { survive->base.name = XRT_DEVICE_VIVE_WAND; - snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Vive Wand Controller %d", idx); - snprintf(survive->base.serial, XRT_DEVICE_NAME_LEN, "%s", - survive->ctrl.config.firmware.device_serial_number); + snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Vive Wand Controller (libsurvive)"); SET_WAND_INPUT(SYSTEM_CLICK, SYSTEM_CLICK); SET_WAND_INPUT(SQUEEZE_CLICK, SQUEEZE_CLICK); @@ -1101,12 +1095,11 @@ _create_controller_device(struct survive_system *sys, survive->ctrl.config.variant == CONTROLLER_TRACKER_GEN2) { if (survive->ctrl.config.variant == CONTROLLER_TRACKER_GEN1) { survive->base.name = XRT_DEVICE_VIVE_TRACKER_GEN1; + snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Vive Tracker Gen1 (libsurvive)"); } else if (survive->ctrl.config.variant == CONTROLLER_TRACKER_GEN2) { survive->base.name = XRT_DEVICE_VIVE_TRACKER_GEN2; + snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Vive Tracker Gen2 (libsurvive)"); } - snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive Vive Tracker %d", idx); - snprintf(survive->base.serial, XRT_DEVICE_NAME_LEN, "%s", - survive->ctrl.config.firmware.device_serial_number); survive->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER; From d5e74b959a6354e0346e37d14f28558ae032d278 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 11 Feb 2021 23:53:21 +0100 Subject: [PATCH 043/883] d/vive: Improve naming scheme --- src/xrt/drivers/vive/vive_controller.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/xrt/drivers/vive/vive_controller.c b/src/xrt/drivers/vive/vive_controller.c index b92204127..5e654bcba 100644 --- a/src/xrt/drivers/vive/vive_controller.c +++ b/src/xrt/drivers/vive/vive_controller.c @@ -1053,9 +1053,6 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w d->base.get_tracked_pose = vive_controller_device_get_tracked_pose; d->base.set_output = vive_controller_device_set_output; - snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "%s %i", "Vive Controller", (int)(controller_num)); - d->index = controller_num; - //! @todo: reading range report fails for powered off controller if (vive_get_imu_range_report(d->controller_hid, &d->config.imu.gyro_range, &d->config.imu.acc_range) != 0) { VIVE_ERROR(d, "Could not get watchman IMU range packet!"); @@ -1084,6 +1081,7 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w if (d->config.variant == CONTROLLER_VIVE_WAND) { d->base.name = XRT_DEVICE_VIVE_WAND; + snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "Vive Wand Controller (vive)"); SET_WAND_INPUT(SYSTEM_CLICK, SYSTEM_CLICK); SET_WAND_INPUT(SQUEEZE_CLICK, SQUEEZE_CLICK); @@ -1146,18 +1144,22 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w if (d->config.variant == CONTROLLER_INDEX_LEFT) { d->base.device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; d->base.inputs[VIVE_CONTROLLER_HAND_TRACKING].name = XRT_INPUT_GENERIC_HAND_TRACKING_LEFT; + snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "Valve Index Left Controller (vive)"); } else if (d->config.variant == CONTROLLER_INDEX_RIGHT) { d->base.device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER; d->base.inputs[VIVE_CONTROLLER_HAND_TRACKING].name = XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT; + snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "Valve Index Right Controller (vive)"); } } else if (d->config.variant == CONTROLLER_TRACKER_GEN1) { d->base.name = XRT_DEVICE_VIVE_TRACKER_GEN1; d->base.update_inputs = _update_tracker_inputs; d->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER; + snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "Vive Tracker Gen1 (vive)"); } else if (d->config.variant == CONTROLLER_TRACKER_GEN2) { d->base.name = XRT_DEVICE_VIVE_TRACKER_GEN2; d->base.update_inputs = _update_tracker_inputs; d->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER; + snprintf(d->base.str, XRT_DEVICE_NAME_LEN, "Vive Tracker Gen2 (vive)"); } else { d->base.name = XRT_DEVICE_GENERIC_HMD; d->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER; From a4bde60e08511bccfc8eed6fafd5694af00c7785 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Fri, 12 Feb 2021 00:26:54 +0100 Subject: [PATCH 044/883] st/steamvr: Use serial number for controller id --- .../state_trackers/steamvr_drv/ovrd_driver.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp b/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp index 1fa4274e3..07b6ab1b2 100644 --- a/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp +++ b/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp @@ -42,6 +42,8 @@ DEBUG_GET_ONCE_BOOL_OPTION(emulate_index_controller, "STEAMVR_EMULATE_INDEX_CONT DEBUG_GET_ONCE_NUM_OPTION(scale_percentage, "XRT_COMPOSITOR_SCALE_PERCENTAGE", 140) +#define MODELNUM_LEN (XRT_DEVICE_NAME_LEN + 9) // "[Monado] " + //#define DUMP_POSE //#define DUMP_POSE_CONTROLLERS @@ -148,16 +150,8 @@ public: m_unObjectId = vr::k_unTrackedDeviceIndexInvalid; m_pose = {}; - // append xrt_hand because SteamVR serial must be unique - std::stringstream ss; - ss << "[Monado] " << xdev->str << " " << hand; - std::string name = ss.str(); - - strncpy(m_sSerialNumber, name.c_str(), XRT_DEVICE_NAME_LEN); - strncpy(m_sModelNumber, name.c_str(), XRT_DEVICE_NAME_LEN); - - strncpy(m_sSerialNumber, name.c_str(), XRT_DEVICE_NAME_LEN); - strncpy(m_sModelNumber, name.c_str(), XRT_DEVICE_NAME_LEN); + snprintf(m_sModelNumber, MODELNUM_LEN, "[Monado] %s", xdev->str); + strncpy(m_sSerialNumber, xdev->serial, XRT_DEVICE_NAME_LEN); switch (this->m_xdev->name) { case XRT_DEVICE_INDEX_CONTROLLER: @@ -703,7 +697,7 @@ public: private: char m_sSerialNumber[XRT_DEVICE_NAME_LEN]; - char m_sModelNumber[XRT_DEVICE_NAME_LEN]; + char m_sModelNumber[MODELNUM_LEN]; const char *m_controller_type = NULL; From 42996d6b1ce93ad22367211e13c417cd49337fe5 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Fri, 12 Feb 2021 02:44:00 +0100 Subject: [PATCH 045/883] os/hid: Add get_physical_address() --- src/xrt/auxiliary/os/os_hid.h | 17 +++++++++++++++++ src/xrt/auxiliary/os/os_hid_hidraw.c | 8 ++++++++ 2 files changed, 25 insertions(+) diff --git a/src/xrt/auxiliary/os/os_hid.h b/src/xrt/auxiliary/os/os_hid.h index 89fde6216..146463c09 100644 --- a/src/xrt/auxiliary/os/os_hid.h +++ b/src/xrt/auxiliary/os/os_hid.h @@ -37,6 +37,8 @@ struct os_hid_device int (*set_feature)(struct os_hid_device *hid_dev, const uint8_t *data, size_t size); + int (*get_physical_address)(struct os_hid_device *hid_dev, uint8_t *data, size_t size); + void (*destroy)(struct os_hid_device *hid_dev); }; @@ -104,6 +106,21 @@ os_hid_set_feature(struct os_hid_device *hid_dev, const uint8_t *data, size_t si return hid_dev->set_feature(hid_dev, data, size); } +/*! + * Get the physical address. + * + * For USB devices, the string contains the physical path to the device (the + * USB controller, hubs, ports, etc). For Bluetooth *devices, the string + * contains the hardware (MAC) address of the device. + * + * @public @memberof os_hid_device + */ +static inline int +os_hid_get_physical_address(struct os_hid_device *hid_dev, uint8_t *data, size_t size) +{ + return hid_dev->get_physical_address(hid_dev, data, size); +} + /*! * Close and free the given device. * diff --git a/src/xrt/auxiliary/os/os_hid_hidraw.c b/src/xrt/auxiliary/os/os_hid_hidraw.c index ca95b3d2a..56c6e3b3e 100644 --- a/src/xrt/auxiliary/os/os_hid_hidraw.c +++ b/src/xrt/auxiliary/os/os_hid_hidraw.c @@ -89,6 +89,13 @@ os_hidraw_get_feature(struct os_hid_device *ohdev, uint8_t report_num, uint8_t * return ioctl(hrdev->fd, HIDIOCGFEATURE(length), data); } +static int +os_hidraw_get_physical_address(struct os_hid_device *ohdev, uint8_t *data, size_t length) +{ + struct hid_hidraw *hrdev = (struct hid_hidraw *)ohdev; + return ioctl(hrdev->fd, HIDIOCGRAWPHYS(length), data); +} + static int os_hidraw_get_feature_timeout(struct os_hid_device *ohdev, void *data, size_t length, uint32_t timeout) { @@ -138,6 +145,7 @@ os_hid_open_hidraw(const char *path, struct os_hid_device **out_hid) hrdev->base.get_feature = os_hidraw_get_feature; hrdev->base.get_feature_timeout = os_hidraw_get_feature_timeout; hrdev->base.set_feature = os_hidraw_set_feature; + hrdev->base.get_physical_address = os_hidraw_get_physical_address; hrdev->base.destroy = os_hidraw_destroy; hrdev->fd = open(path, O_RDWR); if (hrdev->fd < 0) { From c6695b7a276170483841cf848f3a595c99d1680f Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 15 Feb 2021 14:52:32 +0100 Subject: [PATCH 046/883] prober: return XRT_PROBER_STRING_SERIAL_NUMBER for bluetooth devices Using the bluetooth id gotten from uevent. --- src/xrt/state_trackers/prober/p_prober.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/prober/p_prober.c b/src/xrt/state_trackers/prober/p_prober.c index 76383e7e7..54d3e6bc0 100644 --- a/src/xrt/state_trackers/prober/p_prober.c +++ b/src/xrt/state_trackers/prober/p_prober.c @@ -818,13 +818,23 @@ get_string_descriptor(struct xrt_prober *xp, XRT_MAYBE_UNUSED struct prober_device *pdev = (struct prober_device *)xpdev; XRT_MAYBE_UNUSED int ret; #ifdef XRT_HAVE_LIBUSB - if (pdev->usb.dev != NULL) { + if (pdev->base.bus == XRT_BUS_TYPE_USB && pdev->usb.dev != NULL) { ret = p_libusb_get_string_descriptor(p, pdev, which_string, buffer, length); if (ret >= 0) { return ret; } } #endif + if (pdev->base.bus == XRT_BUS_TYPE_BLUETOOTH && which_string == XRT_PROBER_STRING_SERIAL_NUMBER) { + union { + uint8_t arr[8]; + uint64_t v; + } u; + u.v = pdev->bluetooth.id; + return snprintf((char *)buffer, length, "%02X:%02X:%02X:%02X:%02X:%02X", u.arr[5], u.arr[4], u.arr[3], + u.arr[2], u.arr[1], u.arr[0]); + } + //! @todo add more backends //! @todo make this unicode (utf-16)? utf-8 would be better... return 0; From d56834f7a9e567047996991df6caa52f6ff0e122 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 15 Feb 2021 14:54:11 +0100 Subject: [PATCH 047/883] d/psmv: Use bluetooth mac as serial --- src/xrt/drivers/psmv/psmv_driver.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/psmv/psmv_driver.c b/src/xrt/drivers/psmv/psmv_driver.c index 639754eb7..9174c7abd 100644 --- a/src/xrt/drivers/psmv/psmv_driver.c +++ b/src/xrt/drivers/psmv/psmv_driver.c @@ -1035,9 +1035,17 @@ psmv_found(struct xrt_prober *xp, psmv->pid = devices[index]->product_id; psmv->hid = hid; + struct xrt_prober_device *dev = devices[index]; + int str_serial_ret = xrt_prober_get_string_descriptor(xp, dev, XRT_PROBER_STRING_SERIAL_NUMBER, + (unsigned char *)psmv->base.serial, XRT_DEVICE_NAME_LEN); + static int controller_num = 0; + if (str_serial_ret == 0) { + snprintf(psmv->base.serial, XRT_DEVICE_NAME_LEN, "PS Move Controller %d", controller_num++); + PSMV_ERROR(psmv, "Could not get bluetooth serial, fallback: %s", psmv->base.serial); + } + snprintf(psmv->base.str, XRT_DEVICE_NAME_LEN, "%s", "PS Move Controller"); - snprintf(psmv->base.serial, XRT_DEVICE_NAME_LEN, "PS Move Controller %d", controller_num++); m_imu_pre_filter_init(&psmv->calibration.prefilter, 1.f, 1.f); From 165df31d77ba569231639fa9b92e2499cacf0149 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 15 Feb 2021 15:12:08 +0000 Subject: [PATCH 048/883] st/prober: Use U_LOG_RAW for dump function --- src/xrt/state_trackers/prober/p_dump.c | 40 +++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/xrt/state_trackers/prober/p_dump.c b/src/xrt/state_trackers/prober/p_dump.c index feca050c0..d710a9bed 100644 --- a/src/xrt/state_trackers/prober/p_dump.c +++ b/src/xrt/state_trackers/prober/p_dump.c @@ -71,34 +71,34 @@ p_dump_device(struct prober *p, struct prober_device *pdev, int id) return; } - U_LOG_I("\t% 3i: 0x%04x:0x%04x", id, pdev->base.vendor_id, pdev->base.product_id); - U_LOG_I("\t\tptr: %p", (void *)pdev); - U_LOG_I("\t\tusb_dev_class: %02x", pdev->base.usb_dev_class); + U_LOG_RAW("\t% 3i: 0x%04x:0x%04x", id, pdev->base.vendor_id, pdev->base.product_id); + U_LOG_RAW("\t\tptr: %p", (void *)pdev); + U_LOG_RAW("\t\tusb_dev_class: %02x", pdev->base.usb_dev_class); if (pdev->usb.serial != NULL || pdev->usb.product != NULL || pdev->usb.manufacturer != NULL) { - U_LOG_I("\t\tusb.product: %s", pdev->usb.product); - U_LOG_I("\t\tusb.manufacturer: %s", pdev->usb.manufacturer); - U_LOG_I("\t\tusb.serial: %s", pdev->usb.serial); + U_LOG_RAW("\t\tusb.product: %s", pdev->usb.product); + U_LOG_RAW("\t\tusb.manufacturer: %s", pdev->usb.manufacturer); + U_LOG_RAW("\t\tusb.serial: %s", pdev->usb.serial); } if (pdev->usb.bus != 0 || pdev->usb.addr != 0) { - U_LOG_I("\t\tusb.bus: %i", pdev->usb.bus); - U_LOG_I("\t\tusb.addr: %i", pdev->usb.addr); + U_LOG_RAW("\t\tusb.bus: %i", pdev->usb.bus); + U_LOG_RAW("\t\tusb.addr: %i", pdev->usb.addr); } if (pdev->bluetooth.id != 0) { - U_LOG_I("\t\tbluetooth.id: %012" PRIx64 "", pdev->bluetooth.id); + U_LOG_RAW("\t\tbluetooth.id: %012" PRIx64 "", pdev->bluetooth.id); } int num = pdev->usb.num_ports; if (print_ports(tmp, ARRAY_SIZE(tmp), pdev->usb.ports, num)) { - U_LOG_I("\t\tport%s %s", num > 1 ? "s:" : ": ", tmp); + U_LOG_RAW("\t\tport%s %s", num > 1 ? "s:" : ": ", tmp); } #ifdef XRT_HAVE_LIBUSB if (pdev->usb.dev != NULL) { - U_LOG_I("\t\tlibusb: %p", (void *)pdev->usb.dev); + U_LOG_RAW("\t\tlibusb: %p", (void *)pdev->usb.dev); } #endif @@ -107,21 +107,21 @@ p_dump_device(struct prober *p, struct prober_device *pdev, int id) if (uvc_dev != NULL) { struct uvc_device_descriptor *desc; - U_LOG_I("\t\tlibuvc: %p", (void *)uvc_dev); + U_LOG_RAW("\t\tlibuvc: %p", (void *)uvc_dev); uvc_get_device_descriptor(uvc_dev, &desc); if (desc->product != NULL) { - U_LOG_I("\t\tproduct: '%s'", desc->product); + U_LOG_RAW("\t\tproduct: '%s'", desc->product); } if (desc->manufacturer != NULL) { - U_LOG_I("\t\tmanufacturer: '%s'", desc->manufacturer); + U_LOG_RAW("\t\tmanufacturer: '%s'", desc->manufacturer); } if (desc->serialNumber != NULL) { - U_LOG_I("\t\tserial: '%s'", desc->serialNumber); + U_LOG_RAW("\t\tserial: '%s'", desc->serialNumber); } uvc_free_device_descriptor(desc); @@ -133,9 +133,9 @@ p_dump_device(struct prober *p, struct prober_device *pdev, int id) for (size_t j = 0; j < pdev->num_v4ls; j++) { struct prober_v4l *v4l = &pdev->v4ls[j]; - U_LOG_I("\t\tv4l.iface: %i", (int)v4l->usb_iface); - U_LOG_I("\t\tv4l.index: %i", (int)v4l->v4l_index); - U_LOG_I("\t\tv4l.path: '%s'", v4l->path); + U_LOG_RAW("\t\tv4l.iface: %i", (int)v4l->usb_iface); + U_LOG_RAW("\t\tv4l.index: %i", (int)v4l->v4l_index); + U_LOG_RAW("\t\tv4l.path: '%s'", v4l->path); } #endif @@ -143,8 +143,8 @@ p_dump_device(struct prober *p, struct prober_device *pdev, int id) for (size_t j = 0; j < pdev->num_hidraws; j++) { struct prober_hidraw *hidraw = &pdev->hidraws[j]; - U_LOG_I("\t\thidraw.iface: %i", (int)hidraw->interface); - U_LOG_I("\t\thidraw.path: '%s'", hidraw->path); + U_LOG_RAW("\t\thidraw.iface: %i", (int)hidraw->interface); + U_LOG_RAW("\t\thidraw.path: '%s'", hidraw->path); } #endif } From a55c6f3cc4444e5b01abf6efa00ea127160a1343 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 15 Feb 2021 15:16:26 +0000 Subject: [PATCH 049/883] st/prober: Tidy and add doc-comment --- src/xrt/include/xrt/xrt_prober.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/xrt/include/xrt/xrt_prober.h b/src/xrt/include/xrt/xrt_prober.h index ad7623bba..d5f302955 100644 --- a/src/xrt/include/xrt/xrt_prober.h +++ b/src/xrt/include/xrt/xrt_prober.h @@ -163,7 +163,15 @@ struct xrt_prober * xrt_prober_probe() */ int (*probe)(struct xrt_prober *xp); + + /*! + * Dump a listing of all devices found on the system to platform + * dependent output (stdout). + * + * @note Code consuming this interface should use xrt_prober_dump() + */ int (*dump)(struct xrt_prober *xp); + /*! * Iterate through drivers (by ID and auto-probers) checking to see if * they can handle any connected devices from the last xrt_prober::probe @@ -191,21 +199,27 @@ struct xrt_prober * and xrt_prober_select(). */ int (*select)(struct xrt_prober *xp, struct xrt_device **xdevs, size_t num_xdevs); + int (*open_hid_interface)(struct xrt_prober *xp, struct xrt_prober_device *xpdev, int interface, struct os_hid_device **out_hid_dev); + int (*open_video_device)(struct xrt_prober *xp, struct xrt_prober_device *xpdev, struct xrt_frame_context *xfctx, struct xrt_fs **out_xfs); + int (*list_video_devices)(struct xrt_prober *xp, xrt_prober_list_video_cb cb, void *ptr); + int (*get_string_descriptor)(struct xrt_prober *xp, struct xrt_prober_device *xpdev, enum xrt_prober_string which_string, unsigned char *buffer, int length); + bool (*can_open)(struct xrt_prober *xp, struct xrt_prober_device *xpdev); + /*! * Destroy the prober and set the pointer to null. * From a6fe8e8b1ec55e901868452d1e63dd2b5f9f20d1 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 15 Feb 2021 15:28:27 +0000 Subject: [PATCH 050/883] st/prober: Clarify xrt_prober_get_string_descriptor --- src/xrt/drivers/psmv/psmv_driver.c | 2 +- src/xrt/include/xrt/xrt_prober.h | 23 ++++++++++++++++++----- src/xrt/state_trackers/prober/p_prober.c | 13 +++++++------ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/xrt/drivers/psmv/psmv_driver.c b/src/xrt/drivers/psmv/psmv_driver.c index 9174c7abd..5397ca0af 100644 --- a/src/xrt/drivers/psmv/psmv_driver.c +++ b/src/xrt/drivers/psmv/psmv_driver.c @@ -1040,7 +1040,7 @@ psmv_found(struct xrt_prober *xp, (unsigned char *)psmv->base.serial, XRT_DEVICE_NAME_LEN); static int controller_num = 0; - if (str_serial_ret == 0) { + if (str_serial_ret <= 0) { snprintf(psmv->base.serial, XRT_DEVICE_NAME_LEN, "PS Move Controller %d", controller_num++); PSMV_ERROR(psmv, "Could not get bluetooth serial, fallback: %s", psmv->base.serial); } diff --git a/src/xrt/include/xrt/xrt_prober.h b/src/xrt/include/xrt/xrt_prober.h index d5f302955..552642a55 100644 --- a/src/xrt/include/xrt/xrt_prober.h +++ b/src/xrt/include/xrt/xrt_prober.h @@ -212,11 +212,24 @@ struct xrt_prober int (*list_video_devices)(struct xrt_prober *xp, xrt_prober_list_video_cb cb, void *ptr); + /*! + * Returns a string property on the device of the given type + * @p which_string in @p out_buffer. + * + * @param[in] xp Prober. + * @param[in] xpdev Device to get string property from. + * @param[in] which_string Which string property to query. + * @param[in,out] out_buffer Target buffer. + * @param[in] max_length Max length of the target buffer. + * + * @return The length of the string, or negative on error. + * + */ int (*get_string_descriptor)(struct xrt_prober *xp, struct xrt_prober_device *xpdev, enum xrt_prober_string which_string, - unsigned char *buffer, - int length); + unsigned char *out_buffer, + size_t max_length); bool (*can_open)(struct xrt_prober *xp, struct xrt_prober_device *xpdev); @@ -286,10 +299,10 @@ static inline int xrt_prober_get_string_descriptor(struct xrt_prober *xp, struct xrt_prober_device *xpdev, enum xrt_prober_string which_string, - unsigned char *buffer, - int length) + unsigned char *out_buffer, + size_t max_length) { - return xp->get_string_descriptor(xp, xpdev, which_string, buffer, length); + return xp->get_string_descriptor(xp, xpdev, which_string, out_buffer, max_length); } /*! diff --git a/src/xrt/state_trackers/prober/p_prober.c b/src/xrt/state_trackers/prober/p_prober.c index 54d3e6bc0..9441eb12d 100644 --- a/src/xrt/state_trackers/prober/p_prober.c +++ b/src/xrt/state_trackers/prober/p_prober.c @@ -81,7 +81,7 @@ get_string_descriptor(struct xrt_prober *xp, struct xrt_prober_device *xpdev, enum xrt_prober_string which_string, unsigned char *buffer, - int length); + size_t length); static bool can_open(struct xrt_prober *xp, struct xrt_prober_device *xpdev); @@ -145,8 +145,9 @@ xrt_prober_match_string(struct xrt_prober *xp, { unsigned char s[256] = {0}; int len = xrt_prober_get_string_descriptor(xp, dev, type, s, sizeof(s)); - if (len == 0) + if (len <= 0) { return false; + } return 0 == strncmp(to_match, (const char *)s, sizeof(s)); } @@ -812,14 +813,14 @@ get_string_descriptor(struct xrt_prober *xp, struct xrt_prober_device *xpdev, enum xrt_prober_string which_string, unsigned char *buffer, - int length) + size_t max_length) { XRT_MAYBE_UNUSED struct prober *p = (struct prober *)xp; XRT_MAYBE_UNUSED struct prober_device *pdev = (struct prober_device *)xpdev; XRT_MAYBE_UNUSED int ret; #ifdef XRT_HAVE_LIBUSB if (pdev->base.bus == XRT_BUS_TYPE_USB && pdev->usb.dev != NULL) { - ret = p_libusb_get_string_descriptor(p, pdev, which_string, buffer, length); + ret = p_libusb_get_string_descriptor(p, pdev, which_string, buffer, max_length); if (ret >= 0) { return ret; } @@ -831,8 +832,8 @@ get_string_descriptor(struct xrt_prober *xp, uint64_t v; } u; u.v = pdev->bluetooth.id; - return snprintf((char *)buffer, length, "%02X:%02X:%02X:%02X:%02X:%02X", u.arr[5], u.arr[4], u.arr[3], - u.arr[2], u.arr[1], u.arr[0]); + return snprintf((char *)buffer, max_length, "%02X:%02X:%02X:%02X:%02X:%02X", u.arr[5], u.arr[4], + u.arr[3], u.arr[2], u.arr[1], u.arr[0]); } //! @todo add more backends From 2c012374da5a2e33db7b76ceee918aeb26698f5f Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 15 Feb 2021 15:33:19 +0000 Subject: [PATCH 051/883] st/prober: Add copydocs --- src/xrt/include/xrt/xrt_prober.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/xrt/include/xrt/xrt_prober.h b/src/xrt/include/xrt/xrt_prober.h index 552642a55..d0410158b 100644 --- a/src/xrt/include/xrt/xrt_prober.h +++ b/src/xrt/include/xrt/xrt_prober.h @@ -1,4 +1,4 @@ -// Copyright 2019, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -244,6 +244,8 @@ struct xrt_prober }; /*! + * @copydoc xrt_prober::probe + * * Helper function for @ref xrt_prober::probe. * * @public @memberof xrt_prober @@ -255,6 +257,8 @@ xrt_prober_probe(struct xrt_prober *xp) } /*! + * @copydoc xrt_prober::dump + * * Helper function for @ref xrt_prober::dump. * * @public @memberof xrt_prober @@ -266,6 +270,8 @@ xrt_prober_dump(struct xrt_prober *xp) } /*! + * @copydoc xrt_prober::select + * * Helper function for @ref xrt_prober::select. * * @public @memberof xrt_prober @@ -277,6 +283,8 @@ xrt_prober_select(struct xrt_prober *xp, struct xrt_device **xdevs, size_t num_x } /*! + * @copydoc xrt_prober::open_hid_interface + * * Helper function for @ref xrt_prober::open_hid_interface. * * @public @memberof xrt_prober @@ -291,6 +299,8 @@ xrt_prober_open_hid_interface(struct xrt_prober *xp, } /*! + * @copydoc xrt_prober::get_string_descriptor + * * Helper function for @ref xrt_prober::get_string_descriptor. * * @public @memberof xrt_prober @@ -306,6 +316,8 @@ xrt_prober_get_string_descriptor(struct xrt_prober *xp, } /*! + * @copydoc xrt_prober::can_open + * * Helper function for @ref xrt_prober::can_open. * * @public @memberof xrt_prober @@ -318,6 +330,8 @@ xrt_prober_can_open(struct xrt_prober *xp, struct xrt_prober_device *xpdev) /*! + * @copydoc xrt_prober::xrt_prober_open_video_device + * * Helper function for @ref xrt_prober::xrt_prober_open_video_device. * * @public @memberof xrt_prober @@ -332,6 +346,8 @@ xrt_prober_open_video_device(struct xrt_prober *xp, } /*! + * @copydoc xrt_prober::list_video_devices + * * Helper function for @ref xrt_prober::list_video_devices. * * @public @memberof xrt_prober @@ -343,6 +359,8 @@ xrt_prober_list_video_devices(struct xrt_prober *xp, xrt_prober_list_video_cb cb } /*! + * @copydoc xrt_prober::destroy + * * Helper function for @ref xrt_prober::destroy. * * @public @memberof xrt_prober From 78dbbec8914e57b37039fcad9dd41a7d94da598a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 15 Feb 2021 15:33:41 +0000 Subject: [PATCH 052/883] st/prober: Improve xrt_prober_destroy --- src/xrt/include/xrt/xrt_prober.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xrt/include/xrt/xrt_prober.h b/src/xrt/include/xrt/xrt_prober.h index d0410158b..8e3169a85 100644 --- a/src/xrt/include/xrt/xrt_prober.h +++ b/src/xrt/include/xrt/xrt_prober.h @@ -361,7 +361,8 @@ xrt_prober_list_video_devices(struct xrt_prober *xp, xrt_prober_list_video_cb cb /*! * @copydoc xrt_prober::destroy * - * Helper function for @ref xrt_prober::destroy. + * Helper for calling through the function pointer: does a null check and sets + * xp_ptr to null if freed. * * @public @memberof xrt_prober */ @@ -374,6 +375,7 @@ xrt_prober_destroy(struct xrt_prober **xp_ptr) } xp->destroy(xp_ptr); + *xp_ptr = NULL; } /*! From da2691aac0b18df4f30bcf8b164b9569e9165c81 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 15 Feb 2021 15:36:56 +0000 Subject: [PATCH 053/883] doc: Document !686 --- doc/changes/state_trackers/mr.686.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/changes/state_trackers/mr.686.md diff --git a/doc/changes/state_trackers/mr.686.md b/doc/changes/state_trackers/mr.686.md new file mode 100644 index 000000000..f3f434ec5 --- /dev/null +++ b/doc/changes/state_trackers/mr.686.md @@ -0,0 +1,2 @@ +prober: Minor fixes & tidy commits. Mostly around doc-comments and the string +descriptor getter function. From b77630ba5703bfe0c3dfe507871ac769f7d135a0 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 15 Feb 2021 21:42:37 +0100 Subject: [PATCH 054/883] d/remote: define _BSD_SOURCE for SOL_TCP on musl --- src/xrt/drivers/remote/r_hub.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/xrt/drivers/remote/r_hub.c b/src/xrt/drivers/remote/r_hub.c index ab0517c90..73a091565 100644 --- a/src/xrt/drivers/remote/r_hub.c +++ b/src/xrt/drivers/remote/r_hub.c @@ -25,8 +25,9 @@ #include #include -#ifndef __USE_MISC -#define __USE_MISC // SOL_TCP on C11 +#if !defined(__USE_MISC) || !defined(_BSD_SOURCE) +#define __USE_MISC // SOL_TCP on C11 +#define _BSD_SOURCE // same, but for musl #endif #include From def0bef5338484364ad0af3d58f81cdcd2e1dc16 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 15 Feb 2021 21:43:32 +0100 Subject: [PATCH 055/883] build/meson: Explicitly depend on generated binding header fixes header not being generated on alpine --- src/xrt/auxiliary/bindings/meson.build | 1 + src/xrt/state_trackers/steamvr_drv/meson.build | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/bindings/meson.build b/src/xrt/auxiliary/bindings/meson.build index 2cb8c20b1..af3e54566 100644 --- a/src/xrt/auxiliary/bindings/meson.build +++ b/src/xrt/auxiliary/bindings/meson.build @@ -35,5 +35,6 @@ lib_aux_generated_bindings = static_library( aux_generated_bindings = declare_dependency( include_directories: aux_include, + sources: [generated_bindings_h], link_with: lib_aux_generated_bindings, ) diff --git a/src/xrt/state_trackers/steamvr_drv/meson.build b/src/xrt/state_trackers/steamvr_drv/meson.build index 17aa5806b..773608d1e 100644 --- a/src/xrt/state_trackers/steamvr_drv/meson.build +++ b/src/xrt/state_trackers/steamvr_drv/meson.build @@ -14,7 +14,7 @@ lib_st_ovrd = static_library( st_include, # Sigh debian meson requires this. xrt_include, ], - dependencies: aux_util, + dependencies: [aux_util, aux_generated_bindings], c_args: compile_args, cpp_args: compile_args, ) From cfed1c3607d2ee5ed552151004392d3f23a02586 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Feb 2021 07:03:38 +0000 Subject: [PATCH 056/883] st/oxr: It's not a error to pass in XrSystemHandTrackingPropertiesEXT ...when the hand tracking extension is not enabled. --- src/xrt/state_trackers/oxr/oxr_system.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_system.c b/src/xrt/state_trackers/oxr/oxr_system.c index 8ed3a6bb8..1003cdfab 100644 --- a/src/xrt/state_trackers/oxr/oxr_system.c +++ b/src/xrt/state_trackers/oxr/oxr_system.c @@ -201,13 +201,14 @@ oxr_system_get_properties(struct oxr_logger *log, struct oxr_system *sys, XrSyst properties->trackingProperties.orientationTracking = xdev->orientation_tracking_supported; properties->trackingProperties.positionTracking = xdev->position_tracking_supported; - XrSystemHandTrackingPropertiesEXT *hand_tracking_props = OXR_GET_OUTPUT_FROM_CHAIN( - properties, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, XrSystemHandTrackingPropertiesEXT); + XrSystemHandTrackingPropertiesEXT *hand_tracking_props = NULL; + // We should only be looking for extension structs if the extension has been enabled. + if (sys->inst->extensions.EXT_hand_tracking) { + hand_tracking_props = OXR_GET_OUTPUT_FROM_CHAIN(properties, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, + XrSystemHandTrackingPropertiesEXT); + } if (hand_tracking_props) { - if (!sys->inst->extensions.EXT_hand_tracking) { - return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "XR_EXT_hand_tracking is not enabled."); - } hand_tracking_props->supportsHandTracking = oxr_system_get_hand_tracking_support(log, sys->inst); } From 84486aa2b96bb73e36b36226d565099e861ffbea Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Feb 2021 16:25:05 +0000 Subject: [PATCH 057/883] ipc/server: Print application info --- src/xrt/ipc/server/ipc_server_handler.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 068462249..7c4dd2e69 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -280,6 +280,14 @@ ipc_handle_system_set_client_info(volatile struct ipc_client_state *ics, struct { ics->client_state.info = client_desc->info; ics->client_state.pid = client_desc->pid; + + IPC_INFO(ics->server, + "Client info\n" + "\tapplication_name: '%s'\n" + "\tpid: %i", + client_desc->info.application_name, // + client_desc->pid); // + return XRT_SUCCESS; } From 0ee32dfa21568337b59dc34599cb8d5baf68e877 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Feb 2021 16:32:58 +0000 Subject: [PATCH 058/883] st/oxr: Log application info --- src/xrt/state_trackers/oxr/oxr_instance.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c index 1600e0571..f8ab6edca 100644 --- a/src/xrt/state_trackers/oxr/oxr_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_instance.c @@ -330,6 +330,17 @@ oxr_instance_create(struct oxr_logger *log, const XrInstanceCreateInfo *createIn oxr_sdl2_hack_start(inst->hack, inst->xinst); /* ---- HACK ---- */ + oxr_log(log, + "Instance created\n" + "\tapplicationName: %s\n" + "\tapplicationVersion: %i\n" + "\tengineName: %s\n" + "\tengineVersion: %i\n", + createInfo->applicationInfo.applicationName, // + createInfo->applicationInfo.applicationVersion, // + createInfo->applicationInfo.engineName, // + createInfo->applicationInfo.engineVersion); // + *out_instance = inst; return XR_SUCCESS; From 4ef621128655e4f1a313d37222ab2e45d15c95bf Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Feb 2021 17:36:34 +0000 Subject: [PATCH 059/883] st/oxr: Detect UnrealEngine --- src/xrt/state_trackers/oxr/oxr_instance.c | 50 ++++++++++++++++++++--- src/xrt/state_trackers/oxr/oxr_objects.h | 14 +++++++ 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c index f8ab6edca..69798b00e 100644 --- a/src/xrt/state_trackers/oxr/oxr_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_instance.c @@ -121,6 +121,36 @@ min_size_t(size_t a, size_t b) return a < b ? a : b; } +static bool +starts_with(const char *with, const char *string) +{ + for (uint32_t i = 0; with[i] != 0; i++) { + if (string[i] != with[i]) { + return false; + } + } + + return true; +} + +static void +detect_engine(struct oxr_logger *log, struct oxr_instance *inst, const XrInstanceCreateInfo *createInfo) +{ + if (starts_with("UnrealEngine4", createInfo->applicationInfo.engineName)) { + inst->appinfo.detected.engine.name = "UnrealEngine"; + inst->appinfo.detected.engine.major = 4; + inst->appinfo.detected.engine.minor = (createInfo->applicationInfo.engineVersion >> 16) & 0xffff; + inst->appinfo.detected.engine.patch = createInfo->applicationInfo.engineVersion & 0xffff; + } + + if (starts_with("UnrealEngine5", createInfo->applicationInfo.engineName)) { + inst->appinfo.detected.engine.name = "UnrealEngine"; + inst->appinfo.detected.engine.major = 5; + inst->appinfo.detected.engine.minor = (createInfo->applicationInfo.engineVersion >> 16) & 0xffff; + inst->appinfo.detected.engine.patch = createInfo->applicationInfo.engineVersion & 0xffff; + } +} + XrResult oxr_instance_create(struct oxr_logger *log, const XrInstanceCreateInfo *createInfo, struct oxr_instance **out_instance) { @@ -321,9 +351,11 @@ oxr_instance_create(struct oxr_logger *log, const XrInstanceCreateInfo *createIn inst->timekeeping = time_state_create(); - //! @todo check if this (and other creates) failed? + // Detect game engine. + detect_engine(log, inst, createInfo); + u_var_add_root((void *)inst, "XrInstance", true); /* ---- HACK ---- */ @@ -332,14 +364,20 @@ oxr_instance_create(struct oxr_logger *log, const XrInstanceCreateInfo *createIn oxr_log(log, "Instance created\n" - "\tapplicationName: %s\n" - "\tapplicationVersion: %i\n" - "\tengineName: %s\n" - "\tengineVersion: %i\n", + "\tcreateInfo->applicationInfo.applicationName: %s\n" + "\tcreateInfo->applicationInfo.applicationVersion: %i\n" + "\tcreateInfo->applicationInfo.engineName: %s\n" + "\tcreateInfo->applicationInfo.engineVersion: %i\n" + "\tappinfo.detected.engine.name: %s\n" + "\tappinfo.detected.engine.version: %i.%i.%i\n", createInfo->applicationInfo.applicationName, // createInfo->applicationInfo.applicationVersion, // createInfo->applicationInfo.engineName, // - createInfo->applicationInfo.engineVersion); // + createInfo->applicationInfo.engineVersion, // + inst->appinfo.detected.engine.name, // + inst->appinfo.detected.engine.major, // + inst->appinfo.detected.engine.minor, // + inst->appinfo.detected.engine.patch); // *out_instance = inst; diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index f3c92461e..20890a2f3 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -1186,6 +1186,20 @@ struct oxr_instance XrPath mndx_ball_on_a_stick_controller; } path_cache; + struct + { + struct + { + struct + { + uint32_t major; + uint32_t minor; + uint32_t patch; + const char *name; //< Engine name, not freed. + } engine; + } detected; + } appinfo; + //! Debug messengers struct oxr_debug_messenger *messengers[XRT_MAX_HANDLE_CHILDREN]; From 2849c7c5ae8af711618bd8450d88f061d64d96b6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Feb 2021 17:52:42 +0000 Subject: [PATCH 060/883] st/oxr: Quirk UnrealEngine --- src/xrt/state_trackers/oxr/oxr_instance.c | 34 +++++++++++++++++------ src/xrt/state_trackers/oxr/oxr_objects.h | 6 ++++ src/xrt/state_trackers/oxr/oxr_session.c | 18 ++++++++++-- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c index 69798b00e..dc4b3b878 100644 --- a/src/xrt/state_trackers/oxr/oxr_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_instance.c @@ -151,6 +151,17 @@ detect_engine(struct oxr_logger *log, struct oxr_instance *inst, const XrInstanc } } +static void +apply_quirks(struct oxr_logger *log, struct oxr_instance *inst) +{ + if (starts_with("UnrealEngine", inst->appinfo.detected.engine.name) && // + inst->appinfo.detected.engine.major == 4 && // + inst->appinfo.detected.engine.minor <= 27 && // + inst->appinfo.detected.engine.patch <= 0) { + inst->quirks.disable_vulkan_format_depth_stencil = true; + } +} + XrResult oxr_instance_create(struct oxr_logger *log, const XrInstanceCreateInfo *createInfo, struct oxr_instance **out_instance) { @@ -356,6 +367,9 @@ oxr_instance_create(struct oxr_logger *log, const XrInstanceCreateInfo *createIn // Detect game engine. detect_engine(log, inst, createInfo); + // Apply any quirks + apply_quirks(log, inst); + u_var_add_root((void *)inst, "XrInstance", true); /* ---- HACK ---- */ @@ -369,15 +383,17 @@ oxr_instance_create(struct oxr_logger *log, const XrInstanceCreateInfo *createIn "\tcreateInfo->applicationInfo.engineName: %s\n" "\tcreateInfo->applicationInfo.engineVersion: %i\n" "\tappinfo.detected.engine.name: %s\n" - "\tappinfo.detected.engine.version: %i.%i.%i\n", - createInfo->applicationInfo.applicationName, // - createInfo->applicationInfo.applicationVersion, // - createInfo->applicationInfo.engineName, // - createInfo->applicationInfo.engineVersion, // - inst->appinfo.detected.engine.name, // - inst->appinfo.detected.engine.major, // - inst->appinfo.detected.engine.minor, // - inst->appinfo.detected.engine.patch); // + "\tappinfo.detected.engine.version: %i.%i.%i\n" + "\tquirks.disable_vulkan_format_depth_stencil: %s", + createInfo->applicationInfo.applicationName, // + createInfo->applicationInfo.applicationVersion, // + createInfo->applicationInfo.engineName, // + createInfo->applicationInfo.engineVersion, // + inst->appinfo.detected.engine.name, // + inst->appinfo.detected.engine.major, // + inst->appinfo.detected.engine.minor, // + inst->appinfo.detected.engine.patch, // + inst->quirks.disable_vulkan_format_depth_stencil ? "true" : "false"); // *out_instance = inst; diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index 20890a2f3..241ef7546 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -1200,6 +1200,12 @@ struct oxr_instance } detected; } appinfo; + struct + { + //! Unreal has a bug in the VulkanRHI backend. + bool disable_vulkan_format_depth_stencil; + } quirks; + //! Debug messengers struct oxr_debug_messenger *messengers[XRT_MAX_HANDLE_CHILDREN]; diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 216abd2e1..727c63206 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -100,6 +100,7 @@ oxr_session_enumerate_formats(struct oxr_logger *log, uint32_t *formatCountOutput, int64_t *formats) { + struct oxr_instance *inst = sess->sys->inst; struct xrt_compositor *xc = sess->compositor; if (formatCountOutput == NULL) { return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "(formatCountOutput == NULL) can not be null"); @@ -111,8 +112,21 @@ oxr_session_enumerate_formats(struct oxr_logger *log, return oxr_session_success_result(sess); } - OXR_TWO_CALL_HELPER(log, formatCapacityInput, formatCountOutput, formats, xc->info.num_formats, - xc->info.formats, oxr_session_success_result(sess)); + uint32_t filtered_count = 0; + int64_t filtered_formats[XRT_MAX_SWAPCHAIN_FORMATS]; + for (uint32_t i = 0; i < xc->info.num_formats; i++) { + int64_t format = xc->info.formats[i]; + + if (inst->quirks.disable_vulkan_format_depth_stencil && + format == 130 /* VK_FORMAT_D32_SFLOAT_S8_UINT */) { + continue; + } + + filtered_formats[filtered_count++] = format; + } + + OXR_TWO_CALL_HELPER(log, formatCapacityInput, formatCountOutput, formats, filtered_count, filtered_formats, + oxr_session_success_result(sess)); } XrResult From 85c69a43123a661835dcc71f4406d583ec82074a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Feb 2021 18:08:13 +0000 Subject: [PATCH 061/883] doc: Document !688 --- doc/changes/state_trackers/mr.688.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/changes/state_trackers/mr.688.md diff --git a/doc/changes/state_trackers/mr.688.md b/doc/changes/state_trackers/mr.688.md new file mode 100644 index 000000000..e5a85b8b5 --- /dev/null +++ b/doc/changes/state_trackers/mr.688.md @@ -0,0 +1,2 @@ +OpenXR: Ignore XrSystemHandTrackingPropertiesEXT when hand tracking extension +is not enabled. From 2b539f9750fc529ab1c7efcc5b5d2271bfc93773 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Feb 2021 18:08:39 +0000 Subject: [PATCH 062/883] doc: Document !689 --- doc/changes/state_trackers/mr.689.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/changes/state_trackers/mr.689.md diff --git a/doc/changes/state_trackers/mr.689.md b/doc/changes/state_trackers/mr.689.md new file mode 100644 index 000000000..2742f8c92 --- /dev/null +++ b/doc/changes/state_trackers/mr.689.md @@ -0,0 +1,2 @@ +OpenXR: Add quirk for UnrealEngine4.27 to disable depth/stencil buffer to work +around a bug where Unreal would forget to call acquire before wait image. From 5b61a9b905322c4fed8a895b693b23ffd53a3a0c Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Feb 2021 22:45:04 +0000 Subject: [PATCH 063/883] st/oxr: Fix crash --- src/xrt/state_trackers/oxr/oxr_instance.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c index dc4b3b878..b0ca38982 100644 --- a/src/xrt/state_trackers/oxr/oxr_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_instance.c @@ -124,6 +124,12 @@ min_size_t(size_t a, size_t b) static bool starts_with(const char *with, const char *string) { + assert(with != NULL); + + if (string == NULL) { + return false; + } + for (uint32_t i = 0; with[i] != 0; i++) { if (string[i] != with[i]) { return false; From 1934897a1bbf4f7736304481bcf1ee0a1b70c101 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 17 Feb 2021 14:42:12 +0000 Subject: [PATCH 064/883] doc: Document !960 --- doc/changes/state_trackers/mr.689.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changes/state_trackers/mr.689.md b/doc/changes/state_trackers/mr.689.md index 2742f8c92..69c1aa266 100644 --- a/doc/changes/state_trackers/mr.689.md +++ b/doc/changes/state_trackers/mr.689.md @@ -1,2 +1,6 @@ +---- +-- mr.689 +-- mr.690 +---- OpenXR: Add quirk for UnrealEngine4.27 to disable depth/stencil buffer to work around a bug where Unreal would forget to call acquire before wait image. From ab70115a89669ff6a37b88924c55218d08e0a400 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 17 Feb 2021 19:52:47 +0100 Subject: [PATCH 065/883] d/vive: Add HMD rotation pose prediction --- src/xrt/drivers/vive/vive_device.c | 28 ++++++++++++++++++++++------ src/xrt/drivers/vive/vive_device.h | 1 + 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index 5726969bd..5d35a28c2 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -19,6 +19,7 @@ #include "util/u_time.h" #include "math/m_api.h" +#include "math/m_predict.h" #include "os/os_hid.h" #include "os/os_time.h" @@ -89,6 +90,25 @@ vive_device_update_inputs(struct xrt_device *xdev) VIVE_TRACE(d, "ENTER!"); } +static void +predict_pose(struct vive_device *d, uint64_t at_timestamp_ns, struct xrt_space_relation *out_relation) +{ + timepoint_ns prediction_ns = at_timestamp_ns - d->imu.ts_received_ns; + double prediction_s = time_ns_to_s(prediction_ns); + + timepoint_ns monotonic_now_ns = os_monotonic_get_ns(); + timepoint_ns remaining_ns = at_timestamp_ns - monotonic_now_ns; + VIVE_TRACE(d, "dev %s At %ldns: Pose requested for +%ldns (%ldns), predicting %ldns", d->base.str, + monotonic_now_ns, remaining_ns, at_timestamp_ns, prediction_ns); + + //! @todo integrate position here + struct xrt_space_relation relation = {0}; + relation.pose.orientation = d->rot_filtered; + relation.relation_flags = XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT; + + m_predict_relation(&relation, prediction_s, out_relation); +} + static void vive_device_get_tracked_pose(struct xrt_device *xdev, enum xrt_input_name name, @@ -116,12 +136,7 @@ vive_device_get_tracked_pose(struct xrt_device *xdev, return; } - out_relation->pose.orientation = d->rot_filtered; - - //! @todo assuming that orientation is actually currently tracked. - out_relation->relation_flags = (enum xrt_space_relation_flags)( - XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT | - XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); + predict_pose(d, at_timestamp_ns, out_relation); os_thread_helper_unlock(&d->sensors_thread); } @@ -281,6 +296,7 @@ update_imu(struct vive_device *d, const void *buffer) const struct vive_imu_report *report = buffer; const struct vive_imu_sample *sample = report->sample; uint8_t last_seq = d->imu.sequence; + d->imu.ts_received_ns = os_monotonic_get_ns(); int i, j; /* diff --git a/src/xrt/drivers/vive/vive_device.h b/src/xrt/drivers/vive/vive_device.h index 65a9b430e..5110aa142 100644 --- a/src/xrt/drivers/vive/vive_device.h +++ b/src/xrt/drivers/vive/vive_device.h @@ -43,6 +43,7 @@ struct vive_device uint64_t time_ns; uint8_t sequence; uint32_t last_sample_time_raw; + timepoint_ns ts_received_ns; } imu; struct m_imu_3dof fusion; From 4d1b5f033a4674a2a098e6220179df5d6f33604a Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 17 Feb 2021 19:58:24 +0100 Subject: [PATCH 066/883] d/vive: Add controller rotation pose prediction --- src/xrt/drivers/vive/vive_controller.c | 29 ++++++++++++++++++++------ src/xrt/drivers/vive/vive_controller.h | 1 + 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/xrt/drivers/vive/vive_controller.c b/src/xrt/drivers/vive/vive_controller.c index 5e654bcba..132d55a56 100644 --- a/src/xrt/drivers/vive/vive_controller.c +++ b/src/xrt/drivers/vive/vive_controller.c @@ -22,6 +22,7 @@ #include "xrt/xrt_prober.h" #include "math/m_api.h" +#include "math/m_predict.h" #include "util/u_debug.h" #include "util/u_device.h" #include "util/u_json.h" @@ -350,6 +351,25 @@ vive_controller_get_hand_tracking(struct xrt_device *xdev, u_hand_joints_set_out_data(&d->hand_tracking, hand, &controller_relation, &hand_on_handle_pose, out_value); } +static void +predict_pose(struct vive_controller_device *d, uint64_t at_timestamp_ns, struct xrt_space_relation *out_relation) +{ + timepoint_ns prediction_ns = at_timestamp_ns - d->imu.ts_received_ns; + double prediction_s = time_ns_to_s(prediction_ns); + + timepoint_ns monotonic_now_ns = os_monotonic_get_ns(); + timepoint_ns remaining_ns = at_timestamp_ns - monotonic_now_ns; + VIVE_TRACE(d, "dev %s At %ldns: Pose requested for +%ldns (%ldns), predicting %ldns", d->base.str, + monotonic_now_ns, remaining_ns, at_timestamp_ns, prediction_ns); + + //! @todo integrate position here + struct xrt_space_relation relation = {0}; + relation.pose.orientation = d->rot_filtered; + relation.relation_flags = XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT; + + m_predict_relation(&relation, prediction_s, out_relation); +} + static void vive_controller_device_get_tracked_pose(struct xrt_device *xdev, enum xrt_input_name name, @@ -376,12 +396,7 @@ vive_controller_device_get_tracked_pose(struct xrt_device *xdev, return; } - out_relation->pose.orientation = d->rot_filtered; - - //! @todo assuming that orientation is actually currently tracked. - out_relation->relation_flags = (enum xrt_space_relation_flags)( - XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT | - XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); + predict_pose(d, at_timestamp_ns, out_relation); os_thread_helper_unlock(&d->controller_thread); @@ -531,6 +546,8 @@ vive_controller_handle_imu_sample(struct vive_controller_device *d, struct watch uint32_t dt_raw = calc_dt_raw_and_handle_overflow(d, time_raw); uint64_t dt_ns = cald_dt_ns(dt_raw); + d->imu.ts_received_ns = os_monotonic_get_ns(); + int16_t acc[3] = { __le16_to_cpu(sample->acc[0]), __le16_to_cpu(sample->acc[1]), diff --git a/src/xrt/drivers/vive/vive_controller.h b/src/xrt/drivers/vive/vive_controller.h index c30cdf0ae..c5d27e336 100644 --- a/src/xrt/drivers/vive/vive_controller.h +++ b/src/xrt/drivers/vive/vive_controller.h @@ -54,6 +54,7 @@ struct vive_controller_device { uint64_t time_ns; uint32_t last_sample_time_raw; + timepoint_ns ts_received_ns; } imu; struct m_imu_3dof fusion; From 3162f8050c5baf90724d3e0414f33845bf087da0 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 17 Feb 2021 20:03:34 +0100 Subject: [PATCH 067/883] doc: Add changelog for MR 691 --- doc/changes/drivers/mr.691.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/drivers/mr.691.md diff --git a/doc/changes/drivers/mr.691.md b/doc/changes/drivers/mr.691.md new file mode 100644 index 000000000..db714093b --- /dev/null +++ b/doc/changes/drivers/mr.691.md @@ -0,0 +1 @@ +vive: Add rotation pose prediction to HMD and Controllers From daff282946bd34e1def30fe9eb5006615da37b55 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Fri, 19 Feb 2021 14:31:25 -0600 Subject: [PATCH 068/883] ipc: don't drop the blend mode on the floor --- src/xrt/ipc/client/ipc_client_hmd.c | 4 +--- src/xrt/ipc/server/ipc_server_process.c | 2 ++ src/xrt/ipc/shared/ipc_protocol.h | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/xrt/ipc/client/ipc_client_hmd.c b/src/xrt/ipc/client/ipc_client_hmd.c index a9ae77979..edd0b4efa 100644 --- a/src/xrt/ipc/client/ipc_client_hmd.c +++ b/src/xrt/ipc/client/ipc_client_hmd.c @@ -170,15 +170,13 @@ ipc_client_hmd_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin * } #endif - // clang-foramt off - ich->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; + ich->base.hmd->blend_mode = ipc_c->ism->hmd.blend_mode; ich->base.hmd->views[0].display.w_pixels = ipc_c->ism->hmd.views[0].display.w_pixels; ich->base.hmd->views[0].display.h_pixels = ipc_c->ism->hmd.views[0].display.h_pixels; ich->base.hmd->views[0].fov = ipc_c->ism->hmd.views[0].fov; ich->base.hmd->views[1].display.w_pixels = ipc_c->ism->hmd.views[1].display.w_pixels; ich->base.hmd->views[1].display.h_pixels = ipc_c->ism->hmd.views[1].display.h_pixels; ich->base.hmd->views[1].fov = ipc_c->ism->hmd.views[1].fov; - // clang-foramt on // Distortion information, fills in xdev->compute_distortion(). u_distortion_mesh_set_none(&ich->base); diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index bf8479df2..cf3eef876 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -264,6 +264,8 @@ init_shm(struct ipc_server *s) ism->hmd.views[1].display.w_pixels = xdev->hmd->views[1].display.w_pixels; ism->hmd.views[1].display.h_pixels = xdev->hmd->views[1].display.h_pixels; ism->hmd.views[1].fov = xdev->hmd->views[1].fov; + + ism->hmd.blend_mode = xdev->hmd->blend_mode; } // Setup the tracking origin. diff --git a/src/xrt/ipc/shared/ipc_protocol.h b/src/xrt/ipc/shared/ipc_protocol.h index c4c365d3d..2da3add08 100644 --- a/src/xrt/ipc/shared/ipc_protocol.h +++ b/src/xrt/ipc/shared/ipc_protocol.h @@ -224,6 +224,7 @@ struct ipc_shared_memory */ struct xrt_fov fov; } views[2]; + enum xrt_blend_mode blend_mode; } hmd; struct xrt_input inputs[IPC_SHARED_MAX_INPUTS]; From 1b692c638195b62d21812a1d37efde41aafddd52 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 20 Feb 2021 00:51:28 +0000 Subject: [PATCH 069/883] doc: Document !964 --- doc/changes/ipc/mr.694.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/ipc/mr.694.md diff --git a/doc/changes/ipc/mr.694.md b/doc/changes/ipc/mr.694.md new file mode 100644 index 000000000..6f6e59d7b --- /dev/null +++ b/doc/changes/ipc/mr.694.md @@ -0,0 +1 @@ +all: Transfer HMD blend mode, don't drop it on the floor. From b7cc966cb0140c4639b3becda1bacaaf2f24ba13 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 12 Feb 2021 09:26:10 -0600 Subject: [PATCH 070/883] aux/vk: Add docs to helpers --- src/xrt/auxiliary/vk/vk_helpers.h | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/xrt/auxiliary/vk/vk_helpers.h b/src/xrt/auxiliary/vk/vk_helpers.h index b2ecc4ec9..280f5bf46 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.h +++ b/src/xrt/auxiliary/vk/vk_helpers.h @@ -263,13 +263,50 @@ vk_color_space_string(VkColorSpaceKHR code); #define VK_WARN(d, ...) U_LOG_IFL_W(d->ll, __VA_ARGS__) #define VK_ERROR(d, ...) U_LOG_IFL_E(d->ll, __VA_ARGS__) +/*! + * @brief Check a Vulkan VkResult, writing an error to the log and returning true if not VK_SUCCESS + * + * @param fun a string literal with the name of the Vulkan function, for logging purposes. + * @param res a VkResult from that function. + * @param file a string literal with the source code filename, such as from __FILE__ + * @param line a source code line number, such as from __LINE__ + * + * @see vk_check_error, vk_check_error_with_free which wrap this for easier usage. + * + * @ingroup aux_vk + */ bool vk_has_error(VkResult res, const char *fun, const char *file, int line); +/*! + * @def + * @brief Perform checking of a Vulkan result, returning in case it is not VK_SUCCESS. + * + * @param fun A string literal with the name of the Vulkan function, for logging purposes. + * @param res a VkResult from that function. + * @param ret value to return, if any, upon error + * + * @see vk_has_error which is wrapped by this macro + * + * @ingroup aux_vk + */ #define vk_check_error(fun, res, ret) \ if (vk_has_error(res, fun, __FILE__, __LINE__)) \ return ret +/*! + * @def + * @brief Perform checking of a Vulkan result, freeing an allocation and returning in case it is not VK_SUCCESS. + * + * @param fun A string literal with the name of the Vulkan function, for logging purposes. + * @param res a VkResult from that function. + * @param ret value to return, if any, upon error + * @param to_free expression to pass to `free()` upon error + * + * @see vk_has_error which is wrapped by this macro + * + * @ingroup aux_vk + */ #define vk_check_error_with_free(fun, res, ret, to_free) \ if (vk_has_error(res, fun, __FILE__, __LINE__)) { \ free(to_free); \ From 0644521da9b4f58410954cb468b1c2fa33fc2e8d Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 12 Feb 2021 09:26:26 -0600 Subject: [PATCH 071/883] d/ht: Fix typo in docs Fixes doxygen warning. --- src/xrt/drivers/ht/ht_interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/ht/ht_interface.h b/src/xrt/drivers/ht/ht_interface.h index f47439990..af0129bcc 100644 --- a/src/xrt/drivers/ht/ht_interface.h +++ b/src/xrt/drivers/ht/ht_interface.h @@ -32,7 +32,7 @@ struct xrt_auto_prober * ht_create_auto_prober(); /*! - * @dir drivers/handtracking + * @dir drivers/ht * * @brief @ref drv_ht files. */ From ab5af29d056ad4fde14bf64f6fdf9a72832be3c3 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 12 Feb 2021 09:35:08 -0600 Subject: [PATCH 072/883] doc: Fix doxygen warning --- doc/mainpage.md | 2 +- doc/writing-a-new-driver.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mainpage.md b/doc/mainpage.md index b92bf73c8..4c26068c3 100644 --- a/doc/mainpage.md +++ b/doc/mainpage.md @@ -16,7 +16,7 @@ also includes a section for changes that have not yet been in a tagged release. * @ref md_targets * @ref vulkan-extensions -* @ref md_writing-a-new-driver (**not complete**) +* @ref writing-driver (**not complete**) ## Source layout diff --git a/doc/writing-a-new-driver.md b/doc/writing-a-new-driver.md index 54893bfac..9ffe69ffe 100644 --- a/doc/writing-a-new-driver.md +++ b/doc/writing-a-new-driver.md @@ -1,4 +1,4 @@ -# Writing a new driver +# Writing a new driver {#writing-driver} + + +A "brief" overview of the various time-points that a frame goes through, from +when the application gets go ahead to render the frame to when pixels are turned +into photons. This only a single frame, where all of the timings are hit and the +application is single threaded. The HMD also only turns on the display during +the vblank period, meaning the pixel to photon transformation is delayed from +scanout starting to the vblank period (like for the Index). + +* `xrWaitFrame` returns to the application, referred to as **wake_up**. +* The app does a logic step to move the simulation to the next predicted + display time. +* `xrBeginFrame` is called by the application, referred to as **begin**. +* The app renders the current views using the GPU. +* `xrEndFrame` is called by the application submitting the views. +* The compositor wakes up to do it's distorting rendering and any warping, + checking if the applications rendering has finished. When the compositor + submits the work to the GPU, referred to as **submit**. +* The compositor queues it's swapbuffer to the display engine. +* Scanout starts, the kernel checked if the compositors rendering was completed + in time. We refer to this time as **present**, this seems to be common. +* During the vblank period the display lights up turning the pixels into + photons. We refer to this time as **display**, same as in OpenXR. + + +The names for timepoints are chosen to align with the naming in +[`VK_GOOGLE_display_timing`][], reading that extension can provide further +information. + + +## Main compositor perspective + + * @ref xrt_comp_wait_frame - It is within this function that the frame timing is + predicted, see @ref u_frame_timing_predict. The compositor will then wait to + **waku_up** time and then return from this function. + * @ref xrt_comp_begin_frame - The app or IPC server calls this function when it + is done with CPU work and ready to do GPU work. + * @ref xrt_comp_discard_frame - The frame is discarded. + * @ref xrt_comp_layer_begin - Called during transfers of layers. + * @ref xrt_comp_layer_stereo_projection - This and other layer functions are + called to list the layers the compositor should render. + * @ref xrt_comp_layer_commit - The compositor starts to render the frame, + trying to hit the **present** time. + + +[`VK_GOOGLE_display_timing`]: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_GOOGLE_display_timing.html diff --git a/doc/mainpage.md b/doc/mainpage.md index ecf9f6a02..048eaf101 100644 --- a/doc/mainpage.md +++ b/doc/mainpage.md @@ -17,6 +17,7 @@ getting started information and general documentation. * @ref vulkan-extensions * @ref writing-driver (**not complete**) * @ref ipc-design +* @ref frame-timing ## Source layout From 3e13e20c4cc9a69b9c3fbd8579098e3f7cb36f2b Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 25 Feb 2021 16:17:07 +0000 Subject: [PATCH 139/883] doc: Document !697 --- doc/changes/compositor/mr.697.md | 1 + doc/changes/misc_features/mr.697.1.md | 3 +++ doc/changes/misc_features/mr.697.2.md | 2 ++ doc/changes/xrt/mr.697.md | 4 ++++ 4 files changed, 10 insertions(+) create mode 100644 doc/changes/compositor/mr.697.md create mode 100644 doc/changes/misc_features/mr.697.1.md create mode 100644 doc/changes/misc_features/mr.697.2.md create mode 100644 doc/changes/xrt/mr.697.md diff --git a/doc/changes/compositor/mr.697.md b/doc/changes/compositor/mr.697.md new file mode 100644 index 000000000..00529e4a7 --- /dev/null +++ b/doc/changes/compositor/mr.697.md @@ -0,0 +1 @@ +main: Integrate new frame timing code. diff --git a/doc/changes/misc_features/mr.697.1.md b/doc/changes/misc_features/mr.697.1.md new file mode 100644 index 000000000..325c391c8 --- /dev/null +++ b/doc/changes/misc_features/mr.697.1.md @@ -0,0 +1,3 @@ +util: Add trace marker support code, this code uses the Linux trace_marker +kernel support to enable Monado to trace both function calls and other async +events. diff --git a/doc/changes/misc_features/mr.697.2.md b/doc/changes/misc_features/mr.697.2.md new file mode 100644 index 000000000..18ecdc09b --- /dev/null +++ b/doc/changes/misc_features/mr.697.2.md @@ -0,0 +1,2 @@ +util: Add frame timing helper code designed to use Vulkan display timing +extensions to get proper frame timing in the compositor. diff --git a/doc/changes/xrt/mr.697.md b/doc/changes/xrt/mr.697.md new file mode 100644 index 000000000..c8da2b955 --- /dev/null +++ b/doc/changes/xrt/mr.697.md @@ -0,0 +1,4 @@ +Added frame timing code that when the underlying vulkan driver supports the +VK_GOOGLE_display_timing extension greatly improves the timing accerecy of the +compositor. Along with this tracing code was added to better help use understand +what was happening during a frame. From 1e24602ca0299489bd01836997a1645bc4c0287f Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Sun, 7 Mar 2021 00:09:07 +0100 Subject: [PATCH 140/883] st/prober: fix off by one in reallocating list of disabled drivers --- src/xrt/state_trackers/prober/p_prober.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/xrt/state_trackers/prober/p_prober.c b/src/xrt/state_trackers/prober/p_prober.c index b1236abb0..491d16d4e 100644 --- a/src/xrt/state_trackers/prober/p_prober.c +++ b/src/xrt/state_trackers/prober/p_prober.c @@ -360,8 +360,9 @@ disable_drivers_from_conflicts(struct prober *p) } P_INFO(p, "Disabling %s because we have %s", second, first); - U_ARRAY_REALLOC_OR_FREE(p->disabled_drivers, char *, p->num_disabled_drivers++); - p->disabled_drivers[p->num_disabled_drivers - 1] = second; + size_t index = p->num_disabled_drivers++; + U_ARRAY_REALLOC_OR_FREE(p->disabled_drivers, char *, p->num_disabled_drivers); + p->disabled_drivers[index] = second; } } } @@ -369,7 +370,6 @@ disable_drivers_from_conflicts(struct prober *p) static void parse_disabled_drivers(struct prober *p) { - p->num_disabled_drivers = 0; cJSON *disabled_drivers = cJSON_GetObjectItemCaseSensitive(p->json.root, "disabled"); if (!disabled_drivers) { return; @@ -382,8 +382,9 @@ parse_disabled_drivers(struct prober *p) continue; } - U_ARRAY_REALLOC_OR_FREE(p->disabled_drivers, char *, p->num_disabled_drivers++); - p->disabled_drivers[p->num_disabled_drivers - 1] = disabled_driver->valuestring; + size_t index = p->num_disabled_drivers++; + U_ARRAY_REALLOC_OR_FREE(p->disabled_drivers, char *, p->num_disabled_drivers); + p->disabled_drivers[index] = disabled_driver->valuestring; } } @@ -445,6 +446,8 @@ initialize(struct prober *p, struct xrt_prober_entry_lists *lists) p->auto_probers[i] = lists->auto_probers[i](); } + + p->num_disabled_drivers = 0; parse_disabled_drivers(p); disable_drivers_from_conflicts(p); From 484d63a4ebb8da36c44696e19b965fada9937bb7 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Sun, 7 Mar 2021 00:05:06 +0100 Subject: [PATCH 141/883] d/survive: Use thread for processing events Due to an oversight libsurvive events were only processed when inputs were updated. If only triggering event processing when an event is needed, we would need to process a random number of events, causing random overhead. Rather, follow the model of other drivers and process events in a thread. This required creating a local copy of the xrt_input arrays. Fixes #113 Fixes !679 v2: Use a mutex for get_tracked_pose and update_inputs --- src/xrt/drivers/survive/survive_driver.c | 151 +++++++++++++++++------ 1 file changed, 111 insertions(+), 40 deletions(-) diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index 166f15870..c155a27db 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -25,6 +25,8 @@ #include "util/u_device.h" #include "util/u_distortion_mesh.h" +#include "os/os_threading.h" + #include "../auxiliary/os/os_time.h" #include "xrt/xrt_prober.h" @@ -120,6 +122,11 @@ struct survive_device struct xrt_space_relation last_relation; timepoint_ns last_relation_ts; + //! Number of inputs. + size_t num_last_inputs; + //! Array of input structs. + struct xrt_input *last_inputs; + enum DeviceType device_type; union { @@ -152,11 +159,18 @@ struct survive_system struct survive_device *hmd; struct survive_device *controllers[MAX_TRACKED_DEVICE_COUNT]; enum u_logging_level ll; + + struct os_thread_helper event_thread; + struct os_mutex lock; }; static void survive_device_destroy(struct xrt_device *xdev) { + if (!xdev) { + return; + } + U_LOG_D("destroying survive device"); struct survive_device *survive = (struct survive_device *)xdev; @@ -178,11 +192,19 @@ survive_device_destroy(struct xrt_device *xdev) if (survive->sys->hmd == NULL && all_null) { U_LOG_D("Tearing down libsurvive context"); - survive_simple_close(survive->sys->ctx); + os_thread_helper_stop(&survive->sys->event_thread); + os_thread_helper_destroy(&survive->sys->event_thread); + // Now that the thread is not running we can destroy the lock. + os_mutex_destroy(&survive->sys->lock); + + U_LOG_D("Stopped libsurvive event thread"); + + survive_simple_close(survive->sys->ctx); free(survive->sys); } + free(survive->last_inputs); free(survive); } @@ -312,7 +334,9 @@ survive_device_get_tracked_pose(struct xrt_device *xdev, return; } + os_mutex_lock(&survive->sys->lock); _predict_pose(survive, at_timestamp_ns, out_relation); + os_mutex_unlock(&survive->sys->lock); struct xrt_pose *p = &out_relation->pose; SURVIVE_TRACE(survive, "GET_POSITION (%f %f %f) GET_ORIENTATION (%f, %f, %f, %f)", p->position.x, p->position.y, @@ -388,10 +412,10 @@ survive_controller_get_hand_tracking(struct xrt_device *xdev, float thumb_curl = 0.0f; //! @todo place thumb preciely on the button that is touched/pressed - if (survive->base.inputs[VIVE_CONTROLLER_A_TOUCH].value.boolean || - survive->base.inputs[VIVE_CONTROLLER_B_TOUCH].value.boolean || - survive->base.inputs[VIVE_CONTROLLER_THUMBSTICK_TOUCH].value.boolean || - survive->base.inputs[VIVE_CONTROLLER_TRACKPAD_TOUCH].value.boolean) { + if (survive->last_inputs[VIVE_CONTROLLER_A_TOUCH].value.boolean || + survive->last_inputs[VIVE_CONTROLLER_B_TOUCH].value.boolean || + survive->last_inputs[VIVE_CONTROLLER_THUMBSTICK_TOUCH].value.boolean || + survive->last_inputs[VIVE_CONTROLLER_TRACKPAD_TOUCH].value.boolean) { thumb_curl = 1.0; } @@ -502,7 +526,7 @@ update_axis(struct survive_device *survive, struct Axis *axis, const SurviveSimp return false; } - struct xrt_input *in = &survive->base.inputs[axis->input]; + struct xrt_input *in = &survive->last_inputs[axis->input]; float fval = e->axis_val[i]; @@ -560,22 +584,22 @@ update_button(struct survive_device *survive, const struct SurviveSimpleButtonEv if (e_type == SURVIVE_INPUT_EVENT_BUTTON_UP) { enum input_index index = buttons[btn_id].click; - struct xrt_input *input = &survive->base.inputs[index]; + struct xrt_input *input = &survive->last_inputs[index]; input->value.boolean = false; input->timestamp = ts; } else if (e_type == SURVIVE_INPUT_EVENT_BUTTON_DOWN) { enum input_index index = buttons[btn_id].click; - struct xrt_input *input = &survive->base.inputs[index]; + struct xrt_input *input = &survive->last_inputs[index]; input->value.boolean = true; input->timestamp = ts; } else if (e_type == SURVIVE_INPUT_EVENT_TOUCH_UP) { enum input_index index = buttons[btn_id].touch; - struct xrt_input *input = &survive->base.inputs[index]; + struct xrt_input *input = &survive->last_inputs[index]; input->value.boolean = false; input->timestamp = ts; } else if (e_type == SURVIVE_INPUT_EVENT_TOUCH_DOWN) { enum input_index index = buttons[btn_id].touch; - struct xrt_input *input = &survive->base.inputs[index]; + struct xrt_input *input = &survive->last_inputs[index]; input->value.boolean = true; input->timestamp = ts; } @@ -624,7 +648,7 @@ _process_button_event(struct survive_device *survive, const struct SurviveSimple SURVIVE_DEBUG(survive, "axis id: %d val %f", e->axis_ids[i], e->axis_val[i]); } } - struct xrt_input *squeeze_value_in = &survive->base.inputs[VIVE_CONTROLLER_SQUEEZE_VALUE]; + struct xrt_input *squeeze_value_in = &survive->last_inputs[VIVE_CONTROLLER_SQUEEZE_VALUE]; float prev_squeeze_value = squeeze_value_in->value.vec1.x; float squeeze_value = _calculate_squeeze_value(survive); if (prev_squeeze_value != squeeze_value) { @@ -685,7 +709,7 @@ _process_hmd_button_event(struct survive_device *survive, const struct SurviveSi static struct survive_device * get_device_by_object(struct survive_system *sys, const SurviveSimpleObject *object) { - if (sys->hmd->survive_obj == object) { + if (sys->hmd != NULL && sys->hmd->survive_obj == object) { return sys->hmd; } @@ -713,26 +737,20 @@ _process_pose_event(struct survive_device *survive, const struct SurviveSimplePo } static void -_process_event(struct survive_system *ss, struct survive_device *survive, struct SurviveSimpleEvent *event) +_process_event(struct survive_system *ss, struct SurviveSimpleEvent *event) { switch (event->event_type) { case SurviveSimpleEventType_ButtonEvent: { const struct SurviveSimpleButtonEvent *e = survive_simple_get_button_event(event); - struct survive_device *event_device = NULL; - if (e->object == survive->survive_obj) { - event_device = survive; - } else { - event_device = get_device_by_object(survive->sys, e->object); - } - + struct survive_device *event_device = get_device_by_object(ss, e->object); if (event_device == NULL) { - SURVIVE_ERROR(survive, "Event for unknown object not handled"); + U_LOG_IFL_E(ss->ll, "Event for unknown object not handled"); return; } // hmd & controller axes have overlapping enum indices - if (event_device == survive->sys->hmd) { + if (event_device == ss->hmd) { _process_hmd_button_event(event_device, e); } else { _process_button_event(event_device, e); @@ -748,15 +766,9 @@ _process_event(struct survive_system *ss, struct survive_device *survive, struct case SurviveSimpleEventType_PoseUpdateEvent: { const struct SurviveSimplePoseUpdatedEvent *e = survive_simple_get_pose_updated_event(event); - struct survive_device *event_device = NULL; - if (e->object == survive->survive_obj) { - event_device = survive; - } else { - event_device = get_device_by_object(survive->sys, e->object); - } - + struct survive_device *event_device = get_device_by_object(ss, e->object); if (event_device == NULL) { - SURVIVE_ERROR(survive, "Pose Event for unknown object not handled"); + U_LOG_IFL_E(ss->ll, "Event for unknown object not handled"); return; } @@ -764,27 +776,26 @@ _process_event(struct survive_system *ss, struct survive_device *survive, struct break; } case SurviveSimpleEventType_DeviceAdded: { - SURVIVE_WARN(survive, "Device added event, but hotplugging not implemented yet"); + U_LOG_IFL_W(ss->ll, "Device added event, but hotplugging not implemented yet"); break; } case SurviveSimpleEventType_None: break; - default: SURVIVE_ERROR(survive, "Unknown event %d", event->event_type); + default: U_LOG_IFL_E(ss->ll, "Unknown event %d", event->event_type); } } - static void survive_device_update_inputs(struct xrt_device *xdev) { struct survive_device *survive = (struct survive_device *)xdev; - /* one event queue for all devices. _process_events() updates all - devices, not just this survive device. */ + os_mutex_lock(&survive->sys->lock); - struct SurviveSimpleEvent event = {0}; - while (survive_simple_next_event(survive->sys->ctx, &event) != SurviveSimpleEventType_None) { - _process_event(NULL, survive, &event); + for (size_t i = 0; i < survive->base.num_inputs; i++) { + survive->base.inputs[i] = survive->last_inputs[i]; } + + os_mutex_unlock(&survive->sys->lock); } static bool @@ -899,6 +910,12 @@ _create_hmd_device(struct survive_system *sys, const struct SurviveSimpleObject survive->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; + survive->last_inputs = U_TYPED_ARRAY_CALLOC(struct xrt_input, survive->base.num_inputs); + survive->num_last_inputs = survive->base.num_inputs; + for (size_t i = 0; i < survive->base.num_inputs; i++) { + survive->last_inputs[i] = survive->base.inputs[i]; + } + return true; } @@ -1115,6 +1132,12 @@ _create_controller_device(struct survive_system *sys, survive->base.orientation_tracking_supported = true; survive->base.position_tracking_supported = true; + survive->last_inputs = U_TYPED_ARRAY_CALLOC(struct xrt_input, survive->base.num_inputs); + survive->num_last_inputs = survive->base.num_inputs; + for (size_t i = 0; i < survive->base.num_inputs; i++) { + survive->last_inputs[i] = survive->base.inputs[i]; + } + SURVIVE_DEBUG(survive, "Created Controller %d", idx); return true; @@ -1171,12 +1194,12 @@ add_connected_devices(struct survive_system *ss) struct SurviveSimpleEvent event = {0}; while (survive_simple_next_event(ss->ctx, &event) != SurviveSimpleEventType_None) { if (event.event_type == SurviveSimpleEventType_ConfigEvent) { - _process_event(ss, NULL, &event); + _process_event(ss, &event); // libsurvive processes sequentially, restart timeout start = os_monotonic_get_ns(); } else { - U_LOG_IFL_D(ss->ll, "Skipping event\n"); + U_LOG_IFL_T(ss->ll, "Skipping event\n"); } } @@ -1188,6 +1211,32 @@ add_connected_devices(struct survive_system *ss) return true; } +static void * +run_event_thread(void *ptr) +{ + struct survive_system *ss = (struct survive_system *)ptr; + + os_thread_helper_lock(&ss->event_thread); + while (os_thread_helper_is_running_locked(&ss->event_thread)) { + os_thread_helper_unlock(&ss->event_thread); + + // one event queue for all devices. _process_events() updates all devices + struct SurviveSimpleEvent event = {0}; + survive_simple_wait_for_event(ss->ctx, &event); + + os_mutex_lock(&ss->lock); + _process_event(ss, &event); + os_mutex_unlock(&ss->lock); + + // Just keep swimming. + os_thread_helper_lock(&ss->event_thread); + } + + os_thread_helper_unlock(&ss->event_thread); + + return NULL; +} + int survive_device_autoprobe(struct xrt_auto_prober *xap, cJSON *attached_data, @@ -1267,5 +1316,27 @@ survive_device_autoprobe(struct xrt_auto_prober *xap, } survive_already_initialized = true; + + // Mutex before thread. + int ret = os_mutex_init(&ss->lock); + if (ret != 0) { + U_LOG_IFL_E(ss->ll, "Failed to init mutex!"); + survive_device_destroy((struct xrt_device *)ss->hmd); + for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) { + survive_device_destroy((struct xrt_device *)ss->controllers[i]); + } + return 0; + } + + ret = os_thread_helper_start(&ss->event_thread, run_event_thread, ss); + if (ret != 0) { + U_LOG_IFL_E(ss->ll, "Failed to start event thread!"); + survive_device_destroy((struct xrt_device *)ss->hmd); + for (int i = 0; i < MAX_TRACKED_DEVICE_COUNT; i++) { + survive_device_destroy((struct xrt_device *)ss->controllers[i]); + } + return 0; + } + return out_idx; } From aa6548060732d727d40ded2d471abf41433bd744 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 8 Mar 2021 13:41:43 +0100 Subject: [PATCH 142/883] d/vive: Use a mutex for get_tracked_pose --- src/xrt/drivers/vive/vive_device.c | 27 +++++++++++++++++---------- src/xrt/drivers/vive/vive_device.h | 3 +++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index 87ea39ec7..169f9e766 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -54,6 +54,9 @@ vive_device_destroy(struct xrt_device *xdev) os_thread_helper_destroy(&d->watchman_thread); os_thread_helper_destroy(&d->mainboard_thread); + // Now that the thread is not running we can destroy the lock. + os_mutex_destroy(&d->lock); + m_imu_3dof_close(&d->fusion); if (d->mainboard_dev != NULL) { @@ -128,17 +131,9 @@ vive_device_get_tracked_pose(struct xrt_device *xdev, //! @todo Use this properly. (void)at_timestamp_ns; - os_thread_helper_lock(&d->sensors_thread); - - // Don't do anything if we have stopped. - if (!os_thread_helper_is_running_locked(&d->sensors_thread)) { - os_thread_helper_unlock(&d->sensors_thread); - return; - } - + os_mutex_lock(&d->lock); predict_pose(d, at_timestamp_ns, out_relation); - - os_thread_helper_unlock(&d->sensors_thread); + os_mutex_unlock(&d->lock); } static void @@ -579,7 +574,11 @@ vive_sensors_read_one_msg(struct vive_device *d, if (buffer[0] == report_id) { if (!_is_report_size_valid(d, ret, report_size, report_id)) return false; + + os_mutex_lock(&d->lock); process_cb(d, buffer); + os_mutex_unlock(&d->lock); + } else { VIVE_ERROR(d, "Unexpected sensor report type %s (0x%x).", _sensors_get_report_string(buffer[0]), buffer[0]); @@ -901,6 +900,14 @@ vive_device_create(struct os_hid_device *mainboard_dev, } snprintf(d->base.serial, XRT_DEVICE_NAME_LEN, "%s", d->config.firmware.device_serial_number); + // Mutex before thread. + ret = os_mutex_init(&d->lock); + if (ret != 0) { + VIVE_ERROR(d, "Failed to init mutex!"); + vive_device_destroy(&d->base); + return NULL; + } + ret = os_thread_helper_start(&d->sensors_thread, vive_sensors_run_thread, d); if (ret != 0) { VIVE_ERROR(d, "Failed to start sensors thread!"); diff --git a/src/xrt/drivers/vive/vive_device.h b/src/xrt/drivers/vive/vive_device.h index 5110aa142..806c47051 100644 --- a/src/xrt/drivers/vive/vive_device.h +++ b/src/xrt/drivers/vive/vive_device.h @@ -38,6 +38,9 @@ struct vive_device struct os_thread_helper watchman_thread; struct os_thread_helper mainboard_thread; + //! Lock for last and fusion. + struct os_mutex lock; + struct { uint64_t time_ns; From 5c014193f749c5a1f9693b15d115fcb1a1485c37 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 8 Mar 2021 13:47:27 +0100 Subject: [PATCH 143/883] d/vive_controller: Use a mutex for get_tracked_pose and update_inputs --- src/xrt/drivers/vive/vive_controller.c | 40 ++++++++++++++++---------- src/xrt/drivers/vive/vive_controller.h | 1 + 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/xrt/drivers/vive/vive_controller.c b/src/xrt/drivers/vive/vive_controller.c index 132d55a56..c281d30b0 100644 --- a/src/xrt/drivers/vive/vive_controller.c +++ b/src/xrt/drivers/vive/vive_controller.c @@ -107,6 +107,9 @@ vive_controller_device_destroy(struct xrt_device *xdev) os_thread_helper_destroy(&d->controller_thread); + // Now that the thread is not running we can destroy the lock. + os_mutex_destroy(&d->lock); + m_imu_3dof_close(&d->fusion); if (d->controller_hid) @@ -120,7 +123,8 @@ vive_controller_device_update_wand_inputs(struct xrt_device *xdev) { struct vive_controller_device *d = vive_controller_device(xdev); - os_thread_helper_lock(&d->controller_thread); + os_mutex_lock(&d->lock); + uint8_t buttons = d->state.buttons; /* @@ -170,7 +174,7 @@ vive_controller_device_update_wand_inputs(struct xrt_device *xdev) trigger_input->value.vec1.x = d->state.trigger; VIVE_TRACE(d, "Trigger: %f", d->state.trigger); - os_thread_helper_unlock(&d->controller_thread); + os_mutex_unlock(&d->lock); } static void @@ -178,7 +182,7 @@ vive_controller_device_update_index_inputs(struct xrt_device *xdev) { struct vive_controller_device *d = vive_controller_device(xdev); - os_thread_helper_lock(&d->controller_thread); + os_mutex_lock(&d->lock); uint8_t buttons = d->state.buttons; /* @@ -286,7 +290,7 @@ vive_controller_device_update_index_inputs(struct xrt_device *xdev) VIVE_DEBUG(d, "Trackpad force: %f\n", (float)d->state.trackpad_force / UINT8_MAX); } - os_thread_helper_unlock(&d->controller_thread); + os_mutex_unlock(&d->lock); } @@ -388,17 +392,9 @@ vive_controller_device_get_tracked_pose(struct xrt_device *xdev, // Clear out the relation. U_ZERO(out_relation); - os_thread_helper_lock(&d->controller_thread); - - // Don't do anything if we have stopped. - if (!os_thread_helper_is_running_locked(&d->controller_thread)) { - os_thread_helper_unlock(&d->controller_thread); - return; - } - + os_mutex_lock(&d->lock); predict_pose(d, at_timestamp_ns, out_relation); - - os_thread_helper_unlock(&d->controller_thread); + os_mutex_unlock(&d->lock); struct xrt_vec3 pos = out_relation->pose.position; struct xrt_quat quat = out_relation->pose.orientation; @@ -477,7 +473,9 @@ vive_controller_device_set_output(struct xrt_device *xdev, enum xrt_output_name return; } + os_mutex_lock(&d->lock); vive_controller_haptic_pulse(d, value); + os_mutex_unlock(&d->lock); } static void @@ -933,12 +931,16 @@ vive_controller_device_update(struct vive_controller_device *d) switch (buf[0]) { case VIVE_CONTROLLER_REPORT1_ID: + os_mutex_lock(&d->lock); vive_controller_decode_message(d, &((struct vive_controller_report1 *)buf)->message); + os_mutex_unlock(&d->lock); break; case VIVE_CONTROLLER_REPORT2_ID: + os_mutex_lock(&d->lock); vive_controller_decode_message(d, &((struct vive_controller_report2 *)buf)->message[0]); vive_controller_decode_message(d, &((struct vive_controller_report2 *)buf)->message[1]); + os_mutex_unlock(&d->lock); break; case VIVE_CONTROLLER_DISCONNECT_REPORT_ID: VIVE_DEBUG(d, "Controller disconnected."); break; default: VIVE_ERROR(d, "Unknown controller message type: %u", buf[0]); @@ -1184,7 +1186,15 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w } if (d->controller_hid) { - int ret = os_thread_helper_start(&d->controller_thread, vive_controller_run_thread, d); + // Mutex before thread. + int ret = os_mutex_init(&d->lock); + if (ret != 0) { + VIVE_ERROR(d, "Failed to init mutex!"); + vive_controller_device_destroy(&d->base); + return 0; + } + + ret = os_thread_helper_start(&d->controller_thread, vive_controller_run_thread, d); if (ret != 0) { VIVE_ERROR(d, "Failed to start mainboard thread!"); vive_controller_device_destroy((struct xrt_device *)d); diff --git a/src/xrt/drivers/vive/vive_controller.h b/src/xrt/drivers/vive/vive_controller.h index c5d27e336..8c55dee68 100644 --- a/src/xrt/drivers/vive/vive_controller.h +++ b/src/xrt/drivers/vive/vive_controller.h @@ -49,6 +49,7 @@ struct vive_controller_device struct os_hid_device *controller_hid; struct os_thread_helper controller_thread; + struct os_mutex lock; struct { From a887ddcc3c3df49947355188b7af087fcbc93b57 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 8 Mar 2021 13:54:58 +0100 Subject: [PATCH 144/883] d/hdk: Use a mutex for get_tracked_pose --- src/xrt/drivers/hdk/hdk_device.cpp | 24 +++++++++++++++++++----- src/xrt/drivers/hdk/hdk_device.h | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/xrt/drivers/hdk/hdk_device.cpp b/src/xrt/drivers/hdk/hdk_device.cpp index b30751e52..6cd855456 100644 --- a/src/xrt/drivers/hdk/hdk_device.cpp +++ b/src/xrt/drivers/hdk/hdk_device.cpp @@ -99,6 +99,9 @@ hdk_device_destroy(struct xrt_device *xdev) os_thread_helper_destroy(&hd->imu_thread); + // Now that the thread is not running we can destroy the lock. + os_mutex_destroy(&hd->lock); + if (hd->dev != NULL) { os_hid_destroy(hd->dev); hd->dev = NULL; @@ -204,9 +207,12 @@ hdk_device_update(struct hdk_device *hd) math_quat_rotate(&ang_vel_quat, &rot_90_about_x, &ang_vel_quat); math_quat_rotate(&negative_90_about_x, &ang_vel_quat, &ang_vel_quat); + os_mutex_lock(&hd->lock); hd->ang_vel_quat = ang_vel_quat; hd->quat_valid = true; + os_mutex_unlock(&hd->lock); + return 1; } @@ -228,26 +234,26 @@ hdk_device_get_tracked_pose(struct xrt_device *xdev, // Adjusting for latency - 14ms, found empirically. now -= 14000000; + os_mutex_lock(&hd->lock); if (!hd->quat_valid) { out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE; HDK_TRACE(hd, "GET_TRACKED_POSE: No pose"); + os_mutex_unlock(&hd->lock); return; } - os_thread_helper_lock(&hd->imu_thread); - out_relation->pose.orientation = hd->quat; out_relation->angular_velocity.x = hd->ang_vel_quat.x; out_relation->angular_velocity.y = hd->ang_vel_quat.y; out_relation->angular_velocity.z = hd->ang_vel_quat.z; + os_mutex_unlock(&hd->lock); + out_relation->relation_flags = xrt_space_relation_flags(XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); - os_thread_helper_unlock(&hd->imu_thread); - HDK_TRACE(hd, "GET_TRACKED_POSE (%f, %f, %f, %f) ANG_VEL (%f, %f, %f)", hd->quat.x, hd->quat.y, hd->quat.z, hd->quat.w, hd->ang_vel_quat.x, hd->ang_vel_quat.y, hd->ang_vel_quat.z); } @@ -487,7 +493,15 @@ hdk_device_create(struct os_hid_device *dev, enum HDK_VARIANT variant) // } if (hd->dev) { - int ret = os_thread_helper_start(&hd->imu_thread, hdk_device_run_thread, hd); + // Mutex before thread. + int ret = os_mutex_init(&hd->lock); + if (ret != 0) { + HDK_ERROR(hd, "Failed to init mutex!"); + hdk_device_destroy(&hd->base); + return NULL; + } + + ret = os_thread_helper_start(&hd->imu_thread, hdk_device_run_thread, hd); if (ret != 0) { HDK_ERROR(hd, "Failed to start mainboard thread!"); hdk_device_destroy((struct xrt_device *)hd); diff --git a/src/xrt/drivers/hdk/hdk_device.h b/src/xrt/drivers/hdk/hdk_device.h index 39ff10a55..8956d3463 100644 --- a/src/xrt/drivers/hdk/hdk_device.h +++ b/src/xrt/drivers/hdk/hdk_device.h @@ -35,6 +35,7 @@ struct hdk_device enum HDK_VARIANT variant; struct os_thread_helper imu_thread; + struct os_mutex lock; enum u_logging_level ll; bool disconnect_notified; From eb594409dde1060309ca55fbe871dffd2947e022 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Tue, 9 Mar 2021 14:16:28 +0100 Subject: [PATCH 145/883] xrt: Increase number of autoprobers to 16 We actually have a total of 11 auto probers. --- src/xrt/include/xrt/xrt_prober.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/include/xrt/xrt_prober.h b/src/xrt/include/xrt/xrt_prober.h index 2a746038c..ef1272b87 100644 --- a/src/xrt/include/xrt/xrt_prober.h +++ b/src/xrt/include/xrt/xrt_prober.h @@ -42,7 +42,7 @@ struct os_hid_device; */ #define XRT_MAX_DEVICES_PER_PROBE 16 -#define MAX_AUTO_PROBERS 8 +#define MAX_AUTO_PROBERS 16 /*! * Entry for a single device. From 003b70d05e32bacff04201ef160ca80d1d2307a6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 9 Mar 2021 17:45:33 +0000 Subject: [PATCH 146/883] c/main: Use correct predicted display time for rendering Closes #114 Reported-by: Boris-Chengbiao Zhou Tested-by: Boris-Chengbiao Zhou --- src/xrt/compositor/main/comp_compositor.c | 1 + src/xrt/compositor/main/comp_compositor.h | 1 + src/xrt/compositor/main/comp_renderer.c | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index ea382d47f..467a10c0a 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -144,6 +144,7 @@ compositor_wait_frame(struct xrt_compositor *xc, c->frame.waited.id = frame_id; c->frame.waited.desired_present_time_ns = desired_present_time_ns; c->frame.waited.present_slop_ns = present_slop_ns; + c->frame.waited.predicted_display_time_ns = predicted_display_time_ns; uint64_t now_ns = os_monotonic_get_ns(); if (now_ns < wake_up_time_ns) { diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h index 4ff1c558f..8e9d21f64 100644 --- a/src/xrt/compositor/main/comp_compositor.h +++ b/src/xrt/compositor/main/comp_compositor.h @@ -158,6 +158,7 @@ struct comp_shaders struct comp_frame { int64_t id; + uint64_t predicted_display_time_ns; uint64_t desired_present_time_ns; uint64_t present_slop_ns; }; diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index fe44c13d6..6aeb635cf 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -374,7 +374,11 @@ renderer_get_view_projection(struct comp_renderer *r) struct xrt_space_relation relation; - xrt_device_get_tracked_pose(r->c->xdev, XRT_INPUT_GENERIC_HEAD_POSE, r->c->last_next_display_time, &relation); + xrt_device_get_tracked_pose( // + r->c->xdev, // + XRT_INPUT_GENERIC_HEAD_POSE, // + r->c->frame.rendering.predicted_display_time_ns, // + &relation); // struct xrt_vec3 eye_relation = { 0.063000f, /* TODO: get actual ipd_meters */ From a6da40de505b58c28f50dc578d36b7b2f0887ad7 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 9 Mar 2021 17:45:45 +0000 Subject: [PATCH 147/883] c/main: Remove unused fields Tested-by: Boris-Chengbiao Zhou --- src/xrt/compositor/main/comp_compositor.c | 5 ----- src/xrt/compositor/main/comp_compositor.h | 14 -------------- 2 files changed, 19 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 467a10c0a..3ba115774 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -443,8 +443,6 @@ compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_graphic c->last_frame_time_ns = os_monotonic_get_ns(); c->app_profiling.last_end = c->last_frame_time_ns; - //! @todo do a time-weighted average or something. - c->expected_app_duration_ns = c->app_profiling.last_end - c->app_profiling.last_begin; COMP_SPEW(c, "LAYER_COMMIT finished drawing at %8.3fms", ns_to_ms(c->last_frame_time_ns)); @@ -1313,9 +1311,6 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos comp_settings_init(&c->settings, xdev); c->last_frame_time_ns = os_monotonic_get_ns(); - c->frame_overhead_ns = 2000000; - //! @todo set this to an estimate that's better than 6ms - c->expected_app_duration_ns = 6000000; // Need to select window backend before creating Vulkan, then diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h index 8e9d21f64..b24513802 100644 --- a/src/xrt/compositor/main/comp_compositor.h +++ b/src/xrt/compositor/main/comp_compositor.h @@ -212,9 +212,6 @@ struct comp_compositor int64_t last_end; } app_profiling; - //! The time our compositor needs to do rendering - int64_t frame_overhead_ns; - struct { //! Current Index for times_ns. @@ -238,17 +235,6 @@ struct comp_compositor struct comp_frame rendering; } frame; - /*! - * @brief Estimated rendering time per frame of the application. - * - * Set by the begin_frame/end_frame code. - * - * @todo make this atomic. - */ - int64_t expected_app_duration_ns; - //! The last time we provided in the results of wait_frame - int64_t last_next_display_time; - struct { //! Thread object for safely destroying swapchain. From 0adcc179c0f27ae4ad801cb397703ba6196dfd5f Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 21 Oct 2020 20:30:05 +0200 Subject: [PATCH 148/883] xrt: Fix typo in u_file --- src/xrt/auxiliary/util/u_file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xrt/auxiliary/util/u_file.c b/src/xrt/auxiliary/util/u_file.c index c100367cd..d711f5676 100644 --- a/src/xrt/auxiliary/util/u_file.c +++ b/src/xrt/auxiliary/util/u_file.c @@ -54,10 +54,10 @@ mkpath(const char *path) ssize_t u_file_get_config_dir(char *out_path, size_t out_path_size) { - const char *xgd_home = getenv("XDG_CONFIG_HOME"); + const char *xdg_home = getenv("XDG_CONFIG_HOME"); const char *home = getenv("HOME"); - if (xgd_home != NULL) { - return snprintf(out_path, out_path_size, "%s/monado", xgd_home); + if (xdg_home != NULL) { + return snprintf(out_path, out_path_size, "%s/monado", xdg_home); } if (home != NULL) { return snprintf(out_path, out_path_size, "%s/.config/monado", home); From 851a600a6a6b49968b55c3db0f9c7d651b4d9ac2 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 14 Oct 2020 22:52:19 +0200 Subject: [PATCH 149/883] build/meson: Add systemd feature option for monado-service --- meson.build | 1 + meson_options.txt | 5 +++++ src/xrt/include/xrt/meson.build | 4 ++++ src/xrt/targets/service/meson.build | 7 ++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 66fd77a2a..18a21b628 100644 --- a/meson.build +++ b/meson.build @@ -71,6 +71,7 @@ vulkan = dependency('vulkan', required: true) zlib = dependency('zlib', required: false) survive = dependency('survive', required: false) dbus = dependency('dbus-1', required: get_option('dbus')) +systemd = dependency('libsystemd', required: get_option('systemd')) gst = dependency('gstreamer-1.0', required: false) gst_app = dependency('gstreamer-app-1.0', required: false) gst_video= dependency('gstreamer-video-1.0', required: false) diff --git a/meson_options.txt b/meson_options.txt index 9dc75564a..9c20e17c3 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -77,6 +77,11 @@ option('dbus', value: 'auto', description: 'Enable support for dbus.') +option('systemd', + type: 'feature', + value: 'auto', + description: 'Enable systemd support (for socket activation of service)') + option('service', type: 'boolean', value: true, diff --git a/src/xrt/include/xrt/meson.build b/src/xrt/include/xrt/meson.build index 4abefaa95..8ea490550 100644 --- a/src/xrt/include/xrt/meson.build +++ b/src/xrt/include/xrt/meson.build @@ -76,6 +76,10 @@ if dbus.found() and not get_option('dbus').disabled() have_conf.set('XRT_HAVE_DBUS', true) endif +if systemd.found() and not get_option('systemd').disabled() + have_conf.set('XRT_HAVE_SYSTEMD', true) +endif + if get_option('layer_depth') have_conf.set('XRT_FEATURE_OPENXR_LAYER_DEPTH', true) endif diff --git a/src/xrt/targets/service/meson.build b/src/xrt/targets/service/meson.build index 181746bd3..d5007dfcb 100644 --- a/src/xrt/targets/service/meson.build +++ b/src/xrt/targets/service/meson.build @@ -1,6 +1,11 @@ # Copyright 2020, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 +service_deps = [pthreads, libjpeg] +if systemd.found() and not get_option('systemd').disabled() + service_deps += systemd +endif + hack_deps = [] hack_src = [ '../openxr/oxr_sdl2_hack.c'] hack_libs = [] @@ -41,6 +46,6 @@ service = executable( common_include, xrt_include, ] + hack_incs, - dependencies: [pthreads, libjpeg] + hack_deps, + dependencies: [pthreads, libjpeg] + hack_deps + service_deps, install: true, ) From 2a02130301322965d3b52e241d06fe660a9b973c Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 14 Oct 2020 22:40:45 +0200 Subject: [PATCH 150/883] build/meson: Install systemd service file with meson --- src/xrt/targets/service/meson.build | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/xrt/targets/service/meson.build b/src/xrt/targets/service/meson.build index d5007dfcb..3709c5f66 100644 --- a/src/xrt/targets/service/meson.build +++ b/src/xrt/targets/service/meson.build @@ -49,3 +49,29 @@ service = executable( dependencies: [pthreads, libjpeg] + hack_deps + service_deps, install: true, ) + +service_install_path = join_paths(get_option('prefix'), 'bin', 'monado-service') +systemd_dir = join_paths(get_option('prefix'), get_option('libdir'), 'systemd', 'user') + +service_conf_data = configuration_data() +service_conf_data.set('UNIT_NAME', 'monado') +service_conf_data.set('conflicts', 'monado-dev') +service_conf_data.set('exit_on_disconnect', 'off') +service_conf_data.set('extra_desc', '') +service_conf_data.set('service_path', service_install_path) +configure_file( + input: 'monado.in.service', + output: 'monado.service', + configuration: service_conf_data, + install_dir: systemd_dir +) + +socket_conf_data = configuration_data() +socket_conf_data.set('conflicts', 'monado-dev') +socket_conf_data.set('extra_desc', '') +configure_file( + input: 'monado.in.socket', + output: 'monado.socket', + configuration: socket_conf_data, + install_dir: systemd_dir +) From fb0e1ab0ce580e8f23c9faccf2c513b09fb9e0e7 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 14 Oct 2020 23:55:14 +0200 Subject: [PATCH 151/883] build/cmake: Print if systemd is found --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be2f8ab62..941b98070 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,12 +312,13 @@ message(STATUS "# WAYLAND: ${XRT_HAVE_WAYLAND}") message(STATUS "# XLIB: ${XRT_HAVE_XLIB}") message(STATUS "# XRANDR: ${XRT_HAVE_XRANDR}") message(STATUS "# XCB: ${XRT_HAVE_XCB}") +message(STATUS "# VULKAN: ${XRT_HAVE_VULKAN}") message(STATUS "# OPENGL: ${XRT_HAVE_OPENGL}") message(STATUS "# OPENGLES: ${XRT_HAVE_OPENGLES}") -message(STATUS "# VULKAN: ${XRT_HAVE_VULKAN}") message(STATUS "# EGL: ${XRT_HAVE_EGL}") message(STATUS "# DBUS: ${XRT_HAVE_DBUS}") message(STATUS "# VF: ${XRT_HAVE_VF}") +message(STATUS "# SYSTEMD: ${XRT_HAVE_SYSTEMD}") message(STATUS "# LIBUSB: ${XRT_HAVE_LIBUSB}") message(STATUS "# JPEG: ${XRT_HAVE_JPEG}") message(STATUS "# OPENCV: ${XRT_HAVE_OPENCV}") From 94d546322e35cafd3aa396eaabaa544019bb2440 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 15 Oct 2020 00:04:54 +0200 Subject: [PATCH 152/883] build/meson: Print more build options on meson run --- meson.build | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/meson.build b/meson.build index 18a21b628..48d4bb4ae 100644 --- a/meson.build +++ b/meson.build @@ -274,3 +274,51 @@ if get_option('steamvr_plugin') else message('steamvr plugin: no') endif + +if build_opengl + message(' opengl: yes') +else + message(' opengl: no') +endif + +if build_opengles + message(' opengles: yes') +else + message(' opengles: no') +endif + +if build_egl + message(' egl: yes') +else + message(' egl: no') +endif + +if build_xlib + message(' xlib: yes') +else + message(' xlib: no') +endif + +if build_xcb + message(' xcb: yes') +else + message(' xcb: no') +endif + +if build_wayland + message(' wayland: yes') +else + message(' wayland: no') +endif + +if not get_option('systemd').disabled() and systemd.found() + message(' systemd: yes') +else + message(' systemd: no') +endif + +if not get_option('dbus').disabled() and dbus.found() + message(' dbus: yes') +else + message(' dbus: no') +endif From 7b95330bb594f1ccef55542416c127450ff7f89b Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 21 Oct 2020 23:28:43 +0200 Subject: [PATCH 153/883] ipc: Print information to delete socket file --- src/xrt/ipc/server/ipc_server_mainloop_linux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xrt/ipc/server/ipc_server_mainloop_linux.c b/src/xrt/ipc/server/ipc_server_mainloop_linux.c index d15f3dc8f..f74c05369 100644 --- a/src/xrt/ipc/server/ipc_server_mainloop_linux.c +++ b/src/xrt/ipc/server/ipc_server_mainloop_linux.c @@ -98,6 +98,10 @@ create_listen_socket(struct ipc_server_mainloop *ml, int *out_fd) "Or, is the systemd unit monado.socket or " "monado-dev.socket active?"); #endif + if (errno == EADDRINUSE) { + U_LOG_E("If monado-service is not running, delete %s before starting a new instance", + IPC_MSG_SOCK_FILE); + } close(fd); return ret; } From fcc77edb8b5b7d38c6f764e1b95e256c7df7f6da Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 10 Mar 2021 02:04:58 +0100 Subject: [PATCH 154/883] doc: Add changelog for MR 712 --- doc/changes/ipc/mr.712.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/ipc/mr.712.md diff --git a/doc/changes/ipc/mr.712.md b/doc/changes/ipc/mr.712.md new file mode 100644 index 000000000..51ddc6b13 --- /dev/null +++ b/doc/changes/ipc/mr.712.md @@ -0,0 +1 @@ +Support systemd socket activation with meson too. From d71ccc39ceb64cc655409fbdf1642a3b2863574e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 10 Mar 2021 13:54:26 +0000 Subject: [PATCH 155/883] u/timing: Add when_predict_ns on first frame --- src/xrt/auxiliary/util/u_timing_frame.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/xrt/auxiliary/util/u_timing_frame.c b/src/xrt/auxiliary/util/u_timing_frame.c index a8da4e880..1bc19819c 100644 --- a/src/xrt/auxiliary/util/u_timing_frame.c +++ b/src/xrt/auxiliary/util/u_timing_frame.c @@ -207,9 +207,12 @@ static struct frame * do_clean_slate_frame(struct display_timing *dt) { struct frame *f = create_frame(dt, STATE_PREDICTED); + uint64_t now_ns = os_monotonic_get_ns(); // Wild shot in the dark. uint64_t the_time_ns = os_monotonic_get_ns() + dt->frame_period_ns * 10; + f->when_predict_ns = now_ns; + f->desired_present_time_ns = the_time_ns; f->predicted_display_time_ns = calc_display_time_from_present_time(dt, the_time_ns); return f; From dac5bc0ea5b5d2582333a2145f49766f360c6181 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 10 Mar 2021 13:55:15 +0000 Subject: [PATCH 156/883] u/timing: Deal slightly better when timing info appears to time travel --- src/xrt/auxiliary/util/u_timing_frame.c | 30 ++++++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_frame.c b/src/xrt/auxiliary/util/u_timing_frame.c index 1bc19819c..2fb20ad46 100644 --- a/src/xrt/auxiliary/util/u_timing_frame.c +++ b/src/xrt/auxiliary/util/u_timing_frame.c @@ -627,15 +627,33 @@ trace_frame(FILE *file, struct frame *f) } if (!is_within_half_ms(f->actual_present_time_ns, f->desired_present_time_ns)) { - trace_begin_id(file, TID_ERROR, "slippage", f->frame_id, "slippage", f->desired_present_time_ns); - trace_end(file, TID_ERROR, f->actual_present_time_ns); + if (f->actual_present_time_ns > f->desired_present_time_ns) { + trace_begin_id(file, TID_ERROR, "slippage", f->frame_id, "slippage", + f->desired_present_time_ns); + trace_end(file, TID_ERROR, f->actual_present_time_ns); + } else { + trace_begin_id(file, TID_ERROR, "run-ahead", f->frame_id, "run-ahead", + f->actual_present_time_ns); + trace_end(file, TID_ERROR, f->desired_present_time_ns); + } } - trace_begin_id(file, TID_GPU, "gpu", f->frame_id, "gpu", f->when_submitted_ns); - trace_end(file, TID_GPU, f->actual_present_time_ns - f->present_margin_ns); + uint64_t gpu_end_ns = f->actual_present_time_ns - f->present_margin_ns; + if (gpu_end_ns > f->when_submitted_ns) { + trace_begin_id(file, TID_GPU, "gpu", f->frame_id, "gpu", f->when_submitted_ns); + trace_end(file, TID_GPU, gpu_end_ns); + } else { + trace_begin_id(file, TID_GPU, "gpu-time-travel", f->frame_id, "gpu-time-travel", gpu_end_ns); + trace_end(file, TID_GPU, f->when_submitted_ns); + } - trace_begin_id(file, TID_INFO, "info", f->frame_id, "info", f->actual_present_time_ns); - trace_end(file, TID_INFO, f->when_infoed_ns); + if (f->when_infoed_ns >= f->actual_present_time_ns) { + trace_begin_id(file, TID_INFO, "info", f->frame_id, "info", f->actual_present_time_ns); + trace_end(file, TID_INFO, f->when_infoed_ns); + } else { + trace_begin_id(file, TID_INFO, "info before", f->frame_id, "info", f->when_infoed_ns); + trace_end(file, TID_INFO, f->actual_present_time_ns); + } trace_event_id(file, "vsync", f->frame_id, f->earliest_present_time_ns); if (f->actual_present_time_ns != f->earliest_present_time_ns) { From 8992f792578325e3b5147cbf1311fd0da40a172c Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 10 Mar 2021 17:48:38 +0000 Subject: [PATCH 157/883] c/main: Be even more paranoid about display timing code --- src/xrt/compositor/main/comp_target.h | 18 ++++++++++++++++-- .../compositor/main/comp_target_swapchain.c | 13 ++++++------- .../compositor/main/comp_target_swapchain.h | 6 +++++- src/xrt/compositor/main/comp_window_android.c | 3 ++- .../main/comp_window_direct_nvidia.c | 3 ++- .../compositor/main/comp_window_direct_randr.c | 3 ++- src/xrt/compositor/main/comp_window_mswin.c | 3 ++- .../compositor/main/comp_window_vk_display.c | 3 ++- src/xrt/compositor/main/comp_window_wayland.c | 3 ++- src/xrt/compositor/main/comp_window_xcb.c | 6 +++++- 10 files changed, 44 insertions(+), 17 deletions(-) diff --git a/src/xrt/compositor/main/comp_target.h b/src/xrt/compositor/main/comp_target.h index b5a67d4b4..b90943cd0 100644 --- a/src/xrt/compositor/main/comp_target.h +++ b/src/xrt/compositor/main/comp_target.h @@ -32,6 +32,15 @@ enum comp_target_timing_point COMP_TARGET_TIMING_POINT_SUBMIT, //create_images(ct, preferred_width, preferred_height, preferred_color_format, preferred_color_space, - present_mode); + ct->create_images( // + ct, // + preferred_width, // + preferred_height, // + preferred_color_format, // + preferred_color_space, // + present_mode); // } /*! diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index d50f2bf28..fdc1e15f8 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -95,16 +95,13 @@ comp_target_swapchain_create_images(struct comp_target *ct, VkBool32 supported; VkResult ret; -#ifndef XRT_OS_ANDROID - if (cts->uft == NULL && vk->has_GOOGLE_display_timing) { + // Some platforms really don't like the display_timing code. + bool use_display_timing_if_available = cts->timing_usage == COMP_TARGET_USE_DISPLAY_IF_AVAILABLE; + if (cts->uft == NULL && use_display_timing_if_available && vk->has_GOOGLE_display_timing) { u_frame_timing_display_timing_create(ct->c->settings.nominal_frame_interval_ns, &cts->uft); } else if (cts->uft == NULL) { u_frame_timing_fake_create(ct->c->settings.nominal_frame_interval_ns, &cts->uft); } -#else - COMP_INFO(ct->c, "Always using the fake timing code on Android."); - u_frame_timing_fake_create(ct->c->settings.nominal_frame_interval_ns, &cts->uft); -#endif // Free old image views. comp_target_swapchain_destroy_image_views(cts); @@ -645,8 +642,10 @@ comp_target_swapchain_cleanup(struct comp_target_swapchain *cts) } void -comp_target_swapchain_init_set_fnptrs(struct comp_target_swapchain *cts) +comp_target_swapchain_init_and_set_fnptrs(struct comp_target_swapchain *cts, + enum comp_target_display_timing_usage timing_usage) { + cts->timing_usage = timing_usage; cts->base.create_images = comp_target_swapchain_create_images; cts->base.acquire = comp_target_swapchain_acquire_next_image; cts->base.present = comp_target_swapchain_present; diff --git a/src/xrt/compositor/main/comp_target_swapchain.h b/src/xrt/compositor/main/comp_target_swapchain.h index faef81bc1..2f76dd6c7 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.h +++ b/src/xrt/compositor/main/comp_target_swapchain.h @@ -41,6 +41,9 @@ struct comp_target_swapchain //! Frame timing tracker. struct u_frame_timing *uft; + //! If we should use display timing. + enum comp_target_display_timing_usage timing_usage; + //! Also works as a frame index. int64_t current_frame_id; @@ -78,7 +81,8 @@ struct comp_target_swapchain * @ingroup comp_main */ void -comp_target_swapchain_init_set_fnptrs(struct comp_target_swapchain *cts); +comp_target_swapchain_init_and_set_fnptrs(struct comp_target_swapchain *cts, + enum comp_target_display_timing_usage timing_usage); /*! * Free all managed resources on the given @ref comp_target_swapchain, diff --git a/src/xrt/compositor/main/comp_window_android.c b/src/xrt/compositor/main/comp_window_android.c index 187a01a54..bc8967552 100644 --- a/src/xrt/compositor/main/comp_window_android.c +++ b/src/xrt/compositor/main/comp_window_android.c @@ -167,7 +167,8 @@ comp_window_android_create(struct comp_compositor *c) { struct comp_window_android *w = U_TYPED_CALLOC(struct comp_window_android); - comp_target_swapchain_init_set_fnptrs(&w->base); + // The display timing code hasn't been tested on Android and may be broken. + comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_FORCE_FAKE_DISPLAY_TIMING); w->base.base.name = "Android"; w->base.base.destroy = comp_window_android_destroy; diff --git a/src/xrt/compositor/main/comp_window_direct_nvidia.c b/src/xrt/compositor/main/comp_window_direct_nvidia.c index fa1f0aeb0..b2c1eb035 100644 --- a/src/xrt/compositor/main/comp_window_direct_nvidia.c +++ b/src/xrt/compositor/main/comp_window_direct_nvidia.c @@ -86,7 +86,8 @@ comp_window_direct_nvidia_create(struct comp_compositor *c) { struct comp_window_direct_nvidia *w = U_TYPED_CALLOC(struct comp_window_direct_nvidia); - comp_target_swapchain_init_set_fnptrs(&w->base); + // The display timing code hasn't been tested on nVidia and may be broken. + comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_FORCE_FAKE_DISPLAY_TIMING); w->base.base.name = "direct"; w->base.base.destroy = comp_window_direct_nvidia_destroy; diff --git a/src/xrt/compositor/main/comp_window_direct_randr.c b/src/xrt/compositor/main/comp_window_direct_randr.c index ed5dd7287..d42e63438 100644 --- a/src/xrt/compositor/main/comp_window_direct_randr.c +++ b/src/xrt/compositor/main/comp_window_direct_randr.c @@ -113,7 +113,8 @@ comp_window_direct_randr_create(struct comp_compositor *c) { struct comp_window_direct_randr *w = U_TYPED_CALLOC(struct comp_window_direct_randr); - comp_target_swapchain_init_set_fnptrs(&w->base); + // Display timing is tested and know working. + comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_USE_DISPLAY_IF_AVAILABLE); w->base.base.name = "direct"; w->base.base.destroy = comp_window_direct_randr_destroy; diff --git a/src/xrt/compositor/main/comp_window_mswin.c b/src/xrt/compositor/main/comp_window_mswin.c index ae27e233d..4bf343579 100644 --- a/src/xrt/compositor/main/comp_window_mswin.c +++ b/src/xrt/compositor/main/comp_window_mswin.c @@ -189,7 +189,8 @@ comp_window_mswin_create(struct comp_compositor *c) { struct comp_window_mswin *w = U_TYPED_CALLOC(struct comp_window_mswin); - comp_target_swapchain_init_set_fnptrs(&w->base); + // The display timing code hasn't been tested on Windows and may be broken. + comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_FORCE_FAKE_DISPLAY_TIMING); w->base.base.name = "MS Windows"; w->base.base.destroy = comp_window_mswin_destroy; diff --git a/src/xrt/compositor/main/comp_window_vk_display.c b/src/xrt/compositor/main/comp_window_vk_display.c index 52058cb5f..9653b8db0 100644 --- a/src/xrt/compositor/main/comp_window_vk_display.c +++ b/src/xrt/compositor/main/comp_window_vk_display.c @@ -84,7 +84,8 @@ comp_window_vk_display_create(struct comp_compositor *c) { struct comp_window_vk_display *w = U_TYPED_CALLOC(struct comp_window_vk_display); - comp_target_swapchain_init_set_fnptrs(&w->base); + // The display timing code hasn't been tested on vk display and may be broken. + comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_FORCE_FAKE_DISPLAY_TIMING); w->base.base.name = "VkDisplayKHR"; w->base.base.destroy = comp_window_vk_display_destroy; diff --git a/src/xrt/compositor/main/comp_window_wayland.c b/src/xrt/compositor/main/comp_window_wayland.c index 771b5a6ed..c22a9959b 100644 --- a/src/xrt/compositor/main/comp_window_wayland.c +++ b/src/xrt/compositor/main/comp_window_wayland.c @@ -102,7 +102,8 @@ comp_window_wayland_create(struct comp_compositor *c) { struct comp_window_wayland *w = U_TYPED_CALLOC(struct comp_window_wayland); - comp_target_swapchain_init_set_fnptrs(&w->base); + // The display timing code hasn't been tested on Wayland and may be broken. + comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_FORCE_FAKE_DISPLAY_TIMING); w->base.base.name = "wayland"; w->base.base.destroy = comp_window_wayland_destroy; diff --git a/src/xrt/compositor/main/comp_window_xcb.c b/src/xrt/compositor/main/comp_window_xcb.c index 5ec992cbf..07fb91fd9 100644 --- a/src/xrt/compositor/main/comp_window_xcb.c +++ b/src/xrt/compositor/main/comp_window_xcb.c @@ -128,7 +128,11 @@ comp_window_xcb_create(struct comp_compositor *c) { struct comp_window_xcb *w = U_TYPED_CALLOC(struct comp_window_xcb); - comp_target_swapchain_init_set_fnptrs(&w->base); + /* + * The display timing code has been tested on XCB, + * and is know to be broken when using VK_PRESENT_MODE_IMMEDIATE_KHR. + */ + comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_FORCE_FAKE_DISPLAY_TIMING); w->base.base.name = "xcb"; w->base.base.destroy = comp_window_xcb_destroy; From 7d51bbef271b28c80b128b5eb6a22acd659755ff Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 3 Mar 2021 17:02:55 +0000 Subject: [PATCH 158/883] external: Update EGL with another extension --- src/external/glad/command.sh | 1 + src/external/glad/include/glad/egl.h | 11 +++++++---- src/external/glad/include/glad/gl.h | 2 +- src/external/glad/src/egl.c | 2 ++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/external/glad/command.sh b/src/external/glad/command.sh index 7378e0596..8540df6c2 100755 --- a/src/external/glad/command.sh +++ b/src/external/glad/command.sh @@ -35,6 +35,7 @@ EGL_KHR_wait_sync,\ EGL_KHR_image,\ EGL_KHR_image_base,\ EGL_KHR_platform_android,\ +EGL_KHR_no_config_context,\ EGL_EXT_image_gl_colorspace,\ EGL_EXT_image_dma_buf_import,\ EGL_EXT_image_dma_buf_import_modifiers,\ diff --git a/src/external/glad/include/glad/egl.h b/src/external/glad/include/glad/egl.h index 8137c7a28..bbcf3aaa8 100644 --- a/src/external/glad/include/glad/egl.h +++ b/src/external/glad/include/glad/egl.h @@ -1,9 +1,9 @@ /** - * Loader generated by glad 2.0.0-beta on Fri Dec 18 17:45:30 2020 + * Loader generated by glad 2.0.0-beta on Wed Mar 3 17:01:11 2021 * * Generator: C/C++ * Specification: egl - * Extensions: 16 + * Extensions: 17 * * APIs: * - egl=1.4 @@ -18,10 +18,10 @@ * - ON_DEMAND = False * * Commandline: - * --merge --api='egl=1.4' --extensions='EGL_ANDROID_front_buffer_auto_refresh,EGL_ANDROID_get_native_client_buffer,EGL_ANDROID_image_native_buffer,EGL_ANDROID_native_fence_sync,EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_EXT_image_gl_colorspace,EGL_IMG_context_priority,EGL_KHR_create_context,EGL_KHR_fence_sync,EGL_KHR_gl_colorspace,EGL_KHR_image,EGL_KHR_image_base,EGL_KHR_platform_android,EGL_KHR_reusable_sync,EGL_KHR_wait_sync' c + * --merge --api='egl=1.4' --extensions='EGL_ANDROID_front_buffer_auto_refresh,EGL_ANDROID_get_native_client_buffer,EGL_ANDROID_image_native_buffer,EGL_ANDROID_native_fence_sync,EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_EXT_image_gl_colorspace,EGL_IMG_context_priority,EGL_KHR_create_context,EGL_KHR_fence_sync,EGL_KHR_gl_colorspace,EGL_KHR_image,EGL_KHR_image_base,EGL_KHR_no_config_context,EGL_KHR_platform_android,EGL_KHR_reusable_sync,EGL_KHR_wait_sync' c * * Online: - * http://glad.sh/#api=egl%3D1.4&extensions=EGL_ANDROID_front_buffer_auto_refresh%2CEGL_ANDROID_get_native_client_buffer%2CEGL_ANDROID_image_native_buffer%2CEGL_ANDROID_native_fence_sync%2CEGL_EXT_image_dma_buf_import%2CEGL_EXT_image_dma_buf_import_modifiers%2CEGL_EXT_image_gl_colorspace%2CEGL_IMG_context_priority%2CEGL_KHR_create_context%2CEGL_KHR_fence_sync%2CEGL_KHR_gl_colorspace%2CEGL_KHR_image%2CEGL_KHR_image_base%2CEGL_KHR_platform_android%2CEGL_KHR_reusable_sync%2CEGL_KHR_wait_sync&generator=c&options=MERGE + * http://glad.sh/#api=egl%3D1.4&extensions=EGL_ANDROID_front_buffer_auto_refresh%2CEGL_ANDROID_get_native_client_buffer%2CEGL_ANDROID_image_native_buffer%2CEGL_ANDROID_native_fence_sync%2CEGL_EXT_image_dma_buf_import%2CEGL_EXT_image_dma_buf_import_modifiers%2CEGL_EXT_image_gl_colorspace%2CEGL_IMG_context_priority%2CEGL_KHR_create_context%2CEGL_KHR_fence_sync%2CEGL_KHR_gl_colorspace%2CEGL_KHR_image%2CEGL_KHR_image_base%2CEGL_KHR_no_config_context%2CEGL_KHR_platform_android%2CEGL_KHR_reusable_sync%2CEGL_KHR_wait_sync&generator=c&options=MERGE * */ @@ -276,6 +276,7 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define EGL_NONE 0x3038 #define EGL_NON_CONFORMANT_CONFIG 0x3051 #define EGL_NOT_INITIALIZED 0x3001 +#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0) #define EGL_NO_CONTEXT EGL_CAST(EGLContext,0) #define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0) #define EGL_NO_IMAGE_KHR EGL_CAST(EGLImageKHR,0) @@ -512,6 +513,8 @@ GLAD_API_CALL int GLAD_EGL_KHR_gl_colorspace; GLAD_API_CALL int GLAD_EGL_KHR_image; #define EGL_KHR_image_base 1 GLAD_API_CALL int GLAD_EGL_KHR_image_base; +#define EGL_KHR_no_config_context 1 +GLAD_API_CALL int GLAD_EGL_KHR_no_config_context; #define EGL_KHR_platform_android 1 GLAD_API_CALL int GLAD_EGL_KHR_platform_android; #define EGL_KHR_reusable_sync 1 diff --git a/src/external/glad/include/glad/gl.h b/src/external/glad/include/glad/gl.h index e24ab563d..8ca8b88c2 100644 --- a/src/external/glad/include/glad/gl.h +++ b/src/external/glad/include/glad/gl.h @@ -1,5 +1,5 @@ /** - * Loader generated by glad 2.0.0-beta on Fri Dec 18 17:45:30 2020 + * Loader generated by glad 2.0.0-beta on Wed Mar 3 17:01:11 2021 * * Generator: C/C++ * Specification: gl diff --git a/src/external/glad/src/egl.c b/src/external/glad/src/egl.c index 33e520659..c21c8259d 100644 --- a/src/external/glad/src/egl.c +++ b/src/external/glad/src/egl.c @@ -38,6 +38,7 @@ int GLAD_EGL_KHR_fence_sync = 0; int GLAD_EGL_KHR_gl_colorspace = 0; int GLAD_EGL_KHR_image = 0; int GLAD_EGL_KHR_image_base = 0; +int GLAD_EGL_KHR_no_config_context = 0; int GLAD_EGL_KHR_platform_android = 0; int GLAD_EGL_KHR_reusable_sync = 0; int GLAD_EGL_KHR_wait_sync = 0; @@ -230,6 +231,7 @@ static int glad_egl_find_extensions_egl(EGLDisplay display) { GLAD_EGL_KHR_gl_colorspace = glad_egl_has_extension(extensions, "EGL_KHR_gl_colorspace"); GLAD_EGL_KHR_image = glad_egl_has_extension(extensions, "EGL_KHR_image"); GLAD_EGL_KHR_image_base = glad_egl_has_extension(extensions, "EGL_KHR_image_base"); + GLAD_EGL_KHR_no_config_context = glad_egl_has_extension(extensions, "EGL_KHR_no_config_context"); GLAD_EGL_KHR_platform_android = glad_egl_has_extension(extensions, "EGL_KHR_platform_android"); GLAD_EGL_KHR_reusable_sync = glad_egl_has_extension(extensions, "EGL_KHR_reusable_sync"); GLAD_EGL_KHR_wait_sync = glad_egl_has_extension(extensions, "EGL_KHR_wait_sync"); From 8be59f73ec54e8ee3c5438bb0121bb0b947736a3 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 3 Mar 2021 17:17:12 +0000 Subject: [PATCH 159/883] xrt: Return xrt_result_t from xrt_gfx_provider_create_gl_egl --- src/xrt/compositor/client/comp_egl_glue.c | 22 ++++++++++--------- src/xrt/include/xrt/xrt_gfx_egl.h | 5 +++-- src/xrt/state_trackers/oxr/oxr_session_egl.c | 18 ++++++++------- .../oxr/oxr_session_gles_android.c | 18 ++++++++------- 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/xrt/compositor/client/comp_egl_glue.c b/src/xrt/compositor/client/comp_egl_glue.c index 7635d0b7c..87df8c78a 100644 --- a/src/xrt/compositor/client/comp_egl_glue.c +++ b/src/xrt/compositor/client/comp_egl_glue.c @@ -216,12 +216,13 @@ client_egl_compositor_destroy(struct xrt_compositor *xc) free(ceglc); } -struct xrt_compositor_gl * +xrt_result_t xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, EGLDisplay display, EGLConfig config, EGLContext context, - PFNEGLGETPROCADDRESSPROC get_gl_procaddr) + PFNEGLGETPROCADDRESSPROC get_gl_procaddr, + struct xrt_compositor_gl **out_xcgl) { ll = debug_get_log_option_egl_log(); @@ -236,13 +237,13 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context)) { EGL_ERROR("Failed to make EGL context current"); // No need to restore on failure. - return NULL; + return XRT_ERROR_OPENGL; } EGLint egl_client_type; if (!eglQueryContext(display, context, EGL_CONTEXT_CLIENT_TYPE, &egl_client_type)) { old_restore(&old); - return NULL; + return XRT_ERROR_OPENGL; } switch (egl_client_type) { @@ -253,7 +254,7 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, #else EGL_ERROR("OpenGL support not including in this runtime build"); old_restore(&old); - return NULL; + return XRT_ERROR_OPENGL; #endif case EGL_OPENGL_ES_API: @@ -263,9 +264,9 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, #else EGL_ERROR("OpenGL|ES support not including in this runtime build"); old_restore(&old); - return NULL; + return XRT_ERROR_OPENGL; #endif - default: EGL_ERROR("Unsupported EGL client type"); return NULL; + default: EGL_ERROR("Unsupported EGL client type"); return XRT_ERROR_OPENGL; } struct client_egl_compositor *ceglc = U_TYPED_CALLOC(struct client_egl_compositor); @@ -307,7 +308,7 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, "EGL_EXT_image_dma_buf_import or " "GL_EXT_memory_object_fd"); old_restore(&old); - return NULL; + return XRT_ERROR_OPENGL; } #elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER) EGL_INFO("Using EGL_Image swapchain implementation with AHardwareBuffer"); @@ -318,10 +319,11 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, free(ceglc); U_LOG_E("Failed to initialize compositor"); old_restore(&old); - return NULL; + return XRT_ERROR_OPENGL; } ceglc->base.base.base.destroy = client_egl_compositor_destroy; old_restore(&old); - return &ceglc->base.base; + *out_xcgl = &ceglc->base.base; + return XRT_SUCCESS; } diff --git a/src/xrt/include/xrt/xrt_gfx_egl.h b/src/xrt/include/xrt/xrt_gfx_egl.h index 44af50142..10c3b0735 100644 --- a/src/xrt/include/xrt/xrt_gfx_egl.h +++ b/src/xrt/include/xrt/xrt_gfx_egl.h @@ -29,12 +29,13 @@ struct time_state; * @ingroup xrt_iface * @public @memberof xrt_compositor_native */ -struct xrt_compositor_gl * +xrt_result_t xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, EGLDisplay display, EGLConfig config, EGLContext context, - PFNEGLGETPROCADDRESSPROC getProcAddress); + PFNEGLGETPROCADDRESSPROC getProcAddress, + struct xrt_compositor_gl **out_xcgl); #ifdef __cplusplus } diff --git a/src/xrt/state_trackers/oxr/oxr_session_egl.c b/src/xrt/state_trackers/oxr/oxr_session_egl.c index b16246a41..26cfdead1 100644 --- a/src/xrt/state_trackers/oxr/oxr_session_egl.c +++ b/src/xrt/state_trackers/oxr/oxr_session_egl.c @@ -1,4 +1,4 @@ -// Copyright 2018-2020, Collabora, Ltd. +// Copyright 2018-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -60,14 +60,16 @@ oxr_session_populate_egl(struct oxr_logger *log, } struct xrt_compositor_native *xcn = sess->xcn; - struct xrt_compositor_gl *xcgl = xrt_gfx_provider_create_gl_egl( // - xcn, // - next->display, // - next->config, // - next->context, // - next->getProcAddress); // + struct xrt_compositor_gl *xcgl = NULL; + xrt_result_t xret = xrt_gfx_provider_create_gl_egl( // + xcn, // + next->display, // + next->config, // + next->context, // + next->getProcAddress, // + &xcgl); // - if (xcgl == NULL) { + if (xret != XR_SUCCESS || xcgl == NULL) { return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "Failed to create an egl client compositor"); } diff --git a/src/xrt/state_trackers/oxr/oxr_session_gles_android.c b/src/xrt/state_trackers/oxr/oxr_session_gles_android.c index 1b5b850ff..615ed39e8 100644 --- a/src/xrt/state_trackers/oxr/oxr_session_gles_android.c +++ b/src/xrt/state_trackers/oxr/oxr_session_gles_android.c @@ -1,4 +1,4 @@ -// Copyright 2018-2020, Collabora, Ltd. +// Copyright 2018-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -68,14 +68,16 @@ oxr_session_populate_gles_android(struct oxr_logger *log, struct xrt_compositor_native *xcn = sess->xcn; - struct xrt_compositor_gl *xcgl = xrt_gfx_provider_create_gl_egl( // - xcn, // - next->display, // - next->config, // - next->context, // - get_proc_addr); // + struct xrt_compositor_gl *xcgl = NULL; + xrt_result_t xret = xrt_gfx_provider_create_gl_egl( // + xcn, // + next->display, // + next->config, // + next->context, // + get_proc_addr, // + &xcgl); // - if (xcgl == NULL) { + if (xret != XR_SUCCESS || xcgl == NULL) { return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "Failed to create an egl client compositor"); } From 0571e0337ee50324e026c11216afcb8e84f9bb26 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 3 Mar 2021 17:24:40 +0000 Subject: [PATCH 160/883] xrt: Add XRT_ERROR_EGL_CONFIG_MISSING error --- src/xrt/compositor/client/comp_egl_glue.c | 2 +- src/xrt/include/xrt/xrt_results.h | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/xrt/compositor/client/comp_egl_glue.c b/src/xrt/compositor/client/comp_egl_glue.c index 87df8c78a..56516a791 100644 --- a/src/xrt/compositor/client/comp_egl_glue.c +++ b/src/xrt/compositor/client/comp_egl_glue.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file diff --git a/src/xrt/include/xrt/xrt_results.h b/src/xrt/include/xrt/xrt_results.h index a178af9f3..207cb7b74 100644 --- a/src/xrt/include/xrt/xrt_results.h +++ b/src/xrt/include/xrt/xrt_results.h @@ -48,9 +48,13 @@ typedef enum xrt_result * Multiple not supported on this layer level (IPC, compositor). */ XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED = -11, - /*! * The requested format is not supported by Monado. */ XRT_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED = -12, + /*! + * The given config was EGL_NO_CONFIG_KHR and EGL_KHR_no_config_context + * is not supported by the display. + */ + XRT_ERROR_EGL_CONFIG_MISSING = -12, } xrt_result_t; From 6c3ab4151a81a32455a79f9c6ee1bb250a6ddc1d Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 3 Mar 2021 17:27:42 +0000 Subject: [PATCH 161/883] st/oxr: Handle XRT_ERROR_EGL_CONFIG_MISSING --- src/xrt/state_trackers/oxr/oxr_session_egl.c | 5 +++++ src/xrt/state_trackers/oxr/oxr_session_gles_android.c | 5 +++++ src/xrt/state_trackers/oxr/oxr_verify.c | 4 +--- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_session_egl.c b/src/xrt/state_trackers/oxr/oxr_session_egl.c index 26cfdead1..465039029 100644 --- a/src/xrt/state_trackers/oxr/oxr_session_egl.c +++ b/src/xrt/state_trackers/oxr/oxr_session_egl.c @@ -69,6 +69,11 @@ oxr_session_populate_egl(struct oxr_logger *log, next->getProcAddress, // &xcgl); // + if (xret == XRT_ERROR_EGL_CONFIG_MISSING) { + return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, + "XrGraphicsBindingEGLMNDX::config can not be null when EGL_KHR_no_config_context is " + "not supported by the display."); + } if (xret != XR_SUCCESS || xcgl == NULL) { return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "Failed to create an egl client compositor"); } diff --git a/src/xrt/state_trackers/oxr/oxr_session_gles_android.c b/src/xrt/state_trackers/oxr/oxr_session_gles_android.c index 615ed39e8..be55ab2d2 100644 --- a/src/xrt/state_trackers/oxr/oxr_session_gles_android.c +++ b/src/xrt/state_trackers/oxr/oxr_session_gles_android.c @@ -77,6 +77,11 @@ oxr_session_populate_gles_android(struct oxr_logger *log, get_proc_addr, // &xcgl); // + if (xret == XRT_ERROR_EGL_CONFIG_MISSING) { + return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, + "XrGraphicsBindingEGLMNDX::config can not be null when EGL_KHR_no_config_context is " + "not supported by the display."); + } if (xret != XR_SUCCESS || xcgl == NULL) { return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "Failed to create an egl client compositor"); } diff --git a/src/xrt/state_trackers/oxr/oxr_verify.c b/src/xrt/state_trackers/oxr/oxr_verify.c index eade7f524..c70abfbfb 100644 --- a/src/xrt/state_trackers/oxr/oxr_verify.c +++ b/src/xrt/state_trackers/oxr/oxr_verify.c @@ -564,9 +564,7 @@ oxr_verify_XrGraphicsBindingEGLMNDX(struct oxr_logger *log, const XrGraphicsBind return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "XrGraphicsBindingEGLMNDX::display cannot be NULL"); } - if (next->config == NULL) { - return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "XrGraphicsBindingEGLMNDX::config cannot be NULL"); - } + // The next->config field can be NULL if EGL_KHR_no_config_context is supported by the display. if (next->context == NULL) { return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "XrGraphicsBindingEGLMNDX::context cannot be NULL"); From 0452c69caa2d7958047336fd255c0d803079c318 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 3 Mar 2021 17:28:04 +0000 Subject: [PATCH 162/883] c/main: Detect when config is needed but missing --- src/xrt/compositor/client/comp_egl_glue.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xrt/compositor/client/comp_egl_glue.c b/src/xrt/compositor/client/comp_egl_glue.c index 56516a791..ae465f0aa 100644 --- a/src/xrt/compositor/client/comp_egl_glue.c +++ b/src/xrt/compositor/client/comp_egl_glue.c @@ -228,6 +228,11 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, gladLoadEGL(display, get_gl_procaddr); + if (config == EGL_NO_CONFIG_KHR && !EGL_KHR_no_config_context) { + EGL_ERROR("config == EGL_NO_CONFIG_KHR && !EGL_KHR_no_config_context"); + return XRT_ERROR_EGL_CONFIG_MISSING; + } + // On Android this extension is 'hidden'. ensure_native_fence_is_loaded(display, get_gl_procaddr); From a9a706cbbd15bfbbddaa3fede0108ab525f79136 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 3 Mar 2021 18:16:25 +0000 Subject: [PATCH 163/883] doc: Document !705 --- doc/changes/compositor/mr.705.md | 2 ++ doc/changes/misc_features/mr.705.md | 1 + doc/changes/state_trackers/mr.705.md | 2 ++ doc/changes/xrt/mr.705.1.md | 1 + doc/changes/xrt/mr.705.2.md | 2 ++ 5 files changed, 8 insertions(+) create mode 100644 doc/changes/compositor/mr.705.md create mode 100644 doc/changes/misc_features/mr.705.md create mode 100644 doc/changes/state_trackers/mr.705.md create mode 100644 doc/changes/xrt/mr.705.1.md create mode 100644 doc/changes/xrt/mr.705.2.md diff --git a/doc/changes/compositor/mr.705.md b/doc/changes/compositor/mr.705.md new file mode 100644 index 000000000..5393b659b --- /dev/null +++ b/doc/changes/compositor/mr.705.md @@ -0,0 +1,2 @@ +client: Handle EGL_NO_CONTEXT_KHR gracefully if the EGLDisplay supports +EGL_KHR_no_config_context. diff --git a/doc/changes/misc_features/mr.705.md b/doc/changes/misc_features/mr.705.md new file mode 100644 index 000000000..91657da3d --- /dev/null +++ b/doc/changes/misc_features/mr.705.md @@ -0,0 +1 @@ +external/glad: Add EGL extension EGL_KHR_no_config_context. diff --git a/doc/changes/state_trackers/mr.705.md b/doc/changes/state_trackers/mr.705.md new file mode 100644 index 000000000..f4a053c24 --- /dev/null +++ b/doc/changes/state_trackers/mr.705.md @@ -0,0 +1,2 @@ +OpenXR: Support EGL clients sending in no EGLConfig if the EGLDisplay supports +EGL_KHR_no_config_context. diff --git a/doc/changes/xrt/mr.705.1.md b/doc/changes/xrt/mr.705.1.md new file mode 100644 index 000000000..908280e8e --- /dev/null +++ b/doc/changes/xrt/mr.705.1.md @@ -0,0 +1 @@ +xrt: Return xrt_result_t from xrt_gfx_provider_create_gl_egl diff --git a/doc/changes/xrt/mr.705.2.md b/doc/changes/xrt/mr.705.2.md new file mode 100644 index 000000000..c9f145e63 --- /dev/null +++ b/doc/changes/xrt/mr.705.2.md @@ -0,0 +1,2 @@ +xrt: Add XRT_ERROR_EGL_CONFIG_MISSING error, to handle missing config from +EGL compositor creation call. From c73146c6fdea58a75742a7a2cd23aaa6637d20b6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sun, 14 Mar 2021 16:51:05 +0000 Subject: [PATCH 164/883] d/psvr: Ensure that timestamps are always after each other --- doc/changes/drivers/mr.717.md | 2 ++ src/xrt/drivers/psvr/psvr_device.c | 51 ++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 doc/changes/drivers/mr.717.md diff --git a/doc/changes/drivers/mr.717.md b/doc/changes/drivers/mr.717.md new file mode 100644 index 000000000..7218fc44c --- /dev/null +++ b/doc/changes/drivers/mr.717.md @@ -0,0 +1,2 @@ +psvr: Ensure that timestamps are always after each other, stopping any +time-traveling sample packets. diff --git a/src/xrt/drivers/psvr/psvr_device.c b/src/xrt/drivers/psvr/psvr_device.c index f5b45a15f..7392d081d 100644 --- a/src/xrt/drivers/psvr/psvr_device.c +++ b/src/xrt/drivers/psvr/psvr_device.c @@ -1,5 +1,5 @@ // Copyright 2016, Joey Ferwerda. -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -296,10 +296,7 @@ read_sample_and_apply_calibration(struct psvr_device *psvr, } static void -update_fusion(struct psvr_device *psvr, - struct psvr_parsed_sample *sample, - uint32_t tick_delta, - timepoint_ns timestamp_ns) +update_fusion(struct psvr_device *psvr, struct psvr_parsed_sample *sample, uint64_t timestamp_ns) { struct xrt_vec3 mag = {0.0f, 0.0f, 0.0f}; (void)mag; @@ -313,14 +310,7 @@ update_fusion(struct psvr_device *psvr, xrt_tracked_psvr_push_imu(psvr->tracker, timestamp_ns, &sample); } else { -#if 1 - timepoint_ns now = os_monotonic_get_ns(); - m_imu_3dof_update(&psvr->fusion, now, &psvr->read.accel, &psvr->read.gyro); -#else - float delta_secs = tick_delta / PSVR_TICKS_PER_SECOND; - - math_quat_integrate_velocity(&psvr->fusion.rot, &psvr->read.gyro, delta_secs, &psvr->fusion.rot); -#endif + m_imu_3dof_update(&psvr->fusion, timestamp_ns, &psvr->read.accel, &psvr->read.gyro); } } @@ -338,10 +328,27 @@ calc_delta_and_handle_rollover(uint32_t next, uint32_t last) return tick_delta; } +static timepoint_ns +ensure_forward_progress_timestamps(struct psvr_device *psvr, timepoint_ns timestamp_ns) +{ + timepoint_ns t = timestamp_ns; + + /* + * This make sure the timestamp is after the last we sent to the fusion, + * but it effectively drops the sample. + */ + if (psvr->last_sensor_time > t) { + t = psvr->last_sensor_time + 1; + } + + psvr->last_sensor_time = t; + return t; +} + static void handle_tracker_sensor_msg(struct psvr_device *psvr, unsigned char *buffer, int size) { - timepoint_ns now = os_monotonic_get_ns(); + timepoint_ns now_ns = os_monotonic_get_ns(); uint32_t last_sample_tick = psvr->last.samples[1].tick; if (!psvr_parse_sensor_packet(&psvr->last, buffer, size)) { @@ -368,16 +375,26 @@ handle_tracker_sensor_msg(struct psvr_device *psvr, unsigned char *buffer, int s tick_delta = 500; } } + // New delta between the two samples. uint32_t tick_delta2 = calc_delta_and_handle_rollover(s->samples[1].tick, s->samples[0].tick); time_duration_ns inter_sample_duration_ns = tick_delta2 * PSVR_NS_PER_TICK; + + // Move it back in time. + timepoint_ns timestamp_ns = (uint64_t)now_ns - (uint64_t)inter_sample_duration_ns; + + // Make sure timestamps are always after a previous timestamp. + timestamp_ns = ensure_forward_progress_timestamps(psvr, timestamp_ns); + // Update the fusion with first sample. - update_fusion(psvr, &s->samples[0], tick_delta, now - inter_sample_duration_ns); + update_fusion(psvr, &s->samples[0], timestamp_ns); + + // Make sure timestamps are always after a previous timestamp. + timestamp_ns = ensure_forward_progress_timestamps(psvr, now_ns); // Update the fusion with second sample. - update_fusion(psvr, &s->samples[1], tick_delta2, now); - psvr->last_sensor_time = now; + update_fusion(psvr, &s->samples[1], timestamp_ns); } static void From a71b3d35d1cfde8110e0978a45a30ca937663ccb Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sun, 14 Mar 2021 18:39:13 +0000 Subject: [PATCH 165/883] m/3dof: Add assert for timestamp paranoia --- doc/changes/auxiliary/mr.717.md | 1 + src/xrt/auxiliary/math/m_imu_3dof.c | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 doc/changes/auxiliary/mr.717.md diff --git a/doc/changes/auxiliary/mr.717.md b/doc/changes/auxiliary/mr.717.md new file mode 100644 index 000000000..48faabaa2 --- /dev/null +++ b/doc/changes/auxiliary/mr.717.md @@ -0,0 +1 @@ +m/3dof: Add assert to catch time traveling drivers. diff --git a/src/xrt/auxiliary/math/m_imu_3dof.c b/src/xrt/auxiliary/math/m_imu_3dof.c index 9ceceb61c..3f2ebce9e 100644 --- a/src/xrt/auxiliary/math/m_imu_3dof.c +++ b/src/xrt/auxiliary/math/m_imu_3dof.c @@ -19,6 +19,7 @@ #include "math/m_mathinclude.h" #include +#include #define DUR_1S_IN_NS (1000 * 1000 * 1000) #define DUR_300MS_IN_NS (300 * 1000 * 1000) @@ -183,6 +184,9 @@ m_imu_3dof_update(struct m_imu_3dof *f, return; } + // This code assumes all timestamps makes some forward progress. + assert(timestamp_ns >= f->last.timestamp_ns); + f->last.gyro = *gyro; f->last.accel = *accel; From 9b5a5ae30dc25249a4ede8ee84f31302e2e6fb64 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 18 Mar 2021 19:18:50 +0100 Subject: [PATCH 166/883] build: XRT_FEATURE_SERVICE requires XRT_FEATURE_OPENXR Avoid silently building when XRT_FEATURE_SERVICE is enabled, but XRT_FEATURE_OPENXR is not. --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 941b98070..a1017fd25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -357,3 +357,7 @@ message(STATUS "# DRIVER_SURVIVE: ${XRT_BUILD_DRIVER_SURVIVE}") message(STATUS "# DRIVER_VF: ${XRT_BUILD_DRIVER_VF}") message(STATUS "# DRIVER_VIVE: ${XRT_BUILD_DRIVER_VIVE}") message(STATUS "#####----- Config -----#####") + +if(XRT_FEATURE_SERVICE AND NOT XRT_FEATURE_OPENXR) + message(FATAL_ERROR "XRT_FEATURE_SERVICE requires XRT_FEATURE_OPENXR to be enabled") +endif() From 66c1fdaf1f5878ec01c5e306b19bddcf8b81e497 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 18 Mar 2021 19:22:28 +0100 Subject: [PATCH 167/883] build: Depend XRT_FEATURE_SERVICE on XRT_FEATURE_OPENXR --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1017fd25..c27637604 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,7 +131,7 @@ cmake_dependent_option(XRT_HAVE_EGL "Enable OpenGL on EGL Graphics API support" cmake_dependent_option(XRT_HAVE_DBUS "Enable dbus support (for BLE support)" ON "DBUS_FOUND" OFF) cmake_dependent_option(XRT_FEATURE_COMPOSITOR_MAIN "Build main compositor host functionality" ON "XRT_HAVE_VULKAN; XRT_HAVE_WAYLAND OR XRT_HAVE_XCB OR ANDROID OR WIN32" OFF) cmake_dependent_option(XRT_FEATURE_OPENXR "Build OpenXR runtime target" ON "XRT_FEATURE_COMPOSITOR_MAIN" OFF) -cmake_dependent_option(XRT_FEATURE_SERVICE "Enable separate service module for OpenXR runtime" ON "NOT WIN32" OFF) +cmake_dependent_option(XRT_FEATURE_SERVICE "Enable separate service module for OpenXR runtime" ON "NOT WIN32 AND XRT_FEATURE_OPENXR" OFF) cmake_dependent_option(XRT_HAVE_SYSTEMD "Enable systemd support (for socket activation of service)" ON "Systemd_FOUND AND XRT_FEATURE_SERVICE" OFF) cmake_dependent_option(XRT_INSTALL_SYSTEMD_UNIT_FILES "Install user unit files for systemd socket activation on installation" ON "XRT_HAVE_SYSTEMD" OFF) cmake_dependent_option(XRT_INSTALL_ABSOLUTE_SYSTEMD_UNIT_FILES "Use an absolute path to monado-system in installed user unit files for systemd socket activation" ON "XRT_INSTALL_SYSTEMD_UNIT_FILES" OFF) From aca6980ffda13cae187299a5754dbd457b6218b6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Mar 2021 12:35:53 +0000 Subject: [PATCH 168/883] scripts: Print out clang-format version --- scripts/format-project.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/format-project.sh b/scripts/format-project.sh index dd71b15e5..78101b4f2 100755 --- a/scripts/format-project.sh +++ b/scripts/format-project.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright 2019, Collabora, Ltd. +# Copyright 2019-2021, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 # Author: Ryan Pavlik @@ -22,7 +22,10 @@ if [ ! "${CLANGFORMAT}" ]; then fi ( + ${CLANGFORMAT} --version + cd $(dirname $0)/.. + find \ src/xrt/auxiliary \ src/xrt/compositor \ From aa10e9c0130b350d8546e95163b146a594fa1032 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 19 Mar 2021 09:58:06 -0500 Subject: [PATCH 169/883] ci: Add ubuntu groovy. --- .gitlab-ci.yml | 29 ++++++++++++++++++++++ .gitlab-ci/ubuntu_groovy_container_prep.sh | 5 ++++ 2 files changed, 34 insertions(+) create mode 100644 .gitlab-ci/ubuntu_groovy_container_prep.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 02f9ef7db..9d5d75c41 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,6 +36,12 @@ variables: FDO_DISTRIBUTION_VERSION: "20.04" FDO_DISTRIBUTION_TAG: "2021-02-23.0" +# Variables for build and usage of Ubuntu 20.10 (Groovy) image +.monado.variables.ubuntu:groovy: + variables: + FDO_DISTRIBUTION_VERSION: "20.10" + FDO_DISTRIBUTION_TAG: "2021-03-19.0" + # Variables for build and usage of Debian 10 (Buster) + Android NDK image .monado.variables.debian:buster-ndk: variables: @@ -114,6 +120,18 @@ ubuntu:container_prep: # a list of packages to install - assembled from .monado.variables.debian-based-packages FDO_DISTRIBUTION_PACKAGES: "${CORE_REQUIRED_PACKAGES} ${FEATURE_PACKAGES} ${PACKAGING_PACKAGES} ${TOOLS_REQUIRED_PACKAGES}" +# Ubuntu Groovy (x64) +ubuntu:groovy:container_prep: + stage: container_prep + extends: + - .monado.variables.ubuntu:focal + - .monado.variables.container-prep-base + - .monado.variables.debian-based-packages + - .fdo.container-build@ubuntu # from ci-templates + variables: + # a list of packages to install - assembled from .monado.variables.debian-based-packages + FDO_DISTRIBUTION_PACKAGES: "${CORE_REQUIRED_PACKAGES} ${FEATURE_PACKAGES} ${PACKAGING_PACKAGES} ${TOOLS_REQUIRED_PACKAGES}" + # Debian Buster + the Android NDK in /opt/android-ndk # The NDK itself gets installed by .gitlab-ci/ndk:container_prep.sh ndk:container_prep: @@ -351,6 +369,16 @@ ubuntu:focal:package: PACKAGE_BRANCH: ubuntu/focal DISTRO: focal +ubuntu:groovy:package: + extends: + - .monado.variables.ubuntu:groovy + - .fdo.distribution-image@ubuntu # from ci-templates + - .monado.base-job.debuild + + variables: + BACKPORT_SUFFIX: ubuntu20.04 + PACKAGE_BRANCH: ubuntu/focal + DISTRO: focal reprepro:package: stage: reprepro extends: @@ -360,6 +388,7 @@ reprepro:package: dependencies: - debian:buster:package - ubuntu:focal:package + - ubuntu:groovy:package before_script: # Convince gnupg to work properly in CI - mkdir -p ~/.gnupg && chmod 700 ~/.gnupg diff --git a/.gitlab-ci/ubuntu_groovy_container_prep.sh b/.gitlab-ci/ubuntu_groovy_container_prep.sh new file mode 100644 index 000000000..36480abd3 --- /dev/null +++ b/.gitlab-ci/ubuntu_groovy_container_prep.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# Copyright 2021, Collabora, Ltd. and the Monado contributors +# SPDX-License-Identifier: BSL-1.0 + +# Nothing really needed. From 857b831e301cba4f3b889d804ac3f2305229c462 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 22 Mar 2021 01:25:44 +0100 Subject: [PATCH 170/883] d/illixr: Add driver name --- src/xrt/drivers/illixr/illixr_prober.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xrt/drivers/illixr/illixr_prober.c b/src/xrt/drivers/illixr/illixr_prober.c index 76d0381d9..437bc4e9b 100644 --- a/src/xrt/drivers/illixr/illixr_prober.c +++ b/src/xrt/drivers/illixr/illixr_prober.c @@ -62,6 +62,7 @@ struct xrt_auto_prober * illixr_create_auto_prober() { struct illixr_prober *dp = U_TYPED_CALLOC(struct illixr_prober); + dp->base.name = "IlliXR"; dp->base.destroy = illixr_prober_destroy; dp->base.lelo_dallas_autoprobe = illixr_prober_autoprobe; From c90ebd8ec74dc3ae2bf1528bc329a63fd84ea5f5 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 22 Mar 2021 13:13:32 -0500 Subject: [PATCH 171/883] ci: Fix Ubuntu Groovy image. --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9d5d75c41..73f2d515c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,7 +40,7 @@ variables: .monado.variables.ubuntu:groovy: variables: FDO_DISTRIBUTION_VERSION: "20.10" - FDO_DISTRIBUTION_TAG: "2021-03-19.0" + FDO_DISTRIBUTION_TAG: "2021-03-22.0" # Variables for build and usage of Debian 10 (Buster) + Android NDK image .monado.variables.debian:buster-ndk: @@ -109,7 +109,7 @@ arch:container_prep: FDO_DISTRIBUTION_PACKAGES: "git gcc clang cmake meson ninja pkgconfig python3 diffutils patch doxygen graphviz eigen hidapi libxrandr mesa glslang vulkan-headers vulkan-icd-loader check glfw-x11 libusb opencv gtk3 ffmpeg v4l-utils qt5-base" # Ubuntu Focal (x64) -ubuntu:container_prep: +ubuntu:focal:container_prep: stage: container_prep extends: - .monado.variables.ubuntu:focal @@ -124,13 +124,13 @@ ubuntu:container_prep: ubuntu:groovy:container_prep: stage: container_prep extends: - - .monado.variables.ubuntu:focal + - .monado.variables.ubuntu:groovy - .monado.variables.container-prep-base - .monado.variables.debian-based-packages - .fdo.container-build@ubuntu # from ci-templates variables: # a list of packages to install - assembled from .monado.variables.debian-based-packages - FDO_DISTRIBUTION_PACKAGES: "${CORE_REQUIRED_PACKAGES} ${FEATURE_PACKAGES} ${PACKAGING_PACKAGES} ${TOOLS_REQUIRED_PACKAGES}" + FDO_DISTRIBUTION_PACKAGES: "${CORE_REQUIRED_PACKAGES} ${FEATURE_PACKAGES} ${PACKAGING_PACKAGES}" # Debian Buster + the Android NDK in /opt/android-ndk # The NDK itself gets installed by .gitlab-ci/ndk:container_prep.sh From c7bff330e275656928e9913bc006a0f880d51bcd Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 22 Mar 2021 23:47:02 +0000 Subject: [PATCH 172/883] ci: Add doxygen and graphviz to packaging images --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 73f2d515c..6c11894c7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,7 +16,7 @@ variables: FEATURE_PACKAGES: "libhidapi-dev libwayland-dev libuvc-dev libavcodec-dev libopencv-dev libv4l-dev libcjson-dev libsdl2-dev libegl1-mesa-dev libdbus-1-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libsystemd-dev" # Only used for building packages - PACKAGING_PACKAGES: "devscripts debhelper dput-ng gettext-base markdown" + PACKAGING_PACKAGES: "devscripts debhelper dput-ng gettext-base markdown doxygen graphviz" # Used for ancillary "not compilation" jobs/features, like docs, changelogs, formatting, etc. TOOLS_REQUIRED_PACKAGES: "clang-format-7 codespell doxygen graphviz python3-pip python3-click" @@ -28,19 +28,19 @@ variables: .monado.variables.debian:buster: variables: FDO_DISTRIBUTION_VERSION: buster - FDO_DISTRIBUTION_TAG: "2021-02-23.0" + FDO_DISTRIBUTION_TAG: "2021-03-22.1" # Variables for build and usage of Ubuntu 20.04 LTS (Focal) image .monado.variables.ubuntu:focal: variables: FDO_DISTRIBUTION_VERSION: "20.04" - FDO_DISTRIBUTION_TAG: "2021-02-23.0" + FDO_DISTRIBUTION_TAG: "2021-03-22.1" # Variables for build and usage of Ubuntu 20.10 (Groovy) image .monado.variables.ubuntu:groovy: variables: FDO_DISTRIBUTION_VERSION: "20.10" - FDO_DISTRIBUTION_TAG: "2021-03-22.0" + FDO_DISTRIBUTION_TAG: "2021-03-22.1" # Variables for build and usage of Debian 10 (Buster) + Android NDK image .monado.variables.debian:buster-ndk: From d1cad2eda8fb3fb3d79a56e96e66928610cfcfd4 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 23 Mar 2021 02:12:56 +0000 Subject: [PATCH 173/883] ci: Fix focal container --- .gitlab-ci.yml | 6 +++--- ...ntu_container_prep.sh => ubuntu_focal_container_prep.sh} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename .gitlab-ci/{ubuntu_container_prep.sh => ubuntu_focal_container_prep.sh} (100%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6c11894c7..b321bdba1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,19 +28,19 @@ variables: .monado.variables.debian:buster: variables: FDO_DISTRIBUTION_VERSION: buster - FDO_DISTRIBUTION_TAG: "2021-03-22.1" + FDO_DISTRIBUTION_TAG: "2021-03-23.0" # Variables for build and usage of Ubuntu 20.04 LTS (Focal) image .monado.variables.ubuntu:focal: variables: FDO_DISTRIBUTION_VERSION: "20.04" - FDO_DISTRIBUTION_TAG: "2021-03-22.1" + FDO_DISTRIBUTION_TAG: "2021-03-23.0" # Variables for build and usage of Ubuntu 20.10 (Groovy) image .monado.variables.ubuntu:groovy: variables: FDO_DISTRIBUTION_VERSION: "20.10" - FDO_DISTRIBUTION_TAG: "2021-03-22.1" + FDO_DISTRIBUTION_TAG: "2021-03-23.0" # Variables for build and usage of Debian 10 (Buster) + Android NDK image .monado.variables.debian:buster-ndk: diff --git a/.gitlab-ci/ubuntu_container_prep.sh b/.gitlab-ci/ubuntu_focal_container_prep.sh similarity index 100% rename from .gitlab-ci/ubuntu_container_prep.sh rename to .gitlab-ci/ubuntu_focal_container_prep.sh From 2ac4ff84ecec7bd253e845b1aa4beb56b99bdce9 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Tue, 16 Mar 2021 15:51:34 +0100 Subject: [PATCH 174/883] aux/util: Fix comment for u_device_setup_tracking_origins --- src/xrt/auxiliary/util/u_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/util/u_device.h b/src/xrt/auxiliary/util/u_device.h index c3251dfc5..b29d1b9a6 100644 --- a/src/xrt/auxiliary/util/u_device.h +++ b/src/xrt/auxiliary/util/u_device.h @@ -103,7 +103,7 @@ void u_device_assign_xdev_roles(struct xrt_device **xdevs, size_t num_xdevs, int *head, int *left, int *right); /*! - * Helper function to assign head, left hand and right hand roles. + * Helper function for setting up tracking origins. Applies 3dof offsets for devices with XRT_TRACKING_TYPE_NONE. * * @ingroup aux_util */ From 67339a4d7cd9caddcbf57d5a1e5eaa7f13fa2610 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 24 Mar 2021 14:03:54 +0000 Subject: [PATCH 175/883] d/remote: Fix warning --- src/xrt/drivers/remote/r_hub.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/xrt/drivers/remote/r_hub.c b/src/xrt/drivers/remote/r_hub.c index 73a091565..35ec0cfb3 100644 --- a/src/xrt/drivers/remote/r_hub.c +++ b/src/xrt/drivers/remote/r_hub.c @@ -25,13 +25,16 @@ #include #include -#if !defined(__USE_MISC) || !defined(_BSD_SOURCE) -#define __USE_MISC // SOL_TCP on C11 +#ifndef __USE_MISC +#define __USE_MISC // SOL_TCP on C11 +#endif +#ifndef _BSD_SOURCE #define _BSD_SOURCE // same, but for musl #endif #include + /* * * Function. From e066f6a828586406456eb2b9e5bd60792f40b0ad Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 24 Mar 2021 14:04:04 +0000 Subject: [PATCH 176/883] st/gui: Fix warning --- src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c b/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c index 022cc5f3d..c12ddb5c7 100644 --- a/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c +++ b/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c @@ -217,9 +217,8 @@ scene_render(struct gui_scene *scene, struct gui_program *p) bool checked = ts->editing_override == (int)i; - const int len = XRT_DEVICE_NAME_LEN * 2 + 10; - char buf[len]; - snprintf(buf, len, "%s <- %s", ts->overrides[i].target_device_serial, + char buf[XRT_DEVICE_NAME_LEN * 2 + 10]; + snprintf(buf, sizeof(buf), "%s <- %s", ts->overrides[i].target_device_serial, ts->overrides[i].tracker_device_serial); if (igCheckbox(buf, &checked)) { ts->editing_override = i; From dad5c6d5d874262baf9ce6f1ed4fd680b50bd3d9 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 17:33:46 +0100 Subject: [PATCH 177/883] u_config_json: Fix saving when no config file exists If json->root was null, it would write a config file containing only (null). --- src/xrt/auxiliary/util/u_config_json.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 377cf6484..ee75100c7 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -354,6 +354,12 @@ u_config_json_get_tracking_settings(struct u_config_json *json, struct xrt_setti return true; } +static void +u_config_json_make_default_root(struct u_config_json *json) +{ + json->root = cJSON_CreateObject(); +} + static void u_config_write(struct u_config_json *json) { @@ -371,6 +377,9 @@ u_config_write(struct u_config_json *json) void u_config_json_save_calibration(struct u_config_json *json, struct xrt_settings_tracking *settings) { + if (!json->root) { + u_config_json_make_default_root(json); + } cJSON *root = json->root; cJSON *t = cJSON_GetObjectItem(root, "tracking"); @@ -425,6 +434,9 @@ make_pose(struct xrt_pose *pose) void u_config_json_save_overrides(struct u_config_json *json, struct xrt_tracking_override *overrides, size_t num_overrides) { + if (!json->root) { + u_config_json_make_default_root(json); + } cJSON *root = json->root; cJSON *t = cJSON_GetObjectItem(root, "tracking"); From aab94e7add48ebbe88581891368979f818ad6225 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:04:32 +0100 Subject: [PATCH 178/883] build/meson: Allow disabling tracking The tracking code uses ifdefs with XRT_HAVE_OPENCV. --- meson_options.txt | 2 +- src/xrt/include/xrt/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index 9c20e17c3..db96cb415 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -35,7 +35,7 @@ option('gui', option('tracking', type: 'feature', value: 'auto', - description: 'Enable tracking support') + description: 'Enable camera tracking support (disabling this will disable OpenCV support)') option('install-active-runtime', type: 'boolean', diff --git a/src/xrt/include/xrt/meson.build b/src/xrt/include/xrt/meson.build index 8ea490550..827daa4ea 100644 --- a/src/xrt/include/xrt/meson.build +++ b/src/xrt/include/xrt/meson.build @@ -48,7 +48,7 @@ if libuvc.found() have_conf.set('XRT_HAVE_LIBUVC', true) endif -if opencv.found() +if opencv.found() and build_tracking have_conf.set('XRT_HAVE_OPENCV', true) endif From 63f5c86257d2f67781039478ad5f35c07764a4ba Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 18 Mar 2021 14:32:59 +0000 Subject: [PATCH 179/883] xrt: Make xrt_swapchain be reference counted --- doc/changes/xrt/mr.723.md | 3 + src/xrt/compositor/client/comp_gl_client.c | 7 +- .../client/comp_gl_eglimage_swapchain.c | 6 +- .../client/comp_gl_memobj_swapchain.c | 6 +- src/xrt/compositor/client/comp_vk_client.c | 8 +- src/xrt/compositor/main/comp_swapchain.c | 8 +- src/xrt/include/xrt/xrt_compositor.h | 91 ++++++++++++++----- src/xrt/ipc/server/ipc_server_handler.c | 7 +- .../ipc/server/ipc_server_per_client_thread.c | 5 +- src/xrt/state_trackers/oxr/oxr_swapchain.c | 4 +- src/xrt/state_trackers/oxr/oxr_swapchain_gl.c | 8 +- src/xrt/state_trackers/oxr/oxr_swapchain_vk.c | 8 +- 12 files changed, 106 insertions(+), 55 deletions(-) create mode 100644 doc/changes/xrt/mr.723.md diff --git a/doc/changes/xrt/mr.723.md b/doc/changes/xrt/mr.723.md new file mode 100644 index 000000000..9f97c9f45 --- /dev/null +++ b/doc/changes/xrt/mr.723.md @@ -0,0 +1,3 @@ +Make @ref xrt_swapchain be reference counted. This will greatly help with +handling swapchains for multiple clients in the compositor rendering pipeline +where a client might go away while the compositor is using it. diff --git a/src/xrt/compositor/client/comp_gl_client.c b/src/xrt/compositor/client/comp_gl_client.c index 0fd2a0d4e..0ef3f8785 100644 --- a/src/xrt/compositor/client/comp_gl_client.c +++ b/src/xrt/compositor/client/comp_gl_client.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -366,7 +366,7 @@ client_gl_swapchain_create(struct xrt_compositor *xc, struct xrt_swapchain_create_info xinfo = *info; xinfo.format = vk_format; - struct xrt_swapchain_native *xscn = NULL; + struct xrt_swapchain_native *xscn = NULL; // Has to be NULL. xret = xrt_comp_native_create_swapchain(c->xcn, &xinfo, &xscn); @@ -387,7 +387,8 @@ client_gl_swapchain_create(struct xrt_compositor *xc, struct client_gl_swapchain *sc = NULL; if (NULL == c->create_swapchain(xc, info, xscn, &sc)) { - xrt_swapchain_destroy(&xsc); + // Drop our reference, does NULL checking. + xrt_swapchain_reference(&xsc, NULL); return XRT_ERROR_OPENGL; } diff --git a/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c b/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c index 977373c3c..4ad0d1cc0 100644 --- a/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c +++ b/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -84,8 +84,8 @@ client_gl_eglimage_swapchain_destroy(struct xrt_swapchain *xsc) client_gl_eglimage_swapchain_teardown_storage(sc); sc->base.base.base.num_images = 0; - // Destroy the native swapchain as well. - xrt_swapchain_destroy((struct xrt_swapchain **)&sc->base.xscn); + // Drop our reference, does NULL checking. + xrt_swapchain_native_reference(&sc->base.xscn, NULL); free(sc); } diff --git a/src/xrt/compositor/client/comp_gl_memobj_swapchain.c b/src/xrt/compositor/client/comp_gl_memobj_swapchain.c index 8e4a060b6..2aedaf1b8 100644 --- a/src/xrt/compositor/client/comp_gl_memobj_swapchain.c +++ b/src/xrt/compositor/client/comp_gl_memobj_swapchain.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -55,8 +55,8 @@ client_gl_memobj_swapchain_destroy(struct xrt_swapchain *xsc) sc->base.base.base.num_images = 0; } - // Destroy the native swapchain as well. - xrt_swapchain_destroy((struct xrt_swapchain **)&sc->base.xscn); + // Drop our reference, does NULL checking. + xrt_swapchain_reference((struct xrt_swapchain **)&sc->base.xscn, NULL); free(sc); } diff --git a/src/xrt/compositor/client/comp_vk_client.c b/src/xrt/compositor/client/comp_vk_client.c index 3e2e8c62a..8405d709b 100644 --- a/src/xrt/compositor/client/comp_vk_client.c +++ b/src/xrt/compositor/client/comp_vk_client.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -62,8 +62,8 @@ client_vk_swapchain_destroy(struct xrt_swapchain *xsc) } } - // Destroy the native swapchain as well. - xrt_swapchain_destroy((struct xrt_swapchain **)&sc->xscn); + // Drop our reference, does NULL checking. + xrt_swapchain_native_reference(&sc->xscn, NULL); free(sc); } @@ -360,7 +360,7 @@ client_vk_swapchain_create(struct xrt_compositor *xc, VkResult ret; xrt_result_t xret; - struct xrt_swapchain_native *xscn = NULL; + struct xrt_swapchain_native *xscn = NULL; // Has to be NULL. xret = xrt_comp_native_create_swapchain(c->xcn, info, &xscn); if (xret != XRT_SUCCESS) { diff --git a/src/xrt/compositor/main/comp_swapchain.c b/src/xrt/compositor/main/comp_swapchain.c index 71fd08b91..49ac6f0c1 100644 --- a/src/xrt/compositor/main/comp_swapchain.c +++ b/src/xrt/compositor/main/comp_swapchain.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -329,7 +329,8 @@ comp_swapchain_create(struct xrt_compositor *xc, do_post_create_vulkan_setup(c, info, sc); - *out_xsc = &sc->base.base; + // Correctly setup refcounts. + xrt_swapchain_reference(out_xsc, &sc->base.base); return XRT_SUCCESS; } @@ -356,7 +357,8 @@ comp_swapchain_import(struct xrt_compositor *xc, do_post_create_vulkan_setup(c, info, sc); - *out_xsc = &sc->base.base; + // Correctly setup refcounts. + xrt_swapchain_reference(out_xsc, &sc->base.base); return XRT_SUCCESS; } diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h index 65225c301..72f654147 100644 --- a/src/xrt/include/xrt/xrt_compositor.h +++ b/src/xrt/include/xrt/xrt_compositor.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -362,6 +362,11 @@ struct xrt_layer_data */ struct xrt_swapchain { + /*! + * Reference helper. + */ + struct xrt_reference reference; + /*! * Number of images. * @@ -399,6 +404,39 @@ struct xrt_swapchain xrt_result_t (*release_image)(struct xrt_swapchain *xsc, uint32_t index); }; +/*! + * Update the reference counts on swapchain(s). + * + * @param dst Pointer to a object reference, if the object reference is + * non-null will decrement it's counter. The reference that + * @p dst points to will be set to @p src. + * @param[in] src Object to be have it's refcount increased @p dst is set to + * this. + * @ingroup xrt_iface + * @relates xrt_swapchain + */ +static inline void +xrt_swapchain_reference(struct xrt_swapchain **dst, struct xrt_swapchain *src) +{ + struct xrt_swapchain *old_dst = *dst; + + if (old_dst == src) { + return; + } + + if (src) { + xrt_reference_inc(&src->reference); + } + + *dst = src; + + if (old_dst) { + if (xrt_reference_dec(&old_dst->reference)) { + old_dst->destroy(old_dst); + } + } +} + /*! * @copydoc xrt_swapchain::acquire_image * @@ -438,26 +476,6 @@ xrt_swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index) return xsc->release_image(xsc, index); } -/*! - * @copydoc xrt_swapchain::destroy - * - * Helper for calling through the function pointer: does a null check and sets - * xsc_ptr to null if freed. - * - * @public @memberof xrt_swapchain - */ -static inline void -xrt_swapchain_destroy(struct xrt_swapchain **xsc_ptr) -{ - struct xrt_swapchain *xsc = *xsc_ptr; - if (xsc == NULL) { - return; - } - - xsc->destroy(xsc); - *xsc_ptr = NULL; -} - /*! * Event type for compositor events, none means no event was returned. */ @@ -553,6 +571,10 @@ struct xrt_compositor /*! * Create a swapchain with a set of images. + * + * The pointer pointed to by @p out_xsc has to either be NULL or a valid + * @ref xrt_swapchain pointer. If there is a valid @ref xrt_swapchain + * pointed by the pointed pointer it will have it reference decremented. */ xrt_result_t (*create_swapchain)(struct xrt_compositor *xc, const struct xrt_swapchain_create_info *info, @@ -560,6 +582,10 @@ struct xrt_compositor /*! * Create a swapchain from a set of native images. + * + * The pointer pointed to by @p out_xsc has to either be NULL or a valid + * @ref xrt_swapchain pointer. If there is a valid @ref xrt_swapchain + * pointed by the pointed pointer it will have it reference decremented. */ xrt_result_t (*import_swapchain)(struct xrt_compositor *xc, const struct xrt_swapchain_create_info *info, @@ -1184,6 +1210,17 @@ struct xrt_swapchain_native struct xrt_image_native images[XRT_MAX_SWAPCHAIN_IMAGES]; }; +/*! + * @copydoc xrt_swapchain_reference + * + * @relates xrt_swapchain_native + */ +static inline void +xrt_swapchain_native_reference(struct xrt_swapchain_native **dst, struct xrt_swapchain_native *src) +{ + xrt_swapchain_reference((struct xrt_swapchain **)dst, (struct xrt_swapchain *)src); +} + /*! * @interface xrt_compositor_native * @@ -1207,6 +1244,10 @@ struct xrt_compositor_native * Helper for calling through the base's function pointer then performing the * known-safe downcast. * + * The pointer pointed to by @p out_xsc has to either be NULL or a valid + * @ref xrt_swapchain pointer. If there is a valid @ref xrt_swapchain + * pointed by the pointed pointer it will have it reference decremented. + * * @public @memberof xrt_compositor_native */ static inline xrt_result_t @@ -1214,11 +1255,17 @@ xrt_comp_native_create_swapchain(struct xrt_compositor_native *xcn, const struct xrt_swapchain_create_info *info, struct xrt_swapchain_native **out_xscn) { - struct xrt_swapchain *xsc = NULL; + struct xrt_swapchain *xsc = NULL; // Has to be NULL. + xrt_result_t ret = xrt_comp_create_swapchain(&xcn->base, info, &xsc); if (ret == XRT_SUCCESS) { + // Need to dereference any swapchain already there first. + xrt_swapchain_native_reference(out_xscn, NULL); + + // Already referenced. *out_xscn = (struct xrt_swapchain_native *)xsc; } + return ret; } diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 6ce27ccff..3da04b0a7 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -374,7 +374,7 @@ ipc_handle_swapchain_create(volatile struct ipc_client_state *ics, } // Create the swapchain - struct xrt_swapchain *xsc = NULL; + struct xrt_swapchain *xsc = NULL; // Has to be NULL. xret = xrt_comp_create_swapchain(ics->xc, info, &xsc); if (xret != XRT_SUCCESS) { IPC_ERROR(ics->server, "Error xrt_comp_create_swapchain failed!"); @@ -490,7 +490,8 @@ ipc_handle_swapchain_destroy(volatile struct ipc_client_state *ics, uint32_t id) //! @todo Implement destroy swapchain. ics->num_swapchains--; - xrt_swapchain_destroy((struct xrt_swapchain **)&ics->xscs[id]); + // Drop our reference, does NULL checking. Cast away volatile. + xrt_swapchain_reference((struct xrt_swapchain **)&ics->xscs[id], NULL); ics->swapchain_data[id].active = false; return XRT_SUCCESS; diff --git a/src/xrt/ipc/server/ipc_server_per_client_thread.c b/src/xrt/ipc/server/ipc_server_per_client_thread.c index 1ae776783..c1afa1797 100644 --- a/src/xrt/ipc/server/ipc_server_per_client_thread.c +++ b/src/xrt/ipc/server/ipc_server_per_client_thread.c @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -162,7 +162,8 @@ client_loop(volatile struct ipc_client_state *ics) // Destroy all swapchains now. for (uint32_t j = 0; j < IPC_MAX_CLIENT_SWAPCHAINS; j++) { - xrt_swapchain_destroy((struct xrt_swapchain **)&ics->xscs[j]); + // Drop our reference, does NULL checking. Cast away volatile. + xrt_swapchain_reference((struct xrt_swapchain **)&ics->xscs[j], NULL); ics->swapchain_data[j].active = false; IPC_TRACE(ics->server, "Destroyed swapchain %d.", j); } diff --git a/src/xrt/state_trackers/oxr/oxr_swapchain.c b/src/xrt/state_trackers/oxr/oxr_swapchain.c index 43be3fefe..fc23493b8 100644 --- a/src/xrt/state_trackers/oxr/oxr_swapchain.c +++ b/src/xrt/state_trackers/oxr/oxr_swapchain.c @@ -1,4 +1,4 @@ -// Copyright 2018-2020, Collabora, Ltd. +// Copyright 2018-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -205,7 +205,7 @@ oxr_create_swapchain(struct oxr_logger *log, info.array_size = createInfo->arraySize; info.mip_count = createInfo->mipCount; - struct xrt_swapchain *xsc = NULL; + struct xrt_swapchain *xsc = NULL; // Has to be NULL. xret = xrt_comp_create_swapchain(sess->compositor, &info, &xsc); if (xret == XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED) { return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, diff --git a/src/xrt/state_trackers/oxr/oxr_swapchain_gl.c b/src/xrt/state_trackers/oxr/oxr_swapchain_gl.c index 55746234a..7e2b858ef 100644 --- a/src/xrt/state_trackers/oxr/oxr_swapchain_gl.c +++ b/src/xrt/state_trackers/oxr/oxr_swapchain_gl.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -35,10 +35,8 @@ oxr_swapchain_gl_destroy(struct oxr_logger *log, struct oxr_swapchain *sc) sc->release_image(log, sc, NULL); } - if (sc->swapchain != NULL) { - sc->swapchain->destroy(sc->swapchain); - sc->swapchain = NULL; - } + // Drop our reference, does NULL checking. + xrt_swapchain_reference(&sc->swapchain, NULL); return XR_SUCCESS; } diff --git a/src/xrt/state_trackers/oxr/oxr_swapchain_vk.c b/src/xrt/state_trackers/oxr/oxr_swapchain_vk.c index 2a4199726..8b164ef3b 100644 --- a/src/xrt/state_trackers/oxr/oxr_swapchain_vk.c +++ b/src/xrt/state_trackers/oxr/oxr_swapchain_vk.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -32,10 +32,8 @@ oxr_swapchain_vk_destroy(struct oxr_logger *log, struct oxr_swapchain *sc) sc->release_image(log, sc, NULL); } - if (sc->swapchain != NULL) { - sc->swapchain->destroy(sc->swapchain); - sc->swapchain = NULL; - } + // Drop our reference, does NULL checking. + xrt_swapchain_reference(&sc->swapchain, NULL); return XR_SUCCESS; } From f0132eb997adb02699b9731f7883ba52e57fb68c Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:14:39 +0100 Subject: [PATCH 180/883] u_config_json: change no config file warning->info Running without a config file is fully supported, no reason to warn users. --- src/xrt/auxiliary/util/u_config_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index ee75100c7..64d58d4f4 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -163,7 +163,7 @@ is_json_ok(struct u_config_json *json) if (json->file_loaded) { U_LOG_E("JSON not parsed!"); } else { - U_LOG_W("No config file!"); + U_LOG_I("No config file was loaded!"); } return false; } From 2959747221d589c00b5c248cbfa2ddf8fce423f4 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:15:39 +0100 Subject: [PATCH 181/883] u_config_json: clarify json not parsed error message --- src/xrt/auxiliary/util/u_config_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 64d58d4f4..78ca78384 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -161,7 +161,7 @@ is_json_ok(struct u_config_json *json) { if (json->root == NULL) { if (json->file_loaded) { - U_LOG_E("JSON not parsed!"); + U_LOG_E("Config file was loaded but JSON is not parsed!"); } else { U_LOG_I("No config file was loaded!"); } From 054850de765876848b1abc121c972dbcc1d1cebc Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:16:04 +0100 Subject: [PATCH 182/883] u_config_json: Remove duplicated is_json_ok code --- src/xrt/auxiliary/util/u_config_json.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 78ca78384..e084d3d3f 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -238,12 +238,7 @@ u_config_json_get_remote_port(struct u_config_json *json, int *out_port) static cJSON * open_tracking_settings(struct u_config_json *json) { - if (json->root == NULL) { - if (json->file_loaded) { - U_LOG_E("JSON not parsed!"); - } else { - U_LOG_W("No config file!"); - } + if (!is_json_ok(json)) { return NULL; } From 45d889e3906dd7ce5925c24a7e4a92df4b9c8049 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:36:41 +0100 Subject: [PATCH 183/883] u_config_json: Make missing tracking node messages friendlier --- src/xrt/auxiliary/util/u_config_json.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index e084d3d3f..140ffd189 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -244,7 +244,7 @@ open_tracking_settings(struct u_config_json *json) cJSON *t = cJSON_GetObjectItemCaseSensitive(json->root, "tracking"); if (t == NULL) { - U_LOG_E("No tracking node"); + U_LOG_I("Config file does not contain tracking config"); return NULL; } @@ -253,7 +253,7 @@ open_tracking_settings(struct u_config_json *json) bad |= !get_obj_int(t, "version", &ver); if (bad || ver >= 1) { - U_LOG_E("Missing or unknown version tag '%i'", ver); + U_LOG_E("Missing or unknown version tag '%i' in tracking config", ver); return NULL; } From 8f16118020d1525c008e106dbbd063272b991735 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:37:32 +0100 Subject: [PATCH 184/883] u_config_json: Remove bogus "No tracking node" messages * open_tracking_settings() already reports missing tracking nodes. * open_tracking_settings() can also fail for other reasons --- src/xrt/auxiliary/util/u_config_json.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 140ffd189..68dab68ca 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -267,7 +267,6 @@ u_config_json_get_tracking_overrides(struct u_config_json *json, { cJSON *t = open_tracking_settings(json); if (t == NULL) { - U_LOG_E("No tracking node"); return false; } @@ -317,7 +316,6 @@ u_config_json_get_tracking_settings(struct u_config_json *json, struct xrt_setti { cJSON *t = open_tracking_settings(json); if (t == NULL) { - U_LOG_E("No tracking node"); return false; } From 030230eba9233e9e89d2fb27921f7a8779443d00 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:40:22 +0100 Subject: [PATCH 185/883] st/p: change PSVR/PSMV not set up error->info --- src/xrt/state_trackers/prober/p_tracking.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/xrt/state_trackers/prober/p_tracking.c b/src/xrt/state_trackers/prober/p_tracking.c index 722e823d1..6287f0254 100644 --- a/src/xrt/state_trackers/prober/p_tracking.c +++ b/src/xrt/state_trackers/prober/p_tracking.c @@ -136,9 +136,7 @@ p_factory_ensure_frameserver(struct p_factory *fact) fact->tried_settings = true; if (!u_config_json_get_tracking_settings(&fact->p->json, &fact->settings)) { - U_LOG_E( - "Could not setup PSVR and/or PSMV tracking, " - "see above."); + U_LOG_I("PSVR and/or PSMV tracking is not set up, see above."); return; } From f9c2ab7ed77fb21551f09f6ec4c3f38f3984357d Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:42:05 +0100 Subject: [PATCH 186/883] d/ht: Change hand tracking not set up error->debug --- src/xrt/drivers/ht/ht_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/ht/ht_driver.c b/src/xrt/drivers/ht/ht_driver.c index ec1406060..cdab9cd61 100644 --- a/src/xrt/drivers/ht/ht_driver.c +++ b/src/xrt/drivers/ht/ht_driver.c @@ -128,7 +128,7 @@ ht_device_create(struct xrt_auto_prober *xap, cJSON *attached_data, struct xrt_p htd->base.name = XRT_DEVICE_HAND_TRACKER; if (xp->tracking->create_tracked_hand(xp->tracking, &htd->base, &htd->tracker) < 0) { - HT_ERROR(htd, "Failed to create hand tracker module"); + HT_DEBUG(htd, "Failed to create hand tracker module"); return NULL; } From f6210be44af5cce963ca12a8feb3fb70db807f56 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:44:57 +0100 Subject: [PATCH 187/883] d/survive: Change event for unknown object error->info --- src/xrt/drivers/survive/survive_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index c155a27db..43cd83935 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -745,7 +745,7 @@ _process_event(struct survive_system *ss, struct SurviveSimpleEvent *event) struct survive_device *event_device = get_device_by_object(ss, e->object); if (event_device == NULL) { - U_LOG_IFL_E(ss->ll, "Event for unknown object not handled"); + U_LOG_IFL_I(ss->ll, "Event for unknown object not handled"); return; } From de6d2a888ac182a79414e86d3c19378b881d3927 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 18:48:14 +0100 Subject: [PATCH 188/883] ipc: Change server exiting error->info --- src/xrt/ipc/server/ipc_server_process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index 72736e1db..b54cbd951 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -1087,7 +1087,7 @@ ipc_server_main(int argc, char **argv) teardown_all(s); free(s); - U_LOG_E("Server exiting: '%i'!", ret); + U_LOG_I("Server exiting: '%i'!", ret); return ret; } @@ -1117,7 +1117,7 @@ ipc_server_main_android(struct ipc_server **ps, void (*startup_complete_callback teardown_all(s); free(s); - U_LOG_E("Server exiting '%i'!", ret); + U_LOG_I("Server exiting '%i'!", ret); return ret; } From 3ba9a9411a8f083cc35c10442094384dd316ea63 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 19:10:34 +0100 Subject: [PATCH 189/883] d/vive: change config start report error->info And clarify the message that it happens for example for powered off controllers. --- src/xrt/drivers/vive/vive_protocol.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/vive/vive_protocol.c b/src/xrt/drivers/vive/vive_protocol.c index e11ddfb5e..e5e0695ab 100644 --- a/src/xrt/drivers/vive/vive_protocol.c +++ b/src/xrt/drivers/vive/vive_protocol.c @@ -70,7 +70,8 @@ vive_read_config(struct os_hid_device *hid_dev) int ret = os_hid_get_feature_timeout(hid_dev, &start_report, sizeof(start_report), 100); if (ret < 0) { - U_LOG_E("Could not get config start report."); + // e.g. watchman receiver has no connected device (controller powered off) + U_LOG_I("Could not get config start report for device, connected device may be powered off (%d).", ret); return NULL; } From 08db19becac9396f6475cab34a9a2f08ed8d350a Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 19:14:04 +0100 Subject: [PATCH 190/883] u_config_json: Change node not found error->info As our config grows it will happen more often that users won't have all possible nodes. --- src/xrt/auxiliary/util/u_config_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 68dab68ca..392a7f8b6 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -87,7 +87,7 @@ get_obj(cJSON *json, const char *name) { cJSON *item = cJSON_GetObjectItemCaseSensitive(json, name); if (item == NULL) { - U_LOG_E("Failed to find node '%s'!", name); + U_LOG_I("JSON does not contain node '%s'!", name); } return item; } From e8999b06c8bd1e0c9ac54b625a2fc3c612d4905e Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 19:26:22 +0100 Subject: [PATCH 191/883] st/p: Change tracking override target/tracker not found error->warning --- src/xrt/state_trackers/prober/p_prober.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/state_trackers/prober/p_prober.c b/src/xrt/state_trackers/prober/p_prober.c index 491d16d4e..631fe3f43 100644 --- a/src/xrt/state_trackers/prober/p_prober.c +++ b/src/xrt/state_trackers/prober/p_prober.c @@ -797,11 +797,11 @@ apply_tracking_override(struct prober *p, struct xrt_device **xdevs, size_t num_ } if (target_xdev == NULL) { - P_ERROR(p, "Tracking override target xdev %s not found", o->target_device_serial); + P_WARN(p, "Tracking override target xdev %s not found", o->target_device_serial); } if (tracker_xdev == NULL) { - P_ERROR(p, "Tracking override tracker xdev %s not found", o->tracker_device_serial); + P_WARN(p, "Tracking override tracker xdev %s not found", o->tracker_device_serial); } From a2b49138e7602545a8e479d5bace9b2f01595bdf Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 19:29:00 +0100 Subject: [PATCH 192/883] d/vive: change imu range report error->info --- src/xrt/drivers/vive/vive_protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/vive/vive_protocol.c b/src/xrt/drivers/vive/vive_protocol.c index e5e0695ab..faf8da2e0 100644 --- a/src/xrt/drivers/vive/vive_protocol.c +++ b/src/xrt/drivers/vive/vive_protocol.c @@ -152,7 +152,7 @@ vive_get_imu_range_report(struct os_hid_device *hid_dev, double *gyro_range, dou ret = os_hid_get_feature_timeout(hid_dev, &report, sizeof(report), 100); if (ret < 0) { - U_LOG_E("Could not get range report!"); + U_LOG_I("Could not get range report, connected device may be powered off (%d)!", ret); return ret; } From 1f25acfa94d7cb5341b9fd233aaf686c058bcb79 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 19:31:43 +0100 Subject: [PATCH 193/883] d/vive: remove duplicate range record error message --- src/xrt/drivers/vive/vive_controller.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/xrt/drivers/vive/vive_controller.c b/src/xrt/drivers/vive/vive_controller.c index c281d30b0..6f2559de8 100644 --- a/src/xrt/drivers/vive/vive_controller.c +++ b/src/xrt/drivers/vive/vive_controller.c @@ -1072,9 +1072,8 @@ vive_controller_create(struct os_hid_device *controller_hid, enum watchman_gen w d->base.get_tracked_pose = vive_controller_device_get_tracked_pose; d->base.set_output = vive_controller_device_set_output; - //! @todo: reading range report fails for powered off controller if (vive_get_imu_range_report(d->controller_hid, &d->config.imu.gyro_range, &d->config.imu.acc_range) != 0) { - VIVE_ERROR(d, "Could not get watchman IMU range packet!"); + // reading range report fails for powered off controller free(d); return 0; } From a991e66b85bfaa15104127ee9c5eb1a8895d792b Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 24 Mar 2021 19:38:00 +0100 Subject: [PATCH 194/883] u_vive: Fix debug level of printing acc_bias --- src/xrt/auxiliary/vive/vive_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/vive/vive_config.c b/src/xrt/auxiliary/vive/vive_config.c index 4f17bd987..8211b2873 100644 --- a/src/xrt/auxiliary/vive/vive_config.c +++ b/src/xrt/auxiliary/vive/vive_config.c @@ -323,7 +323,7 @@ vive_config_parse(struct vive_config *d, char *json_string) VIVE_DEBUG(d, "eye_target_height_in_pixels: %d", d->display.eye_target_height_in_pixels); VIVE_DEBUG(d, "eye_target_width_in_pixels: %d", d->display.eye_target_width_in_pixels); - if (d->ll >= U_LOGGING_DEBUG) { + if (d->ll <= U_LOGGING_DEBUG) { _print_vec3("acc_bias", &d->imu.acc_bias); _print_vec3("acc_scale", &d->imu.acc_scale); _print_vec3("gyro_bias", &d->imu.gyro_bias); From e83657de45e5d4748ffc2185d604691fd4aee629 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 10:58:22 -0500 Subject: [PATCH 195/883] ci: Adjust quotes based on formatter --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b321bdba1..2e6d59ca8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -317,7 +317,7 @@ ndk:arm64-v8a: .monado.packaging.conditions: rules: # Only the default branch of the "upstream" repo. - - if: '$CI_PROJECT_PATH == $FDO_UPSTREAM_REPO && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH' + - if: "$CI_PROJECT_PATH == $FDO_UPSTREAM_REPO && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH" when: on_success # Otherwise, don't build packages. - when: never From e5c193bcd082bbc42790c62d123fb5c7157d50ec Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 15 Jul 2020 19:39:11 -0700 Subject: [PATCH 196/883] aux/util: Silence warnings on MSVC --- src/xrt/auxiliary/util/u_json.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/xrt/auxiliary/util/u_json.c b/src/xrt/auxiliary/util/u_json.c index a8a595cc8..1b030fef9 100644 --- a/src/xrt/auxiliary/util/u_json.c +++ b/src/xrt/auxiliary/util/u_json.c @@ -21,6 +21,9 @@ #include #ifndef XRT_HAVE_SYSTEM_CJSON +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif // This includes the c file completely. #include "cjson/cJSON.c" #endif From 4ed3d21b0963cc61a6f98b8b93cbe4a004531a52 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 11:03:29 -0500 Subject: [PATCH 197/883] a/util: Stub out trace marker on non-Linux for now. --- src/xrt/auxiliary/util/u_trace_marker.c | 27 ++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/xrt/auxiliary/util/u_trace_marker.c b/src/xrt/auxiliary/util/u_trace_marker.c index 3af85d96c..8b30bf91a 100644 --- a/src/xrt/auxiliary/util/u_trace_marker.c +++ b/src/xrt/auxiliary/util/u_trace_marker.c @@ -10,13 +10,14 @@ // This needs to be first. #define _GNU_SOURCE -#include -#include #include "xrt/xrt_compiler.h" - +#include "xrt/xrt_config_os.h" #include "u_trace_marker.h" +#ifdef XRT_OS_LINUX +#include +#include #include #include #include @@ -92,3 +93,23 @@ u_trace_data(int fd, enum u_trace_data_type type, void *data, size_t size) len = write(fd, tmp, len); } } + +#else + +// Stubs on non-linux for now. +void +u_tracer_maker_init(void) +{} + +void +u_trace_enter(int fd, const char *func) +{} + +void +u_trace_leave(int fd, const char *func) +{} + +void +u_trace_data(int fd, enum u_trace_data_type type, void *data, size_t size) +{} +#endif From c00884e8278a435654586fb92a9fe5a967f43d4e Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 11:04:53 -0500 Subject: [PATCH 198/883] cmake: aux/vk depends on aux/os --- src/xrt/auxiliary/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index 84745f0b1..16d2caae5 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -255,7 +255,7 @@ endif() if(XRT_HAVE_VULKAN) # Vulkan library. add_library(aux_vk STATIC ${VK_SOURCE_FILES}) - target_link_libraries(aux_vk PUBLIC aux-includes) + target_link_libraries(aux_vk PUBLIC aux_os) target_link_libraries(aux_vk PUBLIC Vulkan::Vulkan) target_include_directories(aux_vk PUBLIC ${Vulkan_INCLUDE_DIR}) if(ANDROID) From b147f2ecd4a1320a6e4428ec7716a71f2d9d0ad9 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 11:58:46 -0500 Subject: [PATCH 199/883] a/util: Non-linux implementation of u_file --- src/xrt/auxiliary/CMakeLists.txt | 1 + src/xrt/auxiliary/util/u_file.c | 4 +- src/xrt/auxiliary/util/u_file.cpp | 94 +++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 src/xrt/auxiliary/util/u_file.cpp diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index 16d2caae5..51fa0facb 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -111,6 +111,7 @@ set(UTIL_SOURCE_FILES util/u_distortion_mesh.h util/u_documentation.h util/u_file.c + util/u_file.cpp util/u_file.h util/u_format.c util/u_format.h diff --git a/src/xrt/auxiliary/util/u_file.c b/src/xrt/auxiliary/util/u_file.c index d711f5676..b40295860 100644 --- a/src/xrt/auxiliary/util/u_file.c +++ b/src/xrt/auxiliary/util/u_file.c @@ -104,6 +104,8 @@ u_file_open_file_in_config_dir(const char *filename, const char *mode) return fopen(file_str, mode); } +#endif + char * u_file_read_content(FILE *file) { @@ -128,5 +130,3 @@ u_file_read_content(FILE *file) return buffer; } - -#endif diff --git a/src/xrt/auxiliary/util/u_file.cpp b/src/xrt/auxiliary/util/u_file.cpp new file mode 100644 index 000000000..4a2054fce --- /dev/null +++ b/src/xrt/auxiliary/util/u_file.cpp @@ -0,0 +1,94 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Very simple file opening functions, mostly using std::filesystem for portability. + * @author Ryan Pavlik + * @author Jakob Bornecrantz + * @author Pete Black + * @ingroup aux_util + */ + +#include "xrt/xrt_config_os.h" +#include "util/u_file.h" + +#ifndef XRT_OS_LINUX + +#include +#include +#include +#include + +#if __cplusplus >= 201703L +#include +namespace fs = std::filesystem; +#else +#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING +#include +namespace fs = std::experimental::filesystem; +#endif + +static inline fs::path +get_config_path() +{ +#ifdef XRT_OS_WINDOWS + auto local_app_data = fs::path{getenv("LOCALAPPDATA")}; + return local_app_data / "monado"; +#else + + const char *xdg_home = getenv("XDG_CONFIG_HOME"); + const char *home = getenv("HOME"); + if (xdg_home != NULL) { + return fs::path(xdg_home) / "monado"; + } + if (home != NULL) { + return fs::path(home) / "monado"; + } + return {}; +#endif +} +ssize_t +u_file_get_config_dir(char *out_path, size_t out_path_size) +{ + auto config_path = get_config_path(); + if (config_path.empty()) { + return -1; + } + auto config_path_string = config_path.string(); + return snprintf(out_path, out_path_size, "%s", config_path_string.c_str()); +} + +ssize_t +u_file_get_path_in_config_dir(const char *filename, char *out_path, size_t out_path_size) +{ + auto config_path = get_config_path(); + if (config_path.empty()) { + return -1; + } + auto path_string = (config_path / filename).string(); + return snprintf(out_path, out_path_size, "%s", path_string.c_str()); +} + +FILE * +u_file_open_file_in_config_dir(const char *filename, const char *mode) +{ + auto config_path = get_config_path(); + if (config_path.empty()) { + return NULL; + } + + auto file_path_string = (config_path / filename).string(); + FILE *file = fopen(file_path_string.c_str(), mode); + if (file != NULL) { + return file; + } + + // Try creating the path. + auto directory = (config_path / filename).parent_path(); + fs::create_directories(directory); + + // Do not report error. + return fopen(file_path_string.c_str(), mode); +} + +#endif From 0140ea34b64c13853f2e7103db6f073c007d1760 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 11:59:13 -0500 Subject: [PATCH 200/883] comp/main: Implement consumption of sync handle on Windows --- src/xrt/compositor/main/comp_compositor.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 3ba115774..c499f5312 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -356,6 +356,14 @@ compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_graphic close(sync_handle); sync_handle = XRT_GRAPHICS_SYNC_HANDLE_INVALID; } + +#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE) + // Need to consume this handle. + if (xrt_graphics_sync_handle_is_valid(sync_handle)) { + CloseHandle(sync_handle); + sync_handle = XRT_GRAPHICS_SYNC_HANDLE_INVALID; + } + #else #error "Not yet implemented for this platform" #endif From bd00c7ffd3847a010c4fa6e078fd248d6e252cb7 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 11:59:36 -0500 Subject: [PATCH 201/883] comp/main: Deal with MSVC not liking static array sizes being non-constant. --- src/xrt/compositor/main/comp_target_swapchain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index fdc1e15f8..8dbf95333 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -589,7 +589,7 @@ comp_target_swapchain_update_timings(struct comp_target *ct) return VK_SUCCESS; } - VkPastPresentationTimingGOOGLE timings[count]; + VkPastPresentationTimingGOOGLE *timings = U_TYPED_ARRAY_CALLOC(VkPastPresentationTimingGOOGLE, count); c->vk.vkGetPastPresentationTimingGOOGLE( // vk->device, // cts->swapchain.handle, // @@ -604,7 +604,7 @@ comp_target_swapchain_update_timings(struct comp_target *ct) timings[i].earliestPresentTime, // timings[i].presentMargin); // } - + free(timings); return VK_SUCCESS; } From 8ebd97330d9bdbcaf537644179f92747ce67be94 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 11:59:56 -0500 Subject: [PATCH 202/883] st/steamvr: Fix warnings --- src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp b/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp index 7d720fe86..ae611d6a9 100644 --- a/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp +++ b/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp @@ -1221,7 +1221,7 @@ CServerDriver_Monado::HandleHapticEvent(vr::VREvent_t *event) union xrt_output_value out; out.vibration.amplitude = amp; if (duration > 0.00001) { - out.vibration.duration = duration * 1000. * 1000. * 1000.; + out.vibration.duration = (time_duration_ns)(duration * 1000.f * 1000.f * 1000.f); } else { out.vibration.duration = XRT_MIN_HAPTIC_DURATION; } From a830f46db06c4de49fdc97c2b6616cbcaddd1c97 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 12:00:07 -0500 Subject: [PATCH 203/883] st/prober: Fix warnings --- src/xrt/state_trackers/prober/p_prober.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/prober/p_prober.c b/src/xrt/state_trackers/prober/p_prober.c index 631fe3f43..327e7ece5 100644 --- a/src/xrt/state_trackers/prober/p_prober.c +++ b/src/xrt/state_trackers/prober/p_prober.c @@ -408,7 +408,7 @@ initialize(struct prober *p, struct xrt_prober_entry_lists *lists) p->json.root = NULL; u_var_add_root((void *)p, "Prober", true); - u_var_add_ro_u32(p, &p->ll, "Log Level"); + u_var_add_ro_u32(p, (uint32_t *)&p->ll, "Log Level"); int ret; From b57d52f3732d0b710ffa8db9f1b6ffef9d57d145 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 12:00:26 -0500 Subject: [PATCH 204/883] comp/main: Fix warnings --- src/xrt/compositor/main/comp_window_direct.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/compositor/main/comp_window_direct.c b/src/xrt/compositor/main/comp_window_direct.c index be1af5e33..43a0aad3c 100644 --- a/src/xrt/compositor/main/comp_window_direct.c +++ b/src/xrt/compositor/main/comp_window_direct.c @@ -49,7 +49,7 @@ choose_best_vk_mode_auto(struct comp_target *ct, VkDisplayModePropertiesKHR *mod } VkDisplayModeParametersKHR best = mode_properties[best_index].parameters; COMP_DEBUG(ct->c, "Auto choosing Vk direct mode %d: %dx%d@%.2f", best_index, best.visibleRegion.width, - best.visibleRegion.width, (float)best.refreshRate / 1000.); + best.visibleRegion.width, (float)best.refreshRate / 1000.f); return best_index; } @@ -61,7 +61,7 @@ print_modes(struct comp_target *ct, VkDisplayModePropertiesKHR *mode_properties, VkDisplayModePropertiesKHR props = mode_properties[i]; uint16_t width = props.parameters.visibleRegion.width; uint16_t height = props.parameters.visibleRegion.height; - float refresh = (float)props.parameters.refreshRate / 1000.; + float refresh = (float)props.parameters.refreshRate / 1000.f; COMP_PRINT_MODE(ct->c, "| %2d | %dx%d@%.2f", i, width, height, refresh); } From 3414f62ccf38d1e6d7517e84a84748a178fd919f Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 17:04:20 -0500 Subject: [PATCH 205/883] aux: fix or silence warnings --- src/xrt/auxiliary/bindings/bindings.py | 5 +++-- src/xrt/auxiliary/tracking/t_tracking.h | 2 +- src/xrt/auxiliary/util/u_var.cpp | 4 ++-- src/xrt/auxiliary/util/u_var.h | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/xrt/auxiliary/bindings/bindings.py b/src/xrt/auxiliary/bindings/bindings.py index 8366a31d7..e7782d8b2 100755 --- a/src/xrt/auxiliary/bindings/bindings.py +++ b/src/xrt/auxiliary/bindings/bindings.py @@ -240,13 +240,14 @@ def generate_bindings_h(file, p): "_subpath(const char *str, size_t length);\n") f.write(f''' +#define PATHS_PER_BINDING_TEMPLATE 8 struct binding_template {{ \tconst char *subaction_path; \tconst char *steamvr_path; \tconst char *localized_name; -\tconst char *paths[8]; +\tconst char *paths[PATHS_PER_BINDING_TEMPLATE]; \tenum xrt_input_name input; \tenum xrt_output_name output; }}; @@ -263,7 +264,7 @@ struct profile_template }}; #define NUM_PROFILE_TEMPLATES {len(p.profiles)} -extern struct profile_template profile_templates[{len(p.profiles)}]; +extern struct profile_template profile_templates[NUM_PROFILE_TEMPLATES]; ''') f.write("\n// clang-format on\n") diff --git a/src/xrt/auxiliary/tracking/t_tracking.h b/src/xrt/auxiliary/tracking/t_tracking.h index 79eee7564..3e97ce19b 100644 --- a/src/xrt/auxiliary/tracking/t_tracking.h +++ b/src/xrt/auxiliary/tracking/t_tracking.h @@ -198,7 +198,7 @@ t_stereo_camera_calibration_save_v1(FILE *calib_file, struct t_stereo_camera_cal struct t_convert_table { - uint8_t v[256][256][256][3]; + uint8_t v[256][256][256][3]; // nolint(readability-magic-numbers) }; void diff --git a/src/xrt/auxiliary/util/u_var.cpp b/src/xrt/auxiliary/util/u_var.cpp index 890e8276f..6b759d46d 100644 --- a/src/xrt/auxiliary/util/u_var.cpp +++ b/src/xrt/auxiliary/util/u_var.cpp @@ -52,7 +52,7 @@ public: getNumber(const std::string &name) { auto s = counters.find(name); - int count = (s != counters.end() ? s->second : 0) + 1; + int count = int(s != counters.end() ? s->second : 0) + 1; counters[name] = count; return count; @@ -89,7 +89,7 @@ add_var(void *root, void *ptr, u_var_kind kind, const char *c_name) } Var var; - snprintf(var.info.name, 256, "%s", c_name); + snprintf(var.info.name, U_VAR_NAME_STRING_SIZE, "%s", c_name); var.info.kind = kind; var.info.ptr = ptr; diff --git a/src/xrt/auxiliary/util/u_var.h b/src/xrt/auxiliary/util/u_var.h index 310d664fd..3d64f6579 100644 --- a/src/xrt/auxiliary/util/u_var.h +++ b/src/xrt/auxiliary/util/u_var.h @@ -89,13 +89,14 @@ enum u_var_kind U_VAR_KIND_GUI_HEADER, }; +#define U_VAR_NAME_STRING_SIZE 256 /*! * Struct that keeps all of the information about the variable, some of the UI * state is kept on it. */ struct u_var_info { - char name[256]; + char name[U_VAR_NAME_STRING_SIZE]; void *ptr; enum u_var_kind kind; From 12f9cac46b108df285262975c7b767bf94dd654c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 17:04:34 -0500 Subject: [PATCH 206/883] imgui_monado: Fix a few warnings --- .../imgui/imgui_monado/imgui_monado.cpp | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/external/imgui/imgui_monado/imgui_monado.cpp b/src/external/imgui/imgui_monado/imgui_monado.cpp index 38cf7e335..8f4b1ce59 100644 --- a/src/external/imgui/imgui_monado/imgui_monado.cpp +++ b/src/external/imgui/imgui_monado/imgui_monado.cpp @@ -15,6 +15,8 @@ #endif #include "../imgui/imgui_internal.h" +#include + #include "cimgui_monado.h" using namespace ImGui; @@ -41,20 +43,23 @@ static void _draw_line(ImGuiWindow *window, int values_count, float scale_min, ImGui::RenderText(text_pos, text); ImGui::PopStyleColor(1); } + static void _draw_grid(ImGuiWindow *window, int values_count, float scale_min, float scale_max, float reference_timing, const char *unit, const ImRect inner_bb, ImVec2 frame_size) { - ImVec4 target_color = ImVec4(1.0f, 1.0f, 0.0f, .75f); + const ImVec4 target_color{1.0f, 1.0f, 0.0f, .75f}; _draw_line(window, values_count, scale_min, scale_max, reference_timing, unit, inner_bb, frame_size, GetColorU32(target_color)); - ImVec4 passive_color = ImVec4(0.35f, 0.35f, 0.35f, 1.00f); + const ImVec4 passive_color{0.35f, 0.35f, 0.35f, 1.00f}; // always draw ~5 lines - float step = (scale_max - scale_min) / 5.; - for (float i = scale_min; i < scale_max + step; i += step) { - _draw_line(window, values_count, scale_min, scale_max, i, unit, inner_bb, + const uint8_t max_lines = 5; + float step = (scale_max - scale_min) / (float)max_lines; + for (uint8_t i = 0; i < max_lines; ++i) { + float val = scale_min + step * (float)i; + _draw_line(window, values_count, scale_min, scale_max, val, unit, inner_bb, frame_size, GetColorU32(passive_color)); } } @@ -103,14 +108,16 @@ static void PlotTimings(const char *label, float scale_max = reference_timing + range; if (dynamic_rescale) { - if (v_max > scale_max) + if (v_max > scale_max) { scale_max = v_max; - scale_max = ((int)(scale_max / 10 + 1)) * 10; + } + scale_max = (floorf(scale_max / 10 + 1)) * 10; if (center_reference_timing) { - if (v_min < scale_min) + if (v_min < scale_min) { scale_min = v_min; - scale_min = ((int)(scale_min / 10)) * 10; + } + scale_min = (floorf(scale_min / 10)) * 10; // make sure reference timing stays centered float lower_range = reference_timing - scale_min; From 20468070fadf48c97f45c79033f3fc4cecccf9fd Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 25 Mar 2021 12:05:15 -0500 Subject: [PATCH 207/883] ipc: De-duplicate member for simplicity and to avoid Doxygen warning --- src/xrt/ipc/server/ipc_server.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h index da6932ea9..9645ad2ac 100644 --- a/src/xrt/ipc/server/ipc_server.h +++ b/src/xrt/ipc/server/ipc_server.h @@ -160,13 +160,17 @@ struct ipc_device */ struct ipc_server_mainloop { + +#if defined(XRT_OS_ANDROID) || defined(XRT_OS_LINUX) || defined(XRT_DOXYGEN) + //! For waiting on various events in the main thread. + int epoll_fd; +#endif + #if defined(XRT_OS_ANDROID) || defined(XRT_DOXYGEN) /*! * @name Android Mainloop Members * @{ */ - //! For waiting on various events in the main thread. - int epoll_fd; //! File descriptor for the read end of our pipe for submitting new clients int pipe_read; @@ -233,9 +237,6 @@ struct ipc_server_mainloop //! Socket that we accept connections on. int listen_socket; - //! For waiting on various events in the main thread. - int epoll_fd; - //! Were we launched by socket activation, instead of explicitly? bool launched_by_socket; From 4004402c409a57b444cc12381980b873e6cfd332 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 11:08:33 -0500 Subject: [PATCH 208/883] aux/vk: Wrap statement defines in do {} while (0) --- src/xrt/auxiliary/vk/vk_helpers.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/xrt/auxiliary/vk/vk_helpers.h b/src/xrt/auxiliary/vk/vk_helpers.h index 926b4ee29..52836dddc 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.h +++ b/src/xrt/auxiliary/vk/vk_helpers.h @@ -293,8 +293,10 @@ vk_has_error(VkResult res, const char *fun, const char *file, int line); * @ingroup aux_vk */ #define vk_check_error(fun, res, ret) \ - if (vk_has_error(res, fun, __FILE__, __LINE__)) \ - return ret + do { \ + if (vk_has_error(res, fun, __FILE__, __LINE__)) \ + return ret; \ + } while (0) /*! * @def @@ -310,10 +312,12 @@ vk_has_error(VkResult res, const char *fun, const char *file, int line); * @ingroup aux_vk */ #define vk_check_error_with_free(fun, res, ret, to_free) \ - if (vk_has_error(res, fun, __FILE__, __LINE__)) { \ - free(to_free); \ - return ret; \ - } + do { \ + if (vk_has_error(res, fun, __FILE__, __LINE__)) { \ + free(to_free); \ + return ret; \ + } \ + } while (0) /*! * @ingroup aux_vk From 7b92d212a228b0ec6e2bd623d58c2acfd9f08a2a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 11:19:42 -0500 Subject: [PATCH 209/883] comp: Fix doxygen warnings --- src/xrt/compositor/client/comp_gl_client.h | 2 +- src/xrt/compositor/client/comp_gl_xlib_client.h | 2 +- src/xrt/compositor/client/comp_vk_client.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xrt/compositor/client/comp_gl_client.h b/src/xrt/compositor/client/comp_gl_client.h index 84742c6e0..caf2dfb41 100644 --- a/src/xrt/compositor/client/comp_gl_client.h +++ b/src/xrt/compositor/client/comp_gl_client.h @@ -125,7 +125,7 @@ client_gl_compositor(struct xrt_compositor *xc) * won't be called for you. * * @public @memberof client_gl_compositor - * @relatesalso xrt_compositor_native + * @see xrt_compositor_native */ bool client_gl_compositor_init(struct client_gl_compositor *c, diff --git a/src/xrt/compositor/client/comp_gl_xlib_client.h b/src/xrt/compositor/client/comp_gl_xlib_client.h index a7435fcd7..aa10c5013 100644 --- a/src/xrt/compositor/client/comp_gl_xlib_client.h +++ b/src/xrt/compositor/client/comp_gl_xlib_client.h @@ -34,7 +34,7 @@ struct client_gl_xlib_compositor * Create a new client_gl_xlib_compositor. * * @public @memberof client_gl_xlib_compositor - * @relatesalso xrt_compositor_native + * @see xrt_compositor_native */ struct client_gl_xlib_compositor * client_gl_xlib_compositor_create(struct xrt_compositor_native *xcn, diff --git a/src/xrt/compositor/client/comp_vk_client.h b/src/xrt/compositor/client/comp_vk_client.h index 375c967e2..b37641280 100644 --- a/src/xrt/compositor/client/comp_vk_client.h +++ b/src/xrt/compositor/client/comp_vk_client.h @@ -84,7 +84,7 @@ struct client_vk_compositor * Takes owenership of provided xcn. * * @public @memberof client_vk_compositor - * @relatesalso xrt_compositor_native + * @see xrt_compositor_native */ struct client_vk_compositor * client_vk_compositor_create(struct xrt_compositor_native *xcn, From 6fc4cc0cc9958b4fa19292e35f6b6da82db0d862 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 11:19:55 -0500 Subject: [PATCH 210/883] st/prober: Fix doxygen warnings --- src/xrt/state_trackers/prober/p_prober.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/state_trackers/prober/p_prober.h b/src/xrt/state_trackers/prober/p_prober.h index 3891c46bd..883676cd4 100644 --- a/src/xrt/state_trackers/prober/p_prober.h +++ b/src/xrt/state_trackers/prober/p_prober.h @@ -202,7 +202,7 @@ p_dev_get_bluetooth_dev( * Init the tracking factory. * * @private @memberof prober - * @relatesalso xrt_tracking_factory + * @see xrt_tracking_factory */ int p_tracking_init(struct prober *p); @@ -211,7 +211,7 @@ p_tracking_init(struct prober *p); * Teardown the tracking factory. * * @private @memberof prober - * @relatesalso xrt_tracking_factory + * @see xrt_tracking_factory */ void p_tracking_teardown(struct prober *p); From 08b0fd257fa4654b0c79cdf627b460bd739b2660 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 11:20:13 -0500 Subject: [PATCH 211/883] st/oxr: Fix doxygen warning --- src/xrt/state_trackers/oxr/oxr_objects.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index 241ef7546..883931228 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -369,7 +369,7 @@ oxr_action_to_openxr(struct oxr_action *act) * @return false if an invalid subaction path is provided. * * @public @memberof oxr_instance - * @relatesalso oxr_sub_paths + * @see oxr_sub_paths */ bool oxr_classify_sub_action_paths(struct oxr_logger *log, @@ -410,7 +410,7 @@ oxr_action_create(struct oxr_logger *log, /*! * @public @memberof oxr_session - * @relatesalso oxr_action_set + * @see oxr_action_set */ XrResult oxr_session_attach_action_sets(struct oxr_logger *log, From f82d0f484fbbaaaa893fa4d15c4ffdf892618fbe Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 11:20:26 -0500 Subject: [PATCH 212/883] ipc: Fix doxygen warning --- src/xrt/ipc/shared/ipc_utils.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/xrt/ipc/shared/ipc_utils.h b/src/xrt/ipc/shared/ipc_utils.h index 49a13f9ba..79069e8a7 100644 --- a/src/xrt/ipc/shared/ipc_utils.h +++ b/src/xrt/ipc/shared/ipc_utils.h @@ -137,7 +137,7 @@ ipc_send_fds(struct ipc_message_channel *imc, const void *data, size_t size, con * must be greater than 0 and must match the value provided at the other end. * * @public @memberof ipc_message_channel - * @relatesalso xrt_shmem_handle_t + * @see xrt_shmem_handle_t */ xrt_result_t ipc_receive_handles_shmem(struct ipc_message_channel *imc, @@ -161,7 +161,7 @@ ipc_receive_handles_shmem(struct ipc_message_channel *imc, * time, because the receiver must have the same value in its receive call. * * @public @memberof ipc_message_channel - * @relatesalso xrt_shmem_handle_t + * @see xrt_shmem_handle_t */ xrt_result_t ipc_send_handles_shmem(struct ipc_message_channel *imc, @@ -195,7 +195,7 @@ ipc_send_handles_shmem(struct ipc_message_channel *imc, * must be greater than 0 and must match the value provided at the other end. * * @public @memberof ipc_message_channel - * @relatesalso xrt_graphics_buffer_handle_t + * @see xrt_graphics_buffer_handle_t */ xrt_result_t ipc_receive_handles_graphics_buffer(struct ipc_message_channel *imc, @@ -220,7 +220,7 @@ ipc_receive_handles_graphics_buffer(struct ipc_message_channel *imc, * time, because the receiver must have the same value in its receive call. * * @public @memberof ipc_message_channel - * @relatesalso xrt_graphics_buffer_handle_t + * @see xrt_graphics_buffer_handle_t */ xrt_result_t ipc_send_handles_graphics_buffer(struct ipc_message_channel *imc, @@ -254,7 +254,7 @@ ipc_send_handles_graphics_buffer(struct ipc_message_channel *imc, * must be greater than 0 and must match the value provided at the other end. * * @public @memberof ipc_message_channel - * @relatesalso xrt_graphics_sync_handle_t + * @see xrt_graphics_sync_handle_t */ xrt_result_t ipc_receive_handles_graphics_sync(struct ipc_message_channel *imc, @@ -277,7 +277,7 @@ ipc_receive_handles_graphics_sync(struct ipc_message_channel *imc, * because the receiver must have the same value in its receive call. * * @public @memberof ipc_message_channel - * @relatesalso xrt_graphics_sync_handle_t + * @see xrt_graphics_sync_handle_t */ xrt_result_t ipc_send_handles_graphics_sync(struct ipc_message_channel *imc, From b93b082bd38fd54c0ff8810465de7aab6f5dcff2 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 11:21:00 -0500 Subject: [PATCH 213/883] aux: Fix doxygen warnings --- src/xrt/auxiliary/math/m_api.h | 16 +++++----- src/xrt/auxiliary/os/os_hid.h | 4 +-- src/xrt/auxiliary/tracking/t_tracking.h | 12 ++++---- src/xrt/auxiliary/util/u_sink.h | 39 ++++++++++++------------- 4 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/xrt/auxiliary/math/m_api.h b/src/xrt/auxiliary/math/m_api.h index 2369e6d83..d3483a61a 100644 --- a/src/xrt/auxiliary/math/m_api.h +++ b/src/xrt/auxiliary/math/m_api.h @@ -147,7 +147,7 @@ math_vec3_normalize(struct xrt_vec3 *in); * Create a rotation from a angle in radians and a vector. * * @relates xrt_quat - * @relates xrt_vec3 + * @see xrt_vec3 * @ingroup aux_math */ void @@ -157,7 +157,7 @@ math_quat_from_angle_vector(float angle_rads, const struct xrt_vec3 *vector, str * Create a rotation from a 3x3 rotation matrix. * * @relates xrt_quat - * @relates xrt_matrix_3x3 + * @see xrt_matrix_3x3 * @ingroup aux_math */ void @@ -168,7 +168,7 @@ math_quat_from_matrix_3x3(const struct xrt_matrix_3x3 *mat, struct xrt_quat *res * matrix by crossing z and x to get the y axis. * * @relates xrt_quat - * @relates xrt_vec3 + * @see xrt_vec3 * @ingroup aux_math */ void @@ -226,7 +226,7 @@ math_quat_ensure_normalized(struct xrt_quat *inout); * Rotate a vector. * * @relates xrt_quat - * @relatesalso xrt_vec3 + * @see xrt_vec3 * @ingroup aux_math */ void @@ -250,7 +250,7 @@ math_quat_rotate(const struct xrt_quat *left, const struct xrt_quat *right, stru * vector should be in radians per unit of time. * * @relates xrt_quat - * @relatesalso xrt_vec3 + * @see xrt_vec3 * @ingroup aux_math */ void @@ -269,7 +269,7 @@ math_quat_integrate_velocity(const struct xrt_quat *quat, * radians per unit of time. * * @relates xrt_quat - * @relatesalso xrt_vec3 + * @see xrt_vec3 * @ingroup aux_math */ void @@ -282,7 +282,7 @@ math_quat_finite_difference(const struct xrt_quat *quat0, * Used to rotate a derivative like a angular velocity. * * @relates xrt_quat - * @relatesalso xrt_vec3 + * @see xrt_vec3 * @ingroup aux_math */ void @@ -404,7 +404,7 @@ math_pose_transform(const struct xrt_pose *transform, const struct xrt_pose *pos * The input point and output may be the same pointer. * * @relates xrt_pose - * @relates xrt_vec3 + * @see xrt_vec3 * @ingroup aux_math */ void diff --git a/src/xrt/auxiliary/os/os_hid.h b/src/xrt/auxiliary/os/os_hid.h index 146463c09..f30146879 100644 --- a/src/xrt/auxiliary/os/os_hid.h +++ b/src/xrt/auxiliary/os/os_hid.h @@ -136,8 +136,8 @@ os_hid_destroy(struct os_hid_device *hid_dev) /*! * Open the given path as a hidraw device. * - * @public @memberof hid_hidraw - * @relatesalso os_hid_device + * @see hid_hidraw + * @public @memberof os_hid_device */ int os_hid_open_hidraw(const char *path, struct os_hid_device **out_hid); diff --git a/src/xrt/auxiliary/tracking/t_tracking.h b/src/xrt/auxiliary/tracking/t_tracking.h index 3e97ce19b..15a16e06b 100644 --- a/src/xrt/auxiliary/tracking/t_tracking.h +++ b/src/xrt/auxiliary/tracking/t_tracking.h @@ -296,7 +296,7 @@ t_hsv_filter_sample(struct t_hsv_filter_optimized_table *t, uint32_t y, uint32_t * Construct an HSV filter sink. * @public @memberof t_hsv_filter * - * @relates xrt_frame_context + * @see xrt_frame_context */ int t_hsv_filter_create(struct xrt_frame_context *xfctx, @@ -500,7 +500,7 @@ t_calibration_params_default(struct t_calibration_params *p) * @param gui Frame sink * @param out_sink Output: created frame sink. * - * @relates xrt_frame_context + * @see xrt_frame_context */ int t_calibration_stereo_create(struct xrt_frame_context *xfctx, @@ -517,7 +517,7 @@ t_calibration_stereo_create(struct xrt_frame_context *xfctx, */ /*! - * @relates xrt_frame_context + * @see xrt_frame_context */ int t_convert_yuv_or_yuyv_create(struct xrt_frame_sink *next, struct xrt_frame_sink **out_sink); @@ -525,7 +525,7 @@ t_convert_yuv_or_yuyv_create(struct xrt_frame_sink *next, struct xrt_frame_sink /*! - * @relates xrt_frame_context + * @see xrt_frame_context */ int t_debug_hsv_picker_create(struct xrt_frame_context *xfctx, @@ -533,7 +533,7 @@ t_debug_hsv_picker_create(struct xrt_frame_context *xfctx, struct xrt_frame_sink **out_sink); /*! - * @relates xrt_frame_context + * @see xrt_frame_context */ int t_debug_hsv_viewer_create(struct xrt_frame_context *xfctx, @@ -541,7 +541,7 @@ t_debug_hsv_viewer_create(struct xrt_frame_context *xfctx, struct xrt_frame_sink **out_sink); /*! - * @relates xrt_frame_context + * @see xrt_frame_context */ int t_debug_hsv_filter_create(struct xrt_frame_context *xfctx, diff --git a/src/xrt/auxiliary/util/u_sink.h b/src/xrt/auxiliary/util/u_sink.h index 44558fc74..1f26469eb 100644 --- a/src/xrt/auxiliary/util/u_sink.h +++ b/src/xrt/auxiliary/util/u_sink.h @@ -26,8 +26,8 @@ struct u_sink_quirk_params }; /*! - * @relatesalso xrt_frame_sink - * @relates xrt_frame_context + * @public @memberof xrt_frame_sink + * @see xrt_frame_context */ void u_sink_create_format_converter(struct xrt_frame_context *xfctx, @@ -36,8 +36,8 @@ u_sink_create_format_converter(struct xrt_frame_context *xfctx, struct xrt_frame_sink **out_xfs); /*! - * @relatesalso xrt_frame_sink - * @relates xrt_frame_context + * @public @memberof xrt_frame_sink + * @see xrt_frame_context */ void u_sink_create_to_r8g8b8_or_l8(struct xrt_frame_context *xfctx, @@ -45,8 +45,8 @@ u_sink_create_to_r8g8b8_or_l8(struct xrt_frame_context *xfctx, struct xrt_frame_sink **out_xfs); /*! - * @relatesalso xrt_frame_sink - * @relates xrt_frame_context + * @public @memberof xrt_frame_sink + * @see xrt_frame_context */ void u_sink_create_to_r8g8b8_bayer_or_l8(struct xrt_frame_context *xfctx, @@ -54,8 +54,8 @@ u_sink_create_to_r8g8b8_bayer_or_l8(struct xrt_frame_context *xfctx, struct xrt_frame_sink **out_xfs); /*! - * @relatesalso xrt_frame_sink - * @relates xrt_frame_context + * @public @memberof xrt_frame_sink + * @see xrt_frame_context */ void u_sink_create_to_yuv_yuyv_uyvy_or_l8(struct xrt_frame_context *xfctx, @@ -63,17 +63,16 @@ u_sink_create_to_yuv_yuyv_uyvy_or_l8(struct xrt_frame_context *xfctx, struct xrt_frame_sink **out_xfs); /*! - * @relatesalso xrt_frame_sink - * @relates xrt_frame_context + * @public @memberof xrt_frame_sink + * @see xrt_frame_context */ void u_sink_create_to_yuv_or_yuyv(struct xrt_frame_context *xfctx, struct xrt_frame_sink *downstream, struct xrt_frame_sink **out_xfs); /*! - * @public @memberof u_sink_deinterleaver - * @relatesalso xrt_frame_sink - * @relates xrt_frame_context + * @public @memberof xrt_frame_sink + * @see xrt_frame_context */ void u_sink_deinterleaver_create(struct xrt_frame_context *xfctx, @@ -81,9 +80,8 @@ u_sink_deinterleaver_create(struct xrt_frame_context *xfctx, struct xrt_frame_sink **out_xfs); /*! - * @public @memberof u_sink_queue - * @relatesalso xrt_frame_sink - * @relates xrt_frame_context + * @public @memberof xrt_frame_sink + * @see xrt_frame_context */ bool u_sink_queue_create(struct xrt_frame_context *xfctx, @@ -91,9 +89,8 @@ u_sink_queue_create(struct xrt_frame_context *xfctx, struct xrt_frame_sink **out_xfs); /*! - * @public @memberof u_sink_quirk - * @relatesalso xrt_frame_sink - * @relates xrt_frame_context + * @public @memberof xrt_frame_sink + * @see xrt_frame_context */ void u_sink_quirk_create(struct xrt_frame_context *xfctx, @@ -102,8 +99,8 @@ u_sink_quirk_create(struct xrt_frame_context *xfctx, struct xrt_frame_sink **out_xfs); /*! - * @public @memberof u_sink_split - * @relatesalso xrt_frame_sink + * @public @memberof xrt_frame_sink + * @see xrt_frame_context */ void u_sink_split_create(struct xrt_frame_context *xfctx, From 98886d53179753ebdd14e9a70b3c434085689cdf Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 17:02:53 -0500 Subject: [PATCH 214/883] d/multi: Fix contagious doxygen warning. --- src/xrt/drivers/multi_wrapper/multi.c | 2 +- src/xrt/drivers/multi_wrapper/multi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/drivers/multi_wrapper/multi.c b/src/xrt/drivers/multi_wrapper/multi.c index 994f9df3f..4d52d4057 100644 --- a/src/xrt/drivers/multi_wrapper/multi.c +++ b/src/xrt/drivers/multi_wrapper/multi.c @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 /*! * @file - * @brief Combination of multiple @xrt_device. + * @brief Combination of multiple @ref xrt_device. * @author Christoph Haag * @ingroup drv_multi */ diff --git a/src/xrt/drivers/multi_wrapper/multi.h b/src/xrt/drivers/multi_wrapper/multi.h index 027ff9bd5..0e2ab035d 100644 --- a/src/xrt/drivers/multi_wrapper/multi.h +++ b/src/xrt/drivers/multi_wrapper/multi.h @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 /*! * @file - * @brief Combination of multiple @xrt_device. + * @brief Combination of multiple @ref xrt_device. * @author Christoph Haag * @ingroup drv_multi */ From 0340ae3cc874ddbe4608b650fcf84473d5c1ed83 Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 11:25:00 -0300 Subject: [PATCH 215/883] d/qwerty: Add Qwerty driver initial boilerplate The Qwerty driver will emulate an HMD and controllers through the use of mouse and keyboard, and in particular, using the SDL key events generated from the debug GUI. --- CMakeLists.txt | 3 ++ meson.build | 4 ++ meson_options.txt | 2 +- src/xrt/drivers/CMakeLists.txt | 17 ++++++++ src/xrt/drivers/meson.build | 16 +++++++ src/xrt/drivers/qwerty/qwerty_device.c | 12 ++++++ src/xrt/drivers/qwerty/qwerty_device.h | 28 +++++++++++++ src/xrt/drivers/qwerty/qwerty_interface.h | 40 ++++++++++++++++++ src/xrt/drivers/qwerty/qwerty_prober.c | 51 +++++++++++++++++++++++ src/xrt/drivers/qwerty/qwerty_sdl.c | 12 ++++++ src/xrt/targets/common/CMakeLists.txt | 4 ++ src/xrt/targets/common/target_lists.c | 9 ++++ src/xrt/targets/meson.build | 4 ++ src/xrt/targets/openxr/CMakeLists.txt | 2 + src/xrt/targets/openxr/meson.build | 3 +- src/xrt/targets/service/CMakeLists.txt | 1 + src/xrt/targets/service/meson.build | 1 + tests/meson.build | 1 + 18 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 src/xrt/drivers/qwerty/qwerty_device.c create mode 100644 src/xrt/drivers/qwerty/qwerty_device.h create mode 100644 src/xrt/drivers/qwerty/qwerty_interface.h create mode 100644 src/xrt/drivers/qwerty/qwerty_prober.c create mode 100644 src/xrt/drivers/qwerty/qwerty_sdl.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c27637604..337183880 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,6 +198,7 @@ cmake_dependent_option(XRT_BUILD_DRIVER_VF "Build video frame driver (for video cmake_dependent_option(XRT_BUILD_DRIVER_SURVIVE "Enable libsurvive driver" ON "SURVIVE_FOUND" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_ANDROID "Enable Android sensors driver" ON "ANDROID" OFF) +cmake_dependent_option(XRT_BUILD_DRIVER_QWERTY "Enable Qwerty driver" ON "XRT_HAVE_SDL2" OFF) # You can set this from a superproject to add a driver # All drivers must be listed in here to be included in the generated header! @@ -220,6 +221,7 @@ list(APPEND AVAILABLE_DRIVERS "V4L2" "VF" "VIVE" + "QWERTY" ) @@ -356,6 +358,7 @@ message(STATUS "# DRIVER_REMOTE: ${XRT_BUILD_DRIVER_REMOTE}") message(STATUS "# DRIVER_SURVIVE: ${XRT_BUILD_DRIVER_SURVIVE}") message(STATUS "# DRIVER_VF: ${XRT_BUILD_DRIVER_VF}") message(STATUS "# DRIVER_VIVE: ${XRT_BUILD_DRIVER_VIVE}") +message(STATUS "# DRIVER_QWERTY: ${XRT_BUILD_DRIVER_QWERTY}") message(STATUS "#####----- Config -----#####") if(XRT_FEATURE_SERVICE AND NOT XRT_FEATURE_OPENXR) diff --git a/meson.build b/meson.build index 48d4bb4ae..11b31f8ff 100644 --- a/meson.build +++ b/meson.build @@ -221,6 +221,10 @@ if not get_option('dbus').disabled() and dbus.found() endif endif +if sdl2.found() and ('auto' in drivers and 'qwerty' not in drivers) + drivers += ['qwerty'] +endif + if drivers.length() == 0 or drivers == ['auto'] error('You must enable at least one driver.') endif diff --git a/meson_options.txt b/meson_options.txt index db96cb415..58562047e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,7 +3,7 @@ option('drivers', type: 'array', - choices: ['auto', 'dummy', 'hdk', 'hydra', 'ns', 'ohmd', 'psmv', 'psvr', 'rs', 'v4l2', 'vf', 'vive', 'survive', 'daydream', 'arduino', 'remote', 'handtracking'], + choices: ['auto', 'dummy', 'hdk', 'hydra', 'ns', 'ohmd', 'psmv', 'psvr', 'rs', 'v4l2', 'vf', 'vive', 'survive', 'daydream', 'arduino', 'remote', 'handtracking', 'qwerty'], value: ['auto'], description: 'Set of drivers to build') diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index dd3988fdd..d0e3033cc 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -43,6 +43,23 @@ if(XRT_BUILD_DRIVER_DUMMY) list(APPEND ENABLED_HEADSET_DRIVERS dummy) endif() +if(XRT_BUILD_DRIVER_QWERTY) + set(QWERTY_SOURCE_FILES + qwerty/qwerty_device.c + qwerty/qwerty_device.h + qwerty/qwerty_interface.h + qwerty/qwerty_prober.c + qwerty/qwerty_sdl.c + ) + + add_library(drv_qwerty STATIC ${QWERTY_SOURCE_FILES}) + target_link_libraries(drv_qwerty PRIVATE xrt-interfaces aux_util ${SDL2_LIBRARIES}) + list(APPEND ENABLED_DRIVERS qwerty) + + add_library(drv_qwerty_includes INTERFACE) + target_include_directories(drv_qwerty_includes INTERFACE qwerty) +endif() + if(XRT_BUILD_DRIVER_HDK) set(HDK_SOURCE_FILES hdk/hdk_device.cpp diff --git a/src/xrt/drivers/meson.build b/src/xrt/drivers/meson.build index 320a13216..18b6a6a87 100644 --- a/src/xrt/drivers/meson.build +++ b/src/xrt/drivers/meson.build @@ -241,3 +241,19 @@ lib_drv_multi = static_library( dependencies: [aux], build_by_default: true, ) + +lib_drv_qwerty = static_library( + 'drv_qwerty', + files( + 'qwerty/qwerty_device.c', + 'qwerty/qwerty_device.h', + 'qwerty/qwerty_interface.h', + 'qwerty/qwerty_prober.c', + 'qwerty/qwerty_sdl.c', + ), + include_directories: xrt_include, + dependencies: [aux, sdl2], + build_by_default: 'qwerty' in drivers, +) + +drv_qwerty_include = include_directories('qwerty') diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c new file mode 100644 index 000000000..5f8a9c4bf --- /dev/null +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -0,0 +1,12 @@ +// Copyright 2021, Mateo de Mayo. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Implementation of qwerty_device related methods. + * @author Mateo de Mayo + * @ingroup drv_qwerty + */ + +typedef int _silence_compiler_about_empty_translation_unit; + +// @todo diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h new file mode 100644 index 000000000..103f9ce4b --- /dev/null +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -0,0 +1,28 @@ +// Copyright 2021, Mateo de Mayo. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Internal header for qwerty_device and its friends. + * @author Mateo de Mayo + * @ingroup drv_qwerty + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @addtogroup drv_qwerty + * @{ + */ + +// @todo + +/*! + * @} + */ + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/drivers/qwerty/qwerty_interface.h b/src/xrt/drivers/qwerty/qwerty_interface.h new file mode 100644 index 000000000..97a3d2a10 --- /dev/null +++ b/src/xrt/drivers/qwerty/qwerty_interface.h @@ -0,0 +1,40 @@ +// Copyright 2021, Mateo de Mayo. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Interface to @ref drv_qwerty. + * @author Mateo de Mayo + * @ingroup drv_qwerty + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @defgroup drv_qwerty Qwerty driver + * @ingroup drv + * + * @brief Driver for emulated HMD and controllers through keyboard and mouse. + * @{ + */ + +//! Create an auto prober for qwerty devices. +struct xrt_auto_prober * +qwerty_create_auto_prober(void); + +/*! + * @} + */ + +/*! + * @dir drivers/qwerty + * + * @brief @ref drv_qwerty files. + */ + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/drivers/qwerty/qwerty_prober.c b/src/xrt/drivers/qwerty/qwerty_prober.c new file mode 100644 index 000000000..3b60215ce --- /dev/null +++ b/src/xrt/drivers/qwerty/qwerty_prober.c @@ -0,0 +1,51 @@ +// Copyright 2021, Mateo de Mayo. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Qwerty devices @ref xrt_auto_prober "autoprober". + * @author Mateo de Mayo + * @ingroup drv_qwerty + */ + +#include "util/u_misc.h" +#include "xrt/xrt_prober.h" + +struct qwerty_prober +{ + struct xrt_auto_prober base; +}; + +static struct qwerty_prober * +qwerty_prober(struct xrt_auto_prober *p) +{ + return (struct qwerty_prober *)p; +} + +static void +qwerty_prober_destroy(struct xrt_auto_prober *p) +{ + struct qwerty_prober *qp = qwerty_prober(p); + free(qp); +} + +static int +qwerty_prober_autoprobe(struct xrt_auto_prober *xap, + cJSON *attached_data, + bool no_hmds, + struct xrt_prober *xp, + struct xrt_device **out_xdevs) +{ + // @todo + return 0; +} + +struct xrt_auto_prober * +qwerty_create_auto_prober() +{ + struct qwerty_prober *qp = U_TYPED_CALLOC(struct qwerty_prober); + qp->base.name = "Qwerty"; + qp->base.destroy = qwerty_prober_destroy; + qp->base.lelo_dallas_autoprobe = qwerty_prober_autoprobe; + + return &qp->base; +} diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c new file mode 100644 index 000000000..81f4bf80a --- /dev/null +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -0,0 +1,12 @@ +// Copyright 2021, Mateo de Mayo. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Connection between user-generated SDL events and qwerty devices. + * @author Mateo de Mayo + * @ingroup drv_qwerty + */ + +typedef int _silence_compiler_about_empty_translation_unit; + +// @todo diff --git a/src/xrt/targets/common/CMakeLists.txt b/src/xrt/targets/common/CMakeLists.txt index 3f0f9e5c4..30d048686 100644 --- a/src/xrt/targets/common/CMakeLists.txt +++ b/src/xrt/targets/common/CMakeLists.txt @@ -94,6 +94,10 @@ endif() target_link_libraries(target_lists PRIVATE drv_multi) +if(XRT_BUILD_DRIVER_QWERTY) + target_link_libraries(target_lists PRIVATE drv_qwerty) +endif() + #### # Instance # diff --git a/src/xrt/targets/common/target_lists.c b/src/xrt/targets/common/target_lists.c index 0a7aa5711..8b51cdbd8 100644 --- a/src/xrt/targets/common/target_lists.c +++ b/src/xrt/targets/common/target_lists.c @@ -70,6 +70,10 @@ #include "realsense/rs_interface.h" #endif +#ifdef XRT_BUILD_DRIVER_QWERTY +#include "qwerty/qwerty_interface.h" +#endif + /*! * Each entry should be a vendor ID (VID), product ID (PID), a "found" function, * and a string literal name. @@ -162,10 +166,15 @@ xrt_auto_prober_creator target_auto_list[] = { rs_create_auto_prober, #endif +#ifdef XRT_BUILD_DRIVER_QWERTY + qwerty_create_auto_prober, +#endif + #ifdef XRT_BUILD_DRIVER_DUMMY // Dummy headset driver last. dummy_create_auto_prober, #endif + NULL, // Terminate }; diff --git a/src/xrt/targets/meson.build b/src/xrt/targets/meson.build index e063908e8..d3ebd476f 100644 --- a/src/xrt/targets/meson.build +++ b/src/xrt/targets/meson.build @@ -73,6 +73,10 @@ if 'arduino' in drivers driver_libs += [lib_drv_arduino] endif +if 'qwerty' in drivers + driver_libs += [lib_drv_qwerty] +endif + if 'remote' in drivers driver_libs += [lib_drv_remote] endif diff --git a/src/xrt/targets/openxr/CMakeLists.txt b/src/xrt/targets/openxr/CMakeLists.txt index 1d51db251..516ed71c0 100644 --- a/src/xrt/targets/openxr/CMakeLists.txt +++ b/src/xrt/targets/openxr/CMakeLists.txt @@ -42,6 +42,8 @@ if(XRT_HAVE_SDL2) st_gui imgui_impl_sdl ${SDL2_LIBRARIES} + drv_qwerty + drv_qwerty_includes ) target_include_directories(${RUNTIME_TARGET} PRIVATE ${SDL2_INCLUDE_DIRS} diff --git a/src/xrt/targets/openxr/meson.build b/src/xrt/targets/openxr/meson.build index 351070d9d..ad850f6fd 100644 --- a/src/xrt/targets/openxr/meson.build +++ b/src/xrt/targets/openxr/meson.build @@ -31,9 +31,10 @@ if sdl2.found() '../../../external/imgui/imgui/imgui_impl_sdl.cpp', '../../../external/imgui/imgui/imgui_impl_sdl.h', ] - hack_libs += lib_st_gui + hack_libs += [lib_st_gui, lib_drv_qwerty] hack_incs += [ st_include, + drv_qwerty_include, ] endif diff --git a/src/xrt/targets/service/CMakeLists.txt b/src/xrt/targets/service/CMakeLists.txt index b0c27823e..020e7a6f9 100644 --- a/src/xrt/targets/service/CMakeLists.txt +++ b/src/xrt/targets/service/CMakeLists.txt @@ -86,6 +86,7 @@ if(XRT_HAVE_SDL2) imgui_impl_sdl ${SDL2_LIBRARIES} aux_ogl + drv_qwerty_includes ) target_include_directories(monado-service PRIVATE ${SDL2_INCLUDE_DIRS} diff --git a/src/xrt/targets/service/meson.build b/src/xrt/targets/service/meson.build index 3709c5f66..b66865531 100644 --- a/src/xrt/targets/service/meson.build +++ b/src/xrt/targets/service/meson.build @@ -24,6 +24,7 @@ if sdl2.found() hack_libs += lib_st_gui hack_incs += [ st_include, + drv_qwerty_include, ] endif diff --git a/tests/meson.build b/tests/meson.build index 7502b751d..fdffbdffc 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -29,6 +29,7 @@ if sdl2.found() hack_libs += lib_st_gui hack_incs += [ st_include, + drv_qwerty_include, ] endif From e6db1fae74bd43d0928740f8dbb1f3139211180e Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 12:30:51 -0300 Subject: [PATCH 216/883] d/qwerty: Implement still HMD creation --- src/xrt/drivers/qwerty/qwerty_device.c | 115 ++++++++++++++++++++++++- src/xrt/drivers/qwerty/qwerty_device.h | 19 +++- src/xrt/drivers/qwerty/qwerty_prober.c | 13 ++- src/xrt/include/xrt/xrt_tracking.h | 11 +++ 4 files changed, 153 insertions(+), 5 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 5f8a9c4bf..02fa9dc6a 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -7,6 +7,117 @@ * @ingroup drv_qwerty */ -typedef int _silence_compiler_about_empty_translation_unit; +#include "qwerty_device.h" -// @todo +#include "util/u_device.h" + +#include "util/u_distortion_mesh.h" + +#include "math/m_api.h" +#include "math/m_mathinclude.h" + +#include "xrt/xrt_device.h" + +#include +#include + +struct qwerty_device * +qwerty_device(struct xrt_device *xd) +{ + struct qwerty_device *qd = (struct qwerty_device *)xd; + assert(qd); + return qd; +} + +static void +qwerty_update_inputs(struct xrt_device *xd) +{ + return; +} + +static void +qwerty_get_tracked_pose(struct xrt_device *xd, + enum xrt_input_name name, + uint64_t at_timestamp_ns, + struct xrt_space_relation *out_relation) +{ + if (name != XRT_INPUT_GENERIC_HEAD_POSE) { + printf("Unexpected input name = 0x%04X\n", name >> 8); // @todo: use u_logging.h + return; + } + + struct xrt_pose identity = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; + out_relation->pose = identity; + out_relation->relation_flags = + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_POSITION_VALID_BIT | + XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT; +} + +static void +qwerty_get_view_pose(struct xrt_device *xd, + struct xrt_vec3 *eye_relation, + uint32_t view_index, + struct xrt_pose *out_pose) +{ + // Adapted from dummy_hmd_get_view_pose() + struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; + bool is_left = view_index == 0; + float adjust = is_left ? -0.5f : 0.5f; + struct xrt_vec3 eye_offset = *eye_relation; + math_vec3_scalar_mul(adjust, &eye_offset); + math_vec3_accum(&eye_offset, &pose.position); + *out_pose = pose; +} + +static void +qwerty_destroy(struct xrt_device *xd) +{ + u_device_free(xd); +} + +struct qwerty_device * +qwerty_hmd_create(void) +{ + enum u_device_alloc_flags flags = U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE; + size_t num_inputs = 1, num_outputs = 0; + struct qwerty_device *qd = U_DEVICE_ALLOCATE(struct qwerty_device, flags, num_inputs, num_outputs); + assert(qd); + + struct xrt_device *xd = &qd->base; + xd->name = XRT_DEVICE_GENERIC_HMD; + xd->device_type = XRT_DEVICE_TYPE_HMD; + + snprintf(xd->str, XRT_DEVICE_NAME_LEN, QWERTY_HMD_STR); + snprintf(xd->serial, XRT_DEVICE_NAME_LEN, QWERTY_HMD_STR); + + // Fill in xd->hmd + struct u_device_simple_info info; + info.display.w_pixels = 1280; + info.display.h_pixels = 720; + info.display.w_meters = 0.13f; + info.display.h_meters = 0.07f; + info.lens_horizontal_separation_meters = 0.13f / 2.0f; + info.lens_vertical_position_meters = 0.07f / 2.0f; + info.views[0].fov = 85.0f * (M_PI / 180.0f); + info.views[1].fov = 85.0f * (M_PI / 180.0f); + + if (!u_device_setup_split_side_by_side(xd, &info)) { + printf("Failed to setup HMD properties\n"); // @todo: Use u_logging.h + qwerty_destroy(xd); + assert(false); + return NULL; + } + + xd->tracking_origin->type = XRT_TRACKING_TYPE_OTHER; + snprintf(xd->tracking_origin->name, XRT_TRACKING_NAME_LEN, QWERTY_HMD_TRACKER_STR); + + xd->inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; + + xd->update_inputs = qwerty_update_inputs; + xd->get_tracked_pose = qwerty_get_tracked_pose; + xd->get_view_pose = qwerty_get_view_pose; + xd->destroy = qwerty_destroy; + u_distortion_mesh_set_none(xd); // Fill in xd->compute_distortion() + + return qd; +} diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index 103f9ce4b..d1b1b4933 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -8,6 +8,11 @@ */ #pragma once +#include "xrt/xrt_device.h" + +#define QWERTY_HMD_STR "Qwerty HMD" +#define QWERTY_HMD_TRACKER_STR QWERTY_HMD_STR " Tracker" + #ifdef __cplusplus extern "C" { #endif @@ -17,7 +22,19 @@ extern "C" { * @{ */ -// @todo +//! @implements xrt_device +struct qwerty_device +{ + struct xrt_device base; +}; + +//! Cast to qwerty_device. Ensures returning a valid device or crashing. +struct qwerty_device * +qwerty_device(struct xrt_device *xd); + +//! Create qwerty_hmd. Crash on failure. +struct qwerty_device * +qwerty_hmd_create(void); /*! * @} diff --git a/src/xrt/drivers/qwerty/qwerty_prober.c b/src/xrt/drivers/qwerty/qwerty_prober.c index 3b60215ce..136dc5d1f 100644 --- a/src/xrt/drivers/qwerty/qwerty_prober.c +++ b/src/xrt/drivers/qwerty/qwerty_prober.c @@ -7,6 +7,7 @@ * @ingroup drv_qwerty */ +#include "qwerty_device.h" #include "util/u_misc.h" #include "xrt/xrt_prober.h" @@ -35,8 +36,16 @@ qwerty_prober_autoprobe(struct xrt_auto_prober *xap, struct xrt_prober *xp, struct xrt_device **out_xdevs) { - // @todo - return 0; + bool hmd_wanted = !no_hmds; // Hopefully easier to reason about + + struct qwerty_device *qhmd = qwerty_hmd_create(); + + if (hmd_wanted) { + out_xdevs[0] = &qhmd->base; + } + + int num_qwerty_devices = hmd_wanted; + return num_qwerty_devices; } struct xrt_auto_prober * diff --git a/src/xrt/include/xrt/xrt_tracking.h b/src/xrt/include/xrt/xrt_tracking.h index 1744a3057..4ae4b84f4 100644 --- a/src/xrt/include/xrt/xrt_tracking.h +++ b/src/xrt/include/xrt/xrt_tracking.h @@ -57,6 +57,17 @@ enum xrt_tracking_type // The device(s) are tracked by external SLAM XRT_TRACKING_TYPE_EXTERNAL_SLAM, + + /* @remove: on next commit + Is it a good idea to add a new tracking type instead of using _NONE? Two reasons: + 1. _NONE makes u_device_setup_tracking_origins modify tracking origins in + the app but this is not yet synced with the service + 2. _NONE is not quite exact, for what I understand qwerty devices *are* + being tracked. Though I might be missunderstanding what tracking is. + */ + + // The device(s) are tracked by other methods. + XRT_TRACKING_TYPE_OTHER, }; /*! From 12d52193da1582875efe6b6948be0c5a5106db7b Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 12:49:42 -0300 Subject: [PATCH 217/883] d/qwerty: Connect the debug UI to the Qwerty driver It was necessary to add a list of xdevs to oxr_sdl2_hack_start and to populate such list from its callees. That includes sdl2_program.gui_program->xdevs which was not being filled for the monado-service target. --- src/xrt/drivers/qwerty/qwerty_interface.h | 9 +++++++++ src/xrt/drivers/qwerty/qwerty_sdl.c | 10 ++++++++-- src/xrt/include/xrt/xrt_tracking.h | 8 -------- src/xrt/ipc/server/ipc_server_process.c | 9 +++++++-- src/xrt/state_trackers/oxr/oxr_instance.c | 4 ++-- src/xrt/targets/openxr/oxr_sdl2_hack.c | 18 ++++++++++++++++-- 6 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_interface.h b/src/xrt/drivers/qwerty/qwerty_interface.h index 97a3d2a10..af7096b07 100644 --- a/src/xrt/drivers/qwerty/qwerty_interface.h +++ b/src/xrt/drivers/qwerty/qwerty_interface.h @@ -13,6 +13,8 @@ extern "C" { #endif +typedef union SDL_Event SDL_Event; + /*! * @defgroup drv_qwerty Qwerty driver * @ingroup drv @@ -25,6 +27,13 @@ extern "C" { struct xrt_auto_prober * qwerty_create_auto_prober(void); +/*! + * Process an SDL_Event (like a key press) and dispatches a suitable action + * to the appropriate qwerty_device. + */ +void +qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event event); + /*! * @} */ diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index 81f4bf80a..4b1308ce7 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -7,6 +7,12 @@ * @ingroup drv_qwerty */ -typedef int _silence_compiler_about_empty_translation_unit; +#include "xrt/xrt_device.h" +#include -// @todo +void +qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event event) +{ + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_w) + printf("W pressed and xdevs[0] = %s\n", xdevs[0]->str); +} diff --git a/src/xrt/include/xrt/xrt_tracking.h b/src/xrt/include/xrt/xrt_tracking.h index 4ae4b84f4..729ec51ac 100644 --- a/src/xrt/include/xrt/xrt_tracking.h +++ b/src/xrt/include/xrt/xrt_tracking.h @@ -58,14 +58,6 @@ enum xrt_tracking_type // The device(s) are tracked by external SLAM XRT_TRACKING_TYPE_EXTERNAL_SLAM, - /* @remove: on next commit - Is it a good idea to add a new tracking type instead of using _NONE? Two reasons: - 1. _NONE makes u_device_setup_tracking_origins modify tracking origins in - the app but this is not yet synced with the service - 2. _NONE is not quite exact, for what I understand qwerty devices *are* - being tracked. Though I might be missunderstanding what tracking is. - */ - // The device(s) are tracked by other methods. XRT_TRACKING_TYPE_OTHER, }; diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index b54cbd951..9e19fd441 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -44,7 +44,7 @@ extern int oxr_sdl2_hack_create(void **out_hack); extern void -oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst); +oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst, struct xrt_device **xdevs); extern void oxr_sdl2_hack_stop(void **hack_ptr); @@ -1074,8 +1074,13 @@ ipc_server_main(int argc, char **argv) init_server_state(s); + struct xrt_device *xdevs[IPC_SERVER_NUM_XDEVS]; + for (size_t i = 0; i < IPC_SERVER_NUM_XDEVS; i++) { + xdevs[i] = s->idevs[i].xdev; + } + /* ---- HACK ---- */ - oxr_sdl2_hack_start(s->hack, s->xinst); + oxr_sdl2_hack_start(s->hack, s->xinst, xdevs); /* ---- HACK ---- */ ret = main_loop(s); diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c index b0ca38982..50abe2c66 100644 --- a/src/xrt/state_trackers/oxr/oxr_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_instance.c @@ -57,7 +57,7 @@ extern int oxr_sdl2_hack_create(void **out_hack); extern void -oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst); +oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst, struct xrt_device **xdevs); extern void oxr_sdl2_hack_stop(void **hack_ptr); @@ -379,7 +379,7 @@ oxr_instance_create(struct oxr_logger *log, const XrInstanceCreateInfo *createIn u_var_add_root((void *)inst, "XrInstance", true); /* ---- HACK ---- */ - oxr_sdl2_hack_start(inst->hack, inst->xinst); + oxr_sdl2_hack_start(inst->hack, inst->xinst, sys->xdevs); /* ---- HACK ---- */ oxr_log(log, diff --git a/src/xrt/targets/openxr/oxr_sdl2_hack.c b/src/xrt/targets/openxr/oxr_sdl2_hack.c index 54804ef58..c1a702a40 100644 --- a/src/xrt/targets/openxr/oxr_sdl2_hack.c +++ b/src/xrt/targets/openxr/oxr_sdl2_hack.c @@ -27,7 +27,7 @@ oxr_sdl2_hack_create(void **out_hack) } void -oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst) +oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst, struct xrt_device **xdevs) {} void @@ -41,6 +41,8 @@ oxr_sdl2_hack_stop(void **hack) #include "gui/gui_common.h" #include "gui/gui_imgui.h" +#include "qwerty_interface.h" + #include DEBUG_GET_ONCE_BOOL_OPTION(gui, "OXR_DEBUG_GUI", false) @@ -145,6 +147,9 @@ sdl2_loop(struct sdl2_program *p) ImPlotContext *plot_ctx = ImPlot_CreateContext(); ImPlot_SetCurrentContext(plot_ctx); + // Setup qwerty driver usage + bool qwerty_enabled = true; // @todo: get from an env var + // Main loop struct gui_imgui gui = {0}; gui.clear.r = 0.45f; @@ -162,6 +167,11 @@ sdl2_loop(struct sdl2_program *p) while (SDL_PollEvent(&event)) { igImGui_ImplSDL2_ProcessEvent(&event); + // Caution here, qwerty driver is being accessed by the main thread as well + if (qwerty_enabled) { + qwerty_process_event(p->base.xdevs, NUM_XDEVS, event); + } + if (event.type == SDL_QUIT) { p->base.stopped = true; } @@ -274,7 +284,7 @@ oxr_sdl2_hack_create(void **out_hack) } void -oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst) +oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst, struct xrt_device **xdevs) { struct sdl2_program *p = (struct sdl2_program *)hack; if (p == NULL) { @@ -283,6 +293,10 @@ oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst) xrt_instance_get_prober(xinst, &p->base.xp); + for (size_t i = 0; i < NUM_XDEVS; i++) { + p->base.xdevs[i] = xdevs[i]; + } + if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { U_LOG_E("Failed to init SDL2!"); return; From ec340fabe217f0680321872338ecbde3958b849f Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 15:04:38 -0300 Subject: [PATCH 218/883] d/qwerty: Implement WASDQE and arrow keys HMD movement --- src/xrt/drivers/qwerty/qwerty_device.c | 72 ++++++++++++++++++++++++-- src/xrt/drivers/qwerty/qwerty_device.h | 52 +++++++++++++++++++ src/xrt/drivers/qwerty/qwerty_sdl.c | 68 +++++++++++++++++++++++- 3 files changed, 187 insertions(+), 5 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 02fa9dc6a..2964afbb9 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -21,6 +21,16 @@ #include #include +#define QWERTY_HMD_INITIAL_MOVEMENT_SPEED 0.002f // in meters per frame +#define QWERTY_HMD_INITIAL_LOOK_SPEED 0.02f // in radians per frame + +// clang-format off +// Value copied from u_device_setup_tracking_origins. +#define QWERTY_HMD_INITIAL_POS (struct xrt_vec3){0, 1.6f, 0} +// clang-format on + +// xrt_device functions + struct qwerty_device * qwerty_device(struct xrt_device *xd) { @@ -41,13 +51,39 @@ qwerty_get_tracked_pose(struct xrt_device *xd, uint64_t at_timestamp_ns, struct xrt_space_relation *out_relation) { + struct qwerty_device *qd = qwerty_device(xd); + if (name != XRT_INPUT_GENERIC_HEAD_POSE) { printf("Unexpected input name = 0x%04X\n", name >> 8); // @todo: use u_logging.h return; } - struct xrt_pose identity = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - out_relation->pose = identity; + // Position + + struct xrt_vec3 pos_delta = { + qd->movement_speed * (qd->right_pressed - qd->left_pressed), + 0, // Up/down movement will be relative to base space + qd->movement_speed * (qd->backward_pressed - qd->forward_pressed), + }; + math_quat_rotate_vec3(&qd->pose.orientation, &pos_delta, &pos_delta); + pos_delta.y += qd->movement_speed * (qd->up_pressed - qd->down_pressed); + math_vec3_accum(&pos_delta, &qd->pose.position); + + // Orientation + + // View rotation caused by keys + float y_look_speed = qd->look_speed * (qd->look_left_pressed - qd->look_right_pressed); + float x_look_speed = qd->look_speed * (qd->look_up_pressed - qd->look_down_pressed); + + struct xrt_quat x_rotation, y_rotation; + struct xrt_vec3 x_axis = {1, 0, 0}, y_axis = {0, 1, 0}; + math_quat_from_angle_vector(x_look_speed, &x_axis, &x_rotation); + math_quat_from_angle_vector(y_look_speed, &y_axis, &y_rotation); + math_quat_rotate(&qd->pose.orientation, &x_rotation, &qd->pose.orientation); // local-space pitch + math_quat_rotate(&y_rotation, &qd->pose.orientation, &qd->pose.orientation); // base-space yaw + math_quat_normalize(&qd->pose.orientation); + + out_relation->pose = qd->pose; out_relation->relation_flags = XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT; @@ -59,7 +95,6 @@ qwerty_get_view_pose(struct xrt_device *xd, uint32_t view_index, struct xrt_pose *out_pose) { - // Adapted from dummy_hmd_get_view_pose() struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; bool is_left = view_index == 0; float adjust = is_left ? -0.5f : 0.5f; @@ -83,6 +118,11 @@ qwerty_hmd_create(void) struct qwerty_device *qd = U_DEVICE_ALLOCATE(struct qwerty_device, flags, num_inputs, num_outputs); assert(qd); + qd->pose.orientation.w = 1.f; + qd->pose.position = QWERTY_HMD_INITIAL_POS; + qd->movement_speed = QWERTY_HMD_INITIAL_MOVEMENT_SPEED; + qd->look_speed = QWERTY_HMD_INITIAL_LOOK_SPEED; + struct xrt_device *xd = &qd->base; xd->name = XRT_DEVICE_GENERIC_HMD; xd->device_type = XRT_DEVICE_TYPE_HMD; @@ -121,3 +161,29 @@ qwerty_hmd_create(void) return qd; } + +// Device methods + +// clang-format off +void qwerty_press_left(struct qwerty_device *qd) { qd->left_pressed = true; } +void qwerty_release_left(struct qwerty_device *qd) { qd->left_pressed = false; } +void qwerty_press_right(struct qwerty_device *qd) { qd->right_pressed = true; } +void qwerty_release_right(struct qwerty_device *qd) { qd->right_pressed = false; } +void qwerty_press_forward(struct qwerty_device *qd) { qd->forward_pressed = true; } +void qwerty_release_forward(struct qwerty_device *qd) { qd->forward_pressed = false; } +void qwerty_press_backward(struct qwerty_device *qd) { qd->backward_pressed = true; } +void qwerty_release_backward(struct qwerty_device *qd) { qd->backward_pressed = false; } +void qwerty_press_up(struct qwerty_device *qd) { qd->up_pressed = true; } +void qwerty_release_up(struct qwerty_device *qd) { qd->up_pressed = false; } +void qwerty_press_down(struct qwerty_device *qd) { qd->down_pressed = true; } +void qwerty_release_down(struct qwerty_device *qd) { qd->down_pressed = false; } + +void qwerty_press_look_left(struct qwerty_device *qd) { qd->look_left_pressed = true; } +void qwerty_release_look_left(struct qwerty_device *qd) { qd->look_left_pressed = false; } +void qwerty_press_look_right(struct qwerty_device *qd) { qd->look_right_pressed = true; } +void qwerty_release_look_right(struct qwerty_device *qd) { qd->look_right_pressed = false; } +void qwerty_press_look_up(struct qwerty_device *qd) { qd->look_up_pressed = true; } +void qwerty_release_look_up(struct qwerty_device *qd) { qd->look_up_pressed = false; } +void qwerty_press_look_down(struct qwerty_device *qd) { qd->look_down_pressed = true; } +void qwerty_release_look_down(struct qwerty_device *qd) { qd->look_down_pressed = false; } +// clang-format on diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index d1b1b4933..bb77265ba 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -22,12 +22,36 @@ extern "C" { * @{ */ +//! Fake device that modifies its tracked pose through its methods. //! @implements xrt_device struct qwerty_device { struct xrt_device base; + struct xrt_pose pose; //!< Internal pose state + + float movement_speed; //!< In meters per frame + bool left_pressed; + bool right_pressed; + bool forward_pressed; + bool backward_pressed; + bool up_pressed; + bool down_pressed; + + float look_speed; //!< In radians per frame + bool look_left_pressed; + bool look_right_pressed; + bool look_up_pressed; + bool look_down_pressed; }; +/*! + * @name Qwerty Device + * @memberof qwerty_device + * qwerty_device public methods + * @{ + */ +//! @public @memberof qwerty_device + //! Cast to qwerty_device. Ensures returning a valid device or crashing. struct qwerty_device * qwerty_device(struct xrt_device *xd); @@ -36,6 +60,34 @@ qwerty_device(struct xrt_device *xd); struct qwerty_device * qwerty_hmd_create(void); +// clang-format off +void qwerty_press_left(struct qwerty_device *qd); +void qwerty_release_left(struct qwerty_device *qd); +void qwerty_press_right(struct qwerty_device *qd); +void qwerty_release_right(struct qwerty_device *qd); +void qwerty_press_forward(struct qwerty_device *qd); +void qwerty_release_forward(struct qwerty_device *qd); +void qwerty_press_backward(struct qwerty_device *qd); +void qwerty_release_backward(struct qwerty_device *qd); +void qwerty_press_up(struct qwerty_device *qd); +void qwerty_release_up(struct qwerty_device *qd); +void qwerty_press_down(struct qwerty_device *qd); +void qwerty_release_down(struct qwerty_device *qd); + +void qwerty_press_look_left(struct qwerty_device *qd); +void qwerty_release_look_left(struct qwerty_device *qd); +void qwerty_press_look_right(struct qwerty_device *qd); +void qwerty_release_look_right(struct qwerty_device *qd); +void qwerty_press_look_up(struct qwerty_device *qd); +void qwerty_release_look_up(struct qwerty_device *qd); +void qwerty_press_look_down(struct qwerty_device *qd); +void qwerty_release_look_down(struct qwerty_device *qd); +// clang-format on + +/*! + * @} + */ + /*! * @} */ diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index 4b1308ce7..3e9cf2e93 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -7,12 +7,76 @@ * @ingroup drv_qwerty */ +// @note: This file will process more than one device, that's +// why some comments reference multiple devices + +#include "qwerty_device.h" #include "xrt/xrt_device.h" #include +static void +find_qwerty_devices(struct xrt_device **xdevs, + size_t num_xdevs, + struct xrt_device **xd_hmd) +{ + for (size_t i = 0; i < num_xdevs; i++) { + if (xdevs[i] == NULL) { + continue; + } + + if (strcmp(xdevs[i]->str, QWERTY_HMD_STR) == 0) { + *xd_hmd = xdevs[i]; + } + } +} + void qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event event) { - if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_w) - printf("W pressed and xdevs[0] = %s\n", xdevs[0]->str); + static struct xrt_device *xd_hmd = NULL; + + // We can cache the devices as they don't get destroyed during runtime + static bool cached = false; + if (!cached) { + find_qwerty_devices(xdevs, num_xdevs, &xd_hmd); + cached = true; + } + + bool using_qhmd = xd_hmd != NULL; + struct qwerty_device *qd_hmd = using_qhmd ? qwerty_device(xd_hmd) : NULL; + + if (!qd_hmd) { + return; + } + + // clang-format off + + // Determine focused device + struct qwerty_device *qdev = qd_hmd; + + // WASDQE Movement + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_a) qwerty_press_left(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_a) qwerty_release_left(qdev); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_d) qwerty_press_right(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_d) qwerty_release_right(qdev); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_w) qwerty_press_forward(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_w) qwerty_release_forward(qdev); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_s) qwerty_press_backward(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_s) qwerty_release_backward(qdev); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_e) qwerty_press_up(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_e) qwerty_release_up(qdev); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_q) qwerty_press_down(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_q) qwerty_release_down(qdev); + + // Arrow keys rotation + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_LEFT) qwerty_press_look_left(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_LEFT) qwerty_release_look_left(qdev); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_RIGHT) qwerty_press_look_right(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_RIGHT) qwerty_release_look_right(qdev); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_UP) qwerty_press_look_up(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_UP) qwerty_release_look_up(qdev); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_DOWN) qwerty_press_look_down(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_DOWN) qwerty_release_look_down(qdev); + + // clang-format on } From 183ee4f4ee8ade81c34090c39160b4e707c4279b Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 15:14:54 -0300 Subject: [PATCH 219/883] d/qwerty: Implement mouse input and sprinting --- src/xrt/drivers/qwerty/qwerty_device.c | 41 +++++++++++++++++++++++--- src/xrt/drivers/qwerty/qwerty_device.h | 19 ++++++++++++ src/xrt/drivers/qwerty/qwerty_sdl.c | 22 ++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 2964afbb9..3fbc730aa 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -10,7 +10,6 @@ #include "qwerty_device.h" #include "util/u_device.h" - #include "util/u_distortion_mesh.h" #include "math/m_api.h" @@ -23,6 +22,8 @@ #define QWERTY_HMD_INITIAL_MOVEMENT_SPEED 0.002f // in meters per frame #define QWERTY_HMD_INITIAL_LOOK_SPEED 0.02f // in radians per frame +#define MOVEMENT_SPEED_STEP 1.25f // Multiplier for how fast will mov speed increase/decrease +#define SPRINT_STEPS 5 // Amount of MOVEMENT_SPEED_STEPs to increase when sprinting // clang-format off // Value copied from u_device_setup_tracking_origins. @@ -60,13 +61,15 @@ qwerty_get_tracked_pose(struct xrt_device *xd, // Position + float sprint_boost = qd->sprint_pressed ? powf(MOVEMENT_SPEED_STEP, SPRINT_STEPS) : 1; + float mov_speed = qd->movement_speed * sprint_boost; struct xrt_vec3 pos_delta = { - qd->movement_speed * (qd->right_pressed - qd->left_pressed), + mov_speed * (qd->right_pressed - qd->left_pressed), 0, // Up/down movement will be relative to base space - qd->movement_speed * (qd->backward_pressed - qd->forward_pressed), + mov_speed * (qd->backward_pressed - qd->forward_pressed), }; math_quat_rotate_vec3(&qd->pose.orientation, &pos_delta, &pos_delta); - pos_delta.y += qd->movement_speed * (qd->up_pressed - qd->down_pressed); + pos_delta.y += mov_speed * (qd->up_pressed - qd->down_pressed); math_vec3_accum(&pos_delta, &qd->pose.position); // Orientation @@ -75,6 +78,12 @@ qwerty_get_tracked_pose(struct xrt_device *xd, float y_look_speed = qd->look_speed * (qd->look_left_pressed - qd->look_right_pressed); float x_look_speed = qd->look_speed * (qd->look_up_pressed - qd->look_down_pressed); + // View rotation caused by mouse + y_look_speed += qd->yaw_delta; + x_look_speed += qd->pitch_delta; + qd->yaw_delta = 0; + qd->pitch_delta = 0; + struct xrt_quat x_rotation, y_rotation; struct xrt_vec3 x_axis = {1, 0, 0}, y_axis = {0, 1, 0}; math_quat_from_angle_vector(x_look_speed, &x_axis, &x_rotation); @@ -187,3 +196,27 @@ void qwerty_release_look_up(struct qwerty_device *qd) { qd->look_up_pressed = fa void qwerty_press_look_down(struct qwerty_device *qd) { qd->look_down_pressed = true; } void qwerty_release_look_down(struct qwerty_device *qd) { qd->look_down_pressed = false; } // clang-format on + +void +qwerty_press_sprint(struct qwerty_device *qd) +{ + qd->sprint_pressed = true; +} +void +qwerty_release_sprint(struct qwerty_device *qd) +{ + qd->sprint_pressed = false; +} + +void +qwerty_add_look_delta(struct qwerty_device *qd, float yaw, float pitch) +{ + qd->yaw_delta += yaw * qd->look_speed; + qd->pitch_delta += pitch * qd->look_speed; +} + +void +qwerty_change_movement_speed(struct qwerty_device *qd, float steps) +{ + qd->movement_speed *= powf(MOVEMENT_SPEED_STEP, steps); +} diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index bb77265ba..2caa814de 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -42,6 +42,10 @@ struct qwerty_device bool look_right_pressed; bool look_up_pressed; bool look_down_pressed; + + bool sprint_pressed; //!< Movement speed boost + float yaw_delta; //!< How much extra yaw to add for the next pose. Then reset to 0. + float pitch_delta; //!< Similar to `yaw_delta` }; /*! @@ -84,6 +88,21 @@ void qwerty_press_look_down(struct qwerty_device *qd); void qwerty_release_look_down(struct qwerty_device *qd); // clang-format on +//! Momentarily increase `movement_speed` until `qwerty_release_sprint()` +void +qwerty_press_sprint(struct qwerty_device *qd); + +void +qwerty_release_sprint(struct qwerty_device *qd); + +//! Add yaw and pitch movement for the next frame +void +qwerty_add_look_delta(struct qwerty_device *qd, float yaw, float pitch); + +//! Change movement speed in exponential steps (usually integers, but any float allowed) +void +qwerty_change_movement_speed(struct qwerty_device *qd, float steps); + /*! * @} */ diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index 3e9cf2e93..fbe751711 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -14,6 +14,9 @@ #include "xrt/xrt_device.h" #include +// Amount of look_speed units a mouse delta of 1px in screen space will rotate the device +#define SENSITIVITY 0.1f + static void find_qwerty_devices(struct xrt_device **xdevs, size_t num_xdevs, @@ -78,5 +81,24 @@ qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event even if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_DOWN) qwerty_press_look_down(qdev); if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_DOWN) qwerty_release_look_down(qdev); + // Movement speed + if (event.type == SDL_MOUSEWHEEL) qwerty_change_movement_speed(qdev, event.wheel.y); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_KP_PLUS) qwerty_change_movement_speed(qdev, 1); + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_KP_MINUS) qwerty_change_movement_speed(qdev, -1); + + // Sprinting + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_LSHIFT) qwerty_press_sprint(qdev); + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_LSHIFT) qwerty_release_sprint(qdev); + + // Mouse rotation + if (event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_RIGHT) { + SDL_SetRelativeMouseMode(false); + } + if (event.type == SDL_MOUSEMOTION && event.motion.state & SDL_BUTTON_RMASK) { + SDL_SetRelativeMouseMode(true); + float yaw = -event.motion.xrel * SENSITIVITY; + float pitch = -event.motion.yrel * SENSITIVITY; + qwerty_add_look_delta(qdev, yaw, pitch); + } // clang-format on } From e13a6fc2fde1c0a2e3a5cc0626926162eeeb0f13 Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 15:33:37 -0300 Subject: [PATCH 220/883] d/qwerty: Add QWERTY_ENABLE environment variable --- src/xrt/drivers/qwerty/qwerty_prober.c | 9 +++++++++ src/xrt/targets/openxr/oxr_sdl2_hack.c | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/qwerty/qwerty_prober.c b/src/xrt/drivers/qwerty/qwerty_prober.c index 136dc5d1f..09b4053f2 100644 --- a/src/xrt/drivers/qwerty/qwerty_prober.c +++ b/src/xrt/drivers/qwerty/qwerty_prober.c @@ -9,8 +9,12 @@ #include "qwerty_device.h" #include "util/u_misc.h" +#include "util/u_debug.h" #include "xrt/xrt_prober.h" +// Driver disabled by default for being experimental +DEBUG_GET_ONCE_BOOL_OPTION(qwerty_enable, "QWERTY_ENABLE", false) + struct qwerty_prober { struct xrt_auto_prober base; @@ -36,6 +40,11 @@ qwerty_prober_autoprobe(struct xrt_auto_prober *xap, struct xrt_prober *xp, struct xrt_device **out_xdevs) { + bool qwerty_enabled = debug_get_bool_option_qwerty_enable(); + if (!qwerty_enabled) { + return 0; + } + bool hmd_wanted = !no_hmds; // Hopefully easier to reason about struct qwerty_device *qhmd = qwerty_hmd_create(); diff --git a/src/xrt/targets/openxr/oxr_sdl2_hack.c b/src/xrt/targets/openxr/oxr_sdl2_hack.c index c1a702a40..fb6981084 100644 --- a/src/xrt/targets/openxr/oxr_sdl2_hack.c +++ b/src/xrt/targets/openxr/oxr_sdl2_hack.c @@ -46,6 +46,7 @@ oxr_sdl2_hack_stop(void **hack) #include DEBUG_GET_ONCE_BOOL_OPTION(gui, "OXR_DEBUG_GUI", false) +DEBUG_GET_ONCE_BOOL_OPTION(qwerty_enable, "QWERTY_ENABLE", false) /*! @@ -148,7 +149,7 @@ sdl2_loop(struct sdl2_program *p) ImPlot_SetCurrentContext(plot_ctx); // Setup qwerty driver usage - bool qwerty_enabled = true; // @todo: get from an env var + bool qwerty_enabled = debug_get_bool_option_qwerty_enable(); // Main loop struct gui_imgui gui = {0}; From 62e05f267aac7d4578f00bace886718691fad0ee Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 16:01:58 -0300 Subject: [PATCH 221/883] d/qwerty: Add still qwerty controllers By making an initial inheritance hierarchy, thus separating qwerty_hmd from qwerty_controller, both inheriting from qwerty_device --- src/xrt/drivers/qwerty/qwerty_device.c | 68 +++++++++++++++++++++++--- src/xrt/drivers/qwerty/qwerty_device.h | 52 ++++++++++++++++++-- src/xrt/drivers/qwerty/qwerty_prober.c | 14 ++++-- 3 files changed, 121 insertions(+), 13 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 3fbc730aa..7dc3051e6 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -22,14 +22,24 @@ #define QWERTY_HMD_INITIAL_MOVEMENT_SPEED 0.002f // in meters per frame #define QWERTY_HMD_INITIAL_LOOK_SPEED 0.02f // in radians per frame +#define QWERTY_CONTROLLER_INITIAL_MOVEMENT_SPEED 0.005f +#define QWERTY_CONTROLLER_INITIAL_LOOK_SPEED 0.05f #define MOVEMENT_SPEED_STEP 1.25f // Multiplier for how fast will mov speed increase/decrease #define SPRINT_STEPS 5 // Amount of MOVEMENT_SPEED_STEPs to increase when sprinting // clang-format off -// Value copied from u_device_setup_tracking_origins. +// Values copied from u_device_setup_tracking_origins. #define QWERTY_HMD_INITIAL_POS (struct xrt_vec3){0, 1.6f, 0} +#define QWERTY_CONTROLLER_INITIAL_POS(is_left) (struct xrt_vec3){(is_left) ? -0.2f : 0.2f, -0.3f, -0.5f} // clang-format on +// Indices for fake controller input components +#define QWERTY_SELECT 0 +#define QWERTY_MENU 1 +#define QWERTY_GRIP 2 +#define QWERTY_AIM 3 +#define QWERTY_VIBRATION 0 + // xrt_device functions struct qwerty_device * @@ -46,6 +56,12 @@ qwerty_update_inputs(struct xrt_device *xd) return; } +static void +qwerty_set_output(struct xrt_device *xd, enum xrt_output_name name, union xrt_output_value *value) +{ + return; +} + static void qwerty_get_tracked_pose(struct xrt_device *xd, enum xrt_input_name name, @@ -54,7 +70,7 @@ qwerty_get_tracked_pose(struct xrt_device *xd, { struct qwerty_device *qd = qwerty_device(xd); - if (name != XRT_INPUT_GENERIC_HEAD_POSE) { + if (name != XRT_INPUT_GENERIC_HEAD_POSE && name != XRT_INPUT_SIMPLE_GRIP_POSE) { printf("Unexpected input name = 0x%04X\n", name >> 8); // @todo: use u_logging.h return; } @@ -119,14 +135,15 @@ qwerty_destroy(struct xrt_device *xd) u_device_free(xd); } -struct qwerty_device * +struct qwerty_hmd * qwerty_hmd_create(void) { enum u_device_alloc_flags flags = U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE; size_t num_inputs = 1, num_outputs = 0; - struct qwerty_device *qd = U_DEVICE_ALLOCATE(struct qwerty_device, flags, num_inputs, num_outputs); - assert(qd); + struct qwerty_hmd *qh = U_DEVICE_ALLOCATE(struct qwerty_hmd, flags, num_inputs, num_outputs); + assert(qh); + struct qwerty_device *qd = &qh->base; qd->pose.orientation.w = 1.f; qd->pose.position = QWERTY_HMD_INITIAL_POS; qd->movement_speed = QWERTY_HMD_INITIAL_MOVEMENT_SPEED; @@ -168,7 +185,46 @@ qwerty_hmd_create(void) xd->destroy = qwerty_destroy; u_distortion_mesh_set_none(xd); // Fill in xd->compute_distortion() - return qd; + return qh; +} + +struct qwerty_controller * +qwerty_controller_create(bool is_left, struct qwerty_hmd *qhmd) +{ + struct qwerty_controller *qc = U_DEVICE_ALLOCATE(struct qwerty_controller, U_DEVICE_ALLOC_TRACKING_NONE, 4, 1); + assert(qc); + + struct qwerty_device *qd = &qc->base; + qd->pose.orientation.w = 1.f; + qd->pose.position = QWERTY_CONTROLLER_INITIAL_POS(is_left); + qd->movement_speed = QWERTY_CONTROLLER_INITIAL_MOVEMENT_SPEED; + qd->look_speed = QWERTY_CONTROLLER_INITIAL_LOOK_SPEED; + + struct xrt_device *xd = &qd->base; + + xd->name = XRT_DEVICE_SIMPLE_CONTROLLER; + xd->device_type = is_left ? XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER : XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER; + + char *controller_name = is_left ? QWERTY_LEFT_STR : QWERTY_RIGHT_STR; + snprintf(xd->str, XRT_DEVICE_NAME_LEN, "%s", controller_name); + snprintf(xd->serial, XRT_DEVICE_NAME_LEN, "%s", controller_name); + + xd->tracking_origin->type = XRT_TRACKING_TYPE_OTHER; + char *tracker_name = is_left ? QWERTY_LEFT_TRACKER_STR : QWERTY_RIGHT_TRACKER_STR; + snprintf(xd->tracking_origin->name, XRT_TRACKING_NAME_LEN, "%s", tracker_name); + + xd->inputs[QWERTY_SELECT].name = XRT_INPUT_SIMPLE_SELECT_CLICK; + xd->inputs[QWERTY_MENU].name = XRT_INPUT_SIMPLE_MENU_CLICK; + xd->inputs[QWERTY_GRIP].name = XRT_INPUT_SIMPLE_GRIP_POSE; + xd->inputs[QWERTY_AIM].name = XRT_INPUT_SIMPLE_AIM_POSE; // @todo: aim input not implemented + xd->outputs[QWERTY_VIBRATION].name = XRT_OUTPUT_NAME_SIMPLE_VIBRATION; + + xd->update_inputs = qwerty_update_inputs; + xd->get_tracked_pose = qwerty_get_tracked_pose; + xd->set_output = qwerty_set_output; + xd->destroy = qwerty_destroy; + + return qc; } // Device methods diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index 2caa814de..3a1f931da 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -12,6 +12,10 @@ #define QWERTY_HMD_STR "Qwerty HMD" #define QWERTY_HMD_TRACKER_STR QWERTY_HMD_STR " Tracker" +#define QWERTY_LEFT_STR "Qwerty Left Controller" +#define QWERTY_LEFT_TRACKER_STR QWERTY_LEFT_STR " Tracker" +#define QWERTY_RIGHT_STR "Qwerty Right Controller" +#define QWERTY_RIGHT_TRACKER_STR QWERTY_RIGHT_STR " Tracker" #ifdef __cplusplus extern "C" { @@ -48,6 +52,18 @@ struct qwerty_device float pitch_delta; //!< Similar to `yaw_delta` }; +//! @implements qwerty_device +struct qwerty_hmd +{ + struct qwerty_device base; +}; + +//! @implements qwerty_device +struct qwerty_controller +{ + struct qwerty_device base; +}; + /*! * @name Qwerty Device * @memberof qwerty_device @@ -60,10 +76,6 @@ struct qwerty_device struct qwerty_device * qwerty_device(struct xrt_device *xd); -//! Create qwerty_hmd. Crash on failure. -struct qwerty_device * -qwerty_hmd_create(void); - // clang-format off void qwerty_press_left(struct qwerty_device *qd); void qwerty_release_left(struct qwerty_device *qd); @@ -103,6 +115,38 @@ qwerty_add_look_delta(struct qwerty_device *qd, float yaw, float pitch); void qwerty_change_movement_speed(struct qwerty_device *qd, float steps); +/*! + * @} + */ + +/*! + * @name Qwerty HMD + * @memberof qwerty_hmd + * qwerty_hmd public methods + * @{ + */ +//! @public @memberof qwerty_hmd + +//! Create qwerty_hmd. Crash on failure. +struct qwerty_hmd * +qwerty_hmd_create(void); + +/*! + * @} + */ + +/*! + * @name Qwerty Controller + * @memberof qwerty_controller + * qwerty_controller public methods + * @{ + */ +//! @public @memberof qwerty_controller + +//! Create qwerty_controller. Crash on failure. +struct qwerty_controller * +qwerty_controller_create(bool is_left, struct qwerty_hmd *qhmd); + /*! * @} */ diff --git a/src/xrt/drivers/qwerty/qwerty_prober.c b/src/xrt/drivers/qwerty/qwerty_prober.c index 09b4053f2..509ceb23f 100644 --- a/src/xrt/drivers/qwerty/qwerty_prober.c +++ b/src/xrt/drivers/qwerty/qwerty_prober.c @@ -47,13 +47,21 @@ qwerty_prober_autoprobe(struct xrt_auto_prober *xap, bool hmd_wanted = !no_hmds; // Hopefully easier to reason about - struct qwerty_device *qhmd = qwerty_hmd_create(); + struct qwerty_hmd *qhmd = hmd_wanted ? qwerty_hmd_create() : NULL; + struct qwerty_controller *qleft = qwerty_controller_create(true, qhmd); + struct qwerty_controller *qright = qwerty_controller_create(false, qhmd); + + struct xrt_device *xd_hmd = &qhmd->base.base; + struct xrt_device *xd_left = &qleft->base.base; + struct xrt_device *xd_right = &qright->base.base; if (hmd_wanted) { - out_xdevs[0] = &qhmd->base; + out_xdevs[0] = xd_hmd; } + out_xdevs[1 - !hmd_wanted] = xd_left; + out_xdevs[2 - !hmd_wanted] = xd_right; - int num_qwerty_devices = hmd_wanted; + int num_qwerty_devices = hmd_wanted + 2; return num_qwerty_devices; } From f8f14a1d9e40f5b2feb06f689ed6bf1e75d9c20f Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 16:30:14 -0300 Subject: [PATCH 222/883] d/qwerty: Move left/right controllers with CTRL/ALT In qwerty_sdl.c the u_device_assign_xdev_roles function is used for knowing which devices are being used by the user. These could be other physical devices. And as such the idea of a default focused device is introduced and depends upon which devices the user already has. With this change qwerty devices should be properly introduced to fill any device the user may not have. --- src/xrt/drivers/qwerty/qwerty_device.c | 34 +++++++++ src/xrt/drivers/qwerty/qwerty_device.h | 12 ++++ src/xrt/drivers/qwerty/qwerty_interface.h | 5 ++ src/xrt/drivers/qwerty/qwerty_sdl.c | 85 ++++++++++++++++++++--- 4 files changed, 125 insertions(+), 11 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 7dc3051e6..84009da03 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -50,6 +50,22 @@ qwerty_device(struct xrt_device *xd) return qd; } +struct qwerty_hmd * +qwerty_hmd(struct xrt_device *xd) +{ + struct qwerty_hmd *qh = (struct qwerty_hmd *)xd; + assert(qh); + return qh; +} + +struct qwerty_controller * +qwerty_controller(struct xrt_device *xd) +{ + struct qwerty_controller *qc = (struct qwerty_controller *)xd; + assert(qc); + return qc; +} + static void qwerty_update_inputs(struct xrt_device *xd) { @@ -276,3 +292,21 @@ qwerty_change_movement_speed(struct qwerty_device *qd, float steps) { qd->movement_speed *= powf(MOVEMENT_SPEED_STEP, steps); } + +void +qwerty_release_all(struct qwerty_device *qd) +{ + qd->left_pressed = false; + qd->right_pressed = false; + qd->forward_pressed = false; + qd->backward_pressed = false; + qd->up_pressed = false; + qd->down_pressed = false; + qd->look_left_pressed = false; + qd->look_right_pressed = false; + qd->look_up_pressed = false; + qd->look_down_pressed = false; + qd->sprint_pressed = false; + qd->yaw_delta = 0; + qd->pitch_delta = 0; +} diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index 3a1f931da..ce1cc3387 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -115,6 +115,10 @@ qwerty_add_look_delta(struct qwerty_device *qd, float yaw, float pitch); void qwerty_change_movement_speed(struct qwerty_device *qd, float steps); +//! Release all movement input +void +qwerty_release_all(struct qwerty_device *qd); + /*! * @} */ @@ -131,6 +135,10 @@ qwerty_change_movement_speed(struct qwerty_device *qd, float steps); struct qwerty_hmd * qwerty_hmd_create(void); +//! Cast to qwerty_hmd. Ensures returning a valid HMD or crashing. +struct qwerty_hmd * +qwerty_hmd(struct xrt_device *xd); + /*! * @} */ @@ -147,6 +155,10 @@ qwerty_hmd_create(void); struct qwerty_controller * qwerty_controller_create(bool is_left, struct qwerty_hmd *qhmd); +//! Cast to qwerty_controller. Ensures returning a valid controller or crashing. +struct qwerty_controller * +qwerty_controller(struct xrt_device *xd); + /*! * @} */ diff --git a/src/xrt/drivers/qwerty/qwerty_interface.h b/src/xrt/drivers/qwerty/qwerty_interface.h index af7096b07..eff6cd732 100644 --- a/src/xrt/drivers/qwerty/qwerty_interface.h +++ b/src/xrt/drivers/qwerty/qwerty_interface.h @@ -30,6 +30,11 @@ qwerty_create_auto_prober(void); /*! * Process an SDL_Event (like a key press) and dispatches a suitable action * to the appropriate qwerty_device. + * + * @note A qwerty_controller might not be in use (for example if you have + * physical controllers connected), though its memory will be modified by these + * events regardless. A qwerty_hmd not in use will not be modified as it never + * gets created. */ void qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event event); diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index fbe751711..44a9090c0 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -7,10 +7,8 @@ * @ingroup drv_qwerty */ -// @note: This file will process more than one device, that's -// why some comments reference multiple devices - #include "qwerty_device.h" +#include "util/u_device.h" #include "xrt/xrt_device.h" #include @@ -20,7 +18,9 @@ static void find_qwerty_devices(struct xrt_device **xdevs, size_t num_xdevs, - struct xrt_device **xd_hmd) + struct xrt_device **xd_hmd, + struct xrt_device **xd_left, + struct xrt_device **xd_right) { for (size_t i = 0; i < num_xdevs; i++) { if (xdevs[i] == NULL) { @@ -29,33 +29,96 @@ find_qwerty_devices(struct xrt_device **xdevs, if (strcmp(xdevs[i]->str, QWERTY_HMD_STR) == 0) { *xd_hmd = xdevs[i]; + } else if (strcmp(xdevs[i]->str, QWERTY_LEFT_STR) == 0) { + *xd_left = xdevs[i]; + } else if (strcmp(xdevs[i]->str, QWERTY_RIGHT_STR) == 0) { + *xd_right = xdevs[i]; } } } +// Determines the default qwerty device based on which devices are in use +struct qwerty_device * +default_qwerty_device(struct xrt_device **xdevs, + size_t num_xdevs, + struct xrt_device *xd_hmd, + struct xrt_device *xd_left, + struct xrt_device *xd_right) +{ + int head, left, right; + head = left = right = XRT_DEVICE_ROLE_UNASSIGNED; + u_device_assign_xdev_roles(xdevs, num_xdevs, &head, &left, &right); + + struct qwerty_device *default_qdev = NULL; + if (xdevs[head] == xd_hmd) { + default_qdev = qwerty_device(xd_hmd); + } else if (xdevs[right] == xd_right) { + default_qdev = qwerty_device(xd_right); + } else if (xdevs[left] == xd_left) { + default_qdev = qwerty_device(xd_left); + } else { // Even here, xd_right is allocated and so we can modify it + default_qdev = qwerty_device(xd_right); + } + + return default_qdev; +} + void qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event event) { static struct xrt_device *xd_hmd = NULL; + static struct xrt_device *xd_left = NULL; + static struct xrt_device *xd_right = NULL; + + static bool alt_pressed = false; + static bool ctrl_pressed = false; + + // Default focused device: the one focused when CTRL and ALT are not pressed + static struct qwerty_device *default_qdev; // We can cache the devices as they don't get destroyed during runtime static bool cached = false; if (!cached) { - find_qwerty_devices(xdevs, num_xdevs, &xd_hmd); + find_qwerty_devices(xdevs, num_xdevs, &xd_hmd, &xd_left, &xd_right); + default_qdev = default_qwerty_device(xdevs, num_xdevs, xd_hmd, xd_left, xd_right); cached = true; } - bool using_qhmd = xd_hmd != NULL; - struct qwerty_device *qd_hmd = using_qhmd ? qwerty_device(xd_hmd) : NULL; + // Initialize different views of the same pointers. - if (!qd_hmd) { - return; - } + struct qwerty_controller *qleft = qwerty_controller(xd_left); + struct qwerty_device *qd_left = &qleft->base; + + struct qwerty_controller *qright = qwerty_controller(xd_right); + struct qwerty_device *qd_right = &qright->base; + + bool using_qhmd = xd_hmd != NULL; + struct qwerty_hmd *qhmd = using_qhmd ? qwerty_hmd(xd_hmd) : NULL; + struct qwerty_device *qd_hmd = using_qhmd ? &qhmd->base : NULL; // clang-format off + // CTRL/ALT keys logic + bool alt_down = event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_LALT; + bool alt_up = event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_LALT; + bool ctrl_down = event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_LCTRL; + bool ctrl_up = event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_LCTRL; + if (alt_down) alt_pressed = true; + if (alt_up) alt_pressed = false; + if (ctrl_down) ctrl_pressed = true; + if (ctrl_up) ctrl_pressed = false; + + bool change_focus = alt_down || alt_up || ctrl_down || ctrl_up; + if (change_focus) { + if (using_qhmd) qwerty_release_all(qd_hmd); + qwerty_release_all(qd_right); + qwerty_release_all(qd_left); + } // Determine focused device - struct qwerty_device *qdev = qd_hmd; + struct qwerty_device *qdev; + if (ctrl_pressed) qdev = qd_left; + else if (alt_pressed) qdev = qd_right; + else qdev = default_qdev; // WASDQE Movement if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_a) qwerty_press_left(qdev); From a1b70c746bb178ab0bdd01295cd185f463c193a3 Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 16:56:52 -0300 Subject: [PATCH 223/883] d/qwerty: Add qwerty_system for driver management --- src/xrt/drivers/qwerty/qwerty_device.c | 76 +++++++++++++++++++++++++- src/xrt/drivers/qwerty/qwerty_device.h | 33 ++++++++++- src/xrt/drivers/qwerty/qwerty_prober.c | 2 + src/xrt/drivers/qwerty/qwerty_sdl.c | 59 ++++++++++---------- 4 files changed, 136 insertions(+), 34 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 84009da03..ad01dedde 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -40,13 +40,27 @@ #define QWERTY_AIM 3 #define QWERTY_VIBRATION 0 +static void +qwerty_system_remove(struct qwerty_system *qs, struct qwerty_device *qd); + +static void +qwerty_system_destroy(struct qwerty_system *qs); + +// Compare any two pointers without verbose casts +static inline bool +eq(void *a, void *b) +{ + return a == b; +} + // xrt_device functions struct qwerty_device * qwerty_device(struct xrt_device *xd) { struct qwerty_device *qd = (struct qwerty_device *)xd; - assert(qd); + bool is_qwerty_device = eq(qd, qd->sys->hmd) || eq(qd, qd->sys->lctrl) || eq(qd, qd->sys->rctrl); + assert(is_qwerty_device); return qd; } @@ -54,7 +68,8 @@ struct qwerty_hmd * qwerty_hmd(struct xrt_device *xd) { struct qwerty_hmd *qh = (struct qwerty_hmd *)xd; - assert(qh); + bool is_qwerty_hmd = eq(qh, qh->base.sys->hmd); + assert(is_qwerty_hmd); return qh; } @@ -62,7 +77,8 @@ struct qwerty_controller * qwerty_controller(struct xrt_device *xd) { struct qwerty_controller *qc = (struct qwerty_controller *)xd; - assert(qc); + bool is_qwerty_controller = eq(qc, qc->base.sys->lctrl) || eq(qc, qc->base.sys->rctrl); + assert(is_qwerty_controller); return qc; } @@ -148,6 +164,8 @@ qwerty_get_view_pose(struct xrt_device *xd, static void qwerty_destroy(struct xrt_device *xd) { + struct qwerty_device *qd = qwerty_device(xd); + qwerty_system_remove(qd->sys, qd); u_device_free(xd); } @@ -243,6 +261,58 @@ qwerty_controller_create(bool is_left, struct qwerty_hmd *qhmd) return qc; } +// System methods + +struct qwerty_system * +qwerty_system_create(struct qwerty_hmd *qhmd, + struct qwerty_controller *qleft, + struct qwerty_controller *qright) +{ + assert(qleft && "Cannot create a qwerty system when Left controller is NULL"); + assert(qright && "Cannot create a qwerty system when Right controller is NULL"); + + struct qwerty_system *qs = U_TYPED_CALLOC(struct qwerty_system); + qs->hmd = qhmd; + qs->lctrl = qleft; + qs->rctrl = qright; + qs->process_keys = true; + + if (qhmd) { + qhmd->base.sys = qs; + } + qleft->base.sys = qs; + qright->base.sys = qs; + + return qs; +} + +static void +qwerty_system_remove(struct qwerty_system *qs, struct qwerty_device *qd) +{ + if (eq(qd, qs->hmd)) { + qs->hmd = NULL; + } else if (eq(qd, qs->lctrl)) { + qs->lctrl = NULL; + } else if (eq(qd, qs->rctrl)) { + qs->rctrl = NULL; + } else { + assert(false && "Trying to remove a device that is not in the qwerty system"); + } + + bool all_devices_clean = !qs->hmd && !qs->lctrl && !qs->rctrl; + if (all_devices_clean) { + qwerty_system_destroy(qs); + } +} + +static void +qwerty_system_destroy(struct qwerty_system *qs) +{ + bool all_devices_clean = !qs->hmd && !qs->lctrl && !qs->rctrl; + assert(all_devices_clean && "Tried to destroy a qwerty_system without destroying its devices before."); + free(qs); +} + // Device methods // clang-format off diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index ce1cc3387..76a5f641c 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -26,12 +26,22 @@ extern "C" { * @{ */ +//! Container of qwerty devices and driver properties. +struct qwerty_system +{ + struct qwerty_hmd *hmd; //!< Can be NULL + struct qwerty_controller *lctrl; //!< Cannot be NULL + struct qwerty_controller *rctrl; //!< Cannot be NULL + bool process_keys; //!< If false disable keyboard and mouse input +}; + //! Fake device that modifies its tracked pose through its methods. //! @implements xrt_device struct qwerty_device { struct xrt_device base; - struct xrt_pose pose; //!< Internal pose state + struct xrt_pose pose; //!< Internal pose state + struct qwerty_system *sys; //!< Reference to the system this device is in. float movement_speed; //!< In meters per frame bool left_pressed; @@ -48,8 +58,8 @@ struct qwerty_device bool look_down_pressed; bool sprint_pressed; //!< Movement speed boost - float yaw_delta; //!< How much extra yaw to add for the next pose. Then reset to 0. - float pitch_delta; //!< Similar to `yaw_delta` + float yaw_delta; //!< How much extra yaw to add for the next pose. Then reset to 0. + float pitch_delta; //!< Similar to `yaw_delta` }; //! @implements qwerty_device @@ -64,6 +74,23 @@ struct qwerty_controller struct qwerty_device base; }; +/*! + * @name Qwerty System + * @memberof qwerty_system + * qwerty_system public methods + * @{ + */ +//! @public @memberof qwerty_system + +struct qwerty_system * +qwerty_system_create(struct qwerty_hmd *qhmd, + struct qwerty_controller *qleft, + struct qwerty_controller *qright); + +/*! + * @} + */ + /*! * @name Qwerty Device * @memberof qwerty_device diff --git a/src/xrt/drivers/qwerty/qwerty_prober.c b/src/xrt/drivers/qwerty/qwerty_prober.c index 509ceb23f..37b3c28f6 100644 --- a/src/xrt/drivers/qwerty/qwerty_prober.c +++ b/src/xrt/drivers/qwerty/qwerty_prober.c @@ -51,6 +51,8 @@ qwerty_prober_autoprobe(struct xrt_auto_prober *xap, struct qwerty_controller *qleft = qwerty_controller_create(true, qhmd); struct qwerty_controller *qright = qwerty_controller_create(false, qhmd); + qwerty_system_create(qhmd, qleft, qright); + struct xrt_device *xd_hmd = &qhmd->base.base; struct xrt_device *xd_left = &qleft->base.base; struct xrt_device *xd_right = &qright->base.base; diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index 44a9090c0..2fc6ebe08 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -11,44 +11,45 @@ #include "util/u_device.h" #include "xrt/xrt_device.h" #include +#include // Amount of look_speed units a mouse delta of 1px in screen space will rotate the device #define SENSITIVITY 0.1f -static void -find_qwerty_devices(struct xrt_device **xdevs, - size_t num_xdevs, - struct xrt_device **xd_hmd, - struct xrt_device **xd_left, - struct xrt_device **xd_right) +static struct qwerty_system * +find_qwerty_system(struct xrt_device **xdevs, size_t num_xdevs) { + struct xrt_device *xdev = NULL; for (size_t i = 0; i < num_xdevs; i++) { if (xdevs[i] == NULL) { continue; } - - if (strcmp(xdevs[i]->str, QWERTY_HMD_STR) == 0) { - *xd_hmd = xdevs[i]; - } else if (strcmp(xdevs[i]->str, QWERTY_LEFT_STR) == 0) { - *xd_left = xdevs[i]; - } else if (strcmp(xdevs[i]->str, QWERTY_RIGHT_STR) == 0) { - *xd_right = xdevs[i]; + if (strcmp(xdevs[i]->str, QWERTY_HMD_STR) == 0 || strcmp(xdevs[i]->str, QWERTY_LEFT_STR) == 0 || + strcmp(xdevs[i]->str, QWERTY_RIGHT_STR) == 0) { + xdev = xdevs[i]; + break; } } + + assert(xdev != NULL && "There is no device in xdevs with the name of a qwerty device"); + struct qwerty_device *qdev = qwerty_device(xdev); + struct qwerty_system *qsys = qdev->sys; + assert(qsys != NULL && "The qwerty_system of a qwerty_device was null"); + return qsys; } // Determines the default qwerty device based on which devices are in use -struct qwerty_device * -default_qwerty_device(struct xrt_device **xdevs, - size_t num_xdevs, - struct xrt_device *xd_hmd, - struct xrt_device *xd_left, - struct xrt_device *xd_right) +static struct qwerty_device * +default_qwerty_device(struct xrt_device **xdevs, size_t num_xdevs, struct qwerty_system *qsys) { int head, left, right; head = left = right = XRT_DEVICE_ROLE_UNASSIGNED; u_device_assign_xdev_roles(xdevs, num_xdevs, &head, &left, &right); + struct xrt_device *xd_hmd = qsys->hmd ? &qsys->hmd->base.base : NULL; + struct xrt_device *xd_left = &qsys->lctrl->base.base; + struct xrt_device *xd_right = &qsys->rctrl->base.base; + struct qwerty_device *default_qdev = NULL; if (xdevs[head] == xd_hmd) { default_qdev = qwerty_device(xd_hmd); @@ -66,9 +67,7 @@ default_qwerty_device(struct xrt_device **xdevs, void qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event event) { - static struct xrt_device *xd_hmd = NULL; - static struct xrt_device *xd_left = NULL; - static struct xrt_device *xd_right = NULL; + static struct qwerty_system *qsys = NULL; static bool alt_pressed = false; static bool ctrl_pressed = false; @@ -79,21 +78,25 @@ qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event even // We can cache the devices as they don't get destroyed during runtime static bool cached = false; if (!cached) { - find_qwerty_devices(xdevs, num_xdevs, &xd_hmd, &xd_left, &xd_right); - default_qdev = default_qwerty_device(xdevs, num_xdevs, xd_hmd, xd_left, xd_right); + qsys = find_qwerty_system(xdevs, num_xdevs); + default_qdev = default_qwerty_device(xdevs, num_xdevs, qsys); cached = true; } + if (!qsys->process_keys) { + return; + } + // Initialize different views of the same pointers. - struct qwerty_controller *qleft = qwerty_controller(xd_left); + struct qwerty_controller *qleft = qsys->lctrl; struct qwerty_device *qd_left = &qleft->base; - struct qwerty_controller *qright = qwerty_controller(xd_right); + struct qwerty_controller *qright = qsys->rctrl; struct qwerty_device *qd_right = &qright->base; - bool using_qhmd = xd_hmd != NULL; - struct qwerty_hmd *qhmd = using_qhmd ? qwerty_hmd(xd_hmd) : NULL; + bool using_qhmd = qsys->hmd != NULL; + struct qwerty_hmd *qhmd = using_qhmd ? qsys->hmd : NULL; struct qwerty_device *qd_hmd = using_qhmd ? &qhmd->base : NULL; // clang-format off From ef74e24abe8d32fd9947a7cc523cf6b42438efa3 Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 17:10:24 -0300 Subject: [PATCH 224/883] d/qwerty: Add variable tracking widget to UI --- src/xrt/drivers/qwerty/qwerty_device.c | 52 ++++++++++++++++++++++++++ src/xrt/drivers/qwerty/qwerty_device.h | 3 ++ src/xrt/drivers/qwerty/qwerty_sdl.c | 5 +++ 3 files changed, 60 insertions(+) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index ad01dedde..3b76c1147 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -11,6 +11,7 @@ #include "util/u_device.h" #include "util/u_distortion_mesh.h" +#include "util/u_var.h" #include "math/m_api.h" #include "math/m_mathinclude.h" @@ -164,6 +165,8 @@ qwerty_get_view_pose(struct xrt_device *xd, static void qwerty_destroy(struct xrt_device *xd) { + // Note: do not destroy a single device of a qwerty system or its var tracking + // ui will make a null reference struct qwerty_device *qd = qwerty_device(xd); qwerty_system_remove(qd->sys, qd); u_device_free(xd); @@ -263,6 +266,52 @@ qwerty_controller_create(bool is_left, struct qwerty_hmd *qhmd) // System methods +static void +qwerty_setup_var_tracking(struct qwerty_system *qs) +{ + struct qwerty_device *qd_hmd = qs->hmd ? &qs->hmd->base : NULL; + struct qwerty_device *qd_left = &qs->lctrl->base; + struct qwerty_device *qd_right = &qs->rctrl->base; + + u_var_add_root(qs, "Qwerty System", true); + u_var_add_bool(qs, &qs->process_keys, "process_keys"); + + u_var_add_ro_text(qs, "", "Focused Device"); + if (qd_hmd) { + u_var_add_bool(qs, &qs->hmd_focused, "HMD Focused"); + } + u_var_add_bool(qs, &qs->lctrl_focused, "Left Controller Focused"); + u_var_add_bool(qs, &qs->rctrl_focused, "Right Controller Focused"); + + if (qd_hmd) { + u_var_add_gui_header(qs, NULL, qd_hmd->base.str); + u_var_add_pose(qs, &qd_hmd->pose, "hmd.pose"); + u_var_add_f32(qs, &qd_hmd->movement_speed, "hmd.movement_speed"); + u_var_add_f32(qs, &qd_hmd->look_speed, "hmd.look_speed"); + } + + u_var_add_gui_header(qs, NULL, qd_left->base.str); + u_var_add_pose(qs, &qd_left->pose, "left.pose"); + u_var_add_f32(qs, &qd_left->movement_speed, "left.movement_speed"); + u_var_add_f32(qs, &qd_left->look_speed, "left.look_speed"); + + u_var_add_gui_header(qs, NULL, qd_right->base.str); + u_var_add_pose(qs, &qd_right->pose, "right.pose"); + u_var_add_f32(qs, &qd_right->movement_speed, "right.movement_speed"); + u_var_add_f32(qs, &qd_right->look_speed, "right.look_speed"); + + u_var_add_gui_header(qs, NULL, "Help"); + u_var_add_ro_text(qs, "FD: focused device. FC: focused controller.", "Notation"); + u_var_add_ro_text(qs, "HMD is FD by default. Right is FC by default", "Defaults"); + u_var_add_ro_text(qs, "Hold left/right FD", "LCTRL/LALT"); + u_var_add_ro_text(qs, "Move FD", "WASDQE"); + u_var_add_ro_text(qs, "Rotate FD", "Arrow keys"); + u_var_add_ro_text(qs, "Rotate FD", "Hold right click"); + u_var_add_ro_text(qs, "Hold for movement speed", "LSHIFT"); + u_var_add_ro_text(qs, "Modify FD movement speed", "Mouse wheel"); + u_var_add_ro_text(qs, "Modify FD movement speed", "Numpad +/-"); +} + struct qwerty_system * qwerty_system_create(struct qwerty_hmd *qhmd, struct qwerty_controller *qleft, @@ -283,6 +332,8 @@ qwerty_system_create(struct qwerty_hmd *qhmd, qleft->base.sys = qs; qright->base.sys = qs; + qwerty_setup_var_tracking(qs); + return qs; } @@ -310,6 +361,7 @@ qwerty_system_destroy(struct qwerty_system *qs) { bool all_devices_clean = !qs->hmd && !qs->lctrl && !qs->rctrl; assert(all_devices_clean && "Tried to destroy a qwerty_system without destroying its devices before."); + u_var_remove_root(qs); free(qs); } diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index 76a5f641c..2b8c674c2 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -33,6 +33,9 @@ struct qwerty_system struct qwerty_controller *lctrl; //!< Cannot be NULL struct qwerty_controller *rctrl; //!< Cannot be NULL bool process_keys; //!< If false disable keyboard and mouse input + bool hmd_focused; //!< For gui var tracking only, true if hmd is the focused device + bool lctrl_focused; //!< Same as `hmd_focused` but for the left controller + bool rctrl_focused; //!< Same as `hmd_focused` but for the right controller }; //! Fake device that modifies its tracked pose through its methods. diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index 2fc6ebe08..a524c38e7 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -123,6 +123,11 @@ qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event even else if (alt_pressed) qdev = qd_right; else qdev = default_qdev; + // Update gui tracked variables + qsys->hmd_focused = qdev == qd_hmd; + qsys->lctrl_focused = qdev == qd_left; + qsys->rctrl_focused = qdev == qd_right; + // WASDQE Movement if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_a) qwerty_press_left(qdev); if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_a) qwerty_release_left(qdev); From 582a287dd494d96f04291e65cf2e0aa3229752f4 Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 17:13:58 -0300 Subject: [PATCH 225/883] d/qwerty: Use u_logging.h with QWERTY_LOG env var --- src/xrt/drivers/qwerty/qwerty_device.c | 16 +++++++++++++--- src/xrt/drivers/qwerty/qwerty_device.h | 5 ++++- src/xrt/drivers/qwerty/qwerty_prober.c | 7 ++++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 3b76c1147..e5e789a75 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -12,6 +12,7 @@ #include "util/u_device.h" #include "util/u_distortion_mesh.h" #include "util/u_var.h" +#include "util/u_logging.h" #include "math/m_api.h" #include "math/m_mathinclude.h" @@ -41,6 +42,12 @@ #define QWERTY_AIM 3 #define QWERTY_VIBRATION 0 +#define QWERTY_TRACE(qd, ...) U_LOG_XDEV_IFL_T(&qd->base, qd->sys->ll, __VA_ARGS__) +#define QWERTY_DEBUG(qd, ...) U_LOG_XDEV_IFL_D(&qd->base, qd->sys->ll, __VA_ARGS__) +#define QWERTY_INFO(qd, ...) U_LOG_XDEV_IFL_I(&qd->base, qd->sys->ll, __VA_ARGS__) +#define QWERTY_WARN(qd, ...) U_LOG_XDEV_IFL_W(&qd->base, qd->sys->ll, __VA_ARGS__) +#define QWERTY_ERROR(qd, ...) U_LOG_XDEV_IFL_E(&qd->base, qd->sys->ll, __VA_ARGS__) + static void qwerty_system_remove(struct qwerty_system *qs, struct qwerty_device *qd); @@ -104,7 +111,7 @@ qwerty_get_tracked_pose(struct xrt_device *xd, struct qwerty_device *qd = qwerty_device(xd); if (name != XRT_INPUT_GENERIC_HEAD_POSE && name != XRT_INPUT_SIMPLE_GRIP_POSE) { - printf("Unexpected input name = 0x%04X\n", name >> 8); // @todo: use u_logging.h + QWERTY_ERROR(qd, "Unexpected input name = 0x%04X", name >> 8); return; } @@ -205,7 +212,7 @@ qwerty_hmd_create(void) info.views[1].fov = 85.0f * (M_PI / 180.0f); if (!u_device_setup_split_side_by_side(xd, &info)) { - printf("Failed to setup HMD properties\n"); // @todo: Use u_logging.h + QWERTY_ERROR(qd, "Failed to setup HMD properties"); qwerty_destroy(xd); assert(false); return NULL; @@ -274,6 +281,7 @@ qwerty_setup_var_tracking(struct qwerty_system *qs) struct qwerty_device *qd_right = &qs->rctrl->base; u_var_add_root(qs, "Qwerty System", true); + u_var_add_log_level(qs, &qs->ll, "log_level"); u_var_add_bool(qs, &qs->process_keys, "process_keys"); u_var_add_ro_text(qs, "", "Focused Device"); @@ -315,7 +323,8 @@ qwerty_setup_var_tracking(struct qwerty_system *qs) struct qwerty_system * qwerty_system_create(struct qwerty_hmd *qhmd, struct qwerty_controller *qleft, - struct qwerty_controller *qright) + struct qwerty_controller *qright, + enum u_logging_level log_level) { assert(qleft && "Cannot create a qwerty system when Left controller is NULL"); assert(qright && "Cannot create a qwerty system when Right controller is NULL"); @@ -324,6 +333,7 @@ qwerty_system_create(struct qwerty_hmd *qhmd, qs->hmd = qhmd; qs->lctrl = qleft; qs->rctrl = qright; + qs->ll = log_level; qs->process_keys = true; if (qhmd) { diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index 2b8c674c2..f884fa5ff 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -8,6 +8,7 @@ */ #pragma once +#include "util/u_logging.h" #include "xrt/xrt_device.h" #define QWERTY_HMD_STR "Qwerty HMD" @@ -32,6 +33,7 @@ struct qwerty_system struct qwerty_hmd *hmd; //!< Can be NULL struct qwerty_controller *lctrl; //!< Cannot be NULL struct qwerty_controller *rctrl; //!< Cannot be NULL + enum u_logging_level ll; bool process_keys; //!< If false disable keyboard and mouse input bool hmd_focused; //!< For gui var tracking only, true if hmd is the focused device bool lctrl_focused; //!< Same as `hmd_focused` but for the left controller @@ -88,7 +90,8 @@ struct qwerty_controller struct qwerty_system * qwerty_system_create(struct qwerty_hmd *qhmd, struct qwerty_controller *qleft, - struct qwerty_controller *qright); + struct qwerty_controller *qright, + enum u_logging_level log_level); /*! * @} diff --git a/src/xrt/drivers/qwerty/qwerty_prober.c b/src/xrt/drivers/qwerty/qwerty_prober.c index 37b3c28f6..35f26f3dc 100644 --- a/src/xrt/drivers/qwerty/qwerty_prober.c +++ b/src/xrt/drivers/qwerty/qwerty_prober.c @@ -10,8 +10,12 @@ #include "qwerty_device.h" #include "util/u_misc.h" #include "util/u_debug.h" +#include "util/u_logging.h" #include "xrt/xrt_prober.h" +// Using INFO as default to inform events real devices could report physically +DEBUG_GET_ONCE_LOG_OPTION(qwerty_log, "QWERTY_LOG", U_LOGGING_INFO) + // Driver disabled by default for being experimental DEBUG_GET_ONCE_BOOL_OPTION(qwerty_enable, "QWERTY_ENABLE", false) @@ -51,7 +55,8 @@ qwerty_prober_autoprobe(struct xrt_auto_prober *xap, struct qwerty_controller *qleft = qwerty_controller_create(true, qhmd); struct qwerty_controller *qright = qwerty_controller_create(false, qhmd); - qwerty_system_create(qhmd, qleft, qright); + enum u_logging_level log_level = debug_get_log_option_qwerty_log(); + qwerty_system_create(qhmd, qleft, qright, log_level); struct xrt_device *xd_hmd = &qhmd->base.base; struct xrt_device *xd_left = &qleft->base.base; From 4ea696bfddbde70ff59bb46c26575354e0df1542 Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 17:23:17 -0300 Subject: [PATCH 226/883] d/qwerty: Implement select and menu click inputs --- src/xrt/drivers/qwerty/qwerty_device.c | 30 +++++++++++++++++++++++++- src/xrt/drivers/qwerty/qwerty_device.h | 12 +++++++++++ src/xrt/drivers/qwerty/qwerty_sdl.c | 11 ++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index e5e789a75..8dad61393 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -93,7 +93,24 @@ qwerty_controller(struct xrt_device *xd) static void qwerty_update_inputs(struct xrt_device *xd) { - return; + if (xd->name != XRT_DEVICE_SIMPLE_CONTROLLER) { + return; + } + + struct qwerty_controller *qc = qwerty_controller(xd); + struct qwerty_device *qd = &qc->base; + + xd->inputs[QWERTY_SELECT].value.boolean = qc->select_clicked; + if (qc->select_clicked) { + QWERTY_INFO(qd, "[%s] Select click", xd->str); + qc->select_clicked = false; + } + + xd->inputs[QWERTY_MENU].value.boolean = qc->menu_clicked; + if (qc->menu_clicked) { + QWERTY_INFO(qd, "[%s] Menu click", xd->str); + qc->menu_clicked = false; + } } static void @@ -237,6 +254,8 @@ qwerty_controller_create(bool is_left, struct qwerty_hmd *qhmd) { struct qwerty_controller *qc = U_DEVICE_ALLOCATE(struct qwerty_controller, U_DEVICE_ALLOC_TRACKING_NONE, 4, 1); assert(qc); + qc->select_clicked = false; + qc->menu_clicked = false; struct qwerty_device *qd = &qc->base; qd->pose.orientation.w = 1.f; @@ -318,6 +337,8 @@ qwerty_setup_var_tracking(struct qwerty_system *qs) u_var_add_ro_text(qs, "Hold for movement speed", "LSHIFT"); u_var_add_ro_text(qs, "Modify FD movement speed", "Mouse wheel"); u_var_add_ro_text(qs, "Modify FD movement speed", "Numpad +/-"); + u_var_add_ro_text(qs, "FC Select click", "Left Click"); + u_var_add_ro_text(qs, "FC Menu click", "Middle Click"); } struct qwerty_system * @@ -442,3 +463,10 @@ qwerty_release_all(struct qwerty_device *qd) qd->yaw_delta = 0; qd->pitch_delta = 0; } + +// Controller methods + +// clang-format off +void qwerty_select_click(struct qwerty_controller *qc) { qc->select_clicked = true; } +void qwerty_menu_click(struct qwerty_controller *qc) { qc->menu_clicked = true; } +// clang-format on diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index f884fa5ff..7234f2cac 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -73,10 +73,14 @@ struct qwerty_hmd struct qwerty_device base; }; +//! Supports input actions //! @implements qwerty_device struct qwerty_controller { struct qwerty_device base; + + bool select_clicked; + bool menu_clicked; }; /*! @@ -192,6 +196,14 @@ qwerty_controller_create(bool is_left, struct qwerty_hmd *qhmd); struct qwerty_controller * qwerty_controller(struct xrt_device *xd); +//! Simulate input/select/click +void +qwerty_select_click(struct qwerty_controller *qc); + +//! Simulate input/menu/click +void +qwerty_menu_click(struct qwerty_controller *qc); + /*! * @} */ diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index a524c38e7..81ba2edcb 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -123,6 +123,12 @@ qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event even else if (alt_pressed) qdev = qd_right; else qdev = default_qdev; + // Default focused controller + struct qwerty_controller *default_qctrl = qright; // @todo: set this based on user devices + + // Determine focused controller for qwerty_controller specific methods + struct qwerty_controller *qctrl = qdev != qd_hmd ? qwerty_controller(&qdev->base) : default_qctrl; + // Update gui tracked variables qsys->hmd_focused = qdev == qd_hmd; qsys->lctrl_focused = qdev == qd_left; @@ -171,5 +177,10 @@ qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event even float pitch = -event.motion.yrel * SENSITIVITY; qwerty_add_look_delta(qdev, yaw, pitch); } + + // Select and menu clicks only for controllers. + if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT) qwerty_select_click(qctrl); + if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_MIDDLE) qwerty_menu_click(qctrl); + // clang-format on } From 8b81afeb5994f70f2c0d0fe4e1cc006aa5905efd Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 17:26:16 -0300 Subject: [PATCH 227/883] d/qwerty: Implement haptic output --- src/xrt/drivers/qwerty/qwerty_device.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 8dad61393..ac4cd492e 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -116,7 +116,16 @@ qwerty_update_inputs(struct xrt_device *xd) static void qwerty_set_output(struct xrt_device *xd, enum xrt_output_name name, union xrt_output_value *value) { - return; + struct qwerty_device *qd = qwerty_device(xd); + float frequency = value->vibration.frequency; + float amplitude = value->vibration.amplitude; + time_duration_ns duration = value->vibration.duration; + if (amplitude || duration || frequency) { + QWERTY_INFO(qd, + "[%s] Haptic output: \n" + "\tfrequency=%.2f amplitude=%.2f duration=%ld", + xd->str, frequency, amplitude, duration); + } } static void From 7f00ca3da2c64b61dfd10e710356882aa2f81cc5 Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 17:29:36 -0300 Subject: [PATCH 228/883] d/qwerty: Improve selection of default controller --- src/xrt/drivers/qwerty/qwerty_sdl.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index 81ba2edcb..b888cacd5 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -64,6 +64,29 @@ default_qwerty_device(struct xrt_device **xdevs, size_t num_xdevs, struct qwerty return default_qdev; } +// Determines the default qwerty controller based on which devices are in use +static struct qwerty_controller * +default_qwerty_controller(struct xrt_device **xdevs, size_t num_xdevs, struct qwerty_system *qsys) +{ + int head, left, right; + head = left = right = XRT_DEVICE_ROLE_UNASSIGNED; + u_device_assign_xdev_roles(xdevs, num_xdevs, &head, &left, &right); + + struct xrt_device *xd_left = &qsys->lctrl->base.base; + struct xrt_device *xd_right = &qsys->rctrl->base.base; + + struct qwerty_controller *default_qctrl = NULL; + if (xdevs[right] == xd_right) { + default_qctrl = qwerty_controller(xd_right); + } else if (xdevs[left] == xd_left) { + default_qctrl = qwerty_controller(xd_left); + } else { // Even here, xd_right is allocated and so we can modify it + default_qctrl = qwerty_controller(xd_right); + } + + return default_qctrl; +} + void qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event event) { @@ -74,12 +97,15 @@ qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event even // Default focused device: the one focused when CTRL and ALT are not pressed static struct qwerty_device *default_qdev; + // Default focused controller: the one used for qwerty_controller specific methods + static struct qwerty_controller *default_qctrl; // We can cache the devices as they don't get destroyed during runtime static bool cached = false; if (!cached) { qsys = find_qwerty_system(xdevs, num_xdevs); default_qdev = default_qwerty_device(xdevs, num_xdevs, qsys); + default_qctrl = default_qwerty_controller(xdevs, num_xdevs, qsys); cached = true; } @@ -123,9 +149,6 @@ qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event even else if (alt_pressed) qdev = qd_right; else qdev = default_qdev; - // Default focused controller - struct qwerty_controller *default_qctrl = qright; // @todo: set this based on user devices - // Determine focused controller for qwerty_controller specific methods struct qwerty_controller *qctrl = qdev != qd_hmd ? qwerty_controller(&qdev->base) : default_qctrl; From 5e6c4b63a52d9ee4f3b3ad435b980864793fe0da Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 17:33:33 -0300 Subject: [PATCH 229/883] d/qwerty: Implement controller parenting to HMD Although, it only works for the qwerty HMD. --- src/xrt/drivers/qwerty/qwerty_device.c | 45 ++++++++++++++++++++++++-- src/xrt/drivers/qwerty/qwerty_device.h | 13 +++++++- src/xrt/drivers/qwerty/qwerty_sdl.c | 11 +++++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index ac4cd492e..408562936 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -15,6 +15,7 @@ #include "util/u_logging.h" #include "math/m_api.h" +#include "math/m_space.h" #include "math/m_mathinclude.h" #include "xrt/xrt_device.h" @@ -30,7 +31,7 @@ #define SPRINT_STEPS 5 // Amount of MOVEMENT_SPEED_STEPs to increase when sprinting // clang-format off -// Values copied from u_device_setup_tracking_origins. +// Values copied from u_device_setup_tracking_origins. CONTROLLER relative to HMD. #define QWERTY_HMD_INITIAL_POS (struct xrt_vec3){0, 1.6f, 0} #define QWERTY_CONTROLLER_INITIAL_POS(is_left) (struct xrt_vec3){(is_left) ? -0.2f : 0.2f, -0.3f, -0.5f} // clang-format on @@ -174,7 +175,19 @@ qwerty_get_tracked_pose(struct xrt_device *xd, math_quat_rotate(&y_rotation, &qd->pose.orientation, &qd->pose.orientation); // base-space yaw math_quat_normalize(&qd->pose.orientation); - out_relation->pose = qd->pose; + // HMD Parenting + + bool qd_is_ctrl = name == XRT_INPUT_SIMPLE_GRIP_POSE; + struct qwerty_controller *qc = qd_is_ctrl ? qwerty_controller(&qd->base) : NULL; + if (qd_is_ctrl && qc->follow_hmd) { + struct xrt_space_graph space_graph = {0}; + struct qwerty_device *qd_hmd = &qd->sys->hmd->base; + m_space_graph_add_pose(&space_graph, &qd->pose); // controller pose + m_space_graph_add_pose(&space_graph, &qd_hmd->pose); // base space is hmd space + m_space_graph_resolve(&space_graph, out_relation); + } else { + out_relation->pose = qd->pose; + } out_relation->relation_flags = XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT; @@ -265,6 +278,7 @@ qwerty_controller_create(bool is_left, struct qwerty_hmd *qhmd) assert(qc); qc->select_clicked = false; qc->menu_clicked = false; + qc->follow_hmd = qhmd != NULL; struct qwerty_device *qd = &qc->base; qd->pose.orientation.w = 1.f; @@ -346,6 +360,7 @@ qwerty_setup_var_tracking(struct qwerty_system *qs) u_var_add_ro_text(qs, "Hold for movement speed", "LSHIFT"); u_var_add_ro_text(qs, "Modify FD movement speed", "Mouse wheel"); u_var_add_ro_text(qs, "Modify FD movement speed", "Numpad +/-"); + u_var_add_ro_text(qs, "Toggle both or FC parenting to HMD", "F"); u_var_add_ro_text(qs, "FC Select click", "Left Click"); u_var_add_ro_text(qs, "FC Menu click", "Middle Click"); } @@ -479,3 +494,29 @@ qwerty_release_all(struct qwerty_device *qd) void qwerty_select_click(struct qwerty_controller *qc) { qc->select_clicked = true; } void qwerty_menu_click(struct qwerty_controller *qc) { qc->menu_clicked = true; } // clang-format on + +void +qwerty_follow_hmd(struct qwerty_controller *qc, bool follow) +{ + struct qwerty_device *qd = &qc->base; + bool no_qhmd = !qd->sys->hmd; + bool unchanged = qc->follow_hmd == follow; + if (no_qhmd || unchanged) { + return; + } + + struct qwerty_device *qd_hmd = &qd->sys->hmd->base; + struct xrt_space_graph graph = {0}; + struct xrt_space_relation rel = {0}; + + m_space_graph_add_pose(&graph, &qd->pose); + if (follow) { // From global to hmd + m_space_graph_add_inverted_pose_if_not_identity(&graph, &qd_hmd->pose); + } else { // From hmd to global + m_space_graph_add_pose(&graph, &qd_hmd->pose); + } + m_space_graph_resolve(&graph, &rel); + + qd->pose = rel.pose; + qc->follow_hmd = follow; +} diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index 7234f2cac..f31bf01d8 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -73,7 +73,7 @@ struct qwerty_hmd struct qwerty_device base; }; -//! Supports input actions +//! Supports input actions and can be attached to the HMD pose. //! @implements qwerty_device struct qwerty_controller { @@ -81,6 +81,13 @@ struct qwerty_controller bool select_clicked; bool menu_clicked; + + /*! + * Only used when a qwerty_hmd exists in the system. + * Do not modify directly; use qwerty_follow_hmd(). + * If true, `pose` is relative to the qwerty_hmd. + */ + bool follow_hmd; // @todo: Make this work with non-qwerty HMDs. }; /*! @@ -204,6 +211,10 @@ qwerty_select_click(struct qwerty_controller *qc); void qwerty_menu_click(struct qwerty_controller *qc); +//! Attach/detach the pose of `qc` to its HMD. Only works when a qwerty_hmd is present. +void +qwerty_follow_hmd(struct qwerty_controller *qc, bool follow); + /*! * @} */ diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index b888cacd5..8f50a480d 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -206,4 +206,15 @@ qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event even if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_MIDDLE) qwerty_menu_click(qctrl); // clang-format on + + // Controllers follow/unfollow HMD + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_f && event.key.repeat == 0) { + if (qdev != qd_hmd) { + qwerty_follow_hmd(qctrl, !qctrl->follow_hmd); + } else { // If no controller is focused, set both to the same state + bool both_not_following = !qleft->follow_hmd && !qright->follow_hmd; + qwerty_follow_hmd(qleft, both_not_following); + qwerty_follow_hmd(qright, both_not_following); + } + } } From 5c6158cc8bbd92add1aa38bf44164cd9d0386900 Mon Sep 17 00:00:00 2001 From: Mateo de Mayo Date: Thu, 11 Mar 2021 17:35:14 -0300 Subject: [PATCH 230/883] d/qwerty: Implement controller pose reset --- src/xrt/drivers/qwerty/qwerty_device.c | 19 +++++++++++++++++++ src/xrt/drivers/qwerty/qwerty_device.h | 4 ++++ src/xrt/drivers/qwerty/qwerty_sdl.c | 10 ++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 408562936..e03255195 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -360,6 +360,7 @@ qwerty_setup_var_tracking(struct qwerty_system *qs) u_var_add_ro_text(qs, "Hold for movement speed", "LSHIFT"); u_var_add_ro_text(qs, "Modify FD movement speed", "Mouse wheel"); u_var_add_ro_text(qs, "Modify FD movement speed", "Numpad +/-"); + u_var_add_ro_text(qs, "Reset both or FC pose", "R"); u_var_add_ro_text(qs, "Toggle both or FC parenting to HMD", "F"); u_var_add_ro_text(qs, "FC Select click", "Left Click"); u_var_add_ro_text(qs, "FC Menu click", "Middle Click"); @@ -520,3 +521,21 @@ qwerty_follow_hmd(struct qwerty_controller *qc, bool follow) qd->pose = rel.pose; qc->follow_hmd = follow; } + +void +qwerty_reset_controller_pose(struct qwerty_controller *qc) +{ + struct qwerty_device *qd = &qc->base; + + bool no_qhmd = !qd->sys->hmd; + if (no_qhmd) { + return; + } + + struct xrt_quat quat_identity = {0, 0, 0, 1}; + bool is_left = qc == qd->sys->lctrl; + + qwerty_follow_hmd(qc, true); + struct xrt_pose pose = {quat_identity, QWERTY_CONTROLLER_INITIAL_POS(is_left)}; + qd->pose = pose; +} diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index f31bf01d8..2616321dd 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -215,6 +215,10 @@ qwerty_menu_click(struct qwerty_controller *qc); void qwerty_follow_hmd(struct qwerty_controller *qc, bool follow); +//! Reset controller to initial pose and makes it follow the HMD +void +qwerty_reset_controller_pose(struct qwerty_controller *qc); + /*! * @} */ diff --git a/src/xrt/drivers/qwerty/qwerty_sdl.c b/src/xrt/drivers/qwerty/qwerty_sdl.c index 8f50a480d..1f3ba9556 100644 --- a/src/xrt/drivers/qwerty/qwerty_sdl.c +++ b/src/xrt/drivers/qwerty/qwerty_sdl.c @@ -217,4 +217,14 @@ qwerty_process_event(struct xrt_device **xdevs, size_t num_xdevs, SDL_Event even qwerty_follow_hmd(qright, both_not_following); } } + + // Reset controller poses + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_r && event.key.repeat == 0) { + if (qdev != qd_hmd) { + qwerty_reset_controller_pose(qctrl); + } else { // If no controller is focused, reset both + qwerty_reset_controller_pose(qleft); + qwerty_reset_controller_pose(qright); + } + } } From 083e4f51085751047a158f6f99151e00a1201dce Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 30 Mar 2021 19:14:08 +0100 Subject: [PATCH 231/883] u/logging: Fix first global log message not getting correct level, add comments --- src/xrt/auxiliary/util/u_logging.c | 22 ++++------------------ src/xrt/auxiliary/util/u_logging.h | 24 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/xrt/auxiliary/util/u_logging.c b/src/xrt/auxiliary/util/u_logging.c index fb6f33c1c..89558af20 100644 --- a/src/xrt/auxiliary/util/u_logging.c +++ b/src/xrt/auxiliary/util/u_logging.c @@ -19,17 +19,10 @@ DEBUG_GET_ONCE_LOG_OPTION(global_log, "XRT_LOG", U_LOGGING_WARN) -enum u_logging_level global_log_level; - -static bool _is_log_level_initialized; - -void -_log_level_init() +enum u_logging_level +u_log_get_global_level(void) { - if (!_is_log_level_initialized) { - global_log_level = debug_get_log_option_global_log(); - _is_log_level_initialized = true; - } + return debug_get_log_option_global_log(); } #if defined(XRT_OS_ANDROID) @@ -50,10 +43,10 @@ u_log_convert_priority(enum u_logging_level level) } return ANDROID_LOG_INFO; } + void u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...) { - _log_level_init(); // print_prefix(func, level); android_LogPriority prio = u_log_convert_priority(level); va_list args; @@ -71,7 +64,6 @@ u_log_xdev(const char *file, const char *format, ...) { - _log_level_init(); android_LogPriority prio = u_log_convert_priority(level); va_list args; va_start(args, format); @@ -107,7 +99,6 @@ print_prefix(int remainingBuf, char *buf, const char *func, enum u_logging_level void u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...) { - _log_level_init(); char buf[16384] = {0}; @@ -131,7 +122,6 @@ u_log_xdev(const char *file, const char *format, ...) { - _log_level_init(); char buf[16384] = {0}; @@ -222,8 +212,6 @@ print_prefix(const char *func, enum u_logging_level level) void u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...) { - _log_level_init(); - print_prefix(func, level); va_list args; @@ -243,8 +231,6 @@ u_log_xdev(const char *file, const char *format, ...) { - _log_level_init(); - print_prefix(func, level); va_list args; diff --git a/src/xrt/auxiliary/util/u_logging.h b/src/xrt/auxiliary/util/u_logging.h index edf7e6d72..c90c69ea6 100644 --- a/src/xrt/auxiliary/util/u_logging.h +++ b/src/xrt/auxiliary/util/u_logging.h @@ -64,11 +64,11 @@ struct xrt_device; } while (false) // clang-format off -#define U_LOG_T(...) U_LOG_IFL_T(global_log_level, __VA_ARGS__) -#define U_LOG_D(...) U_LOG_IFL_D(global_log_level, __VA_ARGS__) -#define U_LOG_I(...) U_LOG_IFL_I(global_log_level, __VA_ARGS__) -#define U_LOG_W(...) U_LOG_IFL_W(global_log_level, __VA_ARGS__) -#define U_LOG_E(...) U_LOG_IFL_E(global_log_level, __VA_ARGS__) +#define U_LOG_T(...) U_LOG_IFL_T(u_log_get_global_level(), __VA_ARGS__) +#define U_LOG_D(...) U_LOG_IFL_D(u_log_get_global_level(), __VA_ARGS__) +#define U_LOG_I(...) U_LOG_IFL_I(u_log_get_global_level(), __VA_ARGS__) +#define U_LOG_W(...) U_LOG_IFL_W(u_log_get_global_level(), __VA_ARGS__) +#define U_LOG_E(...) U_LOG_IFL_E(u_log_get_global_level(), __VA_ARGS__) #define U_LOG_IFL_T(cond_level, ...) U_LOG_IFL(U_LOGGING_TRACE, cond_level, __VA_ARGS__) #define U_LOG_IFL_D(cond_level, ...) U_LOG_IFL(U_LOGGING_DEBUG, cond_level, __VA_ARGS__) @@ -99,12 +99,24 @@ enum u_logging_level U_LOGGING_RAW, //!< Special level for raw printing, prints a new-line. }; -extern enum u_logging_level global_log_level; +/*! + * Returns the global logging level, subsystems own logging level take precedence. + */ +enum u_logging_level +u_log_get_global_level(void); +/*! + * This function always logs, level is used for printing or passed to native + * logging functions. + */ void u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...) XRT_PRINTF_FORMAT(5, 6); +/*! + * This function always logs, level is used for printing or passed to native + * logging functions. + */ void u_log_xdev(const char *file, int line, From 967c27060ebdb7d02639cfacbeeabae2ea2d79d2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 30 Mar 2021 19:23:31 +0100 Subject: [PATCH 232/883] st/prober: Change log env variable and set default level to info --- src/xrt/state_trackers/prober/p_prober.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/prober/p_prober.c b/src/xrt/state_trackers/prober/p_prober.c index 327e7ece5..e762809cd 100644 --- a/src/xrt/state_trackers/prober/p_prober.c +++ b/src/xrt/state_trackers/prober/p_prober.c @@ -40,7 +40,7 @@ * */ -DEBUG_GET_ONCE_LOG_OPTION(prober_log, "PROBER_LOG", U_LOGGING_WARN) +DEBUG_GET_ONCE_LOG_OPTION(prober_log, "PROBER_LOG", U_LOGGING_INFO) static void add_device(struct prober *p, struct prober_device **out_dev); From 6f10f474fafec111377290190ac52ff8d4404172 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 30 Mar 2021 19:29:19 +0100 Subject: [PATCH 233/883] t/psvr: Ensure that m_mathinclude.h is included --- src/xrt/auxiliary/tracking/t_tracker_psvr.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp b/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp index a598dc888..b59aa2a88 100644 --- a/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp +++ b/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp @@ -21,6 +21,7 @@ #include "util/u_var.h" #include "util/u_logging.h" +#include "math/m_mathinclude.h" #include "math/m_api.h" #include "math/m_permutation.h" From 6ba27de30530a31eb86036d5fd6a79c1e19cca20 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 30 Mar 2021 19:48:01 +0100 Subject: [PATCH 234/883] m/mathinclude: Apperently _USE_MATH_DEFINES was not enough --- src/xrt/auxiliary/math/m_mathinclude.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/xrt/auxiliary/math/m_mathinclude.h b/src/xrt/auxiliary/math/m_mathinclude.h index 81c3c5a0e..dd51120e4 100644 --- a/src/xrt/auxiliary/math/m_mathinclude.h +++ b/src/xrt/auxiliary/math/m_mathinclude.h @@ -21,6 +21,17 @@ #include #endif + +// Might be missing on Windows. +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + +// Might be missing on Windows. +#ifndef M_PIl +#define M_PIl (3.14159265358979323846264338327950288) +#endif + #ifndef M_1_PI #define M_1_PI (1. / M_PI) #endif From 11bf681e3b743ea4d432a313e8cd89e294ac735d Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 30 Mar 2021 21:28:14 +0100 Subject: [PATCH 235/883] doc: Document !735 --- doc/changes/auxiliary/mr.735.md | 1 + doc/changes/misc_fixes/mr.735.md | 2 ++ doc/changes/state_trackers/mr.735.md | 2 ++ 3 files changed, 5 insertions(+) create mode 100644 doc/changes/auxiliary/mr.735.md create mode 100644 doc/changes/misc_fixes/mr.735.md create mode 100644 doc/changes/state_trackers/mr.735.md diff --git a/doc/changes/auxiliary/mr.735.md b/doc/changes/auxiliary/mr.735.md new file mode 100644 index 000000000..f0086fbe1 --- /dev/null +++ b/doc/changes/auxiliary/mr.735.md @@ -0,0 +1 @@ +math: Fixes for M_PI on Windows. diff --git a/doc/changes/misc_fixes/mr.735.md b/doc/changes/misc_fixes/mr.735.md new file mode 100644 index 000000000..7f7293554 --- /dev/null +++ b/doc/changes/misc_fixes/mr.735.md @@ -0,0 +1,2 @@ +logging: Fix the first message always getting printed due to un-initaialized +variable. diff --git a/doc/changes/state_trackers/mr.735.md b/doc/changes/state_trackers/mr.735.md new file mode 100644 index 000000000..c5ee872dd --- /dev/null +++ b/doc/changes/state_trackers/mr.735.md @@ -0,0 +1,2 @@ +prober: Change the default logging level to info so that people can see what +drivers are disabled. From adb5eefb867eb54f4efe534131101cad9e19071d Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:49:51 -0500 Subject: [PATCH 236/883] aux/vk: Add functions to initialize and clean up mutexes in the vk_bundle --- src/xrt/auxiliary/vk/vk_helpers.c | 20 ++++++++++++++++++++ src/xrt/auxiliary/vk/vk_helpers.h | 24 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/xrt/auxiliary/vk/vk_helpers.c b/src/xrt/auxiliary/vk/vk_helpers.c index c019d5756..bf31a2726 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.c +++ b/src/xrt/auxiliary/vk/vk_helpers.c @@ -1152,6 +1152,26 @@ err_destroy: return ret; } +VkResult +vk_init_mutex(struct vk_bundle *vk) +{ + if (os_mutex_init(&vk->cmd_pool_mutex) < 0) { + return VK_ERROR_INITIALIZATION_FAILED; + } + if (os_mutex_init(&vk->queue_mutex) < 0) { + return VK_ERROR_INITIALIZATION_FAILED; + } + return VK_SUCCESS; +} + +VkResult +vk_deinit_mutex(struct vk_bundle *vk) +{ + os_mutex_destroy(&vk->cmd_pool_mutex); + os_mutex_destroy(&vk->queue_mutex); + return VK_SUCCESS; +} + VkResult vk_init_from_given(struct vk_bundle *vk, PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, diff --git a/src/xrt/auxiliary/vk/vk_helpers.h b/src/xrt/auxiliary/vk/vk_helpers.h index 52836dddc..38d3c394c 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.h +++ b/src/xrt/auxiliary/vk/vk_helpers.h @@ -331,6 +331,23 @@ vk_get_loader_functions(struct vk_bundle *vk, PFN_vkGetInstanceProcAddr g); VkResult vk_get_instance_functions(struct vk_bundle *vk); +/*! + * @brief Initialize mutexes in the @ref vk_bundle. + * + * Not required for all uses, but a precondition for some. + * + * @ingroup aux_vk + */ +VkResult +vk_init_mutex(struct vk_bundle *vk); + +/*! + * @brief De-initialize mutexes in the @ref vk_bundle. + * @ingroup aux_vk + */ +VkResult +vk_deinit_mutex(struct vk_bundle *vk); + /*! * @ingroup aux_vk */ @@ -464,12 +481,14 @@ vk_create_view_swizzle(struct vk_bundle *vk, VkImageView *out_view); /*! + * @pre Requires successful call to vk_init_mutex * @ingroup aux_vk */ VkResult vk_init_cmd_buffer(struct vk_bundle *vk, VkCommandBuffer *out_cmd_buffer); /*! + * @pre Requires successful call to vk_init_mutex * @ingroup aux_vk */ VkResult @@ -483,6 +502,7 @@ vk_set_image_layout(struct vk_bundle *vk, VkImageSubresourceRange subresource_range); /*! + * @pre Requires successful call to vk_init_mutex * @ingroup aux_vk */ VkResult @@ -531,6 +551,10 @@ vk_buffer_destroy(struct vk_buffer *self, struct vk_bundle *vk); bool vk_update_buffer(struct vk_bundle *vk, float *buffer, size_t buffer_size, VkDeviceMemory memory); +/*! + * @pre Requires successful call to vk_init_mutex + * @ingroup aux_vk + */ VkResult vk_locked_submit(struct vk_bundle *vk, VkQueue queue, uint32_t count, const VkSubmitInfo *infos, VkFence fence); From be5a2736597c46116d8d7a1e25571fd9c3cec33c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:50:34 -0500 Subject: [PATCH 237/883] comp/main: Use the new vk_bundle mutex functions. --- src/xrt/compositor/main/comp_compositor.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index c499f5312..c2f332f5d 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -569,8 +569,7 @@ system_compositor_destroy(struct xrt_system_compositor *xsc) vk->device = VK_NULL_HANDLE; } - os_mutex_destroy(&vk->queue_mutex); - os_mutex_destroy(&vk->cmd_pool_mutex); + vk_deinit_mutex(vk); if (vk->instance != VK_NULL_HANDLE) { vk->vkDestroyInstance(vk->instance, NULL); @@ -881,17 +880,15 @@ compositor_init_vulkan(struct comp_compositor *c) ARRAY_SIZE(required_device_extensions), optional_device_extensions, ARRAY_SIZE(optional_device_extensions)); - if (os_mutex_init(&c->vk.queue_mutex) != 0) { - return false; - } - - if (os_mutex_init(&c->vk.cmd_pool_mutex) != 0) { - return false; - } - if (ret != VK_SUCCESS) { return false; } + + ret = vk_init_mutex(&c->vk); + if (ret != VK_SUCCESS) { + return false; + } + c->settings.selected_gpu_index = c->vk.physical_device_index; // store physical device UUID for compositor in settings From 3f2b09ae54e61765cc514139113629c7f81ad7e3 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:50:43 -0500 Subject: [PATCH 238/883] comp: Comment cleanup --- src/xrt/compositor/main/comp_compositor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h index b24513802..e25ff6e01 100644 --- a/src/xrt/compositor/main/comp_compositor.h +++ b/src/xrt/compositor/main/comp_compositor.h @@ -331,7 +331,7 @@ bool comp_shaders_load(struct vk_bundle *vk, struct comp_shaders *s); /*! - * Loads all of the shaders that the compositor uses. + * Unload and cleanup shaders. */ void comp_shaders_close(struct vk_bundle *vk, struct comp_shaders *s); From 8553b5f90122ac54fbe2f3a0e379d250841e8c43 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:51:09 -0500 Subject: [PATCH 239/883] comp/vk_client: Be sure to init/de-init the mutexes in the vulkan bundle --- src/xrt/compositor/client/comp_vk_client.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xrt/compositor/client/comp_vk_client.c b/src/xrt/compositor/client/comp_vk_client.c index 8405d709b..a756abe4e 100644 --- a/src/xrt/compositor/client/comp_vk_client.c +++ b/src/xrt/compositor/client/comp_vk_client.c @@ -158,6 +158,7 @@ client_vk_compositor_destroy(struct xrt_compositor *xc) c->vk.vkDestroyCommandPool(c->vk.device, c->vk.cmd_pool, NULL); c->vk.cmd_pool = VK_NULL_HANDLE; } + vk_deinit_mutex(&c->vk); free(c); } @@ -541,6 +542,10 @@ client_vk_compositor_create(struct xrt_compositor_native *xcn, goto err_free; } + ret = vk_init_mutex(&c->vk); + if (ret != VK_SUCCESS) { + goto err_free; + } return c; err_free: From ace8dc8c4620b2aa7e8c7d94aa0587057c4d607c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:51:28 -0500 Subject: [PATCH 240/883] comp: clean up comment --- src/xrt/compositor/render/comp_render.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/compositor/render/comp_render.h b/src/xrt/compositor/render/comp_render.h index fe40c4b2a..51513486e 100644 --- a/src/xrt/compositor/render/comp_render.h +++ b/src/xrt/compositor/render/comp_render.h @@ -69,7 +69,7 @@ comp_buffer_init(struct vk_bundle *vk, VkDeviceSize size); /*! - * Frees all resources that this buffer has, doesn't not free the buffer itself. + * Frees all resources that this buffer has, but does not free the buffer itself. */ void comp_buffer_close(struct vk_bundle *vk, struct comp_buffer *buffer); From 4e11abc06b0503c434dc8216fb5d7acb9b022f28 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:52:35 -0500 Subject: [PATCH 241/883] aux/vk: Fix warning about narrowing conversion. --- src/xrt/auxiliary/vk/vk_helpers.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/xrt/auxiliary/vk/vk_helpers.c b/src/xrt/auxiliary/vk/vk_helpers.c index bf31a2726..a142637e0 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.c +++ b/src/xrt/auxiliary/vk/vk_helpers.c @@ -1034,11 +1034,11 @@ static bool vk_build_device_extensions(struct vk_bundle *vk, VkPhysicalDevice physical_device, const char *const *required_device_extensions, - size_t num_required_device_extensions, + uint32_t num_required_device_extensions, const char *const *optional_device_extensions, - size_t num_optional_device_extensions, + uint32_t num_optional_device_extensions, const char ***out_device_extensions, - size_t *out_num_device_extensions) + uint32_t *out_num_device_extensions) { VkExtensionProperties *props; uint32_t num_props; @@ -1046,7 +1046,7 @@ vk_build_device_extensions(struct vk_bundle *vk, return false; } - int max_exts = num_required_device_extensions + num_optional_device_extensions; + uint32_t max_exts = num_required_device_extensions + num_optional_device_extensions; const char **device_extensions = U_TYPED_ARRAY_CALLOC(const char *, max_exts); @@ -1098,7 +1098,7 @@ vk_create_device(struct vk_bundle *vk, } const char **device_extensions; - size_t num_device_extensions; + uint32_t num_device_extensions; if (!vk_build_device_extensions(vk, vk->physical_device, required_device_extensions, num_required_device_extensions, optional_device_extensions, num_optional_device_extensions, &device_extensions, &num_device_extensions)) { @@ -1220,6 +1220,7 @@ vk_init_from_given(struct vk_bundle *vk, goto err_memset; } + return VK_SUCCESS; err_memset: From 58ebd7ee2079c402a7e9744b3cf0e07423697db7 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 18:37:10 -0500 Subject: [PATCH 242/883] xrt: Adjust how we define ssize_t on MSVC --- src/xrt/include/xrt/xrt_compiler.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/xrt/include/xrt/xrt_compiler.h b/src/xrt/include/xrt/xrt_compiler.h index 19c97a4e5..43a22c42b 100644 --- a/src/xrt/include/xrt/xrt_compiler.h +++ b/src/xrt/include/xrt/xrt_compiler.h @@ -130,11 +130,9 @@ xrt_atomic_s32_cmpxchg(xrt_atomic_s32_t *p, int32_t old_, int32_t new_) } #ifdef _MSC_VER -#ifdef XRT_64_BIT -typedef int64_t ssize_t; -#else -typedef int32_t ssize_t; -#endif +typedef intptr_t ssize_t; +#define _SSIZE_T_ +#define _SSIZE_T_DEFINED #endif /*! From aefd8c06976bb97e03744b33b891cc7658265c5a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 24 Feb 2021 15:56:18 -0600 Subject: [PATCH 243/883] ipc/android: Be sure to init the mutexes. --- src/xrt/ipc/server/ipc_server_mainloop_android.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xrt/ipc/server/ipc_server_mainloop_android.c b/src/xrt/ipc/server/ipc_server_mainloop_android.c index fdd708da7..d87080198 100644 --- a/src/xrt/ipc/server/ipc_server_mainloop_android.c +++ b/src/xrt/ipc/server/ipc_server_mainloop_android.c @@ -63,8 +63,9 @@ init_epoll(struct ipc_server_mainloop *ml) return ret; } - pthread_mutex_init(&ml->accept_mutex, NULL); + pthread_mutex_init(&ml->client_push_mutex, NULL); pthread_cond_init(&ml->accept_cond, NULL); + pthread_mutex_init(&ml->accept_mutex, NULL); ml->epoll_fd = ret; struct epoll_event ev = {0}; From b3772e2710eb14456105db51f1190e9702c241be Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 15:45:53 -0500 Subject: [PATCH 244/883] cmake: Support multi-config generators --- src/xrt/targets/openxr/CMakeLists.txt | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/xrt/targets/openxr/CMakeLists.txt b/src/xrt/targets/openxr/CMakeLists.txt index 516ed71c0..bdc1ed95d 100644 --- a/src/xrt/targets/openxr/CMakeLists.txt +++ b/src/xrt/targets/openxr/CMakeLists.txt @@ -99,8 +99,27 @@ set(runtime_path $) # Need this step because file(GENERATE) only evaluates generator expressions, and not what configure_file does. configure_file(${MANIFEST_INPUT} ${CMAKE_CURRENT_BINARY_DIR}/intermediate_manifest.json) + +if(CMAKE_VERSION VERSION_LESS 3.9) + # best guess + if(CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(IS_MULTI_CONFIG FALSE) + else() + set(IS_MULTI_CONFIG TRUE) + endif() +else() + # 3.9+ have a global property with the truth + get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +endif() + +if(IS_MULTI_CONFIG) + set(DEV_MANIFEST_OUTPUT "${CMAKE_BINARY_DIR}/$/${RUNTIME_TARGET}-dev.json") +else() + set(DEV_MANIFEST_OUTPUT "${CMAKE_BINARY_DIR}/${RUNTIME_TARGET}-dev.json") +endif() + file(GENERATE - OUTPUT "${CMAKE_BINARY_DIR}/${RUNTIME_TARGET}-dev.json" + OUTPUT "${DEV_MANIFEST_OUTPUT}" INPUT ${CMAKE_CURRENT_BINARY_DIR}/intermediate_manifest.json) ### From ddc9b00d1474a81f918cc7437972cb3c500053db Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:16:29 -0500 Subject: [PATCH 245/883] os: Adjust how we compute the timeout for a semaphore. Preparation for overhaul of timing on Windows. --- src/xrt/auxiliary/os/os_threading.h | 37 ++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/xrt/auxiliary/os/os_threading.h b/src/xrt/auxiliary/os/os_threading.h index 5afb22a5d..6a6fc0606 100644 --- a/src/xrt/auxiliary/os/os_threading.h +++ b/src/xrt/auxiliary/os/os_threading.h @@ -180,6 +180,33 @@ os_semaphore_release(struct os_semaphore *os) sem_post(&os->sem); } +/*! + * Set @p ts to the current time, plus the timeout_ns value. + * + * Intended for use by the threading code only: the timestamps are not interchangeable with other sources of time. + */ +static inline int +os_semaphore_get_realtime_clock(struct timespec *ts, uint64_t timeout_ns) +{ +#if defined(XRT_OS_WINDOWS) + struct timespec relative; + os_ns_to_timespec(timeout_ns, &relative); + pthread_win32_getabstime_np(ts, &relative); + return 0; +#else + struct timespec now; + if (clock_gettime(CLOCK_REALTIME, &now) < 0) { + assert(false); + return -1; + } + uint64_t now_ns = os_timespec_to_ns(ts); + uint64_t when_ns = timeout_ns + now_ns; + + os_ns_to_timespec(when_ns, ts); + return 0; +#endif +} + /*! * Wait, if @p timeout_ns is zero then waits forever. */ @@ -191,17 +218,11 @@ os_semaphore_wait(struct os_semaphore *os, uint64_t timeout_ns) return; } - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + struct timespec abs_timeout; + if (os_semaphore_get_realtime_clock(&abs_timeout, timeout_ns) == -1) { assert(false); } - uint64_t now_ns = os_timespec_to_ns(&ts); - uint64_t when_ns = timeout_ns + now_ns; - - struct timespec abs_timeout = {0, 0}; - os_ns_to_timespec(when_ns, &abs_timeout); - sem_timedwait(&os->sem, &abs_timeout); } From 00915cab0fca11b5e84150a4f093a972b3d4c467 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:18:52 -0500 Subject: [PATCH 246/883] os: Add caveats to some timespec conversion functions. --- src/xrt/auxiliary/os/os_time.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xrt/auxiliary/os/os_time.h b/src/xrt/auxiliary/os/os_time.h index ff6e818ef..ad7670b57 100644 --- a/src/xrt/auxiliary/os/os_time.h +++ b/src/xrt/auxiliary/os/os_time.h @@ -81,6 +81,9 @@ os_nanosleep(long nsec) #ifdef XRT_HAVE_TIMESPEC /*! * @brief Convert a timespec struct to nanoseconds. + * + * Note that this just does the value combining, no adjustment for epochs is performed. + * * @ingroup aux_os_time_extra */ static inline uint64_t @@ -94,6 +97,8 @@ os_timespec_to_ns(const struct timespec *spec) /*! * @brief Convert an nanosecond integer to a timespec struct. + * + * Note that this just does the value splitting, no adjustment for epochs is performed. * @ingroup aux_os_time_extra */ static inline void From 071797585345a7f0cced63aef1cd530b9be1d800 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:19:41 -0500 Subject: [PATCH 247/883] os: Improve timestamp retrieval on Windows. --- src/xrt/auxiliary/os/os_time.h | 37 +++++++++++++--------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/xrt/auxiliary/os/os_time.h b/src/xrt/auxiliary/os/os_time.h index ad7670b57..bde4d8927 100644 --- a/src/xrt/auxiliary/os/os_time.h +++ b/src/xrt/auxiliary/os/os_time.h @@ -126,28 +126,6 @@ os_timeval_to_ns(struct timeval *val) } #endif // XRT_HAVE_TIMEVAL -#ifdef XRT_OS_WINDOWS -#define CLOCK_MONOTONIC 0 -#define CLOCK_REALTIME 1 - -static int -clock_gettime(int clk_id, struct timespec *spec) -{ - __int64 wintime; - - //! @todo We should be using QueryPerformanceCounter - GetSystemTimeAsFileTime((FILETIME *)&wintime); - // 1jan1601 to 1jan1970 - wintime -= 116444736000000000i64; - // seconds - spec->tv_sec = wintime / 10000000i64; - // nano-seconds - spec->tv_nsec = wintime % 10000000i64 * 100; - - return 0; -} - -#endif // XRT_OS_WINDOWS /*! * @brief Return a monotonic clock in nanoseconds. * @ingroup aux_os_time @@ -155,7 +133,7 @@ clock_gettime(int clk_id, struct timespec *spec) static inline uint64_t os_monotonic_get_ns(void) { -#if defined(XRT_OS_LINUX) || defined(XRT_OS_WINDOWS) +#if defined(XRT_OS_LINUX) struct timespec ts; int ret = clock_gettime(CLOCK_MONOTONIC, &ts); if (ret != 0) { @@ -163,6 +141,19 @@ os_monotonic_get_ns(void) } return os_timespec_to_ns(&ts); +#elif defined(XRT_OS_WINDOWS) + static int64_t ns_per_qpc_tick = 0; + if (ns_per_qpc_tick == 0) { + // Fixed at startup, so we can cache this. + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + ns_per_qpc_tick = U_1_000_000_000 / freq.QuadPart; + } + LARGE_INTEGER qpc; + QueryPerformanceCounter(&qpc); + return qpc.QuadPart * ns_per_qpc_tick; +#else +#error "need port" #endif } From 47bf17a0cc4955768fdbcb63a0c018f628e0b33b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:20:01 -0500 Subject: [PATCH 248/883] os: Improve comment and prototype for os_nanosleep --- src/xrt/auxiliary/os/os_time.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/os/os_time.h b/src/xrt/auxiliary/os/os_time.h index bde4d8927..a2e739b6a 100644 --- a/src/xrt/auxiliary/os/os_time.h +++ b/src/xrt/auxiliary/os/os_time.h @@ -60,13 +60,16 @@ extern "C" { * interoperation with platform APIs. */ - /*! * @brief Sleep the given number of nanoseconds. + * + * Note that on some platforms, this may be somewhat less accurate than you might want. + * On all platforms, the system scheduler has the final say. + * * @ingroup aux_os_time */ static inline void -os_nanosleep(long nsec) +os_nanosleep(int32_t nsec) { #if defined(XRT_OS_LINUX) struct timespec spec; From aa3d1c1f6a94f84e07259eaf3d7916b3c0d1ba28 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:20:39 -0500 Subject: [PATCH 249/883] os: Add os_precise_sleeper. Mostly to be able to use a timer on Windows. --- src/xrt/auxiliary/os/os_time.h | 72 +++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/os/os_time.h b/src/xrt/auxiliary/os/os_time.h index a2e739b6a..c5fbf66a6 100644 --- a/src/xrt/auxiliary/os/os_time.h +++ b/src/xrt/auxiliary/os/os_time.h @@ -81,7 +81,77 @@ os_nanosleep(int32_t nsec) #endif } -#ifdef XRT_HAVE_TIMESPEC +/*! + * @brief A structure for storing state as needed for more precise sleeping, mostly for compositor use. + * @ingroup aux_os_time + */ +struct os_precise_sleeper +{ +#if defined(XRT_OS_WINDOWS) + HANDLE timer; +#else + int unused_; +#endif +}; + +/*! + * @brief Initialize members of @ref os_precise_sleeper. + * @public @memberof os_precise_sleeper + */ +static inline void +os_precise_sleeper_init(struct os_precise_sleeper *ops) +{ +#if defined(XRT_OS_WINDOWS) + ops->timer = CreateWaitableTimer(NULL, TRUE, NULL); +#endif +} + +/*! + * @brief De-initialize members of @ref os_precise_sleeper, and free resources, without actually freeing the given + * pointer. + * @public @memberof os_precise_sleeper + */ +static inline void +os_precise_sleeper_deinit(struct os_precise_sleeper *ops) +{ +#if defined(XRT_OS_WINDOWS) + if (ops->timer) { + CloseHandle(ops->timer); + ops->timer = NULL; + } +#endif +} + +/*! + * @brief Sleep the given number of nanoseconds, trying harder to be precise. + * + * On some platforms, there is no way to improve sleep precision easily with some OS-specific state, so we just forward + * to os_nanosleep(). + * + * Note that on all platforms, the system scheduler has the final say. + * + * @public @memberof os_precise_sleeper + */ +static inline void +os_precise_sleeper_nanosleep(struct os_precise_sleeper *ops, int32_t nsec) +{ +#if defined(XRT_OS_WINDOWS) + if (ops->timer) { + LARGE_INTEGER timeperiod; + timeperiod.QuadPart = -nsec; + if (SetWaitableTimer(ops->timer, &timeperiod, 0, NULL, NULL, FALSE)) { + // OK we could set up the timer, now let's wait. + WaitForSingleObject(ops->timer, INFINITE); + return; + } + } +#endif + // If we fall through from an implementation, or there's no implementation needed for a platform, we just + // delegate to the regular os_nanosleep. + os_nanosleep(nsec); +} + +#if defined(XRT_HAVE_TIMESPEC) /*! * @brief Convert a timespec struct to nanoseconds. * From b3280c5bc1531563fe5e4faab906913a0d57672c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 11:53:10 -0500 Subject: [PATCH 250/883] os/time: Small cleanup. --- src/xrt/auxiliary/os/os_time.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/os/os_time.h b/src/xrt/auxiliary/os/os_time.h index c5fbf66a6..00a12bb60 100644 --- a/src/xrt/auxiliary/os/os_time.h +++ b/src/xrt/auxiliary/os/os_time.h @@ -183,7 +183,10 @@ os_ns_to_timespec(uint64_t ns, struct timespec *spec) #endif // XRT_HAVE_TIMESPEC -#ifdef XRT_HAVE_TIMEVAL +#if defined(XRT_HAVE_TIMEVAL) && defined(XRT_OS_LINUX) + +#define OS_NS_PER_USEC (1000) + /*! * @brief Convert a timeval struct to nanoseconds. * @ingroup aux_os_time_extra @@ -193,7 +196,6 @@ os_timeval_to_ns(struct timeval *val) { uint64_t ns = 0; ns += (uint64_t)val->tv_sec * U_1_000_000_000; -#define OS_NS_PER_USEC (1000) ns += (uint64_t)val->tv_usec * OS_NS_PER_USEC; return ns; } From f65635f3786cbee6cb46c1247e774b130608c5c5 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 12:08:52 -0500 Subject: [PATCH 251/883] aux/vk: Fix doxygen warning --- src/xrt/auxiliary/vk/vk_helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/vk/vk_helpers.h b/src/xrt/auxiliary/vk/vk_helpers.h index 38d3c394c..58c5e0d02 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.h +++ b/src/xrt/auxiliary/vk/vk_helpers.h @@ -281,7 +281,7 @@ bool vk_has_error(VkResult res, const char *fun, const char *file, int line); /*! - * @def + * @def vk_check_error * @brief Perform checking of a Vulkan result, returning in case it is not VK_SUCCESS. * * @param fun A string literal with the name of the Vulkan function, for logging purposes. @@ -299,7 +299,7 @@ vk_has_error(VkResult res, const char *fun, const char *file, int line); } while (0) /*! - * @def + * @def vk_check_error_with_free * @brief Perform checking of a Vulkan result, freeing an allocation and returning in case it is not VK_SUCCESS. * * @param fun A string literal with the name of the Vulkan function, for logging purposes. From 78301ae5ebb7e94e7f4042a570ee7c2e6ef2f2f1 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 12:09:51 -0500 Subject: [PATCH 252/883] comp: Use precise sleeper. --- src/xrt/compositor/main/comp_compositor.c | 7 ++++++- src/xrt/compositor/main/comp_compositor.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index c2f332f5d..485de1543 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -148,7 +148,8 @@ compositor_wait_frame(struct xrt_compositor *xc, uint64_t now_ns = os_monotonic_get_ns(); if (now_ns < wake_up_time_ns) { - os_nanosleep(wake_up_time_ns - now_ns); + uint32_t delay = (uint32_t)(wake_up_time_ns - now_ns); + os_precise_sleeper_nanosleep(&c->sleeper, delay); } now_ns = os_monotonic_get_ns(); @@ -580,6 +581,8 @@ system_compositor_destroy(struct xrt_system_compositor *xsc) free(c->compositor_frame_times.debug_var); } + os_precise_sleeper_deinit(&c->sleeper); + u_threading_stack_fini(&c->threading.destroy_swapchains); free(c); @@ -1196,6 +1199,8 @@ compositor_init_window_pre_vulkan(struct comp_compositor *c) static bool compositor_init_window_post_vulkan(struct comp_compositor *c) { + os_precise_sleeper_init(&c->sleeper); + if (c->settings.window_type == WINDOW_DIRECT_NVIDIA) { #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT return compositor_try_window(c, comp_window_direct_nvidia_create(c)); diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h index e25ff6e01..85a0b6415 100644 --- a/src/xrt/compositor/main/comp_compositor.h +++ b/src/xrt/compositor/main/comp_compositor.h @@ -199,6 +199,8 @@ struct comp_compositor //! State for generating the correct set of events. enum comp_state state; + struct os_precise_sleeper sleeper; + //! Triple buffered layer stacks. struct comp_layer_slot slots[3]; From 592df37c0f4ab70c7c6c5ad128a1b6ef7b228d10 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 12:10:06 -0500 Subject: [PATCH 253/883] comp: Fix some narrowing conversion warnings --- src/xrt/compositor/main/comp_compositor.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 485de1543..483fd2e15 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -199,18 +199,18 @@ compositor_add_frame_timing(struct comp_compositor *c) for (int i = 0; i < NUM_FRAME_TIMINGS; i++) { uint64_t frametime_ns = c->compositor_frame_times.times_ns[i + 1] - c->compositor_frame_times.times_ns[i]; - float frametime_s = frametime_ns * 1. / 1000. * 1. / 1000. * 1. / 1000.; + float frametime_s = frametime_ns * 1.f / 1000.f * 1.f / 1000.f * 1.f / 1000.f; total_s += frametime_s; } float avg_frametime_s = total_s / ((float)NUM_FRAME_TIMINGS); - c->compositor_frame_times.fps = 1. / avg_frametime_s; + c->compositor_frame_times.fps = 1.f / avg_frametime_s; } c->compositor_frame_times.times_ns[c->compositor_frame_times.index] = os_monotonic_get_ns(); uint64_t diff = c->compositor_frame_times.times_ns[c->compositor_frame_times.index] - c->compositor_frame_times.times_ns[last_index]; - c->compositor_frame_times.timings_ms[c->compositor_frame_times.index] = (float)diff * 1. / 1000. * 1. / 1000.; + c->compositor_frame_times.timings_ms[c->compositor_frame_times.index] = (float)diff * 1.f / 1000.f * 1.f / 1000.f; } static xrt_result_t @@ -1430,7 +1430,7 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos struct u_var_timing *ft = U_TYPED_CALLOC(struct u_var_timing); - float target_frame_time_ms = c->settings.nominal_frame_interval_ns * 1. / 1000. * 1. / 1000.; + float target_frame_time_ms = c->settings.nominal_frame_interval_ns * 1.f / 1000.f * 1.f / 1000.f; uint64_t now = os_monotonic_get_ns(); for (int i = 0; i < NUM_FRAME_TIMES; i++) { From 061ae2f7b7a0cbd8205c7d5a9e69161e41761d05 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 12:10:20 -0500 Subject: [PATCH 254/883] xrt: Fix more narrowing conversion warnings. --- src/xrt/include/xrt/xrt_device.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/xrt/include/xrt/xrt_device.h b/src/xrt/include/xrt/xrt_device.h index d42aed082..f33631a67 100644 --- a/src/xrt/include/xrt/xrt_device.h +++ b/src/xrt/include/xrt/xrt_device.h @@ -125,20 +125,20 @@ struct xrt_hmd_parts //! Data. float *vertices; //! Number of vertices. - size_t num_vertices; + uint32_t num_vertices; //! Stride of vertices - size_t stride; + uint32_t stride; //! 1 or 3 for (chromatic aberration). - size_t num_uv_channels; + uint32_t num_uv_channels; //! Indices, for triangle strip. int *indices; //! Number of indices for the triangle strip. - size_t num_indices[2]; + uint32_t num_indices[2]; //! Offsets for the indices. - size_t offset_indices[2]; + uint32_t offset_indices[2]; //! Total number of indices. - size_t total_num_indices; + uint32_t total_num_indices; } mesh; } distortion; }; From 942091c10db07eda952bea6840deb0f4b6c59793 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 15:01:21 -0500 Subject: [PATCH 255/883] comp: Enable VK_EXT_debug_report extension --- doc/vulkan-extensions.md | 3 +++ src/xrt/compositor/main/comp_compositor.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/vulkan-extensions.md b/doc/vulkan-extensions.md index 07d4487a2..7eaa7a8b1 100644 --- a/doc/vulkan-extensions.md +++ b/doc/vulkan-extensions.md @@ -43,6 +43,8 @@ minimize frustration. | [`VK_KHR_external_semaphore`][] (8) (+platform: 7) | yes (soon) ||||||| | [`VK_KHR_swapchain`][] | | yes |||||| +[`VK_EXT_debug_report`][] is also used. + ## Notes Kept out of the table above to limit its width. @@ -85,6 +87,7 @@ Kept out of the table above to limit its width. [`VK_KHR_display`]: https://khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_display.html [`VK_KHR_xcb_surface`]: https://khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_xcb_surface.html [`VK_KHR_wayland_surface`]: https://khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_wayland_surface.html +[`VK_EXT_debug_report`]: https://khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_debug_report.html [`VK_EXT_direct_mode_display`]: https://khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_direct_mode_display.html [`VK_EXT_acquire_xlib_display`]: https://khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_acquire_xlib_display.html [`VK_KHR_android_surface`]: https://khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_android_surface.html diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 483fd2e15..b7662c3c6 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -661,8 +661,8 @@ find_get_instance_proc_addr(struct comp_compositor *c) // in `vulkan-extensions.md` #define COMP_INSTANCE_EXTENSIONS_COMMON \ - VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, \ - VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, \ + VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, \ + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, \ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_KHR_SURFACE_EXTENSION_NAME static const char *instance_extensions_none[] = {COMP_INSTANCE_EXTENSIONS_COMMON}; From d4c352ef69d401307f7a8ee5b960356283939d7a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 15:01:44 -0500 Subject: [PATCH 256/883] comp: Improve Windows errors. --- src/xrt/compositor/main/comp_window_mswin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_window_mswin.c b/src/xrt/compositor/main/comp_window_mswin.c index 4bf343579..e1d8c2272 100644 --- a/src/xrt/compositor/main/comp_window_mswin.c +++ b/src/xrt/compositor/main/comp_window_mswin.c @@ -126,7 +126,7 @@ comp_window_mswin_init_swapchain(struct comp_target *ct, uint32_t width, uint32_ ret = comp_window_mswin_create_surface(cwm, &cwm->base.surface.handle); if (ret != VK_SUCCESS) { - COMP_ERROR(ct->c, "Failed to create surface!"); + COMP_ERROR(ct->c, "Failed to create surface '%s'!", vk_result_string(ret)); return false; } From 0139aa15256b923fd8d2df44d3741e9884244c68 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 30 Mar 2021 15:02:14 -0500 Subject: [PATCH 257/883] comp: Fix conversion warnings --- src/xrt/compositor/main/comp_compositor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index b7662c3c6..b27bf37cb 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -210,7 +210,8 @@ compositor_add_frame_timing(struct comp_compositor *c) uint64_t diff = c->compositor_frame_times.times_ns[c->compositor_frame_times.index] - c->compositor_frame_times.times_ns[last_index]; - c->compositor_frame_times.timings_ms[c->compositor_frame_times.index] = (float)diff * 1.f / 1000.f * 1.f / 1000.f; + c->compositor_frame_times.timings_ms[c->compositor_frame_times.index] = + (float)diff * 1.f / 1000.f * 1.f / 1000.f; } static xrt_result_t From a5db03948605c2f20b6d049643a49ced8610b473 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 31 Mar 2021 12:05:24 -0500 Subject: [PATCH 258/883] doc: Add changelog fragments. --- doc/changes/misc_features/mr.739.md | 3 +++ doc/changes/misc_fixes/mr.737.md | 1 + 2 files changed, 4 insertions(+) create mode 100644 doc/changes/misc_features/mr.739.md create mode 100644 doc/changes/misc_fixes/mr.737.md diff --git a/doc/changes/misc_features/mr.739.md b/doc/changes/misc_features/mr.739.md new file mode 100644 index 000000000..b6f9cc364 --- /dev/null +++ b/doc/changes/misc_features/mr.739.md @@ -0,0 +1,3 @@ +--- +--- +More work on the Windows port: fix timing, waiting, sleeping. diff --git a/doc/changes/misc_fixes/mr.737.md b/doc/changes/misc_fixes/mr.737.md new file mode 100644 index 000000000..6c8ff1590 --- /dev/null +++ b/doc/changes/misc_fixes/mr.737.md @@ -0,0 +1 @@ +Ensure we are always initializing our mutexes. From 4061bf7707129d2ad1fd5894b316408a9e7af1de Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Tue, 9 Mar 2021 01:23:31 +0100 Subject: [PATCH 259/883] d/multi: Add "attached" tracking override type Example usage: Leap Motion attached to a Northstar headset. --- src/xrt/auxiliary/util/u_config_json.c | 16 ++++ src/xrt/drivers/multi_wrapper/multi.c | 77 +++++++++++++++++-- src/xrt/drivers/multi_wrapper/multi.h | 4 +- src/xrt/include/xrt/xrt_settings.h | 7 ++ .../gui/gui_scene_tracking_overrides.c | 33 ++++++++ src/xrt/state_trackers/prober/p_prober.c | 5 +- 6 files changed, 132 insertions(+), 10 deletions(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 392a7f8b6..714f8dc2e 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -284,6 +284,14 @@ u_config_json_get_tracking_overrides(struct u_config_json *json, bad |= !get_obj_str(override, "target_device_serial", o->target_device_serial, XRT_DEVICE_NAME_LEN); bad |= !get_obj_str(override, "tracker_device_serial", o->tracker_device_serial, XRT_DEVICE_NAME_LEN); + char override_type[256]; + bad |= !get_obj_str(override, "type", override_type, 256); + if (strncmp(override_type, "direct", 256) == 0) { + o->override_type = XRT_TRACKING_OVERRIDE_DIRECT; + } else if (strncmp(override_type, "attached", 256) == 0) { + o->override_type = XRT_TRACKING_OVERRIDE_ATTACHED; + } + cJSON *offset = cJSON_GetObjectItemCaseSensitive(override, "offset"); if (offset) { cJSON *orientation = cJSON_GetObjectItemCaseSensitive(offset, "orientation"); @@ -445,6 +453,14 @@ u_config_json_save_overrides(struct u_config_json *json, struct xrt_tracking_ove cJSON_AddStringToObject(entry, "target_device_serial", overrides[i].target_device_serial); cJSON_AddStringToObject(entry, "tracker_device_serial", overrides[i].tracker_device_serial); + + char override_type[256]; + switch (overrides[i].override_type) { + case XRT_TRACKING_OVERRIDE_DIRECT: strncpy(override_type, "direct", 256); break; + case XRT_TRACKING_OVERRIDE_ATTACHED: strncpy(override_type, "attached", 256); break; + } + cJSON_AddStringToObject(entry, "type", override_type); + cJSON_AddItemToObject(entry, "offset", make_pose(&overrides[i].offset)); cJSON_AddItemToArray(o, entry); diff --git a/src/xrt/drivers/multi_wrapper/multi.c b/src/xrt/drivers/multi_wrapper/multi.c index 4d52d4057..41a03dfe9 100644 --- a/src/xrt/drivers/multi_wrapper/multi.c +++ b/src/xrt/drivers/multi_wrapper/multi.c @@ -34,8 +34,48 @@ struct multi_device enum xrt_input_name input_name; struct xrt_pose offset_inv; } tracking_override; + + enum xrt_tracking_override_type override_type; }; +static void +direct_override(struct multi_device *d, + struct xrt_space_relation *tracker_relation, + struct xrt_space_relation *out_relation) +{ + struct xrt_space_graph xsg = {0}; + m_space_graph_add_pose_if_not_identity(&xsg, &d->tracking_override.offset_inv); + m_space_graph_add_relation(&xsg, tracker_relation); + m_space_graph_resolve(&xsg, out_relation); +} + +static void +attached_override(struct multi_device *d, + struct xrt_space_relation *target_relation, + struct xrt_pose *target_offset, + struct xrt_space_relation *tracker_relation, + struct xrt_pose *tracker_offset, + struct xrt_space_relation *in_target_space, + struct xrt_space_relation *out_relation) +{ + /* Example: + * - target: hand tracking xrt_device + * - tracker: positional tracker that the target is physically attached to + * - in_target_space: a tracked hand, relative to target's tracking origin + */ + + // XXX TODO tracking origin offsets + // m_space_graph_add_inverted_pose_if_not_identity(&xsg, tracker_offset); + // m_space_graph_add_inverted_relation(&xsg, tracker_relation); + + struct xrt_space_graph xsg = {0}; + m_space_graph_add_relation(&xsg, target_relation); + m_space_graph_add_pose_if_not_identity(&xsg, &d->tracking_override.offset_inv); + m_space_graph_add_relation(&xsg, tracker_relation); + m_space_graph_add_pose_if_not_identity(&xsg, tracker_offset); + m_space_graph_add_relation(&xsg, in_target_space); + m_space_graph_resolve(&xsg, out_relation); +} static void get_tracked_pose(struct xrt_device *xdev, @@ -45,14 +85,35 @@ get_tracked_pose(struct xrt_device *xdev, { struct multi_device *d = (struct multi_device *)xdev; struct xrt_device *tracker = d->tracking_override.tracker; - enum xrt_input_name input_name = d->tracking_override.input_name; + enum xrt_input_name tracker_input_name = d->tracking_override.input_name; - tracker->get_tracked_pose(tracker, input_name, at_timestamp_ns, out_relation); + struct xrt_space_relation tracker_relation; - struct xrt_space_graph xsg = {0}; - m_space_graph_add_pose_if_not_identity(&xsg, &d->tracking_override.offset_inv); - m_space_graph_add_relation(&xsg, out_relation); - m_space_graph_resolve(&xsg, out_relation); + xrt_device_get_tracked_pose(tracker, tracker_input_name, at_timestamp_ns, &tracker_relation); + + switch (d->override_type) { + case XRT_TRACKING_OVERRIDE_DIRECT: { + direct_override(d, &tracker_relation, out_relation); + } break; + case XRT_TRACKING_OVERRIDE_ATTACHED: { + struct xrt_device *target = d->tracking_override.target; + + struct xrt_space_relation target_relation; + xrt_device_get_tracked_pose(target, name, at_timestamp_ns, &target_relation); + + + // just use the origin of the tracker space as reference frame + struct xrt_space_relation in_target_space; + m_space_relation_ident(&in_target_space); + in_target_space.relation_flags = tracker_relation.relation_flags; + + struct xrt_pose *target_offset = &d->tracking_override.target->tracking_origin->offset; + struct xrt_pose *tracker_offset = &d->tracking_override.tracker->tracking_origin->offset; + + attached_override(d, &target_relation, target_offset, &tracker_relation, tracker_offset, + &in_target_space, out_relation); + } break; + } } static void @@ -113,7 +174,8 @@ update_inputs(struct xrt_device *xdev) struct xrt_device * -multi_create_tracking_override(struct xrt_device *tracking_override_target, +multi_create_tracking_override(enum xrt_tracking_override_type override_type, + struct xrt_device *tracking_override_target, struct xrt_device *tracking_override_tracker, enum xrt_input_name tracking_override_input_name, struct xrt_pose *offset) @@ -125,6 +187,7 @@ multi_create_tracking_override(struct xrt_device *tracking_override_target, } d->ll = debug_get_log_option_multi_log(); + d->override_type = override_type; // mimic the tracking override target d->base = *tracking_override_target; diff --git a/src/xrt/drivers/multi_wrapper/multi.h b/src/xrt/drivers/multi_wrapper/multi.h index 0e2ab035d..3be7244e1 100644 --- a/src/xrt/drivers/multi_wrapper/multi.h +++ b/src/xrt/drivers/multi_wrapper/multi.h @@ -11,6 +11,7 @@ #include "xrt/xrt_defines.h" #include "xrt/xrt_device.h" +#include "xrt/xrt_settings.h" #ifdef __cplusplus extern "C" { @@ -41,7 +42,8 @@ extern "C" { * @ingroup drv_multi */ struct xrt_device * -multi_create_tracking_override(struct xrt_device *tracking_override_target, +multi_create_tracking_override(enum xrt_tracking_override_type override_type, + struct xrt_device *tracking_override_target, struct xrt_device *tracking_override_tracker, enum xrt_input_name tracking_override_input_name, struct xrt_pose *offset); diff --git a/src/xrt/include/xrt/xrt_settings.h b/src/xrt/include/xrt/xrt_settings.h index 812b2c8ae..506f78093 100644 --- a/src/xrt/include/xrt/xrt_settings.h +++ b/src/xrt/include/xrt/xrt_settings.h @@ -41,12 +41,19 @@ enum xrt_settings_camera_type #define XRT_MAX_TRACKING_OVERRIDES 16 +enum xrt_tracking_override_type +{ + XRT_TRACKING_OVERRIDE_DIRECT = 0, + XRT_TRACKING_OVERRIDE_ATTACHED, +}; + struct xrt_tracking_override { char target_device_serial[XRT_DEVICE_NAME_LEN]; char tracker_device_serial[XRT_DEVICE_NAME_LEN]; enum xrt_input_name input_name; struct xrt_pose offset; + enum xrt_tracking_override_type override_type; }; /*! diff --git a/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c b/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c index c12ddb5c7..904f96ed6 100644 --- a/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c +++ b/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c @@ -30,6 +30,7 @@ struct gui_tracking_overrides bool add_one; int add_target; int add_tracker; + enum xrt_tracking_override_type override_type; struct u_config_json config; @@ -39,6 +40,11 @@ struct gui_tracking_overrides struct xrt_tracking_override overrides[XRT_MAX_TRACKING_OVERRIDES]; }; +static char *override_type_str[2] = { + [XRT_TRACKING_OVERRIDE_DIRECT] = "direct", + [XRT_TRACKING_OVERRIDE_ATTACHED] = "attached", +}; + static ImVec2 button_dims = {256 + 64, 0}; /* @@ -165,6 +171,15 @@ add_one(struct gui_program *p, struct gui_tracking_overrides *ts) } igEnd(); + igBegin("Tracking Override Type", NULL, 0); + for (int i = 0; i < 2; i++) { + bool selected = (int)ts->override_type == i; + if (igCheckbox(override_type_str[i], &selected)) { + ts->override_type = (enum xrt_tracking_override_type)i; + } + } + igEnd(); + if (ts->add_target >= 0 && ts->add_tracker >= 0 && ts->add_target != ts->add_tracker) { struct xrt_tracking_override *o = &ts->overrides[ts->num_overrides]; o->input_name = XRT_INPUT_GENERIC_TRACKER_POSE; @@ -178,6 +193,8 @@ add_one(struct gui_program *p, struct gui_tracking_overrides *ts) ts->add_tracker = -1; ts->add_one = false; + + ts->override_type = 0; } } @@ -186,6 +203,11 @@ scene_render(struct gui_scene *scene, struct gui_program *p) { struct gui_tracking_overrides *ts = (struct gui_tracking_overrides *)scene; + // don't edit and add at the same time + if (ts->add_one) { + ts->editing_override = -1; + } + if (ts->editing_override >= 0) { struct xrt_tracking_override *o = &ts->overrides[ts->editing_override]; @@ -199,6 +221,13 @@ scene_render(struct gui_scene *scene, struct gui_program *p) } handle_draggable_vec3_f32("Position", &o->offset.position, &ts->reset_offset.position); handle_draggable_quat("Orientation", &o->offset.orientation, &ts->reset_offset.orientation); + + for (int i = 0; i < 2; i++) { + bool selected = (int)o->override_type == i; + if (igCheckbox(override_type_str[i], &selected)) { + o->override_type = (enum xrt_tracking_override_type)i; + } + } igEnd(); } @@ -221,6 +250,10 @@ scene_render(struct gui_scene *scene, struct gui_program *p) snprintf(buf, sizeof(buf), "%s <- %s", ts->overrides[i].target_device_serial, ts->overrides[i].tracker_device_serial); if (igCheckbox(buf, &checked)) { + + // abort adding override when clicking to edit one + ts->add_one = false; + ts->editing_override = i; ts->reset_offset = ts->overrides[i].offset; } diff --git a/src/xrt/state_trackers/prober/p_prober.c b/src/xrt/state_trackers/prober/p_prober.c index e762809cd..03ecb1233 100644 --- a/src/xrt/state_trackers/prober/p_prober.c +++ b/src/xrt/state_trackers/prober/p_prober.c @@ -8,6 +8,7 @@ */ #include "xrt/xrt_config_drivers.h" +#include "xrt/xrt_settings.h" #include "util/u_var.h" #include "util/u_misc.h" @@ -806,8 +807,8 @@ apply_tracking_override(struct prober *p, struct xrt_device **xdevs, size_t num_ if (target_xdev != NULL && tracker_xdev != NULL) { - struct xrt_device *multi = - multi_create_tracking_override(target_xdev, tracker_xdev, o->input_name, &o->offset); + struct xrt_device *multi = multi_create_tracking_override(o->override_type, target_xdev, tracker_xdev, + o->input_name, &o->offset); if (multi) { // drops the target device from the list, but keeps the tracker From d54b65375164ceefed8470e5bdd11dbb82e4a0a5 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Fri, 12 Mar 2021 02:48:36 -0600 Subject: [PATCH 260/883] d/multi: correctly override hand pose for "attached" tracking --- src/xrt/drivers/multi_wrapper/multi.c | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/xrt/drivers/multi_wrapper/multi.c b/src/xrt/drivers/multi_wrapper/multi.c index 41a03dfe9..869e5026c 100644 --- a/src/xrt/drivers/multi_wrapper/multi.c +++ b/src/xrt/drivers/multi_wrapper/multi.c @@ -138,6 +138,36 @@ get_hand_tracking(struct xrt_device *xdev, struct multi_device *d = (struct multi_device *)xdev; struct xrt_device *target = d->tracking_override.target; xrt_device_get_hand_tracking(target, name, at_timestamp_ns, out_value); + + struct xrt_device *tracker = d->tracking_override.tracker; + struct xrt_space_relation tracker_relation; + xrt_device_get_tracked_pose(tracker, XRT_INPUT_GENERIC_TRACKER_POSE, at_timestamp_ns, &tracker_relation); + + + switch (d->override_type) { + case XRT_TRACKING_OVERRIDE_DIRECT: { + // XXX: Codepath not tested. Probably doesn't do what you want. + direct_override(d, &out_value->hand_pose, &out_value->hand_pose); + + } break; + case XRT_TRACKING_OVERRIDE_ATTACHED: { + + // struct xrt_space_relation target_relation; + // xrt_device_get_tracked_pose(target, name, at_timestamp_ns, &target_relation); + + + // just use the origin of the tracker space as reference frame + struct xrt_space_relation in_target_space; + m_space_relation_ident(&in_target_space); + in_target_space.relation_flags = tracker_relation.relation_flags; + + struct xrt_pose *target_offset = &d->tracking_override.target->tracking_origin->offset; + struct xrt_pose *tracker_offset = &d->tracking_override.tracker->tracking_origin->offset; + + attached_override(d, &out_value->hand_pose, target_offset, &tracker_relation, tracker_offset, + &in_target_space, &out_value->hand_pose); + } break; + } } static void From c776a19e15b70fa832e214fa533cf351abfc563e Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Fri, 5 Mar 2021 17:13:27 -0600 Subject: [PATCH 261/883] aux/math: Implement math_matrix_3x3_multiply. --- src/xrt/auxiliary/math/m_api.h | 12 ++++++++++++ src/xrt/auxiliary/math/m_base.cpp | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/xrt/auxiliary/math/m_api.h b/src/xrt/auxiliary/math/m_api.h index d3483a61a..aafbd373a 100644 --- a/src/xrt/auxiliary/math/m_api.h +++ b/src/xrt/auxiliary/math/m_api.h @@ -4,6 +4,7 @@ * @file * @brief C interface to math library. * @author Jakob Bornecrantz + * @author Moses Turner * * @see xrt_vec3 * @see xrt_quat @@ -311,6 +312,17 @@ math_matrix_3x3_transform_vec3(const struct xrt_matrix_3x3 *left, const struct xrt_vec3 *right, struct xrt_vec3 *result); +/*! + * Multiply Matrix3x3. + * + * @relates xrt_matrix_3x3 + * @ingroup aux_math + */ +void +math_matrix_3x3_multiply(const struct xrt_matrix_3x3 *left, + const struct xrt_matrix_3x3 *right, + struct xrt_matrix_3x3 *result); + /*! * Initialize Matrix4x4 with identity. * diff --git a/src/xrt/auxiliary/math/m_base.cpp b/src/xrt/auxiliary/math/m_base.cpp index b01e68064..f6040ccce 100644 --- a/src/xrt/auxiliary/math/m_base.cpp +++ b/src/xrt/auxiliary/math/m_base.cpp @@ -5,6 +5,7 @@ * @brief Base implementations for math library. * @author Jakob Bornecrantz * @author Ryan Pavlik + * @author Moses Turner * @ingroup aux_math */ @@ -314,6 +315,23 @@ math_matrix_3x3_transform_vec3(const struct xrt_matrix_3x3 *left, const struct x map_vec3(*result) = m * copy(right); } +extern "C" void +math_matrix_3x3_multiply(const struct xrt_matrix_3x3 *left, + const struct xrt_matrix_3x3 *right, + struct xrt_matrix_3x3 *result) +{ + result->v[0] = left->v[0] * right->v[0] + left->v[1] * right->v[3] + left->v[2] * right->v[6]; + result->v[1] = left->v[0] * right->v[1] + left->v[1] * right->v[4] + left->v[2] * right->v[7]; + result->v[2] = left->v[0] * right->v[2] + left->v[1] * right->v[5] + left->v[2] * right->v[8]; + + result->v[3] = left->v[3] * right->v[0] + left->v[4] * right->v[3] + left->v[5] * right->v[6]; + result->v[4] = left->v[3] * right->v[1] + left->v[4] * right->v[4] + left->v[5] * right->v[7]; + result->v[5] = left->v[3] * right->v[2] + left->v[4] * right->v[5] + left->v[5] * right->v[8]; + + result->v[6] = left->v[6] * right->v[0] + left->v[7] * right->v[3] + left->v[8] * right->v[6]; + result->v[7] = left->v[6] * right->v[1] + left->v[7] * right->v[4] + left->v[8] * right->v[7]; + result->v[8] = left->v[6] * right->v[2] + left->v[7] * right->v[5] + left->v[8] * right->v[8]; +} void math_matrix_4x4_identity(struct xrt_matrix_4x4 *result) From a02785276743d3d50482075ea4a78e59cccf5dab Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Fri, 5 Mar 2021 17:17:54 -0600 Subject: [PATCH 262/883] aux/math: implement math_pose_identity. --- src/xrt/auxiliary/math/m_api.h | 12 +++++++++++- src/xrt/auxiliary/math/m_base.cpp | 16 ++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/xrt/auxiliary/math/m_api.h b/src/xrt/auxiliary/math/m_api.h index aafbd373a..c78664d79 100644 --- a/src/xrt/auxiliary/math/m_api.h +++ b/src/xrt/auxiliary/math/m_api.h @@ -1,4 +1,4 @@ -// Copyright 2019, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -379,6 +379,16 @@ math_matrix_4x4_inverse_view_projection(const struct xrt_matrix_4x4 *view, * */ + +/*! + * Somewhat laboriously make an xrt_pose identity. + * + * @relates xrt_pose + * @ingroup aux_math + */ +void +math_pose_identity(struct xrt_pose *pose); + /*! * Check if this pose can be used in transformation operations. * diff --git a/src/xrt/auxiliary/math/m_base.cpp b/src/xrt/auxiliary/math/m_base.cpp index f6040ccce..e75fc35ff 100644 --- a/src/xrt/auxiliary/math/m_base.cpp +++ b/src/xrt/auxiliary/math/m_base.cpp @@ -317,8 +317,8 @@ math_matrix_3x3_transform_vec3(const struct xrt_matrix_3x3 *left, const struct x extern "C" void math_matrix_3x3_multiply(const struct xrt_matrix_3x3 *left, - const struct xrt_matrix_3x3 *right, - struct xrt_matrix_3x3 *result) + const struct xrt_matrix_3x3 *right, + struct xrt_matrix_3x3 *result) { result->v[0] = left->v[0] * right->v[0] + left->v[1] * right->v[3] + left->v[2] * right->v[6]; result->v[1] = left->v[0] * right->v[1] + left->v[1] * right->v[4] + left->v[2] * right->v[7]; @@ -419,6 +419,18 @@ math_pose_invert(const struct xrt_pose *pose, struct xrt_pose *outPose) orientation(*outPose) = newOrientation; } +extern "C" void +math_pose_identity(struct xrt_pose *pose) +{ + pose->position.x = 0.0; + pose->position.y = 0.0; + pose->position.z = 0.0; + pose->orientation.x = 0.0; + pose->orientation.y = 0.0; + pose->orientation.z = 0.0; + pose->orientation.w = 1.0; +} + /*! * Return the result of transforming a point by a pose/transform. */ From 6a833b1131b575a9b83ce60f70a5cfa2e64c508b Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Sun, 7 Mar 2021 10:41:57 -0600 Subject: [PATCH 263/883] st/oxr+xrt: add is_active to struct xrt_hand_joint_set to give drivers an easy way to deactivate hands --- src/xrt/include/xrt/xrt_defines.h | 4 +++- src/xrt/state_trackers/oxr/oxr_session.c | 12 ++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/xrt/include/xrt/xrt_defines.h b/src/xrt/include/xrt/xrt_defines.h index 2503340b7..e5a0fe985 100644 --- a/src/xrt/include/xrt/xrt_defines.h +++ b/src/xrt/include/xrt/xrt_defines.h @@ -1,9 +1,10 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file * @brief Common defines and enums for XRT. * @author Jakob Bornecrantz + * @author Moses Turner * @ingroup xrt_iface */ @@ -754,6 +755,7 @@ struct xrt_hand_joint_set // in driver global space, without tracking_origin offset struct xrt_space_relation hand_pose; + bool is_active; }; /*! diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 727c63206..857121ec2 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -1,9 +1,10 @@ -// Copyright 2018-2020, Collabora, Ltd. +// Copyright 2018-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file * @brief Holds session related functions. * @author Jakob Bornecrantz + * @author Moses Turner * @ingroup oxr_main */ @@ -2260,7 +2261,14 @@ oxr_session_hand_joints(struct oxr_logger *log, } } - locations->isActive = true; + if (value.is_active) { + locations->isActive = true; + } else { + locations->isActive = false; + for (uint32_t i = 0; i < locations->jointCount; i++) { + locations->jointLocations[i].locationFlags = XRT_SPACE_RELATION_BITMASK_NONE; + } + } return XR_SUCCESS; } From b319371500be92a153f508be225f8bfbf6f0389f Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Tue, 16 Mar 2021 02:48:06 -0500 Subject: [PATCH 264/883] d/survive: for now always set xrt_hand_joint_set->is_active to true --- src/xrt/drivers/survive/survive_driver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index 43cd83935..e575ce167 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -437,6 +437,8 @@ survive_controller_get_hand_tracking(struct xrt_device *xdev, u_hand_joints_set_out_data(&survive->ctrl.hand_tracking, hand, &survive->last_relation, &hand_on_handle_pose, out_value); + out_value->is_active = true; // Apparently libsurvive doesn't report controller tracked/untracked state, so just + // lie and say that the hand is being tracked } static void From 55b86fe815b85cacd40b459177be132d99559afe Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Mon, 29 Mar 2021 17:31:12 -0500 Subject: [PATCH 265/883] d/ulv2: Create the driver. Co-authored-by: Moses Turner Co-authored-by: Christoph Haag --- CMakeLists.txt | 16 + .../config_v0.json.northstar_lonestar | 57 ++- meson.build | 9 + src/xrt/drivers/CMakeLists.txt | 9 + src/xrt/drivers/meson.build | 11 + src/xrt/drivers/ultraleap_v2/readme.MD | 12 + src/xrt/drivers/ultraleap_v2/ulv2_driver.cpp | 452 ++++++++++++++++++ src/xrt/drivers/ultraleap_v2/ulv2_interface.h | 35 ++ src/xrt/targets/common/CMakeLists.txt | 4 + src/xrt/targets/common/target_lists.c | 8 + src/xrt/targets/meson.build | 4 + 11 files changed, 599 insertions(+), 18 deletions(-) create mode 100644 src/xrt/drivers/ultraleap_v2/readme.MD create mode 100644 src/xrt/drivers/ultraleap_v2/ulv2_driver.cpp create mode 100644 src/xrt/drivers/ultraleap_v2/ulv2_interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 337183880..b2eee630c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,19 @@ find_package(cJSON) find_package(Systemd) find_package(OpenGLES COMPONENTS V3) +#find_package(Leap) + +find_library(Leap + NAMES libLeap.so + PATHS /usr/local/lib + ) +if (Leap) + include_directories(include /usr/local/include/) + message(STATUS "Found libLeap: ${Leap}") +else() + message(STATUS "Could NOT find libLeap: (missing: /usr/local/lib/libLeap.so)") +endif() + # Android SDK doesn't look for 3.8 and 3.9, which is what new distros ship with. set(Python_ADDITIONAL_VERSIONS 3.8 3.9) if(NOT CMAKE_VERSION VERSION_LESS 3.12) @@ -185,6 +198,7 @@ cmake_dependent_option(XRT_BUILD_DRIVER_ARDUINO "Enable Arduino input device wit cmake_dependent_option(XRT_BUILD_DRIVER_ILLIXR "Enable ILLIXR driver" ON "ILLIXR_PATH" OFF) option(XRT_BUILD_DRIVER_DUMMY "Enable dummy driver" ON) +cmake_dependent_option(XRT_BUILD_DRIVER_ULV2 "Enable Ultraleap v2 driver" ON "Leap" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_REMOTE "Enable remote debugging driver" ON "XRT_HAVE_LINUX OR ANDROID" OFF) # These all use the Monado internal hid wrapper. @@ -219,6 +233,7 @@ list(APPEND AVAILABLE_DRIVERS "REMOTE" "SURVIVE" "V4L2" + "ULV2" "VF" "VIVE" "QWERTY" @@ -350,6 +365,7 @@ message(STATUS "# DRIVER_HDK: ${XRT_BUILD_DRIVER_HDK}") message(STATUS "# DRIVER_HYDRA: ${XRT_BUILD_DRIVER_HYDRA}") message(STATUS "# DRIVER_ILLIXR: ${XRT_BUILD_DRIVER_ILLIXR}") message(STATUS "# DRIVER_NS: ${XRT_BUILD_DRIVER_NS}") +message(STATUS "# DRIVER_ULV2: ${XRT_BUILD_DRIVER_ULV2}") message(STATUS "# DRIVER_OHMD: ${XRT_BUILD_DRIVER_OHMD}") message(STATUS "# DRIVER_PSMV: ${XRT_BUILD_DRIVER_PSMV}") message(STATUS "# DRIVER_PSVR: ${XRT_BUILD_DRIVER_PSVR}") diff --git a/doc/example_configs/config_v0.json.northstar_lonestar b/doc/example_configs/config_v0.json.northstar_lonestar index 0d422a762..b33710f75 100644 --- a/doc/example_configs/config_v0.json.northstar_lonestar +++ b/doc/example_configs/config_v0.json.northstar_lonestar @@ -1,23 +1,44 @@ { - "active": "tracking", - "tracking": { - "tracking_overrides": [{ - "target_device_serial": "North Star", - "tracker_device_serial": "Intel RealSense 6-DOF", - "offset": { - "orientation": { - "x": 0, - "y": -0.068300001323223114, - "z": 0.074400000274181366, - "w": 0.99468898773193359 + "active": "tracking", + "tracking": { + "tracking_overrides": [ + { + "target_device_serial": "North Star", + "tracker_device_serial": "Intel RealSense 6-DOF", + "type": "direct", + "offset": { + "orientation": { + "x": -0.102931, + "y": 0, + "z": 0, + "w": 0.994689 }, - "position": { - "x": 0, - "y": -0.068300001323223114, - "z": 0.074400000274181366 + "position": { + "x": 0, + "y": 0.0683, + "z": -0.0744 } } - }], - "version": 0 + }, + { + "target_device_serial": "Leap Motion v2 driver", + "tracker_device_serial": "Intel RealSense 6-DOF", + "type": "attached", + "offset": { + "orientation": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "position": { + "x": 0, + "y": 0.005, + "z": 0 + } + } + } + ], + "version": 0 } -} +} \ No newline at end of file diff --git a/meson.build b/meson.build index 11b31f8ff..c65b9f091 100644 --- a/meson.build +++ b/meson.build @@ -78,6 +78,9 @@ gst_video= dependency('gstreamer-video-1.0', required: false) gst_found = gst.found() and gst_app.found() and gst_video.found() +leap = cc.find_library('Leap', dirs : ['/usr/local/lib'], required: false) +inc_leap = include_directories('/usr/local/include') + opencv = dependency('opencv4', required: false) if not opencv.found() opencv = dependency('opencv', required: get_option('tracking')) @@ -207,6 +210,12 @@ if gst_found and ('auto' in drivers or 'vf' in drivers) endif endif +if leap.found() and ('auto' in drivers or 'ulv2' in drivers) + if 'ulv2' not in drivers + drivers += ['ulv2'] + endif +endif + if survive.found() and ('auto' in drivers and 'survive' not in drivers) drivers += ['survive'] endif diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index d0e3033cc..913e4b0b9 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -101,6 +101,15 @@ if(XRT_BUILD_DRIVER_NS) list(APPEND ENABLED_HEADSET_DRIVERS ns) endif() +if(XRT_BUILD_DRIVER_ULV2) + set(ULV2_SOURCE_FILES + ultraleap_v2/ulv2_driver.cpp + ultraleap_v2/ulv2_interface.h + ) + add_library(drv_ulv2 STATIC ${ULV2_SOURCE_FILES}) + target_link_libraries(drv_ulv2 PRIVATE xrt-interfaces aux_util aux_math Leap) +endif() + if(XRT_BUILD_DRIVER_OHMD) set(OHMD_SOURCE_FILES ohmd/oh_device.c diff --git a/src/xrt/drivers/meson.build b/src/xrt/drivers/meson.build index 18b6a6a87..fba34c8ef 100644 --- a/src/xrt/drivers/meson.build +++ b/src/xrt/drivers/meson.build @@ -58,6 +58,17 @@ lib_drv_ns = static_library( build_by_default: 'ns' in drivers, ) +lib_drv_ulv2 = static_library( + 'drv_ulv2', + files( + 'ultraleap_v2/ulv2_driver.cpp', + 'ultraleap_v2/ulv2_interface.h', + ), + include_directories: [xrt_include, inc_leap], + dependencies: [aux, leap], + build_by_default: 'ulv2' in drivers, +) + lib_drv_ht = static_library( 'drv_ht', files( diff --git a/src/xrt/drivers/ultraleap_v2/readme.MD b/src/xrt/drivers/ultraleap_v2/readme.MD new file mode 100644 index 000000000..692d4ac02 --- /dev/null +++ b/src/xrt/drivers/ultraleap_v2/readme.MD @@ -0,0 +1,12 @@ +## Building +To build you need `Leap.h` and `LeapMath.h` in `/usr/local/include`; and `libLeap.so` in `/usr/local/lib`, and this should automatically build. + +## Running +To have the ultraleap driver successfully initialize, you need to have the Leap Motion Controller plugged in, and `leapd` running. Running `sudo leapd` in another terminal works but it may be slightly more convenient to have it run as a systemd service. + +## Configuring +Presumably, you're using this driver because you want to stick the Leap Motion Controller on the front of your HMD and have it track your hands. + +If you don't have a config file at ~/.config/monado/config_v0.json (or wherever you set `XDG_CONFIG_DIR`), your tracked hands will show up near the tracking origin and not move around with your HMD, which is probably not what you want. + +Instead you probably want to configure Monado to make your Leap Motion Controller-tracked hands follow around your HMD. There's an example of how to do this with North Star in `doc/example_configs/config_v0.json.northstar_lonestar`. If you're using a North Star headset, that should work but unless you're using the Lone Star NS variant you'll need to edit the offsets. If you're using some other HMD you'll have to edit the `tracker_device_serial` to be your HMD serial, and your own offsets. \ No newline at end of file diff --git a/src/xrt/drivers/ultraleap_v2/ulv2_driver.cpp b/src/xrt/drivers/ultraleap_v2/ulv2_driver.cpp new file mode 100644 index 000000000..d05891c68 --- /dev/null +++ b/src/xrt/drivers/ultraleap_v2/ulv2_driver.cpp @@ -0,0 +1,452 @@ +// Copyright 2020-2021, Collabora, Ltd. +// Copyright 2020-2021, Moses Turner +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Driver for Ultraleap's V2 API for the Leap Motion Controller. + * @author Moses Turner + * @author Christoph Haag + * @ingroup drv_ulv2 + */ + +#include "ulv2_interface.h" +#include "util/u_device.h" +#include "util/u_var.h" +#include "util/u_debug.h" +#include "math/m_space.h" +#include "math/m_api.h" +#include "util/u_time.h" +#include "os/os_time.h" +#include "os/os_threading.h" + +#include "Leap.h" + +DEBUG_GET_ONCE_LOG_OPTION(ulv2_log, "ULV2_LOG", U_LOGGING_INFO) + +#define ULV2_TRACE(ulv2d, ...) U_LOG_XDEV_IFL_T(&ulv2d->base, ulv2d->ll, __VA_ARGS__) +#define ULV2_DEBUG(ulv2d, ...) U_LOG_XDEV_IFL_D(&ulv2d->base, ulv2d->ll, __VA_ARGS__) +#define ULV2_INFO(ulv2d, ...) U_LOG_XDEV_IFL_I(&ulv2d->base, ulv2d->ll, __VA_ARGS__) +#define ULV2_WARN(ulv2d, ...) U_LOG_XDEV_IFL_W(&ulv2d->base, ulv2d->ll, __VA_ARGS__) +#define ULV2_ERROR(ulv2d, ...) U_LOG_XDEV_IFL_E(&ulv2d->base, ulv2d->ll, __VA_ARGS__) + +#define printf_pose(pose) \ + printf("%f %f %f %f %f %f %f\n", pose.position.x, pose.position.y, pose.position.z, pose.orientation.x, \ + pose.orientation.y, pose.orientation.z, pose.orientation.w); +extern "C" { + +enum xrt_space_relation_flags valid_flags = (enum xrt_space_relation_flags)( + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | + XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT); + +// Excuse my sketchy thread stuff, I'm sure this violates all kinds of best practices. It uusssuallyyy doesn't explode. +// -Moses Turner +enum leap_thread_status +{ + THREAD_NOT_STARTED, + THREAD_OK, + THREAD_ERRORED_OUT, +}; + +struct ulv2_device +{ + struct xrt_device base; + + struct xrt_tracking_origin tracking_origin; + + enum u_logging_level ll; + + bool pthread_should_stop; + + enum leap_thread_status our_thread_status; + + struct os_thread_helper leap_loop_oth; + + struct xrt_hand_joint_set joints_write_in[2]; + + // Only read/write these last two if you have the mutex + struct xrt_hand_joint_set joints_read_out[2]; + + bool hand_exists[2]; +}; + +inline struct ulv2_device * +ulv2_device(struct xrt_device *xdev) +{ + return (struct ulv2_device *)xdev; +} + + +// Roughly, take the Leap hand joint, do some coordinate conversions, and save it in a xrt_hand_joint_value +static void +ulv2_process_joint( + Leap::Vector jointpos, Leap::Matrix jointbasis, float width, int side, struct xrt_hand_joint_value *joint) +{ + struct xrt_space_relation *relation = &joint->relation; + joint->radius = (width / 1000) / 2; + + struct xrt_matrix_3x3 turn_into_quat; + // clang-format off + // These are matrices so we want to preserve where the rows and columns are, hence the clang-format off + if (side == 1) + { + turn_into_quat = {-jointbasis.xBasis.x, -jointbasis.yBasis.x, -jointbasis.zBasis.x, + -jointbasis.xBasis.z, -jointbasis.yBasis.z, -jointbasis.zBasis.z, + -jointbasis.xBasis.y, -jointbasis.yBasis.y, -jointbasis.zBasis.y}; + } + else + { + turn_into_quat = {jointbasis.xBasis.x, -jointbasis.yBasis.x, -jointbasis.zBasis.x, + jointbasis.xBasis.z, -jointbasis.yBasis.z, -jointbasis.zBasis.z, + jointbasis.xBasis.y, -jointbasis.yBasis.y, -jointbasis.zBasis.y}; + } + // clang-format on + + + math_quat_from_matrix_3x3(&turn_into_quat, &relation->pose.orientation); + relation->pose.position.x = jointpos.x * -1 / 1000.0; + relation->pose.position.y = jointpos.z * -1 / 1000.0; + relation->pose.position.z = jointpos.y * -1 / 1000.0; + relation->relation_flags = valid_flags; +} + +static int error_time; // Lazy counter to prevent printing error messages at 120hz + + +void +ulv2_process_hand(Leap::Hand hand, xrt_hand_joint_set *joint_set, int hi) +{ + +#define xrtj(y) &joint_set->values.hand_joint_set_default[XRT_HAND_JOINT_##y] + + ulv2_process_joint(hand.palmPosition(), hand.basis(), 50, hi, xrtj(PALM)); + ulv2_process_joint(hand.wristPosition(), hand.arm().basis(), 50, hi, xrtj(WRIST)); + + const Leap::FingerList fingers = hand.fingers(); + + // Bunch of macros to make the following + // boilerplate easier to deal with + +#define fb(y) finger.bone(y) +#define prevJ(y) finger.bone(y).prevJoint() +#define nextJ(y) finger.bone(y).nextJoint() + +#define lm Leap::Bone::TYPE_METACARPAL +#define lp Leap::Bone::TYPE_PROXIMAL +#define li Leap::Bone::TYPE_INTERMEDIATE +#define ld Leap::Bone::TYPE_DISTAL + + for (Leap::FingerList::const_iterator fl = fingers.begin(); fl != fingers.end(); ++fl) { + // Iterate on the list of fingers Leap gives us + const Leap::Finger finger = *fl; + Leap::Finger::Type fingerType = finger.type(); + switch (fingerType) { + case Leap::Finger::Type::TYPE_THUMB: + // If the finger is a thumb, then for each joint: process the Leap joint location, + // rotation matrix, finger width, hand side (0 if left, 1 if right), + // and write the finger radius and powe out to the correct xrt_hand_joint_value. + ulv2_process_joint(prevJ(lp), fb(lp).basis(), fb(lp).width(), hi, xrtj(THUMB_METACARPAL)); + ulv2_process_joint(prevJ(li), fb(li).basis(), fb(lp).width(), hi, xrtj(THUMB_PROXIMAL)); + ulv2_process_joint(prevJ(ld), fb(ld).basis(), fb(li).width(), hi, xrtj(THUMB_DISTAL)); + ulv2_process_joint(nextJ(ld), fb(ld).basis(), fb(ld).width(), hi, xrtj(THUMB_TIP)); + // Note that there are only four joints here as opposed to all the other fingers which have five + // joints. + break; + case Leap::Finger::Type::TYPE_INDEX: + // If the finger is an index finger, do the same thing but with index joints + ulv2_process_joint(prevJ(lm), fb(lm).basis(), fb(lm).width(), hi, xrtj(INDEX_METACARPAL)); + ulv2_process_joint(prevJ(lp), fb(lp).basis(), fb(lm).width(), hi, xrtj(INDEX_PROXIMAL)); + ulv2_process_joint(prevJ(li), fb(li).basis(), fb(lp).width(), hi, xrtj(INDEX_INTERMEDIATE)); + ulv2_process_joint(prevJ(ld), fb(ld).basis(), fb(li).width(), hi, xrtj(INDEX_DISTAL)); + ulv2_process_joint(nextJ(ld), fb(ld).basis(), fb(ld).width(), hi, xrtj(INDEX_TIP)); + break; + case Leap::Finger::Type::TYPE_MIDDLE: + // If the finger is a middle finger, do the same thing but with middle joints + ulv2_process_joint(prevJ(lm), fb(lm).basis(), fb(lm).width(), hi, xrtj(MIDDLE_METACARPAL)); + ulv2_process_joint(prevJ(lp), fb(lp).basis(), fb(lm).width(), hi, xrtj(MIDDLE_PROXIMAL)); + ulv2_process_joint(prevJ(li), fb(li).basis(), fb(lp).width(), hi, xrtj(MIDDLE_INTERMEDIATE)); + ulv2_process_joint(prevJ(ld), fb(ld).basis(), fb(li).width(), hi, xrtj(MIDDLE_DISTAL)); + ulv2_process_joint(nextJ(ld), fb(ld).basis(), fb(ld).width(), hi, xrtj(MIDDLE_TIP)); + break; + case Leap::Finger::Type::TYPE_RING: + // Ad nauseum. + ulv2_process_joint(prevJ(lm), fb(lm).basis(), fb(lm).width(), hi, xrtj(RING_METACARPAL)); + ulv2_process_joint(prevJ(lp), fb(lp).basis(), fb(lm).width(), hi, xrtj(RING_PROXIMAL)); + ulv2_process_joint(prevJ(li), fb(li).basis(), fb(lp).width(), hi, xrtj(RING_INTERMEDIATE)); + ulv2_process_joint(prevJ(ld), fb(ld).basis(), fb(li).width(), hi, xrtj(RING_DISTAL)); + ulv2_process_joint(nextJ(ld), fb(ld).basis(), fb(ld).width(), hi, xrtj(RING_TIP)); + break; + case Leap::Finger::Type::TYPE_PINKY: + ulv2_process_joint(prevJ(lm), fb(lm).basis(), fb(lm).width(), hi, xrtj(LITTLE_METACARPAL)); + ulv2_process_joint(prevJ(lp), fb(lp).basis(), fb(lm).width(), hi, xrtj(LITTLE_PROXIMAL)); + ulv2_process_joint(prevJ(li), fb(li).basis(), fb(lp).width(), hi, xrtj(LITTLE_INTERMEDIATE)); + ulv2_process_joint(prevJ(ld), fb(ld).basis(), fb(li).width(), hi, xrtj(LITTLE_DISTAL)); + ulv2_process_joint(nextJ(ld), fb(ld).basis(), fb(ld).width(), hi, xrtj(LITTLE_TIP)); + break; + // I hear that Sagittarius has a better api, in C even, so hopefully + // there'll be less weird boilerplate whenever we get access to that + } + } +} + +void * +leap_input_loop(void *ptr_to_xdev) +{ + float retry_sleep_time = 0.05; + float timeout = 0.5; + int num_tries = (timeout / retry_sleep_time); + bool succeeded_connected = false; + bool succeeded_service_connected = false; + + struct xrt_device *xdev = (struct xrt_device *)ptr_to_xdev; + struct ulv2_device *ulv2d = ulv2_device(xdev); + ULV2_DEBUG(ulv2d, "num tries %d; sleep time %f", num_tries, timeout); + + Leap::Controller LeapController; + os_nanosleep(U_1_000_000_000 * 0.01); + // sleep for an arbitrary amount of time so that Leap::Controller can initialize and connect to the service. + float start = (float)os_monotonic_get_ns() / (float)U_1_000_000_000; + // would be nice to do this only if we're not building release ^^. don't know how to do that though. + + for (int i = 0; i < num_tries; i++) { + succeeded_connected = LeapController.isConnected(); + succeeded_service_connected = LeapController.isServiceConnected(); + if (succeeded_connected) { + ULV2_INFO(ulv2d, "Leap Motion Controller connected!"); + break; + } + if (succeeded_service_connected) { + ULV2_INFO(ulv2d, + "Connected to Leap service, but not " + "connected to Leap Motion " + "controller. Retrying (%i / %i)", + i, num_tries); + // This codepath should very rarely get hit as nowadays this gets probed by VID/PID, so you'd + // have to be pretty fast to unplug after it gets probed and before this check. + } else { + ULV2_INFO(ulv2d, + "Not connected to Leap service. " + "Retrying (%i / %i)", + i, num_tries); + } + os_nanosleep(U_1_000_000_000 * retry_sleep_time); // 1 second * retry_sleep_time + } + + ULV2_DEBUG(ulv2d, "Waited %f seconds", ((float)os_monotonic_get_ns() / (float)U_1_000_000_000) - start); + + bool hmdpolicyset = false; + + + if (!succeeded_connected) { + if (succeeded_service_connected) { + ULV2_INFO(ulv2d, + "Connected to Leap service, but couldn't " + "connect to leap motion controller.\n" + "Is it plugged in and has your Leap service " + "detected it?"); + // ditto on this codepath + } else { + ULV2_INFO(ulv2d, + "Couldn't connect to Leap service. Try " + "running sudo leapd in another terminal."); + } + goto cleanup_leap_loop; + } + + // Try to let the Leap service know that we are on a HMD, not on a desk. + for (int i = 0; i < num_tries; i++) { + LeapController.setPolicy(Leap::Controller::POLICY_OPTIMIZE_HMD); + os_nanosleep(time_s_to_ns(0.02)); + LeapController.setPolicy(Leap::Controller::POLICY_OPTIMIZE_HMD); + hmdpolicyset = LeapController.isPolicySet(Leap::Controller::POLICY_OPTIMIZE_HMD); + if (!hmdpolicyset) { + ULV2_ERROR(ulv2d, "Couldn't set HMD policy. Retrying (%i / %i)", i, num_tries); + } else { + ULV2_DEBUG(ulv2d, "HMD policy set."); + break; + } + os_nanosleep(U_1_000_000_000 * retry_sleep_time); // 1 second * retry_sleep_time + } + ULV2_TRACE(ulv2d, "thread OK\n"); + ulv2d->our_thread_status = THREAD_OK; + + + // Main loop + while (!ulv2d->pthread_should_stop) { + + if (!LeapController.isConnected()) { + if ((error_time % 100) == 0) + ULV2_ERROR(ulv2d, "LeapController is not connected\n"); + os_nanosleep(U_1_000_000_000 * 0.1); + error_time += 1; + continue; + } + error_time = 100; // if there's an error next time, the modulo will return 0. + + Leap::Frame frame = LeapController.frame(); + Leap::HandList hands = frame.hands(); + bool leftbeendone = false; + bool rightbeendone = false; + for (Leap::HandList::const_iterator hl = hands.begin(); hl != hands.end(); ++hl) { + int hi; // hand index + const Leap::Hand hand = *hl; + // if (hand.confidence() < *hand_min_confidence) + // continue; + if (hand.isLeft()) { + if (leftbeendone) + continue; // in case there are more than one left hand + leftbeendone = true; + hi = 0; + } + if (!hand.isLeft()) { + if (rightbeendone) + continue; // in case there are more than one right hand + rightbeendone = true; + hi = 1; + } + + ulv2_process_hand(hand, &ulv2d->joints_write_in[hi], hi); + } + os_thread_helper_lock(&ulv2d->leap_loop_oth); + memcpy(&ulv2d->joints_read_out, &ulv2d->joints_write_in, sizeof(struct xrt_hand_joint_set) * 2); + //! @todo (Moses Turner) Could be using LeapController.now() to try to emulate our own pose prediction, + //! but I ain't got time for that + ulv2d->hand_exists[0] = leftbeendone; + ulv2d->hand_exists[1] = rightbeendone; + os_thread_helper_unlock(&ulv2d->leap_loop_oth); + } + +cleanup_leap_loop: + ULV2_TRACE(ulv2d, "leaving input thread\n"); + ulv2d->our_thread_status = THREAD_ERRORED_OUT; + pthread_exit(NULL); +} + +static void +ulv2_device_update_inputs(struct xrt_device *xdev) +{ + // Empty +} + + +static void +ulv2_device_get_hand_tracking(struct xrt_device *xdev, + enum xrt_input_name name, + uint64_t at_timestamp_ns, + struct xrt_hand_joint_set *out_value) +{ + + //! @todo this function doesn't do anything with at_timestamp_ns, + // would be nice to add pose-prediction. Probably once leap motion sagittarius comes out for Linux + + struct ulv2_device *ulv2d = ulv2_device(xdev); + + if (name != XRT_INPUT_GENERIC_HAND_TRACKING_LEFT && name != XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT) { + ULV2_ERROR(ulv2d, "unknown input name for hand tracker"); + return; + } + + bool hand_index = (name == XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT); // 0 if left, 1 if right. + + bool hand_valid = ulv2d->hand_exists[hand_index]; + + os_thread_helper_lock(&ulv2d->leap_loop_oth); + memcpy(out_value, &ulv2d->joints_read_out[hand_index], sizeof(struct xrt_hand_joint_set)); + hand_valid = ulv2d->hand_exists[hand_index]; + os_thread_helper_unlock(&ulv2d->leap_loop_oth); + m_space_relation_ident(&out_value->hand_pose); + + if (hand_valid) { + out_value->is_active = true; + out_value->hand_pose.relation_flags = valid_flags; + } else { + out_value->is_active = false; + } +} + +static void +ulv2_device_destroy(struct xrt_device *xdev) +{ + struct ulv2_device *ulv2d = ulv2_device(xdev); + + ulv2d->pthread_should_stop = true; + os_thread_helper_stop(&ulv2d->leap_loop_oth); + + // Remove the variable tracking. + u_var_remove_root(ulv2d); + + u_device_free(&ulv2d->base); +} + +int +ulv2_found(struct xrt_prober *xp, + struct xrt_prober_device **devices, + size_t num_devices, + size_t index, + cJSON *attached_data, + struct xrt_device **out_xdev) +{ + enum u_device_alloc_flags flags = U_DEVICE_ALLOC_NO_FLAGS; + + int num_hands = 2; + + struct ulv2_device *ulv2d = U_DEVICE_ALLOCATE(struct ulv2_device, flags, num_hands, 0); + + os_thread_helper_init(&ulv2d->leap_loop_oth); + os_thread_helper_start(&ulv2d->leap_loop_oth, (&leap_input_loop), (void *)&ulv2d->base); + + ulv2d->base.tracking_origin = &ulv2d->tracking_origin; + ulv2d->base.tracking_origin->type = XRT_TRACKING_TYPE_OTHER; + + math_pose_identity(&ulv2d->base.tracking_origin->offset); + + ulv2d->ll = debug_get_log_option_ulv2_log(); + + ulv2d->base.update_inputs = ulv2_device_update_inputs; + ulv2d->base.get_hand_tracking = ulv2_device_get_hand_tracking; + ulv2d->base.destroy = ulv2_device_destroy; + + strncpy(ulv2d->base.str, "Leap Motion v2 driver", XRT_DEVICE_NAME_LEN); + strncpy(ulv2d->base.serial, "Leap Motion v2 driver", XRT_DEVICE_NAME_LEN); + + ulv2d->base.inputs[0].name = XRT_INPUT_GENERIC_HAND_TRACKING_LEFT; + ulv2d->base.inputs[1].name = XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT; + + ulv2d->base.name = XRT_DEVICE_HAND_TRACKER; + + ulv2d->base.device_type = XRT_DEVICE_TYPE_HAND_TRACKER; + ulv2d->base.hand_tracking_supported = true; + + u_var_add_root(ulv2d, "Leap Motion v2 driver", true); + u_var_add_ro_text(ulv2d, ulv2d->base.str, "Name"); + + + + uint64_t start_time = os_monotonic_get_ns(); + uint64_t too_long = time_s_to_ns(15.0f); + + while (ulv2d->our_thread_status != THREAD_OK) { + ULV2_TRACE(ulv2d, "waiting... thread status is %d", ulv2d->our_thread_status); + if (ulv2d->our_thread_status == THREAD_ERRORED_OUT) + goto cleanup; + if ((os_monotonic_get_ns() - (uint64_t)start_time) > too_long) { + ULV2_ERROR(ulv2d, + "For some reason the Leap thread locked up. This is a serious error and should " + "never happen."); + goto cleanup; + } + os_nanosleep(time_s_to_ns(0.01)); + } + + + ULV2_INFO(ulv2d, "Hand Tracker initialized!"); + + out_xdev[0] = &ulv2d->base; + + return 1; + +cleanup: + ulv2_device_destroy(&ulv2d->base); + return 0; +} + +} // extern "C" diff --git a/src/xrt/drivers/ultraleap_v2/ulv2_interface.h b/src/xrt/drivers/ultraleap_v2/ulv2_interface.h new file mode 100644 index 000000000..40c5843db --- /dev/null +++ b/src/xrt/drivers/ultraleap_v2/ulv2_interface.h @@ -0,0 +1,35 @@ +// Copyright 2020-2021, Collabora, Ltd. +// Copyright 2020-2021, Moses Turner. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Driver for Ultraleap's V2 API for the Leap Motion Controller. + * @author Moses Turner + * @author Christoph Haag + * @ingroup drv_ulv2 + */ + +#pragma once + +#include "math/m_api.h" +#include "xrt/xrt_device.h" +#include "xrt/xrt_prober.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ULV2_VID 0xf182 +#define ULV2_PID 0x0003 + +int +ulv2_found(struct xrt_prober *xp, + struct xrt_prober_device **devices, + size_t num_devices, + size_t index, + cJSON *attached_data, + struct xrt_device **out_xdev); + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/targets/common/CMakeLists.txt b/src/xrt/targets/common/CMakeLists.txt index 30d048686..9095da43e 100644 --- a/src/xrt/targets/common/CMakeLists.txt +++ b/src/xrt/targets/common/CMakeLists.txt @@ -44,6 +44,10 @@ if(XRT_BUILD_DRIVER_NS) target_link_libraries(target_lists PRIVATE drv_ns) endif() +if(XRT_BUILD_DRIVER_ULV2) + target_link_libraries(target_lists PRIVATE drv_ulv2) +endif() + if(XRT_BUILD_DRIVER_OHMD) target_link_libraries(target_lists PRIVATE drv_ohmd) endif() diff --git a/src/xrt/targets/common/target_lists.c b/src/xrt/targets/common/target_lists.c index 8b51cdbd8..4413fbe62 100644 --- a/src/xrt/targets/common/target_lists.c +++ b/src/xrt/targets/common/target_lists.c @@ -70,6 +70,10 @@ #include "realsense/rs_interface.h" #endif +#ifdef XRT_BUILD_DRIVER_ULV2 +#include "ultraleap_v2/ulv2_interface.h" +#endif + #ifdef XRT_BUILD_DRIVER_QWERTY #include "qwerty/qwerty_interface.h" #endif @@ -113,6 +117,10 @@ struct xrt_prober_entry target_entry_list[] = { {VALVE_VID, VIVE_WATCHMAN_DONGLE_GEN2, vive_controller_found, "Valve Watchman Wireless Device", "vive"}, #endif +#ifdef XRT_BUILD_DRIVER_ULV2 + {ULV2_VID, ULV2_PID, ulv2_found, "Leap Motion Controller", "ulv2"}, +#endif + {0x0000, 0x0000, NULL, NULL, NULL}, // Terminate }; diff --git a/src/xrt/targets/meson.build b/src/xrt/targets/meson.build index d3ebd476f..9ac834703 100644 --- a/src/xrt/targets/meson.build +++ b/src/xrt/targets/meson.build @@ -81,6 +81,10 @@ if 'remote' in drivers driver_libs += [lib_drv_remote] endif +if 'ulv2' in drivers + driver_libs += [lib_drv_ulv2] +endif + driver_libs += [lib_drv_multi] subdir('common') From cebc8ebed590c06c6da1416f051ec64af59a481f Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 30 Mar 2021 21:17:10 +0100 Subject: [PATCH 266/883] st/oxr: No longer need to work around depth Swapchain on Unreal --- doc/changes/state_trackers/mr.740.md | 1 + src/xrt/state_trackers/oxr/oxr_instance.c | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 doc/changes/state_trackers/mr.740.md diff --git a/doc/changes/state_trackers/mr.740.md b/doc/changes/state_trackers/mr.740.md new file mode 100644 index 000000000..6af700fe9 --- /dev/null +++ b/doc/changes/state_trackers/mr.740.md @@ -0,0 +1 @@ +OpenXR: Unreal Engine 4 depth buffer quirk no longer needed. diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c index 50abe2c66..088d498e6 100644 --- a/src/xrt/state_trackers/oxr/oxr_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_instance.c @@ -160,12 +160,15 @@ detect_engine(struct oxr_logger *log, struct oxr_instance *inst, const XrInstanc static void apply_quirks(struct oxr_logger *log, struct oxr_instance *inst) { +#if 0 + // This is no longer needed. if (starts_with("UnrealEngine", inst->appinfo.detected.engine.name) && // inst->appinfo.detected.engine.major == 4 && // inst->appinfo.detected.engine.minor <= 27 && // inst->appinfo.detected.engine.patch <= 0) { inst->quirks.disable_vulkan_format_depth_stencil = true; } +#endif } XrResult From 9695e90d954203b802e8ba122de6aecb8a8a8702 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 1 Apr 2021 00:07:23 +0100 Subject: [PATCH 267/883] d/vive: Setup the variable tracking for imu fusion --- doc/changes/drivers/mr.740.md | 1 + src/xrt/drivers/vive/vive_device.c | 7 ++----- src/xrt/drivers/vive/vive_device.h | 8 +------- 3 files changed, 4 insertions(+), 12 deletions(-) create mode 100644 doc/changes/drivers/mr.740.md diff --git a/doc/changes/drivers/mr.740.md b/doc/changes/drivers/mr.740.md new file mode 100644 index 000000000..9895eac1c --- /dev/null +++ b/doc/changes/drivers/mr.740.md @@ -0,0 +1 @@ +vive: Setup the variable tracking for imu fusion. diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index 169f9e766..dde1edee8 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -389,8 +389,6 @@ update_imu(struct vive_device *d, const void *buffer) } d->imu.time_ns += dt_ns; - d->last.acc = acceleration; - d->last.gyro = angular_velocity; d->imu.sequence = seq; m_imu_3dof_update(&d->fusion, d->imu.time_ns, &acceleration, &angular_velocity); @@ -858,14 +856,13 @@ vive_device_create(struct os_hid_device *mainboard_dev, m_imu_3dof_init(&d->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); u_var_add_root(d, "Vive Device", true); + u_var_add_gui_header(d, &d->gui.fusion, "3DoF Fusion"); + m_imu_3dof_add_vars(&d->fusion, d, ""); u_var_add_gui_header(d, &d->gui.calibration, "Calibration"); u_var_add_vec3_f32(d, &d->config.imu.acc_scale, "acc_scale"); u_var_add_vec3_f32(d, &d->config.imu.acc_bias, "acc_bias"); u_var_add_vec3_f32(d, &d->config.imu.gyro_scale, "gyro_scale"); u_var_add_vec3_f32(d, &d->config.imu.gyro_bias, "gyro_bias"); - u_var_add_gui_header(d, &d->gui.last, "Last data"); - u_var_add_vec3_f32(d, &d->last.acc, "acc"); - u_var_add_vec3_f32(d, &d->last.gyro, "gyro"); int ret; diff --git a/src/xrt/drivers/vive/vive_device.h b/src/xrt/drivers/vive/vive_device.h index 806c47051..93700b56c 100644 --- a/src/xrt/drivers/vive/vive_device.h +++ b/src/xrt/drivers/vive/vive_device.h @@ -51,12 +51,6 @@ struct vive_device struct m_imu_3dof fusion; - struct - { - struct xrt_vec3 acc; - struct xrt_vec3 gyro; - } last; - struct { uint16_t ipd; @@ -73,7 +67,7 @@ struct vive_device struct { bool calibration; - bool last; + bool fusion; } gui; struct vive_config config; From 85ff0dc73cb1b0f8406fc4022543f6e08ae8bc04 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 1 Apr 2021 23:54:17 +0200 Subject: [PATCH 268/883] xrt: Add msft_hand_interaction path to cache and check func --- src/xrt/state_trackers/oxr/oxr_api_action.c | 2 ++ src/xrt/state_trackers/oxr/oxr_instance.c | 2 ++ src/xrt/state_trackers/oxr/oxr_objects.h | 1 + 3 files changed, 5 insertions(+) diff --git a/src/xrt/state_trackers/oxr/oxr_api_action.c b/src/xrt/state_trackers/oxr/oxr_api_action.c index 21f019634..e6afdbed0 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_action.c +++ b/src/xrt/state_trackers/oxr/oxr_api_action.c @@ -136,6 +136,8 @@ oxr_xrSuggestInteractionProfileBindings(XrInstance instance, func = oxr_verify_valve_index_controller_subpath; } else if (ip == inst->path_cache.mndx_ball_on_a_stick_controller) { func = oxr_verify_mndx_ball_on_a_stick_controller_subpath; + } else if (ip == inst->path_cache.msft_hand_interaction) { + func = oxr_verify_microsoft_hand_interaction_subpath; } else { return oxr_error(&log, XR_ERROR_PATH_UNSUPPORTED, "(suggestedBindings->interactionProfile == \"%s\") is not " diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c index 088d498e6..ddbdc6315 100644 --- a/src/xrt/state_trackers/oxr/oxr_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_instance.c @@ -234,6 +234,8 @@ oxr_instance_create(struct oxr_logger *log, const XrInstanceCreateInfo *createIn cache_path(log, inst, "/interaction_profiles/oculus/touch_controller", &inst->path_cache.oculus_touch_controller); cache_path(log, inst, "/interaction_profiles/valve/index_controller", &inst->path_cache.valve_index_controller); cache_path(log, inst, "/interaction_profiles/mndx/ball_on_a_stick_controller", &inst->path_cache.mndx_ball_on_a_stick_controller); + cache_path(log, inst, "/interaction_profiles/microsoft/hand_interaction", &inst->path_cache.msft_hand_interaction); + // clang-format on // fill in our application info - @todo - replicate all createInfo diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index 883931228..181139ac7 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -1184,6 +1184,7 @@ struct oxr_instance XrPath oculus_touch_controller; XrPath valve_index_controller; XrPath mndx_ball_on_a_stick_controller; + XrPath msft_hand_interaction; } path_cache; struct From 7ce07aeedf8ba4d096c97c3619e3bed4cb408950 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 1 Apr 2021 23:56:49 +0200 Subject: [PATCH 269/883] st/oxr: Support all known interaction profiles in selection Remove the default case to generate a compiler warning when new profiles are missing. --- src/xrt/state_trackers/oxr/oxr_binding.c | 32 +++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/oxr/oxr_binding.c b/src/xrt/state_trackers/oxr/oxr_binding.c index 168c8b1fc..a1e77f17c 100644 --- a/src/xrt/state_trackers/oxr/oxr_binding.c +++ b/src/xrt/state_trackers/oxr/oxr_binding.c @@ -323,7 +323,37 @@ oxr_find_profile_for_device(struct oxr_logger *log, interaction_profile_find(log, inst, inst->path_cache.khr_simple_controller, out_p); interaction_profile_find(log, inst, inst->path_cache.htc_vive_controller, out_p); return; - default: return; + case XRT_DEVICE_TOUCH_CONTROLLER: + interaction_profile_find(log, inst, inst->path_cache.khr_simple_controller, out_p); + interaction_profile_find(log, inst, inst->path_cache.oculus_touch_controller, out_p); + return; + case XRT_DEVICE_WMR_CONTROLLER: + interaction_profile_find(log, inst, inst->path_cache.khr_simple_controller, out_p); + interaction_profile_find(log, inst, inst->path_cache.microsoft_motion_controller, out_p); + return; + case XRT_DEVICE_GO_CONTROLLER: + interaction_profile_find(log, inst, inst->path_cache.khr_simple_controller, out_p); + interaction_profile_find(log, inst, inst->path_cache.oculus_go_controller, out_p); + return; + case XRT_DEVICE_VIVE_PRO: + interaction_profile_find(log, inst, inst->path_cache.khr_simple_controller, out_p); + interaction_profile_find(log, inst, inst->path_cache.htc_vive_pro, out_p); + return; + case XRT_DEVICE_XBOX_CONTROLLER: + interaction_profile_find(log, inst, inst->path_cache.khr_simple_controller, out_p); + interaction_profile_find(log, inst, inst->path_cache.microsoft_xbox_controller, out_p); + return; + case XRT_DEVICE_HAND_INTERACTION: + interaction_profile_find(log, inst, inst->path_cache.khr_simple_controller, out_p); + interaction_profile_find(log, inst, inst->path_cache.msft_hand_interaction, out_p); + return; + + // no interaction + case XRT_DEVICE_GENERIC_HMD: + case XRT_DEVICE_REALSENSE: + case XRT_DEVICE_HAND_TRACKER: + case XRT_DEVICE_VIVE_TRACKER_GEN1: + case XRT_DEVICE_VIVE_TRACKER_GEN2: return; } } From 91a3d8b9cb41836c623a4ce859f85bd0897f6d5d Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 1 Apr 2021 17:48:28 +0200 Subject: [PATCH 270/883] st/steamvr: Add rift controllers --- src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp b/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp index ae611d6a9..dabcf6437 100644 --- a/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp +++ b/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp @@ -166,6 +166,14 @@ public: "right"; } break; + case XRT_DEVICE_TOUCH_CONTROLLER: + if (hand == XRT_HAND_LEFT) { + m_render_model = "oculus_cv1_controller_left"; + } + if (hand == XRT_HAND_RIGHT) { + m_render_model = "oculus_cv1_controller_right"; + } + break; case XRT_DEVICE_VIVE_WAND: m_render_model = "vr_controller_vive_1_5"; break; case XRT_DEVICE_VIVE_TRACKER_GEN1: case XRT_DEVICE_VIVE_TRACKER_GEN2: m_render_model = "{htc}vr_tracker_vive_1_0"; break; @@ -566,6 +574,8 @@ public: grip_name = XRT_INPUT_DAYDREAM_POSE; } else if (m_xdev->name == XRT_DEVICE_HYDRA) { grip_name = XRT_INPUT_HYDRA_POSE; + } else if (m_xdev->name == XRT_DEVICE_TOUCH_CONTROLLER) { + grip_name = XRT_INPUT_TOUCH_GRIP_POSE; } else { ovrd_log("Unhandled device name %u\n", m_xdev->name); grip_name = XRT_INPUT_GENERIC_HEAD_POSE; // ??? From 3a60df33aa251b177a23886e358439f127428e81 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 1 Apr 2021 05:36:17 +0200 Subject: [PATCH 271/883] d/openhmd: Add support for rift CV1 controllers --- src/xrt/drivers/ohmd/oh_device.c | 600 ++++++++++++++++++++++++++++--- src/xrt/drivers/ohmd/oh_device.h | 4 +- src/xrt/drivers/ohmd/oh_prober.c | 66 +--- 3 files changed, 557 insertions(+), 113 deletions(-) diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c index 0aefc4c4d..cc53fbcfd 100644 --- a/src/xrt/drivers/ohmd/oh_device.c +++ b/src/xrt/drivers/ohmd/oh_device.c @@ -10,6 +10,7 @@ #include "math/m_mathinclude.h" #include "xrt/xrt_config_os.h" +#include "xrt/xrt_prober.h" #include #include @@ -40,10 +41,63 @@ // directly retrieved? DEBUG_GET_ONCE_BOOL_OPTION(ohmd_finite_diff, "OHMD_ALLOW_FINITE_DIFF", true) DEBUG_GET_ONCE_LOG_OPTION(ohmd_log, "OHMD_LOG", U_LOGGING_WARN) +DEBUG_GET_ONCE_BOOL_OPTION(ohmd_external, "OHMD_EXTERNAL_DRIVER", false) // Define this if you have the appropriately hacked-up OpenHMD version. #undef OHMD_HAVE_ANG_VEL +enum input_indices +{ + // khronos simple inputs for generic controllers + SIMPLE_SELECT_CLICK = 0, + SIMPLE_MENU_CLICK, + SIMPLE_GRIP_POSE, + SIMPLE_AIM_POSE, + + // longest list of aliased enums has to start last for INPUT_INDICES_LAST to get the biggest value + OCULUS_TOUCH_X_CLICK = 0, + OCULUS_TOUCH_X_TOUCH, + OCULUS_TOUCH_Y_CLICK, + OCULUS_TOUCH_Y_TOUCH, + OCULUS_TOUCH_MENU_CLICK, + OCULUS_TOUCH_A_CLICK, + OCULUS_TOUCH_A_TOUCH, + OCULUS_TOUCH_B_CLICK, + OCULUS_TOUCH_B_TOUCH, + OCULUS_TOUCH_SYSTEM_CLICK, + OCULUS_TOUCH_SQUEEZE_VALUE, + OCULUS_TOUCH_TRIGGER_TOUCH, + OCULUS_TOUCH_TRIGGER_VALUE, + OCULUS_TOUCH_THUMBSTICK_CLICK, + OCULUS_TOUCH_THUMBSTICK_TOUCH, + OCULUS_TOUCH_THUMBSTICK, + OCULUS_TOUCH_THUMBREST_TOUCH, + OCULUS_TOUCH_GRIP_POSE, + OCULUS_TOUCH_AIM_POSE, + + INPUT_INDICES_LAST +}; +#define SET_TOUCH_INPUT(NAME) (ohd->base.inputs[OCULUS_TOUCH_##NAME].name = XRT_INPUT_TOUCH_##NAME) + +// all OpenHMD controls are floats, even "digital" controls. +// this means a trigger can be fed by a discrete button or by a pullable [0,1] analog trigger. +// in case of not so good calibrated triggers we may not reach 1.0 +#define PRESS_FLOAT_THRESHOLD 0.95 +#define FLOAT_TO_DIGITAL_THRESHOLD 0.5 + +// one mapping for each of enum ohmd_control_hint +#define CONTROL_MAPPING_SIZE 16 + +// generic controllers are mapped to the khronos simple profile +// touch controllers input mappings are special cased +enum openhmd_device_type +{ + OPENHMD_GENERIC_HMD, + OPENHMD_GENERIC_CONTROLLER, + OPENHMD_OCULUS_RIFT_HMD, + OPENHMD_OCULUS_RIFT_CONTROLLER, +}; + struct openhmd_values { float hmd_warp_param[4]; @@ -53,6 +107,18 @@ struct openhmd_values float warp_scale; }; +struct oh_device; +struct oh_system +{ + struct xrt_tracking_origin base; + struct oh_device *devices[XRT_MAX_DEVICES_PER_PROBE]; + + //! index into oh_system::devices + int hmd_idx; + int left_idx; + int right_idx; +}; + /*! * @implements xrt_device */ @@ -75,6 +141,27 @@ struct oh_device struct u_vive_values vive[2]; struct openhmd_values openhmd[2]; } distortion; + + struct oh_system *sys; + + + enum openhmd_device_type ohmd_device_type; + + // what function controls serve. + int controls_fn[64]; + + // whether controls are digital or analog. + // unused because the OpenXR interaction profile forces the type. + int controls_types[64]; + + //! maps OpenHMD control hint enum to the corresponding index into base.inputs + enum input_indices controls_mapping[CONTROL_MAPPING_SIZE]; + + // For touch controller we map an analog trigger to a float interaction profile input. + // For simple controller we map a potentially analog trigger to a bool input. + bool make_trigger_digital; + + float last_control_state[256]; }; static inline struct oh_device * @@ -88,21 +175,154 @@ oh_device_destroy(struct xrt_device *xdev) { struct oh_device *ohd = oh_device(xdev); - // Remove the variable tracking. - u_var_remove_root(ohd); - if (ohd->dev != NULL) { ohmd_close_device(ohd->dev); ohd->dev = NULL; } + bool all_null = true; + for (int i = 0; i < XRT_MAX_DEVICES_PER_PROBE; i++) { + if (ohd->sys->devices[i] == ohd) { + ohd->sys->devices[i] = NULL; + } + + if (ohd->sys->devices[i] != NULL) { + all_null = false; + } + } + + if (all_null) { + // Remove the variable tracking. + u_var_remove_root(ohd->sys); + + free(ohd->sys); + } + u_device_free(&ohd->base); } +#define CASE_VEC1(OHMD_CONTROL) \ + case OHMD_CONTROL: \ + if (ohd->controls_mapping[OHMD_CONTROL] == 0) { \ + break; \ + } \ + if (control_state[i] != ohd->last_control_state[i]) { \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].value.vec1.x = control_state[i]; \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].timestamp = ts; \ + } \ + break; + +#define CASE_VEC1_OR_DIGITAL(OHMD_CONTROL, MAKE_DIGITAL) \ + case OHMD_CONTROL: \ + if (ohd->controls_mapping[OHMD_CONTROL] == 0) { \ + break; \ + } \ + if (MAKE_DIGITAL) { \ + if ((control_state[i] > FLOAT_TO_DIGITAL_THRESHOLD) != \ + (ohd->last_control_state[i] > FLOAT_TO_DIGITAL_THRESHOLD)) { \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].value.vec1.x = \ + control_state[i] > FLOAT_TO_DIGITAL_THRESHOLD; \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].timestamp = ts; \ + } \ + } else { \ + if (control_state[i] != ohd->last_control_state[i]) { \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].value.vec1.x = control_state[i]; \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].timestamp = ts; \ + } \ + } \ + break; + +#define CASE_DIGITAL(OHMD_CONTROL, THRESHOLD) \ + case OHMD_CONTROL: \ + if (ohd->controls_mapping[OHMD_CONTROL] == 0) { \ + break; \ + } \ + if (control_state[i] != ohd->last_control_state[i]) { \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].value.boolean = \ + control_state[i] > THRESHOLD; \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].timestamp = ts; \ + } \ + break; + +#define CASE_VEC2_X(OHMD_CONTROL) \ + case OHMD_CONTROL: \ + if (ohd->controls_mapping[OHMD_CONTROL] == 0) { \ + break; \ + } \ + if (control_state[i] != ohd->last_control_state[i]) { \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].value.vec2.x = control_state[i]; \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].timestamp = ts; \ + } \ + break; + +#define CASE_VEC2_Y(OHMD_CONTROL) \ + case OHMD_CONTROL: \ + if (ohd->controls_mapping[OHMD_CONTROL] == 0) { \ + break; \ + } \ + if (control_state[i] != ohd->last_control_state[i]) { \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].value.vec2.y = control_state[i]; \ + ohd->base.inputs[ohd->controls_mapping[OHMD_CONTROL]].timestamp = ts; \ + } \ + break; + +static void +update_ohmd_controller(struct oh_device *ohd, int control_count, float *control_state) +{ + timepoint_ns ts = os_monotonic_get_ns(); + for (int i = 0; i < control_count; i++) { + switch (ohd->controls_fn[i]) { + // CASE macro does nothing, if ohd->controls_mapping[OHMD_CONTROL] has not been assigned + CASE_VEC1_OR_DIGITAL(OHMD_TRIGGER, ohd->make_trigger_digital); + CASE_DIGITAL(OHMD_TRIGGER_CLICK, PRESS_FLOAT_THRESHOLD); + CASE_VEC1(OHMD_SQUEEZE); + CASE_DIGITAL(OHMD_MENU, PRESS_FLOAT_THRESHOLD); + CASE_DIGITAL(OHMD_HOME, PRESS_FLOAT_THRESHOLD); + CASE_VEC2_X(OHMD_ANALOG_X); + CASE_VEC2_Y(OHMD_ANALOG_Y); + CASE_DIGITAL(OHMD_ANALOG_PRESS, PRESS_FLOAT_THRESHOLD); + CASE_DIGITAL(OHMD_BUTTON_A, PRESS_FLOAT_THRESHOLD); + CASE_DIGITAL(OHMD_BUTTON_B, PRESS_FLOAT_THRESHOLD); + CASE_DIGITAL(OHMD_BUTTON_X, PRESS_FLOAT_THRESHOLD); + CASE_DIGITAL(OHMD_BUTTON_Y, PRESS_FLOAT_THRESHOLD); + CASE_DIGITAL(OHMD_VOLUME_PLUS, PRESS_FLOAT_THRESHOLD); + CASE_DIGITAL(OHMD_VOLUME_MINUS, PRESS_FLOAT_THRESHOLD); + CASE_DIGITAL(OHMD_MIC_MUTE, PRESS_FLOAT_THRESHOLD); + } + } +} + static void oh_device_update_inputs(struct xrt_device *xdev) { - // Empty + struct oh_device *ohd = oh_device(xdev); + + int control_count; + float control_state[256]; + + ohmd_device_geti(ohd->dev, OHMD_CONTROL_COUNT, &control_count); + if (control_count > 64) + control_count = 64; + + ohmd_device_getf(ohd->dev, OHMD_CONTROLS_STATE, control_state); + + if (ohd->ohmd_device_type == OPENHMD_OCULUS_RIFT_CONTROLLER || + ohd->ohmd_device_type == OPENHMD_GENERIC_CONTROLLER) { + update_ohmd_controller(ohd, control_count, control_state); + } + + for (int i = 0; i < 256; i++) { + ohd->last_control_state[i] = control_state[i]; + } +} + +static void +oh_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, union xrt_output_value *value) +{ + struct oh_device *ohd = oh_device(xdev); + (void)ohd; + + //! @todo OpenHMD haptic API not finished } static void @@ -115,7 +335,13 @@ oh_device_get_tracked_pose(struct xrt_device *xdev, struct xrt_quat quat = {0.f, 0.f, 0.f, 1.f}; struct xrt_vec3 pos = {0.f, 0.f, 0.f}; - if (name != XRT_INPUT_GENERIC_HEAD_POSE) { + // support generic head pose for all hmds, + // support rift poses for rift controllers, and simple poses for generic controller + if (name != XRT_INPUT_GENERIC_HEAD_POSE && + (ohd->ohmd_device_type == OPENHMD_OCULUS_RIFT_CONTROLLER && + (name != XRT_INPUT_TOUCH_AIM_POSE && name != XRT_INPUT_TOUCH_GRIP_POSE)) && + ohd->ohmd_device_type == OPENHMD_GENERIC_CONTROLLER && + (name != XRT_INPUT_SIMPLE_AIM_POSE && name != XRT_INPUT_SIMPLE_GRIP_POSE)) { OHMD_ERROR(ohd, "unknown input name"); return; } @@ -160,7 +386,7 @@ oh_device_get_tracked_pose(struct xrt_device *xdev, * USB data and use that instead. */ *out_relation = ohd->last_relation; - OHMD_TRACE(ohd, "GET_TRACKED_POSE - no new data"); + OHMD_TRACE(ohd, "GET_TRACKED_POSE (%s) - no new data", ohd->base.str); return; } @@ -192,10 +418,11 @@ oh_device_get_tracked_pose(struct xrt_device *xdev, out_relation->relation_flags = (enum xrt_space_relation_flags)( out_relation->relation_flags | XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT); - OHMD_TRACE(ohd, "GET_TRACKED_POSE (%f, %f, %f, %f) (%f, %f, %f)", quat.x, quat.y, quat.z, quat.w, - ang_vel.x, ang_vel.y, ang_vel.z); + OHMD_TRACE(ohd, "GET_TRACKED_POSE (%s) (%f, %f, %f, %f) (%f, %f, %f)", ohd->base.str, quat.x, quat.y, + quat.z, quat.w, ang_vel.x, ang_vel.y, ang_vel.z); } else { - OHMD_TRACE(ohd, "GET_TRACKED_POSE (%f, %f, %f, %f)", quat.x, quat.y, quat.z, quat.w); + OHMD_TRACE(ohd, "GET_TRACKED_POSE (%s) (%f, %f, %f, %f)", ohd->base.str, quat.x, quat.y, quat.z, + quat.w); } // Update state within driver @@ -284,21 +511,21 @@ struct device_info }; static struct device_info -get_info(struct oh_device *ohd, const char *prod) +get_info(ohmd_device *dev, const char *prod) { struct device_info info = {0}; // clang-format off - ohmd_device_getf(ohd->dev, OHMD_SCREEN_HORIZONTAL_SIZE, &info.display.w_meters); - ohmd_device_getf(ohd->dev, OHMD_SCREEN_VERTICAL_SIZE, &info.display.h_meters); - ohmd_device_getf(ohd->dev, OHMD_LENS_HORIZONTAL_SEPARATION, &info.lens_horizontal_separation); - ohmd_device_getf(ohd->dev, OHMD_LENS_VERTICAL_POSITION, &info.lens_vertical_position); - ohmd_device_getf(ohd->dev, OHMD_LEFT_EYE_FOV, &info.views[0].fov); - ohmd_device_getf(ohd->dev, OHMD_RIGHT_EYE_FOV, &info.views[1].fov); - ohmd_device_geti(ohd->dev, OHMD_SCREEN_HORIZONTAL_RESOLUTION, &info.display.w_pixels); - ohmd_device_geti(ohd->dev, OHMD_SCREEN_VERTICAL_RESOLUTION, &info.display.h_pixels); - ohmd_device_getf(ohd->dev, OHMD_UNIVERSAL_DISTORTION_K, &info.pano_distortion_k[0]); - ohmd_device_getf(ohd->dev, OHMD_UNIVERSAL_ABERRATION_K, &info.pano_aberration_k[0]); + ohmd_device_getf(dev, OHMD_SCREEN_HORIZONTAL_SIZE, &info.display.w_meters); + ohmd_device_getf(dev, OHMD_SCREEN_VERTICAL_SIZE, &info.display.h_meters); + ohmd_device_getf(dev, OHMD_LENS_HORIZONTAL_SEPARATION, &info.lens_horizontal_separation); + ohmd_device_getf(dev, OHMD_LENS_VERTICAL_POSITION, &info.lens_vertical_position); + ohmd_device_getf(dev, OHMD_LEFT_EYE_FOV, &info.views[0].fov); + ohmd_device_getf(dev, OHMD_RIGHT_EYE_FOV, &info.views[1].fov); + ohmd_device_geti(dev, OHMD_SCREEN_HORIZONTAL_RESOLUTION, &info.display.w_pixels); + ohmd_device_geti(dev, OHMD_SCREEN_VERTICAL_RESOLUTION, &info.display.h_pixels); + ohmd_device_getf(dev, OHMD_UNIVERSAL_DISTORTION_K, &info.pano_distortion_k[0]); + ohmd_device_getf(dev, OHMD_UNIVERSAL_ABERRATION_K, &info.pano_aberration_k[0]); // Default to 90FPS info.display.nominal_frame_interval_ns = @@ -415,10 +642,10 @@ get_info(struct oh_device *ohd, const char *prod) if (info.quirks.rotate_screen_right_after) { // OpenHMD describes the logical orintation not the physical. // clang-format off - ohmd_device_getf(ohd->dev, OHMD_SCREEN_HORIZONTAL_SIZE, &info.display.h_meters); - ohmd_device_getf(ohd->dev, OHMD_SCREEN_VERTICAL_SIZE, &info.display.w_meters); - ohmd_device_geti(ohd->dev, OHMD_SCREEN_HORIZONTAL_RESOLUTION, &info.display.h_pixels); - ohmd_device_geti(ohd->dev, OHMD_SCREEN_VERTICAL_RESOLUTION, &info.display.w_pixels); + ohmd_device_getf(dev, OHMD_SCREEN_HORIZONTAL_SIZE, &info.display.h_meters); + ohmd_device_getf(dev, OHMD_SCREEN_VERTICAL_SIZE, &info.display.w_meters); + ohmd_device_geti(dev, OHMD_SCREEN_HORIZONTAL_RESOLUTION, &info.display.h_pixels); + ohmd_device_geti(dev, OHMD_SCREEN_VERTICAL_RESOLUTION, &info.display.w_pixels); // clang-format on } @@ -493,11 +720,19 @@ swap(int *a, int *b) *b = temp; } -struct xrt_device * -oh_device_create(ohmd_context *ctx, ohmd_device *dev, const char *prod) +static struct oh_device * +create_hmd(ohmd_context *ctx, int device_idx, int device_flags) { - enum u_device_alloc_flags flags = - (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); + const char *prod = ohmd_list_gets(ctx, device_idx, OHMD_PRODUCT); + ohmd_device *dev = ohmd_list_open_device(ctx, device_idx); + if (dev == NULL) { + return NULL; + } + + + const struct device_info info = get_info(dev, prod); + + enum u_device_alloc_flags flags = U_DEVICE_ALLOC_HMD; struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, 1, 0); ohd->base.update_inputs = oh_device_update_inputs; ohd->base.get_tracked_pose = oh_device_get_tracked_pose; @@ -509,12 +744,15 @@ oh_device_create(ohmd_context *ctx, ohmd_device *dev, const char *prod) ohd->dev = dev; ohd->ll = debug_get_log_option_ohmd_log(); ohd->enable_finite_difference = debug_get_bool_option_ohmd_finite_diff(); + if (strcmp(prod, "Rift (CV1)") == 0 || strcmp(prod, "Rift S") == 0) { + ohd->ohmd_device_type = OPENHMD_OCULUS_RIFT_HMD; + } else { + ohd->ohmd_device_type = OPENHMD_GENERIC_HMD; + } snprintf(ohd->base.str, XRT_DEVICE_NAME_LEN, "%s (OpenHMD)", prod); snprintf(ohd->base.serial, XRT_DEVICE_NAME_LEN, "%s (OpenHMD)", prod); - const struct device_info info = get_info(ohd, prod); - { /* right eye */ if (!math_compute_fovs(info.views[1].display.w_meters, info.views[1].lens_center_x_meters, @@ -563,20 +801,20 @@ oh_device_create(ohmd_context *ctx, ohmd_device *dev, const char *prod) ohd->base.hmd->views[1].rot = u_device_rotation_ident; OHMD_DEBUG(ohd, - "Display/viewport/offset before rotation %dx%d/%dx%d/%dx%d, " - "%dx%d/%dx%d/%dx%d", - ohd->base.hmd->views[0].display.w_pixels, - ohd->base.hmd->views[0].display.h_pixels, - ohd->base.hmd->views[0].viewport.w_pixels, - ohd->base.hmd->views[0].viewport.h_pixels, - ohd->base.hmd->views[0].viewport.x_pixels, - ohd->base.hmd->views[0].viewport.y_pixels, - ohd->base.hmd->views[1].display.w_pixels, - ohd->base.hmd->views[1].display.h_pixels, - ohd->base.hmd->views[1].viewport.w_pixels, - ohd->base.hmd->views[1].viewport.h_pixels, - ohd->base.hmd->views[0].viewport.x_pixels, - ohd->base.hmd->views[0].viewport.y_pixels); + "Display/viewport/offset before rotation %dx%d/%dx%d/%dx%d, " + "%dx%d/%dx%d/%dx%d", + ohd->base.hmd->views[0].display.w_pixels, + ohd->base.hmd->views[0].display.h_pixels, + ohd->base.hmd->views[0].viewport.w_pixels, + ohd->base.hmd->views[0].viewport.h_pixels, + ohd->base.hmd->views[0].viewport.x_pixels, + ohd->base.hmd->views[0].viewport.y_pixels, + ohd->base.hmd->views[1].display.w_pixels, + ohd->base.hmd->views[1].display.h_pixels, + ohd->base.hmd->views[1].viewport.w_pixels, + ohd->base.hmd->views[1].viewport.h_pixels, + ohd->base.hmd->views[0].viewport.x_pixels, + ohd->base.hmd->views[0].viewport.y_pixels); for (int view = 0; view < 2; view++) { ohd->distortion.openhmd[view].hmd_warp_param[0] = info.pano_distortion_k[0]; @@ -780,8 +1018,276 @@ oh_device_create(ohmd_context *ctx, ohmd_device *dev, const char *prod) u_device_dump_config(&ohd->base, __func__, prod); } - u_var_add_root(ohd, "OpenHMD Wrapper", true); - u_var_add_ro_text(ohd, ohd->base.str, "Card"); + ohd->base.orientation_tracking_supported = (device_flags & OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING) != 0; + ohd->base.position_tracking_supported = (device_flags & OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING) != 0; + ohd->base.device_type = XRT_DEVICE_TYPE_HMD; - return &ohd->base; + + if (info.quirks.delay_after_initialization) { + unsigned int time_to_sleep = 1; + do { + //! @todo convert to os_nanosleep + time_to_sleep = sleep(time_to_sleep); + } while (time_to_sleep); + } + + if (ohd->ll <= U_LOGGING_DEBUG) { + u_device_dump_config(&ohd->base, __func__, prod); + } + + return ohd; +} + +static struct oh_device * +create_controller(ohmd_context *ctx, int device_idx, int device_flags, enum xrt_device_type device_type) +{ + const char *prod = ohmd_list_gets(ctx, device_idx, OHMD_PRODUCT); + ohmd_device *dev = ohmd_list_open_device(ctx, device_idx); + if (dev == NULL) { + return 0; + } + + bool oculus_touch = false; + + int num_inputs = 1; + int num_outputs = 0; + + if (strcmp(prod, "Rift (CV1): Right Controller") == 0 || strcmp(prod, "Rift (CV1): Left Controller") == 0 || + strcmp(prod, "Rift S: Right Controller") == 0 || strcmp(prod, "Rift S: Left Controller") == 0) { + oculus_touch = true; + + num_inputs = INPUT_INDICES_LAST; + num_outputs = 1; + } + + enum u_device_alloc_flags flags = 0; + struct oh_device *ohd = U_DEVICE_ALLOCATE(struct oh_device, flags, num_inputs, num_outputs); + ohd->base.update_inputs = oh_device_update_inputs; + ohd->base.set_output = oh_device_set_output; + ohd->base.get_tracked_pose = oh_device_get_tracked_pose; + ohd->base.get_view_pose = oh_device_get_view_pose; + ohd->base.destroy = oh_device_destroy; + if (oculus_touch) { + ohd->ohmd_device_type = OPENHMD_OCULUS_RIFT_CONTROLLER; + ohd->base.name = XRT_DEVICE_TOUCH_CONTROLLER; + } else { + ohd->ohmd_device_type = OPENHMD_GENERIC_CONTROLLER; + ohd->base.name = XRT_DEVICE_GENERIC_HMD; //! @todo generic tracker + } + ohd->ctx = ctx; + ohd->dev = dev; + ohd->ll = debug_get_log_option_ohmd_log(); + ohd->enable_finite_difference = debug_get_bool_option_ohmd_finite_diff(); + + for (int i = 0; i < CONTROL_MAPPING_SIZE; i++) { + ohd->controls_mapping[i] = 0; + } + + if (oculus_touch) { + SET_TOUCH_INPUT(X_CLICK); + SET_TOUCH_INPUT(X_TOUCH); + SET_TOUCH_INPUT(Y_CLICK); + SET_TOUCH_INPUT(Y_TOUCH); + SET_TOUCH_INPUT(MENU_CLICK); + SET_TOUCH_INPUT(A_CLICK); + SET_TOUCH_INPUT(A_TOUCH); + SET_TOUCH_INPUT(B_CLICK); + SET_TOUCH_INPUT(B_TOUCH); + SET_TOUCH_INPUT(SYSTEM_CLICK); + SET_TOUCH_INPUT(SQUEEZE_VALUE); + SET_TOUCH_INPUT(TRIGGER_TOUCH); + SET_TOUCH_INPUT(TRIGGER_VALUE); + SET_TOUCH_INPUT(THUMBSTICK_CLICK); + SET_TOUCH_INPUT(THUMBSTICK_TOUCH); + SET_TOUCH_INPUT(THUMBSTICK); + SET_TOUCH_INPUT(THUMBREST_TOUCH); + SET_TOUCH_INPUT(GRIP_POSE); + SET_TOUCH_INPUT(AIM_POSE); + + ohd->make_trigger_digital = false; + + ohd->base.outputs[0].name = XRT_OUTPUT_NAME_TOUCH_HAPTIC; + + ohd->controls_mapping[OHMD_TRIGGER] = OCULUS_TOUCH_TRIGGER_VALUE; + ohd->controls_mapping[OHMD_SQUEEZE] = OCULUS_TOUCH_SQUEEZE_VALUE; + ohd->controls_mapping[OHMD_MENU] = OCULUS_TOUCH_MENU_CLICK; + ohd->controls_mapping[OHMD_HOME] = OCULUS_TOUCH_SYSTEM_CLICK; + ohd->controls_mapping[OHMD_ANALOG_X] = OCULUS_TOUCH_THUMBSTICK; + ohd->controls_mapping[OHMD_ANALOG_Y] = OCULUS_TOUCH_THUMBSTICK; + ohd->controls_mapping[OHMD_ANALOG_PRESS] = OCULUS_TOUCH_THUMBSTICK_CLICK; + ohd->controls_mapping[OHMD_BUTTON_A] = OCULUS_TOUCH_A_CLICK; + ohd->controls_mapping[OHMD_BUTTON_B] = OCULUS_TOUCH_B_CLICK; + ohd->controls_mapping[OHMD_BUTTON_X] = OCULUS_TOUCH_X_CLICK; + ohd->controls_mapping[OHMD_BUTTON_Y] = OCULUS_TOUCH_Y_CLICK; + } else { + ohd->base.inputs[SIMPLE_SELECT_CLICK].name = XRT_INPUT_SIMPLE_SELECT_CLICK; + ohd->base.inputs[SIMPLE_MENU_CLICK].name = XRT_INPUT_SIMPLE_MENU_CLICK; + ohd->base.inputs[SIMPLE_GRIP_POSE].name = XRT_INPUT_SIMPLE_GRIP_POSE; + ohd->base.inputs[SIMPLE_AIM_POSE].name = XRT_INPUT_SIMPLE_AIM_POSE; + + // XRT_INPUT_SIMPLE_SELECT_CLICK is digital input. + // in case the hardware is an analog trigger, change the input after a half pulled trigger. + ohd->make_trigger_digital = true; + + ohd->base.outputs[0].name = XRT_OUTPUT_NAME_SIMPLE_VIBRATION; + + ohd->controls_mapping[OHMD_TRIGGER] = SIMPLE_SELECT_CLICK; + ohd->controls_mapping[OHMD_MENU] = SIMPLE_MENU_CLICK; + } + + snprintf(ohd->base.str, XRT_DEVICE_NAME_LEN, "%s (OpenHMD)", prod); + snprintf(ohd->base.serial, XRT_DEVICE_NAME_LEN, "%s (OpenHMD)", prod); + + ohd->base.orientation_tracking_supported = (device_flags & OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING) != 0; + ohd->base.position_tracking_supported = (device_flags & OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING) != 0; + ohd->base.device_type = device_type; + + ohmd_device_geti(ohd->dev, OHMD_CONTROLS_HINTS, ohd->controls_fn); + ohmd_device_geti(ohd->dev, OHMD_CONTROLS_TYPES, ohd->controls_types); + + OHMD_DEBUG(ohd, "Created %s controller", + device_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER ? "left" : "right"); + + return ohd; +} + +int +oh_device_create(ohmd_context *ctx, bool no_hmds, struct xrt_device **out_xdevs) +{ + int hmd_idx = -1; + int hmd_flags = 0; + int left_idx = -1; + int left_flags = 0; + int right_idx = -1; + int right_flags = 0; + + if (no_hmds) { + return 0; + } + + /* Probe for devices */ + int num_devices = ohmd_ctx_probe(ctx); + + /* Then loop */ + for (int i = 0; i < num_devices; i++) { + int device_class = 0, device_flags = 0; + const char *prod = NULL; + + ohmd_list_geti(ctx, i, OHMD_DEVICE_CLASS, &device_class); + ohmd_list_geti(ctx, i, OHMD_DEVICE_FLAGS, &device_flags); + + if (device_class == OHMD_DEVICE_CLASS_CONTROLLER) { + if ((device_flags & OHMD_DEVICE_FLAGS_LEFT_CONTROLLER) != 0) { + if (left_idx != -1) { + continue; + } + U_LOG_D("Selecting left controller idx %i", i); + left_idx = i; + left_flags = device_flags; + } + if ((device_flags & OHMD_DEVICE_FLAGS_RIGHT_CONTROLLER) != 0) { + if (right_idx != -1) { + continue; + } + U_LOG_D("Selecting right controller idx %i", i); + right_idx = i; + right_flags = device_flags; + } + + continue; + } + + if (device_class == OHMD_DEVICE_CLASS_HMD) { + if (hmd_idx != -1) { + continue; + } + U_LOG_D("Selecting hmd idx %i", i); + hmd_idx = i; + hmd_flags = device_flags; + } + + if (device_flags & OHMD_DEVICE_FLAGS_NULL_DEVICE) { + U_LOG_D("Rejecting device idx %i, is a NULL device.", i); + continue; + } + + prod = ohmd_list_gets(ctx, i, OHMD_PRODUCT); + if (strcmp(prod, "External Device") == 0 && !debug_get_bool_option_ohmd_external()) { + U_LOG_D("Rejecting device idx %i, is a External device.", i); + continue; + } + + if (hmd_idx != -1 && left_idx != -1 && right_idx != -1) { + break; + } + } + + + // All OpenHMD devices share the same tracking origin. + // Default everything to 3dof (NONE), but 6dof when the HMD supports position tracking. + //! @todo: support mix of 3dof and 6dof OpenHMD devices + struct oh_system *sys = U_TYPED_CALLOC(struct oh_system); + sys->base.type = XRT_TRACKING_TYPE_NONE; + sys->base.offset.orientation.w = 1.0f; + sys->hmd_idx = -1; + sys->left_idx = -1; + sys->right_idx = -1; + + u_var_add_root(sys, "OpenHMD Wrapper", false); + + int created = 0; + if (!no_hmds && hmd_idx != -1) { + struct oh_device *hmd = create_hmd(ctx, hmd_idx, hmd_flags); + if (hmd) { + hmd->sys = sys; + hmd->base.tracking_origin = &sys->base; + + sys->hmd_idx = created; + sys->devices[sys->hmd_idx] = hmd; + + if (hmd->base.position_tracking_supported) { + sys->base.type = XRT_TRACKING_TYPE_OTHER; + } + + out_xdevs[created++] = &hmd->base; + } + } + + if (left_idx != -1) { + struct oh_device *left = + create_controller(ctx, left_idx, left_flags, XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER); + if (left) { + left->sys = sys; + left->base.tracking_origin = &sys->base; + + sys->left_idx = created; + sys->devices[sys->left_idx] = left; + + out_xdevs[created++] = &left->base; + } + } + + if (right_idx != -1) { + struct oh_device *right = + create_controller(ctx, right_idx, right_flags, XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER); + if (right) { + right->sys = sys; + right->base.tracking_origin = &sys->base; + + sys->right_idx = created; + sys->devices[sys->right_idx] = right; + + out_xdevs[created++] = &right->base; + } + } + + for (int i = 0; i < XRT_MAX_DEVICES_PER_PROBE; i++) { + if (sys->devices[i] != NULL) { + u_var_add_ro_text(sys, sys->devices[i]->base.str, "OpenHMD Device"); + } + } + + //! @todo initialize more devices like generic trackers (nolo) + + return created; } diff --git a/src/xrt/drivers/ohmd/oh_device.h b/src/xrt/drivers/ohmd/oh_device.h index 2d8794a19..633dc086b 100644 --- a/src/xrt/drivers/ohmd/oh_device.h +++ b/src/xrt/drivers/ohmd/oh_device.h @@ -16,8 +16,8 @@ extern "C" { #endif -struct xrt_device * -oh_device_create(ohmd_context *ctx, ohmd_device *dev, const char *prod); +int +oh_device_create(ohmd_context *ctx, bool no_hmds, struct xrt_device **out_xdevs); #define OHMD_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->ll, __VA_ARGS__) #define OHMD_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->ll, __VA_ARGS__) diff --git a/src/xrt/drivers/ohmd/oh_prober.c b/src/xrt/drivers/ohmd/oh_prober.c index 58376ab1e..726f08756 100644 --- a/src/xrt/drivers/ohmd/oh_prober.c +++ b/src/xrt/drivers/ohmd/oh_prober.c @@ -20,8 +20,6 @@ #include "oh_device.h" -DEBUG_GET_ONCE_BOOL_OPTION(ohmd_external, "OHMD_EXTERNAL_DRIVER", false) - /*! * @implements xrt_auto_prober */ @@ -62,68 +60,8 @@ oh_prober_autoprobe(struct xrt_auto_prober *xap, { struct oh_prober *ohp = oh_prober(xap); - // Do not use OpenHMD if we are not looking for HMDs. - if (no_hmds) { - return 0; - } - - int device_idx = -1; - - /* Probe for devices */ - int num_devices = ohmd_ctx_probe(ohp->ctx); - - bool orientation_tracking_supported = false; - bool position_tracking_supported = false; - /* Then loop */ - for (int i = 0; i < num_devices; i++) { - int device_class = 0, device_flags = 0; - const char *prod = NULL; - - ohmd_list_geti(ohp->ctx, i, OHMD_DEVICE_CLASS, &device_class); - ohmd_list_geti(ohp->ctx, i, OHMD_DEVICE_FLAGS, &device_flags); - - if (device_class != OHMD_DEVICE_CLASS_HMD) { - U_LOG_D("Rejecting device idx %i, is not a HMD.", i); - continue; - } - - if (device_flags & OHMD_DEVICE_FLAGS_NULL_DEVICE) { - U_LOG_D("Rejecting device idx %i, is a NULL device.", i); - continue; - } - - prod = ohmd_list_gets(ohp->ctx, i, OHMD_PRODUCT); - if (strcmp(prod, "External Device") == 0 && !debug_get_bool_option_ohmd_external()) { - U_LOG_D("Rejecting device idx %i, is a External device.", i); - continue; - } - - U_LOG_D("Selecting device idx %i", i); - device_idx = i; - - orientation_tracking_supported = (device_flags & OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING) != 0; - position_tracking_supported = (device_flags & OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING) != 0; - break; - } - - if (device_idx < 0) { - return 0; - } - - const char *prod = ohmd_list_gets(ohp->ctx, device_idx, OHMD_PRODUCT); - ohmd_device *dev = ohmd_list_open_device(ohp->ctx, device_idx); - if (dev == NULL) { - return 0; - } - - struct xrt_device *xdev = oh_device_create(ohp->ctx, dev, prod); - - xdev->orientation_tracking_supported = orientation_tracking_supported; - xdev->position_tracking_supported = position_tracking_supported; - xdev->device_type = XRT_DEVICE_TYPE_HMD; - - out_xdevs[0] = xdev; - return 1; + int num_created = oh_device_create(ohp->ctx, no_hmds, out_xdevs); + return num_created; } struct xrt_auto_prober * From e5a77ea80df2b86ab764ca319d2c6890eeb9eb46 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Fri, 2 Apr 2021 03:44:30 +0200 Subject: [PATCH 272/883] doc: Add mr 742 changelog --- doc/changes/drivers/mr.742.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/drivers/mr.742.md diff --git a/doc/changes/drivers/mr.742.md b/doc/changes/drivers/mr.742.md new file mode 100644 index 000000000..2e30da13c --- /dev/null +++ b/doc/changes/drivers/mr.742.md @@ -0,0 +1 @@ +ohmd: Support OpenHMD controllers and specifically the Oculus Touch controller. From 607eae4fdde0f4f4e8d781b4fbe662d91118f9fb Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 2 Apr 2021 17:29:55 -0500 Subject: [PATCH 273/883] aux/vk: Fix creation of Windows external memory backed image. --- src/xrt/auxiliary/vk/vk_image_allocator.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/vk/vk_image_allocator.c b/src/xrt/auxiliary/vk/vk_image_allocator.c index d0e8c2a26..53753cf2b 100644 --- a/src/xrt/auxiliary/vk/vk_image_allocator.c +++ b/src/xrt/auxiliary/vk/vk_image_allocator.c @@ -155,8 +155,12 @@ create_image(struct vk_bundle *vk, const struct xrt_swapchain_create_info *info, .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR, #if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER) .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, -#else +#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_WIN32_HANDLE) + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR, +#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR, +#else +#error "need port" #endif }; @@ -231,7 +235,7 @@ create_image(struct vk_bundle *vk, const struct xrt_swapchain_create_info *info, VkExportMemoryAllocateInfo export_alloc_info = { .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR, .pNext = &dedicated_memory_info, - .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR, }; #else From c81ae4670b8f43b70366b46bf4faf43c819b069d Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 2 Apr 2021 17:47:40 -0500 Subject: [PATCH 274/883] comp: Properly service Windows message queue. --- src/xrt/compositor/main/comp_window_mswin.c | 38 +++++++++++++++------ 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/xrt/compositor/main/comp_window_mswin.c b/src/xrt/compositor/main/comp_window_mswin.c index e1d8c2272..8f309c31a 100644 --- a/src/xrt/compositor/main/comp_window_mswin.c +++ b/src/xrt/compositor/main/comp_window_mswin.c @@ -35,9 +35,11 @@ struct comp_window_mswin bool fullscreen_requested; + bool should_exit; }; static WCHAR szWindowClass[] = L"Monado"; +static WCHAR szWindowData[] = L"MonadoWindow"; /* * @@ -45,23 +47,30 @@ static WCHAR szWindowClass[] = L"Monado"; * */ +static void +draw_window(HWND hWnd, struct comp_window_mswin *cwm) +{ + ValidateRect(hWnd, NULL); +} + static LRESULT CALLBACK WndProc(HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam) { + struct comp_window_mswin *cwm = GetPropW(hWnd, szWindowData); + if (!cwm) { + // This is before we've set up our window, or for some other helper window... + // We might want to handle messages differently in here. + return DefWindowProcW(hWnd, message, wParam, lParam); + } switch (message) { - case WM_PAINT: { - // paint the main window - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hWnd, &ps); - // TODO: Add any drawing code that uses hdc here... - EndPaint(hWnd, &ps); - } break; + case WM_PAINT: draw_window(hWnd, cwm); return 0; + case WM_CLOSE: cwm->should_exit = true; return 0; case WM_DESTROY: // Post a quit message and return. - //! @todo set quit flag + cwm->should_exit = true; PostQuitMessage(0); - break; - default: return DefWindowProc(hWnd, message, wParam, lParam); + return 0; + default: return DefWindowProcW(hWnd, message, wParam, lParam); } return 0; } @@ -140,6 +149,12 @@ static void comp_window_mswin_flush(struct comp_target *ct) { struct comp_window_mswin *cwm = (struct comp_window_mswin *)ct; + // force handling messages. + MSG msg; + while (PeekMessageW(&msg, cwm->window, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } } @@ -171,6 +186,9 @@ comp_window_mswin_init(struct comp_target *ct) cwm->window = CreateWindowW(szWindowClass, L"Monado (Windowed)", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, cwm->instance, NULL); + SetPropW(cwm->window, szWindowData, cwm); + ShowWindow(cwm->window, SW_SHOWDEFAULT); + UpdateWindow(cwm->window); return true; } From d34e1464fd6fb2c8d7eecc08731ac54561f6f781 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 2 Apr 2021 18:02:10 -0500 Subject: [PATCH 275/883] comp: Update file header. --- doc/changes/misc_features/mr.739.md | 3 ++- src/xrt/compositor/main/comp_window_mswin.c | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/changes/misc_features/mr.739.md b/doc/changes/misc_features/mr.739.md index b6f9cc364..92ecfbc65 100644 --- a/doc/changes/misc_features/mr.739.md +++ b/doc/changes/misc_features/mr.739.md @@ -1,3 +1,4 @@ --- +- mr.743 --- -More work on the Windows port: fix timing, waiting, sleeping. +More work on the Windows port: fix timing, waiting, sleeping, handling the message queue. diff --git a/src/xrt/compositor/main/comp_window_mswin.c b/src/xrt/compositor/main/comp_window_mswin.c index 8f309c31a..88fc763a1 100644 --- a/src/xrt/compositor/main/comp_window_mswin.c +++ b/src/xrt/compositor/main/comp_window_mswin.c @@ -1,8 +1,9 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file - * @brief Wayland window code. + * @brief Microsoft Windows window code. + * @author Ryan Pavlik * @author Lubosz Sarnecki * @author Jakob Bornecrantz * @ingroup comp_main From 1155106dc1d196918b2b9a742893a8098b8edd06 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 27 Feb 2021 02:15:30 +0000 Subject: [PATCH 276/883] d/v4l2: Be more tolorant for long pipelines --- src/xrt/drivers/v4l2/v4l2_driver.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/v4l2/v4l2_driver.c b/src/xrt/drivers/v4l2/v4l2_driver.c index 6c3d818c3..7479f9593 100644 --- a/src/xrt/drivers/v4l2/v4l2_driver.c +++ b/src/xrt/drivers/v4l2/v4l2_driver.c @@ -68,7 +68,7 @@ DEBUG_GET_ONCE_LOG_OPTION(v4l2_log, "V4L2_LOG", U_LOGGING_WARN) DEBUG_GET_ONCE_NUM_OPTION(v4l2_exposure_absolute, "V4L2_EXPOSURE_ABSOLUTE", 10) -#define NUM_V4L2_BUFFERS 5 +#define NUM_V4L2_BUFFERS 32 /* @@ -141,6 +141,7 @@ struct v4l2_fs } quirks; struct v4l2_frame frames[NUM_V4L2_BUFFERS]; + uint32_t used_frames; struct { @@ -207,6 +208,8 @@ v4l2_free_frame(struct xrt_frame *xf) struct v4l2_frame *vf = (struct v4l2_frame *)xf; struct v4l2_fs *vid = (struct v4l2_fs *)xf->owner; + vid->used_frames--; + if (!vid->is_running) { return; } @@ -891,6 +894,10 @@ v4l2_fs_stream_run(void *ptr) v_buf.memory = v_bufrequest.memory; while (vid->is_running) { + if (vid->used_frames == NUM_V4L2_BUFFERS) { + V4L2_ERROR(vid, "No frames left"); + } + if (ioctl(vid->fd, VIDIOC_DQBUF, &v_buf) < 0) { V4L2_ERROR(vid, "error: Dequeue failed!"); vid->is_running = false; @@ -925,6 +932,8 @@ v4l2_fs_stream_run(void *ptr) vid->sink->push_frame(vid->sink, xf); + vid->used_frames++; + // The frame is requeued as soon as the refcount reaches zero, // this can be done safely from another thread. xrt_frame_reference(&xf, NULL); From 98f81734c87a066e95f25b553c5bcd0bb6a49ce3 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 4 Feb 2021 16:56:27 +0000 Subject: [PATCH 277/883] d/vf: Add clock overlay to videotestsource --- src/xrt/drivers/vf/vf_driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xrt/drivers/vf/vf_driver.c b/src/xrt/drivers/vf/vf_driver.c index 0210f8980..1fae738d2 100644 --- a/src/xrt/drivers/vf/vf_driver.c +++ b/src/xrt/drivers/vf/vf_driver.c @@ -437,6 +437,7 @@ vf_fs_videotestsource(struct xrt_frame_context *xfctx, uint32_t width, uint32_t gchar *pipeline_string = g_strdup_printf( "videotestsrc name=source ! " + "clockoverlay ! " "videoconvert ! " "videoscale ! " "video/x-raw,format=RGB,width=%u,height=%u ! " From 2b63fd807875180f8e9c16761b145a473b717659 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 3 Feb 2021 19:37:45 +0000 Subject: [PATCH 278/883] xrt: Add helper push frame function --- src/xrt/include/xrt/xrt_frame.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/xrt/include/xrt/xrt_frame.h b/src/xrt/include/xrt/xrt_frame.h index d1bdc6861..707a28cd3 100644 --- a/src/xrt/include/xrt/xrt_frame.h +++ b/src/xrt/include/xrt/xrt_frame.h @@ -62,6 +62,19 @@ struct xrt_frame_sink void (*push_frame)(struct xrt_frame_sink *sink, struct xrt_frame *frame); }; +/*! + * @copydoc xrt_frame_sink::push_frame + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_frame_sink + */ +static inline void +xrt_sink_push_frame(struct xrt_frame_sink *sink, struct xrt_frame *frame) +{ + sink->push_frame(sink, frame); +} + /*! * @interface xrt_frame_node * From 30573fb90f825c0c22164b7472334b8d03125af2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 2 Feb 2021 18:21:14 +0000 Subject: [PATCH 279/883] a/gst: Add GStreamer helper code Co-authored-by: Aaron Boxer --- src/xrt/auxiliary/CMakeLists.txt | 25 +++ src/xrt/auxiliary/gstreamer/gst_internal.h | 80 +++++++++ src/xrt/auxiliary/gstreamer/gst_pipeline.c | 152 +++++++++++++++++ src/xrt/auxiliary/gstreamer/gst_pipeline.h | 40 +++++ src/xrt/auxiliary/gstreamer/gst_sink.c | 187 +++++++++++++++++++++ src/xrt/auxiliary/gstreamer/gst_sink.h | 37 ++++ 6 files changed, 521 insertions(+) create mode 100644 src/xrt/auxiliary/gstreamer/gst_internal.h create mode 100644 src/xrt/auxiliary/gstreamer/gst_pipeline.c create mode 100644 src/xrt/auxiliary/gstreamer/gst_pipeline.h create mode 100644 src/xrt/auxiliary/gstreamer/gst_sink.c create mode 100644 src/xrt/auxiliary/gstreamer/gst_sink.h diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index 51fa0facb..455945fb9 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -69,6 +69,14 @@ if(XRT_HAVE_DBUS) ) endif() +set(GSTREAMER_SOURCE_FILES + gstreamer/gst_internal.h + gstreamer/gst_sink.h + gstreamer/gst_sink.c + gstreamer/gst_pipeline.h + gstreamer/gst_pipeline.c + ) + set(TRACKING_SOURCE_FILES tracking/t_data_utils.c tracking/t_imu_fusion.hpp @@ -221,6 +229,23 @@ if(ANDROID) target_link_libraries(aux_util PUBLIC ${ANDROID_LOG_LIBRARY}) endif() +# GStreamer library. +if(XRT_HAVE_GST) + add_library(aux_gstreamer STATIC ${GSTREAMER_SOURCE_FILES}) + target_link_libraries(aux_gstreamer PUBLIC + aux-includes + ) + target_link_libraries(aux_gstreamer PRIVATE + xrt-interfaces + aux_math + aux_os + ${GST_LIBRARIES} + ) + target_include_directories(aux_gstreamer PRIVATE + ${GST_INCLUDE_DIRS} + ) +endif() + # Tracking library. add_library(aux_tracking STATIC ${TRACKING_SOURCE_FILES}) target_link_libraries(aux_tracking PUBLIC aux-includes PRIVATE aux_math) diff --git a/src/xrt/auxiliary/gstreamer/gst_internal.h b/src/xrt/auxiliary/gstreamer/gst_internal.h new file mode 100644 index 000000000..d975bc8af --- /dev/null +++ b/src/xrt/auxiliary/gstreamer/gst_internal.h @@ -0,0 +1,80 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Semi internal structs for gstreamer code. + * @author Jakob Bornecrantz + * @ingroup aux_util + */ + +#pragma once + +#include "xrt/xrt_frame.h" + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * + * Pipeline + * + */ + +/*! + * A pipeline from which you can create one or more @ref gstreamer_sink from. + * + * @implements xrt_frame_node + */ +struct gstreamer_pipeline +{ + struct xrt_frame_node node; + + struct xrt_frame_context *xfctx; + + GstElement *pipeline; +}; + + +/* + * + * Sink + * + */ + +/*! + * An @ref xrt_frame_sink that uses appsrc. + * + * @implements xrt_frame_sink + * @implements xrt_frame_node + */ +struct gstreamer_sink +{ + //! The base structure exposing the sink interface. + struct xrt_frame_sink base; + + //! A sink can expose multie @ref xrt_frame_sink but only one node. + struct xrt_frame_node node; + + //! Pipeline this sink is producing frames into. + struct gstreamer_pipeline *gp; + + //! Offset applied to timestamps given to GStreamer. + uint64_t offset_ns; + + //! Last sent timestamp, used to calculate duration. + uint64_t timestamp_ns; + + //! Cached appsrc element. + GstElement *appsrc; +}; + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/auxiliary/gstreamer/gst_pipeline.c b/src/xrt/auxiliary/gstreamer/gst_pipeline.c new file mode 100644 index 000000000..43fb619f8 --- /dev/null +++ b/src/xrt/auxiliary/gstreamer/gst_pipeline.c @@ -0,0 +1,152 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief An @ref xrt_frame_sink that does gst things. + * @author Jakob Bornecrantz + * @author Aaron Boxer + * @ingroup aux_util + */ + +#include "util/u_misc.h" +#include "util/u_debug.h" + +#include "gstreamer/gst_internal.h" +#include "gstreamer/gst_pipeline.h" + + +/* + * + * Internal pipeline functions. + * + */ + +static void +break_apart(struct xrt_frame_node *node) +{ + struct gstreamer_pipeline *gp = container_of(node, struct gstreamer_pipeline, node); + + /* + * This function is called when we are shutting down, after returning + * from this function you are not allowed to call any other nodes in the + * graph. But it must be safe for other nodes to call any normal + * functions on us. Once the context is done calling break_aprt on all + * objects it will call destroy on them. + */ + + (void)gp; +} + +static void +destroy(struct xrt_frame_node *node) +{ + struct gstreamer_pipeline *gp = container_of(node, struct gstreamer_pipeline, node); + + /* + * All of the nodes has been broken apart and none of our functions will + * be called, it's now safe to destroy and free ourselves. + */ + + free(gp); +} + + +/* + * + * Exported functions. + * + */ + +void +gstreamer_pipeline_play(struct gstreamer_pipeline *gp) +{ + U_LOG_D("Starting pipeline"); + + gst_element_set_state(gp->pipeline, GST_STATE_PLAYING); +} + +void +gstreamer_pipeline_stop(struct gstreamer_pipeline *gp) +{ + U_LOG_D("Stopping pipeline"); + + // Settle the pipeline. + U_LOG_T("Sending EOS"); + gst_element_send_event(gp->pipeline, gst_event_new_eos()); + + // Wait for EOS message on the pipeline bus. + U_LOG_T("Waiting for EOS"); + GstMessage *msg = NULL; + msg = gst_bus_timed_pop_filtered(GST_ELEMENT_BUS(gp->pipeline), GST_CLOCK_TIME_NONE, + GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + //! @todo Should check if we got an error message here or an eos. + (void)msg; + + // Completely stop the pipeline. + U_LOG_T("Setting to NULL"); + gst_element_set_state(gp->pipeline, GST_STATE_NULL); +} + +void +gstreamer_pipeline_create_from_string(struct xrt_frame_context *xfctx, + const char *pipeline_string, + struct gstreamer_pipeline **out_gp) +{ + gst_init(NULL, NULL); + + struct gstreamer_pipeline *gp = U_TYPED_CALLOC(struct gstreamer_pipeline); + gp->node.break_apart = break_apart; + gp->node.destroy = destroy; + gp->xfctx = xfctx; + + // Setup pipeline. + gp->pipeline = gst_parse_launch(pipeline_string, NULL); + + /* + * Add ourselves to the context so we are destroyed. + * This is done once we know everything is completed. + */ + xrt_frame_context_add(xfctx, &gp->node); + + *out_gp = gp; +} + +void +gstreamer_pipeline_create_autovideo_sink(struct xrt_frame_context *xfctx, + const char *appsrc_name, + struct gstreamer_pipeline **out_gp) +{ + gst_init(NULL, NULL); + + struct gstreamer_pipeline *gp = U_TYPED_CALLOC(struct gstreamer_pipeline); + gp->node.break_apart = break_apart; + gp->node.destroy = destroy; + gp->xfctx = xfctx; + + // Setup pipeline. + gp->pipeline = gst_pipeline_new("pipeline"); + GstElement *appsrc = gst_element_factory_make("appsrc", appsrc_name); + GstElement *conv = gst_element_factory_make("videoconvert", "conv"); + GstElement *scale = gst_element_factory_make("videoscale", "scale"); + GstElement *videosink = gst_element_factory_make("autovideosink", "videosink"); + + gst_bin_add_many(GST_BIN(gp->pipeline), // + appsrc, // + conv, // + scale, // + videosink, // + NULL); + gst_element_link_many(appsrc, // + conv, // + scale, // + videosink, // + NULL); + + /* + * Add ourselves to the context so we are destroyed. + * This is done once we know everything is completed. + */ + xrt_frame_context_add(xfctx, &gp->node); + + *out_gp = gp; +} diff --git a/src/xrt/auxiliary/gstreamer/gst_pipeline.h b/src/xrt/auxiliary/gstreamer/gst_pipeline.h new file mode 100644 index 000000000..c98c279c9 --- /dev/null +++ b/src/xrt/auxiliary/gstreamer/gst_pipeline.h @@ -0,0 +1,40 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Functions for creating @ref gstreamer_pipeline objects. + * @author Jakob Bornecrantz + * @ingroup aux_util + */ + +#pragma once + +#include "xrt/xrt_frame.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +struct gstreamer_pipeline; + +void +gstreamer_pipeline_create_from_string(struct xrt_frame_context *xfctx, + const char *pipeline_string, + struct gstreamer_pipeline **out_gp); + +void +gstreamer_pipeline_create_autovideo_sink(struct xrt_frame_context *xfctx, + const char *appsrc_name, + struct gstreamer_pipeline **out_gp); + +void +gstreamer_pipeline_play(struct gstreamer_pipeline *gp); + +void +gstreamer_pipeline_stop(struct gstreamer_pipeline *gp); + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/auxiliary/gstreamer/gst_sink.c b/src/xrt/auxiliary/gstreamer/gst_sink.c new file mode 100644 index 000000000..caa99ca41 --- /dev/null +++ b/src/xrt/auxiliary/gstreamer/gst_sink.c @@ -0,0 +1,187 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief An @ref xrt_frame_sink that does gst things. + * @author Jakob Bornecrantz + * @author Aaron Boxer + * @ingroup aux_util + */ + +#include "util/u_misc.h" +#include "util/u_debug.h" +#include "util/u_format.h" + +#include "gstreamer/gst_sink.h" +#include "gstreamer/gst_pipeline.h" +#include "gstreamer/gst_internal.h" + +#include + + +/* + * + * Internal sink functions. + * + */ + +static void +wrapped_buffer_destroy(gpointer data) +{ + struct xrt_frame *xf = (struct xrt_frame *)data; + + U_LOG_T("Called"); + + xrt_frame_reference(&xf, NULL); +} + +static void +push_frame(struct xrt_frame_sink *xfs, struct xrt_frame *xf) +{ + struct gstreamer_sink *gs = (struct gstreamer_sink *)xfs; + GstBuffer *buffer; + GstFlowReturn ret; + + U_LOG_T( + "Called" + "\n\tformat: %s" + "\n\twidth: %u" + "\n\theight: %u", + u_format_str(xf->format), xf->width, xf->height); + + /* We need to take a reference on the frame to keep it alive. */ + struct xrt_frame *taken = NULL; + xrt_frame_reference(&taken, xf); + + /* Wrap the frame that we now hold a reference to. */ + buffer = gst_buffer_new_wrapped_full( // + 0, // GstMemoryFlags flags + (gpointer)xf->data, // gpointer data + taken->size, // gsize maxsize + 0, // gsize offset + taken->size, // gsize size + taken, // gpointer user_data + wrapped_buffer_destroy); // GDestroyNotify notify + + //! Get the timestampe from the frame. + uint64_t xtimestamp_ns = xf->timestamp; + + // Use the first frame as offset. + if (gs->offset_ns == 0) { + gs->offset_ns = xtimestamp_ns; + } + + // Need to be offset or gstreamer becomes sad. + GST_BUFFER_PTS(buffer) = xtimestamp_ns - gs->offset_ns; + + // Duration is measured from last time stamp. + GST_BUFFER_DURATION(buffer) = xtimestamp_ns - gs->timestamp_ns; + gs->timestamp_ns = xtimestamp_ns; + + // All done, send it to the gstreamer pipeline. + ret = gst_app_src_push_buffer((GstAppSrc *)gs->appsrc, buffer); + if (ret != GST_FLOW_OK) { + U_LOG_E("Got GST error '%i'", ret); + } +} + +static void +enough_data(GstElement *appsrc, gpointer udata) +{ + // Debugging code. + U_LOG_T("Called"); +} + +static void +break_apart(struct xrt_frame_node *node) +{ + struct gstreamer_sink *gs = container_of(node, struct gstreamer_sink, node); + + /* + * This function is called when we are shutting down, after returning + * from this function you are not allowed to call any other nodes in the + * graph. But it must be safe for other nodes to call any normal + * functions on us. Once the context is done calling break_aprt on all + * objects it will call destroy on them. + */ + + (void)gs; +} + +static void +destroy(struct xrt_frame_node *node) +{ + struct gstreamer_sink *gs = container_of(node, struct gstreamer_sink, node); + + /* + * All of the nodes has been broken apart and none of our functions will + * be called, it's now safe to destroy and free ourselves. + */ + + free(gs); +} + + +/* + * + * Exported functions. + * + */ + +void +gstreamer_sink_send_eos(struct gstreamer_sink *gs) +{ + gst_element_send_event(gs->appsrc, gst_event_new_eos()); +} + +void +gstreamer_sink_create_with_pipeline(struct gstreamer_pipeline *gp, + uint32_t width, + uint32_t height, + enum xrt_format format, + const char *appsrc_name, + struct gstreamer_sink **out_gs, + struct xrt_frame_sink **out_xfs) +{ + const char *format_str = NULL; + switch (format) { + case XRT_FORMAT_R8G8B8: format_str = "RGB"; break; + case XRT_FORMAT_YUYV422: format_str = "YUY2"; break; + case XRT_FORMAT_L8: format_str = "GRAY8"; break; + default: assert(false); break; + } + + struct gstreamer_sink *gs = U_TYPED_CALLOC(struct gstreamer_sink); + gs->base.push_frame = push_frame; + gs->node.break_apart = break_apart; + gs->node.destroy = destroy; + gs->gp = gp; + gs->appsrc = gst_bin_get_by_name(GST_BIN(gp->pipeline), appsrc_name); + + + GstCaps *caps = gst_caps_new_simple( // + "video/x-raw", // + "format", G_TYPE_STRING, format_str, // + "width", G_TYPE_INT, width, // + "height", G_TYPE_INT, height, // + "framerate", GST_TYPE_FRACTION, 0, 1, // + NULL); + + g_object_set(G_OBJECT(gs->appsrc), // + "caps", caps, // + "stream-type", GST_APP_STREAM_TYPE_STREAM, // + "format", GST_FORMAT_TIME, // + "is-live", TRUE, // + NULL); + + g_signal_connect(G_OBJECT(gs->appsrc), "enough-data", G_CALLBACK(enough_data), gs); + + /* + * Add ourselves to the context so we are destroyed. + * This is done once we know everything is completed. + */ + xrt_frame_context_add(gp->xfctx, &gs->node); + + *out_gs = gs; + *out_xfs = &gs->base; +} diff --git a/src/xrt/auxiliary/gstreamer/gst_sink.h b/src/xrt/auxiliary/gstreamer/gst_sink.h new file mode 100644 index 000000000..fc4df2899 --- /dev/null +++ b/src/xrt/auxiliary/gstreamer/gst_sink.h @@ -0,0 +1,37 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief @ref xrt_frame_sink that does gst things. + * @author Jakob Bornecrantz + * @ingroup aux_util + */ + +#pragma once + +#include "xrt/xrt_frame.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct gstreamer_sink; +struct gstreamer_pipeline; + + +void +gstreamer_sink_send_eos(struct gstreamer_sink *gp); + +void +gstreamer_sink_create_with_pipeline(struct gstreamer_pipeline *gp, + uint32_t width, + uint32_t height, + enum xrt_format format, + const char *appsrc_name, + struct gstreamer_sink **out_gs, + struct xrt_frame_sink **out_xfs); + + +#ifdef __cplusplus +} +#endif From 95e71ebba73b9de0361545dcc2692907d4c234f1 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 14 Sep 2020 22:15:41 +0100 Subject: [PATCH 280/883] external: Add STB header library --- src/external/CMakeLists.txt | 4 + src/external/meson.build | 1 + src/external/stb/stb_image_write.h | 1666 ++++++++++++++++++++++++++++ 3 files changed, 1671 insertions(+) create mode 100644 src/external/stb/stb_image_write.h diff --git a/src/external/CMakeLists.txt b/src/external/CMakeLists.txt index d4bffcddc..500c4ae46 100644 --- a/src/external/CMakeLists.txt +++ b/src/external/CMakeLists.txt @@ -49,3 +49,7 @@ endif() # OpenXR add_library(xrt-external-openxr INTERFACE) target_include_directories(xrt-external-openxr INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/openxr_includes) + +# STB +add_library(xrt-external-stb INTERFACE) +target_include_directories(xrt-external-stb INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/stb) diff --git a/src/external/meson.build b/src/external/meson.build index 045ecc529..71300ebd4 100644 --- a/src/external/meson.build +++ b/src/external/meson.build @@ -9,3 +9,4 @@ hungarian_include = include_directories('hungarian') imgui_include = include_directories('imgui') openxr_include = include_directories('openxr_includes') catch2_include = include_directories('Catch2') +stb_include = include_directories('stb') diff --git a/src/external/stb/stb_image_write.h b/src/external/stb/stb_image_write.h new file mode 100644 index 000000000..cffd473c1 --- /dev/null +++ b/src/external/stb/stb_image_write.h @@ -0,0 +1,1666 @@ +/* stb_image_write - v1.14 - public domain - http://nothings.org/stb + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio or a callback. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + +USAGE: + + There are five functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can configure it with these global variables: + int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE + int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression + int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_compression_level' (it defaults to 8). + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + + JPEG does ignore alpha channels in input data; quality is between 1 and 100. + Higher quality looks better but results in a bigger image. + JPEG baseline (no JPEG progressive). + +CREDITS: + + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + Aarni Koskela - allow choosing PNG filter + + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + github:poppolopoppo + Patrick Boettcher + github:xeekworx + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + +LICENSE + + See end of file for license information. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#include + +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif +#endif + +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +extern int stbi_write_tga_with_rle; +extern int stbi_write_png_compression_level; +extern int stbi_write_force_png_filter; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBI_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + +STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_compression_level = 8; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; +#else +int stbi_write_png_compression_level = 8; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; +#endif + +static int stbi__flip_vertically_on_write = 0; + +STBIWDEF void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + +typedef struct +{ + stbi_write_func *func; + void *context; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + unsigned char arr[3]; + arr[0] = a; arr[1] = b; arr[2] = c; + s->func(s->context, arr, 3); +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + s->func(s->context, &d[comp - 1], 1); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + s->func(s->context, d, 1); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + s->func(s->context, &d[comp - 1], 1); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + s->func(s->context, &header, 1); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + s->func(s->context, &header, 1); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + } + return 1; +} + +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +#ifdef __STDC_WANT_SECURE_LIB__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); + STBIW_FREE(scratch); + return 1; + } +} + +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +#ifndef STBIW_ZLIB_COMPRESS +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +#endif // STBIW_ZLIB_COMPRESS + +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); + if (hash_table == NULL) + return NULL; + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) { best=d; bestloc=hlist[j]; } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +#endif +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } +} + +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ From fac93948b3cf1ef4aa89fabd457b15c826cb3174 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 14 Sep 2020 22:24:56 +0100 Subject: [PATCH 281/883] st/gui: Add STB image writing support --- src/xrt/state_trackers/gui/CMakeLists.txt | 2 ++ src/xrt/state_trackers/gui/gui_stb.c | 3 +++ src/xrt/state_trackers/gui/meson.build | 2 ++ 3 files changed, 7 insertions(+) create mode 100644 src/xrt/state_trackers/gui/gui_stb.c diff --git a/src/xrt/state_trackers/gui/CMakeLists.txt b/src/xrt/state_trackers/gui/CMakeLists.txt index e1642b526..c07ed9c90 100644 --- a/src/xrt/state_trackers/gui/CMakeLists.txt +++ b/src/xrt/state_trackers/gui/CMakeLists.txt @@ -16,6 +16,7 @@ set(GUI_SOURCE_FILES gui_scene_remote.c gui_scene_video.c gui_scene_tracking_overrides.c + gui_stb.c ../../../external/imgui/imgui/cimgui.cpp ../../../external/imgui/imgui/cimgui.h ../../../external/imgui/imgui/cimplot.cpp @@ -46,6 +47,7 @@ add_library(st_gui STATIC target_link_libraries(st_gui PRIVATE xrt-external-glad + xrt-external-stb aux_util aux_os ) diff --git a/src/xrt/state_trackers/gui/gui_stb.c b/src/xrt/state_trackers/gui/gui_stb.c new file mode 100644 index 000000000..e1b1583b4 --- /dev/null +++ b/src/xrt/state_trackers/gui/gui_stb.c @@ -0,0 +1,3 @@ + +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb_image_write.h" diff --git a/src/xrt/state_trackers/gui/meson.build b/src/xrt/state_trackers/gui/meson.build index d7953c32d..5de806557 100644 --- a/src/xrt/state_trackers/gui/meson.build +++ b/src/xrt/state_trackers/gui/meson.build @@ -13,6 +13,7 @@ gui_sources = [ 'gui_scene_remote.c', 'gui_scene_video.c', 'gui_scene_tracking_overrides.c', + 'gui_stb.c', '../../../external/imgui/imgui/cimgui.cpp', '../../../external/imgui/imgui/cimgui.h', '../../../external/imgui/imgui/cimplot.cpp', @@ -49,6 +50,7 @@ lib_st_gui = static_library( glad_include, cjson_include, imgui_include, + stb_include, ], dependencies: gui_deps, ) From 1b0d67a895b37304d013ca92488b578ab410cac2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 27 Feb 2021 02:25:22 +0000 Subject: [PATCH 282/883] st/gui: Add recording interface --- src/xrt/state_trackers/gui/CMakeLists.txt | 9 +- src/xrt/state_trackers/gui/gui_common.h | 8 + .../state_trackers/gui/gui_scene_main_menu.c | 11 + src/xrt/state_trackers/gui/gui_scene_record.c | 586 ++++++++++++++++++ src/xrt/state_trackers/gui/meson.build | 7 +- src/xrt/targets/gui/gui_sdl2_main.c | 2 + 6 files changed, 621 insertions(+), 2 deletions(-) create mode 100644 src/xrt/state_trackers/gui/gui_scene_record.c diff --git a/src/xrt/state_trackers/gui/CMakeLists.txt b/src/xrt/state_trackers/gui/CMakeLists.txt index c07ed9c90..610cc458b 100644 --- a/src/xrt/state_trackers/gui/CMakeLists.txt +++ b/src/xrt/state_trackers/gui/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2019-2020, Collabora, Ltd. +# Copyright 2019-2021, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 # c-imgui doesn't do well with IPO - lots of warnings. @@ -13,6 +13,7 @@ set(GUI_SOURCE_FILES gui_scene_calibrate.c gui_scene_debug.c gui_scene_main_menu.c + gui_scene_record.c gui_scene_remote.c gui_scene_video.c gui_scene_tracking_overrides.c @@ -60,6 +61,12 @@ target_compile_definitions(st_gui PUBLIC CIMGUI_NO_EXPORT ) +if(XRT_HAVE_GST) + target_link_libraries(st_gui PRIVATE + aux_gstreamer + ) +endif() + if(XRT_BUILD_DRIVER_REMOTE) target_link_libraries(st_gui PRIVATE drv_remote diff --git a/src/xrt/state_trackers/gui/gui_common.h b/src/xrt/state_trackers/gui/gui_common.h index 16f8c0158..3405b7ddb 100644 --- a/src/xrt/state_trackers/gui/gui_common.h +++ b/src/xrt/state_trackers/gui/gui_common.h @@ -213,6 +213,14 @@ gui_scene_tracking_overrides(struct gui_program *p); void gui_scene_debug(struct gui_program *p); +/*! + * Create a recording view scene. + * + * @ingroup gui + */ +void +gui_scene_record(struct gui_program *p, const char *camera); + /*! * Remote control debugging UI. * diff --git a/src/xrt/state_trackers/gui/gui_scene_main_menu.c b/src/xrt/state_trackers/gui/gui_scene_main_menu.c index 482048075..602213001 100644 --- a/src/xrt/state_trackers/gui/gui_scene_main_menu.c +++ b/src/xrt/state_trackers/gui/gui_scene_main_menu.c @@ -51,6 +51,17 @@ scene_render(struct gui_scene *scene, struct gui_program *p) gui_scene_debug(p); } + if (igButton("Record (Index)", button_dims)) { + gui_scene_delete_me(p, scene); + gui_scene_record(p, "index"); + } + + + if (igButton("Record (Leap Motion)", button_dims)) { + gui_scene_delete_me(p, scene); + gui_scene_record(p, "leap_motion"); + } + if (igButton("Remote", button_dims)) { gui_scene_delete_me(p, scene); diff --git a/src/xrt/state_trackers/gui/gui_scene_record.c b/src/xrt/state_trackers/gui/gui_scene_record.c new file mode 100644 index 000000000..4523a9c2d --- /dev/null +++ b/src/xrt/state_trackers/gui/gui_scene_record.c @@ -0,0 +1,586 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Calibration gui scene. + * @author Jakob Bornecrantz + * @ingroup gui + */ + + +#include "xrt/xrt_config_have.h" +#include "xrt/xrt_config_drivers.h" + +#include "os/os_threading.h" + +#include "util/u_var.h" +#include "util/u_misc.h" +#include "util/u_sink.h" +#include "util/u_file.h" +#include "util/u_json.h" +#include "util/u_frame.h" +#include "util/u_format.h" + +#include "xrt/xrt_frame.h" +#include "xrt/xrt_prober.h" +#include "xrt/xrt_tracking.h" +#include "xrt/xrt_frameserver.h" + +#ifdef XRT_HAVE_GST +#include "gstreamer/gst_sink.h" +#include "gstreamer/gst_pipeline.h" +#endif + +#ifdef XRT_BUILD_DRIVER_VF +#include "vf/vf_interface.h" +#endif + +#include "gui_common.h" +#include "gui_imgui.h" + +#include "stb_image_write.h" + +#include +#include + +enum bitrate +{ + BITRATE_4096, + BITRATE_2048, + BITRATE_1024, +}; + +enum pipeline +{ + PIPELINE_SOFTWARE_FAST, + PIPELINE_SOFTWARE_MEDIUM, + PIPELINE_SOFTWARE_SLOW, + PIPELINE_SOFTWARE_VERYSLOW, + PIPELINE_VAAPI_H246, +}; + +struct record_window +{ + struct xrt_frame_sink sink; + + struct + { + // Use leap_motion. + bool leap_motion; + // Use index. + bool index; + } use; + + struct + { + struct xrt_frame_context xfctx; + + struct xrt_fs *xfs; + + struct xrt_fs_mode mode; + + char name[256]; + } camera; + + struct + { + int scale; + + struct xrt_frame_sink *sink; + struct gui_ogl_texture *ogl; + } texture; + +#ifdef XRT_HAVE_GST + struct + { + enum bitrate bitrate; + + enum pipeline pipeline; + + struct xrt_frame_context xfctx; + + //! When not null we are recording. + struct xrt_frame_sink *sink; + + //! Protects sink + struct os_mutex mutex; + + //! App sink we are pushing frames into. + struct gstreamer_sink *gs; + + //! Recording pipeline. + struct gstreamer_pipeline *gp; + + char filename[512]; + } gst; +#endif +}; + +struct record_scene +{ + struct gui_scene base; + + struct record_window *window; +}; + + +/* + * + * GStreamer functions. + * + */ + +#ifdef XRT_HAVE_GST +static void +create_pipeline(struct record_window *rw) +{ + const char *source_name = "source_name"; + const char *bitrate = NULL; + const char *speed_preset = NULL; + + char pipeline_string[2048]; + + switch (rw->gst.bitrate) { + default: + case BITRATE_4096: bitrate = "4096"; break; + case BITRATE_2048: bitrate = "2048"; break; + case BITRATE_1024: bitrate = "1024"; break; + } + + switch (rw->gst.pipeline) { + case PIPELINE_SOFTWARE_FAST: speed_preset = "fast"; break; + case PIPELINE_SOFTWARE_MEDIUM: speed_preset = "medium"; break; + case PIPELINE_SOFTWARE_SLOW: speed_preset = "slow"; break; + case PIPELINE_SOFTWARE_VERYSLOW: speed_preset = "veryslow"; break; + default: break; + } + + if (speed_preset != NULL) { + snprintf(pipeline_string, // + sizeof(pipeline_string), // + "appsrc name=\"%s\" ! " + "queue ! " + "videoconvert ! " + "queue ! " + "x264enc bitrate=\"%s\" speed-preset=\"%s\" ! " + "h264parse ! " + "queue ! " + "mp4mux ! " + "filesink location=\"%s\"", + source_name, bitrate, speed_preset, rw->gst.filename); + } else { + snprintf(pipeline_string, // + sizeof(pipeline_string), // + "appsrc name=\"%s\" ! " + "queue ! " + "videoconvert ! " + "video/x-raw,format=NV12 ! " + "queue ! " + "vaapih264enc rate-control=cbr bitrate=\"%s\" tune=high-compression ! " + "video/x-h264,profile=main ! " + "h264parse ! " + "queue ! " + "mp4mux ! " + "filesink location=\"%s\"", + source_name, bitrate, rw->gst.filename); + } + + struct xrt_frame_sink *tmp = NULL; + struct gstreamer_pipeline *gp = NULL; + + gstreamer_pipeline_create_from_string(&rw->gst.xfctx, pipeline_string, &gp); + + uint32_t width = rw->camera.mode.width; + uint32_t height = rw->camera.mode.height; + enum xrt_format format = rw->camera.mode.format; + + struct gstreamer_sink *gs = NULL; + + gstreamer_sink_create_with_pipeline(gp, width, height, format, source_name, &gs, &tmp); + u_sink_queue_create(&rw->gst.xfctx, tmp, &tmp); + + os_mutex_lock(&rw->gst.mutex); + rw->gst.gs = gs; + rw->gst.sink = tmp; + rw->gst.gp = gp; + gstreamer_pipeline_play(rw->gst.gp); + os_mutex_unlock(&rw->gst.mutex); +} + +static void +destroy_pipeline(struct record_window *rw) +{ + U_LOG_D("Called"); + + // Make sure we are not streaming any more frames into the pipeline. + os_mutex_lock(&rw->gst.mutex); + rw->gst.gs = NULL; + rw->gst.sink = NULL; + os_mutex_unlock(&rw->gst.mutex); + + // Stop the pipeline. + gstreamer_pipeline_stop(rw->gst.gp); + rw->gst.gp = NULL; + + xrt_frame_context_destroy_nodes(&rw->gst.xfctx); +} + +static void +draw_gst(struct record_window *rw) +{ + static ImVec2 button_dims = {0, 0}; + + if (!igCollapsingHeaderBoolPtr("Record", NULL, ImGuiTreeNodeFlags_DefaultOpen)) { + return; + } + + + os_mutex_lock(&rw->gst.mutex); + bool recording = rw->gst.gp != NULL; + os_mutex_unlock(&rw->gst.mutex); + + igComboStr("Pipeline", (int *)&rw->gst.pipeline, "SW Fast\0SW Medium\0SW Slow\0SW Veryslow\0VAAPI H264\0\0", 5); + + igInputText("Filename", rw->gst.filename, sizeof(rw->gst.filename), 0, NULL, NULL); + + if (!recording && igButton("Start", button_dims)) { + create_pipeline(rw); + } + + if (recording && igButton("Stop", button_dims)) { + destroy_pipeline(rw); + } +} +#endif + + +/* + * + * Record window functions. + * + */ + +static void +window_destroy(struct record_window *rw) +{ + // Stop and remove the recording pipeline first. +#ifdef XRT_HAVE_GST + if (rw->gst.gp != NULL) { + os_mutex_lock(&rw->gst.mutex); + rw->gst.gs = NULL; + rw->gst.sink = NULL; + os_mutex_unlock(&rw->gst.mutex); + + gstreamer_pipeline_stop(rw->gst.gp); + rw->gst.gp = NULL; + xrt_frame_context_destroy_nodes(&rw->gst.xfctx); + } +#endif + + // Stop the camera if we have one. + xrt_frame_context_destroy_nodes(&rw->camera.xfctx); + rw->camera.xfs = NULL; + rw->texture.ogl = NULL; + rw->texture.sink = NULL; + + free(rw); +} + +static bool +window_has_source(struct record_window *rw) +{ + return rw->camera.xfs != NULL; +} + +static void +window_draw_misc(struct record_window *rw) +{ + if (!igCollapsingHeaderBoolPtr("Misc", NULL, ImGuiTreeNodeFlags_DefaultOpen)) { + return; + } + + static ImVec2 button_dims = {0, 0}; + bool plus = igButton("+", button_dims); + igSameLine(0.0f, 4.0f); + bool minus = igButton("-", button_dims); + igSameLine(0.0f, 4.0f); + + if (rw->texture.scale == 1) { + igText("Scale 100%%"); + } else { + igText("Scale 1/%i", rw->texture.scale); + } + + if (plus && rw->texture.scale > 1) { + rw->texture.scale--; + } + if (minus && rw->texture.scale < 6) { + rw->texture.scale++; + } + + igText("Sequence %u", (uint32_t)rw->texture.ogl->seq); +} + +static void +window_render(struct record_window *rw, struct gui_program *p) +{ + igBegin("Preview and Control", NULL, 0); + + gui_ogl_sink_update(rw->texture.ogl); + + struct gui_ogl_texture *tex = rw->texture.ogl; + + int w = tex->w / rw->texture.scale; + int h = tex->h / rw->texture.scale; + + ImVec2 size = {(float)w, (float)h}; + ImVec2 uv0 = {0, 0}; + ImVec2 uv1 = {1, 1}; + ImVec4 white = {1, 1, 1, 1}; + ImTextureID id = (ImTextureID)(intptr_t)tex->id; + igImage(id, size, uv0, uv1, white, white); + +#ifdef XRT_HAVE_GST + draw_gst(rw); +#endif + + window_draw_misc(rw); + + igEnd(); +} + +static void +window_frame(struct xrt_frame_sink *xfs, struct xrt_frame *xf) +{ + struct record_window *rw = container_of(xfs, struct record_window, sink); + +#ifdef XRT_HAVE_GST + os_mutex_lock(&rw->gst.mutex); + if (rw->gst.sink != NULL) { + xrt_sink_push_frame(rw->gst.sink, xf); + } + os_mutex_unlock(&rw->gst.mutex); +#endif + + xrt_sink_push_frame(rw->texture.sink, xf); +} + +static struct record_window * +window_create(struct gui_program *p, const char *camera) +{ + struct record_window *rw = U_TYPED_CALLOC(struct record_window); + rw->sink.push_frame = window_frame; + rw->use.index = camera == NULL ? false : strcmp(camera, "index") == 0; + rw->use.leap_motion = camera == NULL ? false : strcmp(camera, "leap_motion") == 0; + + if (!rw->use.index && !rw->use.leap_motion) { + U_LOG_W("Can't recongnize camera name '%s', options are 'index' & 'leap_motion'", camera); + rw->use.index = true; + } + + // Setup the preview texture. + rw->texture.scale = 1; + struct xrt_frame_sink *tmp = NULL; + rw->texture.ogl = gui_ogl_sink_create("View", &rw->camera.xfctx, &tmp); + u_sink_create_to_r8g8b8_or_l8(&rw->camera.xfctx, tmp, &tmp); + u_sink_queue_create(&rw->camera.xfctx, tmp, &rw->texture.sink); + +#ifdef XRT_HAVE_GST + int ret = os_mutex_init(&rw->gst.mutex); + if (ret < 0) { + free(rw); + return NULL; + } + + snprintf(rw->gst.filename, sizeof(rw->gst.filename), "/tmp/capture.mp4"); +#endif + + return rw; +} + + +/* + * + * Video frame functions + * + */ + +#ifdef XRT_BUILD_DRIVER_VF +static void +create_videotestsrc(struct record_window *rw) +{ + uint32_t width = 1920; + uint32_t height = 960; + rw->camera.xfs = vf_fs_videotestsource(&rw->camera.xfctx, width, height); + + // Just after the camera create a quirk stream. + struct u_sink_quirk_params qp; + U_ZERO(&qp); + qp.stereo_sbs = false; + qp.ps4_cam = false; + qp.leap_motion = false; + + struct xrt_frame_sink *tmp = NULL; + u_sink_quirk_create(&rw->camera.xfctx, &rw->sink, &qp, &tmp); + + // Now that we have setup a node graph, start it. + xrt_fs_stream_start(rw->camera.xfs, tmp, 0, XRT_FS_CAPTURE_TYPE_TRACKING); + + rw->camera.mode.width = width; + rw->camera.mode.height = height; + rw->camera.mode.format = XRT_FORMAT_R8G8B8; + + // If it's a large mode, scale to 50% + if (rw->camera.mode.width > 640) { + rw->texture.scale = 2; + } +} +#endif /* XRT_BUILD_DRIVER_VF */ + + +/* + * + * Prober functions. + * + */ + +static bool +is_camera_index(const char *product, const char *manufacturer) +{ + return strcmp(product, "3D Camera") == 0 && strcmp(manufacturer, "Etron Technology, Inc.") == 0; +} + +static bool +is_camera_leap_motion(const char *product, const char *manufacturer) +{ + return strcmp(product, "Leap Motion Controller") == 0 && strcmp(manufacturer, "Leap Motion") == 0; +} + +static void +on_video_device(struct xrt_prober *xp, + struct xrt_prober_device *pdev, + const char *product, + const char *manufacturer, + const char *serial, + void *ptr) +{ + struct record_window *rw = (struct record_window *)ptr; + + if (rw->camera.xfs != NULL) { + return; + } + + // Hardcoded for the Index. + if (rw->use.index && !is_camera_index(product, manufacturer)) { + return; + } + + // Hardcoded for the Leap Motion. + if (rw->use.leap_motion && !is_camera_leap_motion(product, manufacturer)) { + return; + } + + snprintf(rw->camera.name, sizeof(rw->camera.name), "%s-%s", product, serial); + + xrt_prober_open_video_device(xp, pdev, &rw->camera.xfctx, &rw->camera.xfs); + + struct xrt_frame_sink *tmp = &rw->sink; + + if (rw->use.leap_motion) { + // De-interleaving. + u_sink_deinterleaver_create(&rw->camera.xfctx, tmp, &tmp); + } + + // Just after the camera create a quirk stream. + struct u_sink_quirk_params qp; + U_ZERO(&qp); + qp.stereo_sbs = false; + qp.ps4_cam = false; + qp.leap_motion = rw->use.leap_motion; + + u_sink_quirk_create(&rw->camera.xfctx, tmp, &qp, &tmp); + + struct xrt_fs_mode *modes = NULL; + uint32_t mode_count = 0; + xrt_fs_enumerate_modes(rw->camera.xfs, &modes, &mode_count); + assert(mode_count > 0); + + // Just use the first one. + uint32_t mode_index = 0; + + rw->camera.mode = modes[mode_index]; + free(modes); + modes = NULL; + + // Touch up. + if (rw->use.leap_motion) { + rw->camera.mode.width = rw->camera.mode.width * 2; + rw->camera.mode.format = XRT_FORMAT_L8; + } + + // If it's a large mode, scale to 50% + if (rw->camera.mode.width > 640) { + rw->texture.scale = 2; + } + + // Now that we have setup a node graph, start it. + xrt_fs_stream_start(rw->camera.xfs, tmp, mode_index, XRT_FS_CAPTURE_TYPE_TRACKING); +} + + +/* + * + * Scene functions. + * + */ + +static void +scene_render(struct gui_scene *scene, struct gui_program *p) +{ + static ImVec2 button_dims = {0, 0}; + struct record_scene *rs = (struct record_scene *)scene; + + window_render(rs->window, p); + + igBegin("Record-a-tron!", NULL, 0); + if (igButton("Exit", button_dims)) { + gui_scene_delete_me(p, &rs->base); + } + igEnd(); +} + +static void +scene_destroy(struct gui_scene *scene, struct gui_program *p) +{ + struct record_scene *rs = (struct record_scene *)scene; + + if (rs->window != NULL) { + window_destroy(rs->window); + rs->window = NULL; + } + + free(rs); +} + +void +gui_scene_record(struct gui_program *p, const char *camera) +{ + struct record_scene *rs = U_TYPED_CALLOC(struct record_scene); + + rs->base.render = scene_render; + rs->base.destroy = scene_destroy; + + rs->window = window_create(p, camera); + + if (!window_has_source(rs->window)) { + xrt_prober_list_video_devices(p->xp, on_video_device, rs->window); + } + +#ifdef XRT_BUILD_DRIVER_VF + if (!window_has_source(rs->window)) { + create_videotestsrc(rs->window); + } +#endif + + gui_scene_push_front(p, &rs->base); +} diff --git a/src/xrt/state_trackers/gui/meson.build b/src/xrt/state_trackers/gui/meson.build index 5de806557..75fd44a11 100644 --- a/src/xrt/state_trackers/gui/meson.build +++ b/src/xrt/state_trackers/gui/meson.build @@ -1,4 +1,4 @@ -# Copyright 2019-2020, Collabora, Ltd. +# Copyright 2019-2021, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 gui_sources = [ @@ -10,6 +10,7 @@ gui_sources = [ 'gui_scene_calibrate.c', 'gui_scene_debug.c', 'gui_scene_main_menu.c', + 'gui_scene_record.c', 'gui_scene_remote.c', 'gui_scene_video.c', 'gui_scene_tracking_overrides.c', @@ -41,6 +42,10 @@ gui_sources = [ gui_deps = [aux, xrt_config_have] +if 'vf' in drivers + gui_deps += [drv_vf] +endif + lib_st_gui = static_library( 'st_gui', files(gui_sources), diff --git a/src/xrt/targets/gui/gui_sdl2_main.c b/src/xrt/targets/gui/gui_sdl2_main.c index 9ba17e2d6..1aa0fb281 100644 --- a/src/xrt/targets/gui/gui_sdl2_main.c +++ b/src/xrt/targets/gui/gui_sdl2_main.c @@ -41,6 +41,8 @@ main(int argc, char **argv) gui_scene_select_video_calibrate(&p.base); } else if (argc >= 2 && strcmp("tracking_overrides", argv[1]) == 0) { gui_scene_tracking_overrides(&p.base); + } else if (argc >= 2 && strcmp("record", argv[1]) == 0) { + gui_scene_record(&p.base, argc >= 3 ? argv[2] : NULL); } else if (argc >= 2 && strcmp("remote", argv[1]) == 0) { gui_scene_remote(&p.base); } else { From 727612c0a5f3c04ce9b1381855e39904b316b9b1 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 12 Mar 2021 17:48:26 +0000 Subject: [PATCH 283/883] doc: Document !715 --- doc/changes/drivers/mr.715.md | 1 + doc/changes/misc_features/mr.715.md | 3 +++ doc/changes/state_trackers/mr.715.md | 1 + doc/changes/xrt/mr.715.md | 1 + 4 files changed, 6 insertions(+) create mode 100644 doc/changes/drivers/mr.715.md create mode 100644 doc/changes/misc_features/mr.715.md create mode 100644 doc/changes/state_trackers/mr.715.md create mode 100644 doc/changes/xrt/mr.715.md diff --git a/doc/changes/drivers/mr.715.md b/doc/changes/drivers/mr.715.md new file mode 100644 index 000000000..1fa0d2b33 --- /dev/null +++ b/doc/changes/drivers/mr.715.md @@ -0,0 +1 @@ +vf: Show the time on the video test source video server. diff --git a/doc/changes/misc_features/mr.715.md b/doc/changes/misc_features/mr.715.md new file mode 100644 index 000000000..c8facc4e1 --- /dev/null +++ b/doc/changes/misc_features/mr.715.md @@ -0,0 +1,3 @@ +a/gst: Add a small and fairly dumb framework for integrating gstreamer pipelines +into Monado pipelines. Enough to be able to push frames into it and use various +encoder elements. diff --git a/doc/changes/state_trackers/mr.715.md b/doc/changes/state_trackers/mr.715.md new file mode 100644 index 000000000..cc4d44d11 --- /dev/null +++ b/doc/changes/state_trackers/mr.715.md @@ -0,0 +1 @@ +gui: Add a GUI for recording videos from the Valve Index. diff --git a/doc/changes/xrt/mr.715.md b/doc/changes/xrt/mr.715.md new file mode 100644 index 000000000..78fcc20f6 --- /dev/null +++ b/doc/changes/xrt/mr.715.md @@ -0,0 +1 @@ +Add small helper function for pushing frames. From 2b962a5bfb6506d090088f434c9ad2273fd39b01 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Sun, 4 Apr 2021 20:58:47 +0200 Subject: [PATCH 284/883] u_config_json: Create root node on save if no config file loaded If no config file is loaded, json->root can be uninitialized instead of NULL. Fixes #117 --- src/xrt/auxiliary/util/u_config_json.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 714f8dc2e..826d9aed7 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -378,7 +378,7 @@ u_config_write(struct u_config_json *json) void u_config_json_save_calibration(struct u_config_json *json, struct xrt_settings_tracking *settings) { - if (!json->root) { + if (!json->file_loaded) { u_config_json_make_default_root(json); } cJSON *root = json->root; @@ -435,7 +435,7 @@ make_pose(struct xrt_pose *pose) void u_config_json_save_overrides(struct u_config_json *json, struct xrt_tracking_override *overrides, size_t num_overrides) { - if (!json->root) { + if (!json->file_loaded) { u_config_json_make_default_root(json); } cJSON *root = json->root; From b62b6eaef7ccc9face6bbdf6ace290e7fcba6438 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Sun, 21 Feb 2021 00:35:10 -0600 Subject: [PATCH 285/883] c/main: Follow OpenXR spec with blackground colour, tweek no layer colour. Make background colour completely black if there are layers to display, to follow OpenXR spec. Make the default background colour darker. --- src/xrt/compositor/main/comp_layer_renderer.c | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/xrt/compositor/main/comp_layer_renderer.c b/src/xrt/compositor/main/comp_layer_renderer.c index 79d1a16bb..cb2f3413d 100644 --- a/src/xrt/compositor/main/comp_layer_renderer.c +++ b/src/xrt/compositor/main/comp_layer_renderer.c @@ -22,10 +22,16 @@ struct comp_layer_vertex float uv[2]; }; -static const VkClearColorValue background_color = { - .float32 = {0.3f, 0.3f, 0.3f, 1.0f}, +static const VkClearColorValue background_color_idle = { + .float32 = {0.1f, 0.1f, 0.1f, 1.0f}, }; +static const VkClearColorValue background_color_active = { + .float32 = {0.0f, 0.0f, 0.0f, 1.0f}, +}; + + + static bool _init_render_pass(struct vk_bundle *vk, VkFormat format, @@ -571,7 +577,10 @@ _render_pass_begin(struct vk_bundle *vk, } static void -_render_stereo(struct comp_layer_renderer *self, struct vk_bundle *vk, VkCommandBuffer cmd_buffer) +_render_stereo(struct comp_layer_renderer *self, + struct vk_bundle *vk, + VkCommandBuffer cmd_buffer, + const VkClearColorValue *color) { COMP_TRACE_MARKER(); @@ -586,8 +595,8 @@ _render_stereo(struct comp_layer_renderer *self, struct vk_bundle *vk, VkCommand vk->vkCmdSetScissor(cmd_buffer, 0, 1, &scissor); for (uint32_t eye = 0; eye < 2; eye++) { - _render_pass_begin(vk, self->render_pass, self->extent, background_color, - self->framebuffers[eye].handle, cmd_buffer); + _render_pass_begin(vk, self->render_pass, self->extent, *color, self->framebuffers[eye].handle, + cmd_buffer); _render_eye(self, eye, cmd_buffer, self->pipeline_layout); @@ -605,9 +614,12 @@ comp_layer_renderer_draw(struct comp_layer_renderer *self) VkCommandBuffer cmd_buffer; if (vk_init_cmd_buffer(vk, &cmd_buffer) != VK_SUCCESS) return; - os_mutex_lock(&vk->cmd_pool_mutex); - _render_stereo(self, vk, cmd_buffer); + if (self->num_layers == 0) { + _render_stereo(self, vk, cmd_buffer, &background_color_idle); + } else { + _render_stereo(self, vk, cmd_buffer, &background_color_active); + } os_mutex_unlock(&vk->cmd_pool_mutex); VkResult res = vk_submit_cmd_buffer(vk, cmd_buffer); From 56e3bb428953ff48301ba7a3cf86a1bfdd0b49cd Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Sun, 4 Apr 2021 05:01:36 -0500 Subject: [PATCH 286/883] meson: Add 'ulv2' to driver list --- meson_options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson_options.txt b/meson_options.txt index 58562047e..48661d760 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,7 +3,7 @@ option('drivers', type: 'array', - choices: ['auto', 'dummy', 'hdk', 'hydra', 'ns', 'ohmd', 'psmv', 'psvr', 'rs', 'v4l2', 'vf', 'vive', 'survive', 'daydream', 'arduino', 'remote', 'handtracking', 'qwerty'], + choices: ['auto', 'dummy', 'hdk', 'hydra', 'ns', 'ohmd', 'psmv', 'psvr', 'rs', 'v4l2', 'vf', 'vive', 'survive', 'daydream', 'arduino', 'remote', 'handtracking', 'qwerty', 'ulv2'], value: ['auto'], description: 'Set of drivers to build') From 0ef8f55ef1cb7ed5eeceb760aa766814eb6cb02e Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Sun, 4 Apr 2021 05:15:56 -0500 Subject: [PATCH 287/883] targets/oxr/sdl2_hack: only do Qwerty things if we are building qwerty driver --- src/xrt/targets/openxr/oxr_sdl2_hack.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/xrt/targets/openxr/oxr_sdl2_hack.c b/src/xrt/targets/openxr/oxr_sdl2_hack.c index fb6981084..37423390c 100644 --- a/src/xrt/targets/openxr/oxr_sdl2_hack.c +++ b/src/xrt/targets/openxr/oxr_sdl2_hack.c @@ -8,6 +8,7 @@ #include "xrt/xrt_instance.h" #include "xrt/xrt_config_have.h" +#include "xrt/xrt_config_drivers.h" #include "util/u_var.h" #include "util/u_misc.h" @@ -41,12 +42,16 @@ oxr_sdl2_hack_stop(void **hack) #include "gui/gui_common.h" #include "gui/gui_imgui.h" +#ifdef XRT_BUILD_DRIVER_QWERTY #include "qwerty_interface.h" +#endif #include DEBUG_GET_ONCE_BOOL_OPTION(gui, "OXR_DEBUG_GUI", false) +#ifdef XRT_BUILD_DRIVER_QWERTY DEBUG_GET_ONCE_BOOL_OPTION(qwerty_enable, "QWERTY_ENABLE", false) +#endif /*! @@ -148,8 +153,11 @@ sdl2_loop(struct sdl2_program *p) ImPlotContext *plot_ctx = ImPlot_CreateContext(); ImPlot_SetCurrentContext(plot_ctx); + +#ifdef XRT_BUILD_DRIVER_QWERTY // Setup qwerty driver usage bool qwerty_enabled = debug_get_bool_option_qwerty_enable(); +#endif // Main loop struct gui_imgui gui = {0}; @@ -168,10 +176,12 @@ sdl2_loop(struct sdl2_program *p) while (SDL_PollEvent(&event)) { igImGui_ImplSDL2_ProcessEvent(&event); +#ifdef XRT_BUILD_DRIVER_QWERTY // Caution here, qwerty driver is being accessed by the main thread as well if (qwerty_enabled) { qwerty_process_event(p->base.xdevs, NUM_XDEVS, event); } +#endif if (event.type == SDL_QUIT) { p->base.stopped = true; From 5c15b60cf2d56b61c93bde3ee691238ce728efd6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 7 Apr 2021 00:49:42 +0100 Subject: [PATCH 288/883] st/oxr: Add more trace markers --- src/xrt/state_trackers/oxr/oxr_api_session.c | 6 ++++++ src/xrt/state_trackers/oxr/oxr_api_system.c | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/xrt/state_trackers/oxr/oxr_api_session.c b/src/xrt/state_trackers/oxr/oxr_api_session.c index 0137131a3..c76254c4c 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_session.c +++ b/src/xrt/state_trackers/oxr/oxr_api_session.c @@ -334,6 +334,8 @@ oxr_xrCreateHandTrackerEXT(XrSession session, const XrHandTrackerCreateInfoEXT *createInfo, XrHandTrackerEXT *handTracker) { + OXR_TRACE_MARKER(); + struct oxr_hand_tracker *hand_tracker = NULL; struct oxr_session *sess = NULL; struct oxr_logger log; @@ -366,6 +368,8 @@ oxr_xrCreateHandTrackerEXT(XrSession session, XrResult oxr_xrDestroyHandTrackerEXT(XrHandTrackerEXT handTracker) { + OXR_TRACE_MARKER(); + struct oxr_hand_tracker *hand_tracker; struct oxr_logger log; OXR_VERIFY_HAND_TRACKER_AND_INIT_LOG(&log, handTracker, hand_tracker, "xrDestroyHandTrackerEXT"); @@ -378,6 +382,8 @@ oxr_xrLocateHandJointsEXT(XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT *locateInfo, XrHandJointLocationsEXT *locations) { + OXR_TRACE_MARKER(); + struct oxr_hand_tracker *hand_tracker; struct oxr_space *spc; struct oxr_logger log; diff --git a/src/xrt/state_trackers/oxr/oxr_api_system.c b/src/xrt/state_trackers/oxr/oxr_api_system.c index 92eedb933..96a7a800a 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_system.c +++ b/src/xrt/state_trackers/oxr/oxr_api_system.c @@ -301,6 +301,8 @@ oxr_xrGetVulkanGraphicsDevice2KHR(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR *getInfo, VkPhysicalDevice *vkPhysicalDevice) { + OXR_TRACE_MARKER(); + struct oxr_instance *inst; struct oxr_logger log; OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrGetVulkanGraphicsDeviceKHR"); @@ -334,6 +336,8 @@ oxr_xrGetVulkanGraphicsRequirements2KHR(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkan2KHR *graphicsRequirements) { + OXR_TRACE_MARKER(); + struct oxr_instance *inst; struct oxr_logger log; OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrGetVulkanGraphicsRequirementsKHR"); @@ -351,6 +355,8 @@ oxr_xrCreateVulkanInstanceKHR(XrInstance instance, VkInstance *vulkanInstance, VkResult *vulkanResult) { + OXR_TRACE_MARKER(); + struct oxr_instance *inst; struct oxr_logger log; OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrCreateVulkanInstanceKHR"); @@ -380,6 +386,8 @@ oxr_xrCreateVulkanDeviceKHR(XrInstance instance, VkDevice *vulkanDevice, VkResult *vulkanResult) { + OXR_TRACE_MARKER(); + struct oxr_instance *inst; struct oxr_logger log; From c876087ee732b8bf301195078693ee107a480638 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 5 Apr 2021 22:51:26 +0100 Subject: [PATCH 289/883] u/time: Add helper comparising functions --- src/xrt/auxiliary/util/u_time.h | 85 +++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/xrt/auxiliary/util/u_time.h b/src/xrt/auxiliary/util/u_time.h index 63e8ab185..e5abb5ac9 100644 --- a/src/xrt/auxiliary/util/u_time.h +++ b/src/xrt/auxiliary/util/u_time.h @@ -93,6 +93,91 @@ time_s_to_ns(double duration) return (time_duration_ns)(duration * (double)U_TIME_1S_IN_NS); } +/*! + * Convert nanoseconds to double float milliseconds, useful for printing. + * + * @see timepoint_ns + * @ingroup aux_util + */ +static inline double +time_ns_to_ms_f(time_duration_ns ns) +{ + return (double)(ns) / (double)U_TIME_1MS_IN_NS; +} + +/*! + * Checks if two timepoints are with a certain range of each other. + * + * @see timepoint_ns + * @ingroup aux_util + */ +static inline bool +time_is_within_range_of_each_other(timepoint_ns a, timepoint_ns b, uint64_t range) +{ + int64_t t = (int64_t)a - (int64_t)b; + return (-(int64_t)range < t) && (t < (int64_t)range); +} + +/*! + * Checks if two timepoints are with half a millisecond of each other. + * + * @see timepoint_ns + * @ingroup aux_util + */ +static inline bool +time_is_within_half_ms(timepoint_ns a, timepoint_ns b) +{ + return time_is_within_range_of_each_other(a, b, U_TIME_HALF_MS_IN_NS); +} + +/*! + * Fuzzy comparisons. + * + * @see timepoint_ns + * @ingroup aux_util + */ +static inline bool +time_is_less_then_or_within_range(timepoint_ns a, timepoint_ns b, uint64_t range) +{ + return a < b || time_is_within_range_of_each_other(a, b, range); +} + +/*! + * Fuzzy comparisons. + * + * @see timepoint_ns + * @ingroup aux_util + */ +static inline bool +time_is_less_then_or_within_half_ms(timepoint_ns a, timepoint_ns b) +{ + return time_is_less_then_or_within_range(a, b, U_TIME_HALF_MS_IN_NS); +} + +/*! + * Fuzzy comparisons. + * + * @see timepoint_ns + * @ingroup aux_util + */ +static inline bool +time_is_greater_then_or_within_range(timepoint_ns a, timepoint_ns b, uint64_t range) +{ + return a > b || time_is_within_range_of_each_other(a, b, range); +} + +/*! + * Fuzzy comparisons. + * + * @see timepoint_ns + * @ingroup aux_util + */ +static inline bool +time_is_greater_then_or_within_half_ms(timepoint_ns a, timepoint_ns b) +{ + return time_is_greater_then_or_within_range(a, b, U_TIME_HALF_MS_IN_NS); +} + /*! * @struct time_state util/u_time.h * @brief Time-keeping state structure. From 61c10440898040cbe3eb5eb9d7723f45ab0392a2 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 6 Apr 2021 17:17:29 -0500 Subject: [PATCH 290/883] u/handles: Add graphics sync handle helpers. --- src/xrt/auxiliary/util/u_handles.c | 76 +++++++++++++++++++++++++++++- src/xrt/auxiliary/util/u_handles.h | 35 ++++++++++++-- 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/src/xrt/auxiliary/util/u_handles.c b/src/xrt/auxiliary/util/u_handles.c index c6ddcce5c..7c9d56e80 100644 --- a/src/xrt/auxiliary/util/u_handles.c +++ b/src/xrt/auxiliary/util/u_handles.c @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -11,6 +11,12 @@ #include "u_handles.h" +/* + * + * Graphics Buffer Handles + * + */ + #if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER) #include @@ -89,3 +95,71 @@ u_graphics_buffer_unref(xrt_graphics_buffer_handle_t *handle_ptr) release_graphics_handle(handle); *handle_ptr = XRT_GRAPHICS_BUFFER_HANDLE_INVALID; } + +/* + * + * Graphics Sync Handles + * + */ + +#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) +#include + +static inline void +release_sync_handle(xrt_graphics_sync_handle_t handle) +{ + close(handle); +} + +static inline xrt_graphics_sync_handle_t +ref_sync_handle(xrt_graphics_sync_handle_t handle) +{ + return dup(handle); +} + +#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE) + +static inline void +release_sync_handle(xrt_graphics_sync_handle_t handle) +{ + CloseHandle(handle); +} + +static inline xrt_graphics_sync_handle_t +ref_sync_handle(xrt_graphics_sync_handle_t handle) +{ + HANDLE self = GetCurrentProcess(); + HANDLE result = NULL; + if (DuplicateHandle(self, handle, self, &result, 0, FALSE, DUPLICATE_SAME_ACCESS) != 0) { + return result; + } + return NULL; +} + +#else +#error "need port" +#endif + +xrt_graphics_sync_handle_t +u_graphics_sync_ref(xrt_graphics_sync_handle_t handle) +{ + if (xrt_graphics_sync_handle_is_valid(handle)) { + return ref_sync_handle(handle); + } + + return XRT_GRAPHICS_SYNC_HANDLE_INVALID; +} + +void +u_graphics_sync_unref(xrt_graphics_sync_handle_t *handle_ptr) +{ + if (handle_ptr == NULL) { + return; + } + xrt_graphics_sync_handle_t handle = *handle_ptr; + if (!xrt_graphics_sync_handle_is_valid(handle)) { + return; + } + release_sync_handle(handle); + *handle_ptr = XRT_GRAPHICS_SYNC_HANDLE_INVALID; +} diff --git a/src/xrt/auxiliary/util/u_handles.h b/src/xrt/auxiliary/util/u_handles.h index 34e7d9dad..a64d25cbf 100644 --- a/src/xrt/auxiliary/util/u_handles.h +++ b/src/xrt/auxiliary/util/u_handles.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-20211, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -17,13 +17,15 @@ #ifdef __cplusplus extern "C" { #endif + /*! * Increase the reference count on the buffer handle, returning the new * reference. * - * Depending on the underlying type, the value may be the same or different than - * what was passed in. It should be retained for use at release time, - * regardless. + * + * Depending on the underlying type, the value may be the same or different than what was passed in. It should be + * retained for use at release time, regardless. (For example, if the underlying native handle does not expose reference + * counting, it may be duplicated and the duplicate returned.) * * @public @memberof xrt_graphics_buffer_handle_t */ @@ -42,6 +44,31 @@ u_graphics_buffer_ref(xrt_graphics_buffer_handle_t handle); void u_graphics_buffer_unref(xrt_graphics_buffer_handle_t *handle); +/*! + * Increase the reference count on the sync handle, returning the new + * reference. + * + * Depending on the underlying type, the value may be the same or different than what was passed in. It should be + * retained for use at release time, regardless. (For example, if the underlying native handle does not expose reference + * counting, it may be duplicated and the duplicate returned.) + * + * @public @memberof xrt_graphics_sync_handle_t + */ +xrt_graphics_sync_handle_t +u_graphics_sync_ref(xrt_graphics_sync_handle_t handle); + +/*! + * Decrease the reference count/release the handle reference passed in. + * + * Be sure to only call this once per handle. + * + * Performs null-check and clears the value after unreferencing. + * + * @public @memberof xrt_graphics_sync_handle_t + */ +void +u_graphics_sync_unref(xrt_graphics_sync_handle_t *handle); + #ifdef __cplusplus } // extern "C" #endif From 07fb9941b38bf4ffe0bf0cc81689cc3ddba21b5a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 9 Mar 2021 14:00:42 +0000 Subject: [PATCH 291/883] aux/vk: Add fence import function --- src/xrt/auxiliary/vk/vk_helpers.c | 46 +++++++++++++++++++++++++++++++ src/xrt/auxiliary/vk/vk_helpers.h | 9 ++++++ 2 files changed, 55 insertions(+) diff --git a/src/xrt/auxiliary/vk/vk_helpers.c b/src/xrt/auxiliary/vk/vk_helpers.c index a142637e0..5065f46bb 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.c +++ b/src/xrt/auxiliary/vk/vk_helpers.c @@ -404,6 +404,49 @@ vk_create_image_from_native(struct vk_bundle *vk, return ret; } +VkResult +vk_create_fence_sync_from_native(struct vk_bundle *vk, xrt_graphics_sync_handle_t native, VkFence *out_fence) +{ + VkFence fence = VK_NULL_HANDLE; + VkResult ret; + + VkFenceCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = VK_FENCE_CREATE_SIGNALED_BIT, + }; + + ret = vk->vkCreateFence(vk->device, &create_info, NULL, &fence); + if (ret != VK_SUCCESS) { + VK_ERROR(vk, "vkCreateFence: %s", vk_result_string(ret)); + return ret; + } + +#ifdef XRT_GRAPHICS_SYNC_HANDLE_IS_FD + // This is what is used on Linux Mesa when importing fences from OpenGL. + VkExternalFenceHandleTypeFlagBits handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; + + VkImportFenceFdInfoKHR import_info = { + .sType = VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR, + .fence = fence, + .handleType = handleType, + .fd = native, + }; + + ret = vk->vkImportFenceFdKHR(vk->device, &import_info); + if (ret != VK_SUCCESS) { + vk->vkDestroyFence(vk->device, fence, NULL); + VK_ERROR(vk, "vkImportFenceFdKHR: %s", vk_result_string(ret)); + return ret; + } +#else +#error "Need port to import fence sync handles" +#endif + + *out_fence = fence; + + return VK_SUCCESS; +} + VkResult vk_create_semaphore_from_native(struct vk_bundle *vk, xrt_graphics_sync_handle_t native, VkSemaphore *out_sem) { @@ -857,6 +900,9 @@ vk_get_device_functions(struct vk_bundle *vk) #else vk->vkImportSemaphoreFdKHR = GET_DEV_PROC(vk, vkImportSemaphoreFdKHR); vk->vkGetSemaphoreFdKHR = GET_DEV_PROC(vk, vkGetSemaphoreFdKHR); + + vk->vkImportFenceFdKHR = GET_DEV_PROC(vk, vkImportFenceFdKHR); + vk->vkGetFenceFdKHR = GET_DEV_PROC(vk, vkGetFenceFdKHR); #endif vk->vkGetPastPresentationTimingGOOGLE = GET_DEV_PROC(vk, vkGetPastPresentationTimingGOOGLE); diff --git a/src/xrt/auxiliary/vk/vk_helpers.h b/src/xrt/auxiliary/vk/vk_helpers.h index 58c5e0d02..43941f57a 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.h +++ b/src/xrt/auxiliary/vk/vk_helpers.h @@ -216,6 +216,9 @@ struct vk_bundle #else PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; + + PFN_vkImportFenceFdKHR vkImportFenceFdKHR; + PFN_vkGetFenceFdKHR vkGetFenceFdKHR; #endif PFN_vkGetPastPresentationTimingGOOGLE vkGetPastPresentationTimingGOOGLE; @@ -436,6 +439,12 @@ vk_create_image_from_native(struct vk_bundle *vk, VkImage *out_image, VkDeviceMemory *out_mem); +/*! + * @ingroup aux_vk + */ +VkResult +vk_create_fence_sync_from_native(struct vk_bundle *vk, xrt_graphics_sync_handle_t native, VkFence *out_fence); + /*! * @ingroup aux_vk */ From 2ab99b821bcbc35eb5c6fe546c611b6c09411598 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 9 Mar 2021 14:01:13 +0000 Subject: [PATCH 292/883] xrt: Add compositor fence interface --- src/xrt/include/xrt/xrt_compositor.h | 92 ++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h index 72f654147..dd7487d8e 100644 --- a/src/xrt/include/xrt/xrt_compositor.h +++ b/src/xrt/include/xrt/xrt_compositor.h @@ -476,6 +476,69 @@ xrt_swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index) return xsc->release_image(xsc, index); } + +/* + * + * Fence. + * + */ + +/*! + * Compositor fence used for syncornization. + */ +struct xrt_compositor_fence +{ + /*! + * Destroys the fence. + */ + xrt_result_t (*wait)(struct xrt_compositor_fence *xcf, uint64_t timeout); + + /*! + * Destroys the fence. + */ + void (*destroy)(struct xrt_compositor_fence *xcf); +}; + +/*! + * @copydoc xrt_compositor_fence::wait + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_compositor_fence + */ +static inline xrt_result_t +xrt_compositor_fence_wait(struct xrt_compositor_fence *xcf, uint64_t timeout) +{ + return xcf->wait(xcf, timeout); +} + +/*! + * @copydoc xrt_compositor_fence::destroy + * + * Helper for calling through the function pointer: does a null check and sets + * xcf_ptr to null if freed. + * + * @public @memberof xrt_compositor_fence + */ +static inline void +xrt_compositor_fence_destroy(struct xrt_compositor_fence **xcf_ptr) +{ + struct xrt_compositor_fence *xcf = *xcf_ptr; + if (xcf == NULL) { + return; + } + + xcf->destroy(xcf); + *xcf_ptr = NULL; +} + + +/* + * + * Events. + * + */ + /*! * Event type for compositor events, none means no event was returned. */ @@ -514,6 +577,13 @@ union xrt_compositor_event { struct xrt_compositor_event_state_change overlay; }; + +/* + * + * Compositor. + * + */ + /*! * Swapchain creation info. */ @@ -593,6 +663,13 @@ struct xrt_compositor uint32_t num_images, struct xrt_swapchain **out_xsc); + /*! + * Create a compositor fence from a native sync handle. + */ + xrt_result_t (*import_fence)(struct xrt_compositor *xc, + xrt_graphics_sync_handle_t handle, + struct xrt_compositor_fence **out_xcf); + /*! * Poll events from this compositor. * @@ -799,6 +876,21 @@ xrt_comp_import_swapchain(struct xrt_compositor *xc, return xc->import_swapchain(xc, info, native_images, num_images, out_xsc); } +/*! + * @copydoc xrt_compositor::import_fence + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_compositor + */ +static inline xrt_result_t +xrt_comp_import_fence(struct xrt_compositor *xc, + xrt_graphics_sync_handle_t handle, + struct xrt_compositor_fence **out_xcf) +{ + return xc->import_fence(xc, handle, out_xcf); +} + /*! * @copydoc xrt_compositor::poll_events * From 1f3896d72902a13cb71f156a6a9fa3563e0fee35 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 11 Mar 2021 22:40:23 +0000 Subject: [PATCH 293/883] xrt: Add new error code --- src/xrt/include/xrt/xrt_results.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xrt/include/xrt/xrt_results.h b/src/xrt/include/xrt/xrt_results.h index 207cb7b74..d50f37912 100644 --- a/src/xrt/include/xrt/xrt_results.h +++ b/src/xrt/include/xrt/xrt_results.h @@ -57,4 +57,8 @@ typedef enum xrt_result * is not supported by the display. */ XRT_ERROR_EGL_CONFIG_MISSING = -12, + /*! + * Failed to initialize threading components. + */ + XRT_ERROR_THREADING_INIT_FAILURE = -14, } xrt_result_t; From 353c7735bfe39de5b9104d69f1ec09eabce95b80 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 15 Mar 2021 14:44:51 +0000 Subject: [PATCH 294/883] xrt: Add alternative functions to wait_frame --- src/xrt/include/xrt/xrt_compositor.h | 77 ++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h index dd7487d8e..6646a40d1 100644 --- a/src/xrt/include/xrt/xrt_compositor.h +++ b/src/xrt/include/xrt/xrt_compositor.h @@ -584,6 +584,11 @@ union xrt_compositor_event { * */ +enum xrt_compositor_frame_point +{ + XRT_COMPOSITOR_FRAME_POINT_WOKE, //!< The client woke up after waiting. +}; + /*! * Swapchain creation info. */ @@ -689,6 +694,38 @@ struct xrt_compositor */ xrt_result_t (*end_session)(struct xrt_compositor *xc); + /*! + * This function and @ref mark_woke function calls are a alternative to + * @ref wait_frame. + * + * The only requirement on the compositor for the @p frame_id + * is that it is a positive number. + * + * @param[out] xc The compositor + * @param[out] out_frame_id Frame id + * @param[out] out_predicted_gpu_time_ns When we expect the client to finish the GPU work. + * @param[out] out_predicted_display_time_ns When the pixels turns into photons. + * @param[out] out_predicted_display_period_ns The period for the frames. + */ + xrt_result_t (*predict_frame)(struct xrt_compositor *xc, + int64_t *out_frame_id, + uint64_t *out_wake_time_ns, + uint64_t *out_predicted_gpu_time_ns, + uint64_t *out_predicted_display_time_ns, + uint64_t *out_predicted_display_period_ns); + + /*! + * This function and @ref mark_woke function calls are a alternative to + * @ref wait_frame. + * + * The client calls this function to mark that it woke up from waiting + * on a frame. + */ + xrt_result_t (*mark_frame)(struct xrt_compositor *xc, + int64_t frame_id, + enum xrt_compositor_frame_point point, + uint64_t when_ns); + /*! * See xrWaitFrame. * @@ -930,6 +967,46 @@ xrt_comp_end_session(struct xrt_compositor *xc) return xc->end_session(xc); } +/*! + * @copydoc xrt_compositor::predict_frame + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_compositor + */ +static inline xrt_result_t +xrt_comp_predict_frame(struct xrt_compositor *xc, + int64_t *out_frame_id, + uint64_t *out_wake_time_ns, + uint64_t *out_predicted_gpu_time_ns, + uint64_t *out_predicted_display_time_ns, + uint64_t *out_predicted_display_period_ns) +{ + return xc->predict_frame( // + xc, // + out_frame_id, // + out_wake_time_ns, // + out_predicted_gpu_time_ns, // + out_predicted_display_time_ns, // + out_predicted_display_period_ns); // +} + +/*! + * @copydoc xrt_compositor::mark_frame + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_compositor + */ +static inline xrt_result_t +xrt_comp_mark_frame(struct xrt_compositor *xc, + int64_t frame_id, + enum xrt_compositor_frame_point point, + uint64_t when_ns) +{ + return xc->mark_frame(xc, frame_id, point, when_ns); +} + /*! * @copydoc xrt_compositor::wait_frame * From f3abddf22498570a02286992dc7e76a9c22e90b1 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 18 Mar 2021 23:17:34 +0000 Subject: [PATCH 295/883] xrt: Add multi session managment interface --- src/xrt/include/xrt/xrt_compositor.h | 90 ++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h index 6646a40d1..b4533da40 100644 --- a/src/xrt/include/xrt/xrt_compositor.h +++ b/src/xrt/include/xrt/xrt_compositor.h @@ -1503,6 +1503,39 @@ struct xrt_system_compositor_info uint8_t client_vk_deviceUUID[XRT_GPU_UUID_SIZE]; }; +struct xrt_system_compositor; + +/*! + * Special functions to control multi session/clients. + */ +struct xrt_multi_compositor_control +{ + /*! + * Sets the state of the compositor, generating any events to the client + * if the state is actually changed. Input focus is enforced/handled by + * a different component but is still signaled by the compositor. + */ + xrt_result_t (*set_state)(struct xrt_system_compositor *xsc, + struct xrt_compositor *xc, + bool visible, + bool focused); + + /*! + * Set the rendering Z order for rendering, visible has higher priority + * then z_order but is still saved until visible again. This a signed + * 64 bit integer compared to a unsigned 32 bit integer in OpenXR, so + * that non-overlay clients can be handled like overlay ones. + */ + xrt_result_t (*set_z_order)(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, int64_t z_order); + + /*! + * Tell this client/session if the main application is visible or not. + */ + xrt_result_t (*set_main_app_visibility)(struct xrt_system_compositor *xsc, + struct xrt_compositor *xc, + bool visible); +}; + /*! * The system compositor is a long lived object, it has the same life time as a * XrSystemID. @@ -1512,6 +1545,11 @@ struct xrt_system_compositor //! Info regarding the system. struct xrt_system_compositor_info info; + /*! + * Does this system compositor support multi client controls. + */ + struct xrt_multi_compositor_control *xmcc; + /*! * Create a new native compositor. * @@ -1534,6 +1572,58 @@ struct xrt_system_compositor void (*destroy)(struct xrt_system_compositor *xsc); }; +/*! + * @copydoc xrt_multi_compositor_control::set_state + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_system_compositor + */ +static inline xrt_result_t +xrt_syscomp_set_state(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused) +{ + if (xsc->xmcc == NULL) { + return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED; + } + + return xsc->xmcc->set_state(xsc, xc, visible, focused); +} + +/*! + * @copydoc xrt_multi_compositor_control::set_z_order + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_system_compositor + */ +static inline xrt_result_t +xrt_syscomp_set_z_order(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, int64_t z_order) +{ + if (xsc->xmcc == NULL) { + return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED; + } + + return xsc->xmcc->set_z_order(xsc, xc, z_order); +} + + +/*! + * @copydoc xrt_multi_compositor_control::set_main_app_visibility + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_system_compositor + */ +static inline xrt_result_t +xrt_syscomp_set_main_app_visibility(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible) +{ + if (xsc->xmcc == NULL) { + return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED; + } + + return xsc->xmcc->set_main_app_visibility(xsc, xc, visible); +} + /*! * @copydoc xrt_system_compositor::create_native_compositor * From efdba1602f6db3c389cc1708148b4173418b07ca Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 5 Apr 2021 17:52:44 +0100 Subject: [PATCH 296/883] xrt: Pass along display_time_ns to layer begin --- src/xrt/compositor/client/comp_gl_client.c | 7 +++++-- src/xrt/compositor/client/comp_vk_client.c | 7 +++++-- src/xrt/compositor/main/comp_compositor.c | 5 ++++- src/xrt/include/xrt/xrt_compositor.h | 12 +++++++++--- src/xrt/ipc/client/ipc_client_compositor.c | 8 +++++++- src/xrt/ipc/server/ipc_server_process.c | 2 +- src/xrt/state_trackers/oxr/oxr_session.c | 7 ++++--- 7 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/xrt/compositor/client/comp_gl_client.c b/src/xrt/compositor/client/comp_gl_client.c index 0ef3f8785..33bce4620 100644 --- a/src/xrt/compositor/client/comp_gl_client.c +++ b/src/xrt/compositor/client/comp_gl_client.c @@ -130,11 +130,14 @@ client_gl_compositor_discard_frame(struct xrt_compositor *xc, int64_t frame_id) } static xrt_result_t -client_gl_compositor_layer_begin(struct xrt_compositor *xc, int64_t frame_id, enum xrt_blend_mode env_blend_mode) +client_gl_compositor_layer_begin(struct xrt_compositor *xc, + int64_t frame_id, + uint64_t display_time_ns, + enum xrt_blend_mode env_blend_mode) { struct client_gl_compositor *c = client_gl_compositor(xc); - return xrt_comp_layer_begin(&c->xcn->base, frame_id, env_blend_mode); + return xrt_comp_layer_begin(&c->xcn->base, frame_id, display_time_ns, env_blend_mode); } static xrt_result_t diff --git a/src/xrt/compositor/client/comp_vk_client.c b/src/xrt/compositor/client/comp_vk_client.c index a756abe4e..bcfdc85f3 100644 --- a/src/xrt/compositor/client/comp_vk_client.c +++ b/src/xrt/compositor/client/comp_vk_client.c @@ -212,11 +212,14 @@ client_vk_compositor_discard_frame(struct xrt_compositor *xc, int64_t frame_id) } static xrt_result_t -client_vk_compositor_layer_begin(struct xrt_compositor *xc, int64_t frame_id, enum xrt_blend_mode env_blend_mode) +client_vk_compositor_layer_begin(struct xrt_compositor *xc, + int64_t frame_id, + uint64_t display_time_ns, + enum xrt_blend_mode env_blend_mode) { struct client_vk_compositor *c = client_vk_compositor(xc); - return xrt_comp_layer_begin(&c->xcn->base, frame_id, env_blend_mode); + return xrt_comp_layer_begin(&c->xcn->base, frame_id, display_time_ns, env_blend_mode); } static xrt_result_t diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index b27bf37cb..7350b3c04 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -215,7 +215,10 @@ compositor_add_frame_timing(struct comp_compositor *c) } static xrt_result_t -compositor_layer_begin(struct xrt_compositor *xc, int64_t frame_id, enum xrt_blend_mode env_blend_mode) +compositor_layer_begin(struct xrt_compositor *xc, + int64_t frame_id, + uint64_t display_time_ns, + enum xrt_blend_mode env_blend_mode) { struct comp_compositor *c = comp_compositor(xc); diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h index b4533da40..44f6d4719 100644 --- a/src/xrt/include/xrt/xrt_compositor.h +++ b/src/xrt/include/xrt/xrt_compositor.h @@ -761,7 +761,10 @@ struct xrt_compositor * @p layer_commit that layers will be displayed. From the point of view * of the swapchain the image is used as soon as it's given in a call. */ - xrt_result_t (*layer_begin)(struct xrt_compositor *xc, int64_t frame_id, enum xrt_blend_mode env_blend_mode); + xrt_result_t (*layer_begin)(struct xrt_compositor *xc, + int64_t frame_id, + uint64_t display_time_ns, + enum xrt_blend_mode env_blend_mode); /*! * Adds a stereo projection layer for submissions. @@ -1057,9 +1060,12 @@ xrt_comp_discard_frame(struct xrt_compositor *xc, int64_t frame_id) * @public @memberof xrt_compositor */ static inline xrt_result_t -xrt_comp_layer_begin(struct xrt_compositor *xc, int64_t frame_id, enum xrt_blend_mode env_blend_mode) +xrt_comp_layer_begin(struct xrt_compositor *xc, + int64_t frame_id, + uint64_t display_time_ns, + enum xrt_blend_mode env_blend_mode) { - return xc->layer_begin(xc, frame_id, env_blend_mode); + return xc->layer_begin(xc, frame_id, display_time_ns, env_blend_mode); } /*! diff --git a/src/xrt/ipc/client/ipc_client_compositor.c b/src/xrt/ipc/client/ipc_client_compositor.c index 29daeb4bf..c8edabc9c 100644 --- a/src/xrt/ipc/client/ipc_client_compositor.c +++ b/src/xrt/ipc/client/ipc_client_compositor.c @@ -61,6 +61,8 @@ struct ipc_client_compositor struct { + uint64_t display_time_ns; + //! Id that we are currently using for submitting layers. uint32_t slot_id; @@ -456,10 +458,14 @@ ipc_compositor_begin_frame(struct xrt_compositor *xc, int64_t frame_id) } static xrt_result_t -ipc_compositor_layer_begin(struct xrt_compositor *xc, int64_t frame_id, enum xrt_blend_mode env_blend_mode) +ipc_compositor_layer_begin(struct xrt_compositor *xc, + int64_t frame_id, + uint64_t display_time_ns, + enum xrt_blend_mode env_blend_mode) { struct ipc_client_compositor *icc = ipc_client_compositor(xc); + icc->layers.display_time_ns = display_time_ns; icc->layers.env_blend_mode = env_blend_mode; return XRT_SUCCESS; diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index 9e19fd441..c550ce421 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -875,7 +875,7 @@ main_loop(struct ipc_server *s) broadcast_timings(s, predicted_display_time_ns, predicted_display_period_ns, diff_ns); xrt_comp_begin_frame(xc, frame_id); - xrt_comp_layer_begin(xc, frame_id, 0); + xrt_comp_layer_begin(xc, frame_id, 0, 0); _update_layers(s, xc); diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 857121ec2..06c5ef83a 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -1752,9 +1752,10 @@ oxr_session_frame_end(struct oxr_logger *log, struct oxr_session *sess, const Xr frameEndInfo->displayTime); } - int64_t timestamp = time_state_ts_to_monotonic_ns(sess->sys->inst->timekeeping, frameEndInfo->displayTime); + int64_t display_time_ns = + time_state_ts_to_monotonic_ns(sess->sys->inst->timekeeping, frameEndInfo->displayTime); if (sess->frame_timing_spew) { - oxr_log(log, "End frame at %8.3fms with display time %8.3fms", ts_ms(sess), ns_to_ms(timestamp)); + oxr_log(log, "End frame at %8.3fms with display time %8.3fms", ts_ms(sess), ns_to_ms(display_time_ns)); } struct xrt_compositor *xc = sess->compositor; @@ -1885,7 +1886,7 @@ oxr_session_frame_end(struct oxr_logger *log, struct oxr_session *sess, const Xr struct xrt_pose inv_offset = {0}; math_pose_invert(&xdev->tracking_origin->offset, &inv_offset); - CALL_CHK(xrt_comp_layer_begin(xc, sess->frame_id.begun, blend_mode)); + CALL_CHK(xrt_comp_layer_begin(xc, sess->frame_id.begun, display_time_ns, blend_mode)); for (uint32_t i = 0; i < frameEndInfo->layerCount; i++) { const XrCompositionLayerBaseHeader *layer = frameEndInfo->layers[i]; From 086bef85450c13654892325d8a34644b75b22b94 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 11 Mar 2021 22:40:40 +0000 Subject: [PATCH 297/883] c/multi: Add new multi-client helper --- src/xrt/compositor/CMakeLists.txt | 26 +- src/xrt/compositor/meson.build | 6 +- .../compositor/multi/comp_multi_compositor.c | 563 ++++++++++++++++++ .../compositor/multi/comp_multi_interface.h | 28 + src/xrt/compositor/multi/comp_multi_private.h | 204 +++++++ src/xrt/compositor/multi/comp_multi_system.c | 463 ++++++++++++++ 6 files changed, 1288 insertions(+), 2 deletions(-) create mode 100644 src/xrt/compositor/multi/comp_multi_compositor.c create mode 100644 src/xrt/compositor/multi/comp_multi_interface.h create mode 100644 src/xrt/compositor/multi/comp_multi_private.h create mode 100644 src/xrt/compositor/multi/comp_multi_system.c diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index ae5b9ae40..7dce4d1ad 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2019-2020, Collabora, Ltd. +# Copyright 2019-2021, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 spirv_shaders(SHADER_HEADERS @@ -38,6 +38,14 @@ set(MAIN_SOURCE_FILES render/comp_resources.c ) +set(MULTI_SOURCE_FILES + multi/comp_multi_compositor.c + multi/comp_multi_interface.h + multi/comp_multi_private.h + multi/comp_multi_system.c + ) + + ### # Client library # @@ -96,6 +104,8 @@ endif() if(XRT_HAVE_OPENGL AND XRT_HAVE_XLIB) target_link_libraries(comp_client PRIVATE OpenGL::GLX) endif() + + ## # Main library # @@ -192,3 +202,17 @@ if(XRT_FEATURE_COMPOSITOR_MAIN) add_subdirectory(shaders) endif() + + +### +# Multi client compositor library +# + +add_library(comp_multi STATIC ${MULTI_SOURCE_FILES}) +target_link_libraries(comp_multi PUBLIC xrt-interfaces PRIVATE aux_util aux_os) +target_include_directories(comp_multi PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + + +if(XRT_FEATURE_COMPOSITOR_MAIN) + target_link_libraries(comp_main PRIVATE comp_multi) +endif() diff --git a/src/xrt/compositor/meson.build b/src/xrt/compositor/meson.build index 0651299a1..08e7f9471 100644 --- a/src/xrt/compositor/meson.build +++ b/src/xrt/compositor/meson.build @@ -1,4 +1,4 @@ -# Copyright 2019-2020, Collabora, Ltd. +# Copyright 2019-2021, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 subdir('shaders') @@ -28,6 +28,10 @@ compositor_srcs = [ 'main/comp_window.h', 'main/comp_layer_renderer.c', 'main/comp_layer.c', + 'multi/comp_multi_compositor.c', + 'multi/comp_multi_interface.h', + 'multi/comp_multi_private.h', + 'multi/comp_multi_system.c', 'render/comp_buffer.c', 'render/comp_render.h', 'render/comp_rendering.c', diff --git a/src/xrt/compositor/multi/comp_multi_compositor.c b/src/xrt/compositor/multi/comp_multi_compositor.c new file mode 100644 index 000000000..3a6e0d80f --- /dev/null +++ b/src/xrt/compositor/multi/comp_multi_compositor.c @@ -0,0 +1,563 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Multi client wrapper compositor. + * @author Pete Black + * @author Jakob Bornecrantz + * @ingroup comp_multi + */ + +#include "xrt/xrt_gfx_native.h" + +#include "os/os_time.h" + +#include "util/u_var.h" +#include "util/u_misc.h" +#include "util/u_time.h" +#include "util/u_debug.h" +#include "util/u_handles.h" +#include "util/u_trace_marker.h" +#include "util/u_distortion_mesh.h" + +#include "multi/comp_multi_private.h" + +#include +#include +#include +#include +#include +#include + +#ifdef XRT_GRAPHICS_SYNC_HANDLE_IS_FD +#include +#endif + + +/* + * + * Slot management functions. + * + */ + +static void +slot_clear(struct multi_layer_slot *slot) +{ + for (size_t i = 0; i < slot->num_layers; i++) { + for (size_t k = 0; k < ARRAY_SIZE(slot->layers[i].xscs); k++) { + xrt_swapchain_reference(&slot->layers[i].xscs[k], NULL); + } + } + + U_ZERO(slot); +} + +static void +slot_move_and_clear(struct multi_layer_slot *dst, struct multi_layer_slot *src) +{ + slot_clear(dst); + + // All references are kept. + *dst = *src; + + U_ZERO(src); +} + + +/* + * + * Event management functions. + * + */ + +void +multi_compositor_push_event(struct multi_compositor *mc, const union xrt_compositor_event *xce) +{ + struct multi_event *me = U_TYPED_CALLOC(struct multi_event); + me->xce = *xce; + + os_mutex_lock(&mc->event.mutex); + + // Find the last slot. + struct multi_event **slot = &mc->event.next; + while (*slot != NULL) { + slot = &(*slot)->next; + } + + *slot = me; + + os_mutex_unlock(&mc->event.mutex); +} + +static void +pop_event(struct multi_compositor *mc, union xrt_compositor_event *out_xce) +{ + out_xce->type = XRT_COMPOSITOR_EVENT_NONE; + + os_mutex_lock(&mc->event.mutex); + + if (mc->event.next != NULL) { + struct multi_event *me = mc->event.next; + + *out_xce = me->xce; + mc->event.next = me->next; + free(me); + } + + os_mutex_unlock(&mc->event.mutex); +} + +static void +drain_events(struct multi_compositor *mc) +{ + union xrt_compositor_event xce; + do { + pop_event(mc, &xce); + } while (xce.type != XRT_COMPOSITOR_EVENT_NONE); +} + + +/* + * + * Compositor functions. + * + */ + +static xrt_result_t +multi_compositor_create_swapchain(struct xrt_compositor *xc, + const struct xrt_swapchain_create_info *info, + struct xrt_swapchain **out_xsc) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + + return xrt_comp_create_swapchain(&mc->msc->xcn->base, info, out_xsc); +} + +static xrt_result_t +multi_compositor_import_swapchain(struct xrt_compositor *xc, + const struct xrt_swapchain_create_info *info, + struct xrt_image_native *native_images, + uint32_t num_images, + struct xrt_swapchain **out_xsc) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + + return xrt_comp_import_swapchain(&mc->msc->xcn->base, info, native_images, num_images, out_xsc); +} + +static xrt_result_t +multi_compositor_import_fence(struct xrt_compositor *xc, + xrt_graphics_sync_handle_t handle, + struct xrt_compositor_fence **out_xcf) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + + return xrt_comp_import_fence(&mc->msc->xcn->base, handle, out_xcf); +} + +static xrt_result_t +multi_compositor_begin_session(struct xrt_compositor *xc, enum xrt_view_type type) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + (void)mc; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_end_session(struct xrt_compositor *xc) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + (void)mc; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_predict_frame(struct xrt_compositor *xc, + int64_t *out_frame_id, + uint64_t *out_wake_time_ns, + uint64_t *out_predicted_gpu_time_ns, + uint64_t *out_predicted_display_time_ns, + uint64_t *out_predicted_display_period_ns) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + + os_mutex_lock(&mc->msc->list_and_timing_lock); + + uint64_t min_display_period = 0; + + u_rt_helper_predict( // + &mc->urth, // + out_frame_id, // + out_predicted_display_time_ns, // + out_wake_time_ns, // + out_predicted_display_period_ns, // + &min_display_period); // + + os_mutex_unlock(&mc->msc->list_and_timing_lock); + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_mark_frame(struct xrt_compositor *xc, + int64_t frame_id, + enum xrt_compositor_frame_point point, + uint64_t when_ns) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + + switch (point) { + case XRT_COMPOSITOR_FRAME_POINT_WOKE: + os_mutex_lock(&mc->msc->list_and_timing_lock); + u_rt_helper_mark_wait_woke(&mc->urth, frame_id); + os_mutex_unlock(&mc->msc->list_and_timing_lock); + break; + default: assert(false); + } + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_wait_frame(struct xrt_compositor *xc, + int64_t *out_frame_id, + uint64_t *predicted_display_time, + uint64_t *predicted_display_period) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + (void)mc; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_begin_frame(struct xrt_compositor *xc, int64_t frame_id) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + + os_mutex_lock(&mc->msc->list_and_timing_lock); + u_rt_helper_mark_begin(&mc->urth, frame_id); + os_mutex_unlock(&mc->msc->list_and_timing_lock); + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_discard_frame(struct xrt_compositor *xc, int64_t frame_id) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + + os_mutex_lock(&mc->msc->list_and_timing_lock); + u_rt_helper_mark_discarded(&mc->urth, frame_id); + os_mutex_unlock(&mc->msc->list_and_timing_lock); + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_layer_begin(struct xrt_compositor *xc, + int64_t frame_id, + uint64_t display_time_ns, + enum xrt_blend_mode env_blend_mode) +{ + struct multi_compositor *mc = multi_compositor(xc); + + assert(mc->progress.num_layers == 0); + U_ZERO(&mc->progress); + + mc->progress.display_time_ns = display_time_ns; + mc->progress.env_blend_mode = env_blend_mode; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_layer_stereo_projection(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *l_xsc, + struct xrt_swapchain *r_xsc, + const struct xrt_layer_data *data) +{ + struct multi_compositor *mc = multi_compositor(xc); + (void)mc; + + size_t index = mc->progress.num_layers++; + mc->progress.layers[index].xdev = xdev; + xrt_swapchain_reference(&mc->progress.layers[index].xscs[0], l_xsc); + xrt_swapchain_reference(&mc->progress.layers[index].xscs[1], r_xsc); + mc->progress.layers[index].data = *data; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_layer_stereo_projection_depth(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *l_xsc, + struct xrt_swapchain *r_xsc, + struct xrt_swapchain *l_d_xsc, + struct xrt_swapchain *r_d_xsc, + const struct xrt_layer_data *data) +{ + struct multi_compositor *mc = multi_compositor(xc); + + size_t index = mc->progress.num_layers++; + mc->progress.layers[index].xdev = xdev; + xrt_swapchain_reference(&mc->progress.layers[index].xscs[0], l_xsc); + xrt_swapchain_reference(&mc->progress.layers[index].xscs[1], r_xsc); + xrt_swapchain_reference(&mc->progress.layers[index].xscs[2], l_d_xsc); + xrt_swapchain_reference(&mc->progress.layers[index].xscs[3], r_d_xsc); + mc->progress.layers[index].data = *data; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_layer_quad(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct multi_compositor *mc = multi_compositor(xc); + + size_t index = mc->progress.num_layers++; + mc->progress.layers[index].xdev = xdev; + xrt_swapchain_reference(&mc->progress.layers[index].xscs[0], xsc); + mc->progress.layers[index].data = *data; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_layer_cube(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct multi_compositor *mc = multi_compositor(xc); + + size_t index = mc->progress.num_layers++; + mc->progress.layers[index].xdev = xdev; + xrt_swapchain_reference(&mc->progress.layers[index].xscs[0], xsc); + mc->progress.layers[index].data = *data; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_layer_cylinder(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct multi_compositor *mc = multi_compositor(xc); + + size_t index = mc->progress.num_layers++; + mc->progress.layers[index].xdev = xdev; + xrt_swapchain_reference(&mc->progress.layers[index].xscs[0], xsc); + mc->progress.layers[index].data = *data; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_layer_equirect1(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct multi_compositor *mc = multi_compositor(xc); + + size_t index = mc->progress.num_layers++; + mc->progress.layers[index].xdev = xdev; + xrt_swapchain_reference(&mc->progress.layers[index].xscs[0], xsc); + mc->progress.layers[index].data = *data; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_layer_equirect2(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct multi_compositor *mc = multi_compositor(xc); + + size_t index = mc->progress.num_layers++; + mc->progress.layers[index].xdev = xdev; + xrt_swapchain_reference(&mc->progress.layers[index].xscs[0], xsc); + mc->progress.layers[index].data = *data; + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_graphics_sync_handle_t sync_handle) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + struct xrt_compositor_fence *xcf = NULL; + + do { + if (!xrt_graphics_sync_handle_is_valid(sync_handle)) { + break; + } + + xrt_result_t xret = xrt_comp_import_fence( // + &mc->msc->xcn->base, // + sync_handle, // + &xcf); // + /*! + * If import_fence succeeded, we have transferred ownership to + * the compositor no need to do anything more. If the call + * failed we need to close the handle. + */ + if (xret == XRT_SUCCESS) { + break; + } + + u_graphics_sync_unref(&sync_handle); + } while (false); // Goto without the labels. + + if (xcf != NULL) { + xrt_compositor_fence_wait(xcf, UINT64_MAX); + xrt_compositor_fence_destroy(&xcf); + } + + os_mutex_lock(&mc->msc->list_and_timing_lock); + + slot_move_and_clear(&mc->delivered, &mc->progress); + + u_rt_helper_mark_delivered(&mc->urth, frame_id); + + os_mutex_unlock(&mc->msc->list_and_timing_lock); + + return XRT_SUCCESS; +} + +static xrt_result_t +multi_compositor_poll_events(struct xrt_compositor *xc, union xrt_compositor_event *out_xce) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + + pop_event(mc, out_xce); + + return XRT_SUCCESS; +} + +static void +multi_compositor_destroy(struct xrt_compositor *xc) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = multi_compositor(xc); + + os_mutex_lock(&mc->msc->list_and_timing_lock); + + // Remove it from the list of clients. + for (size_t i = 0; i < MULTI_MAX_CLIENTS; i++) { + if (mc->msc->clients[i] == mc) { + mc->msc->clients[i] = NULL; + } + } + + os_mutex_unlock(&mc->msc->list_and_timing_lock); + + drain_events(mc); + + // We are now off the rendering list, clear slots for any swapchains. + slot_clear(&mc->progress); + slot_clear(&mc->delivered); + + free(mc); +} + +xrt_result_t +multi_compositor_create(struct multi_system_compositor *msc, + const struct xrt_session_info *xsi, + struct xrt_compositor_native **out_xcn) +{ + COMP_TRACE_MARKER(); + + struct multi_compositor *mc = U_TYPED_CALLOC(struct multi_compositor); + + mc->base.base.create_swapchain = multi_compositor_create_swapchain; + mc->base.base.import_swapchain = multi_compositor_import_swapchain; + mc->base.base.import_fence = multi_compositor_import_fence; + mc->base.base.begin_session = multi_compositor_begin_session; + mc->base.base.end_session = multi_compositor_end_session; + mc->base.base.predict_frame = multi_compositor_predict_frame; + mc->base.base.mark_frame = multi_compositor_mark_frame; + mc->base.base.wait_frame = multi_compositor_wait_frame; + mc->base.base.begin_frame = multi_compositor_begin_frame; + mc->base.base.discard_frame = multi_compositor_discard_frame; + mc->base.base.layer_begin = multi_compositor_layer_begin; + mc->base.base.layer_stereo_projection = multi_compositor_layer_stereo_projection; + mc->base.base.layer_stereo_projection_depth = multi_compositor_layer_stereo_projection_depth; + mc->base.base.layer_quad = multi_compositor_layer_quad; + mc->base.base.layer_cube = multi_compositor_layer_cube; + mc->base.base.layer_cylinder = multi_compositor_layer_cylinder; + mc->base.base.layer_equirect1 = multi_compositor_layer_equirect1; + mc->base.base.layer_equirect2 = multi_compositor_layer_equirect2; + mc->base.base.layer_commit = multi_compositor_layer_commit; + mc->base.base.destroy = multi_compositor_destroy; + mc->base.base.poll_events = multi_compositor_poll_events; + mc->msc = msc; + mc->xsi = *xsi; + + // Passthrough our formats from the native compositor to the client. + mc->base.base.info = msc->xcn->base.info; + + // This is safe to do without a lock since we are not on the list yet. + u_rt_helper_init(&mc->urth); + u_rt_helper_client_clear(&mc->urth); + + os_mutex_lock(&msc->list_and_timing_lock); + + // Meh if we have to many clients just ignore it. + for (size_t i = 0; i < MULTI_MAX_CLIENTS; i++) { + if (mc->msc->clients[i] != NULL) { + continue; + } + mc->msc->clients[i] = mc; + break; + } + + u_rt_helper_new_sample( // + &mc->urth, // + msc->last_timings.predicted_display_time_ns, // + msc->last_timings.predicted_display_period_ns, // + msc->last_timings.diff_ns); // + + os_mutex_unlock(&msc->list_and_timing_lock); + + *out_xcn = &mc->base; + + return XRT_SUCCESS; +} diff --git a/src/xrt/compositor/multi/comp_multi_interface.h b/src/xrt/compositor/multi/comp_multi_interface.h new file mode 100644 index 000000000..55b24edf3 --- /dev/null +++ b/src/xrt/compositor/multi/comp_multi_interface.h @@ -0,0 +1,28 @@ +// Copyright 2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Interface for the multi-client layer code. + * @author Jakob Bornecrantz + * @ingroup comp_main + */ + +#pragma once + +#include "xrt/xrt_compositor.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +xrt_result_t +comp_multi_create_system_compositor(struct xrt_compositor_native *xcn, + const struct xrt_system_compositor_info *xsci, + struct xrt_system_compositor **out_xsysc); + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/compositor/multi/comp_multi_private.h b/src/xrt/compositor/multi/comp_multi_private.h new file mode 100644 index 000000000..b27261d15 --- /dev/null +++ b/src/xrt/compositor/multi/comp_multi_private.h @@ -0,0 +1,204 @@ +// Copyright 2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Multi-client compositor internal structs. + * @author Jakob Bornecrantz + * @ingroup comp_multi + */ + +#pragma once + +#include "xrt/xrt_compiler.h" +#include "xrt/xrt_defines.h" +#include "xrt/xrt_compositor.h" + +#include "os/os_time.h" +#include "os/os_threading.h" + +#include "util/u_timing_render.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MULTI_MAX_CLIENTS 64 +#define MULTI_MAX_LAYERS 16 + + +/* + * + * Native compositor. + * + */ + +/*! + * Data for a single composition layer. + * + * Similar in function to @ref comp_layer + * + * @ingroup comp_multi + */ +struct multi_layer_entry +{ + /*! + * Device to get pose from. + */ + struct xrt_device *xdev; + + /*! + * Pointers to swapchains. + * + * How many are actually used depends on the value of @p data.type + */ + struct xrt_swapchain *xscs[4]; + + /*! + * All basic (trivially-serializable) data associated with a layer, + * aside from which swapchain(s) are used. + */ + struct xrt_layer_data data; +}; + +/*! + * Render state for a single client, including all layers. + * + * @ingroup comp_multi + */ +struct multi_layer_slot +{ + uint64_t display_time_ns; //!< When should this be shown, @see XrFrameEndInfo::displayTime. + enum xrt_blend_mode env_blend_mode; + uint32_t num_layers; + struct multi_layer_entry layers[MULTI_MAX_LAYERS]; +}; + +/*! + * Render state for a single client, including all layers. + * + * @ingroup comp_multi + */ +struct multi_event +{ + struct multi_event *next; + union xrt_compositor_event xce; +}; + +/*! + * A single compositor. + * + * @ingroup comp_multi + */ +struct multi_compositor +{ + struct xrt_compositor_native base; + + // Client info. + struct xrt_session_info xsi; + + //! Owning system compositor. + struct multi_system_compositor *msc; + + struct + { + struct os_mutex mutex; + struct multi_event *next; + } event; + + struct + { + struct + { + bool visible; + bool focused; + } sent; + struct + { + bool visible; + bool focused; + } current; + + int64_t z_order; + } state; + + //! Currently being transferred or waited on. + struct multi_layer_slot progress; + + //! Fully ready to be used. + struct multi_layer_slot delivered; + + struct u_rt_helper urth; +}; + +static inline struct multi_compositor * +multi_compositor(struct xrt_compositor *xc) +{ + return (struct multi_compositor *)xc; +} + +/*! + * Create a multi client wrapper compositor. + * + * @ingroup comp_multi + */ +xrt_result_t +multi_compositor_create(struct multi_system_compositor *msc, + const struct xrt_session_info *xsi, + struct xrt_compositor_native **out_xcn); + +/*! + * Push a event to be delivered to the client. + * + * @ingroup comp_multi + */ +void +multi_compositor_push_event(struct multi_compositor *mc, const union xrt_compositor_event *xce); + + +/* + * + * System compositor. + * + */ + +struct multi_system_compositor +{ + struct xrt_system_compositor base; + + //! Extra functions to handle multi client. + struct xrt_multi_compositor_control xmcc; + + //! Real native compositor. + struct xrt_compositor_native *xcn; + + //! Render loop thread. + struct os_thread_helper oth; + + /*! + * This mutex protects the list of client compositor + * and the rendering timings on it. + */ + struct os_mutex list_and_timing_lock; + + struct + { + uint64_t predicted_display_time_ns; + uint64_t predicted_display_period_ns; + uint64_t diff_ns; + } last_timings; + + struct multi_compositor *clients[MULTI_MAX_CLIENTS]; +}; + +static inline struct multi_system_compositor * +multi_system_compositor(struct xrt_system_compositor *xsc) +{ + return (struct multi_system_compositor *)xsc; +} + + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/compositor/multi/comp_multi_system.c b/src/xrt/compositor/multi/comp_multi_system.c new file mode 100644 index 000000000..5ec7b4373 --- /dev/null +++ b/src/xrt/compositor/multi/comp_multi_system.c @@ -0,0 +1,463 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Multi client wrapper compositor. + * @author Pete Black + * @author Jakob Bornecrantz + * @ingroup comp_multi + */ + +#include "xrt/xrt_gfx_native.h" + +#include "os/os_time.h" + +#include "util/u_var.h" +#include "util/u_misc.h" +#include "util/u_time.h" +#include "util/u_debug.h" +#include "util/u_trace_marker.h" +#include "util/u_distortion_mesh.h" + +#include "multi/comp_multi_private.h" + +#include +#include +#include +#include +#include +#include + +#ifdef XRT_GRAPHICS_SYNC_HANDLE_IS_FD +#include +#endif + + +/* + * + * Render thread. + * + */ + +static void +do_projection_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) +{ + struct xrt_device *xdev = layer->xdev; + struct xrt_swapchain *l_xcs = layer->xscs[0]; + struct xrt_swapchain *r_xcs = layer->xscs[1]; + + if (l_xcs == NULL || r_xcs == NULL) { + U_LOG_E("Invalid swap chain for projection layer #%u!", i); + return; + } + + if (xdev == NULL) { + U_LOG_E("Invalid xdev for projection layer #%u!", i); + return; + } + + // Cast away + struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; + + xrt_comp_layer_stereo_projection(xc, xdev, l_xcs, r_xcs, data); +} + +static void +do_projection_layer_depth(struct xrt_compositor *xc, + struct multi_compositor *mc, + struct multi_layer_entry *layer, + uint32_t i) +{ + struct xrt_device *xdev = layer->xdev; + struct xrt_swapchain *l_xcs = layer->xscs[0]; + struct xrt_swapchain *r_xcs = layer->xscs[1]; + struct xrt_swapchain *l_d_xcs = layer->xscs[2]; + struct xrt_swapchain *r_d_xcs = layer->xscs[2]; + + if (l_xcs == NULL || r_xcs == NULL || l_d_xcs == NULL || r_d_xcs == NULL) { + U_LOG_E("Invalid swap chain for projection layer #%u!", i); + return; + } + + if (xdev == NULL) { + U_LOG_E("Invalid xdev for projection layer #%u!", i); + return; + } + + // Cast away + struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; + + xrt_comp_layer_stereo_projection_depth(xc, xdev, l_xcs, r_xcs, l_d_xcs, r_d_xcs, data); +} + +static bool +do_single(struct xrt_compositor *xc, + struct multi_compositor *mc, + struct multi_layer_entry *layer, + uint32_t i, + const char *name, + struct xrt_device **out_xdev, + struct xrt_swapchain **out_xcs, + struct xrt_layer_data **out_data) +{ + struct xrt_device *xdev = layer->xdev; + struct xrt_swapchain *xcs = layer->xscs[0]; + + if (xcs == NULL) { + U_LOG_E("Invalid swapchain for layer #%u '%s'!", i, name); + return false; + } + + if (xdev == NULL) { + U_LOG_E("Invalid xdev for layer #%u '%s'!", i, name); + return false; + } + + // Cast away + struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; + + *out_xdev = xdev; + *out_xcs = xcs; + *out_data = data; + + return true; +} + +static void +do_quad_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) +{ + struct xrt_device *xdev = NULL; + struct xrt_swapchain *xcs = NULL; + struct xrt_layer_data *data = NULL; + + if (!do_single(xc, mc, layer, i, "quad", &xdev, &xcs, &data)) { + return; + } + + xrt_comp_layer_quad(xc, xdev, xcs, data); +} + +static void +do_cube_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) +{ + struct xrt_device *xdev = NULL; + struct xrt_swapchain *xcs = NULL; + struct xrt_layer_data *data = NULL; + + if (!do_single(xc, mc, layer, i, "cube", &xdev, &xcs, &data)) { + return; + } + + xrt_comp_layer_cube(xc, xdev, xcs, data); +} + +static void +do_cylinder_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) +{ + struct xrt_device *xdev = NULL; + struct xrt_swapchain *xcs = NULL; + struct xrt_layer_data *data = NULL; + + if (!do_single(xc, mc, layer, i, "cylinder", &xdev, &xcs, &data)) { + return; + } + + xrt_comp_layer_cylinder(xc, xdev, xcs, data); +} + +static void +do_equirect1_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) +{ + struct xrt_device *xdev = NULL; + struct xrt_swapchain *xcs = NULL; + struct xrt_layer_data *data = NULL; + + if (!do_single(xc, mc, layer, i, "equirect1", &xdev, &xcs, &data)) { + return; + } + + xrt_comp_layer_equirect1(xc, xdev, xcs, data); +} + +static void +do_equirect2_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) +{ + struct xrt_device *xdev = NULL; + struct xrt_swapchain *xcs = NULL; + struct xrt_layer_data *data = NULL; + + if (!do_single(xc, mc, layer, i, "equirect2", &xdev, &xcs, &data)) { + return; + } + + xrt_comp_layer_equirect2(xc, xdev, xcs, data); +} + +static int +overlay_sort_func(const void *a, const void *b) +{ + struct multi_compositor *mc_a = *(struct multi_compositor **)a; + struct multi_compositor *mc_b = *(struct multi_compositor **)b; + + if (mc_a->state.z_order < mc_b->state.z_order) { + return -1; + } + + if (mc_a->state.z_order > mc_b->state.z_order) { + return 1; + } + + return 0; +} + +static void +transfer_layers_locked(struct multi_system_compositor *msc) +{ + COMP_TRACE_MARKER(); + + struct xrt_compositor *xc = &msc->xcn->base; + + struct multi_compositor *array[MULTI_MAX_CLIENTS] = {0}; + + size_t count = 0; + for (size_t k = 0; k < ARRAY_SIZE(array); k++) { + if (msc->clients[k] == NULL) { + continue; + } + + array[count++] = msc->clients[k]; + } + + // Sort the stack array + qsort(array, count, sizeof(struct multi_compositor *), overlay_sort_func); + + for (size_t k = 0; k < count; k++) { + struct multi_compositor *mc = array[k]; + + if (mc == NULL) { + continue; + } + + for (size_t i = 0; i < mc->delivered.num_layers; i++) { + struct multi_layer_entry *layer = &mc->delivered.layers[i]; + + switch (layer->data.type) { + case XRT_LAYER_STEREO_PROJECTION: do_projection_layer(xc, mc, layer, i); break; + case XRT_LAYER_STEREO_PROJECTION_DEPTH: do_projection_layer_depth(xc, mc, layer, i); break; + case XRT_LAYER_QUAD: do_quad_layer(xc, mc, layer, i); break; + case XRT_LAYER_CUBE: do_cube_layer(xc, mc, layer, i); break; + case XRT_LAYER_CYLINDER: do_cylinder_layer(xc, mc, layer, i); break; + case XRT_LAYER_EQUIRECT1: do_equirect1_layer(xc, mc, layer, i); break; + case XRT_LAYER_EQUIRECT2: do_equirect2_layer(xc, mc, layer, i); break; + default: U_LOG_E("Unhandled layer type '%i'!", layer->data.type); break; + } + } + } +} + +static void +broadcast_timings(struct multi_system_compositor *msc, + uint64_t predicted_display_time_ns, + uint64_t predicted_display_period_ns, + uint64_t diff_ns) +{ + COMP_TRACE_MARKER(); + + os_mutex_lock(&msc->list_and_timing_lock); + + for (size_t i = 0; i < ARRAY_SIZE(msc->clients); i++) { + struct multi_compositor *mc = msc->clients[i]; + if (mc == NULL) { + continue; + } + + u_rt_helper_new_sample( // + &mc->urth, // + predicted_display_time_ns, // + predicted_display_period_ns, // + diff_ns); // + } + + msc->last_timings.predicted_display_time_ns = predicted_display_time_ns; + msc->last_timings.predicted_display_period_ns = predicted_display_period_ns; + msc->last_timings.diff_ns = diff_ns; + + os_mutex_unlock(&msc->list_and_timing_lock); +} + +static int +multi_main_loop(struct multi_system_compositor *msc) +{ + COMP_TRACE_MARKER(); + + struct xrt_compositor *xc = &msc->xcn->base; + + //! @todo Don't make this a hack. + enum xrt_view_type view_type = XRT_VIEW_TYPE_STEREO; + + xrt_comp_begin_session(xc, view_type); + + os_thread_helper_lock(&msc->oth); + while (os_thread_helper_is_running_locked(&msc->oth)) { + os_thread_helper_unlock(&msc->oth); + + int64_t frame_id; + uint64_t predicted_display_time_ns; + uint64_t predicted_display_period_ns; + + xrt_comp_wait_frame(xc, &frame_id, &predicted_display_time_ns, &predicted_display_period_ns); + + uint64_t now_ns = os_monotonic_get_ns(); + uint64_t diff_ns = predicted_display_time_ns - now_ns; + + broadcast_timings(msc, predicted_display_time_ns, predicted_display_period_ns, diff_ns); + + // Make sure that the clients doesn't go away. + os_mutex_lock(&msc->list_and_timing_lock); + + xrt_comp_begin_frame(xc, frame_id); + xrt_comp_layer_begin(xc, frame_id, 0, 0); + + transfer_layers_locked(msc); + + xrt_comp_layer_commit(xc, frame_id, XRT_GRAPHICS_SYNC_HANDLE_INVALID); + + os_mutex_unlock(&msc->list_and_timing_lock); + + // Re-lock the thread for check in while statement. + os_thread_helper_lock(&msc->oth); + } + + xrt_comp_end_session(xc); + + return 0; +} + +static void * +thread_func(void *ptr) +{ + return (void *)(intptr_t)multi_main_loop((struct multi_system_compositor *)ptr); +} + + +/* + * + * System multi compositor functions. + * + */ + +static xrt_result_t +system_compositor_set_state(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused) +{ + struct multi_system_compositor *msc = multi_system_compositor(xsc); + struct multi_compositor *mc = multi_compositor(xc); + (void)msc; + + //! @todo Locking? + if (mc->state.sent.visible != visible || mc->state.sent.focused != focused) { + mc->state.sent.visible = visible; + mc->state.sent.focused = focused; + + union xrt_compositor_event xce = {0}; + xce.type = XRT_COMPOSITOR_EVENT_STATE_CHANGE; + xce.state.visible = visible; + xce.state.focused = focused; + + multi_compositor_push_event(mc, &xce); + } + + return XRT_SUCCESS; +} + +static xrt_result_t +system_compositor_set_z_order(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, int64_t z_order) +{ + struct multi_system_compositor *msc = multi_system_compositor(xsc); + struct multi_compositor *mc = multi_compositor(xc); + (void)msc; + + //! @todo Locking? + mc->state.z_order = z_order; + + return XRT_SUCCESS; +} + +static xrt_result_t +system_compositor_set_main_app_visibility(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible) +{ + struct multi_system_compositor *msc = multi_system_compositor(xsc); + struct multi_compositor *mc = multi_compositor(xc); + (void)msc; + + union xrt_compositor_event xce = {0}; + xce.type = XRT_COMPOSITOR_EVENT_OVERLAY_CHANGE; + xce.overlay.visible = visible; + + multi_compositor_push_event(mc, &xce); + + return XRT_SUCCESS; +} + + +/* + * + * System compositor functions. + * + */ + +static xrt_result_t +system_compositor_create_native_compositor(struct xrt_system_compositor *xsc, + const struct xrt_session_info *xsi, + struct xrt_compositor_native **out_xcn) +{ + struct multi_system_compositor *msc = multi_system_compositor(xsc); + + return multi_compositor_create(msc, xsi, out_xcn); +} + +static void +system_compositor_destroy(struct xrt_system_compositor *xsc) +{ + struct multi_system_compositor *msc = multi_system_compositor(xsc); + + // Stop the render thread first. + os_thread_helper_stop(&msc->oth); + + xrt_comp_native_destroy(&msc->xcn); + + free(msc); +} + + +/* + * + * 'Exported' functions. + * + */ + +xrt_result_t +comp_multi_create_system_compositor(struct xrt_compositor_native *xcn, + const struct xrt_system_compositor_info *xsci, + struct xrt_system_compositor **out_xsysc) +{ + struct multi_system_compositor *msc = U_TYPED_CALLOC(struct multi_system_compositor); + msc->base.create_native_compositor = system_compositor_create_native_compositor; + msc->base.destroy = system_compositor_destroy; + msc->xmcc.set_state = system_compositor_set_state; + msc->xmcc.set_z_order = system_compositor_set_z_order; + msc->xmcc.set_main_app_visibility = system_compositor_set_main_app_visibility; + msc->base.xmcc = &msc->xmcc; + msc->base.info = *xsci; + msc->xcn = xcn; + + int ret = os_thread_helper_init(&msc->oth); + if (ret < 0) { + return XRT_ERROR_THREADING_INIT_FAILURE; + } + + os_thread_helper_start(&msc->oth, thread_func, msc); + + *out_xsysc = &msc->base; + + return XRT_SUCCESS; +} From 2035da1ec9e970563361fbcf8c56a65e71f97f24 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 10 Mar 2021 18:01:55 +0000 Subject: [PATCH 298/883] c/main: Implement fence functions --- src/xrt/compositor/CMakeLists.txt | 1 + src/xrt/compositor/main/comp_compositor.c | 1 + src/xrt/compositor/main/comp_compositor.h | 8 ++ src/xrt/compositor/main/comp_sync.c | 122 ++++++++++++++++++++++ src/xrt/compositor/meson.build | 1 + 5 files changed, 133 insertions(+) create mode 100644 src/xrt/compositor/main/comp_sync.c diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index 7dce4d1ad..602805459 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -24,6 +24,7 @@ set(MAIN_SOURCE_FILES main/comp_settings.h main/comp_shaders.c main/comp_swapchain.c + main/comp_sync.c main/comp_target.h main/comp_target_swapchain.c main/comp_target_swapchain.h diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 7350b3c04..a611ee6cb 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -1295,6 +1295,7 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos c->base.base.create_swapchain = comp_swapchain_create; c->base.base.import_swapchain = comp_swapchain_import; + c->base.base.import_fence = comp_compositor_import_fence; c->base.base.begin_session = compositor_begin_session; c->base.base.end_session = compositor_end_session; c->base.base.wait_frame = compositor_wait_frame; diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h index 85a0b6415..68426e0fa 100644 --- a/src/xrt/compositor/main/comp_compositor.h +++ b/src/xrt/compositor/main/comp_compositor.h @@ -326,6 +326,14 @@ comp_swapchain_import(struct xrt_compositor *xc, void comp_swapchain_really_destroy(struct comp_swapchain *sc); +/*! + * For importing fences, defined in comp_sync.c . + */ +xrt_result_t +comp_compositor_import_fence(struct xrt_compositor *xc, + xrt_graphics_sync_handle_t handle, + struct xrt_compositor_fence **out_xcf); + /*! * Loads all of the shaders that the compositor uses. */ diff --git a/src/xrt/compositor/main/comp_sync.c b/src/xrt/compositor/main/comp_sync.c new file mode 100644 index 000000000..c9a02ae29 --- /dev/null +++ b/src/xrt/compositor/main/comp_sync.c @@ -0,0 +1,122 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Sync code for the main compositor. + * @author Jakob Bornecrantz + * @ingroup comp_main + */ + +#include "util/u_misc.h" +#include "util/u_handles.h" + +#include "main/comp_compositor.h" + +#include +#include + +#include +#include + +#include + + + +struct fence +{ + struct xrt_compositor_fence base; + struct comp_compositor *c; + + VkFence fence; +}; + + +/* + * + * Helper functions. + * + */ + + + +/* + * + * Fence member functions. + * + */ + +static xrt_result_t +fence_wait(struct xrt_compositor_fence *xcf, uint64_t timeout) +{ + COMP_TRACE_MARKER(); + + struct fence *f = (struct fence *)xcf; + struct vk_bundle *vk = &f->c->vk; + + // Count no handle as signled fence. + if (f->fence == VK_NULL_HANDLE) { + return XRT_SUCCESS; + } + + VkResult ret = vk->vkWaitForFences(vk->device, 1, &f->fence, VK_TRUE, timeout); + if (ret == VK_TIMEOUT) { + return XRT_SUCCESS; + } + if (ret != VK_SUCCESS) { + COMP_ERROR(f->c, "vkWaitForFences: %s", vk_result_string(ret)); + return XRT_ERROR_VULKAN; + } + + return XRT_SUCCESS; +} + +static void +fence_destroy(struct xrt_compositor_fence *xcf) +{ + COMP_TRACE_MARKER(); + + struct fence *f = (struct fence *)xcf; + struct vk_bundle *vk = &f->c->vk; + + if (f->fence != VK_NULL_HANDLE) { + vk->vkDestroyFence(vk->device, f->fence, NULL); + f->fence = VK_NULL_HANDLE; + } + + free(f); +} + + +/* + * + * Compositor function. + * + */ + +xrt_result_t +comp_compositor_import_fence(struct xrt_compositor *xc, + xrt_graphics_sync_handle_t handle, + struct xrt_compositor_fence **out_xcf) +{ + COMP_TRACE_MARKER(); + + struct comp_compositor *c = comp_compositor(xc); + struct vk_bundle *vk = &c->vk; + + VkFence fence = VK_NULL_HANDLE; + + VkResult ret = vk_create_fence_sync_from_native(vk, handle, &fence); + if (ret != VK_SUCCESS) { + return XRT_ERROR_VULKAN; + } + + struct fence *f = U_TYPED_CALLOC(struct fence); + f->base.wait = fence_wait; + f->base.destroy = fence_destroy; + f->fence = fence; + f->c = c; + + *out_xcf = &f->base; + + return XRT_SUCCESS; +} diff --git a/src/xrt/compositor/meson.build b/src/xrt/compositor/meson.build index 08e7f9471..7caf395d3 100644 --- a/src/xrt/compositor/meson.build +++ b/src/xrt/compositor/meson.build @@ -22,6 +22,7 @@ compositor_srcs = [ 'main/comp_settings.h', 'main/comp_shaders.c', 'main/comp_swapchain.c', + 'main/comp_sync.c', 'main/comp_target.h', 'main/comp_target_swapchain.c', 'main/comp_target_swapchain.h', From 22df47f974ce7f51db7f20206996c10179a43f49 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 6 Apr 2021 17:18:34 -0500 Subject: [PATCH 299/883] c/main: Port to using u_graphics_sync_unref --- src/xrt/compositor/main/comp_compositor.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index a611ee6cb..f75207547 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -49,6 +49,7 @@ #include "util/u_misc.h" #include "util/u_time.h" #include "util/u_debug.h" +#include "util/u_handles.h" #include "util/u_trace_marker.h" #include "util/u_distortion_mesh.h" @@ -355,23 +356,7 @@ compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_graphic COMP_SPEW(c, "LAYER_COMMIT at %8.3fms", ts_ms()); -#ifdef XRT_GRAPHICS_SYNC_HANDLE_IS_FD - // Need to consume this handle. - if (xrt_graphics_sync_handle_is_valid(sync_handle)) { - close(sync_handle); - sync_handle = XRT_GRAPHICS_SYNC_HANDLE_INVALID; - } - -#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE) - // Need to consume this handle. - if (xrt_graphics_sync_handle_is_valid(sync_handle)) { - CloseHandle(sync_handle); - sync_handle = XRT_GRAPHICS_SYNC_HANDLE_INVALID; - } - -#else -#error "Not yet implemented for this platform" -#endif + u_graphics_sync_unref(&sync_handle); // Always zero for now. From 205db10353fe00838f90f89dfff28193646915ab Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 16 Mar 2021 23:33:55 +0000 Subject: [PATCH 300/883] c/main: Implement new predict and mark frame functions --- src/xrt/compositor/main/comp_compositor.c | 85 ++++++++++++++++++----- 1 file changed, 69 insertions(+), 16 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index f75207547..3250cf63a 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -114,15 +114,19 @@ compositor_end_session(struct xrt_compositor *xc) } static xrt_result_t -compositor_wait_frame(struct xrt_compositor *xc, - int64_t *out_frame_id, - uint64_t *out_predicted_display_time_ns, - uint64_t *out_predicted_display_period_ns) +compositor_predict_frame(struct xrt_compositor *xc, + int64_t *out_frame_id, + uint64_t *out_wake_time_ns, + uint64_t *out_predicted_gpu_time_ns, + uint64_t *out_predicted_display_time_ns, + uint64_t *out_predicted_display_period_ns) { COMP_TRACE_MARKER(); struct comp_compositor *c = comp_compositor(xc); + COMP_DEBUG(c, "PREDICT_FRAME"); + // A little bit easier to read. uint64_t interval_ns = (int64_t)c->settings.nominal_frame_interval_ns; @@ -135,18 +139,70 @@ compositor_wait_frame(struct xrt_compositor *xc, uint64_t present_slop_ns = 0; uint64_t desired_present_time_ns = 0; uint64_t predicted_display_time_ns = 0; - comp_target_calc_frame_timings(c->target, // - &frame_id, // - &wake_up_time_ns, // - &desired_present_time_ns, // - &present_slop_ns, // - &predicted_display_time_ns); // + comp_target_calc_frame_timings( // + c->target, // + &frame_id, // + &wake_up_time_ns, // + &desired_present_time_ns, // + &present_slop_ns, // + &predicted_display_time_ns); // c->frame.waited.id = frame_id; c->frame.waited.desired_present_time_ns = desired_present_time_ns; c->frame.waited.present_slop_ns = present_slop_ns; c->frame.waited.predicted_display_time_ns = predicted_display_time_ns; + *out_frame_id = frame_id; + *out_wake_time_ns = wake_up_time_ns; + *out_predicted_gpu_time_ns = desired_present_time_ns; // Not quite right but close enough. + *out_predicted_display_time_ns = predicted_display_time_ns; + *out_predicted_display_period_ns = interval_ns; + + return XRT_SUCCESS; +} + +static xrt_result_t +compositor_mark_frame(struct xrt_compositor *xc, + int64_t frame_id, + enum xrt_compositor_frame_point point, + uint64_t when_ns) +{ + COMP_TRACE_MARKER(); + + struct comp_compositor *c = comp_compositor(xc); + + COMP_DEBUG(c, "MARK_FRAME %i", point); + + switch (point) { + case XRT_COMPOSITOR_FRAME_POINT_WOKE: + comp_target_mark_wake_up(c->target, frame_id, when_ns); + return XRT_SUCCESS; + default: assert(false); + } +} + +static xrt_result_t +compositor_wait_frame(struct xrt_compositor *xc, + int64_t *out_frame_id, + uint64_t *out_predicted_display_time_ns, + uint64_t *out_predicted_display_period_ns) +{ + COMP_TRACE_MARKER(); + + struct comp_compositor *c = comp_compositor(xc); + + int64_t frame_id = -1; + uint64_t wake_up_time_ns = 0; + uint64_t predicted_gpu_time_ns = 0; + + xrt_comp_predict_frame( // + xc, // + &frame_id, // + &wake_up_time_ns, // + &predicted_gpu_time_ns, // + out_predicted_display_time_ns, // + out_predicted_display_period_ns); // + uint64_t now_ns = os_monotonic_get_ns(); if (now_ns < wake_up_time_ns) { uint32_t delay = (uint32_t)(wake_up_time_ns - now_ns); @@ -154,13 +210,8 @@ compositor_wait_frame(struct xrt_compositor *xc, } now_ns = os_monotonic_get_ns(); - comp_target_mark_wake_up(c->target, frame_id, now_ns); - comp_target_update_timings(c->target); - - *out_frame_id = frame_id; - *out_predicted_display_time_ns = predicted_display_time_ns; - *out_predicted_display_period_ns = interval_ns; + xrt_comp_mark_frame(xc, frame_id, XRT_COMPOSITOR_FRAME_POINT_WOKE, now_ns); return XRT_SUCCESS; } @@ -1283,6 +1334,8 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos c->base.base.import_fence = comp_compositor_import_fence; c->base.base.begin_session = compositor_begin_session; c->base.base.end_session = compositor_end_session; + c->base.base.predict_frame = compositor_predict_frame; + c->base.base.mark_frame = compositor_mark_frame; c->base.base.wait_frame = compositor_wait_frame; c->base.base.begin_frame = compositor_begin_frame; c->base.base.discard_frame = compositor_discard_frame; From bf2a90fec5c2bbf1aaed17fa7b37c4c2707c5100 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 11 Mar 2021 23:58:51 +0000 Subject: [PATCH 301/883] c/main: Switch to multi client layer --- src/xrt/compositor/main/comp_compositor.c | 54 +++-------------------- src/xrt/compositor/main/comp_compositor.h | 5 --- 2 files changed, 7 insertions(+), 52 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 3250cf63a..7d1c8e9cd 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -55,6 +55,8 @@ #include "main/comp_compositor.h" +#include "multi/comp_multi_interface.h" + #include #include #include @@ -541,48 +543,9 @@ static void compositor_destroy(struct xrt_compositor *xc) { struct comp_compositor *c = comp_compositor(xc); - - COMP_DEBUG(c, "COMP_DESTROY"); - - assert(c->compositor_created); - - c->compositor_created = false; -} - - -/* - * - * System compositor functions. - * - */ - -static xrt_result_t -system_compositor_create_native_compositor(struct xrt_system_compositor *xsc, - const struct xrt_session_info *xsi, - struct xrt_compositor_native **out_xcn) -{ - struct comp_compositor *c = container_of(xsc, struct comp_compositor, system); - - COMP_DEBUG(c, "SYSCOMP_CREATE_NATIVE_COMPOSITOR"); - - if (c->compositor_created) { - return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED; - } - - c->compositor_created = true; - c->state = COMP_STATE_PREPARED; - *out_xcn = &c->base; - - return XRT_SUCCESS; -} - -static void -system_compositor_destroy(struct xrt_system_compositor *xsc) -{ - struct comp_compositor *c = container_of(xsc, struct comp_compositor, system); struct vk_bundle *vk = &c->vk; - COMP_DEBUG(c, "SYSCOMP_DESTROY"); + COMP_DEBUG(c, "COMP_DESTROY"); // Make sure we don't have anything to destroy. comp_compositor_garbage_collect(c); @@ -1352,8 +1315,6 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos c->base.base.destroy = compositor_destroy; c->frame.waited.id = -1; c->frame.rendering.id = -1; - c->system.create_native_compositor = system_compositor_create_native_compositor; - c->system.destroy = system_compositor_destroy; c->xdev = xdev; u_threading_stack_init(&c->threading.destroy_swapchains); @@ -1381,7 +1342,7 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos !compositor_init_swapchain(c) || !compositor_init_renderer(c)) { COMP_DEBUG(c, "Failed to init compositor %p", (void *)c); - c->system.destroy(&c->system); + c->base.base.destroy(&c->base.base); return XRT_ERROR_VULKAN; } @@ -1427,7 +1388,8 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos assert(formats <= XRT_MAX_SWAPCHAIN_FORMATS); info->num_formats = formats; - struct xrt_system_compositor_info *sys_info = &c->system.info; + struct xrt_system_compositor_info sys_info_storage; + struct xrt_system_compositor_info *sys_info = &sys_info_storage; // Required by OpenXR spec. sys_info->max_layers = 16; @@ -1495,9 +1457,7 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos c->state = COMP_STATE_READY; - *out_xsysc = &c->system; - - return XRT_SUCCESS; + return comp_multi_create_system_compositor(&c->base, sys_info, out_xsysc); } void diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h index 68426e0fa..cfb17f7ea 100644 --- a/src/xrt/compositor/main/comp_compositor.h +++ b/src/xrt/compositor/main/comp_compositor.h @@ -173,8 +173,6 @@ struct comp_compositor { struct xrt_compositor_native base; - struct xrt_system_compositor system; - //! Renderer helper. struct comp_renderer *r; @@ -245,9 +243,6 @@ struct comp_compositor struct comp_resources nr; - - //! To insure only one compositor is created. - bool compositor_created; }; From f14958f2b0e310b29b358b01adca5b528b4d7afb Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 19 Mar 2021 13:50:35 +0000 Subject: [PATCH 302/883] c/main: Explicitly wait for GPU work to finish --- src/xrt/compositor/main/comp_renderer.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index 6aeb635cf..dfcab1230 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -156,6 +156,20 @@ renderer_wait_gpu_idle(struct comp_renderer *r) os_mutex_unlock(&r->c->vk.queue_mutex); } +static void +renderer_wait_for_last_fence(struct comp_renderer *r) +{ + COMP_TRACE_MARKER(); + + struct vk_bundle *vk = &r->c->vk; + VkResult ret; + + ret = vk->vkWaitForFences(vk->device, 1, &r->fences[r->current_buffer], VK_TRUE, UINT64_MAX); + if (ret != VK_SUCCESS) { + COMP_ERROR(r->c, "vkWaitForFences: %s", vk_result_string(ret)); + } +} + static void renderer_submit_queue(struct comp_renderer *r) { @@ -663,12 +677,20 @@ comp_renderer_draw(struct comp_renderer *r) comp_target_update_timings(ct); renderer_submit_queue(r); + + renderer_present_swapchain_image(r, c->frame.rendering.desired_present_time_ns, c->frame.rendering.present_slop_ns); // Clear the frame. c->frame.rendering.id = -1; + /* + * Wait for the last fence to complete so we know that the GPU is done, + * if there is a big GPU bubble this lets us detect that. + */ + renderer_wait_for_last_fence(r); + /* * This fixes a lot of validation issues as it makes sure that the * command buffer has completed and all resources referred by it can From bcf9b62fc0df2693f8bfebc67211bf3393aeef5d Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 18 Mar 2021 23:17:42 +0000 Subject: [PATCH 303/883] ipc: Adopt to new multi client interface --- src/xrt/ipc/client/ipc_client_compositor.c | 81 +- src/xrt/ipc/server/ipc_server.h | 58 +- src/xrt/ipc/server/ipc_server_handler.c | 428 ++++++++--- .../ipc/server/ipc_server_per_client_thread.c | 41 +- src/xrt/ipc/server/ipc_server_process.c | 709 +++++------------- src/xrt/ipc/shared/ipc_protocol.h | 1 + src/xrt/ipc/shared/proto.json | 7 +- 7 files changed, 617 insertions(+), 708 deletions(-) diff --git a/src/xrt/ipc/client/ipc_client_compositor.c b/src/xrt/ipc/client/ipc_client_compositor.c index c8edabc9c..16f18abaa 100644 --- a/src/xrt/ipc/client/ipc_client_compositor.c +++ b/src/xrt/ipc/client/ipc_client_compositor.c @@ -61,14 +61,10 @@ struct ipc_client_compositor struct { - uint64_t display_time_ns; - //! Id that we are currently using for submitting layers. uint32_t slot_id; uint32_t num_layers; - - enum xrt_blend_mode env_blend_mode; } layers; //! Has the native compositor been created, only supports one for now. @@ -397,14 +393,12 @@ ipc_compositor_wait_frame(struct xrt_compositor *xc, struct ipc_client_compositor *icc = ipc_client_compositor(xc); uint64_t wake_up_time_ns = 0; - uint64_t min_display_period_ns = 0; - IPC_CALL_CHK(ipc_call_compositor_wait_frame(icc->ipc_c, // Connection - out_frame_id, // Frame id - out_predicted_display_time, // Display time - &wake_up_time_ns, // When we should wake up - out_predicted_display_period, // Current period - &min_display_period_ns)); // Minimum display period + IPC_CALL_CHK(ipc_call_compositor_predict_frame(icc->ipc_c, // Connection + out_frame_id, // Frame id + &wake_up_time_ns, // When we should wake up + out_predicted_display_time, // Display time + out_predicted_display_period)); // Current period uint64_t now_ns = os_monotonic_get_ns(); @@ -465,8 +459,11 @@ ipc_compositor_layer_begin(struct xrt_compositor *xc, { struct ipc_client_compositor *icc = ipc_client_compositor(xc); - icc->layers.display_time_ns = display_time_ns; - icc->layers.env_blend_mode = env_blend_mode; + struct ipc_shared_memory *ism = icc->ipc_c->ism; + struct ipc_layer_slot *slot = &ism->slots[icc->layers.slot_id]; + + slot->display_time_ns = display_time_ns; + slot->env_blend_mode = env_blend_mode; return XRT_SUCCESS; } @@ -666,6 +663,34 @@ ipc_compositor_destroy(struct xrt_compositor *xc) icc->compositor_created = false; } +static void +ipc_compositor_init(struct ipc_client_compositor *icc, struct xrt_compositor_native **out_xcn) +{ + icc->base.base.create_swapchain = ipc_compositor_swapchain_create; + icc->base.base.import_swapchain = ipc_compositor_swapchain_import; + icc->base.base.begin_session = ipc_compositor_begin_session; + icc->base.base.end_session = ipc_compositor_end_session; + icc->base.base.wait_frame = ipc_compositor_wait_frame; + icc->base.base.begin_frame = ipc_compositor_begin_frame; + icc->base.base.discard_frame = ipc_compositor_discard_frame; + icc->base.base.layer_begin = ipc_compositor_layer_begin; + icc->base.base.layer_stereo_projection = ipc_compositor_layer_stereo_projection; + icc->base.base.layer_stereo_projection_depth = ipc_compositor_layer_stereo_projection_depth; + icc->base.base.layer_quad = ipc_compositor_layer_quad; + icc->base.base.layer_cube = ipc_compositor_layer_cube; + icc->base.base.layer_cylinder = ipc_compositor_layer_cylinder; + icc->base.base.layer_equirect1 = ipc_compositor_layer_equirect1; + icc->base.base.layer_equirect2 = ipc_compositor_layer_equirect2; + icc->base.base.layer_commit = ipc_compositor_layer_commit; + icc->base.base.destroy = ipc_compositor_destroy; + icc->base.base.poll_events = ipc_compositor_poll_events; + + // Fetch info from the compositor, among it the format format list. + get_info(&(icc->base.base), &icc->base.base.info); + + *out_xcn = &icc->base; +} + /* * @@ -792,11 +817,14 @@ ipc_syscomp_create_native_compositor(struct xrt_system_compositor *xsc, return XRT_ERROR_MULTI_SESSION_NOT_IMPLEMENTED; } - icc->compositor_created = true; - *out_xcn = &icc->base; - + // Needs to be done before init. IPC_CALL_CHK(ipc_call_session_create(icc->ipc_c, xsi)); + // Needs to be done after session create call. + ipc_compositor_init(icc, out_xcn); + + icc->compositor_created = true; + return XRT_SUCCESS; } @@ -829,24 +857,6 @@ ipc_client_create_system_compositor(struct ipc_connection *ipc_c, { struct ipc_client_compositor *c = U_TYPED_CALLOC(struct ipc_client_compositor); - c->base.base.create_swapchain = ipc_compositor_swapchain_create; - c->base.base.import_swapchain = ipc_compositor_swapchain_import; - c->base.base.begin_session = ipc_compositor_begin_session; - c->base.base.end_session = ipc_compositor_end_session; - c->base.base.wait_frame = ipc_compositor_wait_frame; - c->base.base.begin_frame = ipc_compositor_begin_frame; - c->base.base.discard_frame = ipc_compositor_discard_frame; - c->base.base.layer_begin = ipc_compositor_layer_begin; - c->base.base.layer_stereo_projection = ipc_compositor_layer_stereo_projection; - c->base.base.layer_stereo_projection_depth = ipc_compositor_layer_stereo_projection_depth; - c->base.base.layer_quad = ipc_compositor_layer_quad; - c->base.base.layer_cube = ipc_compositor_layer_cube; - c->base.base.layer_cylinder = ipc_compositor_layer_cylinder; - c->base.base.layer_equirect1 = ipc_compositor_layer_equirect1; - c->base.base.layer_equirect2 = ipc_compositor_layer_equirect2; - c->base.base.layer_commit = ipc_compositor_layer_commit; - c->base.base.destroy = ipc_compositor_destroy; - c->base.base.poll_events = ipc_compositor_poll_events; c->system.create_native_compositor = ipc_syscomp_create_native_compositor; c->system.destroy = ipc_syscomp_destroy; c->ipc_c = ipc_c; @@ -863,9 +873,6 @@ ipc_client_create_system_compositor(struct ipc_connection *ipc_c, } #endif - // Fetch info from the compositor, among it the format format list. - get_info(&(c->base.base), &c->base.base.info); - // Fetch info from the system compositor. get_system_info(c, &c->system.info); diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h index 9645ad2ac..b247d53c2 100644 --- a/src/xrt/ipc/server/ipc_server.h +++ b/src/xrt/ipc/server/ipc_server.h @@ -69,14 +69,6 @@ struct ipc_swapchain_data bool active; }; - -struct ipc_queued_event -{ - bool pending; - uint64_t timestamp; - union xrt_compositor_event event; -}; - /*! * Holds the state for a single client. * @@ -105,17 +97,7 @@ struct ipc_client_state //! Socket fd used for client comms struct ipc_message_channel imc; - //! State for rendering. - struct ipc_layer_slot render_state; - - //! Whether we are currently rendering @ref render_state - bool rendering_state; - - //! The frame timing state. - struct u_rt_helper urth; - struct ipc_app_state client_state; - struct ipc_queued_event queued_events[IPC_EVENT_QUEUE_SIZE]; int server_thread_index; }; @@ -294,8 +276,6 @@ struct ipc_server //! System compositor. struct xrt_system_compositor *xsysc; - //! Native compositor. - struct xrt_compositor_native *xcn; struct ipc_device idevs[IPC_SERVER_NUM_XDEVS]; struct xrt_tracking_origin *xtracks[IPC_SERVER_NUM_XDEVS]; @@ -317,9 +297,13 @@ struct ipc_server volatile uint32_t current_slot_index; - int active_client_index; - int last_active_client_index; - struct os_mutex global_state_lock; + struct + { + int active_client_index; + int last_active_client_index; + + struct os_mutex lock; + } global_state; }; @@ -349,12 +333,36 @@ ipc_server_main_android(struct ipc_server **ps, void (*startup_complete_callback #endif /*! - * Called by client threads to manage global state + * Set the new active client. * * @ingroup ipc_server */ void -update_server_state(struct ipc_server *vs); +ipc_server_set_active_client(struct ipc_server *s, int active_client_index); + +/*! + * Called by client threads to set a session to active. + * + * @ingroup ipc_server + */ +void +ipc_server_activate_session(volatile struct ipc_client_state *ics); + +/*! + * Called by client threads to set a session to deactivate. + * + * @ingroup ipc_server + */ +void +ipc_server_deactivate_session(volatile struct ipc_client_state *ics); + +/*! + * Called by client threads to recalculate active client. + * + * @ingroup ipc_server + */ +void +ipc_server_update_state(struct ipc_server *s); /*! * Thread function for the client side dispatching. diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 3da04b0a7..4157a2d09 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -10,6 +10,7 @@ #include "xrt/xrt_gfx_native.h" #include "util/u_misc.h" +#include "util/u_handles.h" #include "util/u_trace_marker.h" #include "server/ipc_server.h" @@ -93,33 +94,39 @@ ipc_handle_system_compositor_get_info(volatile struct ipc_client_state *ics, xrt_result_t ipc_handle_session_create(volatile struct ipc_client_state *ics, const struct xrt_session_info *xsi) { - ics->client_state.session_active = false; - ics->client_state.session_overlay = false; - ics->client_state.session_visible = false; + struct xrt_compositor_native *xcn = NULL; - if (xsi->is_overlay) { - ics->client_state.session_overlay = true; - ics->client_state.z_order = xsi->z_order; + xrt_result_t xret = xrt_syscomp_create_native_compositor(ics->server->xsysc, xsi, &xcn); + if (xret != XRT_SUCCESS) { + return xret; } - update_server_state(ics->server); + ics->client_state.session_overlay = xsi->is_overlay; + ics->client_state.z_order = xsi->z_order; + + ics->xc = &xcn->base; + + xrt_syscomp_set_state(ics->server->xsysc, ics->xc, ics->client_state.session_visible, + ics->client_state.session_focused); + xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, ics->client_state.z_order); + return XRT_SUCCESS; } xrt_result_t ipc_handle_session_begin(volatile struct ipc_client_state *ics) { - // ics->client_state.session_active = true; - // update_server_state(ics->server); - return XRT_SUCCESS; + IPC_TRACE_MARKER(); + + return xrt_comp_begin_session(ics->xc, 0); } xrt_result_t ipc_handle_session_end(volatile struct ipc_client_state *ics) { - ics->client_state.session_active = false; - update_server_state(ics->server); - return XRT_SUCCESS; + IPC_TRACE_MARKER(); + + return xrt_comp_end_session(ics->xc); } xrt_result_t @@ -131,62 +138,310 @@ ipc_handle_compositor_get_info(volatile struct ipc_client_state *ics, struct xrt } xrt_result_t -ipc_handle_compositor_wait_frame(volatile struct ipc_client_state *ics, - int64_t *out_frame_id, - uint64_t *predicted_display_time, - uint64_t *wake_up_time, - uint64_t *predicted_display_period, - uint64_t *min_display_period) +ipc_handle_compositor_predict_frame(volatile struct ipc_client_state *ics, + int64_t *out_frame_id, + uint64_t *out_wake_up_time_ns, + uint64_t *out_predicted_display_time_ns, + uint64_t *out_predicted_display_period_ns) { IPC_TRACE_MARKER(); - os_mutex_lock(&ics->server->global_state_lock); + /* + * We use this to signal that the session has started, this is needed + * to make this client/session active/visible/focused. + */ + ipc_server_activate_session(ics); - u_rt_helper_predict((struct u_rt_helper *)&ics->urth, out_frame_id, predicted_display_time, wake_up_time, - predicted_display_period, min_display_period); - - os_mutex_unlock(&ics->server->global_state_lock); - - ics->client_state.session_active = true; - update_server_state(ics->server); - - return XRT_SUCCESS; + uint64_t gpu_time_ns = 0; + return xrt_comp_predict_frame( // + ics->xc, // + out_frame_id, // + out_wake_up_time_ns, // + &gpu_time_ns, // + out_predicted_display_time_ns, // + out_predicted_display_period_ns); // } xrt_result_t ipc_handle_compositor_wait_woke(volatile struct ipc_client_state *ics, int64_t frame_id) { - os_mutex_lock(&ics->server->global_state_lock); + IPC_TRACE_MARKER(); - u_rt_helper_mark_wait_woke((struct u_rt_helper *)&ics->urth, frame_id); - - os_mutex_unlock(&ics->server->global_state_lock); - - return XRT_SUCCESS; + return xrt_comp_mark_frame(ics->xc, frame_id, XRT_COMPOSITOR_FRAME_POINT_WOKE, os_monotonic_get_ns()); } xrt_result_t ipc_handle_compositor_begin_frame(volatile struct ipc_client_state *ics, int64_t frame_id) { - os_mutex_lock(&ics->server->global_state_lock); + IPC_TRACE_MARKER(); - u_rt_helper_mark_begin((struct u_rt_helper *)&ics->urth, frame_id); - - os_mutex_unlock(&ics->server->global_state_lock); - - return XRT_SUCCESS; + return xrt_comp_begin_frame(ics->xc, frame_id); } xrt_result_t ipc_handle_compositor_discard_frame(volatile struct ipc_client_state *ics, int64_t frame_id) { - os_mutex_lock(&ics->server->global_state_lock); + IPC_TRACE_MARKER(); - u_rt_helper_mark_discarded((struct u_rt_helper *)&ics->urth, frame_id); + return xrt_comp_discard_frame(ics->xc, frame_id); +} - os_mutex_unlock(&ics->server->global_state_lock); +static bool +_update_projection_layer(struct xrt_compositor *xc, + volatile struct ipc_client_state *ics, + volatile struct ipc_layer_entry *layer, + uint32_t i) +{ + // xdev + uint32_t device_id = layer->xdev_id; + // left + uint32_t lxsci = layer->swapchain_ids[0]; + // right + uint32_t rxsci = layer->swapchain_ids[1]; - return XRT_SUCCESS; + struct xrt_device *xdev = get_xdev(ics, device_id); + struct xrt_swapchain *lxcs = ics->xscs[lxsci]; + struct xrt_swapchain *rxcs = ics->xscs[rxsci]; + + if (lxcs == NULL || rxcs == NULL) { + U_LOG_E("Invalid swap chain for projection layer!"); + return false; + } + + if (xdev == NULL) { + U_LOG_E("Invalid xdev for projection layer!"); + return false; + } + + // Cast away volatile. + struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; + + xrt_comp_layer_stereo_projection(xc, xdev, lxcs, rxcs, data); + + return true; +} + +static bool +_update_projection_layer_depth(struct xrt_compositor *xc, + volatile struct ipc_client_state *ics, + volatile struct ipc_layer_entry *layer, + uint32_t i) +{ + // xdev + uint32_t xdevi = layer->xdev_id; + // left + uint32_t l_xsci = layer->swapchain_ids[0]; + // right + uint32_t r_xsci = layer->swapchain_ids[1]; + // left + uint32_t l_d_xsci = layer->swapchain_ids[2]; + // right + uint32_t r_d_xsci = layer->swapchain_ids[3]; + + struct xrt_device *xdev = get_xdev(ics, xdevi); + struct xrt_swapchain *l_xcs = ics->xscs[l_xsci]; + struct xrt_swapchain *r_xcs = ics->xscs[r_xsci]; + struct xrt_swapchain *l_d_xcs = ics->xscs[l_d_xsci]; + struct xrt_swapchain *r_d_xcs = ics->xscs[r_d_xsci]; + + if (l_xcs == NULL || r_xcs == NULL || l_d_xcs == NULL || r_d_xcs == NULL) { + U_LOG_E("Invalid swap chain for projection layer #%u!", i); + return false; + } + + if (xdev == NULL) { + U_LOG_E("Invalid xdev for projection layer #%u!", i); + return false; + } + + // Cast away volatile. + struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; + + xrt_comp_layer_stereo_projection_depth(xc, xdev, l_xcs, r_xcs, l_d_xcs, r_d_xcs, data); + + return true; +} + +static bool +do_single(struct xrt_compositor *xc, + volatile struct ipc_client_state *ics, + volatile struct ipc_layer_entry *layer, + uint32_t i, + const char *name, + struct xrt_device **out_xdev, + struct xrt_swapchain **out_xcs, + struct xrt_layer_data **out_data) +{ + uint32_t device_id = layer->xdev_id; + uint32_t sci = layer->swapchain_ids[0]; + + struct xrt_device *xdev = get_xdev(ics, device_id); + struct xrt_swapchain *xcs = ics->xscs[sci]; + + if (xcs == NULL) { + U_LOG_E("Invalid swapchain for layer #%u, '%s'!", i, name); + return false; + } + + if (xdev == NULL) { + U_LOG_E("Invalid xdev for layer #%u, '%s'!", i, name); + return false; + } + + // Cast away volatile. + struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; + + *out_xdev = xdev; + *out_xcs = xcs; + *out_data = data; + + return true; +} + +static bool +_update_quad_layer(struct xrt_compositor *xc, + volatile struct ipc_client_state *ics, + volatile struct ipc_layer_entry *layer, + uint32_t i) +{ + struct xrt_device *xdev; + struct xrt_swapchain *xcs; + struct xrt_layer_data *data; + + if (!do_single(xc, ics, layer, i, "quad", &xdev, &xcs, &data)) { + return false; + } + + xrt_comp_layer_quad(xc, xdev, xcs, data); + + return true; +} + +static bool +_update_cube_layer(struct xrt_compositor *xc, + volatile struct ipc_client_state *ics, + volatile struct ipc_layer_entry *layer, + uint32_t i) +{ + struct xrt_device *xdev; + struct xrt_swapchain *xcs; + struct xrt_layer_data *data; + + if (!do_single(xc, ics, layer, i, "cube", &xdev, &xcs, &data)) { + return false; + } + + xrt_comp_layer_cube(xc, xdev, xcs, data); + + return true; +} + +static bool +_update_cylinder_layer(struct xrt_compositor *xc, + volatile struct ipc_client_state *ics, + volatile struct ipc_layer_entry *layer, + uint32_t i) +{ + struct xrt_device *xdev; + struct xrt_swapchain *xcs; + struct xrt_layer_data *data; + + if (!do_single(xc, ics, layer, i, "cylinder", &xdev, &xcs, &data)) { + return false; + } + + xrt_comp_layer_cylinder(xc, xdev, xcs, data); + + return true; +} + +static bool +_update_equirect1_layer(struct xrt_compositor *xc, + volatile struct ipc_client_state *ics, + volatile struct ipc_layer_entry *layer, + uint32_t i) +{ + struct xrt_device *xdev; + struct xrt_swapchain *xcs; + struct xrt_layer_data *data; + + if (!do_single(xc, ics, layer, i, "equirect1", &xdev, &xcs, &data)) { + return false; + } + + xrt_comp_layer_equirect1(xc, xdev, xcs, data); + + return true; +} + +static bool +_update_equirect2_layer(struct xrt_compositor *xc, + volatile struct ipc_client_state *ics, + volatile struct ipc_layer_entry *layer, + uint32_t i) +{ + struct xrt_device *xdev; + struct xrt_swapchain *xcs; + struct xrt_layer_data *data; + + if (!do_single(xc, ics, layer, i, "equirect2", &xdev, &xcs, &data)) { + return false; + } + + xrt_comp_layer_equirect2(xc, xdev, xcs, data); + + return true; +} + +static bool +_update_layers(volatile struct ipc_client_state *ics, struct xrt_compositor *xc, struct ipc_layer_slot *slot) +{ + IPC_TRACE_MARKER(); + + for (uint32_t i = 0; i < slot->num_layers; i++) { + volatile struct ipc_layer_entry *layer = &slot->layers[i]; + + switch (layer->data.type) { + case XRT_LAYER_STEREO_PROJECTION: + if (!_update_projection_layer(xc, ics, layer, i)) { + return false; + } + break; + case XRT_LAYER_STEREO_PROJECTION_DEPTH: + if (!_update_projection_layer_depth(xc, ics, layer, i)) { + return false; + } + break; + case XRT_LAYER_QUAD: + if (!_update_quad_layer(xc, ics, layer, i)) { + return false; + } + break; + case XRT_LAYER_CUBE: + if (!_update_cube_layer(xc, ics, layer, i)) { + return false; + } + break; + case XRT_LAYER_CYLINDER: + if (!_update_cylinder_layer(xc, ics, layer, i)) { + return false; + } + break; + case XRT_LAYER_EQUIRECT1: + if (!_update_equirect1_layer(xc, ics, layer, i)) { + return false; + } + break; + case XRT_LAYER_EQUIRECT2: + if (!_update_equirect2_layer(xc, ics, layer, i)) { + return false; + } + break; + default: U_LOG_E("Unhandled layer type '%i'!", layer->data.type); break; + } + } + + return true; } xrt_result_t @@ -197,33 +452,49 @@ ipc_handle_compositor_layer_sync(volatile struct ipc_client_state *ics, const xrt_graphics_sync_handle_t *handles, const uint32_t num_handles) { + IPC_TRACE_MARKER(); + struct ipc_shared_memory *ism = ics->server->ism; struct ipc_layer_slot *slot = &ism->slots[slot_id]; + xrt_graphics_sync_handle_t sync_handle = XRT_GRAPHICS_SYNC_HANDLE_INVALID; - for (uint32_t i = 0; i < num_handles; i++) { - if (!xrt_graphics_sync_handle_is_valid(handles[i])) { - continue; - } -#ifdef XRT_GRAPHICS_SYNC_HANDLE_IS_FD - close(handles[i]); -#else -#error "Need port to transport these graphics buffers" -#endif + // If we have one or more save the first handle. + if (num_handles >= 1) { + sync_handle = handles[0]; } - // Copy current slot data to our state. - ics->render_state = *slot; - ics->rendering_state = true; + // Free all sync handles after the first one. + for (uint32_t i = 1; i < num_handles; i++) { + // Checks for valid handle. + xrt_graphics_sync_handle_t tmp = handles[i]; + u_graphics_sync_unref(&tmp); + } - os_mutex_lock(&ics->server->global_state_lock); + // Copy current slot data. + struct ipc_layer_slot copy = *slot; + + + /* + * Transfer data to underlying compositor. + */ + + xrt_comp_layer_begin(ics->xc, frame_id, copy.display_time_ns, copy.env_blend_mode); + + _update_layers(ics, ics->xc, ©); + + xrt_comp_layer_commit(ics->xc, frame_id, sync_handle); + + + /* + * Manage shared state. + */ + + os_mutex_lock(&ics->server->global_state.lock); *out_free_slot_id = (ics->server->current_slot_index + 1) % IPC_MAX_SLOTS; ics->server->current_slot_index = *out_free_slot_id; - // Also protected by the global lock. - u_rt_helper_mark_delivered((struct u_rt_helper *)&ics->urth, frame_id); - - os_mutex_unlock(&ics->server->global_state_lock); + os_mutex_unlock(&ics->server->global_state.lock); return XRT_SUCCESS; } @@ -231,25 +502,9 @@ ipc_handle_compositor_layer_sync(volatile struct ipc_client_state *ics, xrt_result_t ipc_handle_compositor_poll_events(volatile struct ipc_client_state *ics, union xrt_compositor_event *out_xce) { - uint64_t l_timestamp = UINT64_MAX; - volatile struct ipc_queued_event *event_to_send = NULL; - for (uint32_t i = 0; i < IPC_EVENT_QUEUE_SIZE; i++) { - volatile struct ipc_queued_event *e = &ics->queued_events[i]; - if (e->pending == true && e->timestamp < l_timestamp) { - event_to_send = e; - } - } + IPC_TRACE_MARKER(); - // We always return an event in response to this call - - // We signal no events with a special event type. - out_xce->type = XRT_COMPOSITOR_EVENT_NONE; - - if (event_to_send) { - *out_xce = event_to_send->event; - event_to_send->pending = false; - } - - return XRT_SUCCESS; + return xrt_comp_poll_events(ics->xc, out_xce); } xrt_result_t @@ -271,7 +526,7 @@ ipc_handle_system_get_client_info(volatile struct ipc_client_state *_ics, //@todo: track this data in the ipc_client_state struct out_client_desc->primary_application = false; - if (ics->server->active_client_index == (int)id) { + if (ics->server->global_state.active_client_index == (int)id) { out_client_desc->primary_application = true; } @@ -306,10 +561,10 @@ ipc_handle_system_get_clients(volatile struct ipc_client_state *_ics, struct ipc xrt_result_t ipc_handle_system_set_primary_client(volatile struct ipc_client_state *ics, uint32_t client_id) { - - ics->server->active_client_index = client_id; IPC_INFO(ics->server, "System setting active client to %d.", client_id); - update_server_state(ics->server); + + ipc_server_set_active_client(ics->server, client_id); + return XRT_SUCCESS; } @@ -365,6 +620,8 @@ ipc_handle_swapchain_create(volatile struct ipc_client_state *ics, xrt_graphics_buffer_handle_t *out_handles, uint32_t *out_num_handles) { + IPC_TRACE_MARKER(); + xrt_result_t xret = XRT_SUCCESS; uint32_t index = 0; @@ -416,6 +673,8 @@ ipc_handle_swapchain_import(volatile struct ipc_client_state *ics, const xrt_graphics_buffer_handle_t *handles, uint32_t num_handles) { + IPC_TRACE_MARKER(); + xrt_result_t xret = XRT_SUCCESS; uint32_t index = 0; @@ -558,7 +817,6 @@ ipc_handle_device_get_tracked_pose(volatile struct ipc_client_state *ics, uint64_t at_timestamp, struct xrt_space_relation *out_relation) { - // To make the code a bit more readable. uint32_t device_id = id; struct ipc_device *isdev = &ics->server->idevs[device_id]; diff --git a/src/xrt/ipc/server/ipc_server_per_client_thread.c b/src/xrt/ipc/server/ipc_server_per_client_thread.c index c1afa1797..047641ed0 100644 --- a/src/xrt/ipc/server/ipc_server_per_client_thread.c +++ b/src/xrt/ipc/server/ipc_server_per_client_thread.c @@ -69,9 +69,6 @@ client_loop(volatile struct ipc_client_state *ics) { IPC_INFO(ics->server, "Client connected"); - // Make sure it's ready for the client. - u_rt_helper_client_clear((struct u_rt_helper *)&ics->urth); - // Claim the client fd. int epoll_fd = setup_epoll(ics); if (epoll_fd < 0) { @@ -123,43 +120,16 @@ client_loop(volatile struct ipc_client_state *ics) epoll_fd = -1; // Multiple threads might be looking at these fields. - os_mutex_lock(&ics->server->global_state_lock); + os_mutex_lock(&ics->server->global_state.lock); ipc_message_channel_close((struct ipc_message_channel *)&ics->imc); - // Reset the urth for the next client. - u_rt_helper_client_clear((struct u_rt_helper *)&ics->urth); - ics->num_swapchains = 0; ics->server->threads[ics->server_thread_index].state = IPC_THREAD_STOPPING; ics->server_thread_index = -1; memset((void *)&ics->client_state, 0, sizeof(struct ipc_app_state)); - // Make sure to reset the renderstate fully. - ics->rendering_state = false; - ics->render_state.num_layers = 0; - for (uint32_t i = 0; i < ARRAY_SIZE(ics->render_state.layers); ++i) { - volatile struct ipc_layer_entry *rl = &ics->render_state.layers[i]; - - rl->swapchain_ids[0] = 0; - rl->swapchain_ids[1] = 0; - rl->data.flip_y = false; - /*! - * @todo this is redundant, we're setting both elements of a - * union. Why? Can we just zero the whole render_state? - */ - rl->data.stereo.l.sub.image_index = 0; - rl->data.stereo.r.sub.image_index = 0; - rl->data.quad.sub.image_index = 0; - rl->data.cube.sub.image_index = 0; - rl->data.cylinder.sub.image_index = 0; - rl->data.equirect1.sub.image_index = 0; - rl->data.equirect2.sub.image_index = 0; - - //! @todo set rects or array index? - } - // Destroy all swapchains now. for (uint32_t j = 0; j < IPC_MAX_CLIENT_SWAPCHAINS; j++) { // Drop our reference, does NULL checking. Cast away volatile. @@ -168,12 +138,17 @@ client_loop(volatile struct ipc_client_state *ics) IPC_TRACE(ics->server, "Destroyed swapchain %d.", j); } - os_mutex_unlock(&ics->server->global_state_lock); + os_mutex_unlock(&ics->server->global_state.lock); + + // Cast away volatile. + xrt_comp_destroy((struct xrt_compositor **)&ics->xc); // Should we stop the server when a client disconnects? if (ics->server->exit_on_disconnect) { ics->server->running = false; } + + ipc_server_deactivate_session(ics); } @@ -190,7 +165,5 @@ ipc_server_client_thread(void *_ics) client_loop(ics); - update_server_state(ics->server); - return NULL; } diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index c550ce421..089cfc04c 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -50,6 +50,7 @@ extern void oxr_sdl2_hack_stop(void **hack_ptr); /* ---- HACK ---- */ + /* * * Defines and helpers. @@ -59,11 +60,12 @@ oxr_sdl2_hack_stop(void **hack_ptr); DEBUG_GET_ONCE_BOOL_OPTION(exit_on_disconnect, "IPC_EXIT_ON_DISCONNECT", false) DEBUG_GET_ONCE_LOG_OPTION(ipc_log, "IPC_LOG", U_LOGGING_WARN) -struct _z_sort_data -{ - int32_t index; - int32_t z_order; -}; + +/* + * + * Idev functions. + * + */ static void init_idev(struct ipc_device *idev, struct xrt_device *xdev) @@ -89,13 +91,12 @@ teardown_idev(struct ipc_device *idev) * Static functions. * */ + static void teardown_all(struct ipc_server *s) { u_var_remove_root(s); - xrt_comp_native_destroy(&s->xcn); - xrt_syscomp_destroy(&s->xsysc); for (size_t i = 0; i < IPC_SERVER_NUM_XDEVS; i++) { @@ -106,7 +107,7 @@ teardown_all(struct ipc_server *s) ipc_server_mainloop_deinit(&s->ml); - os_mutex_destroy(&s->global_state_lock); + os_mutex_destroy(&s->global_state.lock); } static int @@ -333,7 +334,7 @@ ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd) volatile struct ipc_client_state *ics = NULL; int32_t cs_index = -1; - os_mutex_lock(&vs->global_state_lock); + os_mutex_lock(&vs->global_state.lock); // find the next free thread in our array (server_thread_index is -1) // and have it handle this connection @@ -349,7 +350,7 @@ ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd) close(fd); // Unlock when we are done. - os_mutex_unlock(&vs->global_state_lock); + os_mutex_unlock(&vs->global_state.lock); U_LOG_E("Max client count reached!"); return; @@ -361,7 +362,7 @@ ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd) close(fd); // Unlock when we are done. - os_mutex_unlock(&vs->global_state_lock); + os_mutex_unlock(&vs->global_state.lock); U_LOG_E("Client state management error!"); return; @@ -381,7 +382,7 @@ ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd) os_thread_start(&it->thread, ipc_server_client_thread, (void *)ics); // Unlock when we are done. - os_mutex_unlock(&vs->global_state_lock); + os_mutex_unlock(&vs->global_state.lock); } static int @@ -432,17 +433,6 @@ init_all(struct ipc_server *s) return ret; } - struct xrt_session_info xsi = { - .is_overlay = false, - .flags = 0, - .z_order = 0, - }; - ret = xrt_syscomp_create_native_compositor(s->xsysc, &xsi, &s->xcn); - if (ret < 0) { - teardown_all(s); - return ret; - } - ret = init_shm(s); if (ret < 0) { teardown_all(s); @@ -455,12 +445,7 @@ init_all(struct ipc_server *s) return ret; } - // Init all of the render timing helpers. - for (size_t i = 0; i < ARRAY_SIZE(s->threads); i++) { - u_rt_helper_init((struct u_rt_helper *)&s->threads[i].ics.urth); - } - - ret = os_mutex_init(&s->global_state_lock); + ret = os_mutex_init(&s->global_state.lock); if (ret < 0) { teardown_all(s); return ret; @@ -476,500 +461,31 @@ init_all(struct ipc_server *s) return 0; } -static uint32_t -find_event_slot(volatile struct ipc_client_state *ics) -{ - uint64_t oldest_event_timestamp = UINT64_MAX; - uint32_t oldest_event_index = 0; - for (uint32_t i = 0; i < IPC_EVENT_QUEUE_SIZE; i++) { - if (ics->queued_events->timestamp < oldest_event_timestamp) { - oldest_event_index = i; - } - if (!ics->queued_events[i].pending) { - return i; - } - } - - U_LOG_E("Event queue full - unconsumed event lost!"); - return oldest_event_index; -} - -static void -transition_overlay_visibility(volatile struct ipc_client_state *ics, bool visible) -{ - uint32_t event_slot = find_event_slot(ics); - uint64_t timestamp = os_monotonic_get_ns(); - - volatile struct ipc_queued_event *qe = &ics->queued_events[event_slot]; - - qe->timestamp = timestamp; - qe->pending = true; - qe->event.type = XRT_COMPOSITOR_EVENT_OVERLAY_CHANGE; - qe->event.overlay.visible = visible; -} - -static void -send_client_state(volatile struct ipc_client_state *ics) -{ - uint32_t event_slot = find_event_slot(ics); - uint64_t timestamp = os_monotonic_get_ns(); - - volatile struct ipc_queued_event *qe = &ics->queued_events[event_slot]; - - qe->timestamp = timestamp; - qe->pending = true; - qe->event.type = XRT_COMPOSITOR_EVENT_STATE_CHANGE; - qe->event.state.visible = ics->client_state.session_visible; - qe->event.state.focused = ics->client_state.session_focused; -} - -static bool -_update_projection_layer(struct xrt_compositor *xc, - volatile struct ipc_client_state *ics, - volatile struct ipc_layer_entry *layer, - uint32_t i) -{ - // xdev - uint32_t device_id = layer->xdev_id; - // left - uint32_t lxsci = layer->swapchain_ids[0]; - // right - uint32_t rxsci = layer->swapchain_ids[1]; - - struct xrt_device *xdev = get_xdev(ics, device_id); - struct xrt_swapchain *lxcs = ics->xscs[lxsci]; - struct xrt_swapchain *rxcs = ics->xscs[rxsci]; - - if (lxcs == NULL || rxcs == NULL) { - U_LOG_E("Invalid swap chain for projection layer!"); - return false; - } - - if (xdev == NULL) { - U_LOG_E("Invalid xdev for projection layer!"); - return false; - } - - // Cast away volatile. - struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; - - xrt_comp_layer_stereo_projection(xc, xdev, lxcs, rxcs, data); - - return true; -} - -static bool -_update_projection_layer_depth(struct xrt_compositor *xc, - volatile struct ipc_client_state *ics, - volatile struct ipc_layer_entry *layer, - uint32_t i) -{ - // xdev - uint32_t xdevi = layer->xdev_id; - // left - uint32_t l_xsci = layer->swapchain_ids[0]; - // right - uint32_t r_xsci = layer->swapchain_ids[1]; - // left - uint32_t l_d_xsci = layer->swapchain_ids[2]; - // right - uint32_t r_d_xsci = layer->swapchain_ids[3]; - - struct xrt_device *xdev = get_xdev(ics, xdevi); - struct xrt_swapchain *l_xcs = ics->xscs[l_xsci]; - struct xrt_swapchain *r_xcs = ics->xscs[r_xsci]; - struct xrt_swapchain *l_d_xcs = ics->xscs[l_d_xsci]; - struct xrt_swapchain *r_d_xcs = ics->xscs[r_d_xsci]; - - if (l_xcs == NULL || r_xcs == NULL || l_d_xcs == NULL || r_d_xcs == NULL) { - U_LOG_E("Invalid swap chain for projection layer!"); - return false; - } - - if (xdev == NULL) { - U_LOG_E("Invalid xdev for projection layer!"); - return false; - } - - // Cast away volatile. - struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; - - xrt_comp_layer_stereo_projection_depth(xc, xdev, l_xcs, r_xcs, l_d_xcs, r_d_xcs, data); - - return true; -} - -static bool -do_single(struct xrt_compositor *xc, - volatile struct ipc_client_state *ics, - volatile struct ipc_layer_entry *layer, - uint32_t i, - const char *name, - struct xrt_device **out_xdev, - struct xrt_swapchain **out_xcs, - struct xrt_layer_data **out_data) -{ - uint32_t device_id = layer->xdev_id; - uint32_t sci = layer->swapchain_ids[0]; - - struct xrt_device *xdev = get_xdev(ics, device_id); - struct xrt_swapchain *xcs = ics->xscs[sci]; - - if (xcs == NULL) { - U_LOG_E("Invalid swapchain for '%u' layer, '%s'!", i, name); - return false; - } - - if (xdev == NULL) { - U_LOG_E("Invalid xdev for '%u' layer, '%s'!", i, name); - return false; - } - - // Cast away volatile. - struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; - - *out_xdev = xdev; - *out_xcs = xcs; - *out_data = data; - - return true; -} - -static bool -_update_quad_layer(struct xrt_compositor *xc, - volatile struct ipc_client_state *ics, - volatile struct ipc_layer_entry *layer, - uint32_t i) -{ - struct xrt_device *xdev; - struct xrt_swapchain *xcs; - struct xrt_layer_data *data; - - if (!do_single(xc, ics, layer, i, "quad", &xdev, &xcs, &data)) { - return false; - } - - xrt_comp_layer_quad(xc, xdev, xcs, data); - - return true; -} - -static bool -_update_cube_layer(struct xrt_compositor *xc, - volatile struct ipc_client_state *ics, - volatile struct ipc_layer_entry *layer, - uint32_t i) -{ - struct xrt_device *xdev; - struct xrt_swapchain *xcs; - struct xrt_layer_data *data; - - if (!do_single(xc, ics, layer, i, "cube", &xdev, &xcs, &data)) { - return false; - } - - xrt_comp_layer_cube(xc, xdev, xcs, data); - - return true; -} - -static bool -_update_cylinder_layer(struct xrt_compositor *xc, - volatile struct ipc_client_state *ics, - volatile struct ipc_layer_entry *layer, - uint32_t i) -{ - struct xrt_device *xdev; - struct xrt_swapchain *xcs; - struct xrt_layer_data *data; - - if (!do_single(xc, ics, layer, i, "cylinder", &xdev, &xcs, &data)) { - return false; - } - - xrt_comp_layer_cylinder(xc, xdev, xcs, data); - - return true; -} - -static bool -_update_equirect1_layer(struct xrt_compositor *xc, - volatile struct ipc_client_state *ics, - volatile struct ipc_layer_entry *layer, - uint32_t i) -{ - struct xrt_device *xdev; - struct xrt_swapchain *xcs; - struct xrt_layer_data *data; - - if (!do_single(xc, ics, layer, i, "equirect1", &xdev, &xcs, &data)) { - return false; - } - - xrt_comp_layer_equirect1(xc, xdev, xcs, data); - - return true; -} - -static bool -_update_equirect2_layer(struct xrt_compositor *xc, - volatile struct ipc_client_state *ics, - volatile struct ipc_layer_entry *layer, - uint32_t i) -{ - struct xrt_device *xdev; - struct xrt_swapchain *xcs; - struct xrt_layer_data *data; - - if (!do_single(xc, ics, layer, i, "equirect2", &xdev, &xcs, &data)) { - return false; - } - - xrt_comp_layer_equirect2(xc, xdev, xcs, data); - - return true; -} - -static int -_overlay_sort_func(const void *a, const void *b) -{ - struct _z_sort_data *oa = (struct _z_sort_data *)a; - struct _z_sort_data *ob = (struct _z_sort_data *)b; - if (oa->z_order < ob->z_order) { - return -1; - } - if (oa->z_order > ob->z_order) { - return 1; - } - return 0; -} - -static bool -_update_layers(struct ipc_server *s, struct xrt_compositor *xc) -{ - IPC_TRACE_MARKER(); - - struct _z_sort_data z_data[IPC_MAX_CLIENTS]; - - // initialise, and fill in overlay app data - for (int32_t i = 0; i < IPC_MAX_CLIENTS; i++) { - volatile struct ipc_client_state *ics = &s->threads[i].ics; - z_data[i].index = -1; - z_data[i].z_order = -1; - // we need to create a list of overlay applications, sorted by z - if (ics->client_state.session_overlay) { - if (ics->client_state.session_active) { - z_data[i].index = i; - z_data[i].z_order = ics->client_state.z_order; - } - } - } - - // ensure our primary application is enabled, - // and rendered first in the stack - if (s->active_client_index >= 0) { - z_data[s->active_client_index].index = s->active_client_index; - z_data[s->active_client_index].z_order = INT32_MIN; - } - - // sort the stack array - qsort(z_data, IPC_MAX_CLIENTS, sizeof(struct _z_sort_data), _overlay_sort_func); - - // render the layer stack - for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { - struct _z_sort_data *zd = &z_data[i]; - if (zd->index < 0) { - continue; - } - - volatile struct ipc_client_state *ics = &s->threads[zd->index].ics; - - for (uint32_t j = 0; j < ics->render_state.num_layers; j++) { - volatile struct ipc_layer_entry *layer = &ics->render_state.layers[j]; - - switch (layer->data.type) { - case XRT_LAYER_STEREO_PROJECTION: - if (!_update_projection_layer(xc, ics, layer, i)) { - return false; - } - break; - case XRT_LAYER_STEREO_PROJECTION_DEPTH: - if (!_update_projection_layer_depth(xc, ics, layer, i)) { - return false; - } - break; - case XRT_LAYER_QUAD: - if (!_update_quad_layer(xc, ics, layer, i)) { - return false; - } - break; - case XRT_LAYER_CUBE: - if (!_update_cube_layer(xc, ics, layer, i)) { - return false; - } - break; - case XRT_LAYER_CYLINDER: - if (!_update_cylinder_layer(xc, ics, layer, i)) { - return false; - } - break; - case XRT_LAYER_EQUIRECT1: - if (!_update_equirect1_layer(xc, ics, layer, i)) { - return false; - } - break; - case XRT_LAYER_EQUIRECT2: - if (!_update_equirect2_layer(xc, ics, layer, i)) { - return false; - } - break; - default: U_LOG_E("Unhandled layer type '%i'!", layer->data.type); break; - } - } - } - - return true; -} - -static void -broadcast_timings(struct ipc_server *s, - uint64_t predicted_display_time_ns, - uint64_t predicted_display_period_ns, - uint64_t diff_ns) -{ - IPC_TRACE_MARKER(); - - os_mutex_lock(&s->global_state_lock); - - // Broadcast the new timing information to the helpers. - for (size_t i = 0; i < ARRAY_SIZE(s->threads); i++) { - struct u_rt_helper *urth = (struct u_rt_helper *)&s->threads[i].ics.urth; - u_rt_helper_new_sample( // - urth, // - predicted_display_time_ns, // - predicted_display_period_ns, // - diff_ns); // - } - - os_mutex_unlock(&s->global_state_lock); -} - static int main_loop(struct ipc_server *s) { - struct xrt_compositor *xc = &s->xcn->base; - - // make sure all our client connections have a handle to the - // compositor and consistent initial state - while (s->running) { - int64_t frame_id; - uint64_t predicted_display_time_ns; - uint64_t predicted_display_period_ns; + os_nanosleep(U_TIME_1S_IN_NS / 20); - xrt_comp_wait_frame(xc, &frame_id, &predicted_display_time_ns, &predicted_display_period_ns); - - uint64_t now_ns = os_monotonic_get_ns(); - uint64_t diff_ns = predicted_display_time_ns - now_ns; - - broadcast_timings(s, predicted_display_time_ns, predicted_display_period_ns, diff_ns); - - xrt_comp_begin_frame(xc, frame_id); - xrt_comp_layer_begin(xc, frame_id, 0, 0); - - _update_layers(s, xc); - - xrt_comp_layer_commit(xc, frame_id, XRT_GRAPHICS_SYNC_HANDLE_INVALID); - - // Check polling last, so we know we have valid timing data. + // Check polling. ipc_server_mainloop_poll(s, &s->ml); } return 0; } - static void -handle_overlay_client_events(volatile struct ipc_client_state *ics, int active_id, int prev_active_id) -{ - // this is an overlay session. - if (ics->client_state.session_overlay) { - - // switch between main applications - if (active_id >= 0 && prev_active_id >= 0) { - transition_overlay_visibility(ics, false); - transition_overlay_visibility(ics, true); - } - - // switch from idle to active application - if (active_id >= 0 && prev_active_id < 0) { - transition_overlay_visibility(ics, true); - } - - // switch from active application to idle - if (active_id < 0 && prev_active_id >= 0) { - transition_overlay_visibility(ics, false); - } - } -} - -static void -handle_focused_client_events(volatile struct ipc_client_state *ics, int active_id, int prev_active_id) -{ - - // if our prev active id is -1 and our cur active id is -1, we - // can bail out early - - if (active_id == -1 && prev_active_id == -1) { - return; - } - - // set visibility/focus to false on all applications - ics->client_state.session_focused = false; - ics->client_state.session_visible = false; - - // do we have a primary application? - if (active_id >= 0) { - - // if we are an overlay, we are always visible - // if we have a primary application - if (ics->client_state.session_overlay) { - ics->client_state.session_visible = true; - } - - // set visible + focused if we are the primary - // application - if (ics->server_thread_index == active_id) { - ics->client_state.session_visible = true; - ics->client_state.session_focused = true; - } - send_client_state(ics); - return; - } - - // no primary application, set all overlays to synchronised - // state - if (ics->client_state.session_overlay) { - ics->client_state.session_focused = false; - ics->client_state.session_visible = false; - send_client_state(ics); - } -} - -void init_server_state(struct ipc_server *s) { - // set up initial state for global vars, and each client state - s->active_client_index = -1; // we start off with no active client. - s->last_active_client_index = -1; + s->global_state.active_client_index = -1; // we start off with no active client. + s->global_state.last_active_client_index = -1; s->current_slot_index = 0; for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { volatile struct ipc_client_state *ics = &s->threads[i].ics; ics->server = s; - ics->xc = &s->xcn->base; ics->server_thread_index = -1; } } @@ -977,26 +493,105 @@ init_server_state(struct ipc_server *s) /* * - * Exported functions. + * Client management functions. * */ -void -update_server_state(struct ipc_server *s) +static void +handle_overlay_client_events(volatile struct ipc_client_state *ics, int active_id, int prev_active_id) { - // multiple threads could call this at the same time. - os_mutex_lock(&s->global_state_lock); + // Is an overlay session? + if (!ics->client_state.session_overlay) { + return; + } + // Does this client have a compositor yet? + if (ics->xc) { + return; + } + + // Switch between main applications + if (active_id >= 0 && prev_active_id >= 0) { + xrt_syscomp_set_main_app_visibility(ics->server->xsysc, ics->xc, false); + xrt_syscomp_set_main_app_visibility(ics->server->xsysc, ics->xc, true); + } + + // Switch from idle to active application + if (active_id >= 0 && prev_active_id < 0) { + xrt_syscomp_set_main_app_visibility(ics->server->xsysc, ics->xc, true); + } + + // Switch from active application to idle + if (active_id < 0 && prev_active_id >= 0) { + xrt_syscomp_set_main_app_visibility(ics->server->xsysc, ics->xc, false); + } +} + +static void +handle_focused_client_events(volatile struct ipc_client_state *ics, int active_id, int prev_active_id) +{ + // Set start z_order at the bottom. + int64_t z_order = INT64_MIN; + + // Set visibility/focus to false on all applications. + bool focused = false; + bool visible = false; + + // Set visible + focused if we are the primary application + if (ics->server_thread_index == active_id) { + visible = true; + focused = true; + z_order = INT64_MIN; + } + + // Set all overlays to always active and focused. + if (ics->client_state.session_overlay) { + visible = true; + focused = true; + z_order = ics->client_state.z_order; + } + + ics->client_state.session_visible = visible; + ics->client_state.session_focused = focused; + ics->client_state.z_order = z_order; + + if (ics->xc != NULL) { + xrt_syscomp_set_state(ics->server->xsysc, ics->xc, visible, focused); + xrt_syscomp_set_z_order(ics->server->xsysc, ics->xc, z_order); + } +} + +static void +flush_state_to_all_clients_locked(struct ipc_server *s) +{ + for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + volatile struct ipc_client_state *ics = &s->threads[i].ics; + + // Not running? + if (ics->server_thread_index < 0) { + continue; + } + + handle_focused_client_events(ics, s->global_state.active_client_index, + s->global_state.last_active_client_index); + handle_overlay_client_events(ics, s->global_state.active_client_index, + s->global_state.last_active_client_index); + } +} + +static void +update_server_state_locked(struct ipc_server *s) +{ // if our client that is set to active is still active, // and it is the same as our last active client, we can // early-out, as no events need to be sent - if (s->active_client_index >= 0) { + if (s->global_state.active_client_index >= 0) { - volatile struct ipc_client_state *ics = &s->threads[s->active_client_index].ics; + volatile struct ipc_client_state *ics = &s->threads[s->global_state.active_client_index].ics; - if (ics->client_state.session_active && s->active_client_index == s->last_active_client_index) { - os_mutex_unlock(&s->global_state_lock); + if (ics->client_state.session_active && + s->global_state.active_client_index == s->global_state.last_active_client_index) { return; } } @@ -1026,33 +621,101 @@ update_server_state(struct ipc_server *s) // if our currently-set active primary application is not // actually active/displayable, use the fallback application // instead. - volatile struct ipc_client_state *ics = &s->threads[s->active_client_index].ics; - if (!(ics->client_state.session_overlay == false && s->active_client_index >= 0 && + volatile struct ipc_client_state *ics = &s->threads[s->global_state.active_client_index].ics; + if (!(ics->client_state.session_overlay == false && s->global_state.active_client_index >= 0 && ics->client_state.session_active)) { - s->active_client_index = fallback_active_application; + s->global_state.active_client_index = fallback_active_application; } // if we have no applications to fallback to, enable the idle // wallpaper. if (set_idle) { - s->active_client_index = -1; + s->global_state.active_client_index = -1; } - for (uint32_t i = 0; i < IPC_MAX_CLIENTS; i++) { + flush_state_to_all_clients_locked(s); - volatile struct ipc_client_state *ics = &s->threads[i].ics; - if (ics->server_thread_index >= 0) { + s->global_state.last_active_client_index = s->global_state.active_client_index; +} - handle_focused_client_events(ics, s->active_client_index, s->last_active_client_index); - handle_overlay_client_events(ics, s->active_client_index, s->last_active_client_index); - } +/* + * + * Exported functions. + * + */ + +void +ipc_server_set_active_client(struct ipc_server *s, int client_id) +{ + os_mutex_lock(&s->global_state.lock); + + if (client_id == s->global_state.active_client_index) { + os_mutex_unlock(&s->global_state.lock); + return; } - s->last_active_client_index = s->active_client_index; - os_mutex_unlock(&s->global_state_lock); + + os_mutex_unlock(&s->global_state.lock); +} + +void +ipc_server_activate_session(volatile struct ipc_client_state *ics) +{ + struct ipc_server *s = ics->server; + + // Already active, noop. + if (ics->client_state.session_active) { + return; + } + + assert(ics->server_thread_index >= 0); + + // Multiple threads could call this at the same time. + os_mutex_lock(&s->global_state.lock); + + ics->client_state.session_active = true; + + if (ics->client_state.session_overlay) { + // For new active overlay sessions only update this session. + handle_focused_client_events(ics, s->global_state.active_client_index, + s->global_state.last_active_client_index); + handle_overlay_client_events(ics, s->global_state.active_client_index, + s->global_state.last_active_client_index); + } else { + // For new active regular sessions update all clients. + update_server_state_locked(s); + } + + os_mutex_unlock(&s->global_state.lock); +} + +void +ipc_server_deactivate_session(volatile struct ipc_client_state *ics) +{ + struct ipc_server *s = ics->server; + + // Multiple threads could call this at the same time. + os_mutex_lock(&s->global_state.lock); + + ics->client_state.session_active = false; + + update_server_state_locked(s); + + os_mutex_unlock(&s->global_state.lock); +} + +void +ipc_server_update_state(struct ipc_server *s) +{ + // Multiple threads could call this at the same time. + os_mutex_lock(&s->global_state.lock); + + update_server_state_locked(s); + + os_mutex_unlock(&s->global_state.lock); } #ifndef XRT_OS_ANDROID diff --git a/src/xrt/ipc/shared/ipc_protocol.h b/src/xrt/ipc/shared/ipc_protocol.h index 2da3add08..4625b697d 100644 --- a/src/xrt/ipc/shared/ipc_protocol.h +++ b/src/xrt/ipc/shared/ipc_protocol.h @@ -151,6 +151,7 @@ struct ipc_layer_entry */ struct ipc_layer_slot { + uint64_t display_time_ns; enum xrt_blend_mode env_blend_mode; uint32_t num_layers; struct ipc_layer_entry layers[IPC_MAX_LAYERS]; diff --git a/src/xrt/ipc/shared/proto.json b/src/xrt/ipc/shared/proto.json index 9da7a32c3..cdd6dd936 100644 --- a/src/xrt/ipc/shared/proto.json +++ b/src/xrt/ipc/shared/proto.json @@ -72,13 +72,12 @@ ] }, - "compositor_wait_frame": { + "compositor_predict_frame": { "out": [ {"name": "frame_id", "type": "int64_t"}, - {"name": "predicted_display_time", "type": "uint64_t"}, {"name": "wake_up_time", "type": "uint64_t"}, - {"name": "predicted_display_period", "type": "uint64_t"}, - {"name": "min_display_period", "type": "uint64_t"} + {"name": "predicted_display_time", "type": "uint64_t"}, + {"name": "predicted_display_period", "type": "uint64_t"} ] }, From d74539639683c3aeff8ac1bdae59e35f58cd5486 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 2 Apr 2021 17:54:01 +0100 Subject: [PATCH 304/883] u/ft: Tweak frame timing numbers --- src/xrt/auxiliary/util/u_timing_frame.c | 68 ++++++++++++++++++------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_frame.c b/src/xrt/auxiliary/util/u_timing_frame.c index 2fb20ad46..a9c433514 100644 --- a/src/xrt/auxiliary/util/u_timing_frame.c +++ b/src/xrt/auxiliary/util/u_timing_frame.c @@ -57,6 +57,8 @@ struct frame uint64_t when_began_ns; uint64_t when_submitted_ns; uint64_t when_infoed_ns; + uint64_t current_app_time_ns; + uint64_t expected_done_time_ns; //!< When we expect the compositor to be done with it's frame. uint64_t desired_present_time_ns; uint64_t predicted_display_time_ns; uint64_t present_margin_ns; @@ -87,6 +89,11 @@ struct display_timing */ uint64_t app_time_ns; + /*! + * The amount of time that the application needs to render frame. + */ + uint64_t padding_time_ns; + /*! * Used to generate frame IDs. */ @@ -111,7 +118,7 @@ struct display_timing /*! * The target amount of GPU margin we want. */ - uint64_t adjust_min_margin_ns; + uint64_t min_margin_ns; /*! * Frame store. @@ -145,6 +152,12 @@ get_procent_of_time(uint64_t time_ns, uint32_t fraction_procent) return time_s_to_ns(time_ns_to_s(time_ns) * fraction); } +static uint64_t +calc_total_app_time(struct display_timing *dt) +{ + return dt->app_time_ns + dt->min_margin_ns; +} + static uint64_t calc_display_time_from_present_time(struct display_timing *dt, uint64_t desired_present_time_ns) { @@ -213,7 +226,6 @@ do_clean_slate_frame(struct display_timing *dt) uint64_t the_time_ns = os_monotonic_get_ns() + dt->frame_period_ns * 10; f->when_predict_ns = now_ns; f->desired_present_time_ns = the_time_ns; - f->predicted_display_time_ns = calc_display_time_from_present_time(dt, the_time_ns); return f; } @@ -222,7 +234,7 @@ static struct frame * walk_forward_through_frames(struct display_timing *dt, uint64_t last_present_time_ns) { uint64_t now_ns = os_monotonic_get_ns(); - uint64_t from_time_ns = now_ns + dt->app_time_ns; + uint64_t from_time_ns = now_ns + calc_total_app_time(dt); uint64_t desired_present_time_ns = last_present_time_ns + dt->frame_period_ns; while (desired_present_time_ns <= from_time_ns) { @@ -242,7 +254,6 @@ walk_forward_through_frames(struct display_timing *dt, uint64_t last_present_tim struct frame *f = create_frame(dt, STATE_PREDICTED); f->when_predict_ns = now_ns; f->desired_present_time_ns = desired_present_time_ns; - f->predicted_display_time_ns = calc_display_time_from_present_time(dt, desired_present_time_ns); return f; } @@ -291,7 +302,9 @@ predict_next_frame(struct display_timing *dt) f = walk_forward_through_frames(dt, last_predicted->predicted_display_time_ns); } - f->wake_up_time_ns = f->desired_present_time_ns - dt->app_time_ns; + f->predicted_display_time_ns = calc_display_time_from_present_time(dt, f->desired_present_time_ns); + f->wake_up_time_ns = f->desired_present_time_ns - calc_total_app_time(dt); + f->current_app_time_ns = dt->app_time_ns; return f; } @@ -315,18 +328,18 @@ adjust_app_time(struct display_timing *dt, struct frame *f) return; } - // We want the GPU work to stop at adjust_min_margin_ns. + // We want the GPU work to stop at min_margin_ns. if (is_within_of_each_other( // f->present_margin_ns, // - dt->adjust_min_margin_ns, // + dt->min_margin_ns, // dt->adjust_non_miss_ns)) { // Nothing to do, the GPU ended it's work +-adjust_non_miss_ns - // of adjust_min_margin_ns before the present started. + // of min_margin_ns before the present started. return; } // We didn't miss the frame but we were outside the range adjust the app time. - if (f->present_margin_ns > dt->adjust_min_margin_ns) { + if (f->present_margin_ns > dt->min_margin_ns) { // Approach the present time. dt->app_time_ns -= dt->adjust_non_miss_ns; } else { @@ -479,20 +492,21 @@ u_frame_timing_display_timing_create(uint64_t estimated_frame_period_ns, struct // Just a wild guess. dt->present_offset_ns = U_TIME_1MS_IN_NS * 4; - // Start at 40% of the frame time, will be adjusted. - dt->app_time_ns = get_procent_of_time(estimated_frame_period_ns, 40); - // Max app time at 80%, write a better compositor. - dt->app_time_max_ns = get_procent_of_time(estimated_frame_period_ns, 80); - // When missing back off at 10% increments - dt->adjust_missed_ns = get_procent_of_time(estimated_frame_period_ns, 10); - // When not missing frames but adjusting app time do it at 2% increments + // Start at this of frame time. + dt->app_time_ns = get_procent_of_time(estimated_frame_period_ns, 10); + // Max app time, write a better compositor. + dt->app_time_max_ns = get_procent_of_time(estimated_frame_period_ns, 30); + // When missing, back off in these increments + dt->adjust_missed_ns = get_procent_of_time(estimated_frame_period_ns, 4); + // When not missing frames but adjusting app time at these increments dt->adjust_non_miss_ns = get_procent_of_time(estimated_frame_period_ns, 2); - // Min margin at 8% - dt->adjust_min_margin_ns = get_procent_of_time(estimated_frame_period_ns, 8); + // Extra margin that is added to app time. + dt->min_margin_ns = get_procent_of_time(estimated_frame_period_ns, 8); *out_uft = &dt->base; - FT_LOG_I("Created display timing"); + double estimated_frame_period_ms = ns_to_ms(estimated_frame_period_ns); + FT_LOG_I("Created display timing (%.2fms)", estimated_frame_period_ms); return XRT_SUCCESS; } @@ -509,6 +523,7 @@ u_frame_timing_display_timing_create(uint64_t estimated_frame_period_ns, struct #define TID_INFO 45 #define TID_FRAME 46 #define TID_ERROR 47 +#define TID_APP 48 XRT_MAYBE_UNUSED static void trace_event(FILE *file, const char *name, uint64_t when_ns) @@ -659,6 +674,9 @@ trace_frame(FILE *file, struct frame *f) if (f->actual_present_time_ns != f->earliest_present_time_ns) { trace_event_id(file, "flip", f->frame_id, f->actual_present_time_ns); } + + trace_begin_id(file, TID_APP, "app", f->frame_id, "app", f->wake_up_time_ns); + trace_end(file, TID_APP, f->wake_up_time_ns + f->current_app_time_ns); } void @@ -730,5 +748,17 @@ u_timing_frame_write_json_metadata(FILE *file) "\t\t\t}\n" "\t\t}", TID_ERROR); + fprintf(file, + ",\n" + "\t\t{\n" + "\t\t\t\"ph\": \"M\",\n" + "\t\t\t\"name\": \"thread_name\",\n" + "\t\t\t\"pid\": 42,\n" + "\t\t\t\"tid\": %u,\n" + "\t\t\t\"args\": {\n" + "\t\t\t\t\"name\": \"6 App time\"\n" + "\t\t\t}\n" + "\t\t}", + TID_APP); fflush(file); } From 5dbcca65c544985bc54ee1134604d13055691dc3 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 2 Apr 2021 17:54:22 +0100 Subject: [PATCH 305/883] u/tr: Refactor rendering timing code --- src/xrt/auxiliary/util/u_timing_render.c | 105 +++++++++++------- src/xrt/auxiliary/util/u_timing_render.h | 41 ++++--- .../compositor/multi/comp_multi_compositor.c | 21 ++-- src/xrt/compositor/multi/comp_multi_system.c | 48 +++++++- 4 files changed, 147 insertions(+), 68 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index a780d3714..f6824b1cd 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -42,25 +42,57 @@ min_period(const struct u_rt_helper *urth) } static uint64_t -last_displayed(const struct u_rt_helper *urth) +last_sample_displayed(const struct u_rt_helper *urth) { return urth->last_input.predicted_display_time_ns; } static uint64_t -get_last_input_plus_period_at_least_greater_then(struct u_rt_helper *urth, uint64_t then_ns) +last_return_predicted_display(const struct u_rt_helper *urth) { - uint64_t val = last_displayed(urth); + return urth->last_returned_ns; +} - if (min_period(urth) == 0) { - return then_ns; +static uint64_t +total_app_time_ns(const struct u_rt_helper *urth) +{ + return urth->app.cpu_time_ns + urth->app.draw_time_ns; +} + +static uint64_t +total_app_and_compositor_time_ns(const struct u_rt_helper *urth) +{ + return total_app_time_ns(urth) + urth->app.margin_ns + urth->last_input.extra_ns; +} + +static uint64_t +predict_display_time(struct u_rt_helper *urth) +{ + // Now + uint64_t now_ns = os_monotonic_get_ns(); + + // Error checking. + uint64_t period_ns = min_period(urth); + if (period_ns == 0) { + assert(false && "Have not yet received and samples from timing driver."); + return now_ns; } - while (val <= then_ns) { - val += min_period(urth); - assert(val != 0); + // Total app and compositor time to produce a frame + uint64_t app_and_compositor_time_ns = total_app_and_compositor_time_ns(urth); + + // Start from the last time that the driver displayed something. + uint64_t val = last_sample_displayed(urth); + + // Return a time after the last returned display time. + while (val < last_return_predicted_display(urth)) { + val += period_ns; } + // Have to have enough time to perform app work. + while ((val - app_and_compositor_time_ns) <= now_ns) { + val += period_ns; + } return val; } @@ -79,6 +111,10 @@ u_rt_helper_client_clear(struct u_rt_helper *urth) urth->frames[i].state = U_RT_READY; urth->frames[i].frame_id = -1; } + + urth->app.cpu_time_ns = U_TIME_1MS_IN_NS * 2; + urth->app.draw_time_ns = U_TIME_1MS_IN_NS * 2; + urth->app.margin_ns = U_TIME_1MS_IN_NS / 2; } void @@ -91,31 +127,22 @@ u_rt_helper_init(struct u_rt_helper *urth) void u_rt_helper_predict(struct u_rt_helper *urth, int64_t *out_frame_id, - uint64_t *predicted_display_time, - uint64_t *wake_up_time, - uint64_t *predicted_display_period, - uint64_t *min_display_period) + uint64_t *out_wake_up_time, + uint64_t *out_predicted_display_time, + uint64_t *out_predicted_display_period) { int64_t frame_id = ++urth->frame_counter; *out_frame_id = frame_id; DEBUG_PRINT_FRAME_ID(); - uint64_t at_least_ns = os_monotonic_get_ns(); - - // Don't return a time before the last returned type. - if (at_least_ns < urth->last_returned_ns) { - at_least_ns = urth->last_returned_ns; - } - - uint64_t predict_ns = get_last_input_plus_period_at_least_greater_then(urth, at_least_ns); + uint64_t predict_ns = predict_display_time(urth); urth->last_returned_ns = predict_ns; - *wake_up_time = predict_ns - min_period(urth); - *predicted_display_time = predict_ns; - *predicted_display_period = min_period(urth); - *min_display_period = min_period(urth); + *out_wake_up_time = predict_ns - total_app_and_compositor_time_ns(urth); + *out_predicted_display_time = predict_ns; + *out_predicted_display_period = min_period(urth); size_t index = GET_INDEX_FROM_ID(urth, frame_id); assert(urth->frames[index].frame_id == -1); @@ -134,29 +161,29 @@ u_rt_helper_predict(struct u_rt_helper *urth, } void -u_rt_helper_mark_wait_woke(struct u_rt_helper *urth, int64_t frame_id) +u_rt_helper_mark(struct u_rt_helper *urth, int64_t frame_id, enum u_timing_point point, uint64_t when_ns) { DEBUG_PRINT_FRAME_ID(); size_t index = GET_INDEX_FROM_ID(urth, frame_id); assert(urth->frames[index].frame_id == frame_id); - assert(urth->frames[index].state == U_RT_PREDICTED); - urth->frames[index].when.wait_woke_ns = os_monotonic_get_ns(); - urth->frames[index].state = U_RT_WAIT_LEFT; -} + switch (point) { + case U_TIMING_POINT_WAKE_UP: + assert(urth->frames[index].state == U_RT_PREDICTED); -void -u_rt_helper_mark_begin(struct u_rt_helper *urth, int64_t frame_id) -{ - DEBUG_PRINT_FRAME_ID(); + urth->frames[index].when.wait_woke_ns = when_ns; + urth->frames[index].state = U_RT_WAIT_LEFT; + break; + case U_TIMING_POINT_BEGIN: + assert(urth->frames[index].state == U_RT_WAIT_LEFT); - size_t index = GET_INDEX_FROM_ID(urth, frame_id); - assert(urth->frames[index].frame_id == frame_id); - assert(urth->frames[index].state == U_RT_WAIT_LEFT); - - urth->frames[index].when.begin_ns = os_monotonic_get_ns(); - urth->frames[index].state = U_RT_BEGUN; + urth->frames[index].when.begin_ns = os_monotonic_get_ns(); + urth->frames[index].state = U_RT_BEGUN; + break; + case U_TIMING_POINT_SUBMIT: + default: assert(false); + } } void diff --git a/src/xrt/auxiliary/util/u_timing_render.h b/src/xrt/auxiliary/util/u_timing_render.h index 489e98f05..1be3bad3c 100644 --- a/src/xrt/auxiliary/util/u_timing_render.h +++ b/src/xrt/auxiliary/util/u_timing_render.h @@ -11,6 +11,8 @@ #include "xrt/xrt_compiler.h" #include "os/os_time.h" +#include "util/u_timing.h" + #ifdef __cplusplus extern "C" { @@ -57,6 +59,16 @@ struct u_rt_helper int64_t frame_counter; + struct + { + //! App time between wait returning and begin being called. + uint64_t cpu_time_ns; + //! Time between begin and frame rendering completeing. + uint64_t draw_time_ns; + //! Exrta time between end of draw time and when the compositor wakes up. + uint64_t margin_ns; + } app; //!< App statistics. + struct { //! The last display time that the thing driving this helper got. @@ -83,33 +95,32 @@ void u_rt_helper_client_clear(struct u_rt_helper *urth); /*! - * Predict when the client's next rendered frame will be presented, also when - * the client should be woken up from sleeping, its display period and the - * minimum display period that the client might have. + * Predict when the client's next: rendered frame will be display; when the + * client should be woken up from sleeping; and its display period. * * This is called from `xrWaitFrame`, but it does not do any waiting, the caller * should wait till `out_wake_up_time`. + * + * @param urth Render timing helper. + * @param[out] out_frame_id Frame ID of this predicted frame. + * @param[out] out_wake_up_time When the client should be woken up. + * @param[out] out_predicted_display_time Predicted display time. + * @param[out] out_predicted_display_period Predicted display period. */ void u_rt_helper_predict(struct u_rt_helper *urth, int64_t *out_frame_id, - uint64_t *out_predicted_display_time, uint64_t *out_wake_up_time, - uint64_t *out_predicted_display_period, - uint64_t *out_min_display_period); + uint64_t *out_predicted_display_time, + uint64_t *out_predicted_display_period); /*! - * Log when the client woke up after sleeping for the time returned in - * @ref u_rt_helper_predict. This happens inside of `xrWaitFrame`. + * Mark a point on the frame's lifetime. + * + * @see @ref frame-timing. */ void -u_rt_helper_mark_wait_woke(struct u_rt_helper *urth, int64_t frame_id); - -/*! - * The client has started rendering work, see `xrBeginFrame`. - */ -void -u_rt_helper_mark_begin(struct u_rt_helper *urth, int64_t frame_id); +u_rt_helper_mark(struct u_rt_helper *urth, int64_t frame_id, enum u_timing_point point, uint64_t when_ns); /*! * When a frame has been discarded. diff --git a/src/xrt/compositor/multi/comp_multi_compositor.c b/src/xrt/compositor/multi/comp_multi_compositor.c index 3a6e0d80f..facad36d2 100644 --- a/src/xrt/compositor/multi/comp_multi_compositor.c +++ b/src/xrt/compositor/multi/comp_multi_compositor.c @@ -197,15 +197,12 @@ multi_compositor_predict_frame(struct xrt_compositor *xc, os_mutex_lock(&mc->msc->list_and_timing_lock); - uint64_t min_display_period = 0; - - u_rt_helper_predict( // - &mc->urth, // - out_frame_id, // - out_predicted_display_time_ns, // - out_wake_time_ns, // - out_predicted_display_period_ns, // - &min_display_period); // + u_rt_helper_predict( // + &mc->urth, // + out_frame_id, // + out_wake_time_ns, // + out_predicted_display_time_ns, // + out_predicted_display_period_ns); // os_mutex_unlock(&mc->msc->list_and_timing_lock); @@ -225,7 +222,8 @@ multi_compositor_mark_frame(struct xrt_compositor *xc, switch (point) { case XRT_COMPOSITOR_FRAME_POINT_WOKE: os_mutex_lock(&mc->msc->list_and_timing_lock); - u_rt_helper_mark_wait_woke(&mc->urth, frame_id); + uint64_t now_ns = os_monotonic_get_ns(); + u_rt_helper_mark(&mc->urth, frame_id, U_TIMING_POINT_WAKE_UP, now_ns); os_mutex_unlock(&mc->msc->list_and_timing_lock); break; default: assert(false); @@ -256,7 +254,8 @@ multi_compositor_begin_frame(struct xrt_compositor *xc, int64_t frame_id) struct multi_compositor *mc = multi_compositor(xc); os_mutex_lock(&mc->msc->list_and_timing_lock); - u_rt_helper_mark_begin(&mc->urth, frame_id); + uint64_t now_ns = os_monotonic_get_ns(); + u_rt_helper_mark(&mc->urth, frame_id, U_TIMING_POINT_BEGIN, now_ns); os_mutex_unlock(&mc->msc->list_and_timing_lock); return XRT_SUCCESS; diff --git a/src/xrt/compositor/multi/comp_multi_system.c b/src/xrt/compositor/multi/comp_multi_system.c index 5ec7b4373..20fd21f1a 100644 --- a/src/xrt/compositor/multi/comp_multi_system.c +++ b/src/xrt/compositor/multi/comp_multi_system.c @@ -285,6 +285,40 @@ broadcast_timings(struct multi_system_compositor *msc, os_mutex_unlock(&msc->list_and_timing_lock); } +static void +wait_frame(struct xrt_compositor *xc, + int64_t *out_frame_id, + uint64_t *out_wake_time_ns, + uint64_t *out_predicted_gpu_time_ns, + uint64_t *out_predicted_display_time_ns, + uint64_t *out_predicted_display_period_ns) +{ + COMP_TRACE_MARKER(); + + int64_t frame_id = -1; + uint64_t wake_up_time_ns = 0; + + xrt_comp_predict_frame( // + xc, // + &frame_id, // + &wake_up_time_ns, // + out_predicted_gpu_time_ns, // + out_predicted_display_time_ns, // + out_predicted_display_period_ns); // + + uint64_t now_ns = os_monotonic_get_ns(); + if (now_ns < wake_up_time_ns) { + os_nanosleep(wake_up_time_ns - now_ns); + } + + now_ns = os_monotonic_get_ns(); + + xrt_comp_mark_frame(xc, frame_id, XRT_COMPOSITOR_FRAME_POINT_WOKE, now_ns); + + *out_frame_id = frame_id; + *out_wake_time_ns = wake_up_time_ns; +} + static int multi_main_loop(struct multi_system_compositor *msc) { @@ -302,10 +336,18 @@ multi_main_loop(struct multi_system_compositor *msc) os_thread_helper_unlock(&msc->oth); int64_t frame_id; - uint64_t predicted_display_time_ns; - uint64_t predicted_display_period_ns; + uint64_t wake_time_ns = 0; + uint64_t predicted_gpu_time_ns = 0; + uint64_t predicted_display_time_ns = 0; + uint64_t predicted_display_period_ns = 0; - xrt_comp_wait_frame(xc, &frame_id, &predicted_display_time_ns, &predicted_display_period_ns); + wait_frame( // + xc, // + &frame_id, // + &wake_time_ns, // + &predicted_gpu_time_ns, // + &predicted_display_time_ns, // + &predicted_display_period_ns); // uint64_t now_ns = os_monotonic_get_ns(); uint64_t diff_ns = predicted_display_time_ns - now_ns; From 971f88f34f62af70d665758f614a310f6033ae3e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 2 Apr 2021 19:18:31 +0100 Subject: [PATCH 306/883] u/ft: Rename frame timing functions --- src/xrt/auxiliary/util/u_timing.h | 36 ++++++++--------- src/xrt/auxiliary/util/u_timing_fake.c | 2 +- src/xrt/auxiliary/util/u_timing_frame.c | 12 +++--- src/xrt/auxiliary/util/u_trace_marker.h | 4 +- .../compositor/main/comp_target_swapchain.c | 40 +++++++++---------- src/xrt/targets/cli/cli_cmd_trace.c | 4 +- 6 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing.h b/src/xrt/auxiliary/util/u_timing.h index fce60022e..09709e18d 100644 --- a/src/xrt/auxiliary/util/u_timing.h +++ b/src/xrt/auxiliary/util/u_timing.h @@ -119,14 +119,14 @@ struct u_frame_timing * @ingroup aux_timing */ static inline void -u_frame_timing_predict(struct u_frame_timing *uft, - int64_t *out_frame_id, - uint64_t *out_wake_up_time_ns, - uint64_t *out_desired_present_time_ns, - uint64_t *out_present_slop_ns, - uint64_t *out_predicted_display_time_ns, - uint64_t *out_predicted_display_period_ns, - uint64_t *out_min_display_period_ns) +u_ft_predict(struct u_frame_timing *uft, + int64_t *out_frame_id, + uint64_t *out_wake_up_time_ns, + uint64_t *out_desired_present_time_ns, + uint64_t *out_present_slop_ns, + uint64_t *out_predicted_display_time_ns, + uint64_t *out_predicted_display_period_ns, + uint64_t *out_min_display_period_ns) { uft->predict(uft, // out_frame_id, // @@ -147,7 +147,7 @@ u_frame_timing_predict(struct u_frame_timing *uft, * @ingroup aux_timing */ static inline void -u_frame_timing_mark_point(struct u_frame_timing *uft, enum u_timing_point point, int64_t frame_id, uint64_t when_ns) +u_ft_mark_point(struct u_frame_timing *uft, enum u_timing_point point, int64_t frame_id, uint64_t when_ns) { uft->mark_point(uft, point, frame_id, when_ns); } @@ -161,12 +161,12 @@ u_frame_timing_mark_point(struct u_frame_timing *uft, enum u_timing_point point, * @ingroup aux_timing */ static inline void -u_frame_timing_info(struct u_frame_timing *uft, - int64_t frame_id, - uint64_t desired_present_time_ns, - uint64_t actual_present_time_ns, - uint64_t earliest_present_time_ns, - uint64_t present_margin_ns) +u_ft_info(struct u_frame_timing *uft, + int64_t frame_id, + uint64_t desired_present_time_ns, + uint64_t actual_present_time_ns, + uint64_t earliest_present_time_ns, + uint64_t present_margin_ns) { uft->info(uft, frame_id, desired_present_time_ns, actual_present_time_ns, earliest_present_time_ns, present_margin_ns); @@ -182,7 +182,7 @@ u_frame_timing_info(struct u_frame_timing *uft, * @ingroup aux_timing */ static inline void -u_frame_timing_destroy(struct u_frame_timing **uft_ptr) +u_ft_destroy(struct u_frame_timing **uft_ptr) { struct u_frame_timing *uft = *uft_ptr; if (uft == NULL) { @@ -206,7 +206,7 @@ u_frame_timing_destroy(struct u_frame_timing **uft_ptr) * @ingroup aux_timing */ xrt_result_t -u_frame_timing_display_timing_create(uint64_t estimated_frame_period_ns, struct u_frame_timing **out_uft); +u_ft_display_timing_create(uint64_t estimated_frame_period_ns, struct u_frame_timing **out_uft); /*! * When you can not get display timing information use this. @@ -214,7 +214,7 @@ u_frame_timing_display_timing_create(uint64_t estimated_frame_period_ns, struct * @ingroup aux_timing */ xrt_result_t -u_frame_timing_fake_create(uint64_t estimated_frame_period_ns, struct u_frame_timing **out_uft); +u_ft_fake_create(uint64_t estimated_frame_period_ns, struct u_frame_timing **out_uft); #ifdef __cplusplus diff --git a/src/xrt/auxiliary/util/u_timing_fake.c b/src/xrt/auxiliary/util/u_timing_fake.c index b18dbe6a1..211bcf511 100644 --- a/src/xrt/auxiliary/util/u_timing_fake.c +++ b/src/xrt/auxiliary/util/u_timing_fake.c @@ -166,7 +166,7 @@ ft_destroy(struct u_frame_timing *uft) */ xrt_result_t -u_frame_timing_fake_create(uint64_t estimated_frame_period_ns, struct u_frame_timing **out_uft) +u_ft_fake_create(uint64_t estimated_frame_period_ns, struct u_frame_timing **out_uft) { struct fake_timing *ft = U_TYPED_CALLOC(struct fake_timing); ft->base.predict = ft_predict; diff --git a/src/xrt/auxiliary/util/u_timing_frame.c b/src/xrt/auxiliary/util/u_timing_frame.c index a9c433514..e3bc102f7 100644 --- a/src/xrt/auxiliary/util/u_timing_frame.c +++ b/src/xrt/auxiliary/util/u_timing_frame.c @@ -329,9 +329,9 @@ adjust_app_time(struct display_timing *dt, struct frame *f) } // We want the GPU work to stop at min_margin_ns. - if (is_within_of_each_other( // - f->present_margin_ns, // - dt->min_margin_ns, // + if (is_within_of_each_other( // + f->present_margin_ns, // + dt->min_margin_ns, // dt->adjust_non_miss_ns)) { // Nothing to do, the GPU ended it's work +-adjust_non_miss_ns // of min_margin_ns before the present started. @@ -480,7 +480,7 @@ dt_destroy(struct u_frame_timing *uft) } xrt_result_t -u_frame_timing_display_timing_create(uint64_t estimated_frame_period_ns, struct u_frame_timing **out_uft) +u_ft_display_timing_create(uint64_t estimated_frame_period_ns, struct u_frame_timing **out_uft) { struct display_timing *dt = U_TYPED_CALLOC(struct display_timing); dt->base.predict = dt_predict; @@ -680,13 +680,13 @@ trace_frame(FILE *file, struct frame *f) } void -u_timing_frame_write_json(FILE *file, void *data) +u_ft_write_json(FILE *file, void *data) { trace_frame(file, (struct frame *)data); } void -u_timing_frame_write_json_metadata(FILE *file) +u_ft_write_json_metadata(FILE *file) { fprintf(file, ",\n" diff --git a/src/xrt/auxiliary/util/u_trace_marker.h b/src/xrt/auxiliary/util/u_trace_marker.h index 1518d6776..4818ee36d 100644 --- a/src/xrt/auxiliary/util/u_trace_marker.h +++ b/src/xrt/auxiliary/util/u_trace_marker.h @@ -54,10 +54,10 @@ extern int u_trace_comp_fd; */ void -u_timing_frame_write_json(FILE *file, void *data); +u_ft_write_json(FILE *file, void *data); void -u_timing_frame_write_json_metadata(FILE *file); +u_ft_write_json_metadata(FILE *file); /* diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index 8dbf95333..253c00cb0 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -98,9 +98,9 @@ comp_target_swapchain_create_images(struct comp_target *ct, // Some platforms really don't like the display_timing code. bool use_display_timing_if_available = cts->timing_usage == COMP_TARGET_USE_DISPLAY_IF_AVAILABLE; if (cts->uft == NULL && use_display_timing_if_available && vk->has_GOOGLE_display_timing) { - u_frame_timing_display_timing_create(ct->c->settings.nominal_frame_interval_ns, &cts->uft); + u_ft_display_timing_create(ct->c->settings.nominal_frame_interval_ns, &cts->uft); } else if (cts->uft == NULL) { - u_frame_timing_fake_create(ct->c->settings.nominal_frame_interval_ns, &cts->uft); + u_ft_fake_create(ct->c->settings.nominal_frame_interval_ns, &cts->uft); } // Free old image views. @@ -523,14 +523,14 @@ comp_target_swapchain_calc_frame_timings(struct comp_target *ct, uint64_t predicted_display_period_ns = 0; uint64_t min_display_period_ns = 0; - u_frame_timing_predict(cts->uft, // - &frame_id, // - &wake_up_time_ns, // - &desired_present_time_ns, // - &present_slop_ns, // - &predicted_display_time_ns, // - &predicted_display_period_ns, // - &min_display_period_ns); // + u_ft_predict(cts->uft, // + &frame_id, // + &wake_up_time_ns, // + &desired_present_time_ns, // + &present_slop_ns, // + &predicted_display_time_ns, // + &predicted_display_period_ns, // + &min_display_period_ns); // cts->current_frame_id = frame_id; @@ -552,13 +552,13 @@ comp_target_swapchain_mark_timing_point(struct comp_target *ct, switch (point) { case COMP_TARGET_TIMING_POINT_WAKE_UP: - u_frame_timing_mark_point(cts->uft, U_TIMING_POINT_WAKE_UP, cts->current_frame_id, when_ns); + u_ft_mark_point(cts->uft, U_TIMING_POINT_WAKE_UP, cts->current_frame_id, when_ns); break; case COMP_TARGET_TIMING_POINT_BEGIN: - u_frame_timing_mark_point(cts->uft, U_TIMING_POINT_BEGIN, cts->current_frame_id, when_ns); + u_ft_mark_point(cts->uft, U_TIMING_POINT_BEGIN, cts->current_frame_id, when_ns); break; case COMP_TARGET_TIMING_POINT_SUBMIT: - u_frame_timing_mark_point(cts->uft, U_TIMING_POINT_SUBMIT, cts->current_frame_id, when_ns); + u_ft_mark_point(cts->uft, U_TIMING_POINT_SUBMIT, cts->current_frame_id, when_ns); break; default: assert(false); } @@ -597,12 +597,12 @@ comp_target_swapchain_update_timings(struct comp_target *ct) timings); // for (uint32_t i = 0; i < count; i++) { - u_frame_timing_info(cts->uft, // - timings[i].presentID, // - timings[i].desiredPresentTime, // - timings[i].actualPresentTime, // - timings[i].earliestPresentTime, // - timings[i].presentMargin); // + u_ft_info(cts->uft, // + timings[i].presentID, // + timings[i].desiredPresentTime, // + timings[i].actualPresentTime, // + timings[i].earliestPresentTime, // + timings[i].presentMargin); // } free(timings); return VK_SUCCESS; @@ -638,7 +638,7 @@ comp_target_swapchain_cleanup(struct comp_target_swapchain *cts) cts->swapchain.handle = VK_NULL_HANDLE; } - u_frame_timing_destroy(&cts->uft); + u_ft_destroy(&cts->uft); } void diff --git a/src/xrt/targets/cli/cli_cmd_trace.c b/src/xrt/targets/cli/cli_cmd_trace.c index caebf8724..ca0d3a66b 100644 --- a/src/xrt/targets/cli/cli_cmd_trace.c +++ b/src/xrt/targets/cli/cli_cmd_trace.c @@ -140,7 +140,7 @@ handle_data(const char *rest_of_line, size_t len) } switch (type) { - case U_TRACE_DATA_TYPE_TIMING_FRAME: u_timing_frame_write_json(t.file, (void *)data); break; + case U_TRACE_DATA_TYPE_TIMING_FRAME: u_ft_write_json(t.file, (void *)data); break; default: fprintf(stderr, "%.*s\n", (int)len, rest_of_line); break; } } @@ -268,7 +268,7 @@ trace_pipe(int argc, const char **argv) json_w_header(); - u_timing_frame_write_json_metadata(t.file); + u_ft_write_json_metadata(t.file); P(" :: Looping\n"); From 670906ea0e8be459108f01c14fd02ca2d9e7f4f9 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 6 Apr 2021 20:29:18 +0100 Subject: [PATCH 307/883] u/ft: Spelling --- src/xrt/auxiliary/util/u_timing_frame.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_frame.c b/src/xrt/auxiliary/util/u_timing_frame.c index e3bc102f7..41db82a4c 100644 --- a/src/xrt/auxiliary/util/u_timing_frame.c +++ b/src/xrt/auxiliary/util/u_timing_frame.c @@ -146,9 +146,9 @@ ns_to_ms(int64_t t) } static uint64_t -get_procent_of_time(uint64_t time_ns, uint32_t fraction_procent) +get_percent_of_time(uint64_t time_ns, uint32_t fraction_percent) { - double fraction = (double)fraction_procent / 100.0; + double fraction = (double)fraction_percent / 100.0; return time_s_to_ns(time_ns_to_s(time_ns) * fraction); } @@ -493,15 +493,15 @@ u_ft_display_timing_create(uint64_t estimated_frame_period_ns, struct u_frame_ti dt->present_offset_ns = U_TIME_1MS_IN_NS * 4; // Start at this of frame time. - dt->app_time_ns = get_procent_of_time(estimated_frame_period_ns, 10); + dt->app_time_ns = get_percent_of_time(estimated_frame_period_ns, 10); // Max app time, write a better compositor. - dt->app_time_max_ns = get_procent_of_time(estimated_frame_period_ns, 30); + dt->app_time_max_ns = get_percent_of_time(estimated_frame_period_ns, 30); // When missing, back off in these increments - dt->adjust_missed_ns = get_procent_of_time(estimated_frame_period_ns, 4); + dt->adjust_missed_ns = get_percent_of_time(estimated_frame_period_ns, 4); // When not missing frames but adjusting app time at these increments - dt->adjust_non_miss_ns = get_procent_of_time(estimated_frame_period_ns, 2); + dt->adjust_non_miss_ns = get_percent_of_time(estimated_frame_period_ns, 2); // Extra margin that is added to app time. - dt->min_margin_ns = get_procent_of_time(estimated_frame_period_ns, 8); + dt->min_margin_ns = get_percent_of_time(estimated_frame_period_ns, 8); *out_uft = &dt->base; From 8215af5e5c0aabeb78d4249689cd0e2d983947f6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 2 Apr 2021 19:43:01 +0100 Subject: [PATCH 308/883] u/rt: Refactor render timing --- src/xrt/auxiliary/CMakeLists.txt | 1 - src/xrt/auxiliary/meson.build | 1 - src/xrt/auxiliary/util/u_timing.h | 208 ++++++++++++- src/xrt/auxiliary/util/u_timing_render.c | 284 ++++++++++++------ src/xrt/auxiliary/util/u_timing_render.h | 165 ---------- .../compositor/multi/comp_multi_compositor.c | 22 +- src/xrt/compositor/multi/comp_multi_private.h | 4 +- src/xrt/compositor/multi/comp_multi_system.c | 4 +- src/xrt/ipc/server/ipc_server.h | 1 - 9 files changed, 404 insertions(+), 286 deletions(-) delete mode 100644 src/xrt/auxiliary/util/u_timing_render.h diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index 455945fb9..0827faac9 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -152,7 +152,6 @@ set(UTIL_SOURCE_FILES util/u_timing_fake.c util/u_timing_frame.c util/u_timing_render.c - util/u_timing_render.h util/u_trace_marker.c util/u_trace_marker.h util/u_var.cpp diff --git a/src/xrt/auxiliary/meson.build b/src/xrt/auxiliary/meson.build index 42ad0a246..aac2fc21a 100644 --- a/src/xrt/auxiliary/meson.build +++ b/src/xrt/auxiliary/meson.build @@ -58,7 +58,6 @@ lib_aux_util = static_library( 'util/u_timing_fake.c', 'util/u_timing_frame.c', 'util/u_timing_render.c', - 'util/u_timing_render.h', 'util/u_trace_marker.c', 'util/u_trace_marker.h', 'util/u_var.cpp', diff --git a/src/xrt/auxiliary/util/u_timing.h b/src/xrt/auxiliary/util/u_timing.h index 09709e18d..d0f704f04 100644 --- a/src/xrt/auxiliary/util/u_timing.h +++ b/src/xrt/auxiliary/util/u_timing.h @@ -25,12 +25,6 @@ extern "C" { */ -/* - * - * Frame timing helper. - * - */ - /*! * For marking timepoints on a frame's lifetime, not a async event. * @@ -43,6 +37,13 @@ enum u_timing_point U_TIMING_POINT_SUBMIT, //!< Submitted work to the GPU. }; + +/* + * + * Frame timing helper. + * + */ + /*! * Frame timing helper struct, used for the compositors own frame timing. * @@ -103,13 +104,6 @@ struct u_frame_timing void (*destroy)(struct u_frame_timing *uft); }; - -/* - * - * Helper functions. - * - */ - /*! * @copydoc u_frame_timing::predict * @@ -194,6 +188,186 @@ u_ft_destroy(struct u_frame_timing **uft_ptr) } +/* + * + * Render timing helper. + * + */ + +/*! + * This render timing helper is designed to schedule the rendering time of + * clients that submit frames to a compositor, which runs its own render loop + * that picks latest completed frames for that client. + * + * @ingroup aux_timing + */ +struct u_render_timing +{ + /*! + * Predict when the client's next: rendered frame will be display; when the + * client should be woken up from sleeping; and its display period. + * + * This is called from `xrWaitFrame`, but it does not do any waiting, the caller + * should wait till `out_wake_up_time`. + * + * @param urth Render timing helper. + * @param[out] out_frame_id Frame ID of this predicted frame. + * @param[out] out_wake_up_time When the client should be woken up. + * @param[out] out_predicted_display_time Predicted display time. + * @param[out] out_predicted_display_period Predicted display period. + */ + void (*predict)(struct u_render_timing *urt, + int64_t *out_frame_id, + uint64_t *out_wake_up_time, + uint64_t *out_predicted_display_time, + uint64_t *out_predicted_display_period); + + /*! + * Mark a point on the frame's lifetime. + * + * @see @ref frame-timing. + */ + void (*mark_point)(struct u_render_timing *urt, int64_t frame_id, enum u_timing_point point, uint64_t when_ns); + + /*! + * When a frame has been discarded. + */ + void (*mark_discarded)(struct u_render_timing *urt, int64_t frame_id); + + /*! + * A frame has been delivered from the client, see `xrEndFrame`. The GPU might + * still be rendering the work. + */ + void (*mark_delivered)(struct u_render_timing *urt, int64_t frame_id); + + /*! + * Add a new sample point from the main render loop. + * + * This is called in the main renderer loop that tightly submits frames to the + * real compositor for displaying. This is only used to inform the render helper + * when the frame will be shown, not any timing information about the client. + * + * When this is called doesn't matter that much, as the render timing will need + * to be able to predict one or more frames into the future anyways. But + * preferably as soon as the main loop wakes up from wait frame. + * + * @param urth Self pointer + * @param predicted_display_time_ns Predicted display time for this sample. + * @param predicted_display_period_ns Predicted display period for this sample. + * @param extra_ns Time between display and when this sample + * was created, that is when the main loop + * was woken up by the main compositor. + */ + void (*info)(struct u_render_timing *urt, + uint64_t predicted_display_time_ns, + uint64_t predicted_display_period_ns, + uint64_t extra_ns); + + /*! + * Destroy this u_render_timing. + */ + void (*destroy)(struct u_render_timing *urt); +}; + +/*! + * @copydoc u_frame_timing::predict + * + * Helper for calling through the function pointer. + * + * @public @memberof u_render_timing + * @ingroup aux_timing + */ +static inline void +u_rt_predict(struct u_render_timing *urt, + int64_t *out_frame_id, + uint64_t *out_wake_up_time, + uint64_t *out_predicted_display_time, + uint64_t *out_predicted_display_period) +{ + urt->predict(urt, out_frame_id, out_wake_up_time, out_predicted_display_time, out_predicted_display_period); +} + +/*! + * @copydoc u_frame_timing::mark_point + * + * Helper for calling through the function pointer. + * + * @public @memberof u_render_timing + * @ingroup aux_timing + */ +static inline void +u_rt_mark_point(struct u_render_timing *urt, int64_t frame_id, enum u_timing_point point, uint64_t when_ns) +{ + urt->mark_point(urt, frame_id, point, when_ns); +} + +/*! + * @copydoc u_frame_timing::mark_discarded + * + * Helper for calling through the function pointer. + * + * @public @memberof u_render_timing + * @ingroup aux_timing + */ +static inline void +u_rt_mark_discarded(struct u_render_timing *urt, int64_t frame_id) +{ + urt->mark_discarded(urt, frame_id); +} + +/*! + * @copydoc u_frame_timing::mark_delivered + * + * Helper for calling through the function pointer. + * + * @public @memberof u_render_timing + * @ingroup aux_timing + */ +static inline void +u_rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) +{ + urt->mark_delivered(urt, frame_id); +} + +/*! + * @copydoc u_frame_timing::info + * + * Helper for calling through the function pointer. + * + * @public @memberof u_render_timing + * @ingroup aux_timing + */ +static inline void +u_rt_info(struct u_render_timing *urt, + uint64_t predicted_display_time_ns, + uint64_t predicted_display_period_ns, + uint64_t extra_ns) +{ + urt->info(urt, predicted_display_time_ns, predicted_display_period_ns, extra_ns); +} + +/*! + * @copydoc u_render_timing::destroy + * + * Helper for calling through the function pointer: does a null check and sets + * urt_ptr to null if freed. + * + * @public @memberof u_frame_timing + * @ingroup aux_timing + */ +static inline void +u_rt_destroy(struct u_render_timing **urt_ptr) +{ + struct u_render_timing *urt = *urt_ptr; + if (urt == NULL) { + return; + } + + urt->destroy(urt); + *urt_ptr = NULL; +} + + /* * * Implementations. @@ -216,6 +390,14 @@ u_ft_display_timing_create(uint64_t estimated_frame_period_ns, struct u_frame_ti xrt_result_t u_ft_fake_create(uint64_t estimated_frame_period_ns, struct u_frame_timing **out_uft); +/*! + * Creates a new render timing. + * + * @ingroup aux_timing + */ +xrt_result_t +u_rt_create(struct u_render_timing **out_urt); + #ifdef __cplusplus } diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index f6824b1cd..68e729d56 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -7,23 +7,98 @@ * @ingroup aux_util */ +#include "os/os_time.h" + #include "util/u_time.h" #include "util/u_misc.h" #include "util/u_debug.h" #include "util/u_logging.h" -#include "util/u_timing_render.h" +#include "util/u_timing.h" #include #include #include +/* + * + * Structs enums, and defines. + * + */ + +enum u_rt_state +{ + U_RT_READY, + U_RT_WAIT_LEFT, + U_RT_PREDICTED, + U_RT_BEGUN, +}; + +struct u_rt_frame +{ + //! When we predicted this frame to be shown. + uint64_t predicted_display_time_ns; + //! When the client should have delivered the frame. + uint64_t predicted_delivery_time_ns; + + struct + { + uint64_t predicted_ns; + uint64_t wait_woke_ns; + uint64_t begin_ns; + uint64_t delivered_ns; + } when; //!< When something happened. + + int64_t frame_id; + enum u_rt_state state; +}; + +struct render_timing +{ + struct u_render_timing base; + + struct u_rt_frame frames[2]; + uint32_t current_frame; + uint32_t next_frame; + + int64_t frame_counter; + + struct + { + //! App time between wait returning and begin being called. + uint64_t cpu_time_ns; + //! Time between begin and frame rendering completeing. + uint64_t draw_time_ns; + //! Exrta time between end of draw time and when the compositor wakes up. + uint64_t margin_ns; + } app; //!< App statistics. + + struct + { + //! The last display time that the thing driving this helper got. + uint64_t predicted_display_time_ns; + //! The last display period the hardware is running at. + uint64_t predicted_display_period_ns; + //! The extra time needed by the thing driving this helper. + uint64_t extra_ns; + } last_input; + + uint64_t last_returned_ns; +}; + + /* * * Helpers * */ +static inline struct render_timing * +render_timing(struct u_render_timing *urt) +{ + return (struct render_timing *)urt; +} + DEBUG_GET_ONCE_LOG_OPTION(ll, "U_TIMING_RENDER_LOG", U_LOGGING_WARN) #define RT_LOG_T(...) U_LOG_IFL_T(debug_get_log_option_ll(), __VA_ARGS__) @@ -33,59 +108,59 @@ DEBUG_GET_ONCE_LOG_OPTION(ll, "U_TIMING_RENDER_LOG", U_LOGGING_WARN) #define RT_LOG_E(...) U_LOG_IFL_E(debug_get_log_option_ll(), __VA_ARGS__) #define DEBUG_PRINT_FRAME_ID() RT_LOG_T("%" PRIi64, frame_id) -#define GET_INDEX_FROM_ID(URTH, ID) ((uint64_t)(ID) % ARRAY_SIZE((URTH)->frames)) +#define GET_INDEX_FROM_ID(RT, ID) ((uint64_t)(ID) % ARRAY_SIZE((RT)->frames)) static uint64_t -min_period(const struct u_rt_helper *urth) +min_period(const struct render_timing *rt) { - return urth->last_input.predicted_display_period_ns; + return rt->last_input.predicted_display_period_ns; } static uint64_t -last_sample_displayed(const struct u_rt_helper *urth) +last_sample_displayed(const struct render_timing *rt) { - return urth->last_input.predicted_display_time_ns; + return rt->last_input.predicted_display_time_ns; } static uint64_t -last_return_predicted_display(const struct u_rt_helper *urth) +last_return_predicted_display(const struct render_timing *rt) { - return urth->last_returned_ns; + return rt->last_returned_ns; } static uint64_t -total_app_time_ns(const struct u_rt_helper *urth) +total_app_time_ns(const struct render_timing *rt) { - return urth->app.cpu_time_ns + urth->app.draw_time_ns; + return rt->app.cpu_time_ns + rt->app.draw_time_ns; } static uint64_t -total_app_and_compositor_time_ns(const struct u_rt_helper *urth) +total_app_and_compositor_time_ns(const struct render_timing *rt) { - return total_app_time_ns(urth) + urth->app.margin_ns + urth->last_input.extra_ns; + return total_app_time_ns(rt) + rt->app.margin_ns + rt->last_input.extra_ns; } static uint64_t -predict_display_time(struct u_rt_helper *urth) +predict_display_time(const struct render_timing *rt) { // Now uint64_t now_ns = os_monotonic_get_ns(); // Error checking. - uint64_t period_ns = min_period(urth); + uint64_t period_ns = min_period(rt); if (period_ns == 0) { assert(false && "Have not yet received and samples from timing driver."); return now_ns; } // Total app and compositor time to produce a frame - uint64_t app_and_compositor_time_ns = total_app_and_compositor_time_ns(urth); + uint64_t app_and_compositor_time_ns = total_app_and_compositor_time_ns(rt); // Start from the last time that the driver displayed something. - uint64_t val = last_sample_displayed(urth); + uint64_t val = last_sample_displayed(rt); // Return a time after the last returned display time. - while (val < last_return_predicted_display(urth)) { + while (val < last_return_predicted_display(rt)) { val += period_ns; } @@ -100,122 +175,110 @@ predict_display_time(struct u_rt_helper *urth) /* * - * 'Exported' functions. + * Member functions. * */ -void -u_rt_helper_client_clear(struct u_rt_helper *urth) +static void +rt_predict(struct u_render_timing *urt, + int64_t *out_frame_id, + uint64_t *out_wake_up_time, + uint64_t *out_predicted_display_time, + uint64_t *out_predicted_display_period) { - for (size_t i = 0; i < ARRAY_SIZE(urth->frames); i++) { - urth->frames[i].state = U_RT_READY; - urth->frames[i].frame_id = -1; - } + struct render_timing *rt = render_timing(urt); - urth->app.cpu_time_ns = U_TIME_1MS_IN_NS * 2; - urth->app.draw_time_ns = U_TIME_1MS_IN_NS * 2; - urth->app.margin_ns = U_TIME_1MS_IN_NS / 2; -} - -void -u_rt_helper_init(struct u_rt_helper *urth) -{ - U_ZERO(urth); - u_rt_helper_client_clear(urth); -} - -void -u_rt_helper_predict(struct u_rt_helper *urth, - int64_t *out_frame_id, - uint64_t *out_wake_up_time, - uint64_t *out_predicted_display_time, - uint64_t *out_predicted_display_period) -{ - int64_t frame_id = ++urth->frame_counter; + int64_t frame_id = ++rt->frame_counter; *out_frame_id = frame_id; DEBUG_PRINT_FRAME_ID(); - uint64_t predict_ns = predict_display_time(urth); + uint64_t predict_ns = predict_display_time(rt); - urth->last_returned_ns = predict_ns; + rt->last_returned_ns = predict_ns; - *out_wake_up_time = predict_ns - total_app_and_compositor_time_ns(urth); + *out_wake_up_time = predict_ns - total_app_and_compositor_time_ns(rt); *out_predicted_display_time = predict_ns; - *out_predicted_display_period = min_period(urth); + *out_predicted_display_period = min_period(rt); - size_t index = GET_INDEX_FROM_ID(urth, frame_id); - assert(urth->frames[index].frame_id == -1); - assert(urth->frames[index].state == U_RT_READY); + size_t index = GET_INDEX_FROM_ID(rt, frame_id); + assert(rt->frames[index].frame_id == -1); + assert(rt->frames[index].state == U_RT_READY); /* * When the client should deliver the frame to us, take into account the * extra time needed by the main loop, plus a bit of extra time. */ - uint64_t delivery_time_ns = predict_ns - urth->last_input.extra_ns - U_TIME_HALF_MS_IN_NS; + uint64_t delivery_time_ns = predict_ns - rt->last_input.extra_ns - U_TIME_HALF_MS_IN_NS; - urth->frames[index].when.predicted_ns = os_monotonic_get_ns(); - urth->frames[index].state = U_RT_PREDICTED; - urth->frames[index].frame_id = frame_id; - urth->frames[index].predicted_delivery_time_ns = delivery_time_ns; + rt->frames[index].when.predicted_ns = os_monotonic_get_ns(); + rt->frames[index].state = U_RT_PREDICTED; + rt->frames[index].frame_id = frame_id; + rt->frames[index].predicted_delivery_time_ns = delivery_time_ns; } -void -u_rt_helper_mark(struct u_rt_helper *urth, int64_t frame_id, enum u_timing_point point, uint64_t when_ns) +static void +rt_mark_point(struct u_render_timing *urt, int64_t frame_id, enum u_timing_point point, uint64_t when_ns) { + struct render_timing *rt = render_timing(urt); + DEBUG_PRINT_FRAME_ID(); - size_t index = GET_INDEX_FROM_ID(urth, frame_id); - assert(urth->frames[index].frame_id == frame_id); + size_t index = GET_INDEX_FROM_ID(rt, frame_id); + assert(rt->frames[index].frame_id == frame_id); switch (point) { case U_TIMING_POINT_WAKE_UP: - assert(urth->frames[index].state == U_RT_PREDICTED); + assert(rt->frames[index].state == U_RT_PREDICTED); - urth->frames[index].when.wait_woke_ns = when_ns; - urth->frames[index].state = U_RT_WAIT_LEFT; + rt->frames[index].when.wait_woke_ns = when_ns; + rt->frames[index].state = U_RT_WAIT_LEFT; break; case U_TIMING_POINT_BEGIN: - assert(urth->frames[index].state == U_RT_WAIT_LEFT); + assert(rt->frames[index].state == U_RT_WAIT_LEFT); - urth->frames[index].when.begin_ns = os_monotonic_get_ns(); - urth->frames[index].state = U_RT_BEGUN; + rt->frames[index].when.begin_ns = os_monotonic_get_ns(); + rt->frames[index].state = U_RT_BEGUN; break; case U_TIMING_POINT_SUBMIT: default: assert(false); } } -void -u_rt_helper_mark_discarded(struct u_rt_helper *urth, int64_t frame_id) +static void +rt_mark_discarded(struct u_render_timing *urt, int64_t frame_id) { + struct render_timing *rt = render_timing(urt); + DEBUG_PRINT_FRAME_ID(); - size_t index = GET_INDEX_FROM_ID(urth, frame_id); - assert(urth->frames[index].frame_id == frame_id); - assert(urth->frames[index].state == U_RT_WAIT_LEFT || urth->frames[index].state == U_RT_BEGUN); + size_t index = GET_INDEX_FROM_ID(rt, frame_id); + assert(rt->frames[index].frame_id == frame_id); + assert(rt->frames[index].state == U_RT_WAIT_LEFT || rt->frames[index].state == U_RT_BEGUN); - urth->frames[index].when.delivered_ns = os_monotonic_get_ns(); - urth->frames[index].state = U_RT_READY; - urth->frames[index].frame_id = -1; + rt->frames[index].when.delivered_ns = os_monotonic_get_ns(); + rt->frames[index].state = U_RT_READY; + rt->frames[index].frame_id = -1; } -void -u_rt_helper_mark_delivered(struct u_rt_helper *urth, int64_t frame_id) +static void +rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) { + struct render_timing *rt = render_timing(urt); + DEBUG_PRINT_FRAME_ID(); - size_t index = GET_INDEX_FROM_ID(urth, frame_id); - assert(urth->frames[index].frame_id == frame_id); - assert(urth->frames[index].state == U_RT_BEGUN); + size_t index = GET_INDEX_FROM_ID(rt, frame_id); + assert(rt->frames[index].frame_id == frame_id); + assert(rt->frames[index].state == U_RT_BEGUN); uint64_t now_ns = os_monotonic_get_ns(); - urth->frames[index].when.delivered_ns = now_ns; - urth->frames[index].state = U_RT_READY; - urth->frames[index].frame_id = -1; + rt->frames[index].when.delivered_ns = now_ns; + rt->frames[index].state = U_RT_READY; + rt->frames[index].frame_id = -1; - int64_t diff_ns = urth->frames[index].predicted_delivery_time_ns - now_ns; + int64_t diff_ns = rt->frames[index].predicted_delivery_time_ns - now_ns; bool late = false; if (diff_ns < 0) { diff_ns = -diff_ns; @@ -226,13 +289,52 @@ u_rt_helper_mark_delivered(struct u_rt_helper *urth, int64_t frame_id) RT_LOG_D("Delivered frame %i.%02ims %s.", (int)ms100 / 100, (int)ms100 % 100, late ? "late" : "early"); } -void -u_rt_helper_new_sample(struct u_rt_helper *urth, - uint64_t predicted_display_time_ns, - uint64_t predicted_display_period_ns, - uint64_t extra_ns) +static void +rt_info(struct u_render_timing *urt, + uint64_t predicted_display_time_ns, + uint64_t predicted_display_period_ns, + uint64_t extra_ns) { - urth->last_input.predicted_display_time_ns = predicted_display_time_ns; - urth->last_input.predicted_display_period_ns = predicted_display_period_ns; - urth->last_input.extra_ns = extra_ns; + struct render_timing *rt = render_timing(urt); + + rt->last_input.predicted_display_time_ns = predicted_display_time_ns; + rt->last_input.predicted_display_period_ns = predicted_display_period_ns; + rt->last_input.extra_ns = extra_ns; +} + +static void +rt_destroy(struct u_render_timing *urt) +{ + free(urt); +} + + +/* + * + * 'Exported' functions. + * + */ + +xrt_result_t +u_rt_create(struct u_render_timing **out_urt) +{ + struct render_timing *rt = U_TYPED_CALLOC(struct render_timing); + rt->base.predict = rt_predict; + rt->base.mark_point = rt_mark_point; + rt->base.mark_discarded = rt_mark_discarded; + rt->base.mark_delivered = rt_mark_delivered; + rt->base.info = rt_info; + rt->base.destroy = rt_destroy; + rt->app.cpu_time_ns = U_TIME_1MS_IN_NS * 2; + rt->app.draw_time_ns = U_TIME_1MS_IN_NS * 2; + rt->app.margin_ns = U_TIME_1MS_IN_NS / 2; + + for (size_t i = 0; i < ARRAY_SIZE(rt->frames); i++) { + rt->frames[i].state = U_RT_READY; + rt->frames[i].frame_id = -1; + } + + *out_urt = &rt->base; + + return XRT_SUCCESS; } diff --git a/src/xrt/auxiliary/util/u_timing_render.h b/src/xrt/auxiliary/util/u_timing_render.h deleted file mode 100644 index 1be3bad3c..000000000 --- a/src/xrt/auxiliary/util/u_timing_render.h +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2020-2021, Collabora, Ltd. -// SPDX-License-Identifier: BSL-1.0 -/*! - * @file - * @brief Shared frame timing code. - * @author Jakob Bornecrantz - * @ingroup aux_util - */ - -#pragma once - -#include "xrt/xrt_compiler.h" -#include "os/os_time.h" -#include "util/u_timing.h" - - -#ifdef __cplusplus -extern "C" { -#endif - - -enum u_rt_state -{ - U_RT_READY, - U_RT_WAIT_LEFT, - U_RT_PREDICTED, - U_RT_BEGUN, -}; - -struct u_rt_frame -{ - //! When we predicted this frame to be shown. - uint64_t predicted_display_time_ns; - //! When the client should have delivered the frame. - uint64_t predicted_delivery_time_ns; - - struct - { - uint64_t predicted_ns; - uint64_t wait_woke_ns; - uint64_t begin_ns; - uint64_t delivered_ns; - } when; //!< When something happened. - - int64_t frame_id; - enum u_rt_state state; -}; - -/*! - * This render timing helper is designed to schedule the rendering time of - * clients that submit frames to a compositor, which runs its own render loop - * that picks latest completed frames for that client. - */ -struct u_rt_helper -{ - struct u_rt_frame frames[2]; - uint32_t current_frame; - uint32_t next_frame; - - int64_t frame_counter; - - struct - { - //! App time between wait returning and begin being called. - uint64_t cpu_time_ns; - //! Time between begin and frame rendering completeing. - uint64_t draw_time_ns; - //! Exrta time between end of draw time and when the compositor wakes up. - uint64_t margin_ns; - } app; //!< App statistics. - - struct - { - //! The last display time that the thing driving this helper got. - uint64_t predicted_display_time_ns; - //! The last display period the hardware is running at. - uint64_t predicted_display_period_ns; - //! The extra time needed by the thing driving this helper. - uint64_t extra_ns; - } last_input; - - uint64_t last_returned_ns; -}; - -void -u_rt_helper_init(struct u_rt_helper *urth); - -/*! - * This function gets the client part of the render timing helper ready to be - * used. If you use init you will also clear all of the timing information. - * - * Call this when resetting a client. - */ -void -u_rt_helper_client_clear(struct u_rt_helper *urth); - -/*! - * Predict when the client's next: rendered frame will be display; when the - * client should be woken up from sleeping; and its display period. - * - * This is called from `xrWaitFrame`, but it does not do any waiting, the caller - * should wait till `out_wake_up_time`. - * - * @param urth Render timing helper. - * @param[out] out_frame_id Frame ID of this predicted frame. - * @param[out] out_wake_up_time When the client should be woken up. - * @param[out] out_predicted_display_time Predicted display time. - * @param[out] out_predicted_display_period Predicted display period. - */ -void -u_rt_helper_predict(struct u_rt_helper *urth, - int64_t *out_frame_id, - uint64_t *out_wake_up_time, - uint64_t *out_predicted_display_time, - uint64_t *out_predicted_display_period); - -/*! - * Mark a point on the frame's lifetime. - * - * @see @ref frame-timing. - */ -void -u_rt_helper_mark(struct u_rt_helper *urth, int64_t frame_id, enum u_timing_point point, uint64_t when_ns); - -/*! - * When a frame has been discarded. - */ -void -u_rt_helper_mark_discarded(struct u_rt_helper *urth, int64_t frame_id); - -/*! - * A frame has been delivered from the client, see `xrEndFrame`. The GPU might - * still be rendering the work. - */ -void -u_rt_helper_mark_delivered(struct u_rt_helper *urth, int64_t frame_id); - -/*! - * Add a new sample point from the main render loop. - * - * This is called in the main renderer loop that tightly submits frames to the - * real compositor for displaying. This is only used to inform the render helper - * when the frame will be shown, not any timing information about the client. - * - * When this is called doesn't matter that much, as the render timing will need - * to be able to predict one or more frames into the future anyways. But - * preferably as soon as the main loop wakes up from wait frame. - * - * @param urth Self pointer - * @param predicted_display_time_ns Predicted display time for this sample. - * @param predicted_display_period_ns Predicted display period for this sample. - * @param extra_ns Time between display and when this sample - * was created, that is when the main loop - * was woken up by the main compositor. - */ -void -u_rt_helper_new_sample(struct u_rt_helper *urth, - uint64_t predicted_display_time_ns, - uint64_t predicted_display_period_ns, - uint64_t extra_ns); - - -#ifdef __cplusplus -} -#endif diff --git a/src/xrt/compositor/multi/comp_multi_compositor.c b/src/xrt/compositor/multi/comp_multi_compositor.c index facad36d2..9c8ad55ef 100644 --- a/src/xrt/compositor/multi/comp_multi_compositor.c +++ b/src/xrt/compositor/multi/comp_multi_compositor.c @@ -197,8 +197,8 @@ multi_compositor_predict_frame(struct xrt_compositor *xc, os_mutex_lock(&mc->msc->list_and_timing_lock); - u_rt_helper_predict( // - &mc->urth, // + u_rt_predict( // + mc->urt, // out_frame_id, // out_wake_time_ns, // out_predicted_display_time_ns, // @@ -223,7 +223,7 @@ multi_compositor_mark_frame(struct xrt_compositor *xc, case XRT_COMPOSITOR_FRAME_POINT_WOKE: os_mutex_lock(&mc->msc->list_and_timing_lock); uint64_t now_ns = os_monotonic_get_ns(); - u_rt_helper_mark(&mc->urth, frame_id, U_TIMING_POINT_WAKE_UP, now_ns); + u_rt_mark_point(mc->urt, frame_id, U_TIMING_POINT_WAKE_UP, now_ns); os_mutex_unlock(&mc->msc->list_and_timing_lock); break; default: assert(false); @@ -255,7 +255,7 @@ multi_compositor_begin_frame(struct xrt_compositor *xc, int64_t frame_id) os_mutex_lock(&mc->msc->list_and_timing_lock); uint64_t now_ns = os_monotonic_get_ns(); - u_rt_helper_mark(&mc->urth, frame_id, U_TIMING_POINT_BEGIN, now_ns); + u_rt_mark_point(mc->urt, frame_id, U_TIMING_POINT_BEGIN, now_ns); os_mutex_unlock(&mc->msc->list_and_timing_lock); return XRT_SUCCESS; @@ -269,7 +269,7 @@ multi_compositor_discard_frame(struct xrt_compositor *xc, int64_t frame_id) struct multi_compositor *mc = multi_compositor(xc); os_mutex_lock(&mc->msc->list_and_timing_lock); - u_rt_helper_mark_discarded(&mc->urth, frame_id); + u_rt_mark_discarded(mc->urt, frame_id); os_mutex_unlock(&mc->msc->list_and_timing_lock); return XRT_SUCCESS; @@ -451,7 +451,7 @@ multi_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_g slot_move_and_clear(&mc->delivered, &mc->progress); - u_rt_helper_mark_delivered(&mc->urth, frame_id); + u_rt_mark_delivered(mc->urt, frame_id); os_mutex_unlock(&mc->msc->list_and_timing_lock); @@ -494,6 +494,9 @@ multi_compositor_destroy(struct xrt_compositor *xc) slot_clear(&mc->progress); slot_clear(&mc->delivered); + // Does null checking. + u_rt_destroy(&mc->urt); + free(mc); } @@ -534,8 +537,7 @@ multi_compositor_create(struct multi_system_compositor *msc, mc->base.base.info = msc->xcn->base.info; // This is safe to do without a lock since we are not on the list yet. - u_rt_helper_init(&mc->urth); - u_rt_helper_client_clear(&mc->urth); + u_rt_create(&mc->urt); os_mutex_lock(&msc->list_and_timing_lock); @@ -548,8 +550,8 @@ multi_compositor_create(struct multi_system_compositor *msc, break; } - u_rt_helper_new_sample( // - &mc->urth, // + u_rt_info( // + mc->urt, // msc->last_timings.predicted_display_time_ns, // msc->last_timings.predicted_display_period_ns, // msc->last_timings.diff_ns); // diff --git a/src/xrt/compositor/multi/comp_multi_private.h b/src/xrt/compositor/multi/comp_multi_private.h index b27261d15..64f4cb551 100644 --- a/src/xrt/compositor/multi/comp_multi_private.h +++ b/src/xrt/compositor/multi/comp_multi_private.h @@ -16,7 +16,7 @@ #include "os/os_time.h" #include "os/os_threading.h" -#include "util/u_timing_render.h" +#include "util/u_timing.h" #ifdef __cplusplus extern "C" { @@ -128,7 +128,7 @@ struct multi_compositor //! Fully ready to be used. struct multi_layer_slot delivered; - struct u_rt_helper urth; + struct u_render_timing *urt; }; static inline struct multi_compositor * diff --git a/src/xrt/compositor/multi/comp_multi_system.c b/src/xrt/compositor/multi/comp_multi_system.c index 20fd21f1a..f2a44a82a 100644 --- a/src/xrt/compositor/multi/comp_multi_system.c +++ b/src/xrt/compositor/multi/comp_multi_system.c @@ -271,8 +271,8 @@ broadcast_timings(struct multi_system_compositor *msc, continue; } - u_rt_helper_new_sample( // - &mc->urth, // + u_rt_info( // + mc->urt, // predicted_display_time_ns, // predicted_display_period_ns, // diff_ns); // diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h index b247d53c2..5abf0bc1b 100644 --- a/src/xrt/ipc/server/ipc_server.h +++ b/src/xrt/ipc/server/ipc_server.h @@ -14,7 +14,6 @@ #include "xrt/xrt_compiler.h" #include "util/u_logging.h" -#include "util/u_timing_render.h" #include "os/os_threading.h" From 1b0a9acb56736b9f129bf42db22f1ad303847027 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 3 Apr 2021 02:12:47 +0100 Subject: [PATCH 309/883] u/rt: Adjust app time during runtime --- src/xrt/auxiliary/util/u_timing_render.c | 44 +++++++++++++++++++----- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index 68e729d56..862bc4ce4 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -110,6 +110,19 @@ DEBUG_GET_ONCE_LOG_OPTION(ll, "U_TIMING_RENDER_LOG", U_LOGGING_WARN) #define DEBUG_PRINT_FRAME_ID() RT_LOG_T("%" PRIi64, frame_id) #define GET_INDEX_FROM_ID(RT, ID) ((uint64_t)(ID) % ARRAY_SIZE((RT)->frames)) +#define IIR_ALPHA_LT 0.5 +#define IIR_ALPHA_GT 0.99 + +static void +do_iir_filter(uint64_t *target, double alpha_lt, double alpha_gt, uint64_t sample) +{ + uint64_t t = *target; + double alpha = t < sample ? alpha_lt : alpha_gt; + double a = time_ns_to_s(t) * alpha; + double b = time_ns_to_s(sample) * (1.0 - alpha); + *target = time_s_to_ns(a + b); +} + static uint64_t min_period(const struct render_timing *rt) { @@ -134,10 +147,16 @@ total_app_time_ns(const struct render_timing *rt) return rt->app.cpu_time_ns + rt->app.draw_time_ns; } +static uint64_t +total_compositor_time_ns(const struct render_timing *rt) +{ + return rt->app.margin_ns + rt->last_input.extra_ns; +} + static uint64_t total_app_and_compositor_time_ns(const struct render_timing *rt) { - return total_app_time_ns(rt) + rt->app.margin_ns + rt->last_input.extra_ns; + return total_app_time_ns(rt) + total_compositor_time_ns(rt); } static uint64_t @@ -205,11 +224,8 @@ rt_predict(struct u_render_timing *urt, assert(rt->frames[index].frame_id == -1); assert(rt->frames[index].state == U_RT_READY); - /* - * When the client should deliver the frame to us, take into account the - * extra time needed by the main loop, plus a bit of extra time. - */ - uint64_t delivery_time_ns = predict_ns - rt->last_input.extra_ns - U_TIME_HALF_MS_IN_NS; + // When the client should deliver the frame to us. + uint64_t delivery_time_ns = predict_ns - total_compositor_time_ns(rt); rt->frames[index].when.predicted_ns = os_monotonic_get_ns(); rt->frames[index].state = U_RT_PREDICTED; @@ -285,8 +301,20 @@ rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) late = true; } - int64_t ms100 = diff_ns / (1000 * 10); - RT_LOG_D("Delivered frame %i.%02ims %s.", (int)ms100 / 100, (int)ms100 % 100, late ? "late" : "early"); +#define NS_TO_MS_F(ns) (time_ns_to_s(ns) * 1000.0) + + uint64_t diff_cpu_ns = rt->frames[index].when.begin_ns - rt->frames[index].when.wait_woke_ns; + uint64_t diff_draw_ns = rt->frames[index].when.delivered_ns - rt->frames[index].when.begin_ns; + + RT_LOG_D("Delivered frame %.2fms %s.\n\tcpu o: %.2f, n: %.2f\n\tdraw o: %.2f, n: %.2f", // + time_ns_to_ms_f(diff_ns), late ? "late" : "early", // + time_ns_to_ms_f(rt->app.cpu_time_ns), // + time_ns_to_ms_f(diff_cpu_ns), // + time_ns_to_ms_f(rt->app.draw_time_ns), // + time_ns_to_ms_f(diff_draw_ns)); + + do_iir_filter(&rt->app.cpu_time_ns, IIR_ALPHA_LT, IIR_ALPHA_GT, diff_cpu_ns); + do_iir_filter(&rt->app.draw_time_ns, IIR_ALPHA_LT, IIR_ALPHA_GT, diff_draw_ns); } static void From 8606eb9d11aa4c0f5ecfce4346554cd6a11751b2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 7 Apr 2021 01:03:51 +0100 Subject: [PATCH 310/883] u/rt: Adjust app period depending on app time --- src/xrt/auxiliary/util/u_timing_render.c | 38 +++++++++++++++++------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index 862bc4ce4..9f0949df1 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -160,17 +160,34 @@ total_app_and_compositor_time_ns(const struct render_timing *rt) } static uint64_t -predict_display_time(const struct render_timing *rt) +calc_period(const struct render_timing *rt) +{ + // Error checking. + uint64_t base_period_ns = min_period(rt); + if (base_period_ns == 0) { + assert(false && "Have not yet received and samples from timing driver."); + base_period_ns = U_TIME_1MS_IN_NS * 16; // Sure + } + + // Calculate the using both values separately. + uint64_t period_ns = base_period_ns; + while (rt->app.cpu_time_ns > period_ns) { + period_ns += base_period_ns; + } + + while (rt->app.draw_time_ns > period_ns) { + period_ns += base_period_ns; + } + + return period_ns; +} + +static uint64_t +predict_display_time(const struct render_timing *rt, uint64_t period_ns) { // Now uint64_t now_ns = os_monotonic_get_ns(); - // Error checking. - uint64_t period_ns = min_period(rt); - if (period_ns == 0) { - assert(false && "Have not yet received and samples from timing driver."); - return now_ns; - } // Total app and compositor time to produce a frame uint64_t app_and_compositor_time_ns = total_app_and_compositor_time_ns(rt); @@ -179,7 +196,7 @@ predict_display_time(const struct render_timing *rt) uint64_t val = last_sample_displayed(rt); // Return a time after the last returned display time. - while (val < last_return_predicted_display(rt)) { + while (val <= last_return_predicted_display(rt)) { val += period_ns; } @@ -212,13 +229,14 @@ rt_predict(struct u_render_timing *urt, DEBUG_PRINT_FRAME_ID(); - uint64_t predict_ns = predict_display_time(rt); + uint64_t period_ns = calc_period(rt); + uint64_t predict_ns = predict_display_time(rt, period_ns); rt->last_returned_ns = predict_ns; *out_wake_up_time = predict_ns - total_app_and_compositor_time_ns(rt); *out_predicted_display_time = predict_ns; - *out_predicted_display_period = min_period(rt); + *out_predicted_display_period = period_ns; size_t index = GET_INDEX_FROM_ID(rt, frame_id); assert(rt->frames[index].frame_id == -1); From b68041fb930f347f029f87f1d5f83abcdadd51fa Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 7 Apr 2021 15:40:57 +0100 Subject: [PATCH 311/883] u/rt: Tweak IIR alpha numbers --- src/xrt/auxiliary/util/u_timing_render.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index 9f0949df1..95722a055 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -110,8 +110,8 @@ DEBUG_GET_ONCE_LOG_OPTION(ll, "U_TIMING_RENDER_LOG", U_LOGGING_WARN) #define DEBUG_PRINT_FRAME_ID() RT_LOG_T("%" PRIi64, frame_id) #define GET_INDEX_FROM_ID(RT, ID) ((uint64_t)(ID) % ARRAY_SIZE((RT)->frames)) -#define IIR_ALPHA_LT 0.5 -#define IIR_ALPHA_GT 0.99 +#define IIR_ALPHA_LT 0.8 +#define IIR_ALPHA_GT 0.8 static void do_iir_filter(uint64_t *target, double alpha_lt, double alpha_gt, uint64_t sample) From 736b9abdbe1ebf8dc3b2741ba6d3d44894a671eb Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 7 Apr 2021 15:41:26 +0100 Subject: [PATCH 312/883] u/rt: Print frame period and tidy --- src/xrt/auxiliary/util/u_timing_render.c | 48 ++++++++++++++---------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index 95722a055..3ce5b6431 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -38,6 +38,10 @@ struct u_rt_frame { //! When we predicted this frame to be shown. uint64_t predicted_display_time_ns; + + //! The selected display period. + uint64_t predicted_display_period_ns; + //! When the client should have delivered the frame. uint64_t predicted_delivery_time_ns; @@ -231,10 +235,14 @@ rt_predict(struct u_render_timing *urt, uint64_t period_ns = calc_period(rt); uint64_t predict_ns = predict_display_time(rt, period_ns); + // When should the client wake up. + uint64_t wake_up_time_ns = predict_ns - total_app_and_compositor_time_ns(rt); + // When the client should deliver the frame to us. + uint64_t delivery_time_ns = predict_ns - total_compositor_time_ns(rt); rt->last_returned_ns = predict_ns; - *out_wake_up_time = predict_ns - total_app_and_compositor_time_ns(rt); + *out_wake_up_time = wake_up_time_ns; *out_predicted_display_time = predict_ns; *out_predicted_display_period = period_ns; @@ -242,13 +250,11 @@ rt_predict(struct u_render_timing *urt, assert(rt->frames[index].frame_id == -1); assert(rt->frames[index].state == U_RT_READY); - // When the client should deliver the frame to us. - uint64_t delivery_time_ns = predict_ns - total_compositor_time_ns(rt); - - rt->frames[index].when.predicted_ns = os_monotonic_get_ns(); rt->frames[index].state = U_RT_PREDICTED; rt->frames[index].frame_id = frame_id; rt->frames[index].predicted_delivery_time_ns = delivery_time_ns; + rt->frames[index].predicted_display_period_ns = period_ns; + rt->frames[index].when.predicted_ns = os_monotonic_get_ns(); } static void @@ -303,16 +309,17 @@ rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) DEBUG_PRINT_FRAME_ID(); size_t index = GET_INDEX_FROM_ID(rt, frame_id); - assert(rt->frames[index].frame_id == frame_id); - assert(rt->frames[index].state == U_RT_BEGUN); + struct u_rt_frame *f = &rt->frames[index]; + assert(f->frame_id == frame_id); + assert(f->state == U_RT_BEGUN); uint64_t now_ns = os_monotonic_get_ns(); - rt->frames[index].when.delivered_ns = now_ns; - rt->frames[index].state = U_RT_READY; - rt->frames[index].frame_id = -1; + f->when.delivered_ns = now_ns; + f->state = U_RT_READY; + f->frame_id = -1; - int64_t diff_ns = rt->frames[index].predicted_delivery_time_ns - now_ns; + int64_t diff_ns = f->predicted_delivery_time_ns - now_ns; bool late = false; if (diff_ns < 0) { diff_ns = -diff_ns; @@ -321,15 +328,18 @@ rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) #define NS_TO_MS_F(ns) (time_ns_to_s(ns) * 1000.0) - uint64_t diff_cpu_ns = rt->frames[index].when.begin_ns - rt->frames[index].when.wait_woke_ns; - uint64_t diff_draw_ns = rt->frames[index].when.delivered_ns - rt->frames[index].when.begin_ns; + uint64_t diff_cpu_ns = f->when.begin_ns - f->when.wait_woke_ns; + uint64_t diff_draw_ns = f->when.delivered_ns - f->when.begin_ns; - RT_LOG_D("Delivered frame %.2fms %s.\n\tcpu o: %.2f, n: %.2f\n\tdraw o: %.2f, n: %.2f", // - time_ns_to_ms_f(diff_ns), late ? "late" : "early", // - time_ns_to_ms_f(rt->app.cpu_time_ns), // - time_ns_to_ms_f(diff_cpu_ns), // - time_ns_to_ms_f(rt->app.draw_time_ns), // - time_ns_to_ms_f(diff_draw_ns)); + RT_LOG_D( + "Delivered frame %.2fms %s." // + "\n\tperiod: %.2f" // + "\n\tcpu o: %.2f, n: %.2f" // + "\n\tdraw o: %.2f, n: %.2f", // + time_ns_to_ms_f(diff_ns), late ? "late" : "early", // + time_ns_to_ms_f(f->predicted_display_period_ns), // + time_ns_to_ms_f(rt->app.cpu_time_ns), time_ns_to_ms_f(diff_cpu_ns), // + time_ns_to_ms_f(rt->app.draw_time_ns), time_ns_to_ms_f(diff_draw_ns)); // do_iir_filter(&rt->app.cpu_time_ns, IIR_ALPHA_LT, IIR_ALPHA_GT, diff_cpu_ns); do_iir_filter(&rt->app.draw_time_ns, IIR_ALPHA_LT, IIR_ALPHA_GT, diff_draw_ns); From aca09bdebf0553ac48a196ffe9d9b808f1b9c426 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 5 Apr 2021 23:09:44 +0100 Subject: [PATCH 313/883] c/multi: Do not display frames before they are to be displayed This follows the OpenXR spec that says that a frame might not be displayed before XrFrameEndInfo::displayTime value. --- .../compositor/multi/comp_multi_compositor.c | 38 +++++++++++++++++-- src/xrt/compositor/multi/comp_multi_private.h | 26 ++++++++++++- src/xrt/compositor/multi/comp_multi_system.c | 38 +++++++++++++++---- 3 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/xrt/compositor/multi/comp_multi_compositor.c b/src/xrt/compositor/multi/comp_multi_compositor.c index 9c8ad55ef..1d3d0e978 100644 --- a/src/xrt/compositor/multi/comp_multi_compositor.c +++ b/src/xrt/compositor/multi/comp_multi_compositor.c @@ -286,6 +286,7 @@ multi_compositor_layer_begin(struct xrt_compositor *xc, assert(mc->progress.num_layers == 0); U_ZERO(&mc->progress); + mc->progress.active = true; mc->progress.display_time_ns = display_time_ns; mc->progress.env_blend_mode = env_blend_mode; @@ -447,12 +448,23 @@ multi_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_g xrt_compositor_fence_destroy(&xcf); } + os_mutex_lock(&mc->slot_lock); + + // Block here if the scheduled slot is not clear. + while (mc->scheduled.active) { + os_mutex_unlock(&mc->slot_lock); + + os_nanosleep(U_TIME_1MS_IN_NS); + + os_mutex_lock(&mc->slot_lock); + } + + slot_move_and_clear(&mc->scheduled, &mc->progress); + + os_mutex_unlock(&mc->slot_lock); + os_mutex_lock(&mc->msc->list_and_timing_lock); - - slot_move_and_clear(&mc->delivered, &mc->progress); - u_rt_mark_delivered(mc->urt, frame_id); - os_mutex_unlock(&mc->msc->list_and_timing_lock); return XRT_SUCCESS; @@ -492,6 +504,7 @@ multi_compositor_destroy(struct xrt_compositor *xc) // We are now off the rendering list, clear slots for any swapchains. slot_clear(&mc->progress); + slot_clear(&mc->scheduled); slot_clear(&mc->delivered); // Does null checking. @@ -500,6 +513,23 @@ multi_compositor_destroy(struct xrt_compositor *xc) free(mc); } +void +multi_compositor_deliver_any_frames(struct multi_compositor *mc, uint64_t display_time_ns) +{ + os_mutex_lock(&mc->slot_lock); + + if (!mc->scheduled.active) { + os_mutex_unlock(&mc->slot_lock); + return; + } + + if (time_is_greater_then_or_within_half_ms(display_time_ns, mc->scheduled.display_time_ns)) { + slot_move_and_clear(&mc->delivered, &mc->scheduled); + } + + os_mutex_unlock(&mc->slot_lock); +} + xrt_result_t multi_compositor_create(struct multi_system_compositor *msc, const struct xrt_session_info *xsi, diff --git a/src/xrt/compositor/multi/comp_multi_private.h b/src/xrt/compositor/multi/comp_multi_private.h index 64f4cb551..91954055c 100644 --- a/src/xrt/compositor/multi/comp_multi_private.h +++ b/src/xrt/compositor/multi/comp_multi_private.h @@ -72,6 +72,7 @@ struct multi_layer_slot enum xrt_blend_mode env_blend_mode; uint32_t num_layers; struct multi_layer_entry layers[MULTI_MAX_LAYERS]; + bool active; }; /*! @@ -122,10 +123,22 @@ struct multi_compositor int64_t z_order; } state; - //! Currently being transferred or waited on. + //! Lock for all of the slots. + struct os_mutex slot_lock; + + /*! + * Currently being transferred or waited on. + * Not protected by the slot lock as it is only touched by the client thread. + */ struct multi_layer_slot progress; - //! Fully ready to be used. + //! Scheduled frames for a future timepoint. + struct multi_layer_slot scheduled; + + /*! + * Fully ready to be used. + * Not protected by the slot lock as it is only touched by the main render loop thread. + */ struct multi_layer_slot delivered; struct u_render_timing *urt; @@ -155,6 +168,15 @@ multi_compositor_create(struct multi_system_compositor *msc, void multi_compositor_push_event(struct multi_compositor *mc, const union xrt_compositor_event *xce); +/*! + * Deliver any scheduled frames at that is to be display at or after the given @p display_time_ns. Called by the render + * thread and copies data from multi_compositor::scheduled to multi_compositor::delivered while holding the slot_lock. + * + * @ingroup comp_multi + */ +void +multi_compositor_deliver_any_frames(struct multi_compositor *mc, uint64_t display_time_ns); + /* * diff --git a/src/xrt/compositor/multi/comp_multi_system.c b/src/xrt/compositor/multi/comp_multi_system.c index f2a44a82a..1f48a4dd9 100644 --- a/src/xrt/compositor/multi/comp_multi_system.c +++ b/src/xrt/compositor/multi/comp_multi_system.c @@ -211,7 +211,20 @@ overlay_sort_func(const void *a, const void *b) } static void -transfer_layers_locked(struct multi_system_compositor *msc) +log_frame_time_diff(uint64_t frame_time_ns, uint64_t display_time_ns) +{ + int64_t diff_ns = (int64_t)frame_time_ns - (int64_t)display_time_ns; + bool late = false; + if (diff_ns < 0) { + diff_ns = -diff_ns; + late = true; + } + + U_LOG_W("Frame %s by %.2fms!", late ? "late" : "early", time_ns_to_ms_f(diff_ns)); +} + +static void +transfer_layers_locked(struct multi_system_compositor *msc, uint64_t display_time_ns) { COMP_TRACE_MARKER(); @@ -226,6 +239,9 @@ transfer_layers_locked(struct multi_system_compositor *msc) } array[count++] = msc->clients[k]; + + // Even if it's not shown, make sure that frames are delivered. + multi_compositor_deliver_any_frames(msc->clients[k], display_time_ns); } // Sort the stack array @@ -238,6 +254,16 @@ transfer_layers_locked(struct multi_system_compositor *msc) continue; } + // None of the data in this slot is valid, don't check access it. + if (!mc->delivered.active) { + continue; + } + + uint64_t frame_time_ns = mc->delivered.display_time_ns; + if (!time_is_within_half_ms(frame_time_ns, display_time_ns)) { + log_frame_time_diff(frame_time_ns, display_time_ns); + } + for (size_t i = 0; i < mc->delivered.num_layers; i++) { struct multi_layer_entry *layer = &mc->delivered.layers[i]; @@ -354,18 +380,16 @@ multi_main_loop(struct multi_system_compositor *msc) broadcast_timings(msc, predicted_display_time_ns, predicted_display_period_ns, diff_ns); - // Make sure that the clients doesn't go away. - os_mutex_lock(&msc->list_and_timing_lock); - xrt_comp_begin_frame(xc, frame_id); xrt_comp_layer_begin(xc, frame_id, 0, 0); - transfer_layers_locked(msc); + // Make sure that the clients doesn't go away while we transfer layers. + os_mutex_lock(&msc->list_and_timing_lock); + transfer_layers_locked(msc, predicted_display_time_ns); + os_mutex_unlock(&msc->list_and_timing_lock); xrt_comp_layer_commit(xc, frame_id, XRT_GRAPHICS_SYNC_HANDLE_INVALID); - os_mutex_unlock(&msc->list_and_timing_lock); - // Re-lock the thread for check in while statement. os_thread_helper_lock(&msc->oth); } From ac1acfa7d4ec87b15272b2f2bbbaaefeba25e9c6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 6 Apr 2021 20:27:26 +0100 Subject: [PATCH 314/883] doc: Document !721 --- doc/changes/auxiliary/mr.721.1.md | 1 + doc/changes/auxiliary/mr.721.2.md | 1 + doc/changes/auxiliary/mr.721.3.md | 3 +++ doc/changes/compositor/mr.721.md | 4 ++++ doc/changes/xrt/mr.721.1.md | 2 ++ doc/changes/xrt/mr.721.2.md | 1 + doc/changes/xrt/mr.721.3.md | 3 +++ doc/changes/xrt/mr.721.4.md | 4 ++++ doc/changes/xrt/mr.721.5.md | 3 +++ 9 files changed, 22 insertions(+) create mode 100644 doc/changes/auxiliary/mr.721.1.md create mode 100644 doc/changes/auxiliary/mr.721.2.md create mode 100644 doc/changes/auxiliary/mr.721.3.md create mode 100644 doc/changes/compositor/mr.721.md create mode 100644 doc/changes/xrt/mr.721.1.md create mode 100644 doc/changes/xrt/mr.721.2.md create mode 100644 doc/changes/xrt/mr.721.3.md create mode 100644 doc/changes/xrt/mr.721.4.md create mode 100644 doc/changes/xrt/mr.721.5.md diff --git a/doc/changes/auxiliary/mr.721.1.md b/doc/changes/auxiliary/mr.721.1.md new file mode 100644 index 000000000..0d29ad43f --- /dev/null +++ b/doc/changes/auxiliary/mr.721.1.md @@ -0,0 +1 @@ +u/time: Add helper comparison functions. diff --git a/doc/changes/auxiliary/mr.721.2.md b/doc/changes/auxiliary/mr.721.2.md new file mode 100644 index 000000000..8721d09f0 --- /dev/null +++ b/doc/changes/auxiliary/mr.721.2.md @@ -0,0 +1 @@ +vulkan: Add fence import function. diff --git a/doc/changes/auxiliary/mr.721.3.md b/doc/changes/auxiliary/mr.721.3.md new file mode 100644 index 000000000..d24c9ee60 --- /dev/null +++ b/doc/changes/auxiliary/mr.721.3.md @@ -0,0 +1,3 @@ +u/timing: A rather large refactor that turns makes the rendering timing helper +be more like the frame timing helper. This also makes the rendering timing +adjust the frame timing of the app so that latency is reduced. diff --git a/doc/changes/compositor/mr.721.md b/doc/changes/compositor/mr.721.md new file mode 100644 index 000000000..3ab1fc17f --- /dev/null +++ b/doc/changes/compositor/mr.721.md @@ -0,0 +1,4 @@ +multi: Introduce a new multi client compositor layer, this allows rendering code +to be moved from the IPC layer into the compositor, separating concerns. The +main compositor always uses the multi client compositor, as it gives us a async +render loop for free. diff --git a/doc/changes/xrt/mr.721.1.md b/doc/changes/xrt/mr.721.1.md new file mode 100644 index 000000000..df57756ef --- /dev/null +++ b/doc/changes/xrt/mr.721.1.md @@ -0,0 +1,2 @@ +Add `xrt_compositor_fence` interface to handle service and client render +syncronisation. diff --git a/doc/changes/xrt/mr.721.2.md b/doc/changes/xrt/mr.721.2.md new file mode 100644 index 000000000..830d321ac --- /dev/null +++ b/doc/changes/xrt/mr.721.2.md @@ -0,0 +1 @@ +Add `XRT_ERROR_THREADING_INIT_FAILURE` a new threading related error code. diff --git a/doc/changes/xrt/mr.721.3.md b/doc/changes/xrt/mr.721.3.md new file mode 100644 index 000000000..3c5ec00e7 --- /dev/null +++ b/doc/changes/xrt/mr.721.3.md @@ -0,0 +1,3 @@ +Add alternative functions to `xrt_compositor::wait_frame` called +`xrt_compositor::predict_frame` and `xrt_compositor::mark_frame` these allow one +to do frame timing without having to block on the service side. diff --git a/doc/changes/xrt/mr.721.4.md b/doc/changes/xrt/mr.721.4.md new file mode 100644 index 000000000..b3811a302 --- /dev/null +++ b/doc/changes/xrt/mr.721.4.md @@ -0,0 +1,4 @@ +Add `xrt_multi_compositor_control` that allows the `xrt_system_compositor` to +expose a interface that the IPC layer can use to manage multiple clients +without having to do the rendering. This allows us to move a lot of the code +out the IPC layer and make it more about just passing calls. diff --git a/doc/changes/xrt/mr.721.5.md b/doc/changes/xrt/mr.721.5.md new file mode 100644 index 000000000..f9e3088ac --- /dev/null +++ b/doc/changes/xrt/mr.721.5.md @@ -0,0 +1,3 @@ +Pass `XrFrameEndInfo::displayTime` to `xrt_compositor::layer_begin` so that the +compositor can correctly schedule frames, most importantly do not display them +too early that might lead to stutter. From 08e39a1a0e8a7d2fe8572e7b20480a2c0662dfc8 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 8 Apr 2021 19:34:39 +0200 Subject: [PATCH 315/883] d/survive: Increase device detection timeout With libsurvive 20127ef1bbb9206c9b429de47b891fc71d9df355 it can take a bit longer for devices to appear. --- src/xrt/drivers/survive/survive_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index e575ce167..9b03a8df5 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -46,7 +46,7 @@ // reading usb config takes libsurvive about 50ms per device // to be safe, we wait 500 ms after the last device has been initialized -#define WAIT_TIMEOUT 0.5f +#define WAIT_TIMEOUT .75f // index in sys->controllers[] array #define SURVIVE_LEFT_CONTROLLER_INDEX 0 From e7f82c297ab8583052ba3a4f970805c832c23eb4 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 8 Apr 2021 20:32:55 +0200 Subject: [PATCH 316/883] st/oxr: Fix running when only one hand suports hand tracking --- src/xrt/state_trackers/oxr/oxr_api_session.c | 5 +++-- src/xrt/state_trackers/oxr/oxr_session.c | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_api_session.c b/src/xrt/state_trackers/oxr/oxr_api_session.c index c76254c4c..a07b6995d 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_session.c +++ b/src/xrt/state_trackers/oxr/oxr_api_session.c @@ -298,11 +298,12 @@ oxr_hand_tracker_create(struct oxr_logger *log, hand_tracker->hand = createInfo->hand; hand_tracker->hand_joint_set = createInfo->handJointSet; - //! @todo: Implement choice when more than one device has hand tracking + //! @todo: move hand tracking device selection to oxr_system. + // if no xdev with hand tracking is found, create hand tracker without xdev. for (uint32_t i = 0; i < sess->sys->num_xdevs; i++) { struct xrt_device *xdev = sess->sys->xdevs[i]; - if (!xdev->hand_tracking_supported) { + if (!xdev || !xdev->hand_tracking_supported) { continue; } diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 06c5ef83a..b1ae59065 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -2155,6 +2155,11 @@ oxr_session_hand_joints(struct oxr_logger *log, XrHandJointVelocitiesEXT *vel = OXR_GET_OUTPUT_FROM_CHAIN(locations, XR_TYPE_HAND_JOINT_VELOCITIES_EXT, XrHandJointVelocitiesEXT); + if (hand_tracker->xdev == NULL) { + locations->isActive = false; + return XR_SUCCESS; + } + struct xrt_device *xdev = hand_tracker->xdev; enum xrt_input_name name = hand_tracker->input_name; From d7f0380f53a20d29b665972f19182417f4621fa8 Mon Sep 17 00:00:00 2001 From: zhibinw Date: Tue, 6 Apr 2021 17:59:50 +0800 Subject: [PATCH 317/883] ipc/android: Dup the socket fd in native side, close the fd on java side. --- .../main/java/org/freedesktop/monado/ipc/Client.java | 10 ++++++++-- src/xrt/ipc/client/ipc_client_instance.c | 8 ++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java index 068c50101..7bd217dbc 100644 --- a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java +++ b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java @@ -100,8 +100,14 @@ public class Client implements ServiceConnection { } intent = null; - //! @todo do we close this first? - fd = null; + if (fd != null) { + try { + fd.close(); + } catch (IOException e) { + e.printStackTrace(); + } + fd = null; + } } /** diff --git a/src/xrt/ipc/client/ipc_client_instance.c b/src/xrt/ipc/client/ipc_client_instance.c index 94ff7cb5b..5dce95eed 100644 --- a/src/xrt/ipc/client/ipc_client_instance.c +++ b/src/xrt/ipc/client/ipc_client_instance.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -91,6 +92,13 @@ ipc_connect(struct ipc_connection *ipc_c) IPC_ERROR(ipc_c, "Service Connect error!"); return false; } + // The ownership belongs to the Java object. Dup because the fd will be + // closed when client destroy. + socket = dup(socket); + if (socket < 0) { + IPC_ERROR(ipc_c, "Failed to dup fd with error %d!", errno); + return false; + } ipc_c->imc.socket_fd = socket; ipc_c->imc.ll = ipc_c->ll; From b56441702cce2b399bdd89c95618d786d4e61f90 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 6 Apr 2021 11:30:25 -0500 Subject: [PATCH 318/883] st/oxr: Clean up Android message. --- src/xrt/state_trackers/oxr/oxr_api_instance.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_api_instance.c b/src/xrt/state_trackers/oxr/oxr_api_instance.c index 49250b0dc..ec3431bde 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_api_instance.c @@ -64,9 +64,8 @@ oxr_check_android_extensions(struct oxr_logger *log, const XrInstanceCreateInfo if (!foundAndroidExtension) { return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "(createInfo->enabledExtensionNames) " - "Mandatory platform-specific " - "extension" - " " XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME " not specified"); + "Mandatory platform-specific extension " XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME + " not specified"); } { From 322f6d473a1f274ba2ac862c247dd79ad1efd7a8 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 6 Apr 2021 11:34:50 -0500 Subject: [PATCH 319/883] util: Don't try to use $HOME or $XDG_CONFIG_HOME on Android. --- src/xrt/auxiliary/util/u_config_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 826d9aed7..968136db3 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -39,7 +39,7 @@ u_config_json_close(struct u_config_json *json) void u_config_json_open_or_create_main_file(struct u_config_json *json) { -#ifdef XRT_OS_LINUX +#if defined(XRT_OS_LINUX) && !defined(XRT_OS_ANDROID) char tmp[1024]; ssize_t ret = u_file_get_path_in_config_dir(CONFIG_FILE_NAME, tmp, sizeof(tmp)); if (ret <= 0) { From dde274b13eedcf0866e9bae6780515f54966832e Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 6 Apr 2021 16:27:24 -0500 Subject: [PATCH 320/883] comp: Fix typo. --- src/xrt/compositor/main/comp_settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_settings.h b/src/xrt/compositor/main/comp_settings.h index 52c6c451b..34eafa1cd 100644 --- a/src/xrt/compositor/main/comp_settings.h +++ b/src/xrt/compositor/main/comp_settings.h @@ -86,7 +86,7 @@ struct comp_settings bool wireframe; } debug; - //! Procentage to scale the viewport by. + //! Percentage to scale the viewport by. double viewport_scale; //! Not used with direct mode. From cf08cbba78ff51b51622f575a2bed4b8528ad196 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 6 Apr 2021 17:56:49 -0500 Subject: [PATCH 321/883] aux/vk: Docs for Vulkan native import helpers. --- src/xrt/auxiliary/vk/vk_helpers.h | 39 +++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/xrt/auxiliary/vk/vk_helpers.h b/src/xrt/auxiliary/vk/vk_helpers.h index 43941f57a..77c8d6b40 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.h +++ b/src/xrt/auxiliary/vk/vk_helpers.h @@ -430,6 +430,24 @@ vk_alloc_and_bind_image_memory(struct vk_bundle *vk, VkDeviceSize *out_size); /*! + * + * @brief Creates a Vulkan device memory and image from a native graphics buffer handle. + * + * In case of error, ownership is never transferred and the caller should close the handle themselves. + * + * In case of success, the underlying Vulkan functionality's ownership semantics apply: ownership of the @p image_native + * handle may have transferred, a reference may have been added, or the Vulkan objects may rely on the caller to keep + * the native handle alive until the Vulkan objects are destroyed. Which option applies depends on the particular native + * handle type used. + * + * See the corresponding specification texts: + * + * - Windows: + * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VkImportMemoryWin32HandleInfoKHR + * - Linux: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VkImportMemoryFdInfoKHR + * - Android: + * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VkImportAndroidHardwareBufferInfoANDROID + * * @ingroup aux_vk */ VkResult @@ -440,12 +458,33 @@ vk_create_image_from_native(struct vk_bundle *vk, VkDeviceMemory *out_mem); /*! + * @brief Creates a Vulkan fence from a native graphics sync handle. + * + * In case of error, ownership is never transferred and the caller should close the handle themselves. + * + * In case of success, the underlying Vulkan functionality's ownership semantics apply: ownership of the @p native + * handle may have transferred, a reference may have been added, or the Vulkan object may rely on the caller to keep the + * native handle alive until the Vulkan object is destroyed. Which option applies depends on the particular native + * handle type used. + * + * See the corresponding Vulkan specification text: + * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-fences-importing + * * @ingroup aux_vk */ VkResult vk_create_fence_sync_from_native(struct vk_bundle *vk, xrt_graphics_sync_handle_t native, VkFence *out_fence); /*! + * @brief Creates a Vulkan semaphore from a native graphics sync handle. + * + * In case of error, ownership is never transferred and the caller should close the handle themselves. + * + * In case of success, the underlying Vulkan functionality's ownership semantics apply: ownership of the @p native + * handle may have transferred, a reference may have been added, or the Vulkan object may rely on the caller to keep the + * native handle alive until the Vulkan object is destroyed. Which option applies depends on the particular native + * handle type used. + * * @ingroup aux_vk */ VkResult From 88f1e51d7685ccca502461690173715fb36ce82a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 16 Mar 2021 17:28:23 -0500 Subject: [PATCH 322/883] .gitignore: Update. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d3b8d96dc..497b74509 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ local.properties .cxx .settings .project +.classpath gradlew gradlew.bat From 111d353662b4a9a6d6028f3157c7f8fdf3f0f8c7 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 9 Apr 2021 18:11:28 -0500 Subject: [PATCH 323/883] cmake: Make the git version detection more robust --- cmake/GetGitRevisionDescription.cmake | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake index db291a9b2..4fbd90db7 100644 --- a/cmake/GetGitRevisionDescription.cmake +++ b/cmake/GetGitRevisionDescription.cmake @@ -3,7 +3,7 @@ # These functions force a re-configure on each git commit so that you can # trust the values of the variables in your build system. # -# get_git_head_revision( [ ...]) +# get_git_head_revision( [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR]) # # Returns the refspec and sha hash of the current head revision # @@ -68,7 +68,7 @@ function(_git_find_closest_git_dir _start_dir _git_dir_var) while(NOT EXISTS "${git_dir}") # .git dir not found, search parent directories set(git_previous_parent "${cur_dir}") - get_filename_component(cur_dir ${cur_dir} DIRECTORY) + get_filename_component(cur_dir "${cur_dir}" DIRECTORY) if(cur_dir STREQUAL git_previous_parent) # We have reached the root directory, we are not in git set(${_git_dir_var} @@ -86,10 +86,15 @@ endfunction() function(get_git_head_revision _refspecvar _hashvar) _git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR) + if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR") + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE) + else() + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE) + endif() if(NOT "${GIT_DIR}" STREQUAL "") file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}" "${GIT_DIR}") - if("${_relative_to_source_dir}" MATCHES "[.][.]") + if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR) # We've gone above the CMake root dir. set(GIT_DIR "") endif() From 1ce306cb559ce4324083d29fcb6913102e94d9db Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 9 Apr 2021 18:11:46 -0500 Subject: [PATCH 324/883] cmake: Fix include dir scope for comp_multi --- src/xrt/compositor/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index 602805459..d85691e44 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -211,7 +211,7 @@ endif() add_library(comp_multi STATIC ${MULTI_SOURCE_FILES}) target_link_libraries(comp_multi PUBLIC xrt-interfaces PRIVATE aux_util aux_os) -target_include_directories(comp_multi PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(comp_multi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) if(XRT_FEATURE_COMPOSITOR_MAIN) From 0450e317e181dc60ceef8f7d031c41ad0c6a1612 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 9 Apr 2021 18:16:39 -0500 Subject: [PATCH 325/883] cmake: prober requires drv_multi now. --- src/xrt/state_trackers/prober/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/prober/CMakeLists.txt b/src/xrt/state_trackers/prober/CMakeLists.txt index 34691b887..4f57bcdd5 100644 --- a/src/xrt/state_trackers/prober/CMakeLists.txt +++ b/src/xrt/state_trackers/prober/CMakeLists.txt @@ -39,6 +39,7 @@ target_link_libraries(st_prober PUBLIC xrt-interfaces ) target_link_libraries(st_prober PRIVATE + drv_multi aux_util aux_os aux_tracking @@ -88,4 +89,4 @@ if(XRT_BUILD_DRIVER_REMOTE) target_link_libraries(st_prober PRIVATE drv_remote ) -endif() \ No newline at end of file +endif() From d6d933f20dd55389c26535be14b825f349a887ef Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 9 Apr 2021 18:16:54 -0500 Subject: [PATCH 326/883] xrt: Fix doxygen warnings. --- src/xrt/include/xrt/xrt_compositor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h index 44f6d4719..0fe494520 100644 --- a/src/xrt/include/xrt/xrt_compositor.h +++ b/src/xrt/include/xrt/xrt_compositor.h @@ -695,7 +695,7 @@ struct xrt_compositor xrt_result_t (*end_session)(struct xrt_compositor *xc); /*! - * This function and @ref mark_woke function calls are a alternative to + * This function and @ref mark_frame function calls are a alternative to * @ref wait_frame. * * The only requirement on the compositor for the @p frame_id @@ -715,7 +715,7 @@ struct xrt_compositor uint64_t *out_predicted_display_period_ns); /*! - * This function and @ref mark_woke function calls are a alternative to + * This function and @ref predict_frame function calls are a alternative to * @ref wait_frame. * * The client calls this function to mark that it woke up from waiting From c906151fb1d8d36d355ce46b0824652a73527731 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 9 Apr 2021 18:18:54 -0500 Subject: [PATCH 327/883] util: Fix doxygen warnings --- src/xrt/auxiliary/util/u_timing.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing.h b/src/xrt/auxiliary/util/u_timing.h index d0f704f04..d1ee0f5c8 100644 --- a/src/xrt/auxiliary/util/u_timing.h +++ b/src/xrt/auxiliary/util/u_timing.h @@ -210,7 +210,7 @@ struct u_render_timing * This is called from `xrWaitFrame`, but it does not do any waiting, the caller * should wait till `out_wake_up_time`. * - * @param urth Render timing helper. + * @param urt Render timing helper. * @param[out] out_frame_id Frame ID of this predicted frame. * @param[out] out_wake_up_time When the client should be woken up. * @param[out] out_predicted_display_time Predicted display time. @@ -251,7 +251,7 @@ struct u_render_timing * to be able to predict one or more frames into the future anyways. But * preferably as soon as the main loop wakes up from wait frame. * - * @param urth Self pointer + * @param urt Self pointer * @param predicted_display_time_ns Predicted display time for this sample. * @param predicted_display_period_ns Predicted display period for this sample. * @param extra_ns Time between display and when this sample @@ -270,7 +270,7 @@ struct u_render_timing }; /*! - * @copydoc u_frame_timing::predict + * @copydoc u_render_timing::predict * * Helper for calling through the function pointer. * @@ -288,7 +288,7 @@ u_rt_predict(struct u_render_timing *urt, } /*! - * @copydoc u_frame_timing::mark_point + * @copydoc u_render_timing::mark_point * * Helper for calling through the function pointer. * @@ -302,7 +302,7 @@ u_rt_mark_point(struct u_render_timing *urt, int64_t frame_id, enum u_timing_poi } /*! - * @copydoc u_frame_timing::mark_discarded + * @copydoc u_render_timing::mark_discarded * * Helper for calling through the function pointer. * @@ -316,7 +316,7 @@ u_rt_mark_discarded(struct u_render_timing *urt, int64_t frame_id) } /*! - * @copydoc u_frame_timing::mark_delivered + * @copydoc u_render_timing::mark_delivered * * Helper for calling through the function pointer. * @@ -330,7 +330,7 @@ u_rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) } /*! - * @copydoc u_frame_timing::info + * @copydoc u_render_timing::info * * Helper for calling through the function pointer. * From c591fe770ef4cde50692a5d2356222e5de06f644 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 9 Apr 2021 18:20:49 -0500 Subject: [PATCH 328/883] doc: Clean up render timing docs. --- doc/frame-timing.md | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/doc/frame-timing.md b/doc/frame-timing.md index 61a4da868..30026fb3c 100644 --- a/doc/frame-timing.md +++ b/doc/frame-timing.md @@ -5,7 +5,6 @@ Copyright 2021, Collabora, Ltd. and the Monado contributors SPDX-License-Identifier: BSL-1.0 --> - A "brief" overview of the various time-points that a frame goes through, from when the application gets go ahead to render the frame to when pixels are turned into photons. This only a single frame, where all of the timings are hit and the @@ -28,25 +27,22 @@ scanout starting to the vblank period (like for the Index). * During the vblank period the display lights up turning the pixels into photons. We refer to this time as **display**, same as in OpenXR. - The names for timepoints are chosen to align with the naming in [`VK_GOOGLE_display_timing`][], reading that extension can provide further information. - ## Main compositor perspective - * @ref xrt_comp_wait_frame - It is within this function that the frame timing is - predicted, see @ref u_frame_timing_predict. The compositor will then wait to - **waku_up** time and then return from this function. - * @ref xrt_comp_begin_frame - The app or IPC server calls this function when it - is done with CPU work and ready to do GPU work. - * @ref xrt_comp_discard_frame - The frame is discarded. - * @ref xrt_comp_layer_begin - Called during transfers of layers. - * @ref xrt_comp_layer_stereo_projection - This and other layer functions are - called to list the layers the compositor should render. - * @ref xrt_comp_layer_commit - The compositor starts to render the frame, - trying to hit the **present** time. - +* @ref xrt_comp_wait_frame - It is within this function that the frame timing is + predicted, see @ref u_rt_predict. The compositor will then wait to + **wake_up** time and then return from this function. +* @ref xrt_comp_begin_frame - The app or IPC server calls this function when it + is done with CPU work and ready to do GPU work. +* @ref xrt_comp_discard_frame - The frame is discarded. +* @ref xrt_comp_layer_begin - Called during transfers of layers. +* @ref xrt_comp_layer_stereo_projection - This and other layer functions are + called to list the layers the compositor should render. +* @ref xrt_comp_layer_commit - The compositor starts to render the frame, + trying to hit the **present** time. [`VK_GOOGLE_display_timing`]: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_GOOGLE_display_timing.html From 6f93b4c718987c3009cc5ea39dc4c6d172ac5a1a Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Sun, 11 Apr 2021 04:08:01 -0500 Subject: [PATCH 329/883] inc/xrt: switch blend mode to array In order of how preferred they are. --- src/xrt/include/xrt/xrt_defines.h | 13 +++++++------ src/xrt/include/xrt/xrt_device.h | 6 ++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/xrt/include/xrt/xrt_defines.h b/src/xrt/include/xrt/xrt_defines.h index e5a0fe985..c91b9fdcb 100644 --- a/src/xrt/include/xrt/xrt_defines.h +++ b/src/xrt/include/xrt/xrt_defines.h @@ -33,19 +33,20 @@ struct xrt_reference }; /*! - * Which blend mode does the device support, used as both a bitfield and value. + * Blend mode that the device supports, exact mirror of XrEnvironmentBlendMode * * @ingroup xrt_iface */ enum xrt_blend_mode { - // clang-format off - XRT_BLEND_MODE_OPAQUE = 1 << 0, - XRT_BLEND_MODE_ADDITIVE = 1 << 1, - XRT_BLEND_MODE_ALPHA_BLEND = 1 << 2, - // clang-format on + XRT_BLEND_MODE_OPAQUE = 1, + XRT_BLEND_MODE_ADDITIVE = 2, + XRT_BLEND_MODE_ALPHA_BLEND = 3, + XRT_BLEND_MODE_MAX_ENUM, }; +#define XRT_MAX_DEVICE_BLEND_MODES 3 + /*! * Which distortion model does the device expose, * used both as a bitfield and value. diff --git a/src/xrt/include/xrt/xrt_device.h b/src/xrt/include/xrt/xrt_device.h index f33631a67..760dd78e5 100644 --- a/src/xrt/include/xrt/xrt_device.h +++ b/src/xrt/include/xrt/xrt_device.h @@ -4,6 +4,7 @@ * @file * @brief Header defining an xrt HMD device. * @author Jakob Bornecrantz + * @author Moses Turner * @ingroup xrt_iface */ @@ -106,9 +107,10 @@ struct xrt_hmd_parts struct xrt_view views[2]; /*! - * Supported blend modes, a bitfield. + * Array of supported blend modes. */ - enum xrt_blend_mode blend_mode; + enum xrt_blend_mode blend_modes[XRT_MAX_DEVICE_BLEND_MODES]; + size_t num_blend_modes; /*! * Distortion information. From 1062ef35fc304d13cc661900f3f469ce55764690 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Fri, 9 Apr 2021 19:28:26 -0500 Subject: [PATCH 330/883] st/oxr: switch blend mode to array --- src/xrt/state_trackers/oxr/oxr_session.c | 8 ++++---- src/xrt/state_trackers/oxr/oxr_system.c | 23 +++++++++++------------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index b1ae59065..feada092a 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -25,6 +25,7 @@ #include "util/u_debug.h" #include "util/u_misc.h" #include "util/u_time.h" +#include "util/u_verify.h" #include "math/m_api.h" #include "math/m_mathinclude.h" @@ -1775,7 +1776,6 @@ oxr_session_frame_end(struct oxr_logger *log, struct oxr_session *sess, const Xr return oxr_session_success_result(sess); } - /* * Blend mode. * XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED must always be reported, @@ -1783,16 +1783,16 @@ oxr_session_frame_end(struct oxr_logger *log, struct oxr_session *sess, const Xr */ enum xrt_blend_mode blend_mode = oxr_blend_mode_to_xrt(frameEndInfo->environmentBlendMode); + struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head); - if (blend_mode == 0) { + if (!u_verify_blend_mode_valid(blend_mode)) { return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "(frameEndInfo->environmentBlendMode == " "0x%08x) unknown environment blend mode", frameEndInfo->environmentBlendMode); } - struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head); - if ((blend_mode & xdev->hmd->blend_mode) == 0) { + if (!u_verify_blend_mode_supported(xdev, blend_mode)) { //! @todo Make integer print to string. return oxr_error(log, XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED, "(frameEndInfo->environmentBlendMode == %u) " diff --git a/src/xrt/state_trackers/oxr/oxr_system.c b/src/xrt/state_trackers/oxr/oxr_system.c index 1003cdfab..092702216 100644 --- a/src/xrt/state_trackers/oxr/oxr_system.c +++ b/src/xrt/state_trackers/oxr/oxr_system.c @@ -15,6 +15,7 @@ #include "xrt/xrt_device.h" #include "util/u_debug.h" +#include "util/u_verify.h" #include "oxr_objects.h" #include "oxr_logger.h" @@ -86,6 +87,8 @@ oxr_system_get_by_id(struct oxr_logger *log, struct oxr_instance *inst, XrSystem return XR_SUCCESS; } + + XrResult oxr_system_fill_in(struct oxr_logger *log, struct oxr_instance *inst, XrSystemId systemId, struct oxr_system *sys) { @@ -151,20 +154,16 @@ oxr_system_fill_in(struct oxr_logger *log, struct oxr_instance *inst, XrSystemId struct xrt_device *head = GET_XDEV_BY_ROLE(sys, head); - uint32_t i = 0; - if (head->hmd->blend_mode & XRT_BLEND_MODE_OPAQUE) { - sys->blend_modes[i++] = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; - } - if (head->hmd->blend_mode & XRT_BLEND_MODE_ADDITIVE) { - sys->blend_modes[i++] = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE; - } - if (head->hmd->blend_mode & XRT_BLEND_MODE_ALPHA_BLEND) { - sys->blend_modes[i++] = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND; - } - sys->num_blend_modes = i; + assert(head->hmd->num_blend_modes <= XRT_MAX_DEVICE_BLEND_MODES); + assert(head->hmd->num_blend_modes != 0); - assert(i < ARRAY_SIZE(sys->blend_modes)); + for (size_t i = 0; i < head->hmd->num_blend_modes; i++) { + assert(u_verify_blend_mode_valid(head->hmd->blend_modes[i])); + sys->blend_modes[i] = (XrEnvironmentBlendMode)head->hmd->blend_modes[i]; + } + sys->num_blend_modes = (uint32_t)head->hmd->num_blend_modes; + assert(sys->num_blend_modes <= ARRAY_SIZE(sys->blend_modes)); return XR_SUCCESS; } From c53eba34d068e22b1529db2427bf8f0db46b0f3a Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Fri, 9 Apr 2021 19:36:43 -0500 Subject: [PATCH 331/883] ipc: switch blend mode to array --- src/xrt/ipc/client/ipc_client_hmd.c | 5 ++++- src/xrt/ipc/server/ipc_server_process.c | 8 +++++++- src/xrt/ipc/shared/ipc_protocol.h | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/xrt/ipc/client/ipc_client_hmd.c b/src/xrt/ipc/client/ipc_client_hmd.c index edd0b4efa..f9305c609 100644 --- a/src/xrt/ipc/client/ipc_client_hmd.c +++ b/src/xrt/ipc/client/ipc_client_hmd.c @@ -169,8 +169,11 @@ ipc_client_hmd_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin * return NULL; } #endif + for (int i = 0; i < XRT_MAX_DEVICE_BLEND_MODES; i++) { + ich->base.hmd->blend_modes[i] = ipc_c->ism->hmd.blend_modes[i]; + } + ich->base.hmd->num_blend_modes = ipc_c->ism->hmd.num_blend_modes; - ich->base.hmd->blend_mode = ipc_c->ism->hmd.blend_mode; ich->base.hmd->views[0].display.w_pixels = ipc_c->ism->hmd.views[0].display.w_pixels; ich->base.hmd->views[0].display.h_pixels = ipc_c->ism->hmd.views[0].display.h_pixels; ich->base.hmd->views[0].fov = ipc_c->ism->hmd.views[0].fov; diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index 089cfc04c..4ee940de8 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -20,6 +20,7 @@ #include "util/u_misc.h" #include "util/u_debug.h" #include "util/u_trace_marker.h" +#include "util/u_verify.h" #include "shared/ipc_shmem.h" #include "server/ipc_server.h" @@ -252,7 +253,12 @@ init_shm(struct ipc_server *s) ism->hmd.views[1].display.h_pixels = xdev->hmd->views[1].display.h_pixels; ism->hmd.views[1].fov = xdev->hmd->views[1].fov; - ism->hmd.blend_mode = xdev->hmd->blend_mode; + for (size_t i = 0; i < xdev->hmd->num_blend_modes; i++) { + // Not super necessary, we also do this assert in oxr_system.c + assert(u_verify_blend_mode_valid(xdev->hmd->blend_modes[i])); + ism->hmd.blend_modes[i] = xdev->hmd->blend_modes[i]; + } + ism->hmd.num_blend_modes = xdev->hmd->num_blend_modes; } // Setup the tracking origin. diff --git a/src/xrt/ipc/shared/ipc_protocol.h b/src/xrt/ipc/shared/ipc_protocol.h index 4625b697d..5d3060e5a 100644 --- a/src/xrt/ipc/shared/ipc_protocol.h +++ b/src/xrt/ipc/shared/ipc_protocol.h @@ -225,7 +225,8 @@ struct ipc_shared_memory */ struct xrt_fov fov; } views[2]; - enum xrt_blend_mode blend_mode; + enum xrt_blend_mode blend_modes[XRT_MAX_DEVICE_BLEND_MODES]; + size_t num_blend_modes; } hmd; struct xrt_input inputs[IPC_SHARED_MAX_INPUTS]; From 36a48bd62b55ca8a628646146402c34770969fe6 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Fri, 9 Apr 2021 19:30:00 -0500 Subject: [PATCH 332/883] aux/util: switch blend mode to array --- src/xrt/auxiliary/CMakeLists.txt | 1 + src/xrt/auxiliary/meson.build | 1 + src/xrt/auxiliary/util/u_device.c | 5 ++++- src/xrt/auxiliary/util/u_distortion.c | 6 +++-- src/xrt/auxiliary/util/u_verify.h | 32 +++++++++++++++++++++++++++ 5 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 src/xrt/auxiliary/util/u_verify.h diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index 0827faac9..fa92cd003 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -158,6 +158,7 @@ set(UTIL_SOURCE_FILES util/u_var.h util/u_config_json.c util/u_config_json.h + util/u_verify.h ) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/util/u_git_tag.c.in" "${CMAKE_CURRENT_BINARY_DIR}/u_git_tag.c" @ONLY) diff --git a/src/xrt/auxiliary/meson.build b/src/xrt/auxiliary/meson.build index aac2fc21a..6d7254c58 100644 --- a/src/xrt/auxiliary/meson.build +++ b/src/xrt/auxiliary/meson.build @@ -64,6 +64,7 @@ lib_aux_util = static_library( 'util/u_var.h', 'util/u_config_json.c', 'util/u_config_json.h', + 'util/u_verify.h', ) + [ u_git_tag_c, ], diff --git a/src/xrt/auxiliary/util/u_device.c b/src/xrt/auxiliary/util/u_device.c index 27d131c2c..3abc947f9 100644 --- a/src/xrt/auxiliary/util/u_device.c +++ b/src/xrt/auxiliary/util/u_device.c @@ -149,7 +149,10 @@ u_device_setup_split_side_by_side(struct xrt_device *xdev, const struct u_device }; // Common - xdev->hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; + size_t idx = 0; + xdev->hmd->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE; + xdev->hmd->num_blend_modes = idx; + if (xdev->hmd->distortion.models == 0) { xdev->hmd->distortion.models = XRT_DISTORTION_MODEL_NONE; xdev->hmd->distortion.preferred = XRT_DISTORTION_MODEL_NONE; diff --git a/src/xrt/auxiliary/util/u_distortion.c b/src/xrt/auxiliary/util/u_distortion.c index 1d4790f28..71384608e 100644 --- a/src/xrt/auxiliary/util/u_distortion.c +++ b/src/xrt/auxiliary/util/u_distortion.c @@ -29,8 +29,10 @@ u_distortion_cardboard_calculate(const struct u_cardboard_distortion_arguments * uint32_t h_pixels = args->screen.h_pixels; // Base assumption, the driver can change afterwards. - if (parts->blend_mode == 0) { - parts->blend_mode = XRT_BLEND_MODE_OPAQUE; + if (parts->num_blend_modes == 0) { + size_t idx = 0; + parts->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE; + parts->num_blend_modes = idx; } // Use the full screen. diff --git a/src/xrt/auxiliary/util/u_verify.h b/src/xrt/auxiliary/util/u_verify.h new file mode 100644 index 000000000..5270f9c3c --- /dev/null +++ b/src/xrt/auxiliary/util/u_verify.h @@ -0,0 +1,32 @@ +// Copyright 2021, Collabora, Ltd. +// Copyright 2021, Moses Turner. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Tiny file to verify things + * @author Moses Turner + * @author Jakob Bornecrantz + * @ingroup aux_util + */ + +#pragma once +#include "xrt/xrt_defines.h" +#include "xrt/xrt_device.h" + +static inline bool +u_verify_blend_mode_valid(enum xrt_blend_mode blend_mode) +{ + return ((blend_mode == XRT_BLEND_MODE_OPAQUE) || (blend_mode == XRT_BLEND_MODE_ADDITIVE) || + (blend_mode == XRT_BLEND_MODE_ALPHA_BLEND)); +} + +static inline bool +u_verify_blend_mode_supported(struct xrt_device *xdev, enum xrt_blend_mode blend_mode) +{ + for (size_t i = 0; i < xdev->hmd->num_blend_modes; i++) { + if (xdev->hmd->blend_modes[i] == blend_mode) { + return true; + } + } + return false; +} From 7cd2a337375a550d1ac5b715e90f7c0c5fd578c2 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Sun, 11 Apr 2021 04:08:20 -0500 Subject: [PATCH 333/883] drivers: switch blend mode to array --- src/xrt/drivers/hdk/hdk_device.cpp | 5 ++++- src/xrt/drivers/illixr/illixr_device.cpp | 6 +++++- src/xrt/drivers/north_star/ns_hmd.c | 14 ++++++++++++++ src/xrt/drivers/ohmd/oh_device.c | 8 +++++--- src/xrt/drivers/survive/survive_driver.c | 4 +++- src/xrt/drivers/vive/vive_device.c | 5 ++++- 6 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/xrt/drivers/hdk/hdk_device.cpp b/src/xrt/drivers/hdk/hdk_device.cpp index 6cd855456..883eaab0c 100644 --- a/src/xrt/drivers/hdk/hdk_device.cpp +++ b/src/xrt/drivers/hdk/hdk_device.cpp @@ -321,7 +321,10 @@ hdk_device_create(struct os_hid_device *dev, enum HDK_VARIANT variant) (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); struct hdk_device *hd = U_DEVICE_ALLOCATE(struct hdk_device, flags, 1, 0); - hd->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; + size_t idx = 0; + hd->base.hmd->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE; + hd->base.hmd->num_blend_modes = idx; + hd->base.update_inputs = hdk_device_update_inputs; hd->base.get_tracked_pose = hdk_device_get_tracked_pose; hd->base.get_view_pose = hdk_device_get_view_pose; diff --git a/src/xrt/drivers/illixr/illixr_device.cpp b/src/xrt/drivers/illixr/illixr_device.cpp index 2e69b31b7..ecc7cd250 100644 --- a/src/xrt/drivers/illixr/illixr_device.cpp +++ b/src/xrt/drivers/illixr/illixr_device.cpp @@ -177,7 +177,11 @@ illixr_hmd_create(const char *path_in, const char *comp_in) dh->base.destroy = illixr_hmd_destroy; dh->base.name = XRT_DEVICE_GENERIC_HMD; dh->base.device_type = XRT_DEVICE_TYPE_HMD; - dh->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; + + size_t idx = 0; + dh->base.hmd->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE; + dh->base.hmd->num_blend_modes = idx; + dh->pose.orientation.w = 1.0f; // All other values set to zero. dh->print_spew = debug_get_bool_option_illixr_spew(); dh->print_debug = debug_get_bool_option_illixr_debug(); diff --git a/src/xrt/drivers/north_star/ns_hmd.c b/src/xrt/drivers/north_star/ns_hmd.c index b546c57fa..b9dc958f3 100644 --- a/src/xrt/drivers/north_star/ns_hmd.c +++ b/src/xrt/drivers/north_star/ns_hmd.c @@ -553,6 +553,20 @@ ns_hmd_create(const char *config_path) ns->base.orientation_tracking_supported = true; ns->base.device_type = XRT_DEVICE_TYPE_HMD; + size_t idx = 0; + // Preferred; most North Stars are see-through. + ns->base.hmd->blend_modes[idx++] = XRT_BLEND_MODE_ADDITIVE; + + // XRT_BLEND_MODE_OPAQUE is not preferred and kind of a lie, but we use North Star for VR sometimes despite its + // see-through display. And there's nothing stopping you from covering up the outside of the reflector, turning + // it into an opaque headset. As most VR apps I've encountered require BLEND_MODE_OPAQUE to be an option, we + // need to support it. + ns->base.hmd->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE; + + // Not supporting ALPHA_BLEND for now, because I know nothing about it and want to avoid unintended + // consequences. As soon as you have a specific reason to support it, go ahead and support it. + ns->base.hmd->num_blend_modes = idx; + return &ns->base; cleanup: diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c index cc53fbcfd..bdd4c518b 100644 --- a/src/xrt/drivers/ohmd/oh_device.c +++ b/src/xrt/drivers/ohmd/oh_device.c @@ -839,11 +839,13 @@ create_hmd(ohmd_context *ctx, int device_idx, int device_flags) ohd->base.compute_distortion = compute_distortion_openhmd; // Which blend modes does the device support. - ohd->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; + + size_t bm_idx = 0; if (info.quirks.video_see_through) { - ohd->base.hmd->blend_mode = - (enum xrt_blend_mode)(ohd->base.hmd->blend_mode | XRT_BLEND_MODE_ALPHA_BLEND); + ohd->base.hmd->blend_modes[bm_idx++] = XRT_BLEND_MODE_ALPHA_BLEND; } + ohd->base.hmd->blend_modes[bm_idx++] = XRT_BLEND_MODE_OPAQUE; + ohd->base.hmd->num_blend_modes = bm_idx; if (info.quirks.video_distortion_vive) { // clang-format off diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index 9b03a8df5..0faf8a413 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -830,7 +830,9 @@ _create_hmd_device(struct survive_system *sys, const struct SurviveSimpleObject SURVIVE_INFO(survive, "survive HMD present"); - survive->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; + size_t idx = 0; + survive->base.hmd->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE; + survive->base.hmd->num_blend_modes = idx; survive->hmd.config = *config; diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index dde1edee8..ceced9690 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -746,7 +746,10 @@ vive_device_create(struct os_hid_device *mainboard_dev, (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); struct vive_device *d = U_DEVICE_ALLOCATE(struct vive_device, flags, 1, 0); - d->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; + size_t idx = 0; + d->base.hmd->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE; + d->base.hmd->num_blend_modes = idx; + d->base.update_inputs = vive_device_update_inputs; d->base.get_tracked_pose = vive_device_get_tracked_pose; d->base.get_view_pose = vive_device_get_view_pose; From c54a6bef0a7053f91e02986542b0b7f792e58e18 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Sun, 11 Apr 2021 04:02:11 -0500 Subject: [PATCH 334/883] doc: Document !749 --- doc/changes/xrt/mr.749.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/xrt/mr.749.md diff --git a/doc/changes/xrt/mr.749.md b/doc/changes/xrt/mr.749.md new file mode 100644 index 000000000..d761f5da1 --- /dev/null +++ b/doc/changes/xrt/mr.749.md @@ -0,0 +1 @@ +Make `enum xrt_blend_mode` an array instead of a bitfield, so that drivers can specify which one is preferred. \ No newline at end of file From 0064989e8bec437d84535554fc7611fb69097439 Mon Sep 17 00:00:00 2001 From: iVRy VR Date: Mon, 12 Apr 2021 15:02:16 +0000 Subject: [PATCH 335/883] t/psvr: Various fixes and changes - Fix out of array bounds crash, curr_y can be out of bounds. - Set tracked bits appropriately. - Use m_imu_3dof for orientation. --- src/xrt/auxiliary/tracking/t_tracker_psvr.cpp | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp b/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp index b59aa2a88..008eeb3ea 100644 --- a/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp +++ b/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp @@ -24,6 +24,7 @@ #include "math/m_mathinclude.h" #include "math/m_api.h" #include "math/m_permutation.h" +#include "math/m_imu_3dof.h" #include "os/os_threading.h" @@ -230,7 +231,7 @@ public: struct { struct xrt_vec3 pos = {}; - struct xrt_quat rot = {}; + struct m_imu_3dof imu_3dof; } fusion; struct @@ -1281,7 +1282,7 @@ sample_line(cv::Mat &src, cv::Point2i start, cv::Point2i end, int *inside_length while (1) { // sample our pixel and see if it is in the interior - if (curr_x > 0 && curr_y > 0) { + if (curr_x > 0 && curr_y > 0 && curr_x < src.cols && curr_y < src.rows) { // cv is row, column uint8_t *val = src.ptr(curr_y, curr_x); @@ -1677,7 +1678,9 @@ process(TrackerPSVR &t, struct xrt_frame *xf) // leds. if (t.merged_points.size() >= PSVR_OPTICAL_SOLVE_THRESH) { Eigen::Quaternionf correction = - rot * Eigen::Quaternionf(t.fusion.rot.w, t.fusion.rot.x, t.fusion.rot.y, t.fusion.rot.z).inverse(); + rot * Eigen::Quaternionf(t.fusion.imu_3dof.rot.w, t.fusion.imu_3dof.rot.x, t.fusion.imu_3dof.rot.y, + t.fusion.imu_3dof.rot.z) + .inverse(); float correction_magnitude = t.target_optical_rotation_correction.angularDistance(correction); @@ -1856,10 +1859,14 @@ get_pose(TrackerPSVR &t, timepoint_ns when_ns, struct xrt_space_relation *out_re //! @todo assuming that orientation is actually //! currently tracked. - out_relation->relation_flags = (enum xrt_space_relation_flags)( - XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT | - XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); + out_relation->relation_flags = (enum xrt_space_relation_flags)(XRT_SPACE_RELATION_POSITION_VALID_BIT | + XRT_SPACE_RELATION_POSITION_TRACKED_BIT | + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT); + if (t.done_correction) { + out_relation->relation_flags = (enum xrt_space_relation_flags)( + out_relation->relation_flags | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); + } os_thread_helper_unlock(&t.oth); } @@ -1876,16 +1883,16 @@ imu_data(TrackerPSVR &t, timepoint_ns timestamp_ns, struct xrt_tracking_sample * if (t.last_imu != 0) { time_duration_ns delta_ns = timestamp_ns - t.last_imu; float dt = time_ns_to_s(delta_ns); - // Super simple fusion. - math_quat_integrate_velocity(&t.fusion.rot, &sample->gyro_rad_secs, dt, &t.fusion.rot); + // Update 3DOF fusion + m_imu_3dof_update(&t.fusion.imu_3dof, timestamp_ns, &sample->accel_m_s2, &sample->gyro_rad_secs); } // apply our optical correction to imu rotation // data Eigen::Quaternionf corrected_rot_q = - t.optical_rotation_correction * - Eigen::Quaternionf(t.fusion.rot.w, t.fusion.rot.x, t.fusion.rot.y, t.fusion.rot.z); + t.optical_rotation_correction * Eigen::Quaternionf(t.fusion.imu_3dof.rot.w, t.fusion.imu_3dof.rot.x, + t.fusion.imu_3dof.rot.y, t.fusion.imu_3dof.rot.z); Eigen::Matrix4f corrected_rot = Eigen::Matrix4f::Identity(); corrected_rot.block(0, 0, 3, 3) = corrected_rot_q.toRotationMatrix(); @@ -1990,6 +1997,8 @@ t_psvr_node_destroy(struct xrt_frame_node *node) os_thread_helper_destroy(&t_ptr->oth); + m_imu_3dof_close(&t_ptr->fusion.imu_3dof); + delete t_ptr; } @@ -2096,7 +2105,6 @@ t_psvr_create(struct xrt_frame_context *xfctx, t.sink.push_frame = t_psvr_sink_push_frame; t.node.break_apart = t_psvr_node_break_apart; t.node.destroy = t_psvr_node_destroy; - t.fusion.rot.w = 1.0f; ret = os_thread_helper_init(&t.oth); if (ret != 0) { @@ -2108,10 +2116,12 @@ t_psvr_create(struct xrt_frame_context *xfctx, t.fusion.pos.y = 0.0f; t.fusion.pos.z = 0.0f; - t.fusion.rot.x = 0.0f; - t.fusion.rot.y = 0.0f; - t.fusion.rot.z = 0.0f; - t.fusion.rot.w = 1.0f; + m_imu_3dof_init(&t.fusion.imu_3dof, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); + + t.fusion.imu_3dof.rot.x = 0.0f; + t.fusion.imu_3dof.rot.y = 0.0f; + t.fusion.imu_3dof.rot.z = 0.0f; + t.fusion.imu_3dof.rot.w = 1.0f; xrt_frame_context_add(xfctx, &t.node); From 95e95ba9b58bd04ad76d1d3f32b376a71db7ed3f Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 12 Apr 2021 18:30:22 +0100 Subject: [PATCH 336/883] c/render: Tidy mesh shader --- src/xrt/compositor/main/comp_renderer.c | 12 +++++------- src/xrt/compositor/render/comp_render.h | 3 +-- src/xrt/compositor/shaders/mesh.vert | 16 +++++----------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index dfcab1230..dd39075a2 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -1,4 +1,4 @@ -// Copyright 2019, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -265,12 +265,11 @@ renderer_build_rendering(struct comp_renderer *r, struct comp_rendering *rr, uin struct comp_mesh_ubo_data l_data = { - .rot = l_v->rot, - .flip_y = false, + .vertex_rot = l_v->rot, }; if (pre_rotate) { - math_matrix_2x2_multiply(&l_v->rot, &rotation_90_cw, &l_data.rot); + math_matrix_2x2_multiply(&l_v->rot, &rotation_90_cw, &l_data.vertex_rot); } struct xrt_view *r_v = &r->c->xdev->hmd->views[1]; @@ -294,12 +293,11 @@ renderer_build_rendering(struct comp_renderer *r, struct comp_rendering *rr, uin } struct comp_mesh_ubo_data r_data = { - .rot = r_v->rot, - .flip_y = false, + .vertex_rot = r_v->rot, }; if (pre_rotate) { - math_matrix_2x2_multiply(&r_v->rot, &rotation_90_cw, &r_data.rot); + math_matrix_2x2_multiply(&r_v->rot, &rotation_90_cw, &r_data.vertex_rot); } /* diff --git a/src/xrt/compositor/render/comp_render.h b/src/xrt/compositor/render/comp_render.h index 51513486e..07d22b29c 100644 --- a/src/xrt/compositor/render/comp_render.h +++ b/src/xrt/compositor/render/comp_render.h @@ -276,8 +276,7 @@ struct comp_viewport_data */ struct comp_mesh_ubo_data { - struct xrt_matrix_2x2 rot; - int flip_y; + struct xrt_matrix_2x2 vertex_rot; }; /*! diff --git a/src/xrt/compositor/shaders/mesh.vert b/src/xrt/compositor/shaders/mesh.vert index f9d6b55c5..124836c54 100644 --- a/src/xrt/compositor/shaders/mesh.vert +++ b/src/xrt/compositor/shaders/mesh.vert @@ -1,14 +1,14 @@ -// Copyright 2019, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Lubosz Sarnecki // Author: Pete Black +// Author: Jakob Bornecrantz #version 450 layout (binding = 1, std140) uniform ubo { - vec4 rot; - bool flip_y; + vec4 vertex_rot; } ubo_vp; layout (location = 0) in vec4 in_pos_ruv; @@ -26,8 +26,8 @@ out gl_PerVertex void main() { mat2x2 rot = { - ubo_vp.rot.xy, - ubo_vp.rot.zw, + ubo_vp.vertex_rot.xy, + ubo_vp.vertex_rot.zw, }; vec2 pos = rot * in_pos_ruv.xy; @@ -35,11 +35,5 @@ void main() out_guv = in_guv_buv.xy; out_buv = in_guv_buv.zw; - if (ubo_vp.flip_y) { - out_ruv.y = 1.0 - out_ruv.y; - out_guv.y = 1.0 - out_guv.y; - out_buv.y = 1.0 - out_buv.y; - } - gl_Position = vec4(pos, 0.0f, 1.0f); } From b0c9f2a1d99c3a15509ff32b6bda2b35bb037dc8 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 12 Apr 2021 19:52:05 +0100 Subject: [PATCH 337/883] c/multi: Break potential long running tasks into functions for better trace_marker logging --- .../compositor/multi/comp_multi_compositor.c | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/xrt/compositor/multi/comp_multi_compositor.c b/src/xrt/compositor/multi/comp_multi_compositor.c index 1d3d0e978..587305716 100644 --- a/src/xrt/compositor/multi/comp_multi_compositor.c +++ b/src/xrt/compositor/multi/comp_multi_compositor.c @@ -414,6 +414,35 @@ multi_compositor_layer_equirect2(struct xrt_compositor *xc, return XRT_SUCCESS; } +static void +wait_fence(struct xrt_compositor_fence **xcf_ptr) +{ + COMP_TRACE_MARKER(); + xrt_compositor_fence_wait(*xcf_ptr, UINT64_MAX); + xrt_compositor_fence_destroy(xcf_ptr); +} + +static void +wait_for_scheduled_free(struct multi_compositor *mc) +{ + COMP_TRACE_MARKER(); + + os_mutex_lock(&mc->slot_lock); + + // Block here if the scheduled slot is not clear. + while (mc->scheduled.active) { + os_mutex_unlock(&mc->slot_lock); + + os_nanosleep(U_TIME_1MS_IN_NS); + + os_mutex_lock(&mc->slot_lock); + } + + slot_move_and_clear(&mc->scheduled, &mc->progress); + + os_mutex_unlock(&mc->slot_lock); +} + static xrt_result_t multi_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_graphics_sync_handle_t sync_handle) { @@ -444,24 +473,10 @@ multi_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_g } while (false); // Goto without the labels. if (xcf != NULL) { - xrt_compositor_fence_wait(xcf, UINT64_MAX); - xrt_compositor_fence_destroy(&xcf); + wait_fence(&xcf); } - os_mutex_lock(&mc->slot_lock); - - // Block here if the scheduled slot is not clear. - while (mc->scheduled.active) { - os_mutex_unlock(&mc->slot_lock); - - os_nanosleep(U_TIME_1MS_IN_NS); - - os_mutex_lock(&mc->slot_lock); - } - - slot_move_and_clear(&mc->scheduled, &mc->progress); - - os_mutex_unlock(&mc->slot_lock); + wait_for_scheduled_free(mc); os_mutex_lock(&mc->msc->list_and_timing_lock); u_rt_mark_delivered(mc->urt, frame_id); From c9c362e16ad30f092ee385cf8ba63b0b518334f0 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 12 Apr 2021 20:17:10 +0100 Subject: [PATCH 338/883] c/multi: Overwrite stale scheduled frames --- src/xrt/compositor/multi/comp_multi_compositor.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/xrt/compositor/multi/comp_multi_compositor.c b/src/xrt/compositor/multi/comp_multi_compositor.c index 587305716..6caa6bf7b 100644 --- a/src/xrt/compositor/multi/comp_multi_compositor.c +++ b/src/xrt/compositor/multi/comp_multi_compositor.c @@ -431,6 +431,13 @@ wait_for_scheduled_free(struct multi_compositor *mc) // Block here if the scheduled slot is not clear. while (mc->scheduled.active) { + + // Replace the scheduled frame if it's in the past. + uint64_t now_ns = os_monotonic_get_ns(); + if (mc->scheduled.display_time_ns < now_ns) { + break; + } + os_mutex_unlock(&mc->slot_lock); os_nanosleep(U_TIME_1MS_IN_NS); From 796f3cf7924a6c8a61c575ccd399d7d9e3cf86f8 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 12 Apr 2021 20:32:35 +0100 Subject: [PATCH 339/883] c/main: Set default logging level to INFO --- src/xrt/compositor/main/comp_settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_settings.c b/src/xrt/compositor/main/comp_settings.c index 33474dfef..ed7be09bb 100644 --- a/src/xrt/compositor/main/comp_settings.c +++ b/src/xrt/compositor/main/comp_settings.c @@ -11,7 +11,7 @@ #include "comp_settings.h" // clang-format off -DEBUG_GET_ONCE_LOG_OPTION(log, "XRT_COMPOSITOR_LOG", U_LOGGING_WARN) +DEBUG_GET_ONCE_LOG_OPTION(log, "XRT_COMPOSITOR_LOG", U_LOGGING_INFO) DEBUG_GET_ONCE_BOOL_OPTION(print_modes, "XRT_COMPOSITOR_PRINT_MODES", false) DEBUG_GET_ONCE_BOOL_OPTION(force_randr, "XRT_COMPOSITOR_FORCE_RANDR", false) DEBUG_GET_ONCE_BOOL_OPTION(force_nvidia, "XRT_COMPOSITOR_FORCE_NVIDIA", false) From 1b51cbd1a78075b3862f1e3275e7e9b46ca5deca Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 12 Apr 2021 20:44:49 +0100 Subject: [PATCH 340/883] aux/vk: Add support for VK_EXT_global_priority --- src/xrt/auxiliary/vk/vk_helpers.c | 10 +++++ src/xrt/auxiliary/vk/vk_helpers.h | 2 + src/xrt/compositor/main/comp_compositor.c | 50 +++++++++++++++++++---- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/xrt/auxiliary/vk/vk_helpers.c b/src/xrt/auxiliary/vk/vk_helpers.c index 5065f46bb..54a46c657 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.c +++ b/src/xrt/auxiliary/vk/vk_helpers.c @@ -1051,6 +1051,9 @@ vk_check_extension(struct vk_bundle *vk, VkExtensionProperties *props, uint32_t if (strcmp(ext, VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME) == 0) { vk->has_GOOGLE_display_timing = true; } + if (strcmp(ext, VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME) == 0) { + vk->has_EXT_global_priority = true; + } return true; } @@ -1131,6 +1134,7 @@ vk_build_device_extensions(struct vk_bundle *vk, VkResult vk_create_device(struct vk_bundle *vk, int forced_index, + VkQueueGlobalPriorityEXT global_priorty, const char *const *required_device_extensions, size_t num_required_device_extensions, const char *const *optional_device_extensions, @@ -1165,8 +1169,14 @@ vk_create_device(struct vk_bundle *vk, return ret; } + VkDeviceQueueGlobalPriorityCreateInfoEXT priority_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT, + .globalPriority = global_priorty, + }; + VkDeviceCreateInfo device_create_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = vk->has_EXT_global_priority ? &priority_info : NULL, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queue_create_info, .enabledExtensionCount = num_device_extensions, diff --git a/src/xrt/auxiliary/vk/vk_helpers.h b/src/xrt/auxiliary/vk/vk_helpers.h index 77c8d6b40..cab41f39f 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.h +++ b/src/xrt/auxiliary/vk/vk_helpers.h @@ -49,6 +49,7 @@ struct vk_bundle struct os_mutex queue_mutex; bool has_GOOGLE_display_timing; + bool has_EXT_global_priority; VkDebugReportCallbackEXT debug_report_cb; @@ -363,6 +364,7 @@ vk_init_cmd_pool(struct vk_bundle *vk); VkResult vk_create_device(struct vk_bundle *vk, int forced_index, + VkQueueGlobalPriorityEXT global_priorty, const char *const *required_device_extensions, size_t num_required_device_extensions, const char *const *optional_device_extensions, diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 7d1c8e9cd..d243ddac9 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -745,6 +745,7 @@ static const char *required_device_extensions[] = { static const char *optional_device_extensions[] = { VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, + VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, }; @@ -882,11 +883,41 @@ compositor_init_vulkan(struct comp_compositor *c) return false; } - ret = vk_create_device(&c->vk, c->settings.selected_gpu_index, required_device_extensions, - ARRAY_SIZE(required_device_extensions), optional_device_extensions, - ARRAY_SIZE(optional_device_extensions)); + const char *prio_strs[3] = { + "realtime", + "high", + "normal", + }; - if (ret != VK_SUCCESS) { + VkQueueGlobalPriorityEXT prios[3] = { + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT, // This is the one we really want. + VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT, // Probably not as good but something. + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT, // Default fallback. + }; + + // No other way then to try to see if realtime is available. + for (size_t i = 0; i < ARRAY_SIZE(prios); i++) { + ret = vk_create_device( // + &c->vk, // + c->settings.selected_gpu_index, // + prios[i], // global_priority + required_device_extensions, // + ARRAY_SIZE(required_device_extensions), // + optional_device_extensions, // + ARRAY_SIZE(optional_device_extensions)); // + + // All ok! + if (ret == VK_SUCCESS) { + COMP_INFO(c, "Created device/queue with %s priority.", prio_strs[i]); + break; + } + + // Try a lower priority. + if (ret == VK_ERROR_NOT_PERMITTED_EXT) { + continue; + } + + // Some other error! return false; } @@ -1068,9 +1099,14 @@ compositor_check_vulkan_caps(struct comp_compositor *c) } // follow same device selection logic as subsequent calls - ret = vk_create_device(&temp_vk, c->settings.selected_gpu_index, required_device_extensions, - ARRAY_SIZE(required_device_extensions), optional_device_extensions, - ARRAY_SIZE(optional_device_extensions)); + ret = vk_create_device( // + &temp_vk, // + c->settings.selected_gpu_index, // + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT, // global_priority + required_device_extensions, // + ARRAY_SIZE(required_device_extensions), // + optional_device_extensions, // + ARRAY_SIZE(optional_device_extensions)); // if (ret != VK_SUCCESS) { COMP_ERROR(c, "Failed to create VkDevice: %s", vk_result_string(ret)); From 142a9b4cb5a5cfebe38ead718adf7779f3ee09ee Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 5 Apr 2021 17:02:25 -0500 Subject: [PATCH 341/883] st/oxr: Add XR_KHR_loader_init and ..._android extension --- scripts/generate_oxr_ext_support.py | 2 ++ .../oxr/oxr_extension_support.h | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/scripts/generate_oxr_ext_support.py b/scripts/generate_oxr_ext_support.py index f31a67a1d..14ec3ce05 100755 --- a/scripts/generate_oxr_ext_support.py +++ b/scripts/generate_oxr_ext_support.py @@ -11,6 +11,8 @@ from pathlib import Path # Keep sorted. EXTENSIONS = ( ['XR_KHR_android_create_instance', 'XR_USE_PLATFORM_ANDROID'], + ['XR_KHR_loader_init', 'XR_USE_PLATFORM_ANDROID'], + ['XR_KHR_loader_init_android', 'OXR_HAVE_KHR_loader_init', 'XR_USE_PLATFORM_ANDROID'], ['XR_KHR_convert_timespec_time', 'XR_USE_TIMESPEC'], ['XR_KHR_opengl_enable', 'XR_USE_GRAPHICS_API_OPENGL'], ['XR_KHR_opengl_es_enable', 'XR_USE_GRAPHICS_API_OPENGL_ES'], diff --git a/src/xrt/state_trackers/oxr/oxr_extension_support.h b/src/xrt/state_trackers/oxr/oxr_extension_support.h index f6f85d8c9..3833f4a2d 100644 --- a/src/xrt/state_trackers/oxr/oxr_extension_support.h +++ b/src/xrt/state_trackers/oxr/oxr_extension_support.h @@ -31,6 +31,28 @@ #endif +/* + * XR_KHR_loader_init + */ +#if defined(XR_KHR_loader_init) && defined(XR_USE_PLATFORM_ANDROID) +#define OXR_HAVE_KHR_loader_init +#define OXR_EXTENSION_SUPPORT_KHR_loader_init(_) _(KHR_loader_init, KHR_LOADER_INIT) +#else +#define OXR_EXTENSION_SUPPORT_KHR_loader_init(_) +#endif + + +/* + * XR_KHR_loader_init_android + */ +#if defined(XR_KHR_loader_init_android) && defined(OXR_HAVE_KHR_loader_init) && defined(XR_USE_PLATFORM_ANDROID) +#define OXR_HAVE_KHR_loader_init_android +#define OXR_EXTENSION_SUPPORT_KHR_loader_init_android(_) _(KHR_loader_init_android, KHR_LOADER_INIT_ANDROID) +#else +#define OXR_EXTENSION_SUPPORT_KHR_loader_init_android(_) +#endif + + /* * XR_KHR_convert_timespec_time */ @@ -247,6 +269,8 @@ // clang-format off #define OXR_EXTENSION_SUPPORT_GENERATE(_) \ OXR_EXTENSION_SUPPORT_KHR_android_create_instance(_) \ + OXR_EXTENSION_SUPPORT_KHR_loader_init(_) \ + OXR_EXTENSION_SUPPORT_KHR_loader_init_android(_) \ OXR_EXTENSION_SUPPORT_KHR_convert_timespec_time(_) \ OXR_EXTENSION_SUPPORT_KHR_opengl_enable(_) \ OXR_EXTENSION_SUPPORT_KHR_opengl_es_enable(_) \ From 43e0206abce366f0eb82643662d44b1659928c8c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 5 Apr 2021 17:15:20 -0500 Subject: [PATCH 342/883] st/oxr: Implement loader init extension. --- src/xrt/state_trackers/oxr/oxr_api_funcs.h | 6 +++ src/xrt/state_trackers/oxr/oxr_api_instance.c | 41 +++++++++++++++++++ .../state_trackers/oxr/oxr_api_negotiate.c | 4 ++ 3 files changed, 51 insertions(+) diff --git a/src/xrt/state_trackers/oxr/oxr_api_funcs.h b/src/xrt/state_trackers/oxr/oxr_api_funcs.h index e91d08161..59dc680c1 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_funcs.h +++ b/src/xrt/state_trackers/oxr/oxr_api_funcs.h @@ -50,6 +50,12 @@ oxr_xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput, * */ +#ifdef OXR_HAVE_KHR_loader_init +//! OpenXR API function @ep{xrInitializeLoaderKHR} +XRAPI_ATTR XrResult XRAPI_CALL +oxr_xrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo); +#endif // OXR_HAVE_KHR_loader_init + //! OpenXR API function @ep{xrEnumerateInstanceExtensionProperties} XRAPI_ATTR XrResult XRAPI_CALL oxr_xrEnumerateInstanceExtensionProperties(const char *layerName, diff --git a/src/xrt/state_trackers/oxr/oxr_api_instance.c b/src/xrt/state_trackers/oxr/oxr_api_instance.c index ec3431bde..54d3b1ff8 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_api_instance.c @@ -21,6 +21,11 @@ #include "oxr_api_funcs.h" #include "oxr_api_verify.h" + +#ifdef XRT_OS_ANDROID +#include "android/android_globals.h" +#endif + #include "openxr/openxr.h" #include "openxr/openxr_reflection.h" @@ -49,6 +54,42 @@ oxr_xrEnumerateInstanceExtensionProperties(const char *layerName, ARRAY_SIZE(extension_properties), extension_properties, XR_SUCCESS); } +#ifdef OXR_HAVE_KHR_loader_init +XrResult +oxr_xrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) +{ + struct oxr_logger log; + oxr_log_init(&log, "oxr_xrInitializeLoaderKHR"); + + + oxr_log(&log, "Loader forwarded call to xrInitializeLoaderKHR."); +#ifdef XRT_OS_ANDROID + const XrLoaderInitInfoAndroidKHR *initInfoAndroid = + OXR_GET_INPUT_FROM_CHAIN(loaderInitInfo, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, XrLoaderInitInfoAndroidKHR); + if (initInfoAndroid == NULL) { + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, + "(loaderInitInfo) " + "Did not find XrLoaderInitInfoAndroidKHR"); + } + if (initInfoAndroid->applicationVM == NULL) { + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, + "(initInfoAndroid->applicationVM) " + "applicationVM must be populated"); + } + if (initInfoAndroid->applicationContext == NULL) { + return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, + "(initInfoAndroid->applicationContext) " + "applicationContext must be populated"); + } + //! @todo check that applicationContext is in fact an Activity. + android_globals_store_vm_and_context(initInfoAndroid->applicationVM, initInfoAndroid->applicationContext); + +#endif // XRT_OS_ANDROID + return XR_SUCCESS; +} +#endif // OXR_HAVE_KHR_loader_init + + #ifdef XRT_OS_ANDROID static XrResult oxr_check_android_extensions(struct oxr_logger *log, const XrInstanceCreateInfo *createInfo) diff --git a/src/xrt/state_trackers/oxr/oxr_api_negotiate.c b/src/xrt/state_trackers/oxr/oxr_api_negotiate.c index 91b27ab73..735eaa313 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_negotiate.c +++ b/src/xrt/state_trackers/oxr/oxr_api_negotiate.c @@ -276,6 +276,10 @@ handle_null(struct oxr_logger *log, const char *name, PFN_xrVoidFunction *out_fu ENTRY(xrEnumerateInstanceExtensionProperties); ENTRY(xrEnumerateApiLayerProperties); +#ifdef OXR_HAVE_KHR_loader_init + ENTRY(xrInitializeLoaderKHR); +#endif // OXR_HAVE_KHR_loader_init + /* * This is fine to log, since there should not be other * null-instance calls. From 65a7b490a8e70bddab9b2ed54eef9ff8abeb5627 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 9 Apr 2021 17:00:17 -0500 Subject: [PATCH 343/883] android: Add support for casting Context to Activity --- src/xrt/auxiliary/CMakeLists.txt | 2 +- ...{android_globals.c => android_globals.cpp} | 23 ++++++++++++++----- src/xrt/auxiliary/android/android_globals.h | 7 ++++++ 3 files changed, 25 insertions(+), 7 deletions(-) rename src/xrt/auxiliary/android/{android_globals.c => android_globals.cpp} (68%) diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index fa92cd003..86b302bcf 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -6,7 +6,7 @@ set(ANDROID_SOURCE_FILES android/android_ahardwarebuffer_allocator.h android/android_custom_surface.cpp android/android_custom_surface.h - android/android_globals.c + android/android_globals.cpp android/android_globals.h android/android_load_class.cpp android/android_load_class.hpp diff --git a/src/xrt/auxiliary/android/android_globals.c b/src/xrt/auxiliary/android/android_globals.cpp similarity index 68% rename from src/xrt/auxiliary/android/android_globals.c rename to src/xrt/auxiliary/android/android_globals.cpp index 9bf33bdf9..fd7b68f8b 100644 --- a/src/xrt/auxiliary/android/android_globals.c +++ b/src/xrt/auxiliary/android/android_globals.cpp @@ -10,6 +10,7 @@ #include "android_globals.h" #include +#include /*! * @todo Do we need locking here? Do we need to create global refs for the @@ -17,11 +18,11 @@ */ static struct { - struct _JavaVM *vm; - void *activity; - void *context; - struct _ANativeWindow *window; -} android_globals = {NULL, NULL, NULL}; + struct _JavaVM *vm = nullptr; + void *activity = nullptr; + void *context = nullptr; + struct _ANativeWindow *window = nullptr; +} android_globals; void android_globals_store_vm_and_activity(struct _JavaVM *vm, void *activity) @@ -33,11 +34,21 @@ android_globals_store_vm_and_activity(struct _JavaVM *vm, void *activity) void android_globals_store_vm_and_context(struct _JavaVM *vm, void *context) { - android_globals.vm = vm; android_globals.context = context; + if (android_globals_is_instance_of_activity(vm, context)) { + android_globals.activity = context; + } } +bool +android_globals_is_instance_of_activity(struct _JavaVM *vm, void *obj) +{ + jni::init(vm); + + auto activity_cls = jni::Class(wrap::android::app::Activity::getTypeName()); + return JNI_TRUE == jni::env()->IsInstanceOf((jobject)obj, activity_cls.getHandle()); +} void android_globals_store_window(struct _ANativeWindow *window) { diff --git a/src/xrt/auxiliary/android/android_globals.h b/src/xrt/auxiliary/android/android_globals.h index 5257c7d1e..95f4abc72 100644 --- a/src/xrt/auxiliary/android/android_globals.h +++ b/src/xrt/auxiliary/android/android_globals.h @@ -34,6 +34,13 @@ android_globals_store_vm_and_activity(struct _JavaVM *vm, void *activity); void android_globals_store_vm_and_context(struct _JavaVM *vm, void *context); + +/*! + * Is the provided jobject an instance of android.app.Activity? + */ +bool +android_globals_is_instance_of_activity(struct _JavaVM *vm, void *obj); + /*! * Retrieve the Java VM pointer previously stored, if any. */ From f3dc8393a0061d83b5867b52f54ebd418dd1119b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 6 Apr 2021 10:45:47 -0500 Subject: [PATCH 344/883] gradle: Bump dependency versions. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 72c84403f..ed0cd49b8 100644 --- a/build.gradle +++ b/build.gradle @@ -3,11 +3,11 @@ buildscript { ext { - kotlinVersion = '1.4.10' + kotlinVersion = '1.4.31' latestAboutLibsRelease = "8.5.0" androidxCoreVersion = "1.3.2" - androidxAnnotationVersion = "1.1.0" + androidxAnnotationVersion = '1.2.0' androidxAppCompatVersion = "1.2.0" androidxLifecycleVersion = "2.2.0" androidxConstraintLayoutVersion = '2.0.4' From f537d115fe85f2778f98fc6128cf09b8778d238b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 11:31:22 -0500 Subject: [PATCH 345/883] doc: Exclude Android in-tree build artifacts from doxygen's scanning. --- doc/Doxyfile.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index f1801aef1..4afadb282 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -1,4 +1,4 @@ -# Copyright 2018-2020, Collabora, Ltd. and the Monado contributors +# Copyright 2018-2021, Collabora, Ltd. and the Monado contributors # SPDX-License-Identifier: BSL-1.0 QUIET = YES @@ -17,6 +17,8 @@ RECURSIVE = YES EXCLUDE = @SRCDIR@/src/external \ @SRCDIR@/doc/changes \ @BUILDDIR@ +EXCLUDE_PATTERNS = */build/* + STRIP_FROM_PATH = @SRCDIR@/src/xrt \ @SRCDIR@/src/xrt/include \ @SRCDIR@/doc From 64c56ef8d088c7d9d8bd350d4eec70642dee031a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 11:31:34 -0500 Subject: [PATCH 346/883] editorconfig: Update --- .editorconfig | 6 +++--- src/xrt/.editorconfig | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/xrt/.editorconfig diff --git a/.editorconfig b/.editorconfig index 3ff654b59..178f43667 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,8 +1,8 @@ -# To use this config on you editor, follow the instructions at: +# To use this config on your editor, follow the instructions at: # http://editorconfig.org # SPDX-License-Identifier: CC0-1.0 -# SPDX-FileCopyrightText: 2018-2020 Collabora, Ltd. and the Monado contributors +# SPDX-FileCopyrightText: 2018-2021 Collabora, Ltd. and the Monado contributors root = true @@ -13,7 +13,7 @@ insert_final_newline = true [*.{c,h,cpp}] indent_style = tab indent_size = 8 -max_line_length = 80 +max_line_length = 120 [*.py] indent_size = 4 diff --git a/src/xrt/.editorconfig b/src/xrt/.editorconfig new file mode 100644 index 000000000..8746b3cb6 --- /dev/null +++ b/src/xrt/.editorconfig @@ -0,0 +1,10 @@ +# To use this config on your editor, follow the instructions at: +# http://editorconfig.org + +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2018-2021 Collabora, Ltd. and the Monado contributors + +[*] +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true From 701ea290d0df1e6bcfdc42983bf782514089ff7b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 12 Apr 2021 12:08:41 -0500 Subject: [PATCH 347/883] os: Fix comment typo. --- src/xrt/auxiliary/os/os_threading.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/os/os_threading.h b/src/xrt/auxiliary/os/os_threading.h index 6a6fc0606..610f11a49 100644 --- a/src/xrt/auxiliary/os/os_threading.h +++ b/src/xrt/auxiliary/os/os_threading.h @@ -98,7 +98,7 @@ os_mutex_destroy(struct os_mutex *om) */ /*! - * A wrapper around a native mutex. + * A wrapper around a native thread. */ struct os_thread { From 1e1fe01374ab44ebc38a6c655d302696332ff211 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 11:14:01 -0500 Subject: [PATCH 348/883] comp: Doc improvements. --- src/xrt/compositor/main/comp_target.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_target.h b/src/xrt/compositor/main/comp_target.h index b90943cd0..513f9cda4 100644 --- a/src/xrt/compositor/main/comp_target.h +++ b/src/xrt/compositor/main/comp_target.h @@ -53,10 +53,15 @@ struct comp_target_image }; /*! + * @brief A compositor target: where the compositor renders to. + * * A target is essentially a swapchain, but it is such a overloaded term so - * we are differencating swapchains that the compositor provides to clients and + * we are differentiating swapchains that the compositor provides to clients and * swapchains that the compositor renders by naming the latter to target. * + * For design purposes, when amending this interface, remember that targets may not necessarily be backed by a + * swapchain in all cases, for instance with remote rendering. + * * @ingroup comp_main */ struct comp_target From cb2710db878a8522fb2ad343c0a953b09679587c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 11:30:34 -0500 Subject: [PATCH 349/883] comp: Improve docs on comp_target_swapchain --- .../compositor/main/comp_target_swapchain.h | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_target_swapchain.h b/src/xrt/compositor/main/comp_target_swapchain.h index 2f76dd6c7..8e07b7fc4 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.h +++ b/src/xrt/compositor/main/comp_target_swapchain.h @@ -76,7 +76,23 @@ struct comp_target_swapchain */ /*! - * Pre Vulkan initialisation, sets function pointers. + * @brief Pre Vulkan initialisation, sets function pointers. + * + * Call from the creation function for your "subclass", after allocating. + * + * Initializes these function pointers, all other methods of @ref comp_target are the responsibility of the caller (the + * "subclass"): + * + * - comp_target::create_images + * - comp_target::acquire + * - comp_target::present + * - comp_target::calc_frame_timings + * - comp_target::mark_timing_point + * - comp_target::update_timings + * + * Also sets comp_target_swapchain::timing_usage to the provided value. + * + * @protected @memberof comp_target_swapchain * * @ingroup comp_main */ @@ -88,6 +104,8 @@ comp_target_swapchain_init_and_set_fnptrs(struct comp_target_swapchain *cts, * Free all managed resources on the given @ref comp_target_swapchain, * does not free the struct itself. * + * @protected @memberof comp_target_swapchain + * * @ingroup comp_main */ void From 4507804819b02ab2d0c5f27fac9ed84c1ea3fbd9 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 13 Apr 2021 00:22:36 +0100 Subject: [PATCH 350/883] c/multi: Implement xrt_compositor::wait_frame --- .../compositor/multi/comp_multi_compositor.c | 34 +++++++++++++++++-- src/xrt/compositor/multi/comp_multi_private.h | 3 ++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/xrt/compositor/multi/comp_multi_compositor.c b/src/xrt/compositor/multi/comp_multi_compositor.c index 6caa6bf7b..517185cf6 100644 --- a/src/xrt/compositor/multi/comp_multi_compositor.c +++ b/src/xrt/compositor/multi/comp_multi_compositor.c @@ -235,13 +235,36 @@ multi_compositor_mark_frame(struct xrt_compositor *xc, static xrt_result_t multi_compositor_wait_frame(struct xrt_compositor *xc, int64_t *out_frame_id, - uint64_t *predicted_display_time, - uint64_t *predicted_display_period) + uint64_t *out_predicted_display_time_ns, + uint64_t *out_predicted_display_period_ns) { COMP_TRACE_MARKER(); struct multi_compositor *mc = multi_compositor(xc); - (void)mc; + + int64_t frame_id = -1; + uint64_t wake_up_time_ns = 0; + uint64_t predicted_gpu_time_ns = 0; + + xrt_comp_predict_frame( // + xc, // + &frame_id, // + &wake_up_time_ns, // + &predicted_gpu_time_ns, // + out_predicted_display_time_ns, // + out_predicted_display_period_ns); // + + uint64_t now_ns = os_monotonic_get_ns(); + if (now_ns < wake_up_time_ns) { + uint32_t delay = (uint32_t)(wake_up_time_ns - now_ns); + os_precise_sleeper_nanosleep(&mc->sleeper, delay); + } + + now_ns = os_monotonic_get_ns(); + + xrt_comp_mark_frame(xc, frame_id, XRT_COMPOSITOR_FRAME_POINT_WOKE, now_ns); + + *out_frame_id = frame_id; return XRT_SUCCESS; } @@ -532,6 +555,8 @@ multi_compositor_destroy(struct xrt_compositor *xc) // Does null checking. u_rt_destroy(&mc->urt); + os_precise_sleeper_deinit(&mc->sleeper); + free(mc); } @@ -588,6 +613,9 @@ multi_compositor_create(struct multi_system_compositor *msc, // Passthrough our formats from the native compositor to the client. mc->base.base.info = msc->xcn->base.info; + // Using in wait frame. + os_precise_sleeper_init(&mc->sleeper); + // This is safe to do without a lock since we are not on the list yet. u_rt_create(&mc->urt); diff --git a/src/xrt/compositor/multi/comp_multi_private.h b/src/xrt/compositor/multi/comp_multi_private.h index 91954055c..eabe6cb8e 100644 --- a/src/xrt/compositor/multi/comp_multi_private.h +++ b/src/xrt/compositor/multi/comp_multi_private.h @@ -101,6 +101,9 @@ struct multi_compositor //! Owning system compositor. struct multi_system_compositor *msc; + //! Only matters for Windows and in process. + struct os_precise_sleeper sleeper; + struct { struct os_mutex mutex; From b48cdfed44409825b4d5273da54f14b66fab814a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 13 Apr 2021 01:55:55 +0100 Subject: [PATCH 351/883] c/main: Fix xrt_compositor::wait_frame --- doc/changes/compositor/mr.721.md | 3 +++ src/xrt/compositor/main/comp_compositor.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/doc/changes/compositor/mr.721.md b/doc/changes/compositor/mr.721.md index 3ab1fc17f..73a194938 100644 --- a/doc/changes/compositor/mr.721.md +++ b/doc/changes/compositor/mr.721.md @@ -1,3 +1,6 @@ +--- +- mr.759 +--- multi: Introduce a new multi client compositor layer, this allows rendering code to be moved from the IPC layer into the compositor, separating concerns. The main compositor always uses the multi client compositor, as it gives us a async diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index d243ddac9..7b6c48950 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -215,6 +215,8 @@ compositor_wait_frame(struct xrt_compositor *xc, xrt_comp_mark_frame(xc, frame_id, XRT_COMPOSITOR_FRAME_POINT_WOKE, now_ns); + *out_frame_id = frame_id; + return XRT_SUCCESS; } From f82f2899074b7d56d309f9c47f7f0b7ccd6f0efe Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 13 Apr 2021 02:06:15 +0100 Subject: [PATCH 352/883] u/rt: Also print what kind of point we are marking when tracing --- src/xrt/auxiliary/util/u_timing_render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index 3ce5b6431..6c84f5fc3 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -262,7 +262,7 @@ rt_mark_point(struct u_render_timing *urt, int64_t frame_id, enum u_timing_point { struct render_timing *rt = render_timing(urt); - DEBUG_PRINT_FRAME_ID(); + RT_LOG_T("%" PRIi64 " (%u)", frame_id, point); size_t index = GET_INDEX_FROM_ID(rt, frame_id); assert(rt->frames[index].frame_id == frame_id); From 7c77625da92fe66ddcfb20fb449fd7ff8c2c909e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 13 Apr 2021 02:15:17 +0100 Subject: [PATCH 353/883] st/oxr: Set visibility and z_order if multi compositor controls are available --- doc/changes/state_trackers/mr.759.md | 2 ++ src/xrt/state_trackers/oxr/oxr_session.c | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 doc/changes/state_trackers/mr.759.md diff --git a/doc/changes/state_trackers/mr.759.md b/doc/changes/state_trackers/mr.759.md new file mode 100644 index 000000000..99e93a37f --- /dev/null +++ b/doc/changes/state_trackers/mr.759.md @@ -0,0 +1,2 @@ +OpenXR: Use new multi compositor controls to set visibility and z_order if +available. This is needed for when we are not in service mode. diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index feada092a..8378e8d65 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -1977,6 +1977,10 @@ oxr_session_destroy(struct oxr_logger *log, struct oxr_handle_base *hb) return oxr_error((LOG), XR_ERROR_RUNTIME_FAILURE, "Failed to create native compositor! '%i'", \ xret); \ } \ + if ((SESS)->sys->xsysc->xmcc != NULL) { \ + xrt_syscomp_set_state((SESS)->sys->xsysc, &(SESS)->xcn->base, true, true); \ + xrt_syscomp_set_z_order((SESS)->sys->xsysc, &(SESS)->xcn->base, 0); \ + } \ } while (false) #define OXR_SESSION_ALLOCATE(LOG, SYS, OUT) \ From 7dc132a207405e8995f8a4d3082d4397be5f543f Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 9 Apr 2021 20:29:11 +0100 Subject: [PATCH 354/883] c/client: Set correct reference on swapchain --- .../compositor/client/comp_gl_eglimage_swapchain.c | 11 +++++------ src/xrt/compositor/client/comp_gl_memobj_swapchain.c | 1 + src/xrt/compositor/client/comp_vk_client.c | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c b/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c index 4ad0d1cc0..c29e49c2d 100644 --- a/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c +++ b/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c @@ -193,15 +193,14 @@ client_gl_eglimage_swapchain_create(struct xrt_compositor *xc, struct xrt_swapchain *native_xsc = &xscn->base; struct client_gl_eglimage_swapchain *sc = U_TYPED_CALLOC(struct client_gl_eglimage_swapchain); - struct xrt_swapchain_gl *xscgl = &sc->base.base; - struct xrt_swapchain *client_xsc = &xscgl->base; - client_xsc->destroy = client_gl_eglimage_swapchain_destroy; - // Fetch the number of images from the native swapchain. - client_xsc->num_images = native_xsc->num_images; + sc->base.base.base.destroy = client_gl_eglimage_swapchain_destroy; + sc->base.base.base.reference.count = 1; + sc->base.base.base.num_images = native_xsc->num_images; // Fetch the number of images from the native swapchain. sc->base.xscn = xscn; - sc->display = eglGetCurrentDisplay(); + struct xrt_swapchain_gl *xscgl = &sc->base.base; + glGenTextures(native_xsc->num_images, xscgl->images); GLuint binding_enum = 0; diff --git a/src/xrt/compositor/client/comp_gl_memobj_swapchain.c b/src/xrt/compositor/client/comp_gl_memobj_swapchain.c index 2aedaf1b8..2b4c1e7ab 100644 --- a/src/xrt/compositor/client/comp_gl_memobj_swapchain.c +++ b/src/xrt/compositor/client/comp_gl_memobj_swapchain.c @@ -60,6 +60,7 @@ client_gl_memobj_swapchain_destroy(struct xrt_swapchain *xsc) free(sc); } + struct xrt_swapchain * client_gl_memobj_swapchain_create(struct xrt_compositor *xc, const struct xrt_swapchain_create_info *info, diff --git a/src/xrt/compositor/client/comp_vk_client.c b/src/xrt/compositor/client/comp_vk_client.c index bcfdc85f3..2f8498096 100644 --- a/src/xrt/compositor/client/comp_vk_client.c +++ b/src/xrt/compositor/client/comp_vk_client.c @@ -92,6 +92,7 @@ client_vk_swapchain_acquire_image(struct xrt_swapchain *xsc, uint32_t *out_index VK_ERROR(vk, "Could not submit to queue: %d", ret); return XRT_ERROR_FAILED_TO_SUBMIT_VULKAN_COMMANDS; } + return XRT_SUCCESS; } @@ -392,8 +393,8 @@ client_vk_swapchain_create(struct xrt_compositor *xc, sc->base.base.acquire_image = client_vk_swapchain_acquire_image; sc->base.base.wait_image = client_vk_swapchain_wait_image; sc->base.base.release_image = client_vk_swapchain_release_image; - // Fetch the number of images from the native swapchain. - sc->base.base.num_images = xsc->num_images; + sc->base.base.reference.count = 1; + sc->base.base.num_images = xsc->num_images; // Fetch the number of images from the native swapchain. sc->c = c; sc->xscn = xscn; From c8cde9c447a07ded04af564ff0e4db8080d802ef Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 9 Apr 2021 20:29:51 +0100 Subject: [PATCH 355/883] ipc: Set correct reference count on swapchain --- src/xrt/ipc/client/ipc_client_compositor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xrt/ipc/client/ipc_client_compositor.c b/src/xrt/ipc/client/ipc_client_compositor.c index 16f18abaa..86bec71d7 100644 --- a/src/xrt/ipc/client/ipc_client_compositor.c +++ b/src/xrt/ipc/client/ipc_client_compositor.c @@ -225,6 +225,7 @@ swapchain_server_create(struct ipc_client_compositor *icc, ics->base.base.acquire_image = ipc_compositor_swapchain_acquire_image; ics->base.base.release_image = ipc_compositor_swapchain_release_image; ics->base.base.destroy = ipc_compositor_swapchain_destroy; + ics->base.base.reference.count = 1; ics->icc = icc; ics->id = handle; @@ -272,6 +273,7 @@ swapchain_server_import(struct ipc_client_compositor *icc, ics->base.base.acquire_image = ipc_compositor_swapchain_acquire_image; ics->base.base.release_image = ipc_compositor_swapchain_release_image; ics->base.base.destroy = ipc_compositor_swapchain_destroy; + ics->base.base.reference.count = 1; ics->icc = icc; ics->id = id; From 654043ede51baa5cc72b1bf160bd0237485d821a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 9 Apr 2021 20:31:22 +0100 Subject: [PATCH 356/883] ipc: Remove stale todo --- src/xrt/ipc/server/ipc_server_handler.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 4157a2d09..001e82f13 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -746,7 +746,6 @@ ipc_handle_swapchain_release_image(volatile struct ipc_client_state *ics, uint32 xrt_result_t ipc_handle_swapchain_destroy(volatile struct ipc_client_state *ics, uint32_t id) { - //! @todo Implement destroy swapchain. ics->num_swapchains--; // Drop our reference, does NULL checking. Cast away volatile. From c42198b86fdb38e52fed8dac3d22963c6c0da15f Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 9 Apr 2021 20:38:57 +0100 Subject: [PATCH 357/883] doc: Document !721 & !754 --- doc/changes/compositor/mr.721.md | 1 + doc/changes/ipc/mr.721.md | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 doc/changes/ipc/mr.721.md diff --git a/doc/changes/compositor/mr.721.md b/doc/changes/compositor/mr.721.md index 73a194938..d5e50e7dc 100644 --- a/doc/changes/compositor/mr.721.md +++ b/doc/changes/compositor/mr.721.md @@ -1,4 +1,5 @@ --- +- mr.754 - mr.759 --- multi: Introduce a new multi client compositor layer, this allows rendering code diff --git a/doc/changes/ipc/mr.721.md b/doc/changes/ipc/mr.721.md new file mode 100644 index 000000000..78c297452 --- /dev/null +++ b/doc/changes/ipc/mr.721.md @@ -0,0 +1,5 @@ +--- +- mr.754 +--- +Now that there is a interface that allows the compositor to support +multi-client rendering use that instead of doing our own rendering. From 52d1c4d834f6c063362e4c0a5d1a2c4b64485716 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 7 Apr 2021 19:45:54 +0100 Subject: [PATCH 358/883] u/trace_marker: Add json writing helpers --- src/xrt/auxiliary/util/u_trace_marker.c | 69 +++++++++++++++++++++++++ src/xrt/auxiliary/util/u_trace_marker.h | 30 +++++++++++ 2 files changed, 99 insertions(+) diff --git a/src/xrt/auxiliary/util/u_trace_marker.c b/src/xrt/auxiliary/util/u_trace_marker.c index 8b30bf91a..329f42574 100644 --- a/src/xrt/auxiliary/util/u_trace_marker.c +++ b/src/xrt/auxiliary/util/u_trace_marker.c @@ -16,6 +16,7 @@ #include "u_trace_marker.h" #ifdef XRT_OS_LINUX +#include #include #include #include @@ -113,3 +114,71 @@ void u_trace_data(int fd, enum u_trace_data_type type, void *data, size_t size) {} #endif + + +/* + * + * Writing functions. + * + */ + +void +u_trace_maker_write_json_metadata(FILE *file, uint32_t pid, uint32_t tid, const char *name) +{ + fprintf(file, + ",\n" + "\t\t{\n" + "\t\t\t\"ph\": \"M\",\n" + "\t\t\t\"name\": \"thread_name\",\n" + "\t\t\t\"pid\": %u,\n" + "\t\t\t\"tid\": %u,\n" + "\t\t\t\"args\": {\n" + "\t\t\t\t\"name\": \"%s\"\n" + "\t\t\t}\n" + "\t\t}", + pid, tid, name); +} + +void +u_trace_maker_write_json_begin(FILE *file, // + uint32_t pid, // + uint32_t tid, // + const char *name, // + const char *cat, // + uint64_t when_ns) // +{ + // clang-format off + fprintf(file, + ",\n" + "\t\t{\n" + "\t\t\t\"ph\": \"B\",\n" + "\t\t\t\"name\": \"%s\",\n" + "\t\t\t\"cat\": \"%s\",\n" + "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" + "\t\t\t\"pid\": %u,\n" + "\t\t\t\"tid\": %u,\n" + "\t\t\t\"args\": {}\n" + "\t\t}", + name, cat, when_ns / 1000, when_ns % 1000, pid, tid); + // clang-format on +} + +void +u_trace_maker_write_json_end(FILE *file, // + uint32_t pid, // + uint32_t tid, // + uint64_t when_ns) // +{ + // clang-format off + fprintf(file, + ",\n" + "\t\t{\n" + "\t\t\t\"ph\": \"E\",\n" + "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" + "\t\t\t\"pid\": %u,\n" + "\t\t\t\"tid\": %u,\n" + "\t\t\t\"args\": {}\n" + "\t\t}", + when_ns / 1000, when_ns % 1000, pid, tid); + // clang-format on +} diff --git a/src/xrt/auxiliary/util/u_trace_marker.h b/src/xrt/auxiliary/util/u_trace_marker.h index 4818ee36d..cc15e149e 100644 --- a/src/xrt/auxiliary/util/u_trace_marker.h +++ b/src/xrt/auxiliary/util/u_trace_marker.h @@ -47,6 +47,36 @@ extern int u_trace_comp_fd; #define COMP_TRACE_DATA(type, data) U_TRACE_DATA(u_trace_comp_fd, type, data) +/* + * + * JSON dumper helper files. + * + */ + +void +u_trace_maker_write_json_metadata( // + FILE *file, // + uint32_t pid, // + uint32_t tid, // + const char *name); // + +void +u_trace_maker_write_json_begin( // + FILE *file, // + uint32_t pid, // + uint32_t tid, // + const char *name, // + const char *cat, // + uint64_t when_ns); // + +void +u_trace_maker_write_json_end( // + FILE *file, // + uint32_t pid, // + uint32_t tid, // + uint64_t when_ns); // + + /* * * Functions implemented by other modules. From c750447add2772a171817a1bad12147ec09819a4 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 9 Apr 2021 17:36:49 +0100 Subject: [PATCH 359/883] u/trace_marker: Add render timing support --- src/xrt/auxiliary/util/u_timing_render.c | 70 +++++++++++++++++++++++- src/xrt/auxiliary/util/u_trace_marker.h | 7 +++ src/xrt/targets/cli/cli_cmd_trace.c | 2 + 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index 6c84f5fc3..287ee8dd3 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -12,8 +12,9 @@ #include "util/u_time.h" #include "util/u_misc.h" #include "util/u_debug.h" -#include "util/u_logging.h" #include "util/u_timing.h" +#include "util/u_logging.h" +#include "util/u_trace_marker.h" #include #include @@ -315,9 +316,13 @@ rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) uint64_t now_ns = os_monotonic_get_ns(); + // Update all data. f->when.delivered_ns = now_ns; - f->state = U_RT_READY; - f->frame_id = -1; + + + /* + * Process data. + */ int64_t diff_ns = f->predicted_delivery_time_ns - now_ns; bool late = false; @@ -343,6 +348,13 @@ rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) do_iir_filter(&rt->app.cpu_time_ns, IIR_ALPHA_LT, IIR_ALPHA_GT, diff_cpu_ns); do_iir_filter(&rt->app.draw_time_ns, IIR_ALPHA_LT, IIR_ALPHA_GT, diff_draw_ns); + + // Trace the data. + COMP_TRACE_DATA(U_TRACE_DATA_TYPE_TIMING_RENDER, *f); + + // Reset the frame. + f->state = U_RT_READY; + f->frame_id = -1; } static void @@ -394,3 +406,55 @@ u_rt_create(struct u_render_timing **out_urt) return XRT_SUCCESS; } + + +/* + * + * Tracing data. + * + */ + +#define PID_NR 43 +#define TID_ESTIMATED_CPU 20 +#define TID_ESTIMATED_DRAW 21 +#define TID_ACTUAL_CPU 22 +#define TID_ACTUAL_DRAW 23 + +static void +trace_begin_id(FILE *file, uint32_t tid, const char *name, int64_t frame_id, const char *cat, uint64_t when_ns) +{ + char temp[256]; + snprintf(temp, sizeof(temp), "%s %" PRIi64, name, frame_id); + + u_trace_maker_write_json_begin(file, PID_NR, tid, temp, cat, when_ns); +} + +static void +trace_end(FILE *file, uint32_t tid, uint64_t when_ns) +{ + u_trace_maker_write_json_end(file, PID_NR, tid, when_ns); +} + +void +u_rt_write_json_metadata(FILE *file) +{ + u_trace_maker_write_json_metadata(file, PID_NR, TID_ESTIMATED_CPU, "1 CPU estimated"); + u_trace_maker_write_json_metadata(file, PID_NR, TID_ESTIMATED_DRAW, "2 Draw estimated"); + u_trace_maker_write_json_metadata(file, PID_NR, TID_ACTUAL_CPU, "1 CPU actual"); + u_trace_maker_write_json_metadata(file, PID_NR, TID_ACTUAL_DRAW, "2 Draw actual"); +} + +void +u_rt_write_json(FILE *file, void *data) +{ + struct u_rt_frame *f = (struct u_rt_frame *)data; + + trace_begin_id(file, TID_ACTUAL_CPU, "sleep", f->frame_id, "sleep", f->when.predicted_ns); + trace_end(file, TID_ACTUAL_CPU, f->when.wait_woke_ns); + + trace_begin_id(file, TID_ACTUAL_CPU, "cpu", f->frame_id, "cpu", f->when.wait_woke_ns); + trace_end(file, TID_ACTUAL_CPU, f->when.begin_ns); + + trace_begin_id(file, TID_ACTUAL_DRAW, "draw", f->frame_id, "draw", f->when.begin_ns); + trace_end(file, TID_ACTUAL_DRAW, f->when.delivered_ns); +} diff --git a/src/xrt/auxiliary/util/u_trace_marker.h b/src/xrt/auxiliary/util/u_trace_marker.h index cc15e149e..dfe99e5a2 100644 --- a/src/xrt/auxiliary/util/u_trace_marker.h +++ b/src/xrt/auxiliary/util/u_trace_marker.h @@ -24,6 +24,7 @@ extern "C" { enum u_trace_data_type { U_TRACE_DATA_TYPE_TIMING_FRAME, + U_TRACE_DATA_TYPE_TIMING_RENDER, }; void @@ -89,6 +90,12 @@ u_ft_write_json(FILE *file, void *data); void u_ft_write_json_metadata(FILE *file); +void +u_rt_write_json(FILE *file, void *data); + +void +u_rt_write_json_metadata(FILE *file); + /* * diff --git a/src/xrt/targets/cli/cli_cmd_trace.c b/src/xrt/targets/cli/cli_cmd_trace.c index ca0d3a66b..2e10f4254 100644 --- a/src/xrt/targets/cli/cli_cmd_trace.c +++ b/src/xrt/targets/cli/cli_cmd_trace.c @@ -141,6 +141,7 @@ handle_data(const char *rest_of_line, size_t len) switch (type) { case U_TRACE_DATA_TYPE_TIMING_FRAME: u_ft_write_json(t.file, (void *)data); break; + case U_TRACE_DATA_TYPE_TIMING_RENDER: u_rt_write_json(t.file, (void *)data); break; default: fprintf(stderr, "%.*s\n", (int)len, rest_of_line); break; } } @@ -269,6 +270,7 @@ trace_pipe(int argc, const char **argv) json_w_header(); u_ft_write_json_metadata(t.file); + u_rt_write_json_metadata(t.file); P(" :: Looping\n"); From 898bf15a086063f1aaebd8fc42e40f26f7234001 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 7 Apr 2021 19:47:45 +0100 Subject: [PATCH 360/883] u/tf: Use new trace marker helpers --- src/xrt/auxiliary/util/u_timing_frame.c | 133 +++--------------------- 1 file changed, 15 insertions(+), 118 deletions(-) diff --git a/src/xrt/auxiliary/util/u_timing_frame.c b/src/xrt/auxiliary/util/u_timing_frame.c index 41db82a4c..f7ce6f99e 100644 --- a/src/xrt/auxiliary/util/u_timing_frame.c +++ b/src/xrt/auxiliary/util/u_timing_frame.c @@ -518,6 +518,7 @@ u_ft_display_timing_create(uint64_t estimated_frame_period_ns, struct u_frame_ti * */ +#define PID_NR 42 #define TID_NORMAL 43 #define TID_GPU 44 #define TID_INFO 45 @@ -539,12 +540,12 @@ trace_event(FILE *file, const char *name, uint64_t when_ns) "\t\t\t\"ph\": \"i\",\n" "\t\t\t\"name\": \"%s\",\n" "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": 43,\n" + "\t\t\t\"pid\": %u,\n" + "\t\t\t\"tid\": %u,\n" "\t\t\t\"s\": \"g\",\n" "\t\t\t\"args\": {}\n" "\t\t}", - name, when_ns / 1000, when_ns % 1000); + name, when_ns / 1000, when_ns % 1000, PID_NR, TID_NORMAL); // clang-format off } @@ -562,40 +563,17 @@ trace_event_id(FILE *file, const char *name, int64_t frame_id, uint64_t when_ns) "\t\t\t\"ph\": \"i\",\n" "\t\t\t\"name\": \"%s\",\n" "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": 43,\n" + "\t\t\t\"pid\": %u,\n" + "\t\t\t\"tid\": %u,\n" "\t\t\t\"s\": \"g\",\n" "\t\t\t\"args\": {" "\t\t\t\t\"id\": %" PRIi64 "\n" "\t\t\t}\n" "\t\t}", - name, when_ns / 1000, when_ns % 1000, frame_id); + name, when_ns / 1000, when_ns % 1000, PID_NR, TID_NORMAL, frame_id); // clang-format off } -static void -trace_begin(FILE *file, uint32_t tid, const char *name, const char *cat, uint64_t when_ns) -{ - if (file == NULL) { - return; - } - - // clang-format off - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"B\",\n" - "\t\t\t\"name\": \"%s\",\n" - "\t\t\t\"cat\": \"%s\",\n" - "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {}\n" - "\t\t}", - name, cat, when_ns / 1000, when_ns % 1000, tid); - // clang-format on -} - static void trace_begin_id(FILE *file, uint32_t tid, const char *name, int64_t frame_id, const char *cat, uint64_t when_ns) { @@ -606,28 +584,13 @@ trace_begin_id(FILE *file, uint32_t tid, const char *name, int64_t frame_id, con char temp[256]; snprintf(temp, sizeof(temp), "%s %" PRIi64, name, frame_id); - trace_begin(file, tid, temp, cat, when_ns); + u_trace_maker_write_json_begin(file, PID_NR, tid, temp, cat, when_ns); } static void trace_end(FILE *file, uint32_t tid, uint64_t when_ns) { - if (file == NULL) { - return; - } - - // clang-format off - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"E\",\n" - "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {}\n" - "\t\t}", - when_ns / 1000, when_ns % 1000, tid); - // clang-format on + u_trace_maker_write_json_end(file, PID_NR, tid, when_ns); } static void @@ -688,77 +651,11 @@ u_ft_write_json(FILE *file, void *data) void u_ft_write_json_metadata(FILE *file) { - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"M\",\n" - "\t\t\t\"name\": \"thread_name\",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {\n" - "\t\t\t\t\"name\": \"1 RendererThread\"\n" - "\t\t\t}\n" - "\t\t}", - TID_NORMAL); - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"M\",\n" - "\t\t\t\"name\": \"thread_name\",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {\n" - "\t\t\t\t\"name\": \"2 GPU\"\n" - "\t\t\t}\n" - "\t\t}", - TID_GPU); - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"M\",\n" - "\t\t\t\"name\": \"thread_name\",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {\n" - "\t\t\t\t\"name\": \"3 Info\"\n" - "\t\t\t}\n" - "\t\t}", - TID_INFO); - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"M\",\n" - "\t\t\t\"name\": \"thread_name\",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {\n" - "\t\t\t\t\"name\": \"4 FrameTiming\"\n" - "\t\t\t}\n" - "\t\t}", - TID_FRAME); - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"M\",\n" - "\t\t\t\"name\": \"thread_name\",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {\n" - "\t\t\t\t\"name\": \"5 Slips\"\n" - "\t\t\t}\n" - "\t\t}", - TID_ERROR); - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"M\",\n" - "\t\t\t\"name\": \"thread_name\",\n" - "\t\t\t\"pid\": 42,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {\n" - "\t\t\t\t\"name\": \"6 App time\"\n" - "\t\t\t}\n" - "\t\t}", - TID_APP); + u_trace_maker_write_json_metadata(file, PID_NR, TID_NORMAL, "1 RendererThread"); + u_trace_maker_write_json_metadata(file, PID_NR, TID_GPU, "2 GPU"); + u_trace_maker_write_json_metadata(file, PID_NR, TID_INFO, "3 Info"); + u_trace_maker_write_json_metadata(file, PID_NR, TID_FRAME, "4 FrameTiming"); + u_trace_maker_write_json_metadata(file, PID_NR, TID_ERROR, "5 Slips"); + u_trace_maker_write_json_metadata(file, PID_NR, TID_APP, "6 App time"); fflush(file); } From 05f14461a3a7fb546dfbc15f7cc2d1e5ff3d1ff1 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 15 Apr 2021 17:34:41 +0100 Subject: [PATCH 361/883] t/psvr: Fix warning --- src/xrt/auxiliary/tracking/t_tracker_psvr.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp b/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp index 008eeb3ea..2ee000d2b 100644 --- a/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp +++ b/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp @@ -1881,8 +1881,6 @@ imu_data(TrackerPSVR &t, timepoint_ns timestamp_ns, struct xrt_tracking_sample * return; } if (t.last_imu != 0) { - time_duration_ns delta_ns = timestamp_ns - t.last_imu; - float dt = time_ns_to_s(delta_ns); // Update 3DOF fusion m_imu_3dof_update(&t.fusion.imu_3dof, timestamp_ns, &sample->accel_m_s2, &sample->gyro_rad_secs); } From 26756cc52d2eb5bc7572bcd83e0d3629fc43529a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 15 Apr 2021 17:35:16 +0100 Subject: [PATCH 362/883] aux/vk: Fix use free of stack variable and use correct return --- src/xrt/auxiliary/vk/vk_helpers.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/xrt/auxiliary/vk/vk_helpers.c b/src/xrt/auxiliary/vk/vk_helpers.c index 54a46c657..51e25aff0 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.c +++ b/src/xrt/auxiliary/vk/vk_helpers.c @@ -1062,21 +1062,26 @@ vk_check_extension(struct vk_bundle *vk, VkExtensionProperties *props, uint32_t return false; } -static bool +static VkResult vk_get_device_ext_props(struct vk_bundle *vk, VkPhysicalDevice physical_device, - VkExtensionProperties **props, - uint32_t *num_props) + VkExtensionProperties **out_props, + uint32_t *out_num_props) { - VkResult res = vk->vkEnumerateDeviceExtensionProperties(physical_device, NULL, num_props, NULL); + uint32_t num_props = 0; + VkResult res = vk->vkEnumerateDeviceExtensionProperties(physical_device, NULL, &num_props, NULL); vk_check_error("vkEnumerateDeviceExtensionProperties", res, false); - *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, *num_props); + VkExtensionProperties *props = U_TYPED_ARRAY_CALLOC(VkExtensionProperties, num_props); - res = vk->vkEnumerateDeviceExtensionProperties(physical_device, NULL, num_props, *props); + res = vk->vkEnumerateDeviceExtensionProperties(physical_device, NULL, &num_props, props); vk_check_error_with_free("vkEnumerateDeviceExtensionProperties", res, false, props); - return true; + // Check above returns on failure. + *out_props = props; + *out_num_props = num_props; + + return VK_SUCCESS; } static bool @@ -1089,9 +1094,9 @@ vk_build_device_extensions(struct vk_bundle *vk, const char ***out_device_extensions, uint32_t *out_num_device_extensions) { - VkExtensionProperties *props; - uint32_t num_props; - if (!vk_get_device_ext_props(vk, physical_device, &props, &num_props)) { + VkExtensionProperties *props = NULL; + uint32_t num_props = 0; + if (vk_get_device_ext_props(vk, physical_device, &props, &num_props) != VK_SUCCESS) { return false; } From f434de27bd2c265affad2fbcabce43c19336b0fd Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 15 Apr 2021 17:35:45 +0100 Subject: [PATCH 363/883] st/gui: Fix warning (false positive) --- src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c b/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c index 904f96ed6..63caff4b6 100644 --- a/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c +++ b/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c @@ -212,7 +212,7 @@ scene_render(struct gui_scene *scene, struct gui_program *p) struct xrt_tracking_override *o = &ts->overrides[ts->editing_override]; igBegin("Tracker Device Offset", NULL, 0); - int target, tracker; + int target = 0, tracker = 0; if (get_indices(p, ts, o, &target, &tracker)) { igText("Editing %s [%s] <- %s [%s]", p->xdevs[target]->str, o->target_device_serial, p->xdevs[tracker]->str, o->tracker_device_serial); From 74c9531d4f644f9f992c837ac8580ba7b300728f Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 15 Apr 2021 17:37:19 +0100 Subject: [PATCH 364/883] st/oxr: Use right enum for ret check --- src/xrt/state_trackers/oxr/oxr_session_egl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/oxr/oxr_session_egl.c b/src/xrt/state_trackers/oxr/oxr_session_egl.c index 465039029..75ff35ca4 100644 --- a/src/xrt/state_trackers/oxr/oxr_session_egl.c +++ b/src/xrt/state_trackers/oxr/oxr_session_egl.c @@ -74,7 +74,7 @@ oxr_session_populate_egl(struct oxr_logger *log, "XrGraphicsBindingEGLMNDX::config can not be null when EGL_KHR_no_config_context is " "not supported by the display."); } - if (xret != XR_SUCCESS || xcgl == NULL) { + if (xret != XRT_SUCCESS || xcgl == NULL) { return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED, "Failed to create an egl client compositor"); } From c24a20ce18ab4128de9dd4267ae54fbc010d51a4 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 15 Apr 2021 17:37:32 +0100 Subject: [PATCH 365/883] t/cli: Fix warnings --- src/xrt/targets/cli/cli_cmd_trace.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/xrt/targets/cli/cli_cmd_trace.c b/src/xrt/targets/cli/cli_cmd_trace.c index 2e10f4254..44b78749a 100644 --- a/src/xrt/targets/cli/cli_cmd_trace.c +++ b/src/xrt/targets/cli/cli_cmd_trace.c @@ -130,7 +130,7 @@ handle_data(const char *rest_of_line, size_t len) for (int i = 0; i < data_length; i++) { - int tmp = 0; + unsigned int tmp = 0; scan = sscanf(rest_of_line + (i * 2), "%2x", &tmp); if (scan < 1) { return; @@ -238,7 +238,8 @@ signal_handler(int signum, siginfo_t *info, void *ptr) t.running = false; // Since we are doing a clean shutdown ^C be on it's own line. - write(STDERR_FILENO, "\n", 1); + ssize_t ret = write(STDERR_FILENO, "\n", 1); + (void)ret; // We are just trying to make the CLI look better. } void From cabaece3449ce3c37a8fc99c1088ac1112fb7ce3 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 14 Apr 2021 19:54:33 +0100 Subject: [PATCH 366/883] st/oxr: Print value on bad layer type --- src/xrt/state_trackers/oxr/oxr_session.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 8378e8d65..8ef0bfd7d 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -1865,9 +1865,8 @@ oxr_session_frame_end(struct oxr_logger *log, struct oxr_session *sess, const Xr break; default: return oxr_error(log, XR_ERROR_LAYER_INVALID, - "(frameEndInfo->layers[%u]->type) " - "layer type not supported", - i); + "(frameEndInfo->layers[%u]->type) layer type not supported (%u)", i, + layer->type); } if (res != XR_SUCCESS) { From 0e18e1f8b035dfa9ca388aba5c7e18e043db6860 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 14 Apr 2021 19:55:01 +0100 Subject: [PATCH 367/883] d/qwerty: Add SDL include dirs --- src/xrt/drivers/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index 913e4b0b9..5c686bf03 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -53,7 +53,14 @@ if(XRT_BUILD_DRIVER_QWERTY) ) add_library(drv_qwerty STATIC ${QWERTY_SOURCE_FILES}) - target_link_libraries(drv_qwerty PRIVATE xrt-interfaces aux_util ${SDL2_LIBRARIES}) + target_link_libraries(drv_qwerty PRIVATE + xrt-interfaces + aux_util + ${SDL2_LIBRARIES} + ) + target_include_directories(drv_qwerty PRIVATE + ${SDL2_INCLUDE_DIRS} + ) list(APPEND ENABLED_DRIVERS qwerty) add_library(drv_qwerty_includes INTERFACE) From c92bc0a70495f86aa76b1c50e27629f2a488711b Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 21 Oct 2020 20:48:54 +0200 Subject: [PATCH 368/883] xrt: Add u_file_get_runtime_dir() and u_file_get_path_in_runtime_dir() Analog to u_file_get_path_in_config_dir. --- src/xrt/auxiliary/util/u_file.c | 24 ++++++++++++++++++++++++ src/xrt/auxiliary/util/u_file.h | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/src/xrt/auxiliary/util/u_file.c b/src/xrt/auxiliary/util/u_file.c index b40295860..43152e04f 100644 --- a/src/xrt/auxiliary/util/u_file.c +++ b/src/xrt/auxiliary/util/u_file.c @@ -104,6 +104,30 @@ u_file_open_file_in_config_dir(const char *filename, const char *mode) return fopen(file_str, mode); } +ssize_t +u_file_get_runtime_dir(char *out_path, size_t out_path_size) +{ + const char *xgd_rt = getenv("XDG_RUNTIME_DIR"); + if (xgd_rt != NULL) { + return snprintf(out_path, out_path_size, "%s", xgd_rt); + } + + const char *tmp = "/tmp"; + return snprintf(out_path, out_path_size, "%s", tmp); +} + +ssize_t +u_file_get_path_in_runtime_dir(const char *filename, char *out_path, size_t out_path_size) +{ + char tmp[PATH_MAX]; + ssize_t i = u_file_get_runtime_dir(tmp, sizeof(tmp)); + if (i <= 0) { + return -1; + } + + return snprintf(out_path, out_path_size, "%s/%s", tmp, filename); +} + #endif char * diff --git a/src/xrt/auxiliary/util/u_file.h b/src/xrt/auxiliary/util/u_file.h index e272c94db..fbbe57fb5 100644 --- a/src/xrt/auxiliary/util/u_file.h +++ b/src/xrt/auxiliary/util/u_file.h @@ -28,9 +28,15 @@ u_file_get_path_in_config_dir(const char *suffix, char *out_path, size_t out_pat FILE * u_file_open_file_in_config_dir(const char *filename, const char *mode); +ssize_t +u_file_get_runtime_dir(char *out_path, size_t out_path_size); + char * u_file_read_content(FILE *file); +ssize_t +u_file_get_path_in_runtime_dir(const char *filename, char *out_path, size_t out_path_size); + #ifdef __cplusplus } #endif From 4ea68b89a442ab9407e413638b774e7b761ebac4 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 21 Oct 2020 22:18:57 +0200 Subject: [PATCH 369/883] xrt: Add u_process, backed by libbsd's pidfile Delete stale ipc files in ipc server when not already running. If built without libbsd, fall back to previous behavior of complaining about existing ipc files and exit. --- CMakeLists.txt | 3 + meson.build | 7 ++ meson_options.txt | 5 + src/xrt/auxiliary/CMakeLists.txt | 6 + src/xrt/auxiliary/meson.build | 8 ++ src/xrt/auxiliary/util/u_process.c | 105 ++++++++++++++++++ src/xrt/auxiliary/util/u_process.h | 42 +++++++ src/xrt/include/xrt/meson.build | 4 + .../include/xrt/xrt_config_have.h.cmake_in | 1 + src/xrt/ipc/server/ipc_server.h | 3 + .../ipc/server/ipc_server_mainloop_linux.c | 27 +++-- src/xrt/ipc/server/ipc_server_process.c | 10 ++ 12 files changed, 213 insertions(+), 8 deletions(-) create mode 100644 src/xrt/auxiliary/util/u_process.c create mode 100644 src/xrt/auxiliary/util/u_process.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b2eee630c..c2af2cca3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") endif() find_package(OpenGL COMPONENTS GLX) pkg_search_module(DBUS dbus-1) + pkg_search_module(LIBBSD libbsd) pkg_check_modules(GST gstreamer-1.0 @@ -143,6 +144,7 @@ cmake_dependent_option(XRT_HAVE_OPENGLES "Enable OpenGL-ES Graphics API support" cmake_dependent_option(XRT_HAVE_EGL "Enable OpenGL on EGL Graphics API support" ON "EGL_FOUND; XRT_HAVE_OPENGL OR XRT_HAVE_OPENGLES" OFF) cmake_dependent_option(XRT_HAVE_DBUS "Enable dbus support (for BLE support)" ON "DBUS_FOUND" OFF) cmake_dependent_option(XRT_FEATURE_COMPOSITOR_MAIN "Build main compositor host functionality" ON "XRT_HAVE_VULKAN; XRT_HAVE_WAYLAND OR XRT_HAVE_XCB OR ANDROID OR WIN32" OFF) +cmake_dependent_option(XRT_HAVE_LIBBSD "Enable libbsd support" ON "LIBBSD_FOUND" OFF) cmake_dependent_option(XRT_FEATURE_OPENXR "Build OpenXR runtime target" ON "XRT_FEATURE_COMPOSITOR_MAIN" OFF) cmake_dependent_option(XRT_FEATURE_SERVICE "Enable separate service module for OpenXR runtime" ON "NOT WIN32 AND XRT_FEATURE_OPENXR" OFF) cmake_dependent_option(XRT_HAVE_SYSTEMD "Enable systemd support (for socket activation of service)" ON "Systemd_FOUND AND XRT_FEATURE_SERVICE" OFF) @@ -335,6 +337,7 @@ message(STATUS "# OPENGLES: ${XRT_HAVE_OPENGLES}") message(STATUS "# EGL: ${XRT_HAVE_EGL}") message(STATUS "# DBUS: ${XRT_HAVE_DBUS}") message(STATUS "# VF: ${XRT_HAVE_VF}") +message(STATUS "# LIBBSD: ${XRT_HAVE_LIBBSD}") message(STATUS "# SYSTEMD: ${XRT_HAVE_SYSTEMD}") message(STATUS "# LIBUSB: ${XRT_HAVE_LIBUSB}") message(STATUS "# JPEG: ${XRT_HAVE_JPEG}") diff --git a/meson.build b/meson.build index c65b9f091..507e9c0a9 100644 --- a/meson.build +++ b/meson.build @@ -72,6 +72,7 @@ zlib = dependency('zlib', required: false) survive = dependency('survive', required: false) dbus = dependency('dbus-1', required: get_option('dbus')) systemd = dependency('libsystemd', required: get_option('systemd')) +libbsd = dependency('libbsd', required: get_option('libbsd')) gst = dependency('gstreamer-1.0', required: false) gst_app = dependency('gstreamer-app-1.0', required: false) gst_video= dependency('gstreamer-video-1.0', required: false) @@ -335,3 +336,9 @@ if not get_option('dbus').disabled() and dbus.found() else message(' dbus: no') endif + +if not get_option('libbsd').disabled() and libbsd.found() + message(' libbsd: yes') +else + message(' libbsd: no') +endif diff --git a/meson_options.txt b/meson_options.txt index 48661d760..69ada8163 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -77,6 +77,11 @@ option('dbus', value: 'auto', description: 'Enable support for dbus.') +option('libbsd', + type: 'feature', + value: 'auto', + description: 'Enable support for libbsd.') + option('systemd', type: 'feature', value: 'auto', diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index 86b302bcf..b64665df1 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -159,6 +159,8 @@ set(UTIL_SOURCE_FILES util/u_config_json.c util/u_config_json.h util/u_verify.h + util/u_process.c + util/u_process.h ) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/util/u_git_tag.c.in" "${CMAKE_CURRENT_BINARY_DIR}/u_git_tag.c" @ONLY) @@ -225,6 +227,10 @@ if(XRT_HAVE_SYSTEM_CJSON) else() target_link_libraries(aux_util PUBLIC xrt-external-cjson) endif() +if(XRT_HAVE_LIBBSD) + target_include_directories(aux_util SYSTEM PRIVATE ${LIBBSD_INCLUDE_DIRS}) + target_link_libraries(aux_util PUBLIC ${LIBBSD_LIBRARIES}) +endif() if(ANDROID) target_link_libraries(aux_util PUBLIC ${ANDROID_LOG_LIBRARY}) endif() diff --git a/src/xrt/auxiliary/meson.build b/src/xrt/auxiliary/meson.build index 6d7254c58..d35a238fd 100644 --- a/src/xrt/auxiliary/meson.build +++ b/src/xrt/auxiliary/meson.build @@ -11,6 +11,11 @@ u_git_tag_c = vcs_tag( replace_string: '@GIT_DESC@', ) +aux_util_deps = [ xrt_config_have ] +if libbsd.found() and not get_option('libbsd').disabled() + aux_util_deps += libbsd +endif + lib_aux_util = static_library( 'aux_util', files( @@ -65,6 +70,8 @@ lib_aux_util = static_library( 'util/u_config_json.c', 'util/u_config_json.h', 'util/u_verify.h', + 'util/u_process.c', + 'util/u_process.h', ) + [ u_git_tag_c, ], @@ -73,6 +80,7 @@ lib_aux_util = static_library( cjson_include, ], dependencies: [ + aux_util_deps, xrt_config_have, ] ) diff --git a/src/xrt/auxiliary/util/u_process.c b/src/xrt/auxiliary/util/u_process.c new file mode 100644 index 000000000..09530517c --- /dev/null +++ b/src/xrt/auxiliary/util/u_process.c @@ -0,0 +1,105 @@ + +// Copyright 2019-2020, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Simple process handling + * @author Christoph Haag + * @ingroup aux_util + */ + +#include "xrt/xrt_config.h" + +#ifdef XRT_OS_LINUX + +#define PID_FILE_NAME "monado.pid" + +#ifdef XRT_HAVE_LIBBSD +#include +#endif + +#include + +#include +#include +#include "u_misc.h" +#include "u_file.h" +#include "u_logging.h" + +struct u_process +{ +#ifdef XRT_HAVE_LIBBSD + struct pidfh *pfh; +#else + int pid; +#endif +}; + +static inline int +get_pidfile_path(char *buf) +{ + int size = u_file_get_path_in_runtime_dir(PID_FILE_NAME, buf, PATH_MAX); + if (size == -1) { + U_LOG_W("Failed to determine runtime dir, not creating pidfile"); + return -1; + } + return 0; +} + +struct u_process * +u_process_create_if_not_running() +{ +#ifdef XRT_HAVE_LIBBSD + + char tmp[PATH_MAX]; + if (get_pidfile_path(tmp) < 0) { + U_LOG_W("Failed to determine runtime dir, not creating pidfile"); + return NULL; + } + + U_LOG_T("Using pidfile %s", tmp); + + pid_t otherpid; + + struct pidfh *pfh = pidfile_open(tmp, 0600, &otherpid); + if (errno == EEXIST || pfh == NULL) { + U_LOG_T("Failed to create pidfile (%s): Another Monado instance may be running", strerror(errno)); + // other process is locking pid file + return NULL; + } + + // either new or stale pidfile opened + + int write_ret = pidfile_write(pfh); + if (write_ret != 0) { + pidfile_close(pfh); + return NULL; + } + + struct u_process *ret = U_TYPED_CALLOC(struct u_process); + ret->pfh = pfh; + + U_LOG_T("No other Monado instance was running, got new pidfile"); + return ret; +#else + struct u_process *ret = U_TYPED_CALLOC(struct u_process); + //! @todo alternative implementation + ret->pid = 0; + return ret; +#endif +} + +void +u_process_destroy(struct u_process *proc) +{ + if (proc == NULL) { + return; + } + +#ifdef XRT_HAVE_LIBBSD + pidfile_close(proc->pfh); +#endif + free(proc); +} + +#endif diff --git a/src/xrt/auxiliary/util/u_process.h b/src/xrt/auxiliary/util/u_process.h new file mode 100644 index 000000000..1bbde8c04 --- /dev/null +++ b/src/xrt/auxiliary/util/u_process.h @@ -0,0 +1,42 @@ +// Copyright 2020, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Simple process handling + * @author Christoph Haag + * @ingroup aux_util + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct u_process; + +/*! + * Creates a handle for this process that is unique to the operating system user. Returns NULL if another process + * holding a handle is already running. + * + * @todo If built without libbsd support, a dummy value is returned that needs to be handled by the caller. + * + * @return a new u_process handle if no monado instance is running, NULL if another instance is already running. + * @ingroup aux_util + */ +struct u_process * +u_process_create_if_not_running(); + +/*! + * Releases the unique handle of the operating system user. + * + * @ingroup aux_util + */ +void +u_process_destroy(struct u_process *proc); + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/include/xrt/meson.build b/src/xrt/include/xrt/meson.build index 827daa4ea..40e005f49 100644 --- a/src/xrt/include/xrt/meson.build +++ b/src/xrt/include/xrt/meson.build @@ -100,6 +100,10 @@ if get_option('layer_equirect2') have_conf.set('XRT_FEATURE_OPENXR_LAYER_EQUIRECT2', true) endif +if libbsd.found() and not get_option('libbsd').disabled() + have_conf.set('XRT_HAVE_LIBBSD', true) +endif + xrt_config_have_h = configure_file( output: 'xrt_config_have.h', configuration: have_conf, diff --git a/src/xrt/include/xrt/xrt_config_have.h.cmake_in b/src/xrt/include/xrt/xrt_config_have.h.cmake_in index e490a0f82..175583a8d 100644 --- a/src/xrt/include/xrt/xrt_config_have.h.cmake_in +++ b/src/xrt/include/xrt/xrt_config_have.h.cmake_in @@ -10,6 +10,7 @@ #pragma once #cmakedefine XRT_HAVE_DBUS +#cmakedefine XRT_HAVE_LIBBSD #cmakedefine XRT_HAVE_EGL #cmakedefine XRT_HAVE_FFMPEG #cmakedefine XRT_HAVE_GST diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h index 5abf0bc1b..422f9640e 100644 --- a/src/xrt/ipc/server/ipc_server.h +++ b/src/xrt/ipc/server/ipc_server.h @@ -268,6 +268,9 @@ struct ipc_server { struct xrt_instance *xinst; + //! Handle for the current process, e.g. pidfile on linux + struct u_process *process; + /* ---- HACK ---- */ void *hack; /* ---- HACK ---- */ diff --git a/src/xrt/ipc/server/ipc_server_mainloop_linux.c b/src/xrt/ipc/server/ipc_server_mainloop_linux.c index f74c05369..31b1c6348 100644 --- a/src/xrt/ipc/server/ipc_server_mainloop_linux.c +++ b/src/xrt/ipc/server/ipc_server_mainloop_linux.c @@ -88,15 +88,26 @@ create_listen_socket(struct ipc_server_mainloop *ml, int *out_fd) strcpy(addr.sun_path, IPC_MSG_SOCK_FILE); ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + +#ifdef XRT_HAVE_LIBBSD + // no other instance is running, or we would have never arrived here + if (ret < 0 && errno == EADDRINUSE) { + U_LOG_W("Removing stale socket file %s", IPC_MSG_SOCK_FILE); + + ret = unlink(IPC_MSG_SOCK_FILE); + if (ret < 0) { + U_LOG_E("Failed to remove stale socket file %s: %s", IPC_MSG_SOCK_FILE, strerror(errno)); + return ret; + } + ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + } +#endif + if (ret < 0) { - U_LOG_E( - "Could not bind socket to path %s: is the " - "service running already?", - IPC_MSG_SOCK_FILE); + U_LOG_E("Could not bind socket to path %s: %s. Is the service running already?", IPC_MSG_SOCK_FILE, + strerror(errno)); #ifdef XRT_HAVE_SYSTEMD - U_LOG_E( - "Or, is the systemd unit monado.socket or " - "monado-dev.socket active?"); + U_LOG_E("Or, is the systemd unit monado.socket or monado-dev.socket active?"); #endif if (errno == EADDRINUSE) { U_LOG_E("If monado-service is not running, delete %s before starting a new instance", @@ -113,7 +124,7 @@ create_listen_socket(struct ipc_server_mainloop *ml, int *out_fd) close(fd); return ret; } - U_LOG_D("Created listening socket."); + U_LOG_D("Created listening socket %s.", IPC_MSG_SOCK_FILE); *out_fd = fd; return 0; } diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index 4ee940de8..6f6c93e2c 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -21,6 +21,7 @@ #include "util/u_debug.h" #include "util/u_trace_marker.h" #include "util/u_verify.h" +#include "util/u_process.h" #include "shared/ipc_shmem.h" #include "server/ipc_server.h" @@ -109,6 +110,7 @@ teardown_all(struct ipc_server *s) ipc_server_mainloop_deinit(&s->ml); os_mutex_destroy(&s->global_state.lock); + u_process_destroy(s->process); } static int @@ -394,6 +396,14 @@ ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd) static int init_all(struct ipc_server *s) { + s->process = u_process_create_if_not_running(); + + if (!s->process) { + U_LOG_E("monado-service is already running! Use XRT_LOG=trace for more information."); + teardown_all(s); + return 1; + } + // Yes we should be running. s->running = true; s->exit_on_disconnect = debug_get_bool_option_exit_on_disconnect(); From fd6bd0f592c2964ce5d2a057cc28dd57f0df73f3 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 21 Oct 2020 22:39:46 +0200 Subject: [PATCH 370/883] ipc: Use xdg runtime directory for socket u_file_get_runtime_dir falls back to /tmp if $XDG_RUNTIME_DIR is not set. ipc: %t/monado_comp_ipc socket for systemd socket activation --- src/xrt/ipc/client/ipc_client_instance.c | 13 +++++++-- .../ipc/server/ipc_server_mainloop_linux.c | 27 +++++++++++++------ src/xrt/ipc/shared/ipc_protocol.h | 2 +- src/xrt/targets/ctl/main.c | 13 ++++++++- src/xrt/targets/service/monado.in.socket | 2 +- 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/xrt/ipc/client/ipc_client_instance.c b/src/xrt/ipc/client/ipc_client_instance.c index 5dce95eed..a94d4d2ce 100644 --- a/src/xrt/ipc/client/ipc_client_instance.c +++ b/src/xrt/ipc/client/ipc_client_instance.c @@ -20,6 +20,7 @@ #include "shared/ipc_protocol.h" #include "client/ipc_client.h" #include "ipc_client_generated.h" +#include "util/u_file.h" #include #include @@ -31,7 +32,7 @@ #include #include #include - +#include #ifdef XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER #include "android/android_ahardwarebuffer_allocator.h" @@ -126,9 +127,17 @@ ipc_connect(struct ipc_connection *ipc_c) int socket = ret; + char sock_file[PATH_MAX]; + + int size = u_file_get_path_in_runtime_dir(IPC_MSG_SOCK_FILE, sock_file, PATH_MAX); + if (size == -1) { + IPC_ERROR(ipc_c, "Could not get socket file name"); + return -1; + } + memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, IPC_MSG_SOCK_FILE); + strcpy(addr.sun_path, sock_file); ret = connect(socket, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { diff --git a/src/xrt/ipc/server/ipc_server_mainloop_linux.c b/src/xrt/ipc/server/ipc_server_mainloop_linux.c index 31b1c6348..376e09dda 100644 --- a/src/xrt/ipc/server/ipc_server_mainloop_linux.c +++ b/src/xrt/ipc/server/ipc_server_mainloop_linux.c @@ -20,6 +20,7 @@ #include "util/u_misc.h" #include "util/u_debug.h" #include "util/u_trace_marker.h" +#include "util/u_file.h" #include "shared/ipc_shmem.h" #include "server/ipc_server.h" @@ -39,6 +40,7 @@ #include #include #include +#include #ifdef XRT_HAVE_SYSTEMD #include @@ -82,21 +84,30 @@ create_listen_socket(struct ipc_server_mainloop *ml, int *out_fd) return fd; } + + char sock_file[PATH_MAX]; + + int size = u_file_get_path_in_runtime_dir(IPC_MSG_SOCK_FILE, sock_file, PATH_MAX); + if (size == -1) { + U_LOG_E("Could not get socket file name"); + return -1; + } + memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, IPC_MSG_SOCK_FILE); + strcpy(addr.sun_path, sock_file); ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); #ifdef XRT_HAVE_LIBBSD // no other instance is running, or we would have never arrived here if (ret < 0 && errno == EADDRINUSE) { - U_LOG_W("Removing stale socket file %s", IPC_MSG_SOCK_FILE); + U_LOG_W("Removing stale socket file %s", sock_file); - ret = unlink(IPC_MSG_SOCK_FILE); + ret = unlink(sock_file); if (ret < 0) { - U_LOG_E("Failed to remove stale socket file %s: %s", IPC_MSG_SOCK_FILE, strerror(errno)); + U_LOG_E("Failed to remove stale socket file %s: %s", sock_file, strerror(errno)); return ret; } ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); @@ -104,27 +115,27 @@ create_listen_socket(struct ipc_server_mainloop *ml, int *out_fd) #endif if (ret < 0) { - U_LOG_E("Could not bind socket to path %s: %s. Is the service running already?", IPC_MSG_SOCK_FILE, + U_LOG_E("Could not bind socket to path %s: %s. Is the service running already?", sock_file, strerror(errno)); #ifdef XRT_HAVE_SYSTEMD U_LOG_E("Or, is the systemd unit monado.socket or monado-dev.socket active?"); #endif if (errno == EADDRINUSE) { U_LOG_E("If monado-service is not running, delete %s before starting a new instance", - IPC_MSG_SOCK_FILE); + sock_file); } close(fd); return ret; } // Save for later - ml->socket_filename = strdup(IPC_MSG_SOCK_FILE); + ml->socket_filename = strdup(sock_file); ret = listen(fd, IPC_MAX_CLIENTS); if (ret < 0) { close(fd); return ret; } - U_LOG_D("Created listening socket %s.", IPC_MSG_SOCK_FILE); + U_LOG_D("Created listening socket %s.", sock_file); *out_fd = fd; return 0; } diff --git a/src/xrt/ipc/shared/ipc_protocol.h b/src/xrt/ipc/shared/ipc_protocol.h index 5d3060e5a..e2dcdb868 100644 --- a/src/xrt/ipc/shared/ipc_protocol.h +++ b/src/xrt/ipc/shared/ipc_protocol.h @@ -20,7 +20,7 @@ #include "xrt/xrt_tracking.h" -#define IPC_MSG_SOCK_FILE "/tmp/monado_comp_ipc" +#define IPC_MSG_SOCK_FILE "monado_comp_ipc" #define IPC_MAX_SWAPCHAIN_HANDLES 8 #define IPC_CRED_SIZE 1 // auth not implemented #define IPC_BUF_SIZE 512 // must be >= largest message length in bytes diff --git a/src/xrt/targets/ctl/main.c b/src/xrt/targets/ctl/main.c index 06f68b850..bd915dc24 100644 --- a/src/xrt/targets/ctl/main.c +++ b/src/xrt/targets/ctl/main.c @@ -16,6 +16,9 @@ #include #include #include +#include + +#include "util/u_file.h" #define P(...) fprintf(stdout, __VA_ARGS__) #define PE(...) fprintf(stderr, __VA_ARGS__) @@ -212,9 +215,17 @@ do_connect(struct ipc_connection *ipc_c) return -1; } + char sock_file[PATH_MAX]; + + int rt_size = u_file_get_path_in_runtime_dir(IPC_MSG_SOCK_FILE, sock_file, PATH_MAX); + if (rt_size == -1) { + PE("Could not get socket file name"); + return -1; + } + struct sockaddr_un addr = {0}; addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, IPC_MSG_SOCK_FILE); + strcpy(addr.sun_path, sock_file); ret = connect(ipc_c->imc.socket_fd, // socket (struct sockaddr *)&addr, // address diff --git a/src/xrt/targets/service/monado.in.socket b/src/xrt/targets/service/monado.in.socket index 545486bb8..59f490985 100644 --- a/src/xrt/targets/service/monado.in.socket +++ b/src/xrt/targets/service/monado.in.socket @@ -7,7 +7,7 @@ ConditionUser=!root Conflicts=@conflicts@.socket [Socket] -ListenStream=/tmp/monado_comp_ipc +ListenStream=%t/monado_comp_ipc RemoveOnStop=true [Install] From a6be5ca0ebaa170cfdeaae822694dcd4e2b5fc8b Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Tue, 10 Nov 2020 02:08:36 +0100 Subject: [PATCH 371/883] doc: Add MR 565 changelog --- doc/changes/ipc/mr.565.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 doc/changes/ipc/mr.565.md diff --git a/doc/changes/ipc/mr.565.md b/doc/changes/ipc/mr.565.md new file mode 100644 index 000000000..5604ca24b --- /dev/null +++ b/doc/changes/ipc/mr.565.md @@ -0,0 +1,4 @@ +ipc: Use libbsd pidfile to detect running Monado instances. +Enables automatically deleting stale socket files. +The socket file is now placed in $XDG_RUNTIME_DIR/monado_comp_ipc by default +or falls back to /tmp/monado_comp_ipc again if $XDG_RUNTIME_DIR is not set. From 1f273f37dfda666c87427e4fa0cd814e54ffe909 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 15 Apr 2021 16:46:57 -0500 Subject: [PATCH 372/883] ci: Build against libbsd-dev on Debian-based systems, for pidfile support. --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2e6d59ca8..243e72bc6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ variables: CORE_REQUIRED_PACKAGES: "build-essential git wget unzip cmake meson ninja-build libeigen3-dev curl patch python3 pkg-config libx11-dev libx11-xcb-dev libxxf86vm-dev libxrandr-dev libxcb-randr0-dev libvulkan-dev glslang-tools libglvnd-dev libgl1-mesa-dev ca-certificates libusb-1.0-0-dev libudev-dev" # These are optional packages, that we're building against to ensure we build as much code as possible - FEATURE_PACKAGES: "libhidapi-dev libwayland-dev libuvc-dev libavcodec-dev libopencv-dev libv4l-dev libcjson-dev libsdl2-dev libegl1-mesa-dev libdbus-1-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libsystemd-dev" + FEATURE_PACKAGES: "libhidapi-dev libwayland-dev libuvc-dev libavcodec-dev libopencv-dev libv4l-dev libcjson-dev libsdl2-dev libegl1-mesa-dev libdbus-1-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libsystemd-dev libbsd-dev" # Only used for building packages PACKAGING_PACKAGES: "devscripts debhelper dput-ng gettext-base markdown doxygen graphviz" @@ -28,19 +28,19 @@ variables: .monado.variables.debian:buster: variables: FDO_DISTRIBUTION_VERSION: buster - FDO_DISTRIBUTION_TAG: "2021-03-23.0" + FDO_DISTRIBUTION_TAG: "2021-04-15.0" # Variables for build and usage of Ubuntu 20.04 LTS (Focal) image .monado.variables.ubuntu:focal: variables: FDO_DISTRIBUTION_VERSION: "20.04" - FDO_DISTRIBUTION_TAG: "2021-03-23.0" + FDO_DISTRIBUTION_TAG: "2021-04-15.0" # Variables for build and usage of Ubuntu 20.10 (Groovy) image .monado.variables.ubuntu:groovy: variables: FDO_DISTRIBUTION_VERSION: "20.10" - FDO_DISTRIBUTION_TAG: "2021-03-23.0" + FDO_DISTRIBUTION_TAG: "2021-04-15.0" # Variables for build and usage of Debian 10 (Buster) + Android NDK image .monado.variables.debian:buster-ndk: From 78a199898d8b6f061d56662fc94b896178c79788 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 15 Apr 2021 16:51:03 -0500 Subject: [PATCH 373/883] d/control: Add Build-Depends on libbsd-dev for pidfile support when building service. --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 3fd97bf20..c111a2daf 100644 --- a/debian/control +++ b/debian/control @@ -9,6 +9,7 @@ Build-Depends: debhelper-compat (= 12), glslang-tools, graphviz, libavcodec-dev, + libbsd-dev [linux-any], libcjson-dev, libdbus-1-dev [linux-any], libegl1-mesa-dev, From 53a0f20330fad7356bc57ae5ffe51372a7d94514 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 15 Apr 2021 16:52:23 -0500 Subject: [PATCH 374/883] Update changelog. --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 1e9c21b28..8d0b050fa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +monado (21.0.0~dfsg1-2) UNRELEASED; urgency=medium + + * d/control: Add Build-Depends on libbsd-dev for pidfile support when building service. + + -- Ryan Pavlik Thu, 15 Apr 2021 16:51:09 -0500 + monado (21.0.0~dfsg1-1) unstable; urgency=medium * New upstream version 21.0.0~dfsg1 From 969c78efbd262432a820e98a11f2cb50baa0e07a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 16:53:26 -0500 Subject: [PATCH 375/883] c/client: Fix comment. --- src/xrt/compositor/client/comp_gl_client.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/xrt/compositor/client/comp_gl_client.c b/src/xrt/compositor/client/comp_gl_client.c index 33bce4620..0d83fbaef 100644 --- a/src/xrt/compositor/client/comp_gl_client.c +++ b/src/xrt/compositor/client/comp_gl_client.c @@ -296,8 +296,7 @@ client_gl_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, x xret = c->insert_fence(xc, &sync_handle); } else { /*! - * @hack: The swapchain images should have been externally - * synchronized. + * @todo The swapchain images should have been externally synchronized. */ glFlush(); } From ab5f9ae9d8b5fb34ea87da79e80db99fd3c91219 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 12:30:15 -0500 Subject: [PATCH 376/883] c/main: Add comp_target docs. --- src/xrt/compositor/main/comp_target.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xrt/compositor/main/comp_target.h b/src/xrt/compositor/main/comp_target.h index 513f9cda4..9eb791a70 100644 --- a/src/xrt/compositor/main/comp_target.h +++ b/src/xrt/compositor/main/comp_target.h @@ -123,6 +123,8 @@ struct comp_target /*! * Present the image at index to the screen. + * + * @pre @ref acquire succeeded for the same @p semaphore and @p index you are passing */ VkResult (*present)(struct comp_target *ct, VkQueue queue, From 80da6fe3b80cf5048d0e60e2a179d74f94d762a0 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 16:34:51 -0500 Subject: [PATCH 377/883] c/main: Add comp_renderer docs. --- src/xrt/compositor/main/comp_renderer.h | 45 +++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/xrt/compositor/main/comp_renderer.h b/src/xrt/compositor/main/comp_renderer.h index ff78c3d91..9fbd450fd 100644 --- a/src/xrt/compositor/main/comp_renderer.h +++ b/src/xrt/compositor/main/comp_renderer.h @@ -1,4 +1,4 @@ -// Copyright 2019, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -19,12 +19,17 @@ extern "C" { struct comp_compositor; -struct comp_renderer; struct comp_swapchain_image; +/*! + * @brief Renderer used by compositor. + */ +struct comp_renderer; /*! * Called by the main compositor code to create the renderer. * + * @public @memberof comp_renderer + * @see comp_compositor * @ingroup comp_main */ struct comp_renderer * @@ -33,6 +38,7 @@ comp_renderer_create(struct comp_compositor *c); /*! * Reset renderer as input has changed. * + * @public @memberof comp_renderer * @ingroup comp_main */ void @@ -41,6 +47,7 @@ comp_renderer_reset(struct comp_renderer *r); /*! * Clean up and free the renderer. * + * @public @memberof comp_renderer * @ingroup comp_main */ void @@ -49,11 +56,16 @@ comp_renderer_destroy(struct comp_renderer *r); /*! * Render frame. * + * @public @memberof comp_renderer * @ingroup comp_main */ void comp_renderer_draw(struct comp_renderer *r); +/*! + * @public @memberof comp_renderer + * @ingroup comp_main + */ void comp_renderer_set_projection_layer(struct comp_renderer *r, uint32_t layer, @@ -61,12 +73,20 @@ comp_renderer_set_projection_layer(struct comp_renderer *r, struct comp_swapchain_image *right_image, struct xrt_layer_data *data); +/*! + * @public @memberof comp_renderer + * @ingroup comp_main + */ void comp_renderer_set_quad_layer(struct comp_renderer *r, uint32_t layer, struct comp_swapchain_image *image, struct xrt_layer_data *data); +/*! + * @public @memberof comp_renderer + * @ingroup comp_main + */ void comp_renderer_set_cylinder_layer(struct comp_renderer *r, uint32_t layer, @@ -74,13 +94,22 @@ comp_renderer_set_cylinder_layer(struct comp_renderer *r, struct xrt_layer_data *data); #ifdef XRT_FEATURE_OPENXR_LAYER_EQUIRECT1 +/*! + * @public @memberof comp_renderer + * @ingroup comp_main + */ void comp_renderer_set_equirect1_layer(struct comp_renderer *r, uint32_t layer, struct comp_swapchain_image *image, struct xrt_layer_data *data); #endif + #ifdef XRT_FEATURE_OPENXR_LAYER_EQUIRECT2 +/*! + * @public @memberof comp_renderer + * @ingroup comp_main + */ void comp_renderer_set_equirect2_layer(struct comp_renderer *r, uint32_t layer, @@ -88,9 +117,21 @@ comp_renderer_set_equirect2_layer(struct comp_renderer *r, struct xrt_layer_data *data); #endif +/*! + * Allocate an internal array of per-layer data with the given number of elements. + * + * @public @memberof comp_renderer + * @ingroup comp_main + */ void comp_renderer_allocate_layers(struct comp_renderer *self, uint32_t num_layers); +/*! + * De-initialize and free internal array of per-layer data. + * + * @public @memberof comp_renderer + * @ingroup comp_main + */ void comp_renderer_destroy_layers(struct comp_renderer *self); From ffe458fdbace57c5352fa8aaee972b1291d452b5 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 16:29:22 -0500 Subject: [PATCH 378/883] c/main: Add comp_layer_renderer docs. --- src/xrt/compositor/main/comp_layer_renderer.h | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/src/xrt/compositor/main/comp_layer_renderer.h b/src/xrt/compositor/main/comp_layer_renderer.h index 5fbf4cd12..9e300c6a8 100644 --- a/src/xrt/compositor/main/comp_layer_renderer.h +++ b/src/xrt/compositor/main/comp_layer_renderer.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -7,16 +7,15 @@ * @ingroup comp_main */ +#pragma once + +#include "comp_layer.h" + /*! * Holds associated vulkan objects and state to render quads. * * @ingroup comp_main */ - -#pragma once - -#include "comp_layer.h" - struct comp_layer_renderer { struct vk_bundle *vk; @@ -63,26 +62,72 @@ struct comp_layer_renderer uint32_t texture_binding; }; +/*! + * Create a layer renderer. + * + * @public @memberof comp_layer_renderer + */ struct comp_layer_renderer * comp_layer_renderer_create(struct vk_bundle *vk, struct comp_shaders *s, VkExtent2D extent, VkFormat format); void comp_layer_renderer_destroy(struct comp_layer_renderer *self); +/*! + * Perform draw calls for the layers. + * + * @param self Self pointer. + * + * @public @memberof comp_layer_renderer + */ void comp_layer_renderer_draw(struct comp_layer_renderer *self); +/*! + * Update the internal members derived from the field of view. + * + * @param self Self pointer. + * @param fov Field of view data + * @param eye Eye index: 0 or 1 + * + * @public @memberof comp_layer_renderer + */ void comp_layer_renderer_set_fov(struct comp_layer_renderer *self, const struct xrt_fov *fov, uint32_t eye); +/*! + * Update the internal members derived from the eye and world poses. + * + * @param self Self pointer. + * @param eye_pose Pose of eye in view + * @param world_pose Pose of eye in world + * @param eye Eye index: 0 or 1 + * + * @public @memberof comp_layer_renderer + */ void comp_layer_renderer_set_pose(struct comp_layer_renderer *self, const struct xrt_pose *eye_pose, const struct xrt_pose *world_pose, uint32_t eye); +/*! + * Allocate the array comp_layer_renderer::layers with the given number of elements. + * + * @param self Self pointer. + * @param num_layers The number of layers to support + * + * @public @memberof comp_layer_renderer + */ void comp_layer_renderer_allocate_layers(struct comp_layer_renderer *self, uint32_t num_layers); +/*! + * De-initialize and free comp_layer_renderer::layers array. + * + * @param self Self pointer. + * + * @public @memberof comp_layer_renderer + */ void comp_layer_renderer_destroy_layers(struct comp_layer_renderer *self); From 04c9a7d8923bcf4bd131a168e6954161c66060aa Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 16:31:39 -0500 Subject: [PATCH 379/883] c/main: Normalize comp_layer_renderer_destroy convention. --- src/xrt/compositor/main/comp_layer_renderer.c | 11 ++++++++++- src/xrt/compositor/main/comp_layer_renderer.h | 7 ++++++- src/xrt/compositor/main/comp_renderer.c | 4 +--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/xrt/compositor/main/comp_layer_renderer.c b/src/xrt/compositor/main/comp_layer_renderer.c index cb2f3413d..c59232a94 100644 --- a/src/xrt/compositor/main/comp_layer_renderer.c +++ b/src/xrt/compositor/main/comp_layer_renderer.c @@ -638,8 +638,15 @@ _destroy_framebuffer(struct comp_layer_renderer *self, uint32_t i) } void -comp_layer_renderer_destroy(struct comp_layer_renderer *self) +comp_layer_renderer_destroy(struct comp_layer_renderer **ptr_clr) { + if (ptr_clr == NULL) { + return; + } + struct comp_layer_renderer *self = *ptr_clr; + if (self == NULL) { + return; + } struct vk_bundle *vk = self->vk; if (vk->device == VK_NULL_HANDLE) @@ -670,6 +677,8 @@ comp_layer_renderer_destroy(struct comp_layer_renderer *self) vk_buffer_destroy(&self->vertex_buffer, vk); vk->vkDestroyPipelineCache(vk->device, self->pipeline_cache, NULL); + free(self); + *ptr_clr = NULL; } void diff --git a/src/xrt/compositor/main/comp_layer_renderer.h b/src/xrt/compositor/main/comp_layer_renderer.h index 9e300c6a8..2b5f3f77f 100644 --- a/src/xrt/compositor/main/comp_layer_renderer.h +++ b/src/xrt/compositor/main/comp_layer_renderer.h @@ -70,8 +70,13 @@ struct comp_layer_renderer struct comp_layer_renderer * comp_layer_renderer_create(struct vk_bundle *vk, struct comp_shaders *s, VkExtent2D extent, VkFormat format); +/*! + * Destroy the layer renderer and set the pointer to NULL. + * + * @public @memberof comp_layer_renderer + */ void -comp_layer_renderer_destroy(struct comp_layer_renderer *self); +comp_layer_renderer_destroy(struct comp_layer_renderer **ptr_clr); /*! * Perform draw calls for the layers. diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index dd39075a2..bc2c8e928 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -850,9 +850,7 @@ renderer_destroy(struct comp_renderer *r) r->semaphores.render_complete = VK_NULL_HANDLE; } - comp_layer_renderer_destroy(r->lr); - - free(r->lr); + comp_layer_renderer_destroy(&(r->lr)); } void From 70982e9c39c8af024730674b652eeea1b299e638 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 15 Apr 2021 13:38:32 -0500 Subject: [PATCH 380/883] c/main: Remove unimplemented comp_renderer function. --- src/xrt/compositor/main/comp_renderer.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/xrt/compositor/main/comp_renderer.h b/src/xrt/compositor/main/comp_renderer.h index 9fbd450fd..48c28f03f 100644 --- a/src/xrt/compositor/main/comp_renderer.h +++ b/src/xrt/compositor/main/comp_renderer.h @@ -35,15 +35,6 @@ struct comp_renderer; struct comp_renderer * comp_renderer_create(struct comp_compositor *c); -/*! - * Reset renderer as input has changed. - * - * @public @memberof comp_renderer - * @ingroup comp_main - */ -void -comp_renderer_reset(struct comp_renderer *r); - /*! * Clean up and free the renderer. * From 7c2ea1369fc8ff3062ca4ddc9986a4b1f0d9e2fd Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 15 Apr 2021 13:43:02 -0500 Subject: [PATCH 381/883] c/main: Normalize destroy pattern for comp_renderer. --- src/xrt/compositor/main/comp_compositor.c | 5 +---- src/xrt/compositor/main/comp_renderer.c | 10 +++++++++- src/xrt/compositor/main/comp_renderer.h | 4 +++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 7b6c48950..22664b918 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -552,10 +552,7 @@ compositor_destroy(struct xrt_compositor *xc) // Make sure we don't have anything to destroy. comp_compositor_garbage_collect(c); - if (c->r) { - comp_renderer_destroy(c->r); - c->r = NULL; - } + comp_renderer_destroy(&c->r); comp_resources_close(c, &c->nr); diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index bc2c8e928..8197cc42c 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -120,10 +120,18 @@ comp_renderer_create(struct comp_compositor *c) } void -comp_renderer_destroy(struct comp_renderer *r) +comp_renderer_destroy(struct comp_renderer **ptr_r) { + if (ptr_r == NULL) { + return; + } + struct comp_renderer *r = *ptr_r; + if (r == NULL) { + return; + } renderer_destroy(r); free(r); + *ptr_r = NULL; } /* diff --git a/src/xrt/compositor/main/comp_renderer.h b/src/xrt/compositor/main/comp_renderer.h index 48c28f03f..c1edaaf5a 100644 --- a/src/xrt/compositor/main/comp_renderer.h +++ b/src/xrt/compositor/main/comp_renderer.h @@ -38,11 +38,13 @@ comp_renderer_create(struct comp_compositor *c); /*! * Clean up and free the renderer. * + * Does null checking and sets to null after freeing. + * * @public @memberof comp_renderer * @ingroup comp_main */ void -comp_renderer_destroy(struct comp_renderer *r); +comp_renderer_destroy(struct comp_renderer **ptr_r); /*! * Render frame. From 780ec4fac97616d39bb137ca1f84ee16435aa649 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 16 Apr 2021 01:40:36 +0100 Subject: [PATCH 382/883] c/main: Turn debug into spew --- src/xrt/compositor/main/comp_compositor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 22664b918..fb28deb21 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -127,7 +127,7 @@ compositor_predict_frame(struct xrt_compositor *xc, struct comp_compositor *c = comp_compositor(xc); - COMP_DEBUG(c, "PREDICT_FRAME"); + COMP_SPEW(c, "PREDICT_FRAME"); // A little bit easier to read. uint64_t interval_ns = (int64_t)c->settings.nominal_frame_interval_ns; @@ -173,7 +173,7 @@ compositor_mark_frame(struct xrt_compositor *xc, struct comp_compositor *c = comp_compositor(xc); - COMP_DEBUG(c, "MARK_FRAME %i", point); + COMP_SPEW(c, "MARK_FRAME %i", point); switch (point) { case XRT_COMPOSITOR_FRAME_POINT_WOKE: From 90192118d0898984eff7bfdebb0e0ab171d57bd7 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 11:30:01 -0500 Subject: [PATCH 383/883] c/main: Add comp_target::check_ready, and implement in comp_target_swapchain. --- src/xrt/compositor/main/comp_target.h | 23 +++++++++++++++++++ .../compositor/main/comp_target_swapchain.c | 8 +++++++ .../compositor/main/comp_target_swapchain.h | 1 + 3 files changed, 32 insertions(+) diff --git a/src/xrt/compositor/main/comp_target.h b/src/xrt/compositor/main/comp_target.h index 9eb791a70..96eefa5e7 100644 --- a/src/xrt/compositor/main/comp_target.h +++ b/src/xrt/compositor/main/comp_target.h @@ -105,9 +105,18 @@ struct comp_target */ bool (*init_post_vulkan)(struct comp_target *ct, uint32_t preferred_width, uint32_t preferred_height); + /*! + * Is this target ready for image creation? + * + * Call before calling @ref create_images + */ + bool (*check_ready)(struct comp_target *ct); + /*! * Create or recreate the image(s) of the target, for swapchain based * targets this will (re)create the swapchain. + * + * @pre @ref check_ready returns true */ void (*create_images)(struct comp_target *ct, uint32_t preferred_width, @@ -218,6 +227,20 @@ comp_target_init_post_vulkan(struct comp_target *ct, uint32_t preferred_width, u return ct->init_post_vulkan(ct, preferred_width, preferred_height); } +/*! + * @copydoc comp_target::check_ready + * + * @public @memberof comp_target + * @ingroup comp_main + */ +static inline bool +comp_target_check_ready(struct comp_target *ct) +{ + COMP_TRACE_MARKER(); + + return ct->check_ready(ct); +} + /*! * @copydoc comp_target::create_images * diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index 253c00cb0..9e1dca5c0 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -299,6 +299,13 @@ comp_target_swapchain_present(struct comp_target *ct, return vk->vkQueuePresentKHR(queue, &presentInfo); } +static bool +comp_target_swapchain_check_ready(struct comp_target *ct) +{ + struct comp_target_swapchain *cts = (struct comp_target_swapchain *)ct; + return cts->surface.handle != VK_NULL_HANDLE; +} + static bool _find_surface_format(struct comp_target_swapchain *cts, VkSurfaceKHR surface, VkSurfaceFormatKHR *format) { @@ -646,6 +653,7 @@ comp_target_swapchain_init_and_set_fnptrs(struct comp_target_swapchain *cts, enum comp_target_display_timing_usage timing_usage) { cts->timing_usage = timing_usage; + cts->base.check_ready = comp_target_swapchain_check_ready; cts->base.create_images = comp_target_swapchain_create_images; cts->base.acquire = comp_target_swapchain_acquire_next_image; cts->base.present = comp_target_swapchain_present; diff --git a/src/xrt/compositor/main/comp_target_swapchain.h b/src/xrt/compositor/main/comp_target_swapchain.h index 8e07b7fc4..a30cf24e4 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.h +++ b/src/xrt/compositor/main/comp_target_swapchain.h @@ -83,6 +83,7 @@ struct comp_target_swapchain * Initializes these function pointers, all other methods of @ref comp_target are the responsibility of the caller (the * "subclass"): * + * - comp_target::check_ready * - comp_target::create_images * - comp_target::acquire * - comp_target::present From 1cf39ec2c0e72238b25f68d77871bdb43f9719c0 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 12:30:52 -0500 Subject: [PATCH 384/883] c/main: Add comp_target::has_images, and implement in comp_target_swapchain. --- src/xrt/compositor/main/comp_target.h | 24 +++++++++++++++++++ .../compositor/main/comp_target_swapchain.c | 15 ++++++++++-- .../compositor/main/comp_target_swapchain.h | 1 + 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/xrt/compositor/main/comp_target.h b/src/xrt/compositor/main/comp_target.h index 96eefa5e7..376cacf9d 100644 --- a/src/xrt/compositor/main/comp_target.h +++ b/src/xrt/compositor/main/comp_target.h @@ -125,8 +125,18 @@ struct comp_target VkColorSpaceKHR preferred_color_space, VkPresentModeKHR present_mode); + /*! + * Has this target successfully had images created? + * + * Call before calling @ref acquire - if false but @ref check_ready is true, you'll need to call @ref + * create_images + */ + bool (*has_images)(struct comp_target *ct); + /*! * Acquire the next image for rendering. + * + * @pre @ref has_images returns true */ VkResult (*acquire)(struct comp_target *ct, VkSemaphore semaphore, uint32_t *out_index); @@ -266,6 +276,20 @@ comp_target_create_images(struct comp_target *ct, present_mode); // } +/*! + * @copydoc comp_target::has_images + * + * @public @memberof comp_target + * @ingroup comp_main + */ +static inline bool +comp_target_has_images(struct comp_target *ct) +{ + COMP_TRACE_MARKER(); + + return ct->has_images(ct); +} + /*! * @copydoc comp_target::acquire * diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index 9e1dca5c0..957d64bb5 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -251,10 +251,13 @@ comp_target_swapchain_acquire_next_image(struct comp_target *ct, VkSemaphore sem struct comp_target_swapchain *cts = (struct comp_target_swapchain *)ct; struct vk_bundle *vk = get_vk(cts); - + if (!comp_target_swapchain_has_images(ct)) { + //! @todo what error to return here? + return VK_ERROR_INITIALIZATION_FAILED; + } return vk->vkAcquireNextImageKHR( // vk->device, // device - cts->swapchain.handle, // timeout + cts->swapchain.handle, // swapchain UINT64_MAX, // timeout semaphore, // semaphore VK_NULL_HANDLE, // fence @@ -306,6 +309,13 @@ comp_target_swapchain_check_ready(struct comp_target *ct) return cts->surface.handle != VK_NULL_HANDLE; } +static bool +comp_target_swapchain_has_images(struct comp_target *ct) +{ + struct comp_target_swapchain *cts = (struct comp_target_swapchain *)ct; + return cts->surface.handle != VK_NULL_HANDLE && cts->swapchain.handle != VK_NULL_HANDLE; +} + static bool _find_surface_format(struct comp_target_swapchain *cts, VkSurfaceKHR surface, VkSurfaceFormatKHR *format) { @@ -655,6 +665,7 @@ comp_target_swapchain_init_and_set_fnptrs(struct comp_target_swapchain *cts, cts->timing_usage = timing_usage; cts->base.check_ready = comp_target_swapchain_check_ready; cts->base.create_images = comp_target_swapchain_create_images; + cts->base.has_images = comp_target_swapchain_has_images; cts->base.acquire = comp_target_swapchain_acquire_next_image; cts->base.present = comp_target_swapchain_present; cts->base.calc_frame_timings = comp_target_swapchain_calc_frame_timings; diff --git a/src/xrt/compositor/main/comp_target_swapchain.h b/src/xrt/compositor/main/comp_target_swapchain.h index a30cf24e4..c1e146ab1 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.h +++ b/src/xrt/compositor/main/comp_target_swapchain.h @@ -85,6 +85,7 @@ struct comp_target_swapchain * * - comp_target::check_ready * - comp_target::create_images + * - comp_target::has_images * - comp_target::acquire * - comp_target::present * - comp_target::calc_frame_timings From 1521953813f008c0cad09fa194bd47e5191772ba Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 16 Apr 2021 01:48:34 +0100 Subject: [PATCH 385/883] c/main: Re-arrange comp_renderer to allow late init. Co-author: Jakob Bornecrantz --- src/xrt/compositor/main/comp_renderer.c | 326 ++++++++++++------ .../compositor/main/comp_target_swapchain.c | 15 +- 2 files changed, 222 insertions(+), 119 deletions(-) diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index 8197cc42c..36198f0d6 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -41,9 +41,13 @@ */ struct comp_renderer { - uint32_t current_buffer; + //! @name Durable members + //! @brief These don't require the images to be created and don't depend on it. + //! @{ - VkQueue queue; + //! The compositor we were created by + struct comp_compositor *c; + struct comp_settings *settings; struct { @@ -51,14 +55,37 @@ struct comp_renderer VkSemaphore render_complete; } semaphores; + VkQueue queue; + //! @} + + //! @name Image-dependent members + //! @{ + + //! Index of the current buffer/image + uint32_t current_buffer; + + /*! + * Array of "renderings" equal in size to the number of comp_target images. + */ struct comp_rendering *rrs; + + /*! + * Array of fences equal in size to the number of comp_target images. + */ VkFence *fences; + + /*! + * The number of renderings/fences we've created: set from comp_target when we use that data. + */ uint32_t num_buffers; - struct comp_compositor *c; - struct comp_settings *settings; - + /*! + * @brief The layer renderer, which actually knows how to composite layers. + * + * Depends on the target extents. + */ struct comp_layer_renderer *lr; + //! @} }; @@ -68,23 +95,18 @@ struct comp_renderer * */ +//! Create renderer and initialize non-image-dependent members static void renderer_create(struct comp_renderer *r, struct comp_compositor *c); -static void -renderer_init(struct comp_renderer *r); - static void renderer_submit_queue(struct comp_renderer *r); static void -renderer_build_renderings(struct comp_renderer *r); +renderer_create_renderings_and_fences(struct comp_renderer *r); static void -renderer_allocate_renderings(struct comp_renderer *r); - -static void -renderer_close_renderings(struct comp_renderer *r); +renderer_close_renderings_and_fences(struct comp_renderer *r); static void renderer_init_semaphores(struct comp_renderer *r); @@ -102,6 +124,7 @@ static void renderer_destroy(struct comp_renderer *r); + /* * * Interface functions. @@ -114,7 +137,6 @@ comp_renderer_create(struct comp_compositor *c) struct comp_renderer *r = U_TYPED_CALLOC(struct comp_renderer); renderer_create(r, c); - renderer_init(r); return r; } @@ -134,12 +156,118 @@ comp_renderer_destroy(struct comp_renderer **ptr_r) *ptr_r = NULL; } + /* * * Functions. * */ +static void +renderer_wait_gpu_idle(struct comp_renderer *r) +{ + COMP_TRACE_MARKER(); + + os_mutex_lock(&r->c->vk.queue_mutex); + r->c->vk.vkDeviceWaitIdle(r->c->vk.device); + os_mutex_unlock(&r->c->vk.queue_mutex); +} + +//! @pre comp_target_check_ready(r->c->target) +static void +renderer_create_layer_renderer(struct comp_renderer *r) +{ + struct vk_bundle *vk = &r->c->vk; + + assert(comp_target_check_ready(r->c->target)); + + uint32_t num_layers = 0; + if (r->lr != NULL) { + // if we already had one, re-populate it after recreation. + num_layers = r->lr->num_layers; + comp_layer_renderer_destroy(&r->lr); + } + + VkExtent2D extent; + if (r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || + r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { + // Swapping width and height, since we are pre rotating + extent = (VkExtent2D){ + .width = r->c->xdev->hmd->screens[0].h_pixels, + .height = r->c->xdev->hmd->screens[0].w_pixels, + }; + } else { + extent = (VkExtent2D){ + .width = r->c->xdev->hmd->screens[0].w_pixels, + .height = r->c->xdev->hmd->screens[0].h_pixels, + }; + } + + r->lr = comp_layer_renderer_create(vk, &r->c->shaders, extent, VK_FORMAT_B8G8R8A8_SRGB); + if (num_layers != 0) { + comp_layer_renderer_allocate_layers(r->lr, num_layers); + } +} + +/*! + * @brief Ensure that target images and renderings are created, if possible. + * + * @param r Self pointer + * @param force_recreate If true, will tear down and re-create images and renderings, e.g. for a resize + * + * @returns true if images and renderings are ready and created. + * + * @private @memberof comp_renderer + * @ingroup comp_main + */ +static bool +renderer_ensure_images_and_renderings(struct comp_renderer *r, bool force_recreate) +{ + struct comp_compositor *c = r->c; + struct comp_target *target = c->target; + + if (!comp_target_check_ready(target)) { + // Not ready, so can't render anything. + return false; + } + + // We will create images if we don't have any images or if we were told to recreate them. + bool create = force_recreate || !comp_target_has_images(target) || (r->num_buffers == 0); + if (!create) { + return true; + } + + COMP_DEBUG(c, "Creating iamges and renderings (force_recreate: %s).", force_recreate ? "true" : "false"); + + /* + * This makes sure that any pending command buffer has completed + * and all resources referred by it can now be manipulated. This + * make sure that validation doesn't complain. This is done + * during resize so isn't time critical. + */ + renderer_wait_gpu_idle(r); + + // Make we sure we destroy all dependent things before creating new images. + renderer_close_renderings_and_fences(r); + + comp_target_create_images( // + r->c->target, // + r->c->target->width, // + r->c->target->height, // + r->settings->color_format, // + r->settings->color_space, // + r->settings->present_mode); // + + r->num_buffers = r->c->target->num_images; + + renderer_create_layer_renderer(r); + renderer_create_renderings_and_fences(r); + + assert(r->num_buffers != 0); + + return true; +} + static void renderer_create(struct comp_renderer *r, struct comp_compositor *c) { @@ -150,18 +278,15 @@ renderer_create(struct comp_renderer *r, struct comp_compositor *c) r->queue = VK_NULL_HANDLE; r->semaphores.present_complete = VK_NULL_HANDLE; r->semaphores.render_complete = VK_NULL_HANDLE; - r->rrs = NULL; -} -static void -renderer_wait_gpu_idle(struct comp_renderer *r) -{ - COMP_TRACE_MARKER(); + struct vk_bundle *vk = &r->c->vk; - os_mutex_lock(&r->c->vk.queue_mutex); - r->c->vk.vkDeviceWaitIdle(r->c->vk.device); - os_mutex_unlock(&r->c->vk.queue_mutex); + vk->vkGetDeviceQueue(vk->device, r->c->vk.queue_family_index, 0, &r->queue); + renderer_init_semaphores(r); + + // Try to early-allocate these, in case we can. + renderer_ensure_images_and_renderings(r, false); } static void @@ -215,6 +340,7 @@ renderer_submit_queue(struct comp_renderer *r) } } +//! @pre comp_target_has_images(r->c->target) static void renderer_build_rendering(struct comp_renderer *r, struct comp_rendering *rr, uint32_t index) { @@ -361,14 +487,8 @@ renderer_build_rendering(struct comp_renderer *r, struct comp_rendering *rr, uin comp_draw_end_target(rr); } -static void -renderer_build_renderings(struct comp_renderer *r) -{ - for (uint32_t i = 0; i < r->num_buffers; ++i) { - renderer_build_rendering(r, &r->rrs[i], i); - } -} +//! @pre comp_target_has_images(r->c->target) static void renderer_create_fences(struct comp_renderer *r) { @@ -430,40 +550,6 @@ renderer_get_view_projection(struct comp_renderer *r) } } -static void -renderer_init(struct comp_renderer *r) -{ - struct vk_bundle *vk = &r->c->vk; - - vk->vkGetDeviceQueue(vk->device, r->c->vk.queue_family_index, 0, &r->queue); - renderer_init_semaphores(r); - assert(r->c->target->num_images > 0); - - r->num_buffers = r->c->target->num_images; - - renderer_create_fences(r); - - VkExtent2D extent; - if (r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || - r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { - // Swapping width and height, since we are pre rotating - extent = (VkExtent2D){ - .width = r->c->xdev->hmd->screens[0].h_pixels, - .height = r->c->xdev->hmd->screens[0].w_pixels, - }; - } else { - extent = (VkExtent2D){ - .width = r->c->xdev->hmd->screens[0].w_pixels, - .height = r->c->xdev->hmd->screens[0].h_pixels, - }; - } - - r->lr = comp_layer_renderer_create(vk, &r->c->shaders, extent, VK_FORMAT_B8G8R8A8_SRGB); - - renderer_allocate_renderings(r); - renderer_build_renderings(r); -} - VkImageView get_image_view(struct comp_swapchain_image *image, enum xrt_layer_composition_flags flags, uint32_t array_index) { @@ -660,6 +746,7 @@ comp_renderer_draw(struct comp_renderer *r) struct comp_target *ct = r->c->target; struct comp_compositor *c = r->c; + assert(c->frame.rendering.id == -1); c->frame.rendering = c->frame.waited; @@ -667,10 +754,19 @@ comp_renderer_draw(struct comp_renderer *r) comp_target_mark_begin(ct, c->frame.rendering.id, os_monotonic_get_ns()); + // Are we ready to render? No - skip rendering. + if (!comp_target_check_ready(r->c->target)) { + // Need to emulate rendering for the timing. + //! @todo This should be discard. + comp_target_mark_submit(ct, c->frame.rendering.id, os_monotonic_get_ns()); + return; + } + comp_target_flush(ct); comp_target_update_timings(ct); + // Ensures that renderings are created. renderer_acquire_swapchain_image(r); comp_target_update_timings(ct); @@ -684,7 +780,6 @@ comp_renderer_draw(struct comp_renderer *r) renderer_submit_queue(r); - renderer_present_swapchain_image(r, c->frame.rendering.desired_present_time_ns, c->frame.rendering.present_slop_ns); @@ -709,9 +804,12 @@ comp_renderer_draw(struct comp_renderer *r) comp_target_update_timings(ct); } +//! Update r->num_buffers before calling. static void -renderer_allocate_renderings(struct comp_renderer *r) +renderer_create_renderings_and_fences(struct comp_renderer *r) { + assert(r->rrs == NULL); + assert(r->fences == NULL); if (r->num_buffers == 0) { COMP_ERROR(r->c, "Requested 0 command buffers."); return; @@ -719,22 +817,42 @@ renderer_allocate_renderings(struct comp_renderer *r) COMP_DEBUG(r->c, "Allocating %d Command Buffers.", r->num_buffers); - if (r->rrs != NULL) { - free(r->rrs); + r->rrs = U_TYPED_ARRAY_CALLOC(struct comp_rendering, r->num_buffers); + + for (uint32_t i = 0; i < r->num_buffers; ++i) { + renderer_build_rendering(r, &r->rrs[i], i); } - r->rrs = U_TYPED_ARRAY_CALLOC(struct comp_rendering, r->num_buffers); + //! @todo inline this here or above in the other loop? or just put in renderings? + renderer_create_fences(r); } static void -renderer_close_renderings(struct comp_renderer *r) +renderer_close_renderings_and_fences(struct comp_renderer *r) { - for (uint32_t i = 0; i < r->num_buffers; i++) { - comp_rendering_close(&r->rrs[i]); + struct vk_bundle *vk = &r->c->vk; + // Renderings + if (r->num_buffers > 0 && r->rrs != NULL) { + for (uint32_t i = 0; i < r->num_buffers; i++) { + comp_rendering_close(&r->rrs[i]); + } + + free(r->rrs); + r->rrs = NULL; } - free(r->rrs); - r->rrs = NULL; + // Fences + if (r->num_buffers > 0 && r->fences != NULL) { + for (uint32_t i = 0; i < r->num_buffers; i++) { + vk->vkDestroyFence(vk->device, r->fences[i], NULL); + r->fences[i] = VK_NULL_HANDLE; + } + free(r->fences); + r->fences = NULL; + } + + r->num_buffers = 0; + r->current_buffer = 0; } static void @@ -761,32 +879,16 @@ renderer_init_semaphores(struct comp_renderer *r) static void renderer_resize(struct comp_renderer *r) { - struct vk_bundle *vk = &r->c->vk; + if (!comp_target_check_ready(r->c->target)) { + // Can't create images right now. + // Just close any existing renderings. + renderer_close_renderings_and_fences(r); + return; + } - /* - * This makes sure that any pending command buffer has completed - * and all resources referred by it can now be manipulated. This - * make sure that validation doesn't complain. This is done - * during resize so isn't time critical. - */ - os_mutex_lock(&vk->queue_mutex); - vk->vkDeviceWaitIdle(vk->device); - os_mutex_unlock(&vk->queue_mutex); + renderer_ensure_images_and_renderings(r, true); // Force recreate. - comp_target_create_images( // - r->c->target, // - r->c->target->width, // - r->c->target->height, // - r->settings->color_format, // - r->settings->color_space, // - r->settings->present_mode); // - - renderer_close_renderings(r); - - r->num_buffers = r->c->target->num_images; - - renderer_allocate_renderings(r); - renderer_build_renderings(r); + return; } static void @@ -796,19 +898,29 @@ renderer_acquire_swapchain_image(struct comp_renderer *r) VkResult ret; + if (!renderer_ensure_images_and_renderings(r, false)) { + // Not ready yet. + return; + } ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &r->current_buffer); if ((ret == VK_ERROR_OUT_OF_DATE_KHR) || (ret == VK_SUBOPTIMAL_KHR)) { COMP_DEBUG(r->c, "Received %s.", vk_result_string(ret)); - renderer_resize(r); + if (!renderer_ensure_images_and_renderings(r, true)) { + // Failed on force recreate. + COMP_ERROR(r->c, + "renderer_acquire_swapchain_image: comp_target_acquire was out of date, force " + "re-create image and renderings failed. Probably the target disappeared."); + return; + } /* Acquire image again to silence validation error */ ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &r->current_buffer); if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "vk_swapchain_acquire_next_image: %s", vk_result_string(ret)); + COMP_ERROR(r->c, "comp_target_acquire: %s", vk_result_string(ret)); } } else if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "vk_swapchain_acquire_next_image: %s", vk_result_string(ret)); + COMP_ERROR(r->c, "comp_target_acquire: %s", vk_result_string(ret)); } } @@ -835,18 +947,8 @@ renderer_destroy(struct comp_renderer *r) { struct vk_bundle *vk = &r->c->vk; - // Fences - for (uint32_t i = 0; i < r->num_buffers; i++) - vk->vkDestroyFence(vk->device, r->fences[i], NULL); - free(r->fences); - // Command buffers - renderer_close_renderings(r); - if (r->rrs != NULL) { - free(r->rrs); - } - - r->num_buffers = 0; + renderer_close_renderings_and_fences(r); // Semaphores if (r->semaphores.present_complete != VK_NULL_HANDLE) { diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index 957d64bb5..5a0d3c21c 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -245,6 +245,13 @@ comp_target_swapchain_destroy_old(struct comp_target_swapchain *cts, VkSwapchain } } +static bool +comp_target_swapchain_has_images(struct comp_target *ct) +{ + struct comp_target_swapchain *cts = (struct comp_target_swapchain *)ct; + return cts->surface.handle != VK_NULL_HANDLE && cts->swapchain.handle != VK_NULL_HANDLE; +} + static VkResult comp_target_swapchain_acquire_next_image(struct comp_target *ct, VkSemaphore semaphore, uint32_t *out_index) { @@ -255,6 +262,7 @@ comp_target_swapchain_acquire_next_image(struct comp_target *ct, VkSemaphore sem //! @todo what error to return here? return VK_ERROR_INITIALIZATION_FAILED; } + return vk->vkAcquireNextImageKHR( // vk->device, // device cts->swapchain.handle, // swapchain @@ -309,13 +317,6 @@ comp_target_swapchain_check_ready(struct comp_target *ct) return cts->surface.handle != VK_NULL_HANDLE; } -static bool -comp_target_swapchain_has_images(struct comp_target *ct) -{ - struct comp_target_swapchain *cts = (struct comp_target_swapchain *)ct; - return cts->surface.handle != VK_NULL_HANDLE && cts->swapchain.handle != VK_NULL_HANDLE; -} - static bool _find_surface_format(struct comp_target_swapchain *cts, VkSurfaceKHR surface, VkSurfaceFormatKHR *format) { From 5d605c7b3fd11c4fac99ce98d9b071ce2c7138be Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 16 Apr 2021 01:51:38 +0100 Subject: [PATCH 386/883] c/main: Do not create images when initing swapchain. --- src/xrt/compositor/main/comp_compositor.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index fb28deb21..c045543a3 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -1263,25 +1263,14 @@ compositor_init_window_post_vulkan(struct comp_compositor *c) static bool compositor_init_swapchain(struct comp_compositor *c) { - if (!comp_target_init_post_vulkan(c->target, // - c->settings.preferred.width, // - c->settings.preferred.height)) { - COMP_ERROR(c, "Window init_swapchain failed!"); - goto err_destroy; + if (comp_target_init_post_vulkan(c->target, // + c->settings.preferred.width, // + c->settings.preferred.height)) { + return true; } - comp_target_create_images( // - c->target, // - c->settings.preferred.width, // - c->settings.preferred.height, // - c->settings.color_format, // - c->settings.color_space, // - c->settings.present_mode); // + COMP_ERROR(c, "Window init_swapchain failed!"); - return true; - - // Error path. -err_destroy: comp_target_destroy(&c->target); return false; From 598c1a3b568c2c38035232ee5257324325b3449e Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Fri, 16 Apr 2021 16:37:43 +0200 Subject: [PATCH 387/883] d/ohmd: Only set output name if there is an output This needs to be revisited after OpenHMD gets a proper API for haptic feedback. closes #119 --- src/xrt/drivers/ohmd/oh_device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c index bdd4c518b..89b626bee 100644 --- a/src/xrt/drivers/ohmd/oh_device.c +++ b/src/xrt/drivers/ohmd/oh_device.c @@ -1131,7 +1131,9 @@ create_controller(ohmd_context *ctx, int device_idx, int device_flags, enum xrt_ // in case the hardware is an analog trigger, change the input after a half pulled trigger. ohd->make_trigger_digital = true; - ohd->base.outputs[0].name = XRT_OUTPUT_NAME_SIMPLE_VIBRATION; + if (num_outputs > 0) { + ohd->base.outputs[0].name = XRT_OUTPUT_NAME_SIMPLE_VIBRATION; + } ohd->controls_mapping[OHMD_TRIGGER] = SIMPLE_SELECT_CLICK; ohd->controls_mapping[OHMD_MENU] = SIMPLE_MENU_CLICK; From daff92a275cac0cfa060636a2bf3a38da017a613 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 17 Apr 2021 00:12:22 +0100 Subject: [PATCH 388/883] c/main: None functional refactor of renderer. Not ment to change the functionallity of the code only reflow the code. --- src/xrt/compositor/main/comp_renderer.c | 737 +++++++++++------------- 1 file changed, 350 insertions(+), 387 deletions(-) diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index 36198f0d6..7fbeb4c1e 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -5,6 +5,7 @@ * @brief Compositor rendering code. * @author Lubosz Sarnecki * @author Jakob Bornecrantz + * @author Ryan Pavlik * @ingroup comp_main */ @@ -89,74 +90,6 @@ struct comp_renderer }; -/* - * - * Pre declare functions. - * - */ - -//! Create renderer and initialize non-image-dependent members -static void -renderer_create(struct comp_renderer *r, struct comp_compositor *c); - -static void -renderer_submit_queue(struct comp_renderer *r); - -static void -renderer_create_renderings_and_fences(struct comp_renderer *r); - -static void -renderer_close_renderings_and_fences(struct comp_renderer *r); - -static void -renderer_init_semaphores(struct comp_renderer *r); - -static void -renderer_resize(struct comp_renderer *r); - -static void -renderer_acquire_swapchain_image(struct comp_renderer *r); - -static void -renderer_present_swapchain_image(struct comp_renderer *r, uint64_t desired_present_time_ns, uint64_t present_slop_ns); - -static void -renderer_destroy(struct comp_renderer *r); - - - -/* - * - * Interface functions. - * - */ - -struct comp_renderer * -comp_renderer_create(struct comp_compositor *c) -{ - struct comp_renderer *r = U_TYPED_CALLOC(struct comp_renderer); - - renderer_create(r, c); - - return r; -} - -void -comp_renderer_destroy(struct comp_renderer **ptr_r) -{ - if (ptr_r == NULL) { - return; - } - struct comp_renderer *r = *ptr_r; - if (r == NULL) { - return; - } - renderer_destroy(r); - free(r); - *ptr_r = NULL; -} - - /* * * Functions. @@ -173,170 +106,24 @@ renderer_wait_gpu_idle(struct comp_renderer *r) os_mutex_unlock(&r->c->vk.queue_mutex); } -//! @pre comp_target_check_ready(r->c->target) static void -renderer_create_layer_renderer(struct comp_renderer *r) +renderer_init_semaphores(struct comp_renderer *r) { - struct vk_bundle *vk = &r->c->vk; - - assert(comp_target_check_ready(r->c->target)); - - uint32_t num_layers = 0; - if (r->lr != NULL) { - // if we already had one, re-populate it after recreation. - num_layers = r->lr->num_layers; - comp_layer_renderer_destroy(&r->lr); - } - - VkExtent2D extent; - if (r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || - r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { - // Swapping width and height, since we are pre rotating - extent = (VkExtent2D){ - .width = r->c->xdev->hmd->screens[0].h_pixels, - .height = r->c->xdev->hmd->screens[0].w_pixels, - }; - } else { - extent = (VkExtent2D){ - .width = r->c->xdev->hmd->screens[0].w_pixels, - .height = r->c->xdev->hmd->screens[0].h_pixels, - }; - } - - r->lr = comp_layer_renderer_create(vk, &r->c->shaders, extent, VK_FORMAT_B8G8R8A8_SRGB); - if (num_layers != 0) { - comp_layer_renderer_allocate_layers(r->lr, num_layers); - } -} - -/*! - * @brief Ensure that target images and renderings are created, if possible. - * - * @param r Self pointer - * @param force_recreate If true, will tear down and re-create images and renderings, e.g. for a resize - * - * @returns true if images and renderings are ready and created. - * - * @private @memberof comp_renderer - * @ingroup comp_main - */ -static bool -renderer_ensure_images_and_renderings(struct comp_renderer *r, bool force_recreate) -{ - struct comp_compositor *c = r->c; - struct comp_target *target = c->target; - - if (!comp_target_check_ready(target)) { - // Not ready, so can't render anything. - return false; - } - - // We will create images if we don't have any images or if we were told to recreate them. - bool create = force_recreate || !comp_target_has_images(target) || (r->num_buffers == 0); - if (!create) { - return true; - } - - COMP_DEBUG(c, "Creating iamges and renderings (force_recreate: %s).", force_recreate ? "true" : "false"); - - /* - * This makes sure that any pending command buffer has completed - * and all resources referred by it can now be manipulated. This - * make sure that validation doesn't complain. This is done - * during resize so isn't time critical. - */ - renderer_wait_gpu_idle(r); - - // Make we sure we destroy all dependent things before creating new images. - renderer_close_renderings_and_fences(r); - - comp_target_create_images( // - r->c->target, // - r->c->target->width, // - r->c->target->height, // - r->settings->color_format, // - r->settings->color_space, // - r->settings->present_mode); // - - r->num_buffers = r->c->target->num_images; - - renderer_create_layer_renderer(r); - renderer_create_renderings_and_fences(r); - - assert(r->num_buffers != 0); - - return true; -} - -static void -renderer_create(struct comp_renderer *r, struct comp_compositor *c) -{ - r->c = c; - r->settings = &c->settings; - - r->current_buffer = 0; - r->queue = VK_NULL_HANDLE; - r->semaphores.present_complete = VK_NULL_HANDLE; - r->semaphores.render_complete = VK_NULL_HANDLE; - r->rrs = NULL; - - struct vk_bundle *vk = &r->c->vk; - - vk->vkGetDeviceQueue(vk->device, r->c->vk.queue_family_index, 0, &r->queue); - renderer_init_semaphores(r); - - // Try to early-allocate these, in case we can. - renderer_ensure_images_and_renderings(r, false); -} - -static void -renderer_wait_for_last_fence(struct comp_renderer *r) -{ - COMP_TRACE_MARKER(); - struct vk_bundle *vk = &r->c->vk; VkResult ret; - ret = vk->vkWaitForFences(vk->device, 1, &r->fences[r->current_buffer], VK_TRUE, UINT64_MAX); + VkSemaphoreCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + }; + + ret = vk->vkCreateSemaphore(vk->device, &info, NULL, &r->semaphores.present_complete); if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "vkWaitForFences: %s", vk_result_string(ret)); + COMP_ERROR(r->c, "vkCreateSemaphore: %s", vk_result_string(ret)); } -} -static void -renderer_submit_queue(struct comp_renderer *r) -{ - COMP_TRACE_MARKER(); - - struct vk_bundle *vk = &r->c->vk; - VkResult ret; - - VkPipelineStageFlags stage_flags[1] = { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - }; - - ret = vk->vkWaitForFences(vk->device, 1, &r->fences[r->current_buffer], VK_TRUE, UINT64_MAX); - if (ret != VK_SUCCESS) - COMP_ERROR(r->c, "vkWaitForFences: %s", vk_result_string(ret)); - - ret = vk->vkResetFences(vk->device, 1, &r->fences[r->current_buffer]); - if (ret != VK_SUCCESS) - COMP_ERROR(r->c, "vkResetFences: %s", vk_result_string(ret)); - - VkSubmitInfo comp_submit_info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .waitSemaphoreCount = 1, - .pWaitSemaphores = &r->semaphores.present_complete, - .pWaitDstStageMask = stage_flags, - .commandBufferCount = 1, - .pCommandBuffers = &r->rrs[r->current_buffer].cmd, - .signalSemaphoreCount = 1, - .pSignalSemaphores = &r->semaphores.render_complete, - }; - - ret = vk_locked_submit(vk, r->queue, 1, &comp_submit_info, r->fences[r->current_buffer]); + ret = vk->vkCreateSemaphore(vk->device, &info, NULL, &r->semaphores.render_complete); if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "vkQueueSubmit: %s", vk_result_string(ret)); + COMP_ERROR(r->c, "vkCreateSemaphore: %s", vk_result_string(ret)); } } @@ -487,15 +274,31 @@ renderer_build_rendering(struct comp_renderer *r, struct comp_rendering *rr, uin comp_draw_end_target(rr); } - -//! @pre comp_target_has_images(r->c->target) +/*! + * @pre comp_target_has_images(r->c->target) + * Update r->num_buffers before calling. + */ static void -renderer_create_fences(struct comp_renderer *r) +renderer_create_renderings_and_fences(struct comp_renderer *r) { - r->fences = U_TYPED_ARRAY_CALLOC(VkFence, r->num_buffers); + assert(r->rrs == NULL); + assert(r->fences == NULL); + if (r->num_buffers == 0) { + COMP_ERROR(r->c, "Requested 0 command buffers."); + return; + } + + COMP_DEBUG(r->c, "Allocating %d Command Buffers.", r->num_buffers); struct vk_bundle *vk = &r->c->vk; + r->rrs = U_TYPED_ARRAY_CALLOC(struct comp_rendering, r->num_buffers); + r->fences = U_TYPED_ARRAY_CALLOC(VkFence, r->num_buffers); + + for (uint32_t i = 0; i < r->num_buffers; ++i) { + renderer_build_rendering(r, &r->rrs[i], i); + } + for (uint32_t i = 0; i < r->num_buffers; i++) { VkResult ret = vk->vkCreateFence(vk->device, &(VkFenceCreateInfo){.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, @@ -507,6 +310,202 @@ renderer_create_fences(struct comp_renderer *r) } } +static void +renderer_close_renderings_and_fences(struct comp_renderer *r) +{ + struct vk_bundle *vk = &r->c->vk; + // Renderings + if (r->num_buffers > 0 && r->rrs != NULL) { + for (uint32_t i = 0; i < r->num_buffers; i++) { + comp_rendering_close(&r->rrs[i]); + } + + free(r->rrs); + r->rrs = NULL; + } + + // Fences + if (r->num_buffers > 0 && r->fences != NULL) { + for (uint32_t i = 0; i < r->num_buffers; i++) { + vk->vkDestroyFence(vk->device, r->fences[i], NULL); + r->fences[i] = VK_NULL_HANDLE; + } + free(r->fences); + r->fences = NULL; + } + + r->num_buffers = 0; + r->current_buffer = 0; +} + +//! @pre comp_target_check_ready(r->c->target) +static void +renderer_create_layer_renderer(struct comp_renderer *r) +{ + struct vk_bundle *vk = &r->c->vk; + + assert(comp_target_check_ready(r->c->target)); + + uint32_t num_layers = 0; + if (r->lr != NULL) { + // if we already had one, re-populate it after recreation. + num_layers = r->lr->num_layers; + comp_layer_renderer_destroy(&r->lr); + } + + VkExtent2D extent; + if (r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || + r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { + // Swapping width and height, since we are pre rotating + extent = (VkExtent2D){ + .width = r->c->xdev->hmd->screens[0].h_pixels, + .height = r->c->xdev->hmd->screens[0].w_pixels, + }; + } else { + extent = (VkExtent2D){ + .width = r->c->xdev->hmd->screens[0].w_pixels, + .height = r->c->xdev->hmd->screens[0].h_pixels, + }; + } + + r->lr = comp_layer_renderer_create(vk, &r->c->shaders, extent, VK_FORMAT_B8G8R8A8_SRGB); + if (num_layers != 0) { + comp_layer_renderer_allocate_layers(r->lr, num_layers); + } +} + +/*! + * @brief Ensure that target images and renderings are created, if possible. + * + * @param r Self pointer + * @param force_recreate If true, will tear down and re-create images and renderings, e.g. for a resize + * + * @returns true if images and renderings are ready and created. + * + * @private @memberof comp_renderer + * @ingroup comp_main + */ +static bool +renderer_ensure_images_and_renderings(struct comp_renderer *r, bool force_recreate) +{ + struct comp_compositor *c = r->c; + struct comp_target *target = c->target; + + if (!comp_target_check_ready(target)) { + // Not ready, so can't render anything. + return false; + } + + // We will create images if we don't have any images or if we were told to recreate them. + bool create = force_recreate || !comp_target_has_images(target) || (r->num_buffers == 0); + if (!create) { + return true; + } + + COMP_DEBUG(c, "Creating iamges and renderings (force_recreate: %s).", force_recreate ? "true" : "false"); + + /* + * This makes sure that any pending command buffer has completed + * and all resources referred by it can now be manipulated. This + * make sure that validation doesn't complain. This is done + * during resize so isn't time critical. + */ + renderer_wait_gpu_idle(r); + + // Make we sure we destroy all dependent things before creating new images. + renderer_close_renderings_and_fences(r); + + comp_target_create_images( // + r->c->target, // + r->c->target->width, // + r->c->target->height, // + r->settings->color_format, // + r->settings->color_space, // + r->settings->present_mode); // + + r->num_buffers = r->c->target->num_images; + + renderer_create_layer_renderer(r); + renderer_create_renderings_and_fences(r); + + assert(r->num_buffers != 0); + + return true; +} + +//! Create renderer and initialize non-image-dependent members +static void +renderer_create(struct comp_renderer *r, struct comp_compositor *c) +{ + r->c = c; + r->settings = &c->settings; + + r->current_buffer = 0; + r->queue = VK_NULL_HANDLE; + r->semaphores.present_complete = VK_NULL_HANDLE; + r->semaphores.render_complete = VK_NULL_HANDLE; + r->rrs = NULL; + + struct vk_bundle *vk = &r->c->vk; + + vk->vkGetDeviceQueue(vk->device, r->c->vk.queue_family_index, 0, &r->queue); + renderer_init_semaphores(r); + + // Try to early-allocate these, in case we can. + renderer_ensure_images_and_renderings(r, false); +} + +static void +renderer_wait_for_last_fence(struct comp_renderer *r) +{ + COMP_TRACE_MARKER(); + + struct vk_bundle *vk = &r->c->vk; + VkResult ret; + + ret = vk->vkWaitForFences(vk->device, 1, &r->fences[r->current_buffer], VK_TRUE, UINT64_MAX); + if (ret != VK_SUCCESS) { + COMP_ERROR(r->c, "vkWaitForFences: %s", vk_result_string(ret)); + } +} + +static void +renderer_submit_queue(struct comp_renderer *r) +{ + COMP_TRACE_MARKER(); + + struct vk_bundle *vk = &r->c->vk; + VkResult ret; + + VkPipelineStageFlags stage_flags[1] = { + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + }; + + ret = vk->vkWaitForFences(vk->device, 1, &r->fences[r->current_buffer], VK_TRUE, UINT64_MAX); + if (ret != VK_SUCCESS) + COMP_ERROR(r->c, "vkWaitForFences: %s", vk_result_string(ret)); + + ret = vk->vkResetFences(vk->device, 1, &r->fences[r->current_buffer]); + if (ret != VK_SUCCESS) + COMP_ERROR(r->c, "vkResetFences: %s", vk_result_string(ret)); + + VkSubmitInfo comp_submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &r->semaphores.present_complete, + .pWaitDstStageMask = stage_flags, + .commandBufferCount = 1, + .pCommandBuffers = &r->rrs[r->current_buffer].cmd, + .signalSemaphoreCount = 1, + .pSignalSemaphores = &r->semaphores.render_complete, + }; + + ret = vk_locked_submit(vk, r->queue, 1, &comp_submit_info, r->fences[r->current_buffer]); + if (ret != VK_SUCCESS) { + COMP_ERROR(r->c, "vkQueueSubmit: %s", vk_result_string(ret)); + } +} + static void renderer_get_view_projection(struct comp_renderer *r) { @@ -550,15 +549,110 @@ renderer_get_view_projection(struct comp_renderer *r) } } -VkImageView +static void +renderer_acquire_swapchain_image(struct comp_renderer *r) +{ + COMP_TRACE_MARKER(); + + VkResult ret; + + if (!renderer_ensure_images_and_renderings(r, false)) { + // Not ready yet. + return; + } + ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &r->current_buffer); + + if ((ret == VK_ERROR_OUT_OF_DATE_KHR) || (ret == VK_SUBOPTIMAL_KHR)) { + COMP_DEBUG(r->c, "Received %s.", vk_result_string(ret)); + + if (!renderer_ensure_images_and_renderings(r, true)) { + // Failed on force recreate. + COMP_ERROR(r->c, + "renderer_acquire_swapchain_image: comp_target_acquire was out of date, force " + "re-create image and renderings failed. Probably the target disappeared."); + return; + } + /* Acquire image again to silence validation error */ + ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &r->current_buffer); + if (ret != VK_SUCCESS) { + COMP_ERROR(r->c, "comp_target_acquire: %s", vk_result_string(ret)); + } + } else if (ret != VK_SUCCESS) { + COMP_ERROR(r->c, "comp_target_acquire: %s", vk_result_string(ret)); + } +} + +static void +renderer_resize(struct comp_renderer *r) +{ + if (!comp_target_check_ready(r->c->target)) { + // Can't create images right now. + // Just close any existing renderings. + renderer_close_renderings_and_fences(r); + return; + } + + renderer_ensure_images_and_renderings(r, true); // Force recreate. + + return; +} + +static void +renderer_present_swapchain_image(struct comp_renderer *r, uint64_t desired_present_time_ns, uint64_t present_slop_ns) +{ + COMP_TRACE_MARKER(); + + VkResult ret; + + ret = comp_target_present(r->c->target, r->queue, r->current_buffer, r->semaphores.render_complete, + desired_present_time_ns, present_slop_ns); + if (ret == VK_ERROR_OUT_OF_DATE_KHR) { + renderer_resize(r); + return; + } + if (ret != VK_SUCCESS) { + COMP_ERROR(r->c, "vk_swapchain_present: %s", vk_result_string(ret)); + } +} + +static void +renderer_destroy(struct comp_renderer *r) +{ + struct vk_bundle *vk = &r->c->vk; + + // Command buffers + renderer_close_renderings_and_fences(r); + + // Semaphores + if (r->semaphores.present_complete != VK_NULL_HANDLE) { + vk->vkDestroySemaphore(vk->device, r->semaphores.present_complete, NULL); + r->semaphores.present_complete = VK_NULL_HANDLE; + } + if (r->semaphores.render_complete != VK_NULL_HANDLE) { + vk->vkDestroySemaphore(vk->device, r->semaphores.render_complete, NULL); + r->semaphores.render_complete = VK_NULL_HANDLE; + } + + comp_layer_renderer_destroy(&(r->lr)); +} + +static VkImageView get_image_view(struct comp_swapchain_image *image, enum xrt_layer_composition_flags flags, uint32_t array_index) { if (flags & XRT_LAYER_COMPOSITION_BLEND_TEXTURE_SOURCE_ALPHA_BIT) { return image->views.alpha[array_index]; } + return image->views.no_alpha[array_index]; } + +/* + * + * Interface functions. + * + */ + void comp_renderer_set_quad_layer(struct comp_renderer *r, uint32_t layer, @@ -704,6 +798,7 @@ comp_renderer_set_equirect1_layer(struct comp_renderer *r, } } #endif + #ifdef XRT_FEATURE_OPENXR_LAYER_EQUIRECT2 void comp_renderer_set_equirect2_layer(struct comp_renderer *r, @@ -804,165 +899,6 @@ comp_renderer_draw(struct comp_renderer *r) comp_target_update_timings(ct); } -//! Update r->num_buffers before calling. -static void -renderer_create_renderings_and_fences(struct comp_renderer *r) -{ - assert(r->rrs == NULL); - assert(r->fences == NULL); - if (r->num_buffers == 0) { - COMP_ERROR(r->c, "Requested 0 command buffers."); - return; - } - - COMP_DEBUG(r->c, "Allocating %d Command Buffers.", r->num_buffers); - - r->rrs = U_TYPED_ARRAY_CALLOC(struct comp_rendering, r->num_buffers); - - for (uint32_t i = 0; i < r->num_buffers; ++i) { - renderer_build_rendering(r, &r->rrs[i], i); - } - - //! @todo inline this here or above in the other loop? or just put in renderings? - renderer_create_fences(r); -} - -static void -renderer_close_renderings_and_fences(struct comp_renderer *r) -{ - struct vk_bundle *vk = &r->c->vk; - // Renderings - if (r->num_buffers > 0 && r->rrs != NULL) { - for (uint32_t i = 0; i < r->num_buffers; i++) { - comp_rendering_close(&r->rrs[i]); - } - - free(r->rrs); - r->rrs = NULL; - } - - // Fences - if (r->num_buffers > 0 && r->fences != NULL) { - for (uint32_t i = 0; i < r->num_buffers; i++) { - vk->vkDestroyFence(vk->device, r->fences[i], NULL); - r->fences[i] = VK_NULL_HANDLE; - } - free(r->fences); - r->fences = NULL; - } - - r->num_buffers = 0; - r->current_buffer = 0; -} - -static void -renderer_init_semaphores(struct comp_renderer *r) -{ - struct vk_bundle *vk = &r->c->vk; - VkResult ret; - - VkSemaphoreCreateInfo info = { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - }; - - ret = vk->vkCreateSemaphore(vk->device, &info, NULL, &r->semaphores.present_complete); - if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "vkCreateSemaphore: %s", vk_result_string(ret)); - } - - ret = vk->vkCreateSemaphore(vk->device, &info, NULL, &r->semaphores.render_complete); - if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "vkCreateSemaphore: %s", vk_result_string(ret)); - } -} - -static void -renderer_resize(struct comp_renderer *r) -{ - if (!comp_target_check_ready(r->c->target)) { - // Can't create images right now. - // Just close any existing renderings. - renderer_close_renderings_and_fences(r); - return; - } - - renderer_ensure_images_and_renderings(r, true); // Force recreate. - - return; -} - -static void -renderer_acquire_swapchain_image(struct comp_renderer *r) -{ - COMP_TRACE_MARKER(); - - VkResult ret; - - if (!renderer_ensure_images_and_renderings(r, false)) { - // Not ready yet. - return; - } - ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &r->current_buffer); - - if ((ret == VK_ERROR_OUT_OF_DATE_KHR) || (ret == VK_SUBOPTIMAL_KHR)) { - COMP_DEBUG(r->c, "Received %s.", vk_result_string(ret)); - - if (!renderer_ensure_images_and_renderings(r, true)) { - // Failed on force recreate. - COMP_ERROR(r->c, - "renderer_acquire_swapchain_image: comp_target_acquire was out of date, force " - "re-create image and renderings failed. Probably the target disappeared."); - return; - } - /* Acquire image again to silence validation error */ - ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &r->current_buffer); - if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "comp_target_acquire: %s", vk_result_string(ret)); - } - } else if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "comp_target_acquire: %s", vk_result_string(ret)); - } -} - -static void -renderer_present_swapchain_image(struct comp_renderer *r, uint64_t desired_present_time_ns, uint64_t present_slop_ns) -{ - COMP_TRACE_MARKER(); - - VkResult ret; - - ret = comp_target_present(r->c->target, r->queue, r->current_buffer, r->semaphores.render_complete, - desired_present_time_ns, present_slop_ns); - if (ret == VK_ERROR_OUT_OF_DATE_KHR) { - renderer_resize(r); - return; - } - if (ret != VK_SUCCESS) { - COMP_ERROR(r->c, "vk_swapchain_present: %s", vk_result_string(ret)); - } -} - -static void -renderer_destroy(struct comp_renderer *r) -{ - struct vk_bundle *vk = &r->c->vk; - - // Command buffers - renderer_close_renderings_and_fences(r); - - // Semaphores - if (r->semaphores.present_complete != VK_NULL_HANDLE) { - vk->vkDestroySemaphore(vk->device, r->semaphores.present_complete, NULL); - r->semaphores.present_complete = VK_NULL_HANDLE; - } - if (r->semaphores.render_complete != VK_NULL_HANDLE) { - vk->vkDestroySemaphore(vk->device, r->semaphores.render_complete, NULL); - r->semaphores.render_complete = VK_NULL_HANDLE; - } - - comp_layer_renderer_destroy(&(r->lr)); -} - void comp_renderer_allocate_layers(struct comp_renderer *self, uint32_t num_layers) { @@ -978,3 +914,30 @@ comp_renderer_destroy_layers(struct comp_renderer *self) comp_layer_renderer_destroy_layers(self->lr); } + +struct comp_renderer * +comp_renderer_create(struct comp_compositor *c) +{ + struct comp_renderer *r = U_TYPED_CALLOC(struct comp_renderer); + + renderer_create(r, c); + + return r; +} + +void +comp_renderer_destroy(struct comp_renderer **ptr_r) +{ + if (ptr_r == NULL) { + return; + } + + struct comp_renderer *r = *ptr_r; + if (r == NULL) { + return; + } + + renderer_destroy(r); + free(r); + *ptr_r = NULL; +} From e9eba9a2b4004b087e684e80ae6fd2d33c1e65bb Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 31 Mar 2021 01:28:22 +0200 Subject: [PATCH 389/883] aux/bindings: Generate char* <-> enum for all used inputs --- src/xrt/auxiliary/bindings/bindings.py | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/xrt/auxiliary/bindings/bindings.py b/src/xrt/auxiliary/bindings/bindings.py index e7782d8b2..7cb8ff73d 100755 --- a/src/xrt/auxiliary/bindings/bindings.py +++ b/src/xrt/auxiliary/bindings/bindings.py @@ -215,6 +215,42 @@ def generate_bindings_c(file, p): f.write('}; // /array of profile_template\n\n') + inputs = set() + for profile in p.profiles: + feature: Feature + for idx, feature in enumerate(profile.features): + sp_obj = feature.sub_path_obj + if feature_str not in sp_obj["monado_bindings"]: + continue + monado_binding = sp_obj["monado_bindings"][feature_str] + inputs.add(monado_binding) + + # special cased bindings that are never directly used in the input profiles + inputs.add("XRT_INPUT_GENERIC_HEAD_POSE") + inputs.add("XRT_INPUT_GENERIC_HEAD_DETECT") + inputs.add("XRT_INPUT_GENERIC_HAND_TRACKING_LEFT") + inputs.add("XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT") + inputs.add("XRT_INPUT_GENERIC_TRACKER_POSE") + + f.write('const char *\n') + f.write('xrt_input_name_string(enum xrt_input_name input)\n') + f.write('{\n') + f.write('\tswitch(input)\n') + f.write('\t{\n') + for input in inputs: + f.write(f'\tcase {input}: return "{input}";\n') + f.write(f'\tdefault: return "UNKNOWN";\n') + f.write('\t}\n') + f.write('}\n') + + f.write('enum xrt_input_name\n') + f.write('xrt_input_name_enum(const char *input)\n') + f.write('{\n') + for input in inputs: + f.write(f'\tif(strcmp("{input}", input) == 0) return {input};\n') + f.write(f'\treturn XRT_INPUT_GENERIC_TRACKER_POSE;\n') + f.write('}\n') + f.write("\n// clang-format on\n") f.close() @@ -265,8 +301,15 @@ struct profile_template #define NUM_PROFILE_TEMPLATES {len(p.profiles)} extern struct profile_template profile_templates[NUM_PROFILE_TEMPLATES]; + ''') + f.write('const char *\n') + f.write('xrt_input_name_string(enum xrt_input_name input);\n\n') + + f.write('enum xrt_input_name\n') + f.write('xrt_input_name_enum(const char *input);\n\n') + f.write("\n// clang-format on\n") f.close() From cffd009fe94b1c749d14a094e9c5b87ba4c9813d Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 31 Mar 2021 02:00:58 +0200 Subject: [PATCH 390/883] st/gui: Add tracker pose input name selection --- .../gui/gui_scene_tracking_overrides.c | 47 +++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c b/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c index 63caff4b6..abd7a0766 100644 --- a/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c +++ b/src/xrt/state_trackers/gui/gui_scene_tracking_overrides.c @@ -21,6 +21,8 @@ #include "gui_common.h" #include "gui_imgui.h" +#include "bindings/b_generated_bindings.h" + struct gui_tracking_overrides { struct gui_scene base; @@ -30,7 +32,6 @@ struct gui_tracking_overrides bool add_one; int add_target; int add_tracker; - enum xrt_tracking_override_type override_type; struct u_config_json config; @@ -171,22 +172,22 @@ add_one(struct gui_program *p, struct gui_tracking_overrides *ts) } igEnd(); - igBegin("Tracking Override Type", NULL, 0); - for (int i = 0; i < 2; i++) { - bool selected = (int)ts->override_type == i; - if (igCheckbox(override_type_str[i], &selected)) { - ts->override_type = (enum xrt_tracking_override_type)i; - } - } - igEnd(); - if (ts->add_target >= 0 && ts->add_tracker >= 0 && ts->add_target != ts->add_tracker) { struct xrt_tracking_override *o = &ts->overrides[ts->num_overrides]; - o->input_name = XRT_INPUT_GENERIC_TRACKER_POSE; strncpy(o->target_device_serial, p->xdevs[ts->add_target]->serial, XRT_DEVICE_NAME_LEN); strncpy(o->tracker_device_serial, p->xdevs[ts->add_tracker]->serial, XRT_DEVICE_NAME_LEN); o->offset = identity; + // set input_name to the first pose in the inputs + for (uint32_t i = 0; i < p->xdevs[ts->add_tracker]->num_inputs; i++) { + enum xrt_input_name input_name = p->xdevs[ts->add_tracker]->inputs[i].name; + if (XRT_GET_INPUT_TYPE(input_name) != XRT_INPUT_TYPE_POSE) { + continue; + } + o->input_name = input_name; + break; + } + ts->num_overrides += 1; ts->add_target = -1; @@ -194,7 +195,8 @@ add_one(struct gui_program *p, struct gui_tracking_overrides *ts) ts->add_one = false; - ts->override_type = 0; + // immediately open for editing + ts->editing_override = ts->num_overrides - 1; } } @@ -212,7 +214,7 @@ scene_render(struct gui_scene *scene, struct gui_program *p) struct xrt_tracking_override *o = &ts->overrides[ts->editing_override]; igBegin("Tracker Device Offset", NULL, 0); - int target = 0, tracker = 0; + int target = -1, tracker = -1; if (get_indices(p, ts, o, &target, &tracker)) { igText("Editing %s [%s] <- %s [%s]", p->xdevs[target]->str, o->target_device_serial, p->xdevs[tracker]->str, o->tracker_device_serial); @@ -222,13 +224,30 @@ scene_render(struct gui_scene *scene, struct gui_program *p) handle_draggable_vec3_f32("Position", &o->offset.position, &ts->reset_offset.position); handle_draggable_quat("Orientation", &o->offset.orientation, &ts->reset_offset.orientation); + igText("Tracking Override Type"); for (int i = 0; i < 2; i++) { bool selected = (int)o->override_type == i; if (igCheckbox(override_type_str[i], &selected)) { o->override_type = (enum xrt_tracking_override_type)i; } } - igEnd(); + + if (tracker >= 0) { + igText("Tracker Input Pose Name"); + for (uint32_t i = 0; i < p->xdevs[tracker]->num_inputs; i++) { + enum xrt_input_name input_name = p->xdevs[tracker]->inputs[i].name; + if (XRT_GET_INPUT_TYPE(input_name) != XRT_INPUT_TYPE_POSE) { + continue; + } + + const char *name_str = xrt_input_name_string(input_name); + bool selected = o->input_name == input_name; + if (igCheckbox(name_str, &selected)) { + o->input_name = input_name; + } + } + igEnd(); + } } if (ts->add_one) { From fa794518584e9cec494106a001052aede696bbe2 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 31 Mar 2021 02:57:10 +0200 Subject: [PATCH 391/883] build/cmake: link generated bindings to aux_util --- src/xrt/auxiliary/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index b64665df1..6cd78102b 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -1,6 +1,8 @@ # Copyright 2019-2020, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 +add_subdirectory(bindings) + set(ANDROID_SOURCE_FILES android/android_ahardwarebuffer_allocator.c android/android_ahardwarebuffer_allocator.h @@ -213,7 +215,7 @@ target_include_directories(aux_math SYSTEM # Util library. add_library(aux_util STATIC ${UTIL_SOURCE_FILES}) -target_link_libraries(aux_util PUBLIC aux-includes xrt-pthreads) +target_link_libraries(aux_util PUBLIC aux-includes xrt-pthreads aux_generated_bindings) # for u_device target_link_libraries(aux_util PUBLIC aux_math) if(XRT_HAVE_JPEG) @@ -309,4 +311,3 @@ if(ANDROID) target_link_libraries(aux_vk PUBLIC aux_android) endif() -add_subdirectory(bindings) From 664c103a3e302bad9cc084b0d5746c6af3bb0139 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 31 Mar 2021 02:04:33 +0200 Subject: [PATCH 392/883] u_config_json: Store tracking override pose input name --- src/xrt/auxiliary/util/u_config_json.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 968136db3..6c0e38897 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -22,6 +22,8 @@ #include #include +#include "bindings/b_generated_bindings.h" + DEBUG_GET_ONCE_OPTION(active_config, "P_OVERRIDE_ACTIVE_CONFIG", NULL) #define CONFIG_FILE_NAME "config_v0.json" @@ -463,6 +465,9 @@ u_config_json_save_overrides(struct u_config_json *json, struct xrt_tracking_ove cJSON_AddItemToObject(entry, "offset", make_pose(&overrides[i].offset)); + const char *input_name_string = xrt_input_name_string(overrides[i].input_name); + cJSON_AddStringToObject(entry, "xrt_input_name", input_name_string); + cJSON_AddItemToArray(o, entry); } From 471b87672524989afb20c2b7dea9a66ac47376e5 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 31 Mar 2021 02:21:52 +0200 Subject: [PATCH 393/883] u_config_json: Load tracking override pose input name --- src/xrt/auxiliary/util/u_config_json.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 6c0e38897..4f6a75775 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -310,8 +310,9 @@ u_config_json_get_tracking_overrides(struct u_config_json *json, o->offset.orientation.w = 1; } - //! @todo support arbitrary tracking inputs for overrides - o->input_name = XRT_INPUT_GENERIC_TRACKER_POSE; + char input_name[512]; + get_obj_str(override, "xrt_input_name", input_name, 512); + o->input_name = xrt_input_name_enum(input_name); if (bad) { *out_num_overrides = 0; From e8b18131f3ede33e7d66b32fbcb9c028f0302adf Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Wed, 31 Mar 2021 02:23:48 +0200 Subject: [PATCH 394/883] doc: Add xrt_input_name to northstar example config --- doc/example_configs/config_v0.json.northstar_lonestar | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/example_configs/config_v0.json.northstar_lonestar b/doc/example_configs/config_v0.json.northstar_lonestar index b33710f75..85c1df6fa 100644 --- a/doc/example_configs/config_v0.json.northstar_lonestar +++ b/doc/example_configs/config_v0.json.northstar_lonestar @@ -18,7 +18,8 @@ "y": 0.0683, "z": -0.0744 } - } + }, + "xrt_input_name": "XRT_INPUT_GENERIC_TRACKER_POSE" }, { "target_device_serial": "Leap Motion v2 driver", @@ -36,7 +37,8 @@ "y": 0.005, "z": 0 } - } + }, + "xrt_input_name": "XRT_INPUT_GENERIC_TRACKER_POSE" } ], "version": 0 From 26d93c52dfbd1c282fe0424a45cddd772f378f67 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 1 Apr 2021 01:55:44 +0200 Subject: [PATCH 395/883] d/multi: Use supplied pose input name enum --- src/xrt/drivers/multi_wrapper/multi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/multi_wrapper/multi.c b/src/xrt/drivers/multi_wrapper/multi.c index 869e5026c..c393d62da 100644 --- a/src/xrt/drivers/multi_wrapper/multi.c +++ b/src/xrt/drivers/multi_wrapper/multi.c @@ -141,7 +141,7 @@ get_hand_tracking(struct xrt_device *xdev, struct xrt_device *tracker = d->tracking_override.tracker; struct xrt_space_relation tracker_relation; - xrt_device_get_tracked_pose(tracker, XRT_INPUT_GENERIC_TRACKER_POSE, at_timestamp_ns, &tracker_relation); + xrt_device_get_tracked_pose(tracker, d->tracking_override.input_name, at_timestamp_ns, &tracker_relation); switch (d->override_type) { From 686d12d66f9bf61169c0a3ee86a5d9c8cb58d24c Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 1 Apr 2021 02:25:51 +0200 Subject: [PATCH 396/883] p/prober: Print info for applied tracking override --- src/xrt/state_trackers/prober/p_prober.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xrt/state_trackers/prober/p_prober.c b/src/xrt/state_trackers/prober/p_prober.c index 03ecb1233..9906e8890 100644 --- a/src/xrt/state_trackers/prober/p_prober.c +++ b/src/xrt/state_trackers/prober/p_prober.c @@ -811,6 +811,8 @@ apply_tracking_override(struct prober *p, struct xrt_device **xdevs, size_t num_ o->input_name, &o->offset); if (multi) { + P_INFO(p, "Applying Tracking override %s <- %s", o->target_device_serial, + o->tracker_device_serial); // drops the target device from the list, but keeps the tracker // a tracker could be attached to multiple targets with different names xdevs[target_idx] = multi; From b9b72280bf6a437f9b431f8002d3b54751bf3e12 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 1 Apr 2021 02:31:17 +0200 Subject: [PATCH 397/883] doc: Add MR 741 changelog --- doc/changes/drivers/mr.741.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/drivers/mr.741.md diff --git a/doc/changes/drivers/mr.741.md b/doc/changes/drivers/mr.741.md new file mode 100644 index 000000000..40a298770 --- /dev/null +++ b/doc/changes/drivers/mr.741.md @@ -0,0 +1 @@ +multi: Enable specifying arbitrary xrt_input_name for querying tracker poses. From c47775a95d8e139a2f234063793eb6726f830510 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 19 Apr 2021 13:04:59 +0200 Subject: [PATCH 398/883] comp: Fix warning after Vulkan 1.2.174 VK_NULL_HANDLE change ../src/xrt/compositor/main/comp_layer_renderer.c:317:17: warning: initialization of 'unsigned int' from 'void *' makes integer from pointer without a cast [-Wint-conversion] 317 | .subpass = VK_NULL_HANDLE, | ^~~~~~~~~~~~~~ --- src/xrt/compositor/main/comp_layer_renderer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_layer_renderer.c b/src/xrt/compositor/main/comp_layer_renderer.c index c59232a94..d8a0a6321 100644 --- a/src/xrt/compositor/main/comp_layer_renderer.c +++ b/src/xrt/compositor/main/comp_layer_renderer.c @@ -314,7 +314,7 @@ _init_graphics_pipeline(struct comp_layer_renderer *self, VK_DYNAMIC_STATE_SCISSOR, }, }, - .subpass = VK_NULL_HANDLE, + .subpass = 0, }; VkResult res; From 7b7e66b2b0239eb62960a4897bada0be883054ba Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 19 Apr 2021 14:19:01 +0100 Subject: [PATCH 399/883] ci: Remove build directories --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 243e72bc6..e5b9c30d5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -163,6 +163,7 @@ format-and-spellcheck: .monado.base-job.build-cmake: stage: build script: + - rm -rf build - mkdir build - pushd build - cmake -GNinja .. $CMAKE_ARGS @@ -175,6 +176,7 @@ format-and-spellcheck: .monado.base-job.build-meson: stage: build script: + - rm -rf build - mkdir build - pushd build - meson .. $MESON_ARGS From 005852545740fadef8a918d9109ccc0a53844df9 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 19 Apr 2021 14:26:51 +0100 Subject: [PATCH 400/883] util: Depend on bindings --- src/xrt/auxiliary/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/meson.build b/src/xrt/auxiliary/meson.build index d35a238fd..8433d434f 100644 --- a/src/xrt/auxiliary/meson.build +++ b/src/xrt/auxiliary/meson.build @@ -11,7 +11,7 @@ u_git_tag_c = vcs_tag( replace_string: '@GIT_DESC@', ) -aux_util_deps = [ xrt_config_have ] +aux_util_deps = [ xrt_config_have, aux_generated_bindings ] if libbsd.found() and not get_option('libbsd').disabled() aux_util_deps += libbsd endif From 027ce21bd5f662037f6537a206c97509e8357d23 Mon Sep 17 00:00:00 2001 From: nima01 Date: Fri, 4 Dec 2020 17:43:46 +0100 Subject: [PATCH 401/883] d/wmr: Initial 3DoF WinMR driver Only supports HP Reverb G1 and G2 for now. Squash of the following commits: Initial boilerplate code for HP Reverb G1 driver implementation Detect and open MS HoloLens Sensors interface Power up HMD display when headset is detected, and som general code cleanup Add Reverb G2 PID reverb_g1: Fix defines reverb_g1: Run clang format wmr: Rename Reverb G1 driver to WMR driver d/wmr: Code style d/wmr: Flesh out driver a bit more d/wmr: Code style Add basic 3dof rotational tracking d/wmr: Code style d/wmr: More tidy xrt: Remove XRT_DEVICE_REVERB_G1 d/wmr: Even more tidy d/wmr: Changes for Reverb G2 d/wmr: Fixes since last commit wmr: Fix the meson build and auto-enable the driver d/wmr: Sleep for compositor to get modes d/wmr: Use os_hid for control device d/wmr: Remove hidapi as a dependancy d/wmr: Move sensor reading to own thread and fix locking d/wmr: Read from control device and handle more unknown messages d/wmr: Decode IPD value from control device d/wmr: Remove all left over dummy driver fields Co-author: nima01 Co-author: Jakob Bornecrantz Co-author: Jan Schmidt --- CMakeLists.txt | 4 +- doc/changes/big/mr.774.md | 2 + doc/changes/drivers/mr.774.md | 1 + meson.build | 2 +- meson_options.txt | 2 +- src/xrt/drivers/CMakeLists.txt | 16 + src/xrt/drivers/meson.build | 16 + src/xrt/drivers/wmr/wmr_common.h | 44 +++ src/xrt/drivers/wmr/wmr_hmd.c | 537 ++++++++++++++++++++++++++ src/xrt/drivers/wmr/wmr_hmd.h | 104 +++++ src/xrt/drivers/wmr/wmr_interface.h | 48 +++ src/xrt/drivers/wmr/wmr_prober.c | 160 ++++++++ src/xrt/drivers/wmr/wmr_protocol.c | 60 +++ src/xrt/drivers/wmr/wmr_protocol.h | 126 ++++++ src/xrt/targets/common/CMakeLists.txt | 5 + src/xrt/targets/common/target_lists.c | 10 + src/xrt/targets/meson.build | 4 + 17 files changed, 1138 insertions(+), 3 deletions(-) create mode 100644 doc/changes/big/mr.774.md create mode 100644 doc/changes/drivers/mr.774.md create mode 100644 src/xrt/drivers/wmr/wmr_common.h create mode 100644 src/xrt/drivers/wmr/wmr_hmd.c create mode 100644 src/xrt/drivers/wmr/wmr_hmd.h create mode 100644 src/xrt/drivers/wmr/wmr_interface.h create mode 100644 src/xrt/drivers/wmr/wmr_prober.c create mode 100644 src/xrt/drivers/wmr/wmr_protocol.c create mode 100644 src/xrt/drivers/wmr/wmr_protocol.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c2af2cca3..4b8f94a59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,10 +198,10 @@ cmake_dependent_option(XRT_BUILD_DRIVER_HANDTRACKING "Enable Camera Hand Trackin cmake_dependent_option(XRT_BUILD_DRIVER_DAYDREAM "Enable the Google Daydream View controller driver (BLE, via D-Bus)" ON "XRT_HAVE_DBUS" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_ARDUINO "Enable Arduino input device with BLE via via D-Bus" ON "XRT_HAVE_DBUS" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_ILLIXR "Enable ILLIXR driver" ON "ILLIXR_PATH" OFF) - option(XRT_BUILD_DRIVER_DUMMY "Enable dummy driver" ON) cmake_dependent_option(XRT_BUILD_DRIVER_ULV2 "Enable Ultraleap v2 driver" ON "Leap" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_REMOTE "Enable remote debugging driver" ON "XRT_HAVE_LINUX OR ANDROID" OFF) +option(XRT_BUILD_DRIVER_WMR "Enable Windows Mixed Reality driver" ON) # These all use the Monado internal hid wrapper. cmake_dependent_option(XRT_BUILD_DRIVER_HDK "Enable HDK driver" ON "XRT_HAVE_INTERNAL_HID" OFF) @@ -239,6 +239,7 @@ list(APPEND AVAILABLE_DRIVERS "VF" "VIVE" "QWERTY" + "WMR" ) @@ -378,6 +379,7 @@ message(STATUS "# DRIVER_SURVIVE: ${XRT_BUILD_DRIVER_SURVIVE}") message(STATUS "# DRIVER_VF: ${XRT_BUILD_DRIVER_VF}") message(STATUS "# DRIVER_VIVE: ${XRT_BUILD_DRIVER_VIVE}") message(STATUS "# DRIVER_QWERTY: ${XRT_BUILD_DRIVER_QWERTY}") +message(STATUS "# DRIVER_WMR: ${XRT_BUILD_DRIVER_WMR}") message(STATUS "#####----- Config -----#####") if(XRT_FEATURE_SERVICE AND NOT XRT_FEATURE_OPENXR) diff --git a/doc/changes/big/mr.774.md b/doc/changes/big/mr.774.md new file mode 100644 index 000000000..3a2e186b9 --- /dev/null +++ b/doc/changes/big/mr.774.md @@ -0,0 +1,2 @@ +New WinMR driver, the initial commit only adds simple 3DoF support and not +distortion support. diff --git a/doc/changes/drivers/mr.774.md b/doc/changes/drivers/mr.774.md new file mode 100644 index 000000000..adcf95da0 --- /dev/null +++ b/doc/changes/drivers/mr.774.md @@ -0,0 +1 @@ +wmr: Initial commit of driver, 3DoF only. diff --git a/meson.build b/meson.build index 507e9c0a9..28983ffe9 100644 --- a/meson.build +++ b/meson.build @@ -161,7 +161,7 @@ if 'v4l2' in drivers endif if 'auto' in drivers - drivers += ['dummy', 'hdk', 'hydra', 'ns', 'psmv', 'remote'] + drivers += ['dummy', 'hdk', 'hydra', 'ns', 'psmv', 'remote', 'wmr'] endif openhmd = dependency('openhmd', required: openhmd_required) diff --git a/meson_options.txt b/meson_options.txt index 69ada8163..5953c21f1 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,7 +3,7 @@ option('drivers', type: 'array', - choices: ['auto', 'dummy', 'hdk', 'hydra', 'ns', 'ohmd', 'psmv', 'psvr', 'rs', 'v4l2', 'vf', 'vive', 'survive', 'daydream', 'arduino', 'remote', 'handtracking', 'qwerty', 'ulv2'], + choices: ['auto', 'dummy', 'hdk', 'hydra', 'ns', 'ohmd', 'psmv', 'psvr', 'rs', 'v4l2', 'vf', 'vive', 'wmr', 'survive', 'daydream', 'arduino', 'remote', 'handtracking', 'qwerty', 'ulv2'], value: ['auto'], description: 'Set of drivers to build') diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index 5c686bf03..c3b28a7ba 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -288,6 +288,22 @@ add_library(drv_multi STATIC ${MUlTI_SOURCE_FILES}) target_link_libraries(drv_multi PUBLIC xrt-interfaces aux_util) list(APPEND ENABLED_HEADSET_DRIVERS drv_multi) +if(XRT_BUILD_DRIVER_WMR) + set(WMR_SOURCE_FILES + wmr/wmr_common.h + wmr/wmr_hmd.c + wmr/wmr_hmd.h + wmr/wmr_interface.h + wmr/wmr_prober.c + wmr/wmr_protocol.c + wmr/wmr_protocol.h + ) + + add_library(drv_wmr STATIC ${WMR_SOURCE_FILES}) + target_link_libraries(drv_wmr PRIVATE xrt-interfaces aux_util) + list(APPEND ENABLED_HEADSET_DRIVERS wmr) +endif() + if(ENABLED_HEADSET_DRIVERS) set(ENABLED_DRIVERS ${ENABLED_HEADSET_DRIVERS} ${ENABLED_DRIVERS}) list(SORT ENABLED_DRIVERS) diff --git a/src/xrt/drivers/meson.build b/src/xrt/drivers/meson.build index fba34c8ef..6f13eb7c2 100644 --- a/src/xrt/drivers/meson.build +++ b/src/xrt/drivers/meson.build @@ -268,3 +268,19 @@ lib_drv_qwerty = static_library( ) drv_qwerty_include = include_directories('qwerty') + +lib_drv_wmr = static_library( + 'drv_wmr', + files( + 'wmr/wmr_common.h', + 'wmr/wmr_hmd.c', + 'wmr/wmr_hmd.h', + 'wmr/wmr_interface.h', + 'wmr/wmr_prober.c', + 'wmr/wmr_protocol.c', + 'wmr/wmr_protocol.h', + ), + include_directories: xrt_include, + dependencies: [aux], + build_by_default: 'wmr' in drivers, +) diff --git a/src/xrt/drivers/wmr/wmr_common.h b/src/xrt/drivers/wmr/wmr_common.h new file mode 100644 index 000000000..383445f8d --- /dev/null +++ b/src/xrt/drivers/wmr/wmr_common.h @@ -0,0 +1,44 @@ +// Copyright 2020-2021, N Madsen. +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Defines and constants related to WMR driver code. + * @author nima01 + * @author Jakob Bornecrantz + * @ingroup drv_wmr + */ + +#pragma once + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! + * Defines for the WMR driver. + * + * @ingroup drv_wmr + * @{ + */ + +#define MS_HOLOLENS_MANUFACTURER_STRING "Microsoft" +#define MS_HOLOLENS_PRODUCT_STRING "HoloLens Sensors" + +#define MICROSOFT_VID 0x045e +#define HOLOLENS_SENSORS_PID 0x0659 + +#define HP_VID 0x03f0 +#define REVERB_G1_PID 0x0c6a +#define REVERB_G2_PID 0x0580 + +/*! + * @} + */ + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c new file mode 100644 index 000000000..e14a42629 --- /dev/null +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -0,0 +1,537 @@ +// Copyright 2018, Philipp Zabel. +// Copyright 2020-2021, N Madsen. +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Driver code for a WMR HMD. + * @author Philipp Zabel + * @author nima01 + * @author Jakob Bornecrantz + * @ingroup drv_wmr + */ + +#include "xrt/xrt_config_os.h" +#include "xrt/xrt_device.h" + +#include "os/os_time.h" +#include "os/os_hid.h" + +#include "math/m_mathinclude.h" +#include "math/m_api.h" +#include "math/m_vec2.h" + +#include "util/u_var.h" +#include "util/u_misc.h" +#include "util/u_time.h" +#include "util/u_debug.h" +#include "util/u_device.h" +#include "util/u_distortion_mesh.h" + +#include "wmr_hmd.h" +#include "wmr_common.h" +#include "wmr_protocol.h" + +#include +#include +#include +#include +#ifndef XRT_OS_WINDOWS +#include // for sleep() +#endif + + +/* + * + * Hololens packets. + * + */ + +static void +hololens_unknown_17_decode_packet(struct wmr_hmd *wh, const unsigned char *buffer, int size) +{ + if (size >= 7) { + WMR_TRACE(wh, "Got packet 0x17 (%i)\n\t%02x %02x %02x %02x %02x %02x %02x ", size, buffer[0], buffer[1], + buffer[2], buffer[3], buffer[4], buffer[5], buffer[6]); + } else { + WMR_TRACE(wh, "Got packet 0x17 (%i)", size); + } +} + +static void +hololens_unknown_05_06_0E_decode_packet(struct wmr_hmd *wh, const unsigned char *buffer, int size) +{ + if (size >= 45) { + WMR_TRACE(wh, + "Got controller (%i)\n\t%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x | %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + size, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], + buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15], + buffer[16], buffer[17], buffer[18], buffer[19], buffer[20], buffer[21], buffer[22], + buffer[23], buffer[24], buffer[25], buffer[26], buffer[27], buffer[28], buffer[29]); + } else { + WMR_TRACE(wh, "Got controller packet (%i)\n\t%02x", size, buffer[0]); + } +} + +static void +hololens_sensors_decode_packet(struct wmr_hmd *wh, + struct hololens_sensors_packet *pkt, + const unsigned char *buffer, + int size) +{ + WMR_TRACE(wh, ""); + + if (size != 497 && size != 381) { + WMR_ERROR(wh, "invalid hololens sensor packet size (expected 381 or 497 but got %d)", size); + return; + } + + pkt->id = read8(&buffer); + for (int i = 0; i < 4; i++) { + pkt->temperature[i] = read16(&buffer); + } + + for (int i = 0; i < 4; i++) { + pkt->gyro_timestamp[i] = read64(&buffer); + } + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 32; j++) { + pkt->gyro[i][j] = read16(&buffer); + } + } + + for (int i = 0; i < 4; i++) { + pkt->accel_timestamp[i] = read64(&buffer); + } + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + pkt->accel[i][j] = read32(&buffer); + } + } + + for (int i = 0; i < 4; i++) { + pkt->video_timestamp[i] = read64(&buffer); + } + + return; +} + +static bool +hololens_sensors_read_packets(struct wmr_hmd *wh) +{ + WMR_TRACE(wh, ""); + + unsigned char buffer[WMR_FEATURE_BUFFER_SIZE]; + + // Block for 100ms + int size = os_hid_read(wh->hid_hololens_senors_dev, buffer, sizeof(buffer), 100); + + if (size < 0) { + WMR_ERROR(wh, "Error reading from device"); + return false; + } else if (size == 0) { + WMR_TRACE(wh, "No more data to read"); + return true; // No more messages, return. + } else { + WMR_TRACE(wh, "Read %u bytes", size); + } + + switch (buffer[0]) { + case WMR_MS_HOLOLENS_MSG_SENSORS: + hololens_sensors_decode_packet(wh, &wh->packet, buffer, size); + + for (int i = 0; i < 4; i++) { + vec3_from_hololens_gyro(wh->packet.gyro, i, &wh->raw_gyro); + vec3_from_hololens_accel(wh->packet.accel, i, &wh->raw_accel); + + os_mutex_lock(&wh->fusion_mutex); + m_imu_3dof_update(&wh->fusion, wh->packet.gyro_timestamp[i] * WMR_MS_HOLOLENS_NS_PER_TICK, + &wh->raw_accel, &wh->raw_gyro); + os_mutex_unlock(&wh->fusion_mutex); + } + break; + case WMR_MS_HOLOLENS_MSG_UNKNOWN_05: + case WMR_MS_HOLOLENS_MSG_UNKNOWN_06: + case WMR_MS_HOLOLENS_MSG_UNKNOWN_0E: // + hololens_unknown_05_06_0E_decode_packet(wh, buffer, size); + break; + case WMR_MS_HOLOLENS_MSG_UNKNOWN_17: // + hololens_unknown_17_decode_packet(wh, buffer, size); + break; + case WMR_MS_HOLOLENS_MSG_CONTROL: + case WMR_MS_HOLOLENS_MSG_DEBUG: // + break; + default: // + WMR_DEBUG(wh, "Unknown message type: %02x, (%i)", buffer[0], size); + break; + } + + return true; +} + + +/* + * + * Control packets. + * + */ + +static void +control_ipd_value_decode(struct wmr_hmd *wh, const unsigned char *buffer, int size) +{ + if (size != 4) { + WMR_ERROR(wh, "Invalid control ipd distance packet size (expected 4 but got %i)", size); + return; + } + + uint8_t id = read8(&buffer); + uint8_t unknown = read8(&buffer); + uint16_t value = read16(&buffer); + + (void)id; + (void)unknown; + + wh->raw_ipd = value; + + WMR_DEBUG(wh, "Got IPD value: %04x", value); +} + +static bool +control_read_packets(struct wmr_hmd *wh) +{ + unsigned char buffer[WMR_FEATURE_BUFFER_SIZE]; + + // Do not block + int size = os_hid_read(wh->hid_control_dev, buffer, sizeof(buffer), 0); + + if (size < 0) { + WMR_ERROR(wh, "Error reading from device"); + return false; + } else if (size == 0) { + WMR_TRACE(wh, "No more data to read"); + return true; // No more messages, return. + } else { + WMR_TRACE(wh, "Read %u bytes", size); + } + + switch (buffer[0]) { + case WMR_CONTROL_MSG_IPD_VALUE: // + control_ipd_value_decode(wh, buffer, size); + break; + case WMR_CONTROL_MSG_UNKNOWN_05: // + break; + default: // + WMR_DEBUG(wh, "Unknown message type: %02x, (%i)", buffer[0], size); + break; + } + + return true; +} + + +/* + * + * Helpers and internal functions. + * + */ + +static void * +wmr_run_thread(void *ptr) +{ + struct wmr_hmd *wh = (struct wmr_hmd *)ptr; + + os_thread_helper_lock(&wh->oth); + while (os_thread_helper_is_running_locked(&wh->oth)) { + os_thread_helper_unlock(&wh->oth); + + // Does not block. + if (!control_read_packets(wh)) { + break; + } + + // Does block for a bit. + if (!hololens_sensors_read_packets(wh)) { + break; + } + } + + WMR_DEBUG(wh, "Exiting reading thread."); + + return NULL; +} + +static void +hololens_sensors_enable_imu(struct wmr_hmd *wh) +{ + int size = os_hid_write(wh->hid_hololens_senors_dev, hololens_sensors_imu_on, sizeof(hololens_sensors_imu_on)); + if (size <= 0) { + WMR_ERROR(wh, "Error writing to device"); + return; + } +} + +#define HID_SEND(HID, DATA, STR) \ + do { \ + int _ret = os_hid_set_feature(HID, DATA, sizeof(DATA)); \ + if (_ret < 0) { \ + WMR_ERROR(wh, "Send (%s): %i", STR, _ret); \ + } \ + } while (false); + +#define HID_GET(HID, DATA, STR) \ + do { \ + int _ret = os_hid_get_feature(HID, DATA[0], DATA, sizeof(DATA)); \ + if (_ret < 0) { \ + WMR_ERROR(wh, "Get (%s): %i", STR, _ret); \ + } \ + } while (false); + +static int +wmr_hmd_activate(struct wmr_hmd *wh) +{ + struct os_hid_device *hid = wh->hid_control_dev; + + WMR_TRACE(wh, "Activating HP Reverb G1/G2 HMD..."); + + + // Hack to power up the Reverb G1 display, thanks to OpenHMD contibutors. + // Sleep before we start seems to improve reliability. + // 300ms is what Windows seems to do, so cargo cult that. + os_nanosleep(U_TIME_1MS_IN_NS * 300); + + for (int i = 0; i < 4; i++) { + unsigned char cmd[64] = {0x50, 0x01}; + HID_SEND(hid, cmd, "loop"); + + unsigned char data[64] = {0x50}; + HID_GET(hid, data, "loop"); + + os_nanosleep(U_TIME_1MS_IN_NS * 10); // Sleep 10ms + } + + unsigned char data[64] = {0x09}; + HID_GET(hid, data, "data_1"); + + data[0] = 0x08; + HID_GET(hid, data, "data_2"); + + data[0] = 0x06; + HID_GET(hid, data, "data_3"); + + // Wake up the display. + unsigned char cmd[2] = {0x04, 0x01}; + HID_SEND(hid, cmd, "screen_on"); + + WMR_INFO(wh, "Sent activation report, sleeping for compositor."); + + /* + * Sleep so display completes power up and modes be enumerated. + * Two seconds seems to be needed, 1 was not enough. + */ + os_nanosleep(U_TIME_1MS_IN_NS * 2000); + + + return 0; +} + +static void +wmr_hmd_deactivate(struct wmr_hmd *wh) +{ + struct os_hid_device *hid = wh->hid_control_dev; + + /* Turn the screen off */ + unsigned char cmd[2] = {0x04, 0x00}; + HID_SEND(hid, cmd, "screen_off"); +} + +static void +wmr_hmd_update_inputs(struct xrt_device *xdev) +{ + struct wmr_hmd *wh = wmr_hmd(xdev); + (void)wh; +} + +static void +wmr_hmd_get_tracked_pose(struct xrt_device *xdev, + enum xrt_input_name name, + uint64_t at_timestamp_ns, + struct xrt_space_relation *out_relation) +{ + struct wmr_hmd *wh = wmr_hmd(xdev); + + if (name != XRT_INPUT_GENERIC_HEAD_POSE) { + WMR_ERROR(wh, "Unknown input name"); + return; + } + + // Clear relation. + U_ZERO(out_relation); + + os_mutex_lock(&wh->fusion_mutex); + out_relation->pose.orientation = wh->fusion.rot; + os_mutex_unlock(&wh->fusion_mutex); + + out_relation->relation_flags = (enum xrt_space_relation_flags)( // + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | // + XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); +} + +static void +wmr_hmd_get_view_pose(struct xrt_device *xdev, + struct xrt_vec3 *eye_relation, + uint32_t view_index, + struct xrt_pose *out_pose) +{ + struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; + bool adjust = (view_index == 0); + + pose.position.x = eye_relation->x / 2.0f; + pose.position.y = eye_relation->y / 2.0f; + pose.position.z = eye_relation->z / 2.0f; + + // Adjust for left/right while also making sure there aren't any -0.f. + if (pose.position.x > 0.0f && adjust) { + pose.position.x = -pose.position.x; + } + if (pose.position.y > 0.0f && adjust) { + pose.position.y = -pose.position.y; + } + if (pose.position.z > 0.0f && adjust) { + pose.position.z = -pose.position.z; + } + + *out_pose = pose; +} + +static void +wmr_hmd_destroy(struct xrt_device *xdev) +{ + struct wmr_hmd *wh = wmr_hmd(xdev); + + // Destroy the thread object. + os_thread_helper_destroy(&wh->oth); + + if (wh->hid_hololens_senors_dev != NULL) { + os_hid_destroy(wh->hid_hololens_senors_dev); + wh->hid_hololens_senors_dev = NULL; + } + + if (wh->hid_control_dev != NULL) { + wmr_hmd_deactivate(wh); + os_hid_destroy(wh->hid_control_dev); + wh->hid_control_dev = NULL; + } + + // Destroy the fusion. + m_imu_3dof_close(&wh->fusion); + + os_mutex_destroy(&wh->fusion_mutex); + + free(wh); +} + +struct xrt_device * +wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, enum u_logging_level ll) +{ + enum u_device_alloc_flags flags = + (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); + int ret = 0; + + struct wmr_hmd *wh = U_DEVICE_ALLOCATE(struct wmr_hmd, flags, 1, 0); + if (!wh) { + return NULL; + } + + // Populate the base members. + wh->base.update_inputs = wmr_hmd_update_inputs; + wh->base.get_tracked_pose = wmr_hmd_get_tracked_pose; + wh->base.get_view_pose = wmr_hmd_get_view_pose; + wh->base.destroy = wmr_hmd_destroy; + wh->base.name = XRT_DEVICE_GENERIC_HMD; + wh->base.device_type = XRT_DEVICE_TYPE_HMD; + wh->log_level = ll; + + wh->base.orientation_tracking_supported = true; + wh->base.position_tracking_supported = false; + wh->base.hand_tracking_supported = false; + wh->hid_hololens_senors_dev = hid_holo; + wh->hid_control_dev = hid_ctrl; + + snprintf(wh->base.str, XRT_DEVICE_NAME_LEN, "HP Reverb VR Headset"); + + // Mutex before thread. + ret = os_mutex_init(&wh->fusion_mutex); + if (ret != 0) { + WMR_ERROR(wh, "Failed to init mutex!"); + wmr_hmd_destroy(&wh->base); + wh = NULL; + return NULL; + } + + // Thread and other state. + ret = os_thread_helper_init(&wh->oth); + if (ret != 0) { + WMR_ERROR(wh, "Failed to init threading!"); + wmr_hmd_destroy(&wh->base); + wh = NULL; + return NULL; + } + + if (wmr_hmd_activate(wh) != 0) { + WMR_ERROR(wh, "Activation of HMD failed"); + wmr_hmd_destroy(&wh->base); + wh = NULL; + return NULL; + } + + // Switch on IMU on the HMD. + hololens_sensors_enable_imu(wh); + + + // Hand over hololens sensor device to reading thread. + ret = os_thread_helper_start(&wh->oth, wmr_run_thread, wh); + if (ret != 0) { + WMR_ERROR(wh, "Failed to start thread!"); + wmr_hmd_destroy(&wh->base); + wh = NULL; + return NULL; + } + + // Setup input. + wh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; + + // TODO: Read config file from HMD, provide guestimate values for now. + struct u_device_simple_info info; + info.display.w_pixels = 4320; + info.display.h_pixels = 2160; + info.display.w_meters = 0.13f; + info.display.h_meters = 0.07f; + info.lens_horizontal_separation_meters = 0.13f / 2.0f; + info.lens_vertical_position_meters = 0.07f / 2.0f; + info.views[0].fov = 85.0f * (M_PI / 180.0f); + info.views[1].fov = 85.0f * (M_PI / 180.0f); + + if (!u_device_setup_split_side_by_side(&wh->base, &info)) { + WMR_ERROR(wh, "Failed to setup basic HMD device info"); + wmr_hmd_destroy(&wh->base); + wh = NULL; + return NULL; + } + + m_imu_3dof_init(&wh->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); + + // Setup variable tracker. + u_var_add_root(wh, "WMR HMD", true); + u_var_add_gui_header(wh, &wh->gui.fusion, "3DoF Fusion"); + m_imu_3dof_add_vars(&wh->fusion, wh, ""); + u_var_add_gui_header(wh, &wh->gui.misc, "Misc"); + u_var_add_log_level(wh, &wh->log_level, "log_level"); + + // Distortion information, fills in xdev->compute_distortion(). + u_distortion_mesh_set_none(&wh->base); + + return &wh->base; +} diff --git a/src/xrt/drivers/wmr/wmr_hmd.h b/src/xrt/drivers/wmr/wmr_hmd.h new file mode 100644 index 000000000..6f0410140 --- /dev/null +++ b/src/xrt/drivers/wmr/wmr_hmd.h @@ -0,0 +1,104 @@ +// Copyright 2018, Philipp Zabel. +// Copyright 2020-2021, N Madsen. +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Interface to the WMR HMD driver code. + * @author Philipp Zabel + * @author nima01 + * @author Jakob Bornecrantz + * @ingroup drv_wmr + */ + +#pragma once + +#include "xrt/xrt_device.h" +#include "xrt/xrt_prober.h" +#include "os/os_threading.h" +#include "math/m_imu_3dof.h" +#include "util/u_logging.h" + +#include "wmr_protocol.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +enum rvb_g1_status_bits +{ + // clang-format off + REVERB_G1_STATUS_BIT_UNKNOWN_BIT_0 = (1 << 0), + REVERB_G1_STATUS_BIT_UNKNOWN_BIT_1 = (1 << 1), + REVERB_G1_STATUS_BIT_UNKNOWN_BIT_2 = (1 << 2), + REVERB_G1_STATUS_BIT_UNKNOWN_BIT_3 = (1 << 3), + REVERB_G1_STATUS_BIT_UNKNOWN_BIT_4 = (1 << 4), + REVERB_G1_STATUS_BIT_UNKNOWN_BIT_5 = (1 << 5), + REVERB_G1_STATUS_BIT_UNKNOWN_BIT_6 = (1 << 6), + REVERB_G1_STATUS_BIT_UNKNOWN_BIT_7 = (1 << 7), + // clang-format on +}; + +/*! + * @implements xrt_device + */ +struct wmr_hmd +{ + struct xrt_device base; + + //! Packet reading thread. + struct os_thread_helper oth; + + enum u_logging_level log_level; + + /*! + * This is the hololens sensor device, this is were we get all of the + * IMU data and read the config from. + * + * During start it is owned by the thread creating the device, after + * init it is owned by the reading thread, there is no mutex protecting + * this field as it's only used by the reading thread in @p oth. + */ + struct os_hid_device *hid_hololens_senors_dev; + struct os_hid_device *hid_control_dev; + + //! Latest raw IPD value from the device. + uint16_t raw_ipd; + + struct hololens_sensors_packet packet; + + struct xrt_vec3 raw_accel; + struct xrt_vec3 raw_gyro; + + struct os_mutex fusion_mutex; + //! Protected by @ref fusion_mutex. + struct m_imu_3dof fusion; + + struct + { + bool fusion; + bool misc; + } gui; +}; + +static inline struct wmr_hmd * +wmr_hmd(struct xrt_device *p) +{ + return (struct wmr_hmd *)p; +} + +struct xrt_device * +wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, enum u_logging_level ll); + +#define WMR_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->log_level, __VA_ARGS__) +#define WMR_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->log_level, __VA_ARGS__) +#define WMR_INFO(d, ...) U_LOG_XDEV_IFL_I(&d->base, d->log_level, __VA_ARGS__) +#define WMR_WARN(d, ...) U_LOG_XDEV_IFL_W(&d->base, d->log_level, __VA_ARGS__) +#define WMR_ERROR(d, ...) U_LOG_XDEV_IFL_E(&d->base, d->log_level, __VA_ARGS__) + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/drivers/wmr/wmr_interface.h b/src/xrt/drivers/wmr/wmr_interface.h new file mode 100644 index 000000000..2969b8268 --- /dev/null +++ b/src/xrt/drivers/wmr/wmr_interface.h @@ -0,0 +1,48 @@ +// Copyright 2020-2021, N Madsen. +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Interface to the WMR driver. + * @author nima01 + * @author Jakob Bornecrantz + * @ingroup drv_wmr + */ + +#pragma once + + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @defgroup drv_wmr + * @ingroup drv + * + * @brief Windows Mixed Reality driver. + */ + +/*! + * Probing function for Windows Mixed Reality devices. + * + * @ingroup drv_wmr + */ +int +wmr_found(struct xrt_prober *xp, + struct xrt_prober_device **devices, + size_t num_devices, + size_t index, + cJSON *attached_data, + struct xrt_device **out_xdev); + +/*! + * @dir drivers/wmr + * + * @brief @ref drv_wmr files. + */ + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/drivers/wmr/wmr_prober.c b/src/xrt/drivers/wmr/wmr_prober.c new file mode 100644 index 000000000..bb8796220 --- /dev/null +++ b/src/xrt/drivers/wmr/wmr_prober.c @@ -0,0 +1,160 @@ +// Copyright 2020-2021, N Madsen. +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief WMR prober code. + * @author nima01 + * @author Jakob Bornecrantz + * @ingroup drv_wmr + */ + +#include "xrt/xrt_prober.h" + +#include "util/u_misc.h" +#include "util/u_debug.h" +#include "util/u_logging.h" + +#include "wmr_interface.h" +#include "wmr_hmd.h" +#include "wmr_common.h" + +#include +#include +#include + + +/* + * + * Defines & structs. + * + */ + +DEBUG_GET_ONCE_LOG_OPTION(wmr_log, "WMR_LOG", U_LOGGING_INFO) + + +/* + * + * Functions. + * + */ + +static bool +check_and_get_interface_hp(struct xrt_prober_device *device, int *out_interface) +{ + if (device->product_id != REVERB_G1_PID && device->product_id != REVERB_G2_PID) { + return false; + } + + *out_interface = 0; + + return true; +} + +static bool +find_control_device(struct xrt_prober *xp, + struct xrt_prober_device **devices, + size_t num_devices, + enum u_logging_level ll, + struct xrt_prober_device **out_device, + int *out_interface) +{ + struct xrt_prober_device *dev = NULL; + int interface = 0; + + for (size_t i = 0; i < num_devices; i++) { + bool match = false; + + if (devices[i]->bus != XRT_BUS_TYPE_USB) { + continue; + } + + switch (devices[i]->vendor_id) { + case HP_VID: match = check_and_get_interface_hp(devices[i], &interface); break; + default: break; + } + + if (!match) { + continue; + } + + if (dev != NULL) { + U_LOG_IFL_W(ll, "Found multiple control devices, using the last."); + } + dev = devices[i]; + } + + unsigned char m_str[256] = {0}; + unsigned char p_str[256] = {0}; + xrt_prober_get_string_descriptor(xp, dev, XRT_PROBER_STRING_MANUFACTURER, m_str, sizeof(m_str)); + xrt_prober_get_string_descriptor(xp, dev, XRT_PROBER_STRING_PRODUCT, p_str, sizeof(p_str)); + + U_LOG_IFL_D(ll, "Found control device '%s' '%s' (%04X:%04X)", p_str, m_str, dev->vendor_id, dev->product_id); + + *out_device = dev; + *out_interface = interface; + + return dev != NULL; +} + + +/* + * + * Exported functions. + * + */ + +int +wmr_found(struct xrt_prober *xp, + struct xrt_prober_device **devices, + size_t num_devices, + size_t index, + cJSON *attached_data, + struct xrt_device **out_xdev) +{ + enum u_logging_level ll = debug_get_log_option_wmr_log(); + + struct xrt_prober_device *dev_holo = devices[index]; + struct xrt_prober_device *dev_ctrl = NULL; + int interface_holo = 2; + int interface_ctrl = 0; + + unsigned char buf[256] = {0}; + int result = xrt_prober_get_string_descriptor(xp, dev_holo, XRT_PROBER_STRING_PRODUCT, buf, sizeof(buf)); + + if (!xrt_prober_match_string(xp, dev_holo, XRT_PROBER_STRING_MANUFACTURER, MS_HOLOLENS_MANUFACTURER_STRING) || + !xrt_prober_match_string(xp, dev_holo, XRT_PROBER_STRING_PRODUCT, MS_HOLOLENS_PRODUCT_STRING)) { + U_LOG_IFL_E(ll, "HoloLens Sensors manufacturer or product strings did not match."); + return -1; + } + + if (!find_control_device(xp, devices, num_devices, ll, &dev_ctrl, &interface_ctrl)) { + U_LOG_IFL_E(ll, + "Did not find companion control device." + "\n\tCurrently only Reverb G1 and G2 is supported"); + return -1; + } + + struct os_hid_device *hid_holo = NULL; + result = xrt_prober_open_hid_interface(xp, dev_holo, interface_holo, &hid_holo); + if (result != 0) { + U_LOG_IFL_E(ll, "Failed to open HoloLens Sensors HID interface"); + return -1; + } + + struct os_hid_device *hid_ctrl = NULL; + result = xrt_prober_open_hid_interface(xp, dev_ctrl, interface_ctrl, &hid_ctrl); + if (result != 0) { + U_LOG_IFL_E(ll, "Failed to open HoloLens Sensors HID interface"); + return -1; + } + + struct xrt_device *p = wmr_hmd_create(hid_holo, hid_ctrl, ll); + if (!p) { + U_LOG_IFL_E(ll, "Failed to create Windows Mixed Reality device"); + return -1; + } + + *out_xdev = p; + return 1; +} diff --git a/src/xrt/drivers/wmr/wmr_protocol.c b/src/xrt/drivers/wmr/wmr_protocol.c new file mode 100644 index 000000000..3334cd5bc --- /dev/null +++ b/src/xrt/drivers/wmr/wmr_protocol.c @@ -0,0 +1,60 @@ +// Copyright 2018, Philipp Zabel. +// Copyright 2020-2021, N Madsen. +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief WMR and MS HoloLens protocol helpers implementation. + * @author Philipp Zabel + * @author nima01 + * @ingroup drv_wmr + */ + +#include "wmr_protocol.h" + + +/* + * + * WMR and MS HoloLens Sensors protocol helpers + * + */ + +void +vec3_from_hololens_accel(int32_t sample[3][4], int i, struct xrt_vec3 *out_vec) +{ + out_vec->x = (float)sample[0][i] * 0.001f * -1.0f; + out_vec->y = (float)sample[1][i] * 0.001f * -1.0f; + out_vec->z = (float)sample[2][i] * 0.001f * -1.0f; +} + +void +vec3_from_hololens_gyro(int16_t sample[3][32], int i, struct xrt_vec3 *out_vec) +{ + out_vec->x = (float)(sample[0][8 * i + 0] + // + sample[0][8 * i + 1] + // + sample[0][8 * i + 2] + // + sample[0][8 * i + 3] + // + sample[0][8 * i + 4] + // + sample[0][8 * i + 5] + // + sample[0][8 * i + 6] + // + sample[0][8 * i + 7]) * + 0.001f * 0.125f; + out_vec->y = (float)(sample[1][8 * i + 0] + // + sample[1][8 * i + 1] + // + sample[1][8 * i + 2] + // + sample[1][8 * i + 3] + // + sample[1][8 * i + 4] + // + sample[1][8 * i + 5] + // + sample[1][8 * i + 6] + // + sample[1][8 * i + 7]) * + 0.001f * -0.125f; + out_vec->z = (float)(sample[2][8 * i + 0] + // + sample[2][8 * i + 1] + // + sample[2][8 * i + 2] + // + sample[2][8 * i + 3] + // + sample[2][8 * i + 4] + // + sample[2][8 * i + 5] + // + sample[2][8 * i + 6] + // + sample[2][8 * i + 7]) * + 0.001f * -0.125f; +} diff --git a/src/xrt/drivers/wmr/wmr_protocol.h b/src/xrt/drivers/wmr/wmr_protocol.h new file mode 100644 index 000000000..608a67d4c --- /dev/null +++ b/src/xrt/drivers/wmr/wmr_protocol.h @@ -0,0 +1,126 @@ +// Copyright 2018, Philipp Zabel. +// Copyright 2020-2021, N Madsen. +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief WMR and MS HoloLens protocol constants, structures and helpers header + * @author Philipp Zabel + * @author nima01 + * @ingroup drv_wmr + */ + +#pragma once + +#include "math/m_vec2.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! + * WMR and MS HoloLens Sensors protocol constants and structures + * + * @ingroup drv_wmr + * @{ + */ + +#define WMR_FEATURE_BUFFER_SIZE 497 +#define WMR_MS_HOLOLENS_NS_PER_TICK 100 + +#define WMR_MS_HOLOLENS_MSG_SENSORS 0x01 +#define WMR_MS_HOLOLENS_MSG_CONTROL 0x02 +#define WMR_MS_HOLOLENS_MSG_DEBUG 0x03 +#define WMR_MS_HOLOLENS_MSG_UNKNOWN_05 0x05 +#define WMR_MS_HOLOLENS_MSG_UNKNOWN_06 0x06 +#define WMR_MS_HOLOLENS_MSG_UNKNOWN_0E 0x0E +#define WMR_MS_HOLOLENS_MSG_UNKNOWN_17 0x17 + +#define WMR_CONTROL_MSG_IPD_VALUE 0x01 +#define WMR_CONTROL_MSG_UNKNOWN_05 0x05 + +static const unsigned char hololens_sensors_imu_on[64] = {0x02, 0x07}; + +struct hololens_sensors_packet +{ + uint8_t id; + uint16_t temperature[4]; + uint64_t gyro_timestamp[4]; + int16_t gyro[3][32]; + uint64_t accel_timestamp[4]; + int32_t accel[3][4]; + uint64_t video_timestamp[4]; +}; + +/*! + * @} + */ + + +/*! + * WMR and MS HoloLens Sensors protocol helpers + * + * @ingroup drv_wmr + * @{ + */ + +void +vec3_from_hololens_accel(int32_t sample[3][4], int i, struct xrt_vec3 *out_vec); + +void +vec3_from_hololens_gyro(int16_t sample[3][32], int i, struct xrt_vec3 *out_vec); + + +static inline uint8_t +read8(const unsigned char **buffer) +{ + uint8_t ret = **buffer; + *buffer += 1; + return ret; +} + +static inline int16_t +read16(const unsigned char **buffer) +{ + int16_t ret = (*(*buffer + 0) << 0) | // + (*(*buffer + 1) << 8); + *buffer += 2; + return ret; +} + +static inline int32_t +read32(const unsigned char **buffer) +{ + int32_t ret = (*(*buffer + 0) << 0) | // + (*(*buffer + 1) << 8) | // + (*(*buffer + 2) << 16) | // + (*(*buffer + 3) << 24); + *buffer += 4; + return ret; +} + +static inline uint64_t +read64(const unsigned char **buffer) +{ + uint64_t ret = ((uint64_t) * (*buffer + 0) << 0) | // + ((uint64_t) * (*buffer + 1) << 8) | // + ((uint64_t) * (*buffer + 2) << 16) | // + ((uint64_t) * (*buffer + 3) << 24) | // + ((uint64_t) * (*buffer + 4) << 32) | // + ((uint64_t) * (*buffer + 5) << 40) | // + ((uint64_t) * (*buffer + 6) << 48) | // + ((uint64_t) * (*buffer + 7) << 56); + *buffer += 8; + return ret; +} + +/*! + * @} + */ + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/targets/common/CMakeLists.txt b/src/xrt/targets/common/CMakeLists.txt index 9095da43e..0a31ff126 100644 --- a/src/xrt/targets/common/CMakeLists.txt +++ b/src/xrt/targets/common/CMakeLists.txt @@ -102,6 +102,11 @@ if(XRT_BUILD_DRIVER_QWERTY) target_link_libraries(target_lists PRIVATE drv_qwerty) endif() +if(XRT_BUILD_DRIVER_WMR) + target_link_libraries(target_lists PRIVATE drv_wmr) +endif() + + #### # Instance # diff --git a/src/xrt/targets/common/target_lists.c b/src/xrt/targets/common/target_lists.c index 4413fbe62..20e825c6b 100644 --- a/src/xrt/targets/common/target_lists.c +++ b/src/xrt/targets/common/target_lists.c @@ -78,6 +78,12 @@ #include "qwerty/qwerty_interface.h" #endif +#ifdef XRT_BUILD_DRIVER_WMR +#include "wmr/wmr_interface.h" +#include "wmr/wmr_common.h" +#endif + + /*! * Each entry should be a vendor ID (VID), product ID (PID), a "found" function, * and a string literal name. @@ -121,6 +127,10 @@ struct xrt_prober_entry target_entry_list[] = { {ULV2_VID, ULV2_PID, ulv2_found, "Leap Motion Controller", "ulv2"}, #endif +#ifdef XRT_BUILD_DRIVER_WMR + {MICROSOFT_VID, HOLOLENS_SENSORS_PID, wmr_found, "Microsoft HoloLens Sensors", "wmr"}, +#endif // XRT_BUILD_DRIVER_WMR + {0x0000, 0x0000, NULL, NULL, NULL}, // Terminate }; diff --git a/src/xrt/targets/meson.build b/src/xrt/targets/meson.build index 9ac834703..4bbbdcc5d 100644 --- a/src/xrt/targets/meson.build +++ b/src/xrt/targets/meson.build @@ -61,6 +61,10 @@ if 'vive' in drivers driver_libs += [lib_drv_vive] endif +if 'wmr' in drivers + driver_libs += [lib_drv_wmr] +endif + if 'survive' in drivers driver_libs += [lib_drv_survive] endif From 885a668a0356550f074fdf2a678e2a07c25fc94c Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Tue, 20 Apr 2021 12:43:56 +0200 Subject: [PATCH 402/883] d/oh: Fix number of inputs for generic controller fixes memory corruption --- src/xrt/drivers/ohmd/oh_device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c index 89b626bee..a3b096e9b 100644 --- a/src/xrt/drivers/ohmd/oh_device.c +++ b/src/xrt/drivers/ohmd/oh_device.c @@ -1051,7 +1051,8 @@ create_controller(ohmd_context *ctx, int device_idx, int device_flags, enum xrt_ bool oculus_touch = false; - int num_inputs = 1; + // khronos simple controller has 4 inputs + int num_inputs = 4; int num_outputs = 0; if (strcmp(prod, "Rift (CV1): Right Controller") == 0 || strcmp(prod, "Rift (CV1): Left Controller") == 0 || From 341fa45eda5a07ab700542e80727878d1a9ae404 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Tue, 20 Apr 2021 16:03:44 +0200 Subject: [PATCH 403/883] ipc: Print socket filename and errno in error message --- src/xrt/ipc/client/ipc_client_instance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/ipc/client/ipc_client_instance.c b/src/xrt/ipc/client/ipc_client_instance.c index a94d4d2ce..333a9f448 100644 --- a/src/xrt/ipc/client/ipc_client_instance.c +++ b/src/xrt/ipc/client/ipc_client_instance.c @@ -141,7 +141,7 @@ ipc_connect(struct ipc_connection *ipc_c) ret = connect(socket, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { - IPC_ERROR(ipc_c, "Socket Connect error!"); + IPC_ERROR(ipc_c, "Failed to connec to socket %s: %s!", sock_file, strerror(errno)); close(socket); return false; } From 4488699e555b9a19431a9001635036b0c1cacddf Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 21 Apr 2021 11:13:45 -0500 Subject: [PATCH 404/883] d/ultraleap_v2: Add missing copyright/license header, reflow, and fix markdownlint warnings. --- src/xrt/drivers/ultraleap_v2/readme.MD | 12 --------- src/xrt/drivers/ultraleap_v2/readme.md | 36 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 12 deletions(-) delete mode 100644 src/xrt/drivers/ultraleap_v2/readme.MD create mode 100644 src/xrt/drivers/ultraleap_v2/readme.md diff --git a/src/xrt/drivers/ultraleap_v2/readme.MD b/src/xrt/drivers/ultraleap_v2/readme.MD deleted file mode 100644 index 692d4ac02..000000000 --- a/src/xrt/drivers/ultraleap_v2/readme.MD +++ /dev/null @@ -1,12 +0,0 @@ -## Building -To build you need `Leap.h` and `LeapMath.h` in `/usr/local/include`; and `libLeap.so` in `/usr/local/lib`, and this should automatically build. - -## Running -To have the ultraleap driver successfully initialize, you need to have the Leap Motion Controller plugged in, and `leapd` running. Running `sudo leapd` in another terminal works but it may be slightly more convenient to have it run as a systemd service. - -## Configuring -Presumably, you're using this driver because you want to stick the Leap Motion Controller on the front of your HMD and have it track your hands. - -If you don't have a config file at ~/.config/monado/config_v0.json (or wherever you set `XDG_CONFIG_DIR`), your tracked hands will show up near the tracking origin and not move around with your HMD, which is probably not what you want. - -Instead you probably want to configure Monado to make your Leap Motion Controller-tracked hands follow around your HMD. There's an example of how to do this with North Star in `doc/example_configs/config_v0.json.northstar_lonestar`. If you're using a North Star headset, that should work but unless you're using the Lone Star NS variant you'll need to edit the offsets. If you're using some other HMD you'll have to edit the `tracker_device_serial` to be your HMD serial, and your own offsets. \ No newline at end of file diff --git a/src/xrt/drivers/ultraleap_v2/readme.md b/src/xrt/drivers/ultraleap_v2/readme.md new file mode 100644 index 000000000..7cb0d0b79 --- /dev/null +++ b/src/xrt/drivers/ultraleap_v2/readme.md @@ -0,0 +1,36 @@ +# About Monado's UltraLeap driver + + + +## Building + +To build you need `Leap.h` and `LeapMath.h` in `/usr/local/include`; and +`libLeap.so` in `/usr/local/lib`, and this should automatically build. + +## Running + +To have the ultraleap driver successfully initialize, you need to have the Leap +Motion Controller plugged in, and `leapd` running. Running `sudo leapd` in +another terminal works but it may be slightly more convenient to have it run as +a systemd service. + +## Configuring + +Presumably, you're using this driver because you want to stick the Leap Motion +Controller on the front of your HMD and have it track your hands. + +If you don't have a config file at `~/.config/monado/config_v0.json` (or +wherever you set `XDG_CONFIG_DIR`), your tracked hands will show up near the +tracking origin and not move around with your HMD, which is probably not what +you want. + +Instead you probably want to configure Monado to make your Leap Motion +Controller-tracked hands follow around your HMD. There's an example of how to do +this with North Star in `doc/example_configs/config_v0.json.northstar_lonestar`. +If you're using a North Star headset, that should work but unless you're using +the Lone Star NS variant you'll need to edit the offsets. If you're using some +other HMD you'll have to edit the `tracker_device_serial` to be your HMD serial, +and your own offsets. From 6fb2241948a045942c7e7bb64bee712c3abf5123 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 21 Apr 2021 11:19:31 -0500 Subject: [PATCH 405/883] doc: Add license sidecar file for config_v0.json.northstar_lonestar example config. --- doc/example_configs/config_v0.json.northstar_lonestar.license | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 doc/example_configs/config_v0.json.northstar_lonestar.license diff --git a/doc/example_configs/config_v0.json.northstar_lonestar.license b/doc/example_configs/config_v0.json.northstar_lonestar.license new file mode 100644 index 000000000..c7f54ea2c --- /dev/null +++ b/doc/example_configs/config_v0.json.northstar_lonestar.license @@ -0,0 +1,3 @@ +Copyright 2021, Moses Turner +Copyright 2021, Collabora, Ltd. +SPDX-License-Identifier: CC0-1.0 From bc4661aa48ae7b6645789067338e17eabbbb0d90 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 22 Apr 2021 03:25:01 +1000 Subject: [PATCH 406/883] wmr: Don't start reading thread until setup is complete. Make sure the headset struct is fully configured before starting the reading thread, otherwise we can get a crash if an IMU update arrives for processing before the 3dof fusion is ready. --- src/xrt/drivers/wmr/wmr_hmd.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index e14a42629..b8ff311f2 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -490,16 +490,6 @@ wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, e // Switch on IMU on the HMD. hololens_sensors_enable_imu(wh); - - // Hand over hololens sensor device to reading thread. - ret = os_thread_helper_start(&wh->oth, wmr_run_thread, wh); - if (ret != 0) { - WMR_ERROR(wh, "Failed to start thread!"); - wmr_hmd_destroy(&wh->base); - wh = NULL; - return NULL; - } - // Setup input. wh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; @@ -533,5 +523,14 @@ wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, e // Distortion information, fills in xdev->compute_distortion(). u_distortion_mesh_set_none(&wh->base); + // Hand over hololens sensor device to reading thread. + ret = os_thread_helper_start(&wh->oth, wmr_run_thread, wh); + if (ret != 0) { + WMR_ERROR(wh, "Failed to start thread!"); + wmr_hmd_destroy(&wh->base); + wh = NULL; + return NULL; + } + return &wh->base; } From 7af531a6c565f40735c3f8925f046fc233246804 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sun, 18 Apr 2021 02:34:49 +0100 Subject: [PATCH 407/883] c/main: Refactor so we can do an early acquire --- src/xrt/compositor/main/comp_renderer.c | 77 +++++++++++++++++-------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index 7fbeb4c1e..1535744b9 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -63,7 +63,10 @@ struct comp_renderer //! @{ //! Index of the current buffer/image - uint32_t current_buffer; + int32_t acquired_buffer; + + //! Which buffer was last submitted and has a fence pending. + int32_t fenced_buffer; /*! * Array of "renderings" equal in size to the number of comp_target images. @@ -335,7 +338,8 @@ renderer_close_renderings_and_fences(struct comp_renderer *r) } r->num_buffers = 0; - r->current_buffer = 0; + r->acquired_buffer = -1; + r->fenced_buffer = -1; } //! @pre comp_target_check_ready(r->c->target) @@ -440,7 +444,8 @@ renderer_create(struct comp_renderer *r, struct comp_compositor *c) r->c = c; r->settings = &c->settings; - r->current_buffer = 0; + r->acquired_buffer = -1; + r->fenced_buffer = -1; r->queue = VK_NULL_HANDLE; r->semaphores.present_complete = VK_NULL_HANDLE; r->semaphores.render_complete = VK_NULL_HANDLE; @@ -460,13 +465,19 @@ renderer_wait_for_last_fence(struct comp_renderer *r) { COMP_TRACE_MARKER(); + if (r->fenced_buffer < 0) { + return; + } + struct vk_bundle *vk = &r->c->vk; VkResult ret; - ret = vk->vkWaitForFences(vk->device, 1, &r->fences[r->current_buffer], VK_TRUE, UINT64_MAX); + ret = vk->vkWaitForFences(vk->device, 1, &r->fences[r->fenced_buffer], VK_TRUE, UINT64_MAX); if (ret != VK_SUCCESS) { COMP_ERROR(r->c, "vkWaitForFences: %s", vk_result_string(ret)); } + + r->fenced_buffer = -1; } static void @@ -481,13 +492,15 @@ renderer_submit_queue(struct comp_renderer *r) VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, }; - ret = vk->vkWaitForFences(vk->device, 1, &r->fences[r->current_buffer], VK_TRUE, UINT64_MAX); - if (ret != VK_SUCCESS) - COMP_ERROR(r->c, "vkWaitForFences: %s", vk_result_string(ret)); + // Wait for the last fence, if any. + renderer_wait_for_last_fence(r); + assert(r->fenced_buffer < 0); - ret = vk->vkResetFences(vk->device, 1, &r->fences[r->current_buffer]); - if (ret != VK_SUCCESS) + assert(r->acquired_buffer >= 0); + ret = vk->vkResetFences(vk->device, 1, &r->fences[r->acquired_buffer]); + if (ret != VK_SUCCESS) { COMP_ERROR(r->c, "vkResetFences: %s", vk_result_string(ret)); + } VkSubmitInfo comp_submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, @@ -495,15 +508,18 @@ renderer_submit_queue(struct comp_renderer *r) .pWaitSemaphores = &r->semaphores.present_complete, .pWaitDstStageMask = stage_flags, .commandBufferCount = 1, - .pCommandBuffers = &r->rrs[r->current_buffer].cmd, + .pCommandBuffers = &r->rrs[r->acquired_buffer].cmd, .signalSemaphoreCount = 1, .pSignalSemaphores = &r->semaphores.render_complete, }; - ret = vk_locked_submit(vk, r->queue, 1, &comp_submit_info, r->fences[r->current_buffer]); + ret = vk_locked_submit(vk, r->queue, 1, &comp_submit_info, r->fences[r->acquired_buffer]); if (ret != VK_SUCCESS) { COMP_ERROR(r->c, "vkQueueSubmit: %s", vk_result_string(ret)); } + + // This buffer now have a pending fence. + r->fenced_buffer = r->acquired_buffer; } static void @@ -554,13 +570,16 @@ renderer_acquire_swapchain_image(struct comp_renderer *r) { COMP_TRACE_MARKER(); + uint32_t buffer_index = 0; VkResult ret; + assert(r->acquired_buffer < 0); + if (!renderer_ensure_images_and_renderings(r, false)) { // Not ready yet. return; } - ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &r->current_buffer); + ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &buffer_index); if ((ret == VK_ERROR_OUT_OF_DATE_KHR) || (ret == VK_SUBOPTIMAL_KHR)) { COMP_DEBUG(r->c, "Received %s.", vk_result_string(ret)); @@ -573,13 +592,15 @@ renderer_acquire_swapchain_image(struct comp_renderer *r) return; } /* Acquire image again to silence validation error */ - ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &r->current_buffer); + ret = comp_target_acquire(r->c->target, r->semaphores.present_complete, &buffer_index); if (ret != VK_SUCCESS) { COMP_ERROR(r->c, "comp_target_acquire: %s", vk_result_string(ret)); } } else if (ret != VK_SUCCESS) { COMP_ERROR(r->c, "comp_target_acquire: %s", vk_result_string(ret)); } + + r->acquired_buffer = buffer_index; } static void @@ -604,8 +625,15 @@ renderer_present_swapchain_image(struct comp_renderer *r, uint64_t desired_prese VkResult ret; - ret = comp_target_present(r->c->target, r->queue, r->current_buffer, r->semaphores.render_complete, - desired_present_time_ns, present_slop_ns); + ret = comp_target_present( // + r->c->target, // + r->queue, // + r->acquired_buffer, // + r->semaphores.render_complete, // + desired_present_time_ns, // + present_slop_ns); // + r->acquired_buffer = -1; + if (ret == VK_ERROR_OUT_OF_DATE_KHR) { renderer_resize(r); return; @@ -861,8 +889,10 @@ comp_renderer_draw(struct comp_renderer *r) comp_target_update_timings(ct); - // Ensures that renderings are created. - renderer_acquire_swapchain_image(r); + if (r->acquired_buffer < 0) { + // Ensures that renderings are created. + renderer_acquire_swapchain_image(r); + } comp_target_update_timings(ct); @@ -881,12 +911,6 @@ comp_renderer_draw(struct comp_renderer *r) // Clear the frame. c->frame.rendering.id = -1; - /* - * Wait for the last fence to complete so we know that the GPU is done, - * if there is a big GPU bubble this lets us detect that. - */ - renderer_wait_for_last_fence(r); - /* * This fixes a lot of validation issues as it makes sure that the * command buffer has completed and all resources referred by it can @@ -896,6 +920,13 @@ comp_renderer_draw(struct comp_renderer *r) */ renderer_wait_gpu_idle(r); + /* + * For direct mode this makes us wait until the last frame has been + * actually shown to the user, this avoids us missing that we have + * missed a frame and miss-predicting the next frame. + */ + renderer_acquire_swapchain_image(r); + comp_target_update_timings(ct); } From 5105148c45d8b94543a40ad0571125ec6f2389e8 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 16 Apr 2021 14:44:40 +0100 Subject: [PATCH 408/883] xrt: Correct error number --- src/xrt/include/xrt/xrt_results.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/include/xrt/xrt_results.h b/src/xrt/include/xrt/xrt_results.h index d50f37912..30aebc4b7 100644 --- a/src/xrt/include/xrt/xrt_results.h +++ b/src/xrt/include/xrt/xrt_results.h @@ -56,7 +56,7 @@ typedef enum xrt_result * The given config was EGL_NO_CONFIG_KHR and EGL_KHR_no_config_context * is not supported by the display. */ - XRT_ERROR_EGL_CONFIG_MISSING = -12, + XRT_ERROR_EGL_CONFIG_MISSING = -13, /*! * Failed to initialize threading components. */ From 576ff7d2528f743d3d9d20d16060dd402c9f6323 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 16 Apr 2021 14:45:05 +0100 Subject: [PATCH 409/883] xrt: Add new IPC session not created error --- src/xrt/include/xrt/xrt_results.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xrt/include/xrt/xrt_results.h b/src/xrt/include/xrt/xrt_results.h index 30aebc4b7..ac16ce9ae 100644 --- a/src/xrt/include/xrt/xrt_results.h +++ b/src/xrt/include/xrt/xrt_results.h @@ -61,4 +61,9 @@ typedef enum xrt_result * Failed to initialize threading components. */ XRT_ERROR_THREADING_INIT_FAILURE = -14, + /*! + * The client has not created a session on this IPC connection, + * which is needed for the given command. + */ + XRT_ERROR_IPC_SESSION_NOT_CREATED = -15, } xrt_result_t; From c49abf9103c2a6987798a3a6e4db02f8394ff470 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 16 Apr 2021 15:06:24 +0100 Subject: [PATCH 410/883] ipc: Print out all error messages, and values --- src/xrt/ipc/client/ipc_client_compositor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/ipc/client/ipc_client_compositor.c b/src/xrt/ipc/client/ipc_client_compositor.c index 86bec71d7..5a890288d 100644 --- a/src/xrt/ipc/client/ipc_client_compositor.c +++ b/src/xrt/ipc/client/ipc_client_compositor.c @@ -116,8 +116,8 @@ compositor_disconnect(struct ipc_connection *ipc_c) #define IPC_CALL_CHK(call) \ xrt_result_t res = (call); \ - if (res == XRT_ERROR_IPC_FAILURE) { \ - IPC_ERROR(icc->ipc_c, "Call error '%s'!", __func__); \ + if (res != XRT_SUCCESS) { \ + IPC_ERROR(icc->ipc_c, "Call error '%i'!", res); \ } static xrt_result_t From 3953321129892fb0e9ead32caded4509168c589e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 16 Apr 2021 15:14:19 +0100 Subject: [PATCH 411/883] ipc: Return error from ipc_call_session_create in create_native_compositor --- src/xrt/ipc/client/ipc_client_compositor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xrt/ipc/client/ipc_client_compositor.c b/src/xrt/ipc/client/ipc_client_compositor.c index 5a890288d..136b62ae5 100644 --- a/src/xrt/ipc/client/ipc_client_compositor.c +++ b/src/xrt/ipc/client/ipc_client_compositor.c @@ -822,6 +822,10 @@ ipc_syscomp_create_native_compositor(struct xrt_system_compositor *xsc, // Needs to be done before init. IPC_CALL_CHK(ipc_call_session_create(icc->ipc_c, xsi)); + if (res != XRT_SUCCESS) { + return res; + } + // Needs to be done after session create call. ipc_compositor_init(icc, out_xcn); From 5627849135e3674ccd59a690724a9a42a1f1e2c6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 16 Apr 2021 15:17:53 +0100 Subject: [PATCH 412/883] ipc: More trace_marker functions --- src/xrt/ipc/server/ipc_server_handler.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 001e82f13..9ee273d63 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -75,10 +75,13 @@ ipc_handle_instance_get_shm_fd(volatile struct ipc_client_state *ics, xrt_shmem_handle_t *out_handles, uint32_t *out_num_handles) { + IPC_TRACE_MARKER(); + assert(max_num_handles >= 1); out_handles[0] = ics->server->ism_handle; *out_num_handles = 1; + return XRT_SUCCESS; } @@ -86,6 +89,8 @@ xrt_result_t ipc_handle_system_compositor_get_info(volatile struct ipc_client_state *ics, struct xrt_system_compositor_info *out_info) { + IPC_TRACE_MARKER(); + *out_info = ics->server->xsysc->info; return XRT_SUCCESS; @@ -94,6 +99,8 @@ ipc_handle_system_compositor_get_info(volatile struct ipc_client_state *ics, xrt_result_t ipc_handle_session_create(volatile struct ipc_client_state *ics, const struct xrt_session_info *xsi) { + IPC_TRACE_MARKER(); + struct xrt_compositor_native *xcn = NULL; xrt_result_t xret = xrt_syscomp_create_native_compositor(ics->server->xsysc, xsi, &xcn); @@ -132,6 +139,8 @@ ipc_handle_session_end(volatile struct ipc_client_state *ics) xrt_result_t ipc_handle_compositor_get_info(volatile struct ipc_client_state *ics, struct xrt_compositor_info *out_info) { + IPC_TRACE_MARKER(); + *out_info = ics->xc->info; return XRT_SUCCESS; From 741dcbdf40e1271cc42f629928ef5d175c743a2d Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 16 Apr 2021 15:21:10 +0100 Subject: [PATCH 413/883] ipc: Return XRT_ERROR_IPC_SESSION_NOT_CREATED if so is the case --- src/xrt/ipc/server/ipc_server_handler.c | 52 +++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 9ee273d63..3d9ecc826 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -125,6 +125,10 @@ ipc_handle_session_begin(volatile struct ipc_client_state *ics) { IPC_TRACE_MARKER(); + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + return xrt_comp_begin_session(ics->xc, 0); } @@ -133,6 +137,10 @@ ipc_handle_session_end(volatile struct ipc_client_state *ics) { IPC_TRACE_MARKER(); + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + return xrt_comp_end_session(ics->xc); } @@ -141,6 +149,10 @@ ipc_handle_compositor_get_info(volatile struct ipc_client_state *ics, struct xrt { IPC_TRACE_MARKER(); + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + *out_info = ics->xc->info; return XRT_SUCCESS; @@ -155,6 +167,10 @@ ipc_handle_compositor_predict_frame(volatile struct ipc_client_state *ics, { IPC_TRACE_MARKER(); + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + /* * We use this to signal that the session has started, this is needed * to make this client/session active/visible/focused. @@ -176,6 +192,10 @@ ipc_handle_compositor_wait_woke(volatile struct ipc_client_state *ics, int64_t f { IPC_TRACE_MARKER(); + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + return xrt_comp_mark_frame(ics->xc, frame_id, XRT_COMPOSITOR_FRAME_POINT_WOKE, os_monotonic_get_ns()); } @@ -184,6 +204,10 @@ ipc_handle_compositor_begin_frame(volatile struct ipc_client_state *ics, int64_t { IPC_TRACE_MARKER(); + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + return xrt_comp_begin_frame(ics->xc, frame_id); } @@ -192,6 +216,10 @@ ipc_handle_compositor_discard_frame(volatile struct ipc_client_state *ics, int64 { IPC_TRACE_MARKER(); + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + return xrt_comp_discard_frame(ics->xc, frame_id); } @@ -463,6 +491,10 @@ ipc_handle_compositor_layer_sync(volatile struct ipc_client_state *ics, { IPC_TRACE_MARKER(); + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + struct ipc_shared_memory *ism = ics->server->ism; struct ipc_layer_slot *slot = &ism->slots[slot_id]; xrt_graphics_sync_handle_t sync_handle = XRT_GRAPHICS_SYNC_HANDLE_INVALID; @@ -513,6 +545,10 @@ ipc_handle_compositor_poll_events(volatile struct ipc_client_state *ics, union x { IPC_TRACE_MARKER(); + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + return xrt_comp_poll_events(ics->xc, out_xce); } @@ -719,6 +755,10 @@ ipc_handle_swapchain_import(volatile struct ipc_client_state *ics, xrt_result_t ipc_handle_swapchain_wait_image(volatile struct ipc_client_state *ics, uint32_t id, uint64_t timeout, uint32_t index) { + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + //! @todo Look up the index. uint32_t sc_index = id; struct xrt_swapchain *xsc = ics->xscs[sc_index]; @@ -731,6 +771,10 @@ ipc_handle_swapchain_wait_image(volatile struct ipc_client_state *ics, uint32_t xrt_result_t ipc_handle_swapchain_acquire_image(volatile struct ipc_client_state *ics, uint32_t id, uint32_t *out_index) { + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + //! @todo Look up the index. uint32_t sc_index = id; struct xrt_swapchain *xsc = ics->xscs[sc_index]; @@ -743,6 +787,10 @@ ipc_handle_swapchain_acquire_image(volatile struct ipc_client_state *ics, uint32 xrt_result_t ipc_handle_swapchain_release_image(volatile struct ipc_client_state *ics, uint32_t id, uint32_t index) { + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + //! @todo Look up the index. uint32_t sc_index = id; struct xrt_swapchain *xsc = ics->xscs[sc_index]; @@ -755,6 +803,10 @@ ipc_handle_swapchain_release_image(volatile struct ipc_client_state *ics, uint32 xrt_result_t ipc_handle_swapchain_destroy(volatile struct ipc_client_state *ics, uint32_t id) { + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + ics->num_swapchains--; // Drop our reference, does NULL checking. Cast away volatile. From 2d408384c686fc6cc83cfc74ec36948879b23d02 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 16 Apr 2021 15:53:43 +0100 Subject: [PATCH 414/883] doc: Document !768 --- doc/changes/ipc/mr.721.md | 1 + doc/changes/ipc/mr.768.md | 2 ++ doc/changes/xrt/mr.705.2.md | 3 +++ doc/changes/xrt/mr.768.md | 2 ++ 4 files changed, 8 insertions(+) create mode 100644 doc/changes/ipc/mr.768.md create mode 100644 doc/changes/xrt/mr.768.md diff --git a/doc/changes/ipc/mr.721.md b/doc/changes/ipc/mr.721.md index 78c297452..774754139 100644 --- a/doc/changes/ipc/mr.721.md +++ b/doc/changes/ipc/mr.721.md @@ -1,5 +1,6 @@ --- - mr.754 +- mr.768 --- Now that there is a interface that allows the compositor to support multi-client rendering use that instead of doing our own rendering. diff --git a/doc/changes/ipc/mr.768.md b/doc/changes/ipc/mr.768.md new file mode 100644 index 000000000..fa529bcb3 --- /dev/null +++ b/doc/changes/ipc/mr.768.md @@ -0,0 +1,2 @@ +Ensure that functions that require the compositor can't be called if a session +has not been created yet. diff --git a/doc/changes/xrt/mr.705.2.md b/doc/changes/xrt/mr.705.2.md index c9f145e63..9e17e3485 100644 --- a/doc/changes/xrt/mr.705.2.md +++ b/doc/changes/xrt/mr.705.2.md @@ -1,2 +1,5 @@ +--- +- mr.768 +--- xrt: Add XRT_ERROR_EGL_CONFIG_MISSING error, to handle missing config from EGL compositor creation call. diff --git a/doc/changes/xrt/mr.768.md b/doc/changes/xrt/mr.768.md new file mode 100644 index 000000000..7e2ba3dfe --- /dev/null +++ b/doc/changes/xrt/mr.768.md @@ -0,0 +1,2 @@ +Add new IPC session not created error `XRT_ERROR_IPC_SESSION_NOT_CREATED`, as +some functions can not be called without first creating a session. From 2b70189b45dffadd0b221ae3a29e37e93e8e3019 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 22 Apr 2021 02:40:37 +0200 Subject: [PATCH 415/883] d/wmr: log at least one space in trace log Fixes warnings ../src/xrt/drivers/wmr/wmr_hmd.c:83:16: warning: zero-length gnu_printf format string [-Wformat-zero-length] 83 | WMR_TRACE(wh, ""); | ^~ --- src/xrt/drivers/wmr/wmr_hmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index b8ff311f2..b0bc5c607 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -80,7 +80,7 @@ hololens_sensors_decode_packet(struct wmr_hmd *wh, const unsigned char *buffer, int size) { - WMR_TRACE(wh, ""); + WMR_TRACE(wh, " "); if (size != 497 && size != 381) { WMR_ERROR(wh, "invalid hololens sensor packet size (expected 381 or 497 but got %d)", size); @@ -122,7 +122,7 @@ hololens_sensors_decode_packet(struct wmr_hmd *wh, static bool hololens_sensors_read_packets(struct wmr_hmd *wh) { - WMR_TRACE(wh, ""); + WMR_TRACE(wh, " "); unsigned char buffer[WMR_FEATURE_BUFFER_SIZE]; From 77f47273d86fe3a6c7ddb52c72159654ceb10df4 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 1 Dec 2020 15:40:55 -0600 Subject: [PATCH 416/883] d/README.source: Fix URL --- debian/README.source | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/README.source b/debian/README.source index b1be94f46..6020e1ed4 100644 --- a/debian/README.source +++ b/debian/README.source @@ -4,7 +4,7 @@ directly within the "upstream" source tree. There is useful stuff, more directed at package maintenance for distro submission, in the Debian copy of this file: - + To build a package for local use: From a41a869c7170373079d4da6eede4f62281776272 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 23 Apr 2021 14:47:56 +0100 Subject: [PATCH 417/883] d/wmr: Rename variables and tidy code (NFC) --- src/xrt/drivers/wmr/wmr_hmd.c | 27 +++++++++++++++------------ src/xrt/drivers/wmr/wmr_hmd.h | 11 ++++++++--- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index b0bc5c607..b2bf918a0 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -147,10 +147,13 @@ hololens_sensors_read_packets(struct wmr_hmd *wh) vec3_from_hololens_gyro(wh->packet.gyro, i, &wh->raw_gyro); vec3_from_hololens_accel(wh->packet.accel, i, &wh->raw_accel); - os_mutex_lock(&wh->fusion_mutex); - m_imu_3dof_update(&wh->fusion, wh->packet.gyro_timestamp[i] * WMR_MS_HOLOLENS_NS_PER_TICK, - &wh->raw_accel, &wh->raw_gyro); - os_mutex_unlock(&wh->fusion_mutex); + os_mutex_lock(&wh->fusion.mutex); + m_imu_3dof_update( // + &wh->fusion.i3dof, // + wh->packet.gyro_timestamp[i] * WMR_MS_HOLOLENS_NS_PER_TICK, // + &wh->raw_accel, // + &wh->raw_gyro); // + os_mutex_unlock(&wh->fusion.mutex); } break; case WMR_MS_HOLOLENS_MSG_UNKNOWN_05: @@ -370,9 +373,9 @@ wmr_hmd_get_tracked_pose(struct xrt_device *xdev, // Clear relation. U_ZERO(out_relation); - os_mutex_lock(&wh->fusion_mutex); - out_relation->pose.orientation = wh->fusion.rot; - os_mutex_unlock(&wh->fusion_mutex); + os_mutex_lock(&wh->fusion.mutex); + out_relation->pose.orientation = wh->fusion.i3dof.rot; + os_mutex_unlock(&wh->fusion.mutex); out_relation->relation_flags = (enum xrt_space_relation_flags)( // XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | // @@ -426,9 +429,9 @@ wmr_hmd_destroy(struct xrt_device *xdev) } // Destroy the fusion. - m_imu_3dof_close(&wh->fusion); + m_imu_3dof_close(&wh->fusion.i3dof); - os_mutex_destroy(&wh->fusion_mutex); + os_mutex_destroy(&wh->fusion.mutex); free(wh); } @@ -463,7 +466,7 @@ wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, e snprintf(wh->base.str, XRT_DEVICE_NAME_LEN, "HP Reverb VR Headset"); // Mutex before thread. - ret = os_mutex_init(&wh->fusion_mutex); + ret = os_mutex_init(&wh->fusion.mutex); if (ret != 0) { WMR_ERROR(wh, "Failed to init mutex!"); wmr_hmd_destroy(&wh->base); @@ -511,12 +514,12 @@ wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, e return NULL; } - m_imu_3dof_init(&wh->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); + m_imu_3dof_init(&wh->fusion.i3dof, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); // Setup variable tracker. u_var_add_root(wh, "WMR HMD", true); u_var_add_gui_header(wh, &wh->gui.fusion, "3DoF Fusion"); - m_imu_3dof_add_vars(&wh->fusion, wh, ""); + m_imu_3dof_add_vars(&wh->fusion.i3dof, wh, ""); u_var_add_gui_header(wh, &wh->gui.misc, "Misc"); u_var_add_log_level(wh, &wh->log_level, "log_level"); diff --git a/src/xrt/drivers/wmr/wmr_hmd.h b/src/xrt/drivers/wmr/wmr_hmd.h index 6f0410140..9f1d98d28 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.h +++ b/src/xrt/drivers/wmr/wmr_hmd.h @@ -72,9 +72,14 @@ struct wmr_hmd struct xrt_vec3 raw_accel; struct xrt_vec3 raw_gyro; - struct os_mutex fusion_mutex; - //! Protected by @ref fusion_mutex. - struct m_imu_3dof fusion; + struct + { + //! Protects all members of the `fusion` substruct. + struct os_mutex mutex; + + //! Main fusion calculator. + struct m_imu_3dof i3dof; + } fusion; struct { From 1b4b180e6120d2c1af625f2f803d96d34e264f74 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 23 Apr 2021 14:59:18 +0100 Subject: [PATCH 418/883] d/wmr: Do prediction when returning poses --- src/xrt/drivers/wmr/wmr_hmd.c | 36 ++++++++++++++++++++++++++++------- src/xrt/drivers/wmr/wmr_hmd.h | 6 ++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index b2bf918a0..fa4e7a54e 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -20,6 +20,7 @@ #include "math/m_mathinclude.h" #include "math/m_api.h" #include "math/m_vec2.h" +#include "math/m_predict.h" #include "util/u_var.h" #include "util/u_misc.h" @@ -140,7 +141,10 @@ hololens_sensors_read_packets(struct wmr_hmd *wh) } switch (buffer[0]) { - case WMR_MS_HOLOLENS_MSG_SENSORS: + case WMR_MS_HOLOLENS_MSG_SENSORS: { + // Get the timing as close to reading the packet as possible. + uint64_t now_ns = os_monotonic_get_ns(); + hololens_sensors_decode_packet(wh, &wh->packet, buffer, size); for (int i = 0; i < 4; i++) { @@ -148,6 +152,8 @@ hololens_sensors_read_packets(struct wmr_hmd *wh) vec3_from_hololens_accel(wh->packet.accel, i, &wh->raw_accel); os_mutex_lock(&wh->fusion.mutex); + wh->fusion.last_imu_timestamp_ns = now_ns; + wh->fusion.last_angular_velocity = wh->raw_gyro; m_imu_3dof_update( // &wh->fusion.i3dof, // wh->packet.gyro_timestamp[i] * WMR_MS_HOLOLENS_NS_PER_TICK, // @@ -156,6 +162,7 @@ hololens_sensors_read_packets(struct wmr_hmd *wh) os_mutex_unlock(&wh->fusion.mutex); } break; + } case WMR_MS_HOLOLENS_MSG_UNKNOWN_05: case WMR_MS_HOLOLENS_MSG_UNKNOWN_06: case WMR_MS_HOLOLENS_MSG_UNKNOWN_0E: // @@ -370,16 +377,31 @@ wmr_hmd_get_tracked_pose(struct xrt_device *xdev, return; } - // Clear relation. - U_ZERO(out_relation); + // Variables needed for prediction. + uint64_t last_imu_timestamp_ns = 0; + struct xrt_space_relation relation = {0}; + relation.relation_flags = (enum xrt_space_relation_flags)( // + XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT | // + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | // + XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); + // Get data while holding the lock. os_mutex_lock(&wh->fusion.mutex); - out_relation->pose.orientation = wh->fusion.i3dof.rot; + relation.pose.orientation = wh->fusion.i3dof.rot; + relation.angular_velocity = wh->fusion.last_angular_velocity; + last_imu_timestamp_ns = wh->fusion.last_imu_timestamp_ns; os_mutex_unlock(&wh->fusion.mutex); - out_relation->relation_flags = (enum xrt_space_relation_flags)( // - XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | // - XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); + // No prediction needed. + if (at_timestamp_ns < last_imu_timestamp_ns) { + *out_relation = relation; + return; + } + + uint64_t prediction_ns = at_timestamp_ns - last_imu_timestamp_ns; + double prediction_s = time_ns_to_s(prediction_ns); + + m_predict_relation(&relation, prediction_s, out_relation); } static void diff --git a/src/xrt/drivers/wmr/wmr_hmd.h b/src/xrt/drivers/wmr/wmr_hmd.h index 9f1d98d28..5a6df1cff 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.h +++ b/src/xrt/drivers/wmr/wmr_hmd.h @@ -79,6 +79,12 @@ struct wmr_hmd //! Main fusion calculator. struct m_imu_3dof i3dof; + + //! The last angular velocity from the IMU, for prediction. + struct xrt_vec3 last_angular_velocity; + + //! When did we get the last IMU sample, in CPU time. + uint64_t last_imu_timestamp_ns; } fusion; struct From 13d127035b4f8d640dec291febaedbff45d2ff42 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 23 Apr 2021 18:25:39 +0100 Subject: [PATCH 419/883] d/wmr: Remove raw_accel and raw_gyro fields (NFC) --- src/xrt/drivers/wmr/wmr_hmd.c | 13 ++++++++----- src/xrt/drivers/wmr/wmr_hmd.h | 3 --- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index fa4e7a54e..d7d65f44a 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -148,17 +148,20 @@ hololens_sensors_read_packets(struct wmr_hmd *wh) hololens_sensors_decode_packet(wh, &wh->packet, buffer, size); for (int i = 0; i < 4; i++) { - vec3_from_hololens_gyro(wh->packet.gyro, i, &wh->raw_gyro); - vec3_from_hololens_accel(wh->packet.accel, i, &wh->raw_accel); + struct xrt_vec3 raw_gyro; + struct xrt_vec3 raw_accel; + + vec3_from_hololens_gyro(wh->packet.gyro, i, &raw_gyro); + vec3_from_hololens_accel(wh->packet.accel, i, &raw_accel); os_mutex_lock(&wh->fusion.mutex); wh->fusion.last_imu_timestamp_ns = now_ns; - wh->fusion.last_angular_velocity = wh->raw_gyro; + wh->fusion.last_angular_velocity = raw_gyro; m_imu_3dof_update( // &wh->fusion.i3dof, // wh->packet.gyro_timestamp[i] * WMR_MS_HOLOLENS_NS_PER_TICK, // - &wh->raw_accel, // - &wh->raw_gyro); // + &raw_accel, // + &raw_gyro); // os_mutex_unlock(&wh->fusion.mutex); } break; diff --git a/src/xrt/drivers/wmr/wmr_hmd.h b/src/xrt/drivers/wmr/wmr_hmd.h index 5a6df1cff..9469d3bad 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.h +++ b/src/xrt/drivers/wmr/wmr_hmd.h @@ -69,9 +69,6 @@ struct wmr_hmd struct hololens_sensors_packet packet; - struct xrt_vec3 raw_accel; - struct xrt_vec3 raw_gyro; - struct { //! Protects all members of the `fusion` substruct. From 0807ce6dddc1a938155dcc90bc59897bbe3bc6a1 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 23 Apr 2021 22:47:40 +0100 Subject: [PATCH 420/883] d/wmr: Only take the lock once per received packet --- src/xrt/drivers/wmr/wmr_hmd.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index d7d65f44a..fc1e4d20e 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -147,23 +147,26 @@ hololens_sensors_read_packets(struct wmr_hmd *wh) hololens_sensors_decode_packet(wh, &wh->packet, buffer, size); + struct xrt_vec3 raw_gyro[4]; + struct xrt_vec3 raw_accel[4]; + for (int i = 0; i < 4; i++) { - struct xrt_vec3 raw_gyro; - struct xrt_vec3 raw_accel; + vec3_from_hololens_gyro(wh->packet.gyro, i, &raw_gyro[i]); + vec3_from_hololens_accel(wh->packet.accel, i, &raw_accel[i]); + } - vec3_from_hololens_gyro(wh->packet.gyro, i, &raw_gyro); - vec3_from_hololens_accel(wh->packet.accel, i, &raw_accel); - - os_mutex_lock(&wh->fusion.mutex); - wh->fusion.last_imu_timestamp_ns = now_ns; - wh->fusion.last_angular_velocity = raw_gyro; + os_mutex_lock(&wh->fusion.mutex); + for (int i = 0; i < 4; i++) { m_imu_3dof_update( // &wh->fusion.i3dof, // wh->packet.gyro_timestamp[i] * WMR_MS_HOLOLENS_NS_PER_TICK, // - &raw_accel, // - &raw_gyro); // - os_mutex_unlock(&wh->fusion.mutex); + &raw_accel[i], // + &raw_gyro[i]); // } + wh->fusion.last_imu_timestamp_ns = now_ns; + wh->fusion.last_angular_velocity = raw_gyro[3]; + os_mutex_unlock(&wh->fusion.mutex); + break; } case WMR_MS_HOLOLENS_MSG_UNKNOWN_05: From 1ef79820e6e5644bb8955d75545ba81a55c6f905 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 23 Apr 2021 22:48:08 +0100 Subject: [PATCH 421/883] d/wmr: Clarify struct layout (NFC) --- src/xrt/drivers/wmr/wmr_protocol.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/wmr/wmr_protocol.h b/src/xrt/drivers/wmr/wmr_protocol.h index 608a67d4c..e54e67759 100644 --- a/src/xrt/drivers/wmr/wmr_protocol.h +++ b/src/xrt/drivers/wmr/wmr_protocol.h @@ -41,14 +41,16 @@ extern "C" { #define WMR_CONTROL_MSG_IPD_VALUE 0x01 #define WMR_CONTROL_MSG_UNKNOWN_05 0x05 + static const unsigned char hololens_sensors_imu_on[64] = {0x02, 0x07}; + struct hololens_sensors_packet { uint8_t id; uint16_t temperature[4]; uint64_t gyro_timestamp[4]; - int16_t gyro[3][32]; + int16_t gyro[3][4 * 8]; uint64_t accel_timestamp[4]; int32_t accel[3][4]; uint64_t video_timestamp[4]; From d05aa9a458f49ff60d1ae69fedbc3b8ec117fa35 Mon Sep 17 00:00:00 2001 From: Boris-Chengbiao Zhou Date: Sat, 24 Apr 2021 17:49:54 +0200 Subject: [PATCH 422/883] aux/vk: Extend the correct structure for VK_EXT_global_priority --- src/xrt/auxiliary/vk/vk_helpers.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/xrt/auxiliary/vk/vk_helpers.c b/src/xrt/auxiliary/vk/vk_helpers.c index 51e25aff0..b93a42ba7 100644 --- a/src/xrt/auxiliary/vk/vk_helpers.c +++ b/src/xrt/auxiliary/vk/vk_helpers.c @@ -1139,7 +1139,7 @@ vk_build_device_extensions(struct vk_bundle *vk, VkResult vk_create_device(struct vk_bundle *vk, int forced_index, - VkQueueGlobalPriorityEXT global_priorty, + VkQueueGlobalPriorityEXT global_priority, const char *const *required_device_extensions, size_t num_required_device_extensions, const char *const *optional_device_extensions, @@ -1162,9 +1162,15 @@ vk_create_device(struct vk_bundle *vk, VkPhysicalDeviceFeatures *enabled_features = NULL; + VkDeviceQueueGlobalPriorityCreateInfoEXT priority_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT, + .globalPriority = global_priority, + }; + float queue_priority = 0.0f; VkDeviceQueueCreateInfo queue_create_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = vk->has_EXT_global_priority ? &priority_info : NULL, .queueCount = 1, .pQueuePriorities = &queue_priority, }; @@ -1174,14 +1180,8 @@ vk_create_device(struct vk_bundle *vk, return ret; } - VkDeviceQueueGlobalPriorityCreateInfoEXT priority_info = { - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT, - .globalPriority = global_priorty, - }; - VkDeviceCreateInfo device_create_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = vk->has_EXT_global_priority ? &priority_info : NULL, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queue_create_info, .enabledExtensionCount = num_device_extensions, From 08c91d4136695798375fce41d547f25dcd485045 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Mon, 26 Apr 2021 14:47:46 +0200 Subject: [PATCH 423/883] st/oxr: Fix printing of the format in error message --- src/xrt/state_trackers/oxr/oxr_api_swapchain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_api_swapchain.c b/src/xrt/state_trackers/oxr/oxr_api_swapchain.c index 0d1d1506d..254502109 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_swapchain.c +++ b/src/xrt/state_trackers/oxr/oxr_api_swapchain.c @@ -78,7 +78,7 @@ oxr_xrCreateSwapchain(XrSession session, const XrSwapchainCreateInfo *createInfo if ((createInfo->usageFlags & ~flags) != 0) { return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, - "(createInfo->usageFlags == 0x08%" PRIx64 ") contains invalid flags", + "(createInfo->usageFlags == 0x%04" PRIx64 ") contains invalid flags", createInfo->usageFlags); } bool format_supported = false; @@ -92,7 +92,7 @@ oxr_xrCreateSwapchain(XrSession session, const XrSwapchainCreateInfo *createInfo if (!format_supported) { return oxr_error(&log, XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED, - "(createInfo->format == 0x08%" PRIx64 ") is not supported", createInfo->format); + "(createInfo->format == 0x%04" PRIx64 ") is not supported", createInfo->format); } ret = sess->create_swapchain(&log, sess, createInfo, &sc); From f1ca54376cbcf5abef2bb1291152cb14dd2208b9 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 21 Apr 2021 10:51:13 -0500 Subject: [PATCH 424/883] doc: Fix date on IPC docs and add copyright header --- doc/ipc.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/ipc.md b/doc/ipc.md index 2bfbeb615..3dd547b78 100644 --- a/doc/ipc.md +++ b/doc/ipc.md @@ -1,6 +1,11 @@ # IPC Design {#ipc-design} -- Last updated: 8-February-2021 + + +- Last updated: 24-February-2021 When the service starts, an `xrt_instance` is created and selected, a native system compositor is initialized, a shared memory segment for device data is From 6d4b098e65e0bb73e4bc8fbd48385a319c940143 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 21 Apr 2021 11:12:10 -0500 Subject: [PATCH 425/883] t/steamvr_drv: Add license sidecar files --- src/xrt/targets/steamvr_drv/driver.vrdrivermanifest.license | 2 ++ .../targets/steamvr_drv/resources/driver.vrresources.license | 4 ++++ .../resources/icons/controller_status_error.png.license | 3 +++ .../resources/icons/controller_status_off.png.license | 3 +++ .../resources/icons/controller_status_ready.png.license | 3 +++ .../resources/icons/controller_status_ready_alert.png.license | 3 +++ .../resources/icons/controller_status_ready_low.png.license | 3 +++ .../resources/icons/controller_status_searching.gif.license | 3 +++ .../icons/controller_status_searching_alert.gif.license | 3 +++ .../resources/icons/controller_status_standby.png.license | 3 +++ .../resources/icons/headset_monado_status_error.png.license | 3 +++ .../resources/icons/headset_monado_status_off.png.license | 3 +++ .../resources/icons/headset_monado_status_ready.png.license | 3 +++ .../icons/headset_monado_status_ready_alert.png.license | 3 +++ .../icons/headset_monado_status_ready_low.png.license | 3 +++ .../icons/headset_monado_status_searching.gif.license | 3 +++ .../icons/headset_monado_status_searching_alert.gif.license | 3 +++ .../resources/icons/headset_monado_status_standby.png.license | 3 +++ .../resources/localization/localization.json.license | 2 ++ .../steamvr_drv/resources/settings/default.vrsettings.license | 2 ++ src/xrt/targets/steamvr_drv/steamvr.vrsettings.license | 2 ++ 21 files changed, 60 insertions(+) create mode 100644 src/xrt/targets/steamvr_drv/driver.vrdrivermanifest.license create mode 100644 src/xrt/targets/steamvr_drv/resources/driver.vrresources.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/controller_status_error.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/controller_status_off.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready_alert.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready_low.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/controller_status_searching.gif.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/controller_status_searching_alert.gif.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/controller_status_standby.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_error.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_off.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready_alert.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready_low.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_searching.gif.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_searching_alert.gif.license create mode 100644 src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_standby.png.license create mode 100644 src/xrt/targets/steamvr_drv/resources/localization/localization.json.license create mode 100644 src/xrt/targets/steamvr_drv/resources/settings/default.vrsettings.license create mode 100644 src/xrt/targets/steamvr_drv/steamvr.vrsettings.license diff --git a/src/xrt/targets/steamvr_drv/driver.vrdrivermanifest.license b/src/xrt/targets/steamvr_drv/driver.vrdrivermanifest.license new file mode 100644 index 000000000..003e3e74a --- /dev/null +++ b/src/xrt/targets/steamvr_drv/driver.vrdrivermanifest.license @@ -0,0 +1,2 @@ +Copyright 2020, Collabora, Ltd. +SPDX-License-Identifier: BSL-1.0 diff --git a/src/xrt/targets/steamvr_drv/resources/driver.vrresources.license b/src/xrt/targets/steamvr_drv/resources/driver.vrresources.license new file mode 100644 index 000000000..c3f0f3034 --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/driver.vrresources.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation +SPDX-FileCopyrightText: 2020, Collabora, Ltd. + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/controller_status_error.png.license b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_error.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_error.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/controller_status_off.png.license b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_off.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_off.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready.png.license b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready_alert.png.license b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready_alert.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready_alert.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready_low.png.license b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready_low.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_ready_low.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/controller_status_searching.gif.license b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_searching.gif.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_searching.gif.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/controller_status_searching_alert.gif.license b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_searching_alert.gif.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_searching_alert.gif.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/controller_status_standby.png.license b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_standby.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/controller_status_standby.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_error.png.license b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_error.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_error.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_off.png.license b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_off.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_off.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready.png.license b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready_alert.png.license b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready_alert.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready_alert.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready_low.png.license b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready_low.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_ready_low.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_searching.gif.license b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_searching.gif.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_searching.gif.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_searching_alert.gif.license b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_searching_alert.gif.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_searching_alert.gif.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_standby.png.license b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_standby.png.license new file mode 100644 index 000000000..f1d2db0bc --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/icons/headset_monado_status_standby.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015, Valve Corporation + +SPDX-License-Identifier: BSD-3-Clause diff --git a/src/xrt/targets/steamvr_drv/resources/localization/localization.json.license b/src/xrt/targets/steamvr_drv/resources/localization/localization.json.license new file mode 100644 index 000000000..003e3e74a --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/localization/localization.json.license @@ -0,0 +1,2 @@ +Copyright 2020, Collabora, Ltd. +SPDX-License-Identifier: BSL-1.0 diff --git a/src/xrt/targets/steamvr_drv/resources/settings/default.vrsettings.license b/src/xrt/targets/steamvr_drv/resources/settings/default.vrsettings.license new file mode 100644 index 000000000..003e3e74a --- /dev/null +++ b/src/xrt/targets/steamvr_drv/resources/settings/default.vrsettings.license @@ -0,0 +1,2 @@ +Copyright 2020, Collabora, Ltd. +SPDX-License-Identifier: BSL-1.0 diff --git a/src/xrt/targets/steamvr_drv/steamvr.vrsettings.license b/src/xrt/targets/steamvr_drv/steamvr.vrsettings.license new file mode 100644 index 000000000..003e3e74a --- /dev/null +++ b/src/xrt/targets/steamvr_drv/steamvr.vrsettings.license @@ -0,0 +1,2 @@ +Copyright 2020, Collabora, Ltd. +SPDX-License-Identifier: BSL-1.0 From d2c81681fe742dd1b7802d0910084b55aa54af01 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 21 Apr 2021 11:12:29 -0500 Subject: [PATCH 426/883] external/stb: Add license sidecar file for stb_image_write.h --- src/external/stb/stb_image_write.h.license | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/external/stb/stb_image_write.h.license diff --git a/src/external/stb/stb_image_write.h.license b/src/external/stb/stb_image_write.h.license new file mode 100644 index 000000000..a27e204e9 --- /dev/null +++ b/src/external/stb/stb_image_write.h.license @@ -0,0 +1,3 @@ +Copyright (c) 2017 Sean Barrett + +SPDX-License-Identifier: MIT OR Unlicense From 3df2708a5d826efeec43d7aaf1896b20bcb5334f Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 21 Apr 2021 11:12:37 -0500 Subject: [PATCH 427/883] st/gui: Add missing copyright header to file --- src/xrt/state_trackers/gui/gui_stb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/xrt/state_trackers/gui/gui_stb.c b/src/xrt/state_trackers/gui/gui_stb.c index e1b1583b4..fc7a0c7a3 100644 --- a/src/xrt/state_trackers/gui/gui_stb.c +++ b/src/xrt/state_trackers/gui/gui_stb.c @@ -1,3 +1,10 @@ +// Copyright 2020, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Compile the STB image write implementation. + * @author Jakob Bornecrantz + */ #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" From 53042f88a0fa72b07d9500e37dfbebd7a7dac130 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 21 Apr 2021 11:12:54 -0500 Subject: [PATCH 428/883] reuse: Update dep5 file to cover all changelog directories --- .reuse/dep5 | 1 + 1 file changed, 1 insertion(+) diff --git a/.reuse/dep5 b/.reuse/dep5 index 291b59df3..e2b525dc8 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -10,6 +10,7 @@ Files: doc/changes/drivers/* doc/changes/xrt/* doc/changes/auxiliary/* doc/changes/compositor/* + doc/changes/big/* Copyright: 2020-2021, Collabora, Ltd. and the Monado contributors License: CC0-1.0 Comment: Prevents needing a license header per fragment between releases. From ae8562efec08be5ab8a1ea6087c1b172c83c1a53 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 21 Apr 2021 14:24:03 -0500 Subject: [PATCH 429/883] licenses: Include unlicense in LICENSES directory as one option for STB_write_image --- LICENSES/Unlicense.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 LICENSES/Unlicense.txt diff --git a/LICENSES/Unlicense.txt b/LICENSES/Unlicense.txt new file mode 100644 index 000000000..cde4ac698 --- /dev/null +++ b/LICENSES/Unlicense.txt @@ -0,0 +1,10 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. + +In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to From d65829c6844c94e2787cac993314622f4bfa16ec Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 21 Apr 2021 14:27:04 -0500 Subject: [PATCH 430/883] ci: Add REUSE check to CI. --- .gitlab-ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e5b9c30d5..6951bd358 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -159,6 +159,15 @@ format-and-spellcheck: expire_in: 1 week when: on_failure +# Verify REUSE compliance +reuse: + stage: build + image: + name: fsfe/reuse:latest + entrypoint: [""] + script: + - reuse lint + # "Base" job for a CMake build .monado.base-job.build-cmake: stage: build @@ -381,6 +390,7 @@ ubuntu:groovy:package: BACKPORT_SUFFIX: ubuntu20.04 PACKAGE_BRANCH: ubuntu/focal DISTRO: focal + reprepro:package: stage: reprepro extends: From 0868a90a1f299275a37b2443cf5ba90c5030ed5b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 9 Dec 2020 10:13:49 -0600 Subject: [PATCH 431/883] gradle: Only forward EIGEN3_INCLUDE_DIR definition if we actually have it set. --- build.gradle | 4 ++-- src/xrt/targets/openxr_android/build.gradle | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index ed0cd49b8..d2357a021 100644 --- a/build.gradle +++ b/build.gradle @@ -48,8 +48,8 @@ ext { sharedMinSdk = 26 // If you are building on Windows, you will need to explicitly set eigenIncludeDir in your - // local.properties file since the default value provided below only makes sense on *nix - eigenIncludeDir = project.findProperty('eigenIncludeDir') ?: '/usr/include/eigen3' + // local.properties file + eigenIncludeDir = project.findProperty('eigenIncludeDir') // If you're having trouble with a "can't find python" CMake error, you can specify the path to // Python 3 explicitly in local.properties with a property named "pythonBinary" diff --git a/src/xrt/targets/openxr_android/build.gradle b/src/xrt/targets/openxr_android/build.gradle index a02b569b6..3dbd1b26b 100644 --- a/src/xrt/targets/openxr_android/build.gradle +++ b/src/xrt/targets/openxr_android/build.gradle @@ -89,13 +89,17 @@ android { externalNativeBuild { cmake { - arguments "-DEIGEN3_INCLUDE_DIR=${project.eigenIncludeDir}", "-DANDROID_PLATFORM=26", "-DANDROID_STL=c++_shared", "-DANDROID_ARM_NEON=TRUE" + arguments "-DANDROID_PLATFORM=26", "-DANDROID_STL=c++_shared", "-DANDROID_ARM_NEON=TRUE" } if (project.pythonBinary != null) { - println "Path to Python 3 explicitly specified: ${project.pythonBinary}" + println "Path to Python 3 explicitly specified: pythonBinary=${project.pythonBinary}" cmake.arguments "-DPYTHON_EXECUTABLE=${project.pythonBinary}" } + if (project.eigenIncludeDir != null) { + println "Path to Eigen3 includes explicitly specified: eigenIncludeDir=${project.eigenIncludeDir}" + cmake.arguments "-DEIGEN3_INCLUDE_DIR=${project.eigenIncludeDir}" + } } // Be sure to copy over licenses formatted as required. From c1d18f9b25d180d1a6e779c7b7a9d66f585406a4 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 26 Apr 2021 14:40:32 +0100 Subject: [PATCH 432/883] c/client: Add support for more formats in GL --- src/xrt/compositor/client/comp_gl_client.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/xrt/compositor/client/comp_gl_client.c b/src/xrt/compositor/client/comp_gl_client.c index 0d83fbaef..f7e58c603 100644 --- a/src/xrt/compositor/client/comp_gl_client.c +++ b/src/xrt/compositor/client/comp_gl_client.c @@ -312,9 +312,14 @@ static int64_t gl_format_to_vk(int64_t format) { switch (format) { - case GL_RGBA8: return 37 /*VK_FORMAT_R8G8B8A8_UNORM*/; + case GL_RGB8: return 23 /*VK_FORMAT_R8G8B8_UNORM*/; // Should not be used, colour precision. + case GL_SRGB8: return 29 /*VK_FORMAT_R8G8B8_SRGB*/; + case GL_RGBA8: return 37 /*VK_FORMAT_R8G8B8A8_UNORM*/; // Should not be used, colour precision. case GL_SRGB8_ALPHA8: return 43 /*VK_FORMAT_R8G8B8A8_SRGB*/; case GL_RGB10_A2: return 64 /*VK_FORMAT_A2B10G10R10_UNORM_PACK32*/; + case GL_RGB16: return 84 /*VK_FORMAT_R16G16B16_UNORM*/; + case GL_RGB16F: return 90 /*VK_FORMAT_R16G16B16_SFLOAT*/; + case GL_RGBA16: return 91 /*VK_FORMAT_R16G16B16A16_UNORM*/; case GL_RGBA16F: return 97 /*VK_FORMAT_R16G16B16A16_SFLOAT*/; case GL_DEPTH_COMPONENT16: return 124 /*VK_FORMAT_D16_UNORM*/; case GL_DEPTH_COMPONENT32F: return 126 /*VK_FORMAT_D32_SFLOAT*/; @@ -328,11 +333,17 @@ static int64_t vk_format_to_gl(int64_t format) { switch (format) { - case 37 /*VK_FORMAT_R8G8B8A8_UNORM*/: return GL_RGBA8; + case 23 /*VK_FORMAT_R8G8B8_UNORM*/: return GL_RGB8; // Should not be used, colour precision. + case 29 /*VK_FORMAT_R8G8B8_SRGB*/: return GL_SRGB8; + case 30 /*VK_FORMAT_B8G8R8_UNORM*/: return 0; + case 37 /*VK_FORMAT_R8G8B8A8_UNORM*/: return GL_RGBA8; // Should not be used, colour precision. case 43 /*VK_FORMAT_R8G8B8A8_SRGB*/: return GL_SRGB8_ALPHA8; case 44 /*VK_FORMAT_B8G8R8A8_UNORM*/: return 0; case 50 /*VK_FORMAT_B8G8R8A8_SRGB*/: return 0; case 64 /*VK_FORMAT_A2B10G10R10_UNORM_PACK32*/: return GL_RGB10_A2; + case 84 /*VK_FORMAT_R16G16B16_UNORM*/: return GL_RGB16; + case 90 /*VK_FORMAT_R16G16B16_SFLOAT*/: return GL_RGB16F; + case 91 /*VK_FORMAT_R16G16B16A16_UNORM*/: return GL_RGBA16; case 97 /*VK_FORMAT_R16G16B16A16_SFLOAT*/: return GL_RGBA16F; case 124 /*VK_FORMAT_D16_UNORM*/: return GL_DEPTH_COMPONENT16; case 126 /*VK_FORMAT_D32_SFLOAT*/: return GL_DEPTH_COMPONENT32F; From a377fb135f0b8dd3090192b67d3862e165120391 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 26 Apr 2021 15:04:38 +0100 Subject: [PATCH 433/883] c/client: Vulkan formats are listed as numbers not hex --- src/xrt/compositor/client/comp_gl_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/compositor/client/comp_gl_client.c b/src/xrt/compositor/client/comp_gl_client.c index f7e58c603..f5445bb00 100644 --- a/src/xrt/compositor/client/comp_gl_client.c +++ b/src/xrt/compositor/client/comp_gl_client.c @@ -349,7 +349,7 @@ vk_format_to_gl(int64_t format) case 126 /*VK_FORMAT_D32_SFLOAT*/: return GL_DEPTH_COMPONENT32F; case 129 /*VK_FORMAT_D24_UNORM_S8_UINT*/: return GL_DEPTH24_STENCIL8; case 130 /*VK_FORMAT_D32_SFLOAT_S8_UINT*/: return GL_DEPTH32F_STENCIL8; - default: U_LOG_W("Cannot convert VK format 0x%016" PRIx64 " to GL format!\n", format); return 0; + default: U_LOG_W("Cannot convert VK format %" PRIu64 " to GL format!\n", format); return 0; } } From 64093dfaafaba6204ef13db4a3f18a50172ff531 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 26 Apr 2021 14:40:45 +0100 Subject: [PATCH 434/883] c/main: Expose more formats --- src/xrt/compositor/main/comp_compositor.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index c045543a3..2460c28f6 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -1395,11 +1395,17 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos // color formats ADD_IF_SUPPORTED(VK_FORMAT_A2B10G10R10_UNORM_PACK32); // OGL VK + ADD_IF_SUPPORTED(VK_FORMAT_R16G16B16A16_UNORM); // OGL VK ADD_IF_SUPPORTED(VK_FORMAT_R16G16B16A16_SFLOAT); // OGL VK + ADD_IF_SUPPORTED(VK_FORMAT_R16G16B16_UNORM); // OGL VK - Uncommon. + ADD_IF_SUPPORTED(VK_FORMAT_R16G16B16_SFLOAT); // OGL VK - Uncommon. ADD_IF_SUPPORTED(VK_FORMAT_R8G8B8A8_SRGB); // OGL VK ADD_IF_SUPPORTED(VK_FORMAT_B8G8R8A8_SRGB); // VK - ADD_IF_SUPPORTED(VK_FORMAT_R8G8B8A8_UNORM); // OGL VK - ADD_IF_SUPPORTED(VK_FORMAT_B8G8R8A8_UNORM); // VK + ADD_IF_SUPPORTED(VK_FORMAT_R8G8B8_SRGB); // OGL VK - Uncommon. + ADD_IF_SUPPORTED(VK_FORMAT_R8G8B8A8_UNORM); // OGL VK - Bad colour precision. + ADD_IF_SUPPORTED(VK_FORMAT_B8G8R8A8_UNORM); // VK - Bad colour precision. + ADD_IF_SUPPORTED(VK_FORMAT_R8G8B8_UNORM); // OGL VK - Uncommon. Bad colour precision. + ADD_IF_SUPPORTED(VK_FORMAT_B8G8R8_UNORM); // VK - Uncommon. Bad colour precision. // depth formats ADD_IF_SUPPORTED(VK_FORMAT_D16_UNORM); // OGL VK From 846a66394204ba776a1fa325322bab297522df06 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 24 Apr 2021 15:19:31 +0100 Subject: [PATCH 435/883] c/main: Make instance extension list more readable (NFC) --- src/xrt/compositor/main/comp_compositor.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 2460c28f6..109f34e6e 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -662,10 +662,15 @@ find_get_instance_proc_addr(struct comp_compositor *c) // If any of these lists are updated, please also update the appropriate column // in `vulkan-extensions.md` -#define COMP_INSTANCE_EXTENSIONS_COMMON \ - VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, \ - VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, \ - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_KHR_SURFACE_EXTENSION_NAME +// clang-format off +#define COMP_INSTANCE_EXTENSIONS_COMMON \ + VK_EXT_DEBUG_REPORT_EXTENSION_NAME, \ + VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, \ + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, \ + VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, \ + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, \ + VK_KHR_SURFACE_EXTENSION_NAME +// clang-format on static const char *instance_extensions_none[] = {COMP_INSTANCE_EXTENSIONS_COMMON}; From ceb6c8b3fe98c14212cf0982252ab96f55bd3af2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 24 Apr 2021 15:20:10 +0100 Subject: [PATCH 436/883] c/main: Remove trailing newline in error message (NFC) --- src/xrt/compositor/main/comp_compositor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 109f34e6e..4fa179272 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -833,7 +833,7 @@ create_instance(struct comp_compositor *c) ret = c->vk.vkCreateInstance(&instance_info, NULL, &c->vk.instance); if (ret != VK_SUCCESS) { - COMP_ERROR(c, "vkCreateInstance: %s\n", vk_result_string(ret)); + COMP_ERROR(c, "vkCreateInstance: %s", vk_result_string(ret)); COMP_ERROR(c, "Failed to create Vulkan instance"); return ret; } From 59153186542d9e178a61f5cd693877a1ae3e44f9 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 24 Apr 2021 15:22:43 +0100 Subject: [PATCH 437/883] c/main: Clarify in code that it is preferred dimensions (NFC) --- .../compositor/main/comp_target_swapchain.c | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index 5a0d3c21c..3f577766e 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -60,8 +60,8 @@ comp_target_swapchain_destroy_old(struct comp_target_swapchain *cts, VkSwapchain static VkExtent2D comp_target_swapchain_select_extent(struct comp_target_swapchain *cts, VkSurfaceCapabilitiesKHR caps, - uint32_t width, - uint32_t height); + uint32_t preferred_width, + uint32_t preferred_height); static bool _find_surface_format(struct comp_target_swapchain *cts, VkSurfaceKHR surface, VkSurfaceFormatKHR *format); @@ -84,8 +84,8 @@ get_vk(struct comp_target_swapchain *cts) static void comp_target_swapchain_create_images(struct comp_target *ct, - uint32_t width, - uint32_t height, + uint32_t preferred_width, + uint32_t preferred_height, VkFormat color_format, VkColorSpaceKHR color_space, VkPresentModeKHR present_mode) @@ -150,7 +150,7 @@ comp_target_swapchain_create_images(struct comp_target *ct, } // Get the extents of the swapchain. - VkExtent2D extent = comp_target_swapchain_select_extent(cts, surface_caps, width, height); + VkExtent2D extent = comp_target_swapchain_select_extent(cts, surface_caps, preferred_width, preferred_height); if (surface_caps.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || surface_caps.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { @@ -212,24 +212,26 @@ comp_target_swapchain_create_images(struct comp_target *ct, static VkExtent2D comp_target_swapchain_select_extent(struct comp_target_swapchain *cts, VkSurfaceCapabilitiesKHR caps, - uint32_t width, - uint32_t height) + uint32_t preferred_width, + uint32_t preferred_height) { // If width (and height) equals the special value 0xFFFFFFFF, // the size of the surface will be set by the swapchain if (caps.currentExtent.width == (uint32_t)-1) { VkExtent2D extent = { - .width = width, - .height = height, + .width = preferred_width, + .height = preferred_height, }; return extent; } - if (caps.currentExtent.width != width || caps.currentExtent.height != height) { - COMP_DEBUG(cts->base.c, - "Using swap chain extent dimensions %dx%d instead " - "of requested %dx%d.", - caps.currentExtent.width, caps.currentExtent.height, width, height); + if (caps.currentExtent.width != preferred_width || // + caps.currentExtent.height != preferred_height) { + COMP_DEBUG(cts->base.c, "Using swap chain extent dimensions %dx%d instead of requested %dx%d.", + caps.currentExtent.width, // + caps.currentExtent.height, // + preferred_width, // + preferred_height); // } return caps.currentExtent; From 2efd2f543fac43fc0d0f02c50e7c526f11c33a88 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 24 Apr 2021 15:23:43 +0100 Subject: [PATCH 438/883] c/main: Tidy code in comp_target_swapchain (NFC) --- src/xrt/compositor/main/comp_target_swapchain.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index 3f577766e..f322c474e 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -118,9 +118,7 @@ comp_target_swapchain_create_images(struct comp_target *ct, // Sanity check. ret = vk->vkGetPhysicalDeviceSurfaceSupportKHR(vk->physical_device, 0, cts->surface.handle, &supported); if (!supported) { - COMP_ERROR(ct->c, - "vkGetPhysicalDeviceSurfaceSupportKHR: surface not " - "supported! '%s'", + COMP_ERROR(ct->c, "vkGetPhysicalDeviceSurfaceSupportKHR: surface not supported! '%s'", vk_result_string(ret)); } @@ -154,9 +152,7 @@ comp_target_swapchain_create_images(struct comp_target *ct, if (surface_caps.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || surface_caps.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { - COMP_DEBUG(ct->c, - "Swapping width and height," - "since we are going to pre rotate"); + COMP_DEBUG(ct->c, "Swapping width and height, since we are going to pre rotate"); uint32_t w2 = extent.width; uint32_t h2 = extent.height; extent.width = h2; From 9c4b41f58e5f2a43e6637e958befae673c49d71e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 24 Apr 2021 15:25:52 +0100 Subject: [PATCH 439/883] c/main: Assert that preferred dimensions are somewhat valid --- src/xrt/compositor/main/comp_target_swapchain.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index f322c474e..4999b8bd3 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -214,6 +214,8 @@ comp_target_swapchain_select_extent(struct comp_target_swapchain *cts, // If width (and height) equals the special value 0xFFFFFFFF, // the size of the surface will be set by the swapchain if (caps.currentExtent.width == (uint32_t)-1) { + assert(preferred_width > 0 && preferred_height > 0); + VkExtent2D extent = { .width = preferred_width, .height = preferred_height, From 159eeb81a797bd9ae6ed783922524b3c2a2d280b Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 24 Apr 2021 15:26:19 +0100 Subject: [PATCH 440/883] c/main: Pass in preferred dimensions to create images Fixes #120 --- src/xrt/compositor/main/comp_renderer.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index 1535744b9..1c626c371 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -419,13 +419,13 @@ renderer_ensure_images_and_renderings(struct comp_renderer *r, bool force_recrea // Make we sure we destroy all dependent things before creating new images. renderer_close_renderings_and_fences(r); - comp_target_create_images( // - r->c->target, // - r->c->target->width, // - r->c->target->height, // - r->settings->color_format, // - r->settings->color_space, // - r->settings->present_mode); // + comp_target_create_images( // + r->c->target, // + r->c->settings.preferred.width, // + r->c->settings.preferred.height, // + r->settings->color_format, // + r->settings->color_space, // + r->settings->present_mode); // r->num_buffers = r->c->target->num_images; From 323eebf126569a37bce3d1e60ae5064801066c49 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 24 Apr 2021 15:33:29 +0100 Subject: [PATCH 441/883] doc: Document !767 and !787 --- doc/changes/compositor/mr.767.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/changes/compositor/mr.767.md diff --git a/doc/changes/compositor/mr.767.md b/doc/changes/compositor/mr.767.md new file mode 100644 index 000000000..f3e74cab2 --- /dev/null +++ b/doc/changes/compositor/mr.767.md @@ -0,0 +1,6 @@ +--- +- issue.120 +- mr.787 +--- +main: Make it possible to create the swapchain later when actually needed, +and have the swapchain be in a non-ready state that stops drawing. From 8c26be37ae75380feca86f315ca76286b65f8b4c Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 26 Apr 2021 19:42:16 +0100 Subject: [PATCH 442/883] u/ft: Warn when missing frames --- src/xrt/auxiliary/util/u_timing_frame.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/util/u_timing_frame.c b/src/xrt/auxiliary/util/u_timing_frame.c index f7ce6f99e..32e46b963 100644 --- a/src/xrt/auxiliary/util/u_timing_frame.c +++ b/src/xrt/auxiliary/util/u_timing_frame.c @@ -317,7 +317,7 @@ adjust_app_time(struct display_timing *dt, struct frame *f) if (f->actual_present_time_ns > f->desired_present_time_ns && !is_within_half_ms(f->actual_present_time_ns, f->desired_present_time_ns)) { double missed_ms = ns_to_ms(f->actual_present_time_ns - f->desired_present_time_ns); - FT_LOG_D("Missed by %.2f!", missed_ms); + FT_LOG_W("Frame %" PRIu64 " missed by %.2f!", f->frame_id, missed_ms); app_time_ns += dt->adjust_missed_ns; if (app_time_ns > dt->app_time_max_ns) { From 41ad1dcf993250e4849e6a000d68f934bbbf7440 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 26 Apr 2021 22:43:06 +0100 Subject: [PATCH 443/883] c/main: Better Vulkan error printing --- src/xrt/compositor/main/comp_compositor.c | 45 ++++++++++++++--------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 4fa179272..2c0c337f4 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -78,6 +78,8 @@ * */ +#define CVK_ERROR(C, FUNC, MSG, RET) COMP_ERROR(C, FUNC ": %s\t\n" MSG, vk_result_string(RET)); + static double ns_to_ms(int64_t ns) { @@ -820,7 +822,7 @@ create_instance(struct comp_compositor *c) ret = select_instances_extensions(c, &instance_extensions, &num_extensions); if (ret != VK_SUCCESS) { - COMP_ERROR(c, "Failed to select instance extensions: %s", vk_result_string(ret)); + CVK_ERROR(c, "select_instances_extensions", "Failed to select instance extensions.", ret); return ret; } @@ -833,14 +835,13 @@ create_instance(struct comp_compositor *c) ret = c->vk.vkCreateInstance(&instance_info, NULL, &c->vk.instance); if (ret != VK_SUCCESS) { - COMP_ERROR(c, "vkCreateInstance: %s", vk_result_string(ret)); - COMP_ERROR(c, "Failed to create Vulkan instance"); + CVK_ERROR(c, "vkCreateInstance", "Failed to create Vulkan instance", ret); return ret; } ret = vk_get_instance_functions(&c->vk); if (ret != VK_SUCCESS) { - COMP_ERROR(c, "Failed to get Vulkan instance functions: %s", vk_result_string(ret)); + CVK_ERROR(c, "vk_get_instance_functions", "Failed to get Vulkan instance functions.", ret); return ret; } @@ -860,7 +861,7 @@ get_device_uuid(struct vk_bundle *vk, struct comp_compositor *c, int gpu_index, ret = vk->vkEnumeratePhysicalDevices(vk->instance, &gpu_count, phys); if (ret != VK_SUCCESS) { - COMP_ERROR(c, "Failed to enumerate physical devices!"); + CVK_ERROR(c, "vkEnumeratePhysicalDevices", "Failed to enumerate physical devices.", ret); return false; } vk->vkGetPhysicalDeviceProperties2(phys[gpu_index], &pdp2); @@ -872,18 +873,19 @@ get_device_uuid(struct vk_bundle *vk, struct comp_compositor *c, int gpu_index, static bool compositor_init_vulkan(struct comp_compositor *c) { - VkResult ret; c->vk.ll = c->settings.log_level; ret = find_get_instance_proc_addr(c); if (ret != VK_SUCCESS) { + CVK_ERROR(c, "find_get_instance_proc_addr", "Failed to get VkInstance get process address.", ret); return false; } ret = create_instance(c); if (ret != VK_SUCCESS) { + // Error already reported. return false; } @@ -922,11 +924,13 @@ compositor_init_vulkan(struct comp_compositor *c) } // Some other error! + CVK_ERROR(c, "vk_create_device", "Failed to create Vulkan device.", ret); return false; } ret = vk_init_mutex(&c->vk); if (ret != VK_SUCCESS) { + CVK_ERROR(c, "vk_init_mutex", "Failed to init mutex.", ret); return false; } @@ -964,7 +968,12 @@ compositor_init_vulkan(struct comp_compositor *c) } ret = vk_init_cmd_pool(&c->vk); - return ret == VK_SUCCESS; + if (ret != VK_SUCCESS) { + CVK_ERROR(c, "vk_init_cmd_pool", "Failed to init command pool.", ret); + return false; + } + + return true; } @@ -1002,6 +1011,8 @@ _match_wl_entry(const char *wl_entry, VkDisplayPropertiesKHR *disp) static bool _test_for_nvidia(struct comp_compositor *c, struct vk_bundle *vk) { + VkResult ret; + VkPhysicalDeviceProperties physical_device_properties; vk->vkGetPhysicalDeviceProperties(vk->physical_device, &physical_device_properties); @@ -1011,8 +1022,9 @@ _test_for_nvidia(struct comp_compositor *c, struct vk_bundle *vk) // get a list of attached displays uint32_t display_count; - if (vk->vkGetPhysicalDeviceDisplayPropertiesKHR(vk->physical_device, &display_count, NULL) != VK_SUCCESS) { - COMP_ERROR(c, "Failed to get vulkan display count"); + ret = vk->vkGetPhysicalDeviceDisplayPropertiesKHR(vk->physical_device, &display_count, NULL); + if (ret != VK_SUCCESS) { + CVK_ERROR(c, "vkGetPhysicalDeviceDisplayPropertiesKHR", "Failed to get vulkan display count", ret); return false; } @@ -1020,7 +1032,7 @@ _test_for_nvidia(struct comp_compositor *c, struct vk_bundle *vk) if (display_props && vk->vkGetPhysicalDeviceDisplayPropertiesKHR(vk->physical_device, &display_count, display_props) != VK_SUCCESS) { - COMP_ERROR(c, "Failed to get display properties"); + CVK_ERROR(c, "vkGetPhysicalDeviceDisplayPropertiesKHR", "Failed to get display properties", ret); free(display_props); return false; } @@ -1078,6 +1090,7 @@ compositor_check_vulkan_caps(struct comp_compositor *c) struct vk_bundle temp_vk = {0}; ret = vk_get_loader_functions(&temp_vk, vkGetInstanceProcAddr); if (ret != VK_SUCCESS) { + CVK_ERROR(c, "vk_get_loader_functions", "Failed to get loader functions.", ret); return false; } @@ -1092,13 +1105,13 @@ compositor_check_vulkan_caps(struct comp_compositor *c) ret = temp_vk.vkCreateInstance(&instance_create_info, NULL, &(temp_vk.instance)); if (ret != VK_SUCCESS) { - COMP_ERROR(c, "Failed to create VkInstance: %s", vk_result_string(ret)); + CVK_ERROR(c, "vkCreateInstance", "Failed to create VkInstance.", ret); return false; } ret = vk_get_instance_functions(&temp_vk); if (ret != VK_SUCCESS) { - COMP_ERROR(c, "Failed to get Vulkan instance functions: %s", vk_result_string(ret)); + CVK_ERROR(c, "vk_get_instance_functions", "Failed to get Vulkan instance functions.", ret); return false; } @@ -1113,7 +1126,7 @@ compositor_check_vulkan_caps(struct comp_compositor *c) ARRAY_SIZE(optional_device_extensions)); // if (ret != VK_SUCCESS) { - COMP_ERROR(c, "Failed to create VkDevice: %s", vk_result_string(ret)); + CVK_ERROR(c, "vk_create_device", "Failed to create VkDevice.", ret); return false; } @@ -1173,9 +1186,7 @@ compositor_init_window_pre_vulkan(struct comp_compositor *c) #ifdef VK_USE_PLATFORM_XCB_KHR if (compositor_try_window(c, comp_window_xcb_create(c))) { c->settings.window_type = WINDOW_XCB; - COMP_DEBUG(c, - "Using VK_PRESENT_MODE_IMMEDIATE_KHR for " - "xcb window") + COMP_DEBUG(c, "Using VK_PRESENT_MODE_IMMEDIATE_KHR for xcb window") c->settings.present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; return true; } @@ -1370,7 +1381,7 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos !compositor_init_shaders(c) || !compositor_init_swapchain(c) || !compositor_init_renderer(c)) { - COMP_DEBUG(c, "Failed to init compositor %p", (void *)c); + COMP_ERROR(c, "Failed to init compositor %p", (void *)c); c->base.base.destroy(&c->base.base); return XRT_ERROR_VULKAN; From 2adbde4673e3b122081425ef2920a75079639224 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:28:12 -0500 Subject: [PATCH 444/883] a/util: Add u_device_get_view_pose helper function. I saw many, many exact copies of this function in the code: good to de-duplicate them. --- src/xrt/auxiliary/util/u_device.c | 27 ++++++++++++++++++++++++++- src/xrt/auxiliary/util/u_device.h | 19 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/util/u_device.c b/src/xrt/auxiliary/util/u_device.c index 3abc947f9..55ca8cf77 100644 --- a/src/xrt/auxiliary/util/u_device.c +++ b/src/xrt/auxiliary/util/u_device.c @@ -1,9 +1,10 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file * @brief Misc helpers for device drivers. * @author Jakob Bornecrantz + * @author Ryan Pavlik * @ingroup aux_util */ @@ -395,3 +396,27 @@ u_device_setup_tracking_origins(struct xrt_device *head, apply_offset(&right->tracking_origin->offset.position, global_tracking_origin_offset); } } + +void +u_device_get_view_pose(const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) +{ + struct xrt_pose pose = XRT_POSE_IDENTITY; + bool adjust = view_index == 0; + + pose.position.x = eye_relation->x / 2.0f; + pose.position.y = eye_relation->y / 2.0f; + pose.position.z = eye_relation->z / 2.0f; + + // Adjust for left/right while also making sure there aren't any -0.f. + if (pose.position.x > 0.0f && adjust) { + pose.position.x = -pose.position.x; + } + if (pose.position.y > 0.0f && adjust) { + pose.position.y = -pose.position.y; + } + if (pose.position.z > 0.0f && adjust) { + pose.position.z = -pose.position.z; + } + + *out_pose = pose; +} diff --git a/src/xrt/auxiliary/util/u_device.h b/src/xrt/auxiliary/util/u_device.h index b29d1b9a6..857ebb705 100644 --- a/src/xrt/auxiliary/util/u_device.h +++ b/src/xrt/auxiliary/util/u_device.h @@ -1,9 +1,10 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file * @brief Misc helpers for device drivers. * @author Jakob Bornecrantz + * @author Ryan Pavlik * @ingroup aux_util */ @@ -113,6 +114,22 @@ u_device_setup_tracking_origins(struct xrt_device *head, struct xrt_device *right, struct xrt_vec3 *global_tracking_origin_offset); +/*! + * Helper function for `get_view_pose` in an HMD driver. + * + * Takes in a translation from the left to right eye, and returns a center to left or right eye transform that assumes + * the eye relation is symmetrical around the tracked point ("center eye"). Knowing IPD is a subset of this: If you know + * IPD better than the overall Monado system, copy @p eye_relation and put your known IPD in @p real_eye_relation->x + * + * If you have rotation, apply it after calling this function. + * + * @param eye_relation 3D translation from left eye to right eye. + * @param view_index 0 for left, 1 for right. + * @param out_pose The output pose to populate. Will receive translation, with an identity rotation. + */ +void +u_device_get_view_pose(const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose); + #ifdef __cplusplus } #endif From f4a1c5344b36269ed93ccad410c7a09a38c947d8 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:35:51 -0500 Subject: [PATCH 445/883] d/android_sensors: Port to u_device_get_view_pose --- src/xrt/drivers/android/android_sensors.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/xrt/drivers/android/android_sensors.c b/src/xrt/drivers/android/android_sensors.c index 00159a809..d717dc3e8 100644 --- a/src/xrt/drivers/android/android_sensors.c +++ b/src/xrt/drivers/android/android_sensors.c @@ -174,25 +174,8 @@ android_device_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = view_index == 0; - - pose.position.x = eye_relation->x / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + (void)xdev; + u_device_get_view_pose(eye_relation, view_index, out_pose); } /* From d45e13642eeb6d66786fdc83971ae0692f93d406 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:35:59 -0500 Subject: [PATCH 446/883] d/dummy: Port to u_device_get_view_pose --- src/xrt/drivers/dummy/dummy_hmd.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/xrt/drivers/dummy/dummy_hmd.c b/src/xrt/drivers/dummy/dummy_hmd.c index ad4b030b1..edcb28df4 100644 --- a/src/xrt/drivers/dummy/dummy_hmd.c +++ b/src/xrt/drivers/dummy/dummy_hmd.c @@ -125,25 +125,8 @@ dummy_hmd_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = view_index == 0; - - pose.position.x = eye_relation->x / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + (void)xdev; + u_device_get_view_pose(eye_relation, view_index, out_pose); } struct xrt_device * From 2774b3375fbe50f50c84659c4533c1d760b0ff4c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:36:07 -0500 Subject: [PATCH 447/883] d/north_star: Port to u_device_get_view_pose --- src/xrt/drivers/north_star/ns_hmd.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/xrt/drivers/north_star/ns_hmd.c b/src/xrt/drivers/north_star/ns_hmd.c index b9dc958f3..929b1ad6a 100644 --- a/src/xrt/drivers/north_star/ns_hmd.c +++ b/src/xrt/drivers/north_star/ns_hmd.c @@ -205,29 +205,11 @@ ns_v2_hmd_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - // Copied from dummy driver - struct ns_hmd *ns = ns_hmd(xdev); + struct xrt_vec3 real_eye_relation = *eye_relation; + real_eye_relation.x = ns->ipd; - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = view_index == 0; - - pose.position.x = ns->ipd / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + u_device_get_view_pose(&real_eye_relation, view_index, out_pose); } static float From 7c5342efe21b2a191c52631b8c361a95ff677bcf Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:36:15 -0500 Subject: [PATCH 448/883] d/oh: Port to u_device_get_view_pose --- src/xrt/drivers/ohmd/oh_device.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c index a3b096e9b..98e0db0ff 100644 --- a/src/xrt/drivers/ohmd/oh_device.c +++ b/src/xrt/drivers/ohmd/oh_device.c @@ -436,25 +436,8 @@ oh_device_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = view_index == 0; - - pose.position.x = eye_relation->x / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + (void)xdev; + u_device_get_view_pose(eye_relation, view_index, out_pose); } struct display_info From 89895be83bfd3fbb6360a06830f4027eac9072da Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:36:30 -0500 Subject: [PATCH 449/883] d/psvr: Port to u_device_get_view_pose --- src/xrt/drivers/psvr/psvr_device.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/xrt/drivers/psvr/psvr_device.c b/src/xrt/drivers/psvr/psvr_device.c index 7392d081d..9188b16bd 100644 --- a/src/xrt/drivers/psvr/psvr_device.c +++ b/src/xrt/drivers/psvr/psvr_device.c @@ -933,25 +933,8 @@ psvr_device_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = view_index == 0; - - pose.position.x = eye_relation->x / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + (void)xdev; + u_device_get_view_pose(eye_relation, view_index, out_pose); } static void From 52c00436c74436e554068f16e9939209144f252d Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:36:40 -0500 Subject: [PATCH 450/883] d/remote: Port to u_device_get_view_pose --- src/xrt/drivers/remote/r_hmd.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/xrt/drivers/remote/r_hmd.c b/src/xrt/drivers/remote/r_hmd.c index 1aa1df9ff..0be94a456 100644 --- a/src/xrt/drivers/remote/r_hmd.c +++ b/src/xrt/drivers/remote/r_hmd.c @@ -89,25 +89,8 @@ r_hmd_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = view_index == 0; - - pose.position.x = eye_relation->x / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + (void)xdev; + u_device_get_view_pose(eye_relation, view_index, out_pose); } static void From 6682bb02910ee5cfcfa3dc0084005621a7a9540b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:36:47 -0500 Subject: [PATCH 451/883] d/hdk: Port to u_device_get_view_pose --- src/xrt/drivers/hdk/hdk_device.cpp | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/xrt/drivers/hdk/hdk_device.cpp b/src/xrt/drivers/hdk/hdk_device.cpp index 883eaab0c..a082d45c4 100644 --- a/src/xrt/drivers/hdk/hdk_device.cpp +++ b/src/xrt/drivers/hdk/hdk_device.cpp @@ -264,25 +264,8 @@ hdk_device_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = view_index == 0; - - pose.position.x = eye_relation->x / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + (void)xdev; + u_device_get_view_pose(eye_relation, view_index, out_pose); } static void * From 2d47c496e60412afeb068eadac5f33f0a75dd5bf Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:36:57 -0500 Subject: [PATCH 452/883] d/survive: Port to u_device_get_view_pose --- src/xrt/drivers/survive/survive_driver.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index 0faf8a413..1190fd8b2 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -447,27 +447,9 @@ survive_device_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = view_index == 0; - struct survive_device *survive = (struct survive_device *)xdev; - pose.orientation = survive->hmd.config.display.rot[view_index]; - pose.position.x = eye_relation->x / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + u_device_get_view_pose(eye_relation, view_index, out_pose); + out_pose->orientation = survive->hmd.config.display.rot[view_index]; } enum InputComponent From 3b0a6a558c043faed799f55a1a3f934e5318374b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:37:06 -0500 Subject: [PATCH 453/883] d/vive: Port to u_device_get_view_pose --- src/xrt/drivers/vive/vive_device.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index ceced9690..08d4799b8 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -142,27 +142,9 @@ vive_device_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { + u_device_get_view_pose(eye_relation, view_index, out_pose); struct vive_device *d = vive_device(xdev); - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = view_index == 0; - - pose.orientation = d->config.display.rot[view_index]; - pose.position.x = eye_relation->x / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + out_pose->orientation = d->config.display.rot[view_index]; } static int From e44c6d56c7a8b9d416559df43663980d2b76bfae Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:37:51 -0500 Subject: [PATCH 454/883] d/wmr: Port to u_device_get_view_pose --- src/xrt/drivers/wmr/wmr_hmd.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index fc1e4d20e..619188cac 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -416,25 +416,8 @@ wmr_hmd_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; - bool adjust = (view_index == 0); - - pose.position.x = eye_relation->x / 2.0f; - pose.position.y = eye_relation->y / 2.0f; - pose.position.z = eye_relation->z / 2.0f; - - // Adjust for left/right while also making sure there aren't any -0.f. - if (pose.position.x > 0.0f && adjust) { - pose.position.x = -pose.position.x; - } - if (pose.position.y > 0.0f && adjust) { - pose.position.y = -pose.position.y; - } - if (pose.position.z > 0.0f && adjust) { - pose.position.z = -pose.position.z; - } - - *out_pose = pose; + (void)xdev; + u_device_get_view_pose(eye_relation, view_index, out_pose); } static void From 8c0aabfc0d8f8f942302be30db1b5ea102a380a4 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 14:47:54 -0500 Subject: [PATCH 455/883] xrt: Add definitions for zero/identity initializers for pose-related structs. --- src/xrt/include/xrt/xrt_defines.h | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/xrt/include/xrt/xrt_defines.h b/src/xrt/include/xrt/xrt_defines.h index c91b9fdcb..1e16cedf4 100644 --- a/src/xrt/include/xrt/xrt_defines.h +++ b/src/xrt/include/xrt/xrt_defines.h @@ -111,6 +111,17 @@ struct xrt_quat float w; }; +/*! + * Identity value for @ref xrt_quat + * + * @ingroup xrt_iface math + * @relates xrt_quat + */ +#define XRT_QUAT_IDENTITY \ + { \ + 0.f, 0.f, 0.f, 1.f \ + } + /*! * A 1 element vector with single floats. * @@ -154,6 +165,17 @@ struct xrt_vec3 float z; }; +/*! + * All-zero value for @ref xrt_vec3 + * + * @ingroup xrt_iface math + * @relates xrt_vec3 + */ +#define XRT_VEC3_ZERO \ + { \ + 0.f, 0.f, 0.f \ + } + /*! * A 3 element vector with 32 bit integers. * @@ -271,6 +293,16 @@ struct xrt_pose struct xrt_quat orientation; struct xrt_vec3 position; }; +/*! + * Identity value for @ref xrt_pose + * + * @ingroup xrt_iface math + * @relates xrt_pose + */ +#define XRT_POSE_IDENTITY \ + { \ + XRT_QUAT_IDENTITY, XRT_VEC3_ZERO \ + } /*! * Describes a projection matrix fov. @@ -374,6 +406,20 @@ struct xrt_space_relation struct xrt_vec3 angular_velocity; }; +/*! + * A zero/identity value for @ref xrt_space_relation + * + * @note Despite this initializing all members (to zero or identity), this sets the xrt_space_relation::relation_flags + * to XRT_SPACE_RELATION_BITMASK_NONE - so this is safe to assign before an error return, etc. + * + * @ingroup xrt_iface math + * @relates xrt_space_relation + */ +#define XRT_SPACE_RELATION_ZERO \ + { \ + XRT_SPACE_RELATION_BITMASK_NONE, XRT_POSE_IDENTITY, XRT_VEC3_ZERO, XRT_VEC3_ZERO \ + } + /*! * The maximum number of steps that can be in a space graph chain. * From edc6490d74e12c5da9580710b93aea11bfdd994e Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 14:51:32 -0500 Subject: [PATCH 456/883] a/math: Port to using the new zero/identity defines --- src/xrt/auxiliary/math/m_space.cpp | 33 +++++++++++++----------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/xrt/auxiliary/math/m_space.cpp b/src/xrt/auxiliary/math/m_space.cpp index 73ab3bab1..baecba29b 100644 --- a/src/xrt/auxiliary/math/m_space.cpp +++ b/src/xrt/auxiliary/math/m_space.cpp @@ -126,18 +126,13 @@ make_valid_pose(flags flags, const struct xrt_pose *in_pose, struct xrt_pose *ou if (flags.has_orientation) { out_pose->orientation = in_pose->orientation; } else { - out_pose->orientation.x = 0.0f; - out_pose->orientation.y = 0.0f; - out_pose->orientation.z = 0.0f; - out_pose->orientation.w = 1.0f; + out_pose->orientation = XRT_QUAT_IDENTITY; } if (flags.has_position) { out_pose->position = in_pose->position; } else { - out_pose->position.x = 0.0f; - out_pose->position.y = 0.0f; - out_pose->position.z = 0.0f; + out_pose->position = XRT_VEC3_ZERO; } } @@ -150,9 +145,9 @@ apply_relation(const struct xrt_space_relation *a, flags bf = get_flags(b); flags nf = {}; - struct xrt_pose pose = {}; - struct xrt_vec3 linear_velocity = {}; - struct xrt_vec3 angular_velocity = {}; + struct xrt_pose pose = XRT_POSE_IDENTITY; + struct xrt_vec3 linear_velocity = XRT_VEC3_ZERO; + struct xrt_vec3 angular_velocity = XRT_VEC3_ZERO; /* @@ -161,7 +156,7 @@ apply_relation(const struct xrt_space_relation *a, if (af.has_linear_velocity) { nf.has_linear_velocity = true; - struct xrt_vec3 tmp = {}; + struct xrt_vec3 tmp = XRT_VEC3_ZERO; math_quat_rotate_vec3(&b->pose.orientation, // Base rotation &a->linear_velocity, // In base space &tmp); // Output @@ -180,7 +175,7 @@ apply_relation(const struct xrt_space_relation *a, if (af.has_angular_velocity) { nf.has_angular_velocity = true; - struct xrt_vec3 tmp = {}; + struct xrt_vec3 tmp = XRT_VEC3_ZERO; math_quat_rotate_derivative(&b->pose.orientation, // Base rotation &a->angular_velocity, // In base space @@ -194,10 +189,10 @@ apply_relation(const struct xrt_space_relation *a, nf.has_linear_velocity = true; angular_velocity += b->angular_velocity; - struct xrt_vec3 rotated_position = {}; - struct xrt_vec3 position = {}; - struct xrt_quat orientation = {}; - struct xrt_vec3 tangental_velocity = {}; + struct xrt_vec3 rotated_position = XRT_VEC3_ZERO; + struct xrt_vec3 position = XRT_VEC3_ZERO; + struct xrt_quat orientation = XRT_QUAT_IDENTITY; + struct xrt_vec3 tangental_velocity = XRT_VEC3_ZERO; position = a->pose.position; // In the base space orientation = b->pose.orientation; // Base space @@ -218,8 +213,8 @@ apply_relation(const struct xrt_space_relation *a, * Apply the pose part. */ - struct xrt_pose body_pose = {}; - struct xrt_pose base_pose = {}; + struct xrt_pose body_pose = XRT_POSE_IDENTITY; + struct xrt_pose base_pose = XRT_POSE_IDENTITY; // Only valid poses handled in graph. Flags are determined later. make_valid_pose(af, &a->pose, &body_pose); @@ -284,7 +279,7 @@ void m_space_graph_resolve(const struct xrt_space_graph *xsg, struct xrt_space_relation *out_relation) { if (xsg->num_steps == 0 || has_step_with_no_pose(xsg)) { - U_ZERO(out_relation); + *out_relation = XRT_SPACE_RELATION_ZERO; return; } From cb8925ae048f8ec924b730375d3241ba927ea265 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:04:47 -0500 Subject: [PATCH 457/883] u/ht: Port to using new zero/identity defines --- src/xrt/auxiliary/util/u_hand_tracking.c | 60 ++++++++++++------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/xrt/auxiliary/util/u_hand_tracking.c b/src/xrt/auxiliary/util/u_hand_tracking.c index d78e1d930..ade01d055 100644 --- a/src/xrt/auxiliary/util/u_hand_tracking.c +++ b/src/xrt/auxiliary/util/u_hand_tracking.c @@ -60,7 +60,7 @@ struct u_joint_curl_model static struct u_joint_curl_model hand_joint_default_set_curl_model_defaults[XRT_HAND_JOINT_COUNT] = { // special cases: wrist and palm without bone lengths, offsets are // absolute, relative to hand origin (palm) - [XRT_HAND_JOINT_PALM] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_PALM] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0, .radius = 0.018, @@ -84,25 +84,25 @@ static struct u_joint_curl_model hand_joint_default_set_curl_model_defaults[XRT_ .radius = 0.015, .joint_id = XRT_HAND_JOINT_LITTLE_METACARPAL}, - [XRT_HAND_JOINT_LITTLE_PROXIMAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_LITTLE_PROXIMAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, DEG_TO_RAD(20), 0}, .bone_length = 0.035, .radius = 0.01, .joint_id = XRT_HAND_JOINT_LITTLE_PROXIMAL}, - [XRT_HAND_JOINT_LITTLE_INTERMEDIATE] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_LITTLE_INTERMEDIATE] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.028, .radius = 0.009, .joint_id = XRT_HAND_JOINT_LITTLE_INTERMEDIATE}, - [XRT_HAND_JOINT_LITTLE_DISTAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_LITTLE_DISTAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.022, .radius = 0.009, .joint_id = XRT_HAND_JOINT_LITTLE_DISTAL}, - [XRT_HAND_JOINT_LITTLE_TIP] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_LITTLE_TIP] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0, .radius = 0.012, @@ -115,25 +115,25 @@ static struct u_joint_curl_model hand_joint_default_set_curl_model_defaults[XRT_ .radius = 0.015, .joint_id = XRT_HAND_JOINT_RING_METACARPAL}, - [XRT_HAND_JOINT_RING_PROXIMAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_RING_PROXIMAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, DEG_TO_RAD(10), 0}, .bone_length = 0.040, .radius = 0.012, .joint_id = XRT_HAND_JOINT_RING_PROXIMAL}, - [XRT_HAND_JOINT_RING_INTERMEDIATE] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_RING_INTERMEDIATE] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.031, .radius = 0.01, .joint_id = XRT_HAND_JOINT_RING_INTERMEDIATE}, - [XRT_HAND_JOINT_RING_DISTAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_RING_DISTAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.023, .radius = 0.01, .joint_id = XRT_HAND_JOINT_RING_DISTAL}, - [XRT_HAND_JOINT_RING_TIP] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_RING_TIP] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0, .radius = 0.013, @@ -146,25 +146,25 @@ static struct u_joint_curl_model hand_joint_default_set_curl_model_defaults[XRT_ .radius = 0.012, .joint_id = XRT_HAND_JOINT_MIDDLE_METACARPAL}, - [XRT_HAND_JOINT_MIDDLE_PROXIMAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_MIDDLE_PROXIMAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.042, .radius = 0.01, .joint_id = XRT_HAND_JOINT_MIDDLE_PROXIMAL}, - [XRT_HAND_JOINT_MIDDLE_INTERMEDIATE] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_MIDDLE_INTERMEDIATE] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.033, .radius = 0.01, .joint_id = XRT_HAND_JOINT_MIDDLE_INTERMEDIATE}, - [XRT_HAND_JOINT_MIDDLE_DISTAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_MIDDLE_DISTAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.024, .radius = 0.01, .joint_id = XRT_HAND_JOINT_MIDDLE_DISTAL}, - [XRT_HAND_JOINT_MIDDLE_TIP] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_MIDDLE_TIP] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0, .radius = 0.01, @@ -177,25 +177,25 @@ static struct u_joint_curl_model hand_joint_default_set_curl_model_defaults[XRT_ .radius = 0.012, .joint_id = XRT_HAND_JOINT_INDEX_METACARPAL}, - [XRT_HAND_JOINT_INDEX_PROXIMAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_INDEX_PROXIMAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, DEG_TO_RAD(-10), 0}, .bone_length = 0.040, .radius = 0.011, .joint_id = XRT_HAND_JOINT_INDEX_PROXIMAL}, - [XRT_HAND_JOINT_INDEX_INTERMEDIATE] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_INDEX_INTERMEDIATE] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.031, .radius = 0.01, .joint_id = XRT_HAND_JOINT_INDEX_INTERMEDIATE}, - [XRT_HAND_JOINT_INDEX_DISTAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_INDEX_DISTAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.023, .radius = 0.01, .joint_id = XRT_HAND_JOINT_INDEX_DISTAL}, - [XRT_HAND_JOINT_INDEX_TIP] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_INDEX_TIP] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0, .radius = 0.01, @@ -208,20 +208,20 @@ static struct u_joint_curl_model hand_joint_default_set_curl_model_defaults[XRT_ .radius = 0.0175, .joint_id = XRT_HAND_JOINT_THUMB_METACARPAL}, - [XRT_HAND_JOINT_THUMB_PROXIMAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_THUMB_PROXIMAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, DEG_TO_RAD(-12), 0}, .bone_length = 0.038, .radius = 0.017, .joint_id = XRT_HAND_JOINT_THUMB_PROXIMAL}, // no intermediate - [XRT_HAND_JOINT_THUMB_DISTAL] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_THUMB_DISTAL] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0.028, .radius = 0.017, .joint_id = XRT_HAND_JOINT_THUMB_DISTAL}, - [XRT_HAND_JOINT_THUMB_TIP] = {.position_offset = {.x = 0, .y = 0, .z = 0}, + [XRT_HAND_JOINT_THUMB_TIP] = {.position_offset = XRT_VEC3_ZERO, .axis_angle_offset = {0, 0, 0}, .bone_length = 0, .radius = 0.016, @@ -325,7 +325,7 @@ u_hand_joint_compute_next_by_curl(struct u_hand_tracking *set, //! @todo more axis rotations & make sure order is right //! @todo handle velocities - struct xrt_pose offset_pose; + struct xrt_pose offset_pose = XRT_POSE_IDENTITY; if (hand == XRT_HAND_LEFT) { quat_from_angle_vector_clockwise(defaults.axis_angle_offset[1], &y_axis, &offset_pose.orientation); offset_pose.position = defaults.position_offset; @@ -385,7 +385,7 @@ u_hand_joint_compute_next_by_curl(struct u_hand_tracking *set, math_quat_finite_difference(&old_relation.pose.orientation, &out_joint->relation.pose.orientation, time_diff_s, &out_joint->relation.angular_velocity); } else { - out_joint->relation.angular_velocity = (struct xrt_vec3){0, 0, 0}; + out_joint->relation.angular_velocity = (struct xrt_vec3)XRT_VEC3_ZERO; } out_joint->relation.relation_flags = POSE_VALID_FLAGS | VELOCIY_VALID_FLAGS; @@ -403,7 +403,7 @@ u_hand_joints_update_curl(struct u_hand_tracking *set, float curl_index = curl_values->index; float curl_thumb = curl_values->thumb; - const struct xrt_quat identity_quat = {0, 0, 0, 1}; + const struct xrt_quat identity_quat = XRT_QUAT_IDENTITY; //! @todo: full relations with velocities @@ -411,15 +411,15 @@ u_hand_joints_update_curl(struct u_hand_tracking *set, set->joints.wrist.relation.pose = (struct xrt_pose){ .position = hand_joint_default_set_curl_model_defaults[XRT_HAND_JOINT_WRIST].position_offset, .orientation = identity_quat}; - set->joints.wrist.relation.linear_velocity = (struct xrt_vec3){0, 0, 0}; - set->joints.wrist.relation.angular_velocity = (struct xrt_vec3){0, 0, 0}; + set->joints.wrist.relation.linear_velocity = (struct xrt_vec3)XRT_VEC3_ZERO; + set->joints.wrist.relation.angular_velocity = (struct xrt_vec3)XRT_VEC3_ZERO; set->joints.wrist.relation.relation_flags = POSE_VALID_FLAGS | VELOCIY_VALID_FLAGS; set->joints.palm.relation.pose = (struct xrt_pose){ .position = hand_joint_default_set_curl_model_defaults[XRT_HAND_JOINT_PALM].position_offset, .orientation = identity_quat}; - set->joints.palm.relation.linear_velocity = (struct xrt_vec3){0, 0, 0}; - set->joints.palm.relation.angular_velocity = (struct xrt_vec3){0, 0, 0}; + set->joints.palm.relation.linear_velocity = (struct xrt_vec3)XRT_VEC3_ZERO; + set->joints.palm.relation.angular_velocity = (struct xrt_vec3)XRT_VEC3_ZERO; set->joints.palm.relation.relation_flags = POSE_VALID_FLAGS | VELOCIY_VALID_FLAGS; struct u_joint_space_relation *prev = &set->joints.wrist; @@ -704,13 +704,13 @@ u_hand_joints_offset_valve_index_controller(enum xrt_hand hand, struct xrt_vec3 } - struct xrt_quat hand_rotation_y = {0, 0, 0, 1}; + struct xrt_quat hand_rotation_y = XRT_QUAT_IDENTITY; math_quat_from_angle_vector(hand_on_handle_y_rotation, &y, &hand_rotation_y); - struct xrt_quat hand_rotation_z = {0, 0, 0, 1}; math_quat_from_angle_vector(hand_on_handle_z_rotation, &z, &hand_rotation_z); + struct xrt_quat hand_rotation_z = XRT_QUAT_IDENTITY; - struct xrt_quat hand_rotation_x = {0, 0, 0, 1}; + struct xrt_quat hand_rotation_x = XRT_QUAT_IDENTITY; math_quat_from_angle_vector(hand_on_handle_x_rotation, &x, &hand_rotation_x); struct xrt_quat hand_rotation; From 20053252aa32b2ec22ca19415dd16d95aa266da1 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:05:34 -0500 Subject: [PATCH 458/883] m/space: Port to using new zero/identity defines --- src/xrt/auxiliary/math/m_space.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/xrt/auxiliary/math/m_space.h b/src/xrt/auxiliary/math/m_space.h index 502041683..fb569fb4d 100644 --- a/src/xrt/auxiliary/math/m_space.h +++ b/src/xrt/auxiliary/math/m_space.h @@ -65,8 +65,8 @@ m_space_relation_from_pose(const struct xrt_pose *pose, struct xrt_space_relatio struct xrt_space_relation relation = { flags, *pose, - {0, 0, 0}, - {0, 0, 0}, + XRT_VEC3_ZERO, + XRT_VEC3_ZERO, }; *out_relation = relation; @@ -75,10 +75,7 @@ m_space_relation_from_pose(const struct xrt_pose *pose, struct xrt_space_relatio static inline void m_space_relation_ident(struct xrt_space_relation *out_relation) { - struct xrt_pose identity = { - {0, 0, 0, 1}, - {0, 0, 0}, - }; + struct xrt_pose identity = XRT_POSE_IDENTITY; m_space_relation_from_pose(&identity, out_relation); } From 6f46fcc25186b606e52fcdb6ebd07910efe1e35d Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:06:15 -0500 Subject: [PATCH 459/883] aux/vive: Port to using new zero/identity defines --- src/xrt/auxiliary/vive/vive_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/vive/vive_config.c b/src/xrt/auxiliary/vive/vive_config.c index 8211b2873..eb869e51c 100644 --- a/src/xrt/auxiliary/vive/vive_config.c +++ b/src/xrt/auxiliary/vive/vive_config.c @@ -162,7 +162,7 @@ _get_lighthouse(struct vive_config *d, const cJSON *json) // Transform the sensors into IMU space. - struct xrt_pose trackref_to_imu = {0}; + struct xrt_pose trackref_to_imu = XRT_POSE_IDENTITY; math_pose_invert(&d->imu.trackref, &trackref_to_imu); for (i = 0; i < d->lh.num_sensors; i++) { From 2dd81f53e347a191930b6ef3dd4f095e83c6f356 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:06:53 -0500 Subject: [PATCH 460/883] comp: Port to using new zero/identity defines --- src/xrt/compositor/main/comp_renderer.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index 1c626c371..12fce0af9 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -541,10 +541,7 @@ renderer_get_view_projection(struct comp_renderer *r) 0.0f, }; - struct xrt_pose base_space_pose = { - .position = (struct xrt_vec3){0, 0, 0}, - .orientation = (struct xrt_quat){0, 0, 0, 1}, - }; + struct xrt_pose base_space_pose = XRT_POSE_IDENTITY; for (uint32_t i = 0; i < 2; i++) { struct xrt_fov fov = r->c->xdev->hmd->views[i].fov; From 71fabf50c549e93b528ebc16c0c131ae704e6b6f Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:11:39 -0500 Subject: [PATCH 461/883] d/north_star: Port to using new zero/identity defines --- src/xrt/drivers/north_star/ns_hmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/north_star/ns_hmd.c b/src/xrt/drivers/north_star/ns_hmd.c index 929b1ad6a..645c2b1b8 100644 --- a/src/xrt/drivers/north_star/ns_hmd.c +++ b/src/xrt/drivers/north_star/ns_hmd.c @@ -35,7 +35,7 @@ DEBUG_GET_ONCE_LOG_OPTION(ns_log, "NS_LOG", U_LOGGING_INFO) -struct xrt_pose t265_to_nose_bridge = {.orientation = {0, 0, 0, 1}, .position = {0, 0, 0}}; +struct xrt_pose t265_to_nose_bridge = XRT_POSE_IDENTITY; /* * From 85ea0f8f78bef6d58a509d07686bcc001ab4d861 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:12:21 -0500 Subject: [PATCH 462/883] d/oh: Port to using new zero/identity defines --- src/xrt/drivers/ohmd/oh_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c index 98e0db0ff..87a57da8c 100644 --- a/src/xrt/drivers/ohmd/oh_device.c +++ b/src/xrt/drivers/ohmd/oh_device.c @@ -332,8 +332,8 @@ oh_device_get_tracked_pose(struct xrt_device *xdev, struct xrt_space_relation *out_relation) { struct oh_device *ohd = oh_device(xdev); - struct xrt_quat quat = {0.f, 0.f, 0.f, 1.f}; - struct xrt_vec3 pos = {0.f, 0.f, 0.f}; + struct xrt_quat quat = XRT_QUAT_IDENTITY; + struct xrt_vec3 pos = XRT_VEC3_ZERO; // support generic head pose for all hmds, // support rift poses for rift controllers, and simple poses for generic controller From fde3e631cf3b3d3d86751bb65e5a487b3ecae521 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:15:12 -0500 Subject: [PATCH 463/883] d/qwerty: Port to using new zero/identity defines --- src/xrt/drivers/qwerty/qwerty_device.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index e03255195..2ee143f01 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -199,7 +199,7 @@ qwerty_get_view_pose(struct xrt_device *xd, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; + struct xrt_pose pose = XRT_POSE_IDENTITY; bool is_left = view_index == 0; float adjust = is_left ? -0.5f : 0.5f; struct xrt_vec3 eye_offset = *eye_relation; @@ -532,10 +532,9 @@ qwerty_reset_controller_pose(struct qwerty_controller *qc) return; } - struct xrt_quat quat_identity = {0, 0, 0, 1}; bool is_left = qc == qd->sys->lctrl; qwerty_follow_hmd(qc, true); - struct xrt_pose pose = {quat_identity, QWERTY_CONTROLLER_INITIAL_POS(is_left)}; + struct xrt_pose pose = {XRT_QUAT_IDENTITY, QWERTY_CONTROLLER_INITIAL_POS(is_left)}; qd->pose = pose; } From 06eab724ec3dc6081fb4aa08a802ce305985258d Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:15:56 -0500 Subject: [PATCH 464/883] d/remote: Port to using new zero/identity defines --- src/xrt/drivers/remote/r_device.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/xrt/drivers/remote/r_device.c b/src/xrt/drivers/remote/r_device.c index 91f0008e5..f21af1299 100644 --- a/src/xrt/drivers/remote/r_device.c +++ b/src/xrt/drivers/remote/r_device.c @@ -138,10 +138,7 @@ r_device_get_hand_tracking(struct xrt_device *xdev, enum xrt_hand hand = rd->is_left ? XRT_HAND_LEFT : XRT_HAND_RIGHT; u_hand_joints_update_curl(&rd->hand_tracking, hand, at_timestamp_ns, &values); - struct xrt_pose hand_on_handle_pose = { - {0, 0, 0, 1}, - {0, 0, 0}, - }; + struct xrt_pose hand_on_handle_pose = XRT_POSE_IDENTITY; struct xrt_space_relation relation; xrt_device_get_tracked_pose(xdev, XRT_INPUT_SIMPLE_GRIP_POSE, at_timestamp_ns, &relation); From c3ce7f33a0d8f401f7e023c332f6ecf465e20520 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:16:18 -0500 Subject: [PATCH 465/883] d/ht: Port to using new zero/identity defines --- src/xrt/drivers/ht/ht_driver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/xrt/drivers/ht/ht_driver.c b/src/xrt/drivers/ht/ht_driver.c index cdab9cd61..55f5d66a8 100644 --- a/src/xrt/drivers/ht/ht_driver.c +++ b/src/xrt/drivers/ht/ht_driver.c @@ -78,8 +78,7 @@ ht_device_get_hand_tracking(struct xrt_device *xdev, &htd->hand_relation[index]); htd->u_tracking[index].timestamp_ns = at_timestamp_ns; - struct xrt_pose identity = {.orientation = {.x = 0, .y = 0, .z = 0, .w = 1}, - .position = {.x = 0, .y = 0, .z = 0}}; + struct xrt_pose identity = XRT_POSE_IDENTITY; u_hand_joints_set_out_data(&htd->u_tracking[index], hand, &htd->hand_relation[index], &identity, out_value); } From 48d043796cf7e1288fb8e19a8d992411fc9c6dcd Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:17:08 -0500 Subject: [PATCH 466/883] d/vive: Port to using new zero/identity defines --- src/xrt/drivers/vive/vive_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index 08d4799b8..93b81a75c 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -228,7 +228,7 @@ vive_mainboard_decode_message(struct vive_device *d, struct vive_mainboard_statu if (d->board.button != report->button) { d->board.button = report->button; VIVE_TRACE(d, "Button %d.", report->button); - d->rot_filtered = (struct xrt_quat){0, 0, 0, 1}; + d->rot_filtered = (struct xrt_quat)XRT_QUAT_IDENTITY; } } From 3cfaa2ea9f402ee4f1f218310247942c8071f070 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:17:29 -0500 Subject: [PATCH 467/883] st/oxr: Port to using new zero/identity defines --- src/xrt/state_trackers/oxr/oxr_space.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/oxr/oxr_space.c b/src/xrt/state_trackers/oxr/oxr_space.c index 96600aba5..c1e4332b0 100644 --- a/src/xrt/state_trackers/oxr/oxr_space.c +++ b/src/xrt/state_trackers/oxr/oxr_space.c @@ -22,7 +22,7 @@ #include "oxr_handle.h" -const struct xrt_pose origin = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; +const struct xrt_pose origin = XRT_POSE_IDENTITY; static XrResult check_reference_space_type(struct oxr_logger *log, XrReferenceSpaceType type) From 19a1228bd2737be7a9162c89751587aba760fff3 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:17:46 -0500 Subject: [PATCH 468/883] xrt: Add unit vector defines for xrt_vec3 --- src/xrt/include/xrt/xrt_defines.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/xrt/include/xrt/xrt_defines.h b/src/xrt/include/xrt/xrt_defines.h index 1e16cedf4..e400fb1a9 100644 --- a/src/xrt/include/xrt/xrt_defines.h +++ b/src/xrt/include/xrt/xrt_defines.h @@ -175,6 +175,36 @@ struct xrt_vec3 { \ 0.f, 0.f, 0.f \ } +/*! + * Value for @ref xrt_vec3 with 1 in the @p x coordinate. + * + * @ingroup xrt_iface math + * @relates xrt_vec3 + */ +#define XRT_VEC3_UNIT_X \ + { \ + 1.f, 0.f, 0.f \ + } +/*! + * Value for @ref xrt_vec3 with 1 in the @p y coordinate. + * + * @ingroup xrt_iface math + * @relates xrt_vec3 + */ +#define XRT_VEC3_UNIT_Y \ + { \ + 0.f, 1.f, 0.f \ + } +/*! + * Value for @ref xrt_vec3 with 1 in the @p z coordinate. + * + * @ingroup xrt_iface math + * @relates xrt_vec3 + */ +#define XRT_VEC3_UNIT_Z \ + { \ + 0.f, 0.f, 1.f \ + } /*! * A 3 element vector with 32 bit integers. From a80d159b0705e3d3246f6a9d3d4d918a2d74ca66 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:18:02 -0500 Subject: [PATCH 469/883] t/ht: Port to using unit-vector defines. --- src/xrt/auxiliary/util/u_hand_tracking.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/xrt/auxiliary/util/u_hand_tracking.c b/src/xrt/auxiliary/util/u_hand_tracking.c index ade01d055..c521d7104 100644 --- a/src/xrt/auxiliary/util/u_hand_tracking.c +++ b/src/xrt/auxiliary/util/u_hand_tracking.c @@ -303,9 +303,6 @@ u_hand_joint_compute_next_by_curl(struct u_hand_tracking *set, scale_model_param(&prev_defaults, set->scale); scale_model_param(&defaults, set->scale); - struct xrt_vec3 x_axis = {1, 0, 0}; - struct xrt_vec3 y_axis = {0, 1, 0}; - // prev joint pose is transformed to next joint pose by adding the bone // vector to the joint, and adding rotation based on finger curl struct xrt_pose pose = prev->relation.pose; @@ -325,6 +322,7 @@ u_hand_joint_compute_next_by_curl(struct u_hand_tracking *set, //! @todo more axis rotations & make sure order is right //! @todo handle velocities + const struct xrt_vec3 y_axis = XRT_VEC3_UNIT_Y; struct xrt_pose offset_pose = XRT_POSE_IDENTITY; if (hand == XRT_HAND_LEFT) { quat_from_angle_vector_clockwise(defaults.axis_angle_offset[1], &y_axis, &offset_pose.orientation); @@ -366,6 +364,7 @@ u_hand_joint_compute_next_by_curl(struct u_hand_tracking *set, float curl_angle = curl_value * full_curl_angle; + const struct xrt_vec3 x_axis = XRT_VEC3_UNIT_X; struct xrt_quat curl_rotation; math_quat_from_angle_vector(-curl_angle, &x_axis, &curl_rotation); math_quat_rotate(&pose.orientation, &curl_rotation, &pose.orientation); From 334b59f9faa718da11190b400473c950850452a5 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:18:25 -0500 Subject: [PATCH 470/883] d/qwerty: Port to new unit-vector defines --- src/xrt/drivers/qwerty/qwerty_device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 2ee143f01..b27e3ffe4 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -168,7 +168,8 @@ qwerty_get_tracked_pose(struct xrt_device *xd, qd->pitch_delta = 0; struct xrt_quat x_rotation, y_rotation; - struct xrt_vec3 x_axis = {1, 0, 0}, y_axis = {0, 1, 0}; + const struct xrt_vec3 x_axis = XRT_VEC3_UNIT_X; + const struct xrt_vec3 y_axis = XRT_VEC3_UNIT_Y; math_quat_from_angle_vector(x_look_speed, &x_axis, &x_rotation); math_quat_from_angle_vector(y_look_speed, &y_axis, &y_rotation); math_quat_rotate(&qd->pose.orientation, &x_rotation, &qd->pose.orientation); // local-space pitch From bc279076b81fa618e22498f265cf22b2a7b85f7c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 16:08:10 -0500 Subject: [PATCH 471/883] u/ht: Port to new unit-vector defines --- src/xrt/auxiliary/util/u_hand_tracking.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/xrt/auxiliary/util/u_hand_tracking.c b/src/xrt/auxiliary/util/u_hand_tracking.c index c521d7104..2a6c6d4ca 100644 --- a/src/xrt/auxiliary/util/u_hand_tracking.c +++ b/src/xrt/auxiliary/util/u_hand_tracking.c @@ -689,9 +689,9 @@ u_hand_joints_offset_valve_index_controller(enum xrt_hand hand, struct xrt_vec3 * * Now the hand points "through the strap" like at normal use. */ - struct xrt_vec3 x = {1, 0, 0}; - struct xrt_vec3 y = {0, 1, 0}; - struct xrt_vec3 z = {0, 0, -1}; + const struct xrt_vec3 x = XRT_VEC3_UNIT_X; + const struct xrt_vec3 y = XRT_VEC3_UNIT_Y; + const struct xrt_vec3 negative_z = {0, 0, -1}; float hand_on_handle_x_rotation = DEG_TO_RAD(-72); float hand_on_handle_y_rotation = 0; @@ -706,8 +706,8 @@ u_hand_joints_offset_valve_index_controller(enum xrt_hand hand, struct xrt_vec3 struct xrt_quat hand_rotation_y = XRT_QUAT_IDENTITY; math_quat_from_angle_vector(hand_on_handle_y_rotation, &y, &hand_rotation_y); - math_quat_from_angle_vector(hand_on_handle_z_rotation, &z, &hand_rotation_z); struct xrt_quat hand_rotation_z = XRT_QUAT_IDENTITY; + math_quat_from_angle_vector(hand_on_handle_z_rotation, &negative_z, &hand_rotation_z); struct xrt_quat hand_rotation_x = XRT_QUAT_IDENTITY; math_quat_from_angle_vector(hand_on_handle_x_rotation, &x, &hand_rotation_x); From 4dd96a666b4736071f4d72dad4a9116e5ad9078a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 15:20:13 -0500 Subject: [PATCH 472/883] u/ht: Const-correctness --- src/xrt/auxiliary/util/u_hand_tracking.c | 12 +++++++----- src/xrt/auxiliary/util/u_hand_tracking.h | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/xrt/auxiliary/util/u_hand_tracking.c b/src/xrt/auxiliary/util/u_hand_tracking.c index 2a6c6d4ca..2fde71145 100644 --- a/src/xrt/auxiliary/util/u_hand_tracking.c +++ b/src/xrt/auxiliary/util/u_hand_tracking.c @@ -288,8 +288,8 @@ scale_model_param(struct u_joint_curl_model *param, float scale) } void -u_hand_joint_compute_next_by_curl(struct u_hand_tracking *set, - struct u_joint_space_relation *prev, +u_hand_joint_compute_next_by_curl(const struct u_hand_tracking *set, + const struct u_joint_space_relation *prev, enum xrt_hand hand, uint64_t at_timestamp_ns, struct u_joint_space_relation *out_joint, @@ -649,8 +649,8 @@ get_joint_data(struct u_hand_tracking *set, enum xrt_hand_joint joint_id) void u_hand_joints_set_out_data(struct u_hand_tracking *set, enum xrt_hand hand, - struct xrt_space_relation *hand_relation, - struct xrt_pose *hand_offset, + const struct xrt_space_relation *hand_relation, + const struct xrt_pose *hand_offset, struct xrt_hand_joint_set *out_value) { @@ -676,7 +676,9 @@ u_hand_joints_set_out_data(struct u_hand_tracking *set, } void -u_hand_joints_offset_valve_index_controller(enum xrt_hand hand, struct xrt_vec3 *static_offset, struct xrt_pose *offset) +u_hand_joints_offset_valve_index_controller(enum xrt_hand hand, + const struct xrt_vec3 *static_offset, + struct xrt_pose *offset) { /* Controller space origin is at the very tip of the controller, * handle pointing forward at -z. diff --git a/src/xrt/auxiliary/util/u_hand_tracking.h b/src/xrt/auxiliary/util/u_hand_tracking.h index e8f2253ee..6e2265c6b 100644 --- a/src/xrt/auxiliary/util/u_hand_tracking.h +++ b/src/xrt/auxiliary/util/u_hand_tracking.h @@ -164,8 +164,8 @@ u_hand_joints_init_default_set(struct u_hand_tracking *set, void u_hand_joints_set_out_data(struct u_hand_tracking *set, enum xrt_hand hand, - struct xrt_space_relation *hand_relation, - struct xrt_pose *hand_offset, + const struct xrt_space_relation *hand_relation, + const struct xrt_pose *hand_offset, struct xrt_hand_joint_set *out_value); @@ -179,8 +179,8 @@ u_hand_joints_set_out_data(struct u_hand_tracking *set, * @ingroup aux_util */ void -u_hand_joint_compute_next_by_curl(struct u_hand_tracking *set, - struct u_joint_space_relation *prev, +u_hand_joint_compute_next_by_curl(const struct u_hand_tracking *set, + const struct u_joint_space_relation *prev, enum xrt_hand hand, uint64_t at_timestamp_ns, struct u_joint_space_relation *out_joint, @@ -202,7 +202,7 @@ u_hand_joints_update_curl(struct u_hand_tracking *set, */ void u_hand_joints_offset_valve_index_controller(enum xrt_hand hand, - struct xrt_vec3 *static_offset, + const struct xrt_vec3 *static_offset, struct xrt_pose *offset); From 8277df418d73c507a1e5531b854cb4bbb6251cd2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 00:52:31 +0100 Subject: [PATCH 473/883] xrt: Make eye_relation argument to xrt_device_get_view_pose const (NFC) --- src/xrt/drivers/android/android_sensors.c | 2 +- src/xrt/drivers/dummy/dummy_hmd.c | 2 +- src/xrt/drivers/hdk/hdk_device.cpp | 2 +- src/xrt/drivers/illixr/illixr_device.cpp | 2 +- src/xrt/drivers/multi_wrapper/multi.c | 5 ++++- src/xrt/drivers/north_star/ns_hmd.c | 4 ++-- src/xrt/drivers/ohmd/oh_device.c | 2 +- src/xrt/drivers/psvr/psvr_device.c | 2 +- src/xrt/drivers/qwerty/qwerty_device.c | 2 +- src/xrt/drivers/realsense/rs_6dof.c | 2 +- src/xrt/drivers/remote/r_device.c | 2 +- src/xrt/drivers/remote/r_hmd.c | 2 +- src/xrt/drivers/survive/survive_driver.c | 2 +- src/xrt/drivers/vive/vive_device.c | 2 +- src/xrt/drivers/wmr/wmr_hmd.c | 2 +- src/xrt/include/xrt/xrt_device.h | 4 ++-- src/xrt/ipc/client/ipc_client_device.c | 2 +- src/xrt/ipc/client/ipc_client_hmd.c | 2 +- src/xrt/ipc/server/ipc_server_handler.c | 3 ++- src/xrt/ipc/shared/proto.json | 2 +- 20 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/xrt/drivers/android/android_sensors.c b/src/xrt/drivers/android/android_sensors.c index d717dc3e8..57f0cd6d2 100644 --- a/src/xrt/drivers/android/android_sensors.c +++ b/src/xrt/drivers/android/android_sensors.c @@ -170,7 +170,7 @@ android_device_get_tracked_pose(struct xrt_device *xdev, static void android_device_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/dummy/dummy_hmd.c b/src/xrt/drivers/dummy/dummy_hmd.c index edcb28df4..216d2b6be 100644 --- a/src/xrt/drivers/dummy/dummy_hmd.c +++ b/src/xrt/drivers/dummy/dummy_hmd.c @@ -121,7 +121,7 @@ dummy_hmd_get_tracked_pose(struct xrt_device *xdev, static void dummy_hmd_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/hdk/hdk_device.cpp b/src/xrt/drivers/hdk/hdk_device.cpp index a082d45c4..d2ca2a2d7 100644 --- a/src/xrt/drivers/hdk/hdk_device.cpp +++ b/src/xrt/drivers/hdk/hdk_device.cpp @@ -260,7 +260,7 @@ hdk_device_get_tracked_pose(struct xrt_device *xdev, static void hdk_device_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/illixr/illixr_device.cpp b/src/xrt/drivers/illixr/illixr_device.cpp index ecc7cd250..897c0275b 100644 --- a/src/xrt/drivers/illixr/illixr_device.cpp +++ b/src/xrt/drivers/illixr/illixr_device.cpp @@ -132,7 +132,7 @@ illixr_hmd_get_tracked_pose(struct xrt_device *xdev, static void illixr_hmd_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/multi_wrapper/multi.c b/src/xrt/drivers/multi_wrapper/multi.c index c393d62da..8a90256dd 100644 --- a/src/xrt/drivers/multi_wrapper/multi.c +++ b/src/xrt/drivers/multi_wrapper/multi.c @@ -179,7 +179,10 @@ set_output(struct xrt_device *xdev, enum xrt_output_name name, union xrt_output_ } static void -get_view_pose(struct xrt_device *xdev, struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) +get_view_pose(struct xrt_device *xdev, + const struct xrt_vec3 *eye_relation, + uint32_t view_index, + struct xrt_pose *out_pose) { struct multi_device *d = (struct multi_device *)xdev; struct xrt_device *target = d->tracking_override.target; diff --git a/src/xrt/drivers/north_star/ns_hmd.c b/src/xrt/drivers/north_star/ns_hmd.c index 645c2b1b8..b1316051d 100644 --- a/src/xrt/drivers/north_star/ns_hmd.c +++ b/src/xrt/drivers/north_star/ns_hmd.c @@ -93,7 +93,7 @@ ns_hmd_get_tracked_pose(struct xrt_device *xdev, static void ns_hmd_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { @@ -201,7 +201,7 @@ ns_fov_calculate(struct xrt_fov *fov, struct xrt_quat projection) static void ns_v2_hmd_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c index 87a57da8c..fc6144802 100644 --- a/src/xrt/drivers/ohmd/oh_device.c +++ b/src/xrt/drivers/ohmd/oh_device.c @@ -432,7 +432,7 @@ oh_device_get_tracked_pose(struct xrt_device *xdev, static void oh_device_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/psvr/psvr_device.c b/src/xrt/drivers/psvr/psvr_device.c index 9188b16bd..c7ba60b28 100644 --- a/src/xrt/drivers/psvr/psvr_device.c +++ b/src/xrt/drivers/psvr/psvr_device.c @@ -929,7 +929,7 @@ psvr_device_get_tracked_pose(struct xrt_device *xdev, static void psvr_device_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index b27e3ffe4..7540e1e8f 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -196,7 +196,7 @@ qwerty_get_tracked_pose(struct xrt_device *xd, static void qwerty_get_view_pose(struct xrt_device *xd, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/realsense/rs_6dof.c b/src/xrt/drivers/realsense/rs_6dof.c index 3a6d00673..7a5460a2a 100644 --- a/src/xrt/drivers/realsense/rs_6dof.c +++ b/src/xrt/drivers/realsense/rs_6dof.c @@ -366,7 +366,7 @@ rs_6dof_get_tracked_pose(struct xrt_device *xdev, } static void rs_6dof_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/remote/r_device.c b/src/xrt/drivers/remote/r_device.c index f21af1299..9075feab1 100644 --- a/src/xrt/drivers/remote/r_device.c +++ b/src/xrt/drivers/remote/r_device.c @@ -148,7 +148,7 @@ r_device_get_hand_tracking(struct xrt_device *xdev, static void r_device_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/remote/r_hmd.c b/src/xrt/drivers/remote/r_hmd.c index 0be94a456..717cf664c 100644 --- a/src/xrt/drivers/remote/r_hmd.c +++ b/src/xrt/drivers/remote/r_hmd.c @@ -85,7 +85,7 @@ r_hmd_get_hand_tracking(struct xrt_device *xdev, static void r_hmd_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index 1190fd8b2..63beb076c 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -443,7 +443,7 @@ survive_controller_get_hand_tracking(struct xrt_device *xdev, static void survive_device_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index 93b81a75c..17f4d4b53 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -138,7 +138,7 @@ vive_device_get_tracked_pose(struct xrt_device *xdev, static void vive_device_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index 619188cac..4dca42be2 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -412,7 +412,7 @@ wmr_hmd_get_tracked_pose(struct xrt_device *xdev, static void wmr_hmd_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/include/xrt/xrt_device.h b/src/xrt/include/xrt/xrt_device.h index 760dd78e5..f4d001a90 100644 --- a/src/xrt/include/xrt/xrt_device.h +++ b/src/xrt/include/xrt/xrt_device.h @@ -341,7 +341,7 @@ struct xrt_device * orientation unless you have canted screens. */ void (*get_view_pose)(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose); @@ -410,7 +410,7 @@ xrt_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, union */ static inline void xrt_device_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/ipc/client/ipc_client_device.c b/src/xrt/ipc/client/ipc_client_device.c index a03587d1c..1ddb2eaed 100644 --- a/src/xrt/ipc/client/ipc_client_device.c +++ b/src/xrt/ipc/client/ipc_client_device.c @@ -120,7 +120,7 @@ ipc_client_device_get_hand_tracking(struct xrt_device *xdev, static void ipc_client_device_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/ipc/client/ipc_client_hmd.c b/src/xrt/ipc/client/ipc_client_hmd.c index f9305c609..ef44e12c6 100644 --- a/src/xrt/ipc/client/ipc_client_hmd.c +++ b/src/xrt/ipc/client/ipc_client_hmd.c @@ -106,7 +106,7 @@ ipc_client_hmd_get_tracked_pose(struct xrt_device *xdev, static void ipc_client_hmd_get_view_pose(struct xrt_device *xdev, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 3d9ecc826..2ce9f94fb 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -925,10 +925,11 @@ ipc_handle_device_get_hand_tracking(volatile struct ipc_client_state *ics, return XRT_SUCCESS; } + xrt_result_t ipc_handle_device_get_view_pose(volatile struct ipc_client_state *ics, uint32_t id, - struct xrt_vec3 *eye_relation, + const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { diff --git a/src/xrt/ipc/shared/proto.json b/src/xrt/ipc/shared/proto.json index cdd6dd936..d069e39cd 100644 --- a/src/xrt/ipc/shared/proto.json +++ b/src/xrt/ipc/shared/proto.json @@ -200,7 +200,7 @@ "device_get_view_pose": { "in": [ {"name": "id", "type": "uint32_t"}, - {"name": "eye_relation", "type": "struct xrt_vec3"}, + {"name": "eye_relation", "type": "const struct xrt_vec3"}, {"name": "view_index", "type": "uint32_t"} ], "out": [ From 78f7d5ce914c802c66584fb90c1bae01fee6a153 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 01:00:26 +0100 Subject: [PATCH 474/883] ipc: Assert if st/oxr calls the wrong thing --- src/xrt/ipc/client/ipc_client_device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xrt/ipc/client/ipc_client_device.c b/src/xrt/ipc/client/ipc_client_device.c index 1ddb2eaed..3c42a7d26 100644 --- a/src/xrt/ipc/client/ipc_client_device.c +++ b/src/xrt/ipc/client/ipc_client_device.c @@ -125,6 +125,7 @@ ipc_client_device_get_view_pose(struct xrt_device *xdev, struct xrt_pose *out_pose) { // Empty + assert(false); } static void From 4da87635d1db917776445abb3eb388d5d79616e6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 00:54:37 +0100 Subject: [PATCH 475/883] st/oxr: Tidy xrLocateViews function --- src/xrt/state_trackers/oxr/oxr_session.c | 26 +++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 8ef0bfd7d..0c6d8a4d1 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -366,8 +366,13 @@ oxr_session_views(struct oxr_logger *log, // Get the viewLocateInfo->space to view space relation. struct xrt_space_relation pure_relation; - oxr_space_ref_relation(log, sess, XR_REFERENCE_SPACE_TYPE_VIEW, baseSpc->type, viewLocateInfo->displayTime, - &pure_relation); + oxr_space_ref_relation( // + log, // + sess, // + XR_REFERENCE_SPACE_TYPE_VIEW, // + baseSpc->type, // + viewLocateInfo->displayTime, // + &pure_relation); // // @todo the fov information that we get from xdev->hmd->views[i].fov is // not properly filled out in oh_device.c, fix before wasting time @@ -375,17 +380,18 @@ oxr_session_views(struct oxr_logger *log, viewState->viewStateFlags = 0; + //! @todo Do not hardcode IPD. + const struct xrt_vec3 eye_relation = { + sess->ipd_meters, + 0.0f, + 0.0f, + }; + for (uint32_t i = 0; i < num_views; i++) { - //! @todo Do not hardcode IPD. - struct xrt_vec3 eye_relation = { - sess->ipd_meters, - 0.0f, - 0.0f, - }; - struct xrt_pose view_pose; + struct xrt_pose view_pose = XRT_POSE_IDENTITY; // Get the per view pose from the device. - xdev->get_view_pose(xdev, &eye_relation, i, &view_pose); + xrt_device_get_view_pose(xdev, &eye_relation, i, &view_pose); // Do the magical space relation dance here. struct xrt_space_relation result = {0}; From 4e572af96ad0740483a60d294d1cda55fec0021e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 01:43:35 +0100 Subject: [PATCH 476/883] st/oxr: Rename oxr_session_views to oxr_session_locate_views (NFC) --- src/xrt/state_trackers/oxr/oxr_api_session.c | 9 ++++++++- src/xrt/state_trackers/oxr/oxr_objects.h | 14 +++++++------- src/xrt/state_trackers/oxr/oxr_session.c | 14 +++++++------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_api_session.c b/src/xrt/state_trackers/oxr/oxr_api_session.c index a07b6995d..07da5e0b9 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_session.c +++ b/src/xrt/state_trackers/oxr/oxr_api_session.c @@ -184,7 +184,14 @@ oxr_xrLocateViews(XrSession session, OXR_VERIFY_ARG_NOT_NULL(&log, views); } - return oxr_session_views(&log, sess, viewLocateInfo, viewState, viewCapacityInput, viewCountOutput, views); + return oxr_session_locate_views( // + &log, // + sess, // + viewLocateInfo, // + viewState, // + viewCapacityInput, // + viewCountOutput, // + views); // } diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index 181139ac7..6cba596a4 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -634,13 +634,13 @@ oxr_session_get_view_relation_at(struct oxr_logger *, struct xrt_space_relation *out_relation); XrResult -oxr_session_views(struct oxr_logger *log, - struct oxr_session *sess, - const XrViewLocateInfo *viewLocateInfo, - XrViewState *viewState, - uint32_t viewCapacityInput, - uint32_t *viewCountOutput, - XrView *views); +oxr_session_locate_views(struct oxr_logger *log, + struct oxr_session *sess, + const XrViewLocateInfo *viewLocateInfo, + XrViewState *viewState, + uint32_t viewCapacityInput, + uint32_t *viewCountOutput, + XrView *views); XrResult oxr_session_frame_wait(struct oxr_logger *log, struct oxr_session *sess, XrFrameState *frameState); diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 0c6d8a4d1..aafdb67c5 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -329,13 +329,13 @@ xrt_to_view_state_flags(enum xrt_space_relation_flags flags) } XrResult -oxr_session_views(struct oxr_logger *log, - struct oxr_session *sess, - const XrViewLocateInfo *viewLocateInfo, - XrViewState *viewState, - uint32_t viewCapacityInput, - uint32_t *viewCountOutput, - XrView *views) +oxr_session_locate_views(struct oxr_logger *log, + struct oxr_session *sess, + const XrViewLocateInfo *viewLocateInfo, + XrViewState *viewState, + uint32_t viewCapacityInput, + uint32_t *viewCountOutput, + XrView *views) { struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head); struct oxr_space *baseSpc = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_space *, viewLocateInfo->space); From e9839f3fe914a4824c92e94a1bfbe5b4a6bd5c73 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 02:11:13 +0100 Subject: [PATCH 477/883] doc: Document !794 --- doc/changes/xrt/mr.794.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/changes/xrt/mr.794.md diff --git a/doc/changes/xrt/mr.794.md b/doc/changes/xrt/mr.794.md new file mode 100644 index 000000000..891e7dda6 --- /dev/null +++ b/doc/changes/xrt/mr.794.md @@ -0,0 +1,2 @@ +Make eye_relation argument to xrt_device_get_view_pose const, more safety for +everybody. From a6b908f3ce6a2d1cdd036299c311d7c420267a4b Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 16:51:56 +0100 Subject: [PATCH 478/883] d/vive: Add comment and assert to get_view_pose (NFC) --- src/xrt/drivers/vive/vive_device.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index 17f4d4b53..79ab11c9b 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -142,7 +142,12 @@ vive_device_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { + // Only supports two views. + assert(view_index < 2); + u_device_get_view_pose(eye_relation, view_index, out_pose); + + // This is for the Index' canted displays, on the Vive [Pro] they are identity. struct vive_device *d = vive_device(xdev); out_pose->orientation = d->config.display.rot[view_index]; } From 385af79e82b716e2210bdaabfde14b987d9ae683 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 17:19:18 +0100 Subject: [PATCH 479/883] d/survive: Add comment and assert to get_view_pose (NFC) --- src/xrt/drivers/survive/survive_driver.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index 63beb076c..330dad168 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -447,8 +447,13 @@ survive_device_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct survive_device *survive = (struct survive_device *)xdev; + // Only supports two views. + assert(view_index < 2); + u_device_get_view_pose(eye_relation, view_index, out_pose); + + // This is for the Index' canted displays, on the Vive [Pro] they are identity. + struct survive_device *survive = (struct survive_device *)xdev; out_pose->orientation = survive->hmd.config.display.rot[view_index]; } From b81d3138af3f0ef51903cd20571bd2b2aad900ba Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 17:32:44 +0100 Subject: [PATCH 480/883] d/remote: Assert if st/oxr calls the wrong thing (NFC) --- src/xrt/drivers/remote/r_device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xrt/drivers/remote/r_device.c b/src/xrt/drivers/remote/r_device.c index 9075feab1..08a02a102 100644 --- a/src/xrt/drivers/remote/r_device.c +++ b/src/xrt/drivers/remote/r_device.c @@ -153,6 +153,7 @@ r_device_get_view_pose(struct xrt_device *xdev, struct xrt_pose *out_pose) { // Empty + assert(false); } static void From 3e127a1fa37fd0ad155bdb9c548bb7d5828554e4 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 27 Apr 2021 11:00:05 -0500 Subject: [PATCH 481/883] build: Move finding Python earlier, so it builds in Android Studio on Linux. --- CMakeLists.txt | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b8f94a59..cc5cb0539 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,19 @@ if(NOT ${CMAKE_VERSION} VERSION_LESS 3.9) check_ipo_supported(RESULT HAS_IPO) endif() +# Android SDK doesn't look for 3.8 and 3.9, which is what new distros ship with. +set(Python_ADDITIONAL_VERSIONS 3.8 3.9) +if(NOT CMAKE_VERSION VERSION_LESS 3.12) + find_package(Python3 REQUIRED Interpreter) + set(PYTHON_EXECUTABLE Python3::Interpreter) +else() + find_program(PYTHON_EXECUTABLE python3) + if(PYTHON_EXECUTABLE MATCHES "WindowsApps") + # If you hit this error, you will have to install Python 3 or try harder to tell CMake where it is. + message(FATAL_ERROR "Found WindowsApps alias for Python. Make sure Python3 is installed, then choose 'Manage App Execution Aliases' in Start and disable the aliases for Python.") + endif() +endif() + # Redundant mention of version is required because module defaults to looking for 2.91-compatible, # which the config file for a 3.x says it's not compatible with. find_package(Eigen3 3 REQUIRED) @@ -56,18 +69,6 @@ else() message(STATUS "Could NOT find libLeap: (missing: /usr/local/lib/libLeap.so)") endif() -# Android SDK doesn't look for 3.8 and 3.9, which is what new distros ship with. -set(Python_ADDITIONAL_VERSIONS 3.8 3.9) -if(NOT CMAKE_VERSION VERSION_LESS 3.12) - find_package(Python3 REQUIRED Interpreter) - set(PYTHON_EXECUTABLE Python3::Interpreter) -else() - find_program(PYTHON_EXECUTABLE python3) - if(PYTHON_EXECUTABLE MATCHES "WindowsApps") - # If you hit this error, you will have to install Python 3 or try harder to tell CMake where it is. - message(FATAL_ERROR "Found WindowsApps alias for Python. Make sure Python3 is installed, then choose 'Manage App Execution Aliases' in Start and disable the aliases for Python.") - endif() -endif() add_library(xrt-pthreads INTERFACE) if(WIN32) From 5a7412e86d9a1a35f8a57b540737089e9f020e1d Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 27 Apr 2021 11:00:40 -0500 Subject: [PATCH 482/883] a/bindings: Fix typos --- src/xrt/auxiliary/bindings/bindings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrt/auxiliary/bindings/bindings.py b/src/xrt/auxiliary/bindings/bindings.py index 7cb8ff73d..b20c3a1e5 100755 --- a/src/xrt/auxiliary/bindings/bindings.py +++ b/src/xrt/auxiliary/bindings/bindings.py @@ -60,7 +60,7 @@ class Feature: return paths def is_input(self): - # only haptics is output so far, everythine else is input + # only haptics is output so far, everything else is input return self.feature_str != "haptic" def is_output(self): @@ -68,7 +68,7 @@ class Feature: class Profile: - """An interctive bindings profile.""" + """An interactive bindings profile.""" def __init__(self, name, data): """Construct an profile.""" self.name = name From d8cf72f6d9a151e6983892a00464e0712d7abab8 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 27 Apr 2021 11:00:57 -0500 Subject: [PATCH 483/883] a/bindings: Simplify as suggested by IDE --- src/xrt/auxiliary/bindings/bindings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/bindings/bindings.py b/src/xrt/auxiliary/bindings/bindings.py index b20c3a1e5..f165591a7 100755 --- a/src/xrt/auxiliary/bindings/bindings.py +++ b/src/xrt/auxiliary/bindings/bindings.py @@ -83,7 +83,7 @@ class Profile: for feature in self.features: for path in feature.to_monado_paths(): length = len(path) - if (length in self.by_length): + if length in self.by_length: self.by_length[length].append(path) else: self.by_length[length] = [path] From 2c382734ca1d36287cf00df3ff4941cb33f86568 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 27 Apr 2021 11:07:31 -0500 Subject: [PATCH 484/883] a/bindings: Clean up formatting of script --- src/xrt/auxiliary/bindings/bindings.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/xrt/auxiliary/bindings/bindings.py b/src/xrt/auxiliary/bindings/bindings.py index f165591a7..73207daa9 100755 --- a/src/xrt/auxiliary/bindings/bindings.py +++ b/src/xrt/auxiliary/bindings/bindings.py @@ -4,8 +4,8 @@ """Generate code from a JSON file describing interaction profiles and bindings.""" -import json import argparse +import json def handle_subpath(pathgroup_cls, feature_list, subaction_path, sub_path_itm): @@ -31,7 +31,8 @@ class Feature: feature_list = [] for subaction_path in subaction_paths: for sub_path_itm in paths.items(): - handle_subpath(feature_cls, feature_list, subaction_path, sub_path_itm) + handle_subpath(feature_cls, feature_list, + subaction_path, sub_path_itm) return feature_list def __init__(self, subaction_path, sub_path_itm, feature_str): @@ -41,10 +42,10 @@ class Feature: self.subaction_path = subaction_path self.feature_str = feature_str - """A group of paths that derive from the same input. - For example .../thumbstick, .../thumbstick/x, .../thumbstick/y - """ def to_monado_paths(self): + """A group of paths that derive from the same input. + For example .../thumbstick, .../thumbstick/x, .../thumbstick/y + """ paths = [] basepath = self.subaction_path + self.sub_path_name @@ -69,6 +70,7 @@ class Feature: class Profile: """An interactive bindings profile.""" + def __init__(self, name, data): """Construct an profile.""" self.name = name @@ -152,7 +154,8 @@ def generate_bindings_c(file, p): f.write("{\n\t\t\treturn false;\n\t\t}\n") f.write("\tdefault:\n\t\treturn false;\n\t}\n}\n") - f.write(f'\n\nstruct profile_template profile_templates[{len(p.profiles)}] = {{ // array of profile_template\n') + f.write( + f'\n\nstruct profile_template profile_templates[{len(p.profiles)}] = {{ // array of profile_template\n') for profile in p.profiles: hw_name = str(profile.name.split("/")[-1]) vendor_name = str(profile.name.split("/")[-2]) @@ -167,7 +170,8 @@ def generate_bindings_c(file, p): f.write(f'\t\t.steamvr_input_profile_path = "{fname}",\n') f.write(f'\t\t.steamvr_controller_type = "{controller_type}",\n') f.write(f'\t\t.num_bindings = {num_bindings},\n') - f.write(f'\t\t.bindings = (struct binding_template[]){{ // array of binding_template\n') + f.write( + f'\t\t.bindings = (struct binding_template[]){{ // array of binding_template\n') feature: Feature for idx, feature in enumerate(profile.features): @@ -180,7 +184,8 @@ def generate_bindings_c(file, p): f.write(f'\t\t\t{{ // binding_template {idx}\n') f.write(f'\t\t\t\t.subaction_path = "{feature.subaction_path}",\n') f.write(f'\t\t\t\t.steamvr_path = "{steamvr_path}",\n') - f.write(f'\t\t\t\t.localized_name = "{sp_obj["localized_name"]}",\n') + f.write( + f'\t\t\t\t.localized_name = "{sp_obj["localized_name"]}",\n') f.write('\t\t\t\t.paths = { // array of paths\n') for path in feature.to_monado_paths(): From 8a936f247494002667f0f66a9324132649d6cc10 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 23 Apr 2021 09:13:14 -0500 Subject: [PATCH 485/883] doc: Extract static file members when set to extract all. --- doc/Doxyfile.in | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 4afadb282..710d5f147 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -65,6 +65,7 @@ ALWAYS_DETAILED_SEC = YES WARN_IF_UNDOCUMENTED = @DOXYGEN_WARN_UNDOCUMENTED@ EXTRACT_ALL = @DOXYGEN_EXTRACT_ALL@ HIDE_UNDOC_RELATIONS = NO +EXTRACT_STATIC = @DOXYGEN_EXTRACT_ALL@ MACRO_EXPANSION = YES From 8af1bfbf8cea7a70d2b68b16259c735742dcecee Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 26 Apr 2021 14:34:19 -0500 Subject: [PATCH 486/883] a/u_logging: Docs for logging. --- src/xrt/auxiliary/util/u_logging.h | 228 ++++++++++++++++++++++++----- 1 file changed, 188 insertions(+), 40 deletions(-) diff --git a/src/xrt/auxiliary/util/u_logging.h b/src/xrt/auxiliary/util/u_logging.h index c90c69ea6..706284705 100644 --- a/src/xrt/auxiliary/util/u_logging.h +++ b/src/xrt/auxiliary/util/u_logging.h @@ -31,6 +31,19 @@ struct xrt_device; * @{ */ +/*! + * @brief Logging level enum + */ +enum u_logging_level +{ + U_LOGGING_TRACE, //!< Trace messages, highly verbose. + U_LOGGING_DEBUG, //!< Debug messages, verbose. + U_LOGGING_INFO, //!< Info messages: not very verbose, not indicating a problem. + U_LOGGING_WARN, //!< Warning messages: indicating a potential problem + U_LOGGING_ERROR, //!< Error messages: indicating a problem + U_LOGGING_RAW, //!< Special level for raw printing, prints a new-line. +}; + /*! * For places where you really just want printf, prints a new-line. */ @@ -39,23 +52,63 @@ struct xrt_device; u_log(__FILE__, __LINE__, __func__, U_LOGGING_RAW, __VA_ARGS__); \ } while (false) +/*! + * @name Base Logging Utilities + * In most cases, you will want to use another macro from this file, or a module/driver-local macro, to do your logging. + * @{ + */ +/*! + * @brief Log a message at @p level , with file, line, and function context (always logs) - typically wrapped + * in a helper macro. + * + * @param level A @ref u_logging_level value for this message. + * @param ... Format string and optional format arguments. + */ #define U_LOG(level, ...) \ do { \ u_log(__FILE__, __LINE__, __func__, level, __VA_ARGS__); \ } while (false) +/*! + * @brief Log at @p level only if the level is at least @p cond_level - typically wrapped in a helper macro. + * + * Adds file, line, and function context. Like U_LOG() but conditional. + * + * @param level A @ref u_logging_level value for this message. + * @param cond_level The minimum @ref u_logging_level that will be actually output. + * @param ... Format string and optional format arguments. + */ #define U_LOG_IFL(level, cond_level, ...) \ do { \ if (cond_level <= level) { \ u_log(__FILE__, __LINE__, __func__, level, __VA_ARGS__); \ } \ } while (false) - +/*! + * @brief Log at @p level for a given @ref xrt_device - typically wrapped in a helper macro. + * + * Adds file, line, and function context, and forwards device context from provided @p xdev . + * + * Like U_LOG() but calling u_log_xdev() (which takes a device) instead. + * + * @param level A @ref u_logging_level value for this message. + * @param xdev The @ref xrt_device pointer associated with this message. + * @param ... Format string and optional format arguments. + */ #define U_LOG_XDEV(level, xdev, ...) \ do { \ u_log_xdev(__FILE__, __LINE__, __func__, level, xdev, __VA_ARGS__); \ } while (false) - +/*! + * @brief Log at @p level for a given @ref xrt_device, only if the level is at least @p cond_level - typically wrapped + * in a helper macro. + * + * Adds file, line, and function context, and forwards device context from provided @p xdev . + * @param level A @ref u_logging_level value for this message. + * @param cond_level The minimum @ref u_logging_level that will be actually output. + * @param xdev The @ref xrt_device pointer associated with this message. + * @param ... Format string and optional format arguments. + */ #define U_LOG_XDEV_IFL(level, cond_level, xdev, ...) \ do { \ if (cond_level <= level) { \ @@ -63,41 +116,7 @@ struct xrt_device; } \ } while (false) -// clang-format off -#define U_LOG_T(...) U_LOG_IFL_T(u_log_get_global_level(), __VA_ARGS__) -#define U_LOG_D(...) U_LOG_IFL_D(u_log_get_global_level(), __VA_ARGS__) -#define U_LOG_I(...) U_LOG_IFL_I(u_log_get_global_level(), __VA_ARGS__) -#define U_LOG_W(...) U_LOG_IFL_W(u_log_get_global_level(), __VA_ARGS__) -#define U_LOG_E(...) U_LOG_IFL_E(u_log_get_global_level(), __VA_ARGS__) -#define U_LOG_IFL_T(cond_level, ...) U_LOG_IFL(U_LOGGING_TRACE, cond_level, __VA_ARGS__) -#define U_LOG_IFL_D(cond_level, ...) U_LOG_IFL(U_LOGGING_DEBUG, cond_level, __VA_ARGS__) -#define U_LOG_IFL_I(cond_level, ...) U_LOG_IFL(U_LOGGING_INFO, cond_level, __VA_ARGS__) -#define U_LOG_IFL_W(cond_level, ...) U_LOG_IFL(U_LOGGING_WARN, cond_level, __VA_ARGS__) -#define U_LOG_IFL_E(cond_level, ...) U_LOG_IFL(U_LOGGING_ERROR, cond_level, __VA_ARGS__) - -#define U_LOG_XDEV_IFL_T(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_TRACE, cond_level, xdev, __VA_ARGS__) -#define U_LOG_XDEV_IFL_D(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_DEBUG, cond_level, xdev, __VA_ARGS__) -#define U_LOG_XDEV_IFL_I(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_INFO, cond_level, xdev, __VA_ARGS__) -#define U_LOG_XDEV_IFL_W(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_WARN, cond_level, xdev, __VA_ARGS__) -#define U_LOG_XDEV_IFL_E(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_ERROR, cond_level, xdev, __VA_ARGS__) - -#define U_LOG_XDEV_T(xdev, ...) U_LOG_XDEV(U_LOGGING_TRACE, xdev, __VA_ARGS__) -#define U_LOG_XDEV_D(xdev, ...) U_LOG_XDEV(U_LOGGING_DEBUG, xdev, __VA_ARGS__) -#define U_LOG_XDEV_I(xdev, ...) U_LOG_XDEV(U_LOGGING_INFO, xdev, __VA_ARGS__) -#define U_LOG_XDEV_W(xdev, ...) U_LOG_XDEV(U_LOGGING_WARN, xdev, __VA_ARGS__) -#define U_LOG_XDEV_E(xdev, ...) U_LOG_XDEV(U_LOGGING_ERROR, xdev, __VA_ARGS__) -// clang-format on - -enum u_logging_level -{ - U_LOGGING_TRACE, - U_LOGGING_DEBUG, - U_LOGGING_INFO, - U_LOGGING_WARN, - U_LOGGING_ERROR, - U_LOGGING_RAW, //!< Special level for raw printing, prints a new-line. -}; /*! * Returns the global logging level, subsystems own logging level take precedence. @@ -106,16 +125,32 @@ enum u_logging_level u_log_get_global_level(void); /*! - * This function always logs, level is used for printing or passed to native - * logging functions. + * @brief Main non-device-related log implementation function: do not call directly, use a macro that wraps it. + * + * This function always logs: level is used for printing or passed to native logging functions. + * + * @param file Source file name associated with a message + * @param line Source file line associated with a message + * @param func Function name associated with a message + * @param level Message level: used for formatting or forwarding to native log functions + * @param format Format string + * @param ... Format parameters */ void u_log(const char *file, int line, const char *func, enum u_logging_level level, const char *format, ...) XRT_PRINTF_FORMAT(5, 6); /*! - * This function always logs, level is used for printing or passed to native - * logging functions. + * @brief Main device-related log implementation function: do not call directly, use a macro that wraps it. + * + * This function always logs: level is used for printing or passed to native logging functions. + * @param file Source file name associated with a message + * @param line Source file line associated with a message + * @param func Function name associated with a message + * @param level Message level: used for formatting or forwarding to native log functions + * @param xdev The associated @ref xrt_device + * @param format Format string + * @param ... Format parameters */ void u_log_xdev(const char *file, @@ -126,6 +161,119 @@ u_log_xdev(const char *file, const char *format, ...) XRT_PRINTF_FORMAT(6, 7); +/*! + * @} + */ + + +/*! + * @name Logging macros conditional on global log level + * + * These each imply a log level, and will only log if the global log level is equal or lower. + * They are often used for one-off logging in a module with few other logging needs, + * where having a module-specific log level would be unnecessary. + * + * @see U_LOG_IFL, u_log_get_global_level() + * @param ... Format string and optional format arguments. + * @{ + */ +//! Log a message at U_LOGGING_TRACE level, conditional on the global log level +#define U_LOG_T(...) U_LOG_IFL_T(u_log_get_global_level(), __VA_ARGS__) + +//! Log a message at U_LOGGING_DEBUG level, conditional on the global log level +#define U_LOG_D(...) U_LOG_IFL_D(u_log_get_global_level(), __VA_ARGS__) + +//! Log a message at U_LOGGING_INFO level, conditional on the global log level +#define U_LOG_I(...) U_LOG_IFL_I(u_log_get_global_level(), __VA_ARGS__) + +//! Log a message at U_LOGGING_WARN level, conditional on the global log level +#define U_LOG_W(...) U_LOG_IFL_W(u_log_get_global_level(), __VA_ARGS__) + +//! Log a message at U_LOGGING_ERROR level, conditional on the global log level +#define U_LOG_E(...) U_LOG_IFL_E(u_log_get_global_level(), __VA_ARGS__) + +/*! + * @} + */ + +/*! + * @name Logging macros conditional on provided log level + * + * These are often wrapped within a module, to automatically supply + * @p cond_level as appropriate for that module. + * + * @see U_LOG_IFL + * @param cond_level The minimum @ref u_logging_level that will be actually output. + * @param ... Format string and optional format arguments. + * + * @{ + */ +//! Conditionally log a message at U_LOGGING_TRACE level. +#define U_LOG_IFL_T(cond_level, ...) U_LOG_IFL(U_LOGGING_TRACE, cond_level, __VA_ARGS__) +//! Conditionally log a message at U_LOGGING_DEBUG level. +#define U_LOG_IFL_D(cond_level, ...) U_LOG_IFL(U_LOGGING_DEBUG, cond_level, __VA_ARGS__) +//! Conditionally log a message at U_LOGGING_INFO level. +#define U_LOG_IFL_I(cond_level, ...) U_LOG_IFL(U_LOGGING_INFO, cond_level, __VA_ARGS__) +//! Conditionally log a message at U_LOGGING_WARN level. +#define U_LOG_IFL_W(cond_level, ...) U_LOG_IFL(U_LOGGING_WARN, cond_level, __VA_ARGS__) +//! Conditionally log a message at U_LOGGING_ERROR level. +#define U_LOG_IFL_E(cond_level, ...) U_LOG_IFL(U_LOGGING_ERROR, cond_level, __VA_ARGS__) +/*! + * @} + */ + + + +/*! + * @name Device-related logging macros conditional on provided log level + * + * These are often wrapped within a driver, to automatically supply @p xdev and + * @p cond_level from their conventional names and log level member variable. + * + * @param level A @ref u_logging_level value for this message. + * @param cond_level The minimum @ref u_logging_level that will be actually output. + * @param xdev The @ref xrt_device pointer associated with this message. + * @param ... Format string and optional format arguments. + * + * @{ + */ +//! Conditionally log a device-related message at U_LOGGING_TRACE level. +#define U_LOG_XDEV_IFL_T(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_TRACE, cond_level, xdev, __VA_ARGS__) +//! Conditionally log a device-related message at U_LOGGING_DEBUG level. +#define U_LOG_XDEV_IFL_D(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_DEBUG, cond_level, xdev, __VA_ARGS__) +//! Conditionally log a device-related message at U_LOGGING_INFO level. +#define U_LOG_XDEV_IFL_I(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_INFO, cond_level, xdev, __VA_ARGS__) +//! Conditionally log a device-related message at U_LOGGING_WARN level. +#define U_LOG_XDEV_IFL_W(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_WARN, cond_level, xdev, __VA_ARGS__) +//! Conditionally log a device-related message at U_LOGGING_ERROR level. +#define U_LOG_XDEV_IFL_E(xdev, cond_level, ...) U_LOG_XDEV_IFL(U_LOGGING_ERROR, cond_level, xdev, __VA_ARGS__) +/*! + * @} + */ + +/*! + * @name Device-related logging macros that always log. + * + * These wrap U_LOG_XDEV() to supply the @p level - which is only used for formatting the output, these macros always + * log regardless of level. + * + * @param xdev The @ref xrt_device pointer associated with this message. + * @param ... Format string and optional format arguments. + * @{ + */ +//! Log a device-related message at U_LOGGING_TRACE level (always logs). +#define U_LOG_XDEV_T(xdev, ...) U_LOG_XDEV(U_LOGGING_TRACE, xdev, __VA_ARGS__) +//! Log a device-related message at U_LOGGING_DEBUG level (always logs). +#define U_LOG_XDEV_D(xdev, ...) U_LOG_XDEV(U_LOGGING_DEBUG, xdev, __VA_ARGS__) +//! Log a device-related message at U_LOGGING_INFO level (always logs). +#define U_LOG_XDEV_I(xdev, ...) U_LOG_XDEV(U_LOGGING_INFO, xdev, __VA_ARGS__) +//! Log a device-related message at U_LOGGING_WARN level (always logs). +#define U_LOG_XDEV_W(xdev, ...) U_LOG_XDEV(U_LOGGING_WARN, xdev, __VA_ARGS__) +//! Log a device-related message at U_LOGGING_ERROR level (always logs). +#define U_LOG_XDEV_E(xdev, ...) U_LOG_XDEV(U_LOGGING_ERROR, xdev, __VA_ARGS__) +/*! + * @} + */ /*! * @} From 7d1c8480b360edc4af2b2b36e1247f34501dfc9b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 27 Apr 2021 16:58:57 -0500 Subject: [PATCH 487/883] xrt: Fix an incomplete compositor method doc. --- src/xrt/include/xrt/xrt_compositor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h index 0fe494520..eea69758a 100644 --- a/src/xrt/include/xrt/xrt_compositor.h +++ b/src/xrt/include/xrt/xrt_compositor.h @@ -703,6 +703,7 @@ struct xrt_compositor * * @param[out] xc The compositor * @param[out] out_frame_id Frame id + * @param[out] out_wake_time_ns When we want the client to be awoken to begin rendering. * @param[out] out_predicted_gpu_time_ns When we expect the client to finish the GPU work. * @param[out] out_predicted_display_time_ns When the pixels turns into photons. * @param[out] out_predicted_display_period_ns The period for the frames. From 0c685cf7ba89d6a2ce4002c65813114baa90c641 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 17:27:41 +0100 Subject: [PATCH 488/883] d/qwerty: Use u_device_get_view_pose helper --- src/xrt/drivers/qwerty/qwerty_device.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.c b/src/xrt/drivers/qwerty/qwerty_device.c index 7540e1e8f..84ece8515 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.c +++ b/src/xrt/drivers/qwerty/qwerty_device.c @@ -195,18 +195,13 @@ qwerty_get_tracked_pose(struct xrt_device *xd, } static void -qwerty_get_view_pose(struct xrt_device *xd, +qwerty_get_view_pose(struct xrt_device *xdev, const struct xrt_vec3 *eye_relation, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = XRT_POSE_IDENTITY; - bool is_left = view_index == 0; - float adjust = is_left ? -0.5f : 0.5f; - struct xrt_vec3 eye_offset = *eye_relation; - math_vec3_scalar_mul(adjust, &eye_offset); - math_vec3_accum(&eye_offset, &pose.position); - *out_pose = pose; + (void)xdev; + u_device_get_view_pose(eye_relation, view_index, out_pose); } static void From 8a715ec41c1a4220b5547a7e64bbdc5056f8a178 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 19:49:04 +0100 Subject: [PATCH 489/883] xrt: Add new error return for IPC --- src/xrt/include/xrt/xrt_results.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xrt/include/xrt/xrt_results.h b/src/xrt/include/xrt/xrt_results.h index ac16ce9ae..9ddfb68d2 100644 --- a/src/xrt/include/xrt/xrt_results.h +++ b/src/xrt/include/xrt/xrt_results.h @@ -66,4 +66,8 @@ typedef enum xrt_result * which is needed for the given command. */ XRT_ERROR_IPC_SESSION_NOT_CREATED = -15, + /*! + * The client has already created a session on this IPC connection. + */ + XRT_ERROR_IPC_SESSION_ALREADY_CREATED = -16, } xrt_result_t; From 8a191daa297088133b9452a5fda7f2b3f207b2ba Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 20:16:09 +0100 Subject: [PATCH 490/883] ipc: Add session_destroy to handle session destruction --- src/xrt/ipc/client/ipc_client_compositor.c | 4 ++ src/xrt/ipc/server/ipc_server.h | 7 +++ src/xrt/ipc/server/ipc_server_handler.c | 18 ++++++++ .../ipc/server/ipc_server_per_client_thread.c | 43 ++++++++++++------- src/xrt/ipc/shared/proto.json | 2 + 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/xrt/ipc/client/ipc_client_compositor.c b/src/xrt/ipc/client/ipc_client_compositor.c index 136b62ae5..2cd3d916b 100644 --- a/src/xrt/ipc/client/ipc_client_compositor.c +++ b/src/xrt/ipc/client/ipc_client_compositor.c @@ -662,6 +662,10 @@ ipc_compositor_destroy(struct xrt_compositor *xc) assert(icc->compositor_created); + IPC_ERROR(icc->ipc_c, "Called"); + + IPC_CALL_CHK(ipc_call_session_destroy(icc->ipc_c)); + icc->compositor_created = false; } diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h index 422f9640e..f5296533a 100644 --- a/src/xrt/ipc/server/ipc_server.h +++ b/src/xrt/ipc/server/ipc_server.h @@ -374,6 +374,13 @@ ipc_server_update_state(struct ipc_server *s); void * ipc_server_client_thread(void *_cs); +/*! + * This destroyes the native compositor for this client and any extra objects + * created from it, like all of the swapchains. + */ +void +ipc_server_client_destroy_compositor(volatile struct ipc_client_state *ics); + /*! * @defgroup ipc_server_internals Server Internals * @brief These are only called by the platform-specific mainloop polling code. diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 2ce9f94fb..5b3e786dc 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -103,6 +103,10 @@ ipc_handle_session_create(volatile struct ipc_client_state *ics, const struct xr struct xrt_compositor_native *xcn = NULL; + if (ics->xc != NULL) { + return XRT_ERROR_IPC_SESSION_ALREADY_CREATED; + } + xrt_result_t xret = xrt_syscomp_create_native_compositor(ics->server->xsysc, xsi, &xcn); if (xret != XRT_SUCCESS) { return xret; @@ -144,6 +148,20 @@ ipc_handle_session_end(volatile struct ipc_client_state *ics) return xrt_comp_end_session(ics->xc); } +xrt_result_t +ipc_handle_session_destroy(volatile struct ipc_client_state *ics) +{ + IPC_TRACE_MARKER(); + + if (ics->xc == NULL) { + return XRT_ERROR_IPC_SESSION_NOT_CREATED; + } + + ipc_server_client_destroy_compositor(ics); + + return XRT_SUCCESS; +} + xrt_result_t ipc_handle_compositor_get_info(volatile struct ipc_client_state *ics, struct xrt_compositor_info *out_info) { diff --git a/src/xrt/ipc/server/ipc_server_per_client_thread.c b/src/xrt/ipc/server/ipc_server_per_client_thread.c index 047641ed0..adafec590 100644 --- a/src/xrt/ipc/server/ipc_server_per_client_thread.c +++ b/src/xrt/ipc/server/ipc_server_per_client_thread.c @@ -124,12 +124,37 @@ client_loop(volatile struct ipc_client_state *ics) ipc_message_channel_close((struct ipc_message_channel *)&ics->imc); - ics->num_swapchains = 0; - ics->server->threads[ics->server_thread_index].state = IPC_THREAD_STOPPING; ics->server_thread_index = -1; memset((void *)&ics->client_state, 0, sizeof(struct ipc_app_state)); + os_mutex_unlock(&ics->server->global_state.lock); + + ipc_server_client_destroy_compositor(ics); + + // Should we stop the server when a client disconnects? + if (ics->server->exit_on_disconnect) { + ics->server->running = false; + } + + ipc_server_deactivate_session(ics); +} + + +/* + * + * 'Exported' functions. + * + */ + +void +ipc_server_client_destroy_compositor(volatile struct ipc_client_state *ics) +{ + // Multiple threads might be looking at these fields. + os_mutex_lock(&ics->server->global_state.lock); + + ics->num_swapchains = 0; + // Destroy all swapchains now. for (uint32_t j = 0; j < IPC_MAX_CLIENT_SWAPCHAINS; j++) { // Drop our reference, does NULL checking. Cast away volatile. @@ -142,22 +167,8 @@ client_loop(volatile struct ipc_client_state *ics) // Cast away volatile. xrt_comp_destroy((struct xrt_compositor **)&ics->xc); - - // Should we stop the server when a client disconnects? - if (ics->server->exit_on_disconnect) { - ics->server->running = false; - } - - ipc_server_deactivate_session(ics); } - -/* - * - * Entry point. - * - */ - void * ipc_server_client_thread(void *_ics) { diff --git a/src/xrt/ipc/shared/proto.json b/src/xrt/ipc/shared/proto.json index d069e39cd..8b27e7415 100644 --- a/src/xrt/ipc/shared/proto.json +++ b/src/xrt/ipc/shared/proto.json @@ -66,6 +66,8 @@ "session_end": {}, + "session_destroy": {}, + "compositor_get_info": { "out": [ {"name": "info", "type": "struct xrt_compositor_info"} From f51851d0e647c20cfef5d886c71504afa0fd8422 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 20:53:57 +0100 Subject: [PATCH 491/883] doc: Document !800 --- doc/changes/ipc/mr.721.md | 1 + doc/changes/xrt/mr.800.md | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 doc/changes/xrt/mr.800.md diff --git a/doc/changes/ipc/mr.721.md b/doc/changes/ipc/mr.721.md index 774754139..6d747090e 100644 --- a/doc/changes/ipc/mr.721.md +++ b/doc/changes/ipc/mr.721.md @@ -1,6 +1,7 @@ --- - mr.754 - mr.768 +- mr.800 --- Now that there is a interface that allows the compositor to support multi-client rendering use that instead of doing our own rendering. diff --git a/doc/changes/xrt/mr.800.md b/doc/changes/xrt/mr.800.md new file mode 100644 index 000000000..a7a3e1f03 --- /dev/null +++ b/doc/changes/xrt/mr.800.md @@ -0,0 +1,2 @@ +Add XRT_ERROR_IPC_SESSION_ALREADY_CREATED error message to signal that a session +has already been created on this connection. From 5befa76f42891c472422126ebd7b7984695c95c1 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 20:46:42 +0100 Subject: [PATCH 492/883] m/3dof: Add manual way to set the gyro bias --- src/xrt/auxiliary/math/m_imu_3dof.c | 43 ++++++++++++++++++++++++----- src/xrt/auxiliary/math/m_imu_3dof.h | 7 +++++ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/xrt/auxiliary/math/m_imu_3dof.c b/src/xrt/auxiliary/math/m_imu_3dof.c index 3f2ebce9e..0a8849a8b 100644 --- a/src/xrt/auxiliary/math/m_imu_3dof.c +++ b/src/xrt/auxiliary/math/m_imu_3dof.c @@ -69,6 +69,11 @@ m_imu_3dof_add_vars(struct m_imu_3dof *f, void *root, const char *prefix) u_var_add_ro_vec3_f32(root, &f->grav.error_axis, tmp); snprintf(tmp, sizeof(tmp), "%sgrav.error_angle", prefix); u_var_add_ro_f32(root, &f->grav.error_angle, tmp); + + snprintf(tmp, sizeof(tmp), "%sgyro_bias.value", prefix); + u_var_add_ro_vec3_f32(root, &f->gyro_bias.value, tmp); + snprintf(tmp, sizeof(tmp), "%sgyro_bias.manually_fire", prefix); + u_var_add_bool(root, &f->gyro_bias.manually_fire, tmp); } static void @@ -171,6 +176,26 @@ gravity_correction(struct m_imu_3dof *f, } } +static void +gyro_biasing(struct m_imu_3dof *f, uint64_t timestamp_ns) +{ + if (!f->gyro_bias.manually_fire) { + return; + } + + f->gyro_bias.manually_fire = false; + + uint64_t dur_ns = DUR_300MS_IN_NS; + + struct xrt_vec3 gyro_mean = XRT_VEC3_ZERO; + m_ff_vec3_f32_filter(f->gyro_ff, // Filter + timestamp_ns - dur_ns, // Start time + timestamp_ns, // End time + &gyro_mean); // Results + + f->gyro_bias.value = gyro_mean; +} + void m_imu_3dof_update(struct m_imu_3dof *f, uint64_t timestamp_ns, @@ -202,19 +227,20 @@ m_imu_3dof_update(struct m_imu_3dof *f, m_ff_vec3_f32_push(f->word_accel_ff, &world_accel, timestamp_ns); m_ff_vec3_f32_push(f->gyro_ff, gyro, timestamp_ns); - float gyro_length = m_vec3_len(*gyro); + struct xrt_vec3 gyro_biased = m_vec3_sub(*gyro, f->gyro_bias.value); + float gyro_biased_length = m_vec3_len(gyro_biased); - if (gyro_length > 0.0001f) { + if (gyro_biased_length > 0.0001f) { #if 0 math_quat_integrate_velocity(&f->rot, gyro, dt, &f->rot); #else struct xrt_vec3 rot_axis = { - gyro->x / gyro_length, - gyro->y / gyro_length, - gyro->z / gyro_length, + gyro_biased.x / gyro_biased_length, + gyro_biased.y / gyro_biased_length, + gyro_biased.z / gyro_biased_length, }; - float rot_angle = gyro_length * dt; + float rot_angle = gyro_biased_length * dt; struct xrt_quat delta_orient; math_quat_from_angle_vector(rot_angle, &rot_axis, &delta_orient); @@ -224,7 +250,10 @@ m_imu_3dof_update(struct m_imu_3dof *f, } // Gravity correction. - gravity_correction(f, timestamp_ns, accel, gyro, dt, gyro_length); + gravity_correction(f, timestamp_ns, accel, &gyro_biased, dt, gyro_biased_length); + + // Gyro bias calculations. + gyro_biasing(f, timestamp_ns); /* * Mitigate drift due to floating point diff --git a/src/xrt/auxiliary/math/m_imu_3dof.h b/src/xrt/auxiliary/math/m_imu_3dof.h index 0d9e1ef04..074349041 100644 --- a/src/xrt/auxiliary/math/m_imu_3dof.h +++ b/src/xrt/auxiliary/math/m_imu_3dof.h @@ -58,6 +58,13 @@ struct m_imu_3dof struct xrt_vec3 error_axis; float error_angle; } grav; + + // gyro bias correction + struct + { + struct xrt_vec3 value; + bool manually_fire; + } gyro_bias; }; void From 76ed4d16ced9bc451f75f3d73147eb58708a4ea8 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 23:09:44 +0100 Subject: [PATCH 493/883] c/client: Tidy and lower the logging level --- src/xrt/compositor/client/comp_egl_glue.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/xrt/compositor/client/comp_egl_glue.c b/src/xrt/compositor/client/comp_egl_glue.c index ae465f0aa..abcf31d44 100644 --- a/src/xrt/compositor/client/comp_egl_glue.c +++ b/src/xrt/compositor/client/comp_egl_glue.c @@ -279,8 +279,8 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, client_gl_swapchain_create_func sc_create = NULL; - EGL_INFO("Extension availability:"); -#define DUMP_EXTENSION_STATUS(EXT) EGL_INFO(" - " #EXT ": %s", GLAD_##EXT ? "true" : "false") + EGL_DEBUG("Extension availability:"); +#define DUMP_EXTENSION_STATUS(EXT) EGL_DEBUG(" - " #EXT ": %s", GLAD_##EXT ? "true" : "false") DUMP_EXTENSION_STATUS(GL_EXT_memory_object); DUMP_EXTENSION_STATUS(GL_EXT_memory_object_fd); @@ -299,30 +299,29 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, #if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) if (GLAD_GL_EXT_memory_object && GLAD_GL_EXT_memory_object_fd) { - EGL_INFO("Using GL memory object swapchain implementation"); + EGL_DEBUG("Using GL memory object swapchain implementation"); sc_create = client_gl_memobj_swapchain_create; } if (sc_create == NULL && GLAD_EGL_EXT_image_dma_buf_import) { - EGL_INFO("Using EGL_Image swapchain implementation"); + EGL_DEBUG("Using EGL_Image swapchain implementation"); sc_create = client_gl_eglimage_swapchain_create; } if (sc_create == NULL) { free(ceglc); EGL_ERROR( - "Could not find a required extension: need either " - "EGL_EXT_image_dma_buf_import or " + "Could not find a required extension: need either EGL_EXT_image_dma_buf_import or " "GL_EXT_memory_object_fd"); old_restore(&old); return XRT_ERROR_OPENGL; } #elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER) - EGL_INFO("Using EGL_Image swapchain implementation with AHardwareBuffer"); + EGL_DEBUG("Using EGL_Image swapchain implementation with AHardwareBuffer"); sc_create = client_gl_eglimage_swapchain_create; #endif if (!client_gl_compositor_init(&ceglc->base, xcn, sc_create, insert_fence)) { free(ceglc); - U_LOG_E("Failed to initialize compositor"); + EGL_ERROR("Failed to initialize compositor"); old_restore(&old); return XRT_ERROR_OPENGL; } From a11ce715ae565757b49bcc9c3a242bab7243d199 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 23 Apr 2021 17:25:07 -0500 Subject: [PATCH 494/883] doc: Add JSON Schema --- doc/CMakeLists.txt | 8 + doc/changes/misc_features/mr.785.md | 4 + doc/example_configs/config_v0.schema.json | 228 ++++++++++++++++++ .../config_v0.schema.json.license | 2 + 4 files changed, 242 insertions(+) create mode 100644 doc/changes/misc_features/mr.785.md create mode 100644 doc/example_configs/config_v0.schema.json create mode 100644 doc/example_configs/config_v0.schema.json.license diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index dff5e83ff..d6b248ba7 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -29,6 +29,14 @@ if(BUILD_DOC) # request to configure the file configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) + # copy the schema + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/example_configs/config_v0.schema.json + ${CMAKE_CURRENT_BINARY_DIR}/html/config_v0.schema.json + @ONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/example_configs/config_v0.schema.json.license + ${CMAKE_CURRENT_BINARY_DIR}/html/config_v0.schema.json.license + @ONLY) + # note the option ALL which allows to build the docs together with the application add_custom_target(doc_doxygen ALL COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} diff --git a/doc/changes/misc_features/mr.785.md b/doc/changes/misc_features/mr.785.md new file mode 100644 index 000000000..c7fae496b --- /dev/null +++ b/doc/changes/misc_features/mr.785.md @@ -0,0 +1,4 @@ +--- +- issue.82 +--- +Add JSON Schema for config files. diff --git a/doc/example_configs/config_v0.schema.json b/doc/example_configs/config_v0.schema.json new file mode 100644 index 000000000..d066635f3 --- /dev/null +++ b/doc/example_configs/config_v0.schema.json @@ -0,0 +1,228 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "title": "Monado configuration file schema v0", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "title": "JSON Schema directive", + "default": "https://monado.pages.freedesktop.org/monado/config_v0.schema.json" + }, + "active": { + "type": "string", + "title": "Name of the active config object", + "description": "Must match a key in the top-level object. Only config data in that object will be used.", + "$comment": "have omitted 'none' because it primarily exists for environment overrides: just leave out this key in the json for 'none'", + "enum": [ + "tracking", + "remote" + ] + }, + "tracking": { + "$ref": "#/definitions/tracking" + }, + "remote": { + "$ref": "#/definitions/remote" + } + }, + "definitions": { + "remote": { + "title": "Remote device configuration", + "required": [ + "version" + ], + "properties": { + "port": { + "type": "integer" + }, + "version": { + "type": "integer", + "title": "Remote config file schema version", + "enum": [ + 0 + ] + } + } + }, + "tracking": { + "title": "Tracking configuration", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "integer", + "title": "Tracking config file schema version", + "enum": [ + 0 + ] + }, + "tracking_overrides": { + "$ref": "#/definitions/tracking_overrides" + }, + "camera_name": { + "type": "string" + }, + "camera_mode": { + "type": "integer" + }, + "camera_type": { + "type": "string", + "enum": [ + "regular_mono", + "regular_sbs", + "ps4", + "leap_motion" + ] + }, + "calibration_path": { + "type": "string" + }, + } + }, + "tracking_overrides": { + "title": "Tracking overrides", + "type": "array", + "items": { + "$ref": "#/definitions/tracking_override" + } + }, + "tracking_override": { + "type": "object", + "title": "Tracking override object", + "required": [ + "target_device_serial", + "tracker_device_serial", + "type" + ], + "properties": { + "target_device_serial": { + "title": "Target Device Serial", + "$ref": "#/definitions/device_serial" + }, + "tracker_device_serial": { + "title": "Tracker Device Serial", + "$ref": "#/definitions/device_serial" + }, + "type": { + "type": "string", + "enum": [ + "direct", + "attached" + ] + }, + "offset": { + "type": "object", + "title": "Tracking offset", + "default": { + "orientation": { + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "position": { + "x": 0, + "y": 0, + "z": 0 + } + }, + "required": [ + "orientation", + "position" + ], + "properties": { + "orientation": { + "$ref": "#/definitions/quaternion" + }, + "position": { + "title": "Position offset", + "$ref": "#/definitions/vector3" + } + } + }, + "xrt_input_name": { + "type": "string", + "enum": [ + "XRT_INPUT_HYDRA_POSE", + "XRT_INPUT_TOUCH_AIM_POSE", + "XRT_INPUT_SIMPLE_AIM_POSE", + "XRT_INPUT_GENERIC_HEAD_DETECT", + "XRT_INPUT_SIMPLE_GRIP_POSE", + "XRT_INPUT_INDEX_GRIP_POSE", + "XRT_INPUT_VIVE_GRIP_POSE", + "XRT_INPUT_PSMV_AIM_POSE", + "XRT_INPUT_WMR_AIM_POSE", + "XRT_INPUT_WMR_GRIP_POSE", + "XRT_INPUT_PSMV_BODY_CENTER_POSE", + "XRT_INPUT_HAND_AIM_POSE", + "XRT_INPUT_INDEX_AIM_POSE", + "XRT_INPUT_DAYDREAM_POSE", + "XRT_INPUT_GENERIC_HEAD_POSE", + "XRT_INPUT_PSMV_BALL_CENTER_POSE", + "XRT_INPUT_GO_GRIP_POSE", + "XRT_INPUT_TOUCH_GRIP_POSE", + "XRT_INPUT_HAND_GRIP_POSE", + "XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT", + "XRT_INPUT_GENERIC_HAND_TRACKING_LEFT", + "XRT_INPUT_GENERIC_TRACKER_POSE", + "XRT_INPUT_PSMV_GRIP_POSE", + "XRT_INPUT_GO_AIM_POSE", + "XRT_INPUT_VIVE_AIM_POSE" + ], + "default": "XRT_INPUT_GENERIC_TRACKER_POSE" + } + } + }, + "device_serial": { + "type": "string", + "title": "Device serial", + "description": "The unique string assigned to a particular instance of a device by the driver." + }, + "quaternion": { + "type": "object", + "title": "Quaternion", + "description": "Should be normalized (length == 1) to represent rotation", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "z": { + "type": "number" + }, + "w": { + "type": "number" + } + }, + "required": [ + "x", + "y", + "z", + "w" + ] + }, + "vec3": { + "type": "object", + "title": "Vector3", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "z": { + "type": "number" + } + }, + "required": [ + "x", + "y", + "z" + ] + } + } +} diff --git a/doc/example_configs/config_v0.schema.json.license b/doc/example_configs/config_v0.schema.json.license new file mode 100644 index 000000000..a1d1e58cc --- /dev/null +++ b/doc/example_configs/config_v0.schema.json.license @@ -0,0 +1,2 @@ +Copyright 2021, Collabora, Ltd. +SPDX-License-Identifier: CC0-1.0 From cfbb81cb710b8a1f53bb7054db8f972dca608eb0 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 23 Apr 2021 17:30:35 -0500 Subject: [PATCH 495/883] a/util: Add schema directive to json before writing. --- src/xrt/auxiliary/util/u_config_json.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 4f6a75775..91f2fbdf5 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -173,6 +173,14 @@ is_json_ok(struct u_config_json *json) return true; } +static void +u_config_json_assign_schema(struct u_config_json *json) +{ + cJSON_DeleteItemFromObject(json->root, "$schema"); + cJSON_AddStringToObject(json->root, "$schema", + "https://monado.pages.freedesktop.org/monado/config_v0.schema.json"); +} + static bool parse_active(const char *str, const char *from, enum u_config_json_active_config *out_active) { @@ -384,6 +392,8 @@ u_config_json_save_calibration(struct u_config_json *json, struct xrt_settings_t if (!json->file_loaded) { u_config_json_make_default_root(json); } + u_config_json_assign_schema(json); + cJSON *root = json->root; cJSON *t = cJSON_GetObjectItem(root, "tracking"); @@ -441,6 +451,7 @@ u_config_json_save_overrides(struct u_config_json *json, struct xrt_tracking_ove if (!json->file_loaded) { u_config_json_make_default_root(json); } + u_config_json_assign_schema(json); cJSON *root = json->root; cJSON *t = cJSON_GetObjectItem(root, "tracking"); From 23c73e145bb94def9dc07bbb8c1a1adb9879ed16 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 23 Apr 2021 17:31:07 -0500 Subject: [PATCH 496/883] a/util: Make JSON reading more robust. We were missing some null checks. --- doc/changes/misc_fixes/mr.785.md | 1 + src/xrt/auxiliary/util/u_config_json.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 doc/changes/misc_fixes/mr.785.md diff --git a/doc/changes/misc_fixes/mr.785.md b/doc/changes/misc_fixes/mr.785.md new file mode 100644 index 000000000..0612d7129 --- /dev/null +++ b/doc/changes/misc_fixes/mr.785.md @@ -0,0 +1 @@ +Make config file reading more robust. diff --git a/src/xrt/auxiliary/util/u_config_json.c b/src/xrt/auxiliary/util/u_config_json.c index 91f2fbdf5..fc8c5a2a7 100644 --- a/src/xrt/auxiliary/util/u_config_json.c +++ b/src/xrt/auxiliary/util/u_config_json.c @@ -97,6 +97,9 @@ get_obj(cJSON *json, const char *name) XRT_MAYBE_UNUSED static bool get_obj_bool(cJSON *json, const char *name, bool *out_bool) { + if (json == NULL) { + return false; + } cJSON *item = get_obj(json, name); if (item == NULL) { return false; @@ -113,6 +116,9 @@ get_obj_bool(cJSON *json, const char *name, bool *out_bool) static bool get_obj_int(cJSON *json, const char *name, int *out_int) { + if (json == NULL) { + return false; + } cJSON *item = get_obj(json, name); if (item == NULL) { return false; @@ -129,6 +135,9 @@ get_obj_int(cJSON *json, const char *name, int *out_int) static bool get_obj_float(cJSON *json, const char *name, float *out_float) { + if (json == NULL) { + return false; + } cJSON *item = get_obj(json, name); if (item == NULL) { return false; @@ -145,6 +154,9 @@ get_obj_float(cJSON *json, const char *name, float *out_float) static bool get_obj_str(cJSON *json, const char *name, char *array, size_t array_size) { + if (json == NULL) { + return false; + } cJSON *item = get_obj(json, name); if (item == NULL) { return false; @@ -318,7 +330,7 @@ u_config_json_get_tracking_overrides(struct u_config_json *json, o->offset.orientation.w = 1; } - char input_name[512]; + char input_name[512] = {'\0'}; get_obj_str(override, "xrt_input_name", input_name, 512); o->input_name = xrt_input_name_enum(input_name); From c6a3dec08ec401fe4a4e487eefbd93d0e4877934 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 23 Apr 2021 17:36:07 -0500 Subject: [PATCH 497/883] doc: Rename sample NorthStar config for file extension reasons, and add schema --- ...orthstar_lonestar => config_v0.northstar_lonestar.json} | 7 ++++--- ...r.license => config_v0.northstar_lonestar.json.license} | 0 src/xrt/drivers/ultraleap_v2/readme.md | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) rename doc/example_configs/{config_v0.json.northstar_lonestar => config_v0.northstar_lonestar.json} (79%) rename doc/example_configs/{config_v0.json.northstar_lonestar.license => config_v0.northstar_lonestar.json.license} (100%) diff --git a/doc/example_configs/config_v0.json.northstar_lonestar b/doc/example_configs/config_v0.northstar_lonestar.json similarity index 79% rename from doc/example_configs/config_v0.json.northstar_lonestar rename to doc/example_configs/config_v0.northstar_lonestar.json index 85c1df6fa..664cd3b36 100644 --- a/doc/example_configs/config_v0.json.northstar_lonestar +++ b/doc/example_configs/config_v0.northstar_lonestar.json @@ -1,4 +1,5 @@ { + "$schema": "https://monado.pages.freedesktop.org/monado/config_v0.schema.json", "active": "tracking", "tracking": { "tracking_overrides": [ @@ -19,7 +20,7 @@ "z": -0.0744 } }, - "xrt_input_name": "XRT_INPUT_GENERIC_TRACKER_POSE" + "xrt_input_name": "XRT_INPUT_GENERIC_TRACKER_POSE" }, { "target_device_serial": "Leap Motion v2 driver", @@ -38,9 +39,9 @@ "z": 0 } }, - "xrt_input_name": "XRT_INPUT_GENERIC_TRACKER_POSE" + "xrt_input_name": "XRT_INPUT_GENERIC_TRACKER_POSE" } ], "version": 0 } -} \ No newline at end of file +} diff --git a/doc/example_configs/config_v0.json.northstar_lonestar.license b/doc/example_configs/config_v0.northstar_lonestar.json.license similarity index 100% rename from doc/example_configs/config_v0.json.northstar_lonestar.license rename to doc/example_configs/config_v0.northstar_lonestar.json.license diff --git a/src/xrt/drivers/ultraleap_v2/readme.md b/src/xrt/drivers/ultraleap_v2/readme.md index 7cb0d0b79..7a7a87a2c 100644 --- a/src/xrt/drivers/ultraleap_v2/readme.md +++ b/src/xrt/drivers/ultraleap_v2/readme.md @@ -29,7 +29,7 @@ you want. Instead you probably want to configure Monado to make your Leap Motion Controller-tracked hands follow around your HMD. There's an example of how to do -this with North Star in `doc/example_configs/config_v0.json.northstar_lonestar`. +this with North Star in `doc/example_configs/config_v0.northstar_lonestar.json`. If you're using a North Star headset, that should work but unless you're using the Lone Star NS variant you'll need to edit the offsets. If you're using some other HMD you'll have to edit the `tracker_device_serial` to be your HMD serial, From f09e02c51764d51ff8d8c9c3e8af779ec2ad9a94 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Wed, 28 Apr 2021 18:07:07 -0500 Subject: [PATCH 498/883] d/ns: fix resolution from 2880x1440 to 2880x1600 --- src/xrt/drivers/north_star/ns_hmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/north_star/ns_hmd.c b/src/xrt/drivers/north_star/ns_hmd.c index b1316051d..3c9a88e18 100644 --- a/src/xrt/drivers/north_star/ns_hmd.c +++ b/src/xrt/drivers/north_star/ns_hmd.c @@ -477,7 +477,7 @@ ns_hmd_create(const char *config_path) // Setup info. struct u_device_simple_info info; info.display.w_pixels = 2880; - info.display.h_pixels = 1440; + info.display.h_pixels = 1600; info.display.w_meters = 0.13f; info.display.h_meters = 0.07f; info.lens_horizontal_separation_meters = 0.13f / 2.0f; From daccde940e6bd3d7a9e33ad57aff091a701d38a5 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 20:20:56 +0100 Subject: [PATCH 499/883] d/wmr: Fix accel axis conversion --- doc/changes/drivers/mr.774.md | 3 +++ src/xrt/drivers/wmr/wmr_protocol.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/changes/drivers/mr.774.md b/doc/changes/drivers/mr.774.md index adcf95da0..c55e11d19 100644 --- a/doc/changes/drivers/mr.774.md +++ b/doc/changes/drivers/mr.774.md @@ -1 +1,4 @@ +--- +- mr.803 +--- wmr: Initial commit of driver, 3DoF only. diff --git a/src/xrt/drivers/wmr/wmr_protocol.c b/src/xrt/drivers/wmr/wmr_protocol.c index 3334cd5bc..da851294b 100644 --- a/src/xrt/drivers/wmr/wmr_protocol.c +++ b/src/xrt/drivers/wmr/wmr_protocol.c @@ -22,7 +22,7 @@ void vec3_from_hololens_accel(int32_t sample[3][4], int i, struct xrt_vec3 *out_vec) { - out_vec->x = (float)sample[0][i] * 0.001f * -1.0f; + out_vec->x = (float)sample[0][i] * 0.001f * 1.0f; out_vec->y = (float)sample[1][i] * 0.001f * -1.0f; out_vec->z = (float)sample[2][i] * 0.001f * -1.0f; } From e82fafb1867aab12f7200c053db26a20c0551a0a Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 15:27:49 -0500 Subject: [PATCH 500/883] cmake: Allow C++17 mode on all platforms, all modules. Remove per-module C++17 settings. --- CMakeLists.txt | 6 +++++- doc/changes/misc_features/mr.809.md | 1 + src/external/CMakeLists.txt | 4 ---- src/xrt/auxiliary/CMakeLists.txt | 4 ---- src/xrt/drivers/CMakeLists.txt | 1 - src/xrt/ipc/CMakeLists.txt | 4 ---- src/xrt/targets/service-lib/CMakeLists.txt | 5 ----- 7 files changed, 6 insertions(+), 19 deletions(-) create mode 100644 doc/changes/misc_features/mr.809.md diff --git a/CMakeLists.txt b/CMakeLists.txt index cc5cb0539..ca1933b66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2018-2020, Collabora, Ltd. +# Copyright 2018-2021, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 cmake_minimum_required(VERSION 3.10.2) @@ -12,6 +12,10 @@ endif() option(XRT_OPENXR_INSTALL_ABSOLUTE_RUNTIME_PATH "Use the absolute path to the runtime in the installed manifest, rather than a bare filename." ON) option(XRT_OPENXR_INSTALL_ACTIVE_RUNTIME "Make Monado the default OpenXR runtime on install" ON) +# We use C++17 +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + ### # Dependencies ### diff --git a/doc/changes/misc_features/mr.809.md b/doc/changes/misc_features/mr.809.md new file mode 100644 index 000000000..3d8819b12 --- /dev/null +++ b/doc/changes/misc_features/mr.809.md @@ -0,0 +1 @@ +For code that is implemented in C++, note that the default standard mode is now C++17 across all platforms and modules, instead of a mix of 14 and 17 like before. The CI remains the decider of what functionality is available, as it contains the oldest distribution we support (Debian Buster). diff --git a/src/external/CMakeLists.txt b/src/external/CMakeLists.txt index 500c4ae46..b2d2998a5 100644 --- a/src/external/CMakeLists.txt +++ b/src/external/CMakeLists.txt @@ -40,10 +40,6 @@ if(ANDROID) ${WRAP_SOURCES}) target_include_directories(xrt-external-jni-wrap PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/android-jni-wrap) target_link_libraries(xrt-external-jni-wrap PUBLIC xrt-external-jnipp) - set_target_properties(xrt-external-jni-wrap - PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON) endif() # OpenXR diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index 6cd78102b..85b5367cd 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -304,10 +304,6 @@ if(ANDROID) PUBLIC aux_util PRIVATE ${ANDROID_LIBRARY} ${ANDROID_LOG_LIBRARY} xrt-external-jni-wrap xrt-external-jnipp ) - set_target_properties(aux_android - PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON) target_link_libraries(aux_vk PUBLIC aux_android) endif() diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index c3b28a7ba..421374178 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -276,7 +276,6 @@ if (XRT_BUILD_DRIVER_ILLIXR) add_library(drv_illixr STATIC ${ILLIXR_SOURCE_FILES}) target_link_libraries(drv_illixr PUBLIC ${CMAKE_DL_LIBS} xrt-interfaces aux_util aux_os) target_include_directories(drv_illixr PUBLIC ${ILLIXR_PATH}) - target_compile_options(drv_illixr PUBLIC $<$:-std=c++17>) list(APPEND ENABLED_HEADSET_DRIVERS illixr) endif() diff --git a/src/xrt/ipc/CMakeLists.txt b/src/xrt/ipc/CMakeLists.txt index 55943dc28..1d4c9e62c 100644 --- a/src/xrt/ipc/CMakeLists.txt +++ b/src/xrt/ipc/CMakeLists.txt @@ -110,10 +110,6 @@ if(ANDROID) xrt-external-jnipp aux_android ) - set_target_properties(ipc_android - PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON) target_sources(ipc_server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/server/ipc_server_mainloop_android.c ) diff --git a/src/xrt/targets/service-lib/CMakeLists.txt b/src/xrt/targets/service-lib/CMakeLists.txt index 8a0e03983..3b80ba8f4 100644 --- a/src/xrt/targets/service-lib/CMakeLists.txt +++ b/src/xrt/targets/service-lib/CMakeLists.txt @@ -15,8 +15,3 @@ target_link_libraries(monado-service PRIVATE target_instance xrt-external-jni-wrap ) - -set_target_properties(monado-service - PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON) From e0bf0a423fe450adfba4f8385654fd43803eb808 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 28 Apr 2021 17:54:47 +0100 Subject: [PATCH 501/883] st/oxr: Make Vulkan optional --- src/xrt/state_trackers/oxr/CMakeLists.txt | 1 - src/xrt/state_trackers/oxr/oxr_objects.h | 2 ++ src/xrt/state_trackers/oxr/oxr_system.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/xrt/state_trackers/oxr/CMakeLists.txt b/src/xrt/state_trackers/oxr/CMakeLists.txt index 13accff35..57e8e8269 100644 --- a/src/xrt/state_trackers/oxr/CMakeLists.txt +++ b/src/xrt/state_trackers/oxr/CMakeLists.txt @@ -87,7 +87,6 @@ target_link_libraries(st_oxr PRIVATE aux-includes PUBLIC aux_os - Vulkan::Vulkan ) if(XRT_HAVE_VULKAN) target_link_libraries(st_oxr PRIVATE Vulkan::Vulkan) diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index 6cba596a4..036887ece 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -1092,9 +1092,11 @@ struct oxr_system uint32_t num_blend_modes; XrEnvironmentBlendMode blend_modes[3]; +#ifdef XR_USE_GRAPHICS_API_VULKAN //! The instance/device we create when vulkan_enable2 is used VkInstance vulkan_enable2_instance; VkPhysicalDevice vulkan_enable2_physical_device; +#endif }; #define GET_XDEV_BY_ROLE(SYS, ROLE) SYS->role.ROLE == XRT_DEVICE_ROLE_UNASSIGNED ? NULL : SYS->xdevs[SYS->role.ROLE] diff --git a/src/xrt/state_trackers/oxr/oxr_system.c b/src/xrt/state_trackers/oxr/oxr_system.c index 092702216..1b14a1525 100644 --- a/src/xrt/state_trackers/oxr/oxr_system.c +++ b/src/xrt/state_trackers/oxr/oxr_system.c @@ -99,8 +99,10 @@ oxr_system_fill_in(struct oxr_logger *log, struct oxr_instance *inst, XrSystemId sys->form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; sys->view_config_type = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; +#ifdef XR_USE_GRAPHICS_API_VULKAN sys->vulkan_enable2_instance = VK_NULL_HANDLE; sys->vulkan_enable2_physical_device = VK_NULL_HANDLE; +#endif // Headless. if (sys->xsysc == NULL) { From 61d4d86874b03268c10f8e9d8343f08a84d8aae4 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 29 Apr 2021 18:33:15 +0100 Subject: [PATCH 502/883] ipc: Remove debug print (NFC) --- src/xrt/ipc/client/ipc_client_compositor.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/xrt/ipc/client/ipc_client_compositor.c b/src/xrt/ipc/client/ipc_client_compositor.c index 2cd3d916b..4279d1d49 100644 --- a/src/xrt/ipc/client/ipc_client_compositor.c +++ b/src/xrt/ipc/client/ipc_client_compositor.c @@ -662,8 +662,6 @@ ipc_compositor_destroy(struct xrt_compositor *xc) assert(icc->compositor_created); - IPC_ERROR(icc->ipc_c, "Called"); - IPC_CALL_CHK(ipc_call_session_destroy(icc->ipc_c)); icc->compositor_created = false; From 1af00e7cbe1e771f7a6908c746b7a4a03aafd653 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 29 Apr 2021 18:38:10 +0100 Subject: [PATCH 503/883] c/client: Fix swapchain leak --- src/xrt/compositor/client/comp_gl_memobj_swapchain.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/xrt/compositor/client/comp_gl_memobj_swapchain.c b/src/xrt/compositor/client/comp_gl_memobj_swapchain.c index 2b4c1e7ab..dbf089973 100644 --- a/src/xrt/compositor/client/comp_gl_memobj_swapchain.c +++ b/src/xrt/compositor/client/comp_gl_memobj_swapchain.c @@ -81,14 +81,14 @@ client_gl_memobj_swapchain_create(struct xrt_compositor *xc, struct xrt_swapchain *native_xsc = &xscn->base; struct client_gl_memobj_swapchain *sc = U_TYPED_CALLOC(struct client_gl_memobj_swapchain); - struct xrt_swapchain_gl *xscgl = &sc->base.base; - struct xrt_swapchain *client_xsc = &xscgl->base; - client_xsc->destroy = client_gl_memobj_swapchain_destroy; - // Fetch the number of images from the native swapchain. - client_xsc->num_images = native_xsc->num_images; + sc->base.base.base.destroy = client_gl_memobj_swapchain_destroy; + sc->base.base.base.reference.count = 1; + sc->base.base.base.num_images = native_xsc->num_images; // Fetch the number of images from the native swapchain. sc->base.xscn = xscn; sc->base.tex_target = tex_target; + struct xrt_swapchain_gl *xscgl = &sc->base.base; + glGenTextures(native_xsc->num_images, xscgl->images); for (uint32_t i = 0; i < native_xsc->num_images; i++) { glBindTexture(tex_target, xscgl->images[i]); @@ -114,7 +114,7 @@ client_gl_memobj_swapchain_create(struct xrt_compositor *xc, } *out_cglsc = &sc->base; - return client_xsc; + return &sc->base.base.base; #else // silence unused function warning From c02a343b4a79375e2939710043d56c9d42683b42 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 29 Apr 2021 19:49:11 +0100 Subject: [PATCH 504/883] doc: Add !754 and !807 to !723 --- doc/changes/xrt/mr.723.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changes/xrt/mr.723.md b/doc/changes/xrt/mr.723.md index 9f97c9f45..5b03d6c5f 100644 --- a/doc/changes/xrt/mr.723.md +++ b/doc/changes/xrt/mr.723.md @@ -1,3 +1,7 @@ +--- +- mr.754 +- mr.807 +--- Make @ref xrt_swapchain be reference counted. This will greatly help with handling swapchains for multiple clients in the compositor rendering pipeline where a client might go away while the compositor is using it. From ad313459862190ca39b84a6a653e1fbf5b6c316c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 12:20:21 -0500 Subject: [PATCH 505/883] d/qwerty: Fix doxygen warnings. Comments were a bit too clever to work across doxygen versions. --- src/xrt/drivers/qwerty/qwerty_device.h | 213 ++++++++++++++++--------- 1 file changed, 136 insertions(+), 77 deletions(-) diff --git a/src/xrt/drivers/qwerty/qwerty_device.h b/src/xrt/drivers/qwerty/qwerty_device.h index 2616321dd..96f289a57 100644 --- a/src/xrt/drivers/qwerty/qwerty_device.h +++ b/src/xrt/drivers/qwerty/qwerty_device.h @@ -27,7 +27,10 @@ extern "C" { * @{ */ -//! Container of qwerty devices and driver properties. +/*! + * @brief Container of qwerty devices and driver properties. + * @see qwerty_hmd, qwerty_controller + */ struct qwerty_system { struct qwerty_hmd *hmd; //!< Can be NULL @@ -40,8 +43,10 @@ struct qwerty_system bool rctrl_focused; //!< Same as `hmd_focused` but for the right controller }; -//! Fake device that modifies its tracked pose through its methods. -//! @implements xrt_device +/*! + * Fake device that modifies its tracked pose through its methods. + * @implements xrt_device + */ struct qwerty_device { struct xrt_device base; @@ -67,14 +72,20 @@ struct qwerty_device float pitch_delta; //!< Similar to `yaw_delta` }; -//! @implements qwerty_device +/*! + * @implements qwerty_device + * @see qwerty_system + */ struct qwerty_hmd { struct qwerty_device base; }; -//! Supports input actions and can be attached to the HMD pose. -//! @implements qwerty_device +/*! + * Supports input actions and can be attached to the HMD pose. + * @implements qwerty_device + * @see qwerty_system + */ struct qwerty_controller { struct qwerty_device base; @@ -91,137 +102,185 @@ struct qwerty_controller }; /*! - * @name Qwerty System - * @memberof qwerty_system - * qwerty_system public methods - * @{ + * @public @memberof qwerty_system */ -//! @public @memberof qwerty_system - struct qwerty_system * qwerty_system_create(struct qwerty_hmd *qhmd, struct qwerty_controller *qleft, struct qwerty_controller *qright, enum u_logging_level log_level); -/*! - * @} +/* + * + * qwerty_device methods + * */ /*! - * @name Qwerty Device - * @memberof qwerty_device - * qwerty_device public methods - * @{ + * @brief Cast to qwerty_device. Ensures returning a valid device or crashing. + * @public @memberof qwerty_device */ -//! @public @memberof qwerty_device - -//! Cast to qwerty_device. Ensures returning a valid device or crashing. struct qwerty_device * qwerty_device(struct xrt_device *xd); -// clang-format off -void qwerty_press_left(struct qwerty_device *qd); -void qwerty_release_left(struct qwerty_device *qd); -void qwerty_press_right(struct qwerty_device *qd); -void qwerty_release_right(struct qwerty_device *qd); -void qwerty_press_forward(struct qwerty_device *qd); -void qwerty_release_forward(struct qwerty_device *qd); -void qwerty_press_backward(struct qwerty_device *qd); -void qwerty_release_backward(struct qwerty_device *qd); -void qwerty_press_up(struct qwerty_device *qd); -void qwerty_release_up(struct qwerty_device *qd); -void qwerty_press_down(struct qwerty_device *qd); -void qwerty_release_down(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_press_left(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_left(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_press_right(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_right(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_press_forward(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_forward(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_press_backward(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_backward(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_press_up(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_up(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_press_down(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_down(struct qwerty_device *qd); -void qwerty_press_look_left(struct qwerty_device *qd); -void qwerty_release_look_left(struct qwerty_device *qd); -void qwerty_press_look_right(struct qwerty_device *qd); -void qwerty_release_look_right(struct qwerty_device *qd); -void qwerty_press_look_up(struct qwerty_device *qd); -void qwerty_release_look_up(struct qwerty_device *qd); -void qwerty_press_look_down(struct qwerty_device *qd); -void qwerty_release_look_down(struct qwerty_device *qd); -// clang-format on +//! @public @memberof qwerty_device +void +qwerty_press_look_left(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_look_left(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_press_look_right(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_look_right(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_press_look_up(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_look_up(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_press_look_down(struct qwerty_device *qd); +//! @public @memberof qwerty_device +void +qwerty_release_look_down(struct qwerty_device *qd); -//! Momentarily increase `movement_speed` until `qwerty_release_sprint()` +/*! + * Momentarily increase `movement_speed` until `qwerty_release_sprint()` + * @public @memberof qwerty_device + */ void qwerty_press_sprint(struct qwerty_device *qd); +/*! + * Stop doing what @ref qwerty_press_sprint started. + * @public @memberof qwerty_device + */ void qwerty_release_sprint(struct qwerty_device *qd); -//! Add yaw and pitch movement for the next frame +/*! + * Add yaw and pitch movement for the next frame + * @public @memberof qwerty_device + */ void qwerty_add_look_delta(struct qwerty_device *qd, float yaw, float pitch); -//! Change movement speed in exponential steps (usually integers, but any float allowed) +/*! + * Change movement speed in exponential steps (usually integers, but any float allowed) + * @public @memberof qwerty_device + */ void qwerty_change_movement_speed(struct qwerty_device *qd, float steps); -//! Release all movement input +/*! + * Release all movement input + * @public @memberof qwerty_device + */ void qwerty_release_all(struct qwerty_device *qd); /*! - * @} + * Create qwerty_hmd. Crash on failure. + * @public @memberof qwerty_hmd */ - -/*! - * @name Qwerty HMD - * @memberof qwerty_hmd - * qwerty_hmd public methods - * @{ - */ -//! @public @memberof qwerty_hmd - -//! Create qwerty_hmd. Crash on failure. struct qwerty_hmd * qwerty_hmd_create(void); -//! Cast to qwerty_hmd. Ensures returning a valid HMD or crashing. +/*! + * Cast to qwerty_hmd. Ensures returning a valid HMD or crashing. + * @public @memberof qwerty_hmd + */ struct qwerty_hmd * qwerty_hmd(struct xrt_device *xd); -/*! - * @} +/* + * + * qwerty_controller methods + * */ - /*! - * @name Qwerty Controller - * @memberof qwerty_controller - * qwerty_controller public methods - * @{ + * Create qwerty_controller. Crash on failure. + * @public @memberof qwerty_controller */ -//! @public @memberof qwerty_controller - -//! Create qwerty_controller. Crash on failure. struct qwerty_controller * qwerty_controller_create(bool is_left, struct qwerty_hmd *qhmd); -//! Cast to qwerty_controller. Ensures returning a valid controller or crashing. +/*! + * Cast to qwerty_controller. Ensures returning a valid controller or crashing. + * @public @memberof qwerty_controller + */ struct qwerty_controller * qwerty_controller(struct xrt_device *xd); -//! Simulate input/select/click +/*! + * Simulate input/select/click + * @public @memberof qwerty_controller + */ void qwerty_select_click(struct qwerty_controller *qc); -//! Simulate input/menu/click +/*! + * Simulate input/menu/click + * @public @memberof qwerty_controller + */ void qwerty_menu_click(struct qwerty_controller *qc); -//! Attach/detach the pose of `qc` to its HMD. Only works when a qwerty_hmd is present. +/*! + * Attach/detach the pose of `qc` to its HMD. Only works when a qwerty_hmd is present. + * @public @memberof qwerty_controller + */ void qwerty_follow_hmd(struct qwerty_controller *qc, bool follow); -//! Reset controller to initial pose and makes it follow the HMD +/*! + * Reset controller to initial pose and makes it follow the HMD + * @public @memberof qwerty_controller + */ void qwerty_reset_controller_pose(struct qwerty_controller *qc); -/*! - * @} - */ /*! * @} From 928771fddfc078f941f8717241470ed9f9fde0c8 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 27 Apr 2021 17:15:11 -0500 Subject: [PATCH 506/883] t/oxr_android: Update recyclerview, and do not use wildcard version --- doc/changes/misc_features/mr.676.md | 2 ++ src/xrt/targets/openxr_android/build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/changes/misc_features/mr.676.md b/doc/changes/misc_features/mr.676.md index 8f2259432..55e16f6b3 100644 --- a/doc/changes/misc_features/mr.676.md +++ b/doc/changes/misc_features/mr.676.md @@ -1,4 +1,6 @@ --- - mr.703 +- mr.783 +- mr.808 --- More improvements to the Android port. diff --git a/src/xrt/targets/openxr_android/build.gradle b/src/xrt/targets/openxr_android/build.gradle index 3dbd1b26b..f633d3faa 100644 --- a/src/xrt/targets/openxr_android/build.gradle +++ b/src/xrt/targets/openxr_android/build.gradle @@ -177,8 +177,8 @@ dependencies { // Dependencies related only to AboutLibraries implementation "com.mikepenz:aboutlibraries-core:${latestAboutLibsRelease}" implementation "com.mikepenz:aboutlibraries:${latestAboutLibsRelease}" - implementation "androidx.cardview:cardview:1.*.*" - implementation "androidx.recyclerview:recyclerview:1.1.*" + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.recyclerview:recyclerview:1.2.0' // for Hilt dependency injection From 417de87cb26cc25d11c0b7330319929ae6c516f0 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 26 Mar 2021 14:49:54 -0500 Subject: [PATCH 507/883] a/util: Add a generic callbacks collection. Based on the work for the Android surface callbacks, just finished being made generic since we'll need to reuse it. --- src/xrt/auxiliary/CMakeLists.txt | 1 + src/xrt/auxiliary/meson.build | 1 + .../auxiliary/util/u_generic_callbacks.hpp | 231 ++++++++++++++++++ tests/CMakeLists.txt | 6 + tests/tests_generic_callbacks.cpp | 104 ++++++++ 5 files changed, 343 insertions(+) create mode 100644 src/xrt/auxiliary/util/u_generic_callbacks.hpp create mode 100644 tests/tests_generic_callbacks.cpp diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index 85b5367cd..ad6027081 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -127,6 +127,7 @@ set(UTIL_SOURCE_FILES util/u_format.h util/u_frame.c util/u_frame.h + util/u_generic_callbacks.hpp util/u_git_tag.h util/u_hand_tracking.c util/u_hand_tracking.h diff --git a/src/xrt/auxiliary/meson.build b/src/xrt/auxiliary/meson.build index 8433d434f..2d2e2bc0f 100644 --- a/src/xrt/auxiliary/meson.build +++ b/src/xrt/auxiliary/meson.build @@ -36,6 +36,7 @@ lib_aux_util = static_library( 'util/u_format.h', 'util/u_frame.c', 'util/u_frame.h', + 'util/u_generic_callbacks.hpp', 'util/u_git_tag.h', 'util/u_hand_tracking.c', 'util/u_hand_tracking.h', diff --git a/src/xrt/auxiliary/util/u_generic_callbacks.hpp b/src/xrt/auxiliary/util/u_generic_callbacks.hpp new file mode 100644 index 000000000..f3d6c13f7 --- /dev/null +++ b/src/xrt/auxiliary/util/u_generic_callbacks.hpp @@ -0,0 +1,231 @@ +// Copyright 2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Implementation of a generic callback collection, intended to be wrapped for a specific event type. + * @author Ryan Pavlik + * @ingroup aux_util + */ + +#include +#include + +namespace xrt::auxiliary::util { +template struct GenericCallbacks; + +namespace detail { + + /*! + * @brief Element type stored in @ref GenericCallbacks, for internal use only. + */ + template struct GenericCallbackEntry + { + CallbackType callback; + MaskType event_mask; + void *userdata; + bool should_remove = false; + + GenericCallbackEntry(CallbackType callback_, MaskType event_mask_, void *userdata_) noexcept + : callback(callback_), event_mask(event_mask_), userdata(userdata_) + {} + + /*! + * Do the two entries match? Used for removal "by value" + */ + bool + matches(GenericCallbackEntry const &other) const noexcept + { + return callback == other.callback && event_mask == other.event_mask && + userdata == other.userdata; + } + + bool + operator==(GenericCallbackEntry const &other) const noexcept + { + return matches(other); + } + + bool + shouldInvoke(MaskType event) const noexcept + { + return (event_mask & event) != 0; + } + }; + + template struct identity + { + using type = T; + }; + + // This lets us handle being passed an enum (which we can call underlying_type on) as well as an integer (which + // we cannot) + template + using mask_from_enum_t = + typename std::conditional_t::value, std::underlying_type, identity>::type; + +} // namespace detail + +/*! + * @brief A generic collection of callbacks for event types represented as a bitmask, intended to be wrapped for each + * usage. + * + * A registered callback may identify one or more event types (bits in the bitmask) that it wants to be invoked for. A + * userdata void pointer is also stored for each callback. Bitmasks are tested at invocation time, and the general + * callback format allows for callbacks to indicate they should be removed from the collection. Actually calling each + * callback is left to a consumer-provided "invoker" to allow adding context and event data to the call. The "invoker" + * also allows the option of whether or how to expose the self-removal capability: yours might simply always return + * "false". + * + * This generic structure supports callbacks that are included multiple times in the collection, if the consuming code + * needs it. GenericCallbacks::contains may be used by consuming code before conditionally calling addCallback, to + * limit to a single instance in a collection. + * + * @tparam CallbackType the function pointer type to store for each callback. + * @tparam EventType the event enum type. + */ +template struct GenericCallbacks +{ + +public: + static_assert(std::is_integral::value || std::is_enum::value, + "Your event type must either be an integer or an enum"); + using callback_t = CallbackType; + using event_t = EventType; + using mask_t = detail::mask_from_enum_t; + +private: + static_assert(std::is_integral::value, "Our enum to mask conversion should have produced an integer"); + + //! The type stored for each added callback. + using callback_entry_t = detail::GenericCallbackEntry; + +public: + /*! + * @brief Add a new callback entry with the given callback function pointer, event mask, and user data. + * + * New callback entries are always added at the end of the collection. + */ + void + addCallback(CallbackType callback, mask_t event_mask, void *userdata) + { + callbacks.emplace_back(callback, event_mask, userdata); + } + + /*! + * @brief Remove some number of callback entries matching the given callback function pointer, event mask, and + * user data. + * + * @param callback The callback function pointer. Tested for equality with each callback entry. + * @param event_mask The callback event mask. Tested for equality with each callback entry. + * @param userdata The opaque user data pointer. Tested for equality with each callback entry. + * @param num_skip The number of matches to skip before starting to remove callbacks. Defaults to 0. + * @param max_remove The number of matches to remove, or negative if no limit. Defaults to -1. + * + * @returns the number of callbacks removed. + */ + int + removeCallback( + CallbackType callback, mask_t event_mask, void *userdata, unsigned int num_skip = 0, int max_remove = -1) + { + if (max_remove == 0) { + // We were told to remove none. We can do this very quickly. + // Avoids a corner case in the loop where we assume max_remove is non-zero. + return 0; + } + bool found = false; + + const callback_entry_t needle{callback, event_mask, userdata}; + for (auto &entry : callbacks) { + if (entry.matches(needle)) { + if (num_skip > 0) { + // We are still in our skipping phase. + num_skip--; + continue; + } + entry.should_remove = true; + found = true; + // Negatives (no max) get more negative, which is OK. + max_remove--; + if (max_remove == 0) { + // not looking for more + break; + } + } + } + if (found) { + return purgeMarkedCallbacks(); + } + // if we didn't find any, we removed zero. + return 0; + } + + /*! + * @brief See if the collection contains at least one matching callback. + * + * @param callback The callback function pointer. Tested for equality with each callback entry. + * @param event_mask The callback event mask. Tested for equality with each callback entry. + * @param userdata The opaque user data pointer. Tested for equality with each callback entry. + * + * @returns true if a matching callback is found. + */ + bool + contains(CallbackType callback, mask_t event_mask, void *userdata) + { + const callback_entry_t needle{callback, event_mask, userdata}; + auto it = std::find(callbacks.begin(), callbacks.end(), needle); + return it != callbacks.end(); + } + + /*! + * @brief Invokes the callbacks, by passing the ones we should run to your "invoker" to add any desired + * context/event data and forward the call. + * + * Callbacks are called in order, filtering out those whose event mask does not include the given event. + * + * @param event The event type to invoke callbacks for. + * @param invoker A function/functor accepting the event, a callback function pointer, and the callback entry's + * userdata as parameters, and returning true if the callback should be removed from the collection. It is + * assumed that the invoker will add any additional context or event data and call the provided callback. + * + * Typically, a lambda with some captures and a single return statement will be sufficient for an invoker. + * + * @returns the number of callbacks run + */ + template + int + invokeCallbacks(EventType event, F &&invoker) + { + bool needPurge = false; + + int ran = 0; + for (auto &entry : callbacks) { + if (entry.shouldInvoke(static_cast(event))) { + bool willRemove = invoker(event, entry.callback, entry.userdata); + if (willRemove) { + entry.should_remove = true; + needPurge = true; + } + ran++; + } + } + if (needPurge) { + purgeMarkedCallbacks(); + } + return ran; + } + +private: + std::vector callbacks; + + int + purgeMarkedCallbacks() + { + auto b = callbacks.begin(); + auto e = callbacks.end(); + auto new_end = std::remove_if(b, e, [](callback_entry_t const &entry) { return entry.should_remove; }); + auto num_removed = std::distance(new_end, e); + callbacks.erase(new_end, e); + return static_cast(num_removed); + } +}; +} // namespace xrt::auxiliary::util diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8b71246d9..f261fb69f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,3 +17,9 @@ target_link_libraries(tests_input_transform PRIVATE xrt-external-openxr aux_util) add_test(NAME input_transform COMMAND tests_input_transform --success) + +# Generic callbacks +add_executable(tests_generic_callbacks tests_generic_callbacks.cpp) +target_link_libraries(tests_generic_callbacks PRIVATE tests_main) +target_link_libraries(tests_generic_callbacks PRIVATE aux_util) +add_test(NAME tests_generic_callbacks COMMAND tests_generic_callbacks --success) diff --git a/tests/tests_generic_callbacks.cpp b/tests/tests_generic_callbacks.cpp new file mode 100644 index 000000000..e3997723a --- /dev/null +++ b/tests/tests_generic_callbacks.cpp @@ -0,0 +1,104 @@ +// Copyright 2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Generic callback collection tests. + * @author Ryan Pavlik + */ + +#include "catch/catch.hpp" + +#include + +using xrt::auxiliary::util::GenericCallbacks; + +enum class MyEvent +{ + ACQUIRED, + LOST, +}; + +using mask_t = std::underlying_type_t; + +static bool +increment_userdata_int(MyEvent event, void *userdata) +{ + *static_cast(userdata) += 1; + return true; +} + + +using callback_t = bool (*)(MyEvent event, void *userdata); + +TEST_CASE("u_generic_callbacks") +{ + GenericCallbacks callbacks; + // Simplest possible invoker. + auto invoker = [](MyEvent event, callback_t callback, void *userdata) { return callback(event, userdata); }; + + SECTION("call when empty") + { + CHECK(0 == callbacks.invokeCallbacks(MyEvent::ACQUIRED, invoker)); + CHECK(0 == callbacks.invokeCallbacks(MyEvent::LOST, invoker)); + CHECK(0 == callbacks.removeCallback(&increment_userdata_int, (mask_t)MyEvent::LOST, nullptr)); + } + SECTION("same function, different mask and userdata") + { + int numAcquired = 0; + int numLost = 0; + REQUIRE_NOTHROW(callbacks.addCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numAcquired)); + REQUIRE_NOTHROW(callbacks.addCallback(increment_userdata_int, (mask_t)MyEvent::LOST, &numLost)); + SECTION("contains") + { + CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::LOST, &numLost)); + CHECK_FALSE(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::LOST, &numAcquired)); + } + SECTION("removal matching") + { + CHECK(0 == + callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::LOST, &numAcquired)); + CHECK(0 == + callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numLost)); + } + SECTION("duplicates, contains, and removal") + { + REQUIRE(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numAcquired)); + REQUIRE_NOTHROW( + callbacks.addCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numAcquired)); + CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, &numAcquired)); + // Now we have two ACQUIRED and one LOST callback. + SECTION("max_remove") + { + CHECK(0 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired, 0, 0)); + CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired)); + + CHECK(1 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired, 0, 1)); + CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired)); + } + SECTION("large max_remove") + { + CHECK(2 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired, 0, 3)); + CHECK_FALSE(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired)); + } + SECTION("num_skip") + { + CHECK(0 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired, 3)); + CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired)); + + CHECK(1 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired, 1)); + CHECK(callbacks.contains(increment_userdata_int, (mask_t)MyEvent::ACQUIRED, + &numAcquired)); + } + } + CHECK(1 == callbacks.removeCallback(increment_userdata_int, (mask_t)MyEvent::LOST, &numLost)); + } +} From e4f2ac32860f8c6fc8d0dc317fc5b0b32f54fc12 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 9 Apr 2021 16:32:46 -0500 Subject: [PATCH 508/883] android: Revise MonadoView so it doesn't require an Activity. --- .../monado/auxiliary/MonadoView.java | 138 ++++++++++-------- 1 file changed, 80 insertions(+), 58 deletions(-) diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java index 692485f78..5bd32fd7a 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java @@ -10,6 +10,7 @@ package org.freedesktop.monado.auxiliary; import android.app.Activity; +import android.content.Context; import android.os.Build; import android.util.DisplayMetrics; import android.util.Log; @@ -41,32 +42,40 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // we want sticky immersive | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - /// The activity we've connected to. - private final Activity activity; - + private final Context context; /// Guards currentSurfaceHolder private final Object currentSurfaceHolderSync = new Object(); + /// The activity we've connected to. + @Nullable + private final + Activity activity; private final Method viewSetSysUiVis; - private NativeCounterpart nativeCounterpart; - public int width = -1; public int height = -1; public int format = -1; - + private NativeCounterpart nativeCounterpart; /// Guarded by currentSurfaceHolderSync private SurfaceHolder currentSurfaceHolder = null; + public MonadoView(Context context) { + super(context); + this.context = context; + Activity activity; + if (context instanceof Activity) { + activity = (Activity) context; + } else { + activity = null; + } + this.activity = activity; + viewSetSysUiVis = getSystemUiVisMethod(); + } + public MonadoView(Activity activity) { super(activity); + this.context = activity; this.activity = activity; - Method method; - try { - method = activity.getWindow().getDecorView().getClass().getMethod("setSystemUiVisibility", int.class); - } catch (NoSuchMethodException e) { - // ok - method = null; - } - viewSetSysUiVis = method; + + viewSetSysUiVis = getSystemUiVisMethod(); } private MonadoView(Activity activity, long nativePointer) { @@ -74,39 +83,15 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S nativeCounterpart = new NativeCounterpart(nativePointer); } - private void createSurface() { - createSurface(false); - } - - /** - * @param focusable Indicates MonadoView should be focusable or not - */ - private void createSurface(boolean focusable) { - Log.i(TAG, "Starting to add a new surface!"); - activity.runOnUiThread(() -> { - Log.i(TAG, "Starting runOnUiThread"); - activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - - WindowManager windowManager = activity.getWindowManager(); - WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); - if (focusable) { - lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN; - } else { - // There are 2 problems if view is focusable on all-in-one device: - // 1. Navigation bar won't go away because view gets focus. - // 2. Underlying activity lost focus and can not receive input. - lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN | - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; - } - windowManager.addView(this, lp); - if (focusable) { - requestFocus(); - } - SurfaceHolder surfaceHolder = getHolder(); - surfaceHolder.addCallback(this); - Log.i(TAG, "Registered callbacks!"); - }); + private static Method getSystemUiVisMethod() { + Method method; + try { + method = android.view.View.class.getMethod("setSystemUiVisibility", int.class); + } catch (NoSuchMethodException e) { + // ok + method = null; + } + return method; } /** @@ -120,7 +105,7 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S @SuppressWarnings("deprecation") public static MonadoView attachToActivity(@NonNull final Activity activity, long nativePointer) { final MonadoView view = new MonadoView(activity, nativePointer); - view.createSurface(); + view.createSurfaceInActivity(); return view; } @@ -128,10 +113,53 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S @Keep public static MonadoView attachToActivity(@NonNull final Activity activity) { final MonadoView view = new MonadoView(activity); - view.createSurface(); + view.createSurfaceInActivity(); return view; } + @NonNull + @Keep + public static DisplayMetrics getDisplayMetrics(Activity activity) { + DisplayMetrics displayMetrics = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + return displayMetrics; + } + + private void createSurfaceInActivity() { + createSurfaceInActivity(false); + } + + /** + * @param focusable Indicates MonadoView should be focusable or not + */ + private void createSurfaceInActivity(boolean focusable) { + Log.i(TAG, "Starting to add a new surface!"); + activity.runOnUiThread(() -> { + Log.i(TAG, "Starting runOnUiThread"); + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + WindowManager windowManager = activity.getWindowManager(); + WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); + if (focusable) { + lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN; + } else { + // There are 2 problems if view is focusable on all-in-one device: + // 1. Navigation bar won't go away because view gets focus. + // 2. Underlying activity lost focus and can not receive input. + lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN | + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + } + windowManager.addView(this, lp); + if (focusable) { + requestFocus(); + } + SurfaceHolder surfaceHolder = getHolder(); + surfaceHolder.addCallback(this); + Log.i(TAG, "Registered callbacks!"); + }); + } + /** * Block up to a specified amount of time, waiting for the surfaceCreated callback to be fired * and populate the currentSurfaceHolder. @@ -200,13 +228,15 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S return true; } - /** * Add a listener so that if our system UI display state doesn't include all we want, we re-apply. */ @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) @SuppressWarnings("deprecation") private void setSystemUiVisChangeListener() { + if (activity == null) { + return; + } activity.getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> { // If not fullscreen, fix it. if (0 == (visibility & View.SYSTEM_UI_FLAG_FULLSCREEN)) { @@ -268,12 +298,4 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S Log.i(TAG, "surfaceRedrawNeeded"); } - @NonNull - @Keep - public static DisplayMetrics getDisplayMetrics(Activity activity) { - DisplayMetrics displayMetrics = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); - return displayMetrics; - } - } From faa753c667da9e2ce1b3f4c9cda3947622854e7f Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 13 Apr 2021 11:39:28 -0500 Subject: [PATCH 509/883] android: Annotation, docs, and formatting improvements for MonadoView --- .../monado/auxiliary/MonadoView.java | 23 ++++++++++++++----- .../monado/auxiliary/UiProvider.kt | 2 -- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java index 5bd32fd7a..4d471a1e2 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java @@ -19,6 +19,7 @@ import android.view.SurfaceView; import android.view.View; import android.view.WindowManager; +import androidx.annotation.GuardedBy; import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -31,6 +32,7 @@ import java.util.Calendar; @Keep public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, SurfaceHolder.Callback2 { private static final String TAG = "MonadoView"; + @SuppressWarnings("deprecation") private static final int sysUiVisFlags = 0 // Give us a stable view of content insets @@ -42,19 +44,27 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // we want sticky immersive | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + + @NonNull private final Context context; - /// Guards currentSurfaceHolder - private final Object currentSurfaceHolderSync = new Object(); + /// The activity we've connected to. @Nullable - private final - Activity activity; + private final Activity activity; + + @Nullable private final Method viewSetSysUiVis; + + private final Object currentSurfaceHolderSync = new Object(); + public int width = -1; public int height = -1; public int format = -1; + private NativeCounterpart nativeCounterpart; - /// Guarded by currentSurfaceHolderSync + + @GuardedBy("currentSurfaceHolderSync") + @Nullable private SurfaceHolder currentSurfaceHolder = null; public MonadoView(Context context) { @@ -97,7 +107,8 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S /** * Construct and start attaching a MonadoView to a client application. * - * @param activity The activity to attach to. + * @param activity The activity to attach to. + * @param nativePointer The native android_custom_surface pointer, cast to a long. * @return The MonadoView instance created and asynchronously attached. */ @NonNull diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/UiProvider.kt b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/UiProvider.kt index 3a9c89c7e..b46f3341a 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/UiProvider.kt +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/UiProvider.kt @@ -9,8 +9,6 @@ package org.freedesktop.monado.auxiliary import android.app.PendingIntent -import android.content.Context -import android.graphics.drawable.Drawable import android.graphics.drawable.Icon /** From 45c0ca2ef934f03dc54578db38dc3f92577b17a8 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 12 Apr 2021 15:04:48 -0500 Subject: [PATCH 510/883] aux/android: Expose native pointer from MonadoView --- .../java/org/freedesktop/monado/auxiliary/MonadoView.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java index 4d471a1e2..9d8fb6794 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java @@ -136,6 +136,14 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S return displayMetrics; } + @Keep + public long getNativePointer() { + if (nativeCounterpart == null) { + return 0; + } + return nativeCounterpart.getNativePointer(); + } + private void createSurfaceInActivity() { createSurfaceInActivity(false); } From 125b0799a38b25acf2e1246e313480e436982538 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 10:35:28 -0500 Subject: [PATCH 511/883] aux/android: Update wrappers --- .../org.freedesktop.monado.auxiliary.cpp | 16 ++-- .../org.freedesktop.monado.auxiliary.hpp | 74 ++++++++++++++----- .../org.freedesktop.monado.auxiliary.impl.hpp | 46 ++++++++---- 3 files changed, 97 insertions(+), 39 deletions(-) diff --git a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp index 63d1f34ce..2d44d1149 100644 --- a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp +++ b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -14,13 +14,15 @@ namespace wrap { namespace org::freedesktop::monado::auxiliary { MonadoView::Meta::Meta(jni::jclass clazz) : MetaBase(MonadoView::getTypeName(), clazz), - attachToActivity(classRef().getStaticMethod("attachToActivity", - "(Landroid/app/Activity;J)Lorg/freedesktop/" - "monado/auxiliary/MonadoView;")), - waitGetSurfaceHolder(classRef().getMethod("waitGetSurfaceHolder", "(I)Landroid/view/SurfaceHolder;")), - markAsDiscardedByNative(classRef().getMethod("markAsDiscardedByNative", "()V")), + attachToActivity(classRef().getStaticMethod( + "attachToActivity", "(Landroid/app/Activity;J)Lorg/freedesktop/monado/auxiliary/MonadoView;")), + attachToActivity1(classRef().getStaticMethod( + "attachToActivity", "(Landroid/app/Activity;)Lorg/freedesktop/monado/auxiliary/MonadoView;")), getDisplayMetrics(classRef().getStaticMethod("getDisplayMetrics", - "(Landroid/app/Activity;)Landroid/util/DisplayMetrics;")) + "(Landroid/app/Activity;)Landroid/util/DisplayMetrics;")), + getNativePointer(classRef().getMethod("getNativePointer", "()J")), + markAsDiscardedByNative(classRef().getMethod("markAsDiscardedByNative", "()V")), + waitGetSurfaceHolder(classRef().getMethod("waitGetSurfaceHolder", "(I)Landroid/view/SurfaceHolder;")) {} } // namespace org::freedesktop::monado::auxiliary } // namespace wrap diff --git a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp index 1cea26e62..909c11988 100644 --- a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp +++ b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -27,6 +27,7 @@ namespace org::freedesktop::monado::auxiliary { } // namespace wrap + namespace wrap { namespace org::freedesktop::monado::auxiliary { /*! @@ -42,32 +43,60 @@ namespace org::freedesktop::monado::auxiliary { return "org/freedesktop/monado/auxiliary/MonadoView"; } + static constexpr const char * + getFullyQualifiedTypeName() noexcept + { + return "org.freedesktop.monado.auxiliary.MonadoView"; + } + /*! * Wrapper for the attachToActivity static method * * Java prototype: - * `public static org.freedesktop.monado.auxiliary.MonadoView - * attachToActivity(android.app.Activity, long);` + * `public static org.freedesktop.monado.auxiliary.MonadoView attachToActivity(android.app.Activity, + * long);` * - * JNI signature: - * (Landroid/app/Activity;J)Lorg/freedesktop/monado/auxiliary/MonadoView; + * JNI signature: (Landroid/app/Activity;J)Lorg/freedesktop/monado/auxiliary/MonadoView; * */ static MonadoView attachToActivity(android::app::Activity const &activity, void *nativePointer); /*! - * Wrapper for the waitGetSurfaceHolder method + * Wrapper for the attachToActivity static method * * Java prototype: - * `public android.view.SurfaceHolder - * waitGetSurfaceHolder(int);` + * `public static org.freedesktop.monado.auxiliary.MonadoView attachToActivity(android.app.Activity);` * - * JNI signature: (I)Landroid/view/SurfaceHolder; + * JNI signature: (Landroid/app/Activity;)Lorg/freedesktop/monado/auxiliary/MonadoView; * */ - android::view::SurfaceHolder - waitGetSurfaceHolder(int32_t wait_ms); + static MonadoView + attachToActivity(android::app::Activity const &activity); + + /*! + * Wrapper for the getDisplayMetrics static method + * + * Java prototype: + * `public static android.util.DisplayMetrics getDisplayMetrics(android.app.Activity);` + * + * JNI signature: (Landroid/app/Activity;)Landroid/util/DisplayMetrics; + * + */ + static jni::Object + getDisplayMetrics(android::app::Activity const &activity); + + /*! + * Wrapper for the getNativePointer method + * + * Java prototype: + * `public long getNativePointer();` + * + * JNI signature: ()J + * + */ + void * + getNativePointer(); /*! * Wrapper for the markAsDiscardedByNative method @@ -81,9 +110,17 @@ namespace org::freedesktop::monado::auxiliary { void markAsDiscardedByNative(); - - static jni::Object - getDisplayMetrics(android::app::Activity const &activity); + /*! + * Wrapper for the waitGetSurfaceHolder method + * + * Java prototype: + * `public android.view.SurfaceHolder waitGetSurfaceHolder(int);` + * + * JNI signature: (I)Landroid/view/SurfaceHolder; + * + */ + android::view::SurfaceHolder + waitGetSurfaceHolder(int32_t wait_ms); /*! * Initialize the static metadata of this wrapper with a known @@ -101,9 +138,11 @@ namespace org::freedesktop::monado::auxiliary { struct Meta : public MetaBase { jni::method_t attachToActivity; - jni::method_t waitGetSurfaceHolder; - jni::method_t markAsDiscardedByNative; + jni::method_t attachToActivity1; jni::method_t getDisplayMetrics; + jni::method_t getNativePointer; + jni::method_t markAsDiscardedByNative; + jni::method_t waitGetSurfaceHolder; /*! * Singleton accessor @@ -116,9 +155,10 @@ namespace org::freedesktop::monado::auxiliary { } private: - Meta(jni::jclass clazz); + explicit Meta(jni::jclass clazz); }; }; + } // namespace org::freedesktop::monado::auxiliary } // namespace wrap #include "org.freedesktop.monado.auxiliary.impl.hpp" diff --git a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp index a334933ea..a34f3fa6c 100644 --- a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp +++ b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -13,6 +13,7 @@ #include "wrap/android.app.h" #include "wrap/android.view.h" + namespace wrap { namespace org::freedesktop::monado::auxiliary { inline MonadoView @@ -20,7 +21,35 @@ namespace org::freedesktop::monado::auxiliary { { return MonadoView(Meta::data().clazz().call( Meta::data().attachToActivity, activity.object(), - static_cast(reinterpret_cast(nativePointer)))); + static_cast(reinterpret_cast(nativePointer)))); + } + + inline MonadoView + MonadoView::attachToActivity(android::app::Activity const &activity) + { + return MonadoView( + Meta::data().clazz().call(Meta::data().attachToActivity1, activity.object())); + } + + inline jni::Object + MonadoView::getDisplayMetrics(android::app::Activity const &activity) + { + return Meta::data().clazz().call(Meta::data().getDisplayMetrics, activity.object()); + } + + inline void * + MonadoView::getNativePointer() + { + assert(!isNull()); + return reinterpret_cast( + static_cast(object().call(Meta::data().getNativePointer))); + } + + inline void + MonadoView::markAsDiscardedByNative() + { + assert(!isNull()); + return object().call(Meta::data().markAsDiscardedByNative); } inline android::view::SurfaceHolder @@ -31,18 +60,5 @@ namespace org::freedesktop::monado::auxiliary { object().call(Meta::data().waitGetSurfaceHolder, wait_ms)); } - inline void - MonadoView::markAsDiscardedByNative() - { - assert(!isNull()); - return object().call(Meta::data().markAsDiscardedByNative); - } - - inline jni::Object - MonadoView::getDisplayMetrics(android::app::Activity const &activity) - { - return Meta::data().clazz().call(Meta::data().getDisplayMetrics, activity.object()); - } - } // namespace org::freedesktop::monado::auxiliary } // namespace wrap From cf2abe7d88ab19994863635336afcb3f60b6f6a0 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 11:02:07 -0500 Subject: [PATCH 512/883] u/process: Fix a warning by marking a function as maybe unused. --- src/xrt/auxiliary/util/u_process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/auxiliary/util/u_process.c b/src/xrt/auxiliary/util/u_process.c index 09530517c..5e81624b2 100644 --- a/src/xrt/auxiliary/util/u_process.c +++ b/src/xrt/auxiliary/util/u_process.c @@ -35,7 +35,7 @@ struct u_process #endif }; -static inline int +XRT_MAYBE_UNUSED static inline int get_pidfile_path(char *buf) { int size = u_file_get_path_in_runtime_dir(PID_FILE_NAME, buf, PATH_MAX); From 5c62db854e6f93a2104cc305aa7408b7eb7b4e68 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 11:36:49 -0500 Subject: [PATCH 513/883] gradle: update Android gradle plugin --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d2357a021..aa629c958 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.2' + classpath 'com.android.tools.build:gradle:4.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${latestAboutLibsRelease}" classpath 'com.quittle:svg-2-android-vector:0.0.5' From 354010461329a00866e716aee5c069899d35bd9e Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 12:02:12 -0500 Subject: [PATCH 514/883] gradle: Bump kotlin version. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index aa629c958..b517d3503 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { ext { - kotlinVersion = '1.4.31' + kotlinVersion = '1.4.32' latestAboutLibsRelease = "8.5.0" androidxCoreVersion = "1.3.2" From a66f567392d950baa9a1b498206c7cc3e70ac1b6 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 14:53:24 -0500 Subject: [PATCH 515/883] aux/android: Remove unused include --- src/xrt/auxiliary/android/android_load_class.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xrt/auxiliary/android/android_load_class.cpp b/src/xrt/auxiliary/android/android_load_class.cpp index 24b2a85f9..47f42c60b 100644 --- a/src/xrt/auxiliary/android/android_load_class.cpp +++ b/src/xrt/auxiliary/android/android_load_class.cpp @@ -12,7 +12,6 @@ #include "util/u_logging.h" #include "wrap/android.content.h" -#include "wrap/dalvik.system.h" #include "jni.h" From d31bab93988d29306777b32547791206b9af6edb Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 11:51:05 -0500 Subject: [PATCH 516/883] external: Update jnipp --- src/external/jnipp/jnipp.cpp | 4 ++++ src/external/jnipp/jnipp.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/external/jnipp/jnipp.cpp b/src/external/jnipp/jnipp.cpp index cc9941be1..2c558bda6 100644 --- a/src/external/jnipp/jnipp.cpp +++ b/src/external/jnipp/jnipp.cpp @@ -1480,6 +1480,10 @@ namespace jni ((jvalue*) v)->l = env()->NewStringUTF(a); } + void valueArg(value_t* v, std::nullptr_t) + { + ((jvalue*) v)->l = nullptr; + } template <> void cleanupArg(value_t* v) { diff --git a/src/external/jnipp/jnipp.h b/src/external/jnipp/jnipp.h index 53e12719e..aa20c217d 100644 --- a/src/external/jnipp/jnipp.h +++ b/src/external/jnipp/jnipp.h @@ -134,6 +134,7 @@ namespace jni void valueArg(value_t* v, const char* a); void valueArg(value_t* v, const std::wstring& a); void valueArg(value_t* v, const wchar_t* a); + void valueArg(value_t* v, std::nullptr_t); inline void args(value_t*) {} From f35ce4ea9b0d3cd6b7429e92c01e1fe34ed6f581 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 11:41:48 -0500 Subject: [PATCH 517/883] external: Update android-jni-wrap --- .../android-jni-wrap/wrap/android.app.cpp | 2 +- .../android-jni-wrap/wrap/android.app.h | 8 +- .../android-jni-wrap/wrap/android.app.impl.h | 4 +- .../android-jni-wrap/wrap/android.content.cpp | 21 ++- .../android-jni-wrap/wrap/android.content.h | 134 +++++++++++++++--- .../wrap/android.content.impl.h | 71 +++++++--- .../wrap/android.content.pm.cpp | 5 +- .../wrap/android.content.pm.h | 44 +++--- .../wrap/android.content.pm.impl.h | 24 ++-- .../wrap/android.database.cpp | 22 +++ .../android-jni-wrap/wrap/android.database.h | 125 ++++++++++++++++ .../wrap/android.database.impl.h | 48 +++++++ .../wrap/android.graphics.cpp | 2 +- .../android-jni-wrap/wrap/android.graphics.h | 5 +- .../wrap/android.graphics.impl.h | 4 +- .../android-jni-wrap/wrap/android.os.cpp | 2 +- .../android-jni-wrap/wrap/android.os.h | 10 +- .../android-jni-wrap/wrap/android.os.impl.h | 4 +- .../wrap/android.provider.cpp | 2 +- .../android-jni-wrap/wrap/android.provider.h | 5 +- .../wrap/android.provider.impl.h | 4 +- .../wrap/android.service.vr.cpp | 2 +- .../wrap/android.service.vr.h | 5 +- .../wrap/android.service.vr.impl.h | 4 +- .../android-jni-wrap/wrap/android.util.cpp | 2 +- .../android-jni-wrap/wrap/android.util.h | 5 +- .../android-jni-wrap/wrap/android.util.impl.h | 4 +- .../android-jni-wrap/wrap/android.view.cpp | 2 +- .../android-jni-wrap/wrap/android.view.h | 11 +- .../android-jni-wrap/wrap/android.view.impl.h | 6 +- .../android-jni-wrap/wrap/android.widget.cpp | 2 +- .../android-jni-wrap/wrap/android.widget.h | 9 +- .../wrap/android.widget.impl.h | 10 +- .../android-jni-wrap/wrap/dalvik.system.cpp | 15 -- .../android-jni-wrap/wrap/dalvik.system.h | 67 --------- .../wrap/dalvik.system.impl.h | 21 --- .../android-jni-wrap/wrap/java.lang.cpp | 5 +- .../android-jni-wrap/wrap/java.lang.h | 28 ++-- .../android-jni-wrap/wrap/java.lang.impl.h | 20 ++- .../android-jni-wrap/wrap/java.util.cpp | 2 +- .../android-jni-wrap/wrap/java.util.h | 5 +- .../android-jni-wrap/wrap/java.util.impl.h | 4 +- 42 files changed, 499 insertions(+), 276 deletions(-) create mode 100644 src/external/android-jni-wrap/wrap/android.database.cpp create mode 100644 src/external/android-jni-wrap/wrap/android.database.h create mode 100644 src/external/android-jni-wrap/wrap/android.database.impl.h delete mode 100644 src/external/android-jni-wrap/wrap/dalvik.system.cpp delete mode 100644 src/external/android-jni-wrap/wrap/dalvik.system.h delete mode 100644 src/external/android-jni-wrap/wrap/dalvik.system.impl.h diff --git a/src/external/android-jni-wrap/wrap/android.app.cpp b/src/external/android-jni-wrap/wrap/android.app.cpp index 66bb57a9e..36928ea24 100644 --- a/src/external/android-jni-wrap/wrap/android.app.cpp +++ b/src/external/android-jni-wrap/wrap/android.app.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik diff --git a/src/external/android-jni-wrap/wrap/android.app.h b/src/external/android-jni-wrap/wrap/android.app.h index c57dabdbd..bb8698ea2 100644 --- a/src/external/android-jni-wrap/wrap/android.app.h +++ b/src/external/android-jni-wrap/wrap/android.app.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -34,7 +34,7 @@ class Service : public content::Context { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -42,6 +42,7 @@ class Service : public content::Context { Meta(); }; }; + /*! * Wrapper for android.app.Activity objects. */ @@ -87,7 +88,7 @@ class Activity : public content::Context { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -95,6 +96,7 @@ class Activity : public content::Context { Meta(); }; }; + } // namespace android::app } // namespace wrap #include "android.app.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.app.impl.h b/src/external/android-jni-wrap/wrap/android.app.impl.h index b5853e0f1..2319bd3dc 100644 --- a/src/external/android-jni-wrap/wrap/android.app.impl.h +++ b/src/external/android-jni-wrap/wrap/android.app.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -22,5 +23,6 @@ Activity::setVrModeEnabled(bool enabled, return object().call(Meta::data().setVrModeEnabled, enabled, requestedComponent.object()); } + } // namespace android::app } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.content.cpp b/src/external/android-jni-wrap/wrap/android.content.cpp index 7723d5f44..083bd5b27 100644 --- a/src/external/android-jni-wrap/wrap/android.content.cpp +++ b/src/external/android-jni-wrap/wrap/android.content.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -12,6 +12,8 @@ Context::Meta::Meta(bool deferDrop) WINDOW_SERVICE(classRef(), "WINDOW_SERVICE"), getPackageManager(classRef().getMethod( "getPackageManager", "()Landroid/content/pm/PackageManager;")), + getContentResolver(classRef().getMethod( + "getContentResolver", "()Landroid/content/ContentResolver;")), getApplicationContext(classRef().getMethod( "getApplicationContext", "()Landroid/content/Context;")), getClassLoader( @@ -39,7 +41,6 @@ ComponentName::Meta::Meta() Intent::Meta::Meta() : MetaBase(Intent::getTypeName()), FLAG_ACTIVITY_NEW_TASK(classRef(), "FLAG_ACTIVITY_NEW_TASK"), - init(classRef().getMethod("", "()V")), init1(classRef().getMethod("", "(Landroid/content/Intent;)V")), init2(classRef().getMethod("", "(Ljava/lang/String;)V")), init3(classRef().getMethod("", @@ -51,5 +52,21 @@ Intent::Meta::Meta() "content/Context;Ljava/lang/Class;)V")), setFlags( classRef().getMethod("setFlags", "(I)Landroid/content/Intent;")) {} +ContentResolver::Meta::Meta() + : MetaBaseDroppable(ContentResolver::getTypeName()), + query(classRef().getMethod( + "query", + "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/" + "String;Ljava/lang/String;)Landroid/database/Cursor;")), + query1(classRef().getMethod( + "query", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/" + "String;[Ljava/lang/String;Ljava/lang/String;Landroid/os/" + "CancellationSignal;)Landroid/database/Cursor;")), + query2(classRef().getMethod( + "query", + "(Landroid/net/Uri;[Ljava/lang/String;Landroid/os/Bundle;Landroid/os/" + "CancellationSignal;)Landroid/database/Cursor;")) { + MetaBaseDroppable::dropClassRef(); +} } // namespace android::content } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.content.h b/src/external/android-jni-wrap/wrap/android.content.h index 339bd2fa3..0bd07e678 100644 --- a/src/external/android-jni-wrap/wrap/android.content.h +++ b/src/external/android-jni-wrap/wrap/android.content.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -10,6 +10,7 @@ namespace wrap { namespace android::content { class ComponentName; +class ContentResolver; class Context; class Intent; } // namespace android::content @@ -18,6 +19,10 @@ namespace android::content::pm { class PackageManager; } // namespace android::content::pm +namespace android::database { +class Cursor; +} // namespace android::database + namespace android::os { class Bundle; } // namespace android::os @@ -74,6 +79,17 @@ class Context : public ObjectWrapperBase { */ pm::PackageManager getPackageManager(); + /*! + * Wrapper for the getContentResolver method + * + * Java prototype: + * `public abstract android.content.ContentResolver getContentResolver();` + * + * JNI signature: ()Landroid/content/ContentResolver; + * + */ + ContentResolver getContentResolver() const; + /*! * Wrapper for the getApplicationContext method * @@ -144,6 +160,7 @@ class Context : public ObjectWrapperBase { impl::StaticFieldId DISPLAY_SERVICE; impl::StaticFieldId WINDOW_SERVICE; jni::method_t getPackageManager; + jni::method_t getContentResolver; jni::method_t getApplicationContext; jni::method_t getClassLoader; jni::method_t startActivity; @@ -162,6 +179,7 @@ class Context : public ObjectWrapperBase { explicit Meta(bool deferDrop); }; }; + /*! * Wrapper for android.content.ComponentName objects. */ @@ -183,7 +201,7 @@ class ComponentName : public ObjectWrapperBase { * */ static ComponentName construct(std::string const &pkg, - std::string const &cls); + std::string const &className); /*! * Wrapper for a constructor @@ -195,7 +213,8 @@ class ComponentName : public ObjectWrapperBase { * JNI signature: (Landroid/content/Context;Ljava/lang/String;)V * */ - static ComponentName construct(Context const &pkg, std::string const &cls); + static ComponentName construct(Context const &context, + std::string const &className); /*! * Wrapper for a constructor @@ -207,7 +226,7 @@ class ComponentName : public ObjectWrapperBase { * JNI signature: (Landroid/content/Context;Ljava/lang/Class;)V * */ - static ComponentName construct(Context const &pkg, + static ComponentName construct(Context const &context, java::lang::Class const &cls); /*! @@ -234,7 +253,7 @@ class ComponentName : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -242,6 +261,7 @@ class ComponentName : public ObjectWrapperBase { Meta(); }; }; + /*! * Wrapper for android.content.Intent objects. */ @@ -263,20 +283,6 @@ class Intent : public ObjectWrapperBase { */ static int32_t FLAG_ACTIVITY_NEW_TASK(); -#if 0 - // disabled because of zero-length array warning in jnipp - /*! - * Wrapper for a constructor - * - * Java prototype: - * `public android.content.Intent();` - * - * JNI signature: ()V - * - */ - static Intent construct(); -#endif - /*! * Wrapper for a constructor * @@ -286,7 +292,7 @@ class Intent : public ObjectWrapperBase { * JNI signature: (Landroid/content/Intent;)V * */ - static Intent construct(Intent &intent); + static Intent construct(Intent const &intent); /*! * Wrapper for a constructor @@ -354,7 +360,6 @@ class Intent : public ObjectWrapperBase { */ struct Meta : public MetaBase { impl::StaticFieldId FLAG_ACTIVITY_NEW_TASK; - jni::method_t init; jni::method_t init1; jni::method_t init2; jni::method_t init3; @@ -366,7 +371,7 @@ class Intent : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -374,6 +379,91 @@ class Intent : public ObjectWrapperBase { Meta(); }; }; + +/*! + * Wrapper for android.content.ContentResolver objects. + */ +class ContentResolver : public ObjectWrapperBase { + public: + using ObjectWrapperBase::ObjectWrapperBase; + static constexpr const char *getTypeName() noexcept { + return "android/content/ContentResolver"; + } + + /*! + * Wrapper for the query method - overload added in API level 1 + * + * Java prototype: + * `public final android.database.Cursor query(android.net.Uri, + * java.lang.String[], java.lang.String, java.lang.String[], + * java.lang.String);` + * + * JNI signature: + * (Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor; + * + */ + database::Cursor query(jni::Object const &uri, + jni::Array const &projection, + std::string const &selection, + jni::Array const &selectionArgs, + std::string const &sortOrder); + + /*! + * Wrapper for the query method - overload added in API level 16 + * + * Java prototype: + * `public final android.database.Cursor query(android.net.Uri, + * java.lang.String[], java.lang.String, java.lang.String[], + * java.lang.String, android.os.CancellationSignal);` + * + * JNI signature: + * (Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/database/Cursor; + * + */ + database::Cursor query(jni::Object const &uri, + jni::Array const &projection, + std::string const &selection, + jni::Array const &selectionArgs, + std::string const &sortOrder, + jni::Object const &cancellationSignal); + + /*! + * Wrapper for the query method - overload added in API level 26 + * + * Java prototype: + * `public final android.database.Cursor query(android.net.Uri, + * java.lang.String[], android.os.Bundle, android.os.CancellationSignal);` + * + * JNI signature: + * (Landroid/net/Uri;[Ljava/lang/String;Landroid/os/Bundle;Landroid/os/CancellationSignal;)Landroid/database/Cursor; + * + */ + database::Cursor query(jni::Object const &uri, + jni::Array const &projection, + os::Bundle const &queryArgs, + jni::Object const &cancellationSignal); + + /*! + * Class metadata + */ + struct Meta : public MetaBaseDroppable { + jni::method_t query; + jni::method_t query1; + jni::method_t query2; + + /*! + * Singleton accessor + */ + static Meta &data() { + static Meta instance{}; + return instance; + } + + private: + Meta(); + }; +}; + } // namespace android::content } // namespace wrap #include "android.content.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.content.impl.h b/src/external/android-jni-wrap/wrap/android.content.impl.h index f1e88b126..09d2d79d5 100644 --- a/src/external/android-jni-wrap/wrap/android.content.impl.h +++ b/src/external/android-jni-wrap/wrap/android.content.impl.h @@ -1,10 +1,12 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once #include "android.content.pm.h" +#include "android.database.h" #include "android.os.h" #include "java.lang.h" #include @@ -12,8 +14,6 @@ namespace wrap { namespace android::content { inline std::string Context::DISPLAY_SERVICE() { - // Defer dropping the class ref to avoid having to do two class lookups - // by name for this static field. Instead, drop it before we return. auto &data = Meta::data(true); auto ret = get(data.DISPLAY_SERVICE, data.clazz()); data.dropClassRef(); @@ -21,8 +21,6 @@ inline std::string Context::DISPLAY_SERVICE() { } inline std::string Context::WINDOW_SERVICE() { - // Defer dropping the class ref to avoid having to do two class lookups - // by name for this static field. Instead, drop it before we return. auto &data = Meta::data(true); auto ret = get(data.WINDOW_SERVICE, data.clazz()); data.dropClassRef(); @@ -35,6 +33,12 @@ inline pm::PackageManager Context::getPackageManager() { object().call(Meta::data().getPackageManager)); } +inline ContentResolver Context::getContentResolver() const { + assert(!isNull()); + return ContentResolver( + object().call(Meta::data().getContentResolver)); +} + inline Context Context::getApplicationContext() { assert(!isNull()); return Context( @@ -65,40 +69,35 @@ inline Context Context::createPackageContext(std::string const &packageName, return Context(object().call(Meta::data().createPackageContext, packageName, flags)); } + inline ComponentName ComponentName::construct(std::string const &pkg, - std::string const &cls) { + std::string const &className) { return ComponentName( - Meta::data().clazz().newInstance(Meta::data().init, pkg, cls)); + Meta::data().clazz().newInstance(Meta::data().init, pkg, className)); } -inline ComponentName ComponentName::construct(Context const &pkg, - std::string const &cls) { - return ComponentName(Meta::data().clazz().newInstance(Meta::data().init1, - pkg.object(), cls)); +inline ComponentName ComponentName::construct(Context const &context, + std::string const &className) { + return ComponentName(Meta::data().clazz().newInstance( + Meta::data().init1, context.object(), className)); } -inline ComponentName ComponentName::construct(Context const &pkg, +inline ComponentName ComponentName::construct(Context const &context, java::lang::Class const &cls) { return ComponentName(Meta::data().clazz().newInstance( - Meta::data().init2, pkg.object(), cls.object())); + Meta::data().init2, context.object(), cls.object())); } inline ComponentName ComponentName::construct(jni::Object const &parcel) { return ComponentName( Meta::data().clazz().newInstance(Meta::data().init3, parcel)); } + inline int32_t Intent::FLAG_ACTIVITY_NEW_TASK() { return get(Meta::data().FLAG_ACTIVITY_NEW_TASK, Meta::data().clazz()); } -#if 0 -// disabled because of zero-length array warning in jnipp -inline Intent Intent::construct() { - return Intent(Meta::data().clazz().newInstance(Meta::data().init)); -} -#endif - -inline Intent Intent::construct(Intent &intent) { +inline Intent Intent::construct(Intent const &intent) { return Intent( Meta::data().clazz().newInstance(Meta::data().init1, intent.object())); } @@ -131,5 +130,35 @@ inline Intent Intent::setFlags(int32_t flags) { assert(!isNull()); return Intent(object().call(Meta::data().setFlags, flags)); } + +inline database::Cursor ContentResolver::query( + jni::Object const &uri, jni::Array const &projection, + std::string const &selection, jni::Array const &selectionArgs, + std::string const &sortOrder) { + assert(!isNull()); + return database::Cursor( + object().call(Meta::data().query, uri, projection, + selection, selectionArgs, sortOrder)); +} + +inline database::Cursor ContentResolver::query( + jni::Object const &uri, jni::Array const &projection, + std::string const &selection, jni::Array const &selectionArgs, + std::string const &sortOrder, jni::Object const &cancellationSignal) { + assert(!isNull()); + return database::Cursor(object().call( + Meta::data().query1, uri, projection, selection, selectionArgs, + sortOrder, cancellationSignal)); +} + +inline database::Cursor ContentResolver::query( + jni::Object const &uri, jni::Array const &projection, + os::Bundle const &queryArgs, jni::Object const &cancellationSignal) { + assert(!isNull()); + return database::Cursor( + object().call(Meta::data().query2, uri, projection, + queryArgs.object(), cancellationSignal)); +} + } // namespace android::content } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.content.pm.cpp b/src/external/android-jni-wrap/wrap/android.content.pm.cpp index 3c378de67..3a4fe0ddd 100644 --- a/src/external/android-jni-wrap/wrap/android.content.pm.cpp +++ b/src/external/android-jni-wrap/wrap/android.content.pm.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -40,9 +40,6 @@ PackageManager::Meta::Meta() getPackageInfo(classRef().getMethod( "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;")), - getPackageInfo1(classRef().getMethod( - "getPackageInfo", "(Landroid/content/pm/VersionedPackage;I)Landroid/" - "content/pm/PackageInfo;")), getApplicationInfo(classRef().getMethod( "getApplicationInfo", "(Ljava/lang/String;I)Landroid/content/pm/ApplicationInfo;")), diff --git a/src/external/android-jni-wrap/wrap/android.content.pm.h b/src/external/android-jni-wrap/wrap/android.content.pm.h index 81a872a87..5cb9c7434 100644 --- a/src/external/android-jni-wrap/wrap/android.content.pm.h +++ b/src/external/android-jni-wrap/wrap/android.content.pm.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -86,7 +86,7 @@ class PackageItemInfo : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -94,6 +94,7 @@ class PackageItemInfo : public ObjectWrapperBase { Meta(); }; }; + /*! * Wrapper for android.content.pm.ComponentInfo objects. */ @@ -113,7 +114,7 @@ class ComponentInfo : public PackageItemInfo { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -121,6 +122,7 @@ class ComponentInfo : public PackageItemInfo { Meta(); }; }; + /*! * Wrapper for android.content.pm.ServiceInfo objects. */ @@ -140,7 +142,7 @@ class ServiceInfo : public PackageItemInfo { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -148,6 +150,7 @@ class ServiceInfo : public PackageItemInfo { Meta(); }; }; + /*! * Wrapper for android.content.pm.ApplicationInfo objects. */ @@ -191,7 +194,7 @@ class ApplicationInfo : public PackageItemInfo { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -199,6 +202,7 @@ class ApplicationInfo : public PackageItemInfo { Meta(); }; }; + /*! * Wrapper for android.content.pm.PackageInfo objects. */ @@ -242,7 +246,7 @@ class PackageInfo : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -250,6 +254,7 @@ class PackageInfo : public ObjectWrapperBase { Meta(); }; }; + /*! * Wrapper for android.content.pm.ResolveInfo objects. */ @@ -281,7 +286,7 @@ class ResolveInfo : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -289,6 +294,7 @@ class ResolveInfo : public ObjectWrapperBase { Meta(); }; }; + /*! * Wrapper for android.content.pm.PackageManager objects. */ @@ -312,24 +318,6 @@ class PackageManager : public ObjectWrapperBase { */ PackageInfo getPackageInfo(std::string const &name, int32_t flags); -#if 0 - // Ambiguous overload until we wrap VersionedPackage - /*! - * Wrapper for the getPackageInfo method - * - * Java prototype: - * `public abstract android.content.pm.PackageInfo - * getPackageInfo(android.content.pm.VersionedPackage, int) throws - * android.content.pm.PackageManager$NameNotFoundException;` - * - * JNI signature: - * (Landroid/content/pm/VersionedPackage;I)Landroid/content/pm/PackageInfo; - * - */ - PackageInfo getPackageInfo(jni::Object &versionedPackage, int32_t flags); - -#endif - /*! * Wrapper for the getApplicationInfo method * @@ -354,7 +342,7 @@ class PackageManager : public ObjectWrapperBase { * JNI signature: (Landroid/content/Intent;I)Ljava/util/List; * */ - java::util::List queryIntentServices(Intent &intent, int32_t intParam); + java::util::List queryIntentServices(Intent const &intent, int32_t flags); enum { GET_META_DATA = 128, @@ -366,7 +354,6 @@ class PackageManager : public ObjectWrapperBase { */ struct Meta : public MetaBaseDroppable { jni::method_t getPackageInfo; - jni::method_t getPackageInfo1; jni::method_t getApplicationInfo; jni::method_t queryIntentServices; @@ -374,7 +361,7 @@ class PackageManager : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -382,6 +369,7 @@ class PackageManager : public ObjectWrapperBase { Meta(); }; }; + } // namespace android::content::pm } // namespace wrap #include "android.content.pm.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.content.pm.impl.h b/src/external/android-jni-wrap/wrap/android.content.pm.impl.h index be6e5b377..84b405073 100644 --- a/src/external/android-jni-wrap/wrap/android.content.pm.impl.h +++ b/src/external/android-jni-wrap/wrap/android.content.pm.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -34,6 +35,7 @@ inline std::string ApplicationInfo::getPublicSourceDir() const { assert(!isNull()); return get(Meta::data().publicSourceDir, object()); } + inline ApplicationInfo PackageInfo::getApplicationInfo() const { assert(!isNull()); return get(Meta::data().applicationInfo, object()); @@ -43,10 +45,12 @@ inline std::string PackageInfo::getPackageName() const { assert(!isNull()); return get(Meta::data().packageName, object()); } + inline ServiceInfo ResolveInfo::getServiceInfo() const { assert(!isNull()); return get(Meta::data().serviceInfo, object()); } + inline PackageInfo PackageManager::getPackageInfo(std::string const &name, int32_t flags) { assert(!isNull()); @@ -54,17 +58,6 @@ inline PackageInfo PackageManager::getPackageInfo(std::string const &name, object().call(Meta::data().getPackageInfo, name, flags)); } -#if 0 -// Ambiguous overload until we wrap VersionedPackage -inline PackageInfo -PackageManager::getPackageInfo(jni::Object const &versionedPackage, - int32_t flags) { - assert(!isNull()); - return PackageInfo(object().call(Meta::data().getPackageInfo1, - versionedPackage, flags)); -} -#endif - inline ApplicationInfo PackageManager::getApplicationInfo(std::string const &packageName, int32_t flags) { @@ -73,11 +66,12 @@ PackageManager::getApplicationInfo(std::string const &packageName, Meta::data().getApplicationInfo, packageName, flags)); } -inline java::util::List PackageManager::queryIntentServices(Intent &intent, - int32_t intParam) { +inline java::util::List +PackageManager::queryIntentServices(Intent const &intent, int32_t flags) { assert(!isNull()); return java::util::List(object().call( - Meta::data().queryIntentServices, intent.object(), intParam)); + Meta::data().queryIntentServices, intent.object(), flags)); } + } // namespace android::content::pm } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.database.cpp b/src/external/android-jni-wrap/wrap/android.database.cpp new file mode 100644 index 000000000..f03e5730c --- /dev/null +++ b/src/external/android-jni-wrap/wrap/android.database.cpp @@ -0,0 +1,22 @@ +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +// Author: Ryan Pavlik + +#include "android.database.h" + +namespace wrap { +namespace android::database { +Cursor::Meta::Meta() + : MetaBaseDroppable(Cursor::getTypeName()), + getCount(classRef().getMethod("getCount", "()I")), + moveToFirst(classRef().getMethod("moveToFirst", "()Z")), + moveToNext(classRef().getMethod("moveToNext", "()Z")), + getColumnIndex( + classRef().getMethod("getColumnIndex", "(Ljava/lang/String;)I")), + getString(classRef().getMethod("getString", "(I)Ljava/lang/String;")), + getInt(classRef().getMethod("getInt", "(I)I")), + close(classRef().getMethod("close", "()V")) { + MetaBaseDroppable::dropClassRef(); +} +} // namespace android::database +} // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.database.h b/src/external/android-jni-wrap/wrap/android.database.h new file mode 100644 index 000000000..308fa2e03 --- /dev/null +++ b/src/external/android-jni-wrap/wrap/android.database.h @@ -0,0 +1,125 @@ +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +// Author: Ryan Pavlik + +#pragma once + +#include "ObjectWrapperBase.h" + +namespace wrap { +namespace android::database { +/*! + * Wrapper for android.database.Cursor objects. + */ +class Cursor : public ObjectWrapperBase { + public: + using ObjectWrapperBase::ObjectWrapperBase; + static constexpr const char *getTypeName() noexcept { + return "android/database/Cursor"; + } + + /*! + * Wrapper for the getCount method + * + * Java prototype: + * `public abstract int getCount();` + * + * JNI signature: ()I + * + */ + int32_t getCount(); + + /*! + * Wrapper for the moveToFirst method + * + * Java prototype: + * `public abstract boolean moveToFirst();` + * + * JNI signature: ()Z + * + */ + bool moveToFirst(); + + /*! + * Wrapper for the moveToNext method + * + * Java prototype: + * `public abstract boolean moveToNext();` + * + * JNI signature: ()Z + * + */ + bool moveToNext(); + + /*! + * Wrapper for the getColumnIndex method + * + * Java prototype: + * `public abstract int getColumnIndex(java.lang.String);` + * + * JNI signature: (Ljava/lang/String;)I + * + */ + int32_t getColumnIndex(std::string const &columnName); + + /*! + * Wrapper for the getString method + * + * Java prototype: + * `public abstract java.lang.String getString(int);` + * + * JNI signature: (I)Ljava/lang/String; + * + */ + std::string getString(int32_t column); + + /*! + * Wrapper for the getInt method + * + * Java prototype: + * `public abstract int getInt(int);` + * + * JNI signature: (I)I + * + */ + int32_t getInt(int32_t column); + + /*! + * Wrapper for the close method + * + * Java prototype: + * `public abstract void close();` + * + * JNI signature: ()V + * + */ + void close(); + + /*! + * Class metadata + */ + struct Meta : public MetaBaseDroppable { + jni::method_t getCount; + jni::method_t moveToFirst; + jni::method_t moveToNext; + jni::method_t getColumnIndex; + jni::method_t getString; + jni::method_t getInt; + jni::method_t close; + + /*! + * Singleton accessor + */ + static Meta &data() { + static Meta instance{}; + return instance; + } + + private: + Meta(); + }; +}; + +} // namespace android::database +} // namespace wrap +#include "android.database.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.database.impl.h b/src/external/android-jni-wrap/wrap/android.database.impl.h new file mode 100644 index 000000000..b48931efc --- /dev/null +++ b/src/external/android-jni-wrap/wrap/android.database.impl.h @@ -0,0 +1,48 @@ +// Copyright 2020-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +// Author: Ryan Pavlik +// Inline implementations: do not include on its own! + +#pragma once + +#include + +namespace wrap { +namespace android::database { +inline int32_t Cursor::getCount() { + assert(!isNull()); + return object().call(Meta::data().getCount); +} + +inline bool Cursor::moveToFirst() { + assert(!isNull()); + return object().call(Meta::data().moveToFirst); +} + +inline bool Cursor::moveToNext() { + assert(!isNull()); + return object().call(Meta::data().moveToNext); +} + +inline int32_t Cursor::getColumnIndex(std::string const &columnName) { + assert(!isNull()); + return object().call(Meta::data().getColumnIndex, columnName); +} + +inline std::string Cursor::getString(int32_t column) { + assert(!isNull()); + return object().call(Meta::data().getString, column); +} + +inline int32_t Cursor::getInt(int32_t column) { + assert(!isNull()); + return object().call(Meta::data().getInt, column); +} + +inline void Cursor::close() { + assert(!isNull()); + return object().call(Meta::data().close); +} + +} // namespace android::database +} // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.graphics.cpp b/src/external/android-jni-wrap/wrap/android.graphics.cpp index 99809b737..54a33a8bb 100644 --- a/src/external/android-jni-wrap/wrap/android.graphics.cpp +++ b/src/external/android-jni-wrap/wrap/android.graphics.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik diff --git a/src/external/android-jni-wrap/wrap/android.graphics.h b/src/external/android-jni-wrap/wrap/android.graphics.h index bbe35fa8a..3d0070ea0 100644 --- a/src/external/android-jni-wrap/wrap/android.graphics.h +++ b/src/external/android-jni-wrap/wrap/android.graphics.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -51,7 +51,7 @@ class Point : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -59,6 +59,7 @@ class Point : public ObjectWrapperBase { Meta(); }; }; + } // namespace android::graphics } // namespace wrap #include "android.graphics.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.graphics.impl.h b/src/external/android-jni-wrap/wrap/android.graphics.impl.h index 30ba5bcf5..db38da785 100644 --- a/src/external/android-jni-wrap/wrap/android.graphics.impl.h +++ b/src/external/android-jni-wrap/wrap/android.graphics.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -15,5 +16,6 @@ inline int32_t Point::getY() const { assert(!isNull()); return get(Meta::data().y, object()); } + } // namespace android::graphics } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.os.cpp b/src/external/android-jni-wrap/wrap/android.os.cpp index bfa898305..2b5c43eeb 100644 --- a/src/external/android-jni-wrap/wrap/android.os.cpp +++ b/src/external/android-jni-wrap/wrap/android.os.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik diff --git a/src/external/android-jni-wrap/wrap/android.os.h b/src/external/android-jni-wrap/wrap/android.os.h index 2ea3f5d4d..eb9a57e20 100644 --- a/src/external/android-jni-wrap/wrap/android.os.h +++ b/src/external/android-jni-wrap/wrap/android.os.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -71,7 +71,7 @@ class BaseBundle : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -79,6 +79,7 @@ class BaseBundle : public ObjectWrapperBase { Meta(); }; }; + /*! * Wrapper for android.os.Bundle objects. */ @@ -98,7 +99,7 @@ class Bundle : public BaseBundle { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -186,7 +187,7 @@ class ParcelFileDescriptor : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -194,6 +195,7 @@ class ParcelFileDescriptor : public ObjectWrapperBase { Meta(); }; }; + } // namespace android::os } // namespace wrap #include "android.os.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.os.impl.h b/src/external/android-jni-wrap/wrap/android.os.impl.h index 6078d378e..d4f2e7e1f 100644 --- a/src/external/android-jni-wrap/wrap/android.os.impl.h +++ b/src/external/android-jni-wrap/wrap/android.os.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -49,5 +50,6 @@ inline void ParcelFileDescriptor::checkError() const { assert(!isNull()); return object().call(Meta::data().checkError); } + } // namespace android::os } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.provider.cpp b/src/external/android-jni-wrap/wrap/android.provider.cpp index 2648c4b05..fe7d22953 100644 --- a/src/external/android-jni-wrap/wrap/android.provider.cpp +++ b/src/external/android-jni-wrap/wrap/android.provider.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik diff --git a/src/external/android-jni-wrap/wrap/android.provider.h b/src/external/android-jni-wrap/wrap/android.provider.h index e139e3151..85290b333 100644 --- a/src/external/android-jni-wrap/wrap/android.provider.h +++ b/src/external/android-jni-wrap/wrap/android.provider.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -40,7 +40,7 @@ class Settings : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -48,6 +48,7 @@ class Settings : public ObjectWrapperBase { Meta(); }; }; + } // namespace android::provider } // namespace wrap #include "android.provider.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.provider.impl.h b/src/external/android-jni-wrap/wrap/android.provider.impl.h index 066782847..618181564 100644 --- a/src/external/android-jni-wrap/wrap/android.provider.impl.h +++ b/src/external/android-jni-wrap/wrap/android.provider.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -9,5 +10,6 @@ namespace android::provider { inline std::string Settings::ACTION_VR_LISTENER_SETTINGS() { return get(Meta::data().ACTION_VR_LISTENER_SETTINGS, Meta::data().clazz()); } + } // namespace android::provider } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.service.vr.cpp b/src/external/android-jni-wrap/wrap/android.service.vr.cpp index a1381a404..535a6bbdb 100644 --- a/src/external/android-jni-wrap/wrap/android.service.vr.cpp +++ b/src/external/android-jni-wrap/wrap/android.service.vr.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik diff --git a/src/external/android-jni-wrap/wrap/android.service.vr.h b/src/external/android-jni-wrap/wrap/android.service.vr.h index 65fa9b705..11a851d56 100644 --- a/src/external/android-jni-wrap/wrap/android.service.vr.h +++ b/src/external/android-jni-wrap/wrap/android.service.vr.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -52,7 +52,7 @@ class VrListenerService : public app::Service { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -60,6 +60,7 @@ class VrListenerService : public app::Service { Meta(); }; }; + } // namespace android::service::vr } // namespace wrap #include "android.service.vr.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.service.vr.impl.h b/src/external/android-jni-wrap/wrap/android.service.vr.impl.h index 45b7304d6..dcb1782f4 100644 --- a/src/external/android-jni-wrap/wrap/android.service.vr.impl.h +++ b/src/external/android-jni-wrap/wrap/android.service.vr.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -15,5 +16,6 @@ inline bool VrListenerService::isVrModePackageEnabled( context.object(), componentName.object()); } + } // namespace android::service::vr } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.util.cpp b/src/external/android-jni-wrap/wrap/android.util.cpp index 3c96d69a0..0a088289d 100644 --- a/src/external/android-jni-wrap/wrap/android.util.cpp +++ b/src/external/android-jni-wrap/wrap/android.util.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik diff --git a/src/external/android-jni-wrap/wrap/android.util.h b/src/external/android-jni-wrap/wrap/android.util.h index 418b797f8..332acb408 100644 --- a/src/external/android-jni-wrap/wrap/android.util.h +++ b/src/external/android-jni-wrap/wrap/android.util.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -51,7 +51,7 @@ class DisplayMetrics : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -59,6 +59,7 @@ class DisplayMetrics : public ObjectWrapperBase { Meta(); }; }; + } // namespace android::util } // namespace wrap #include "android.util.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.util.impl.h b/src/external/android-jni-wrap/wrap/android.util.impl.h index adfc8b4f4..bcaeb2df7 100644 --- a/src/external/android-jni-wrap/wrap/android.util.impl.h +++ b/src/external/android-jni-wrap/wrap/android.util.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -15,5 +16,6 @@ inline int32_t DisplayMetrics::getWidthPixels() const { assert(!isNull()); return get(Meta::data().widthPixels, object()); } + } // namespace android::util } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.view.cpp b/src/external/android-jni-wrap/wrap/android.view.cpp index 3934ea31e..7afe038ae 100644 --- a/src/external/android-jni-wrap/wrap/android.view.cpp +++ b/src/external/android-jni-wrap/wrap/android.view.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik diff --git a/src/external/android-jni-wrap/wrap/android.view.h b/src/external/android-jni-wrap/wrap/android.view.h index f958085c9..d58fa101e 100644 --- a/src/external/android-jni-wrap/wrap/android.view.h +++ b/src/external/android-jni-wrap/wrap/android.view.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -66,7 +66,7 @@ class Display : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -74,6 +74,7 @@ class Display : public ObjectWrapperBase { Meta(); }; }; + /*! * Wrapper for android.view.Surface objects. */ @@ -105,7 +106,7 @@ class Surface : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -113,6 +114,7 @@ class Surface : public ObjectWrapperBase { Meta(); }; }; + /*! * Wrapper for android.view.SurfaceHolder objects. */ @@ -144,7 +146,7 @@ class SurfaceHolder : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -152,6 +154,7 @@ class SurfaceHolder : public ObjectWrapperBase { Meta(); }; }; + } // namespace android::view } // namespace wrap #include "android.view.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.view.impl.h b/src/external/android-jni-wrap/wrap/android.view.impl.h index caf34c570..5e91091c1 100644 --- a/src/external/android-jni-wrap/wrap/android.view.impl.h +++ b/src/external/android-jni-wrap/wrap/android.view.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -19,13 +20,16 @@ inline void Display::getRealMetrics(util::DisplayMetrics &out_displayMetrics) { return object().call(Meta::data().getRealMetrics, out_displayMetrics.object()); } + inline bool Surface::isValid() const { assert(!isNull()); return object().call(Meta::data().isValid); } + inline Surface SurfaceHolder::getSurface() { assert(!isNull()); return Surface(object().call(Meta::data().getSurface)); } + } // namespace android::view } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/android.widget.cpp b/src/external/android-jni-wrap/wrap/android.widget.cpp index 8da994786..073aacb68 100644 --- a/src/external/android-jni-wrap/wrap/android.widget.cpp +++ b/src/external/android-jni-wrap/wrap/android.widget.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik diff --git a/src/external/android-jni-wrap/wrap/android.widget.h b/src/external/android-jni-wrap/wrap/android.widget.h index 52289c2f3..630474c13 100644 --- a/src/external/android-jni-wrap/wrap/android.widget.h +++ b/src/external/android-jni-wrap/wrap/android.widget.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -74,7 +74,7 @@ class Toast : public ObjectWrapperBase { * */ static Toast makeText(content::Context const &context, - std::string const &stringParam, int32_t duration); + jni::Object const &text, int32_t duration); /*! * Wrapper for the makeText static method @@ -86,7 +86,7 @@ class Toast : public ObjectWrapperBase { * JNI signature: (Landroid/content/Context;II)Landroid/widget/Toast; * */ - static Toast makeText(content::Context &context, int32_t resId, + static Toast makeText(content::Context const &context, int32_t resId, int32_t duration); /*! @@ -103,7 +103,7 @@ class Toast : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -111,6 +111,7 @@ class Toast : public ObjectWrapperBase { Meta(); }; }; + } // namespace android::widget } // namespace wrap #include "android.widget.impl.h" diff --git a/src/external/android-jni-wrap/wrap/android.widget.impl.h b/src/external/android-jni-wrap/wrap/android.widget.impl.h index ecb511603..370a1566a 100644 --- a/src/external/android-jni-wrap/wrap/android.widget.impl.h +++ b/src/external/android-jni-wrap/wrap/android.widget.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -22,15 +23,16 @@ inline void Toast::show() const { } inline Toast Toast::makeText(content::Context const &context, - std::string const &stringParam, int32_t duration) { + jni::Object const &text, int32_t duration) { return Toast(Meta::data().clazz().call( - Meta::data().makeText, context.object(), stringParam, duration)); + Meta::data().makeText, context.object(), text, duration)); } -inline Toast Toast::makeText(content::Context &context, int32_t resId, +inline Toast Toast::makeText(content::Context const &context, int32_t resId, int32_t duration) { return Toast(Meta::data().clazz().call( Meta::data().makeText1, context.object(), resId, duration)); } + } // namespace android::widget } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/dalvik.system.cpp b/src/external/android-jni-wrap/wrap/dalvik.system.cpp deleted file mode 100644 index 671773395..000000000 --- a/src/external/android-jni-wrap/wrap/dalvik.system.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2020, Collabora, Ltd. -// SPDX-License-Identifier: BSL-1.0 -// Author: Ryan Pavlik - -#include "dalvik.system.h" - -namespace wrap { -namespace dalvik::system { -DexClassLoader::Meta::Meta() - : MetaBase(DexClassLoader::getTypeName()), - init(classRef().getMethod("", - "(Ljava/lang/String;Ljava/lang/String;Ljava/" - "lang/String;Ljava/lang/ClassLoader;)V")) {} -} // namespace dalvik::system -} // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/dalvik.system.h b/src/external/android-jni-wrap/wrap/dalvik.system.h deleted file mode 100644 index b3775f9ac..000000000 --- a/src/external/android-jni-wrap/wrap/dalvik.system.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2020, Collabora, Ltd. -// SPDX-License-Identifier: BSL-1.0 -// Author: Ryan Pavlik - -#pragma once - -#include "ObjectWrapperBase.h" - -namespace wrap { -namespace dalvik::system { -class DexClassLoader; -} // namespace dalvik::system - -namespace java::lang { -class ClassLoader; -} // namespace java::lang - -} // namespace wrap - -namespace wrap { -namespace dalvik::system { -/*! - * Wrapper for dalvik.system.DexClassLoader objects. - */ -class DexClassLoader : public ObjectWrapperBase { - public: - using ObjectWrapperBase::ObjectWrapperBase; - static constexpr const char *getTypeName() noexcept { - return "dalvik/system/DexClassLoader"; - } - - /*! - * Wrapper for a constructor - * - * Java prototype: - * `public dalvik.system.DexClassLoader(java.lang.String, java.lang.String, - * java.lang.String, java.lang.ClassLoader);` - * - * JNI signature: - * (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V - * - */ - static DexClassLoader construct(std::string const &searchPath, - std::string const &nativeSearchPath, - jni::Object parentClassLoader); - - /*! - * Class metadata - */ - struct Meta : public MetaBase { - jni::method_t init; - - /*! - * Singleton accessor - */ - static Meta &data() { - static Meta instance; - return instance; - } - - private: - Meta(); - }; -}; -} // namespace dalvik::system -} // namespace wrap -#include "dalvik.system.impl.h" diff --git a/src/external/android-jni-wrap/wrap/dalvik.system.impl.h b/src/external/android-jni-wrap/wrap/dalvik.system.impl.h deleted file mode 100644 index c23a80839..000000000 --- a/src/external/android-jni-wrap/wrap/dalvik.system.impl.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2020, Collabora, Ltd. -// SPDX-License-Identifier: BSL-1.0 -// Author: Ryan Pavlik - -#pragma once - -#include "java.lang.h" -#include - -namespace wrap { -namespace dalvik::system { -inline DexClassLoader -DexClassLoader::construct(std::string const &searchPath, - std::string const &nativeSearchPath, - jni::Object parentClassLoader) { - return DexClassLoader{ - Meta::data().clazz().newInstance(Meta::data().init, searchPath, "", - nativeSearchPath, parentClassLoader)}; -} -} // namespace dalvik::system -} // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/java.lang.cpp b/src/external/android-jni-wrap/wrap/java.lang.cpp index 523bbaaee..980fb57f0 100644 --- a/src/external/android-jni-wrap/wrap/java.lang.cpp +++ b/src/external/android-jni-wrap/wrap/java.lang.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -13,9 +13,6 @@ Class::Meta::Meta() forName1(classRef().getStaticMethod( "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;")), - forName2(classRef().getStaticMethod( - "forName", - "(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;")), getCanonicalName( classRef().getMethod("getCanonicalName", "()Ljava/lang/String;")) {} ClassLoader::Meta::Meta() diff --git a/src/external/android-jni-wrap/wrap/java.lang.h b/src/external/android-jni-wrap/wrap/java.lang.h index 56541411b..cfd112b11 100644 --- a/src/external/android-jni-wrap/wrap/java.lang.h +++ b/src/external/android-jni-wrap/wrap/java.lang.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -36,7 +36,7 @@ class Class : public ObjectWrapperBase { * JNI signature: (Ljava/lang/String;)Ljava/lang/Class; * */ - static Class forName(std::string &stringParam); + static Class forName(std::string const &name); /*! * Wrapper for the forName static method @@ -50,23 +50,11 @@ class Class : public ObjectWrapperBase { * */ static Class forName(std::string const &name, bool initialize, - jni::Object classLoader); + ClassLoader const &classLoader); //! @overload static Class forName(jstring name, bool initialize, jni::Object classLoader); - /*! - * Wrapper for the forName static method - * - * Java prototype: - * `public static java.lang.Class forName(java.lang.Module, - * java.lang.String);` - * - * JNI signature: (Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class; - * - */ - static Class forName(jni::Object const &module, std::string const &name); - /*! * Wrapper for the getCanonicalName method * @@ -84,14 +72,13 @@ class Class : public ObjectWrapperBase { struct Meta : public MetaBase { jni::method_t forName; jni::method_t forName1; - jni::method_t forName2; jni::method_t getCanonicalName; /*! * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -99,6 +86,7 @@ class Class : public ObjectWrapperBase { Meta(); }; }; + /*! * Wrapper for java.lang.ClassLoader objects. */ @@ -143,7 +131,7 @@ class ClassLoader : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -151,6 +139,7 @@ class ClassLoader : public ObjectWrapperBase { Meta(); }; }; + /*! * Wrapper for java.lang.System objects. */ @@ -182,7 +171,7 @@ class System : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -190,6 +179,7 @@ class System : public ObjectWrapperBase { Meta(); }; }; + } // namespace java::lang } // namespace wrap #include "java.lang.impl.h" diff --git a/src/external/android-jni-wrap/wrap/java.lang.impl.h b/src/external/android-jni-wrap/wrap/java.lang.impl.h index 8c95ea8de..324bfc1b4 100644 --- a/src/external/android-jni-wrap/wrap/java.lang.impl.h +++ b/src/external/android-jni-wrap/wrap/java.lang.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -8,15 +9,15 @@ namespace wrap { namespace java::lang { -inline Class Class::forName(std::string &stringParam) { - return Class(Meta::data().clazz().call(Meta::data().forName, - stringParam)); +inline Class Class::forName(std::string const &name) { + return Class( + Meta::data().clazz().call(Meta::data().forName, name)); } inline Class Class::forName(std::string const &name, bool initialize, - jni::Object classLoader) { + ClassLoader const &classLoader) { return Class(Meta::data().clazz().call( - Meta::data().forName1, name, initialize, classLoader)); + Meta::data().forName1, name, initialize, classLoader.object())); } inline Class Class::forName(jstring name, bool initialize, @@ -25,12 +26,6 @@ inline Class Class::forName(jstring name, bool initialize, Meta::data().forName, name, initialize, classLoader)}; } -inline Class Class::forName(jni::Object const &module, - std::string const &name) { - return Class(Meta::data().clazz().call(Meta::data().forName2, - module, name)); -} - inline std::string Class::getCanonicalName() { assert(!isNull()); return object().call(Meta::data().getCanonicalName); @@ -55,5 +50,6 @@ inline std::string System::mapLibraryName(std::string const &name) { return Meta::data().clazz().call(Meta::data().mapLibraryName, name); } + } // namespace java::lang } // namespace wrap diff --git a/src/external/android-jni-wrap/wrap/java.util.cpp b/src/external/android-jni-wrap/wrap/java.util.cpp index 1582bed56..8ee0e0818 100644 --- a/src/external/android-jni-wrap/wrap/java.util.cpp +++ b/src/external/android-jni-wrap/wrap/java.util.cpp @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik diff --git a/src/external/android-jni-wrap/wrap/java.util.h b/src/external/android-jni-wrap/wrap/java.util.h index 1cda61aec..863f7c682 100644 --- a/src/external/android-jni-wrap/wrap/java.util.h +++ b/src/external/android-jni-wrap/wrap/java.util.h @@ -1,4 +1,4 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik @@ -51,7 +51,7 @@ class List : public ObjectWrapperBase { * Singleton accessor */ static Meta &data() { - static Meta instance; + static Meta instance{}; return instance; } @@ -59,6 +59,7 @@ class List : public ObjectWrapperBase { Meta(); }; }; + } // namespace java::util } // namespace wrap #include "java.util.impl.h" diff --git a/src/external/android-jni-wrap/wrap/java.util.impl.h b/src/external/android-jni-wrap/wrap/java.util.impl.h index d394388ee..e40ad7224 100644 --- a/src/external/android-jni-wrap/wrap/java.util.impl.h +++ b/src/external/android-jni-wrap/wrap/java.util.impl.h @@ -1,6 +1,7 @@ -// Copyright 2020, Collabora, Ltd. +// Copyright 2020-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik +// Inline implementations: do not include on its own! #pragma once @@ -15,5 +16,6 @@ inline jni::Object List::get(int32_t index) const { assert(!isNull()); return object().call(Meta::data().get, index); } + } // namespace java::util } // namespace wrap From 5ac1b341a3501011154fc5b506a862ccbdddaf01 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 14:59:33 -0500 Subject: [PATCH 518/883] doc: Add markdownlint config file for changelog fragments. --- doc/changes/.markdownlint.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 doc/changes/.markdownlint.yaml diff --git a/doc/changes/.markdownlint.yaml b/doc/changes/.markdownlint.yaml new file mode 100644 index 000000000..fc50c2457 --- /dev/null +++ b/doc/changes/.markdownlint.yaml @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2021 Collabora, Ltd. + +# Changelog fragments will never start with a header. +MD041: false From 739f869517b28a2e24e1940c817c0aa1d9b2feab Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 16:35:52 -0500 Subject: [PATCH 519/883] doc: Fix typo --- doc/changes/misc_fixes/mr.735.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/misc_fixes/mr.735.md b/doc/changes/misc_fixes/mr.735.md index 7f7293554..be622ac5b 100644 --- a/doc/changes/misc_fixes/mr.735.md +++ b/doc/changes/misc_fixes/mr.735.md @@ -1,2 +1,2 @@ -logging: Fix the first message always getting printed due to un-initaialized +logging: Fix the first message always getting printed due to un-initialized variable. From 4ef5b65487ad878072283b6692b48ac39484f4f4 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 16:36:24 -0500 Subject: [PATCH 520/883] d/wmr: Fix typo --- src/xrt/drivers/wmr/wmr_hmd.c | 12 ++++++------ src/xrt/drivers/wmr/wmr_hmd.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index 4dca42be2..294e69a1d 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -128,7 +128,7 @@ hololens_sensors_read_packets(struct wmr_hmd *wh) unsigned char buffer[WMR_FEATURE_BUFFER_SIZE]; // Block for 100ms - int size = os_hid_read(wh->hid_hololens_senors_dev, buffer, sizeof(buffer), 100); + int size = os_hid_read(wh->hid_hololens_sensors_dev, buffer, sizeof(buffer), 100); if (size < 0) { WMR_ERROR(wh, "Error reading from device"); @@ -282,7 +282,7 @@ wmr_run_thread(void *ptr) static void hololens_sensors_enable_imu(struct wmr_hmd *wh) { - int size = os_hid_write(wh->hid_hololens_senors_dev, hololens_sensors_imu_on, sizeof(hololens_sensors_imu_on)); + int size = os_hid_write(wh->hid_hololens_sensors_dev, hololens_sensors_imu_on, sizeof(hololens_sensors_imu_on)); if (size <= 0) { WMR_ERROR(wh, "Error writing to device"); return; @@ -428,9 +428,9 @@ wmr_hmd_destroy(struct xrt_device *xdev) // Destroy the thread object. os_thread_helper_destroy(&wh->oth); - if (wh->hid_hololens_senors_dev != NULL) { - os_hid_destroy(wh->hid_hololens_senors_dev); - wh->hid_hololens_senors_dev = NULL; + if (wh->hid_hololens_sensors_dev != NULL) { + os_hid_destroy(wh->hid_hololens_sensors_dev); + wh->hid_hololens_sensors_dev = NULL; } if (wh->hid_control_dev != NULL) { @@ -471,7 +471,7 @@ wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, e wh->base.orientation_tracking_supported = true; wh->base.position_tracking_supported = false; wh->base.hand_tracking_supported = false; - wh->hid_hololens_senors_dev = hid_holo; + wh->hid_hololens_sensors_dev = hid_holo; wh->hid_control_dev = hid_ctrl; snprintf(wh->base.str, XRT_DEVICE_NAME_LEN, "HP Reverb VR Headset"); diff --git a/src/xrt/drivers/wmr/wmr_hmd.h b/src/xrt/drivers/wmr/wmr_hmd.h index 9469d3bad..b02195232 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.h +++ b/src/xrt/drivers/wmr/wmr_hmd.h @@ -61,7 +61,7 @@ struct wmr_hmd * init it is owned by the reading thread, there is no mutex protecting * this field as it's only used by the reading thread in @p oth. */ - struct os_hid_device *hid_hololens_senors_dev; + struct os_hid_device *hid_hololens_sensors_dev; struct os_hid_device *hid_control_dev; //! Latest raw IPD value from the device. From bc4cf1cb93c90a7ed572530962bbf3b6d932722b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 17:55:34 -0500 Subject: [PATCH 521/883] external/jnipp: Move away from explicit instantiation of function templates. Makes it too hard to track down errors: they showed up as linker errors, instead of compiler errors. --- src/external/jnipp/jnipp.cpp | 46 ++++++++++++++++++------------------ src/external/jnipp/jnipp.h | 43 +++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 27 deletions(-) diff --git a/src/external/jnipp/jnipp.cpp b/src/external/jnipp/jnipp.cpp index 2c558bda6..a250b76cd 100644 --- a/src/external/jnipp/jnipp.cpp +++ b/src/external/jnipp/jnipp.cpp @@ -353,20 +353,20 @@ namespace jni return _handle == nullptr || env()->IsSameObject(_handle, nullptr); } - template <> void Object::callMethod(method_t method, internal::value_t* args) const + void Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { env()->CallVoidMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); } - template <> bool Object::callMethod(method_t method, internal::value_t* args) const + bool Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallBooleanMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return result != 0; } - template <> bool Object::get(field_t field) const + bool Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return env()->GetBooleanField(_handle, field) != 0; } @@ -376,122 +376,122 @@ namespace jni env()->SetBooleanField(_handle, field, value); } - template <> byte_t Object::callMethod(method_t method, internal::value_t* args) const + byte_t Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallByteMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return result; } - template <> wchar_t Object::callMethod(method_t method, internal::value_t* args) const + wchar_t Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallCharMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return result; } - template <> short Object::callMethod(method_t method, internal::value_t* args) const + short Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallShortMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return result; } - template <> int Object::callMethod(method_t method, internal::value_t* args) const + int Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallIntMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return result; } - template <> long long Object::callMethod(method_t method, internal::value_t* args) const + long long Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallLongMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return result; } - template <> float Object::callMethod(method_t method, internal::value_t* args) const + float Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallFloatMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return result; } - template <> double Object::callMethod(method_t method, internal::value_t* args) const + double Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallDoubleMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return result; } - template <> std::string Object::callMethod(method_t method, internal::value_t* args) const + std::string Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return toString(result); } - template <> std::wstring Object::callMethod(method_t method, internal::value_t* args) const + std::wstring Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return toWString(result); } - template <> jni::Object Object::callMethod(method_t method, internal::value_t* args) const + jni::Object Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const { auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args); handleJavaExceptions(); return Object(result, DeleteLocalInput); } - template <> byte_t Object::get(field_t field) const + byte_t Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return env()->GetByteField(_handle, field); } - template <> wchar_t Object::get(field_t field) const + wchar_t Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return env()->GetCharField(_handle, field); } - template <> short Object::get(field_t field) const + short Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return env()->GetShortField(_handle, field); } - template <> int Object::get(field_t field) const + int Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return env()->GetIntField(_handle, field); } - template <> long long Object::get(field_t field) const + long long Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return env()->GetLongField(_handle, field); } - template <> float Object::get(field_t field) const + float Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return env()->GetFloatField(_handle, field); } - template <> double Object::get(field_t field) const + double Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return env()->GetDoubleField(_handle, field); } - template <> std::string Object::get(field_t field) const + std::string Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return toString(env()->GetObjectField(_handle, field)); } - template <> std::wstring Object::get(field_t field) const + std::wstring Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return toWString(env()->GetObjectField(_handle, field)); } - template <> Object Object::get(field_t field) const + Object Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return Object(env()->GetObjectField(_handle, field), DeleteLocalInput); } diff --git a/src/external/jnipp/jnipp.h b/src/external/jnipp/jnipp.h index aa20c217d..70515c979 100644 --- a/src/external/jnipp/jnipp.h +++ b/src/external/jnipp/jnipp.h @@ -176,6 +176,11 @@ namespace jni }; long getArrayLength(jarray array); + + template + struct ReturnTypeWrapper{ + using type = T; + }; } /** @@ -282,7 +287,7 @@ namespace jni \return The method's return value. */ template - TReturn call(method_t method) const { return callMethod(method, nullptr); } + TReturn call(method_t method) const { return callMethod(method, nullptr, internal::ReturnTypeWrapper{}); } /** Calls the method on this Object with the given name, and no arguments. @@ -312,7 +317,7 @@ namespace jni template TReturn call(method_t method, const TArgs&... args) const { internal::ArgArray transform(args...); - return callMethod(method, transform.values); + return callMethod(method, transform.values, internal::ReturnTypeWrapper{}); } /** @@ -342,7 +347,11 @@ namespace jni \return The field's value. */ template - TType get(field_t field) const; + TType get(field_t field) const { + // If you get a compile error here, then you've asked for a type + // we don't know how to get from JNI directly. + return getFieldValue(field, internal::ReturnTypeWrapper{}); + } /** Gets a field value from this Object. The field must belong to the @@ -410,7 +419,33 @@ namespace jni method_t getMethod(const char* name, const char* signature) const; method_t getMethod(const char* nameAndSignature) const; field_t getField(const char* name, const char* signature) const; - template TType callMethod(method_t method, internal::value_t* values) const; + + void callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + bool callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + byte_t callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + wchar_t callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + short callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + int callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + long long callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + float callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + double callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + std::string callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + std::wstring callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + jni::Object callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; + + + void getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + bool getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + byte_t getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + wchar_t getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + short getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + int getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + long long getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + float getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + double getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + std::string getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + std::wstring getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; + jni::Object getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; // Instance Variables jobject _handle; From e008e4f3190c4a51a6b465bdc36a9204d80ff7ab Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 16:35:40 -0500 Subject: [PATCH 522/883] doc: Start documenting code style/conventions/idioms --- doc/conventions.md | 165 +++++++++++++++++++++++++++++++++++++++++++++ doc/mainpage.md | 3 +- 2 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 doc/conventions.md diff --git a/doc/conventions.md b/doc/conventions.md new file mode 100644 index 000000000..3ab47bad3 --- /dev/null +++ b/doc/conventions.md @@ -0,0 +1,165 @@ +# Code Style and Conventions {#conventions} + + + + + +Here are some general code style guidelines we follow. + +## APIs + +Internal APIs, when it makes sense, should be C APIs. Headers that define +general communication interfaces between modules (not just use of utilities) +belong in the `xrt/include/xrt` directory, and should not depend on any other module outside +that directory. (As a historical note: this directory gets its name from a +compressed version of the phrase "XR RunTime", a generic term for Monado and an +early development codename. Also, it's shorter than `monado_` and so nicer to +use in code.) + +What follows are some basic API usage rules. Note that all the module usage +relations must be expressed in the build system, so module usage should form a +directed-acyclic-graph. + +- Any module can implement or use APIs declared in `xrt/include/xrt` +- Any module (except the `xrt` interface headers themselves) can (and should!) + use APIs declared in `xrt/auxiliary/util`. +- Any module except for `auxiliary/util` and the `xrt` interface headers + themselves can use APIs declared in other `xrt/auxiliary` modules. + +## Naming + +- C APIs: + - `lower_snake_case` for types and functions. + - `UPPER_SNAKE_CASE` for macros. e.g. @ref U_TYPED_CALLOC (which is how all + allocations in C code should be performed) + - Prefix names with a "namespace" - the library/module where they reside. e.g. + @ref u_var_add_root, @ref math_pose_validate + - Related: only things prefixed by `xrt_` belong in the `xrt/include/xrt` + directory, and nothing named starting with `xrt_` should be declared + anywhere else. (Interfaces *declared* in `xrt/include/xrt` are + *implemented* in other modules.) + - Generally, we do not declare typedefs for `struct` and `enum` types, but + instead refer to them in long form, saying `struct` or `enum` then the name. + - If a typedef is needed, it should be named ending with `_t`. + - Parameters: `lower_snake_case` or acronyms. + - Output parameters should begin with `out_`. + - Of special note: Structures/types that represent "objects" often have long + type names or "conceptual" names. When a pointer to them is passed to a + function or kept as a local variable, it is typically named by taking the + first letter of each (typically `_`-delimited) word in the structure type + name. Sometimes, it is an abbreviated form of that name instead. Relevant + examples: + - @ref xrt_comp_native_create_swapchain() is a member function of the + interface @ref xrt_compositor_native, and takes a pointer to that + interface named `xcn`. It creates an @ref xrt_swapchain, which it + populates in the parameter named `out_xscn`: `out_` because it's a + purely output parameter, `xscn` from @ref xrt_swapchain_native + specifically the letters `Xrt_SwapChain_Native`. @ref xrt_swapchain and + related types are a small exception to the rules - there are only 2 + words if you go by the `_` delimiters, but for clarity we treat + swapchain as if it were two words when abbreviating. A few other places + in the `xrt` headers use `x` + an abbreviated name form, like `xinst` + for @ref xrt_instance, `xdev` for @ref xrt_device, `xsysc` sometimes + used for @ref xrt_system_compositor. + - `create` and `destroy` are used when the functions actually perform + allocation and return the new object, or deallocation of the passed-in + object. + - If some initialization or cleanup is required but the type is not opaque and + is allocated by the caller, the names to use are `init` and, if needed, one + of `cleanup`/`fini`/`teardown`. (We are not yet consistent on these names.) + One common example is when there is some shared code and a structure + partially implementing an interface: a further-derived object may need to + call an `init` function on the shared structure, but it was allocated by the + derived object and held by value. +- C++: + - Where a C API is exposed, it should follow the C API naming schemes. + - If only a C++ API is exposed, a fairly conventional C++ naming scheme is used: + - Namespaces: nested to match directory structure, starting with `xrt::`. + (Migration to this pattern is still in progress.) + - There are no C++ interfaces in the `xrt/include/xrt`, by design, so this + is not ambiguous. + - Place types that need to be exposed in a header for technical reasons, + but that are still considered implementation details, within a + further-nested `detail` namespace, as seen elsewhere in the C++ + ecosystem. + - Types/classes: `CamelCase` + - Methods/functions: `lowerCamelCase` + - If a header is only usable from C++ code, it should be named with the + extension `.hpp` to signify this. + +## Patterns and Idioms + +This is an incomplete list of conventional idioms used in the Monado codebase. + +### C "Inheritance" through first struct member + +Despite being in C, the design is fairly object-oriented. Types implement +interfaces and derive from other types typically by placing a field of that +parent type/interface as their first element, conventionally named `base`. This +means that a pointer to the derived type, and a pointer to the base type, have +the same value. + +For example, consider @ref client_gl_swapchain + +- Its first element is named @ref client_gl_swapchain::base and is of type @ref + xrt_swapchain_gl - meaning that it implements @ref xrt_swapchain_gl +- @ref xrt_swapchain_gl in turn starts with @ref xrt_swapchain_gl::base which is + @ref xrt_swapchain - meaning that @ref xrt_swapchain_gl **extends** @ref + xrt_swapchain. (Both @ref xrt_swapchain_gl and @ref xrt_swapchain are abstract + interfaces, as indicated by the `xrt_` prefix.) + +Structures/types that represent "objects" are often passed as the first +parameter to many functions, which serve as their "member functions". Sometimes, +these types are opaque and not related to other types in the system in a +user-visible way: they should have a `_create` and `_destroy` function. See @ref +time_state, @ref time_state_create, @ref time_state_destroy + +In other cases, an interface will have function pointers defined as fields in +the interface structure. (A type implementing these may be opaque, but would +begin with a member of the interface/base type.) These interface function +pointers must still take in a self pointer as their first parameter, because +there is no implied `this` pointer in C. This would result in awkward calls with +repeated, error-prone mentions of the object pointer, such as this example +calling the @ref xrt_device::update_inputs interface: +`xdev->update_inputs(xdev)`. These are typically wrapped by inline free +functions that make the call through the function pointer. Considering again the +@ref xrt_device example, the way you would call @ref xrt_device::update_inputs +is actually @ref xrt_device_update_inputs(). + +### Destroy takes a pointer to a pointer, nulls it out + +Destroy free functions should take a pointer to a pointer, performing null checks +before destruction, and setting null. They always succeed (void return): a +failure when destroying an object has little meaning in most cases. For a +sample, see @ref xrt_images_destroy. It would be used like this: + +```c +struct xrt_image_native_allocator *xina = /* created and initialized, or maybe NULL */; + +/* ... */ + +xrt_images_destroy(&xina); + +/* here, xina is NULL in all cases, and if it wasn't NULL before, it has been freed. */ +``` + +Note that this pattern is used in most cases but not all in the codebase: we +are gradually migrating those that don't fit this pattern. If you call a +destroy function that does not take a pointer-to-a-pointer, make sure to do +null checks before calling and set it to null after it returns. + +Also note: when an interface includes a "destroy" function pointer, it just +takes the normal pointer to an object: The free function wrapper is the one that +takes a pointer-to-a-pointer and handles the null checks. See for example @ref +xrt_instance_destroy takes the pointer-to-a-pointer, while the interface method +@ref xrt_instance::destroy takes just the single pointer. diff --git a/doc/mainpage.md b/doc/mainpage.md index 048eaf101..0aef3d2ea 100644 --- a/doc/mainpage.md +++ b/doc/mainpage.md @@ -1,7 +1,7 @@ # Monado @@ -13,6 +13,7 @@ getting started information and general documentation. * @ref CHANGELOG - If this is the web version of the docs, the changelog also includes a section for changes that have not yet been in a tagged release. +* @ref conventions * @ref understanding-targets * @ref vulkan-extensions * @ref writing-driver (**not complete**) From d88aefafbcb7dc47254352e68238b9fdfd963aa9 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 16:49:20 -0500 Subject: [PATCH 523/883] a/tracking: Migrate C++ APIs to the official namespaces now that we have some. --- src/xrt/auxiliary/tracking/t_calibration.cpp | 4 ++- .../tracking/t_calibration_opencv.hpp | 3 ++ src/xrt/auxiliary/tracking/t_file.cpp | 6 +++- src/xrt/auxiliary/tracking/t_fusion.hpp | 6 ++-- .../tracking/t_helper_debug_sink.hpp | 3 ++ src/xrt/auxiliary/tracking/t_imu.cpp | 3 +- src/xrt/auxiliary/tracking/t_imu_fusion.hpp | 8 ++++-- src/xrt/auxiliary/tracking/t_lowpass.hpp | 11 ++++---- .../auxiliary/tracking/t_lowpass_vector.hpp | 6 ++-- src/xrt/auxiliary/tracking/t_tracker_hand.cpp | 11 +++++++- src/xrt/auxiliary/tracking/t_tracker_psmv.cpp | 11 ++++++-- .../tracking/t_tracker_psmv_fusion.cpp | 28 ++++++++++--------- .../tracking/t_tracker_psmv_fusion.hpp | 5 ++-- src/xrt/auxiliary/tracking/t_tracker_psvr.cpp | 10 +++++++ src/xrt/auxiliary/tracking/t_tracking.h | 13 +++++++++ 15 files changed, 95 insertions(+), 33 deletions(-) diff --git a/src/xrt/auxiliary/tracking/t_calibration.cpp b/src/xrt/auxiliary/tracking/t_calibration.cpp index 8bf79116d..2aaa1e38e 100644 --- a/src/xrt/auxiliary/tracking/t_calibration.cpp +++ b/src/xrt/auxiliary/tracking/t_calibration.cpp @@ -27,7 +27,7 @@ DEBUG_GET_ONCE_BOOL_OPTION(hsv_filter, "T_DEBUG_HSV_FILTER", false) DEBUG_GET_ONCE_BOOL_OPTION(hsv_picker, "T_DEBUG_HSV_PICKER", false) DEBUG_GET_ONCE_BOOL_OPTION(hsv_viewer, "T_DEBUG_HSV_VIEWER", false) - +namespace xrt::auxiliary::tracking { /* * * Structs @@ -1416,3 +1416,5 @@ NormalizedCoordsCache::getNormalizedVector(cv::Point2f origCoords) const auto z = -std::sqrt(1.f - pt.dot(pt)); return {pt[0], pt[1], z}; } + +} // namespace xrt::auxiliary::tracking diff --git a/src/xrt/auxiliary/tracking/t_calibration_opencv.hpp b/src/xrt/auxiliary/tracking/t_calibration_opencv.hpp index 20bf20009..9205d63db 100644 --- a/src/xrt/auxiliary/tracking/t_calibration_opencv.hpp +++ b/src/xrt/auxiliary/tracking/t_calibration_opencv.hpp @@ -20,6 +20,7 @@ #include #include +namespace xrt::auxiliary::tracking { /*! * @brief Essential calibration data wrapped for C++. @@ -290,3 +291,5 @@ private: cv::Mat_ cacheX_; cv::Mat_ cacheY_; }; + +} // namespace xrt::auxiliary::tracking diff --git a/src/xrt/auxiliary/tracking/t_file.cpp b/src/xrt/auxiliary/tracking/t_file.cpp index 9cb9113ef..c1a4c74f6 100644 --- a/src/xrt/auxiliary/tracking/t_file.cpp +++ b/src/xrt/auxiliary/tracking/t_file.cpp @@ -13,6 +13,7 @@ #include "util/u_misc.h" #include "util/u_logging.h" + /* * * Pre-declar functions. @@ -31,7 +32,7 @@ write_cv_mat(FILE *f, cv::Mat *m); * Refine and create functions. * */ - +namespace xrt::auxiliary::tracking { RemapPair calibration_get_undistort_map(t_camera_calibration &calib, cv::InputArray rectify_transform_optional, @@ -165,6 +166,7 @@ StereoRectificationMaps::StereoRectificationMaps(t_stereo_camera_calibration *da view[0].rectify = calibration_get_undistort_map(data->view[0], view[0].rotation_mat, view[0].projection_mat); view[1].rectify = calibration_get_undistort_map(data->view[1], view[1].rotation_mat, view[1].projection_mat); } +} // namespace xrt::auxiliary::tracking /* * @@ -175,6 +177,7 @@ StereoRectificationMaps::StereoRectificationMaps(t_stereo_camera_calibration *da extern "C" bool t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_calibration **out_data) { + using xrt::auxiliary::tracking::StereoCameraCalibrationWrapper; t_stereo_camera_calibration *data_ptr = NULL; t_stereo_camera_calibration_alloc(&data_ptr); StereoCameraCalibrationWrapper wrapped(data_ptr); @@ -255,6 +258,7 @@ t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_cal extern "C" bool t_stereo_camera_calibration_save_v1(FILE *calib_file, struct t_stereo_camera_calibration *data) { + using xrt::auxiliary::tracking::StereoCameraCalibrationWrapper; StereoCameraCalibrationWrapper wrapped(data); // Dummy matrix cv::Mat dummy; diff --git a/src/xrt/auxiliary/tracking/t_fusion.hpp b/src/xrt/auxiliary/tracking/t_fusion.hpp index 7c644e3d6..ffb9c9e0f 100644 --- a/src/xrt/auxiliary/tracking/t_fusion.hpp +++ b/src/xrt/auxiliary/tracking/t_fusion.hpp @@ -22,7 +22,8 @@ #include "flexkalman/PoseState.h" -namespace xrt_fusion { +namespace xrt::auxiliary::tracking { + namespace types = flexkalman::types; using flexkalman::types::Vector; @@ -227,4 +228,5 @@ private: MeasurementVector knownLocationInBodySpace_; MeasurementSquareMatrix covariance_; }; -} // namespace xrt_fusion + +} // namespace xrt::auxiliary::tracking diff --git a/src/xrt/auxiliary/tracking/t_helper_debug_sink.hpp b/src/xrt/auxiliary/tracking/t_helper_debug_sink.hpp index 59274351d..40faa6d7b 100644 --- a/src/xrt/auxiliary/tracking/t_helper_debug_sink.hpp +++ b/src/xrt/auxiliary/tracking/t_helper_debug_sink.hpp @@ -16,6 +16,7 @@ #include #include "util/u_frame.h" +namespace xrt::auxiliary::tracking { struct HelperDebugSink { @@ -124,3 +125,5 @@ public: xrt_frame_reference(&frame, NULL); } }; + +} // namespace xrt::auxiliary::tracking diff --git a/src/xrt/auxiliary/tracking/t_imu.cpp b/src/xrt/auxiliary/tracking/t_imu.cpp index 9df57331f..97da7147f 100644 --- a/src/xrt/auxiliary/tracking/t_imu.cpp +++ b/src/xrt/auxiliary/tracking/t_imu.cpp @@ -16,13 +16,14 @@ #include +using xrt::auxiliary::tracking::SimpleIMUFusion; struct imu_fusion { public: uint64_t time_ns{0}; - xrt_fusion::SimpleIMUFusion simple_fusion; + SimpleIMUFusion simple_fusion; public: diff --git a/src/xrt/auxiliary/tracking/t_imu_fusion.hpp b/src/xrt/auxiliary/tracking/t_imu_fusion.hpp index d16e3514c..5efab5e93 100644 --- a/src/xrt/auxiliary/tracking/t_imu_fusion.hpp +++ b/src/xrt/auxiliary/tracking/t_imu_fusion.hpp @@ -33,7 +33,11 @@ DEBUG_GET_ONCE_LOG_OPTION(simple_imu_log, "SIMPLE_IMU_LOG", U_LOGGING_WARN) #define SIMPLE_IMU_WARN(...) U_LOG_IFL_W(ll, __VA_ARGS__) #define SIMPLE_IMU_ERROR(...) U_LOG_IFL_E(ll, __VA_ARGS__) -namespace xrt_fusion { +namespace xrt::auxiliary::tracking { + +/*! + * @brief A simple IMU fusion class. + */ class SimpleIMUFusion { public: @@ -304,4 +308,4 @@ SimpleIMUFusion::handleAccel(Eigen::Vector3d const &accel, timepoint_ns timestam return true; } -} // namespace xrt_fusion +} // namespace xrt::auxiliary::tracking diff --git a/src/xrt/auxiliary/tracking/t_lowpass.hpp b/src/xrt/auxiliary/tracking/t_lowpass.hpp index 6105ed103..5b8aee262 100644 --- a/src/xrt/auxiliary/tracking/t_lowpass.hpp +++ b/src/xrt/auxiliary/tracking/t_lowpass.hpp @@ -20,8 +20,9 @@ #include -namespace xrt_fusion { -namespace implementation { +namespace xrt::auxiliary::tracking { + +namespace detail { /*! * The shared implementation (between vector and scalar versions) of an * IIR low-pass filter. @@ -99,7 +100,7 @@ namespace implementation { bool initialized{false}; timepoint_ns filter_timestamp_ns{0}; }; -} // namespace implementation +} // namespace detail /*! * A very simple low-pass filter, using a "one-pole infinite impulse response" @@ -172,7 +173,7 @@ public: } private: - implementation::LowPassIIR impl_; + detail::LowPassIIR impl_; }; -} // namespace xrt_fusion +} // namespace xrt::auxiliary::tracking diff --git a/src/xrt/auxiliary/tracking/t_lowpass_vector.hpp b/src/xrt/auxiliary/tracking/t_lowpass_vector.hpp index 2e2dbc8fa..c8b6d7f71 100644 --- a/src/xrt/auxiliary/tracking/t_lowpass_vector.hpp +++ b/src/xrt/auxiliary/tracking/t_lowpass_vector.hpp @@ -18,7 +18,7 @@ #include -namespace xrt_fusion { +namespace xrt::auxiliary::tracking { /*! * A very simple low-pass filter, using a "one-pole infinite impulse response" @@ -95,7 +95,7 @@ public: } private: - implementation::LowPassIIR impl_; + detail::LowPassIIR impl_; }; -} // namespace xrt_fusion +} // namespace xrt::auxiliary::tracking diff --git a/src/xrt/auxiliary/tracking/t_tracker_hand.cpp b/src/xrt/auxiliary/tracking/t_tracker_hand.cpp index b2482d101..17923cb11 100644 --- a/src/xrt/auxiliary/tracking/t_tracker_hand.cpp +++ b/src/xrt/auxiliary/tracking/t_tracker_hand.cpp @@ -19,11 +19,15 @@ #include "t_tracking.h" #include "tracking/t_calibration_opencv.hpp" +using namespace xrt::auxiliary::tracking; + +//! Namespace for hand tracker implementation +namespace xrt::auxiliary::tracking::hand { /*! * Single camera. * - * @see TrackerPSMV + * @see TrackerHand */ struct View { @@ -236,6 +240,11 @@ run(TrackerHand &t) os_thread_helper_unlock(&t.oth); } + +} // namespace xrt::auxiliary::tracking::hand + +using xrt::auxiliary::tracking::hand::TrackerHand; + extern "C" void * t_ht_run(void *ptr) { diff --git a/src/xrt/auxiliary/tracking/t_tracker_psmv.cpp b/src/xrt/auxiliary/tracking/t_tracker_psmv.cpp index 7cd6bf8ed..d79d04667 100644 --- a/src/xrt/auxiliary/tracking/t_tracker_psmv.cpp +++ b/src/xrt/auxiliary/tracking/t_tracker_psmv.cpp @@ -30,6 +30,10 @@ #include #include +using namespace xrt::auxiliary::tracking; + +//! Namespace for PS Move tracking implementation +namespace xrt::auxiliary::tracking::psmv { /*! * Single camera. @@ -106,7 +110,7 @@ struct TrackerPSMV cv::Ptr sbd; - std::unique_ptr filter; + std::unique_ptr filter; xrt_vec3 tracked_object_position; }; @@ -431,6 +435,9 @@ break_apart(TrackerPSMV &t) os_thread_helper_stop(&t.oth); } +} // namespace xrt::auxiliary::tracking::psmv + +using xrt::auxiliary::tracking::psmv::TrackerPSMV; /* * @@ -534,7 +541,7 @@ t_psmv_create(struct xrt_frame_context *xfctx, t.fusion.rot.y = 0.0f; t.fusion.rot.z = 0.0f; t.fusion.rot.w = 1.0f; - t.filter = xrt_fusion::PSMVFusionInterface::create(); + t.filter = PSMVFusionInterface::create(); ret = os_thread_helper_init(&t.oth); if (ret != 0) { diff --git a/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.cpp b/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.cpp index 5ea065e21..f09e1e243 100644 --- a/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.cpp +++ b/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.cpp @@ -28,17 +28,19 @@ #include "flexkalman/PoseState.h" -using State = flexkalman::pose_externalized_rotation::State; -using ProcessModel = flexkalman::PoseSeparatelyDampedConstantVelocityProcessModel; +namespace xrt::auxiliary::tracking { -namespace xrt_fusion { - -struct TrackingInfo -{ - bool valid{false}; - bool tracked{false}; -}; +//! Anonymous namespace to hide implementation names namespace { + + using State = flexkalman::pose_externalized_rotation::State; + using ProcessModel = flexkalman::PoseSeparatelyDampedConstantVelocityProcessModel; + + struct TrackingInfo + { + bool valid{false}; + bool tracked{false}; + }; class PSMVFusion : public PSMVFusionInterface { public: @@ -70,7 +72,7 @@ namespace { State filter_state; ProcessModel process_model; - xrt_fusion::SimpleIMUFusion imu; + xrt::auxiliary::tracking::SimpleIMUFusion imu; timepoint_ns filter_time_ns{0}; bool tracked{false}; @@ -162,8 +164,8 @@ namespace { if (lever_arm_optional) { lever_arm = map_vec3(*lever_arm_optional).cast(); } - auto measurement = - xrt_fusion::AbsolutePositionLeverArmMeasurement{pos.cast(), lever_arm, variance}; + auto measurement = xrt::auxiliary::tracking::AbsolutePositionLeverArmMeasurement{pos.cast(), + lever_arm, variance}; double resid = measurement.getResidual(filter_state).norm(); if (resid > residual_limit) { @@ -233,4 +235,4 @@ PSMVFusionInterface::create() auto ret = std::make_unique(); return ret; } -} // namespace xrt_fusion +} // namespace xrt::auxiliary::tracking diff --git a/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.hpp b/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.hpp index 44f907a58..9e4b606ba 100644 --- a/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.hpp +++ b/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.hpp @@ -23,7 +23,8 @@ #include -namespace xrt_fusion { +namespace xrt::auxiliary::tracking { + class PSMVFusionInterface { public: @@ -52,4 +53,4 @@ public: virtual void get_prediction(timepoint_ns when_ns, struct xrt_space_relation *out_relation) = 0; }; -} // namespace xrt_fusion +} // namespace xrt::auxiliary::tracking diff --git a/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp b/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp index 2ee000d2b..0fa266918 100644 --- a/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp +++ b/src/xrt/auxiliary/tracking/t_tracker_psvr.cpp @@ -109,6 +109,11 @@ DEBUG_GET_ONCE_LOG_OPTION(psvr_log, "PSVR_TRACKING_LOG", U_LOGGING_WARN) //#define PSVR_DUMP_FOR_OFFLINE_ANALYSIS //#define PSVR_DUMP_IMU_FOR_OFFLINE_ANALYSIS +using namespace xrt::auxiliary::tracking; + +//! Namespace for PSVR tracking implementation +namespace xrt::auxiliary::tracking::psvr { + typedef enum blob_type { BLOB_TYPE_UNKNOWN, @@ -1945,6 +1950,9 @@ break_apart(TrackerPSVR &t) os_thread_helper_stop(&t.oth); } +} // namespace xrt::auxiliary::tracking::psvr + +using xrt::auxiliary::tracking::psvr::TrackerPSVR; /* * @@ -2042,6 +2050,8 @@ t_psvr_create(struct xrt_frame_context *xfctx, PSVR_INFO("%s", __func__); int ret; + using xrt::auxiliary::tracking::psvr::init_filter; + for (uint32_t i = 0; i < PSVR_NUM_LEDS; i++) { init_filter(t.track_filters[i], PSVR_BLOB_PROCESS_NOISE, PSVR_BLOB_MEASUREMENT_NOISE, 1.0f); } diff --git a/src/xrt/auxiliary/tracking/t_tracking.h b/src/xrt/auxiliary/tracking/t_tracking.h index 15a16e06b..075402435 100644 --- a/src/xrt/auxiliary/tracking/t_tracking.h +++ b/src/xrt/auxiliary/tracking/t_tracking.h @@ -548,6 +548,19 @@ t_debug_hsv_filter_create(struct xrt_frame_context *xfctx, struct xrt_frame_sink *passthrough, struct xrt_frame_sink **out_sink); + +#ifdef __cplusplus + +namespace xrt::auxiliary { + /*! + * @brief Namespace used by C++ interfaces in the auxiliary tracking library code. + */ + namespace tracking { + + } // namespace tracking +} // namespace xrt::auxiliary +#endif + /*! * @} */ From 2ae3ce883db3f16e77d92e0f0c106680033e670b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 16:58:04 -0500 Subject: [PATCH 524/883] a/util: Namespace documentation --- src/xrt/auxiliary/util/u_documentation.h | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/xrt/auxiliary/util/u_documentation.h b/src/xrt/auxiliary/util/u_documentation.h index 99dd6cd75..032892c8b 100644 --- a/src/xrt/auxiliary/util/u_documentation.h +++ b/src/xrt/auxiliary/util/u_documentation.h @@ -38,3 +38,29 @@ * * @brief Smaller pieces of auxiliary utilities code. */ + +#ifdef __cplusplus +/*! + * @brief C++-only APIs in Monado. + * + * There are not very many of them. + */ +namespace xrt { + +/*! + * @brief C++-only functionality from assorted helper libraries + */ +namespace auxiliary { + + /*! + * @brief C++-only functionality from the miscellaneous "util" helper library + */ + namespace util { + + } // namespace util + +} // namespace auxiliary + +} // namespace xrt + +#endif From 265c49d33794be47d3c39c79267e0e6a8e2b26b4 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 17:23:32 -0500 Subject: [PATCH 525/883] a/math: Move functionality into official namespaces. --- src/xrt/auxiliary/math/m_base.cpp | 1 + src/xrt/auxiliary/math/m_documentation.hpp | 18 ++++++++++++++++++ src/xrt/auxiliary/math/m_eigen_interop.hpp | 5 ++++- src/xrt/auxiliary/math/m_quatexpmap.cpp | 2 ++ src/xrt/auxiliary/tracking/t_imu.cpp | 1 + .../tracking/t_tracker_psmv_fusion.cpp | 2 ++ 6 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/xrt/auxiliary/math/m_documentation.hpp diff --git a/src/xrt/auxiliary/math/m_base.cpp b/src/xrt/auxiliary/math/m_base.cpp index e75fc35ff..0f22621a6 100644 --- a/src/xrt/auxiliary/math/m_base.cpp +++ b/src/xrt/auxiliary/math/m_base.cpp @@ -17,6 +17,7 @@ #include +using namespace xrt::auxiliary::math; /* * diff --git a/src/xrt/auxiliary/math/m_documentation.hpp b/src/xrt/auxiliary/math/m_documentation.hpp new file mode 100644 index 000000000..3f839e84e --- /dev/null +++ b/src/xrt/auxiliary/math/m_documentation.hpp @@ -0,0 +1,18 @@ +// Copyright 2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Header with just documentation. + * @author Ryan Pavlik + * @ingroup aux_math + */ + +#pragma once + + +namespace xrt::auxiliary { +//! C++-only functionality in the Math helper library +namespace math { + +} // namespace math +} // namespace xrt::auxiliary diff --git a/src/xrt/auxiliary/math/m_eigen_interop.hpp b/src/xrt/auxiliary/math/m_eigen_interop.hpp index ed54d5435..3a8040f6f 100644 --- a/src/xrt/auxiliary/math/m_eigen_interop.hpp +++ b/src/xrt/auxiliary/math/m_eigen_interop.hpp @@ -1,4 +1,4 @@ -// Copyright 2019, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -18,6 +18,7 @@ #include #include +namespace xrt::auxiliary::math { /*! * @brief Wrap an internal quaternion struct in an Eigen type, const overload. @@ -124,3 +125,5 @@ position(struct xrt_pose &pose) { return map_vec3(pose.position); } + +} // namespace xrt::auxiliary::math diff --git a/src/xrt/auxiliary/math/m_quatexpmap.cpp b/src/xrt/auxiliary/math/m_quatexpmap.cpp index f5d0dd99e..725bd9a44 100644 --- a/src/xrt/auxiliary/math/m_quatexpmap.cpp +++ b/src/xrt/auxiliary/math/m_quatexpmap.cpp @@ -130,6 +130,8 @@ quat_ln(Eigen::Quaternion const &quat) } // namespace +using namespace xrt::auxiliary::math; + extern "C" void math_quat_integrate_velocity(const struct xrt_quat *quat, const struct xrt_vec3 *ang_vel, diff --git a/src/xrt/auxiliary/tracking/t_imu.cpp b/src/xrt/auxiliary/tracking/t_imu.cpp index 97da7147f..ebb586e11 100644 --- a/src/xrt/auxiliary/tracking/t_imu.cpp +++ b/src/xrt/auxiliary/tracking/t_imu.cpp @@ -17,6 +17,7 @@ #include using xrt::auxiliary::tracking::SimpleIMUFusion; +using namespace xrt::auxiliary::math; struct imu_fusion { diff --git a/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.cpp b/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.cpp index f09e1e243..0e45869f5 100644 --- a/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.cpp +++ b/src/xrt/auxiliary/tracking/t_tracker_psmv_fusion.cpp @@ -30,6 +30,8 @@ namespace xrt::auxiliary::tracking { +using namespace xrt::auxiliary::math; + //! Anonymous namespace to hide implementation names namespace { From 77baa8b7e61ca5bf85f8b74fe20fc1a589882cc6 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 17:23:59 -0500 Subject: [PATCH 526/883] aux/android: Move code into official namespaces --- src/xrt/auxiliary/android/android_custom_surface.cpp | 2 ++ src/xrt/auxiliary/android/android_load_class.cpp | 5 +++++ src/xrt/auxiliary/android/android_load_class.hpp | 5 +++++ src/xrt/ipc/android/ipc_client_android.cpp | 2 ++ 4 files changed, 14 insertions(+) diff --git a/src/xrt/auxiliary/android/android_custom_surface.cpp b/src/xrt/auxiliary/android/android_custom_surface.cpp index 829f01fd4..eacfabe1c 100644 --- a/src/xrt/auxiliary/android/android_custom_surface.cpp +++ b/src/xrt/auxiliary/android/android_custom_surface.cpp @@ -24,6 +24,8 @@ using wrap::android::app::Activity; using wrap::android::view::SurfaceHolder; using wrap::org::freedesktop::monado::auxiliary::MonadoView; +using xrt::auxiliary::android::getAppInfo; +using xrt::auxiliary::android::loadClassFromPackage; struct android_custom_surface diff --git a/src/xrt/auxiliary/android/android_load_class.cpp b/src/xrt/auxiliary/android/android_load_class.cpp index 47f42c60b..5db978ba4 100644 --- a/src/xrt/auxiliary/android/android_load_class.cpp +++ b/src/xrt/auxiliary/android/android_load_class.cpp @@ -19,6 +19,8 @@ using wrap::android::content::Context; using wrap::android::content::pm::ApplicationInfo; using wrap::android::content::pm::PackageManager; +namespace xrt::auxiliary::android { + ApplicationInfo getAppInfo(std::string const &packageName, jobject application_context) { @@ -78,6 +80,8 @@ loadClassFromPackage(ApplicationInfo applicationInfo, jobject application_contex return wrap::java::lang::Class(); } } +} // namespace xrt::auxiliary::android + void * android_load_class_from_package(struct _JavaVM *vm, @@ -85,6 +89,7 @@ android_load_class_from_package(struct _JavaVM *vm, void *application_context, const char *classname) { + using namespace xrt::auxiliary::android; jni::init(vm); Context context((jobject)application_context); auto info = getAppInfo(pkgname, (jobject)application_context); diff --git a/src/xrt/auxiliary/android/android_load_class.hpp b/src/xrt/auxiliary/android/android_load_class.hpp index 327158c3e..967889150 100644 --- a/src/xrt/auxiliary/android/android_load_class.hpp +++ b/src/xrt/auxiliary/android/android_load_class.hpp @@ -15,6 +15,9 @@ #ifdef XRT_OS_ANDROID +//! C++-only functionality in the Android auxiliary library +namespace xrt::auxiliary::android { + using wrap::android::content::pm::ApplicationInfo; ApplicationInfo @@ -23,4 +26,6 @@ getAppInfo(std::string const &packageName, jobject application_context); wrap::java::lang::Class loadClassFromPackage(ApplicationInfo applicationInfo, jobject application_context, const char *clazz_name); +} // namespace xrt::auxiliary::android + #endif // XRT_OS_ANDROID diff --git a/src/xrt/ipc/android/ipc_client_android.cpp b/src/xrt/ipc/android/ipc_client_android.cpp index 46adb195a..3d69a346f 100644 --- a/src/xrt/ipc/android/ipc_client_android.cpp +++ b/src/xrt/ipc/android/ipc_client_android.cpp @@ -19,6 +19,8 @@ using wrap::android::app::Activity; using wrap::org::freedesktop::monado::ipc::Client; +using xrt::auxiliary::android::getAppInfo; +using xrt::auxiliary::android::loadClassFromPackage; struct ipc_client_android { From 8d7f449efb1429451fe7cc75ea85d4cca8c03954 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 30 Apr 2021 17:27:35 -0500 Subject: [PATCH 527/883] doc: Document !810 --- doc/changes/auxiliary/mr.810.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/auxiliary/mr.810.md diff --git a/doc/changes/auxiliary/mr.810.md b/doc/changes/auxiliary/mr.810.md new file mode 100644 index 000000000..ce1c15eea --- /dev/null +++ b/doc/changes/auxiliary/mr.810.md @@ -0,0 +1 @@ +Move C++-only functionality into the newly-conventional namespaces. From 348b7dff3a2e7ba998a85721d61409f26216bd86 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 4 May 2021 10:28:47 -0500 Subject: [PATCH 528/883] d/wmr: fix doxygen warning --- src/xrt/drivers/wmr/wmr_interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/drivers/wmr/wmr_interface.h b/src/xrt/drivers/wmr/wmr_interface.h index 2969b8268..c6821e1f5 100644 --- a/src/xrt/drivers/wmr/wmr_interface.h +++ b/src/xrt/drivers/wmr/wmr_interface.h @@ -17,7 +17,7 @@ extern "C" { #endif /*! - * @defgroup drv_wmr + * @defgroup drv_wmr Windows Mixed Reality driver * @ingroup drv * * @brief Windows Mixed Reality driver. From b6f440fa26eb3b912da989d6073fdd7556b33772 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Tue, 4 May 2021 10:40:01 -0500 Subject: [PATCH 529/883] aux/tracking: Move general docs to a separate header. --- src/xrt/auxiliary/tracking/t_documentation.h | 70 ++++++++++++++++++++ src/xrt/auxiliary/tracking/t_tracking.h | 49 -------------- 2 files changed, 70 insertions(+), 49 deletions(-) create mode 100644 src/xrt/auxiliary/tracking/t_documentation.h diff --git a/src/xrt/auxiliary/tracking/t_documentation.h b/src/xrt/auxiliary/tracking/t_documentation.h new file mode 100644 index 000000000..f25fb9811 --- /dev/null +++ b/src/xrt/auxiliary/tracking/t_documentation.h @@ -0,0 +1,70 @@ +// Copyright 2019-2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Documentation-only header. + * @author Pete Black + * @author Jakob Bornecrantz + * @author Ryan Pavlik + * @ingroup aux_tracking + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! + * @defgroup aux_tracking Tracking + * @ingroup aux + * @brief Trackers, filters and associated helper code. + * + * + * ### Coordinate system + * + * Right now there is no specific convention on where a tracking systems + * coordinate system is centered, and is something we probably need to figure + * out. Right now the stereo based tracking system used by the PSVR and PSMV + * tracking system is centered on the camera that OpenCV decided is origin. + * + * To go a bit further on the PSVR/PSMV case. Think about a idealized start up + * case, the user is wearing the HMD headset and holding two PSMV controllers. + * The HMD's coordinate system axis are perfectly parallel with the user + * coordinate with the user's coordinate system. Where -Z is forward. The user + * holds the controllers with the ball pointing up and the buttons on the back + * pointing forward. Which if you read the documentation of @ref psmv_device + * will that the axis of the PSMV are also perfectly aligned with the users + * coordinate system. So everything "attached" to the user have it's coordinate + * system parallel to the user's. + * + * The camera on the other hand is looking directly at the user, it's Z-axis and + * X-axis is flipped in relation to the user's. So to compare what is sees to + * what the user sees, everything is rotated 180° around the Y-axis. + */ + +/*! + * @dir auxiliary/tracking + * @ingroup aux + * + * @brief Trackers, filters and associated helper code. + */ + + +#ifdef __cplusplus + +namespace xrt::auxiliary { + /*! + * @brief Namespace used by C++ interfaces in the auxiliary tracking library code. + */ + namespace tracking { + + } // namespace tracking +} // namespace xrt::auxiliary +#endif + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/auxiliary/tracking/t_tracking.h b/src/xrt/auxiliary/tracking/t_tracking.h index 075402435..7f96ee8ee 100644 --- a/src/xrt/auxiliary/tracking/t_tracking.h +++ b/src/xrt/auxiliary/tracking/t_tracking.h @@ -21,42 +21,6 @@ extern "C" { #endif - -/*! - * @defgroup aux_tracking Tracking - * @ingroup aux - * @brief Trackers, filters and associated helper code. - * - * - * ### Coordinate system - * - * Right now there is no specific convention on where a tracking systems - * coordinate system is centered, and is something we probably need to figure - * out. Right now the stereo based tracking system used by the PSVR and PSMV - * tracking system is centered on the camera that OpenCV decided is origin. - * - * To go a bit further on the PSVR/PSMV case. Think about a idealized start up - * case, the user is wearing the HMD headset and holding two PSMV controllers. - * The HMD's coordinate system axis are perfectly parallel with the user - * coordinate with the user's coordinate system. Where -Z is forward. The user - * holds the controllers with the ball pointing up and the buttons on the back - * pointing forward. Which if you read the documentation of @ref psmv_device - * will that the axis of the PSMV are also perfectly aligned with the users - * coordinate system. So everything "attached" to the user have it's coordinate - * system parallel to the user's. - * - * The camera on the other hand is looking directly at the user, it's Z-axis and - * X-axis is flipped in relation to the user's. So to compare what is sees to - * what the user sees, everything is rotated 180° around the Y-axis. - */ - -/*! - * @dir auxiliary/tracking - * @ingroup aux - * - * @brief Trackers, filters and associated helper code. - */ - /*! * @addtogroup aux_tracking * @{ @@ -548,19 +512,6 @@ t_debug_hsv_filter_create(struct xrt_frame_context *xfctx, struct xrt_frame_sink *passthrough, struct xrt_frame_sink **out_sink); - -#ifdef __cplusplus - -namespace xrt::auxiliary { - /*! - * @brief Namespace used by C++ interfaces in the auxiliary tracking library code. - */ - namespace tracking { - - } // namespace tracking -} // namespace xrt::auxiliary -#endif - /*! * @} */ From 5c916fd77d7271de65fb4466ebe3832960c86384 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 27 Apr 2021 17:33:35 +0100 Subject: [PATCH 530/883] d/illixr: Use u_device_get_view_pose helper --- src/xrt/drivers/illixr/illixr_device.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/xrt/drivers/illixr/illixr_device.cpp b/src/xrt/drivers/illixr/illixr_device.cpp index 897c0275b..158a0aa96 100644 --- a/src/xrt/drivers/illixr/illixr_device.cpp +++ b/src/xrt/drivers/illixr/illixr_device.cpp @@ -136,9 +136,8 @@ illixr_hmd_get_view_pose(struct xrt_device *xdev, uint32_t view_index, struct xrt_pose *out_pose) { - struct xrt_pose pose = illixr_read_pose(); - - *out_pose = pose; + (void)xdev; + u_device_get_view_pose(eye_relation, view_index, out_pose); } std::vector From b3455555c2a12c931863b5a5e541c9271f35eada Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 1 May 2021 03:07:50 +0100 Subject: [PATCH 531/883] u/trace_marker: Use Percetto/Perfetto for tracing --- CMakeLists.txt | 4 +- doc/mainpage.md | 1 + doc/tracing.md | 65 ++++ src/xrt/auxiliary/CMakeLists.txt | 7 +- src/xrt/auxiliary/util/u_timing_frame.c | 261 ++++++-------- src/xrt/auxiliary/util/u_timing_render.c | 70 +--- src/xrt/auxiliary/util/u_trace_marker.c | 218 ++++------- src/xrt/auxiliary/util/u_trace_marker.h | 165 ++++----- .../include/xrt/xrt_config_have.h.cmake_in | 1 + src/xrt/targets/cli/CMakeLists.txt | 9 +- src/xrt/targets/cli/cli_cmd_trace.c | 337 ------------------ src/xrt/targets/cli/cli_main.c | 8 +- src/xrt/targets/cli/meson.build | 3 +- src/xrt/targets/openxr/target.c | 9 +- src/xrt/targets/service/main.c | 2 +- 15 files changed, 350 insertions(+), 810 deletions(-) create mode 100644 doc/tracing.md delete mode 100644 src/xrt/targets/cli/cli_cmd_trace.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ca1933b66..96a411957 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") ) pkg_check_modules(SURVIVE IMPORTED_TARGET survive) + pkg_check_modules(PERCETTO percetto) else() find_package(OpenGL) endif() @@ -193,7 +194,7 @@ cmake_dependent_option(XRT_HAVE_FFMPEG "Enable ffmpeg testing video driver" ON " cmake_dependent_option(XRT_HAVE_SDL2 "Enable use of SDL2" ON "SDL2_FOUND AND XRT_HAVE_OPENGL" OFF) cmake_dependent_option(XRT_HAVE_SYSTEM_CJSON "Enable cJSON from system, instead of bundled source" ON "CJSON_FOUND" OFF) cmake_dependent_option(XRT_HAVE_GST "Enable gstreamer" ON "GST_FOUND" OFF) - +cmake_dependent_option(XRT_HAVE_PERCETTO "Enable percetto support" ON "PERCETTO_FOUND" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_PSVR "Enable PSVR HMD driver" ON "HIDAPI_FOUND" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_RS "Enable RealSense device driver" ON "realsense2_FOUND" OFF) @@ -351,6 +352,7 @@ message(STATUS "# OPENCV: ${XRT_HAVE_OPENCV}") message(STATUS "# LIBUVC: ${XRT_HAVE_LIBUVC}") message(STATUS "# FFMPEG: ${XRT_HAVE_FFMPEG}") message(STATUS "# SDL2: ${XRT_HAVE_SDL2}") +message(STATUS "# PERCETTO: ${XRT_HAVE_PERCETTO}") message(STATUS "# SYSTEM_CJSON: ${XRT_HAVE_SYSTEM_CJSON}") message(STATUS "#") message(STATUS "# FEATURE_COMPOSITOR_MAIN: ${XRT_FEATURE_COMPOSITOR_MAIN}") diff --git a/doc/mainpage.md b/doc/mainpage.md index 0aef3d2ea..e4d1a1598 100644 --- a/doc/mainpage.md +++ b/doc/mainpage.md @@ -19,6 +19,7 @@ getting started information and general documentation. * @ref writing-driver (**not complete**) * @ref ipc-design * @ref frame-timing +* @ref tracing ## Source layout diff --git a/doc/tracing.md b/doc/tracing.md new file mode 100644 index 000000000..16fd85024 --- /dev/null +++ b/doc/tracing.md @@ -0,0 +1,65 @@ +# Tracing support {#tracing} + + + +## Requirements + +Monado uses the [Perfetto][]/[Percetto][] framework for tracining support, you +need to first build and install [Percetto][] in a place where CMake can find it. +Build [Perfetto][] (you will have gotten the source at least as part of build +[Percetto][]). It is a good idea to familiarise yourself with Perfetto before +proceeding. You then need to build Monado with CMake and give make sure +`XRT_FEATURE_TRACING` is enabled. + +* Build and install [Percetto][]. +* Build and get [Perfetto][] running. +* Build Monado with CMake and with `XRT_FEATURE_TRACING` being `ON`. + +## Running + +Save the following file to `data_events.cfg`, next to your perfetto folder. +Please refer to [Perfetto][] documentation about the format and options of this +config file, but the most important bits is the `tracker_event` section. + +```c +flush_period_ms: 30000 + +incremental_state_config { + clear_period_ms: 500 +} + +buffers: { + size_kb: 63488 + fill_policy: DISCARD +} + +# This is the important bit, this enables all data events from Monado. +data_sources: { + config: { + name: "track_event" + target_buffer: 0 + } +} +``` + +Then run the following commands before launching Monado. + +```bash +# Start the daemon. +# Only needs to be run once and keeps running. +./perfetto/out/linux_clang_release/traced & + +# Start the daemon ftrace probes daemon. +# Only needs to be run once and keeps running. +# Not needed with the above config. +./perfetto/out/linux_clang_release/traced_probes & + +# When you want to run a capture do and then run Monado. +./perfetto/out/linux_clang_release/perfetto --txt -c data_events.cfg -o /tmp/trace.protobuf +``` + +[Perfetto]: https://perfetto.dev +[Percetto]: https://github.com/olvaffe/percetto diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt index ad6027081..44eff39c8 100644 --- a/src/xrt/auxiliary/CMakeLists.txt +++ b/src/xrt/auxiliary/CMakeLists.txt @@ -230,6 +230,11 @@ if(XRT_HAVE_SYSTEM_CJSON) else() target_link_libraries(aux_util PUBLIC xrt-external-cjson) endif() +# For u_trace_marker +if(XRT_HAVE_PERCETTO) + target_link_libraries(aux_util PRIVATE ${PERCETTO_LINK_LIBRARIES}) + target_include_directories(aux_util PUBLIC ${PERCETTO_INCLUDE_DIRS}) +endif() if(XRT_HAVE_LIBBSD) target_include_directories(aux_util SYSTEM PRIVATE ${LIBBSD_INCLUDE_DIRS}) target_link_libraries(aux_util PUBLIC ${LIBBSD_LIBRARIES}) @@ -290,7 +295,7 @@ endif() if(XRT_HAVE_VULKAN) # Vulkan library. add_library(aux_vk STATIC ${VK_SOURCE_FILES}) - target_link_libraries(aux_vk PUBLIC aux_os) + target_link_libraries(aux_vk PUBLIC aux_os aux_util) target_link_libraries(aux_vk PUBLIC Vulkan::Vulkan) target_include_directories(aux_vk PUBLIC ${Vulkan_INCLUDE_DIR}) if(ANDROID) diff --git a/src/xrt/auxiliary/util/u_timing_frame.c b/src/xrt/auxiliary/util/u_timing_frame.c index 32e46b963..50e1b38ac 100644 --- a/src/xrt/auxiliary/util/u_timing_frame.c +++ b/src/xrt/auxiliary/util/u_timing_frame.c @@ -468,7 +468,117 @@ dt_info(struct u_frame_timing *uft, f->present_margin_ns, // present_margin_ms); // - COMP_TRACE_DATA(U_TRACE_DATA_TYPE_TIMING_FRAME, *f); + + if (!U_TRACE_CATEGORY_IS_ENABLED(timing)) { + return; + } + +#define TE_BEG(TRACK, TIME, NAME) U_TRACE_EVENT_BEGIN_ON_TRACK_DATA(timing, TRACK, TIME, NAME, PERCETTO_I(f->frame_id)) +#define TE_END(TRACK, TIME) U_TRACE_EVENT_END_ON_TRACK(timing, TRACK, TIME) + + + /* + * + * CPU + * + */ + + TE_BEG(rt_cpu, f->when_predict_ns, "sleep"); + TE_END(rt_cpu, f->wake_up_time_ns); + + uint64_t oversleep_start_ns = f->wake_up_time_ns + 1; + if (f->when_woke_ns > oversleep_start_ns) { + TE_BEG(rt_cpu, oversleep_start_ns, "oversleep"); + TE_END(rt_cpu, f->when_woke_ns); + } + + + /* + * + * GPU + * + */ + + uint64_t gpu_end_ns = f->actual_present_time_ns - f->present_margin_ns; + if (gpu_end_ns > f->when_submitted_ns) { + TE_BEG(rt_gpu, f->when_submitted_ns, "gpu"); + TE_END(rt_gpu, gpu_end_ns); + } else { + TE_BEG(rt_gpu, gpu_end_ns, "gpu-time-travel"); + TE_END(rt_gpu, f->when_submitted_ns); + } + + + /* + * + * Margin + * + */ + + if (gpu_end_ns < f->desired_present_time_ns) { + TE_BEG(rt_margin, gpu_end_ns, "margin"); + TE_END(rt_margin, f->desired_present_time_ns); + } + + + /* + * + * ERROR + * + */ + + if (!is_within_half_ms(f->actual_present_time_ns, f->desired_present_time_ns)) { + if (f->actual_present_time_ns > f->desired_present_time_ns) { + TE_BEG(rt_error, f->desired_present_time_ns, "slippage"); + TE_END(rt_error, f->actual_present_time_ns); + } else { + TE_BEG(rt_error, f->actual_present_time_ns, "run-ahead"); + TE_END(rt_error, f->desired_present_time_ns); + } + } + + + /* + * + * Info + * + */ + + if (f->when_infoed_ns >= f->actual_present_time_ns) { + TE_BEG(rt_info, f->actual_present_time_ns, "info"); + TE_END(rt_info, f->when_infoed_ns); + } else { + TE_BEG(rt_info, f->when_infoed_ns, "info_before"); + TE_END(rt_info, f->actual_present_time_ns); + } + + + /* + * + * Present + * + */ + + if (f->actual_present_time_ns != f->earliest_present_time_ns) { + U_TRACE_INSTANT_ON_TRACK(timing, rt_present, f->earliest_present_time_ns, "earliest"); + } + if (!is_within_half_ms(f->desired_present_time_ns, f->earliest_present_time_ns)) { + U_TRACE_INSTANT_ON_TRACK(timing, rt_present, f->desired_present_time_ns, "predicted"); + } + U_TRACE_INSTANT_ON_TRACK(timing, rt_present, f->actual_present_time_ns, "vsync"); + + + /* + * + * Compositor time + * + */ + + TE_BEG(rt_allotted, f->wake_up_time_ns, "allotted"); + TE_END(rt_allotted, f->wake_up_time_ns + f->current_app_time_ns); + +#undef TE_BEG +#undef TE_END } static void @@ -510,152 +620,3 @@ u_ft_display_timing_create(uint64_t estimated_frame_period_ns, struct u_frame_ti return XRT_SUCCESS; } - - -/* - * - * Tracing functions. - * - */ - -#define PID_NR 42 -#define TID_NORMAL 43 -#define TID_GPU 44 -#define TID_INFO 45 -#define TID_FRAME 46 -#define TID_ERROR 47 -#define TID_APP 48 - -XRT_MAYBE_UNUSED static void -trace_event(FILE *file, const char *name, uint64_t when_ns) -{ - if (file == NULL) { - return; - } - - // clang-format off - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"i\",\n" - "\t\t\t\"name\": \"%s\",\n" - "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" - "\t\t\t\"pid\": %u,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"s\": \"g\",\n" - "\t\t\t\"args\": {}\n" - "\t\t}", - name, when_ns / 1000, when_ns % 1000, PID_NR, TID_NORMAL); - // clang-format off -} - -static void -trace_event_id(FILE *file, const char *name, int64_t frame_id, uint64_t when_ns) -{ - if (file == NULL) { - return; - } - - // clang-format off - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"i\",\n" - "\t\t\t\"name\": \"%s\",\n" - "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" - "\t\t\t\"pid\": %u,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"s\": \"g\",\n" - "\t\t\t\"args\": {" - "\t\t\t\t\"id\": %" PRIi64 "\n" - "\t\t\t}\n" - "\t\t}", - name, when_ns / 1000, when_ns % 1000, PID_NR, TID_NORMAL, frame_id); - // clang-format off -} - -static void -trace_begin_id(FILE *file, uint32_t tid, const char *name, int64_t frame_id, const char *cat, uint64_t when_ns) -{ - if (file == NULL) { - return; - } - - char temp[256]; - snprintf(temp, sizeof(temp), "%s %" PRIi64, name, frame_id); - - u_trace_maker_write_json_begin(file, PID_NR, tid, temp, cat, when_ns); -} - -static void -trace_end(FILE *file, uint32_t tid, uint64_t when_ns) -{ - u_trace_maker_write_json_end(file, PID_NR, tid, when_ns); -} - -static void -trace_frame(FILE *file, struct frame *f) -{ - trace_begin_id(file, TID_NORMAL, "sleep", f->frame_id, "sleep", f->when_predict_ns); - trace_end(file, TID_NORMAL, f->wake_up_time_ns); - - if (f->when_woke_ns > f->wake_up_time_ns) { - trace_begin_id(file, TID_NORMAL, "oversleep", f->frame_id, "sleep", f->wake_up_time_ns); - trace_end(file, TID_NORMAL, f->when_woke_ns); - } - - if (!is_within_half_ms(f->actual_present_time_ns, f->desired_present_time_ns)) { - if (f->actual_present_time_ns > f->desired_present_time_ns) { - trace_begin_id(file, TID_ERROR, "slippage", f->frame_id, "slippage", - f->desired_present_time_ns); - trace_end(file, TID_ERROR, f->actual_present_time_ns); - } else { - trace_begin_id(file, TID_ERROR, "run-ahead", f->frame_id, "run-ahead", - f->actual_present_time_ns); - trace_end(file, TID_ERROR, f->desired_present_time_ns); - } - } - - uint64_t gpu_end_ns = f->actual_present_time_ns - f->present_margin_ns; - if (gpu_end_ns > f->when_submitted_ns) { - trace_begin_id(file, TID_GPU, "gpu", f->frame_id, "gpu", f->when_submitted_ns); - trace_end(file, TID_GPU, gpu_end_ns); - } else { - trace_begin_id(file, TID_GPU, "gpu-time-travel", f->frame_id, "gpu-time-travel", gpu_end_ns); - trace_end(file, TID_GPU, f->when_submitted_ns); - } - - if (f->when_infoed_ns >= f->actual_present_time_ns) { - trace_begin_id(file, TID_INFO, "info", f->frame_id, "info", f->actual_present_time_ns); - trace_end(file, TID_INFO, f->when_infoed_ns); - } else { - trace_begin_id(file, TID_INFO, "info before", f->frame_id, "info", f->when_infoed_ns); - trace_end(file, TID_INFO, f->actual_present_time_ns); - } - - trace_event_id(file, "vsync", f->frame_id, f->earliest_present_time_ns); - if (f->actual_present_time_ns != f->earliest_present_time_ns) { - trace_event_id(file, "flip", f->frame_id, f->actual_present_time_ns); - } - - trace_begin_id(file, TID_APP, "app", f->frame_id, "app", f->wake_up_time_ns); - trace_end(file, TID_APP, f->wake_up_time_ns + f->current_app_time_ns); -} - -void -u_ft_write_json(FILE *file, void *data) -{ - trace_frame(file, (struct frame *)data); -} - -void -u_ft_write_json_metadata(FILE *file) -{ - u_trace_maker_write_json_metadata(file, PID_NR, TID_NORMAL, "1 RendererThread"); - u_trace_maker_write_json_metadata(file, PID_NR, TID_GPU, "2 GPU"); - u_trace_maker_write_json_metadata(file, PID_NR, TID_INFO, "3 Info"); - u_trace_maker_write_json_metadata(file, PID_NR, TID_FRAME, "4 FrameTiming"); - u_trace_maker_write_json_metadata(file, PID_NR, TID_ERROR, "5 Slips"); - u_trace_maker_write_json_metadata(file, PID_NR, TID_APP, "6 App time"); - fflush(file); -} diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index 287ee8dd3..c9370db8a 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -350,7 +350,23 @@ rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) do_iir_filter(&rt->app.draw_time_ns, IIR_ALPHA_LT, IIR_ALPHA_GT, diff_draw_ns); // Trace the data. - COMP_TRACE_DATA(U_TRACE_DATA_TYPE_TIMING_RENDER, *f); +#define TE_BEG(TRACK, TIME, NAME) U_TRACE_EVENT_BEGIN_ON_TRACK_DATA(timing, TRACK, TIME, NAME, PERCETTO_I(f->frame_id)) +#define TE_END(TRACK, TIME) U_TRACE_EVENT_END_ON_TRACK(timing, TRACK, TIME) + + if (U_TRACE_CATEGORY_IS_ENABLED(timing)) { + TE_BEG(ft_cpu, f->when.predicted_ns, "sleep"); + TE_END(ft_cpu, f->when.wait_woke_ns); + + uint64_t cpu_start_ns = f->when.wait_woke_ns + 1; + TE_BEG(ft_cpu, cpu_start_ns, "cpu"); + TE_END(ft_cpu, f->when.begin_ns); + + TE_BEG(ft_draw, f->when.begin_ns, "draw"); + TE_END(ft_draw, f->when.delivered_ns); + } + +#undef TE_BEG +#undef TE_END // Reset the frame. f->state = U_RT_READY; @@ -406,55 +422,3 @@ u_rt_create(struct u_render_timing **out_urt) return XRT_SUCCESS; } - - -/* - * - * Tracing data. - * - */ - -#define PID_NR 43 -#define TID_ESTIMATED_CPU 20 -#define TID_ESTIMATED_DRAW 21 -#define TID_ACTUAL_CPU 22 -#define TID_ACTUAL_DRAW 23 - -static void -trace_begin_id(FILE *file, uint32_t tid, const char *name, int64_t frame_id, const char *cat, uint64_t when_ns) -{ - char temp[256]; - snprintf(temp, sizeof(temp), "%s %" PRIi64, name, frame_id); - - u_trace_maker_write_json_begin(file, PID_NR, tid, temp, cat, when_ns); -} - -static void -trace_end(FILE *file, uint32_t tid, uint64_t when_ns) -{ - u_trace_maker_write_json_end(file, PID_NR, tid, when_ns); -} - -void -u_rt_write_json_metadata(FILE *file) -{ - u_trace_maker_write_json_metadata(file, PID_NR, TID_ESTIMATED_CPU, "1 CPU estimated"); - u_trace_maker_write_json_metadata(file, PID_NR, TID_ESTIMATED_DRAW, "2 Draw estimated"); - u_trace_maker_write_json_metadata(file, PID_NR, TID_ACTUAL_CPU, "1 CPU actual"); - u_trace_maker_write_json_metadata(file, PID_NR, TID_ACTUAL_DRAW, "2 Draw actual"); -} - -void -u_rt_write_json(FILE *file, void *data) -{ - struct u_rt_frame *f = (struct u_rt_frame *)data; - - trace_begin_id(file, TID_ACTUAL_CPU, "sleep", f->frame_id, "sleep", f->when.predicted_ns); - trace_end(file, TID_ACTUAL_CPU, f->when.wait_woke_ns); - - trace_begin_id(file, TID_ACTUAL_CPU, "cpu", f->frame_id, "cpu", f->when.wait_woke_ns); - trace_end(file, TID_ACTUAL_CPU, f->when.begin_ns); - - trace_begin_id(file, TID_ACTUAL_DRAW, "draw", f->frame_id, "draw", f->when.begin_ns); - trace_end(file, TID_ACTUAL_DRAW, f->when.delivered_ns); -} diff --git a/src/xrt/auxiliary/util/u_trace_marker.c b/src/xrt/auxiliary/util/u_trace_marker.c index 329f42574..6e157d9da 100644 --- a/src/xrt/auxiliary/util/u_trace_marker.c +++ b/src/xrt/auxiliary/util/u_trace_marker.c @@ -2,183 +2,87 @@ // SPDX-License-Identifier: BSL-1.0 /*! * @file - * @brief Trace marking debugging code. + * @brief Tracing support code, see @ref tracing. * @author Jakob Bornecrantz * @ingroup aux_util */ - -// This needs to be first. -#define _GNU_SOURCE - #include "xrt/xrt_compiler.h" #include "xrt/xrt_config_os.h" -#include "u_trace_marker.h" +#include "xrt/xrt_config_have.h" + +#include "os/os_time.h" + +#include "util/u_trace_marker.h" + +#ifdef XRT_FEATURE_TRACING -#ifdef XRT_OS_LINUX #include -#include -#include -#include -#include -#include -#include -#include +PERCETTO_CATEGORY_DEFINE(U_TRACE_CATEGORIES) -#define TRACE_MARKER_FILENAME "/sys/kernel/tracing/trace_marker" - -int u_trace_xrt_fd = -1; -int u_trace_ipc_fd = -1; -int u_trace_oxr_fd = -1; -int u_trace_comp_fd = -1; +PERCETTO_TRACK_DEFINE(rt_cpu, PERCETTO_TRACK_EVENTS); +PERCETTO_TRACK_DEFINE(rt_allotted, PERCETTO_TRACK_EVENTS); +PERCETTO_TRACK_DEFINE(rt_gpu, PERCETTO_TRACK_EVENTS); +PERCETTO_TRACK_DEFINE(rt_margin, PERCETTO_TRACK_EVENTS); +PERCETTO_TRACK_DEFINE(rt_error, PERCETTO_TRACK_EVENTS); +PERCETTO_TRACK_DEFINE(rt_info, PERCETTO_TRACK_EVENTS); +PERCETTO_TRACK_DEFINE(rt_present, PERCETTO_TRACK_EVENTS); +PERCETTO_TRACK_DEFINE(ft_cpu, PERCETTO_TRACK_EVENTS); +PERCETTO_TRACK_DEFINE(ft_draw, PERCETTO_TRACK_EVENTS); void -u_tracer_maker_init(void) +u_tracer_maker_init(enum u_trace_which which) { - int fd = open(TRACE_MARKER_FILENAME, O_WRONLY); - - u_trace_oxr_fd = fd; - u_trace_ipc_fd = fd; - u_trace_xrt_fd = fd; - u_trace_comp_fd = fd; -} - -void -u_trace_enter(int fd, const char *func) -{ - if (fd < 0) { + int ret = PERCETTO_INIT(PERCETTO_CLOCK_MONOTONIC); + if (ret != 0) { return; } - char tmp[512]; - ssize_t len = snprintf(tmp, sizeof(tmp), "B %u %s", getpid(), func); - if (len > 0) { - len = write(fd, tmp, len); + I_PERCETTO_TRACK_PTR(rt_cpu)->name = "RT 1 Sleep"; + I_PERCETTO_TRACK_PTR(rt_allotted)->name = "RT 2 Allotted time"; + I_PERCETTO_TRACK_PTR(rt_gpu)->name = "RT 3 GPU"; + I_PERCETTO_TRACK_PTR(rt_margin)->name = "RT 4 Margin"; + I_PERCETTO_TRACK_PTR(rt_error)->name = "RT 5 Error"; + I_PERCETTO_TRACK_PTR(rt_info)->name = "RT 6 Info"; + I_PERCETTO_TRACK_PTR(rt_present)->name = "RT 7 Present"; + + I_PERCETTO_TRACK_PTR(ft_cpu)->name = "FT 1 App"; + I_PERCETTO_TRACK_PTR(ft_draw)->name = "FT 2 Draw"; + + if (which == U_TRACE_WHICH_SERVICE) { + PERCETTO_REGISTER_TRACK(rt_cpu); + PERCETTO_REGISTER_TRACK(rt_allotted); + PERCETTO_REGISTER_TRACK(rt_gpu); + PERCETTO_REGISTER_TRACK(rt_margin); + PERCETTO_REGISTER_TRACK(rt_error); + PERCETTO_REGISTER_TRACK(rt_info); + PERCETTO_REGISTER_TRACK(rt_present); + + PERCETTO_REGISTER_TRACK(ft_cpu); + PERCETTO_REGISTER_TRACK(ft_draw); } + + + /* + * + * Hack to get consistent names. + * https://github.com/olvaffe/percetto/issues/15 + * + */ + + os_nanosleep(1000 * 1000); + + // But also shows when the app was started. + XRT_TRACE_MARKER(); } +#else /* XRT_FEATURE_TRACING */ + void -u_trace_leave(int fd, const char *func) +u_tracer_maker_init(enum u_trace_which which) { - if (fd < 0) { - return; - } - - char tmp[512]; - ssize_t len = snprintf(tmp, sizeof(tmp), "E %u %s", getpid(), func); - if (len > 0) { - len = write(fd, tmp, len); - } + (void)which; } -void -u_trace_data(int fd, enum u_trace_data_type type, void *data, size_t size) -{ - char tmp[1024 * 8]; - - ssize_t len = snprintf(tmp, sizeof(tmp), "r %u %u %u ", getpid(), type, (uint32_t)size); - if (len <= 0) { - return; - } - - for (size_t i = 0; i < size; i++) { - ssize_t ret = snprintf(tmp + (size_t)len, sizeof(tmp) - (size_t)len, "%02x", ((uint8_t *)data)[i]); - if (ret <= 0) { - return; - } - len += ret; - } - - if (len > 0) { - len = write(fd, tmp, len); - } -} - -#else - -// Stubs on non-linux for now. -void -u_tracer_maker_init(void) -{} - -void -u_trace_enter(int fd, const char *func) -{} - -void -u_trace_leave(int fd, const char *func) -{} - -void -u_trace_data(int fd, enum u_trace_data_type type, void *data, size_t size) -{} -#endif - - -/* - * - * Writing functions. - * - */ - -void -u_trace_maker_write_json_metadata(FILE *file, uint32_t pid, uint32_t tid, const char *name) -{ - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"M\",\n" - "\t\t\t\"name\": \"thread_name\",\n" - "\t\t\t\"pid\": %u,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {\n" - "\t\t\t\t\"name\": \"%s\"\n" - "\t\t\t}\n" - "\t\t}", - pid, tid, name); -} - -void -u_trace_maker_write_json_begin(FILE *file, // - uint32_t pid, // - uint32_t tid, // - const char *name, // - const char *cat, // - uint64_t when_ns) // -{ - // clang-format off - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"B\",\n" - "\t\t\t\"name\": \"%s\",\n" - "\t\t\t\"cat\": \"%s\",\n" - "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" - "\t\t\t\"pid\": %u,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {}\n" - "\t\t}", - name, cat, when_ns / 1000, when_ns % 1000, pid, tid); - // clang-format on -} - -void -u_trace_maker_write_json_end(FILE *file, // - uint32_t pid, // - uint32_t tid, // - uint64_t when_ns) // -{ - // clang-format off - fprintf(file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"E\",\n" - "\t\t\t\"ts\": %" PRIu64 ".%03" PRIu64 ",\n" - "\t\t\t\"pid\": %u,\n" - "\t\t\t\"tid\": %u,\n" - "\t\t\t\"args\": {}\n" - "\t\t}", - when_ns / 1000, when_ns % 1000, pid, tid); - // clang-format on -} +#endif /* XRT_FEATURE_TRACING */ diff --git a/src/xrt/auxiliary/util/u_trace_marker.h b/src/xrt/auxiliary/util/u_trace_marker.h index dfe99e5a2..069b29ef3 100644 --- a/src/xrt/auxiliary/util/u_trace_marker.h +++ b/src/xrt/auxiliary/util/u_trace_marker.h @@ -2,7 +2,7 @@ // SPDX-License-Identifier: BSL-1.0 /*! * @file - * @brief Trace marking debugging code. + * @brief Tracing support code, see @ref tracing. * @author Jakob Bornecrantz * @ingroup aux_util */ @@ -11,6 +11,7 @@ #include "xrt/xrt_compiler.h" #include "xrt/xrt_config_os.h" +#include "xrt/xrt_config_have.h" #include "xrt/xrt_config_build.h" #include @@ -20,81 +21,30 @@ extern "C" { #endif - -enum u_trace_data_type +/*! + * Should the extra tracks be enabled, see @ref tracing. + * + * @ingroup aux_util + */ +enum u_trace_which { - U_TRACE_DATA_TYPE_TIMING_FRAME, - U_TRACE_DATA_TYPE_TIMING_RENDER, + U_TRACE_WHICH_SERVICE, + U_TRACE_WHICH_OPENXR, }; -void -u_tracer_maker_init(void); -void -u_trace_enter(int fd, const char *func); -void -u_trace_leave(int fd, const char *func); -void -u_trace_data(int fd, enum u_trace_data_type type, void *data, size_t size); - -extern int u_trace_xrt_fd; -extern int u_trace_ipc_fd; -extern int u_trace_oxr_fd; -extern int u_trace_comp_fd; - -#define XRT_TRACE_MARKER() U_TRACE_MARKER(u_trace_xrt_fd) -#define IPC_TRACE_MARKER() U_TRACE_MARKER(u_trace_ipc_fd) -#define OXR_TRACE_MARKER() U_TRACE_MARKER(u_trace_oxr_fd) -#define COMP_TRACE_MARKER() U_TRACE_MARKER(u_trace_comp_fd) -#define COMP_TRACE_DATA(type, data) U_TRACE_DATA(u_trace_comp_fd, type, data) - - -/* - * - * JSON dumper helper files. +/*! + * Internal init function, use @ref U_TRACE_TARGET_INIT, see @ref tracing. * + * @ingroup aux_util */ - void -u_trace_maker_write_json_metadata( // - FILE *file, // - uint32_t pid, // - uint32_t tid, // - const char *name); // +u_tracer_maker_init(enum u_trace_which which); -void -u_trace_maker_write_json_begin( // - FILE *file, // - uint32_t pid, // - uint32_t tid, // - const char *name, // - const char *cat, // - uint64_t when_ns); // - -void -u_trace_maker_write_json_end( // - FILE *file, // - uint32_t pid, // - uint32_t tid, // - uint64_t when_ns); // - - -/* - * - * Functions implemented by other modules. - * - */ - -void -u_ft_write_json(FILE *file, void *data); - -void -u_ft_write_json_metadata(FILE *file); - -void -u_rt_write_json(FILE *file, void *data); - -void -u_rt_write_json_metadata(FILE *file); +#define VK_TRACE_IDENT(IDENT) U_TRACE_EVENT(vk, #IDENT) +#define XRT_TRACE_MARKER() U_TRACE_EVENT(xrt, __func__) +#define IPC_TRACE_MARKER() U_TRACE_EVENT(ipc, __func__) +#define OXR_TRACE_MARKER() U_TRACE_EVENT(oxr, __func__) +#define COMP_TRACE_MARKER() U_TRACE_EVENT(comp, __func__) /* @@ -109,34 +59,50 @@ u_rt_write_json_metadata(FILE *file); #error "Tracing only supported on Linux" #endif -struct u_trace_scoped_struct -{ - const char *name; - int data; -}; +#ifndef XRT_HAVE_PERCETTO +#error "Need to have Percetto/Perfetto" +#endif -static inline void -u_trace_scope_cleanup(struct u_trace_scoped_struct *data) -{ - u_trace_leave(data->data, data->name); -} - -#define U_TRACE_MARKER(fd) \ - struct u_trace_scoped_struct __attribute__((cleanup(u_trace_scope_cleanup))) \ - u_trace_marker_func_data = {__func__, fd}; \ - u_trace_enter(u_trace_marker_func_data.data, u_trace_marker_func_data.name) +#include +#define U_TRACE_CATEGORIES(C, G) \ + C(vk, "vk") /* Vulkan calls */ \ + C(xrt, "xrt") /* Misc XRT calls */ \ + C(oxr, "st/oxr") /* OpenXR State Tracker calls */ \ + C(comp, "comp") /* Compositor calls */ \ + C(ipc, "ipc") /* IPC calls */ \ + C(timing, "timing") /* Timing calls */ +PERCETTO_CATEGORY_DECLARE(U_TRACE_CATEGORIES) + +PERCETTO_TRACK_DECLARE(rt_cpu); +PERCETTO_TRACK_DECLARE(rt_allotted); +PERCETTO_TRACK_DECLARE(rt_gpu); +PERCETTO_TRACK_DECLARE(rt_margin); +PERCETTO_TRACK_DECLARE(rt_error); +PERCETTO_TRACK_DECLARE(rt_info); +PERCETTO_TRACK_DECLARE(rt_present); +PERCETTO_TRACK_DECLARE(ft_cpu); +PERCETTO_TRACK_DECLARE(ft_draw); + +#define U_TRACE_EVENT(CATEGORY, NAME) TRACE_EVENT(CATEGORY, NAME) +#define U_TRACE_EVENT_BEGIN_ON_TRACK(CATEGORY, TRACK, TIME, NAME) \ + TRACE_EVENT_BEGIN_ON_TRACK(CATEGORY, TRACK, TIME, NAME) +#define U_TRACE_EVENT_BEGIN_ON_TRACK_DATA(CATEGORY, TRACK, TIME, NAME, ...) \ + TRACE_EVENT_BEGIN_ON_TRACK_DATA(CATEGORY, TRACK, TIME, NAME, __VA_ARGS__) +#define U_TRACE_EVENT_END_ON_TRACK(CATEGORY, TRACK, TIME) TRACE_EVENT_END_ON_TRACK(CATEGORY, TRACK, TIME) +#define U_TRACE_CATEGORY_IS_ENABLED(CATEGORY) PERCETTO_CATEGORY_IS_ENABLED(CATEGORY) +#define U_TRACE_INSTANT_ON_TRACK(CATEGORY, TRACK, TIME, NAME) \ + TRACE_ANY_WITH_ARGS(PERCETTO_EVENT_INSTANT, CATEGORY, &g_percetto_track_##TRACK, TIME, NAME, 0) #define U_TRACE_DATA(fd, type, data) u_trace_data(fd, type, (void *)&(data), sizeof(data)) - -#define U_TRACE_TARGET_INIT() \ +#define U_TRACE_TARGET_INIT(WHICH) \ void __attribute__((constructor(101))) u_trace_maker_constructor(void); \ \ void u_trace_maker_constructor(void) \ { \ - u_tracer_maker_init(); \ + u_tracer_maker_init(WHICH); \ } @@ -149,15 +115,34 @@ u_trace_scope_cleanup(struct u_trace_scoped_struct *data) * */ -#define U_TRACE_MARKER(fd) \ +#define U_TRACE_EVENT(CATEGORY, NAME) \ do { \ } while (false) -#define U_TRACE_DATA(fd, type, data) \ +#define U_TRACE_EVENT_BEGIN_ON_TRACK(CATEGORY, TRACK, TIME, NAME) \ do { \ } while (false) -#define U_TRACE_TARGET_INIT() +#define U_TRACE_EVENT_BEGIN_ON_TRACK_DATA(CATEGORY, TRACK, TIME, NAME, ...) \ + do { \ + } while (false) + +#define U_TRACE_EVENT_END_ON_TRACK(CATEGORY, TRACK, TIME) \ + do { \ + } while (false) + +#define U_TRACE_INSTANT_ON_TRACK(CATEGORY, TRACK, TIME, NAME) \ + do { \ + } while (false) + +#define U_TRACE_CATEGORY_IS_ENABLED(_) (false) + +/*! + * Add to target c file to enable tracing, see @ref tracing. + * + * @ingroup aux_util + */ +#define U_TRACE_TARGET_INIT(WHICH) #endif // XRT_FEATURE_TRACING diff --git a/src/xrt/include/xrt/xrt_config_have.h.cmake_in b/src/xrt/include/xrt/xrt_config_have.h.cmake_in index 175583a8d..c4f978162 100644 --- a/src/xrt/include/xrt/xrt_config_have.h.cmake_in +++ b/src/xrt/include/xrt/xrt_config_have.h.cmake_in @@ -25,3 +25,4 @@ #cmakedefine XRT_HAVE_SYSTEMD #cmakedefine XRT_HAVE_V4L2 #cmakedefine XRT_HAVE_VULKAN +#cmakedefine XRT_HAVE_PERCETTO diff --git a/src/xrt/targets/cli/CMakeLists.txt b/src/xrt/targets/cli/CMakeLists.txt index 2d44964b5..6c2a1d792 100644 --- a/src/xrt/targets/cli/CMakeLists.txt +++ b/src/xrt/targets/cli/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2019-2020, Collabora, Ltd. +# Copyright 2019-2021, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 ###### @@ -13,13 +13,6 @@ set(SOURCE_FILES cli_main.c ) -if(NOT WIN32) - # Lots of linux assumptions in this file. - list(APPEND SOURCE_FILES - cli_cmd_trace.c - ) -endif() - if(NOT WIN32) # No getline on Windows, so until we have a portable impl list(APPEND SOURCE_FILES diff --git a/src/xrt/targets/cli/cli_cmd_trace.c b/src/xrt/targets/cli/cli_cmd_trace.c deleted file mode 100644 index 44b78749a..000000000 --- a/src/xrt/targets/cli/cli_cmd_trace.c +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2021, Collabora, Ltd. -// SPDX-License-Identifier: BSL-1.0 -/*! - * @file - * @brief Trace marker parsing and coversion code. - * @author Jakob Bornecrantz - */ - -#include "xrt/xrt_compiler.h" - -#include "util/u_misc.h" -#include "util/u_trace_marker.h" - -#include "cli_common.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define P(...) fprintf(stderr, __VA_ARGS__) - -#define TRACE_PIPE_FILENAME "/sys/kernel/tracing/trace_pipe" -#define TRACE_MARKER_FILENAME "/sys/kernel/tracing/trace_marker" -#define BUF_SIZE (1024 * 8) - - -struct trace -{ - int fd; - FILE *file; - - bool running; - - char buffer[BUF_SIZE]; -}; - -static struct trace t = {0}; - - -/* - * - * JSON writing. - * - */ - -static void -json_w_header() -{ - fprintf(t.file, - "{\n" - "\t\"displayTimeUnit\": \"ms\",\n" - "\t\"traceEvents\": [\n" - "\t\t{\n" - "\t\t\t\"#\": \"This is to avoid having to deal with ',' all over the code.\"\n" - "\t\t}"); -} - -static void -json_w_end() -{ - fprintf(t.file, - "\n" - "\t]\n" - "}\n"); -} - - -/* - * - * Functions. - * - */ - -static int -open_file_fd(const char *filename, int flags) -{ - int fd = open(filename, flags); - if (fd < 0) { - fprintf(stderr, " :: Failed to open the file: '%s'\n", filename); - fprintf(stderr, " See command help!\n"); - } - - return fd; -} - -static int -open_fd() -{ - int check_fd = open_file_fd(TRACE_MARKER_FILENAME, O_WRONLY); - if (check_fd < 0) { - return -1; - } - close(check_fd); - - fprintf(stderr, " :: Checked '%s'\n", TRACE_MARKER_FILENAME); - - t.fd = open_file_fd(TRACE_PIPE_FILENAME, O_RDONLY); - - fprintf(stderr, " :: Opened '%s'\n", TRACE_PIPE_FILENAME); - - return 0; -} - -static void -handle_data(const char *rest_of_line, size_t len) -{ - int type = 0; - int data_length = 0; - int consumed = 0; - int scan = sscanf(rest_of_line, "%i %i %n", &type, &data_length, &consumed); - char data[1024]; - - if ((int)data_length * 2 != (int)len - (int)consumed) { - return; - } - - if ((size_t)data_length > sizeof(data)) { - return; - } - - rest_of_line = rest_of_line + consumed; - len = len - (size_t)consumed; - - - for (int i = 0; i < data_length; i++) { - unsigned int tmp = 0; - scan = sscanf(rest_of_line + (i * 2), "%2x", &tmp); - if (scan < 1) { - return; - } - - data[i] = tmp; - } - - switch (type) { - case U_TRACE_DATA_TYPE_TIMING_FRAME: u_ft_write_json(t.file, (void *)data); break; - case U_TRACE_DATA_TYPE_TIMING_RENDER: u_rt_write_json(t.file, (void *)data); break; - default: fprintf(stderr, "%.*s\n", (int)len, rest_of_line); break; - } -} - -static void -handle_line(const char *line, size_t len) -{ - int pid = 0, tid = 0; - int secs = 0, usecs = 0; - char cmd = '\0'; - int consumed = 0; - char function[256] = {0}; - - int scan = sscanf( // - line, // - " <...>-%i %*s %*s %d.%d: tracing_mark_write: %1s %i %n", // - &tid, // - &secs, // - &usecs, // - &cmd, // - &pid, // - &consumed); // - - if (scan < 5) { - fprintf(stderr, "%.*s\n", (int)len, line); - return; - } - - switch (cmd) { - case 'E': - case 'B': - scan = sscanf(line + consumed, "%256s", function); - if (scan < 1) { - fprintf(stderr, "%.*s\n", (int)len, line); - return; - } - - fprintf(t.file, - ",\n" - "\t\t{\n" - "\t\t\t\"ph\": \"%.1s\",\n" - "\t\t\t\"name\": \"%s\",\n" - "\t\t\t\"cat\": \"%s\",\n" - "\t\t\t\"ts\": %u%06u,\n" - "\t\t\t\"pid\": %u,\n" - "\t\t\t\"tid\": %u\n" - "\t\t}", - &cmd, function, "func", secs, usecs, pid, tid); - break; - case 'r': handle_data(line + consumed, len - (size_t)consumed); break; - default: fprintf(stderr, "%.*s\n", (int)len, line); break; - } -} - -static int -loop() -{ - while (t.running) { - ssize_t ret = read(t.fd, t.buffer, BUF_SIZE); - if (ret < 0) { - return 1; - } - if (ret == 0) { - continue; - } - - size_t pos = 0; - size_t count = 0; - while (count < (size_t)ret) { - if (t.buffer[count] != '\n') { - count++; - continue; - } - - assert(t.buffer[pos] != '\n'); - - size_t length = count - pos; - handle_line(t.buffer + pos, length); - - // Point *after* the newline. - count++; - pos = count; - } - - fflush(t.file); - } - - return 0; -} - -void -signal_handler(int signum, siginfo_t *info, void *ptr) -{ - t.running = false; - - // Since we are doing a clean shutdown ^C be on it's own line. - ssize_t ret = write(STDERR_FILENO, "\n", 1); - (void)ret; // We are just trying to make the CLI look better. -} - -void -catch_sigterm() -{ - static struct sigaction _sigact; - - memset(&_sigact, 0, sizeof(_sigact)); - _sigact.sa_sigaction = signal_handler; - _sigact.sa_flags = SA_SIGINFO; - - sigaction(SIGTERM, &_sigact, NULL); - sigaction(SIGINT, &_sigact, NULL); -} - -static int -trace_pipe(int argc, const char **argv) -{ - catch_sigterm(); - - t.file = stdout; - t.running = true; - - int ret = open_fd(); - if (ret < 0) { - return 1; - } - - json_w_header(); - - u_ft_write_json_metadata(t.file); - u_rt_write_json_metadata(t.file); - - P(" :: Looping\n"); - - ret = loop(); - if (ret < 0) { - return 1; - } - - json_w_end(); - - P(" :: Clean shutdown\n"); - - return 0; -} - -static void -print_help(int argc, const char **argv) -{ - if (argc >= 3) { - P("Unknown trace command '%s'\n\n", argv[2]); - } - - P("Usage %s trace \n", argv[0]); - P("\n"); - P("Commands:\n"); - P(" pipe - Read the trace_pipe stream and convert into json outputted to stdout.\n"); - P("\n"); - P("Example:\n"); - P(" $ %s trace pipe 1> /tmp/chrome_tracing.json\n", argv[0]); - P("\n"); - P("Make sure your user has access to the files:\n"); - P(" '%s'.\n", TRACE_PIPE_FILENAME); - P(" '%s'.\n", TRACE_MARKER_FILENAME); - P("\n"); - P("The reference clocks needs to be the same in Monado and the tracing framework.\n"); - P(" $ echo mono | sudo dd of=/sys/kernel/tracing/trace_clock\n"); - P("This command is very unsecure but will make things work.\n"); - P(" $ sudo chown -R : /sys/kernel/tracing\n"); - P("\n"); - P("See https://lwn.net/Articles/366796/\n"); -} - -int -cli_cmd_trace(int argc, const char **argv) -{ - if (argc <= 2) { - print_help(argc, argv); - return 1; - } - - if (strcmp(argv[2], "help") == 0) { - print_help(2, argv); - return 0; - } - - if (strcmp(argv[2], "pipe") == 0) { - return trace_pipe(argc, argv); - } - - print_help(argc, argv); - - return 1; -} diff --git a/src/xrt/targets/cli/cli_main.c b/src/xrt/targets/cli/cli_main.c index 8ffc05a3e..0d471e91c 100644 --- a/src/xrt/targets/cli/cli_main.c +++ b/src/xrt/targets/cli/cli_main.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020, Collabora, Ltd. +// Copyright 2019-2021, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -31,7 +31,6 @@ cli_print_help(int argc, const char **argv) P(" probe - Just probe and then exit.\n"); P(" lighthouse - Control the power of lighthouses [on|off].\n"); P(" calibrate - Calibrate a camera and save config (not implemented yet).\n"); - P(" trace - Tracing functionality.\n"); return 1; } @@ -57,10 +56,5 @@ main(int argc, const char **argv) if (strcmp(argv[1], "lighthouse") == 0) { return cli_cmd_lighthouse(argc, argv); } -#ifndef XRT_OS_WINDOWS - if (strcmp(argv[1], "trace") == 0) { - return cli_cmd_trace(argc, argv); - } -#endif // !XRT_OS_WINDOWS return cli_print_help(argc, argv); } diff --git a/src/xrt/targets/cli/meson.build b/src/xrt/targets/cli/meson.build index 4a470464f..88e5feb62 100644 --- a/src/xrt/targets/cli/meson.build +++ b/src/xrt/targets/cli/meson.build @@ -1,4 +1,4 @@ -# Copyright 2019, Collabora, Ltd. +# Copyright 2019-2021, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 cli = executable( @@ -8,7 +8,6 @@ cli = executable( 'cli_cmd_lighthouse.c', 'cli_cmd_probe.c', 'cli_cmd_test.c', - 'cli_cmd_trace.c', 'cli_common.h', 'cli_main.c', ), diff --git a/src/xrt/targets/openxr/target.c b/src/xrt/targets/openxr/target.c index 0ac5f2366..837478b6a 100644 --- a/src/xrt/targets/openxr/target.c +++ b/src/xrt/targets/openxr/target.c @@ -10,12 +10,12 @@ #include "util/u_trace_marker.h" -// Insert the on load constructor to init trace marker. -U_TRACE_TARGET_INIT() - #ifdef XRT_FEATURE_SERVICE +// Insert the on load constructor to init trace marker. +U_TRACE_TARGET_INIT(U_TRACE_WHICH_OPENXR) + #include "xrt/xrt_instance.h" // Forward declaration @@ -32,6 +32,9 @@ xrt_instance_create(struct xrt_instance_info *i_info, struct xrt_instance **out_ #else +// Insert the on load constructor to init trace marker. +U_TRACE_TARGET_INIT(U_TRACE_WHICH_SERVICE) + /* * For non-service runtime, xrt_instance_create defined in target_instance * helper lib, so we just have a dummy symbol below to silence warnings about diff --git a/src/xrt/targets/service/main.c b/src/xrt/targets/service/main.c index 9271ef317..1bc1d9b70 100644 --- a/src/xrt/targets/service/main.c +++ b/src/xrt/targets/service/main.c @@ -14,7 +14,7 @@ // Insert the on load constructor to init trace marker. -U_TRACE_TARGET_INIT() +U_TRACE_TARGET_INIT(U_TRACE_WHICH_SERVICE) int ipc_server_main(int argc, char *argv[]); From 41817b6e11fd3220322ace0d9388a285582becdd Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 28 Apr 2021 13:38:02 +0100 Subject: [PATCH 532/883] c/client: Tidy EGL code (NFC) --- src/xrt/compositor/client/comp_egl_glue.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/xrt/compositor/client/comp_egl_glue.c b/src/xrt/compositor/client/comp_egl_glue.c index abcf31d44..c3e3b4162 100644 --- a/src/xrt/compositor/client/comp_egl_glue.c +++ b/src/xrt/compositor/client/comp_egl_glue.c @@ -201,6 +201,7 @@ insert_fence(struct xrt_compositor *xc, xrt_graphics_sync_handle_t *out_handle) } *out_handle = fence_fd; + #else (void)cglc; #endif @@ -296,16 +297,20 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, DUMP_EXTENSION_STATUS(EGL_KHR_reusable_sync); DUMP_EXTENSION_STATUS(EGL_KHR_wait_sync); +#undef DUMP_EXTENSION_STATUS #if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) + if (GLAD_GL_EXT_memory_object && GLAD_GL_EXT_memory_object_fd) { EGL_DEBUG("Using GL memory object swapchain implementation"); sc_create = client_gl_memobj_swapchain_create; } + if (sc_create == NULL && GLAD_EGL_EXT_image_dma_buf_import) { EGL_DEBUG("Using EGL_Image swapchain implementation"); sc_create = client_gl_eglimage_swapchain_create; } + if (sc_create == NULL) { free(ceglc); EGL_ERROR( @@ -314,9 +319,12 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, old_restore(&old); return XRT_ERROR_OPENGL; } + #elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER) + EGL_DEBUG("Using EGL_Image swapchain implementation with AHardwareBuffer"); sc_create = client_gl_eglimage_swapchain_create; + #endif if (!client_gl_compositor_init(&ceglc->base, xcn, sc_create, insert_fence)) { @@ -329,5 +337,6 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, ceglc->base.base.base.destroy = client_egl_compositor_destroy; old_restore(&old); *out_xcgl = &ceglc->base.base; + return XRT_SUCCESS; } From 12489295cb694e221f9fa20b4dc0de286f2c5b93 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 28 Apr 2021 13:44:44 +0100 Subject: [PATCH 533/883] c/client: Do not blindly try to restore no EGLDisplay contexts --- src/xrt/compositor/client/comp_egl_glue.c | 38 ++++++++++++++++------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/xrt/compositor/client/comp_egl_glue.c b/src/xrt/compositor/client/comp_egl_glue.c index c3e3b4162..83eb1f8ec 100644 --- a/src/xrt/compositor/client/comp_egl_glue.c +++ b/src/xrt/compositor/client/comp_egl_glue.c @@ -145,19 +145,33 @@ old_save(void) { struct old_helper old = { .dpy = eglGetCurrentDisplay(), - .ctx = eglGetCurrentContext(), - .read = eglGetCurrentSurface(EGL_READ), - .draw = eglGetCurrentSurface(EGL_DRAW), + .ctx = EGL_NO_CONTEXT, + .read = EGL_NO_SURFACE, + .draw = EGL_NO_SURFACE, }; + // Do we have a valid display? + if (old.dpy != EGL_NO_DISPLAY) { + old.ctx = eglGetCurrentContext(); + old.read = eglGetCurrentSurface(EGL_READ); + old.draw = eglGetCurrentSurface(EGL_DRAW); + } + return old; } static inline void -old_restore(struct old_helper *old) +old_restore(struct old_helper *old, EGLDisplay current_dpy) { - if (eglMakeCurrent(old->dpy, old->draw, old->read, old->ctx)) { - return; + if (old->dpy == EGL_NO_DISPLAY) { + // There were no display, just unbind the context. + if (eglMakeCurrent(current_dpy, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE)) { + return; + } + } else { + if (eglMakeCurrent(old->dpy, old->draw, old->read, old->ctx)) { + return; + } } EGL_ERROR("Failed to make old EGL context current! (%p, %p, %p, %p)", old->dpy, old->draw, old->read, old->ctx); @@ -248,7 +262,7 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, EGLint egl_client_type; if (!eglQueryContext(display, context, EGL_CONTEXT_CLIENT_TYPE, &egl_client_type)) { - old_restore(&old); + old_restore(&old, display); return XRT_ERROR_OPENGL; } @@ -259,7 +273,7 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, break; #else EGL_ERROR("OpenGL support not including in this runtime build"); - old_restore(&old); + old_restore(&old, display); return XRT_ERROR_OPENGL; #endif @@ -269,7 +283,7 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, break; #else EGL_ERROR("OpenGL|ES support not including in this runtime build"); - old_restore(&old); + old_restore(&old, display); return XRT_ERROR_OPENGL; #endif default: EGL_ERROR("Unsupported EGL client type"); return XRT_ERROR_OPENGL; @@ -316,7 +330,7 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, EGL_ERROR( "Could not find a required extension: need either EGL_EXT_image_dma_buf_import or " "GL_EXT_memory_object_fd"); - old_restore(&old); + old_restore(&old, display); return XRT_ERROR_OPENGL; } @@ -330,12 +344,12 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, if (!client_gl_compositor_init(&ceglc->base, xcn, sc_create, insert_fence)) { free(ceglc); EGL_ERROR("Failed to initialize compositor"); - old_restore(&old); + old_restore(&old, display); return XRT_ERROR_OPENGL; } ceglc->base.base.base.destroy = client_egl_compositor_destroy; - old_restore(&old); + old_restore(&old, display); *out_xcgl = &ceglc->base.base; return XRT_SUCCESS; From 3a537b83746f69aeeb3e8ffe859ec855f78f579b Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 28 Apr 2021 13:49:16 +0100 Subject: [PATCH 534/883] c/client: Tidy EGL code (NFC) --- src/xrt/compositor/client/comp_egl_glue.c | 122 +++++++++++++--------- 1 file changed, 71 insertions(+), 51 deletions(-) diff --git a/src/xrt/compositor/client/comp_egl_glue.c b/src/xrt/compositor/client/comp_egl_glue.c index 83eb1f8ec..f2b227dff 100644 --- a/src/xrt/compositor/client/comp_egl_glue.c +++ b/src/xrt/compositor/client/comp_egl_glue.c @@ -32,6 +32,13 @@ #error "This file shouldn't be compiled without EGL" #endif + +/* + * + * Logging. + * + */ + static enum u_logging_level ll; #define EGL_TRACE(...) U_LOG_IFL_T(ll, __VA_ARGS__) @@ -43,6 +50,12 @@ static enum u_logging_level ll; DEBUG_GET_ONCE_LOG_OPTION(egl_log, "EGL_LOG", U_LOGGING_INFO) +/* + * + * Declarations. + * + */ + #ifdef XRT_OS_ANDROID typedef const char *EGLAPIENTRY (*PFNEGLQUERYSTRINGIMPLEMENTATIONANDROIDPROC)(EGLDisplay dpy, EGLint name); #endif @@ -51,6 +64,64 @@ typedef const char *EGLAPIENTRY (*PFNEGLQUERYSTRINGIMPLEMENTATIONANDROIDPROC)(EG typedef EGLBoolean EGLAPIENTRY (*PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); + +/* + * + * Old helper. + * + */ + +struct old_helper +{ + EGLDisplay dpy; + EGLContext ctx; + EGLSurface read, draw; +}; + +static inline struct old_helper +old_save(void) +{ + struct old_helper old = { + .dpy = eglGetCurrentDisplay(), + .ctx = EGL_NO_CONTEXT, + .read = EGL_NO_SURFACE, + .draw = EGL_NO_SURFACE, + }; + + // Do we have a valid display? + if (old.dpy != EGL_NO_DISPLAY) { + old.ctx = eglGetCurrentContext(); + old.read = eglGetCurrentSurface(EGL_READ); + old.draw = eglGetCurrentSurface(EGL_DRAW); + } + + return old; +} + +static inline void +old_restore(struct old_helper *old, EGLDisplay current_dpy) +{ + if (old->dpy == EGL_NO_DISPLAY) { + // There were no display, just unbind the context. + if (eglMakeCurrent(current_dpy, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE)) { + return; + } + } else { + if (eglMakeCurrent(old->dpy, old->draw, old->read, old->ctx)) { + return; + } + } + + EGL_ERROR("Failed to make old EGL context current! (%p, %p, %p, %p)", old->dpy, old->draw, old->read, old->ctx); +} + + +/* + * + * EGL compositor subclass. + * + */ + /*! * EGL based compositor. */ @@ -127,57 +198,6 @@ ensure_native_fence_is_loaded(EGLDisplay dpy, PFNEGLGETPROCADDRESSPROC get_gl_pr } -/* - * - * Old helper. - * - */ - -struct old_helper -{ - EGLDisplay dpy; - EGLContext ctx; - EGLSurface read, draw; -}; - -static inline struct old_helper -old_save(void) -{ - struct old_helper old = { - .dpy = eglGetCurrentDisplay(), - .ctx = EGL_NO_CONTEXT, - .read = EGL_NO_SURFACE, - .draw = EGL_NO_SURFACE, - }; - - // Do we have a valid display? - if (old.dpy != EGL_NO_DISPLAY) { - old.ctx = eglGetCurrentContext(); - old.read = eglGetCurrentSurface(EGL_READ); - old.draw = eglGetCurrentSurface(EGL_DRAW); - } - - return old; -} - -static inline void -old_restore(struct old_helper *old, EGLDisplay current_dpy) -{ - if (old->dpy == EGL_NO_DISPLAY) { - // There were no display, just unbind the context. - if (eglMakeCurrent(current_dpy, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE)) { - return; - } - } else { - if (eglMakeCurrent(old->dpy, old->draw, old->read, old->ctx)) { - return; - } - } - - EGL_ERROR("Failed to make old EGL context current! (%p, %p, %p, %p)", old->dpy, old->draw, old->read, old->ctx); -} - - /* * * Functions. From c1ac7fc6790cd030e004df1de8ec0452cdc7d53f Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 28 Apr 2021 13:50:58 +0100 Subject: [PATCH 535/883] c/client: s/comp_egl_glue.c/comp_egl_client.c (NFC) --- src/xrt/compositor/CMakeLists.txt | 2 +- .../compositor/client/{comp_egl_glue.c => comp_egl_client.c} | 0 src/xrt/compositor/meson.build | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/xrt/compositor/client/{comp_egl_glue.c => comp_egl_client.c} (100%) diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index d85691e44..dd4ce3a7f 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -87,7 +87,7 @@ if(XRT_HAVE_OPENGL AND XRT_HAVE_XLIB) endif() if(XRT_HAVE_EGL) list(APPEND CLIENT_SOURCE_FILES - client/comp_egl_glue.c + client/comp_egl_client.c ) endif() diff --git a/src/xrt/compositor/client/comp_egl_glue.c b/src/xrt/compositor/client/comp_egl_client.c similarity index 100% rename from src/xrt/compositor/client/comp_egl_glue.c rename to src/xrt/compositor/client/comp_egl_client.c diff --git a/src/xrt/compositor/meson.build b/src/xrt/compositor/meson.build index 7caf395d3..2ac4479c0 100644 --- a/src/xrt/compositor/meson.build +++ b/src/xrt/compositor/meson.build @@ -101,7 +101,7 @@ endif if build_egl compositor_srcs += [ - 'client/comp_egl_glue.c', + 'client/comp_egl_client.c', ] compositor_deps += [egl] endif From 35beaeead421ffcd9a88205e6584af55220f8415 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 3 May 2021 23:22:19 +0100 Subject: [PATCH 536/883] c/client: Add EGL comment (NFC) --- src/xrt/compositor/client/comp_egl_client.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/xrt/compositor/client/comp_egl_client.c b/src/xrt/compositor/client/comp_egl_client.c index f2b227dff..77b35deec 100644 --- a/src/xrt/compositor/client/comp_egl_client.c +++ b/src/xrt/compositor/client/comp_egl_client.c @@ -123,7 +123,10 @@ old_restore(struct old_helper *old, EGLDisplay current_dpy) */ /*! - * EGL based compositor. + * EGL based compositor, carries the extra needed EGL information needed by the + * client side code and can handle both GL Desktop or GLES contexts. + * + * @ingroup comp_client */ struct client_egl_compositor { From d384c90104d9a86a5ab977c05c4677afb2e26cb6 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Fri, 7 May 2021 00:34:47 +0200 Subject: [PATCH 537/883] st/oxr: Check that VkPhysicalDevice in graphics binding matches suggested device XR_KHR_vulkan_enable2: physicalDevice VkPhysicalDevice must match the device specified by xrGetVulkanGraphicsDevice2KHR XR_KHR_vulkan_enable: physicalDevice VkPhysicalDevice must match the device specified by xrGetVulkanGraphicsDeviceKHR XR_KHR_vulkan_enable: Add a trivial check that xrGetVulkanGraphicsDeviceKHR is called before xrCreateSession. (our cached suggested device will be XR_NULL_HANDLE if it has not been called). The XR_KHR_vulkan_enable2 code path already contains this check. --- src/xrt/state_trackers/oxr/oxr_api_system.c | 4 ++-- src/xrt/state_trackers/oxr/oxr_objects.h | 4 +++- src/xrt/state_trackers/oxr/oxr_session.c | 15 +++++++++++++++ src/xrt/state_trackers/oxr/oxr_system.c | 2 +- src/xrt/state_trackers/oxr/oxr_vulkan.c | 5 ++++- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_api_system.c b/src/xrt/state_trackers/oxr/oxr_api_system.c index 96a7a800a..ef3f24e5f 100644 --- a/src/xrt/state_trackers/oxr/oxr_api_system.c +++ b/src/xrt/state_trackers/oxr/oxr_api_system.c @@ -403,10 +403,10 @@ oxr_xrCreateVulkanDeviceKHR(XrInstance instance, // VK_NULL_HANDLE is 0 OXR_VERIFY_ARG_NOT_NULL(&log, createInfo->vulkanPhysicalDevice); - OXR_VERIFY_ARG_NOT_NULL(&log, sys->vulkan_enable2_physical_device); + OXR_VERIFY_ARG_NOT_NULL(&log, sys->suggested_vulkan_physical_device); OXR_VERIFY_ARG_NOT_NULL(&log, sys->vulkan_enable2_instance); - if (sys->vulkan_enable2_physical_device != createInfo->vulkanPhysicalDevice) { + if (sys->suggested_vulkan_physical_device != createInfo->vulkanPhysicalDevice) { return oxr_error(&log, XR_ERROR_HANDLE_INVALID, "createInfo->vulkanPhysicalDevice must be the device " "returned by xrGetVulkanGraphicsDeviceKHR"); diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index 036887ece..914fad391 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -1095,7 +1095,9 @@ struct oxr_system #ifdef XR_USE_GRAPHICS_API_VULKAN //! The instance/device we create when vulkan_enable2 is used VkInstance vulkan_enable2_instance; - VkPhysicalDevice vulkan_enable2_physical_device; + //! The device returned with the last xrGetVulkanGraphicsDeviceKHR or xrGetVulkanGraphicsDevice2KHR call. + //! XR_NULL_HANDLE if neither has been called. + VkPhysicalDevice suggested_vulkan_physical_device; #endif }; diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index aafdb67c5..53f4eeaa9 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -2048,6 +2048,21 @@ oxr_session_create_impl(struct oxr_logger *log, "xrGetVulkanGraphicsRequirementsKHR"); } + if (sys->suggested_vulkan_physical_device == VK_NULL_HANDLE) { + char *fn = sys->inst->extensions.KHR_vulkan_enable ? "xrGetVulkanGraphicsDeviceKHR" + : "xrGetVulkanGraphicsDevice2KHR"; + return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "Has not called %s", fn); + } + + if (sys->suggested_vulkan_physical_device != vulkan->physicalDevice) { + char *fn = sys->inst->extensions.KHR_vulkan_enable ? "xrGetVulkanGraphicsDeviceKHR" + : "xrGetVulkanGraphicsDevice2KHR"; + return oxr_error( + log, XR_ERROR_VALIDATION_FAILURE, + "XrGraphicsBindingVulkanKHR::physicalDevice %p must match device %p specified by %s", + (void *)vulkan->physicalDevice, (void *)sys->suggested_vulkan_physical_device, fn); + } + OXR_SESSION_ALLOCATE(log, sys, *out_session); OXR_ALLOCATE_NATIVE_COMPOSITOR(log, xsi, *out_session); return oxr_session_populate_vk(log, sys, vulkan, *out_session); diff --git a/src/xrt/state_trackers/oxr/oxr_system.c b/src/xrt/state_trackers/oxr/oxr_system.c index 1b14a1525..79f314dde 100644 --- a/src/xrt/state_trackers/oxr/oxr_system.c +++ b/src/xrt/state_trackers/oxr/oxr_system.c @@ -101,7 +101,7 @@ oxr_system_fill_in(struct oxr_logger *log, struct oxr_instance *inst, XrSystemId #ifdef XR_USE_GRAPHICS_API_VULKAN sys->vulkan_enable2_instance = VK_NULL_HANDLE; - sys->vulkan_enable2_physical_device = VK_NULL_HANDLE; + sys->suggested_vulkan_physical_device = VK_NULL_HANDLE; #endif // Headless. diff --git a/src/xrt/state_trackers/oxr/oxr_vulkan.c b/src/xrt/state_trackers/oxr/oxr_vulkan.c index 6cc93d0f7..4d6498543 100644 --- a/src/xrt/state_trackers/oxr/oxr_vulkan.c +++ b/src/xrt/state_trackers/oxr/oxr_vulkan.c @@ -369,7 +369,10 @@ oxr_vk_get_physical_device(struct oxr_logger *log, // vulkan_enable2 needs the physical device in xrCreateVulkanDeviceKHR if (inst->extensions.KHR_vulkan_enable2) { sys->vulkan_enable2_instance = vkInstance; - sys->vulkan_enable2_physical_device = *vkPhysicalDevice; + } + sys->suggested_vulkan_physical_device = *vkPhysicalDevice; + if (ll <= U_LOGGING_DEBUG) { + oxr_log(log, "Suggesting vulkan physical device %p", (void *)*vkPhysicalDevice); } free(phys); From e8b4059de91394195b5a94133b28fb890248d2d2 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Mon, 10 May 2021 10:01:46 -0500 Subject: [PATCH 538/883] meson: use c++17 --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 28983ffe9..138d7dd87 100644 --- a/meson.build +++ b/meson.build @@ -9,6 +9,7 @@ project( meson_version: '>=0.49.0', default_options: [ 'c_std=c11', + 'cpp_std=c++17', 'warning_level=3', ], ) From 886a87e5effd4488ac536711f5e35450c9a1a127 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Mon, 10 May 2021 10:05:09 -0500 Subject: [PATCH 539/883] meson: add option for tracing --- meson_options.txt | 6 ++++++ src/xrt/include/xrt/meson.build | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/meson_options.txt b/meson_options.txt index 5953c21f1..1adbd5bee 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -93,6 +93,12 @@ option('service', description: 'Enable separate service module for OpenXR runtime' ) +option('tracing', + type: 'boolean', + value: false, + description: 'Enable Perfetto/Percetto tracing' +) + option('layer_depth', type: 'boolean', value: true, diff --git a/src/xrt/include/xrt/meson.build b/src/xrt/include/xrt/meson.build index 40e005f49..e33c3bb53 100644 --- a/src/xrt/include/xrt/meson.build +++ b/src/xrt/include/xrt/meson.build @@ -124,6 +124,10 @@ if get_option('service') build_conf.set('XRT_FEATURE_SERVICE', true) endif +if get_option('tracing') + build_conf.set('XRT_FEATURE_TRACING', true) +endif + if get_option('color_log') build_conf.set('XRT_FEATURE_COLOR_LOG', true) endif From 4ff7fb74ff27eb8b44476d7009af38c8f89af4b7 Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Mon, 10 May 2021 10:00:49 -0500 Subject: [PATCH 540/883] aux/util: only do tracing things if XRT_FEATURE_TRACING is enabled --- src/xrt/auxiliary/util/u_timing_render.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xrt/auxiliary/util/u_timing_render.c b/src/xrt/auxiliary/util/u_timing_render.c index c9370db8a..c8e8120a8 100644 --- a/src/xrt/auxiliary/util/u_timing_render.c +++ b/src/xrt/auxiliary/util/u_timing_render.c @@ -350,6 +350,7 @@ rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) do_iir_filter(&rt->app.draw_time_ns, IIR_ALPHA_LT, IIR_ALPHA_GT, diff_draw_ns); // Trace the data. +#ifdef XRT_FEATURE_TRACING #define TE_BEG(TRACK, TIME, NAME) U_TRACE_EVENT_BEGIN_ON_TRACK_DATA(timing, TRACK, TIME, NAME, PERCETTO_I(f->frame_id)) #define TE_END(TRACK, TIME) U_TRACE_EVENT_END_ON_TRACK(timing, TRACK, TIME) @@ -367,6 +368,7 @@ rt_mark_delivered(struct u_render_timing *urt, int64_t frame_id) #undef TE_BEG #undef TE_END +#endif // Reset the frame. f->state = U_RT_READY; From 28a29f81527eb7332c0ff1f99af54d61eeabb77f Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Tue, 11 May 2021 00:54:02 +0200 Subject: [PATCH 541/883] st/oxr: Fix xrGetSystemProperties crash in headless mode fixes #125 v2: Handle sys->xsysc being NULL --- src/xrt/state_trackers/oxr/oxr_system.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/xrt/state_trackers/oxr/oxr_system.c b/src/xrt/state_trackers/oxr/oxr_system.c index 79f314dde..ff0bd76e6 100644 --- a/src/xrt/state_trackers/oxr/oxr_system.c +++ b/src/xrt/state_trackers/oxr/oxr_system.c @@ -194,9 +194,14 @@ oxr_system_get_properties(struct oxr_logger *log, struct oxr_system *sys, XrSyst snprintf(properties->systemName, XR_MAX_SYSTEM_NAME_SIZE, "Monado: %.*s", 247, xdev->str); // Get from compositor. - struct xrt_system_compositor_info *info = &sys->xsysc->info; + struct xrt_system_compositor_info *info = sys->xsysc ? &sys->xsysc->info : NULL; - properties->graphicsProperties.maxLayerCount = info->max_layers; + if (info) { + properties->graphicsProperties.maxLayerCount = info->max_layers; + } else { + // probably using the headless extension, but the extension does not modify the 16 layer minimum. + properties->graphicsProperties.maxLayerCount = 16; + } properties->graphicsProperties.maxSwapchainImageWidth = 1024 * 16; properties->graphicsProperties.maxSwapchainImageHeight = 1024 * 16; properties->trackingProperties.orientationTracking = xdev->orientation_tracking_supported; From 3af65d60d2d997d38f556bd4803d35d0b1a512e6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 1 May 2021 02:23:45 +0100 Subject: [PATCH 542/883] c/client: Follow style of using vk variable for vk_bundle interactions --- src/xrt/compositor/client/comp_vk_client.c | 51 ++++++++++++---------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/xrt/compositor/client/comp_vk_client.c b/src/xrt/compositor/client/comp_vk_client.c index 2f8498096..1c58bc4f0 100644 --- a/src/xrt/compositor/client/comp_vk_client.c +++ b/src/xrt/compositor/client/comp_vk_client.c @@ -49,15 +49,16 @@ client_vk_swapchain_destroy(struct xrt_swapchain *xsc) { struct client_vk_swapchain *sc = client_vk_swapchain(xsc); struct client_vk_compositor *c = sc->c; + struct vk_bundle *vk = &c->vk; for (uint32_t i = 0; i < sc->base.base.num_images; i++) { if (sc->base.images[i] != VK_NULL_HANDLE) { - c->vk.vkDestroyImage(c->vk.device, sc->base.images[i], NULL); + vk->vkDestroyImage(vk->device, sc->base.images[i], NULL); sc->base.images[i] = VK_NULL_HANDLE; } if (sc->mems[i] != VK_NULL_HANDLE) { - c->vk.vkFreeMemory(c->vk.device, sc->mems[i], NULL); + vk->vkFreeMemory(vk->device, sc->mems[i], NULL); sc->mems[i] = VK_NULL_HANDLE; } } @@ -148,18 +149,19 @@ static void client_vk_compositor_destroy(struct xrt_compositor *xc) { struct client_vk_compositor *c = client_vk_compositor(xc); + struct vk_bundle *vk = &c->vk; - if (c->vk.cmd_pool != VK_NULL_HANDLE) { + if (vk->cmd_pool != VK_NULL_HANDLE) { // Make sure that any of the command buffers from this command // pool are n used here, this pleases the validation layer. - os_mutex_lock(&c->vk.queue_mutex); - c->vk.vkDeviceWaitIdle(c->vk.device); - os_mutex_unlock(&c->vk.queue_mutex); + os_mutex_lock(&vk->queue_mutex); + vk->vkDeviceWaitIdle(vk->device); + os_mutex_unlock(&vk->queue_mutex); - c->vk.vkDestroyCommandPool(c->vk.device, c->vk.cmd_pool, NULL); - c->vk.cmd_pool = VK_NULL_HANDLE; + vk->vkDestroyCommandPool(vk->device, vk->cmd_pool, NULL); + vk->cmd_pool = VK_NULL_HANDLE; } - vk_deinit_mutex(&c->vk); + vk_deinit_mutex(vk); free(c); } @@ -361,6 +363,7 @@ client_vk_swapchain_create(struct xrt_compositor *xc, struct xrt_swapchain **out_xsc) { struct client_vk_compositor *c = client_vk_compositor(xc); + struct vk_bundle *vk = &c->vk; VkCommandBuffer cmd_buffer; VkResult ret; xrt_result_t xret; @@ -375,7 +378,7 @@ client_vk_swapchain_create(struct xrt_compositor *xc, struct xrt_swapchain *xsc = &xscn->base; - ret = vk_init_cmd_buffer(&c->vk, &cmd_buffer); + ret = vk_init_cmd_buffer(vk, &cmd_buffer); if (ret != VK_SUCCESS) { return XRT_ERROR_VULKAN; } @@ -399,7 +402,7 @@ client_vk_swapchain_create(struct xrt_compositor *xc, sc->xscn = xscn; for (uint32_t i = 0; i < xsc->num_images; i++) { - ret = vk_create_image_from_native(&c->vk, info, &xscn->images[i], &sc->base.images[i], &sc->mems[i]); + ret = vk_create_image_from_native(vk, info, &xscn->images[i], &sc->base.images[i], &sc->mems[i]); if (ret != VK_SUCCESS) { @@ -411,11 +414,11 @@ client_vk_swapchain_create(struct xrt_compositor *xc, * not be a bug in the validation layer. That may or may not be * fixed in the future version of the validation layer. */ - vk_set_image_layout(&c->vk, cmd_buffer, sc->base.images[i], 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + vk_set_image_layout(vk, cmd_buffer, sc->base.images[i], 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, subresource_range); } - ret = vk_submit_cmd_buffer(&c->vk, cmd_buffer); + ret = vk_submit_cmd_buffer(vk, cmd_buffer); if (ret != VK_SUCCESS) { return XRT_ERROR_FAILED_TO_SUBMIT_VULKAN_COMMANDS; } @@ -423,11 +426,11 @@ client_vk_swapchain_create(struct xrt_compositor *xc, // Prerecord command buffers for swapchain image ownership/layout // transitions for (uint32_t i = 0; i < xsc->num_images; i++) { - ret = vk_init_cmd_buffer(&c->vk, &sc->acquire[i]); + ret = vk_init_cmd_buffer(vk, &sc->acquire[i]); if (ret != VK_SUCCESS) { return XRT_ERROR_VULKAN; } - ret = vk_init_cmd_buffer(&c->vk, &sc->release[i]); + ret = vk_init_cmd_buffer(vk, &sc->release[i]); if (ret != VK_SUCCESS) { return XRT_ERROR_VULKAN; } @@ -474,26 +477,26 @@ client_vk_swapchain_create(struct xrt_compositor *xc, .dstAccessMask = 0, .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - .srcQueueFamilyIndex = c->vk.queue_family_index, + .srcQueueFamilyIndex = vk->queue_family_index, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL, .image = sc->base.images[i], .subresourceRange = subresource_range, }; //! @todo less conservative pipeline stage masks based on usage - c->vk.vkCmdPipelineBarrier(sc->acquire[i], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 0, NULL, 1, &acquire); - c->vk.vkCmdPipelineBarrier(sc->release[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &release); + vk->vkCmdPipelineBarrier(sc->acquire[i], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 0, NULL, 1, &acquire); + vk->vkCmdPipelineBarrier(sc->release[i], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &release); - ret = c->vk.vkEndCommandBuffer(sc->acquire[i]); + ret = vk->vkEndCommandBuffer(sc->acquire[i]); if (ret != VK_SUCCESS) { - VK_ERROR((&c->vk), "vkEndCommandBuffer: %s", vk_result_string(ret)); + VK_ERROR(vk, "vkEndCommandBuffer: %s", vk_result_string(ret)); return XRT_ERROR_VULKAN; } - ret = c->vk.vkEndCommandBuffer(sc->release[i]); + ret = vk->vkEndCommandBuffer(sc->release[i]); if (ret != VK_SUCCESS) { - VK_ERROR((&c->vk), "vkEndCommandBuffer: %s", vk_result_string(ret)); + VK_ERROR(vk, "vkEndCommandBuffer: %s", vk_result_string(ret)); return XRT_ERROR_VULKAN; } } From bd6e15c70c70ae4ec268760c352fb12732c8119f Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 1 May 2021 03:00:07 +0100 Subject: [PATCH 543/883] c/main: Follow style of using vk variable for vk_bundle interactions --- src/xrt/compositor/main/comp_compositor.c | 46 ++++--- src/xrt/compositor/main/comp_layer.c | 116 ++++++++++++------ src/xrt/compositor/main/comp_renderer.c | 9 +- src/xrt/compositor/main/comp_swapchain.c | 23 ++-- .../compositor/main/comp_target_swapchain.c | 23 ++-- .../main/comp_window_direct_nvidia.c | 3 +- .../compositor/main/comp_window_vk_display.c | 3 +- 7 files changed, 131 insertions(+), 92 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 2c0c337f4..e13132820 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -559,7 +559,7 @@ compositor_destroy(struct xrt_compositor *xc) comp_resources_close(c, &c->nr); // As long as vk_bundle is valid it's safe to call this function. - comp_shaders_close(&c->vk, &c->shaders); + comp_shaders_close(vk, &c->shaders); // Does NULL checking. comp_target_destroy(&c->target); @@ -645,21 +645,10 @@ compositor_check_and_prepare_xdev(struct comp_compositor *c, struct xrt_device * * */ -#define GET_DEV_PROC(c, name) (PFN_##name) c->vk.vkGetDeviceProcAddr(c->vk.device, #name); -#define GET_INS_PROC(c, name) (PFN_##name) c->vk.vkGetInstanceProcAddr(c->vk.instance, #name); -#define GET_DEV_PROC(c, name) (PFN_##name) c->vk.vkGetDeviceProcAddr(c->vk.device, #name); - // NOLINTNEXTLINE // don't remove the forward decl. VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *pName); -static VkResult -find_get_instance_proc_addr(struct comp_compositor *c) -{ - //! @todo Do any library loading here. - return vk_get_loader_functions(&c->vk, vkGetInstanceProcAddr); -} - // If any of these lists are updated, please also update the appropriate column // in `vulkan-extensions.md` @@ -809,6 +798,7 @@ select_instances_extensions(struct comp_compositor *c, const char ***out_exts, u static VkResult create_instance(struct comp_compositor *c) { + struct vk_bundle *vk = &c->vk; const char **instance_extensions; uint32_t num_extensions; VkResult ret; @@ -833,13 +823,13 @@ create_instance(struct comp_compositor *c) .ppEnabledExtensionNames = instance_extensions, }; - ret = c->vk.vkCreateInstance(&instance_info, NULL, &c->vk.instance); + ret = vk->vkCreateInstance(&instance_info, NULL, &vk->instance); if (ret != VK_SUCCESS) { CVK_ERROR(c, "vkCreateInstance", "Failed to create Vulkan instance", ret); return ret; } - ret = vk_get_instance_functions(&c->vk); + ret = vk_get_instance_functions(vk); if (ret != VK_SUCCESS) { CVK_ERROR(c, "vk_get_instance_functions", "Failed to get Vulkan instance functions.", ret); return ret; @@ -873,13 +863,15 @@ get_device_uuid(struct vk_bundle *vk, struct comp_compositor *c, int gpu_index, static bool compositor_init_vulkan(struct comp_compositor *c) { + struct vk_bundle *vk = &c->vk; VkResult ret; - c->vk.ll = c->settings.log_level; + vk->ll = c->settings.log_level; - ret = find_get_instance_proc_addr(c); + //! @todo Do any library loading here. + ret = vk_get_loader_functions(vk, vkGetInstanceProcAddr); if (ret != VK_SUCCESS) { - CVK_ERROR(c, "find_get_instance_proc_addr", "Failed to get VkInstance get process address.", ret); + CVK_ERROR(c, "vk_get_loader_functions", "Failed to get VkInstance get process address.", ret); return false; } @@ -904,7 +896,7 @@ compositor_init_vulkan(struct comp_compositor *c) // No other way then to try to see if realtime is available. for (size_t i = 0; i < ARRAY_SIZE(prios); i++) { ret = vk_create_device( // - &c->vk, // + vk, // c->settings.selected_gpu_index, // prios[i], // global_priority required_device_extensions, // @@ -928,17 +920,17 @@ compositor_init_vulkan(struct comp_compositor *c) return false; } - ret = vk_init_mutex(&c->vk); + ret = vk_init_mutex(vk); if (ret != VK_SUCCESS) { CVK_ERROR(c, "vk_init_mutex", "Failed to init mutex.", ret); return false; } - c->settings.selected_gpu_index = c->vk.physical_device_index; + c->settings.selected_gpu_index = vk->physical_device_index; // store physical device UUID for compositor in settings if (c->settings.selected_gpu_index >= 0) { - if (get_device_uuid(&c->vk, c, c->settings.selected_gpu_index, c->settings.selected_gpu_deviceUUID)) { + if (get_device_uuid(vk, c, c->settings.selected_gpu_index, c->settings.selected_gpu_deviceUUID)) { char uuid_str[XRT_GPU_UUID_SIZE * 3 + 1] = {0}; for (int i = 0; i < XRT_GPU_UUID_SIZE; i++) { sprintf(uuid_str + i * 3, "%02x ", c->settings.selected_gpu_deviceUUID[i]); @@ -956,7 +948,7 @@ compositor_init_vulkan(struct comp_compositor *c) // store physical device UUID suggested to clients in settings if (c->settings.client_gpu_index >= 0) { - if (get_device_uuid(&c->vk, c, c->settings.client_gpu_index, c->settings.client_gpu_deviceUUID)) { + if (get_device_uuid(vk, c, c->settings.client_gpu_index, c->settings.client_gpu_deviceUUID)) { char uuid_str[XRT_GPU_UUID_SIZE * 3 + 1] = {0}; for (int i = 0; i < XRT_GPU_UUID_SIZE; i++) { sprintf(uuid_str + i * 3, "%02x ", c->settings.client_gpu_deviceUUID[i]); @@ -967,7 +959,7 @@ compositor_init_vulkan(struct comp_compositor *c) } } - ret = vk_init_cmd_pool(&c->vk); + ret = vk_init_cmd_pool(vk); if (ret != VK_SUCCESS) { CVK_ERROR(c, "vk_init_cmd_pool", "Failed to init command pool.", ret); return false; @@ -1295,7 +1287,9 @@ compositor_init_swapchain(struct comp_compositor *c) static bool compositor_init_shaders(struct comp_compositor *c) { - return comp_shaders_load(&c->vk, &c->shaders); + struct vk_bundle *vk = &c->vk; + + return comp_shaders_load(vk, &c->shaders); } static bool @@ -1312,8 +1306,10 @@ compositor_init_renderer(struct comp_compositor *c) bool comp_is_format_supported(struct comp_compositor *c, VkFormat format) { + struct vk_bundle *vk = &c->vk; VkFormatProperties prop; - c->vk.vkGetPhysicalDeviceFormatProperties(c->vk.physical_device, format, &prop); + + vk->vkGetPhysicalDeviceFormatProperties(vk->physical_device, format, &prop); // This is a fairly crude way of checking support, // but works well enough. diff --git a/src/xrt/compositor/main/comp_layer.c b/src/xrt/compositor/main/comp_layer.c index bb57ca70f..0ea9278d4 100644 --- a/src/xrt/compositor/main/comp_layer.c +++ b/src/xrt/compositor/main/comp_layer.c @@ -51,18 +51,25 @@ _update_mvp_matrix(struct comp_render_layer *self, uint32_t eye, const struct xr static bool _init_ubos(struct comp_render_layer *self) { + struct vk_bundle *vk = self->vk; + VkBufferUsageFlags usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; for (uint32_t i = 0; i < 2; i++) { math_matrix_4x4_identity(&self->transformation[i].mvp); - if (!vk_buffer_init(self->vk, sizeof(struct layer_transformation), usage, properties, - &self->transformation_ubos[i].handle, &self->transformation_ubos[i].memory)) + if (!vk_buffer_init(vk, // + sizeof(struct layer_transformation), // + usage, // + properties, // + &self->transformation_ubos[i].handle, // + &self->transformation_ubos[i].memory)) { return false; + } - VkResult res = self->vk->vkMapMemory(self->vk->device, self->transformation_ubos[i].memory, 0, - VK_WHOLE_SIZE, 0, &self->transformation_ubos[i].data); + VkResult res = vk->vkMapMemory(vk->device, self->transformation_ubos[i].memory, 0, VK_WHOLE_SIZE, 0, + &self->transformation_ubos[i].data); vk_check_error("vkMapMemory", res, false); memcpy(self->transformation_ubos[i].data, &self->transformation[i], @@ -75,15 +82,22 @@ _init_ubos(struct comp_render_layer *self) static bool _init_equirect1_ubo(struct comp_render_layer *self) { + struct vk_bundle *vk = self->vk; + VkBufferUsageFlags usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - if (!vk_buffer_init(self->vk, sizeof(struct layer_transformation), usage, properties, - &self->equirect1_ubo.handle, &self->equirect1_ubo.memory)) + if (!vk_buffer_init(vk, // + sizeof(struct layer_transformation), // + usage, // + properties, // + &self->equirect1_ubo.handle, // + &self->equirect1_ubo.memory)) { return false; + } - VkResult res = self->vk->vkMapMemory(self->vk->device, self->equirect1_ubo.memory, 0, VK_WHOLE_SIZE, 0, - &self->equirect1_ubo.data); + VkResult res = + vk->vkMapMemory(vk->device, self->equirect1_ubo.memory, 0, VK_WHOLE_SIZE, 0, &self->equirect1_ubo.data); vk_check_error("vkMapMemory", res, false); memcpy(self->equirect1_ubo.data, &self->equirect1_data, sizeof(struct layer_equirect1_data)); @@ -95,15 +109,22 @@ _init_equirect1_ubo(struct comp_render_layer *self) static bool _init_equirect2_ubo(struct comp_render_layer *self) { + struct vk_bundle *vk = self->vk; + VkBufferUsageFlags usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - if (!vk_buffer_init(self->vk, sizeof(struct layer_transformation), usage, properties, - &self->equirect2_ubo.handle, &self->equirect2_ubo.memory)) + if (!vk_buffer_init(vk, // + sizeof(struct layer_transformation), // + usage, // + properties, // + &self->equirect2_ubo.handle, // + &self->equirect2_ubo.memory)) { return false; + } - VkResult res = self->vk->vkMapMemory(self->vk->device, self->equirect2_ubo.memory, 0, VK_WHOLE_SIZE, 0, - &self->equirect2_ubo.data); + VkResult res = + vk->vkMapMemory(vk->device, self->equirect2_ubo.memory, 0, VK_WHOLE_SIZE, 0, &self->equirect2_ubo.data); vk_check_error("vkMapMemory", res, false); memcpy(self->equirect2_ubo.data, &self->equirect2_data, sizeof(struct layer_equirect2_data)); @@ -159,6 +180,8 @@ _update_descriptor(struct comp_render_layer *self, static void _update_descriptor_equirect(struct comp_render_layer *self, VkDescriptorSet set, VkBuffer buffer) { + struct vk_bundle *vk = self->vk; + VkWriteDescriptorSet *sets = (VkWriteDescriptorSet[]){ { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, @@ -176,16 +199,19 @@ _update_descriptor_equirect(struct comp_render_layer *self, VkDescriptorSet set, }, }; - self->vk->vkUpdateDescriptorSets(self->vk->device, 1, sets, 0, NULL); + vk->vkUpdateDescriptorSets(vk->device, 1, sets, 0, NULL); } #endif void comp_layer_update_descriptors(struct comp_render_layer *self, VkSampler sampler, VkImageView image_view) { - for (uint32_t eye = 0; eye < 2; eye++) - _update_descriptor(self, self->vk, self->descriptor_sets[eye], self->transformation_ubos[eye].handle, - sampler, image_view); + struct vk_bundle *vk = self->vk; + + for (uint32_t eye = 0; eye < 2; eye++) { + _update_descriptor(self, vk, self->descriptor_sets[eye], self->transformation_ubos[eye].handle, sampler, + image_view); + } } #ifdef XRT_FEATURE_OPENXR_LAYER_EQUIRECT1 @@ -225,10 +251,12 @@ comp_layer_update_stereo_descriptors(struct comp_render_layer *self, VkImageView left_image_view, VkImageView right_image_view) { - _update_descriptor(self, self->vk, self->descriptor_sets[0], self->transformation_ubos[0].handle, left_sampler, + struct vk_bundle *vk = self->vk; + + _update_descriptor(self, vk, self->descriptor_sets[0], self->transformation_ubos[0].handle, left_sampler, left_image_view); - _update_descriptor(self, self->vk, self->descriptor_sets[1], self->transformation_ubos[1].handle, right_sampler, + _update_descriptor(self, vk, self->descriptor_sets[1], self->transformation_ubos[1].handle, right_sampler, right_image_view); } @@ -268,17 +296,15 @@ _init(struct comp_render_layer *self, }, }; - if (!vk_init_descriptor_pool(self->vk, pool_sizes, ARRAY_SIZE(pool_sizes), 3, &self->descriptor_pool)) + if (!vk_init_descriptor_pool(vk, pool_sizes, ARRAY_SIZE(pool_sizes), 3, &self->descriptor_pool)) return false; for (uint32_t eye = 0; eye < 2; eye++) - if (!vk_allocate_descriptor_sets(self->vk, self->descriptor_pool, 1, layout, - &self->descriptor_sets[eye])) + if (!vk_allocate_descriptor_sets(vk, self->descriptor_pool, 1, layout, &self->descriptor_sets[eye])) return false; #if defined(XRT_FEATURE_OPENXR_LAYER_EQUIRECT1) || defined(XRT_FEATURE_OPENXR_LAYER_EQUIRECT2) - if (!vk_allocate_descriptor_sets(self->vk, self->descriptor_pool, 1, layout_equirect, - &self->descriptor_equirect)) + if (!vk_allocate_descriptor_sets(vk, self->descriptor_pool, 1, layout_equirect, &self->descriptor_equirect)) return false; #endif return true; @@ -294,6 +320,8 @@ comp_layer_draw(struct comp_render_layer *self, const struct xrt_matrix_4x4 *vp_world, const struct xrt_matrix_4x4 *vp_eye) { + struct vk_bundle *vk = self->vk; + if (eye == 0 && (self->visibility & XRT_LAYER_EYE_VISIBILITY_LEFT_BIT) == 0) { return; } @@ -302,7 +330,7 @@ comp_layer_draw(struct comp_render_layer *self, return; } - self->vk->vkCmdBindPipeline(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + vk->vkCmdBindPipeline(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); // Is this layer viewspace or not. const struct xrt_matrix_4x4 *vp = self->view_space ? vp_eye : vp_world; @@ -326,18 +354,18 @@ comp_layer_draw(struct comp_render_layer *self, self->descriptor_equirect, }; - self->vk->vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, - sets, 0, NULL); + vk->vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, sets, 0, + NULL); } else { - self->vk->vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, - &self->descriptor_sets[eye], 0, NULL); + vk->vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, + &self->descriptor_sets[eye], 0, NULL); } VkDeviceSize offsets[1] = {0}; - self->vk->vkCmdBindVertexBuffers(cmd_buffer, 0, 1, &vertex_buffer->handle, &offsets[0]); + vk->vkCmdBindVertexBuffers(cmd_buffer, 0, 1, &vertex_buffer->handle, &offsets[0]); - self->vk->vkCmdDraw(cmd_buffer, vertex_buffer->size, 1, 0, 0); + vk->vkCmdDraw(cmd_buffer, vertex_buffer->size, 1, 0, 0); } // clang-format off @@ -444,11 +472,17 @@ _init_cylinder_vertex_buffer(struct comp_render_layer *self) VkBufferUsageFlags usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - if (!vk_buffer_init(vk, sizeof(float) * ARRAY_SIZE(cylinder_vertices), usage, properties, - &self->cylinder.vertex_buffer.handle, &self->cylinder.vertex_buffer.memory)) + if (!vk_buffer_init(vk, // + sizeof(float) * ARRAY_SIZE(cylinder_vertices), // + usage, // + properties, // + &self->cylinder.vertex_buffer.handle, // + &self->cylinder.vertex_buffer.memory)) { return false; + } self->cylinder.vertex_buffer.size = CYLINDER_VERTICES; + return true; } @@ -465,8 +499,9 @@ comp_layer_create(struct vk_bundle *vk, VkDescriptorSetLayout *layout, VkDescrip _init(q, vk, layout, layout_equirect); - if (!_init_cylinder_vertex_buffer(q)) + if (!_init_cylinder_vertex_buffer(q)) { return NULL; + } return q; } @@ -474,18 +509,21 @@ comp_layer_create(struct vk_bundle *vk, VkDescriptorSetLayout *layout, VkDescrip void comp_layer_destroy(struct comp_render_layer *self) { - for (uint32_t eye = 0; eye < 2; eye++) - vk_buffer_destroy(&self->transformation_ubos[eye], self->vk); + struct vk_bundle *vk = self->vk; + + for (uint32_t eye = 0; eye < 2; eye++) { + vk_buffer_destroy(&self->transformation_ubos[eye], vk); + } #ifdef XRT_FEATURE_OPENXR_LAYER_EQUIRECT1 - vk_buffer_destroy(&self->equirect1_ubo, self->vk); + vk_buffer_destroy(&self->equirect1_ubo, vk); #endif #ifdef XRT_FEATURE_OPENXR_LAYER_EQUIRECT2 - vk_buffer_destroy(&self->equirect2_ubo, self->vk); + vk_buffer_destroy(&self->equirect2_ubo, vk); #endif - self->vk->vkDestroyDescriptorPool(self->vk->device, self->descriptor_pool, NULL); + vk->vkDestroyDescriptorPool(vk->device, self->descriptor_pool, NULL); - vk_buffer_destroy(&self->cylinder.vertex_buffer, self->vk); + vk_buffer_destroy(&self->cylinder.vertex_buffer, vk); free(self); } diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c index 12fce0af9..7e5a3464f 100644 --- a/src/xrt/compositor/main/comp_renderer.c +++ b/src/xrt/compositor/main/comp_renderer.c @@ -103,10 +103,11 @@ static void renderer_wait_gpu_idle(struct comp_renderer *r) { COMP_TRACE_MARKER(); + struct vk_bundle *vk = &r->c->vk; - os_mutex_lock(&r->c->vk.queue_mutex); - r->c->vk.vkDeviceWaitIdle(r->c->vk.device); - os_mutex_unlock(&r->c->vk.queue_mutex); + os_mutex_lock(&vk->queue_mutex); + vk->vkDeviceWaitIdle(vk->device); + os_mutex_unlock(&vk->queue_mutex); } static void @@ -453,7 +454,7 @@ renderer_create(struct comp_renderer *r, struct comp_compositor *c) struct vk_bundle *vk = &r->c->vk; - vk->vkGetDeviceQueue(vk->device, r->c->vk.queue_family_index, 0, &r->queue); + vk->vkGetDeviceQueue(vk->device, vk->queue_family_index, 0, &r->queue); renderer_init_semaphores(r); // Try to early-allocate these, in case we can. diff --git a/src/xrt/compositor/main/comp_swapchain.c b/src/xrt/compositor/main/comp_swapchain.c index 49ac6f0c1..0bfd7fa58 100644 --- a/src/xrt/compositor/main/comp_swapchain.c +++ b/src/xrt/compositor/main/comp_swapchain.c @@ -132,6 +132,7 @@ do_post_create_vulkan_setup(struct comp_compositor *c, const struct xrt_swapchain_create_info *info, struct comp_swapchain *sc) { + struct vk_bundle *vk = &c->vk; uint32_t num_images = sc->vkic.num_images; VkCommandBuffer cmd_buffer; @@ -172,9 +173,9 @@ do_post_create_vulkan_setup(struct comp_compositor *c, sc->images[i].views.no_alpha = U_TYPED_ARRAY_CALLOC(VkImageView, info->array_size); sc->images[i].array_size = info->array_size; - vk_create_sampler(&c->vk, VK_SAMPLER_ADDRESS_MODE_REPEAT, &sc->images[i].repeat_sampler); + vk_create_sampler(vk, VK_SAMPLER_ADDRESS_MODE_REPEAT, &sc->images[i].repeat_sampler); - vk_create_sampler(&c->vk, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, &sc->images[i].sampler); + vk_create_sampler(vk, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, &sc->images[i].sampler); for (uint32_t layer = 0; layer < info->array_size; ++layer) { @@ -186,9 +187,9 @@ do_post_create_vulkan_setup(struct comp_compositor *c, .layerCount = 1, }; - vk_create_view(&c->vk, sc->vkic.images[i].handle, (VkFormat)info->format, subresource_range, + vk_create_view(vk, sc->vkic.images[i].handle, (VkFormat)info->format, subresource_range, &sc->images[i].views.alpha[layer]); - vk_create_view_swizzle(&c->vk, sc->vkic.images[i].handle, format, subresource_range, components, + vk_create_view_swizzle(vk, sc->vkic.images[i].handle, format, subresource_range, components, &sc->images[i].views.no_alpha[layer]); } } @@ -205,7 +206,7 @@ do_post_create_vulkan_setup(struct comp_compositor *c, * */ - vk_init_cmd_buffer(&c->vk, &cmd_buffer); + vk_init_cmd_buffer(vk, &cmd_buffer); VkImageSubresourceRange subresource_range = { .aspectMask = aspect, @@ -216,12 +217,12 @@ do_post_create_vulkan_setup(struct comp_compositor *c, }; for (uint32_t i = 0; i < num_images; i++) { - vk_set_image_layout(&c->vk, cmd_buffer, sc->vkic.images[i].handle, 0, VK_ACCESS_SHADER_READ_BIT, + vk_set_image_layout(vk, cmd_buffer, sc->vkic.images[i].handle, 0, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresource_range); } - vk_submit_cmd_buffer(&c->vk, cmd_buffer); + vk_submit_cmd_buffer(vk, cmd_buffer); } static void @@ -282,6 +283,7 @@ comp_swapchain_create(struct xrt_compositor *xc, struct xrt_swapchain **out_xsc) { struct comp_compositor *c = comp_compositor(xc); + struct vk_bundle *vk = &c->vk; uint32_t num_images = 3; VkResult ret; @@ -306,7 +308,7 @@ comp_swapchain_create(struct xrt_compositor *xc, vk_color_format_string(info->format)); // Use the image helper to allocate the images. - ret = vk_ic_allocate(&c->vk, info, num_images, &sc->vkic); + ret = vk_ic_allocate(vk, info, num_images, &sc->vkic); if (ret == VK_ERROR_FEATURE_NOT_PRESENT) { free(sc); return XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED; @@ -321,7 +323,7 @@ comp_swapchain_create(struct xrt_compositor *xc, xrt_graphics_buffer_handle_t handles[ARRAY_SIZE(sc->vkic.images)]; - vk_ic_get_handles(&c->vk, &sc->vkic, ARRAY_SIZE(handles), handles); + vk_ic_get_handles(vk, &sc->vkic, ARRAY_SIZE(handles), handles); for (uint32_t i = 0; i < sc->vkic.num_images; i++) { sc->base.images[i].handle = handles[i]; sc->base.images[i].size = sc->vkic.images[i].size; @@ -343,6 +345,7 @@ comp_swapchain_import(struct xrt_compositor *xc, struct xrt_swapchain **out_xsc) { struct comp_compositor *c = comp_compositor(xc); + struct vk_bundle *vk = &c->vk; VkResult ret; struct comp_swapchain *sc = alloc_and_set_funcs(c, num_images); @@ -350,7 +353,7 @@ comp_swapchain_import(struct xrt_compositor *xc, COMP_DEBUG(c, "CREATE FROM NATIVE %p %dx%d", (void *)sc, info->width, info->height); // Use the image helper to get the images. - ret = vk_ic_from_natives(&c->vk, info, native_images, num_images, &sc->vkic); + ret = vk_ic_from_natives(vk, info, native_images, num_images, &sc->vkic); if (ret != VK_SUCCESS) { return XRT_ERROR_VULKAN; } diff --git a/src/xrt/compositor/main/comp_target_swapchain.c b/src/xrt/compositor/main/comp_target_swapchain.c index 4999b8bd3..8b87d456a 100644 --- a/src/xrt/compositor/main/comp_target_swapchain.c +++ b/src/xrt/compositor/main/comp_target_swapchain.c @@ -586,8 +586,7 @@ static VkResult comp_target_swapchain_update_timings(struct comp_target *ct) { struct comp_target_swapchain *cts = (struct comp_target_swapchain *)ct; - struct comp_compositor *c = ct->c; - struct vk_bundle *vk = &c->vk; + struct vk_bundle *vk = get_vk(cts); if (!vk->has_GOOGLE_display_timing) { return VK_SUCCESS; @@ -598,21 +597,21 @@ comp_target_swapchain_update_timings(struct comp_target *ct) } uint32_t count = 0; - c->vk.vkGetPastPresentationTimingGOOGLE( // - vk->device, // - cts->swapchain.handle, // - &count, // - NULL); // + vk->vkGetPastPresentationTimingGOOGLE( // + vk->device, // + cts->swapchain.handle, // + &count, // + NULL); // if (count <= 0) { return VK_SUCCESS; } VkPastPresentationTimingGOOGLE *timings = U_TYPED_ARRAY_CALLOC(VkPastPresentationTimingGOOGLE, count); - c->vk.vkGetPastPresentationTimingGOOGLE( // - vk->device, // - cts->swapchain.handle, // - &count, // - timings); // + vk->vkGetPastPresentationTimingGOOGLE( // + vk->device, // + cts->swapchain.handle, // + &count, // + timings); // for (uint32_t i = 0; i < count; i++) { u_ft_info(cts->uft, // diff --git a/src/xrt/compositor/main/comp_window_direct_nvidia.c b/src/xrt/compositor/main/comp_window_direct_nvidia.c index b2c1eb035..8dd28d38e 100644 --- a/src/xrt/compositor/main/comp_window_direct_nvidia.c +++ b/src/xrt/compositor/main/comp_window_direct_nvidia.c @@ -163,9 +163,10 @@ static bool comp_window_direct_nvidia_init(struct comp_target *ct) { struct comp_window_direct_nvidia *w_direct = (struct comp_window_direct_nvidia *)ct; + struct vk_bundle *vk = &ct->c->vk; // Sanity check. - if (ct->c->vk.instance == VK_NULL_HANDLE) { + if (vk->instance == VK_NULL_HANDLE) { COMP_ERROR(ct->c, "Vulkan not initialized before NVIDIA init!"); return false; } diff --git a/src/xrt/compositor/main/comp_window_vk_display.c b/src/xrt/compositor/main/comp_window_vk_display.c index 9653b8db0..fc0dcecaf 100644 --- a/src/xrt/compositor/main/comp_window_vk_display.c +++ b/src/xrt/compositor/main/comp_window_vk_display.c @@ -152,9 +152,10 @@ static bool comp_window_vk_display_init(struct comp_target *ct) { struct comp_window_vk_display *w_direct = (struct comp_window_vk_display *)ct; + struct vk_bundle *vk = &ct->c->vk; // Sanity check. - if (ct->c->vk.instance == VK_NULL_HANDLE) { + if (vk->instance == VK_NULL_HANDLE) { COMP_ERROR(ct->c, "Vulkan not initialized before vk display init!"); return false; } From 9b6b5b7e6ac7d9d420ad49a2ad26f872eaaed829 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 1 May 2021 03:49:04 +0100 Subject: [PATCH 544/883] c/main: Do not copy vk_bundle --- src/xrt/compositor/main/comp_window_direct_nvidia.c | 9 +++------ src/xrt/compositor/main/comp_window_vk_display.c | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/xrt/compositor/main/comp_window_direct_nvidia.c b/src/xrt/compositor/main/comp_window_direct_nvidia.c index 8dd28d38e..b142c65f6 100644 --- a/src/xrt/compositor/main/comp_window_direct_nvidia.c +++ b/src/xrt/compositor/main/comp_window_direct_nvidia.c @@ -176,13 +176,10 @@ comp_window_direct_nvidia_init(struct comp_target *ct) return false; } - struct vk_bundle comp_vk = ct->c->vk; - // find our display using nvidia whitelist, enumerate its modes, and // pick the best one get a list of attached displays uint32_t display_count; - if (comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR(comp_vk.physical_device, &display_count, NULL) != - VK_SUCCESS) { + if (vk->vkGetPhysicalDeviceDisplayPropertiesKHR(vk->physical_device, &display_count, NULL) != VK_SUCCESS) { COMP_ERROR(ct->c, "Failed to get vulkan display count"); return false; } @@ -194,8 +191,8 @@ comp_window_direct_nvidia_init(struct comp_target *ct) struct VkDisplayPropertiesKHR *display_props = U_TYPED_ARRAY_CALLOC(VkDisplayPropertiesKHR, display_count); - if (display_props && comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR(comp_vk.physical_device, &display_count, - display_props) != VK_SUCCESS) { + if (display_props && vk->vkGetPhysicalDeviceDisplayPropertiesKHR(vk->physical_device, &display_count, + display_props) != VK_SUCCESS) { COMP_ERROR(ct->c, "Failed to get display properties"); free(display_props); return false; diff --git a/src/xrt/compositor/main/comp_window_vk_display.c b/src/xrt/compositor/main/comp_window_vk_display.c index fc0dcecaf..6ac900372 100644 --- a/src/xrt/compositor/main/comp_window_vk_display.c +++ b/src/xrt/compositor/main/comp_window_vk_display.c @@ -160,11 +160,8 @@ comp_window_vk_display_init(struct comp_target *ct) return false; } - struct vk_bundle comp_vk = ct->c->vk; - uint32_t display_count; - if (comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR(comp_vk.physical_device, &display_count, NULL) != - VK_SUCCESS) { + if (vk->vkGetPhysicalDeviceDisplayPropertiesKHR(vk->physical_device, &display_count, NULL) != VK_SUCCESS) { COMP_ERROR(ct->c, "Failed to get vulkan display count"); return false; } @@ -176,8 +173,8 @@ comp_window_vk_display_init(struct comp_target *ct) struct VkDisplayPropertiesKHR *display_props = U_TYPED_ARRAY_CALLOC(VkDisplayPropertiesKHR, display_count); - if (display_props && comp_vk.vkGetPhysicalDeviceDisplayPropertiesKHR(comp_vk.physical_device, &display_count, - display_props) != VK_SUCCESS) { + if (display_props && vk->vkGetPhysicalDeviceDisplayPropertiesKHR(vk->physical_device, &display_count, + display_props) != VK_SUCCESS) { COMP_ERROR(ct->c, "Failed to get display properties"); free(display_props); return false; From 13a5036b24ae690cb4693eb7508b48c8314196b0 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 1 May 2021 03:49:21 +0100 Subject: [PATCH 545/883] c/main: Make temp_vk be a pointer --- src/xrt/compositor/main/comp_compositor.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index e13132820..80e7592fd 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -1079,8 +1079,10 @@ compositor_check_vulkan_caps(struct comp_compositor *c) } COMP_DEBUG(c, "Checking for NVIDIA vulkan driver."); - struct vk_bundle temp_vk = {0}; - ret = vk_get_loader_functions(&temp_vk, vkGetInstanceProcAddr); + struct vk_bundle temp_vk_storage = {0}; + struct vk_bundle *temp_vk = &temp_vk_storage; + + ret = vk_get_loader_functions(temp_vk, vkGetInstanceProcAddr); if (ret != VK_SUCCESS) { CVK_ERROR(c, "vk_get_loader_functions", "Failed to get loader functions.", ret); return false; @@ -1095,13 +1097,13 @@ compositor_check_vulkan_caps(struct comp_compositor *c) .ppEnabledExtensionNames = extension_names, }; - ret = temp_vk.vkCreateInstance(&instance_create_info, NULL, &(temp_vk.instance)); + ret = temp_vk->vkCreateInstance(&instance_create_info, NULL, &(temp_vk->instance)); if (ret != VK_SUCCESS) { CVK_ERROR(c, "vkCreateInstance", "Failed to create VkInstance.", ret); return false; } - ret = vk_get_instance_functions(&temp_vk); + ret = vk_get_instance_functions(temp_vk); if (ret != VK_SUCCESS) { CVK_ERROR(c, "vk_get_instance_functions", "Failed to get Vulkan instance functions.", ret); return false; @@ -1109,7 +1111,7 @@ compositor_check_vulkan_caps(struct comp_compositor *c) // follow same device selection logic as subsequent calls ret = vk_create_device( // - &temp_vk, // + temp_vk, // c->settings.selected_gpu_index, // VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT, // global_priority required_device_extensions, // @@ -1122,13 +1124,13 @@ compositor_check_vulkan_caps(struct comp_compositor *c) return false; } - if (_test_for_nvidia(c, &temp_vk)) { + if (_test_for_nvidia(c, temp_vk)) { c->settings.window_type = WINDOW_DIRECT_NVIDIA; COMP_DEBUG(c, "Selecting direct NVIDIA window type!"); } - temp_vk.vkDestroyDevice(temp_vk.device, NULL); - temp_vk.vkDestroyInstance(temp_vk.instance, NULL); + temp_vk->vkDestroyDevice(temp_vk->device, NULL); + temp_vk->vkDestroyInstance(temp_vk->instance, NULL); #endif // VK_USE_PLATFORM_XLIB_XRANDR_EXT return true; From b4a7666a7544b0e57e4bd86a96f0193e2c30627e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 12 May 2021 14:54:44 +0100 Subject: [PATCH 546/883] doc: Document #61 and !810 --- doc/changes/xrt/mr.810.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 doc/changes/xrt/mr.810.md diff --git a/doc/changes/xrt/mr.810.md b/doc/changes/xrt/mr.810.md new file mode 100644 index 000000000..2bef57966 --- /dev/null +++ b/doc/changes/xrt/mr.810.md @@ -0,0 +1,4 @@ +--- +- issue.61 +--- +Add a @ref conventions page. From f6e831d8fbc060f62f27c89c4f4335da53598846 Mon Sep 17 00:00:00 2001 From: Christoph Haag Date: Thu, 13 May 2021 13:51:02 +0200 Subject: [PATCH 547/883] steamvr: Don't crash if we don't have bindings for device --- src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp b/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp index dabcf6437..42d773bd3 100644 --- a/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp +++ b/src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp @@ -489,6 +489,11 @@ public: struct profile_template *p = get_profile_template(m_xdev->name); + if (p == NULL) { + ovrd_log("Monado device has unknown profile: %d\n", m_xdev->name); + return vr::VRInitError_Unknown; + } + m_input_profile = std::string("{monado}/input/") + std::string(p->steamvr_input_profile_path); m_controller_type = p->steamvr_controller_type; } From 423084e827fbba714b671b3b69b834d8567e6f9b Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Fri, 16 Apr 2021 10:31:30 -0500 Subject: [PATCH 548/883] gitignore: ignore Sourcetrail things --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 497b74509..58049f355 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,8 @@ local.properties gradlew gradlew.bat gradle-wrapper.jar + +#ignore Sourcetrail things +*.srctrlbm +*.srctrldb +*.srctrlprj From 302e72b2feb7394a59806fd0ed60c5d3747e80af Mon Sep 17 00:00:00 2001 From: Moses Turner Date: Thu, 13 May 2021 17:54:37 -0500 Subject: [PATCH 549/883] d/rs: remove superfluous rs_update_offset; add config options --- src/xrt/drivers/meson.build | 2 +- src/xrt/drivers/realsense/rs_6dof.c | 150 +++++++++++++++-------- src/xrt/drivers/realsense/rs_interface.h | 3 - 3 files changed, 102 insertions(+), 53 deletions(-) diff --git a/src/xrt/drivers/meson.build b/src/xrt/drivers/meson.build index 6f13eb7c2..41f21d589 100644 --- a/src/xrt/drivers/meson.build +++ b/src/xrt/drivers/meson.build @@ -127,7 +127,7 @@ lib_drv_rs = static_library( 'realsense/rs_interface.h', 'realsense/rs_prober.c', ), - include_directories: xrt_include, + include_directories: [xrt_include,cjson_include], dependencies: [aux, rs], build_by_default: 'rs' in drivers, ) diff --git a/src/xrt/drivers/realsense/rs_6dof.c b/src/xrt/drivers/realsense/rs_6dof.c index 7a5460a2a..ef20e63b3 100644 --- a/src/xrt/drivers/realsense/rs_6dof.c +++ b/src/xrt/drivers/realsense/rs_6dof.c @@ -4,6 +4,7 @@ /*! * @file * @brief RealSense helper driver for 6DOF tracking. + * @author Moses Turner * @author Nova King * @author Jakob Bornecrantz * @ingroup drv_rs @@ -22,6 +23,9 @@ #include "util/u_device.h" #include "util/u_logging.h" +#include "util/u_json.h" +#include "util/u_config_json.h" + #include #include #include @@ -50,11 +54,14 @@ struct rs_6dof uint64_t relation_timestamp_ns; struct xrt_space_relation relation; - // arbitrary offset to apply to the pose the t265 gives us - struct xrt_pose offset; - struct os_thread_helper oth; + bool enable_mapping; + bool enable_pose_jumping; + bool enable_relocalization; + bool enable_pose_prediction; + bool enable_pose_filtering; // Forward compatibility for when that 1-euro filter is working + rs2_context *ctx; rs2_pipeline *pipe; rs2_pipeline_profile *profile; @@ -115,6 +122,15 @@ close_6dof(struct rs_6dof *rs) } } +#define CHECK_RS2() \ + do { \ + if (check_error(rs, e) != 0) { \ + close_6dof(rs); \ + return 1; \ + } \ + } while (0) + + /*! * Create all RealSense resources needed for 6DOF tracking. */ @@ -125,22 +141,13 @@ create_6dof(struct rs_6dof *rs) rs2_error *e = NULL; rs->ctx = rs2_create_context(RS2_API_VERSION, &e); - if (check_error(rs, e) != 0) { - close_6dof(rs); - return 1; - } + CHECK_RS2(); rs2_device_list *device_list = rs2_query_devices(rs->ctx, &e); - if (check_error(rs, e) != 0) { - close_6dof(rs); - return 1; - } + CHECK_RS2(); int dev_count = rs2_get_device_count(device_list, &e); - if (check_error(rs, e) != 0) { - close_6dof(rs); - return 1; - } + CHECK_RS2(); U_LOG_D("There are %d connected RealSense devices.", dev_count); if (0 == dev_count) { @@ -149,16 +156,10 @@ create_6dof(struct rs_6dof *rs) } rs->pipe = rs2_create_pipeline(rs->ctx, &e); - if (check_error(rs, e) != 0) { - close_6dof(rs); - return 1; - } + CHECK_RS2(); rs->config = rs2_create_config(&e); - if (check_error(rs, e) != 0) { - close_6dof(rs); - return 1; - } + CHECK_RS2(); rs2_config_enable_stream(rs->config, // RS2_STREAM_POSE, // Type @@ -168,29 +169,42 @@ create_6dof(struct rs_6dof *rs) RS2_FORMAT_6DOF, // Format 200, // FPS &e); - if (check_error(rs, e) != 0) { - close_6dof(rs); - return 1; + CHECK_RS2(); + + rs2_pipeline_profile *prof = rs2_config_resolve(rs->config, rs->pipe, &e); + CHECK_RS2(); + + rs2_device *cameras = rs2_pipeline_profile_get_device(prof, &e); + CHECK_RS2(); + + rs2_sensor_list *sensors = rs2_query_sensors(cameras, &e); + CHECK_RS2(); + + rs2_sensor *sensor = rs2_create_sensor(sensors, 0, &e); + CHECK_RS2(); + + rs2_set_option((rs2_options *)sensor, RS2_OPTION_ENABLE_MAPPING, rs->enable_mapping ? 1.0f : 0.0f, &e); + CHECK_RS2(); + + if (rs->enable_mapping) { + // Neither of these options mean anything if mapping is off; in fact it errors out + // if we mess with these + // with mapping off + rs2_set_option((rs2_options *)sensor, RS2_OPTION_ENABLE_RELOCALIZATION, + rs->enable_relocalization ? 1.0f : 0.0f, &e); + CHECK_RS2(); + + rs2_set_option((rs2_options *)sensor, RS2_OPTION_ENABLE_POSE_JUMPING, + rs->enable_pose_jumping ? 1.0f : 0.0f, &e); + CHECK_RS2(); } rs->profile = rs2_pipeline_start_with_config(rs->pipe, rs->config, &e); - if (check_error(rs, e) != 0) { - close_6dof(rs); - return 1; - } + CHECK_RS2(); return 0; } - -void -rs_update_offset(struct xrt_pose offset, struct xrt_device *xdev) -{ - struct rs_6dof *rs = rs_6dof(xdev); - memcpy(&rs->offset, &offset, sizeof(struct xrt_pose)); -} - - /*! * Process a frame as 6DOF data, does not assume ownership of the frame. */ @@ -354,15 +368,13 @@ rs_6dof_get_tracked_pose(struct xrt_device *xdev, int64_t diff_prediction_ns = 0; diff_prediction_ns = at_timestamp_ns - relation_timestamp_ns; - struct xrt_space_relation relation; double delta_s = time_ns_to_s(diff_prediction_ns); - m_predict_relation(&relation_not_predicted, delta_s, &relation); - - struct xrt_space_graph xsg = {0}; - m_space_graph_add_pose(&xsg, &rs->offset); - m_space_graph_add_relation(&xsg, &relation); - m_space_graph_resolve(&xsg, out_relation); + if (rs->enable_pose_prediction) { + m_predict_relation(&relation_not_predicted, delta_s, out_relation); + } else { + *out_relation = relation_not_predicted; + } } static void rs_6dof_get_view_pose(struct xrt_device *xdev, @@ -390,9 +402,45 @@ struct xrt_device * rs_6dof_create(void) { struct rs_6dof *rs = U_DEVICE_ALLOCATE(struct rs_6dof, U_DEVICE_ALLOC_TRACKING_NONE, 1, 0); - rs->offset = - (struct xrt_pose){.orientation = {.x = 0, .y = 0, .z = 0, .w = 1}, .position = {.x = 0, .y = 0, .z = 0}}; - int ret = 0; + + rs->enable_mapping = true; + rs->enable_pose_jumping = true; + rs->enable_relocalization = true; + rs->enable_pose_prediction = true; + rs->enable_pose_filtering = true; + + struct u_config_json config_json; + u_config_json_open_or_create_main_file(&config_json); + cJSON *realsense_config_json = cJSON_GetObjectItemCaseSensitive(config_json.root, "config_realsense"); + if (realsense_config_json != NULL) { + cJSON *mapping = cJSON_GetObjectItemCaseSensitive(realsense_config_json, "enable_mapping"); + cJSON *pose_jumping = cJSON_GetObjectItemCaseSensitive(realsense_config_json, "enable_pose_jumping"); + cJSON *relocalization = + cJSON_GetObjectItemCaseSensitive(realsense_config_json, "enable_relocalization"); + cJSON *pose_prediction = + cJSON_GetObjectItemCaseSensitive(realsense_config_json, "enable_pose_prediction"); + cJSON *pose_filtering = + cJSON_GetObjectItemCaseSensitive(realsense_config_json, "enable_pose_filtering"); + + // if json key isn't in the json, default to true. if it is in there, use json value + if (mapping != NULL) { + rs->enable_mapping = cJSON_IsTrue(mapping); + } + if (pose_jumping != NULL) { + rs->enable_pose_jumping = cJSON_IsTrue(pose_jumping); + } + if (relocalization != NULL) { + rs->enable_relocalization = cJSON_IsTrue(relocalization); + } + if (pose_prediction != NULL) { + rs->enable_pose_prediction = cJSON_IsTrue(pose_prediction); + } + if (pose_filtering != NULL) { + rs->enable_pose_filtering = cJSON_IsTrue(pose_filtering); + } + } + U_LOG_D("Realsense opts are %i %i %i %i %i\n", rs->enable_mapping, rs->enable_pose_jumping, + rs->enable_relocalization, rs->enable_pose_prediction, rs->enable_pose_filtering); rs->base.update_inputs = rs_6dof_update_inputs; rs->base.get_tracked_pose = rs_6dof_get_tracked_pose; @@ -409,6 +457,10 @@ rs_6dof_create(void) rs->base.inputs[0].name = XRT_INPUT_GENERIC_TRACKER_POSE; + int ret = 0; + + + // Thread and other state. ret = os_thread_helper_init(&rs->oth); if (ret != 0) { diff --git a/src/xrt/drivers/realsense/rs_interface.h b/src/xrt/drivers/realsense/rs_interface.h index befe0f7bf..9a3108bd3 100644 --- a/src/xrt/drivers/realsense/rs_interface.h +++ b/src/xrt/drivers/realsense/rs_interface.h @@ -29,9 +29,6 @@ extern "C" { struct xrt_device * rs_6dof_create(void); -void -rs_update_offset(struct xrt_pose offset, struct xrt_device *xdev); - /*! * Create a auto prober for rs devices. * From d11ef4ae1ea098ebd5dbf60d04682055d753089c Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 14 May 2021 14:54:52 -0500 Subject: [PATCH 550/883] Revert "gradle: Only forward EIGEN3_INCLUDE_DIR definition if we actually have it set." This reverts commit 0868a90a1f299275a37b2443cf5ba90c5030ed5b. --- build.gradle | 4 ++-- src/xrt/targets/openxr_android/build.gradle | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index b517d3503..190bfa7d3 100644 --- a/build.gradle +++ b/build.gradle @@ -48,8 +48,8 @@ ext { sharedMinSdk = 26 // If you are building on Windows, you will need to explicitly set eigenIncludeDir in your - // local.properties file - eigenIncludeDir = project.findProperty('eigenIncludeDir') + // local.properties file since the default value provided below only makes sense on *nix + eigenIncludeDir = project.findProperty('eigenIncludeDir') ?: '/usr/include/eigen3' // If you're having trouble with a "can't find python" CMake error, you can specify the path to // Python 3 explicitly in local.properties with a property named "pythonBinary" diff --git a/src/xrt/targets/openxr_android/build.gradle b/src/xrt/targets/openxr_android/build.gradle index f633d3faa..2cd5fa446 100644 --- a/src/xrt/targets/openxr_android/build.gradle +++ b/src/xrt/targets/openxr_android/build.gradle @@ -89,17 +89,13 @@ android { externalNativeBuild { cmake { - arguments "-DANDROID_PLATFORM=26", "-DANDROID_STL=c++_shared", "-DANDROID_ARM_NEON=TRUE" + arguments "-DEIGEN3_INCLUDE_DIR=${project.eigenIncludeDir}", "-DANDROID_PLATFORM=26", "-DANDROID_STL=c++_shared", "-DANDROID_ARM_NEON=TRUE" } if (project.pythonBinary != null) { - println "Path to Python 3 explicitly specified: pythonBinary=${project.pythonBinary}" + println "Path to Python 3 explicitly specified: ${project.pythonBinary}" cmake.arguments "-DPYTHON_EXECUTABLE=${project.pythonBinary}" } - if (project.eigenIncludeDir != null) { - println "Path to Eigen3 includes explicitly specified: eigenIncludeDir=${project.eigenIncludeDir}" - cmake.arguments "-DEIGEN3_INCLUDE_DIR=${project.eigenIncludeDir}" - } } // Be sure to copy over licenses formatted as required. From bdc53b97a303ce7107e3200fdf8923cd381c2dee Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 6 May 2021 09:27:38 -0500 Subject: [PATCH 551/883] gradle: Apply suggestion from android studio --- src/xrt/targets/openxr_android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrt/targets/openxr_android/build.gradle b/src/xrt/targets/openxr_android/build.gradle index 2cd5fa446..63de2a152 100644 --- a/src/xrt/targets/openxr_android/build.gradle +++ b/src/xrt/targets/openxr_android/build.gradle @@ -24,7 +24,7 @@ androidGitVersion { def parseOpenXRVersion(def fn) { def matches = file(fn).readLines().find { it.contains('XR_CURRENT_API_VERSION') - } =~ ~/XR_MAKE_VERSION\(([^\)]+)\)/ + } =~ ~/XR_MAKE_VERSION\(([^)]+)\)/ def components = matches[0][1].split(',').each { it.replace(' ', '').trim() } String.join('.', components) } From dd1fa85f052469e7a7af4698ca51212bae779ebb Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 5 May 2021 15:42:33 -0500 Subject: [PATCH 552/883] gradle: Remove jcenter usage, it was shut down. --- build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 190bfa7d3..7de07df45 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,6 @@ buildscript { } repositories { google() - jcenter() mavenCentral() } dependencies { @@ -59,6 +58,6 @@ ext { allprojects { repositories { google() - jcenter() + mavenCentral() } } From 27f872fdfc95bba6fce4c70e4c33af7e66bd7cd8 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 6 May 2021 09:28:33 -0500 Subject: [PATCH 553/883] gradle: Update to 6.8.3 --- gradle/wrapper/gradle-wrapper.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1fa2c866d..2c828a4ed 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Nov 04 14:30:07 CST 2020 +#Wed May 05 16:48:28 CDT 2021 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +zipStoreBase=GRADLE_USER_HOME From df9ebf261fb7dd3014e72a4683633ac5dba8156a Mon Sep 17 00:00:00 2001 From: Jae Lee Date: Sun, 16 May 2021 22:59:32 +0000 Subject: [PATCH 554/883] d/illixr: Update ILLIXR driver. --- src/xrt/drivers/illixr/illixr_component.cpp | 17 ++--------------- src/xrt/drivers/illixr/illixr_prober.c | 2 +- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/xrt/drivers/illixr/illixr_component.cpp b/src/xrt/drivers/illixr/illixr_component.cpp index 7b412c585..d802678f9 100644 --- a/src/xrt/drivers/illixr/illixr_component.cpp +++ b/src/xrt/drivers/illixr/illixr_component.cpp @@ -24,18 +24,11 @@ class illixr_plugin : public plugin { public: illixr_plugin(std::string name_, phonebook *pb_) - : plugin{name_, pb_}, sb{pb->lookup_impl()}, sb_pose{pb->lookup_impl()}, - sb_eyebuffer{sb->publish("eyebuffer")}, sb_vsync_estimate{sb->subscribe_latest( - "vsync_estimate")} + : plugin{name_, pb_}, sb{pb->lookup_impl()}, sb_pose{pb->lookup_impl()} {} const std::shared_ptr sb; const std::shared_ptr sb_pose; - const std::unique_ptr> sb_eyebuffer; - const std::unique_ptr> sb_vsync_estimate; - fast_pose_type prev_pose; /* stores a copy of pose each time - illixr_read_pose() is called */ - std::chrono::time_point sample_time; /* when prev_pose was stored */ }; static illixr_plugin *illixr_plugin_obj = nullptr; @@ -60,9 +53,6 @@ illixr_read_pose() const fast_pose_type fast_pose = illixr_plugin_obj->sb_pose->get_fast_pose(); const pose_type pose = fast_pose.pose; - // record when the pose was read for use in write_frame - illixr_plugin_obj->sample_time = std::chrono::system_clock::now(); - ret.orientation.x = pose.orientation.x(); ret.orientation.y = pose.orientation.y(); ret.orientation.z = pose.orientation.z(); @@ -71,8 +61,5 @@ illixr_read_pose() ret.position.y = pose.position.y(); ret.position.z = pose.position.z(); - // store pose in static variable for use in write_frame - illixr_plugin_obj->prev_pose = fast_pose; // copy member variables - return ret; -} \ No newline at end of file +} diff --git a/src/xrt/drivers/illixr/illixr_prober.c b/src/xrt/drivers/illixr/illixr_prober.c index 437bc4e9b..964bb8c95 100644 --- a/src/xrt/drivers/illixr/illixr_prober.c +++ b/src/xrt/drivers/illixr/illixr_prober.c @@ -62,7 +62,7 @@ struct xrt_auto_prober * illixr_create_auto_prober() { struct illixr_prober *dp = U_TYPED_CALLOC(struct illixr_prober); - dp->base.name = "IlliXR"; + dp->base.name = "ILLIXR"; dp->base.destroy = illixr_prober_destroy; dp->base.lelo_dallas_autoprobe = illixr_prober_autoprobe; From 92565b7f21c631aa1088addddaab6b2a421812ea Mon Sep 17 00:00:00 2001 From: zhibinw Date: Wed, 12 May 2021 10:11:56 +0800 Subject: [PATCH 555/883] ipc/android: support create surface from runtime. --- .../monado/auxiliary/MonadoView.java | 72 ------ .../monado/auxiliary/SystemUiController.kt | 95 ++++++++ .../org/freedesktop/monado/ipc/IMonado.aidl | 10 + .../org/freedesktop/monado/ipc/Client.java | 135 +++++++---- .../freedesktop/monado/ipc/MonadoImpl.java | 34 +++ .../freedesktop/monado/ipc/MonadoService.kt | 18 +- .../freedesktop/monado/ipc/SurfaceManager.kt | 219 ++++++++++++++++++ .../src/main/AndroidManifest.xml | 3 + .../monado/android_common/AboutActivity.java | 9 +- .../DisplayOverOtherAppsStatusFragment.kt | 104 +++++++++ .../RestartRuntimeDialogFragment.kt | 61 +++++ .../src/main/res/layout/activity_about.xml | 24 +- ...fragment_display_over_other_app_status.xml | 34 +++ .../res/layout/fragment_vr_mode_status.xml | 2 +- .../display_over_other_apps_strings.xml | 12 + .../res/values/restart_runtime_strings.xml | 7 + 16 files changed, 708 insertions(+), 131 deletions(-) create mode 100644 src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/SystemUiController.kt create mode 100644 src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/SurfaceManager.kt create mode 100644 src/xrt/targets/android_common/src/main/java/org/freedesktop/monado/android_common/DisplayOverOtherAppsStatusFragment.kt create mode 100644 src/xrt/targets/android_common/src/main/java/org/freedesktop/monado/android_common/RestartRuntimeDialogFragment.kt create mode 100644 src/xrt/targets/android_common/src/main/res/layout/fragment_display_over_other_app_status.xml create mode 100644 src/xrt/targets/android_common/src/main/res/values/display_over_other_apps_strings.xml create mode 100644 src/xrt/targets/android_common/src/main/res/values/restart_runtime_strings.xml diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java index 9d8fb6794..029b3e34a 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java @@ -33,28 +33,12 @@ import java.util.Calendar; public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, SurfaceHolder.Callback2 { private static final String TAG = "MonadoView"; - @SuppressWarnings("deprecation") - private static final int sysUiVisFlags = 0 - // Give us a stable view of content insets - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE - // Be able to do fullscreen and hide navigation - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - // we want sticky immersive - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - @NonNull private final Context context; /// The activity we've connected to. @Nullable private final Activity activity; - - @Nullable - private final Method viewSetSysUiVis; - private final Object currentSurfaceHolderSync = new Object(); public int width = -1; @@ -77,15 +61,12 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S activity = null; } this.activity = activity; - viewSetSysUiVis = getSystemUiVisMethod(); } public MonadoView(Activity activity) { super(activity); this.context = activity; this.activity = activity; - - viewSetSysUiVis = getSystemUiVisMethod(); } private MonadoView(Activity activity, long nativePointer) { @@ -93,17 +74,6 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S nativeCounterpart = new NativeCounterpart(nativePointer); } - private static Method getSystemUiVisMethod() { - Method method; - try { - method = android.view.View.class.getMethod("setSystemUiVisibility", int.class); - } catch (NoSuchMethodException e) { - // ok - method = null; - } - return method; - } - /** * Construct and start attaching a MonadoView to a client application. * @@ -228,43 +198,6 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S nativeCounterpart.markAsDiscardedByNative(TAG); } - private boolean makeFullscreen() { - if (activity == null) { - return false; - } - if (viewSetSysUiVis == null) { - return false; - } - View decorView = activity.getWindow().getDecorView(); - //! @todo implement with WindowInsetsController to ward off the stink of deprecation - try { - viewSetSysUiVis.invoke(decorView, sysUiVisFlags); - } catch (IllegalAccessException e) { - return false; - } catch (InvocationTargetException e) { - return false; - } - return true; - } - - /** - * Add a listener so that if our system UI display state doesn't include all we want, we re-apply. - */ - @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) - @SuppressWarnings("deprecation") - private void setSystemUiVisChangeListener() { - if (activity == null) { - return; - } - activity.getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> { - // If not fullscreen, fix it. - if (0 == (visibility & View.SYSTEM_UI_FLAG_FULLSCREEN)) { - makeFullscreen(); - } - }); - - } - @Override public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) { synchronized (currentSurfaceHolderSync) { @@ -272,11 +205,6 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S currentSurfaceHolderSync.notifyAll(); } Log.i(TAG, "surfaceCreated: Got a surface holder!"); - - if (makeFullscreen()) { - // If we could make it full screen, make it really stick. - setSystemUiVisChangeListener(); - } } @Override diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/SystemUiController.kt b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/SystemUiController.kt new file mode 100644 index 000000000..eb1388e75 --- /dev/null +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/SystemUiController.kt @@ -0,0 +1,95 @@ +// Copyright 2021, Qualcomm Innovation Center, Inc. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Class to handle system ui visibility + * @author Jarvis Huang + * @ingroup aux_android_java + */ +package org.freedesktop.monado.auxiliary + +import android.app.Activity +import android.os.Build +import android.view.View +import android.view.WindowInsets +import android.view.WindowInsetsController +import androidx.annotation.RequiresApi + +/** + * Helper class that handles system ui visibility. + */ +class SystemUiController(activity: Activity) { + private val impl: Impl = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + WindowInsetsControllerImpl(activity) + } else { + SystemUiVisibilityImpl(activity) + } + + /** + * Hide system ui and make fullscreen. + */ + fun hide() { + impl.hide() + } + + private abstract class Impl(var activity: Activity) { + abstract fun hide() + fun runOnUiThread(runnable: Runnable) { + activity.runOnUiThread(runnable) + } + } + + @Suppress("DEPRECATION") + private class SystemUiVisibilityImpl(activity: Activity) : Impl(activity) { + override fun hide() { + activity.runOnUiThread { + activity.window.decorView.systemUiVisibility = FLAG_FULL_SCREEN_IMMERSIVE_STICKY + } + } + + companion object { + private const val FLAG_FULL_SCREEN_IMMERSIVE_STICKY = + // Give us a stable view of content insets + (View.SYSTEM_UI_FLAG_LAYOUT_STABLE // Be able to do fullscreen and hide navigation + or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_FULLSCREEN + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // we want sticky immersive + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) + } + + init { + runOnUiThread { + activity.window.decorView.setOnSystemUiVisibilityChangeListener { visibility: Int -> + // If not fullscreen, fix it. + if (0 == visibility and View.SYSTEM_UI_FLAG_FULLSCREEN) { + hide() + } + } + } + } + } + + @RequiresApi(api = Build.VERSION_CODES.R) + private class WindowInsetsControllerImpl(activity: Activity) : Impl(activity) { + override fun hide() { + activity.runOnUiThread { + val controller = activity.window.insetsController + controller!!.hide(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()) + controller.systemBarsBehavior = + WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + } + + init { + runOnUiThread { + activity.window.insetsController!!.addOnControllableInsetsChangedListener { _: WindowInsetsController?, typeMask: Int -> + if (typeMask and WindowInsets.Type.statusBars() == 1 || typeMask and WindowInsets.Type.navigationBars() == 1) { + hide() + } + } + } + } + } + +} diff --git a/src/xrt/ipc/android/src/main/aidl/org/freedesktop/monado/ipc/IMonado.aidl b/src/xrt/ipc/android/src/main/aidl/org/freedesktop/monado/ipc/IMonado.aidl index 88bf3b33d..e06a56a4a 100644 --- a/src/xrt/ipc/android/src/main/aidl/org/freedesktop/monado/ipc/IMonado.aidl +++ b/src/xrt/ipc/android/src/main/aidl/org/freedesktop/monado/ipc/IMonado.aidl @@ -22,4 +22,14 @@ interface IMonado { * Provide the surface we inject into the activity, back to the service. */ void passAppSurface(in Surface surface); + + /*! + * Asking service to create surface and attach it to the display matches given display id. + */ + boolean createSurface(int displayId, boolean focusable); + + /*! + * Asking service whether it has the capbility to draw over other apps or not. + */ + boolean canDrawOverOtherApps(); } diff --git a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java index 7bd217dbc..d0bc2914f 100644 --- a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java +++ b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java @@ -20,12 +20,16 @@ import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; +import android.view.Surface; import android.view.SurfaceHolder; +import android.view.WindowManager; import androidx.annotation.Keep; +import androidx.annotation.Nullable; import org.freedesktop.monado.auxiliary.MonadoView; import org.freedesktop.monado.auxiliary.NativeCounterpart; +import org.freedesktop.monado.auxiliary.SystemUiController; import java.io.IOException; @@ -38,9 +42,9 @@ import java.io.IOException; public class Client implements ServiceConnection { private static final String TAG = "monado-ipc-client"; /** - * Used to block native until we have our side of the socket pair. + * Used to block until binder is ready. */ - private final Object connectSync = new Object(); + private final Object binderSync = new Object(); /** * Keep track of the ipc_client_android instance over on the native side. */ @@ -76,8 +80,10 @@ public class Client implements ServiceConnection { * Intent for connecting to service */ private Intent intent = null; - - private SurfaceHolder surfaceHolder; + /** + * Controll system ui visibility + */ + private SystemUiController systemUiController = null; /** * Constructor @@ -124,6 +130,8 @@ public class Client implements ServiceConnection { *

* The IPC client code on Android should load this class (from the right package), instantiate * this class (retaining a reference to it!), and call this method. + *

+ * This method must not be called from the main (UI) thread. * * @param context_ Context to use to make the connection. (We get the application context * from it.) @@ -140,26 +148,75 @@ public class Client implements ServiceConnection { public int blockingConnect(Context context_, String packageName) { Log.i(TAG, "blockingConnect"); - Activity activity = (Activity) context_; - - MonadoView monadoView = MonadoView.attachToActivity(activity); - surfaceHolder = monadoView.waitGetSurfaceHolder(2000); - - synchronized (connectSync) { + synchronized (binderSync) { if (!bind(context_, packageName)) { Log.e(TAG, "Bind failed immediately"); // Bind failed immediately return -1; } try { - while (fd == null) { - connectSync.wait(); - } + binderSync.wait(); } catch (InterruptedException e) { Log.e(TAG, "Interrupted: " + e.toString()); return -1; } } + + if (monado == null) { + Log.e(TAG, "Invalid binder object"); + return -1; + } + + boolean surfaceCreated = false; + Activity activity = (Activity) context_; + + try { + // Determine whether runtime or client should create surface + if (monado.canDrawOverOtherApps()) { + WindowManager wm = (WindowManager) context_.getSystemService(Context.WINDOW_SERVICE); + surfaceCreated = monado.createSurface(wm.getDefaultDisplay().getDisplayId(), false); + } else { + Surface surface = attachViewAndGetSurface(activity); + surfaceCreated = (surface != null); + if (surfaceCreated) { + monado.passAppSurface(surface); + } + } + } catch (RemoteException e) { + e.printStackTrace(); + } + + if (!surfaceCreated) { + Log.e(TAG, "Failed to create surface"); + handleFailure(); + return -1; + } + + systemUiController = new SystemUiController(activity); + systemUiController.hide(); + + // Create socket pair + ParcelFileDescriptor theirs; + ParcelFileDescriptor ours; + try { + ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(); + ours = fds[0]; + theirs = fds[1]; + monado.connect(theirs); + } catch (IOException e) { + e.printStackTrace(); + Log.e(TAG, "could not create socket pair: " + e.toString()); + handleFailure(); + return -1; + } catch (RemoteException e) { + e.printStackTrace(); + Log.e(TAG, "could not connect to service: " + e.toString()); + handleFailure(); + return -1; + } + + fd = ours; + Log.i(TAG, "Socket fd " + fd.getFd()); return fd.getFd(); } @@ -221,12 +278,20 @@ public class Client implements ServiceConnection { shutdown(); } + @Nullable + private Surface attachViewAndGetSurface(Activity activity) { + MonadoView monadoView = MonadoView.attachToActivity(activity); + SurfaceHolder holder = monadoView.waitGetSurfaceHolder(2000); + Surface surface = null; + if (holder != null) { + surface = holder.getSurface(); + } + + return surface; + } + /** * Handle the asynchronous connection of the binder IPC. - *

- * This sets up the class member `monado`, as well as the member `fd`. It calls - * `IMonado.connect()` automatically. The client still needs to call `IMonado.passAppSurface()` - * on `monado`. * * @param name should match the intent above, but not used. * @param service the associated service, which we cast in this function. @@ -234,40 +299,10 @@ public class Client implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, "onServiceConnected"); - monado = IMonado.Stub.asInterface(service); - try { - monado.passAppSurface(surfaceHolder.getSurface()); - } catch (RemoteException e) { - e.printStackTrace(); - Log.e(TAG, "Could not pass app surface: " + e.toString()); - } - - ParcelFileDescriptor theirs; - ParcelFileDescriptor ours; - try { - ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(); - ours = fds[0]; - theirs = fds[1]; - } catch (IOException e) { - e.printStackTrace(); - Log.e(TAG, "could not create socket pair: " + e.toString()); - handleFailure(); - return; - } - - try { - monado.connect(theirs); - } catch (RemoteException e) { - e.printStackTrace(); - Log.e(TAG, "could not connect to service: " + e.toString()); - handleFailure(); - return; - } - synchronized (connectSync) { - Log.e(TAG, String.format("Notifying connectSync with fd %d", ours.getFd())); - fd = ours; - connectSync.notify(); + synchronized (binderSync) { + monado = IMonado.Stub.asInterface(service); + binderSync.notify(); } } diff --git a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoImpl.java b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoImpl.java index 1995904f2..30d7f06f8 100644 --- a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoImpl.java +++ b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoImpl.java @@ -13,6 +13,7 @@ package org.freedesktop.monado.ipc; import android.os.ParcelFileDescriptor; import android.util.Log; import android.view.Surface; +import android.view.SurfaceHolder; import androidx.annotation.Keep; import androidx.annotation.NonNull; @@ -46,6 +47,27 @@ public class MonadoImpl extends IMonado.Stub { "CompositorThread"); private boolean started = false; + private SurfaceManager surfaceManager; + + public MonadoImpl(@NonNull SurfaceManager surfaceManager) { + this.surfaceManager = surfaceManager; + this.surfaceManager.setCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + Log.i(TAG, "surfaceCreated"); + nativeAppSurface(holder.getSurface()); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + } + }); + } + private void launchThreadIfNeeded() { synchronized (compositorThread) { if (!started) { @@ -85,6 +107,18 @@ public class MonadoImpl extends IMonado.Stub { nativeAppSurface(surface); } + @Override + public boolean createSurface(int displayId, boolean focusable) { + Log.i(TAG, "createSurface"); + return surfaceManager.createSurfaceOnDisplay(displayId, focusable); + } + + @Override + public boolean canDrawOverOtherApps() { + Log.i(TAG, "canDrawOverOtherApps"); + return surfaceManager.canDrawOverlays(); + } + private void threadEntry() { Log.i(TAG, "threadEntry"); nativeThreadEntry(); diff --git a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.kt b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.kt index fcd1943c0..306052d6a 100644 --- a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.kt +++ b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.kt @@ -26,11 +26,27 @@ import javax.inject.Inject */ @AndroidEntryPoint class MonadoService : Service() { - private val binder = MonadoImpl() + private val binder: MonadoImpl by lazy { + MonadoImpl(surfaceManager) + } @Inject lateinit var serviceNotification: IServiceNotification + private lateinit var surfaceManager: SurfaceManager + + override fun onCreate() { + super.onCreate() + + surfaceManager = SurfaceManager(this) + } + + override fun onDestroy() { + super.onDestroy() + + surfaceManager.destroySurface() + } + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.d(TAG, "onStartCommand") // if this isn't a restart diff --git a/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/SurfaceManager.kt b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/SurfaceManager.kt new file mode 100644 index 000000000..3cf7c4113 --- /dev/null +++ b/src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/SurfaceManager.kt @@ -0,0 +1,219 @@ +// Copyright 2021, Qualcomm Innovation Center, Inc. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Class that manages surface + * @author Jarvis Huang + * @ingroup ipc_android + */ +package org.freedesktop.monado.ipc + +import android.content.Context +import android.hardware.display.DisplayManager +import android.os.Handler +import android.os.Looper +import android.provider.Settings +import android.util.Log +import android.view.Display +import android.view.SurfaceHolder +import android.view.SurfaceView +import android.view.WindowManager +import androidx.annotation.UiThread +import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.ReentrantLock + +/** + * Class that creates/manages surface on display. + */ +class SurfaceManager(context: Context) : SurfaceHolder.Callback { + private val appContext: Context = context.applicationContext + private val surfaceLock: ReentrantLock = ReentrantLock() + private val surfaceCondition: Condition = surfaceLock.newCondition() + private var callback: SurfaceHolder.Callback? = null + private val uiHandler: Handler = Handler(Looper.getMainLooper()) + private val viewHelper: ViewHelper = ViewHelper(this) + + override fun surfaceCreated(holder: SurfaceHolder) { + Log.i(TAG, "surfaceCreated") + callback?.surfaceCreated(holder) + + surfaceLock.lock() + surfaceCondition.signal() + surfaceLock.unlock() + } + + override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { + Log.i(TAG, "surfaceChanged, size: " + width + "x" + height) + callback?.surfaceChanged(holder, format, width, height) + } + + override fun surfaceDestroyed(holder: SurfaceHolder) { + Log.i(TAG, "surfaceDestroyed") + callback?.surfaceDestroyed(holder) + } + + /** + * Register a callback for surface status. + * + * @param callback Callback to be invoked. + */ + fun setCallback(callback: SurfaceHolder.Callback?) { + this.callback = callback + } + + /** + * Create surface on required display. + * + * @param displayId Target display id. + * @param focusable True if the surface should be focusable; otherwise false. + * @return True if operation succeeded. + */ + @Synchronized + fun createSurfaceOnDisplay(displayId: Int, focusable: Boolean): Boolean { + if (!canDrawOverlays()) { + Log.w(TAG, "Unable to draw over other apps!") + return false + } + + val dm = appContext.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager + val targetDisplay = dm.getDisplay(displayId) + if (targetDisplay == null) { + Log.w(TAG, "Can't find target display, id: $displayId") + return false + } + + if (viewHelper.hasSamePropertiesWithCurrentView(targetDisplay, focusable)) { + Log.i(TAG, "Reuse current surface") + return true + } + + if (Looper.getMainLooper().isCurrentThread) { + viewHelper.removeAndAddView(appContext, targetDisplay, focusable) + } else { + uiHandler.post { viewHelper.removeAndAddView(appContext, targetDisplay, focusable) } + surfaceLock.lock() + try { + surfaceCondition.await(1, TimeUnit.SECONDS) + } catch (exception: InterruptedException) { + exception.printStackTrace() + } finally { + Log.i(TAG, "surface ready") + surfaceLock.unlock() + } + } + return true + } + + /** + * Check if current process has the capability to draw over other applications. + * + * Implementation of [Settings.canDrawOverlays] checks both context and UID, + * therefore this cannot be done in client side. + * + * @return True if current process can draw over other applications; otherwise false. + */ + fun canDrawOverlays(): Boolean { + return Settings.canDrawOverlays(appContext) + } + + /** + * Destroy created surface. + */ + fun destroySurface() { + viewHelper.removeView() + } + + /** + * Helper class that manages surface view. + */ + private class ViewHelper(private val callback: SurfaceHolder.Callback) { + private var view: SurfaceView? = null + private var displayContext: Context? = null + + @UiThread + fun removeAndAddView(context: Context, targetDisplay: Display, focusable: Boolean) { + removeView() + addView(context, targetDisplay, focusable) + } + + @UiThread + fun addView(context: Context, display: Display, focusable: Boolean) { + // WindowManager is associated with display context. + Log.i(TAG, "Add view to display " + display.displayId) + displayContext = context.createDisplayContext(display) + addViewInternal(displayContext!!, focusable) + } + + @UiThread + fun removeView() { + if (view != null && displayContext != null) { + removeViewInternal(displayContext!!) + displayContext = null + } + } + + fun hasSamePropertiesWithCurrentView(display: Display, focusable: Boolean): Boolean { + return if (view == null || displayContext == null) { + false + } else { + isSameDisplay(displayContext!!, display) && !isFocusableChanged(focusable) + } + } + + /** + * Check whether given display is the one being used right now. + */ + @Suppress("DEPRECATION") + private fun isSameDisplay(context: Context, display: Display): Boolean { + val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + return wm.defaultDisplay != null && wm.defaultDisplay.displayId == display.displayId + } + + private fun isFocusableChanged(focusable: Boolean): Boolean { + val lp = view!!.layoutParams as WindowManager.LayoutParams + val currentFocusable = lp.flags == VIEW_FLAG_FOCUSABLE + return focusable != currentFocusable + } + + @UiThread + private fun addViewInternal(context: Context, focusable: Boolean) { + val v = SurfaceView(context) + v.holder.addCallback(callback) + val lp = WindowManager.LayoutParams() + lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY + lp.flags = if (focusable) VIEW_FLAG_FOCUSABLE else VIEW_FLAG_NOT_FOCUSABLE + + val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + wm.addView(v, lp) + if (focusable) { + v.requestFocus() + } + + view = v + } + + @UiThread + private fun removeViewInternal(context: Context) { + val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + wm.removeView(view) + view = null + } + + companion object { + @Suppress("DEPRECATION") + private const val VIEW_FLAG_FOCUSABLE = WindowManager.LayoutParams.FLAG_FULLSCREEN + + @Suppress("DEPRECATION") + private const val VIEW_FLAG_NOT_FOCUSABLE = + WindowManager.LayoutParams.FLAG_FULLSCREEN or + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + } + } + + companion object { + private const val TAG = "SurfaceManager" + } + +} diff --git a/src/xrt/targets/android_common/src/main/AndroidManifest.xml b/src/xrt/targets/android_common/src/main/AndroidManifest.xml index 1d758e8fd..2b1f76387 100644 --- a/src/xrt/targets/android_common/src/main/AndroidManifest.xml +++ b/src/xrt/targets/android_common/src/main/AndroidManifest.xml @@ -6,6 +6,9 @@ SPDX-License-Identifier: BSL-1.0 --> + + + (R.id.btnLaunchDisplayOverOtherAppsSettings) + .setOnClickListener { launchDisplayOverOtherAppsSettings() } + return view + } + + private fun updateStatus(view: View?) { + displayOverOtherAppsEnabled = Settings.canDrawOverlays(requireContext()) + val tv = view!!.findViewById(R.id.textDisplayOverOtherAppsStatus) + // Combining format with html style tag might have problem. See + // https://developer.android.com/guide/topics/resources/string-resource.html#StylingWithHTML + val msg = getString( + R.string.msg_display_over_other_apps, + if (displayOverOtherAppsEnabled) getString(R.string.enabled) else getString(R.string.disabled) + ) + tv.text = Html.fromHtml(msg, Html.FROM_HTML_MODE_LEGACY) + } + + private fun launchDisplayOverOtherAppsSettings() { + // Since Android 11, framework ignores the uri and takes user to the top-level settings. + // See https://developer.android.com/about/versions/11/privacy/permissions#system-alert + // for detail. + val intent = Intent( + Settings.ACTION_MANAGE_OVERLAY_PERMISSION, + Uri.parse("package:" + context!!.packageName) + ) + startActivityForResult(intent, REQUEST_CODE_DISPLAY_OVER_OTHER_APPS) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + // resultCode is always Activity.RESULT_CANCELED + if (requestCode != REQUEST_CODE_DISPLAY_OVER_OTHER_APPS) { + return + } + + if (isRuntimeServiceRunning && + displayOverOtherAppsEnabled != Settings.canDrawOverlays(requireContext()) + ) { + showRestartDialog() + } else { + updateStatus(view) + } + } + + @Suppress("DEPRECATION") + private val isRuntimeServiceRunning: Boolean + get() { + var running = false + val am = requireContext().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + for (service in am.getRunningServices(Int.MAX_VALUE)) { + if (service.pid == Process.myPid()) { + running = true + break + } + } + return running + } + + private fun showRestartDialog() { + val dialog: DialogFragment = RestartRuntimeDialogFragment.newInstance( + getString(R.string.msg_display_over_other_apps_changed) + ) + dialog.show(parentFragmentManager, null) + } + + companion object { + private const val REQUEST_CODE_DISPLAY_OVER_OTHER_APPS = 1000 + } +} diff --git a/src/xrt/targets/android_common/src/main/java/org/freedesktop/monado/android_common/RestartRuntimeDialogFragment.kt b/src/xrt/targets/android_common/src/main/java/org/freedesktop/monado/android_common/RestartRuntimeDialogFragment.kt new file mode 100644 index 000000000..844135588 --- /dev/null +++ b/src/xrt/targets/android_common/src/main/java/org/freedesktop/monado/android_common/RestartRuntimeDialogFragment.kt @@ -0,0 +1,61 @@ +// Copyright 2021, Qualcomm Innovation Center, Inc. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Fragment to display the reason of runtime restart. + * @author Jarvis Huang + */ +package org.freedesktop.monado.android_common + +import android.app.AlarmManager +import android.app.Dialog +import android.app.PendingIntent +import android.content.Context +import android.content.DialogInterface +import android.content.Intent +import android.os.Bundle +import android.os.Process +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment + +class RestartRuntimeDialogFragment : DialogFragment() { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val message = arguments!!.getString(ARGS_KEY_MESSAGE) + val builder = AlertDialog.Builder(requireActivity()) + builder.setMessage(message) + .setCancelable(false) + .setPositiveButton(R.string.restart) { _: DialogInterface?, _: Int -> + delayRestart(DELAY_RESTART_DURATION) + //! @todo elegant way to stop service? A bounded service might be restarted by + // framework automatically. + Process.killProcess(Process.myPid()) + } + return builder.create() + } + + private fun delayRestart(delayMillis: Long) { + val intent = Intent(requireContext(), AboutActivity::class.java) + val pendingIntent = PendingIntent.getActivity( + requireContext(), REQUEST_CODE, + intent, PendingIntent.FLAG_CANCEL_CURRENT + ) + val am = requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager + am.setExact(AlarmManager.RTC, System.currentTimeMillis() + delayMillis, pendingIntent) + } + + companion object { + private const val ARGS_KEY_MESSAGE = "message" + private const val REQUEST_CODE = 2000 + private const val DELAY_RESTART_DURATION: Long = 200 + + @JvmStatic + fun newInstance(msg: String): RestartRuntimeDialogFragment { + val fragment = RestartRuntimeDialogFragment() + val args = Bundle() + args.putString(ARGS_KEY_MESSAGE, msg) + fragment.arguments = args + return fragment + } + } +} diff --git a/src/xrt/targets/android_common/src/main/res/layout/activity_about.xml b/src/xrt/targets/android_common/src/main/res/layout/activity_about.xml index bfe1f14b9..387060ffa 100644 --- a/src/xrt/targets/android_common/src/main/res/layout/activity_about.xml +++ b/src/xrt/targets/android_common/src/main/res/layout/activity_about.xml @@ -32,7 +32,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/imageView" /> + app:layout_constraintTop_toBottomOf="@id/imageView" /> + app:layout_constraintTop_toBottomOf="@id/versionView" /> + app:layout_constraintTop_toBottomOf="@id/textName" />