4、Screen Window与Composition:Window类型与合成流程

好,咱们今天聊点实在的。Window 和 Composition,说白了就是 QNX 图形显示栈里最核心的拼图游戏。你想想看,仪表盘上那么多元素——车速、转速、警告灯、导航箭头——它们怎么叠到一起,又怎么送到屏幕上的?答案就在 Window 类型和合成流程里。

4.1 Window 的三种类型

我个人习惯把 Window 分成三类:Child、Group、Application。别被名字唬住,其实很好理解。

4.1.1 Application Window(应用窗口)

这是最基础的窗口类型。每个应用进程创建一个 Application Window,用来展示自己的内容。比如你的车速表是一个应用,导航地图是另一个应用,它们各自拥有一个 Application Window。

特点:

  • 每个 Application Window 有独立的缓冲区
  • 可以设置透明度、旋转、缩放等属性
  • 是合成器直接操作的基本单位

核心概念:Application Window 是合成器的「输入源」。合成器读取这些窗口的内容,然后拼成最终画面。

4.1.2 Child Window(子窗口)

子窗口是挂在 Application Window 下面的。我在项目中遇到过一种场景:车速表应用里有个数字显示区域,这个区域需要独立更新(比如数字跳变时),但又不想重新绘制整个车速表。这时候 Child Window 就派上用场了。

使用场景:

  • 局部刷新:只更新子窗口区域,父窗口不动
  • 层级控制:子窗口可以浮在父窗口上面
  • 裁剪效果:子窗口内容超出父窗口边界时会被裁剪

避坑指南:我曾经在项目里滥用 Child Window,结果窗口数量一多,合成性能直线下降。后来我总结了一个经验:Child Window 数量控制在 5 个以内,超过这个数就该考虑用 Group Window 了。

4.1.3 Group Window(组窗口)

Group Window 是个容器,可以把多个 Application Window 或 Child Window 打包在一起。为什么要这么做?因为有时候你需要对一组窗口做统一操作,比如整体移动、整体隐藏、整体设置透明度。

举个例子:

仪表盘上的「运动模式」切换。当用户切换到运动模式时,整个仪表盘的配色、布局都要变。如果你把转速表、车速表、油量表都放在一个 Group Window 里,切换时只需要操作这个 Group 就行了,不用一个个去改。

Window 类型 典型用途 性能影响
Application Window 独立应用的内容展示 低(每个应用一个)
Child Window 局部刷新、浮层效果 中(数量多时影响大)
Group Window 统一管理多个窗口 低(适合批量操作)

4.2 Composition 流程

Composition,说白了就是「拼图」。合成器把各个 Window 的内容按照 Z-order(层级顺序)叠在一起,然后输出到屏幕。这个过程听起来简单,但里面门道不少。

4.2.1 合成的基本步骤

  1. 收集窗口信息:合成器遍历所有 Window,获取它们的位置、大小、透明度、缓冲区地址
  2. 排序:按 Z-order 从低到高排序,底层的先画,上层的后画
  3. 混合:如果有透明度,需要做 alpha blending(透明度混合)
  4. 输出:最终合成结果写入显示缓冲区

关键点:合成器不是每帧都重新合成所有窗口。它只合成「有变化」的窗口区域。这就是为什么 QNX 的合成效率高——它做了脏区域追踪(Dirty Region Tracking)。

4.2.2 合成策略的选择

我建议你根据硬件能力选择合成策略。QNX 支持两种方式:

  • 软件合成:CPU 来做混合运算。适合窗口数量少、分辨率低的场景
  • 硬件合成:GPU 或显示控制器来做。适合多窗口、高分辨率、高帧率的场景

嗯,这里要注意:软件合成虽然灵活,但 CPU 负载高。我在一个 4K 分辨率的项目里试过软件合成,CPU 占用直接飙到 80%,帧率还掉到 30fps。后来切到硬件合成,CPU 占用降到 10%,帧率稳定 60fps。

4.3 硬件 Overlay 与合成

硬件 Overlay 是 QNX 图形栈里一个「作弊器」。它允许你把某些窗口直接交给显示控制器处理,不经过合成器。

4.3.1 什么是 Overlay?

Overlay 是显示控制器的一个硬件层。你可以把某个 Window 的内容直接映射到这个硬件层上。显示控制器会自动把这个层叠加到主画面上,不需要 CPU 或 GPU 参与。

Overlay 的优势:

  • 零 CPU 开销:合成工作由硬件完成
  • 低延迟:Overlay 层的内容更新可以立即显示
  • 节省带宽:不需要把 Overlay 内容拷贝到合成缓冲区

注意:Overlay 不是万能的。大多数显示控制器只支持 2-4 个硬件 Overlay 层。而且 Overlay 层的格式有限制,比如只支持 RGB565 或 NV12 格式。我曾经踩过这个坑——想用 Overlay 显示一个 ARGB8888 的窗口,结果硬件不支持,只能退回到软件合成。

4.3.2 Overlay 的使用场景

我个人最常用的 Overlay 场景是视频播放和摄像头预览。因为这些内容需要低延迟、高帧率,而且格式通常是 YUV,正好适合 Overlay。

代码示例:创建一个 Overlay 窗口

// 创建一个 Overlay 窗口
screen_window_t overlay_win;
screen_create_window(&overlay_win, screen_ctx);

// 设置窗口类型为 Overlay
int usage = SCREEN_USAGE_OVERLAY;
screen_set_window_property_iv(overlay_win, SCREEN_PROPERTY_USAGE, &usage);

// 设置 Overlay 的格式(比如 NV12)
int format = SCREEN_FORMAT_NV12;
screen_set_window_property_iv(overlay_win, SCREEN_PROPERTY_FORMAT, &format);

// 设置 Overlay 的 Z-order,让它浮在主画面上面
int zorder = 1;
screen_set_window_property_iv(overlay_win, SCREEN_PROPERTY_ZORDER, &zorder);

4.3.3 合成与 Overlay 的配合

实际项目中,合成器和 Overlay 是配合使用的。举个例子:

  • 主画面(仪表盘背景、固定元素)由合成器合成
  • 视频流(倒车影像)通过 Overlay 显示
  • 警告灯(需要高优先级显示)也通过 Overlay 显示

这样既保证了主画面的灵活性(合成器可以处理复杂的 UI 效果),又保证了视频和警告灯的低延迟。

我的经验:如果你需要同时使用多个 Overlay,一定要先查硬件手册。有些显示控制器支持 Overlay 叠加(Overlay 叠 Overlay),有些不支持。不支持的话,你就只能把多个 Overlay 内容合并到一个硬件层里,或者退回到合成器处理。

4.4 总结一下

Window 类型和 Composition 是 QNX 图形显示栈的基石。记住三点:

  1. 选对 Window 类型:Application 做主体,Child 做局部,Group 做批量
  2. 合成策略要匹配硬件:能硬件合成就别用软件,能 Overlay 就别走合成器
  3. Overlay 是性能利器:但有限制,用之前先确认硬件能力

下一章我会讲 Screen Buffer 的管理和双缓冲机制,那是保证画面不撕裂的关键。咱们到时候接着聊。