OpenRA/OpenRA · critical · InvalidOperationException
Can not bind OpenGL context. (Error: {SDL.SDL_GetError()})
Error message
Can not bind OpenGL context. (Error: {SDL.SDL_GetError()}) What it means
Thrown in InitializeOpenGL when, after pinning the render thread affinity, SDL_GL_MakeCurrent(window, context) returns < 0. The context was successfully created and released on the main thread in the constructor, but rebinding it to the render thread fails. SDL_GetError() is interpolated to surface the driver reason, which is usually that the context is still current elsewhere, the thread is not allowed to bind it, or the window/context were invalidated.
Source
Thrown at OpenRA.Platforms.Default/Sdl2GraphicsContext.cs:41
public string GLVersion => OpenGL.Version;
public Sdl2GraphicsContext(Sdl2PlatformWindow window)
{
this.window = window;
// SDL requires us to create the GL context on the main thread to avoid various platform-specific issues.
// We must then release it from the main thread before we rebind it to the render thread (in InitializeOpenGL below).
context = SDL.SDL_GL_CreateContext(window.Window);
if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window.Window, IntPtr.Zero) < 0)
throw new InvalidOperationException($"Can not create OpenGL context. (Error: {SDL.SDL_GetError()})");
}
internal void InitializeOpenGL()
{
SetThreadAffinity();
if (SDL.SDL_GL_MakeCurrent(window.Window, context) < 0)
throw new InvalidOperationException($"Can not bind OpenGL context. (Error: {SDL.SDL_GetError()})");
OpenGL.Initialize();
OpenGL.CheckGLError();
OpenGL.glGenVertexArrays(1, out var vao);
OpenGL.CheckGLError();
OpenGL.glBindVertexArray(vao);
OpenGL.CheckGLError();
}
public IVertexBuffer<T> CreateEmptyVertexBuffer<T>(int size) where T : struct
{
VerifyThreadAffinity();
return new VertexBuffer<T>(size);
}
public IVertexBuffer<T> CreateVertexBuffer<T>(T[] data, bool dynamic = true) where T : struct
{View on GitHub (pinned to a520984d91)
Solutions
- Read SDL_GetError() from the message — 'context already current' vs 'invalid context/window' points to different causes.
- Confirm the constructor's SDL_GL_MakeCurrent(window, IntPtr.Zero) release actually succeeded (it is checked together with context creation in 603 — if that did not throw, release worked).
- Ensure InitializeOpenGL runs on exactly one dedicated render thread and that no other thread has called SDL_GL_MakeCurrent with this context.
- Verify the window handle passed to MakeCurrent is the same live window used to create the context and has not been destroyed/recreated.
- Update SDL2 bindings/driver; on macOS confirm the main-thread release and render-thread bind follow Cocoa's thread rules.
Example fix
// before: rebinding a context that was never released on the main thread
internal void InitializeOpenGL()
{
SetThreadAffinity();
if (SDL.SDL_GL_MakeCurrent(window.Window, context) < 0)
throw new InvalidOperationException(...); // -> fires
}
// after: guarantee the constructor released it first
public Sdl2GraphicsContext(Sdl2PlatformWindow window)
{
context = SDL.SDL_GL_CreateContext(window.Window);
if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window.Window, IntPtr.Zero) < 0)
throw new InvalidOperationException(...);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure the context is released on the main thread before binding on the render thread.
if (SDL.SDL_GL_MakeCurrent(window.Window, IntPtr.Zero) < 0)
throw new InvalidOperationException($"Failed to release context on main thread: {SDL.SDL_GetError()}"); Try / catch
try
{
graphicsContext.InitializeOpenGL();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("bind OpenGL context"))
{
var sdlErr = SDL.SDL_GetError();
if (sdlErr.Contains("already current")) { /* release elsewhere and retry once */ }
else throw;
} Prevention
- Bind the GL context on exactly one dedicated render thread; never share it across threads.
- Always pair SDL_GL_MakeCurrent(win, ctx) on the render thread with a prior SDL_GL_MakeCurrent(win, Zero) on the main thread.
- Do not destroy/recreate the window between context creation and InitializeOpenGL.
- Test the render-thread bootstrap on macOS, Linux, and Windows since thread rules differ.
When it happens
Trigger: The context was never released on the main thread (constructor release failed silently upstream), the context is already current on another thread, the window was destroyed/recreated between construction and InitializeOpenGL, or the platform restricts context binding to the thread that created it.
Common situations: Multi-threaded render bootstrap ordering bug; window recreation during display-mode changes; driver/platform (notably some macOS or NVIDIA configurations) that forbid moving a context across threads; SDL/library version regression in SDL_GL_MakeCurrent.
Related errors
- Can not create OpenGL context. (Error: {SDL.SDL_GetError()})
- No supported OpenGL profiles were found.
- OpenGL Error: See graphics.log for details.
- Failed to create surface: {SDL.SDL_GetError()}
- Failed to initialize platform-integration library. Check gra
AI-assisted analysis of OpenRA/OpenRA@a520984d91 (2026-08-13).
Data as JSON: /api/errors/48f16bdc866181cd.
Report an issue: GitHub.