SurfaceFlinger 合成一帧的完整流程
本文以 Android 16 的物理屏常规路径为主线:从 Scheduler 收到一次帧信号,到 SurfaceFlinger 提交状态、锁定 buffer、完成 GPU/HWC 分工、present,再到 fence 和回调收尾。虚拟屏、多屏 offload、合成策略预测等分支单独说明,不打断主线。
目录
- 正确的调用层级
- 关键对象和数据
- 阶段 A:Scheduler 发起一帧
- 阶段 B:commit 提交本帧状态
- 阶段 C:composite 组装合成输入
- 阶段 D:CompositionEngine 协调 Output
- 阶段 E:单屏 Output 合成与上屏
- fence 如何串起整帧
- 帧结束、回调与下一帧
- 重要分支与常见误解
1. 正确的调用层级

主调用树是:
text
Scheduler::onFrameSignal
├─ SurfaceFlinger::commit
│ └─ updateLayerSnapshots
│ ├─ collect / addLayers / flush / applyTransactions
│ ├─ LayerHierarchyBuilder::update
│ ├─ LayerSnapshotBuilder::update
│ └─ Layer::latchBufferImpl
└─ SurfaceFlinger::composite
├─ 组装 CompositionRefreshArgs
└─ CompositionEngine::present
├─ preComposition
├─ Output::prepare // 每块屏建立可见 OutputLayer
├─ Output::present // 每块屏合成、present、释放
└─ postComposition
**关键纠偏:**不要把
commit + composite + present当成三个并列阶段。CompositionEngine::present()是SurfaceFlinger::composite()内部的主要执行步骤,Output::present()又是它的单屏子流程。
从职责上看,一帧只有两个顶层阶段:
commit:把本帧应使用的 Layer 状态和 buffer 定下来。composite:把已确定的状态变成各屏的合成任务,完成 validate → GPU/HWC 合成 → present → release。
2. 关键对象和数据
| 对象 | 本帧职责 |
|---|---|
Scheduler / FrameTargeter |
建立帧目标,调用 commit() / composite(),最后执行 endFrame() |
SurfaceFlinger |
刷新事务、维护前端状态、锁定 buffer,并组装 CompositionRefreshArgs |
RequestedLayerState |
保存服务端收到的请求状态、transaction 字段和 changes |
LayerHierarchy |
根据父子、relative-Z 和 mirror 关系提供 Z 序遍历 |
LayerSnapshot |
保存特定遍历路径下的几何、可见性、buffer、色彩和效果等派生状态 |
LayerFE |
向 CompositionEngine 暴露快照,并生成 GPU 所需的 LayerSettings |
Output / OutputLayer |
Output 表示合成目标;OutputLayer 表示 Layer 在该输出上的状态 |
Display |
将物理屏的 Output present 操作落到 HWComposer |
RenderEngine |
把 CLIENT 类型的 Layer 绘制到 client target |
HWComposer |
封装 Composer HAL 的 validate、present 和 fence 获取 |
LayerSnapshot 不是一个全局唯一的 Layer 副本。镜像或相对层级会让同一 Layer 沿不同 TraversalPath 出现,因此快照是"Layer + 遍历路径"下的合成状态。
3. 阶段 A:Scheduler 发起一帧
入口为 Scheduler::onFrameSignal():
cpp
const FrameTargeter::BeginFrameArgs beginFrameArgs = {
.frameBeginTime = mClock->now(),
.vsyncId = vsyncId,
.expectedVsyncTime = expectedVsyncTime,
.sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration,
.hwcMinWorkDuration = getCurrentVsyncConfigs().hwcMinWorkDuration,
};
pacesetterPtr->targeterPtr->beginFrame(beginFrameArgs, *pacesetterPtr->schedulePtr);
if (!compositor.commit(pacesetterPtr->displayId, targets)) return;
const auto results = compositor.composite(pacesetterPtr->displayId, targeters);
for (const auto& [id, targeter] : targeters) targeter->endFrame(*results.get(id));
- 先为 pacesetter 屏建立
FrameTarget,确定expectedPresentTime、截止时间和前一帧 fence 状态。 - 再为可 present 的 follower 屏建立目标。follower 可因 backpressure 被暂时排除。
- 严格按
commit → composite → endFrame执行。commit()返回false时,本次不进入合成。
onFrameSignal 接到的是 Scheduler 分发后的帧信号;其时钟源可由 VSyncSchedule 的当前配置决定,不应简化成"始终直接接收面板硬件 VSYNC"。
4. 阶段 B:commit 提交本帧状态
4.1 先决定这次是否值得合成
SurfaceFlinger::commit() 先处理显示模式切换、HWC backpressure 等情况,再从 mMustComposite、前端状态变化、新 buffer latch 和 display transaction 等来源累积 mustComposite。
didMissFrame() 主要用于统计和时序判断,并不等价于"只要 miss 就立即 return false"。
4.2 事务从 Binder 队列进入 RequestedLayerState

新建 Layer 必须在 flush 前入册,所以完整顺序是:
text
SurfaceFlinger::setTransactionState
→ TransactionHandler::queueTransaction // Binder 线程入无锁队列
SurfaceFlinger::updateLayerSnapshots
→ collectTransactions // 按 applyToken 归入 pending queues
→ LayerLifecycleManager::addLayers // 先注册本批新 Layer
→ flushTransactions // readiness / barrier / present time
→ LayerLifecycleManager::applyTransactions
→ RequestedLayerState::merge // 合并 layer_state_t,设置 changes
applyToken 保证同一 token 队列内顺序;barrier、buffer readiness 和期望呈现时间可以让队头事务继续等待。merge() 同时保留原始 what 位和更粗粒度的 RequestedLayerState::Changes,供增量更新使用。
4.3 更新层级图,再生成 LayerSnapshot

cpp
mLayerHierarchyBuilder.update(mLayerLifecycleManager);
frontend::LayerSnapshotBuilder::Args args{
.root = mLayerHierarchyBuilder.getHierarchy(),
.layerLifecycleManager = mLayerLifecycleManager,
.displays = mFrontEndDisplayInfos,
// metadata / blur / shadow / generic metadata ...
};
mLayerSnapshotBuilder.update(args);
LayerHierarchyBuilder根据parentId/relativeParentId/ mirror 边更新场景图,并以 Z 序遍历。LayerSnapshotBuilder为遍历路径创建或增量更新快照,继承父层的 alpha、transform、crop、metadata 等状态。
几何计算的核心关系如下:
cpp
snapshot.geomLayerTransform = parentSnapshot.geomLayerTransform * snapshot.localTransform;
snapshot.geomLayerBounds = requested.externalTexture ? snapshot.bufferSize.toFloatRect()
: parentBounds;
snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(snapshot.geomLayerCrop);
snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds);
此时产出的是后端合成可消费的本帧快照,不是已经画好的像素。
4.4 锁定本帧 buffer

updateLayerSnapshots() 随后对已准备好帧或需释放 buffer 的 Layer 调用 Layer::latchBufferImpl():
cpp
if (!layer->hasReadyFrame() && !willReleaseBufferOnLatch) continue;
layer->latchBufferImpl(recomputeVisibleRegions, latchTime,
expectedPresentTimeNs, bgColorOnly);
latchBufferImpl() 依次处理 sideband stream;在策略要求时检查 acquire fence;用 updateTexImage() 记录 latch/acquire 时序和 on-commit callback;再由 gatherBufferInfo() 收集 buffer、fence、frame number、buffer transform 和 dataspace。buffer 尺寸、crop 或 transform 变化还会要求重算 visible region。
例外:
Layer::fenceHasSignaled()在enableLatchUnsignaledConfig不是Disabled时会允许锁定未 signal 的 acquire fence。因此"acquire fence 未 signal 必然不 latch"不是 Android 16 所有配置下的绝对规则。
4.5 commit 的输出
commit 结束时,RequestedLayerState / hierarchy / snapshots 已更新,可用新 buffer 已 latch,on-commit 回调可发送,刷新率选择可使用新状态。其返回值决定 Scheduler 是否继续调用 composite()。
5. 阶段 C:composite 组装合成输入
SurfaceFlinger::composite() 组装输入、执行 CompositionEngine,并在 present 后完成统计和回调:
text
1. 填充 CompositionRefreshArgs
- color setting / frame interval / scheduled frame time
- updatingGeometryThisFrame / updatingOutputGeometryThisFrame
- frameTargets / bufferIdsToUncache
2. addOutputsToRefreshArgs
- 物理屏通常进主线程
- 符合条件的 GPU 虚拟屏可 offload
3. addLayerSnapshotsToCompositionArgs
4. prepareLayersForComposition
- Layer::onPreComposition
- 为 release fence 建立 future/promise
5. CompositionEngine::present
6. onCompositionPresented / callbacks / TimeStats / power hint
CompositionRefreshArgs 是前端到合成引擎的帧级边界:args.layers 是 LayerFE 序列,args.outputs 是本帧要处理的合成目标。
6. 阶段 D:CompositionEngine 协调 Output
CompositionEngine::present() 的执行顺序:
cpp
preComposition(args);
LayerFESet latchedLayers;
for (const auto& output : args.outputs) output->prepare(args, latchedLayers);
offloadOutputs(args.outputs);
for (const auto& output : args.outputs) presentFutures.push_back(output->present(args));
for (auto& future : presentFutures) future.get();
postComposition(args);
| 步骤 | 作用 |
|---|---|
preComposition |
LayerFE 处理帧前状态,汇总是否需再次 update |
Output::prepare |
按屏重建可见 OutputLayer,计算 coverage/dirty region,处理 uncache |
offloadOutputs |
HWC 支持时允许多屏 present 并行 |
Output::present |
各屏完成策略、GPU/HWC 合成、present 和 Layer 释放 |
postComposition |
为没有在任何 Output 呈现的已 latch Layer 补齐 release-fence promise |
6.1 Output::prepare:从 LayerFE 到可见 OutputLayer

rebuildLayerStacks() 从前到后遍历层(对已按 Z 序的 args.layers 使用 reversed()),累积上方层 coverage:
cpp
coveredRegion = coverage.aboveCoveredLayers.intersect(visibleRegion);
coverage.aboveCoveredLayers.orSelf(visibleRegion);
visibleRegion.subtractSelf(coverage.aboveOpaqueLayers);
if (layerFEState->contentDirty) {
dirty = visibleRegion | oldVisibleRegion;
} else {
const Region newExposed = visibleRegion - coveredRegion;
const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
dirty = (visibleRegion & oldCoveredRegion) | (newExposed - oldExposed);
}
coverage.aboveOpaqueLayers.orSelf(opaqueRegion);
visibleRegion:本层足迹减去上方不透明层;被半透明层覆盖的区域仍可见。coveredRegion:被上方所有可见区域覆盖的部分,包含半透明覆盖。opaqueRegion:在可安全判定时,本层完全遮挡下方的区域。dirtyRegion:内容变化、新暴露或几何变化需重画的区域。
7. 阶段 E:单屏 Output 合成与上屏

7.1 真实执行顺序
text
updateColorProfile
→ updateCompositionState
→ planComposition
→ writeCompositionState
→ setColorTransform
→ beginFrame
→ prepareFrame / prepareFrameAsync
→ devOptRepaintFlash
→ finishFrame
→ presentFrameAndReleaseLayers [可 offload]
→ renderCachedSets
beginFrame() 设置 mMustRecompose。即使不需重画 client target,物理屏/HWC 也可能需继续状态机,所以不能把"脏区为空"直接等同于整个 present 跳过。
7.2 计算每层在该屏上的状态
OutputLayer::updateCompositionState() 写入:
cpp
state.displayFrame = calculateOutputDisplayFrame();
state.sourceCrop = calculateOutputSourceCrop(internalDisplayRotationFlags);
state.bufferTransform = calculateOutputRelativeBufferTransform(...);
同时计算 dataspace、HDR/SDR dimming、white point、LUT,并根据安全显示、无效 transform、色域支持、调试开关和 LayerFE 状态标记 forceClientComposition。
7.3 先写 HWC 请求,再 validate 定最终分工

writeCompositionState() 遍历 Z 序 OutputLayer,把 displayFrame / sourceCrop / bufferTransform / z、blend/alpha/dataspace/HDR/LUT、buffer/fence 和请求的 composition type 翻译成 HWC2::Layer 命令。这一步只是填写 Composer 命令,还没有最终上屏。
prepareFrame() 通过 Display::chooseCompositionStrategy() 进入 HWComposer::getDeviceCompositionChanges()。HWC validate 可要求某些层从 DEVICE 改为 CLIENT,applyCompositionStrategy() 把最终结果写回 OutputLayer。
某种效果是否必然走 GPU 取决于 Layer 状态、HWC 能力和 validate 结果。不能把"有圆角"简单写成"必然 CLIENT";当前前端显式强制 CLIENT 的效果包括 shadow、stretch、edge extension、border/box shadow 等,还有输出/HWC 限制。
7.4 CLIENT 层由 RenderEngine 合成为 client target

text
dequeueRenderBuffer
→ composeSurfaces
├─ generateClientCompositionDisplaySettings
├─ generateClientCompositionRequests
│ └─ LayerFE::prepareClientComposition
└─ RenderEngine::drawLayers(..., clientTarget, acquireFence)
→ RenderSurface::queueBuffer(GPU-fence)
composeSurfaces() 在 usesClientComposition == false 时直接返回;有 CLIENT 层时,RenderEngine 按 Z 序画到一块 client target。该目标缓冲对 HWC 是一个整体输入,GPU 完成 fence 随 queueBuffer() 成为 HWC 使用它之前的等待条件。
7.5 HWC present,再设置 release fence
cpp
hwc.presentAndGetReleaseFences(halDisplayId, earliestPresentTime);
fences.presentFence = hwc.getPresentFence(halDisplayId);
for (const auto* layer : getOutputLayersOrderedByZ()) {
fences.layerFences.emplace(hwcLayer,
hwc.getLayerReleaseFence(halDisplayId, hwcLayer));
}
presentFrameAndReleaseLayers() 先取 HWC layer release fence。如果本帧使用 client composition,还会把相关 Layer 的释放条件与 client-target acquire fence 合并,然后通过 LayerFE::setReleaseFence() 完成之前建立的 promise。
8. fence 如何串起整帧
text
App/producer 写 buffer
└─ acquire fence ──→ Layer latch / HWC 或 GPU 读取前等待
RenderEngine 写 client target
└─ GPU completion fence ──→ client target 的 acquire fence
HWC present
├─ present fence ──→ FrameTimeline / Scheduler 时序
└─ per-layer release fence ──→ 生产者何时可复用旧 buffer
| fence | 谁生产 | 保护什么 |
|---|---|---|
| buffer acquire fence | App/GPU 生产者 | 消费者不在 buffer 写完前读取 |
| client target acquire fence | RenderEngine | HWC 不在 GPU 合成完成前扫描 client target |
| present fence | HWC | 描述 display 呈现完成时序,也用于帧时序模型 |
| layer release fence | HWC,必要时与 client-target fence 合并 | 上一个 Layer buffer 何时不再被消费 |
fence 是可传递、可合并的同步原语。一个 fence 已经被交给下游,不代表它此刻已 signal。
9. 帧结束、回调与下一帧
SurfaceFlinger::onCompositionPresented() 在提交 present 后:
- 从
HWComposer取各物理屏 present fence,设置到FrameTargeter。 - 将 pacesetter present fence 交给 transaction callback 和 FrameTimeline。
- 更新 Layer 的 presented/jank 信息,调用
releasePendingBuffer()。 - 发送非 on-commit-only 的 transaction completed callback。
- 将 present fence 送回 Scheduler,供 VSync 模型、backpressure 和统计使用。
回到 Scheduler::onFrameSignal() 后,FrameTargeter::endFrame() 记录本帧 CompositeResult。如果 CompositionEngine 还需再 update,或期间到达了新 transaction/buffer,Scheduler 会安排下一帧。
10. 重要分支与常见误解
10.1 合成策略预测
Output::present() 可走 prepareFrameAsync():用上一帧 HWC changes 预测 GPU 工作,同时异步 validate。预测未命中时应用新 changes,利用已 dequeue 的 buffer 重做正确合成。不应把该路径写成"一般永远不开"。
10.2 present offload 和多屏
CompositionEngine::offloadOutputs() 和 Output::presentFrameAndReleaseLayersAsync() 可以把支持 multi-threaded present 的 HWC 调用移出主线程。符合条件的 GPU 虚拟屏还可由 SurfaceFlinger::offloadGpuCompositedDisplays() 在后台 CompositionEngine 处理。
10.3 GPU 和 HWC 不是二选一
- 全 DEVICE:层都交给 HWC。
- 混合:CLIENT 层由 GPU 合成为 client target,再与 DEVICE 层一起交给 HWC。
- 以 CLIENT 为主:大部分或全部层进 client target,HWC 仍负责 display present。
10.4 不是每个帧信号都产生新画面
commit() 可因 mode-set pending、backpressure、没有必要合成的变化或 boot 阶段返回 false。即使进入 composite(),某个 Output 也可能复用 client composition 或不重画 GPU 目标。
总结
SurfaceFlinger 合成一帧的核心是:Scheduler 给出时序目标;commit 将 transaction、层级、快照和 buffer 收敛为本帧状态;composite 把它们分发给各 Output;HWC validate 决定 GPU/HWC 分工;RenderEngine 仅生成需要的 client target;HWC 完成 present;最后用 present/release fence 关闭本帧时序和 buffer 生命周期。