Fixing Godot splash screen gray flicker
I’m polishing my new game, Just Fly, which means I’ve been restarting it dozens of times a day. After a while, I got really tired of the gray flicker between the native Godot boot splash and my custom loading screen. I finally tracked down and fixed the root cause, without just masking the symptoms.
TL;DR: Do NOT set modes on the DisplayServer (like fullscreen or V-Sync) in your main script’s _ready() function if the requested value is already the current one. Re-applying identical settings causes Godot to redraw the window with a clear frame.
The workarounds that didn’t work
In my previous game, I “fixed” this issue by force-rendering a frame in the main script’s _ready() using await get_tree().process_frame. In Just Fly, however, that only made the flicker worse. It was just masking the symptom rather than solving the real problem.
I turned to the community and asked for help on the Godot subreddit . Most replies suggested setting the default clear color to black instead of Godot’s default gray. But as I noted in my post, that doesn’t eliminate the flicker, it just makes the screen flash black instead of gray, which is still annoying.
Other suggestions pointed to scene loading speed, arguing that loading too many resources stalled the engine, forcing Godot to show an empty cleared frame. This didn’t seem right: synchronous loading on the main thread (like preload) blocks execution. While blocked, the application isn’t redrawing its window nor handling input, so it shouldn’t be swapping buffers on its own.
Finding the Root Cause
The transition used to be smooth, so I knew something in my recent setup was triggering the clear frame buffer swap.
After digging into it, I have found that the issue was caused by applying graphics settings during the game’s startup. Specifically, setting the fullscreen mode or V-Sync mode via DisplayServer causes Godot to redraw the window buffer – even when the requested mode is the same as the current one. There could be more settings on the DisplayServer tha cause this, so beware.
Because my startup script always applied the saved settings, it forced Godot to render an empty cleared frame and swap buffers before the first scene had finished rendering its first frame.
The Fix
The fix is straightforward: only update DisplayServer settings if the requested value differs from the current one.
Here is what my settings handlers look like now:
func set_fullscreen_enabled(enabled: bool) -> void:
var requested_mode: DisplayServer.WindowMode = (
DisplayServer.WINDOW_MODE_FULLSCREEN if enabled else DisplayServer.WINDOW_MODE_WINDOWED
)
# apply the mode only if different, otherwise the app will flicker with the clear color (gray by default)
if DisplayServer.window_get_mode() != requested_mode:
DisplayServer.window_set_mode(requested_mode)
func set_vsync_enabled(enabled: bool) -> void:
var requested_mode: DisplayServer.VSyncMode = (
DisplayServer.VSYNC_ENABLED if enabled else DisplayServer.VSYNC_DISABLED
)
# apply the mode only if different, otherwise the app will flicker with the clear color (gray by default)
if DisplayServer.window_get_vsync_mode() != requested_mode:
DisplayServer.window_set_vsync_mode(requested_mode)
The Result
With those redundant calls removed, the transition is now completely seamless and flicker-free. I even added a subtle fade-in for the labels:
To prove that scene loading time wasn’t the issue, I tested adding an artificial delay in _ready() with OS.delay_msec(5000). Godot’s native boot splash simply stays on screen for an extra five seconds, with zero flicker before the main scene appears.
Peace of mind restored! :)
Just Fly on Steam
The game is still in early development, but it already has a Steam page . If you like what you see, feel free to wishlist it!