Open almarklein opened 4 years ago
wgpu-native just got support: https://github.com/gfx-rs/wgpu-native/pull/160/ but apparently GLFW's support for Wayland is still experimental and pyGLFW may not support it yet.
It looks like all the components are there to connect things up (with glfw), but when I run it, the system crashes and I'm back in my login screen 😆 I've spend some time checking and trying things, but no luck.
For Qt, this seems like a good staring point: https://doc.qt.io/qt-5/wayland-and-qt.html I have not looked at that myself yet.
Current status: it's not known if the latest versions of GLFW and wgpu-py together support wayland or not. Needs verification before we can close.
I'm not too sure about the packages on pypi, but I've compiled qt and wayland for conda-forge: https://github.com/conda-forge/qt-wayland-feedstock
https://github.com/conda-forge/qt-main-feedstock/issues/120#issuecomment-1546916602
let me know if that helps.
If you feel that an other package is missing wayland support, I've found that:
2 has been largely alleviated recently with the introduction of things like manylinux_20YY.
Qt did not work on Wayland.
can you expand on this? I was trying this a while back too, it seems that Python for Qt (PyQt6 and PySide6) likely doesn't expose the API required to make this work. My next attempt was to dig deeper into the C++ API to see if there was a small patch I could make to pyside2 to expose the required functions.
I'm not sure if you already tried this.
glfw did, kinda,[...] undecorated window.
regarding undecorated windows, it seems that this is a "choice" by Wayland, they are pushing the decorations on the client side, many frameworks now have a "switch" that you have to toggle if you want the "default" decorations.
I the decison to make the the client's (the application we are writing in our python+wgpu context) choice was one that came about because Chrome + Firefox were starting to try to make more use of the space typically reserved for "decorations".
Qt did not work on Wayland.
can you expand on this?
Basically, we need the display handle (pointer to display object), and although Qt has API to get it, this is not exposed in PySide nor PyQt5. In X we deal with this by creating our own display object. Unfortunately, Wayland does not accept this trick (and the app segfaults). IIRC window ids on X are pretty big numbers, while on Wayland they're small ints. Which makes me think X uses globally unique window ids, where in Wayland they are namespaced to the display object.
I have not thought about submitting a patch to PySide / PyQt yet.
regarding undecorated windows, it seems that this is a "choice" by Wayland, t
Yeah, and I think glfw now does the decoration, but from what I read, I think it does this in glfw 3.4, which is not yet available via pyglfw.
I have not thought about submitting a patch to PySide / PyQt yet.
Do you recall the function we need to call from Qt's C++ API? If so, it would make it easier to open an issue on the PySide Bugtracker. They don't seem to have an active tracking issue: https://bugreports.qt.io/browse/PYSIDE-2190?jql=project+%3D+PYSIDE+AND+text+%7E+wayland
glfw 3.4
I tried to just install pyglfw from conda-forge, and for some reason I got:
$ mamba list glfw
# packages in environment at /home/mark/miniforge3/envs/dev:
#
# Name Version Build Channel
glfw 3.4 hd590300_0 conda-forge
pyglfw 2.7.0 py310hff52083_0 conda-forge
$ python triangle_glfw.py
Detected skylake derivative running on mesa i915. Clears to srgb textures will use manual shader clears.
/home/mark/miniforge3/envs/dev/lib/python3.10/site-packages/glfw/__init__.py:914: GLFWError: (65550) b'X11: Platform not initialized'
warnings.warn(message, GLFWError)
Traceback (most recent call last):
File "/home/mark/git/wgpu-py/examples/triangle_glfw.py", line 18, in <module>
device = main(canvas)
File "/home/mark/git/wgpu-py/examples/triangle.py", line 67, in main
return _main(canvas, device)
File "/home/mark/git/wgpu-py/examples/triangle.py", line 84, in _main
render_texture_format = present_context.get_preferred_format(device.adapter)
File "/home/mark/miniforge3/envs/dev/lib/python3.10/site-packages/wgpu/backends/wgpu_native/_api.py", line 664, in get_preferred_format
self._get_surface_id(), adapter._internal
File "/home/mark/miniforge3/envs/dev/lib/python3.10/site-packages/wgpu/backends/wgpu_native/_api.py", line 368, in _get_surface_id
self._surface_id = get_surface_id_from_canvas(self._get_canvas())
File "/home/mark/miniforge3/envs/dev/lib/python3.10/site-packages/wgpu/backends/wgpu_native/_helpers.py", line 104, in get_surface_id_from_canvas
surface_info = canvas.get_surface_info()
File "/home/mark/miniforge3/envs/dev/lib/python3.10/site-packages/wgpu/gui/glfw.py", line 289, in get_surface_info
"display": int(glfw.get_x11_display()),
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
the qt wayland example works!!!! and consequently my own personal application seems to be doing fine on intel + wayland.
Do you recall the function we need to call from Qt's C++ API?
I mean this. It looks like this patch implements it for PySide. It's very recent, so not yet available in a release.
the qt wayland example works!!!!
Do you mean the qt triangle example, running on Wayland?
int(glfw.get_x11_display()), TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
I suppose this is related to glfw 3.4 having one binary that supports both X11 and Wayland, and the PYGLFW_LIBRARY_VARIANT
is somehow not applied in the correct way. It does mean that wgpu is broken for glfw installed with conda, so that's unfortunate 😕
Notes to self: I think this is the structure that we need to get https://doc.qt.io/qt-6/qnativeinterface-qwaylandapplication.html
But QNativeInterface on qt 6.7.1 + pyside6 on conda-forge only exposes the X11 interface
from PySide6.QtGui import QNativeInterface
QNativeInterface.QX11Application
Will try to investigate -- https://bugreports.qt.io/browse/PYSIDE-2787
Hi @hmaarrfk in the Pyside bug report there a new comment there. Thanks for helping with that, it can be very helpful.
About GLFW it's running very well on Wayland, i just needed to comment
if "glfw" not in sys.modules:
os.environ["PYGLFW_LIBRARY_VARIANT"] = "x11"
in gui/_gui_utils.py
.
Also, commenting os.environ["GDK_BACKEND"] = "x11"
in gui/_gui_utils.py
GLFW will use correct window decoration from Gnome.
@tfmoraes what OS is that on, and have you install glfw via pip install glfw
or are you somehow using a glfw lib provided by the system?
@almarklein I'm using Fedora 41, Gnome 47 and Nvidia 4070 with proprietary drivers. I installed using pip install glfw
. I think you need to install libdecor to have the Gnome window decoration. Also, this is the output of gui_glfw.py
:
❯ python gui_glfw.py
Using GLFW with Wayland, which is experimental.
No config found!
EGL says it can present to the window but not natively
Max vertex attribute stride unknown. Assuming it is 2048
Re-initializing Gles context due to Wayland window
No config found!
EGL says it can present to the window but not natively
Also, using GLFW just from pip package:
❯ cat /proc/76780/maps | grep -i glfw
7f2f6c893000-7f2f6c89c000 r--p 00000000 00:36 1253 /tmp/lll/.venv/lib/python3.13/site-packages/glfw/wayland/libglfw.so
7f2f6c89c000-7f2f6c8b6000 r-xp 00009000 00:36 1253 /tmp/lll/.venv/lib/python3.13/site-packages/glfw/wayland/libglfw.so
7f2f6c8b6000-7f2f6c8db000 r--p 00023000 00:36 1253 /tmp/lll/.venv/lib/python3.13/site-packages/glfw/wayland/libglfw.so
7f2f6c8db000-7f2f6c8dd000 r--p 00047000 00:36 1253 /tmp/lll/.venv/lib/python3.13/site-packages/glfw/wayland/libglfw.so
7f2f6c8dd000-7f2f6c8df000 rw-p 00049000 00:36 1253 /tmp/lll/.venv/lib/python3.13/site-packages/glfw/wayland/libglfw.so
Updated 17-09-2024
Current status
Up to 17-09-2024:
Introduction
Since Ubuntu 21.04, Wayland is the default display server. This means that this issue potentially affects a lot of users.
The
XDG_SESSION_TYPE
env variable is eitherx11
orwayland
. This variable is used by many applications to select the window system. What's important for us is that glfw and qt (and wx?) use this variable too.Forntunately, there is XWayland, a compatibility layer that allows applications to "talk X", but still run on Wayland. XWayland is installed by default on Ubuntu too.
This means we can tell glfw and qt to just use X, even when on Wayland. There are env vars for that.
How does it affect us exactly?
To obtain a surface id for the canvas to render to, we call
wgpuInstanceCreateSurface()
, the descriptor argument for that function is platform specific; there is a different struct for Windows, Metal, X11, Wayland, and Xcb.On Windows and MacOS, that struct can be composed with just the "window id". Glfw, Qt and Wx have a metthod to obtain it. So Windows and MacOS are relatievely easy.
On Linux, apart from having to deal with multiple window platforms, we also need an additional value: the display id. This is basically a pointer to a display context: the thing an app creates to start doing things with x11/Wayland. A bit similar to a device of wgpu. This is where the hard part is.
Support for glfw
GLFW has improved support over the past years/months, but seems not quite 100% yet. Pyglfw on Linux includes one lib for x11 and one for Wayland, and selects one based on
XDG_SESSION_TYPE
and a few other variables.The latest glfw (3.4, released 23-02-2024) ought to have better support for Wayland. And includes that support in a single binary lib. Unfortunately, there are some build problems, so pyglfw cannot ship with these binaries yet. It ships glfw 3.3.9 instead.
When I
apt install libglfw3
it installs version 3.3.6 (on Ubunty 22.04). I don't feel like compiling glfw from source right now. So I have not tested the new glfw 3.4.This snippet can be used to create a glfw window. Without the
PYGLFW_LIBRARY_VARIANT
this produces an unresponsive window without decorations on Wayland (with glfw 3.3.9).Also see https://github.com/gfx-rs/wgpu/issues/4775 and https://github.com/gfx-rs/wgpu-native/issues/377.
The solution for now (March 2024) is to force glfw to use X11 (i.e. XWayland on Wayland).
Support for Qt
The problem with Qt is that we cannot obtain the display id that Qt uses internally. There is QGuiApplication.nativeInterface but ... it's not implemented in PySide or PyQt. See e.g. https://wiki.qt.io/Qt_for_Python_Missing_Bindings. Though maybe its available soon?
Another thing I tried was to mage qt's
WgpuCanvas
aQWindow
instead of aQWidget
. This class has asurfaceHandle()
method ... except it raises an exception saying the method is private.Instead of using the actual display id that Qt uses, we can also create our own "display object" and use that. That works fine for X11. Unfortunately, this does not work for Wayland.
Then there is
QT_QPA_PLATFORM
, which can be set to (amongst other things "wayland-egl" and "xcb".The solution for now (March 2024) is to set
QT_QPA_PLATFORM
toxcb
to tell Qt to use X11 (i.e. XWayland on Wayland).Support for wx
Can force to use x11 by setting
GDK_BACKEND
to "x11". But I haven't tested because cannot installwxPython
with apt or pip.