MozillaReality / FirefoxReality

INACTIVE - A fast and secure browser for standalone virtual-reality and augmented-reality headsets.
https://mzl.la/reality
Mozilla Public License 2.0
768 stars 217 forks source link

Extremely poor performance in immersive mode in Sketchfab.com #374

Closed avrignaud closed 2 months ago

avrignaud commented 6 years ago

Hardware

Oculus Go

Steps to Reproduce

  1. Visit sketchfab.com
  2. Attempt to interact with sample 3D mech model

Current Behavior

Initially site says to touch and drag, but pointing laser pointer and clicking does not cause model to move.

Entering immersive (using same mech model) is very slow, and several graphic glitches occur on way. Once loaded, performance is terrible - 2-5 FPS? Then locks up.

Backing out of model brings you back to home page, at which point user can click/drag model on page, but again, with extremely poor performance.

Expected Behavior

Should be able to visit website, point and click to interact with model, enter immersive, navigate in immersive at full performance, and return seamlessly.

Possible Solution

Hoping we have ideas. :)

avrignaud commented 6 years ago

For reference, sketchfab works very well in the just released Samsung Internet browser for the Oculus Go. Both in terms of immersive mode and framerate.

MortimerGoro commented 6 years ago

Did some research on Sketchfab issues:

MortimerGoro commented 6 years ago

Update:

Important things that we need to land

@avrignaud In summary, I think the ship blocker is enabling multiprocess preference. Our WebGL is also slower but that may be difficult to be fixed

MortimerGoro commented 6 years ago

Blocked by #451

daoshengmu commented 6 years ago

@MortimerGoro I have a few progress about the performance investigation.

First of all, we take too much waiting time for posting VR tasks in the immersive mode. Ideally, for Oculus Go, it expects 16 ms per frame for 60 FPS. That means for one rAF to the next rAF only has 16 ms. But our delayed thread makes it postpone to 50ms [1][2]. After changing them to 0, in the immersive mode, we can normally only need 16 ms for rAF for most WebVR examples.

I can show you some stats for aframe/sky [3] and playcanvas[4] when calling VRManagerChild::RunFrameRequestCallbacks() in Gecko.

  1. aframe/sky
    • Non immersive 60 fps stale frames 0 VR profiling 'raf time' delta time: 16.790127 no loop time for callback, it seems a-frame doesn't call it when away from the immersive.
  1. playcanvas
    • Non immersive 60 fps stale frames 0 VR profiling 'raf time' delta time: 16.170517 VR profiling 'loop time' delta time: 10.691268

According to the PlayCanvas example, we can understand the VSync time still work properly even the FPS is not good enough. In the immersive mode, the loop time increase to 17 ms from 10 ms, that also make rAF increase 7 ms for waiting the finish of rAF loop. So, we can realize PlayCanvas is a CPU bound from WebGL, and we need to investigate WebGL functions' bottleneck. But, for aframe/sky, the only strange thing is its stale frames, we can solve it by #453 but no idea why this kind of simple demo would happen stale frames.

[1] https://github.com/MozillaReality/FirefoxReality/blob/b20b91e545981b8538d73bc6662dd162a299c35e/app/src/main/cpp/ExternalVR.cpp#L385 [2] https://dxr.mozilla.org/mozilla-central/rev/c2e3be6a1dd352b969a45f0b85e87674e24ad284/gfx/vr/gfxVRExternal.cpp#144 [3] https://aframe.io/examples/showcase/sky/ [4] https://developer.playcanvas.com/en/tutorials/webvr-lab/

larsbergstrom commented 6 years ago

Moving to V1.1, as blocked on a key bug we can't fix for V1.

MortimerGoro commented 6 years ago

First of all, we take too much waiting time for posting VR tasks in the immersive mode. Ideally, for Oculus Go, it expects 16 ms per frame for 60 FPS. That means for one rAF to the next rAF only has 16 ms. But our delayed thread makes it postpone to 50ms [1][2]. After changing them to 0, in the immersive mode, we can normally only need 16 ms for rAF for most WebVR examples.

[1] Should not be changed to 0, because it will skip most of the frame submits or use the previous frame.

[2] as I understand that's used to trigger the watchdog, which only triggers a new frame in special situations. A new frame should be triggered immediately (with no timers) just after finishing the previous one, isn't Gecko WebVR doing that?

daoshengmu commented 6 years ago

After removing Wait wait(m.data.browserMutex, m.data.browserCond); at ExternalVR::WaitFrameResult, we would have no stale frames, and the FPS would be steady to 60. I think the problem is from pthread mutex between GV and FxR. I am confused with the value of kConditionTimeout = 0.1f, does it mean 100 ms? That would be huge for the waiting time.

Besides, the Playcanvas immersive demo was doing stereo render in the content side, so they have more draw calls, so it makes sense to take more time in their render loop.

The purpose of watchdog in the desktop is in order to force calling rAF again if it has been stuck 50ms after the last update of VRDisplay.rAF. But the VR thread.PostDelayedTask() in Android seems to make it only calls VRDisplay.rAF every 50ms instead of watchdog behavior. [1][2]

https://dxr.mozilla.org/mozilla-central/source/gfx/vr/VRDisplayHost.cpp#274 https://dxr.mozilla.org/mozilla-central/source/gfx/vr/VRDisplayHost.cpp#217

MortimerGoro commented 6 years ago

After removing Wait wait(m.data.browserMutex, m.data.browserCond); at ExternalVR::WaitFrameResult, we would have no stale frames, and the FPS would be steady to 60. I think the problem is from pthread mutex between GV and FxR. I am confused with the value of kConditionTimeout = 0.1f, does it mean 100 ms? That would be huge for the waiting time.

Removing the wait can cause discarded frames or using old WebGL frames. Stats are going to show 60 FPS but the latency is going to be high or inconsistent.

kConditionTimeout is the maximum wait time, it's set to 100ms (10FPS) but ideally it should exit before 16ms when Gecko notifies that the WebGL frame for the latest pose is ready.

The purpose of watchdog in the desktop is in order to force calling rAF again if it has been stuck 50ms after the last update of VRDisplay.rAF. But the VR thread.PostDelayedTask() in Android seems to make it only calls VRDisplay.rAF every 50ms instead of watchdog behavior. [1][2]

That 50ms should be used for the watchdog checks only. A new frame is submitted immediately after the last frame was submitted succesfully. It's a bit confusing but I found that the loop call is done here: https://dxr.mozilla.org/mozilla-central/source/gfx/vr/VRDisplayHost.cpp#317.

cvan commented 6 years ago

There was a recent regression here - possibly on Sketchfab's side because of mobile sniffing vs. feature detection. Not sure if from FxR's last UA change. But entering VR from a Sketchfab model page is currently not possible.

larsbergstrom commented 5 years ago

@cvan Are things better with the latest builds and the updates from Sketchfab, especially around the UA sniffing?

cvan commented 5 years ago

@lbergstrom: the perf is not in good shape still. I can send them perf traces, but I am not sure they will be optimising for the Go hardware.

the otherwise two WebCompat/ContentFeed issues I found and asked about having fixed are these:

  1. Hook up the Go controller's trigger to teleport (whilst keeping the existing button controls).
  2. Hide the Vive controller mesh when using a non-Vive controller.

I can friendly ping them, as it has been a while.

cvan commented 5 years ago

Thanks for all the investigation.

No noticeable perf improvements, and we still have the controller issues per my comment above.

This is unfortunate, but it looks like we are blocked on Sketchfab. And Multiprocess (issue #451) will help. We can address this after v1.1.

cvan commented 5 years ago

BTW: The performance of Sketchfab models on the Oculus Go is still significantly worse than that of Oculus Browser.