Closed Bug 1720634 Opened 3 years ago Closed 3 years ago

Bad frame rate when multiple windows are animating on Nvidia/Linux

Categories

(Core :: Graphics: WebRender, defect, P3)

Firefox 91
x86_64
Linux
defect

Tracking

()

RESOLVED DUPLICATE of bug 1716049
Tracking Status
firefox-esr78 --- disabled
firefox-esr91 --- wontfix
firefox91 --- wontfix
firefox92 --- wontfix
firefox93 --- wontfix

People

(Reporter: lexlexlex, Unassigned)

References

(Blocks 2 open bugs)

Details

Attachments

(3 files)

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0

Steps to reproduce:

  1. Run the latest git build of XFWM4 on a computer with an Nvidia graphics card (reproduced with GTX 1080 Ti) and a 59.95 Hz monitor (reproduced with 1920x1200 Acer G24).
  2. Have the proprietary Nvidia driver version 470 or later installed. (This may happen with earlier versions of the Nvidia driver, but this bug was reproduced today with 470.)
  3. Have "Force Composition Pipeline" enabled in nvidia-settings, and saved to the xorg configuration file.
  4. In xfconf settings editor, navigate to "xfwm4".
  5. Ensure "vblank_mode" is set to "off" (string value).
  6. Ensure "sync_to_vblank" is set to false (boolean value). (Vsync is handled by the nvidia driver's composition pipeline, so this prevents XFWM4 from trying to do its own erroneous vsync timing.)
  7. Ensure "use_compositing" is set to true (boolean value).
  8. Reboot to ensure all settings are applied.
  9. Install and run a fresh Firefox Nightly with default settings.
  10. Navigate to https://www.vsynctester.com/ .
  11. In a new window in the same Firefox Nightly instance without closing the previous window, navigate to any other website that continuously animates, such as https://orteil.dashnet.org/cookieclicker/ or simply another instance of https://www.vsynctester.com/ .
  12. In a new window in the same Firefox Nightly instance without closing the previous windows, navigate to any other website that continuously animates, such as https://orteil.dashnet.org/cookieclicker/ or simply another instance of https://www.vsynctester.com/ .
  13. Without closing any of the windows that have continuously-animating websites, navigate to the original vsynctester window and view its output.

Actual results:

The frame rate is split between the number of continuously-animating windows present.

  • For example, if there are 2 continuously-animating windows and the display's refresh rate is 59.95 Hz, the frame rate is 29.975 Hz.
  • For example, if there are 3 continuously-animating windows and the display's refresh rate is 59.95 Hz, the frame rate is 19.983333 Hz.

A workaround is available. Navigating to about:config and changing layout.frame_rate from -1 to 0 fixes the issue for that session, allowing vsync to happen normally across all windows. This makes sense because of the following Firefox code and comment, found in gfx/gl/GLContextProviderCGL.mm at line 85:

bool GLContextCGL::MakeCurrentImpl() const {
  if (mContext) {
    [mContext makeCurrentContext];
    MOZ_ASSERT(IsCurrentImpl());
    // Use non-blocking swap in "ASAP mode".
    // ASAP mode means that rendering is iterated as fast as possible.
    // ASAP mode is entered when layout.frame_rate=0 (requires restart).
    // If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal.
    // When we're iterating as fast as possible, however, we want a non-blocking
    // glSwapBuffers, which will happen when swapInt==0.
    GLint swapInt = StaticPrefs::layout_frame_rate() == 0 ? 0 : 1;
    [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
  }
  return true;
}

This means that if layout.frame_rate is set to 0, Firefox stops trying to do its own frame timing, and just renders as fast as it can, except it waits for vblank each frame for that session. The comment says that you should restart if you want "ASAP mode", but I just want Firefox to vsync properly, so I do it each session and set layout.frame_rate back to -1 (the default value) before closing it so I can do it again the next session. This allows swapInt to continue to equal 1, which is what I need to keep proper hardware-driven vsync.

Expected results:

  • The frame rate is expected to match the display's refresh rate, regardless of the number of continuously-animating windows present, which is the behavior when the workaround is applied.
  • Only hardware-driven vsync is expected to be used when layout.frame_rate is set to -1, and not Firefox' own extra method of timing frame presentation.
Component: Untriaged → Graphics: WebRender
Product: Firefox → Core

I think that this is happening because we are presenting from multiple GL contexts on the same thread which for some reason upsets some drivers. We have a few other bugs on file about this.

Severity: -- → S3
Priority: -- → P3
Summary: Firefox splits frames rendered per second between multiple windows → Bad frame rate when multiple windows are animating on Linux

Note: GLContextCGL is not used on Linux - we use either GLContextGLX or GLContextEGL. The former seems to behave analogous: https://searchfox.org/mozilla-central/source/gfx/gl/GLContextProviderGLX.cpp#690-691

What you could try is running with the EGL backend (which is supposed to replace GLX in the future). To do so, you can run FF with MOZ_X11_EGL=1 or enable gfx.x11-egl.force-enabled in about:config. If Nico is right, that should fix the issue, as the EGL backend uses a single shared GL context.

P.S.: uh, nvidia driver - this may or may not work until bug 1702546 land and nvidia implements the required new extension: https://github.com/KhronosGroup/EGL-Registry/pull/124

Flags: needinfo?(lexlexlex)

(This is a known Nvidia/Linux bug: bug 1667165, bug 1659848, bug 1497481, bug 1716049. It would be great if switching to EGL helps.)

Blocks: wr-nv-linux
OS: Unspecified → Linux
Hardware: Unspecified → x86_64
See Also: → 1667165
Summary: Bad frame rate when multiple windows are animating on Linux → Bad frame rate when multiple windows are animating on Nvidia/Linux
I tried changing `gfx.x11-egl.force-enabled` in `about:config` to `true` and restarting, then opening 2 vsynctester windows.  It started to synchronize to a frame rate that is not my monitor's refresh rate (60 Hz instead of 59.95 Hz), which caused some frames to be rendered correctly for a while, then periodically have short bursts of many dropped frames, then stabilize, and repeat.  I checked `about:support`, and it seems there's an error saying the EGL surface could not be created and it's using "WebRender (software)", which obviously doesn't have proper hardware vsync.  Please see the decision log in my `about:support` information, which I'm now attaching here.

(In reply to lexlexlex from comment #5)
Thanks for testing! Some of your prefs might have caused problems. You only need to set gfx.webrender.all=true to force-enable WebRender and gfx.x11-egl.force-enabled=true to use EGL instead of GLX. When using EGL, only Mesa has correct framerate detection, fallback is hardcoded 60 Hz.
Please set

  • gfx.webrender.precache-shaders back to false.
  • gfx.webrender.program-binary-disk back to false.
  • gfx.webrender.compositor/gfx.webrender.compositor.force-enabled (Wayland OS compositor instead of internal draw compositor) back to false
  • layers.omtp.enabled back to false

and try again. It would be great to know if EGL/XFCE/Nvidia works. (It should work due to bug 1717816 and bug 1646135.)

(In reply to Darkspirit from comment #6)

and try again. It would be great to know if EGL/XFCE/Nvidia works. (It should work due to bug 1717816 and bug 1646135.)

It could be that it's still blocked by bug 1702546 - it works on Wayland though.

(In reply to Darkspirit from comment #6)

(In reply to lexlexlex from comment #5)
Thanks for testing! Some of your prefs might have caused problems. You only need to set gfx.webrender.all=true to force-enable WebRender and gfx.x11-egl.force-enabled=true to use EGL instead of GLX. When using EGL, only Mesa has correct framerate detection, fallback is hardcoded 60 Hz.
Please set

  • gfx.webrender.precache-shaders back to false.
  • gfx.webrender.program-binary-disk back to false.
  • gfx.webrender.compositor/gfx.webrender.compositor.force-enabled (Wayland OS compositor instead of internal draw compositor) back to false
  • layers.omtp.enabled back to false

and try again. It would be great to know if EGL/XFCE/Nvidia works. (It should work due to bug 1717816 and bug 1646135.)

I've made all those changes now and the behavior is the same as in comment #5 , except the decision log no longer contains failed shader cache loading entries. I'm attaching my latest about:support JSON next, to allow Bugzilla to render the reply Markdown correctly.

Flags: needinfo?(lexlexlex)

Same here on KDE with NVidia 460 drivers. With or without pipelining, and vblank settings.

I noticed because when I watched Twitch streams in a 2nd window, on another screen, I was dropping frames, and it was very laggy. When I went to view video stats I could see that I was dropping over half the frames.

I noticed the frame drop on the 2nd window using testufo.com. One window was 60FPS. It dropped below 60 with twitch stream going, and even further when tab was dragged to another Window.

I also figured out using layers.frame_rate=0 made everything buttery smooth, and no more dropped frames, posted about it on reddit, and someone sent me to your comment and bug report here.

Setting frame_rate to anything other than 0 made no difference. I tried setting to 120 or 144, but that didn't change anything for me.

See Also: → 1722055

Nical and/or Jamie, can you see if you can reproduce this?

Flags: needinfo?(nical.bugzilla)
Flags: needinfo?(jnicol)

(In reply to Jason from comment #10)

Same here on KDE with NVidia 460 drivers. With or without pipelining, and vblank settings.

I noticed because when I watched Twitch streams in a 2nd window, on another screen, I was dropping frames, and it was very laggy. When I went to view video stats I could see that I was dropping over half the frames.

I noticed the frame drop on the 2nd window using testufo.com. One window was 60FPS. It dropped below 60 with twitch stream going, and even further when tab was dragged to another Window.

I also figured out using layers.frame_rate=0 made everything buttery smooth, and no more dropped frames, posted about it on reddit, and someone sent me to your comment and bug report here.

Setting frame_rate to anything other than 0 made no difference. I tried setting to 120 or 144, but that didn't change anything for me.

To add to my own here, I've also noticed another peculiarity that may or may not be helpful information...

After setting layout.frame_rate to 0, it makes FF much faster, but it's not the same across displays.

Whichever screen is either top-most or left-most gives me about twice the FPS on testufo.com. It doesn't appear to be an Xorg/Nvidia thing, because glxgears doesn't act that way.

To explain further:

At home my 3 monitors are vertically stacked. If I move the FF window to the top, it's about twice as fast as the lower 2.

At work my 3 monitors are horizontal, and if I put FF on the left one, it's faster than the 2 on the right.

This is using the same laptop in both locations with the same model docking station.

Nical and/or Jamie, can you see if you can reproduce this?

When I have multiple windows continuously presenting, framerate tanks and the render thread spends all of its time in glMakeCurrent. We've had this problem on x11+nvidia for as long as I can remember (at least with WR).

Without WebRender we also spend a large amount of time in glMakeCurrent (40%+ of the compositor thread), but the frame rate suffers much less).

Nouveau driver is unaffected.

Flags: needinfo?(nical.bugzilla)

It sounds like Nical has confirmed this. Can this be changed from "UNCONFIRMED" now?

Status: UNCONFIRMED → NEW
Ever confirmed: true
See Also: → 1716049
Flags: needinfo?(jnicol)
Status: NEW → RESOLVED
Closed: 3 years ago
Resolution: --- → DUPLICATE

For anyone checking this ticket from a link posted somewhere, I found in another ticket that this issue is finally resolved with GLX with a one-time workaround instead of a workaround every session!

The one-time workaround is setting:

  1. layout.frame_rate to -1 (integer value)
  2. gfx.x11-egl.force-disabled to true (boolean value)
  3. gfx.swap-interval.glx to false (boolean value)
  4. and restarting the browser once.

Finally, vsync without having to navigate to about:config and set layout.frame_rate to 0 and -1 back and forth every single session to have responsive scrolling! I'd been having to do that a very long time.

Thanks to whoever implemented this workaround.

I hope EGL can get correct vsync soon so I can use video decoding acceleration. EGL still uses 60.000 Hz on my 59.95 Hz display, which causes periodic 2-second periods of many dropped frames every 10 seconds.

I am trying to play CPS test game in Mozilla browser on multiple tabs but when my cps is greater then 50 that means i click 50 times in 1 second my browser get lag and i am unable to see gaming animation.

Here you can try - https://www.clicktests.com

Is anyone solve this issues please tell me by commenting below.

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: