以下是Android 14中SurfaceFlinger::composite
函数的逐行解析,详细说明其逻辑和关键代码的作用:
1. 函数签名与性能跟踪
void SurfaceFlinger::composite(TimePoint frameTime, VsyncId vsyncId)
FTL_FAKE_GUARD(kMainThreadContext) {
ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId.value);
- 功能:函数入口,声明合成操作,记录性能跟踪信息。
FTL_FAKE_GUARD
:标记当前代码段在kMainThreadContext
线程上下文中运行(调试用)。ATRACE_FORMAT
:记录函数名和vsyncId
到性能跟踪系统(如Perfetto)。
2. 初始化合成参数
compositionengine::CompositionRefreshArgs refreshArgs;
const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
refreshArgs.outputs.reserve(displays.size());
std::vector<DisplayId> displayIds;
- 功能:初始化合成引擎需要的参数
refreshArgs
。 mDisplays
:获取当前所有显示设备(受mStateLock
保护)。outputs.reserve
:预分配内存,避免动态扩容。displayIds
:记录所有显示设备的ID。
3. 遍历显示设备
for (const auto& [_, display] : displays) {
bool dropFrame = false;
if (display->isVirtual()) {
Fps refreshRate = display->getAdjustedRefreshRate();
using fps_approx_ops::operator>;
dropFrame = (refreshRate > 0_Hz) && !mScheduler->isVsyncInPhase(frameTime, refreshRate);
}
if (!dropFrame) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
display->tracePowerMode();
displayIds.push_back(display->getId());
}
mPowerAdvisor->setDisplays(displayIds);
- 功能:遍历所有显示设备,决定是否丢弃当前帧。
- 虚拟显示:检查是否需要根据VSync相位丢弃帧(避免合成时机不匹配)。
tracePowerMode
:记录显示设备的电源状态(用于调试或电源管理)。mPowerAdvisor->setDisplays
:通知电源管理模块当前活动的显示设备。
4. 更新图层元数据快照
const bool updateTaskMetadata = mCompositionEngine->getFeatureFlags().test(
compositionengine::Feature::kSnapshotLayerMetadata);
if (updateTaskMetadata && (mVisibleRegionsDirty || mLayerMetadataSnapshotNeeded)) {
updateLayerMetadataSnapshot();
mLayerMetadataSnapshotNeeded = false;
}
- 功能:若启用元数据快照且需要更新,生成图层元数据快照。
kSnapshotLayerMetadata
:合成引擎的特性标志,表示需要元数据快照。mVisibleRegionsDirty
:可见区域是否变化(脏标记)。
5. 处理边框渲染
if (DOES_CONTAIN_BORDER) {
refreshArgs.borderInfoList.clear();
mDrawingState.traverse([&refreshArgs](Layer* layer) {
if (layer->isBorderEnabled()) {
compositionengine::BorderRenderInfo info;
info.width = layer->getBorderWidth();
info.color = layer->getBorderColor();
layer->traverse(LayerVector::StateSet::Drawing, [&info](Layer* ilayer) {
info.layerIds.push_back(ilayer->getSequence());
});
refreshArgs.borderInfoList.emplace_back(std::move(info));
}
});
}
- 功能:若启用边框渲染,收集所有启用边框的图层信息。
- 遍历所有图层,收集边框宽度、颜色及其子图层的ID。
6. 清理待释放缓冲区
refreshArgs.bufferIdsToUncache = std::move(mBufferIdsToUncache);
- 功能:将待释放的缓冲区ID传递给合成引擎(避免内存泄漏)。
7. 收集有排队帧的图层
refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
for (auto layer : mLayersWithQueuedFrames) {
if (auto layerFE = layer->getCompositionEngineLayerFE())
refreshArgs.layersWithQueuedFrames.push_back(layerFE);
}
- 功能:将需要合成的图层前端(LayerFE)添加到参数中。
mLayersWithQueuedFrames
:当前有未处理帧的图层列表。
8. 颜色管理配置
refreshArgs.outputColorSetting = useColorManagement
? mDisplayColorSetting
: compositionengine::OutputColorSetting::kUnmanaged;
refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace;
refreshArgs.forceOutputColorMode = mForceColorMode;
- 功能:配置颜色空间、数据空间和强制颜色模式。
useColorManagement
:是否启用颜色管理(如HDR)。
9. 几何更新标记
refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty;
refreshArgs.internalDisplayRotationFlags = getActiveDisplayRotationFlags();
- 功能:标记几何信息是否更新(如屏幕旋转、图层位置变化)。
mVisibleRegionsDirty
:可见区域是否变化。mGeometryDirty
:几何信息是否变化(原子变量,交换后重置)。
10. 颜色矩阵更新
if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix;
mDrawingState.colorMatrixChanged = false;
}
- 功能:若颜色矩阵变化,传递新矩阵并重置标记。
11. 调试选项
refreshArgs.devOptForceClientComposition = mDebugDisableHWC;
if (mDebugFlashDelay != 0) {
refreshArgs.devOptForceClientComposition = true;
refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
}
- 功能:调试模式下强制使用GPU合成或模拟脏区域闪烁。
mDebugDisableHWC
:禁用硬件合成(HWC),强制使用GPU。mDebugFlashDelay
:脏区域闪烁延迟(用于可视化调试)。
12. VSync与时间计算
const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period();
if (!getHwComposer().getComposer()->isSupported(
Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
wouldPresentEarly(frameTime, vsyncPeriod)) {
const auto prevVsyncTime = mExpectedPresentTime - vsyncPeriod;
const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
}
- 功能:计算合成的最早提交时间,避免过早提交导致HWC无法处理。
hwcMinWorkDuration
:硬件合成器(HWC)需要的最小工作时间。
13. 时间参数传递
refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
refreshArgs.expectedPresentTime = mExpectedPresentTime.ns();
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
- 功能:传递计划帧时间、预期呈现时间和监听器状态。
14. 调用合成引擎
const auto presentTime = systemTime();
std::vector<std::pair<Layer*, LayerFE*>> layers =
moveSnapshotsToCompositionArgs(refreshArgs, /*cursorOnly=*/false, vsyncId.value);
mCompositionEngine->present(refreshArgs);
moveSnapshotsFromCompositionArgs(refreshArgs, layers);
- 功能:调用合成引擎执行合成操作。
moveSnapshotsToCompositionArgs
:传递图层快照到合成参数。present
:触发合成引擎的present
方法。
15. 处理合成结果
for (auto [layer, layerFE] : layers) {
CompositionResult compositionResult{layerFE->stealCompositionResult()};
layer->onPreComposition(compositionResult.refreshStartTime);
for (auto& [releaseFence, layerStack] : compositionResult.releaseFences) {
Layer* clonedFrom = layer->getClonedFrom().get();
auto owningLayer = clonedFrom ? clonedFrom : layer;
owningLayer->onLayerDisplayed(std::move(releaseFence), layerStack);
}
if (compositionResult.lastClientCompositionFence) {
layer->setWasClientComposed(compositionResult.lastClientCompositionFence);
}
}
- 功能:处理每个图层的合成结果(如释放栅栏、标记合成方式)。
releaseFences
:通知图层可以释放缓冲区。setWasClientComposed
:标记图层是否由GPU合成。
16. 性能统计
mTimeStats->recordFrameDuration(frameTime.ns(), systemTime());
- 功能:记录帧处理时长(从VSync到合成完成)。
17. 电源管理
if (mPowerHintSessionEnabled) {
const auto& previousPresentFence = mPreviousPresentFences[0].fenceTime;
mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(previousPresentFence->getSignalTime()),
TimePoint::now());
mPowerAdvisor->reportActualWorkDuration();
}
- 功能:上报合成耗时,供电源管理模块调整性能策略。
18. 调度后续合成
if (mScheduler->onPostComposition(presentTime)) {
scheduleComposite(FrameHint::kNone);
}
- 功能:根据当前合成结果,决定是否需要立即调度下一次合成。
19. 后处理与清理
postComposition(presentTime);
const bool hadGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu);
mCompositionCoverage.clear();
postComposition
:处理合成后的清理(如释放旧的帧缓冲区)。mCompositionCoverage
:记录合成方式(GPU/HWC)。
20. 合成策略统计
TimeStats::ClientCompositionRecord clientCompositionRecord;
for (const auto& [_, display] : displays) {
const auto& state = display->getCompositionDisplay()->getState();
// ...统计GPU/HWC使用情况
}
mTimeStats->pushCompositionStrategyState(clientCompositionRecord);
- 功能:记录客户端合成策略的统计信息(如预测是否成功)。
21. VSync动态调整
mScheduler->modulateVsync({}, &VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse);
- 功能:根据是否使用GPU合成动态调整VSync周期(如降低延迟)。
22. 重置状态与调试
mLayersWithQueuedFrames.clear();
if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
addToLayerTracing(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value);
}
mVisibleRegionsDirty = false;
- 功能:清空队列、调试跟踪图层状态、重置脏标记。
23. 检查是否需要重新合成
if (mCompositionEngine->needsAnotherUpdate()) {
scheduleCommit(FrameHint::kNone);
}
- 功能:若合成引擎需要再次更新(如异步内容变更),调度新的提交。
24. 电源会话结束
if (mPowerHintSessionEnabled) {
mPowerAdvisor->setCompositeEnd(TimePoint::now());
}
- 功能:记录合成结束时间,用于电源管理模块优化能效。
总结
SurfaceFlinger::composite
是Android图形合成的核心函数,负责:
- 准备参数:收集显示设备、图层、颜色配置等信息。
- 调用合成引擎:通过
CompositionEngine
进行实际合成。 - 处理结果:释放资源、更新状态、统计性能。
- 调度与优化:动态调整VSync、电源管理、调试跟踪。
- 清理与重置:为下一帧合成做准备。
Output::prepare是Android合成引擎中处理每一帧准备阶段的核心函数,其主要作用是为后续的图层合成准备必要的状态和数据。具体流程如下:
1. 重建图层堆栈(rebuildLayerStacks)
- 功能:重新计算可见图层及其覆盖区域,更新输出的脏区和未定义区域。
- 步骤:
- 检查输出状态:若输出未启用或无需更新几何结构(
updatingOutputGeometryThisFrame=false
),则跳过。 - 初始化覆盖状态(CoverageState):记录图层的可见性、覆盖区域、不透明区域等信息。
- 收集可见图层(collectVisibleLayers):
- 倒序遍历图层(从前到后),逐层处理:
- 调用
ensureOutputLayerIfVisible
,确保可见的图层创建对应的OutputLayer
。 - 更新覆盖区域(
coveredRegion
)和脏区(dirtyRegion
)。
- 调用
- 设置释放的图层(
setReleasedLayers
):标记不再使用的图层。 - 最终确定输出层(
finalizePendingOutputLayers
)。
- 倒序遍历图层(从前到后),逐层处理:
- 计算未定义区域:从显示区域中剔除被不透明图层覆盖的部分,得到
undefinedRegion
。 - 合并脏区:将当前帧的脏区合并到输出的
dirtyRegion
中。
- 检查输出状态:若输出未启用或无需更新几何结构(
2. 取消缓冲区缓存(uncacheBuffers)
- 功能:释放不再需要使用的图形缓冲区,避免资源泄漏。
- 步骤:
- 遍历所有输出层(
getOutputLayersOrderedByZ
)。 - 对每个
OutputLayer
调用uncacheBuffers
,传入需要释放的缓冲区ID列表(bufferIdsToUncache
)。
- 遍历所有输出层(
核心逻辑解析
- 可见性计算:通过倒序遍历图层(从最上层到底层),逐层判断可见性,并更新覆盖区域。这确保上层图层会遮挡下层图层,减少无效绘制。
- 脏区优化:通过记录
dirtyRegion
,仅合成发生变化的区域,提升性能。 - 资源管理:通过
uncacheBuffers
释放无效缓冲区,避免内存占用过高。
关键代码段
void Output::prepare(...) {
rebuildLayerStacks(...); // 重建图层堆栈,更新覆盖区域和脏区
uncacheBuffers(...); // 释放不再使用的缓冲区
}
总结
Output::prepare
的作用是为帧合成做准备,核心任务包括:
- 确定可见图层及覆盖区域,优化后续合成范围。
- 管理图形缓冲区资源,释放无效缓存。
这些步骤确保合成引擎高效运行,仅处理必要的内容,减少计算和内存开销。
从代码注释来看,rebuildLayerStacks
的注释提到“Process the layers to determine visibility and coverage”,即处理图层以确定可见性和覆盖范围。因此,初步推测这个函数的主要功能是确定哪些图层在当前输出中是可见的,并计算它们的覆盖区域,从而为后续的合成步骤提供必要的信息。
接下来,我需要逐行分析代码逻辑:
- 函数入口与条件检查:
-
检查输出是否启用(
outputState.isEnabled
)。 -
检查是否需要更新输出几何结构(
refreshArgs.updatingOutputGeometryThisFrame
)。 -
如果任一条件不满足,直接返回,跳过后续处理。这表明只有在需要更新几何结构时才会执行重建图层堆栈的操作。
- 初始化覆盖状态(CoverageState):
-
创建一个
CoverageState
对象,用于跟踪图层的可见性、覆盖区域等信息。 -
根据
refreshArgs.hasTrustedPresentationListener
决定是否排除覆盖层(如状态栏)的影响。
- 收集可见图层(collectVisibleLayers):
-
调用
collectVisibleLayers
函数,逆序遍历图层(从Z轴最高的图层开始),处理每个图层的可见性。 -
对于每个图层,调用
ensureOutputLayerIfVisible
函数,确保可见的图层创建对应的OutputLayer
,并更新覆盖区域和脏区。
- 计算未定义区域(undefinedRegion):
-
初始未定义区域为整个显示区域。
-
通过减去被不透明图层覆盖的区域(
coverage.aboveOpaqueLayers
),得到最终的未定义区域。
- 更新输出状态:
- 将计算得到的未定义区域和脏区保存到输出状态中,供后续合成步骤使用。
在分析过程中,需要确认以下关键点:
-
逆序遍历图层的原因:逆序遍历(从最上层到底层)可以确保上层图层的覆盖区域正确计算,避免下层图层被错误地认为可见。
-
覆盖区域和脏区的计算:通过累加各图层的可见区域和覆盖区域,确定哪些区域需要重新合成。
-
未定义区域的作用:未定义区域表示未被任何不透明图层覆盖的部分,可能需要填充默认颜色或进行透明合成。
此外,需要注意代码中的一些细节:
-
coverage.aboveCoveredLayers
和coverage.aboveOpaqueLayers
分别记录累积的覆盖区域和不透明区域。 -
dirtyRegion
用于标记需要重新绘制的区域,优化合成性能。
在理解过程中,可能会遇到一些疑问,例如:
-
collectVisibleLayers
的具体实现:需要查看collectVisibleLayers
函数,了解如何处理每个图层的可见性和覆盖区域。 -
ensureOutputLayerIfVisible
的作用:该函数可能负责创建或更新OutputLayer
,确保图层在输出中的正确表示。 -
finalizePendingOutputLayers
的功能:可能用于确认所有待处理的输出层已准备就绪。
通过逐步分析代码逻辑和验证每个步骤的作用,可以全面理解rebuildLayerStacks
的功能及其在合成流程中的重要性。
Output::rebuildLayerStacks
是 Android 合成引擎中负责 重建图层堆栈并计算可见性与覆盖区域 的核心函数。其作用是为当前输出(如屏幕)确定哪些图层可见、如何被覆盖,并更新相关合成状态(如脏区、未定义区域)。以下是其代码逻辑的详细解析:
1. 函数入口与条件检查
- 条件判断:
- 检查输出是否启用(
outputState.isEnabled
)。 - 检查是否需要更新输出几何结构(
refreshArgs.updatingOutputGeometryThisFrame
)。 - 若任一条件不满足,直接返回。仅当输出启用且需要更新几何结构时,才会执行后续操作。
- 检查输出是否启用(
2. 初始化覆盖状态(CoverageState)
- 创建
CoverageState
对象,包含以下关键字段:aboveCoveredLayers
:累积的覆盖区域(包括透明和半透明图层)。aboveOpaqueLayers
:累积的不透明区域(完全遮挡下层)。dirtyRegion
:需重新合成的脏区。latchedLayers
:已处理的图层快照(避免重复处理同一图层)。aboveCoveredLayersExcludingOverlays
(可选):排除覆盖层(如状态栏)的覆盖区域。
3. 收集可见图层(collectVisibleLayers)
- 逆序遍历图层(从 Z 轴最高/最上层开始):
ensureOutputLayerIfVisible
:对每个图层执行以下操作:- 过滤非当前输出的图层:通过
includesLayer
判断图层是否属于当前输出(如多屏场景)。 - 检查可见性:若图层标记为不可见(
layerFEState->isVisible
为假),跳过。 - 计算可见区域:
- 根据图层的变换(
geomLayerTransform
)和边界(geomLayerBounds
),计算其在屏幕上的可见区域(visibleRegion
)。 - 若图层有阴影(
shadowRadius > 0
),扩展可见区域并计算阴影区域(shadowRegion
)。
- 根据图层的变换(
- 处理透明区域:
- 若图层非不透明(
isOpaque = false
),根据transparentRegionHint
裁剪透明区域。
- 若图层非不透明(
- 更新覆盖区域:
coveredRegion
:当前图层被上层覆盖的区域。aboveCoveredLayers
累积所有图层的覆盖区域。aboveOpaqueLayers
累积所有不透明图层的覆盖区域。
- 计算脏区:
- 若图层内容变化(
contentDirty
),标记整个可见区域为脏区。 - 否则,计算因覆盖关系变化导致的暴露区域(
newExposed - oldExposed
)。
- 若图层内容变化(
- 创建或复用
OutputLayer
:- 若图层可见,创建或复用对应的
OutputLayer
,并保存其可见性、覆盖区域等信息。
- 若图层可见,创建或复用对应的
- 过滤非当前输出的图层:通过
4. 计算未定义区域(undefinedRegion)
- 初始范围:
undefinedRegion
初始为整个显示区域(outputState.displaySpace.getBoundsAsRect()
)。
- 剔除被不透明图层覆盖的区域:
undefinedRegion.subtractSelf(tr.transform(coverage.aboveOpaqueLayers));
- 最终
undefinedRegion
表示未被任何不透明图层覆盖的区域,可能需要填充默认背景或进行透明合成。
- 最终
5. 更新输出状态
- 合并脏区:
- 将当前帧的脏区(
coverage.dirtyRegion
)合并到全局脏区(outputState.dirtyRegion
)。
outputState.dirtyRegion.orSelf(coverage.dirtyRegion);
- 将当前帧的脏区(
- 保存未定义区域:
outputState.undefinedRegion = undefinedRegion;
核心作用总结
- 可见性筛选:
- 通过逆序遍历确定哪些图层在当前输出中可见。
- 覆盖关系计算:
- 动态更新各图层的覆盖区域,避免冗余合成。
- 脏区标记:
- 通过
dirtyRegion
标记需要重新合成的区域,优化性能。
- 通过
- 资源管理:
- 复用或创建
OutputLayer
,减少内存分配开销。
- 复用或创建
关键优化点
- 逆序遍历:确保上层图层优先处理,正确计算遮挡关系。
- 脏区合并:通过
orSelf
操作高效合并区域,减少全屏重绘。 - 未定义区域计算:避免对完全覆盖区域进行无效合成。
通过 rebuildLayerStacks
,Android 合成引擎能够高效管理图层的可见性、覆盖关系和资源状态,为后续的合成操作(如 GPU/硬件合成)奠定基础。
接下来,我需要仔细阅读collectVisibleLayers
的代码。函数参数是refreshArgs
和coverage
,其中coverage
是一个CoverageState
对象。函数内部有一个逆序循环遍历refreshArgs.layers
,也就是从最上层的图层开始处理。对于每个图层,调用了ensureOutputLayerIfVisible
,然后调用setReleasedLayers
和finalizePendingOutputLayers
。
首先,ensureOutputLayerIfVisible
这个函数名看起来是确保如果图层可见的话,就创建一个对应的OutputLayer
。这里可能涉及到判断图层的可见性,比如检查图层是否属于当前输出、是否被隐藏、是否有透明区域等。然后,setReleasedLayers
可能用于标记不再需要的图层,以便后续释放资源。finalizePendingOutputLayers
可能是确认所有的OutputLayer
已经处理完毕。
在ensureOutputLayerIfVisible
内部,首先检查图层是否已经被快照处理过,如果没有,则加入latchedLayers
集合。接着判断图层是否属于当前输出,如果不是则返回。然后获取图层的前端状态layerFEState
,如果图层不可见则返回。接下来计算opaqueRegion
、visibleRegion
、coveredRegion
等区域,并更新覆盖状态。
在计算可见区域时,考虑了图层的变换、阴影、透明度等因素。例如,如果有阴影的话,需要扩展可见区域。然后处理透明区域,如果图层不是不透明的,需要根据transparentRegionHint
进行调整。接着计算被上层覆盖的区域,并更新累积的覆盖区域aboveCoveredLayers
和aboveOpaqueLayers
。
脏区的计算也很重要,如果图层内容有变化(contentDirty
),则整个可见区域都是脏区;否则根据新旧覆盖区域的差异计算需要重新绘制的区域。最后,如果图层可见,就创建或复用OutputLayer
,并保存相关区域信息。
不过,我在理解具体的区域计算和覆盖关系时还是有些困惑,比如coveredRegion
和aboveCoveredLayers
是如何具体更新的,以及如何判断一个区域是否被覆盖。可能需要进一步查看相关的Region操作函数,比如intersect
、subtractSelf
等,来理解这些区域是如何组合的。
另外,setReleasedLayers
在collectVisibleLayers
中被调用,但具体的实现在哪里呢?在代码中,setReleasedLayers
的基类实现是空的,可能子类会有具体实现,但当前代码中可能只是标记需要释放的图层。
总结来说,collectVisibleLayers
的主要作用是遍历所有图层,计算它们的可见区域、覆盖关系,并更新脏区,以便后续的合成操作。同时,管理OutputLayer
的创建和释放,确保只有可见的图层被处理。
Output::collectVisibleLayers
是 Android 合成引擎中用于 逐层筛选可见图层并计算覆盖关系 的核心函数。其作用是通过逆序遍历所有图层(从最上层开始),确定每个图层的可见性、覆盖区域和脏区,并生成或复用对应的 OutputLayer
。以下是其代码逻辑的详细解析:
1. 函数入口与参数
- 参数:
refreshArgs
:包含当前帧的合成参数(如图层列表、是否需要更新几何结构等)。coverage
:CoverageState
对象,用于累积图层的覆盖状态(如脏区、不透明区域等)。
2. 逆序遍历图层
- 从 Z 轴最高(最上层)开始处理:
for (auto layer : reversed(refreshArgs.layers)) { ensureOutputLayerIfVisible(layer, coverage); }
- 逆序确保上层图层优先处理,正确计算遮挡关系。
3. 处理单个图层(ensureOutputLayerIfVisible)
- 步骤:
- 图层快照检查:
- 若图层未被处理过(
latchedLayers
集合中不存在),则将其加入集合,避免重复处理。
- 若图层未被处理过(
- 过滤非当前输出的图层:
- 通过
includesLayer(layerFE)
判断图层是否属于当前输出(如多屏场景)。
- 通过
- 检查可见性:
- 若图层标记为不可见(
layerFEState->isVisible
为false
),跳过后续处理。
- 若图层标记为不可见(
- 计算可见区域:
- 根据图层的变换(
geomLayerTransform
)和边界(geomLayerBounds
),计算其在屏幕上的visibleRect
。 - 若有阴影(
shadowRadius > 0
),扩展可见区域并计算shadowRegion
。
- 根据图层的变换(
- 处理透明区域:
- 若图层非不透明(
isOpaque = false
),根据transparentRegionHint
裁剪透明区域。
- 若图层非不透明(
- 计算覆盖区域:
coveredRegion
:当前图层被上层覆盖的区域(通过coverage.aboveCoveredLayers.intersect(visibleRegion)
计算)。coverage.aboveCoveredLayers
累积所有图层的覆盖区域(包括透明和半透明)。coverage.aboveOpaqueLayers
累积所有不透明图层的覆盖区域。
- 更新脏区:
- 若图层内容变化(
contentDirty
),标记整个可见区域为脏区。 - 否则,通过新旧覆盖区域差异计算暴露区域(
newExposed - oldExposed
)。
- 若图层内容变化(
- 创建或复用 OutputLayer:
- 若图层可见,创建或复用对应的
OutputLayer
,保存其可见区域、覆盖区域等信息。
- 若图层可见,创建或复用对应的
- 图层快照检查:
4. 最终处理
- 标记释放的图层:
setReleasedLayers(refreshArgs);
- 将不再需要的图层加入
mReleasedLayers
,后续释放资源。
- 将不再需要的图层加入
- 确认 OutputLayer 状态:
finalizePendingOutputLayers();
- 确保所有
OutputLayer
已处理完毕,更新输出状态。
- 确保所有
核心作用总结
- 可见性筛选:
- 通过图层属性(可见性、所属输出、透明度)过滤不可见图层。
- 覆盖关系计算:
- 动态更新每层的覆盖区域,避免冗余合成。
- 脏区标记:
- 通过
dirtyRegion
标记需要重新合成的区域,优化性能。
- 通过
- 资源管理:
- 复用或创建
OutputLayer
,减少内存分配开销。 - 标记待释放的图层,防止内存泄漏。
- 复用或创建
关键代码段
// 逆序遍历图层
for (auto layer : reversed(refreshArgs.layers)) {
ensureOutputLayerIfVisible(layer, coverage);
}
// 计算脏区示例
if (layerFEState->contentDirty) {
dirty = visibleRegion; // 整个可见区域为脏区
} else {
// 计算新旧暴露区域的差异
dirty = (visibleRegion & oldCoveredRegion) | (newExposed - oldExposed);
}
coverage.dirtyRegion.orSelf(dirty); // 合并到全局脏区
优化点
- 逆序处理:确保上层图层优先计算,正确反映遮挡关系。
- 区域操作:通过
Region
类的高效集合操作(intersect
、subtractSelf
等),减少计算复杂度。 - 脏区合并:仅标记实际变化的区域,避免全屏重绘。
通过 collectVisibleLayers
,Android 合成引擎能够高效管理图层的可见性和覆盖关系,为后续的 GPU/硬件合成提供精确的输入数据。
Output::present()
是 Android SurfaceFlinger 中负责 将图层合成为最终帧并提交到显示设备 的核心函数。其执行流程可分解为以下关键步骤:
1. 初始化阶段
1.1 updateColorProfile(refreshArgs)
- 作用: 根据当前显示设备的特性(如色域、HDR 支持)更新颜色配置。
- 细节: 可能调整输出色彩空间(如 sRGB、Display P3),确保颜色准确性与设备匹配。
1.2 updateCompositionState(refreshArgs)
- 作用: 更新所有图层的合成状态。
- 细节:
- 遍历所有 Layer,计算可见区域、透明度、Z 轴顺序等属性。
- 处理动画或变换(如旋转、缩放)后的状态。
1.3 planComposition()
- 作用: 制定合成策略,决定使用 GPU合成 还是 硬件合成器(如 Overlay)。
- 细节:
- 评估各图层是否适合硬件加速(如视频解码层),减少 GPU 负载。
- 确定是否需要分块渲染(Tiling)以优化大纹理处理。
2. 状态提交与预处理
2.1 writeCompositionState(refreshArgs)
- 作用: 将合成计划写入底层硬件合成器(如 HWC)。
- 细节: 通过 HWC HAL 接口传递图层信息(位置、混合模式等),让硬件进行优化合成。
2.2 setColorTransform(refreshArgs)
- 作用: 应用全局颜色变换矩阵。
- 细节: 实现夜间模式、色彩校正等效果,调整最终输出的颜色值。
2.3 beginFrame()
- 作用: 启动新帧的渲染流程。
- 细节:
- 初始化 GPU 上下文(如 EGL/Vulkan)。
- 分配或锁定帧缓冲区,准备接收渲染数据。
3. 帧准备策略
3.1 GpuCompositionResult 与 prepareFrame
- predictCompositionStrategy: 判断是否可预测合成策略(如静态 UI)。
- 异步准备(prepareFrameAsync()): 若预测成功,使用异步线程生成 GPU 合成结果,减少主线程阻塞。
- 同步准备(prepareFrame()): 若预测失败(如动态内容),同步执行避免竞态条件。
4. 调试与帧提交
4.1 devOptRepaintFlash(refreshArgs)
- 作用: 开发者选项功能,闪烁标记被重绘的区域。
- 细节: 通过叠加半透明色块帮助识别无效绘制(过度重绘问题)。
4.2 finishFrame()
- 作用: 结束帧处理,提交合成结果。
- 细节:
- 合并 GPU/HWC 合成结果。
- 触发 VSync 同步信号,确保帧率稳定。
4.3 postFramebuffer()
- 作用: 将最终帧提交到显示设备。
- 细节:
- 通过 DRM/KMS 或 SurfaceFlinger 的 BufferQueue 推送帧数据。
- 处理多屏显示(如主屏、外接显示器)的分发逻辑。
5. 缓存优化
5.1 renderCachedSets(refreshArgs)
- 作用: 渲染并缓存可复用的合成结果(如静态背景)。
- 细节: 减少重复合成开销,提升后续帧率,尤其适用于界面变化较少的场景。
总结:合成流水线
Output::present()
通过 状态更新 → 策略规划 → 异步/同步执行 → 提交显示 的流程,平衡性能与正确性。其核心优化点包括:
- 硬件加速: 利用 HWC 减少 GPU 负载。
- 异步处理: 预测策略降低延迟。
- 缓存复用: 避免冗余计算,提升流畅度。
该函数直接影响了 Android 系统的显示性能、功耗及视觉效果,是图形栈的关键路径。
Planner::plan()
是 Android SurfaceFlinger 中 图层合成策略规划 的核心函数,其作用是通过 追踪图层状态变化、优化合成策略 来减少 GPU 负载并提升合成效率。以下是其代码逻辑的详细解析:
1. 初始化与追踪移除的图层
std::unordered_set<LayerId> removedLayers;
std::transform(mPreviousLayers.begin(), ..., [](const auto& layer) { return layer.first; });
- 目的:初始化
removedLayers
,假设所有上一帧的图层都可能被移除。 - 实现:通过
std::transform
将上一帧的图层 ID(mPreviousLayers
)存入removedLayers
,后续再根据当前帧的图层状态剔除仍存在的图层,最终剩余的即为真正被移除的图层。
2. 遍历当前帧图层
for (auto layer : layers) {
LayerId id = layer->getLayerFE().getSequence();
// 处理已有图层或新增图层
}
- 目的:遍历当前帧的所有图层,更新或创建对应的图层状态。
2.1 更新已有图层状态
LayerState& state = layerEntry->second;
ftl::Flags<LayerStateField> differences = state.update(layer);
- 作用:比较当前图层与上一帧的差异。
differences
:标记变化的字段(如Buffer
、Geometry
、Alpha
等)。- 计数器管理:
- 无变化:递增
framesSinceBufferUpdate
,用于判断图层是否可缓存。 - Buffer 变化:重置计数器(说明内容更新,需重新合成)。
- 无变化:递增
2.2 处理新增图层
LayerState state(layer);
mPreviousLayers.emplace(id, std::move(state));
- 作用:为新增图层创建
LayerState
并存入mPreviousLayers
。
2.3 维护当前图层 ID 列表
currentLayerIds.emplace_back(id);
removedLayers.erase(id); // 剔除未移除的图层
- 目的:构建当前帧的图层 ID 列表,并更新
removedLayers
以反映实际被移除的图层。
3. 构建当前帧图层状态
mCurrentLayers.clear();
std::transform(currentLayerIds.cbegin(), ..., [this](LayerId id) { return &mPreviousLayers.at(id); });
- 作用:将当前帧的图层指针存入
mCurrentLayers
,并重置overrideInfo
(可能用于调试或覆盖合成参数)。
4. 哈希计算与图层扁平化
const NonBufferHash hash = getNonBufferHash(mCurrentLayers);
mFlattenedHash = mFlattener.flattenLayers(...);
const bool layersWereFlattened = (hash != mFlattenedHash);
- 目的:优化合成策略,减少 GPU 负载。
NonBufferHash
:基于图层的 非缓冲属性(位置、透明度、变换矩阵等)生成的哈希值,用于判断图层状态是否变化。flattenLayers
:合并多个静态或低变化图层为一个(如 UI 背景),减少绘制调用次数。layersWereFlattened
:标记是否发生了扁平化操作,影响后续预测策略。
5. 合成策略预测
if (mPredictorEnabled) {
mPredictedPlan = mPredictor.getPredictedPlan(...);
}
- 作用:通过历史数据预测当前帧的最佳合成策略。
- 输入:若图层被扁平化(
layersWereFlattened
),传递空列表(扁平化后无法预测单个图层);否则传递当前图层列表。 - 输出:预测的合成计划(如是否使用硬件合成器、分块渲染等)。
- 输入:若图层被扁平化(
6. 清理无效图层
for (LayerId removedLayer : removedLayers) {
mPreviousLayers.erase(removedLayer);
}
- 目的:从
mPreviousLayers
中删除已被移除的图层,避免内存泄漏和无效状态累积。
核心作用总结
-
状态跟踪:
- 记录图层的新增、更新、移除状态。
- 通过哈希值快速判断图层变化,减少冗余计算。
-
合成优化:
- 扁平化(Flattening):合并静态图层,减少 GPU 绘制调用。
- 预测(Prediction):基于历史数据选择高效合成策略,降低延迟。
-
资源管理:
- 维护
mPreviousLayers
缓存,避免重复创建/销毁图层状态对象。 - 清理无效图层,防止内存泄漏。
- 维护
对性能的影响
- 减少重绘:通过
framesSinceBufferUpdate
识别静态图层,复用缓存结果。 - 降低 GPU 负载:扁平化减少绘制调用,预测策略避免无效计算。
- 适应动态内容:动态图层(如视频)跳过扁平化,确保渲染正确性。
与 Output::present()
的关系
- 前置步骤:
Planner::plan()
在Output::present()
的planComposition()
阶段被调用,为合成提供优化策略。 - 数据传递:生成的
mPredictedPlan
可能影响prepareFrameAsync()
或prepareFrame()
的执行逻辑。
此函数是 Android 图形栈中 平衡性能与正确性 的关键环节,直接影响界面流畅度与功耗。
首先,函数名writeCompositionState
暗示它可能与将合成状态写入硬件相关,比如HWC(Hardware Composer)。之前的讨论中,Planner::plan
负责规划合成策略,而Output::present
中的writeCompositionState
可能是在执行具体的状态写入操作。
接下来,代码开始处检查getState().isEnabled
,如果未启用则直接返回。这说明该函数只在Output启用时执行操作。然后,设置earliestPresentTime
和expectedPresentTime
,这些可能与帧的呈现时间有关,用于同步。
然后,变量peekThroughLayer
和previousOverride
被初始化,可能用于处理某些特殊图层,比如覆盖层或穿透层。includeGeometry
根据refreshArgs.updatingGeometryThisFrame
决定是否包含几何信息,这可能在几何变化时才需要更新。
循环遍历getOutputLayersOrderedByZ()
返回的图层,按Z轴顺序处理每个图层。这里有一个条件判断,如果当前图层是peekThroughLayer
,则跳过,因为可能已经被提前处理过。注释提到“peekThroughLayer was already drawn ahead of its z order”,说明可能存在某种图层覆盖的情况,需要调整绘制顺序。
接下来,检查是否有overrideInfo.buffer
,即是否存在覆盖缓冲区。如果存在,且与之前的覆盖缓冲区相同,则跳过当前图层,避免重复处理。如果是新的覆盖缓冲区,处理peekThroughLayer
,这可能是一个需要提前绘制的底层图层。这里会调用writeStateToHWC
方法,将图层状态写入HWC,并更新哈希值outputLayerHash
。同时,previousOverride
被更新,以便后续图层比较。
对于每个图层,调用writeStateToHWC
,传递参数如是否包含几何信息、是否跳过、Z轴顺序等。如果未跳过,则计算哈希值,用于后续可能的状态验证或缓存。
最后,将outputLayerHash
存入editState().outputLayerHash
,可能用于后续的验证或优化步骤。
总结,writeCompositionState
的作用是将当前帧的图层状态(包括位置、缓冲区、合成方式等)写入HWC,处理特殊的覆盖层情况,并生成哈希值以跟踪状态变化。这有助于HWC高效执行硬件合成,减少不必要的GPU操作,提升性能。
在解析过程中,需要注意几个关键点:
-
peekThroughLayer
的处理逻辑,可能涉及图层覆盖或穿透,比如半透明效果需要先绘制底层图层。 -
overrideInfo
的作用,可能用于调试或特定合成策略的覆盖。 -
哈希值的生成,可能用于检测图层状态变化,优化后续帧的处理。
-
按Z轴顺序处理图层,确保正确的合成顺序。
可能存在的疑问包括:overrideInfo
的具体应用场景,peekThroughLayer
如何被设置,以及哈希值在后续流程中的具体用途。这些可能需要参考其他部分的代码或文档来深入理解,但根据现有代码,可以推断其主要目的是状态提交和优化处理。
Output::writeCompositionState()
是 Android SurfaceFlinger 中 将图层合成状态提交到硬件合成器(HWC) 的核心函数,其作用是通过 按 Z 轴顺序遍历图层、处理特殊覆盖逻辑、生成状态哈希值,确保 HWC 能以最优方式合成帧。以下是其代码逻辑的详细解析:
1. 前置条件与时间戳更新
if (!getState().isEnabled) return;
editState().earliestPresentTime = refreshArgs.earliestPresentTime;
editState().expectedPresentTime = refreshArgs.expectedPresentTime;
- 作用:
- 仅当
Output
(如屏幕)启用时执行。 - 记录帧的 最早提交时间 和 预期显示时间,用于与显示设备的 VSync 信号同步。
- 仅当
2. 初始化变量与图层遍历
compositionengine::OutputLayer* peekThroughLayer = nullptr;
sp<GraphicBuffer> previousOverride = nullptr;
bool includeGeometry = refreshArgs.updatingGeometryThisFrame;
uint32_t z = 0;
bool overrideZ = false;
uint64_t outputLayerHash = 0;
for (auto* layer : getOutputLayersOrderedByZ()) { ... }
- 变量说明:
peekThroughLayer
:标记需要提前绘制的穿透层(如半透明图层下方的背景层)。previousOverride
:缓存上一个覆盖缓冲区,避免重复提交相同内容。includeGeometry
:若当前帧有几何变化(如旋转、缩放),需向 HWC 提交几何信息。z
:当前图层的 Z 轴顺序计数器。overrideZ
:标记是否因穿透层调整了绘制顺序。outputLayerHash
:图层状态哈希值,用于检测合成状态变化。
3. 穿透层(PeekThroughLayer)处理
3.1 跳过已处理的穿透层
if (layer == peekThroughLayer) {
peekThroughLayer = nullptr;
continue;
}
- 场景:若当前图层是之前标记的穿透层,说明其已提前绘制,跳过后续处理。
3.2 覆盖缓冲区(Override Buffer)逻辑
const auto& overrideInfo = layer->getState().overrideInfo;
if (overrideInfo.buffer != nullptr) {
if (previousOverride && overrideInfo.buffer->getBuffer() == previousOverride) {
skipLayer = true; // 跳过重复缓冲区
} else {
// 处理新覆盖缓冲区
if (overrideInfo.peekThroughLayer) {
peekThroughLayer = overrideInfo.peekThroughLayer;
// 提前绘制穿透层
peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ, true);
// 更新哈希值
outputLayerHash ^= hashCombine(...);
}
previousOverride = overrideInfo.buffer->getBuffer();
}
}
- 作用:
- 覆盖缓冲区:可能用于调试(如开发者选项中的“显示更新区域”),或强制覆盖图层内容。
- 穿透层:当某图层需要显示其下方内容时(如半透明 UI),需先绘制穿透层,再绘制覆盖层。例如:
- 半透明状态栏需先绘制其下方的壁纸层(
peekThroughLayer
),再绘制状态栏自身。
- 半透明状态栏需先绘制其下方的壁纸层(
- 哈希计算:将穿透层的状态(指针、Z 值、合成方式等)组合到哈希中,确保状态变化可被追踪。
4. 常规图层提交到 HWC
constexpr bool isPeekingThrough = false;
layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough);
if (!skipLayer) {
outputLayerHash ^= hashCombine(...);
}
writeStateToHWC
:- 将图层的几何信息(位置、裁剪区域)、缓冲区句柄、混合模式等写入 HWC。
- 参数说明:
includeGeometry
:仅当几何变化时提交,避免冗余传输。skipLayer
:若为覆盖缓冲区的重复内容,跳过提交。z
:递增 Z 轴顺序,确保合成顺序正确。overrideZ
:若因穿透层调整了顺序,需标记此状态。
- 哈希计算:将图层状态组合到哈希中,用于后续检测合成策略是否需要更新。
5. 哈希值存储
editState().outputLayerHash = outputLayerHash;
- 作用:通过哈希值快速判断当前帧的图层状态是否与上一帧相同。若哈希未变化,可复用之前的合成策略,减少 HWC 配置开销。
核心作用总结
-
状态提交到 HWC:
- 按 Z 轴顺序提交图层信息,处理穿透层以调整绘制顺序。
- 跳过重复的覆盖缓冲区,减少数据传输。
- 动态控制几何信息提交,优化性能。
-
穿透层处理:
- 确保半透明或特殊效果图层下方的背景正确合成。
- 调整 Z 轴顺序,满足视觉效果需求。
-
状态哈希跟踪:
- 通过
outputLayerHash
快速检测图层状态变化,避免无效的 HWC 重配置。
- 通过
与 HWC 的协作
- 硬件优化:HWC 可能将多个图层直接叠加显示(Overlay),而非通过 GPU 合成,从而降低功耗。
- 条件传递:仅传递变化的图层状态,减少 HWC 处理的数据量。
性能影响
- 减少 HWC 负载:通过跳过重复图层和增量更新几何信息,降低总线带宽占用。
- 正确性保障:穿透层处理确保复杂合成场景(如半透明、动画)的显示正确性。
实际应用场景
- 半透明状态栏:需先绘制壁纸层(穿透层),再绘制状态栏。
- 开发者选项:通过覆盖缓冲区高亮更新区域,帮助识别过度绘制。
- 动态界面:哈希变化触发 HWC 重新配置,适应快速变化的 UI。
此函数是 Android 图形栈中 连接合成策略与硬件执行 的关键环节,直接影响显示效果与能效。