XWayland开发入门系列3:Wayland架构

系列索引地址:X11/Wayland开发入门系列教程索引

上一篇:XWayland开发入门系列2:库安装配置与介绍

本文译自https://wayland.freedesktop.org/architecture.html

翻译时间:2021.09.27

Wayland架构

理解Wayland架构以及它与X不同的好方法是跟踪一个事件从输入设备到它所影响的变化出现在屏幕上的程度。

下面是与X的架构:

xwayland-arch

1.内核从输入设备获取一个事件,并通过evdev输入驱动程序将其发送给X。内核通过驱动设备并将不同设备特定的事件协议转换为linuxevdev输入事件标准来完成这里所有的艰苦工作。

2.X服务器确定事件影响的是哪个窗口,并将其发送到该窗口上为相关事件选择的客户端。X服务器实际上并不知道如何正确做到这一点,因为屏幕上的窗口位置由合成器控制,并且可能以许多X服务器不理解的方式进行转换(缩小、旋转、摆动等)。

3.客户端会查看事件并决定要做什么。通常UI界面必须根据事件而更改—也许单击了一个复选框,或者指针输入了一个必须突出显示的按钮。因此,客户端向X服务器发送渲染请求。

4.当X服务器接收到渲染请求时,它将其发送给驱动程序,让它对硬件进行编程以进行渲染。X服务器还计算渲染的边界区域,并将其作为损坏事件发送到合成器。

5.损坏事件告诉合成字器窗口中发生了变化,它必须重新合成屏幕中可见该窗口的部分。合成器负责根据其场景图和X窗口的内容来渲染整个屏幕内容。然而,它必须通过X服务器来渲染这个过程。

6.X服务器接收来自合成器的渲染请求,并将合成器返回缓冲区复制到前缓冲区或执行页面翻转。在一般情况下,X服务器必须执行此步骤,以便它可以解释重叠的窗口,这可能需要剪切并确定它是否可以翻转页面。但是,对于一个总是全屏的合成器来说,这是另一个不必要的上下文切换。

如上所述,这种方法存在一些问题。X服务器没有决定哪个窗口应该接收事件的信息,也不能将屏幕坐标转换为窗口-本地坐标。尽管X已经将屏幕的最终绘制工作交给了合成管理器,但X仍然控制着前缓冲区和建模。X服务器用于处理的大部分复杂性现在都在内核或自包含的库(KMS、evdev、台面、字体配置、自由类型、cairo、Qt等)中可用。一般来说,X服务器现在只是一个中间人,它可以在应用程序和合成器之间引入额外的步骤,并在合成器和硬件之间引入额外的步骤。

在Wayland中,合成器显示服务器。我们将KMS和evdev的控制转移到合成器上。wayland协议允许合成器将输入事件直接发送给客户端,并允许客户端将损坏事件直接发送给合成器:

wayland-arch

1.内核得到一个事件并将其发送到合成器。这类似于X的情况,这非常好,因为我们可以重用内核中的所有输入驱动程序。

2.合成器通过其场景图来确定哪个窗口应该接收该事件。场景图对应于屏幕上的内容,合成者理解它可能应用于场景图中的元素的转换。因此,合成器可以通过应用逆转换,选择正确的窗口,并将屏幕坐标转换为窗口-局部坐标。可以应用于窗口的转换类型仅限于合成器可以做的事情,只要它可以计算输入事件的逆转换。

3.与X示例一样,当客户端收到事件时,它会响应地更新UI。但是在wayland情况下,渲染发生在客户端中,客户端只是向合成器发送一个请求,以指示已更新的区域。

4.合成器从其客户端收集损坏请求,然后重新合成屏幕。然后,合成器可以直接发布一个ioctl来用KMS安排一个页面翻转。

Wayland渲染

我在上面的概述中遗漏的一个细节是客户如何在wayland下实际渲染。通过从图片中删除X服务器,我们还删除了X客户机典型渲染的机制。但是在X下,我们已经在DRI2中使用了另一种机制:直接渲染。通过直接渲染,客户端和服务器共享一个视频内存缓冲区。客户端链接到一个呈现库,比如OpenGL,该库知道如何对硬件进行编程并直接呈现到缓冲区中。合成器反过来可以使用缓冲区,并在合成桌面时将其用作纹理。在初始设置之后,客户端只需要告诉合成器使用哪个缓冲区,以及何时在地向新内容呈现到其中。

这使得应用程序有两种方法来更新其窗口内容:

1.将新内容渲染到一个新的缓冲区中,并告诉合成器使用该内容而不是旧的缓冲区。应用程序可以在每次需要更新窗口内容时分配一个新的缓冲区,也可以保留两个(或多个)缓冲区并在它们之间循环。缓冲区管理完全处于应用程序的控制之下。

2.将新内容渲染到之前告诉合成器使用的缓冲区中。虽然只可以直接渲染到与合成器共享的缓冲区中,但这可能会与合成器竞争。可能发生的事情是,重新绘制窗口内容可能会被合成器重新绘制桌面而中断。如果应用程序在清除窗口之后但在呈现内容之前被中断,合成程序将从空白缓冲区进行纹理。其结果是,应用程序窗口将在空白窗口或半渲染的内容之间闪烁。避免这种情况的传统方法是将新内容渲染到一个反向缓冲区中,然后从那里复制到合成器表面中。反向缓冲区可以动态分配,足够大到容纳新内容,或者应用程序可以保留一个缓冲区。同样,这是在应用程序的控制之下进行的。

在任何一种情况下,应用程序都必须告诉合成器表面的哪个区域包含新内容。当应用程序直接呈现到共享缓冲区时,需要注意到有新的内容。但是,在交换缓冲区时,合成器也不假设有任何变化,需要来自应用程序的请求才能重新绘制桌面。即使应用程序将一个新的缓冲区传递给合成器,也只有一小部分缓冲区可能是不同的,比如闪烁的光标或旋转器。

Wayland使用硬件

通常,硬件启用包括模式设置/显示和EGL/GLES2。最重要的是,wayland需要一种方法来在进程之间有效地共享缓冲区。它有两方面,客户端和服务器端。

在客户端,我们已经定义了一个Wayland EGL平台。在EGL模型中,它包括本机类型(EGLNativeDisplayType、EGLNativeWindowType和EGLNativePixmapType)以及创建这些类型的方法。换句话说,它是将EGL堆栈及其缓冲区共享机制绑定到通用的Wayland API的粘合剂代码。EGL堆栈有望提供Wayland EGL平台的实现。完整的API在wayland-egl.h头文件中。mesa EGL堆栈中的开源实现在platform_wayland.c中。

在引擎盖(hood)下,EGL堆栈预计将定义一个特定于供应商的协议扩展,它允许客户端EGL堆栈与合成器通信缓冲区详细信息,以便共享缓冲区。wayland-egl.h API是抽象它,然后让客户端为Wayland表面创建一个egl表面并开始渲染。开源堆栈使用drm Wayland扩展,它允许客户端发现要使用的drm设备并进行身份验证,然后与合成器共享drm(GEM)缓冲区。

Wayland的服务器端是垂直的合成器和核心UX,通常集成任务切换器,应用程序启动器,锁屏幕在一个单片应用程序。服务器运行在模块处理API(内核模块处理、OpenWF显示或类似)上,如果可用,GLES2使用EGL/GLES2合成器和硬件覆盖混合组合最终的UI。启用模块化、EGL/GLES2和覆盖层应该是标准硬件支撑的一部分。启用Wayland的额外要求是EGL_WL_bind_wayland_display扩展,它允许合成器从通用的Wayland共享缓冲区创建EGLImage。它类似于EGL_KHR_image_pixmap扩展,从X像素图创建一个EGLImage。

扩展有一个设置步骤,您必须将EGL显示器绑定到Wayland显示器。然后,当合成器从客户端接收通用的Wayland缓冲区时(通常当客户端调用egl交换缓冲区时),它将能够将结构wl_buffer指针传递给eglCreateImageKHR作为egl客户端缓冲区参数,并以EGL_WAYLAND_BUFFER_WL作为目标。这将创建一个EGLImage,然后合成器可以将其用作纹理,或者传递给模态代码以用作覆盖平面。同样,这是由供应商特定的协议扩展实现的,它在服务器端将接收关于共享缓冲区的驱动程序特定细节,并在用户调用eglCreateImageKHR时将其转换为EGL映像。

下一篇:XWayland开发入门系列4:XServer