Skip to content

[PrusaSlicer 3.0] Run natively on Wayland by building wxGLCanvas and GLEW against EGL - #15826

Open
xarbit wants to merge 5 commits into
prusa3d:masterfrom
xarbit:wayland-native-egl
Open

[PrusaSlicer 3.0] Run natively on Wayland by building wxGLCanvas and GLEW against EGL#15826
xarbit wants to merge 5 commits into
prusa3d:masterfrom
xarbit:wayland-native-egl

Conversation

@xarbit

@xarbit xarbit commented Sep 12, 2026

Copy link
Copy Markdown

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.

@xarbit xarbit changed the title Run natively on Wayland by building wxGLCanvas and GLEW against EGL [PrusaSlicer 3.0] Run natively on Wayland by building wxGLCanvas and GLEW against EGL Sep 12, 2026
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.
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.
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.

PS uses XWayland and ignores GDK_BACKEND on Wayland

1 participant