fix: timestamp predicted Touch poses

This commit is contained in:
XxJSONDeruloxX committed 2026-10-14 22:12:15 -04:00
1 parent b60fac6dda
commit 356bdede67
4 files changed
+15 -3

No files matched your search

+4
View File
@@ -321,6 +321,10 @@ thumbrest and face-button touch actions in previously unused button bits, keepin
the 296-byte tracking layout and existing low click bits compatible. Inactive
hands clear every input; invalid analog values are sanitized. The flat Cardboard
gamepad path retains its existing Vive profile and mappings.
Hand poses now carry the converted OpenXR prediction timestamp relative to
SteamVR's clock, matching the headset instead of reporting a future hand pose
as a present-time sample. The common timestamp conversion is host-tested for
future, past and unavailable prediction times.
Host tests cover the input decoder's independent clicks, touch-versus-press,
handed menu, analog ranges and inactive reset. The Android native frontend and
+4 -3
View File
@@ -431,7 +431,7 @@ public:
DriverPose_t GetPose() override { return pose_; }
VRInputComponentHandle_t HapticHandle() const { return haptic_; }
void UpdateXr(const DroidDeckXrHand &hand) {
void UpdateXr(const DroidDeckXrHand &hand, int64_t predicted) {
if (id_ == k_unTrackedDeviceIndexInvalid) return;
DriverPose_t pose{};
pose.qWorldFromDriverRotation.w = pose.qDriverFromHeadRotation.w = 1;
@@ -441,6 +441,7 @@ public:
if (pose.poseIsValid) {
pose.qRotation = {hand.pose.orientation[3], hand.pose.orientation[0], hand.pose.orientation[1], hand.pose.orientation[2]};
for (int axis = 0; axis < 3; axis++) pose.vecPosition[axis] = hand.pose.position[axis];
pose.poseTimeOffset = XrTrackingFile::PoseTimeOffset(predicted, XrTrackingFile::Now());
}
pose.result = pose.poseIsValid ? TrackingResult_Running_OK : TrackingResult_Running_OutOfRange;
pose_ = pose;
@@ -611,7 +612,7 @@ public:
if (p.poseIsValid) {
p.qRotation = {xr.head.orientation[3], xr.head.orientation[0], xr.head.orientation[1], xr.head.orientation[2]};
for (int axis = 0; axis < 3; axis++) p.vecPosition[axis] = xr.head.position[axis];
if (xr.predicted_ns > 0) p.poseTimeOffset = (xr.predicted_ns - XrTrackingFile::Now()) / 1000000000.0;
p.poseTimeOffset = XrTrackingFile::PoseTimeOffset(xr.predicted_ns, XrTrackingFile::Now());
}
return p;
}
@@ -678,7 +679,7 @@ private:
VRServerDriverHost()->TrackedDevicePoseUpdated(id_, head, sizeof(head));
for (int hand = 0; hand < 2; hand++) if (hands_[hand]) {
DroidDeckXrHand state = fresh ? xr.hands[hand] : DroidDeckXrHand{};
hands_[hand]->UpdateXr(state);
hands_[hand]->UpdateXr(state, fresh ? xr.predicted_ns : 0);
}
VRDriverInput()->UpdateBooleanComponent(proximity_, fresh, 0);
std::this_thread::sleep_for(std::chrono::milliseconds(2));
+3
View File
@@ -42,6 +42,9 @@ public:
timespec now{}; clock_gettime(CLOCK_MONOTONIC, &now);
return (int64_t)now.tv_sec * 1000000000LL + now.tv_nsec;
}
static double PoseTimeOffset(int64_t predicted, int64_t now) {
return predicted > 0 ? (static_cast<double>(predicted) - static_cast<double>(now)) / 1000000000.0 : 0;
}
static bool Fresh(const DroidDeckXrTracking &packet) {
int64_t age = Now() - packet.sampled_ns;
return packet.active && age >= 0 && age < 500000000LL && packet.period_ns >= 1000000LL
+4
View File
@@ -5,6 +5,10 @@
#include <limits>
int main(int argc, char **argv) {
assert(XrTrackingFile::PoseTimeOffset(1010000000LL, 1000000000LL) == 0.01);
assert(XrTrackingFile::PoseTimeOffset(990000000LL, 1000000000LL) == -0.01);
assert(XrTrackingFile::PoseTimeOffset(0, 1000000000LL) == 0);
assert(XrTrackingFile::PoseTimeOffset(-1, 1000000000LL) == 0);
char filename[256];
std::snprintf(filename, sizeof(filename), "%s/droiddeck-xr-test-XXXXXX", argc > 1 ? argv[1] : "/tmp");
int descriptor = mkstemp(filename);