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。图层属性的封装类型也会从LayerSnapShotOutputLayerCompositionState,对应不同的图层类型。同时,会以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的释放等操作。

相关推荐
风浅月明9 小时前
[Android]如何判断当前APP是Debug还是Release环境?
android
freflying11199 小时前
使用jenkins构建Android+Flutter项目依赖自动升级带来兼容性问题及Jenkins构建速度慢问题解决
android·flutter·jenkins
私人珍藏库11 小时前
[Android] APK提取器(1.3.7)版本
android
m0_7482326411 小时前
mysql的主从配置
android·mysql·adb
秋长愁11 小时前
Android监听应用前台的实现方案解析
android
胖虎112 小时前
2025 新版Android Studio创建Java语言项目
android·java·android studio·创建java项目
JabamiLight14 小时前
Lineageos 22.1(Android 15)Launcer简单调整初始化配置
android·android 15·lineageos 22.1·launcer
敲代码的鱼哇15 小时前
设备唯一ID获取,支持安卓/iOS/鸿蒙Next(uni-device-id)UTS插件
android·ios·uniapp·harmonyos
太空漫步1117 小时前
android滑动看新闻
android
KdanMin17 小时前
“让App玩捉迷藏:Android教育平板的‘隐身术’开发实录”
android