Plugin GUI: first window per Bitwig launch fails to open (GLX has no framebuffer configs yet) #72

Open
opened 2026-09-06 19:55:35 +00:00 by bcox · 0 comments
Owner

Priority: low. Accepted and lived-with; the workaround is to click the plugin's GUI button a second time, which opens normally. Filed so the analysis is not lost.

Symptom

The very first plugin window opened in a fresh Bitwig (Flatpak) session does not appear. Opening it again works, and every window after the first works for the rest of the session. Once per launch.

What the logs show (TYMBAL_GUI_LOG=1)

On the first set_parent, glXChooseFBConfig returns zero configs for both the strict and the relaxed attribute lists, and glXGetFBConfigs (unfiltered) reports 0 total configs on the display -- the X server genuinely has no framebuffer configs at that moment, not "none matching ours". glXQueryVersion succeeds (1.4) on that same connection, so GLX is present and the GLVND vendor is bound; the configs simply are not there yet. A beat later (the second set_parent) they are.

What was tried and ruled out

  • Retrying the config query on the same connection (with XSync round-trips between tries): all attempts fail. Not a settling delay the query itself can wait out.
  • glXQueryVersion first to force GLVND vendor binding: it succeeds and changes nothing -- the vendor is bound and configs are still absent. Removed again.
  • Reopening the display in-process (fresh XOpenDisplay) within one set_parent: all three fresh connections in the same call report 0 total. So it is not connection-bound.
  • Deferring the open onto the frame timer (the shipped mitigation): set_parent accepts the parent and the ~16ms timer retries the open for ~3s. This still does not catch it, which is the key remaining clue: elapsed time alone does not make the configs appear within the budget. What does make them appear is whatever Bitwig does between the first failed attempt and the user's second click -- most likely a further step in the host's own GL bring-up, not the clock.

Leading hypothesis

XWayland (Flatpak Bitwig over XWayland) populates its GLX framebuffer-config list lazily, and the trigger is an action in the host's GL setup rather than wall-clock time, so the first plugin to ask -- before that trigger -- sees an empty list. The plugin-side deferred retry cannot win a race whose finish line is a host action it does not cause.

Options for a real fix (none pursued; low priority)

  1. Switch context creation from GLX to EGL (plugin/gui_window.cc). EGL initialises cleanly on XWayland and does not have the GLX-FBConfig-enumeration lag. Isolated to the context-creation code; the ImGui renderer and everything above are GL-API-agnostic. Durable fix, most likely ends the whole class.
  2. Widen the deferred-open budget well past 3s -- only helps if the configs eventually appear on their own, which the evidence does not support.

Where the code is

The deferred-open machinery (PluginGui::TryOpenWindow, the open_pending_/open_attempts_ retry on the frame timer) and the TYMBAL_GUI_LOG diagnostics are in plugin/gui.cc and plugin/gui_window.cc. glXGetFBConfigs's total-count log line is the one to watch on the next attempt.

**Priority: low.** Accepted and lived-with; the workaround is to click the plugin's GUI button a second time, which opens normally. Filed so the analysis is not lost. ## Symptom The very first plugin window opened in a fresh Bitwig (Flatpak) session does not appear. Opening it again works, and every window after the first works for the rest of the session. Once per launch. ## What the logs show (TYMBAL_GUI_LOG=1) On the first `set_parent`, `glXChooseFBConfig` returns zero configs for both the strict and the relaxed attribute lists, and `glXGetFBConfigs` (unfiltered) reports **0 total** configs on the display -- the X server genuinely has no framebuffer configs at that moment, not "none matching ours". `glXQueryVersion` succeeds (1.4) on that same connection, so GLX is present and the GLVND vendor is bound; the configs simply are not there yet. A beat later (the second `set_parent`) they are. ## What was tried and ruled out - **Retrying the config query on the same connection** (with XSync round-trips between tries): all attempts fail. Not a settling delay the query itself can wait out. - **glXQueryVersion first** to force GLVND vendor binding: it succeeds and changes nothing -- the vendor is bound and configs are still absent. Removed again. - **Reopening the display in-process** (fresh XOpenDisplay) within one `set_parent`: all three fresh connections in the same call report 0 total. So it is not connection-bound. - **Deferring the open onto the frame timer** (the shipped mitigation): `set_parent` accepts the parent and the ~16ms timer retries the open for ~3s. This still does not catch it, which is the key remaining clue: **elapsed time alone does not make the configs appear** within the budget. What does make them appear is whatever Bitwig does between the first failed attempt and the user's second click -- most likely a further step in the host's own GL bring-up, not the clock. ## Leading hypothesis XWayland (Flatpak Bitwig over XWayland) populates its GLX framebuffer-config list lazily, and the trigger is an action in the host's GL setup rather than wall-clock time, so the first plugin to ask -- before that trigger -- sees an empty list. The plugin-side deferred retry cannot win a race whose finish line is a host action it does not cause. ## Options for a real fix (none pursued; low priority) 1. **Switch context creation from GLX to EGL** (`plugin/gui_window.cc`). EGL initialises cleanly on XWayland and does not have the GLX-FBConfig-enumeration lag. Isolated to the context-creation code; the ImGui renderer and everything above are GL-API-agnostic. Durable fix, most likely ends the whole class. 2. Widen the deferred-open budget well past 3s -- only helps if the configs eventually appear on their own, which the evidence does not support. ## Where the code is The deferred-open machinery (`PluginGui::TryOpenWindow`, the `open_pending_`/`open_attempts_` retry on the frame timer) and the `TYMBAL_GUI_LOG` diagnostics are in `plugin/gui.cc` and `plugin/gui_window.cc`. `glXGetFBConfigs`'s total-count log line is the one to watch on the next attempt.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
bcox/tymbal#72
No description provided.