翻译于: https://wayland.freedesktop.org/architecture.html
Wayland Architecture
理解Wayland架构及其与X的不同之处的一种好方法是跟踪事件从"输入设备到屏幕上"出现的变化。
这就是我们现在使用的X的逻辑架构:
- 内核从输入设备获取事件,然后通过evdev输入驱动程序将其发送到X。内核通过驱动设备并将不同的设备事件转换为linux evdev输入标准事件来完成所有的艰难工作。
- X服务器确认事件影响哪个窗口,并将其发送到在该窗口上为该事件选择的客户端。X服务器实际上并不知道如何正确执行此操作,因为屏幕上的窗口位置是由合成器控制的,并且可能以X服务器无法理解的多种方式进行转换(缩小,旋转,摆动,等等)。
- 客户端查看事件并决定要做什么。UI通常必须响应事件而改变-也许单击了复选框或指针输入了必须突出显示的按钮。因此,客户端将渲染请求发送回X服务器。
- X服务器接收到渲染请求后,会将其发送给驱动程序,以使其对硬件进行编程以进行渲染。X服务器还计算渲染的边界区域,并将其作为damage事件发送到合成器。 //比weston麻烦的地方,绘画要通过server传给driver
- damage事件告诉合成器窗口中发生了某些更改,并且必须重新合成可见该窗口的屏幕部分。合成器负责根据其场景图和X窗口的内容渲染整个屏幕内容。但是,它必须通过X服务器来呈现它。
- X服务器从合成器接收渲染请求,然后将合成器后缓冲区复制到前缓冲区或进行页面翻转。在一般情况下,X服务器必须执行此步骤,以便它可以考虑重叠的窗口,这可能需要裁剪并确定是否可以翻页。但是,对于始终为全屏显示的合成器,这是另一个不必要的上下文切换。
如上所述,这种方法存在一些问题。X服务器没有信息来决定哪个窗口应该接收事件,它也不能将屏幕坐标转换为窗口局部坐标。尽管X已将屏幕的最终绘制工作移交给了合成管理器,但X仍控制着前缓冲区和模式设置。X服务器用来处理的大多数复杂性现在都可以在内核或自包含的库中找到(KMS,evdev,mesa,fontconfig,freetype,cairo,Qt等)。通常,X服务器现在只是一个中间人,它在应用程序和合成器之间引入了一个额外的步骤,在合成器和硬件之间引入了一个额外的步骤。
在Wayland中,合成器是显示服务器。我们将KMS和evdev的控制权转移给合成器。wayland协议允许合成器将输入事件直接发送到客户端,并让客户端将damage事件直接发送到合成器:
- 内核获取一个事件,并将其发送到合成器。这与X情况类似,这非常好,因为我们可以重用内核中的所有输入驱动程序。
- 合成器通过其场景图进行查看,以确定应该接收该事件的窗口。场景图与屏幕上的内容相对应,并且合成器了解它可能已应用于场景图中的元素的转换。因此,合成器可以选择右窗口,并通过应用逆变换将屏幕坐标转换为窗口局部坐标。可以应用于窗口的转换类型仅限于合成器可以执行的操作,只要它可以计算输入事件的逆转换即可。
- 与X情况一样,当客户端收到事件时,它会更新UI作为响应。但是在wayland中,渲染发生在客户端中,并且客户端只是向合成器发送请求以指示已更新的区域。
- 合成器从其客户端收集damage请求,然后重新合成屏幕。然后,合成器可以直接发出ioctl来调度带有KMS的翻页。
Wayland Rendering
在上面的概述中,我遗漏的细节之一是客户在Wayland下的实际渲染方式。通过从图片中删除X服务器,我们还删除了X客户端通常呈现的机制。但是,我们已经在X下的DRI2中使用了另一种机制:直接渲染。通过直接渲染,客户端和服务器共享内存缓冲区。客户端链接到诸如OpenGL之类的渲染库,该库知道如何对硬件进行编程并将其直接渲染到缓冲区中。当合成器合成桌面时,合成器又可以获取该缓冲区并将其用作纹理。初始设置后,客户端仅需要告诉合成器要使用哪个缓冲区以及何时何地向其提交了新内容。
这为应用程序留下了两种更新窗口内容的方法:
- 将新内容呈现到新缓冲区中,并告知合成器使用该内容代替旧缓冲区。应用程序可以在每次需要更新窗口内容时分配一个新的缓冲区,也可以保留两个(或多个)缓冲区并在它们之间循环。缓冲区管理完全在应用程序控制之下。
- 将新内容呈现到以前告诉合成器使用的缓冲区中。尽管可以直接渲染到与合成器共享的缓冲区中,但这可能会与合成器竞争。可能发生的情况是,合成器重新绘制桌面可能会中断重新绘制窗口内容。如果应用程序在清除窗口后,呈现内容之前被中断,则合成器将从空白缓冲区进行贴图。结果是应用程序窗口将在空白窗口或半渲染内容之间闪烁。避免这种情况的传统方法是将新内容呈现到后台缓冲区中,然后从那里复制到合成器表面中。后台缓冲区可以动态分配,大小足以容纳新内容,或者应用程序可以保留缓冲区。同样,这在应用程序控制之下。
无论哪种情况,应用程序都必须告诉合成器表面的哪个区域包含新内容。当应用程序直接呈现到共享缓冲区时,需要注意合成器存在新内容。而且在交换缓冲区时,合成器不会假设任何更改,并且需要应用程序发出请求才能重新绘制桌面。即使应用程序将新缓冲区传递给合成器,该缓冲区只有一小部分也可能会有所不同,例如闪烁的光标或微调框。
Hardware Enabling for 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的服务器端是合成器和垂直领域的核心用户体验,通常将任务切换器,应用程序启动器,锁屏集成在一个整体应用程序中。服务器在模式设置API(内核模式设置,OpenWF Display或类似功能)之上运行,并结合使用EGL / GLES2合成器和硬件覆盖(如果有)来组合最终的UI。启用模式设置,EGL / GLES2和叠加层应该成为标准硬件升级的一部分。Wayland启用的额外要求是EGL_WL_bind_wayland_display 扩展,该扩展使合成器可以从通用Wayland共享缓冲区中创建EGLImage。它类似于EGL_KHR_image_pixmap 扩展名,可以从X像素图创建EGLImage。
该扩展程序有一个设置步骤,在该步骤中,您必须将EGL显示器绑定到Wayland显示器。然后,当合成器从客户端接收通用Wayland缓冲区时(通常在客户端调用eglSwapBuffers时),它将能够将struct wl_buffer指针作为EGLClientBuffer参数传递给eglCreateImageKHR,并将EGL_WAYLAND_BUFFER_WL作为目标。这将创建一个EGLImage,合成器随后可以将其用作纹理,或传递给模式设置代码以用作覆盖平面。同样,这是由供应商特定的协议扩展实现的,该扩展在服务器端将接收有关共享缓冲区的驱动程序特定的详细信息,并在用户调用eglCreateImageKHR时将其转换为EGL映像。