Opened 3 years ago

Last modified 5 weeks ago

#17702 new defect

wxGLCanvas doesn't work with Wayland

Reported by: swt2c Owned by:
Priority: normal Milestone:
Component: wxGTK Version: 3.1.0
Keywords: wxGLCanvas Wayland Cc: swt@…, ojwb
Blocked By: Blocking:
Patch: no

Description

Attempting to run any of the opengl demos under Wayland results in a segfault:

#0  0x00000000006d0280 in  ()
#1  0x00007efea61de12e in XQueryExtension () at /lib64/libX11.so.6
#2  0x00007efea61d1ab2 in XInitExtension () at /lib64/libX11.so.6
#3  0x00007efea9864e2c in __glXInitialize () at /lib64/libGL.so.1
#4  0x00007efea98605f1 in glXQueryVersion () at /lib64/libGL.so.1
#5  0x00007efea9acca8d in wxGLCanvasX11::GetGLXVersion() ()
    at ./src/unix/glx11.cpp:750
#6  0x00007efea9acb4d3 in wxGLAttributes::RGBA() (this=0x7ffeeb104ad0)
    at ./src/unix/glx11.cpp:267
#7  0x00007efea9acb96a in wxGLAttributes::Defaults() (this=0x7ffeeb104ad0)
    at ./src/unix/glx11.cpp:431
#8  0x00007efea9ac8392 in wxGLCanvasBase::ParseAttribList(int const*, wxGLAttributes&, wxGLContextAttrs*) (attribList=0x0, dispAttrs=..., ctxAttrs=0x7b94f0)
    at ./src/common/glcmn.cpp:191
#9  0x00007efea9acd39e in wxGLCanvas::Create(wxWindow*, int, wxPoint const&, wxSize const&, long, wxString const&, int const*, wxPalette const&) (this=0x7b9260, parent=0x745b40, id=-1, pos=..., size=..., style=65536, name=..., attribList=0x0, palette=...) at ./src/gtk/glcanvas.cpp:238
#10 0x00007efea9acd32d in wxGLCanvas::wxGLCanvas(wxWindow*, int, int const*, wxPoint const&, wxSize const&, long, wxString const&, wxPalette const&) (this=0x7b9260, parent=0x745b40, id=-1, attribList=0x0, pos=..., size=..., style=65536, name=..., palette=...) at ./src/gtk/glcanvas.cpp:172

It looks like the existing code makes some X11 calls unconditionally. I'm guessing this probably won't be trivial to fix. It looks like there a GtkGLArea widget in GTK now, but it's 3.16+. Maybe that could be a solution for Wayland support.

Change History (27)

comment:1 Changed 3 years ago by mmarsan

In ticket http://trac.wxwidgets.org/ticket/17425 there are two patches wxGLContext_ctor_x11Direct20160316.patch and GLReworkOldHardware20160830.patch

Please, apply (specially the first) and try again.
You may have some issues applying the second patch because it's a local git copy.

comment:2 Changed 3 years ago by mmarsan

  • Keywords wxGLCanvas Wayland added
  • Version changed from 3.0.2 to 3.1.0

Aaarrggg, sorry, I completely missed 'Wayland' word. No matter if it was 72p bold font.
Yes, this is not a trivial fix. Don't expect a solution soon. Sorry again.

comment:3 Changed 3 years ago by fredericgermain

Just to add a use case, we have this crash on Fedora 25 (which migrated to wayland by default) + aegisub

https://bugzilla.rpmfusion.org/show_bug.cgi?id=4256

comment:4 Changed 2 years ago by tm

Anything new with this bug? Or are there workarounds?

Hugin on Fedora 25 is now also affected by this bug
(https://groups.google.com/d/msg/hugin-ptx/cIHVQoL67Fs/PuhWSBI7AgAJ)

It seems that (older) Hugin version compiled with wxWidgets 2.8.12 (with gtk2-2.24.31) works fine on Wayland (but Hugin upgraded in the meantime to wxWidgets 3.x). So it seems the bug was introduced by the changes in the OpenGL code.

comment:5 Changed 2 years ago by swt2c

The bug wasn't really introduced by any changes in the OpenGL code. It's that wxGLCanvas only works on X11 and Fedora has enabled Wayland by default. wxWidgets 2.8 only supported gtk2, which only supports X11.

The workaround is probably to force using the X11 backend for now:

GDK_BACKEND=x11 hugin

comment:6 Changed 21 months ago by swt2c

  • Cc swt@… added

I have started working on making wxGLCanvas work under Wayland. I see two ways of doing this:

1) Use GtkGLArea/GtkGLContext. The downside of this is that it doesn't really seem to fix exactly into the wxGLCanvas model (GtkGLArea seems to always want to have a GtkGLContext) and I don't see any way to support the wxGLAttributes.

2) Implement an EGL backend for wxGLCanvas. EGL seems to be coming more into favor over GLX anyway, and it supports X11 also.

I am leaning towards doing an EGL implementation. Any opinions?

comment:7 Changed 21 months ago by vadz

I really don't know much about OpenGL, but even I vaguely heard that EGL should be preferred for the new code, so why not. I'm not sure if we're really going keep 100% compatibility in this way, but having 99% compatibility and just needing to fix a few things would still be a big improvement compared to the current situation.

OTOH I think we may well need API changes to accommodate GTK+ 4 drawing model soon anyhow, so it wouldn't be shocking to have to provide some new and (hopefully not that much?) incompatible API that you'd need to use for Wayland and GTK+ 4 support. So if (1) could be simpler to do and the only problem is with compatibility, it could still be a good choice too.

In any case, thanks a lot for looking at this!

comment:8 Changed 21 months ago by mmarsan

  • Cc mmarsan@… added

The way OpenGL is supported under wx is currently based on:

  • Create a simple window, with its attributes (colors, buffers, etc)
  • Create a gl-context, with its attributes (version, profile, debug, etc)
  • Provide the SwapBuffers function.
  • Provide the gl-contex SetCurrent function.
  • Provide some checks (IsXXXSuported, IsOk.

Those are OS matters, there isn't an API gl-call there.

I have never done an app for Wayland, but I know some things:
OpenGL-ES is used mainly in mobile devices. Is not the same as the OGL desktop API, although it tends to. OGL-ES is what Wayland uses. Instead of GLX it uses its own binding called EGL. I've read somewhere about code that makes possible to work with X11 in Wayland (apart that GDK command in comment 5)

Not only GLX calls must be replaced with EGL calls, but also some X11 calls used for the window and its attributes.

What is good about GLX and its WGL equivalent in MSW is that they use very similar functions, specially for gl-context stuff. And that not other API is needed (i.e. no GTK).

I propose to work on low level, develop a Wayland port without GTK. This is what wx currently does. And avoids GTK issues.

comment:9 Changed 21 months ago by swt2c

Okay, I'll continue working on the EGL approach without involving GTK (much).

comment:10 Changed 14 months ago by Vadim Zeitlin <vadim@…>

In 95857a1f7/git-wxWidgets:

Give an error when trying to use wxGLCanvas on non-X11 display

Currently, wxGLCanvas on wxGTK is only supported on X11 displays. If a
user attempts to use wxGLCanvas on Wayland, for example, the application
will core dump. This change adds an error message and a suggested
workaround until wxGLCanvas is supported on Wayland.

See #17702.

Closes https://github.com/wxWidgets/wxWidgets/pull/871

comment:11 Changed 14 months ago by Paul Cornett <paulcor@…>

In 76c393b8b/git-wxWidgets:

Give an error when trying to use wxGLCanvas on non-X11 display

Currently, wxGLCanvas on wxGTK is only supported on X11 displays. If a
user attempts to use wxGLCanvas on Wayland, for example, the application
will core dump. This change adds an error message and a suggested
workaround until wxGLCanvas is supported on Wayland.
See #17702
See https://github.com/wxWidgets/wxWidgets/pull/871

(backport of 95857a1f71bd0c19e3059ebf0eea28e9bb8b7602)

comment:12 Changed 14 months ago by ojwb

I found I can implement the suggested workaround in my application's code by adding this to the start of main():

#ifdef __WXGTK3__
    setenv("GDK_BACKEND", "x11", 1);
#endif

I already use IMPLEMENT_APP_NO_MAIN rather than IMPLEMENT_APP for wxGTK for other reasons, but I thought it worth noting that it seems you can actually set this in the application itself if you can arrange for it to happen early enough.

comment:13 Changed 14 months ago by swt2c

Thanks Olly. I found that this trick works also if you don't want to use IMPLEMENT_APP_NO_MAIN, although it isn't technically portable:

void __attribute__ ((constructor)) force_x11()
{
    setenv("GDK_BACKEND", "x11", 1);
}

comment:14 Changed 14 months ago by ojwb

Good idea. This is the more portable version of that which also seems to work:

#ifdef __WXGTK3__
struct ForceX11 {
    ForceX11() {
       setenv("GDK_BACKEND", "x11", 1);
    }
};

static struct ForceX11 forcex11;
#endif

Historically constructors on global objects didn't get reliably run in some situations on some platforms. I'm not sure if that's still true anywhere, but I'd think they would work everywhere __attribute__ ((constructor)) worked, and probably anywhere that Wayland is likely to currently be found:

comment:15 follow-up: Changed 14 months ago by ojwb

I guess wx itself can't easily set this automatically because it doesn't know if wxGLCanvas will be used at the point where it's about to initialise GTK/GDK?

comment:16 in reply to: ↑ 15 Changed 14 months ago by swt2c

Replying to ojwb:

I guess wx itself can't easily set this automatically because it doesn't know if wxGLCanvas will be used at the point where it's about to initialise GTK/GDK?

Right. I can't think of a way for it to know that GLCanvas is going to be used.

comment:17 Changed 14 months ago by vadz

We could do this at wxGLApp level. But I'm not sure if (m)any programs using wxGLCanvas really use it (and notwxApp) as the base class for their application class.

At the very least I guess having some function that could be called to force the use of X11 could be useful, e.g. to allow writing something like

static bool forceX11 = wxGLApp::ForceUseOfX11WithWayland();

comment:18 follow-up: Changed 14 months ago by mmarsan

  • Cc mmarsan@… removed

wxGLApp is something I have never understood. There's nothing special in an app that uses OpenGL. The comment at glcanvas.h::

wxGLApp: a special wxApp subclass for OpenGL applications which must be used to select a visual compatible with the given attributes

is useless for me. The visual with attributes is created with wxGLCanvas.

Plus, wxGLApp is undocumented. I don't know if any body has used it ever.

For the Wayland thing, can anyone tell me if a simple wxWidgets app works for Wayland without using GDK_BACKEND=x11? If it's needed anyhow, all efforts to make wx to use it automatically should be at wxApp level, not just for OpenGL.

comment:19 in reply to: ↑ 18 Changed 14 months ago by swt2c

Replying to mmarsan:

For the Wayland thing, can anyone tell me if a simple wxWidgets app works for Wayland without using GDK_BACKEND=x11? If it's needed anyhow, all efforts to make wx to use it automatically should be at wxApp level, not just for OpenGL.

Yes, most wxWidgets apps work just fine on Wayland. It's only when wx uses X11 functionality directly (rather than going through GTK+) that it's a problem.

comment:20 Changed 14 months ago by ojwb

  • Cc ojwb added

Someone definitely has used wxGLApp - me!

As it happens, I actually stopped using wxGLApp a few weeks ago. I switched to using wxGLCanvas::IsDisplaySupported() instead, since that was (a) actually documented and (b) allowed putting all the OpenGL-specific code in a single source file.

But wxGLApp certainly isn't very discoverable currently so I think it's likely that it isn't very widely used (I'm not sure how I found it existed back in 2006 when I started using it - I guess by reading the wx source code, or maybe it used to be documented somewhere).

Some stats - https://codesearch.debian.net/search?q=wxGLApp shows the following packages:

survex wxpython4.0 wxwidgets3.0 wxpython3.0 therion libwx-glcanvas-perl

(and survex is the one I changed upstream a few weeks ago to stop using wxGLApp.)

but https://codesearch.debian.net/search?q=wxGLCanvas shows many more packages:

projectm mrpt megaglest qutemol libwx-perl wxpython4.0 darkradiant survex wxwidgets3.0 kicad objcryst-fox 0ad cubicsdr ginkgocadx erlang-cl geshi openscenegraph-3.4 dokuwiki ctsim silverjuke slic3r-prusa wxpython3.0 aegisub wings3d limesuite therion hugin 3depict erlang codeblocks golly openscenegraph slic3r pymol libwx-glcanvas-perl

The workaround could probably be automatically enabled if the "gl" wx library is linked in. This library isn't in the default list for wx-config --libs so if it's being linked it must have been explicitly specified which seems a pretty clear sign that wxGLCanvas will be used (not true for a monolithic build though).

comment:21 Changed 13 months ago by bpetty

relaying from Leio:

15:09 <leio> They should stop mucking around with env vars, and use gdk_set_allowed_backends instead (probably just something like x11,* to not break things; essentially just pushing x11 in front of wayland for gtk)
15:10 <leio> the default order currently is quartz,win32,wayland,mir,x11,broadway
15:10 <leio> and
15:10 <leio> EGL works fine with desktop GL
15:10 <leio> full GL
15:10 <leio> EGL is not GLES specific
15:11 <leio> (of course driver and environment support is another question, but these days it should be fine)

comment:22 Changed 13 months ago by ojwb

The big advantage of "mucking around with env vars" for a workaround in the application is that you don't need to start including GDK headers in the application code and linking the application directly to libgdk. All it needs is a few lines of code adding (plus making sure <stdlib.h> or <cstdlib> has been included).

comment:23 Changed 13 months ago by leio

Alright, now that I haven't locked myself out again, let me clarify.

I meant the gdk_set_allowed_backends for a wxGTK integrated interim workaround solution. Some sort of wxWidgets code solution should be using that, not env vars. In short - don't make wxGTK code itself muck with env vars - it has the headers included and can use the function; albeit it might be necessary as a fallback for older than gtk 3.10 build- or runtime, as that API is new since then.

I can see how it can be much easier by setting an env var, though it does stop people from using the app in some interesting combinations, like a potential wxGTK with quartz backend on OSX, etc; however those would probably hit similar issues as wayland is.
That env var can be a comma-separated listing too, iirc, so something better can be done than just forcing x11 there, too. Also if env var is already set (by user) and doesn't even have wayland in it, maybe it's not good to force something else on it, which the API function would avoid.

EGL works fine with full OpenGL context for many years now, it's not limited to GLES, so as a first step, don't have to necessarily worry about making wxGLCanvas compatible with GLES, just EGL.

To clarify this EGL business more, I wrote about it elsewhere just recently, so I'm just going to copy-paste citate myself with a few edits:

To make things easier to follow, there are basically three different
concepts and potential choices to make:

  • API
  • Platform
  • Windowing system

API is either "full desktop" OpenGL (think e.g. OpenGL 4.5), or GLES;
GLES has multiple versions, but in practice it's GLESv2 with optional
support for GLESv3 - however afaik latest mesa supports GLESv3 too
whenever GLESv2 is built. [GLES has also versions like 3.1 and 3.2, but the API headers are mostly same and just support code from a library like wxGLCanvas probably doesn't need to distinguish these]

Platform is either GLX or EGL. GLX only works in combination with "full
desktop" OpenGL; EGL can work with either.
For non-Linux there's also CGL (OSX), WGL (Windows), EAGL (iOS) and
more.

"EGL is an interface between Khronos rendering APIs such as OpenGL ES
or OpenVG and the underlying native platform window system." - thus the
third choice with EGL platform - windowing system. This then is about
supporting a certain graphics environment with EGL (with GLX that can
be taken as just always X).
This can be for example x11, wayland, GBM (think rendering 3D directly
on top of a KMS terminal), win32, cocoa, android, vivante framebuffer
(with proprietary vivante 3D stack; not applicable to open source
etnaviv), DispmanX (RPi), etc.
This can be a choice especially for certain kind of OpenGL libraries;
one big example I know of is GStreamer GL libraries.

comment:24 follow-up: Changed 5 weeks ago by ojwb

I've been wondering about setting the allowed GDK backends list to X11 when the wx gl library is loaded - here's a prototype patch, which seems to work:

  • src/gtk/glcanvas.cpp

    a b  
    1919#include <gdk/gdkx.h>
    2020#include "wx/gtk/private/gtk2-compat.h"
    2121
     22#if GTK_CHECK_VERSION(3,10,0)
     23// wxGTK's wxGLCanvas requires X11 currently, so tell GDK that so under
     24// Wayland the app is still run using X11.  We put this here so it's
     25// only run when the wx GL library is loaded (in a monolithic build this
     26// will always be active if wx's GL support is enabled).
     27struct ForceX11 {
     28    ForceX11() { gdk_set_allowed_backends("x11"); }
     29};
     30static ForceX11 forcex11;
     31#endif
     32
    2233#if WXWIN_COMPATIBILITY_2_8
    2334
    2435//-----------------------------------------------------------------------------

I'm setting the list to just x11 (rather than x11,* or some reordering of the default list) because the wxGTK implementation of these classes currently requires GLX so I can't see any other GDK backend working here currently.

The main downside I can see is if the build is configured with --enable-monolithic --with-opengl then this will always force X11 even if the GL support isn't used. It would also force X11 in a non-monolithic build if the wx GL library was linked but not actually used, but that doesn't seem a big problem (and some distros default to linking with --as-needed so this situation doesn't occur there anyway).

Thoughts? If this seems suitable to apply I can make a PR for it.

comment:25 in reply to: ↑ 24 Changed 5 weeks ago by swt2c

Replying to ojwb:

I've been wondering about setting the allowed GDK backends list to X11 when the wx gl library is loaded - here's a prototype patch, which seems to work:

What will happen in the case of wxPython? Without trying it, my guess is either that it will force X11 for *all* wxPython apps, or it won't work at all for wxPython unless a user imports wx.glcanvas before creating the app?

comment:26 Changed 5 weeks ago by ojwb

What will happen in the case of wxPython? Without trying it, my guess is either that it will force X11 for *all* wxPython apps

Good question.

I tested with wxPython3 by running an interactive python and doing import wx, then finding the PID and doing:

grep wx /proc/$PID/maps 

This shows that the wx gl library isn't loaded just by import wx.

Thinking about it, this really must be the case or else we'd have had a lot more bug reports since every wxPython app would fail to work under wayland out of the box!

After import wx.glcanvas the command above shows the wx gl library has been loaded.

And I get equivalent results with python3 and wxPython4.

or it won't work at all for wxPython unless a user imports wx.glcanvas before creating the app?

The workaround needs to be triggered before gtk_init() or equivalent is called to work, so if you lazily import wx.glcanvas it won't kick in. But if it's called later it just has no effect, so it seems we'd be no worse off than currently in this case.

comment:27 Changed 5 weeks ago by ojwb

Thinking about it, this really must be the case or else we'd have had a lot more bug reports since every wxPython app would fail to work under wayland out of the box!

Hmm, I may be wrong here actually - I was thinking that one of my C++ apps which uses wxGLCanvas would originally segfault on start up rather than when the GL window is actually created, but that's probably because it checks for OpenGL support on startup.

But anyway, adding this patch wouldn't be a problem for wxPython.

Note: See TracTickets for help on using tickets.