引用 Wayland 文档:
The open source stack uses the drm Wayland extension, which lets the client discover the drm device to use and authenticate and then share drm (GEM) buffers with the compositor.
这里的“Open source stack”即 mesa,“drm extension”指 mesa 定义的 wayland-drm.xml。执行 weston-info 查看 Compositor 提供的全局对象,如果其中包含wl_drm接口,就表明支持 drm extension。
较近版本的 Ubuntu 桌面都是基于 Wayland 的,并且支持 drm extension。在桌面运行 Weston(以 wayland-backend.so作为 backend),也支持 drm extension。执行 weston-info 检查 Weston 时,要设置 WAYLAND_DISPLAY 环境变量:
WAYLAND_DISPLAY=wayland-1 weston-info
包含 <EGL/egl.h> 头文件,要求定义宏 WL_EGL_PLATFORM。<EGL/egl.h> 包含了 <EGL/eglplatform.h>,在 <EGL/eglplatform.h> 中看到:
...
#elif defined(WL_EGL_PLATFORM)
typedef struct wl_display *EGLNativeDisplayType;
typedef struct wl_egl_pixmap *EGLNativePixmapType;
typedef struct wl_egl_window *EGLNativeWindowType;
头文件 <wayland-egl.h> 中定义了宏 WL_EGL_PLATFORM。可以先包含 <wayland-egl.h>,再包含 <EGL/egl.h>,确保 WL_EGL_PLATFORM 宏定义应用到 <EGL/egl.h>。也可以在编译时定义,例如 -D WL_EGL_PLATFORM。
首先获得 wl_display 和 wl_surface 对象,从这两个 Wayland 对象创建对应的 EGL 对象:
#include <wayland-egl.h>
#include <EGL/egl.h>
...
static struct
{
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_output *output;
struct zwp_fullscreen_shell_v1 *fullscreen_shell;
struct wl_surface *surface;
} wayland_objects = {0};
static struct
{
int32_t width;
int32_t height;
} wayland_output_info = {0};
...
EGLDisplay display = eglGetDisplay((EGLNativeDisplayType)wayland_objects.display);
...
EGLNativeWindowType window = wl_egl_window_create(wayland_objects.surface, wayland_output_info.width, wayland_output_info.height);
...
EGLConfig config = ...
const EGLint attrs[] = ...
EGLSurface surface = eglCreateWindowSurface(display, config, window, attrs);
...
Build 时,要链接 wayland-client, wayland-egl, egl 库;如果是 OpenGL ES 渲染,当然还要链接 glesv2 库。
我的运行环境是 Raspberry Pi 4B + Ubuntu 22.04,在桌面启动全屏 Shell 模式的 Weston:
weston --backend=wayland-backend.so --shell=fullscreen-shell.so --width=320 --height=480
运行测试程序时要设置 WAYLAND_DISPLAY 环境变量:
WAYLAND_DISPLAY=wayland-1 ./build/egl_demo
作为简单的 Demo,我直接在程序主线程中进行 GL 渲染(清除背景):
static void render_init()
{
// Clear
glClearColor(.3f, 1.f, .3f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
eglSwapBuffers(egl_objects.display, egl_objects.surface);
}
int main()
{
...
render_init();
while (1)
{
wl_display_dispatch(wayland_objects.display);
// TODO: exit
}
return 0;
}
就这:
TODO: Wayland 通讯线程和 GL 渲染线程怎么组织最科学,这点还没搞清楚