3. PLANE核心概念:PLANE的作用、帧缓冲绑定、像素格式、Alpha混合、Z-order排序

在DRM/KMS显示子系统中,PLANE(图层/平面)是构成最终显示画面的基本元素。理解PLANE的核心概念,是掌握多图层显示驱动开发的基石。本章将深入剖析PLANE的作用、与帧缓冲(FB)的绑定关系、像素格式、Alpha混合机制以及Z-order排序规则。

3.1 PLANE的作用与分类

PLANE在硬件上对应显示控制器中的一个独立图层。每个PLANE可以承载一个独立的帧缓冲(Framebuffer),并拥有自己的位置、尺寸、像素格式和透明度属性。CRTC(显示控制器定时器)负责将多个PLANE按照特定的顺序(Z-order)叠加混合,最终生成一帧完整的画面输出到显示器。

根据功能和性能,PLANE通常分为以下几类:

类型 硬件特性 典型用途 数量
主图层 (Primary Plane) 必须存在,通常支持扫描输出,与CRTC直接关联 桌面背景、视频播放、游戏主画面 至少1个
光标图层 (Cursor Plane) 硬件光标,尺寸小(通常64x64),更新快,无需重新配置整个管线 鼠标指针、光标 0或1个
覆盖图层 (Overlay Plane) 可选的额外图层,支持独立缩放、旋转、色彩空间转换 画中画、字幕、UI元素、摄像头预览 0或多个
驱动开发提示: 在驱动初始化时,必须为每个CRTC注册至少一个Primary Plane。Overlay Plane是可选的,但现代SoC通常提供2-4个硬件图层,驱动应尽可能暴露这些能力给用户空间,以实现零拷贝合成(Zero-Copy Composition)。

3.2 帧缓冲绑定(Framebuffer Binding)

PLANE本身不存储像素数据,它只是一个“窗口”。PLANE通过绑定一个帧缓冲(Framebuffer,FB)来获取实际的像素内容。帧缓冲是内存中的一块区域,存储了渲染好的图像数据。

绑定过程通过drmModeSetPlane或atomic接口完成,核心参数包括:

  • plane_id:目标PLANE的ID。
  • fb_id:要绑定的帧缓冲的ID。
  • crtc_id:目标CRTC的ID。
  • src_x, src_y, src_w, src_h:源裁剪区域(以16.16固定点格式表示)。
  • crtc_x, crtc_y, crtc_w, crtc_h:目标显示区域(以像素为单位)。
// 用户空间通过libdrm调用示例
int ret = drmModeSetPlane(fd, plane_id, crtc_id, fb_id, flags,
                          crtc_x, crtc_y, crtc_w, crtc_h,
                          src_x << 16, src_y << 16, src_w << 16, src_h << 16);
if (ret) {
    // 错误处理
    printf("Failed to set plane: %s\n", strerror(errno));
}
关键点: 源裁剪区域(src_*)允许从帧缓冲中截取一部分显示,而目标区域(crtc_*)定义了该部分在屏幕上的位置和大小。通过调整这两个区域,可以实现硬件级别的缩放和平移,无需CPU介入。

3.3 像素格式(Pixel Format)

像素格式定义了帧缓冲中每个像素的数据排列方式。DRM子系统通过四字符码(FourCC)来标识像素格式。PLANE支持的像素格式列表是驱动初始化时注册的,用户空间必须查询并选择PLANE支持的格式。

常见的像素格式分类如下:

分类 FourCC 描述 位深
RGB 打包格式 DRM_FORMAT_XRGB8888 32位,无Alpha通道,RGB各8位 32
RGB 打包格式 DRM_FORMAT_ARGB8888 32位,含Alpha通道,RGB各8位 32
RGB 打包格式 DRM_FORMAT_RGB565 16位,R:5 G:6 B:5 16
YUV 半平面格式 DRM_FORMAT_NV12 Y平面 + UV交错平面,视频编码常用 12
YUV 平面格式 DRM_FORMAT_YUV420 Y、U、V三个独立平面 12
压缩格式 DRM_FORMAT_MODIFIER 通过修饰符(Modifier)指定压缩方式,如AFBC、DCC 可变
常见陷阱: 不要假设所有PLANE都支持相同的像素格式。Primary Plane通常支持RGB格式,而Overlay Plane可能只支持YUV格式。驱动开发时,务必在plane->format_modifiers中正确声明支持的格式列表,否则用户空间的合成器(如Weston、Wayland)将无法正确使用该PLANE。

3.4 Alpha混合(Alpha Blending)

当多个PLANE叠加时,Alpha混合决定了上层像素如何与下层像素融合。DRM/KMS支持两种主要的Alpha模式:

  • 全局Alpha(Plane Alpha):整个PLANE使用一个统一的Alpha值,对所有像素生效。
  • 逐像素Alpha(Per-Pixel Alpha):每个像素使用其自身的Alpha通道值(如ARGB8888格式中的A分量)。

混合公式(使用预乘Alpha):

// 假设上层像素为 S(源),下层像素为 D(目标),Alpha值为 A
// 预乘Alpha混合公式
Output = S + D * (1 - A)

// 如果S是预乘Alpha格式(Premultiplied Alpha),则直接使用上述公式。
// 如果S是直通Alpha格式(Straight Alpha),则需要先进行预乘:
// S_premultiplied = S * A
// Output = S_premultiplied + D * (1 - A)

PLANE的Alpha属性通过以下属性控制:

属性名 类型 说明
alpha 范围 [0, 0xffff] 全局Alpha值,0为完全透明,0xffff为完全不透明
pixel blend mode 枚举 None(禁用混合)、Pre-multiplied(预乘)、Coverage(直通/覆盖)
性能优化: 如果PLANE不需要透明度,应使用DRM_FORMAT_XRGB8888(无Alpha通道)并设置alpha为0xffff,这样硬件可以跳过Alpha混合计算,降低带宽消耗。

3.5 Z-order排序(Z-order Ordering)

Z-order决定了多个PLANE在垂直方向上的叠加顺序。Z-order值越小,图层越靠近“底部”(离观察者越远);Z-order值越大,图层越靠近“顶部”(离观察者越近)。

在DRM/KMS中,Z-order通常通过PLANE的ID或显式的Z-order属性来控制:

  • 隐式Z-order(基于ID):某些硬件按照PLANE注册的顺序或ID大小决定叠加顺序。这种方式不够灵活,已逐渐被淘汰。
  • 显式Z-order(基于属性):现代驱动通过zpos属性来显式控制Z-order。用户空间可以动态调整每个PLANE的zpos值。
// 内核驱动中注册zpos属性的示例
struct drm_plane *plane;
drm_object_attach_property(&plane->base,
                           config->plane_zpos_property,
                           plane->base.id); // 默认zpos等于plane ID

// 用户空间通过atomic ioctl设置zpos
drmModeAtomicReq *req = drmModeAtomicAlloc();
drmModeAtomicSetProperty(req, plane_id, zpos_prop_id, 10); // 设置zpos为10
drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
drmModeAtomicFree(req);

下图展示了三个PLANE(背景、视频、UI)通过Z-order叠加的典型场景:

PLANE Z-order 叠加示意图 背景层 (Primary Plane) Z-order = 0 格式: XRGB8888 视频层 (Overlay Plane 1) Z-order = 1 格式: NV12 Alpha: 0xCCCC (80%) UI层 (Overlay Plane 2) Z-order = 2 格式: ARGB8888 逐像素Alpha Z-order 增加 (越靠近观察者) 说明 CRTC按照Z-order从低到高依次混合各PLANE。 上层PLANE的Alpha值决定其下层内容的可见程度。

3.6 核心数据结构与驱动接口

在内核驱动中,PLANE由struct drm_plane结构体表示。驱动开发者需要实现一系列回调函数来支持PLANE的操作。

// 内核中 drm_plane 结构体(简化版)
struct drm_plane {
    struct drm_device *dev;
    struct drm_crtc *crtc;          // 当前绑定的CRTC
    struct drm_framebuffer *fb;     // 当前绑定的帧缓冲
    struct drm_plane_state *state;  // 当前状态

    uint32_t possible_crtcs;        // 位掩码,表示该PLANE可以绑定到哪些CRTC
    uint32_t format_count;          // 支持的像素格式数量
    const uint32_t *format_types;   // 支持的像素格式列表

    // 核心回调函数
    int (*update_plane)(struct drm_plane *plane, struct drm_crtc *crtc,
                        struct drm_framebuffer *fb, int crtc_x, int crtc_y,
                        unsigned int crtc_w, unsigned int crtc_h,
                        uint32_t src_x, uint32_t src_y,
                        uint32_t src_w, uint32_t src_h,
                        struct drm_modeset_acquire_ctx *ctx);
    int (*disable_plane)(struct drm_plane *plane,
                         struct drm_modeset_acquire_ctx *ctx);
    void (*destroy)(struct drm_plane *plane);
};
驱动开发要点:
  • possible_crtcs:必须正确设置,否则用户空间无法将PLANE绑定到目标CRTC。
  • format_types:必须包含硬件支持的所有格式,包括带修饰符的格式。
  • atomic_check:在atomic模式下,驱动应实现atomic_check回调,验证状态变更的合法性(如检查缩放比例是否在硬件限制内)。

3.7 本章小结

PLANE是DRM/KMS多图层合成的核心抽象。理解PLANE的作用、帧缓冲绑定机制、像素格式选择、Alpha混合原理以及Z-order排序规则,是开发高效、灵活的显示驱动的关键。在实际项目中,驱动开发者需要根据硬件能力,合理暴露PLANE的属性,并确保用户空间能够通过标准接口(如libdrm、Wayland)充分利用硬件图层功能,实现低功耗、高性能的显示合成。