WayLand的架构和协议

WayLand的架构和协议

1. Wayland简介

1.1 Wayland是啥?为啥它这么重要?

嘿,你知道吗?有时候咱们用电脑的时候,是不是觉得图形界面有点慢、有点卡?那是因为我们还在用一个叫X Window System (X11)的老伙计。这个老伙计虽然功不可没,但毕竟年纪大了,有些力不从心啦。这时候就轮到我们的新朋友——Wayland登场了!

1.2 Wayland背后的故事:它是怎么来的?

话说2008年的时候,有个叫Kristian Høgsberg的人,他想:“为什么不能有一个更好的方式来处理图形呢?”于是他就开始了Wayland项目。经过多年的努力,Wayland逐渐成长起来,现在已经被很多主流桌面环境如GNOMEKDE Plasma所采用。可以说,Wayland已经成为了Linux社区的新宠儿。

1.3 Wayland的梦想:它想带给我们什么?

简单来说,Wayland想让你的电脑图形体验变得更棒!它通过简化图形渲染流程,直接与硬件对话,减少不必要的通信层,从而提高了性能和安全性。对于开发者而言,这意味着更少的代码维护工作;对于用户来说,则意味着更流畅的操作体验。


2. Wayland架构

2.1 X和Wayland:两者架构有何不同?

来聊聊X是怎么处理输入到显示的

1

想象一下,当你在使用基于X的应用时,每次你点击鼠标或者敲击键盘,都会触发一系列复杂的步骤,直到最终的变化出现在屏幕上。这个过程有点像一个接力赛,每个环节都至关重要。

首先,内核会通过evdev输入驱动捕捉来自设备(如鼠标或键盘)的事件,并将这些事件发送给X Server。这里,内核做了很多重活,它负责管理硬件并将各种特定于设备的事件协议转换成统一的Linux evdev标准格式。

接下来,X Server要决定哪个窗口应该接收这个事件,并将其转发给那些已经注册了该类型事件监听的客户端。但是,这里有个小问题——X Server并不完全清楚窗口的实际位置和状态,因为这些是由合成器控制的,而合成器可能会对窗口进行各种变换(缩放、旋转、特效等),这些变化是X Server所不了解的。

然后,接收到事件的客户端根据需要更新用户界面。比如,你可能点击了一个复选框,或者鼠标指针进入了某个按钮区域,这时就需要高亮显示。因此,客户端会向X Server发送渲染请求。

X Server收到渲染请求后,它会把任务交给显卡驱动,让其直接编程硬件完成渲染工作。同时,X Server还会计算出渲染影响的屏幕区域,并向合成器发送一个损坏事件(damage event),告知合成器需要重新组合那一部分屏幕内容。

最后,合成器会通知X Server,由它来决定是直接复制合成器的后台缓冲区到前台缓冲区,还是执行一次页面翻转(pageflip)。这一步骤对于处理窗口重叠等情况非常重要,但对于总是全屏显示的合成器来说,就显得多余了,因为它引入了不必要的上下文切换。

现在轮到Wayland登场啦!

Wayland的世界里,整个流程变得更加简洁高效。这里的关键点在于,合成器就是显示服务器本身,这意味着我们可以直接从内核获取事件并立即传递给合成器,而不需要经过额外的中间层。我们还把KMS(模式设置)和evdev的控制权交给了合成器,进一步简化了架构。

这个过程大致如下:

2

  • 内核依旧负责捕捉输入事件并通过evdev接口发送给合成器。这部分与X的情况相似,所以我们可以继续利用内核中已有的输入驱动。

  • 合成器则会根据它的场景图(scenegraph)来确定哪个窗口应该接收事件。由于合成器掌控着所有窗口的状态及其可能应用的各种变换,它可以准确地选择正确的窗口,并将屏幕坐标转换为窗口本地坐标。只要合成器能够计算出针对输入事件的逆变换,那么理论上可以对窗口施加任何类型的变换。

  • 客户端接收到事件后,就像之前一样更新用户界面。不过,在Wayland下,渲染是在客户端这边完成的,之后只需告诉合成器哪些区域被更新了即可。

  • 合成器收集来自各个客户端的损坏请求,然后重新组合屏幕内容。这个时候,合成器可以直接调用ioctl命令通过KMS安排页面翻转,无需再经过X Server这一环。

这样做的好处是减少了不必要的通信开销,提高了系统的响应速度和效率。Wayland的设计使得每个组件都能专注于自己最擅长的事情,从而构建出了一个更加流畅且安全的图形环境。

2.2 Wayland的图像渲染

Wayland的世界里,所有的视觉内容都是通过缓冲区来管理的。应用程序想要显示任何东西时,它会在自己的内存空间中创建一个或多个图像缓冲区,并将这些缓冲区提交给合成器(compositor)合成器扮演着艺术家的角色,负责将这些图像组合成最终的画面,展示给用户。

Wayland利用现代GPU的强大功能,确保无论是播放视频还是运行3D游戏,都能提供即时响应的速度。所有绘图命令都通过DMA-BUF接口发送给GPU,这保证了即使在多任务环境中也能保持高效运作。

客户端渲染机制

X Server被移除后,传统的X客户端渲染机制也随之消失。但Wayland引入了直接渲染(direct rendering)作为替代方案,这一机制已经在XDRI2中有所体现。在直接渲染模式下,客户端合成器共享一块视频内存缓冲区。客户端链接到如OpenGL这样的渲染库,该库知道如何编程硬件,并能够直接将内容渲染到共享缓冲区中。合成器则可以将这块缓冲区用作texture,当它合成桌面时就能显示出更新的内容。

硬件支持的重要性

为了使Wayland能有效工作,良好的硬件支持至关重要。这包括但不限于模式设置/显示管理和EGL/GLES2等功能。此外,Wayland还需要一种机制来高效地在进程间共享缓冲区,这部分涉及到客户端和服务器端两个方面的工作。

  • 客户端实现:定义了一个Wayland EGL平台,它包含了一套原生类型(如EGLNativeDisplayTypeEGLNativeWindowTypeEGLNativePixmapType),以及创建这些类型的接口。这是将EGL栈及其缓冲区共享机制绑定到通用Wayland API的胶水代码。开源实现中,mesa EGL栈中的wayland-egl.cplatform_wayland.c文件实现了这一功能。

  • 服务器端实现Wayland的服务器端即为合成器,它通常集成了任务切换器、应用启动器、锁屏界面等核心用户体验组件。服务器运行在一个模式设置API之上(如内核模式设置、OpenWF Display或其他类似技术),并通过EGL/GLES2合成器和硬件叠加层(如果有的话)来组合最终用户界面。为了让合成器能够处理来自客户端的Wayland共享缓冲区,必须启用EGL_WL_bind_wayland_display扩展,这样合成器就可以从任意Wayland共享缓冲区创建一个EGLImage对象。这个过程首先需要绑定EGL显示到Wayland显示,之后每当合成器接收到客户端发来的缓冲区(通常是通过调用eglSwapBuffers时),它可以将wl_buffer指针传递给eglCreateImageKHR函数,以EGLClientBuffer参数的形式创建一个EGL图像,用于后续作为纹理或通过模式设置代码作为叠加平面使用。

3. Wayland协议

WayLand协议, 是WayLand客户端WayLand合成器之间的通讯协议

官方提供的WayLand协议的参考实现
https://gitlab.freedesktop.org/wayland/wayland

官方提供的WayLand合成器的参考实现
https://gitlab.freedesktop.org/wayland/weston

3.1 协议传输与消息格式

Wayland 协议通过UNIX域流套接字进行传输,通常情况下,该套接字的端点名为wayland-0(尽管可以通过环境变量WAYLAND_DISPLAY来更改)。从Wayland 1.15版本开始,实现可以选配支持位于文件系统任意位置的服务器套接字端点,只需将WAYLAND_DISPLAY设置为服务器端点监听的绝对路径即可。

每条消息被构造成由多个32位字组成的序列;值以主机的字节序表示。消息头部包含两个32位字:

  • 第一个字是发送者的对象ID(32位)。
  • 第二个字分为两部分:高16位是消息大小(以字节为单位),从头部开始计算(即最小值为8字节);低16位是请求或事件的操作码。

有效载荷描述了请求或事件的参数。每个参数总是对齐到32位边界;如果需要填充,填充字节的值未定义。没有前缀描述类型,而是隐式地从XML规范推断出来。

以下是参数类型的表示方式:

  • int, uint

    • 表示32位有符号或无符号整数值。
  • fixed

    • 有符号的24.8定点数。它是一种提供符号位、23位整数精度和8位小数精度的有符号十进制类型。在C API中,它作为一个不透明的结构体,并提供了转换为双精度浮点数和整数的帮助函数。
  • string

    • 以一个无符号的32位长度(包括空终止符)开头,接着是字符串内容,包含终止的空字节,然后是对齐到32位边界的填充。空值用长度为0表示。
  • object

    • 32位对象ID。空值用ID为0表示。
  • new_id

    • 32位对象ID。一般情况下,新对象使用的接口可以从XML推断出来,但在接口未指定的情况下,new_id之前会有一个指定接口名称的字符串,以及一个指定版本的无符号整数。
  • array

    • 以32位数组大小(以字节为单位)开头,接着是数组内容的直接拷贝,最后是对齐到32位边界的填充。
  • fd

    • 文件描述符并不存储在消息缓冲区中,而是在UNIX域套接字消息的辅助数据(msg_control)中。

Wayland协议并未明确规定辅助数据在流中的确切位置,只规定文件描述符的顺序与消息及其内部的fd参数在网络上的顺序相同。

这意味着流中的任何字节,甚至是消息头部,都可能携带带有文件描述符的辅助数据。

客户端和合成器(compositor)应当排队等待接收的数据,直到他们有完整的消息可供处理,因为文件描述符可能会早于或晚于对应的数据字节到达。

3.2 核心接口概述

Wayland协议设计了一套核心接口,用于客户端与服务器之间的交互。这些接口提供了请求、事件和错误(实际上也是特殊类型的事件)的功能,如前文所述。虽然具体的合成器(compositor)实现可能会提供作为扩展的自有接口,但有一些接口是预期一定会存在的。

以下是Wayland的核心接口:

  1. wl_display

    • 作为核心全局对象,它充当了客户端与Wayland服务器之间通信的起点。通过这个接口,客户端可以获取其他全局对象,并发送或接收消息。
  2. wl_registry

    • 全局注册表对象,用来枚举当前可用的全局对象。客户端使用此接口来发现并绑定到它们需要的服务。
  3. wl_callback

    • 回调对象通常用于异步操作的完成通知,比如帧同步。
  4. wl_compositor

    • 合成器(compositor)单例,提供创建surface和其他图形资源的方法。
  5. wl_shm_poolwl_shm

    • 这两个接口共同支持共享内存池的创建和管理,使得图像数据可以直接在客户端和合成器(compositor)之间交换。
  6. wl_buffer

    • 表示一个surface的内容,可以由多种不同方式创建,包括但不限于共享内存。
  7. wl_data_offer, wl_data_source, wl_data_devicewl_data_device_manager

    • 这组接口支持数据传输功能,例如剪贴板和拖放操作。
  8. wl_shellwl_shell_surface

    • 提供了创建桌面风格surface的方法,并为这些surface提供了额外的元数据接口。
  9. wl_surface

    • 屏幕上的surface,是所有可视内容的基础元素。
  10. wl_seat

    • 输入设备的集合,每个seat代表一组输入设备,比如键盘、鼠标和触控屏。
  11. wl_pointer, wl_keyboard, wl_touch

    • 分别对应指针、键盘和触摸屏等输入设备的具体接口。
  12. wl_output

    • 描述合成器(compositor)输出区域的信息,比如显示器的几何属性和模式。
  13. wl_region

    • 定义了一个不规则形状的区域,可以应用于surface以控制其可见性或其他特性。
  14. wl_subcompositorwl_subsurface

    • 支持子surface组合,允许将一个surface嵌入到另一个surface中,形成复杂的用户界面布局。

上述接口构成了Wayland协议的基本构建块,确保了客户端应用程序能够与合成器(compositor)进行高效且安全的通信。


4. Wayland对X11应用的支持

3

为了让那些还没迁移到Wayland上的老应用继续工作,Wayland引入了一个叫做XWayland的小帮手。它实际上就是一个小型的X Server,可以在Wayland环境中运行,接受来自传统X11客户端的连接请求,并将它们适配到新的显示协议之上。这样一来,用户就可以在同一桌面上同时运行两种类型的应用程序,无缝切换毫无压力。

尽管Wayland本身并不需要传统的X窗口管理器,但在某些情况下(例如通过XWayland运行X11应用时),它们仍然扮演着重要角色。此时,Wayland合成器会充当“超级管理员”,负责协调不同类型的窗口行为,确保整个系统稳定运行。

4.1 X11 应用程序的连接方式

X11应用程序连接到Xwayland的方式就如同它连接到任何其他X服务器一样。Xwayland负责处理所有的X11请求,并且在另一端,它作为一个Wayland客户端连接到了Wayland合成器(compositor)。

4.2 X Window Manager (XWM) 和 Wayland Window Manager (WWM)

XWMWayland合成器(compositor)不可或缺的一部分。它使用标准的X11窗口管理协议来管理所有通过Xwayland运行的X11窗口。重要的是,XWM充当了Xwayland窗口状态和Wayland合成器(compositor)的WWM之间的桥梁。这样,WWM就可以统一管理所有类型的窗口,无论是原生的Wayland窗口还是X11(即Xwayland)窗口。这对于提供一致的用户体验至关重要。

4.3 Xwayland的工作原理

由于Xwayland依赖Wayland进行输入和输出操作,所以它不需要像Xorg那样使用设备驱动程序。这意味着不会使用任何xf86-video-*xf86-input-*模块。此外,Xwayland服务器没有配置文件。对于可选的硬件加速渲染,Xwayland采用了GLAMOR库。

4.4 单一实例的Xwayland

通常,一个Wayland合成器(compositor)只会产生一个Xwayland实例。这是因为许多X11应用程序假设它们可以通过X服务器与其他X11应用程序通信,而这需要共享同一个X服务器实例。这也意味着,除非Wayland合成器(compositor)特别选择通过为特定应用程序生成独立的Xwayland实例来打破这种通信,否则Xwayland不会保护或隔离各个X11客户端。值得注意的是,X11客户端与Wayland客户端之间是天然隔离的。

4.5 Xwayland的兼容性挑战

尽管Xwayland尽可能地兼容传统的X服务器,但要达到100%的兼容几乎是不可能的。特别是桌面环境组件中的X11窗口管理器基本上不受支持。一个X11窗口管理器无法识别原生的Wayland窗口,因此它只能管理X11窗口。然而,必须有一个XWM来保留独占的窗口管理角色,以便Wayland合成器(compositor)可以适当地显示X11窗口。对于其他的桌面环境组件,如分页器和面板,为了在WWM中通过XWM支持它们而添加必要的接口往往被认为是不值得的。

4.6 窗口标识与同步通信

Xwayland中,一个X11窗口可能会对应于Wayland中的一个wl_surface对象。这个wl_surface对象用于输入和输出:它被输入事件引用,并用于向Wayland合成器(compositor)提供X11窗口的内容。X11窗口和wl_surface存在于不同的协议流中,因此需要将它们匹配起来以使XWM能够正常工作。

XwaylandWayland上创建一个wl_surface时,它也会发送一个类型为原子"WL_SURFACE_ID"的X11 ClientMessage给对应的X11窗口,该消息的第一个32位数据元素携带的是wl_surfaceWayland对象ID。这是XWM关联wl_surfaceX11窗口的方法。需要注意的是,创建wl_surface的请求和ID消息可能以任意顺序到达Wayland合成器(compositor)。因此,在实现XWM时,需要格外小心以避免(随机)死锁。强烈建议所有来自XWMX11通信都应该是异步的,因为证明同步或阻塞的X11调用不会导致死锁通常是极其困难的。所有Wayland通信已经天生就是异步设计的。

5. 总结

本文介绍了Wayland作为新一代显示服务器协议,旨在替代传统的X Window System (X11),为Linux及其他类Unix系统提供更高效、安全的图形界面体验。

Wayland通过简化图形渲染流程,直接与硬件对话,减少了不必要的通信层,提高了性能。其架构中合成器即为显示服务器,可直接从内核获取事件并传递给合成器,避免了额外中间层,从而减少通信开销。Wayland利用现代GPU功能确保图像内容即时响应,通过DMA-BUF接口发送绘图命令保持高效运作。

在Wayland协议方面,它定义了一套核心接口,用于客户端与服务器之间的交互,包括wl_display、wl_registry等,确保应用程序能与合成器进行高效安全通信。

此外,为了兼容传统X11应用,引入了XWayland作为小型X Server,在Wayland环境中运行,使新旧应用无缝共存。然而,尽管XWayland尽力兼容,仍存在一定的兼容性挑战,特别是对于X11窗口管理器的支持有限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值