I was playing around with drawing on an HTML canvas using mousemove
events when I noticed that the lines I was drawing were more "pixellated" when the developer console was open. As I suspected the reason is that while the developer console is open mouse events are sampled/triggered at a much higher rate.
You can verify with the following code snippet. On my Windows 10 laptop with Chrome and Opera I get at most around 60 events per second, unless I open the developer console (with Ctrl + Shift + J) at which point I get up to 1000 events per second.
const header = document.querySelector('h3');
let eventsPerSec = 0;
function decreaseCounter() {
eventsPerSec--;
renderText();
}
function renderText() {
header.innerHTML = `Mouse move events in the last second: ${eventsPerSec}`
}
document.addEventListener('mousemove', event => {
eventsPerSec++;
setTimeout(decreaseCounter, 1000);
renderText();
})
renderText();
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Count Events</title>
<h3>
</h3>
</head>
So my question is two-fold:
PS: Results may differ based on browser and version (and maybe OS or something?). A friend only got up to 128 events per second with the dev console open in Chrome and Edge. Firefox maxed out at 60 with or without dev console.
I am the creator of Blur Busters TestUFO website, a display testing website used by many. So I have lots of experience with this.
For those who needs higher mouse poll rate, use the PointerEvents API. You can get all 1000 mouse positions per second, although not quickly, as it is delivered in batches. This is useful for things like better line drawing, or de-stuttering FPS mouseturns or mousepans (in a WebGL FPS game).
Another option is chrome.exe --disable-gpu-vsync --disable-frame-throttle which allows the software cursor to run ahead of the hardware cursor (lower lag). When the browser runs at 1000fps, it is getting all 1000 events per second.
PRECEDENT OF USERS: Some people who play fast-twitch online games launch their browser in high framerate mode to reduce latency, since framerates above refresh rates are useful in reducing input latency. That's why competitive gamers love to use VSYNC OFF (tearing). See Are There Advantages To Frame Rates Above Refresh Rates?, some gamers actually do this: Google Search.
I wish that WHATWG/W3C/etc will add an API to enable/disable VSYNC programmatically for full screen applications.
Use Case #1 (common): It is useful for latency reductions in gaming applications, as seen above. Also, since VSYNC OFF causes some games to run at 1000fps+ on modern machines, each frame (requestAnimationFrame or WebGL) runs at a thousand times per second if the GPU is powerful enough such as RTX GPUs -- it automatically means low-latency mouse events, as each animation frame can often get a fresh mouse event at much lower latencies, as the the browsers' internal compositing now rapidly keeps up.
Here's TestUFO framerate counter running in VSYNC OFF mode, it's able to run at over 2000 frames per second:
But it requires the VSYNC OFF command line option, sadly. The neat thing is that the software mouse cursor is lower lag than the hardware mouse cursor (Windows cursor).
So the software-drawn cursor drawn inside requestAnimationFrame() runs AHEAD of the Windows mouse cursor, due to 1000Hz mouse versus Window's once-per-refresh-cycle mouse cursor position check. Pretty neat you can beat the latency of Windows with the custom Chrome command line options?
Gamers who want the lowest possible mouse lag, is why some gamers run Chrome with this command line option. However, I'd like the web consortiums to standardize the ability to do VSYNC OFF. At least for supported machines (e.g. GPUs that support VSYNC OFF, such as Intel GPUs, AMD GPUs, and NVIDIA GPUs). It works on any graphics API that supports VSYNC OFF. As of 2023, no HTML5 API exists to turn VSYNC ON/OFF.
VSYNC OFF also makes a game work better in variable refresh rate mode, as full screen games successfully run in VRR if the graphics drivers setting is configured to use VRR instead of VSYNC OFF.
This is a fairly undocumented trick, but games work fine in VRR mode this way on Windows machines -- meaning Chrome already supports VRR if you do two things:
(A) You launch chrome via the command line option on a VRR-supported OS with --disable-gpu-vsync (for this use, --disable-frame-throttle is optional but has use); AND
(B) If you force the graphics drivers to use VRR (FreeSync/G-SYNC) in fullscreen mode, like NVIDIA Control Panel global options for software.
Use Case #2 (rare): Beam racing in Javascript (raster interrupt style, it works!)
Also some yesteryear consoles such as Atari 2600 had no graphics frame buffer (Wired Magazine Article) and had to realtime generate graphics as the CRT tube scanned out.
Even today, a 240Hz GSYNC VRR DisplayPort signal is still scanned out as a serialization of 2D image to 1D cable, and that's why VSYNC OFF creates tearlines as scanout interruptions. This is still beamraceable today, as per Tearline Jedi Demo. You can't screenshot those realtime animations, yet it still works on AMD/NVIDIA/Intel GPUs! And even in Chrome in VSYNC OFF mode.
For future Javascript-powered beam racing, I released some Apache 2.0 licensed source code, ala https://github.com/blurbusters/RefreshRateCalculator/ where you can steer a VSYNC OFF tearline to a more exact position, ala Tearline Jedi ... we have an internal project that is successfully controlling a tearline to a raster-exact position in Google Chrome under Windows, so we are working on the world's first javascript browser-based beam racing rasterdemo -- VSYNC OFF tearlines are a sort of a cross platformable beam raceable item, ala raster interrupts of 8-bit yesteryore, and useful for reducing emulator lag -- it's implemented already in some emulators such as WinUAE's lagless VSYNC mode. And some software such as RTSS Scanline Sync and Special K Latent Sync.
The only way to get beam racing to work in javascript is one browser in one user profile runs in VSYNC ON mode to listen to the VSYNC heartbeat, another browser in another user profile runs in VSYNC OFF. And the server communicates between them, and the refresh rate calculator dejitters the timestamps, to create accurate raster scan line number estimates as time offsets between VSYNC's. It's fairly accurate (right down to the current Chromium-limited 0.1ms timer resolution, enough for just 6-scanline raster jitter at 67KHz horizontal scanrate of 1080p 60Hz)
If I can use API to enable VSYNC, count the refresh rate accurately ala www.testufo.com/refreshrate and then use API to disable VSYNC, I can deadreckon the raster scan line estimate accurately enough to create a Kefrens Bars in JavaScript.
I've got a prototype emulator-compatible "lagless vsync mode" as a tearingless VSYNC OFF mode for emulators that only works with local command line options and a VSYNC heartbeat (2nd VSYNC ON chrome window running on same machine, or a local background API server sending VSYNC timestamps).
But I would rather that a web consoritum enable a VSYNC OFF API, so that VSYNC can be turned ON/OFF under JavaScript control instead for a specific full screen window. There's already a common use case (reducing latency in gaming), so it's a nobrainer to include this mode.
This mode is good for history preservation of retro preservation (Atari 2600, Commodore 64, TI99/4A, Nintendo, BBC Micro, etc) since those machines were dependant on things like beam racing to multiply sprites. Now, today, running classic emulators in a web browser at the lowest possible latency (original machine latency without hacks such as RunAhead) can sometimes require software-based lagless vsync modes via raster beam racing techniques to sync emulator raster to real world raster (with a jitter error margin). Future versions of the Internet Archive emulators might, for example, utilize these kinds of latency reduction techniques, if such APIs were made available.
Just faced the exact same problem and that was really annoying to me.
I solved it by adding these lines at the very start of my pointer move handler function to filter high rate events (when using devtools) and keep a consistant experience (60fps).
In my example, this.pointerTimestamp is a member of the class listening to the event.
if (event.timeStamp - this.pointerTimestamp < 1000/60) {
return
}
this.pointerTimestamp = event.timeStamp
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With