ValveSoftware / openvr

OpenVR SDK
http://steamvr.com
BSD 3-Clause "New" or "Revised" License
6.07k stars 1.28k forks source link

Programmatically turn on/off motion smoothing and force interleaved reprojection? #1012

Open jomijomi opened 5 years ago

jomijomi commented 5 years ago

Short story: I want to programmatically be able to turn on/off motion smoothing and force interleaved reprojection on (i.e. forcing 45Hz, similar to pressing shift + r). How can I do that?

Long story: I’m rendering huge 3D-CAD models containing like 100 to 200 million triangles (Yes, you read right). This is on a very efficient GPU-driven renderer (very little CPU-work, all done by “indirect” rendering, and these models have a lot of occlusion), but still there are viewpoints when I’m not always able to reach 90Hz. In these situations I find that turning off motion smoothing and shift + r gives a much better experience (motion smoothing is way worse on these types of scenes). I’m using gpu timer queries so I know when I’m not able to reach 90Hz, and in those situations I want to turn off motion smoothing and force interleaved reprojection at 45Hz. I’ve tried vr::VRCompositor()->ForceInterleavedReprojectionOn – but that didn’t do it (at least not as shift + r). Regarding motion smoothing, I’ve tried vr::VRSettings()->SetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_MotionSmoothing_Bool, _currentForceInterleavedReprojectionAlwaysOn); - but that I’m not allowed to do...

What works ok-isch is to do some CPU-spinning in order to let OpenVR belive that I'm only doing 45Hz but it would be sooo much better if I could just "emulate" shift + r. Even so, I still need to disable motion smoothing in those situations.

Anything, please!

Best regards, Mikael

sergioberg commented 5 years ago

Don't forget to use: virtual bool Sync( bool bForce = false, EVRSettingsError *peError = nullptr ) = 0; It should works at least for motion smoothing setting.

jomijomi commented 5 years ago

Thanks for the input! However, I know about ”Sync” (just missed to add it in the above code). Unfortunately, since v1.1.3 scene applications are NOT allowed to change settings ([https://steamcommunity.com/games/250820/announcements/detail/1705071932994697845]). I’ve read about “solutions” where you can start a new instance as an overlay application (just to be able to change settings) but that seems, well, rather awkward... Why allow it for overlay but not for scene applications? Or is this the ONLY possible way? Also, as this “ability” was taken away from scene applications because of misuse (?), it might very well be removed for overlay applications in future releases...

/Mikael

jomijomi commented 5 years ago

Update: Apparently, vr::VRCompositor()->ForceInterleavedReprojectionOn does nothing (maybe it makes interleaved reprojection allowed, but it does not force it on). Or, do I have to call this explicitly EVERY frame for it to be forced on??

“Shift + r” gives me want I want. Looking at the logs I can see “Force application throttling”. Can I somehow enable/control this programmatically??

As I explained previously, my ”solution” is to do some CPU-spinning, but I would really like the option to force 45Hz / interleaved on like “shift + r”.

Still, the issue of turning off motion smoothing remains. Before moving on to implement the “solution” involving starting a _overlay instance (and change the setting from there), I would really like some input from someone at Valve regarding thoughts / future plans.

/Mikael

aleiby commented 5 years ago

ForceInterleavedReprojectionOn only applies to the legacy non-async reprojection compositor mode, although I can see an argument being made for it to be applied in the async case as well.

If your applications is not making framerate, then it should automatically get throttled after 4 dropped frames (out of the past 10) when motion smoothing is disabled - regardless of if this is due to the cpu or gpu being the bottleneck.

You can disable motion smoothing globally for all apps in the SteamVR desktop settings under Video, or on a per-app basis under the Applications section (and select your app in the dropdown). We do not currently have a way for apps to specify a default setting for this.

Are you seeing throttling not kick in at all, or is it behaving sporadically? Can you post a screenshot of the SteamVR Frame Timing graph to demonstrate the behavior you are seeing and would like to correct?

aleiby commented 5 years ago

ForceInterleavedReprojectionOn will be obeyed in async mode starting with the next beta cycle (v1.3.1). If set, this will prevent the application from running faster than half-rate (e.g. clamped to 45hz on a 90hz native refresh device). The runtime may still throttle down to 1/3rd rate if it determines the app is performing poorly enough to benefit.

mlfarrell commented 5 years ago

We do not currently have a way for apps to specify a default setting for this.

Releasing this terrible feature without a way for apps to opt-out of it was downright reckless. I'm furious. I've lost countless hours on my day off today tracking down the source of my ugly warping when making sudden changes to my app UI panels, only to find out its caused by this warping feature, and now you're telling me I have no way to turn it off??? Come on guys!

jomijomi commented 5 years ago

@aleiby Thanks for the quick response regarding this, greatly appreciated! (and sorry for my delay in response, had some non-VR stuff to work on + managed to catch the flu...). It’s great that we soon will have this ability in the API.

Regarding why OpenVR isn’t able to catch this now and throttle down “by itself”, it might have to do with my culling/rendering being fully gpu-based and I’m running on a gaming laptop (Windows 10, NVIDIA GTX 1080) and at high loads, although it’s not really throttling, we have slight variations in the gpu frame times (partly due to other processes also wants some gpu time). It seems like when I am on the “threshold boundary” OpenVR throttling kicks in, which gives the gpu some slack, allowing it to go below the threshold again, and then OpenVR skips throttling, and it sort of jumps between these modes (I’ll post some frame time graphs later to illustrate this).

What I’m doing that seems to work better is I always record the current gpu frame time (gpu time queries, readback is done a frame later), and then I see if ALL of the last three frames has been ABOVE the threshold, and if so I do my own throttling (cpu-spin). What I perhaps do differently is that I then require ALL of the last three frames to be BELOW the threshold again before I “turn off” my cpu-throttling. Doing so makes sure we don’t jump in and out of throttling. On the other hand, this might already be what you do?

I should probably also say that I’m using OpenGL. By the way, are you using any OpenGL timer queries internally (just to make sure my/yours are not interfering)?

Regarding Motion Smoothing, although I do not want to use the same vocabulary as others, I think that this is actually something that we could really need to be able to turn off through the API. For some scenes it produces very annoying “shimmering” that is way worse than interleaved reprojection. As many users are not hardcore gamers it is not always likely that they will go in and fiddle with the settings or know where certain behaviour is coming from. Although I understand the problem with an application overriding the global settings (and "forgetting" to set them back, which could then affect all other apps), maybe everything could be reset to global settings automatically when an app closes?

Thanks, Mikael