Quick answer: Pass vsync=1 with the SCALED flag to pygame.display.set_mode. On multi-monitor setups, vsync syncs to one monitor; spanning two monitors causes tearing on whichever the window does not sync to. Confine to a single monitor or use fullscreen for stability.

Here is how to fix Pygame games that tear or stutter on multi-monitor desktops. Per-monitor refresh rates are independent; vsync can only sync to one. The fix is to pin the window to a single monitor or use fullscreen.

The Symptom

Pygame window in the middle of a multi-monitor setup tears at every flip. Moving the window to a single monitor stops the tearing.

What Causes This

Per-monitor vsync. SDL syncs to a single display. Spanning two breaks sync.

Different refresh rates. 144 Hz primary plus 60 Hz secondary mismatched.

Compositor mismatch. On Linux, X11 compositor settings can disable vsync; Wayland tends to handle this better.

The Fix

Step 1: Enable vsync with SCALED.

import pygame
pygame.init()
screen = pygame.display.set_mode(
    (1280, 720),
    flags=pygame.SCALED,
    vsync=1
)

SCALED flag is required for vsync to take effect on most SDL2 builds.

Step 2: Pin to a single monitor.

import os
os.environ["SDL_VIDEO_WINDOW_POS"] = "100,100"   # top-left of primary
# or center on a specific monitor via SDL display index
os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()

Set environment vars before pygame.init.

Step 3: Use fullscreen for shipping.

screen = pygame.display.set_mode(
    (1920, 1080),
    flags=pygame.FULLSCREEN | pygame.SCALED,
    vsync=1
)

Fullscreen takes exclusive display control; vsync is reliable.

Step 4: Linux compositor hints.

# Before pygame.init
os.environ["SDL_VIDEODRIVER"] = "wayland"   # on Wayland desktops
os.environ["SDL_HINT_RENDER_VSYNC"] = "1"

Step 5: Document the limitation. If you cannot avoid windowed multi-monitor users, note in your settings menu that windowed mode may tear on multi-monitor setups and recommend fullscreen.

“vsync=1 + SCALED, single-monitor or fullscreen. Multi-monitor windowed tearing is an SDL limitation.”

Related Issues

For Pygame CPU usage, see Clock.tick CPU. For mixer events, see mixer.music End Event.

vsync=1 + SCALED. Pin the window. Fullscreen for shipping. Tearing minimized.