mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 01:00:06 +02:00
ft-powerd: ask SteamVR every 100 ms, not on every input event
The loop polled the input devices with a 100 ms timeout and then, on every wake, did SteamVR's part: PollNextEvent, the headset's activity level and every device's pose, all IPC calls to vrserver. Input wakes it at once so the displays come on with the first key or motion, but a moving mouse sends hundreds of events a second, so moving the mouse meant hundreds of rounds of IPC a second instead of 10. Every wake still drains the input devices and the control socket and counts input as use straight away; SteamVR's part, and the backlight read that goes with it, now run only when 100 ms have passed since the last time, and poll sleeps until then. Built in the dev container (power/build.sh, no warnings); not run, since the live ft-powerd holds @ft_powerd. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b7dfe4759e
commit
57617d4a14
1 file changed
+72
-64
+72
-64
@@ -306,14 +306,19 @@ int main() {
|
||||
std::printf("displays on: %s\n", why.c_str());
|
||||
};
|
||||
|
||||
// SteamVR is asked every 100 ms (events, the activity level, poses: IPC calls to
|
||||
// vrserver). Input wakes the loop too, to wake the displays at once, but a moving mouse
|
||||
// sends hundreds of events a second, so those wakes only drain the devices.
|
||||
constexpr auto kTick = std::chrono::milliseconds(100);
|
||||
auto lastVr = now - kTick;
|
||||
std::vector<pollfd> fds;
|
||||
while (!stopSignal) {
|
||||
// Sleep until input or 100 ms: input wakes the displays at once, poses every tick.
|
||||
fds.clear();
|
||||
fds.push_back({ctl, POLLIN, 0});
|
||||
for (auto &[path, d] : inputs)
|
||||
if (d.fd >= 0) fds.push_back({d.fd, POLLIN, 0});
|
||||
poll(fds.data(), fds.size(), 100);
|
||||
const auto wait = std::chrono::ceil<std::chrono::milliseconds>(kTick - (Clock::now() - lastVr));
|
||||
poll(fds.data(), fds.size(), std::clamp<int>(wait.count(), 0, kTick.count()));
|
||||
now = Clock::now();
|
||||
const bool grace = now < graceUntil;
|
||||
std::string use; // why this tick counts as use
|
||||
@@ -329,71 +334,74 @@ int main() {
|
||||
lastConf = now;
|
||||
}
|
||||
|
||||
vr::VREvent_t ev;
|
||||
while (sys->PollNextEvent(&ev, sizeof ev)) {
|
||||
if (ev.eventType == vr::VREvent_Quit) {
|
||||
stopSignal = SIGTERM;
|
||||
sys->AcknowledgeQuit_Exiting();
|
||||
} else if (ev.eventType == vr::VREvent_TrackedDeviceActivated ||
|
||||
ev.eventType == vr::VREvent_TrackedDeviceDeactivated) {
|
||||
lastClasses = now - std::chrono::hours(1);
|
||||
}
|
||||
}
|
||||
if (now - lastClasses > std::chrono::seconds(5)) {
|
||||
for (vr::TrackedDeviceIndex_t i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i)
|
||||
classes[i] = sys->GetTrackedDeviceClass(i);
|
||||
lastClasses = now;
|
||||
}
|
||||
|
||||
// SteamVR's standby (headset taken off) turns the displays off itself; putting the
|
||||
// headset on again (or the mount covering the sensor again) counts as use.
|
||||
// A change counts once it has held for a second (the first reading after connecting
|
||||
// is Idle).
|
||||
const auto level = sys->GetTrackedDeviceActivityLevel(vr::k_unTrackedDeviceIndex_Hmd);
|
||||
const bool awayNow = level == vr::k_EDeviceActivityLevel_Idle || level == vr::k_EDeviceActivityLevel_Standby ||
|
||||
level == vr::k_EDeviceActivityLevel_Idle_Timeout;
|
||||
if (awayNow == away) awaySince = now;
|
||||
if (awayNow != away && now - awaySince >= std::chrono::seconds(1)) {
|
||||
away = awayNow;
|
||||
std::printf("SteamVR: headset %s\n", away ? "off (SteamVR's standby has the displays)" : "on");
|
||||
if (!away) use = "headset on again";
|
||||
}
|
||||
|
||||
// Raw poses: recentering or a new play area doesn't move anything.
|
||||
sys->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0, poses, vr::k_unMaxTrackedDeviceCount);
|
||||
for (vr::TrackedDeviceIndex_t i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i) {
|
||||
const auto c = classes[i];
|
||||
if (c != vr::TrackedDeviceClass_HMD && c != vr::TrackedDeviceClass_Controller &&
|
||||
c != vr::TrackedDeviceClass_GenericTracker)
|
||||
continue;
|
||||
const auto &p = poses[i];
|
||||
if (!p.bPoseIsValid || p.eTrackingResult != vr::TrackingResult_Running_OK) {
|
||||
anchors[i].set = false; // tracking back or a controller turned on: start over
|
||||
continue;
|
||||
}
|
||||
if (!anchors[i].set || grace || now - anchors[i].at > kMoveWindow) {
|
||||
SetAnchor(anchors[i], p.mDeviceToAbsoluteTracking, now);
|
||||
continue;
|
||||
}
|
||||
double metres, degrees;
|
||||
Distance(anchors[i], p.mDeviceToAbsoluteTracking, metres, degrees);
|
||||
if (metres > moveMetres || degrees > moveDegrees) {
|
||||
SetAnchor(anchors[i], p.mDeviceToAbsoluteTracking, now);
|
||||
if (use.empty()) {
|
||||
char why[96];
|
||||
std::snprintf(why, sizeof why, "%s %u moved %.1f mm, %.2f deg",
|
||||
c == vr::TrackedDeviceClass_HMD ? "headset" : "device", i, metres * 1000, degrees);
|
||||
use = why;
|
||||
if (now - lastVr >= kTick) {
|
||||
lastVr = now;
|
||||
vr::VREvent_t ev;
|
||||
while (sys->PollNextEvent(&ev, sizeof ev)) {
|
||||
if (ev.eventType == vr::VREvent_Quit) {
|
||||
stopSignal = SIGTERM;
|
||||
sys->AcknowledgeQuit_Exiting();
|
||||
} else if (ev.eventType == vr::VREvent_TrackedDeviceActivated ||
|
||||
ev.eventType == vr::VREvent_TrackedDeviceDeactivated) {
|
||||
lastClasses = now - std::chrono::hours(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (now - lastClasses > std::chrono::seconds(5)) {
|
||||
for (vr::TrackedDeviceIndex_t i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i)
|
||||
classes[i] = sys->GetTrackedDeviceClass(i);
|
||||
lastClasses = now;
|
||||
}
|
||||
|
||||
if (off && ReadInt(kBacklight, -1) > 0) {
|
||||
// Something else lit them (SteamVR leaving standby, the brightness setting).
|
||||
off = false;
|
||||
std::remove(SavedPath().c_str());
|
||||
use = "turned on elsewhere";
|
||||
std::printf("displays on: turned on elsewhere\n");
|
||||
// SteamVR's standby (headset taken off) turns the displays off itself; putting the
|
||||
// headset on again (or the mount covering the sensor again) counts as use.
|
||||
// A change counts once it has held for a second (the first reading after connecting
|
||||
// is Idle).
|
||||
const auto level = sys->GetTrackedDeviceActivityLevel(vr::k_unTrackedDeviceIndex_Hmd);
|
||||
const bool awayNow = level == vr::k_EDeviceActivityLevel_Idle || level == vr::k_EDeviceActivityLevel_Standby ||
|
||||
level == vr::k_EDeviceActivityLevel_Idle_Timeout;
|
||||
if (awayNow == away) awaySince = now;
|
||||
if (awayNow != away && now - awaySince >= std::chrono::seconds(1)) {
|
||||
away = awayNow;
|
||||
std::printf("SteamVR: headset %s\n", away ? "off (SteamVR's standby has the displays)" : "on");
|
||||
if (!away) use = "headset on again";
|
||||
}
|
||||
|
||||
// Raw poses: recentering or a new play area doesn't move anything.
|
||||
sys->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0, poses, vr::k_unMaxTrackedDeviceCount);
|
||||
for (vr::TrackedDeviceIndex_t i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i) {
|
||||
const auto c = classes[i];
|
||||
if (c != vr::TrackedDeviceClass_HMD && c != vr::TrackedDeviceClass_Controller &&
|
||||
c != vr::TrackedDeviceClass_GenericTracker)
|
||||
continue;
|
||||
const auto &p = poses[i];
|
||||
if (!p.bPoseIsValid || p.eTrackingResult != vr::TrackingResult_Running_OK) {
|
||||
anchors[i].set = false; // tracking back or a controller turned on: start over
|
||||
continue;
|
||||
}
|
||||
if (!anchors[i].set || grace || now - anchors[i].at > kMoveWindow) {
|
||||
SetAnchor(anchors[i], p.mDeviceToAbsoluteTracking, now);
|
||||
continue;
|
||||
}
|
||||
double metres, degrees;
|
||||
Distance(anchors[i], p.mDeviceToAbsoluteTracking, metres, degrees);
|
||||
if (metres > moveMetres || degrees > moveDegrees) {
|
||||
SetAnchor(anchors[i], p.mDeviceToAbsoluteTracking, now);
|
||||
if (use.empty()) {
|
||||
char why[96];
|
||||
std::snprintf(why, sizeof why, "%s %u moved %.1f mm, %.2f deg",
|
||||
c == vr::TrackedDeviceClass_HMD ? "headset" : "device", i, metres * 1000, degrees);
|
||||
use = why;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (off && ReadInt(kBacklight, -1) > 0) {
|
||||
// Something else lit them (SteamVR leaving standby, the brightness setting).
|
||||
off = false;
|
||||
std::remove(SavedPath().c_str());
|
||||
use = "turned on elsewhere";
|
||||
std::printf("displays on: turned on elsewhere\n");
|
||||
}
|
||||
}
|
||||
if (!use.empty()) {
|
||||
lastUse = now;
|
||||
|
||||
Reference in new issue
Block a user