Wayland Architecture

本文探讨了Wayland和传统X架构的区别,特别是在输入事件处理、渲染请求和硬件交互方面。Wayland通过让compositor直接控制KMS和evdev,简化了流程,提高了效率。

A good way to understand the wayland architecture and how it is different from X is to follow an event from the input device to the point where the change it affects appears on screen.

This is where we are now with X:

X architecture diagram

  1. The kernel gets an event from an input device and sends it to X through the evdev input driver. The kernel does all the hard work here by driving the device and translating the different device specific event protocols to the linux evdev input event standard.
  2. The X server determines which window the event affects and sends it to the clients that have selected for the event in question on that window. The X server doesn't actually know how to do this right, since the window location on screen is controlled by the compositor and may be transformed in a number of ways that the X server doesn't understand (scaled down, rotated, wobbling, etc).
  3. The client looks at the event and decides what to do. Often the UI will have to change in response to the event - perhaps a check box was clicked or the pointer entered a button that must be highlighted. Thus the client sends a rendering request back to the X server.
  4. When the X server receives the rendering request, it sends it to the driver to let it program the hardware to do the rendering. The X server also calculates the bounding region of the rendering, and sends that to the compositor as a damage event.
  5. The damage event tells the compositor that something changed in the window and that it has to recomposite the part of the screen where that window is visible. The compositor is responsible for rendering the entire screen contents based on its scenegraph and the contents of the X windows. Yet, it has to go through the X server to render this.
  6. The X server receives the rendering requests from the compositor and either copies the compositor back buffer to the front buffer or does a pageflip. In the general case, the X server has to do this step so it can account for overlapping windows, which may require clipping and determine whether or not it can page flip. However, for a compositor, which is always fullscreen, this is another unnecessary context switch.

As suggested above, there are a few problems with this approach. The X server doesn't have the information to decide which window should receive the event, nor can it transform the screen coordinates to window-local coordinates. And even though X has handed responsibility for the final painting of the screen to the compositing manager, X still controls the front buffer and modesetting. Most of the complexity that the X server used to handle is now available in the kernel or self contained libraries (KMS, evdev, mesa, fontconfig, freetype, cairo, Qt, etc). In general, the X server is now just a middle man that introduces an extra step between applications and the compositor and an extra step between the compositor and the hardware.

In wayland the compositor is the display server. We transfer the control of KMS and evdev to the compositor. The wayland protocol lets the compositor send the input events directly to the clients and lets the client send the damage event directly to the compositor:

Wayland architecture diagram

  1. The kernel gets an event and sends it to the compositor. This is similar to the X case, which is great, since we get to reuse all the input drivers in the kernel.
  2. The compositor looks through its scenegraph to determine which window should receive the event. The scenegraph corresponds to what's on screen and the compositor understands the transformations that it may have applied to the elements in the scenegraph. Thus, the compositor can pick the right window and transform the screen coordinates to window-local coordinates, by applying the inverse transformations. The types of transformation that can be applied to a window is only restricted to what the compositor can do, as long as it can compute the inverse transformation for the input events.
  3. As in the X case, when the client receives the event, it updates the UI in response. But in the wayland case, the rendering happens in the client, and the client just sends a request to the compositor to indicate the region that was updated.
  4. The compositor collects damage requests from its clients and then recomposites the screen. The compositor can then directly issue an ioctl to schedule a pageflip with KMS.

Wayland Rendering

One of the details I left out in the above overview is how clients actually render under wayland. By removing the X server from the picture we also removed the mechanism by which X clients typically render. But there's another mechanism that we're already using with DRI2 under X: direct rendering. With direct rendering, the client and the server share a video memory buffer. The client links to a rendering library such as OpenGL that knows how to program the hardware and renders directly into the buffer. The compositor in turn can take the buffer and use it as a texture when it composites the desktop. After the initial setup, the client only needs to tell the compositor which buffer to use and when and where it has rendered new content into it.

This leaves an application with two ways to update its window contents:

  1. Render the new content into a new buffer and tell the compositor to use that instead of the old buffer. The application can allocate a new buffer every time it needs to update the window contents or it can keep two (or more) buffers around and cycle between them. The buffer management is entirely under application control.
  2. Render the new content into the buffer that it previously told the compositor to use. While it's possible to just render directly into the buffer shared with the compositor, this might race with the compositor. What can happen is that repainting the window contents could be interrupted by the compositor repainting the desktop. If the application gets interrupted just after clearing the window but before rendering the contents, the compositor will texture from a blank buffer. The result is that the application window will flicker between a blank window or half-rendered content. The traditional way to avoid this is to render the new content into a back buffer and then copy from there into the compositor surface. The back buffer can be allocated on the fly and just big enough to hold the new content, or the application can keep a buffer around. Again, this is under application control.

In either case, the application must tell the compositor which area of the surface holds new contents. When the application renders directly to the shared buffer, the compositor needs to be noticed that there is new content. But also when exchanging buffers, the compositor doesn't assume anything changed, and needs a request from the application before it will repaint the desktop. The idea that even if an application passes a new buffer to the compositor, only a small part of the buffer may be different, like a blinking cursor or a spinner.

Hardware Enabling for Wayland

Typically, hardware enabling includes modesetting/display and EGL/GLES2. On top of that, Wayland needs a way to share buffers efficiently between processes. There are two sides to that, the client side and the server side.

On the client side we've defined a Wayland EGL platform. In the EGL model, that consists of the native types (EGLNativeDisplayType, EGLNativeWindowType and EGLNativePixmapType) and a way to create those types. In other words, it's the glue code that binds the EGL stack and its buffer sharing mechanism to the generic Wayland API. The EGL stack is expected to provide an implementation of the Wayland EGL platform. The full API is in the wayland-egl.h header. The open source implementation in the mesa EGL stack is in platform_wayland.c.

Under the hood, the EGL stack is expected to define a vendor-specific protocol extension that lets the client side EGL stack communicate buffer details with the compositor in order to share buffers. The point of the wayland-egl.h API is to abstract that away and just let the client create an EGLSurface for a Wayland surface and start rendering. The open source stack uses the drm Wayland extension, which lets the client discover the drm device to use and authenticate and then share drm (GEM) buffers with the compositor.

The server side of Wayland is the compositor and core UX for the vertical, typically integrating task switcher, app launcher, lock screen in one monolithic application. The server runs on top of a modesetting API (kernel modesetting, OpenWF Display or similar) and composites the final UI using a mix of EGL/GLES2 compositor and hardware overlays if available. Enabling modesetting, EGL/GLES2 and overlays is something that should be part of standard hardware bringup. The extra requirement for Wayland enabling is the EGL_WL_bind_wayland_display extension that lets the compositor create an EGLImage from a generic Wayland shared buffer. It's similar to the EGL_KHR_image_pixmap extension to create an EGLImage from an X pixmap.

The extension has a setup step where you have to bind the EGL display to a Wayland display. Then as the compositor receives generic Wayland buffers from the clients (typically when the client calls eglSwapBuffers), it will be able to pass the struct wl_buffer pointer to eglCreateImageKHR as the EGLClientBuffer argument and with EGL_WAYLAND_BUFFER_WL as the target. This will create an EGLImage, which can then be used by the compositor as a texture or passed to the modesetting code to use as an overlay plane. Again, this is implemented by the vendor specific protocol extension, which on the server side will receive the driver specific details about the shared buffer and turn that into an EGL image when the user calls eglCreateImageKHR.

<think>我们正在为ARM64架构的Debian 11系统编译wayland-protocols。wayland-protocols是Wayland的协议扩展集合,它包含了一些额外的协议,这些协议不是核心Wayland协议的一部分。 根据引用[1]中的步骤,我们使用wayland-build-tools来构建Wayland相关的项目。但是,引用[1]中的步骤是针对x86架构的,并且是在一个构建环境中设置整个Wayland栈(包括Wayland和Weston)。对于我们的需求,我们只需要编译wayland-protocols,并且是针对ARM64架构。 然而,需要注意的是,wayland-protocols主要是由XML文件(用于生成头文件和代码)和一些Autotools构建系统组成的。因此,编译它通常不需要在目标架构上运行代码,只需要在构建主机上使用交叉编译工具链。 由于我们是在Debian 11上为ARM64编译,我们可以使用Debian提供的交叉编译工具链。但是,wayland-protocols本身并不包含需要编译的代码(它主要是生成头文件),所以实际上它只是一个安装这些XML文件和生成的头文件的过程。但是,它确实需要构建系统来生成一些文件(比如pkg-config文件)以及安装头文件。 因此,我们可以采用以下步骤: 1. 安装必要的构建工具和依赖项。 2. 获取wayland-protocols的源代码。 3. 配置构建环境,使用交叉编译工具链(如果必要的话)或者直接为ARM64架构构建(如果我们在ARM64机器上构建,则不需要交叉编译)。 4. 构建并安装。 但是,如果我们是在一个x86的主机上为ARM64交叉编译,那么我们需要设置交叉编译环境。而如果我们的Debian 11主机本身就是ARM64架构,那么直接编译安装即可。 由于问题没有明确说明主机架构,我们假设两种情况: 情况A:在ARM64主机上编译(本机编译) 情况B:在x86主机上交叉编译 由于问题中提到了“在Debian 11上为ARM64架构编译”,所以更可能的情况是:我们可能是在一个x86主机上交叉编译,或者直接在ARM64主机上编译。但为了通用性,我们将分别说明。 但是,wayland-protocols本身并不需要复杂的编译,它主要是由XML协议文件和由这些XML文件生成的头文件(通过wayland-scanner)组成。因此,交叉编译的关键在于确保wayland-scanner可以在构建主机上运行(因为它是用来生成头文件的工具),同时生成的pkg-config文件等要指向目标架构的路径。 实际上,wayland-protocols的构建过程并不涉及目标平台的代码编译(如C代码),所以它通常不需要交叉编译。但是,它依赖于已经为目标平台安装的Wayland库(至少是头文件)。因此,我们需要确保已经为目标平台(ARM64)安装了Wayland。 然而,如果我们是在x86主机上交叉编译,并且目标平台是ARM64,那么我们需要: 1. 安装交叉编译工具链。 2. 为ARM64目标安装Wayland库(包括头文件和pkg-config文件)。 3. 确保构建过程中使用的工具(如wayland-scanner)可以在构建主机上运行(因为它是用于生成头文件的,所以必须是构建主机可以运行的二进制文件)。 由于这个过程可能比较复杂,而且wayland-protocols的构建过程相对简单,通常的做法是在目标平台(ARM64)上直接编译安装。因此,我们首先介绍在ARM64主机上的编译步骤。 情况A:在ARM64主机上编译(本机编译) 步骤1:安装必要的依赖 在终端中运行: ```bash sudo apt update sudo apt install -y git meson pkg-config wayland-protocols-core ``` 注意:我们安装的是`wayland-protocols-core`,但实际上我们可能需要的是构建依赖,包括`meson`和`pkg-config`,以及`wayland-scanner`(它通常包含在`wayland-protocols-core`包中?)。实际上,在Debian中,构建wayland-protocols需要以下包: - meson - ninja-build - pkg-config - wayland-scanner (通常由libwayland-dev提供) 因此,我们可能需要安装: ```bash sudo apt install -y meson ninja-build pkg-config libwayland-dev ``` 步骤2:获取源代码 ```bash git clone https://gitlab.freedesktop.org/wayland/wayland-protocols.git cd wayland-protocols ``` 步骤3:配置并构建 使用meson构建系统: ```bash meson build --prefix=/usr ninja -C build ``` 步骤4:安装 ```bash sudo ninja -C build install ``` 情况B:在x86主机上为ARM64交叉编译 交叉编译需要设置交叉编译环境。我们可以使用Debian提供的交叉编译工具链。 步骤1:安装交叉编译工具链和依赖 ```bash sudo apt update sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu meson ninja-build pkg-config-aarch64-linux-gnu ``` 步骤2:安装目标架构的Wayland库(ARM64) 我们需要为ARM64架构安装libwayland-dev。这可以通过多架构支持来安装: ```bash sudo dpkg --add-architecture arm64 sudo apt update sudo apt install -y libwayland-dev:arm64 ``` 步骤3:获取源代码 ```bash git clone https://gitlab.freedesktop.org/wayland/wayland-protocols.git cd wayland-protocols ``` 步骤4:配置交叉编译 我们需要创建一个交叉编译文件(例如`cross.txt`)来指定交叉编译选项。创建文件`cross.txt`,内容如下: ```ini [host_machine] system = 'linux' cpu_family = 'aarch64' cpu = 'aarch64' endian = 'little' [binaries] c = 'aarch64-linux-gnu-gcc' cpp = 'aarch64-linux-gnu-g++' ar = 'aarch64-linux-gnu-ar' strip = 'aarch64-linux-gnu-strip' pkgconfig = 'aarch64-linux-gnu-pkg-config' ``` 然后使用meson进行配置: ```bash meson build --prefix=/usr --cross-file cross.txt ``` 步骤5:构建 ```bash ninja -C build ``` 步骤6:安装 安装到sysroot或者直接打包?由于我们是在交叉编译,安装到主机系统可能不是我们想要的。我们可以指定安装目录: ```bash DESTDIR=/path/to/arm64/sysroot ninja -C build install ``` 或者,如果我们只是想要生成的文件,可以安装到一个临时目录,然后复制到目标设备: ```bash mkdir -p arm64-install DESTDIR=$(pwd)/arm64-install ninja -C build install ``` 然后,将`arm64-install`目录下的文件复制到目标设备的对应路径。 但是,需要注意的是,wayland-protocols安装的主要是XML文件和生成的头文件,这些文件是架构无关的。因此,实际上我们也可以直接在x86主机上编译(不进行交叉编译),然后将生成的文件(在/usr/share/wayland-protocols和/usr/include)复制到ARM64目标设备上。但是,这样会缺少pkg-config文件(如果有的话)以及可能的一些其他配置。 由于wayland-protocols的构建过程生成的pkg-config文件(.pc文件)也是架构无关的(它们只包含路径信息),所以实际上我们也可以直接在x86主机上编译(使用本机配置),然后将安装的文件复制到ARM64设备。但是,为了确保一致性,最好还是按照目标架构来构建。 但是,考虑到wayland-protocols没有二进制代码,我们也可以直接从ARM64架构的Debian仓库中下载预编译的包。如果目标设备是Debian 11 ARM64,那么最简单的方法是: ```bash sudo apt install wayland-protocols ``` 但是,如果我们需要最新版本,或者需要从源代码构建(例如为了开发或定制),那么就需要按照上述步骤。 由于问题要求编译,我们假设需要从源代码构建。 总结: 根据你的主机平台选择情况A或情况B。 注意:在情况B中,我们可能需要确保在目标设备上已经安装了相同版本的Wayland库,否则生成的头文件可能不匹配。 另外,wayland-protocols的版本需要与目标设备上的Wayland库版本兼容。 生成的相关问题: 1. 如何验证wayland-protocols已经正确安装? 2. 在交叉编译wayland-protocols时,如何处理其他依赖(如wayland-scanner)? 3. 如何为其他架构(如ARMhf)交叉编译wayland-protocols? 4. 在Debian上,如何安装特定版本的wayland-protocols? 5. 如何将编译好的wayland-protocols文件打包成deb包? 请根据你的具体情况选择编译方法。</think>### 在 Debian 11 上为 ARM64 架构编译 Wayland 协议 以下是完整的编译步骤,已针对 ARM64 架构进行适配: #### 步骤 1: 安装依赖工具 ```bash sudo apt update sudo apt install -y git meson ninja-build pkg-config \ libwayland-dev gcc-aarch64-linux-gnu \ automake autoconf libtool ``` #### 步骤 2: 克隆构建工具和协议源码 ```bash # 克隆构建工具 git clone https://gitlab.freedesktop.org/wayland/wayland-build-tools.git cd wayland-build-tools # 创建构建目录结构 mkdir -p ~/Wayland/{sources,builds} cp wl_defines.sh ~/.config/wayland-build-tools/ ``` #### 步骤 3: 配置 ARM64 交叉编译环境 编辑 `~/.config/wayland-build-tools/wl_defines.sh`: ```bash # 设置 ARM64 目标架构 export WL_ROOT="$HOME/Wayland" export WLD="$WL_ROOT/builds/arm64" export ARCH="aarch64" export CROSS_COMPILE="aarch64-linux-gnu-" export PKG_CONFIG_PATH="$WLD/lib/pkgconfig:$PKG_CONFIG_PATH" ``` #### 步骤 4: 安装 ARM64 依赖库 ```bash # 添加 ARM64 架构支持 sudo dpkg --add-architecture arm64 sudo apt update # 安装 ARM64 版 Wayland 依赖 sudo apt install -y libffi-dev:arm64 libexpat1-dev:arm64 \ libxml2-dev:arm64 ``` #### 步骤 5: 构建 Wayland 协议 ```bash # 克隆协议源码 ./wl_clone -p wayland-protocols # 配置 ARM64 构建 cd $WL_ROOT/sources/wayland-protocols meson setup build-arm64 \ --prefix=$WLD \ --cross-file ../wayland-build-tools/cross.txt \ -Dtests=false # 编译和安装 ninja -C build-arm64 ninja -C build-arm64 install ``` #### 步骤 6: 验证安装 ```bash # 检查 ARM64 协议文件 file $WLD/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml # 应显示 XML 文本文件 # 检查 pkg-config aarch64-linux-gnu-pkg-config --modversion wayland-protocols # 应显示版本号 ``` #### 关键配置说明 1. **交叉编译文件**:`wayland-build-tools/cross.txt` 需包含: ```ini [binaries] c = 'aarch64-linux-gnu-gcc' pkgconfig = 'aarch64-linux-gnu-pkg-config' ``` 2. **ARM64 特定设置**: ```bash export PATH="$WLD/bin:$PATH" export ACLOCAL_PATH="$WLD/share/aclocal" ``` > **注意**:如果直接在 ARM64 设备上编译,可跳过交叉编译步骤,直接使用 `meson build --prefix=/usr/local` 配置[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值