Android 显示问题最终常落到两个问题上:一块 Buffer 什么时候被拿去合成,以及它以什么形式交给显示硬件。SurfaceFlinger 的核心价值就在这里。它不负责 App 怎么画,也不直接控制 DPU 的寄存器;它站在系统窗口模型和硬件合成能力之间,把可见 Layer、Buffer、VSync、Fence、HWC 策略组织成一次可送显的提交。
这条链路看起来长,但边界清楚。App 生产图像,system_server 维护窗口关系和可见性,SurfaceFlinger 决定合成,HWC 抽象硬件能力,DRM 驱动对接 DPU,DPU 才是最终扫描输出的芯片外设。理解这条链,很多黑屏、卡顿、Client 合成、WaitGPU 异常都不会再停留在“SurfaceFlinger 很复杂”的层面。
一、一块 Buffer 的旅程:SurfaceFlinger 在显示链路里的位置

1.1 显示链路全景
从硬件往上看,DPU 是 Display Process Unit,一般作为芯片外设存在,负责把内容输出到内置屏、HDMI 等显示接口。DPU 之上是 kernel 层 DRM 驱动。DRM 提供通用显示抽象,屏蔽不同 DPU 的寄存器、plane、crtc、connector 等硬件细节。再往上是 HWC,也就是 Hardware Composer,它通常是独立进程,对 Android 显示框架暴露硬件合成能力。
SurfaceFlinger 与 HWC 更像同级协作关系。SurfaceFlinger 是 Android framework 的核心显示服务,独立进程运行。它接收来自 App 和 system_server 的 Layer、Buffer、Transaction,再把“这帧应该怎样合成”交给 HWC。system_server 里的 WMS(WindowManagerService)、AMS(ActivityManagerService)再往上连接 Activity、Window、Task 等系统概念。最上层才是 App。
这条路径可以概括为:DPU → DRM 驱动 → HWC → SurfaceFlinger → system_server → APP。方向不是数据单向流动的全部含义,但足够说明每一层抽象的位置。App 不应该知道 DPU 细节,SurfaceFlinger 也不应该直接理解 Activity 切换策略。每层只暴露必要接口。
1.2 SurfaceFlinger 的接口很原始
SurfaceFlinger 不是窗口管理器。它对外提供的是偏底层的图层接口,例如 createLayer 和 SurfaceControl。开机动画这类组件可以直接使用这套接口创建 Surface,把图像送进显示链路。普通 App 通常不会直接面对这些原始接口,而是经过 ViewRootImpl、Window、Surface 等更高层封装。
SurfaceFlinger 的职责可以概括为:决定这块内存什么时候触发合成,以及这块内存以什么形式送给 HWC 去合成。
“什么时候”对应 VSync、Transaction、Buffer ready、调度模型。“什么形式”对应 Device 合成还是 Client 合成、哪些 Layer 进 framebuffer、哪些 Layer 交给 HWC plane。后面的所有细节都围绕这两个判断展开。
二、Layer 的两个世界:SurfaceFlinger Layer 与 HWC Layer

2.1 SurfaceFlinger Layer 表示窗口本体
上层所说的 Surface,一般意味着有一块可绘制内存,里面有图像内容。在 SurfaceFlinger 内部,对应的是 Layer。这个 Layer 描述真实窗口大小、Buffer、变换、裁剪、透明度、Z 序等状态。它不是屏幕上的最终物理 plane,也不是 Activity 本身。
还有一种 container layer。它更偏容器概念,常由 WMS/AMS 管理,用来组织父子关系、继承属性、一起进退。Activity 跳转时,哪个窗口可见,父子 Layer 如何联动,哪些属性在事务中继承,主要由 system_server 维护。SurfaceFlinger 收到的是结果状态,然后在可见 Layer 集合上做合成判断。
2.2 HWC Layer 表示输出视角
HWC 里也有 Layer,dump SurfaceFlinger 时常能看到 output layer 相关信息。这里的 Layer 更接近“这个内容在某个 Display 上以什么位置、裁剪、变换参与输出”。同一个 SurfaceFlinger Layer 可以在输出阶段形成 HWC 需要理解的对象。
一个容易混淆的点是大小和位置。SurfaceFlinger 的 Layer 代表真实窗口大小;HWC 的 output layer 代表这个 Layer 在屏幕上的位置和输出关系。两者不是两份图像内存。后面谈 Gralloc 时会看到,它们最终指向同一块 Buffer,只是在不同抽象层中携带不同元数据。
可见性也不由 SurfaceFlinger 主动推断业务语义。比如 Activity 退到后台,WMS/AMS 会把相关 Layer 设置为不可见。SurfaceFlinger 只对可见 Layer 做合成处理。黑屏排查里,这个边界很关键:一帧里所有窗口突然不可见,问题往往在窗口事务,而不是 Buffer 没画完。
三、同一块内存:Gralloc/Allocator 与跨进程共享

3.1 allocator 申请的是可跨设备访问的 Buffer
Android 图形 Buffer 不是普通 Java 对象,也不是在每个进程复制一份位图。系统里有独立的 allocator 进程,历史上常被称为 gralloc。它负责申请一块适合图形设备访问的内存,常见形态是 DMA-BUF,并绑定一个 FD。
FD 可以通过 Binder 在 App、SurfaceFlinger、HWC 等进程之间传递。跨进程传输时,每个进程看到的 FD 数值可能不同,因为内核会为目标进程重新安装文件描述符。但 FD 指向的底层内存对象仍然是同一块。这个细节解释了为什么 App 画完以后不用把图像“拷贝给”SurfaceFlinger。
3.2 Buffer 沿链路传递,图像不复制
App 使用 OpenGL 等图形 API 绘制这块内存。绘制完成后,新版路径通过 setBuffer,老版 BufferQueue 路径通过 queueBuffer,把携带 Buffer 句柄的 FD 交给 SurfaceFlinger。SurfaceFlinger 再把它交给 HWC,HWC 继续交给 DRM,最终由 DPU 扫描或参与硬件合成。
这里要区分“FD 已传到”和“GPU 已画完”。前者说明各进程已经能索引到同一块内存;后者要靠 Fence 判断。显示系统不需要在每个环节都阻塞等待 GPU 完成,只要在真正使用前保证 ready 即可。这是 Android 图形链路能流水化的基础。
四、HWC 硬件合成与 plane 上限

4.1 plane 是硬件合成的资源
HWC 抽象的是下层显示硬件能力。真正的硬件合成能力在 DPU 里,DRM 负责把这种能力抽象成通用接口。常见平台上,DPU 能直接合成的输入内存块数量有限,直播素材中按 4 个 planes 说明。这个数字是平台经验值,不是 AOSP 强制规则;不同 SoC、不同显示控制器、不同 DRM 驱动都可能不一样。
一个简单桌面场景可能只有 statusbar、navbar、应用窗口三块内容。3 个 Layer 都可以交给 HWC 做 Device 合成,DPU 按层级覆盖后送屏。窗口更多时,例如再叠两个画中画 PIP,可见 Layer 数超过硬件 plane 能力,就需要 SurfaceFlinger 介入做 GPU 兜底。
这里还要把“窗口数量”和“Buffer 数量”分开。一个 Activity 在窗口管理上可能是一个窗口,但系统栏、启动动画、画中画、输入法、壁纸等都可能带来额外 Layer。SurfaceFlinger 关心的是当前 Display 上可见且参与合成的 Layer 集合,而不是用户主观上看到几个应用。排查 Client 合成时,直接数界面元素通常不准,应该以 dump 和 trace 中的 Layer 列表为准。
4.2 为什么要给 framebuffer 留一个 plane
GPU 兜底不是把所有内容都改成软件绘制,而是由 SurfaceFlinger 创建一个 FramebufferSurface,把一部分 Layer 用 GPU 先合成成一张更大的图,再把这张图作为一个输入交给 HWC。这样 HWC 仍然做最后一次硬件合成,只是其中一个 plane 放的是 SurfaceFlinger 预合成结果。
因此实际可给普通 Layer 使用的 plane 数通常要减 1,给 framebuffer 保留位置。下面代码只表达 drm_hwcomposer 的数量思路:调用 DRM 接口拿 planes 数量,再减去 framebuffer 占用。它是示意,非厂商原代码。
// 示意:通过 DRM 接口查询 plane 数量(真实实现需处理查询失败的情况)uint32_t plane_count = GetDrmPlaneCount();// 示意:为 SurfaceFlinger 的 framebuffer 预留一个 plane;plane_count 为 0 时不下溢uint32_t app_layer_plane_budget = (plane_count > 0) ? (plane_count - 1) : 0;// 示意:用剩余 plane 数判断普通 Layer 能否全部硬件合成bool can_compose_all_layers = (plane_count > 0) && (visible_layer_count <= app_layer_plane_budget);这段代码说明的不是 AOSP 存在某个同名函数,而是硬件资源预算的方向:HWC 能力有限,SurfaceFlinger 必须把 framebuffer 也算进最终输出资源。输入是 DRM 暴露的 plane 数和当前可见 Layer 数,输出是这帧是否可能全 Device 合成的判断。
五、合成策略:什么时候用 GPU 兜底

5.1 HWC 覆盖模型要求 Layer 连续
硬件合成可以把多块内存按层级叠加到屏幕上。为了把问题说清楚,可以把它类比成“按 Z 序盖图片”:底层先放,上层再覆盖。即使某些 HWC 支持透明度、缩放、旋转等能力,SurfaceFlinger 在决定 Client 合成集合时仍要尊重覆盖顺序。类比到这里就要回到精确定义:如果被 GPU 预合成的一组 Layer 在 Z 序上不连续,中间未参与预合成的 Layer 会被 framebuffer 覆盖,最终显示就错了。
所以被合成为 framebuffer 的 Layer 必须是连续的一段。假设 Z 序是 A、B、C、D,如果只把 A 和 C 合成到 framebuffer,再让 B 走硬件 plane,B 可能被包含 A/C 的 framebuffer 盖住。正确策略只能选择 A/B、B/C、C/D 这类连续区间,或者更长的连续区间。
5.2 像素和最小是合理目标
GPU 负载与参与重合成的像素点数量相关。窗口越大、需要处理的像素越多,RenderEngine 压力越大。SurfaceFlinger 在全部可见 Layer 里寻找连续 N 个且像素点个数之和最少的一组做 GPU 合成,是一个合理策略:既满足 Z 序连续约束,又尽量降低 GPU 开销。
这里的 N 取决于硬件 plane 缺口。比如可见 Layer 有 5 个,而可用硬件资源只能容纳 4 个,并且还要为 framebuffer 留一个位置,那么至少需要把一部分 Layer 合成为一个 framebuffer。最后 HWC 看到的可能是若干 Device Layer 加一个 Client 合成结果。dump 中看到的 Device/Client 合成类型,正是这类策略落地后的表现。
FramebufferSurface 不是 App 创建的 Layer,而是 SurfaceFlinger 自己创建的承载物。它让 SurfaceFlinger 在必要时“自己当一回生产者”,产出一个新的 Buffer,交给 HWC 作为普通输入参与最终合成。
六、RenderEngine:SurfaceFlinger 自己当一回 App

6.1 GPU 合成模块
RenderEngine 是 SurfaceFlinger 内部负责 GPU 合成的模块。它把需要 Client 合成的 Layer 当作图片,按照裁剪、变换、透明度、Z 序重新叠加,输出到 framebuffer。这个动作其实和 App 用 OpenGL 绘制一块 Buffer 类似,只是生产者换成了 SurfaceFlinger,输入来自多个已经存在的 Layer。
RenderEngine 有 OpenGL 和 Skia 相关实现路径,也有同步、异步配置。素材里把它概括成四种组合。对应到已核实的 AOSP 公开符号,libs/renderengine/include/renderengine/RenderEngine.h 中能看到 GraphicsApi 和 Threaded 参数。这里看代码,是为了确认“引擎类型”和“线程模式”确实是创建参数,而不是口头分类。
// 定义 RenderEngine 使用的图形 API 类型enum class GraphicsApi { GL, VK };// 定义 RenderEngine 是否使用线程化模式enum class Threaded { NO, YES };这两个 enum 说明 SurfaceFlinger 创建 RenderEngine 时会显式选择图形后端和线程模式。需要区分:当前统一使用 Skia 渲染路径时,GraphicsApi 的 GL/VK 是这条路径内部选择 OpenGL ES 还是 Vulkan 作为后端,并不等于"OpenGL 引擎 vs Skia 引擎"两种历史上并存过的实现(旧的非 Skia GLES RenderEngine 在后续版本中已被替换)。素材中的 OpenGL/Skia 与同步/异步是讲解口径;AOSP 公开头文件里可核实的是 GraphicsApi{GL,VK} 和 Threaded{NO,YES}。具体到某一分支,实现边界以源码为准。
6.2 异步不等于不用等
RenderEngine 的异步不是“提交后主线程永远不管”。它只是把一部分 CPU 能做的工作放到独立线程,减少 SurfaceFlinger 主线程同步消耗。GPU 指令真正完成前,最终 present 仍要等待相关结果。换句话说,异步能改善调度和并行度,但不能绕过 GPU 执行时间。
这也是 trace 中常见的现象:SurfaceFlinger 主线程发起 GPU 合成后,RenderEngine 线程工作,随后主线程仍要等合成结果满足送显条件,再调用下一次 present。看到“异步”标签时,不能直接推断这段成本已经消失。
七、完整合成流程:present → 失败 → 策略 → 再 present

7.1 四步主流程
一次完整合成可以按四步看。SurfaceFlinger 主线程先处理可见 Layer,构建当前 Display 的 layer stack,并创建 HWC 需要的 output layer。然后调用 present 或 validate/present 路径尝试送显。第一次不一定成功,因为 HWC 会根据硬件能力返回这帧的合成策略,哪些 Layer 可以 Device 合成,哪些 Layer 必须 Client 合成。
如果存在 Client 合成需求,SurfaceFlinger 调用 RenderEngine,把不适合硬件合成的一段 Layer 合成为 framebuffer。等 GPU 完成后,再调一次 present。这次应当成功,因为 HWC 已经拿到了符合硬件资源限制的输入集合。DRM 再等 VSync,把内容送到屏幕。
用更短的话说:可见 Layer 处理 → 尝试送显 → 失败则 GPU 合成 → 再送一次。这里的“失败”不是异常崩溃,而是 HWC 用返回策略告诉 SurfaceFlinger:当前 Layer 集合不能原样由硬件完成。
读这段流程时容易问:为什么不一开始就让 SurfaceFlinger 自己决定哪些 Layer 走 GPU?答案是 HWC 能力不是静态常量。硬件可能支持的格式、缩放比例、旋转、透明度、保护内容、显示目标都会影响本帧策略。SurfaceFlinger 可以预估,但最终仍要让 HWC validate。validate 的价值就在于把平台相关判断收口到硬件抽象层,避免 framework 侧写死厂商能力。

7.2 和 trace 对齐
Perfetto trace 里可以关注 SurfaceFlinger 主线程和 RenderEngine 线程。主线程通常能看到处理 transaction、build layer stack、validateDisplay、present 等阶段。发现硬件合成能力不足时,会创建或使用 framebuffer service,切到 GPU 合成路径。RenderEngine 线程执行合成,主线程等待结果,再 present。
双屏场景下,可能看到两个 Display 各自 present。当前 Android 多屏框架中,VSync 以主屏为基准的串行刷新是一个重要限制,后面会单独收束。读 trace 时不要把两个 Display 的 present 混成一次,也不要只用“有没有 3D launcher”判断是否 Client 合成。是否走 GPU 兜底主要看窗口数量、plane 能力和特殊效果,例如 blur、圆角等硬件不支持的组合。
八、VSync:多个生产端和一个消费端之间的节拍

8.1 App 绘制不能各自触发合成
App 是生产端,而且是多个;SurfaceFlinger 是消费端,通常一个 Display 对应一条消费节奏。没有 VSync 约束时,各 App 绘制完各自通知 SurfaceFlinger 合成,哪怕时间差只有一两毫秒,也可能造成 SurfaceFlinger 在一帧中只拿到部分新内容。它一次只能处理一个合成周期,错过窗口就会显示不同步。
所以 App 绘制完通常不是直接要求立即合成,而是发起 schedule、requestNextVsync 等请求,等待下一个 VSync 信号。到了统一节拍,SurfaceFlinger 再 latch Buffer、处理事务并触发合成。VSync 的意义不是让系统变慢,而是让多个生产端在同一帧边界上对齐。
8.2 硬件 VSync 与软件 VSync
硬件 VSync 来自 HWC 的 onVsync 回调。SurfaceFlinger 使用硬件 VSync 校准自己的 VSync 模型,再产生软件 VSync 分发给不同参与者。软件 VSync 不是虚构节拍,而是在硬件节拍基础上结合预测、偏移、调度窗口生成的框架侧信号。
显示链路中有三个典型等待者。App 等 VSync 决定什么时候开始绘制下一帧;SurfaceFlinger 等 VSync 决定什么时候合成;DRM 驱动等 VSync 决定什么时候真正送显,通过 MIPI 等链路把内容交给屏幕。三者等待的目标不同,混在一起看容易误判卡顿位置。
九、Fence:CPU 和 GPU 谁先谁后

9.1 Fence 解决 ready 判断
App 调用 OpenGL 时,CPU 往往只是把指令提交给 GPU。函数返回不代表 GPU 已经把 Buffer 画完。SurfaceFlinger、HWC、DRM 拿到 FD 时,也不能直接假设内存内容 ready。Fence 解决的就是 CPU 如何知道 GPU 完成:GPU 完成后 signal fence,CPU 或其他消费者在 fence 上 wait。
AcquireFence 表示消费者获取 Buffer 前需要等待的完成条件。ReleaseFence 表示前一个消费者释放 Buffer 后,生产者或后续使用者可继续操作的条件。素材中 ReleaseFence 没在主体部分展开,但追问环节补充了它在性能问题中的重要性。
9.2 DQBuffer 与 QBuffer 的等待边界
DQBuffer 等的是有没有可用 Buffer。没有空闲 Buffer 时,生产者需要等待队列释放。QBuffer 时可能等待上一帧的 AcquireFence,目的是避免 GPU 任务无限堆积。release fence 本身不影响 GPU 绘制指令的语义,但如果 release fence 迟迟不释放,GPU 可能无法开始使用目标 Buffer,trace 上就会表现为 WaitGPU 很长。更严格的 BufferQueue 语义是:dequeueBuffer 等的是该 slot 上一次被消费者释放时的 release fence(确认内存可复用),queueBuffer 则把这一帧的 acquire fence 交给消费者在真正使用前 wait;素材里"Q 等上一帧 acquire fence"是讲解口径的简化说法,细节以当前分支的 BufferQueueProducer 源码为准。
因此 WaitGPU 长不一定代表 GPU 算力不足。更严谨的看法是同时看 HWC release fence 和 GPU fence 两条线。如果 release fence 很晚 signal,GPU 等的是资源可用,不是计算慢。素材还提到 MTK 平台上 present fence 与 release fence 最终可能合并,具体实现要看厂商 HWC/DRM 路径。
这解释了一个性能分析陷阱:只盯 App 线程或 GPU slice,很容易把等待资源误判成绘制复杂。Fence 把生产者和消费者串起来,任何一端释放慢都会反映到后续等待。分析时应沿 Buffer 生命周期看 acquire、release、present 三类信号的先后关系,而不是只看某个线程上的单点耗时。

9.3 unsignaled buffer 与 AutoSingleLayer
一个现实问题是:SurfaceFlinger 能否在 acquireFence 还没 signal 时就 latch buffer?Android 13 引入的相关策略可以减少某些全屏游戏或单层更新场景中的卡顿。看这段代码,是为了确认可配置状态的公开枚举和属性名。
// 定义 SurfaceFlinger 处理未 signal Buffer 的策略enum class LatchUnsignaledConfig { Disabled, AutoSingleLayer, Always };# 系统属性不是 C++ 成员,独立列出避免混在一个语言块里# 控制 AutoSingleLayer 是否生效(Android 13 默认开启)# 控制 Always 模式:所有 buffer 一律 unsignaled latch,优先级高于 AutoSingleLayer该枚举证明策略至少包含 Disabled、AutoSingleLayer、Always 三种状态。AutoSingleLayer 的含义是单层更新时才允许 latch unsignaled buffer,用更激进的 latch 换取全屏单 Layer 场景的流畅度;debug.sf.latch_unsignaled 对应的 Always 模式会无条件忽略 acquire fence,官方文档标注可能导致画面冻结、不推荐。它不表示可以无条件忽略 Fence,最终送显前仍要满足 Buffer ready。
十、实战:黑屏怎么排查

10.1 先确认参与合成的窗口
黑屏排查不要从“是不是 GPU 慢”开始猜。第一步可以 dump SurfaceFlinger,看当前参与合成的 window 有哪些、Layer 是否可见、合成类型是 Device 还是 Client、是否有 Buffer。对一闪而逝的黑屏,单次 dump 可能抓不到,需要逐帧工具。
WinScope 适合定位这类问题。它能把窗口、Layer、Transaction、可见性变化按帧展开,本质是把 SurfaceFlinger dump、Transaction trace、Perfetto trace 等多个数据源按帧对齐后可视化,解决的是"人眼很难在几十次 dumpsys 里找到那一帧"的问题。素材里的教程步骤包括下载 winscope.html 并执行 winscope_proxy.py 连接设备,与当前 AOSP 官方流程一致(以下路径以 AOSP master 为准):
# 前置条件:已配置 adb 与 Android 源码树(含 development/tools/winscope)# 启动 WinScope 本地代理,成功后终端会打印一个 proxy tokenpython3 $ANDROID_BUILD_TOP/development/tools/winscope/src/adb/winscope_proxy.py# 打开 WinScope 页面(AOSP 树内自带,或官方托管的 web 版本)# 本地路径:$ANDROID_BUILD_TOP/prebuilts/misc/common/winscope/winscope.html# 页面内选择 Collect Traces -> Winscope Proxy,粘贴上一步的 token 建立连接实际使用时以当前 AOSP 分支或本地源码树中的 winscope 工具为准。
10.2 Buffer 没 ready 通常不会直接黑屏
一个常见误判是把黑屏归因于 Buffer 没画完。多数情况下,Buffer 没 ready 不会让屏幕立刻黑掉,系统可以沿用上一帧 Buffer。真正一闪而逝的黑屏,更常见原因是 WMS/AMS 在事务切换时把所有 window 设成不可见。例如启动动画和 launcher 切换窗口时,如果事务顺序或可见性状态出现空档,SurfaceFlinger 会忠实合成“没有可见窗口”的结果。
定位这类问题要看哪一帧、哪几个窗口突然不可见,再回到对应 transaction。还要检查 setBuffer 是否传入异常 Buffer,避免把可见性问题和 Buffer 内容问题混为一谈。SurfaceFlinger 是执行者,WMS/AMS 才是很多窗口状态的来源。
如果黑屏只持续一帧,普通日志通常太粗。比较有效的路径是先用现象时间点缩小 trace 区间,再用 WinScope 找到异常帧,随后对照 SurfaceFlinger dump 或 Perfetto 中的 transaction 应用顺序。看到某个 Layer 没 Buffer,不等于它导致黑屏;看到所有前台窗口同时不可见,才更接近窗口切换事务的问题核心。
十一、边界与回扣
11.1 多屏的限制
多屏不是把单屏逻辑复制两份就结束。当前 Android 多屏框架里,VSync 以主屏为基准,所有屏幕串行刷新。这会限制副屏独立刷新能力。单屏独立刷新还受 DRM 驱动和芯片接口能力影响,需要与芯片厂商合作。素材中提到作者团队做过尝试,但受接口限制,这是已知待优化点。这里不能把它写成所有平台都无法独立刷新;准确边界是当前框架和具体驱动能力共同决定。
11.2 回到两个问题
SurfaceFlinger 的主线仍是两个判断:什么时候触发合成,以及以什么形式送给 HWC。什么时候,取决于 VSync、Buffer 到达、Fence 状态、Transaction 调度。什么形式,取决于可见 Layer 集合、Z 序、plane 数量、HWC 能力、是否存在 blur/圆角等特殊效果,以及 RenderEngine 兜底成本。
可复现的验证入口也围绕这两点展开。用 dumpsys SurfaceFlinger 看 Layer、可见性、output layer、Device/Client 合成类型;用 Perfetto 抓 SurfaceFlinger 主线程和 RenderEngine 线程,看 transaction、build layer stack、validateDisplay、present、GPU 合成等待;结合窗口数量和平台 plane 能力判断为什么超过 4 个常见 plane 预算后会出现 Client 合成;黑屏问题则用 WinScope 按帧看 WMS/AMS transaction 和 Layer 可见性变化。
附:术语速查
| 术语 | 定义 | 章节 |
|---|---|---|
| Layer | Surface 在 SurfaceFlinger 里的替身,描述真实窗口大小与状态 | 二 |
| output layer / HWC Layer | Layer 在某个 Display 上的输出位置与关系 | 二 |
| Gralloc / allocator | 申请 DMA-Buffer 并绑定 FD 的独立进程,内存跨进程、GPU 可直访 | 三 |
| plane | DPU 能直接合成的输入内存块数量,通常 4,平台经验值 | 四 |
| Device 合成 | HWC 硬件合成;Client 合成指需要 GPU 兜底 | 五 |
| RenderEngine | SurfaceFlinger 内部做 GPU 合成的模块(OpenGL ES/Vulkan × 同步/异步) | 六 |
| validate / present | HWC 返回本帧合成策略 / 提交合成结果送显 | 七 |
| VSync | 多个生产端与单个消费端对齐的节拍信号,硬件/软件两级 | 八 |
| AcquireFence / ReleaseFence | 消费者使用前等待的完成条件 / 前一消费者释放后的可复用条件 | 九 |
视频素材来自本地 corpus 目录,未推送到远程仓库。
本文由 AgentWorkFlow 生成