SurfaceFlinger09-合成流程概述

前言

本文基于Android 14源码分析整理

合成是指对多个图层合成到一个最终图层上,并同步给硬件屏幕进行呈现的这个过程。整个过程软硬件协同参与:

  • surfaceflinger:负责图层的管理,包括图层状态管理、GraphicBuffer管理、图层位置、层级、区域的计算等;
  • GPU:GPU负责内容的绘制和合成,可以快速执行复杂的图形计算任务;
  • Hardware composer: 硬件合成器,为了减轻CPU和GPU压力,通过专门的硬件图形处理单元,来提升图形合成效率和系统执行效率;

根据合成方式的不同,在实际执行过程中,可分为三种情况:

  • GPU合成(Client合成):使用GPU对图层进行合成,可处理复杂的图形任务,灵活性强,但功耗高,同时处理复杂图形任务时,可能会带来性能问题;
  • DPU合成(Device合成):使用HWC对图层进行合成,减轻CPU和GPU负载,合成效率高、功耗低,但复杂的图形任务无法实现,一般只支持简单的图形合成任务;
  • Mixed合成:表示在一次合成过程中,GPU合成和DPU合成都有参与,有些图层通过GPU合成,剩余图层则通过DPU合成。

Client合成和Device合成优缺点如下:

优点 缺点
Client合成 1. 计算力强:能处理处理复杂的图形任务和大量图层; 2. 特效强:能实现高级特效,入模糊、阴影、辉光等; 3. 灵活性强:不强依赖硬件,跨平台(shader自定义效果); 1. 性能影响:大量的GPU计算会影响其他任务的调度; 2. 功耗影响:GPU合成会消耗更多的功耗;
Device合成 1. 性能强:通过单独的硬件处理单元,减轻CPU/GPU压力,提升系统整体性能; 2. 高效地处理多个图层的合成,提供较低的延迟和更高的帧率; 3. 功耗低:相比软件合成,能更有效降低功耗; 1. 灵活性差:不同设备可能使用不同的HWC,对合成效果有影响; 2. 合成类型单一:受硬件设计的限制,无法支持所有复杂的图形效果; 3. 图层数量受限:一般直支持图层最大个数有限;

合成过程可以说是surfaceflinger进程的主线任务,在这条任务线上,几乎贯穿了所有的支线任务(Layer创建/销毁、层级更新、GraphicBuffer锁定/释放、屏幕管理......)

在这个过程中,Layer和Display(Output)作为合成工作和于硬件屏幕交互的元数据,将图层数据传递给HWC/GPU进行处理后完成显示。

从本篇文章开始,将通过一系列文档对合成流程进行详细的梳理分析,本篇将首先会对整个合成过程中的关键操作进行基础性的介绍。

当surfaceflinger进程由于收到新内容而被VSYNC信号唤醒后,便执行合成操作。整个合成操作可分为两个大阶段:

  • 提交阶段:主要负责Transaction更新、Layer属性的更新和准备工作;
  • 合成阶段:当提交阶段导致显示内容更改时,进入合成阶段执行合成操作。会将图层信息更新给HWC完成内容的更新与显示。

全部流程如下图所示:

一、提交阶段

在提交阶段,会将收到的Transaction中携带的各类数据进行应用,更新Layer的相关属性。在提交阶段,主要还是以Layer为核心进行操作。

SurfaceFlinger中收到VSYNC信号后,首先是执行commit()方法,对Transaction队列进行过滤提交:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime)
        FTL_FAKE_GUARD(kMainThreadContext) {
    
    ......
    {
        frontend::Update updates;
        // 1. 刷新提交事件
        if (flushTransactions) {
            updates = flushLifecycleUpdates();
        }
        bool transactionsAreEmpty;
        // 2. 更新LayerSnapshot、提交Transaction携带参数
        if (mLegacyFrontEndEnabled) {
            mustComposite |= updateLayerSnapshotsLegacy(vsyncId, updates, flushTransactions,
                                                        transactionsAreEmpty);
        }
        ......
        if (transactionFlushNeeded()) {
            setTransactionFlags(eTransactionFlushNeeded);
        }
        ......
    }

    ......
    return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}

这里对commit()方法进行了大量精简,只关注合成过程中针对Layer处理最为核心的步骤:

  1. 执行flushLifecycleUpdates()方法刷新提交事件;

    1. 过滤Transaction队列,收集满足此次提交条件的Transaction;
    2. 收集新建Layer列表;
    3. 收集待销毁Layer列表;
  2. 执行updateLayerSnapshotsLegacy()方法应用并提交Transaction携带参数;

    1. 提交Mirror Display;
    2. 提交新创建Layer;
    3. 应用Transaction携带参数;
    4. 提交Transaction;
    5. 执行latch Buffer操作;
    6. 更新Layer几何属性。

1.1、刷新提交事件

业务进程在执行完成Transaction::apply()操作后,会将Transaction保存在队列mPendingTransactionQueues中,这步操作在binder线程完成,然后在提交阶段,会遍历该队列,选择符合此次提交的Transaction参与后续合成过程。

Transaction可以支持设置一些具体的条件来指定它的提交时机,比如可以指定期望合成时间(desiredPresentTime)、Buffer barrier、Fence信号等条件,满足后才会允许其参与到合成过程。

完成过滤后,会将符合条件的Transaction列表保持在frontend::Update中参与后续流程。

此外,在这里还会将新建Layer列表和销毁LayerHandle列表也保存在frontend::Update对象中,为后续进行逻辑结构的更新做准备。

关于Layer创建和销毁流程,见:

《SurfaceFlinger06-Layer创建流程》

《SurfaceFlinger07-Layer销毁流程 》

1.2、应用并提交Transaction

完成Transaction的过滤、填充完成frontend::Update对象后,将开始执行updateLayerSnapshotsLegacy()方法应用并提交Transaction携带参数。

1.2.1、提交Mirror Display

通过commitMirrorDisplays()方法,对创建的镜像虚拟屏进行LayerTree的构建。这个过程中,会根据创建时指定的rootLayer,遍历其所有子Layer,并创建对应的镜像Layer。

在Android 14中,在镜像时会创建一个"MirrorRoot" Layer,并对所有被镜像Layer拷贝创建新的Layer:

cpp 复制代码
// frameworks/native/services/surfaceflinger/Layer.cpp

void Layer::updateClonedChildren(const sp<Layer>& mirrorRoot,
                                 std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
    ......
    sp<Layer> clonedFrom = getClonedFrom();
    // 对被镜像Layer的所有子Layer进行拷贝,生成新的Layer
    for (sp<Layer>& child : clonedFrom->mDrawingChildren) {
        sp<Layer> clonedChild = clonedLayersMap[child];
        if (clonedChild == nullptr) {
            clonedChild = child->createClone(mirrorRoot->getSequence());
            clonedLayersMap[child] = clonedChild;
        }
        addChildToDrawing(clonedChild);
        clonedChild->updateClonedChildren(mirrorRoot, clonedLayersMap);
    }
}

而在Android 15上开始,对Layer结构进行了优化,通过图结构的方式,不再拷贝创建新Layer对象,而是直接创建一个Mirror Root节点后建立镜像关系:

cpp 复制代码
// frameworks/native/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp

void LayerHierarchyBuilder::updateMirrorLayer(RequestedLayerState* layer) {
    LayerHierarchy* hierarchy = getHierarchyFromId(layer->id);
    ......
    // layer->mirrorIds中保存整个LayerStack的镜像layer
    for (uint32_t mirrorId : layer->mirrorIds) {
        // 将被镜像layer对应添加到hierarchy的mChildren列表中,关系为Mirror
        hierarchy->addChild(getHierarchyFromId(mirrorId), LayerHierarchy::Variant::Mirror);
    }
    if (FlagManager::getInstance().detached_mirror()) {
        // layer->layerIdToMirror表示镜像单个layer
        // 将被镜像layer对应添加到hierarchy的mChildren列表中,关系为Detached_Mirror
        if (layer->layerIdToMirror != UNASSIGNED_LAYER_ID) {
            hierarchy->addChild(getHierarchyFromId(layer->layerIdToMirror),
                                LayerHierarchy::Variant::Detached_Mirror);
        }
    }
}

1.2.2、提交新创建Layer

通过commitCreatedLayers()方法,将会对新创建的Layer进行逻辑结构的设置,包括为其设置父Layer和存储位置等。

1.2.3、应用Transaction携带参数

从applyTransactions()方法开始,将会对已筛选的Transaction进行应用。

在SurfaceComposerClient中,客户端进程将更新属性放在了两个结构体中:

  • DisplayState:保存更新给surfaceflinger的Display信息;
  • ComposerState:保存更新给surfaceflinger的Layer信息;

在该方法中,会遍历以上结构体,并通过setDisplayStateLocked()和setClientStateLocked()方法分别为对应的Display和Layer进行属性更新,将Transaction中的参数赋给Display和Layer。

1.2.4、提交Transaction

从commitTransactions()方法开始,会根据transactionFlags标记,进行SurfaceFlinger提交状态、Layer提交状态等全局状态的更新,这一步是整个提交阶段中核心的一步,主要操作包括:

  • 处理Display更新:包括更新、添加、移除对应的DisplayDevice以相关组件;
  • 处理Layer更新:包括Layer的mDrawingState、mDrawingParent、mDrawingChildren更新、已销毁Layer Offscreen列表更新;
  • 更新mDrawingState:代表SurfaceFlinger类中当前全局状态;

执行完成这一步后,SurfaceFlinger类和Layer中所有的状态都已经完成更新。

1.1.3、latchBuffers操作

SurfaceFlinger::latchBuffers()方法开始,将会对Layer进行Buffer的锁存操作。首先会收集有帧更新的Layer,将它们放在mLayersWithQueuedFrames列表中,然后对这个列表中的元素分别进行Buffer锁存操作,具体就是对Layer::mBufferInfo进行更新,并在后续流程中,将Buffer信息传递给HWC进行进一步合成。

从trace上看,当完成latchBuffers操作后,"Pending Buffer"的个数将会减一:

1.1.4、更新Layer的几何参数

updateLayerGeometry()方法中,会对当前所有Layer按照层级关系进行几何属性的计算和更新根据Layer层级。这里会更新Layer的以下几个属性:

  • mEffectiveTransform:表示该Layer的LayerStack空间变换矩阵,由Parent 变换矩阵对象乘以Layer自己的变换矩阵对象获得,用于将Layer空间图形变换到LayerStack空间;
  • mBounds:表示经过指定的Crop和Parent bound裁剪后的区域,但还未经过变换,也是当前Layer空间内的显示区域;

这两值可以在dump信息中看到:

完成提交操作后,Transaction中携带的参数全部完成应用,同时Display、Layer中的状态也全部更新完成,根据提交操作的返回结果,将决定是否进行合成操作。

二、合成阶段(composite)

从SurfaceFlinger::composite()方法开始,将进入合成阶段,这个过程中,Layer和Composition::Display(即Output)作为元数据,根据设置的所有属性(位置、颜色、内容、层级),经过多层处理,将Layer内容最终呈现在屏幕上。

在合成阶段,图层数据会从Layer到LayerFE、再到OutputLayer和HWC::Layer,并流向HW Composer。图层属性的封装类型也会从LayerSnapShot到OutputLayerCompositionState,对应不同的图层类型。同时,会以Output为基本单位,对每个屏幕执行合成。合成方式的选择也是在这个过程中确定。

合成阶段核心步骤拆解如下:

  1. 填充CompositionRefreshArgs属性;

  2. 更新LayerSnapshot并转移所有权给LayerFE;

  3. Output中执行准备操作(prepare);

    • 构建参与合成的Layer栈;
    • 执行uncacheBuffer操作;
  4. Output中执行准备操作(prepare);

  5. Output中执行合成操作(present);

  6. 合成后的处理(将LayerSnapshot转移回Layer)。

2.1、填充CompositionRefreshArgs属性

CompositionRefreshArgs表示用于指定、描述合成操作的一个合成参数,其中保存了需要合成的屏幕(Output)、Layer、以及其他共性特征,在SurfaceFlinger类中完成填充后,传递给CompositionEngine类后根据CompositionRefreshArgs中的数据执行后续操作。

cpp 复制代码
// frameworks/native/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h

struct CompositionRefreshArgs {
    // std::vector<std::shared_ptr<compositionengine::Output>>类型,
    // 用于保存所有compositionengine::Output对象
    Outputs outputs;

    // std::vector<sp<compositionengine::LayerFE>>类型,
    // 用于保存所有可能可见的LayerFE,按照层级升序顺序排列
    Layers layers;

    // 所有进行了latchBuffer的LayerFE列表
    Layers layersWithQueuedFrames;

    // uncached buffer id,用于更新buffer cache
    std::vector<uint64_t> bufferIdsToUncache;

    // 用于控制如何为Output选择Color mode,有三个值:
    //     kManaged = 0, 
    //     kUnmanaged = 1,
    //     kEnhanced = 2,
    OutputColorSetting outputColorSetting{OutputColorSetting::kEnhanced};

    // 色彩空间相关
    ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN};

    // 通过属性persist.sys.sf.color_mod强制设置的色彩空间,ui::ColorMode::NATIVE表示未设置
    ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE};

    // 当前屏幕旋转方向
    ui::Transform::RotationFlags internalDisplayRotationFlags{ui::Transform::ROT_0};

    // 是否要在该帧中更新Output各区域,该值由SF::mVisibleRegionsDirty变量值决定
    bool updatingOutputGeometryThisFrame{false};

    // 是否需要在该帧中更新Layer显示区域,与上一个变量为充分不必要关系
    bool updatingGeometryThisFrame{false};

    // Color变换矩阵,只有当色彩矩阵发生变化后才会更新
    std::optional<mat4> colorTransformMatrix;

    // true表示强制使用GPU合成,如开发者选项中的"停用HW叠加层"开启时
    bool devOptForceClientComposition{false};

    // 是否开启开发者选项中"显示Surface更新"
    std::optional<std::chrono::microseconds> devOptFlashDirtyRegionsDelay;

    // 最早present时间,将当前命令发送给HAL的最早时间,跟Vsync period相关
    std::optional<std::chrono::steady_clock::time_point> earliestPresentTime;

    // 下一帧的期望时间
    nsecs_t expectedPresentTime{0};

    // 该帧执行的时间
    std::optional<std::chrono::steady_clock::time_point> scheduledFrameTime;

    std::vector<BorderRenderInfo> borderInfoList;
    // 是否有注册可信监听
    bool hasTrustedPresentationListener = false;
};

2.2、更新LayerSnapshot并转移所有权给LayerFE

Layer在创建时会初始化一个LayerSnapshot对象,表示该Layer的"快照",用来保存合成过程中的相关数据,而且LayerSnapshot可以在Layer跟LayerFE之间移动,在合成过程中,会将LayerSnapshot转移给LayerFE参与合成,完成后转移会Layer中。

在moveSnapshotsToCompositionArgs()方法中,会先对LayerSnapshot进行更新,包括各类几何属性、合成方式、色彩属性.......等。

完成更新后,将其转移给LayerFE,同时将LayerFE对象放置到refreshArgs.layers中:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
// 更新LayerSnapshot
layer->updateSnapshot(refreshArgs.updatingGeometryThisFrame);
// 转移给LayerFE
layerFE->mSnapshot = layer->stealLayerSnapshot();
// 将LayerFE放在refreshArgs.layers中
refreshArgs.layers.push_back(layerFE);

完成这一步操作后,接下来的流程中,将通过CompositionEngine::present()方法,对每个Output单独进行处理:

cpp 复制代码
// frameworks/native/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp

void CompositionEngine::present(CompositionRefreshArgs& args) {
    {
        LayerFESet latchedLayers;
        // 准备OuputLayer过程
        for (const auto& output : args.outputs) {
            output->prepare(args, latchedLayers);
        }
    }
    // 呈现过程
    for (const auto& output : args.outputs) {
        output->present(args);
    }
}

下面进入Output中,看下prepare和present分别做了哪些工作。

2.3、Output中执行准备操作(prepare)

这个方法中,将开始进入合成前的准备阶段:

cpp 复制代码
// frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp

void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs,
                     LayerFESet& geomSnapshots) {
    .......
    // 收集、构建需要参与合成的Layer栈
    rebuildLayerStacks(refreshArgs, geomSnapshots);
    // 进行uncache buffer操作
    uncacheBuffers(refreshArgs.bufferIdsToUncache);
}

从以上方法可知,准备操作包括两部分任务:

  1. 收集、构建参与此次合成的Layer栈;
  2. 处理uncacheBuffer操作;

2.3.1、构建参与合成的Layer栈

通过Output::rebuildLayerStacks()方法,开始构待合成Layer的Layer栈。

2.3.1.1、收集参与合成的Layer列表

添加到refreshArgs.layers列表中的LayerFE是对当前所有的Layer进行遍历的结果,并非这里所有的LayerFE都会参与到合成过程,比如设置为隐藏不可见(通过Transaction.hide()设置)、透明度为0、没有Buffer/Color/Blur/Shadow等时,都不会进行合成显示。

此外,也会根据LayerStack来对Output和Layer进行匹配,以确保Layer按照期望的方式合成并显示在正确的屏幕上。

2.3.1.2、计算Layer显示区域

在Layer筛选的过程中,会同步对确定参与合成的Layer进行各区域计算,如可见区域、覆盖区域、阴影区域等。

Layer筛选的过程是从高层级到底层进行的,每次计算时都会对上一层的区域取交集,以得到新的区域。

我们在dump信息中看到的区域,就是通过这里计算获得:

2.3.1.3、创建OutputLayer和HWC2::Layer

OutputLayer是图层的进一步封装,相比LayerFE更偏底一层,封装了所有的用于合成的状态属性,这些状态保存在OutputLayerCompositionState中。

HWC2::Layer则是相比OutputLayer的更进一步封装,也是surfaceflinger进程中的最后一层封装类,也是Layer合成状态流向HW Composer的最末端。它由HW Composer创建并返回,通过HWC2::Layer将surfaceflinger进程中所有合成Layer的数据传递给HW Composer HAL。

OutputLayer的创建以模板类的方式创建,创建完成后,会保存在Output::mCurrentOutputLayersOrderedByZ列表中,后续操作,将通过OutputLayer进行。

Layer、LayerFE、OutputLayer、HWC2::Layer的递进关系如图所示:

2.3.2、执行uncacheBuffer操作

这一步是关于GraphicBuffer在Client端和sf端传递过程中的一个缓存机制处理。每个Layer申请的GraphicBuffer数量是固定且通过BufferQueue的调用进行循环使用。如果每次刷帧过程中传递GraphicBuffer对象本身,传递数据占用内存开销会很大,因此,通过GraphicBuffer的缓存机制,只有当Client端和sf端第一次使用到该GraphicBuffer时,才会传递实际GraphicBuffer对象本身,并且同时通过一个映射表缓存起来,后续再使用时,仅仅传递其buffer id即可。

当Client端缓存状态发生变化后,也需要同步到sf侧,进行uncacheBuffer的处理,从而对该GraphicBuffer的操作和Client端保持一致。

2.4、Output中执行合成操作(present)

完成准备工作后,接下来将进入合成操作,对每个OutputLayer更新OutputLayerCompositionState属性,通过HWC2::Layer传递给HW Composer,然后给HWC发送present命令,完成合成与上屏的工作。

这一步通过Output::present()方法实现:

cpp 复制代码
// frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp

void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
    // 向OutputCompositionState中设置ColorMode/Dataspace相关属性
    updateColorProfile(refreshArgs);
    // 向OutputCompositionState中设置其他合成状态
    updateCompositionState(refreshArgs);
    planComposition();
    // 向HW Composer传递合成状态
    writeCompositionState(refreshArgs);
    setColorTransform(refreshArgs);
    beginFrame();

    GpuCompositionResult result;
    const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs);
    if (predictCompositionStrategy) {
        // HWC异步合成
        result = prepareFrameAsync();
    } else {
        // 向HW Composer发送校验和合成命令
        prepareFrame();
    }

    devOptRepaintFlash(refreshArgs);
    // 根据HWComposer返回结果,决定是否再进行GPU合成
    finishFrame(std::move(result));
    // 完成合成操作后对Framebuffer处理
    postFramebuffer();
    // 缓存
    renderCachedSets(refreshArgs);
}

这个方法中涉及的操作量很大,核心几个任务拆解如下:

  1. 为所有OuptutLayer设置合成状态属性;
  2. 向HW Composer发送合成状态;
  3. 向HW Composer发送校验合成命令;
  4. 执行GPU合成(根据HWComposer返回结果,决定是否进行GPU合成)。

2.4.1、给OuptutLayer设置合成状态属性

每个OuputLayer的合成状态属性都是保存在OutputLayerCompositionState对象中,Output::present()方法执行之初就会更新所有OuputLayer的OutputLayerCompositionState属性:

  • updateColorProfile()中更新Color mode、dataspace等属性;
  • updateCompositionState()中更新其他属性。

合成方式的选择也是在这里进行,比如遍历OutputLayer寻找是否存在背景模糊的Layer,如果存在,该Layer及其底部的Layer会强制使用client合成。

2.4.2、向HW Composer发送合成状态

完成OutputLayerCompositionState的更新后,将通过HWC2::Layer把设置的所有合成状态传递给HW Composer。

这一步是通过Output::writeCompositionState()方法开始,并陆续执行OutputLayer中的多个"write"命名开头的方法,最终通过HWC HAL定义的接口传递给HW Composer。

2.4.3、向HW Composer发送校验合成命令

接下来便是向HWC发送校验及合成命令,HWC中检查Layer状态,并决定如何进行合成。

Android 12开始,系统开始支持HWC异步合成,即将校验检查放在了单独的线程进行:

cpp 复制代码
// frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp
GpuCompositionResult result;
// 是否支持HWC异步合成
const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs);
if (predictCompositionStrategy) {
    result = prepareFrameAsync();
} else {
    // 主线程合成
    prepareFrame();
}

但由于受平台影响,目前主流平台都未使用异步合成,这里我们依然以主线程合成流程为主。

这步操作从Output::prepareFrame()方法开始,HWC合成的全部操作基本都在这里完成:

  • Step 1、 调用presentOrValidate方法,向HWC发送present命令,HWC中决定如何进行合成;
  • Step 2、 调用getChangedCompositionTypes方法,获取HWC返回的结果;
  • Step 3、 调用applyCompositionStrategy方法应用结果。
2.4.3.1、通知HWC校验Layer状态

通过Display::chooseCompositionStrategy()方法开始执行通知HWC校验Layer的操作,这里会进一步执行HWComposer::getDeviceCompositionChanges()方法,最终执行HWC HAL组件presentOrValidateDisplay()方法,进入HWC中校验、合成Layer状态。

如果这里能够全部被HWC合成,那么这里将直接完成合成操作;否则,会等待GPU合成的FramBuffer给到HWC后再执行合成操作。

2.4.3.2、获取HWC返回结果

在执行HWComposer::getDeviceCompositionChanges()方法时,传递了一个DeviceRequestedChanges对象,这个对象用于接收HWC的校验结果,当执行完成校验后,会从HWC中读取相关校验值,并封装在DeviceRequestedChanges中:

rust 复制代码
// frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.h

struct DeviceRequestedChanges {
    // HWC校验后返回的layer和该Layer合成类型
    using ChangedTypes =
            std::unordered_map<HWC2::Layer*,
                               aidl::android::hardware::graphics::composer3::Composition>;
    // HWC校验后返回的当前Output亮度相关参数
    // brightness字段: 让HWC可为客户端合成指定亮度空间,并指示RenderEngine是否调暗
    // 客户端合成中的SDR层
    // dimmingStage字段: 让HWC可配置RenderEngine应何时调暗内容
    using ClientTargetProperty =
            aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
    // HWC校验后返回的当前Display相关请求标记
    // FLIP_CLIENT_TARGET: 指示RenderEngine提供一个新的Target Buffer
    // WRITE_CLIENT_TARGET_TO_OUTPUT: 虚拟屏合成相关,设置时指示GPU合成直接写入Virtual output buffer
    using DisplayRequests = hal::DisplayRequest;
    // HWC校验后返回的Layer标记
    using LayerRequests = std::unordered_map<HWC2::Layer*, hal::LayerRequest>;

    ChangedTypes changedTypes;
    DisplayRequests displayRequests;
    LayerRequests layerRequests;
    ClientTargetProperty clientTargetProperty;
};
2.4.3.3、应用HWC返回结果

接下来,在Output中执行applyCompositionStrategy()方法对HWC校验返回的结果进行应用。

在应用时,也是将DeviceRequestedChanges上的属性更新到OutLayerCompositionState和OutputCompositionState上,这些属性会参与到后面的GPU合成流程。

2.4.4、执行GPU合成

如果HWC的返回结果中标记了Layer需要进行Client合成,会对这些Layer进行Client合成。

这一步从Output::finishFrame()方法开始,并主要在Output::composeSurfaces()中完成。

在应用HWC返回时,将是否进行Client合成结果更新给了outputState.usesClientComposition属性,因此当该值在应用完HWC返回结果后为true时,便意味着需要进行Client合成。

在trace中,也可通过hasClientCompositionTAG看是否存在GPU合成:

Client合成的核心步骤如下:

  1. Step1、执行RenderSurface::dequeueBuffer()申请一块空闲Buffer作为"ClientTarget";
  2. Step2、根据HWC返回结果创建生成Client合成参数;
  3. Step3、执行RenderEngine::drawLayers()开始进行Client合成;
  4. Step4、执行HWComposer::setClientTarget()方法将Client合成后的Buffer(ClientTarget)给到HWC中;
  5. Step5、执行HWComposer::presentAndGetReleaseFences()方法通知HWC再次进行present,完成最终的合成。

其中Step5在接下来的postFrameBuffer操作操作完成。

从trace中可以看到以上步骤的时序:

2.4.5、执行postFrameBuffer

这步操作从Output::postFramebuffer()开始,主要做两件事:

  1. 执行HWComposer::presentAndGetReleaseFences()向HWC再发送一次present命令,并从HWC获取releaseFence;
  2. 执行Layer::onLayerDisplayed()方法,进行Buffer的release操作。

如果存在GPU合成,HWC中会present两次:

执行到这里,合成阶段就已完成。

2.5、合成后的处理

在完成合成操作后,会回到SurfaceFlinger::composite()方法中,做一些收尾工作。

在这里,会将LayerSnapshot重新转移到Layer中:

cpp 复制代码
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::moveSnapshotsFromCompositionArgs(
        compositionengine::CompositionRefreshArgs& refreshArgs,
        std::vector<std::pair<Layer*, LayerFE*>>& layers) {
    ......
    // 将LayerSnapshot重新转移到Layer中
    if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) {
        for (auto [layer, layerFE] : layers) {
            layer->updateLayerSnapshot(std::move(layerFE->mSnapshot));
        }
    }
}

并为layer设置releaseFence,并执行上一帧显示Buffer的释放等操作。

相关推荐
千里马学框架5 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台5 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone5 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc5 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo5 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077005 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼5 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone5 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen5 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone5 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui