Chrome swapping (display) buffers on ‘vsync signal’ is causing 2x input lag on Windows
Reported by jer...@duckware.com, Oct 23 2016
UserAgent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 Steps to reproduce the problem: [This bug can only be seen when Chrome is run on an OS that composites – like Windows with Aero enabled] The input lag in Chrome on Windows is too large (currently two frames). This is confirmed by using vsynctester.com, which includes a mouse input lag detector. The input lag in Chrome under Windows used to be ONE frame. But this (low input lag) was actually due to a vsync bug. See issue 465356 and issue 632785 . Once the bug was fixed (or the workaround – resizing the Chrome app window – was applied), the mouse input lag jumped from 1 frame to 2 frames. The ultimate cause of this bug appears to be caused by an interaction between how and when Chrome swaps buffers and the fact that the Windows OS composites everything already to prevent tearing (at an OS level). Namely, when Chrome swaps buffers (on the vsync signal?), IT IS ALREADY TOO LATE for the frame Chrome just swapped to make it into the next display frame (as the OS has already started the NEXT buffered display frame). The frame Chrome just sent to the OS must wait ONE EXTRA whole frame before even being displayed on the screen. This behavior was ‘confirmed’ by modifying the test code from issue 467617 and repainting a ‘mouse input lag detector’ on either (1) mouse input or (2) the vsync signal. When repainting on mouse input, there was very little lag in the detector. But when repainting on the vsync signal, the lag jumped by a large amount and was very noticeable. Chrome’s current behavior is the ‘correct’ behavior – but ONLY if the OS does NOT composite. But if the OS does composite (as Windows does with Aero on, and it is now always on), Chrome’s current behavior is the worst possible behavior, adding an entire extra frame of lag into the pipeline before a rendered frame is displayed on the screen. The challenge for Chrome is that with the Windows Areo interface (compositing), Chrome must complete swapping buffers BEFORE the Windows DWM composites the current frame. Is there some hook into Windows to do this? If not, Chrome must adjust when it sends rendered frames to the OS (to immediately before the vsync signal – because any time at or after the vsync signal is too late, because the Windows OS has already started compositing the NEXT frame). What is the expected behavior? What went wrong? This issue is tightly related to issue 467617 and the desire to use D3DKMTWaitForVerticalBlankEvent. It is also very interesting to note that for many animations that can be easily rendered in 1/2 a frame time (or even less), that input lag can easily be reduced by Chrome to under a single frame by intentionally delaying the start of a frame by 1/2 frame. Did this work before? Yes Chrome version: 54.0.2840.71 Channel: stable OS Version: 6.1 (Windows 7, Windows Server 2008 R2) Flash Version: Shockwave Flash 23.0 r0
Oct 24 2016,
jmukthavaram: Please undup immediately. The two issues are RELATED (work on one issue will impact the other issue) -- but they are NOT the same.
Oct 28 2016,
As per Comment#2,unduping the issue-467617 from this issue.
Jan 5 2017,
I've been looking at compositor <-> GPU interaction code lately. I may be wrong but I think the reason for extra frame delay is compositing deadline. With the currently implemented delay based VSync source it is defined as time of next calculated VSync (i.e. time of current VSync + VSync interval). This puts the deadline right on the frame boundary and pretty much guarantees it to be slightly late. The challenge here is to determine how much earlier the deadline should be. That should be just enough time to conver latency of IPC call to GPU process and enough time to allow GPU process to finish the swap. This extra latency is going to depend on computing capacity, number of CPU cores, other processes, etc. I guess there could be some sort of feedback mechanism that would continuously calculate the latency between the deadline and completing the swap and communicate it back to browser process to update the next deadline. This way the deadline would self-adjust. If not done properly this might cause animation/video playback smoothness issues which is worse than the extra lag.
Jan 5 2017,
stanisc/4: Under Windows (with Aero), why is Chrome compositing at all? Just send everything to the display immediately -- with no delay -- and let Windows DWM do the compositing?
Jan 6 2017,
stanisc/4: Another thing to consider is the DirectX calls Chrome is using to 'present' (and how that will affect things). When I first wrote vsynctester.com, I could turn Windows Aero off, use vsynctester.com 'Tear helper bar' with custom Hz and skew, and precisely place a tear position on the screen under Chrome. But in Chrome today, that no longer works. There is NO tear position with Aero off. So there is now something else syncing to vsync (is it back pressure from Direct X presents waiting for vsync?)
Jan 9 2017,
I am not an expert in compositor. I believe compositing is already done in GPU when possible. The deadline is to signal when to swap frames.
Feb 9 2017,
Would it be possible for someone to investigate why Chrome uses DirectX D3DPRESENT_INTERVAL_* flags (DEFAULT/ONE/etc) that causes DirectX (as per https://msdn.microsoft.com/en-us/library/windows/desktop/bb172585(v=vs.85).aspx) to "wait for the vertical retrace period" -- instead of D3DPRESENT_INTERVAL_IMMEDIATE? Under Windows Aero, Windows is already compositing, so present 'immediate' is what is wanted. If DirectX (on Chrome's behalf) waits "for the vertical retrace period", that would interfere with DWM composition and add an extra frame of delay -- and that is exactly what we observe with Chrome -- a two frame delay.
Feb 10 2017,
ANGLE is vsyncing -- and it should not when Windows is compositing (DWM). Search Chromium source code for ANGLE_VSYNC, which defaults to ANGLE_ENABLED. It should be set to ANGLE_DISABLED.
Feb 11 2017,
After an extensive bisect, the change that apparently caused Chrome to change from one frame of input lag to two frames of input lag has been found: https://bugs.chromium.org/p/angleproject/issues/detail?id=814
Feb 12 2017,
Please merge this issue into issue 460919. It appears both issue have the same root cause.
Aug 7 2017,
Brian, could you please check and merge this into issue 460919?
Sign in to add a comment