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.