Weston (Wayland) 窗口系统

Wayland 是一种显示服务器与其客户端之间通信的协议。Wayland 服务器使用 Wayland 协议与 GUI 程序(即 Wayland 客户端)通信。Wayland 服务器也称为 Wayland 合成器,因为它也充当合成窗口管理器。
Weston 服务器,通常简称为 Weston,是 Wayland 合成器的参考实现。它管理显示器,包括其内容的合成、对其输入设备事件(触摸屏、鼠标、键盘等)的支持以及其设置(壁纸、分辨率、多显示器显示等)。
与 X11 相比,Weston 更轻量级,并且作为合成器速度很快。它适用于许多嵌入式和移动用例。
当前版本的 Jetson Linux 支持 Weston 6.0。

Weston/Wayland 架构

Diagram Description automatically generated
Wayland 服务器和一组 Weston 库统称为 Weston/Wayland。此图描述了 Weston/Wayland 架构。
Wayland 服务器库实现了 Weston 的 Wayland 协议。Weston 库实现了 Wayland 合成器,它使用 Linux 内核模式设置 (KMS) 来设置显示,使用 OpenGLES直接渲染管理器 (DRM) 执行合成,并管理 Linux 输入设备。
Wayland 客户端应用程序使用 Wayland 协议与 Wayland 合成器通信。它可能是 EGL 应用程序、X 服务器(无根)或其他类型的显示服务器。

Shells

Weston 通过 shell 插件支持不同的图形用户界面。NVIDIA 发行版 Weston 带有两个插件:桌面 shell 和 IVI shell。
桌面和 IVI shell 各自为 Wayland 客户端提供自己的 Wayland 协议接口。因此,为特定 shell 协议编写的 Wayland 客户端不适用于其他 shell 协议。
桌面 shell 提供类似于 X11 的现代桌面环境,以及键盘和鼠标的接口。它由库 desktop-shell.so 实现。一个特殊的桌面 shell 客户端 weston-desktop-shell 渲染壁纸、面板和其他桌面元素。
IVI shell 专为车载信息娱乐 (IVI) 应用程序设计。它通过其控制器模块提供与 GENIVI Layer Manager 兼容的 API,以及供 IVI 应用程序使用的简单协议。它由库 ivi-shell.so 实现。

配置

您可以通过配置文件 /etc/xdg/weston/weston.ini 配置 Weston shell 的外观和行为偏好设置。
有关配置 Weston shell 的更多信息,请参阅 Ubuntu weston.ini 手册页

环境变量

Weston 使用的环境变量有
WAYLAND_DEBUG:如果设置为任何值,则会导致 libwayland 将实时协议打印到 stderr
XDG_RUNTIME_DIR:指定 Weston 的套接字和锁定文件的目录。如果设置,Weston 将在此目录下创建其套接字,Wayland 客户端使用此目录下的套接字与 Weston 通信。

运行 Weston 6.0

使用以下步骤启动 Weston。
启动 Weston
1. 如果 X 服务器正在运行,请停止它
$ sudo service gdm stop; sudo pkill -9 Xorg
2. 启动 Tegra 虚拟 DRM 驱动程序
$ sudo modprobe tegra-udrm modeset=1
3. 创建 libgbm.so.1 符号链接
$ sudo ln -sf /usr/lib/aarch64-linux-gnu/tegra/libnvgbm.so /usr/lib/aarch64-linux-gnu/libgbm.so.1
4. 设置环境和目录权限
$ unset DISPLAY
$ mkdir /tmp/xdg
$ chmod 700 /tmp/xdg
5. 选择有效的 TTY 设备
$ export WESTON_TTY=1
6. 启动 Weston。
1. 要以 root 用户身份启动 Weston,请输入此命令
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston --tty="$WESTON_TTY" --idle-time=0 &
可选:将环境变量 WAYLAND_DEBUG 设置为 server 以将协议消息从服务器转储到 stderr
$ export WAYLAND_DEBUG=server
可选:使用 --use-egldevice 开关禁用 GBM 交换链,并使用 EGLStream 写入 Weston 输出。
2. 要使用 weston-launch 以非 root 用户身份启动 Weston,请输入以下命令
$ sudo groupadd weston-launch
$ sudo usermod -a -G weston-launch $USER
$ sudo chown root /usr/bin/weston-launch
$ sudo chmod +s /usr/bin/weston-launch
$ weston-launch &
7. 运行 Wayland 客户端
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston-simple-egl
可选:将环境变量 WAYLAND_DEBUG 设置为 1 以将所有协议消息转储到 stderr
$ WAYLAND_DEBUG=1
8. 要运行 Weston 测试,您必须使用命令行选项或 weston.ini 中的设置加载模块 weston-test.so。例如,您可以指定选项:--modules=/usr/lib/aarch64-linux-gnu/tegra/weston/weston test.so
9. 要在设备上使用 ivi-shellivi-controller 启动 Weston,请将参数传递给 weston 二进制文件,如下所示:--shell=ivi-shell.so --modules=ivi-controller.so

多显示头

Weston 在所有 Jetson 设备上都支持具有多个覆盖层的多显示头。使用 weston.ini 设置监视器的预期分辨率和方向。
如果连接了多个显示器,则应用程序会在启动时鼠标指针所在的显示器上启动。应用程序启动后,您可以将其拖过显示器之间的边界。
如果连接了多个显示器并且它们具有不同的分辨率,则 Weston 会报告窗口显示超过 50% 的显示器的帧速率。如果在 Weston 运行时移除监视器(热移除),则正在运行的应用程序会动态转移到剩余的活动监视器。

weston.ini 显示选项示例

使用此示例作为在 weston.ini 中设置您自己的显示选项的模型。
name=HDMI-A-1
mode=1920 x 1080
transform=90 (0,90,180,270)

热插拔

Weston 使用 udev 监视直接渲染管理器 (DRM) 子系统发送的事件。当显示配置更改时,udev 接收 HOTPLUG 事件。它调用 drmModeGetResources() 来识别已添加或移除的连接器,并采取相应的操作。
在 T210 上,没有真正的内核模式 DRM 驱动程序;相反,有一个用户模式 DRM 驱动程序 drm-nvdc 和一个虚拟内核模式 DRM 驱动程序 tegra-udrm。这些驱动程序协同工作,为 Weston 提供类似真实 DRM 驱动程序的接口。tegra-udrm 驱动程序在显示连接状态更改时发出 HOTPLUG 事件信号。

已验证的用例

在启动 Weston 后,断开并连接 HDMI™ 显示器。
在应用程序 nvgldemo 运行时,断开并连接 HDMI 显示器,并验证连接后应用程序绘图是否可见。
在未连接 HDMI 显示器的情况下启动 Weston,然后连接 HDMI 显示器。
在未连接 HDMI 显示器的情况下启动 Weston,启动 nvgldemo 应用程序,然后连接 HDMI 显示器。
上述所有用例也已通过 DisplayPort 显示器验证。

Weston 中修复的问题

重新连接显示器时,应用程序窗口消失。
此问题的修复程序已从上游 Weston 主代码线反向移植到下游 Weston 6 代码线。有关更多信息,请参阅 freedesktop.org GitLab
在未连接显示器时,使用 ivi-shell 会导致 Weston 崩溃。
ivi-shell 中添加了对多个热插拔显示器的支持。
ivi-shell 最初并非设计为支持热插拔。这是 NVIDIA 的增强功能。
该修复程序向 ivi-vm 添加了一个协议,使客户端可以接收由 ivi-controller 发送的热插拔事件。客户端必须在使用 ivi-layermanagement API 的热插拔期间处理事件,以重新定位表面、销毁表面等等。客户端可以创建侦听器来侦听 ivi-wm-screen 接口中的 connector_namescreen_idscreen_destroy 事件,以获取 ivi-wm 协议以获取热插拔通知。
以下是一些示例代码
static void
screen_id(void *data, struct ivi_wm_screen *ivi_wm_screen, uint32_t id);
 
static void
screen_destroy(void *data,struct ivi_wm_screen *ivi_wm_screen, uint32_t id);
 
static void
connector_name(void *data, struct ivi_wm_screen *ivi_wm_screen, const char *process_name);
 
struct ivi_wm_screen_listener wm_screen_listener = {
screen_id,
screen_destroy,
layer_added,
connector_name,
error,
};
 
ivi_wm_screen_add_listener(ivi_wm_screen, &wm_screen_listener, args);

已知问题

DRM 模块目前无法通知 Weston 页面翻转失败。因此,当 Weston 配置为支持多个显示器时,在特定时间热插拔显示器可能会导致 drmAtomicCommit() 因“页面翻转挂起”断言而失败。

Weston 中的合成模式

Jetson 设备每个显示头有多个平面。平面的主要类型有
主平面
覆盖平面
光标平面
在每一帧,Weston 都会评估所有表面和视图,并选择以下策略之一来合成它们
仅覆盖模式:Weston 尝试为每个表面或视图分配一个平面。如果不可能,它将切换到“混合模式”。
混合模式:Weston 尝试为某些表面和视图分配覆盖平面,使用 GL 合成剩余的表面和视图,并将结果更新到主平面。如果仍然不可能,它将继续使用“仅 GL 模式”。
仅 GL 模式:Weston 使用 GL 合成所有表面和视图,并将结果更新到主平面。
使用所有这些策略,Weston 确保保留表面和视图的渲染顺序。您可以通过将环境变量 WESTON_FORCE_RENDERER 设置为 1 来强制使用仅 GL 模式合成。
演示应用程序 weston-simple-dmabuf-egldevice 演示了 Weston 中的混合模式合成,其中一些表面被分配了覆盖平面,而另一些表面则使用 GL 合成到主平面。
您可以使用应用程序 weston-debug 来验证是否正在分配覆盖平面。使用以下步骤
1. 如果 X 正在运行,请停止 X 并准备设备以启动 Weston
$ sudo service gdm stop; sudo pkill -9 Xorg
$ unset DISPLAY
$ mkdir /tmp/xdg
$ chmod 700 /tmp/xdg
$ export WESTON_TTY=1
$ sudo modprobe tegra-udrm modeset=1
$ sudo ln -sf /usr/lib/aarch64-linux-gnu/tegra/libnvgbm.so /usr/lib/aarch64-linux-gnu/libgbm.so.1
2. 使用 --debug 开关启动 Weston
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston --tty="$WESTON_TTY" --idle-time=0 --debug &
3. 启动几个 Weston 客户端应用程序
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston-simple-egl &
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston-simple-dmabuf-egldevice &
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston-simple-dmabuf-egldevice &
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston-simple-dmabuf-egldevice &
4. 运行 weston-debug 应用程序
$ sudo XDG_RUNTIME_DIR=/tmp/xdg ./weston-debug -a
5. weston-debug 输出中查找如下所示的信息。蓝色表面是覆盖合成的,绿色表面是 GL 合成的。
Layer 5 (pos 0x50000000)
View 0 (role xdg_toplevel, PID 8080, surface ID 3, top-level window 'simple-dmabuf-egldevice', 0x33c798b0)
position: (714, 860) -> (970, 1116)
[not opaque]
outputs: 0 (HDMI-A-1) (primary)
dmabuf buffer
format: 0x34325258 XRGB8888
modifier: 0x3800000000fe014
View 1 (role xdg_toplevel, PID 8073, surface ID 3, top-level window 'simple-dmabuf-egldevice', 0x33bb9500)
position: (209, 591) -> (465, 847)
[not opaque]
outputs: 0 (HDMI-A-1) (primary)
dmabuf buffer
format: 0x34325258 XRGB8888
modifier: 0x3800000000fe014
 
View 2 (role xdg_toplevel, PID 8066, surface ID 3, top-level window 'simple-dmabuf-egldevice', 0x31769110)
position: (1129, 339) -> (1385, 595)
[not opaque]
outputs: 0 (HDMI-A-1) (primary)
dmabuf buffer
format: 0x34325258 XRGB8888
modifier: 0x3800000000fe014
 
View 3 (role xdg_toplevel, PID 8051, surface ID 9, top-level window 'simple-egl', 0x314c6430)
position: (1343, 642) -> (1593, 892)
[not opaque]
outputs: 0 (HDMI-A-1) (primary)
EGL buffer
 
Layer 6 (pos 0x2)
...
[view] evaluating view 0x33c798b0 for output HDMI-A-1 (0)
[view] view 0x33c798b0 format: XRGB8888
[overlay] provisionally placing view 0x33c798b0 on overlay 4002 in mixed mode
[view] evaluating view 0x33bb9500 for output HDMI-A-1 (0)
[view] view 0x33bb9500 format: XRGB8888
[overlay] provisionally placing view 0x33bb9500 on overlay 4001 in mixed mode
[view] evaluating view 0x31769110 for output HDMI-A-1 (0)
[view] view 0x31769110 format: XRGB8888
[overlay] not placing view 0x31769110 on overlay: no free overlay planes
[view] evaluating view 0x314c6430 for output HDMI-A-1 (0)
[overlay] not placing view 0x314c6430 on overlay: couldn't get fb
[repaint] Using mixed state composition
[repaint] view 0x33c798b0 on Overlay plane 4002
[repaint] view 0x33bb9500 on Overlay plane 4001
[repaint] view 0x31769110 using renderer composition
[repaint] view 0x314c6430 using renderer composition

Weston 中的 NV16/NV24

Weston GL 合成器通过共享内存缓冲区添加了对 NV16 和 NV24 内容的支持。
使用 WL_SHM_FORMAT_NV24 枚举的应用程序可以替换 DRM_FORMAT_NV24,因为按照惯例,这两个枚举都使用 drm_fourcc.h 中定义的符号。

共享内存渲染

Weston 测试 color-format.weston 对 Weston 当前支持的所有格式执行共享内存渲染。虽然作为测试用例实现,但它旨在用于视觉验证,并且必须手动终止。
要运行测试用例
1. 使用 weston-test.so 模块启动 Weston,例如
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston --tty="$WESTON_TTY" --idle-time=0 --modules=weston-test.so &
2. 输入此命令以执行测试应用程序
$ sudo XDG_RUNTIME_DIR=/tmp/xdg color-format.weston
该应用程序显示八种颜色测试模式,每种模式都使用不同的颜色格式渲染。所有模式都应基本相同,只有因格式限制而造成的细微差异。
3. 要终止测试,请输入 Ctrl-C。

DMA 缓冲区渲染

DRM 现在支持 NV16 和 NV24 颜色格式。要使用这些格式,请通过公开的 EXT_image_dma_buf_importEXT_image_dma_buf_import_modifiers 扩展从 DMA 缓冲区构造 EGLImage
当前仅支持块线性 DMA 缓冲区布局。DRM_FORMAT_NV21DRM_FORMAT_NV16DRM_FORMAT_NV24 已添加到 supported_drm_formats
要运行已验证的用例(视频播放测试)
输入此命令
$ gst-launch-1.0 filesrc location=<mp4_src_file> ! qtdemux ! h264parse ! nvv4l2decoder ! nvvidconv ! 'video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)<format>' ! nvdrmvideosink
其中
<mp4_src_file>apt 源文件的路径名
<format>NV16NV24
gst-launch-1.0 命令是用于显示视频的 GStreamer 管道。它使用 nvvidconv 插件将流中的其他格式转换为 NV16/NV24。视频通过 nvdrmvideosink 插件显示,该插件在内部使用 DRM。

VPR 内存

您可以使用 nbuf_utils通用缓冲区管理 (GBM) 和 EGLStream 分配 VPR 内存。
使用 nvbuf_utils:将 NvBufferTag_PROTECTED 标记添加到 struct NvBufferCreateParamsNvBufferTag 成员,并将其传递给 NvBufferCreate()
使用 GBM:为 gbm_bo_create() 指定 GBM_BO_USE_PROTECTED 用法标志。
使用 EGLStream:在创建 eglSurface 对象时添加 EGL_PROTECTED_CONTENT_EXT 属性。为受保护的纹理指定纹理参数 GL_TEXTURE_PROTECTED_EXT
要使用 GL 写入受保护的纹理,您还必须使用受保护的上下文,您可以通过指定 EGL_PROTECTED_CONTENT_EXT 属性来创建该上下文。请注意,当您将 dmabuf 导入 EGL 时,如果 dmabuf 是在 VPR 内存中创建的,则还必须指定此属性。
要运行示例用例
使用 -p 开关运行 weston-simple-dmabuf-egldevice 应用程序。
要验证结果的正确性,请在屏幕上检查它。它应该与您在不使用 VPR 内存的情况下运行应用程序时相同。
当前限制
VPR 内容只能通过覆盖 GL 合成在屏幕上渲染。GL 尚不支持受保护的内容。此类支持将在以后的版本中添加。
因此,如果屏幕上有多个窗口超过覆盖合成的限制,则不会为超出限制的窗口渲染受保护的内容。
HDCP 支持尚不可用。它将在未来的版本中支持。但是,对于 Jetson Nano 设备,即使不建立 HDCP 链接,您也可以在屏幕上显示 VPR 内容。

Weston dma-buf 支持

客户端可以使用 Wayland 的 Linux DMA-BUF 不稳定 V1 协议将 dma-buf 缓冲区发布到 Weston。具有 Weston 的 Dma-buf 支持具有以下组件。

缓冲区分配

GBM 通常用于分配缓冲区,这些缓冲区由 dma-buf 文件描述符支持。
此代码段显示了如何使用 GBM 分配缓冲区
drm_fd = open("/dev/dri/card0", O_RDWR);
device = gbm_create_device(drm_fd);
bo = gbm_bo_create_with_modifiers(device, width, height,
format, modifiers, modifiers_count);
Weston 支持格式 DRM_FORMAT_XRGB8888DRM_FORMAT_ARGB8888
modifier 是特定于供应商的缓冲区布局参数的编码。Weston 支持的修饰符受 DRM 支持(读取 IN_FORMATS 平面属性 blob)和 EGL 支持(调用 eglQueryDmaBufModifiersEXT() )。

从 CPU 写入/读取缓冲区

您可以使用此 API 函数将数据直接写入 GBM 缓冲区
gbm_bo_write(bo, user_buffer, sizeof user_buffer);
您还可以内存映射 GBM 缓冲区并获取 CPU 可访问的地址,以用于写入或读取其中的数据。以下代码段显示了如何操作
uint32_t dst_stride = 0;
void *gbo_mapping = NULL;
// 将 bo 映射到 CPU 可访问的地址。
char *dst_ptr = gbm_bo_map(bo,
0, 0,
width,
height,
GBM_BO_TRANSFER_READ_WRITE,
&dst_stride,
&gbo_mapping);
 
// 将数据写入 dst_ptr 或从中读取数据。
. . .
 
// 取消映射 bo。
gbm_bo_unmap(bo, gbo_mapping);

将 dma-buf 缓冲区发布到 Weston 的 Wayland 协议

Weston 使用通用缓冲区管理 (GBM) 库来分配缓冲区,这些缓冲区由 dma-buf 文件描述符支持。客户端应用程序必须调用以下 GBM 函数才能从 GBM 缓冲区对象获取 dma-buf 文件描述符和关联的参数。要将 dma-buf 发布到 Wayland 表面,必须通过 Linux DMA-BUF 不稳定 V1 协议提供文件描述符和参数。
以下代码段显示了涉及的主要调用。
stride = gbm_bo_get_stride_for_plane(bo, 0);
offset = gbm_bo_get_offset(bo, 0);
handle = gbm_bo_get_handle_for_plane(bo, 0);
modifier = gbm_bo_get_modifier(bo);
drmPrimeHandleToFD(drm_fd, handle, 0, &dmabuf_fd);
 
zwp_linux_buffer_params_v1_add(params, dmabuf_fds, 0, offset,
stride, modifier >> 32,
modifier & 0xffffffff);
zwp_linux_buffer_params_v1_create(params, width, height,
format, flags);

Weston 中的 GL 渲染器

Weston 中的 GL 渲染器使用 EGL_EXT_image_dma_buf_importEGL_EXT_image_dma_buf_import_modifiers 扩展,从它通过 Linux DMA-BUF 不稳定 V1 协议接收的 dma-buf 对象创建 EGLImage。Weston 通过调用 eglQueryDmaBufModifiersEXT() 获取要与此 EGLImage 一起使用的 GL 纹理目标,并将 EGLImage 绑定到纹理。

Weston 中的显示硬件合成

Weston 中的 DRM 合成器调用 drmModeAddFB2WithModifiers(),以将 DRM 帧缓冲区 ID 与通过 Linux DMA-BUF 不稳定 V1 协议接收的 dma-buf 相关联。然后,它使用帧缓冲区 ID 将 dma-buf 呈现给可用的显示硬件平面之一,在旧版路径中使用 drmModeSetPlane(),或在原子模式设置路径中使用 drmModeAtomicCommit()。这采用翻转的形式,其中对新缓冲区的引用在垂直消隐期间交换。

Weston dma-buf 示例

weston-dmabuf-formats 是一个简单的应用程序,用于测试 Weston dmabuf 对不同格式(如 XRGB8888、NV12、NV16、NV24)的支持。
输入此命令以启动应用程序
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston-dmabuf-formats --import-format=<format> --loop=<count> --use-gbm
其中
<format> 是 NV16 或 NV24。
<count> 是要执行的迭代次数。
--use-gbm 表示应用程序将使用 GBM 而不是 nvbuf_utils 进行缓冲区分配。

weston-debug

客户端应用程序 weston-debug 使用 weston-debug 协议接收和打印调试消息。例如,当 Weston 重新合成时,它会打印所有表面视图以及有关将其分配给覆盖层和 GL 合成的决策过程的描述。
要使 weston-debug 工作,您必须使用 ‑‑debug 开关运行 Weston。请勿在生产环境中使用此开关。
您可以传递 weston-debug 附加参数来选择要显示的调试输出类别
$ sudo XDG_RUNTIME_DIR=/tmp/xdg weston –debug
$ sudo XDG_RUNTIME_DIR=/tmp/xdg ./weston-debug -a
或者,您可以通过设置环境变量 WAYLAND_DEBUG=server 来启用 Weston 调试输出,并通过设置 WAYLAND_DEBUG=1 来启用 Weston 客户端调试。

Gnome-Wayland 桌面 Shell 支持

在 L4T 版本 32.4.2 中,NVIDIA 支持 Gnome-Wayland 窗口系统。L4T 对 Gnome-Wayland 的支持目前处于实验阶段。
本节介绍一些使用 Gnome-Wayland 的步骤。
要启动窗口系统
1. /etc/systemd/nvuser.sh 中,更改
GNOME_WAYLAND="0"
GNOME_WAYLAND="1"
2. /etc/modprobe.d/tegra-udrm.conf 中,取消注释行
#options tegra-udrm modeset=1
(删除行首的“#”。)
3. /etc/systemd/nv.sh 中,更改
DISABLE_MESA_EGL="1"
DISABLE_MESA_EGL="0"
4. /etc/systemd/system/nvargus-daemon.service 中,通过在行首插入“;”来阻止 nvargus 守护程序在启动时启动
ExecStart=/usr/sbin/nvargus-daemon
5. 重启设备。如果启用 auto-login,L4T 会将您登录到 Wayland 会话;否则,它会显示可用接口列表(例如 Wayland、命令行),并将您登录到您选择的类型的会话。