Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]: Driver passing a member to TrackedDevicePoseUpdated results in black frames submitted to HMD #1583

Closed
okawo80085 opened this issue Aug 28, 2021 · 4 comments

Comments

@okawo80085
Copy link

If an HMD device calls TrackedDevicePoseUpdated with a member passed as newPose it will result in black frames submitted to the device and applications such as room setup will see the device as turned off even though it appears as active in the status window.

    // DriverPose_t pose - is member of the device class
    pose.result = TrackingResult_Running_OK;
    pose.poseIsValid = true;
    pose.deviceIsConnected = true;
    /* update tracking information in pose*/

    if (m_unObjectId != vr::k_unTrackedDeviceIndexInvalid) {
      vr::VRServerDriverHost()->TrackedDevicePoseUpdated(
          m_unObjectId, pose, sizeof(pose));
    }

However if the passed pose is defined locally, the device receives proper frames and perceived normally by applications.

    DriverPose_t pose = { 0 }; // local declaration
    pose.result = TrackingResult_Running_OK;
    pose.poseIsValid = true;
    pose.deviceIsConnected = true;
    /* update tracking information in pose*/

    if (m_unObjectId != vr::k_unTrackedDeviceIndexInvalid) {
      vr::VRServerDriverHost()->TrackedDevicePoseUpdated(
          m_unObjectId, pose, sizeof(pose));
    }

I see no reason why members passed to TrackedDevicePoseUpdated should result in such behavior, its not documented anywhere, and the driver example just uses local declaration and pass without any explanation.

@okawo80085 okawo80085 changed the title [BUG]: TrackedDevicePoseUpdated if passed a member results with black frames submitted to the HMD [BUG]: Passing a member to TrackedDevicePoseUpdated results in black frames submitted to HMD Aug 28, 2021
@okawo80085 okawo80085 changed the title [BUG]: Passing a member to TrackedDevicePoseUpdated results in black frames submitted to HMD [BUG]: Driver passing a member to TrackedDevicePoseUpdated results in black frames submitted to HMD Aug 28, 2021
@okawo80085
Copy link
Author

okawo80085 commented Aug 28, 2021

I was testing this further and this may be C++ phenomenon, maybe in too used to C, this behavior persists with public members, both inherited and not.

Which still does not make it better, and it being undocumented is even worse

@okawo80085
Copy link
Author

I've been testing it more, trying to reproduce this behavior in normal C++ has been unsuccessful so far, the sample driver is next on the chopping block, it should be closer to the ideal test case and its easier to break

im testing builds with cmake on linux amd64 and windows x64

@okawo80085
Copy link
Author

Well well well, i found the root cause of this issue, and it appears to be poor C++ design on my part, unfortunately tho the same design is used in places in openvr too...

The root cause of this issue is inline virtual default methods of the parent class, especially when the parent class is in the header that is not included in project's source files(in my case it was a missed include directory after a project restructure), and worst of all is that this can cause undefined behavior.

That means that random methods from child classes will use the default parent methods instead of the child methods. In my case it resulted in my pose update method and my display component's methods being switched to the default ones at random, with no indication of it happening apart from the devices not behaving how i expected them to, and seemingly code that should be executed not being executed.

Why is this issue important? Because the compiler will not catch this issue, and the closest you can get to catching this issue is to enable Wall, Wextra, pedantic and Werror but even then there is no guaranty it will catch it, because this is not actually an code error, its an error in design intention that the compiler has no way of knowing about.

However after enabling Wall, Wextra, pedantic and Werror I found out that openvr driver API itself does not comply with Werror and pedantic....

To be specific the IVRDriverDirectModeComponent and IVRWatchdogHost interfaces, i had to patch them, as well as other things, in my fork of openvr (see werror fix, pedantic fix and other fixes in my fork)

Why is the majority of open source drivers don't encounter this issue? Most open source drivers don't use device/component parents, due to the fact that their drivers only need to support one(or very few) specific hardware devices in which case they are rather simple and directly inheriting ITrackedDeviceServerDriver to their device classes may be good enough AND most of the said drivers are derived from the sample driver present in this repository.
Which is simply too old(but that's a completely different issue)

Not all drivers can afford to be that simple though.

So how do we avoid this issue? Unfortunately i could not find a 100% way to iron out this issue, only to minimize the chances of getting it and debugging it, which are the following:

  • Enable Wall, Wextra, pedantic and Werror in your project
  • Any header only files that include device or component code must be included in the project as header files
  • Try to minimize the use of virtual inline methods in parent device or component classes, if not able to do so use the override specifier
  • Add a log in suspect methods to check if its actually getting executed at runtime (IMO this is the second best way to debug this issue)

Next time you get crazy behavior from your driver, like frames not being delivered or tracking pose update calls not working, for seemingly no reason, check if your method is actually the one that's being executed at runtime.

@okawo80085
Copy link
Author

I feel crazy

While fixing a seemingly unrelated issue, i found out that having any of the quats in the pose struct filled with zeros makes the tracked device disappear on Linux and on Windows the tracked device disappears sometimes

Also if qWorldFromDriverRotation or qDriverFromHeadRotation is not set or is set to all zeros, there is a chance your device will never show up in VR view, specially when using multiple drivers

This entire issue was actually caused by 2 quat boiz not being set, i mistook it for a member pass issue (even though there is no way in hell that actually makes sense) because when passing members i forgot to set those 2 fields and when passing locally defined poses i did not forget to set those

I think this is caused by SteamVR's prediction algorithm, it obviously takes orientation into account, but here is the thing about 0 filled quats... they make your points disappear✨, so of course the device disappears literally all of it's point are gone after the first pass of tracking predictions sigh

Oh and btw non unitized quats are bad too, those make your device try to escape this dimension

All in all, dumb issue, i should've known what will happen when setting those quats to zeros 🤷
After all its sooooooooooooooo obvious 🙃

I hope that the poor soul that gets the same issue will find this at least a bit helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant