Skip to content

FIX(overlay_gl): modernise OpenGL overlay with core profile rendering#7138

Open
ChrisLane wants to merge 3 commits intomumble-voip:masterfrom
ChrisLane:fix-opengl-overlay
Open

FIX(overlay_gl): modernise OpenGL overlay with core profile rendering#7138
ChrisLane wants to merge 3 commits intomumble-voip:masterfrom
ChrisLane:fix-opengl-overlay

Conversation

@ChrisLane
Copy link
Copy Markdown
Contributor

@ChrisLane ChrisLane commented Mar 24, 2026

Notes for Reviewers

This was built with Claude Code (Opus 4.6). OpenGL/C is not my area of expertise. I drove the design and validated behaviour through testing, but the entire implementation needs review by someone comfortable with OpenGL C code. I don't have the background to judge whether the OpenGL usage is idiomatic or just functional. Apologies if this is low quality but from my inexperienced eyes the changes seem reasonable and are at least functional.

Summary

Fixes #5932

Rewrites the OpenGL overlay renderer to use OpenGL 3.3 core profile, fixing crashes on modern Mesa drivers (e.g. Mesa 26 on Arch Linux) that no longer export legacy/compatibility GL symbols such as glPopClientAttrib.

The problem

The overlay library is injected via LD_PRELOAD and was compiled with GL_GLEXT_PROTOTYPES, causing it to link directly against GL function symbols like glPopClientAttrib, glPushAttrib, glMatrixMode, glEnableClientState, and other fixed-function pipeline functions. Modern Mesa builds only provide an OpenGL core profile by default, which removes these deprecated symbols entirely. When the dynamic linker tried to resolve them at load time, it failed with undefined symbol: glPopClientAttrib (or similar), preventing the overlay from starting.

A secondary crash ("Unable to find symbol malloc") was caused by the find_odlsym() ELF-walking loop using dyn as its termination condition instead of checking dyn->d_tag != DT_NULL, which could walk past the end of the dynamic section on some systems.

What changed

  • Replace all fixed-function GL calls (matrix stack, attribute stack, client state, glOrtho, glColorMaterial, glTexEnvi, glRenderMode, etc.) with core profile equivalents: explicit VAO/VBO, uniform MVP matrix, and manual state save/restore
  • Upgrade shaders from GLSL 1.10 (implicit builtins) to GLSL 3.30 with explicit layout attributes and uniform mat4 mvp
  • Resolve all GL function pointers at runtime via glXGetProcAddress instead of relying on compile-time symbol availability - the overlay now uses FDEF/GLRESOLVE macros and #define redirects so no GL symbols need to be exported by the driver at link time
  • Remove #define GL_GLEXT_PROTOTYPES which was the root cause of the link-time symbol dependency
  • Fix the find_odlsym() ELF dynamic-section loop to terminate on DT_NULL instead of a null pointer check
  • Add error handling for shader compilation, program linking, and GL function resolution failures so the overlay logs and exits gracefully instead of segfaulting
  • Remove a stray debug echo from the mumble-overlay shell script
  • Use SOCK_CLOEXEC / O_CLOEXEC to avoid leaking file descriptors to child processes

Testing

  • Compiled and tested on Arch Linux with Mesa 26
  • Overlay appears correctly on both old and new versions of Minecraft (newer versions required extra GL state protection)
  • Overlay appears correctly with glxgears
  • Valgrind returns same result against glxgears with and without the overlay

Checks

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 24, 2026

Walkthrough

This change modernizes the Mumble overlay system. It fixes a script output issue in the mumble-overlay launcher, updates OpenGL feature detection to require modern shader-based symbols instead of deprecated fixed-function calls, adds runtime GL function pointer resolution for UNIX platforms, and refactors the rendering pipeline to use VAO/VBO with GLSL 330 shaders instead of fixed-function vertex arrays. Socket and shared memory handles now use close-on-exec flags. The overlay state save/restore mechanism transitions from fixed-function push/pop operations to explicit state tracking.

Suggested reviewers

  • Krzmbrzl
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: modernizing the OpenGL overlay to use core profile rendering, which is the primary objective of this PR.
Linked Issues check ✅ Passed The PR directly addresses issue #5932 by fixing GL symbol resolution failures and the ELF parsing bug ('Unable to find symbol malloc'), restoring overlay functionality on modern Mesa drivers.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the overlay issues: GL modernization, runtime symbol resolution, ELF parsing fix, error handling, CLOEXEC flags, and a stray echo removal are all necessary for the fix.
Description check ✅ Passed The PR description is comprehensive and complete, covering problem statement, solution, changes made, and testing performed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
overlay_gl/overlay.c (2)

893-895: Polygon mode restore may not handle asymmetric front/back modes.

glGetIntegerv(GL_POLYGON_MODE, ...) returns [front, back] polygon modes. The current restore only checks savedPolygonMode[0] (front face). If an application uses different modes for front and back faces (rare but valid), the back face mode won't be restored correctly.

This is a minor edge case since asymmetric polygon modes are uncommon.

♻️ More complete restore
-	if (savedPolygonMode[0] != GL_FILL) {
-		glPolygonMode(GL_FRONT_AND_BACK, (GLenum) savedPolygonMode[0]);
-	}
+	if (savedPolygonMode[0] != GL_FILL || savedPolygonMode[1] != GL_FILL) {
+		if (savedPolygonMode[0] == savedPolygonMode[1]) {
+			glPolygonMode(GL_FRONT_AND_BACK, (GLenum) savedPolygonMode[0]);
+		} else {
+			glPolygonMode(GL_FRONT, (GLenum) savedPolygonMode[0]);
+			glPolygonMode(GL_BACK, (GLenum) savedPolygonMode[1]);
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@overlay_gl/overlay.c` around lines 893 - 895, Restore both front and back
polygon modes instead of only checking savedPolygonMode[0]; read/remember the
two-element savedPolygonMode (from GL_POLYGON_MODE) and when restoring call
glPolygonMode(GL_FRONT, savedPolygonMode[0]) and glPolygonMode(GL_BACK,
savedPolygonMode[1]) (or glPolygonMode(GL_FRONT_AND_BACK, ...) only when both
elements equal) so asymmetric modes are preserved; update the restore logic
around savedPolygonMode and glPolygonMode accordingly.

272-278: Consider expanding the failure check to cover more critical functions.

The failure check validates only a subset of resolved functions. Several functions used in rendering paths are not verified:

  • glTexImage2D, glTexSubImage2D (texture uploads)
  • glTexParameteri, glGetTexParameterfv (texture state)
  • glGetUniformLocation, glUniform1i, glUniformMatrix4fv (shader uniforms)
  • glGetShaderiv, glGetProgramiv (shader compilation checks)

While shader compilation failures are handled gracefully in newContext, texture operations in regenTexture and drawOverlay would crash if these pointers are NULL.

♻️ Suggested addition to failure check
 	if (!oglBindBuffer || !oglBindTexture || !oglBindVertexArray || !oglUseProgram || !oglDrawArrays || !oglEnable
 		|| !oglDisable || !oglViewport || !oglGetIntegerv || !oglGetError || !oglGenBuffers || !oglGenTextures
 		|| !oglGenVertexArrays || !oglCreateProgram || !oglCreateShader || !oglCompileShader || !oglLinkProgram
-		|| !oglAttachShader || !oglBlendEquation) {
+		|| !oglAttachShader || !oglBlendEquation || !oglTexImage2D || !oglTexParameteri || !oglGetUniformLocation
+		|| !oglUniformMatrix4fv || !oglUniform1i || !oglBufferSubData) {
 		resolveFailed = true;
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@overlay_gl/overlay.c` around lines 272 - 278, The current resolve-failure
check only verifies a subset of OpenGL function pointers and misses several
functions used by texture uploads and uniform/shader checks, which can cause
crashes in regenTexture and drawOverlay; update the failure check (the block
that sets resolveFailed) to also include glTexImage2D, glTexSubImage2D,
glTexParameteri, glGetTexParameterfv, glGetUniformLocation, glUniform1i,
glUniformMatrix4fv, glGetShaderiv, and glGetProgramiv (the same place where
oglBindBuffer/... are verified) so resolveFailed is set if any of these are
NULL, and ensure code paths in regenTexture, drawOverlay, and newContext assume
resolveFailed prevents usage when any pointer is missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@overlay_gl/overlay.c`:
- Around line 418-429: The shader program is leaked when glLinkProgram fails
because ctx->uiProgram isn't deleted; add FDEF(glDeleteProgram) to the
function-pointer/FDEF list (alongside existing FDEFs like
glDeleteShader/glDeleteTextures) so the resolver exposes glDeleteProgram, and in
the link-failure path (after glGetProgramiv detects !status and before
returning) call glDeleteProgram(ctx->uiProgram) to delete the orphaned program,
then proceed to log the info and return.

---

Nitpick comments:
In `@overlay_gl/overlay.c`:
- Around line 893-895: Restore both front and back polygon modes instead of only
checking savedPolygonMode[0]; read/remember the two-element savedPolygonMode
(from GL_POLYGON_MODE) and when restoring call glPolygonMode(GL_FRONT,
savedPolygonMode[0]) and glPolygonMode(GL_BACK, savedPolygonMode[1]) (or
glPolygonMode(GL_FRONT_AND_BACK, ...) only when both elements equal) so
asymmetric modes are preserved; update the restore logic around savedPolygonMode
and glPolygonMode accordingly.
- Around line 272-278: The current resolve-failure check only verifies a subset
of OpenGL function pointers and misses several functions used by texture uploads
and uniform/shader checks, which can cause crashes in regenTexture and
drawOverlay; update the failure check (the block that sets resolveFailed) to
also include glTexImage2D, glTexSubImage2D, glTexParameteri,
glGetTexParameterfv, glGetUniformLocation, glUniform1i, glUniformMatrix4fv,
glGetShaderiv, and glGetProgramiv (the same place where oglBindBuffer/... are
verified) so resolveFailed is set if any of these are NULL, and ensure code
paths in regenTexture, drawOverlay, and newContext assume resolveFailed prevents
usage when any pointer is missing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9ff90832-845a-460f-8918-94b63b510e34

📥 Commits

Reviewing files that changed from the base of the PR and between f2a0d8e and 4e403c7.

📒 Files selected for processing (4)
  • auxiliary_files/run_scripts/mumble-overlay.in
  • overlay_gl/avail_mac.h
  • overlay_gl/init_unix.c
  • overlay_gl/overlay.c

Comment thread overlay_gl/overlay.c
@ChrisLane ChrisLane force-pushed the fix-opengl-overlay branch from 4e403c7 to a814fda Compare March 24, 2026 14:33
@ChrisLane ChrisLane force-pushed the fix-opengl-overlay branch from a814fda to de4d364 Compare March 24, 2026 15:11
ChrisLane and others added 3 commits April 8, 2026 22:31
Replace deprecated fixed-function pipeline calls (matrix stack,
attribute push/pop, client state, glOrtho, glColorMaterial, glTexEnvi,
glRenderMode, etc.) with modern OpenGL 3.3 core profile equivalents:
explicit VAO/VBO, uniform MVP matrix, GLSL 3.30 shaders with layout
attributes, and manual state save/restore.

Resolve all GL function pointers at runtime via glXGetProcAddress
instead of relying on compile-time symbol availability. The overlay now
uses FDEF/GLRESOLVE macros and #define redirects so no GL symbols need
to be exported by the driver at link time. This fixes "undefined symbol:
glPopClientAttrib" (and similar) crashes on systems where Mesa only
provides a core profile context (e.g. Mesa 26 on Arch Linux).

Also fixes the find_odlsym() ELF dynamic-section loop to terminate on
DT_NULL instead of a null pointer check, which could walk past the end
of the section and cause "Unable to find symbol malloc" aborts.

Other minor improvements: SOCK_CLOEXEC/O_CLOEXEC to avoid leaking
file descriptors to child processes, NULL-check on malloc for blit
buffer.

Fixes mumble-voip#5932

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove leftover debug "echo set" from the 64-bit library path detection
in the mumble-overlay launch script.
@ChrisLane ChrisLane force-pushed the fix-opengl-overlay branch from de4d364 to 07effa2 Compare April 8, 2026 21:32
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.

Mumble overlay does not work

1 participant