monado/src/xrt/auxiliary/util/u_time.cpp
Christoph Haag c24e482e5e st/oxr: Make OpenXR timestamps relative to service startup
This solves a problem where OpenXR timestamps could become invalid
(negative) in certain circumstances:

The timestamps that the OpenXR state tracker returned were offset such
that they appeared to start at OpenXR application startup time.

However monado-service is a long running service using system timestamps.
Because of this, if monado-service started work using a system timestamp
acquired before an OpenXR application started, then this system timestamp
could not be converted into an OpenXR without becoming invalid.

With this change, the OpenXR timestamps for OpenXR applications are offset
such that they appear to start at monado-service startup time instead.

As a side effect, all OpenXR applications connected to the same
monado-service instance will receive timestamps from the same domain.
2022-08-08 15:52:18 +00:00

145 lines
2.8 KiB
C++

// Copyright 2019-2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Implementation of a steady, convertible clock.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @ingroup aux_util
*/
#include "xrt/xrt_config_os.h"
#include "xrt/xrt_compiler.h"
#include "os/os_time.h"
#include "u_time.h"
#include <new>
#include <assert.h>
#include <stdlib.h>
#include <time.h>
/*
*
* Structs.
*
*/
struct time_state
{
timepoint_ns offset;
};
/*
*
* 'Exported' functions.
*
*/
extern "C" struct time_state *
time_state_create(uint64_t offset)
{
time_state *state = new (std::nothrow) time_state;
if (!state) {
return state;
}
state->offset = offset;
return state;
}
extern "C" void
time_state_destroy(struct time_state **state_ptr)
{
struct time_state *state = *state_ptr;
if (state == NULL) {
return;
}
delete state;
*state_ptr = NULL;
}
extern "C" timepoint_ns
time_state_get_now(struct time_state const *state)
{
assert(state != NULL);
return time_state_monotonic_to_ts_ns(state, os_monotonic_get_ns());
}
extern "C" timepoint_ns
time_state_get_now_and_update(struct time_state *state)
{
assert(state != NULL);
return time_state_get_now(state);
}
extern "C" void
time_state_to_timespec(struct time_state const *state, timepoint_ns timestamp, struct timespec *out)
{
assert(state != NULL);
assert(out != NULL);
uint64_t ns = time_state_ts_to_monotonic_ns(state, timestamp);
out->tv_sec = ns / (U_1_000_000_000);
out->tv_nsec = ns % (U_1_000_000_000);
}
extern "C" timepoint_ns
time_state_from_timespec(struct time_state const *state, const struct timespec *timespecTime)
{
assert(state != NULL);
assert(timespecTime != NULL);
uint64_t ns = 0;
ns += timespecTime->tv_nsec;
ns += timespecTime->tv_sec * U_1_000_000_000;
return time_state_monotonic_to_ts_ns(state, ns);
}
extern "C" timepoint_ns
time_state_monotonic_to_ts_ns(struct time_state const *state, uint64_t monotonic_ns)
{
assert(state != NULL);
return monotonic_ns - state->offset;
}
extern "C" uint64_t
time_state_ts_to_monotonic_ns(struct time_state const *state, timepoint_ns timestamp)
{
assert(state != NULL);
return timestamp + state->offset;
}
#ifdef XRT_OS_WINDOWS
extern "C" void
time_state_to_win32perfcounter(struct time_state const *state, timepoint_ns timestamp, LARGE_INTEGER *out_qpc_ticks)
{
assert(state != NULL);
assert(out_qpc_ticks != NULL);
uint64_t ns = time_state_ts_to_monotonic_ns(state, timestamp);
out_qpc_ticks->QuadPart = ns / os_ns_per_qpc_tick_get();
}
extern "C" timepoint_ns
time_state_from_win32perfcounter(struct time_state const *state, const LARGE_INTEGER *qpc_ticks)
{
assert(state != NULL);
assert(qpc_ticks != NULL);
uint64_t ns = qpc_ticks->QuadPart * os_ns_per_qpc_tick_get();
return time_state_monotonic_to_ts_ns(state, ns);
}
#endif // XRT_OS_WINDOWS