mirror of
https://github.com/lbgos/rift-s-linux.git
synced 2026-10-17 13:00:59 +02:00
Keep recognized SteamVR room stable and enable Wayland desktop capture
This commit is contained in:
1 parent
4024175ac8
commit
b7ee38860c
10 files changed
+235
-25
No files matched your search
@@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Rift S SteamVR
|
||||
Exec=@CMAKE_INSTALL_FULL_BINDIR@/rifts-steamvr
|
||||
Icon=steam
|
||||
Terminal=false
|
||||
Categories=Game;
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Steam owns desktop capture. Enable its portal path for native Wayland windows.
|
||||
set -eu
|
||||
if [ "${XDG_SESSION_TYPE:-}" = wayland ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then
|
||||
exec steam -pipewire -applaunch 250820 -pipewire "$@"
|
||||
fi
|
||||
exec steam -applaunch 250820 "$@"
|
||||
@@ -246,8 +246,10 @@ rift_s_slam_guard_suspend(struct rift_s_slam_guard *g, const struct xrt_quat *fu
|
||||
}
|
||||
|
||||
bool
|
||||
rift_s_slam_guard_verify_world(struct rift_s_slam_guard *g, const struct xrt_pose *world_from_slam)
|
||||
rift_s_slam_guard_verify_world(struct rift_s_slam_guard *g, const struct xrt_pose *world_from_slam,
|
||||
uint32_t confirmations)
|
||||
{
|
||||
if (confirmations < 3) return true;
|
||||
float dot = fabsf(g->align.orientation.x * world_from_slam->orientation.x +
|
||||
g->align.orientation.y * world_from_slam->orientation.y +
|
||||
g->align.orientation.z * world_from_slam->orientation.z +
|
||||
|
||||
@@ -166,9 +166,10 @@ rift_s_slam_guard_fallback_pose(const struct rift_s_slam_guard *g,
|
||||
void
|
||||
rift_s_slam_guard_suspend(struct rift_s_slam_guard *g, const struct xrt_quat *fusion_orientation);
|
||||
|
||||
//! Compare a fresh visual match with the current alignment; revoke saved bounds on disagreement.
|
||||
//! Revoke saved bounds only after three agreeing visual votes disagree with the current alignment.
|
||||
bool
|
||||
rift_s_slam_guard_verify_world(struct rift_s_slam_guard *g, const struct xrt_pose *world_from_slam);
|
||||
rift_s_slam_guard_verify_world(struct rift_s_slam_guard *g, const struct xrt_pose *world_from_slam,
|
||||
uint32_t confirmations);
|
||||
|
||||
//! Start the replacement backend's recovery interval without changing the held world pose.
|
||||
void
|
||||
|
||||
@@ -1320,6 +1320,9 @@ world_write_status(struct rift_s_tracker *t)
|
||||
: "unanchored";
|
||||
struct rift_s_world_diagnostics diagnostics = t->world_diagnostics;
|
||||
bool standby = t->standby, paused = t->slam_paused, restarting = t->slam_restart_pending;
|
||||
bool tracking = t->slam_guard.state == RIFT_S_SLAM_GUARD_TRACKING;
|
||||
bool world_valid = t->slam_guard.world_valid;
|
||||
bool alignment_changed = t->world_alignment_changed;
|
||||
uint64_t generation = t->slam_generation;
|
||||
uint32_t confirmations = t->world_confirmations;
|
||||
os_mutex_unlock(&t->mutex);
|
||||
@@ -1363,14 +1366,14 @@ world_write_status(struct rift_s_tracker *t)
|
||||
// available without a debug launch or stopping tracking with a debugger.
|
||||
fprintf(file, "%lld %s attempts=%" PRIu64 " usable=%" PRIu64
|
||||
" capture_ns=%lld sample_ns=%lld pose_valid=%d flags=%u history=%d standby=%d paused=%d restart=%d"
|
||||
" generation=%" PRIu64 " confirmations=%u keyframes=%u"
|
||||
" tracking=%d world_valid=%d alignment_changed=%d generation=%" PRIu64 " confirmations=%u keyframes=%u"
|
||||
" features=%u/%u/%u/%u/%u matches=%u/%u/%u/%u/%u inliers=%u/%u/%u/%u/%u"
|
||||
" matched=%d rejection=%s"
|
||||
" fail_paused=%" PRIu64 " fail_sample=%" PRIu64 " fail_gap=%" PRIu64 " fail_flags=%" PRIu64
|
||||
" fail_generation=%" PRIu64 " fail_guard=%" PRIu64 "\n",
|
||||
(long long)os_monotonic_get_ns(), state, diagnostics.attempts, diagnostics.usable,
|
||||
(long long)diagnostics.capture_ns, (long long)diagnostics.sample_ns, diagnostics.pose_valid,
|
||||
diagnostics.pose_flags, diagnostics.history_result, standby, paused, restarting, generation, confirmations, result->keyframes,
|
||||
diagnostics.pose_flags, diagnostics.history_result, standby, paused, restarting, tracking, world_valid, alignment_changed, generation, confirmations, result->keyframes,
|
||||
result->features[0], result->features[1], result->features[2], result->features[3], result->features[4],
|
||||
result->matches[0], result->matches[1], result->matches[2], result->matches[3], result->matches[4],
|
||||
result->inliers[0], result->inliers[1], result->inliers[2], result->inliers[3], result->inliers[4],
|
||||
@@ -1398,6 +1401,7 @@ world_read_command(struct rift_s_tracker *t)
|
||||
rift_s_world_anchor_clear(t->world_anchor);
|
||||
os_mutex_lock(&t->mutex);
|
||||
t->world_setup = true;
|
||||
t->world_alignment_changed = false;
|
||||
t->slam_guard.boundary_confirmed = false;
|
||||
t->slam_guard.require_relocalization = false;
|
||||
t->world_confirmations = 0;
|
||||
@@ -1423,6 +1427,7 @@ world_read_command(struct rift_s_tracker *t)
|
||||
t->slam_guard.boundary_confirmed = saved && t->slam_guard.world_valid &&
|
||||
rift_s_world_anchor_has_map(t->world_anchor);
|
||||
t->world_setup = false;
|
||||
t->world_alignment_changed = false;
|
||||
t->world_map_available = rift_s_world_anchor_has_map(t->world_anchor);
|
||||
t->slam_guard.require_relocalization = requires_relocalization;
|
||||
if (!saved || !t->world_map_available)
|
||||
@@ -1444,6 +1449,7 @@ world_read_command(struct rift_s_tracker *t)
|
||||
rift_s_slam_guard_suspend(&t->slam_guard, &t->pose.orientation);
|
||||
}
|
||||
t->world_setup = false;
|
||||
t->world_alignment_changed = false;
|
||||
t->world_map_available = rift_s_world_anchor_has_map(t->world_anchor);
|
||||
t->slam_guard.require_relocalization = requires_relocalization;
|
||||
t->world_confirmations = 0;
|
||||
@@ -1626,12 +1632,6 @@ rift_s_world_thread(void *ptr)
|
||||
struct xrt_vec3 rotated;
|
||||
math_quat_rotate_vec3(&candidate.orientation, &capture.pose.position, &rotated);
|
||||
candidate.position = m_vec3_sub(result.world_from_imu.position, rotated);
|
||||
if (t->slam_guard.boundary_confirmed &&
|
||||
!rift_s_slam_guard_verify_world(&t->slam_guard, &candidate)) {
|
||||
t->world_confirmations = 0;
|
||||
t->world_last_verify_ns = 0;
|
||||
RIFT_S_WARN("Saved room alignment changed; boundary unavailable until reconfirmed");
|
||||
}
|
||||
bool consistent =
|
||||
t->world_confirmations > 0 && t->world_candidate_generation == generation &&
|
||||
capture_ns > t->world_candidate_ns &&
|
||||
@@ -1644,8 +1644,18 @@ rift_s_world_thread(void *ptr)
|
||||
t->world_candidate = candidate;
|
||||
t->world_candidate_generation = generation;
|
||||
t->world_candidate_ns = capture_ns;
|
||||
if (t->world_confirmations >= 3 && !t->slam_guard.boundary_confirmed) {
|
||||
// Verification needs the same three agreeing votes as recognition. One
|
||||
// displaced solution must not revoke bounds and re-place the dashboard.
|
||||
if (t->slam_guard.boundary_confirmed) {
|
||||
if (!rift_s_slam_guard_verify_world(&t->slam_guard, &candidate, t->world_confirmations)) {
|
||||
t->world_alignment_changed = true;
|
||||
t->world_last_verify_ns = 0;
|
||||
RIFT_S_WARN("Saved room alignment changed across three votes; boundary unavailable until reconfirmed");
|
||||
}
|
||||
if (t->world_confirmations >= 3) t->world_confirmations = 0;
|
||||
} else if (t->world_confirmations >= 3) {
|
||||
rift_s_slam_guard_set_world(&t->slam_guard, &candidate);
|
||||
t->world_alignment_changed = false;
|
||||
RIFT_S_INFO(
|
||||
"World relocalized inliers=%u/%u error_px=%.3f "
|
||||
"transform=(%.4f,%.4f,%.4f)",
|
||||
|
||||
@@ -73,6 +73,7 @@ struct rift_s_tracker
|
||||
bool world_setup;
|
||||
bool world_map_available;
|
||||
bool world_storage_failed;
|
||||
bool world_alignment_changed;
|
||||
uint64_t world_command_id;
|
||||
uint32_t world_confirmations;
|
||||
struct xrt_pose world_candidate;
|
||||
|
||||
@@ -90,7 +90,8 @@ is_rift_s_touch(const struct xrt_device *xdev)
|
||||
}
|
||||
|
||||
static void
|
||||
update_rift_s_universe(vr::PropertyContainerHandle_t container, uint64_t &universe, int64_t &last_poll)
|
||||
update_rift_s_universe(vr::PropertyContainerHandle_t container, uint64_t &universe, int64_t &last_poll,
|
||||
RiftSWorldUniverse &selection)
|
||||
{
|
||||
int64_t now = os_monotonic_get_ns();
|
||||
if (now - last_poll < 500000000LL) return;
|
||||
@@ -101,9 +102,10 @@ update_rift_s_universe(vr::PropertyContainerHandle_t container, uint64_t &univer
|
||||
int64_t stamp = 0;
|
||||
std::string status;
|
||||
stream >> stamp >> status;
|
||||
if (!stream) return; // Missing or half-written status: keep the current universe, do not flap.
|
||||
static const int64_t started = now;
|
||||
uint64_t next = rift_s_world_universe(status, stamp, now, started);
|
||||
std::string details;
|
||||
if (stream) std::getline(stream, details);
|
||||
else { stamp = 0; status.clear(); }
|
||||
uint64_t next = selection.update(status, stamp, now, details, universe);
|
||||
if (next == universe) return;
|
||||
auto error = vr::VRProperties()->SetUint64Property(container, vr::Prop_CurrentUniverseId_Uint64, next);
|
||||
if (error == vr::TrackedProp_Success) {
|
||||
@@ -928,7 +930,7 @@ public:
|
||||
|
||||
if (m_unObjectId != vr::k_unTrackedDeviceIndexInvalid) {
|
||||
if (is_rift_s_touch(m_xdev))
|
||||
update_rift_s_universe(m_ulPropertyContainer, m_worldUniverse, m_worldPoll);
|
||||
update_rift_s_universe(m_ulPropertyContainer, m_worldUniverse, m_worldPoll, m_worldSelection);
|
||||
vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_unObjectId, GetPose(),
|
||||
sizeof(vr::DriverPose_t));
|
||||
}
|
||||
@@ -961,8 +963,14 @@ public:
|
||||
m_ulPropertyContainer = vr::VRProperties()->TrackedDeviceToPropertyContainer(m_unObjectId);
|
||||
|
||||
// return a constant that's not 0 (invalid) or 1 (reserved for Oculus)
|
||||
m_worldUniverse = is_rift_s_touch(m_xdev) ? 3 : 2;
|
||||
vr::VRProperties()->SetUint64Property(m_ulPropertyContainer, vr::Prop_CurrentUniverseId_Uint64, m_worldUniverse);
|
||||
if (m_poseUpdateThread == nullptr) {
|
||||
m_worldSelection = {};
|
||||
m_worldPoll = 0;
|
||||
m_worldUniverse = is_rift_s_touch(m_xdev) ? 3 : 2;
|
||||
auto error = vr::VRProperties()->SetUint64Property(m_ulPropertyContainer,
|
||||
vr::Prop_CurrentUniverseId_Uint64, m_worldUniverse);
|
||||
if (error != vr::TrackedProp_Success) m_worldUniverse = 0; // Retry on the pose thread.
|
||||
}
|
||||
vr::VRProperties()->SetInt32Property(m_ulPropertyContainer, vr::Prop_DeviceClass_Int32, vr::TrackedDeviceClass_Controller);
|
||||
|
||||
if (m_hand == XRT_HAND_LEFT) {
|
||||
@@ -1316,6 +1324,7 @@ public:
|
||||
vr::PropertyContainerHandle_t m_ulPropertyContainer = vr::k_ulInvalidPropertyContainer;
|
||||
uint64_t m_worldUniverse = 3;
|
||||
int64_t m_worldPoll = 0;
|
||||
RiftSWorldUniverse m_worldSelection;
|
||||
|
||||
bool m_emulate_index_controller = false;
|
||||
|
||||
@@ -1430,6 +1439,7 @@ private:
|
||||
vr::PropertyContainerHandle_t m_ulPropertyContainer = vr::k_ulInvalidPropertyContainer;
|
||||
uint64_t m_worldUniverse = 3;
|
||||
int64_t m_worldPoll = 0;
|
||||
RiftSWorldUniverse m_worldSelection;
|
||||
|
||||
float m_flSecondsFromVsyncToPhotons = -1;
|
||||
float m_flDisplayFrequency = -1;
|
||||
@@ -1513,7 +1523,7 @@ CDeviceDriver_Monado::PoseUpdateThreadFunction()
|
||||
vr::VRDriverInput()->UpdateBooleanComponent(m_proximity, detected, 0);
|
||||
}
|
||||
if (strncmp(m_xdev->str, "Oculus Rift S", 13) == 0)
|
||||
update_rift_s_universe(m_ulPropertyContainer, m_worldUniverse, m_worldPoll);
|
||||
update_rift_s_universe(m_ulPropertyContainer, m_worldUniverse, m_worldPoll, m_worldSelection);
|
||||
vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_trackedDeviceIndex, GetPose(),
|
||||
sizeof(vr::DriverPose_t));
|
||||
}
|
||||
@@ -1555,8 +1565,14 @@ CDeviceDriver_Monado::Activate(vr::TrackedDeviceIndex_t unObjectId)
|
||||
// return a constant that's not 0 (invalid) or 1 (reserved for Oculus)
|
||||
if (strncmp(m_xdev->str, "Oculus Rift S", 13) == 0 && !rift_s_prepare_session_origin())
|
||||
ovrd_log("Could not prepare unbounded Rift S session origin\n");
|
||||
m_worldUniverse = strncmp(m_xdev->str, "Oculus Rift S", 13) == 0 ? 3 : 2;
|
||||
vr::VRProperties()->SetUint64Property(m_ulPropertyContainer, vr::Prop_CurrentUniverseId_Uint64, m_worldUniverse);
|
||||
if (m_poseUpdateThread == nullptr) {
|
||||
m_worldSelection = {};
|
||||
m_worldPoll = 0;
|
||||
m_worldUniverse = strncmp(m_xdev->str, "Oculus Rift S", 13) == 0 ? 3 : 2;
|
||||
auto error = vr::VRProperties()->SetUint64Property(m_ulPropertyContainer,
|
||||
vr::Prop_CurrentUniverseId_Uint64, m_worldUniverse);
|
||||
if (error != vr::TrackedProp_Success) m_worldUniverse = 0; // Retry on the pose thread.
|
||||
}
|
||||
|
||||
if (m_xdev->camera) {
|
||||
vr::EVRInitError queue_error = vr::VRInitError_None;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <charconv>
|
||||
|
||||
// Universe 2 contains the saved room. Universe 3 has only an unbounded session origin.
|
||||
// A session frame must never use universe 2's floor, heading or collision bounds.
|
||||
@@ -13,3 +14,66 @@ rift_s_world_universe(std::string_view status, int64_t stamp, int64_t now, int64
|
||||
bool fresh = stamp > 0 && stamp >= started && stamp <= now && now - stamp <= 2000000000LL;
|
||||
return fresh && (status == "localized" || status == "setup") ? 2 : 3;
|
||||
}
|
||||
|
||||
// Keep an admitted room through visual-matching misses in the same tracked frame.
|
||||
// Coordinate-frame replacement is immediate; continuous tracking/status loss gets five seconds.
|
||||
class RiftSWorldUniverse
|
||||
{
|
||||
int64_t started = 0;
|
||||
int64_t lost_since = 0;
|
||||
uint64_t generation = 0;
|
||||
bool have_generation = false;
|
||||
|
||||
static int64_t field(std::string_view details, std::string_view key)
|
||||
{
|
||||
while (!details.empty()) {
|
||||
auto end = details.find(' ');
|
||||
auto token = details.substr(0, end);
|
||||
if (token.substr(0, key.size()) == key && token.size() > key.size() && token[key.size()] == '=') {
|
||||
int64_t value = -1;
|
||||
auto number = token.substr(key.size() + 1);
|
||||
auto result = std::from_chars(number.data(), number.data() + number.size(), value);
|
||||
return result.ec == std::errc{} && result.ptr == number.data() + number.size() ? value : -1;
|
||||
}
|
||||
if (end == std::string_view::npos) break;
|
||||
details.remove_prefix(end + 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
uint64_t update(std::string_view status, int64_t stamp, int64_t now,
|
||||
std::string_view details, uint64_t current)
|
||||
{
|
||||
if (!started) started = now;
|
||||
current = current == 2 ? 2 : 3;
|
||||
bool fresh = stamp > 0 && stamp >= started && stamp <= now && now - stamp <= 2000000000LL;
|
||||
if (fresh) {
|
||||
auto next_generation = field(details, "generation");
|
||||
bool replaced = next_generation >= 0 && have_generation &&
|
||||
generation != static_cast<uint64_t>(next_generation);
|
||||
if (next_generation >= 0) {
|
||||
generation = static_cast<uint64_t>(next_generation);
|
||||
have_generation = true;
|
||||
}
|
||||
if (replaced || field(details, "standby") == 1 || field(details, "restart") == 1 ||
|
||||
field(details, "world_valid") == 0 || field(details, "alignment_changed") == 1 ||
|
||||
status == "unanchored" || status == "save_failed") {
|
||||
lost_since = 0;
|
||||
return 3;
|
||||
}
|
||||
if ((status == "setup" || status == "localized") && field(details, "tracking") == 1 && field(details, "world_valid") == 1 &&
|
||||
field(details, "paused") == 0) {
|
||||
lost_since = 0;
|
||||
return 2;
|
||||
}
|
||||
if (status == "relocalizing" && field(details, "tracking") == 1 && field(details, "world_valid") == 1 &&
|
||||
field(details, "paused") == 0) {
|
||||
lost_since = 0;
|
||||
return current;
|
||||
}
|
||||
}
|
||||
if (!lost_since) lost_since = now;
|
||||
return now - lost_since >= 5000000000LL ? 3 : current;
|
||||
}
|
||||
};
|
||||
@@ -88,6 +88,10 @@ if(TARGET monado-roomsetup-guard)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
configure_file(${PROJECT_SOURCE_DIR}/scripts/rifts-setup.in ${PROJECT_BINARY_DIR}/rifts-setup @ONLY)
|
||||
configure_file(${PROJECT_SOURCE_DIR}/scripts/rifts-steamvr.in ${PROJECT_BINARY_DIR}/rifts-steamvr @ONLY)
|
||||
configure_file(${PROJECT_SOURCE_DIR}/scripts/rifts-steamvr.desktop.in ${PROJECT_BINARY_DIR}/rifts-steamvr.desktop @ONLY)
|
||||
install(PROGRAMS ${PROJECT_BINARY_DIR}/rifts-steamvr DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(FILES ${PROJECT_BINARY_DIR}/rifts-steamvr.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
||||
configure_file(${PROJECT_SOURCE_DIR}/scripts/rifts-session-install.in ${PROJECT_BINARY_DIR}/rifts-session-install @ONLY)
|
||||
configure_file(${PROJECT_SOURCE_DIR}/scripts/rifts-steamvr-registration.service.in
|
||||
${PROJECT_BINARY_DIR}/rifts-steamvr-registration.service @ONLY)
|
||||
|
||||
@@ -537,18 +537,116 @@ TEST_CASE("A fresh visual match detects saved boundary translation and yaw drift
|
||||
xrt_pose candidate = saved;
|
||||
SECTION("Near alignment remains confirmed") {
|
||||
candidate.position.x += .03f;
|
||||
CHECK(rift_s_slam_guard_verify_world(&s.g, &candidate));
|
||||
CHECK(rift_s_slam_guard_verify_world(&s.g, &candidate, 3));
|
||||
CHECK(s.g.boundary_confirmed);
|
||||
}
|
||||
SECTION("Translation drift hides bounds without moving the held pose") {
|
||||
candidate.position.x += .05f;
|
||||
CHECK_FALSE(rift_s_slam_guard_verify_world(&s.g, &candidate));
|
||||
CHECK_FALSE(rift_s_slam_guard_verify_world(&s.g, &candidate, 3));
|
||||
CHECK_FALSE(s.g.boundary_confirmed);
|
||||
}
|
||||
SECTION("Yaw drift hides bounds") {
|
||||
candidate.orientation = yaw_quat(yaw_of(saved.orientation) + .06f);
|
||||
CHECK_FALSE(rift_s_slam_guard_verify_world(&s.g, &candidate));
|
||||
CHECK_FALSE(rift_s_slam_guard_verify_world(&s.g, &candidate, 3));
|
||||
CHECK_FALSE(s.g.boundary_confirmed);
|
||||
}
|
||||
CHECK(dist(s.g.align.position, saved.position) < 1e-6f);
|
||||
}
|
||||
|
||||
TEST_CASE("Admitted SteamVR room survives alternating matching status without universe flips")
|
||||
{
|
||||
RiftSWorldUniverse selection;
|
||||
const int64_t start = 10000000000LL;
|
||||
uint64_t universe = selection.update("localized", start, start,
|
||||
" generation=6 tracking=1 world_valid=1 standby=0 paused=0 restart=0", 3);
|
||||
REQUIRE(universe == 2);
|
||||
unsigned flips = 0;
|
||||
for (int i = 1; i <= 120; ++i) {
|
||||
auto now = start + i * 500 * MS;
|
||||
auto next = selection.update(i % 2 ? "relocalizing" : "localized", now, now,
|
||||
"generation=6 tracking=1 world_valid=1 standby=0 paused=0 restart=0", universe);
|
||||
flips += next != universe;
|
||||
universe = next;
|
||||
}
|
||||
CHECK(flips == 0);
|
||||
// Matching failure alone does not prove another room, even after a minute.
|
||||
for (int i = 121; i <= 240; ++i) {
|
||||
auto now = start + i * 500 * MS;
|
||||
universe = selection.update("relocalizing", now, now,
|
||||
"generation=6 tracking=1 world_valid=1 paused=0", universe);
|
||||
CHECK(universe == 2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("SteamVR room hysteresis releases real tracking or coordinate-frame loss")
|
||||
{
|
||||
RiftSWorldUniverse selection;
|
||||
const int64_t start = 10000000000LL;
|
||||
const auto tracked = "generation=6 tracking=1 world_valid=1 paused=0";
|
||||
REQUIRE(selection.update("localized", start, start, tracked, 3) == 2);
|
||||
SECTION("continuous tracking loss has a five second grace") {
|
||||
CHECK(selection.update("relocalizing", start + MS, start + MS,
|
||||
"generation=6 tracking=0 world_valid=1", 2) == 2);
|
||||
CHECK(selection.update("relocalizing", start + 5000 * MS, start + 5000 * MS,
|
||||
"generation=6 tracking=0 world_valid=1", 2) == 2);
|
||||
CHECK(selection.update("relocalizing", start + 5001 * MS, start + 5001 * MS,
|
||||
"generation=6 tracking=0 world_valid=1", 2) == 3);
|
||||
}
|
||||
SECTION("a brief loss followed by tracked matching misses clears the timer") {
|
||||
CHECK(selection.update("relocalizing", start + MS, start + MS,
|
||||
"tracking=0 world_valid=1", 2) == 2);
|
||||
CHECK(selection.update("relocalizing", start + 4000 * MS, start + 4000 * MS, tracked, 2) == 2);
|
||||
CHECK(selection.update("relocalizing", start + 6000 * MS, start + 6000 * MS,
|
||||
"tracking=0 world_valid=1", 2) == 2);
|
||||
}
|
||||
SECTION("missing and stale status eventually release bounds") {
|
||||
CHECK(selection.update("", 0, start + MS, "", 2) == 2);
|
||||
CHECK(selection.update("", 0, start + 5001 * MS, "", 2) == 3);
|
||||
CHECK(selection.update("localized", start, start + 6000 * MS, tracked, 3) == 3);
|
||||
}
|
||||
SECTION("standby and replacement frames release immediately") {
|
||||
CHECK(selection.update("localized", start + MS, start + MS, "standby=1", 2) == 3);
|
||||
CHECK(selection.update("localized", start + MS, start + MS, "generation=7", 2) == 3);
|
||||
CHECK(selection.update("relocalizing", start + MS, start + MS, "world_valid=0", 2) == 3);
|
||||
CHECK(selection.update("relocalizing", start + MS, start + MS, "alignment_changed=1", 2) == 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("SteamVR room admission rejects a prior runtime's status")
|
||||
{
|
||||
RiftSWorldUniverse selection;
|
||||
const int64_t start = 10000000000LL;
|
||||
CHECK(selection.update("localized", start - 1, start, "tracking=1 world_valid=1 paused=0", 3) == 3);
|
||||
CHECK(selection.update("relocalizing", start + MS, start + MS, "tracking=1 world_valid=1 paused=0", 3) == 3);
|
||||
CHECK(selection.update("localized", start + 2 * MS, start + 2 * MS, "tracking=1 world_valid=1 paused=0", 3) == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("One displaced alignment vote cannot revoke saved bounds")
|
||||
{
|
||||
Sim s;
|
||||
xrt_pose raw = XRT_POSE_IDENTITY;
|
||||
REQUIRE(s.settle(raw) > 0);
|
||||
xrt_pose candidate = s.g.align;
|
||||
rift_s_slam_guard_set_world(&s.g, &candidate);
|
||||
candidate.position.x += .1f;
|
||||
for (uint32_t votes = 1; votes < 3; ++votes) {
|
||||
CHECK(rift_s_slam_guard_verify_world(&s.g, &candidate, votes));
|
||||
CHECK(s.g.boundary_confirmed);
|
||||
}
|
||||
CHECK_FALSE(rift_s_slam_guard_verify_world(&s.g, &candidate, 3));
|
||||
CHECK_FALSE(s.g.boundary_confirmed);
|
||||
}
|
||||
|
||||
TEST_CASE("SteamVR room admission needs complete live tracking metadata")
|
||||
{
|
||||
const int64_t start = 10000000000LL;
|
||||
for (auto details : {"", "tracking=garbage world_valid=1 paused=0",
|
||||
"tracking=2 world_valid=1 paused=0", "tracking=1 paused=0",
|
||||
"tracking=1 world_valid=1", "tracking=1 world_valid=1 paused=1"}) {
|
||||
RiftSWorldUniverse selection;
|
||||
CHECK(selection.update("localized", start, start, details, 3) == 3);
|
||||
}
|
||||
RiftSWorldUniverse selection;
|
||||
CHECK(selection.update("setup", start, start, "tracking=1 world_valid=1 paused=0", 3) == 2);
|
||||
CHECK(selection.update("localized", start + MS, start + MS, "restart=1", 2) == 3);
|
||||
}
|
||||
Reference in new issue
Block a user