Wayland架构

Wayland架构

了解 Wayland 架构以及它与 X 有何不同的一个好方法是跟踪从输入设备到它影响的更改出现在屏幕上的点的事件。

这就是我们现在使用 X 的地方:

Wayland架构_第1张图片

  • 内核从输入设备获取事件,并通过 evdev 输入驱动程序将其发送到 X。内核通过驱动设备并将不同的设备特定事件协议转换为 linux evdev 输入事件标准来完成所有繁重的工作。
  • X 服务器确定事件影响哪个窗口,并将其发送到为该窗口上的相关事件选择的客户端。X 服务器实际上并不知道如何正确执行此操作,因为屏幕上的窗口位置由合成器控制,并且可能以 X 服务器无法理解的多种方式进行转换(缩小、旋转、摆动、等等)。
  • 客户端查看事件并决定要做什么。通常,UI 必须响应事件而更改 - 可能是单击了复选框或指针进入了必须突出显示的按钮。因此,客户端将渲染请求发送回 X 服务器。
  • 当 X 服务器收到渲染请求时,它会将它发送给驱动程序,让它编程硬件来进行渲染。X 服务器还计算渲染的边界区域,并将其作为损坏事件发送到合成器。
  • 损坏事件告诉合成器窗口中的某些内容发生了变化,并且它必须重新合成该窗口可见的屏幕部分。合成器负责根据其场景图和 X 窗口的内容渲染整个屏幕内容。然而,它必须通过 X 服务器来呈现它。
  • X 服务器接收来自合成器的渲染请求,并将合成器后台缓冲区复制到前台缓冲区或执行翻页。在一般情况下,X 服务器必须执行此步骤,以便它可以考虑重叠窗口,这可能需要裁剪并确定它是否可以翻页。但是,对于始终全屏显示的合成器,这是另一个不必要的上下文切换。

如上所述,这种方法存在一些问题。X 服务器没有信息来决定哪个窗口应该接收事件,也不能将屏幕坐标转换为窗口本地坐标。即使 X 已将屏幕最终绘制的责任交给合成经理,但 X 仍控制前端缓冲区和模式设置。X 服务器过去处理的大部分复杂性现在都可以在内核或自包含库(KMS、evdev、mesa、fontconfig、freetype、cairo、Qt 等)中使用。总的来说,X 服务器现在只是一个中间人,它在应用程序和合成器之间引入了一个额外的步骤,在合成器和硬件之间引入了一个额外的步骤。

在wayland 中,合成器是显示服务器。我们将 KMS 和 evdev 的控制权交给合成器。wayland 协议让合成器直接将输入事件发送给客户端,让客户端直接将损坏事件发送给合成器:

Wayland架构_第2张图片

  • 内核获取一个事件并将其发送到合成器。这类似于 X 的情况,这很好,因为我们可以重用内核中的所有输入驱动程序。
  • 合成器查看其场景图以确定应接收事件的窗口。场景图形对应于屏幕上的内容,合成器了解它可能已应用于场景图形中的元素的转换。因此,合成器可以选择正确的窗口,并通过应用逆变换将屏幕坐标转换为窗口局部坐标。可应用于窗口的变换类型仅限于合成器可以执行的操作,只要它可以计算输入事件的逆变换即可。
    在 X 的情况下,当客户端收到事件时,它会更新 UI 作为响应。但在wayland 的情况下,渲染发生在客户端,客户端只是向合成器发送请求以指示更新的区域。
  • 合成器从其客户端收集损坏请求,然后重新合成屏幕。然后,合成器可以直接发出 ioctl 以使用 KMS 安排翻页。

Wayland渲染

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

这给应用程序留下了两种更新其窗口内容的方法:

  • 将新内容渲染到新缓冲区中,并告诉合成器使用它而不是旧缓冲区。应用程序可以在每次需要更新窗口内容时分配一个新缓冲区,或者它可以保留两个(或更多)缓冲区并在它们之间循环。缓冲区管理完全在应用程序控制之下。
  • 将新内容渲染到它之前告诉合成器使用的缓冲区中。虽然可以直接渲染到与合成器共享的缓冲区中,但这可能会与合成器竞争。可能发生的情况是,重新绘制窗口内容可能会被合成器重新绘制桌面而中断。如果应用程序在清除窗口之后但在渲染内容之前被中断,合成器将从空白缓冲区进行纹理化。结果是应用程序窗口将在空白窗口或半渲染内容之间闪烁。避免这种情况的传统方法是将新内容渲染到后台缓冲区中,然后从那里复制到合成器表面。后台缓冲区可以动态分配,大小刚好足以容纳新内容,或者应用程序可以保留一个缓冲区。同样,这在应用程序控制之下。

在任何一种情况下,应用程序都必须告诉合成器表面的哪个区域包含新内容。当应用程序直接渲染到共享缓冲区时,需要注意合成器有新的内容。但同样在交换缓冲区时,合成器不会假设任何更改,并且在重新绘制桌面之前需要来自应用程序的请求。即使应用程序将新缓冲区传递给合成器,也只有一小部分缓冲区可能不同,例如闪烁的光标或微调器。

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 中。

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

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

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

参考资料

https://wayland.freedesktop.org/architecture.html

你可能感兴趣的:(Unix,Like)