Quick answer: pygame.display.set_mode with OPENGL recreates the context - reload textures and shaders after toggling fullscreen.
If you are searching for how to fix pygame display toggle fullscreen loses opengl context, you are not alone. This is a recurring issue in Pygame that comes up across many team projects. The behavior looks like a deep bug, but it usually traces back to a known interaction between two systems. Here is the full breakdown of the symptom, the cause, and a fix you can apply today.
The Symptom
Your pygame OpenGL game runs fine in windowed mode, but when the player toggles fullscreen with F11, all textures become solid white and shader programs fail to bind. The screen still renders, just with no resources.
Root Cause
pygame.display.set_mode() with the OPENGL flag creates a fresh OpenGL context. The new context doesn't share resources with the old one - all texture IDs, shader programs, VBOs, and VAOs become invalid handles.
The Fix
Step 1: After calling set_mode for fullscreen toggle, re-upload all textures with glTexImage2D and recompile all shaders. Cache the source data outside GL.
import pygame
import os
os.environ['SDL_VIDEO_X11_LEGACY_FULLSCREEN'] = '1'
pygame.init()
flags = pygame.OPENGL | pygame.DOUBLEBUF | pygame.RESIZABLE
screen = pygame.display.set_mode((1280, 720), flags)
def toggle_fullscreen():
new_flags = flags ^ pygame.FULLSCREEN
pygame.display.set_mode((1280, 720), new_flags)
reload_all_textures()
recompile_all_shaders()
rebuild_vaos()
Step 2: On Linux X11, set os.environ['SDL_VIDEO_X11_LEGACY_FULLSCREEN'] = '1' to use the legacy borderless-fullscreen mode that preserves context.
# Cache source data for reload
texture_cache = {}
def load_texture(path):
if path not in texture_cache:
texture_cache[path] = pygame.image.load(path)
surf = texture_cache[path]
return upload_to_gl(surf)
Step 3: For minimal disruption, use pygame.display.toggle_fullscreen() instead of set_mode - on SDL2 backends it tries to preserve the context.
Check the boundary; the bug lives between systems.