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 CVDisplayLink or CADisplayLink APIs.
  • Android: Hooks into the operating system's Choreographer subsystem.
  • 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.

  1. 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.
  2. The Blink Main Thread: If the webpage requires JavaScript execution, DOM manipulation, or complex CSS updates, the Compositor thread forwards a BeginMainFrame message to the Renderer's Main thread. Receiving this message triggers the execution of requestAnimationFrame() 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.