Skip to content

ui: create the GL window surface + first make_current on the main thread - #97

Merged
techomancer merged 1 commit into
mainfrom
gl-init-main-thread
Sep 10, 2026
Merged

ui: create the GL window surface + first make_current on the main thread#97
techomancer merged 1 commit into
mainfrom
gl-init-main-thread

Conversation

@techomancer

Copy link
Copy Markdown
Owner

issue #94: on some AMD machines the CLI died during startup with a null read inside atio6axx.dll (the AMD OpenGL ICD) on the main thread, inside a window procedure. The ICD subclasses the GL window when SetPixelFormat is called; its wndproc hook then runs on the window-owning (main) thread. iris was doing SetPixelFormat + the first wglMakeCurrent lazily on the REX3 refresh thread, in GlRenderer::ensure_init - so a startup resize could reach the freshly-installed subclass before wglMakeCurrent had populated the driver's per-HWND state.

Ui::new() now builds the Surface and binds the context once (make_current -> make_not_current) on the main thread, before Ui::run starts pumping messages, and hands both the NotCurrentContext and the Surface (initial_surface) to GlRenderer. ensure_init() consumes the surface on the true first frame and only make_current()s it on the refresh thread - the "move a context between threads" handoff. Rendering stays entirely on REX3; only the one-time bind moved.

After a stop()/start() cycle (jitcheck checkpoint restore, reset, snapshot load) initial_surface is None and ensure_init makes a fresh surface on the refresh thread as before - safe by then, the pixel format is set and the driver's window state exists.

mac/Linux unaffected (macOS window_handle() is already captured on the main thread; Linux/GLX benefits - the drawable calls now happen on the window-creating thread, matching the proprietary-NVIDIA note on not_current_context). Verified on Windows: boots clean, and reset (exercises the fresh-surface path) does not crash.

issue #94: on some AMD machines the CLI died during startup with a null
read inside atio6axx.dll (the AMD OpenGL ICD) on the main thread, inside
a window procedure. The ICD subclasses the GL window when SetPixelFormat
is called; its wndproc hook then runs on the window-owning (main) thread.
iris was doing SetPixelFormat + the first wglMakeCurrent lazily on the
REX3 refresh thread, in GlRenderer::ensure_init - so a startup resize
could reach the freshly-installed subclass before wglMakeCurrent had
populated the driver's per-HWND state.

Ui::new() now builds the Surface and binds the context once
(make_current -> make_not_current) on the main thread, before Ui::run
starts pumping messages, and hands both the NotCurrentContext and the
Surface (initial_surface) to GlRenderer. ensure_init() consumes the
surface on the true first frame and only make_current()s it on the
refresh thread - the "move a context between threads" handoff. Rendering
stays entirely on REX3; only the one-time bind moved.

After a stop()/start() cycle (jitcheck checkpoint restore, reset,
snapshot load) initial_surface is None and ensure_init makes a fresh
surface on the refresh thread as before - safe by then, the pixel format
is set and the driver's window state exists.

mac/Linux unaffected (macOS window_handle() is already captured on the
main thread; Linux/GLX benefits - the drawable calls now happen on the
window-creating thread, matching the proprietary-NVIDIA note on
not_current_context). Verified on Windows: boots clean, and `reset`
(exercises the fresh-surface path) does not crash.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@techomancer
techomancer merged commit aac7674 into main Sep 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant