[PrusaSlicer 3.0] Run natively on Wayland by building wxGLCanvas and GLEW against EGL - #15826
Open
xarbit wants to merge 5 commits into
Open
[PrusaSlicer 3.0] Run natively on Wayland by building wxGLCanvas and GLEW against EGL#15826xarbit wants to merge 5 commits into
xarbit wants to merge 5 commits into
Conversation
GLX only exists on X11, so while wxGLCanvas could only create GLX contexts the 3D view could not work under Wayland at all. wxWidgets was built with wxUSE_GLCANVAS_EGL=OFF and GLEW in its default GLX mode, where glewInit() resolves entry points through glXGetProcAddress. EGL works on X11 as well, so one binary still serves both. Dropping GLX also drops the libraries it pulled in implicitly, and the static wx libraries do not propagate them, so link them explicitly. Which ones are needed depends on the backends GTK was built for, hence the pkg-config check rather than requiring both.
The backend was forced with replace=true, so a GDK_BACKEND from the environment was discarded before GTK saw it and there was no way to run under anything else. The comment blamed wxGTK, but the real obstacle was the GLX only GL context addressed in the previous commit. Fall back to X11 only when there is no Wayland session, and leave an explicitly set GDK_BACKEND alone. Fixes prusa3d#8284.
xarbit
force-pushed
the
wayland-native-egl
branch
from
September 13, 2026 13:45
bbdc50f to
dc0dbac
Compare
With the EGL backend wxGLCanvas::SwapBuffers() returns false whenever the canvas has no surface it can present to, which the GLX backend never did. There are two ordinary reasons for it, and both were logged as errors. The first is start up: under Wayland wx deliberately refuses to present until the compositor has signalled that the surface is ready, because presenting earlier can deadlock inside eglSwapBuffers(). The second is the canvas being off screen. wx destroys the EGL subsurface when the widget is unmapped, so minimising the window or leaving its workspace makes every swap fail until it is mapped again and the next frame callback arrives. Track whether there is a surface to present to and report an error only when a swap fails although there is.
on_idle() drained the main thread dispatcher before repainting. The first thing queued at start up is loading the preset bundles, which blocks the main thread for over a second with a large configuration, so the canvas only presented once that was done. LoadingRenderModule was drawing the whole time, it just never reached the screen. Present a frame first. Under Wayland that takes a few idle cycles, since the EGL backend waits for the compositor, so drain the dispatcher anyway after 500 ms in case no frame can be presented at all.
A window is matched to its desktop file, and so to its icon, by the identity it advertises: app_id on Wayland, WM_CLASS on X11. GTK derives both from the program name, which defaults to the executable, so the window announced slic3r-app-launcher while the desktop file installed for it is com.prusa3d.PrusaSlicer. Nothing matched and the window was drawn with a generic icon. Set the program name to the desktop file name, and take both it and StartupWMClass from one CMake variable so they cannot drift apart. This only showed up once the application started running on Wayland directly instead of through XWayland.
xarbit
force-pushed
the
wayland-native-egl
branch
from
September 13, 2026 14:39
dc0dbac to
eb7f94f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PrusaSlicer forces GDK_BACKEND=x11 on every Linux start.
The reason is that wxGLCanvas could only create GLX contexts, and GLX is X11 only. wx does have an EGL backend in src/unix/glegl.cpp, it was just compiled out.
Two build flags pinned it to GLX. wx was built with wxUSE_GLCANVAS_EGL=OFF, and GLEW was built in its default GLX mode, so glewInit() went through glXGetProcAddress. This turns both on. EGL works on X11 as well, so one binary still serves both.
Dropping GLX also drops the libraries that came in through it. The wx libraries are static and their CONFIG package does not propagate them, so slic3r-platform-wx now links X11 and Wayland explicitly, each gated on the matching gtk+-x11-3.0 or gtk+-wayland-3.0 pkg-config file. A GTK built for only one backend still works.
With that in place the backend no longer has to be forced. X11 is now only a
fallback when WAYLAND_DISPLAY is absent, and replace=false means an explicitly
set GDK_BACKEND is respected. That part fixes #8284.
The other three commits are things that only become visible on application actually runs on Wayland instead of through XWayland.
SwapBuffers() returns false under EGL until the compositor signals that the surface is ready. wx does that deliberately, because presenting earlier can deadlock inside eglSwapBuffers(). The GLX path never returned false, so a normal start logged several errors that are not errors. One is now re a frame has actually been presented.
on_idle() drained the main thread dispatcher before repainting. The first thing queued at start up is loading the preset bundles, which blocks the main thread for over a second with a large configuration, so the canvas only presented once that work was already done. LoadingRenderModule was drawing the whole time, it just never reached the screen.
It now gets a frame out first, with a 500 ms deadline so start up cannot stall if no frame can be presented
The window announced slic3r-app-launcher as its app id, which executable name, while the desktop file installed for it is com.prusa3d.PrusaSlicer. Nothing matched, so the window was drawn with a generic icon.
The program name is now set to the desktop file name, and StartupWMClass comes from the same CMake variable so the two cannot drift apart.
Testing
Built and run from the Flathub manifest against the GNOME 50 S GTK 3.24.52 and Mesa 26.1.6.
The application runs as a native Wayland client:
WAYLAND_DEBUG shows it binding wl_compositor itself with no X11 connection, on a hardware OpenGL 4.6 core profile context. GDK_BACKEND=x11 still gives a working X11 session.
Tested on one machine, AMD radeonsi, with a GTK built for both pkg-config gating for a GTK with only one backend follows wx's own #ifdef guards but has not been run anywhere.