How Chromium Syncs Frame Timing with Display VSync
This article provides a technical overview of the architecture and
mechanisms the Chromium web browser uses to synchronize its rendering
pipeline with a display monitor's vertical blanking interval (VSync). It
covers how the browser intercepts hardware timing signals from the
operating system, distributes these signals across its multi-process
architecture using the BeginFrame message, and aligns
JavaScript execution, layout updates, and GPU compositing to deliver
smooth, tear-free visual frames.
The Role of the Vertical Blanking Interval
The vertical blanking interval is the brief time period between the end of drawing the final line of a frame on a display and the beginning of drawing the first line of the next frame. Chromium aligns its rendering pipeline with this hardware interval—commonly referred to as VSync—to prevent screen tearing, which occurs when the display updates with a new frame before the previous one has finished scanning out. On a standard 60Hz monitor, VSync occurs every 16.67 milliseconds, establishing a strict, recurring deadline for Chromium to produce and present a new frame.
Capturing the Hardware Signal
Because Chromium runs across multiple platforms, it does not
communicate directly with the display hardware. Instead, it relies on
Operating System APIs to detect the VSync signal. Within Chromium's GPU
process, a subsystem called the Viz (Visuals) service
listens to platform-specific timing APIs to capture the exact moment the
vertical blanking interval occurs:
- Windows: Uses DirectX Graphics Infrastructure (DXGI) and Desktop Window Manager (DWM) APIs.
- macOS: Uses
CVDisplayLinkorCADisplayLinkAPIs. - Android: Hooks into the operating system's
Choreographersubsystem. - Linux: Queries the Direct Rendering Manager (DRM) and Kernel Mode Setting (KMS) subsystems.
If an OS fails to provide a reliable hardware VSync signal, Chromium falls back to a synthetic software timer that approximates the refresh rate of the monitor.
The BeginFrame
Mechanism
Once the Viz service captures the OS VSync signal, it
translates that hardware interrupt into an internal Chromium heartbeat
called a BeginFrame. This message contains critical timing
metadata:
- The timestamp of the current VSync.
- The expected timestamp of the next VSync (the deadline).
- The interval duration between frames (e.g., 16.67ms for 60Hz, 8.33ms for 120Hz).
The Display Compositor, which resides in the Viz
process, acts as the central coordinator. To conserve CPU and GPU power,
it does not broadcast BeginFrame messages continuously.
Instead, processes must register as "observers" when they have active
animations, scrolling, or pending visual updates. Once the updates are
complete, the Display Compositor stops sending BeginFrame
signals and allows the system to idle.
Coordinating the Renderer Process
When a webpage requires visual updates, the sandboxed Renderer
process requests and receives the BeginFrame signal via
Mojo, Chromium's Inter-Process Communication (IPC) system. The signal
arrives first at the Renderer's Compositor thread.
- The Compositor Thread: This thread handles high-priority, time-sensitive interactions like scrolling, pinch-to-zoom, and CSS animations that only affect transform or opacity properties. If the frame update only requires these operations, the Compositor thread processes the movement immediately without waking up the main thread.
- The Blink Main Thread: If the webpage requires
JavaScript execution, DOM manipulation, or complex CSS updates, the
Compositor thread forwards a
BeginMainFramemessage to the Renderer's Main thread. Receiving this message triggers the execution ofrequestAnimationFrame()callbacks, followed by style calculations, layout (reflow), and paint recording.
Frame Submission and Presentation
To hit the VSync deadline, the Renderer must finalize its work before the current interval expires.
Once the Main thread finishes its layout and paint steps, it pauses
and "commits" the updated layer tree to the Compositor thread. The
Compositor thread then breaks the page into smaller tiles, converts
those tiles into bitmaps (rasterization) using the GPU, and packages the
drawing instructions into a data structure called a
CompositorFrame.
This CompositorFrame is sent back over IPC to the
Display Compositor in the Viz process. The Display
Compositor aggregates the Renderer's frame with frames from other
sources—such as the browser's own UI (tabs, address bar) and other
iframes. Finally, Viz issues the low-level graphics API
calls (via Vulkan, Metal, DirectX, or OpenGL) to draw the final image to
the back buffer. It then instructs the GPU to swap the back buffer to
the front buffer precisely during the monitor's vertical blanking
interval.
Handling Missed Deadlines
Websites frequently run heavy JavaScript that takes longer than 16.67ms to execute, causing the Main thread to miss the VSync deadline. Chromium's split-thread architecture is specifically designed to mitigate this issue.
Because the Compositor thread operates independently of the Main
thread, it does not wait indefinitely for a slow
BeginMainFrame to finish. If the deadline is approaching
and the Main thread is still busy, the Compositor thread simply
generates a CompositorFrame using the data from the
previous frame, applying any new scroll offsets or
compositor-driven animations. It submits this frame to Viz
in time for the VSync interval. As a result, the user experiences smooth
scrolling and animations even while the main content of the webpage is
temporarily frozen or lagging behind.