Quick answer: Check surface_exists(surf) at the top of every Draw event that uses the surface. Recreate with surf = surface_create(w, h) if invalid. For content you can’t redraw cheaply, store via buffer_get_surface and restore with buffer_set_surface.

Game uses a custom surface for a fog-of-war reveal mask. Player alt-tabs out and back. Surface is corrupt or black. The OS yanked GPU memory away when the game lost focus.

The Symptom

Custom surfaces (light/shadow buffers, render targets, mini-map) lose their content after window resize, alt-tab, fullscreen toggle, or driver hiccup. Sometimes the surface returns garbage; sometimes black; sometimes draw calls quietly fail.

What Causes This

GPU surface memory is not guaranteed across context-loss events. Windows in particular reclaims surfaces during alt-tab. GameMaker re-creates the application surface for you, but custom surfaces created with surface_create are your responsibility.

The Fix

Pattern: Check + recreate + redraw.

/// In obj_fog Draw event

if (!surface_exists(fog_surf)) {
    fog_surf = surface_create(1024, 1024);
    surface_set_target(fog_surf);
    draw_clear(c_black);
    surface_reset_target();
}

surface_set_target(fog_surf);
// reveal logic for this frame
RevealCircle(player.x, player.y, 100);
surface_reset_target();

// composite into the world view
gpu_set_blendmode(bm_subtract);
draw_surface(fog_surf, 0, 0);
gpu_set_blendmode(bm_normal);

Every Draw event starts with the existence check. Cost is negligible (one boolean) but always safe.

Persistent Content Across Loss

For surfaces with content you accumulate over time and can’t cheaply redraw (a player’s drawing, baked light data), back the surface with a buffer.

/// Create
fog_surf  = surface_create(1024, 1024);
fog_buf   = buffer_create(1024 * 1024 * 4, buffer_fixed, 1);

/// Whenever the surface changes (after a draw)
buffer_get_surface(fog_buf, fog_surf, 0);

/// On context recovery
if (!surface_exists(fog_surf)) {
    fog_surf = surface_create(1024, 1024);
    buffer_set_surface(fog_buf, fog_surf, 0);
}

The buffer lives in main RAM and survives context loss. Save it after meaningful changes; restore on recreation.

Application Surface

The application_surface is recreated automatically by GameMaker. Don’t store references across frames; always reference it via the global. Custom surfaces, however, do not auto-recover.

Resize Cleanup

Listen for the OS_TYPE-specific resize event:

/// Window Resize event (or watch in Step)
if (window_get_width() != last_w) {
    last_w = window_get_width();
    last_h = window_get_height();
    if (surface_exists(fog_surf)) {
        surface_free(fog_surf);
    }
    fog_surf = surface_create(last_w, last_h);
}

Free explicitly before recreating to avoid leaking the GPU memory.

Verifying

In editor: alt-tab out. Wait. Alt-tab back. Surfaces should look correct (blank if you accept regenerate-from-scratch, restored from buffer if you save).

In Debug, watch surface_exists return false after the alt-tab and true after your handler runs.

“Check first. Recreate if not. Buffer-back when content matters. Surfaces survive.”

Related Issues

For pixel-perfect camera, see camera zoom. For instance deactivate, see deactivate region.

surface_exists. Recreate. Buffer-back. Persist.