ReviANGLE v1.0.1
ReviANGLE v1.0.1 โ Compatibility Hotfix
Release date: April 26, 2026
This is a mod-compatibility hotfix release. No new performance modules,
no behaviour changes for vanilla GD. The focus is on hardening the OpenGL
proxy so that Geode mods which drive OpenGL aggressively cannot take the
whole game down with them.
If you only run vanilla GD, v1.0.0 and v1.0.1 are functionally identical.
Highlights
- No more crashes when toggling fullscreen with overlay/menu mods active.
- No more crashes from mods that write GL uniforms or upload buffers
before fully setting up GL state. - Mods that ship ImGui-style overlays now compile their shaders correctly
under ANGLE D3D11 โ the menu actually opens on machines that previously
hung at start. - Eight other defensive guards added across the GL proxy.
Global summary of what we fixed
ReviANGLE proxies the desktop GL API on top of Google ANGLE's GLES backend.
ANGLE is stricter than desktop GL: a call sequence that desktop drivers
silently no-op (e.g. glUniform1i with no program bound) will null-deref deep
inside libGLESv2.dll and kill the game. Many Geode mods rely on the
desktop-GL "tolerant" behaviour and crash only when ReviANGLE is active.
v1.0.1 adds a defensive layer between mods and ANGLE that:
- Mirrors desktop-GL "silently no-op on bad state" semantics for the
commonly-misused calls (uniforms, buffer storage, renderbuffer storage). - Translates desktop GLSL idioms (
#version 130/330,
GL_ARB_explicit_attrib_location, โฆ) into ESSL3 equivalents that
ANGLE accepts. - Tracks GL state across
wglMakeCurrent(fullscreen toggle) so dedup
caches don't carry stale bindings into a freshly-created context. - Catches the
__fastfail/ud2instruction that ANGLE emits inside
draw calls when a mod feeds it a vertex format it can't translate, so
one bad draw doesn't kill the frame.
Detailed changes
1. glUniform* โ null-program guard
Class of mods affected: anything that writes uniforms outside of a
strict bind-program โ set-uniforms โ draw cycle.
Symptom: GD crashes the moment the offending mod runs its first
frame. Stack ends in libGLESv2!GL_Uniform* + 0xb7, null deref at
offset +0x1F0.
Cause: ANGLE assumes GL_CURRENT_PROGRAM is a valid object inside
every glUniform*. Some mods write uniforms before / between program
binds. Desktop GL silently no-ops; ANGLE crashes.
Fix: gd_noProgramBound() cache-only check at the top of every
gl_glUniform* family function. The cache is kept in sync by:
- Querying
GL_CURRENT_PROGRAMafter everygl_glUseProgram(catches
ANGLE rejecting an invalid program ID). - Clearing the cache from
gl_glDeleteProgramwhen the deleted program
was the bound one.
2. glBufferData / glBufferSubData โ null-buffer guard
Class of mods affected: anything that uploads vertex/index data
without first binding a buffer to the matching target.
Symptom: Intermittent null-deref inside ANGLE's buffer upload path.
Cause: ANGLE crashes when glBufferData is called with no buffer
bound to the target. Desktop GL silently no-ops.
Fix: Per-target binding map (g_bufferBindings[8]); both
gl_glBufferData and gl_glBufferSubData bail out with no-op when the
target slot is 0/sentinel.
3. glRenderbufferStorage โ null-RBO guard + cache invalidation
Class of mods affected: anything that hooks into CCEGLView::toggleFullScreen
or otherwise triggers GL context recreation (custom resolution mods,
overlay mods that re-init their FBOs on resize, etc.).
Symptom: GD crashes when toggling fullscreen. Stack:
cocos2d::CCEGLView::toggleFullScreen โ updateWindow โ
glRenderbufferStorage โ ANGLE crash at offset +0xB8.
Cause: Two bugs combined:
CCEGLView::updateWindowdoesn't always re-bind a renderbuffer in
the freshly-created context before callingRenderbufferStorage.- Our previous
gl_glBindRenderbufferhad a thread-local dedup cache
that survived context recreation. AfterwglMakeCurrentto a
new context, a "rebind to the same ID" got dedup-skipped, but
ANGLE's new context had nothing bound.
Fix:
- Removed dedup from
gl_glBindRenderbufferandgl_glBindFramebuffer
(these binds are not on the hot path; correctness > 1 % perf). - Added
gd_noRBOBound()defensive guard forglRenderbufferStorage
andglRenderbufferStorageMultisample. - New
gdangle_invalidateAllStateCaches()is called from
wgl_wglMakeCurrentwhenever the EGL context changes โ drops every
thread-local dedup cache (g_currentProgram,g_currentVAO,
g_bufferBindings[8],g_currentRBO, VAP cache).
4. Shader source translator โ #version 130 โ 300 es
Class of mods affected: any mod that ships its own shaders or embeds
a UI library (ImGui-based menus, custom particle systems, post-processing
effects).
Symptom: Menu / overlay never appears; stderr full of
'in' : storage qualifier supported in GLSL ES 3.00 and above only or
'#version' : directive must occur before any non-preprocessor tokens.
Cause: Most desktop UI libraries generate shaders with #version 130
or higher (desktop GL 3.0+); ANGLE only accepts ESSL 100, 300 es,
310 es, 320 es. Our previous gl_glShaderSource only prepended a
precision qualifier โ it didn't translate the version directive at all,
and (worse) it placed the qualifier before #version, which is itself
a hard error.
Fix: Rewrote gl_glShaderSource shader translator:
- Detect existing
#version. Map desktop versions to ES:110/120(attribute/varying) โ#version 100130/140/150/330/400+(in/out) โ#version 300 es- Anything already
โฆ esโ kept verbatim
- Inject
precision mediump float; precision mediump int;after the
#versionline and after all consecutive#extensiondirectives.
ESSL3 forbids non-preprocessor tokens before#extension. - Strip desktop-only ARB extensions that have no ES counterpart or whose
feature is built into ES 3.00:
GL_ARB_explicit_attrib_location,GL_ARB_explicit_uniform_location,
GL_ARB_separate_shader_objects,GL_ARB_shading_language_420pack,
GL_ARB_enhanced_layouts,GL_ARB_uniform_buffer_object,
GL_ARB_texture_rectangle,GL_ARB_sample_shading,
GL_ARB_gpu_shader5.
Stripped lines are replaced with// stripped (desktop-only): โฆto
preserve line numbers in error messages.
5. glDraw{Arrays,Elements,ElementsBaseVertex} โ broken-program & SEH guard
Class of mods affected: mods that ship advanced shaders (custom
post-processing, render-passes, GPGPU-style effects), and any mod that
resolves GL functions via direct GetProcAddress(libGLESv2.dll, โฆ)
instead of wglGetProcAddress.
Symptom: Crash inside glDrawElements / glDrawArrays with
EXCEPTION_ILLEGAL_INSTRUCTION deep in libGLESv2's stream translator.
Cause: Two paths feed into the same crash:
- Mod's shaders use desktop-only syntax that ESSL3 doesn't support
(e.g.layout(location=N) uniform, integer attribute streams,
gl_FragColorwrites in a#version 300 esshader). The shader
never compiles, the program never links, but the mod proceeds to
draw with it. ANGLE responds by hitting anUNREACHABLE()deep in
its D3D11 stream translator. - Some mods bypass our proxy entirely for shader / program management
by resolving function pointers directly fromlibGLESv2.dll. We
can't see their broken shaders to patch them โ we can only
intercept the eventual draw call.
Fix (two layers):
gdangle_currentProgramOK()queriesGL_CURRENT_PROGRAMfrom ANGLE
on each draw and looks up itsGL_LINK_STATUS(cached per program
ID, thread-local hot-path cache so it costs ~1 ns when the bound
program doesn't change). Bails with no-op when the bound program is
known to have failed linking.- Wrapped the actual ANGLE call in
__try / __exceptSEH that catches
EXCEPTION_ILLEGAL_INSTRUCTIONandEXCEPTION_ACCESS_VIOLATION,
logs the first 16 occurrences toangle_log.txt, and skips the
draw. ANGLE's internal C++ state may leak (held mutex, half-mutated
buffer) but the game survives.
Applied to: gl_glDrawArrays, gl_glDrawElements,
gl_glDrawElementsBaseVertex.
6. Other small fixes
gl_glBindBuffernow updates a file-scopeg_bufferBindings[8](was
previously local-static), lettingglBufferDataand the VAP cache
inspect current bindings.- VAP cache (
g_vapCache[16]) and array-buffer cache
(g_vapCacheArrayBuffer) are now cleared by
gdangle_invalidateAllStateCaches()on context switch. - Five additional GL exports (
glDrawBuffer,glBindSampler,
glBlendEquationSeparate,glGetVertexAttribiv,
glGetVertexAttribPointerv) for mods that resolve them via
wglGetProcAddress; without these, those mods bailed with
ERROR_PROC_NOT_FOUNDon attach.
What still won't work after v1.0.1
These are inherent ANGLE / GLES 3.0 limitations, not bugs in our proxy:
- Mods whose shaders use
layout(location=N) uniform. This syntax is
#version 330+desktop orGL_ARB_explicit_uniform_locationonly;
ESSL 3.00 has no equivalent. v1.0.1 prevents the crash and silently
drops the bad draws โ the rest of the mod continues to work, but the
affected render passes won't display. The mod author has to remove
the explicitlocationqualifier and switch toglGetUniformLocation. - Mods that read pixels via persistent / buffer-mapped PBOs
(e.g. screen recorders that useglMapBufferRangefor async
capture). ANGLE D3D11 doesn't fully implement persistent mapping.
Recording will produce black or stale frames; the game will not
crash. - Mods that use
glDrawElementsInstancedBaseVertexwith non-zero
baseVertex. GLES has no equivalent; we shim it as
glDrawElementsInstanced, which is correct only forbaseVertex == 0. - Anything that requires desktop GL โฅ 3.2 features without an ES path
(geometry shaders, tessellation, compute outside ES 3.10+, etc.).
A mod failing in any of these ways is no longer a crash; it is at most
a missing visual feature.
Files touched
src/gl_proxy.cpp + SEH wrapper, gdangle_currentProgramOK draw guard
src/gl_proxy_ext.cpp + null-program / null-buffer / null-RBO guards
+ shader translator (version + extension + precision)
+ program link-status tracking
+ state-cache invalidation hook
src/wgl_proxy.cpp + wgl_wglMakeCurrent calls invalidateAllStateCaches
on context unbind / switch
release/opengl32.dll rebuilt (~443 KB)
docs/INSTALLATION.md v1.0.0 โ v1.0.1
README.md v1.0.0 โ v1.0.1 in performance table
.github/ISSUE_TEMPLATE/ example version bumped
No new public API. No new config flags. Drop-in replacement for v1.0.0's
opengl32.dll.
Upgrade
- Close GD.
- Replace your existing
C:\Geometry Dash\opengl32.dllwith the one
fromReviANGLE-v1.0.1-win64.zip. - Launch.
If anything regresses vs. v1.0.0 on vanilla GD, please open an issue with
your angle_log.txt.