Wayland Architecture Wayland架构

本文只是翻译,原文地址Chapter 3. Wayland Architecture

X vs. Wayland Architecture

理解Wayland架构及其与X的不同之处的一个好方法是跟踪一个事件从输入设备到它在屏幕上产生影响的点的过程。

这是我们现在在X中的情况:

  1. 内核从输入设备获取事件,并通过evdev输入驱动程序将其发送给X。内核在这里完成了所有艰苦的工作,包括驱动设备以及将不同的设备特定事件协议转换为Linux evdev输入事件标准。
  2. X服务器确定哪个窗口受到事件的影响,并将其发送给在该窗口上选择了该事件的客户端 。但实际上,X服务器并不知道如何正确执行此操作,因为窗口在屏幕上的位置由合成器控制,并且可能会以X服务器不理解的方式(如缩小、旋转、晃动等)进行各种变换。
  3. 客户端查看事件并决定如何处理。 通常,UI需要以某种方式响应事件------比如一个复选框被点击,或者指针进入了一个需要被高亮显示的按钮。因此,客户端向X服务器发送渲染请求
  4. 当X服务器接收到渲染请求时,它将其发送给驱动程序,以便让驱动程序编程硬件进行渲染。X服务器还计算渲染的边界区域,并将其作为损坏事件发送给合成器
  5. 损坏事件告诉合成器窗口中的某些内容已更改,并且它必须重新合成屏幕上该窗口可见的部分。合成器负责根据其场景图和X窗口的内容渲染整个屏幕内容 。然而,它仍然需要通过X服务器来进行此渲染
  6. X服务器从合成器接收渲染请求,要么将合成器的后缓冲区复制到前缓冲区,要么执行页面翻转。在一般情况下,X服务器必须执行此步骤,以便它可以处理重叠窗口,这可能需要裁剪并确定是否可以执行页面翻转。然而,对于始终是全屏的合成器来说,这是另一个不必要的上下文切换。

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

在Wayland中,合成器充当显示服务器的角色。我们将KMS(Kernel Mode Setting,内核模式设置)和evdev(Event Device,事件设备)的控制权转移给了合成器。Wayland协议允许合成器直接将输入事件发送给客户端,并允许客户端直接将损坏事件发送给合成器:

复制代码
内核获取事件并将其发送给合成器。这与X的情况类似,这很好,因为我们能够重用内核中的所有输入驱动程序。
  1. 合成器通过其场景图来确定哪个窗口应该接收事件。场景图对应于屏幕上的内容,并且合成器理解它可能对场景图中的元素应用的变换。因此,合成器可以通过应用逆变换来选择正确的窗口,并将屏幕坐标转换为窗口本地坐标。只要合成器能够为输入事件计算逆变换,就可以对窗口应用各种类型的变换。
  2. 与X的情况一样,当客户端接收到事件时,它会更新UI以作出响应。但在Wayland的情况下,渲染在客户端进行,客户端只需向合成器发送一个请求,指示已更新的区域。
  3. 合成器从客户端收集损坏请求,然后重新合成屏幕。之后,合成器可以直接发出ioctl(输入/输出控制)命令,使用KMS安排页面翻转。

Wayland Rendering

在之前概述中遗漏的一个细节是,在Wayland下客户端实际上是如何进行渲染的。通过从图中移除X服务器,我们也移除了X客户端通常用来渲染的机制。但是,在X下使用DRI2(Direct Rendering Infrastructure 2,直接渲染基础架构2)时,我们已经在使用另一种机制:直接渲染。在直接渲染中,客户端和服务器共享一个视频内存缓冲区。客户端链接到一个渲染库(如OpenGL),该库知道如何对硬件进行编程,并直接将内容渲染到缓冲区中。合成器则可以获取该缓冲区,并在合成桌面时将其作为纹理使用。在初始设置之后,客户端只需告诉合成器要使用哪个缓冲区,以及何时和在哪里向其中渲染了新内容。

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

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

  2. 将新内容渲染到之前告诉合成器要使用的缓冲区中。虽然可以直接渲染到与合成器共享的缓冲区中,但这可能会与合成器产生竞争。可能会发生的情况是,窗口内容的重绘被合成器重绘桌面的操作打断。如果应用程序在清除窗口后立即被中断,但在渲染内容之前,合成器将从一个空白缓冲区中获取纹理。结果是,应用程序窗口将在空白窗口或部分渲染的内容之间闪烁。避免这种情况的传统方法是将新内容渲染到一个后缓冲区中,然后从那里复制到合成器表面。后缓冲区可以动态分配,并且仅足够大以容纳新内容,或者应用程序可以保留一个缓冲区。同样,这也由应用程序控制。

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

Hardware Enabling for Wayland

通常,硬件启用包括模式设置/显示和EGL/GLES2(嵌入式图形库/OpenGL ES 2.0)。在此基础上,Wayland还需要一种在进程之间高效共享缓冲区的方法。这包括客户端和服务器端两个方面。

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

在底层,EGL堆栈应定义一个供应商特定的协议扩展,允许客户端EGL堆栈与合成器通信缓冲区详细信息,以便共享缓冲区。wayland-egl.h API的目的是抽象出这些细节,并仅允许客户端为Wayland表面创建一个EGLSurface并开始渲染。开源堆栈使用drm Wayland扩展,该扩展允许客户端发现要使用的drm设备并进行身份验证,然后与合成器共享drm(GEM)缓冲区。

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

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

相关推荐
二进制人工智能1 小时前
【QT5 网络编程示例】TCP 通信
网络·c++·qt·tcp/ip
莫有杯子的龙潭峡谷3 小时前
3.31 代码随想录第三十一天打卡
c++·算法
AaronZZH4 小时前
【进阶】vscode 中使用 cmake 编译调试 C++ 工程
c++·ide·vscode
杨筱毅5 小时前
【性能优化点滴】odygrd/quill 中将 MacroMetadata 变量声明为 constexpr
c++·性能优化
NaZiMeKiY5 小时前
C++ 结构体与函数
开发语言·c++
涛ing5 小时前
【Git “fetch“ 命令详解】
linux·c语言·c++·人工智能·git·vscode·svn
学习是种信仰啊5 小时前
QT图片轮播器实现方法二(QT实操2)
开发语言·c++·qt
nqqcat~7 小时前
STL常用算法
开发语言·c++·算法
_GR7 小时前
2022年蓝桥杯第十三届C&C++大学B组真题及代码
c语言·数据结构·c++·算法·蓝桥杯·动态规划
虾球xz7 小时前
游戏引擎学习第195天
c++·学习·游戏引擎