···1111#include "util/u_misc.h"
1212#include "util/u_trace_marker.h"
1313#include "util/u_logging.h"
1414+#include "util/u_var.h"
1415#include "os/os_threading.h"
1616+1717+#include "math/m_space.h"
1818+#include "math/m_relation_history.h"
151916201721//!@todo Definitely needs a destroy function, will leak a ton.
···24282529 struct xrt_frame *frames[2];
26303131+ bool use_prediction;
3232+ struct u_var_draggable_f32 prediction_offset_ms;
3333+2734 struct
2835 {
2936 struct xrt_hand_joint_set hands[2];
···3441 {
3542 struct os_mutex mutex;
3643 struct xrt_hand_joint_set hands[2];
4444+ struct m_relation_history *relation_hist[2];
3745 uint64_t timestamp;
3846 } present;
3947···8492 xrt_frame_reference(&hta->frames[1], NULL);
8593 os_mutex_lock(&hta->present.mutex);
8694 hta->present.timestamp = hta->working.timestamp;
8787- hta->present.hands[0] = hta->working.hands[0];
8888- hta->present.hands[1] = hta->working.hands[1];
9595+ for (int i = 0; i < 2; i++) {
9696+ hta->present.hands[i] = hta->working.hands[i];
9797+9898+ struct xrt_space_relation wrist_rel =
9999+ hta->working.hands[i].values.hand_joint_set_default[XRT_HAND_JOINT_WRIST].relation;
100100+101101+ m_relation_history_estimate_motion(hta->present.relation_hist[i], //
102102+ &wrist_rel, //
103103+ hta->working.timestamp, //
104104+ &wrist_rel);
105105+ m_relation_history_push(hta->present.relation_hist[i], &wrist_rel, hta->working.timestamp);
106106+ }
89107 os_mutex_unlock(&hta->present.mutex);
9010891109 hta->hand_tracking_work_active = false;
···145163 if (name == XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT) {
146164 idx = 1;
147165 }
148148- *out_value = hta->present.hands[idx];
149149- *out_timestamp_ns = hta->present.timestamp;
166166+167167+ os_mutex_lock(&hta->present.mutex);
168168+169169+ struct xrt_hand_joint_set latest_hand = hta->present.hands[idx];
170170+171171+ if (!hta->use_prediction) {
172172+ *out_value = latest_hand;
173173+ *out_timestamp_ns = hta->present.timestamp;
174174+ os_mutex_unlock(&hta->present.mutex);
175175+ return;
176176+ }
177177+178178+ double prediction_offset_ns = (double)hta->prediction_offset_ms.val * (double)U_TIME_1MS_IN_NS;
179179+180180+ desired_timestamp_ns += (uint64_t)prediction_offset_ns;
181181+182182+ struct xrt_space_relation predicted_wrist;
183183+ m_relation_history_get(hta->present.relation_hist[idx], desired_timestamp_ns, &predicted_wrist);
184184+185185+ os_mutex_unlock(&hta->present.mutex);
186186+187187+ struct xrt_space_relation latest_wrist =
188188+ latest_hand.values.hand_joint_set_default[XRT_HAND_JOINT_WRIST].relation;
189189+190190+ *out_value = latest_hand;
191191+192192+ // apply the pose change from the latest wrist to the predicted wrist
193193+ // to all the joints on the hand.
194194+195195+ //!@optimize We could slightly reduce the total number of transforms by putting some of this in
196196+ //! ht_async_mainloop
197197+ for (int i = 0; i < XRT_HAND_JOINT_COUNT; i++) {
198198+ struct xrt_relation_chain xrc = {0};
199199+ m_relation_chain_push_relation(&xrc, &latest_hand.values.hand_joint_set_default[i].relation);
200200+ m_relation_chain_push_inverted_relation(&xrc, &latest_wrist);
201201+ m_relation_chain_push_relation(&xrc, &predicted_wrist);
202202+ m_relation_chain_resolve(&xrc, &out_value->values.hand_joint_set_default[i].relation);
203203+ }
204204+205205+ *out_timestamp_ns = desired_timestamp_ns;
150206}
151207152208void
···165221166222 t_ht_sync_destroy(&hta->provider);
167223224224+ for (int i = 0; i < 2; i++) {
225225+ m_relation_history_destroy(&hta->present.relation_hist[i]);
226226+ }
227227+168228 free(hta);
169229}
170230···181241 hta->base.get_hand = ht_async_get_hand;
182242183243 hta->provider = sync;
244244+245245+ for (int i = 0; i < 2; i++) {
246246+ m_relation_history_create(&hta->present.relation_hist[i]);
247247+ }
248248+249249+ u_var_add_root(hta, "Hand-tracking async shim!", 0);
250250+251251+ //!@todo We came up with this value just by seeing what worked - with Index and WMR, we'd be around 40ms late by
252252+ //! the time the camera frames arrived and were processed.
253253+254254+ // We _really_ need a way to calibrate this live - something like an exponential filter that looks at the
255255+ // typical maximum time between the time at which we were asked for a sample and most recent processed sample
256256+ // timestamp.
257257+258258+ hta->prediction_offset_ms.val = -40;
259259+ hta->prediction_offset_ms.step = 0.5;
260260+261261+ hta->use_prediction = true;
262262+263263+ // No need to enforce limits, although generally around -40 is what you want.
264264+ hta->prediction_offset_ms.min = -1000000;
265265+ hta->prediction_offset_ms.max = 1000000;
266266+267267+ u_var_add_bool(hta, &hta->use_prediction, "Predict wrist movement");
268268+ u_var_add_draggable_f32(hta, &hta->prediction_offset_ms, "Amount to time-travel (ms)");
269269+184270185271 os_mutex_init(&hta->present.mutex);
186272 os_thread_helper_init(&hta->mainloop);