这个是Wayland官网文章的翻译。原文链接:https://wayland.freedesktop.org/architecture.html
主页(已翻译):https://bbs.deepin.org/post/256834
我们可以跟随从一个输入设备发送的事件(event)到他让屏幕上的内容发生改变的整个过程,来弄明白Wayland架构和与X的区别。
使用X架构时是这样的:
1.内核从一个输入设备获取事件,然后通过evdev输入设备驱动把他发送到X。这个过程是内核完成了主要工作,包括运行设备和把各种设备规定的事件协议翻译成标准的linux evdev输入事件。
2.X服务器来检查哪个窗口会被事件影响,然后把事件发送到这个窗口关联的X客户端。X服务器不会保证这个过程没有问题,因为在屏幕上的窗口位置被合成器控制,而且可以制造很多种X服务器不理解的变形(缩小、旋转、摇晃等)。(译注:过去的Linux玩家很喜欢在桌面上使用各种有趣的窗口特效,比如说compiz合成器的窗口「果冻」效果。在使用这些窗口特效时只会在外观上变形,是「障眼法」,而窗口的真实位置并没有发生变化。这是因为X的窗口管理器和合成管理器是两个不同的组件,X架构能提供给窗口管理器的窗口动作并不多。因此通常只能用来制作一些连贯动画,做不到让窗口在可操作的情况下变形。在作者的这个案例中,一个进程同时作为窗口管理器和合成管理器,这是比较常见的情况,但是这也做不到把两个功能完全整合起来。)
3.客户端获得事件然后决定他要做什么。通常为了回应这个事件,用户界面会发生变化,可能是一个选框被点选,可能是指针悬停到了一个按钮上,需要把这个按钮变亮提示用户。由此客户端回复X服务器一个渲染请求。
4.当X服务器接收到渲染请求的时候,他再将其发送到驱动程序,让他操作硬件渲染内容。X服务器也会计算渲染的区域边界位置,然后用待修事件(damage event)(译注:为了提高渲染效率,屏幕上的任何内容更新都只是重新渲染那一个区域,而不是重新渲染整个屏幕。damage event用来传递需要更新的区域信息。)的形式发送给合成器。
5.待修事件会告知合成器窗口中的一些内容发生了改变,当窗口上的这个部分在屏幕上有显示时,他就重新合成这个位置的图像。合成器需要从他的窗口层叠关系(scenegraph)和X中各窗口的内容渲染出整个屏幕的内容。但是这个过程中,他必须通过X服务器才能完成这个渲染过程。
6.X服务器接收到合成器发来的渲染请求,要么从合成器的后置缓冲区复制到前置缓冲区,要么做一个翻页动作(pageflip)(译注:先在缓冲区渲染好内容,然后等待垂直同步的信号后切换要显示的缓冲区,避免画面发生撕裂)。普遍情况是X服务器有必要记录窗口的重叠,因为可能需要做图像的剪裁(clipping),影响到是否能做翻页动作。然而对通常是全屏运行的合成器来说,其实这是又一个没有必要的内容变换。(译注:这部分我也不太理解。可能是说本来合成器就有窗口重叠的计算了,而X又重复做了一次,为了剪裁图像。)
我们可以发现上面的这个过程中有一些弊端。X服务器不了解是哪个窗口要接收到事件,他也不知道怎么变换屏幕坐标和各窗口的单独(local)坐标。更甚的是虽然X把整个屏幕最后绘图的任务交给了合成管理器,X仍然掌控着前置缓冲区和模式设置(modesetting)(译注:比如说是屏幕分辨率等)。X服务器曾经做的大量复杂工作现在已经被内核中或独立的库(KMS、evdev、mesa、fontconfig、freetype、cairo、Qt等)代替。实际上X服务器现在只是一个传声筒,在应用程序和合成器之间、合成器和硬件之间徒增一步。
在Wayland中,合成器就是显示服务器。我们把KMS和evdev的控制权交给了合成器。Wayland协议让合成器能直接发送输入事件到各个客户端,而客户端把待修事件直接发送给合成器:
1.内核获取事件然后把他发送给合成器。好在Wayland和X的做法类似,这样我们能重复利用所有内核的输入驱动。
2.合成器在窗口层叠关系(scenegraph)中找到应该接收事件的窗口。窗口层叠关系相当于屏幕上的内容,合成器能知道窗口层叠关系中每个元素的形变情况(transformation)。因此合成器能找到正确的窗口,可以把屏幕坐标变换成窗口的单独(local)坐标,只需要反向使用形变情况即可(译注:这是数学!不过开发过游戏的会清楚这是怎么做到的)。各种形变方法都可以用到窗口上,只需要合成器能够对输入事件计算反向形变即可。
3.和X的做法一样,当客户端接收到事件时,他会相应地更新用户界面。但是在Wayland中,渲染是在客户端内部进行的。客户端只需要发送请求给合成器,表明需要更新的位置。
4.合成器从各个客户端收集待修请求然后重新合成屏幕图像。合成器能直接发出一个ioctl来用KMS计划执行一次翻页动作(pageflip)。
我在上文中没有提到的细节就是客户端到底是怎么在Wayland中渲染的。X服务器不仅从上面的结构图中消失,而且我们也移除了常规的X客户端渲染的机制。但是其实还有另一个机制,我们曾在X中的DRI2使用到:「直接渲染」。在直接渲染时,客户端和服务器共享一个显存缓冲区。客户端链接到一个能操作硬件的渲染库,比如OpenGL,然后直接渲染到这个缓冲区中。接下来合成器可以取得这个缓冲区,然后把他作为一个纹理(texture)用在合成桌面(译注:这个是计算机图形学中的相关内容。「纹理」相当于一个图像数据)。在初始设置结束后,客户端只需要告诉合成器他用了哪个缓冲区,以及他渲染新内容时的时机和位置。
这样应用程序有两个更新窗口内容的方法:
1.把新内容渲染到一个新的缓冲区内,然后告知合成器用新的缓冲区代替旧的。这样应用程序可以每次更新窗口内容都重新划分一块缓冲区,也可以保留两块或者更多的缓冲区,然后在这些缓冲区之间循环操作。所有缓冲区的管理都由应用程序所掌控。
2.把新内容渲染到他之前让合成器使用的缓冲器。虽然可以直接渲染到与合成器共享的缓冲区,但是可能发生应用程序和合成器比拼速度的情况。重新绘制窗口内容可能会被合成器重新绘制桌面所打断。如果应用程序在清理窗口之后而绘图之前被打断,合成器就相当于从一个空的缓冲区里取出材质。结果就是应用窗口会从一个空窗口和一个渲染了一半的窗口之间来回闪烁。传统解决方法是先绘制新内容到另外的缓冲区内(译注:称为「后置缓冲区」),之后再复制到合成器的表面(surface)上(译注:这也是个图形学的术语,代表可以绘制图像的地方。其实就是上面说的共享缓冲区)。后置缓冲区可以在使用时随时划分,只要够大能容下新绘制的内容;也可以永远保持一个缓冲区随时使用。还是那句话,一切都由应用程序所掌控。
无论选择两个方案中的哪个,应用程序必须告知什么表面容纳的是新绘制好的内容。当应用程序在共享缓冲区中直接渲染时,要提醒合成器哪里是新内容。当交换缓冲区的时候,如果应用程序不发送一个请求,合成器在重绘桌面之前就不会认定有内容发生变化。这个设计是因为有些应用程序在传递新缓冲区给合成器的时候,可能只有一个小部分发生变化,比如一个输入文字时光标的闪烁或者程序繁忙时的旋转盘标志。(译注:即用于节约系统的资源消耗。)
通常来说硬件支持包括模式设置/显示和EGL/GLES2。在此之外Wayland还需要一个共享缓冲区的高效方法。这个功能的实现分为客户端方面和服务器方面。
在客户端方面,我们设计了个Wayland EGL平台。他在EGL模型中是由几个原生类型(EGLNativeDisplayType,EGLNativeWindowType和EGLNativePixmapType)和创建这些类型的途径所组成。换句话说,这个就想当于「胶水」,来让EGL技术栈和缓冲区共享机制接合到通用的Wayland API。EGL技术栈用来帮助实现一个Wayland EGL平台。完整API见 wayland-egl.h(原文)头文件。mesa的EGL技术栈实现的开源Wayland EGL平台见platform_wayland.c(原文)。
深层次的是,为了实现共享缓冲区,EGL技术栈需要定义一个各厂商(vendor)特定的协议扩展,来让客户端的EGL技术栈与合成器交流缓冲区的详情。wayland-egl.h的API目标是把这些细节抽离开,让客户端只需要创建一个为Wayland表面使用的EGLSurface就能开始渲染。开源技术栈使用drm(原文) Wayland扩展,这能让客户端发现drm来使用和注册,之后与将drm(GEM)缓冲区与合成器共享。
Wayland的服务器方面是合成器和核心用户体验,比如说传统的任务切换器、应用启动器、锁屏画面都在同一个单独程序中。服务器在一个模式设定(modesetting)的API上运行(KMS、OpenWF Display或者类似的),然后使用混合的EGL/GLES2合成器以及可能使用的硬件叠加(hardware overlay)(译注:指直接在显存中连续播放视频等内容。)合成最终UI。模式设定、EGL/GLES2和叠加的功能都应该是标准硬件附属物的一部分。启用Wayland的另外需求是EGL_WL_bind_wayland_display(原文)扩展,能让合成器从通常的Wayland共享缓冲区创建一个EGLImage。他有点像EGL_KHR_image_pixmap(原文),用于从X pixmap创建EGLImage。
这个扩展有个设定阶段,需要把EGL显示接合到Wayland显示上。然后当合成器从客户端接收到通用Wayland缓冲器时(通常是客户端调用eglSwapBuffers),他能把结构体wl_buffer的指针作为参数EGLClientBuffer传递给eglCreateImageKHR,同时EGL_WAYLAND_BUFFER_WL为目标。这会创建一个EGLImage,可以用作合成器的纹理或者用一个叠加平面传递到模式设定代码上。还是那句话,这是被各厂商特定的协议扩展实现,在服务器方面会接收到共享缓冲区基于特定驱动的详细信息,在用户调用eglCreateImageKHR会把缓冲区转换成EGL图像。(译注:此处比较混乱,不保证能翻译得很准确,请读原文。)
在20。9这个版本使用浏览器进行上下滚动的时候,会出现明显的波浪条,不知道是不是x的原因?
可能是垂直同步有问题。
建议你单独开帖讨论。
Popular Ranking
Popular Events
这个是Wayland官网文章的翻译。原文链接:https://wayland.freedesktop.org/architecture.html
主页(已翻译):https://bbs.deepin.org/post/256834
Wayland架构
我们可以跟随从一个输入设备发送的事件(event)到他让屏幕上的内容发生改变的整个过程,来弄明白Wayland架构和与X的区别。
使用X架构时是这样的:
1.内核从一个输入设备获取事件,然后通过evdev输入设备驱动把他发送到X。这个过程是内核完成了主要工作,包括运行设备和把各种设备规定的事件协议翻译成标准的linux evdev输入事件。
2.X服务器来检查哪个窗口会被事件影响,然后把事件发送到这个窗口关联的X客户端。X服务器不会保证这个过程没有问题,因为在屏幕上的窗口位置被合成器控制,而且可以制造很多种X服务器不理解的变形(缩小、旋转、摇晃等)。(译注:过去的Linux玩家很喜欢在桌面上使用各种有趣的窗口特效,比如说compiz合成器的窗口「果冻」效果。在使用这些窗口特效时只会在外观上变形,是「障眼法」,而窗口的真实位置并没有发生变化。这是因为X的窗口管理器和合成管理器是两个不同的组件,X架构能提供给窗口管理器的窗口动作并不多。因此通常只能用来制作一些连贯动画,做不到让窗口在可操作的情况下变形。在作者的这个案例中,一个进程同时作为窗口管理器和合成管理器,这是比较常见的情况,但是这也做不到把两个功能完全整合起来。)
3.客户端获得事件然后决定他要做什么。通常为了回应这个事件,用户界面会发生变化,可能是一个选框被点选,可能是指针悬停到了一个按钮上,需要把这个按钮变亮提示用户。由此客户端回复X服务器一个渲染请求。
4.当X服务器接收到渲染请求的时候,他再将其发送到驱动程序,让他操作硬件渲染内容。X服务器也会计算渲染的区域边界位置,然后用待修事件(damage event)(译注:为了提高渲染效率,屏幕上的任何内容更新都只是重新渲染那一个区域,而不是重新渲染整个屏幕。damage event用来传递需要更新的区域信息。)的形式发送给合成器。
5.待修事件会告知合成器窗口中的一些内容发生了改变,当窗口上的这个部分在屏幕上有显示时,他就重新合成这个位置的图像。合成器需要从他的窗口层叠关系(scenegraph)和X中各窗口的内容渲染出整个屏幕的内容。但是这个过程中,他必须通过X服务器才能完成这个渲染过程。
6.X服务器接收到合成器发来的渲染请求,要么从合成器的后置缓冲区复制到前置缓冲区,要么做一个翻页动作(pageflip)(译注:先在缓冲区渲染好内容,然后等待垂直同步的信号后切换要显示的缓冲区,避免画面发生撕裂)。普遍情况是X服务器有必要记录窗口的重叠,因为可能需要做图像的剪裁(clipping),影响到是否能做翻页动作。然而对通常是全屏运行的合成器来说,其实这是又一个没有必要的内容变换。(译注:这部分我也不太理解。可能是说本来合成器就有窗口重叠的计算了,而X又重复做了一次,为了剪裁图像。)
我们可以发现上面的这个过程中有一些弊端。X服务器不了解是哪个窗口要接收到事件,他也不知道怎么变换屏幕坐标和各窗口的单独(local)坐标。更甚的是虽然X把整个屏幕最后绘图的任务交给了合成管理器,X仍然掌控着前置缓冲区和模式设置(modesetting)(译注:比如说是屏幕分辨率等)。X服务器曾经做的大量复杂工作现在已经被内核中或独立的库(KMS、evdev、mesa、fontconfig、freetype、cairo、Qt等)代替。实际上X服务器现在只是一个传声筒,在应用程序和合成器之间、合成器和硬件之间徒增一步。
在Wayland中,合成器就是显示服务器。我们把KMS和evdev的控制权交给了合成器。Wayland协议让合成器能直接发送输入事件到各个客户端,而客户端把待修事件直接发送给合成器:
1.内核获取事件然后把他发送给合成器。好在Wayland和X的做法类似,这样我们能重复利用所有内核的输入驱动。
2.合成器在窗口层叠关系(scenegraph)中找到应该接收事件的窗口。窗口层叠关系相当于屏幕上的内容,合成器能知道窗口层叠关系中每个元素的形变情况(transformation)。因此合成器能找到正确的窗口,可以把屏幕坐标变换成窗口的单独(local)坐标,只需要反向使用形变情况即可(译注:这是数学!不过开发过游戏的会清楚这是怎么做到的)。各种形变方法都可以用到窗口上,只需要合成器能够对输入事件计算反向形变即可。
3.和X的做法一样,当客户端接收到事件时,他会相应地更新用户界面。但是在Wayland中,渲染是在客户端内部进行的。客户端只需要发送请求给合成器,表明需要更新的位置。
4.合成器从各个客户端收集待修请求然后重新合成屏幕图像。合成器能直接发出一个ioctl来用KMS计划执行一次翻页动作(pageflip)。
Wayland 渲染
我在上文中没有提到的细节就是客户端到底是怎么在Wayland中渲染的。X服务器不仅从上面的结构图中消失,而且我们也移除了常规的X客户端渲染的机制。但是其实还有另一个机制,我们曾在X中的DRI2使用到:「直接渲染」。在直接渲染时,客户端和服务器共享一个显存缓冲区。客户端链接到一个能操作硬件的渲染库,比如OpenGL,然后直接渲染到这个缓冲区中。接下来合成器可以取得这个缓冲区,然后把他作为一个纹理(texture)用在合成桌面(译注:这个是计算机图形学中的相关内容。「纹理」相当于一个图像数据)。在初始设置结束后,客户端只需要告诉合成器他用了哪个缓冲区,以及他渲染新内容时的时机和位置。
这样应用程序有两个更新窗口内容的方法:
1.把新内容渲染到一个新的缓冲区内,然后告知合成器用新的缓冲区代替旧的。这样应用程序可以每次更新窗口内容都重新划分一块缓冲区,也可以保留两块或者更多的缓冲区,然后在这些缓冲区之间循环操作。所有缓冲区的管理都由应用程序所掌控。
2.把新内容渲染到他之前让合成器使用的缓冲器。虽然可以直接渲染到与合成器共享的缓冲区,但是可能发生应用程序和合成器比拼速度的情况。重新绘制窗口内容可能会被合成器重新绘制桌面所打断。如果应用程序在清理窗口之后而绘图之前被打断,合成器就相当于从一个空的缓冲区里取出材质。结果就是应用窗口会从一个空窗口和一个渲染了一半的窗口之间来回闪烁。传统解决方法是先绘制新内容到另外的缓冲区内(译注:称为「后置缓冲区」),之后再复制到合成器的表面(surface)上(译注:这也是个图形学的术语,代表可以绘制图像的地方。其实就是上面说的共享缓冲区)。后置缓冲区可以在使用时随时划分,只要够大能容下新绘制的内容;也可以永远保持一个缓冲区随时使用。还是那句话,一切都由应用程序所掌控。
无论选择两个方案中的哪个,应用程序必须告知什么表面容纳的是新绘制好的内容。当应用程序在共享缓冲区中直接渲染时,要提醒合成器哪里是新内容。当交换缓冲区的时候,如果应用程序不发送一个请求,合成器在重绘桌面之前就不会认定有内容发生变化。这个设计是因为有些应用程序在传递新缓冲区给合成器的时候,可能只有一个小部分发生变化,比如一个输入文字时光标的闪烁或者程序繁忙时的旋转盘标志。(译注:即用于节约系统的资源消耗。)
Wayland的硬件支持
通常来说硬件支持包括模式设置/显示和EGL/GLES2。在此之外Wayland还需要一个共享缓冲区的高效方法。这个功能的实现分为客户端方面和服务器方面。
在客户端方面,我们设计了个Wayland EGL平台。他在EGL模型中是由几个原生类型(EGLNativeDisplayType,EGLNativeWindowType和EGLNativePixmapType)和创建这些类型的途径所组成。换句话说,这个就想当于「胶水」,来让EGL技术栈和缓冲区共享机制接合到通用的Wayland API。EGL技术栈用来帮助实现一个Wayland EGL平台。完整API见 wayland-egl.h(原文)头文件。mesa的EGL技术栈实现的开源Wayland EGL平台见platform_wayland.c(原文)。
深层次的是,为了实现共享缓冲区,EGL技术栈需要定义一个各厂商(vendor)特定的协议扩展,来让客户端的EGL技术栈与合成器交流缓冲区的详情。wayland-egl.h的API目标是把这些细节抽离开,让客户端只需要创建一个为Wayland表面使用的EGLSurface就能开始渲染。开源技术栈使用drm(原文) Wayland扩展,这能让客户端发现drm来使用和注册,之后与将drm(GEM)缓冲区与合成器共享。
Wayland的服务器方面是合成器和核心用户体验,比如说传统的任务切换器、应用启动器、锁屏画面都在同一个单独程序中。服务器在一个模式设定(modesetting)的API上运行(KMS、OpenWF Display或者类似的),然后使用混合的EGL/GLES2合成器以及可能使用的硬件叠加(hardware overlay)(译注:指直接在显存中连续播放视频等内容。)合成最终UI。模式设定、EGL/GLES2和叠加的功能都应该是标准硬件附属物的一部分。启用Wayland的另外需求是EGL_WL_bind_wayland_display(原文)扩展,能让合成器从通常的Wayland共享缓冲区创建一个EGLImage。他有点像EGL_KHR_image_pixmap(原文),用于从X pixmap创建EGLImage。
这个扩展有个设定阶段,需要把EGL显示接合到Wayland显示上。然后当合成器从客户端接收到通用Wayland缓冲器时(通常是客户端调用eglSwapBuffers),他能把结构体wl_buffer的指针作为参数EGLClientBuffer传递给eglCreateImageKHR,同时EGL_WAYLAND_BUFFER_WL为目标。这会创建一个EGLImage,可以用作合成器的纹理或者用一个叠加平面传递到模式设定代码上。还是那句话,这是被各厂商特定的协议扩展实现,在服务器方面会接收到共享缓冲区基于特定驱动的详细信息,在用户调用eglCreateImageKHR会把缓冲区转换成EGL图像。(译注:此处比较混乱,不保证能翻译得很准确,请读原文。)