2025-07-14 | 研究与探索 | UNLOCK

在 MacOS 上运行 Wayland

只看 Wayland 协议,会觉得它只用到了 Unix 领域套接字(Unix Domain Socket),应该很容易移植到 Linux 之外的类 Unix 系统上去,事实上也的确如 此,FreeBSD 现在也移植了 Wayland 可以用。于是我就想能不能让 Wayland 在 MacOS 上运行。

我们可以找到一些前人的工作:合成器 Owl1,还有同一组织下的修改过的 wayland 库2。可惜这项目已经四年没更新了。

经过一番修改,将 wayland rebase 到稍新的版本,现在 epoll-shimxkbcommon 可以直接用 homebrew 安装,但还是要面对一些 Linux 和 MacOS 之间的差异,比如 MacOS 不支持 SOCK_CLOEXEC,需要定义 _DARWIN_C_SOURCE 宏等。

Wayland 需要考虑的问题之一是如何在服务器和客户端之间交换要渲染的数据。Unix 领域套接字有一个神奇的机制,可以在进程间分享文件描述符,也就是说你 在 A 进程有一个文件描述符 x,可以通过 Unix 领域套接字用一个特殊的机制把它发送给 B 进程,B 进程接收到的文件描述符 y 就是一个在 B 进程可用的文 件描述符了,它和 A 进程的 x 代表同一对象。由此可以使用 shmdma-buf 来共享内存或者 GPU 数据。

我一开始看的教程3create_memfd 来创建共享内存,但 MacOS 不支持,需要改用 shm_open,据说还可以先创建一个临时文件再 unlink 它,只保留打开的文件描述符用来 mmap,没试过。总之写的简单的 demo4 成功在 Owl 下跑起来了。

我想找一些简单的只涉及 shm 的程序来看看能不能移植。当然第一时间想到了 foot5。解决了一些 MacOS 没有 C thread 库,没有 uchar.h 之类 的问题之后,运行还是失败了,这次是因为 foot 需要更高版本的 wayland 协议支持。

于是还要改改 Owl,一番修改之后 foot 能显示一个黑框了,但没法正常工作……

又找到一个项目 havoc6,修改一番之后,终于能工作了,可喜可贺。

havoc on MacOS

大家对于把 Wayland 移植到 MacOS 似乎不是很热衷。我想这是因为大多数软件想移植到 MacOS 的都有原生支持,没有通过 Wayland 实现移植的需求吧,比 如 Dolphin 和 kitty。

上面只涉及到了通过共享内存向 Wayland 服务器发送绘制好的帧,如果想移植用到了 GPU 绘制的程序,一般是用到了 EGL 和 OpenGL ES,那就需要实现一套 类似在 Linux 上 MESA 所实现的机制。Linux 上通过 dma-buf 机制来跨线程共享纹理,也是通过传递文件描述符来实现的,可以看 这个知乎回答

MacOS 上有类似的 IOSurface 实现类似的功能7 8,因此我们可以搞类似 linux-dma-buf 的协议来传递纹理,Owl 就有一个 owl_iosurface_unstable_v1 协议。我发现至今 MacOS 的 OpenGL.framework 虽然底层都用 Metal 实现了,但仍有 CGLIOSurface.hCGLTexImageIOSurface2D,因此跨进程共享纹理理论上是可行的。

那么我们需要自己实现一套 EGL 或者修改 ANGLE 代码来实现 EGL_EXT_platform_wayland 扩展,并在底层使用 IOSurface 来共享纹理。要是想用 Vulkan 那就需要修改 MoltenVk,想用 Metal 那就需要客户端代码手动操作 IOSurface 了。

知道 EGL 1.5 支持创建 OpenGL 上下文之后,我就想能否写一个简单的包装把 OpenGL.framework 上下文管理的部分包装成 EGL,在请求 OpenGL ES 2.0 上下文时返回 OpenGL 4.1 core 上下文,因为它支持 GL_ARB_ES2_compatibility 扩展嘛。但是实际测试后发现,MacOS 的 OpenGL 4.1 core 上下文不支持 OpenGL ES 2.0 用的 GLSL ES 1.00,看来其虽然支持 GL_ARB_ES2_compatibility,但遵循了扩展文档9中的 “#version 100 只在 compatible profile 中支持”,而众所周知 MacOS OpenGL 没有 compatible profile……

也许简单的改改(把 atrributevarying 替换成 in 或者 outgl_FragColor 替换成 out 声明的变量)就能跑起来,不过这之后再 说吧……

相关代码已上传到 github,可以在这个仓库体验:

<github.com/chirsz-ever/run-wayland-app-on-macos>

Footnotes

  1. Owl https://github.com/owl-compositor/owl

  2. wayland https://github.com/owl-compositor/wayland

  3. writing wayland clients https://bugaevc.gitbooks.io/writing-wayland-clients/content/

  4. https://github.com/chirsz-ever/simple-wayland-client-demo

  5. foot https://codeberg.org/dnkl/foot

  6. havoc https://github.com/ii8/havoc

  7. https://developer.apple.com/documentation/iosurface

  8. https://www.chromium.org/developers/design-documents/iosurface-meeting-notes/

  9. https://registry.khronos.org/OpenGL/extensions/ARB/ARB_ES2_compatibility.txt