Skip to content

Take screenshots from an off-screen framebuffer - #379

Closed
HennesHajduk wants to merge 1 commit into
GLVis:masterfrom
HennesHajduk:virt-bg-run-bugfix
Closed

HennesHajduk wants to merge 1 commit into
GLVis:masterfrom
HennesHajduk:virt-bg-run-bugfix

Conversation

@HennesHajduk

Copy link
Copy Markdown

On X11, the contents of a window framebuffer are undefined wherever the window
is not visible on screen (pixel ownership test). Window managers that unmap
windows on non-current workspaces — Marco/MATE, among others — therefore make
Screenshot() read undefined data: every PNG written while the user is on
another workspace comes out black. This breaks batch rendering via
glvis -run script.glvis, which is otherwise meant to run in the background.

This patch renders the scene into an application-created FBO (RGBA8 color +
DEPTH24 renderbuffer at the current draw size) and reads the image back from
there. FBO attachments belong to the GL context rather than to the window
system, so they stay valid regardless of window visibility. If framebuffer
objects are unavailable (legacy GL context), the previous back/front buffer
path is used unchanged.

Two supporting changes are needed for this to work:

  • MeshRenderer gains a configurable target framebuffer. The MSAA resolve step
    previously hardcoded glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0), which would
    send the antialiased image back to the window instead of the off-screen
    target.
  • After the MSAA resolve, the read binding is restored to the target
    framebuffer. The resolve FBO is deleted when render() returns, which resets
    the read binding to the default framebuffer; reading from it afterwards
    raises GL_INVALID_OPERATION and yields the window contents again.

Verified on Marco/MATE with an NVIDIA GL driver, using a script that writes a
series of PNGs while the GLVis window is moved to another workspace, unmapped,
and left visible. Before: all frames taken while the window was hidden are
black. After: all frames are correct and match the frames rendered with the
window visible.


This fix was generated with Claude Code. I don't understand much of what is going
on here, since GL internals are not my area of expertise — please review
accordingly.

@najlkin

najlkin commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Hi @HennesHajduk , have you tried the headless rendering feature of GLVis? It is intended exactly for such situations when you do not want to pull up the window and only render a picture from a script. There is a command for it: headless, which you should put at the begging of the script.

@HennesHajduk

Copy link
Copy Markdown
Author

Hi @HennesHajduk , have you tried the headless rendering feature of GLVis? It is intended exactly for such situations when you do not want to pull up the window and only render a picture from a script. There is a command for it: headless, which you should put at the begging of the script.

I wasn't aware of that. Thanks @najlkin! Yes, if I compile GLVis with GLVIS_USE_EGL=YES, then it does the trick. Closing the PR therefore.

@HennesHajduk
HennesHajduk deleted the virt-bg-run-bugfix branch September 24, 2026 09:31
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.

2 participants