安卓显示-latchbuffer模式-AutoSingleLayer(修改中)

30 阅读8分钟

写在前面

在看本文前,建议了解前置内容:[090]unsignaled-buffer-latch功能 - 简书

本文仍在修正补充中...

sf对fence状态的不同处理

在 Android 显示系统的合成流程中,SurfaceFlinger 负责将来自不同 Layer 的 buffer 合成到屏幕输出。 每个 buffer 通过 Fence来标记它是否已经准备好被读取,Fence 消息是由生产方在写入完成后发出的。

  • Signaled fence:表示 buffer 被硬件写入完毕
  • Unsignaled fence:表示 buffer 还没写好

sf侧有三种处理Unsignaled fence的策略:

enum class LatchUnsignaledConfig {
    // 当acquireFence处于无信号状态时,不会进行对应Tranaction的提交
    Disabled,
    // 对于只携带一个了Layer属性的Transaction,会跳过acquireFence状态检查
    AutoSingleLayer,
    // 所有Transaction都会跳过acquireFence状态检查
    Always,
};

配置时通过debug.sf.auto_latch_unsignaleddebug.sf.latch_unsignaled属性指定模式,在sf启动时会读取该属性:

//不同芯片厂商定制策略不同,部分厂商没有这段代码
LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
    if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, true)) {
        return LatchUnsignaledConfig::Always;
    }
    if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) {
        return LatchUnsignaledConfig::AutoSingleLayer;
    }

    return LatchUnsignaledConfig::Disabled;
}

开启debug.sf.auto_latch_unsignaled时会执行AutoSingleLayer模式(MTK默认使用Always模式)

AutoSingleLayer的使用条件

debug.sf.latch_unsignaled = false

debug.sf.auto_latch_unsignaled = true

能使用到AutoSingleLayer的判定逻辑主要在下面代码中

1.未使用Disabled模式

2.变更的图层只有1个

3.开启了AutoSingleLayer并且是该图层首个事件

4.不是Early()状态

bool SurfaceFlinger::shouldLatchUnsignaled(const layer_state_t& state, size_t numStates,
                                           bool firstTransaction) const {
    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
        ATRACE_FORMAT_INSTANT("%s: false (LatchUnsignaledConfig::Disabled)", __func__);
        return false;
    }

    // We only want to latch unsignaled when a single layer is updated in this
    // transaction (i.e. not a blast sync transaction).
    //numStates表示在当前事务中更新的图层数量
    //只针对带有一个Layer属性的Transaction
    if (numStates != 1) {
        ATRACE_FORMAT_INSTANT("%s: false (numStates=%zu)", __func__, numStates);
        return false;
    }
    
    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
        //是否是第一个transaction
        if (!firstTransaction) {
            ATRACE_FORMAT_INSTANT("%s: false (LatchUnsignaledConfig::AutoSingleLayer; not first "
                                  "transaction)",
                                  __func__);
            return false;
        }

        //如果当前处于 Early 模式或客户端合成模式,我们不希望进行 Latch Unsignaled,因为这会导致:
        //RenderEngine 等待未完成的 buffer,造成卡顿 (jank)
        //动画(尤其是窗口动画)变慢
        
        //判断是否处于“Early”模式
        if (mScheduler->vsyncModulator().isVsyncConfigEarly()) {
            ATRACE_FORMAT_INSTANT("%s: false (LatchUnsignaledConfig::AutoSingleLayer; "
                                  "isVsyncConfigEarly)",
                                  __func__);
            return false;
        }
    }

    return true;
}

trace现象

如图,sf验证buffer状态时(左边竖线),该buffer是fence未释放状态,但仍然被sf取用。

虽然当前开启的是Always,但是该场景下只有一个layer的修改,开启autoSingleLayer也会是同样的情况

img转存失败,建议直接上传图片文件

代码走读

commit阶段处理transaction

循环处理一些条件,然后再apply fence未释放的transaction,具体处理逻辑看下文

std::vector<TransactionState> TransactionHandler::flushTransactions() {
    // Collect transaction that are ready to be applied.
    std::vector<TransactionState> transactions;
    TransactionFlushState flushState;
    flushState.queueProcessTime = systemTime();
    int lastTransactionsPendingBarrier = 0;
    int transactionsPendingBarrier = 0;
    do {
        lastTransactionsPendingBarrier = transactionsPendingBarrier;
        // Collect transactions that are ready to be applied.
        transactionsPendingBarrier = flushPendingTransactionQueues(transactions, flushState);
    } while (lastTransactionsPendingBarrier != transactionsPendingBarrier);

    applyUnsignaledBufferTransaction(transactions, flushState);

    mPendingTransactionCount.fetch_sub(transactions.size());
    ATRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
    return transactions;
}

继续调用applyFilters判断是否达到取用标准

达到使用autoSingleLayer的buffer会进入情况3的判断

int TransactionHandler::flushPendingTransactionQueues(
        std::vector<QueuedTransactionState>& transactions, TransactionFlushState& flushState) {
    int transactionsPendingBarrier = 0; // 统计有多少事务被 Barrier 阻塞(Barrier 是一种同步控制信号,这里用来限制事务处理顺序)
    auto it = mPendingTransactionQueues.begin(); // mPendingTransactionQueues 保存按 applyToken 分组的待处理事务队列

    while (it != mPendingTransactionQueues.end()) {
        auto& [applyToken, queue] = *it; 

        while (!queue.empty()) {
            auto& transaction = queue.front(); // 获取队列最前面的事务(FIFO)
            flushState.transaction = &transaction; 

            //applyFilters会进入TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck
            auto ready = applyFilters(flushState); 

            if (ready == TransactionReadiness::NotReadyBarrier) {
                // 情况1:事务由于 Barrier 未准备好,必须等待前置事务完成
                transactionsPendingBarrier++; 
                break; // 阻塞条件下退出当前队列的处理循环
            } else if (ready == TransactionReadiness::NotReady) {
                // 情况2:事务只是还没准备好(非 Barrier),保留在队列中,等待下次 flush
                break;
            } else if (ready == TransactionReadiness::NotReadyUnsignaled) {
                // 情况3:事务依赖的 Buffer 还没发出信号,但可能是唯一一个可处理的事务
                flushState.queueWithUnsignaledBuffer = applyToken; 
                break;
            }
            // 情况4:事务已准备好,可以执行
            popTransactionFromPending(transactions, flushState, queue); 
            // 从 pending 队列中取出该事务,加入 transactions 待执行列表,并更新 flush 状态
        }

        if (queue.empty()) {
            // 当前队列处理完,从 mPendingTransactionQueues 中删除这个队列
            it = mPendingTransactionQueues.erase(it);
        } else {
            // 否则,移动到下一个队列继续处理
            it = std::next(it, 1);
        }
    }
    return transactionsPendingBarrier; // 返回还有多少事务被 Barrier 阻塞
}
TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck(
        const TransactionHandler::TransactionFlushState& flushState) {
        
        .....
        if (!fenceSignaled){
        ...
            const bool allowLatchUnsignaled =
                        shouldLatchUnsignaled(s, transaction.states.size(),
                                              flushState.firstTransaction) &&
                        layer->isSimpleBufferUpdate(s);
            
                if (allowLatchUnsignaled) {
                    ATRACE_FORMAT("fence unsignaled try allowLatchUnsignaled %s",
                                  layer->name.c_str());
                    //注意这个返回值,对应flushPendingTransactionQueues方法的情况3
                    ready = TransactionReadiness::NotReadyUnsignaled;
                } else {
                    ready = TransactionReadiness::NotReady;
            ......

isSimpleBufferUpdate()返回true是进入shouldLatchUnsignaled的前提

方法通过3个阶段判断是简单buffer:

  1. s.what 中必须包含 layer_state_t::eBufferChanged 标志,表示事务确实提供了一个新的 buffer。

  2. 不能包含 deniedFlags

    1. s.what 不能包含以下任意标志,否则返回 false:

      • 断开生产者(eProducerDisconnect
      • 改变 Layer 属性(eLayerChanged
      • 改变相对 Layer(eRelativeLayerChanged
      • 修改透明区域(eTransparentRegionChanged
      • 修改高斯模糊区域(eBlurRegionsChanged
      • 改变 LayerStack(eLayerStackChanged
      • Layer 重新父子关系(eReparent
      • (视 FlagManager 配置而定)自动刷新变化(eAutoRefreshChanged
      • (视 FlagManager 配置而定)eFlagsChanged
    2. 这里过滤掉所有结构性变化,确保事务只是在替换 buffer,而不是调整图层关系。

  3. 不能包含 deniedChanges

    1. diff(s) 表示事务中 layer 属性发生了哪些变化(和之前状态的差异)。
    2. 必须保证这些变化中 不包含
      • 几何变化(位置、矩阵、裁剪等)
      • 透明度变化(Alpha)
      • 颜色/色彩空间变化(ColorTransform、Dataspace 等)
      • 圆角、模糊半径等 UI 装饰变化
      • buffer transformation / crop / destination frame 变化
      • HDR 元数据变化、亮度调整
      • Shadow、Overlay、Stretch 等视觉效果变化
      • 以及某些 Flag 变化(取决于配置)
    3. 这些都是会影响合成或渲染结果的属性变化,一旦出现,就不再属于“简单 buffer 更新”。
bool RequestedLayerState::isSimpleBufferUpdate(const layer_state_t& s) const {
    static constexpr uint64_t requiredFlags = layer_state_t::eBufferChanged;
    if ((s.what & requiredFlags) != requiredFlags) {
        ATRACE_FORMAT_INSTANT("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
                              (s.what | requiredFlags) & ~s.what);
        return false;
    }

    const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
            layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
            layer_state_t::eBlurRegionsChanged | layer_state_t::eLayerStackChanged |
            layer_state_t::eReparent |
            (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed()
                     ? 0
                     : (layer_state_t::eAutoRefreshChanged | layer_state_t::eFlagsChanged));
    if (s.what & deniedFlags) {
        ATRACE_FORMAT_INSTANT("%s: false [has denied flags 0x%" PRIx64 "]", __func__,
                              s.what & deniedFlags);
        return false;
    }

    const uint64_t changedFlags = diff(s);
    const uint64_t deniedChanges = layer_state_t::ePositionChanged | layer_state_t::eAlphaChanged |
            layer_state_t::eColorTransformChanged | layer_state_t::eBackgroundColorChanged |
            layer_state_t::eMatrixChanged | layer_state_t::eCornerRadiusChanged |
            layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBufferTransformChanged |
            layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eCropChanged |
            layer_state_t::eDataspaceChanged | layer_state_t::eHdrMetadataChanged |
            layer_state_t::eSidebandStreamChanged | layer_state_t::eColorSpaceAgnosticChanged |
            layer_state_t::eShadowRadiusChanged | layer_state_t::eFixedTransformHintChanged |
            layer_state_t::eTrustedOverlayChanged | layer_state_t::eStretchChanged |
            layer_state_t::eBufferCropChanged | layer_state_t::eDestinationFrameChanged |
            layer_state_t::eDimmingEnabledChanged | layer_state_t::eExtendedRangeBrightnessChanged |
            layer_state_t::eDesiredHdrHeadroomChanged |
            (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed()
                     ? layer_state_t::eFlagsChanged
                     : 0);
    if (changedFlags & deniedChanges) {
        ATRACE_FORMAT_INSTANT("%s: false [has denied changes flags 0x%" PRIx64 "]", __func__,
                              changedFlags & deniedChanges);
        return false;
    }

    return true;
}

这段代码就是上面我们分析过的

bool SurfaceFlinger::shouldLatchUnsignaled(const layer_state_t& state, size_t numStates,
                                           bool firstTransaction) const {
    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
        ATRACE_FORMAT_INSTANT("%s: false (LatchUnsignaledConfig::Disabled)", __func__);
        return false;
    }

    // We only want to latch unsignaled when a single layer is updated in this
    // transaction (i.e. not a blast sync transaction).
    if (numStates != 1) {
        ATRACE_FORMAT_INSTANT("%s: false (numStates=%zu)", __func__, numStates);
        return false;
    }

    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
        if (!firstTransaction) {
            ATRACE_FORMAT_INSTANT("%s: false (LatchUnsignaledConfig::AutoSingleLayer; not first "
                                  "transaction)",
                                  __func__);
            return false;
        }

        // We don't want to latch unsignaled if are in early / client composition
        // as it leads to jank due to RenderEngine waiting for unsignaled buffer
        // or window animations being slow.
        if (mScheduler->vsyncModulator().isVsyncConfigEarly()) {
            ATRACE_FORMAT_INSTANT("%s: false (LatchUnsignaledConfig::AutoSingleLayer; "
                                  "isVsyncConfigEarly)",
                                  __func__);
            return false;
        }
    }

    return true;
}

回到TransactionHandler::flushTransactions()中,循环处理了所有pending的 transaction,现在判断是否latch fence未释放的buffer

void TransactionHandler::applyUnsignaledBufferTransaction(
        std::vector<TransactionState>& transactions, TransactionFlushState& flushState) {

    // 情况1:如果 flushState 里没有记录 "未发出信号的队列"
    // 说明在 flushPendingTransactionQueues 遍历时,没有发现唯一的 NotReadyUnsignaled 状态事务
    // 直接返回,不做处理
    if (!flushState.queueWithUnsignaledBuffer) {
        return;
    }

    // 情况2:只在当前 flush 周期内,它是 "第一个且唯一" 的事务时才会处理
    // 如果已经有其他事务准备执行,就不处理这个未发信号的事务
    if (!transactions.empty()) {
        ATRACE_NAME("fence unsignaled"); 
        return;
    }

    // 情况3:定位这个 queueWithUnsignaledBuffer 对应的事务队列
    auto it = mPendingTransactionQueues.find(flushState.queueWithUnsignaledBuffer);

    LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mPendingTransactionQueues.end(),
        "Could not find queue with unsignaled buffer!");

    // 拿到该队列的引用
    auto& queue = it->second;

    // 情况4:使用 popTransactionFromPending 将该事务真正移出 pending 队列,加入执行事务列表
    popTransactionFromPending(transactions, flushState, queue);

    if (queue.empty()) {
        it = mPendingTransactionQueues.erase(it);
    }
}

将这个fence未释放的buffer加入到待执行队列等待取用。

void TransactionHandler::popTransactionFromPending(std::vector<TransactionState>& transactions,
                                                   TransactionFlushState& flushState,
                                                   std::queue<TransactionState>& queue) {
    auto& transaction = queue.front(); 

    // 当前事务已准备好,将它从 pending 队列移动到正式执行列表
    flushState.firstTransaction = false; 

    // 从“阻塞事务集合”中移除这个事务的 ID
    removeFromStalledTransactions(transaction.id); 

    // 将事务对象移动到可执行事务集合 transactions 中
    transactions.emplace_back(std::move(transaction)); 
    
    queue.pop(); 

    // 取刚刚加入执行队列的事务的引用
    auto& readyToApplyTransaction = transactions.back(); 

    // 遍历该事务包含的所有 layer_state,注意一个事务中可能包含多个 Layer 的更新
    readyToApplyTransaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
        const bool frameNumberChanged =
                state.bufferData->flags.test(BufferData::BufferDataChange::frameNumberChanged);
        // 检查该 Layer 的 buffer 状态中,图像缓冲区的帧号是否发生变化

        if (frameNumberChanged) {
            // 如果帧号发生变化,说明 Layer 准备显示新的 Buffer
            flushState.bufferLayersReadyToPresent.emplace_or_replace(
                state.surface.get(), 
                state.bufferData->frameNumber
            );
        } else {
            flushState.bufferLayersReadyToPresent.emplace_or_replace(
                state.surface.get(), 
                std::numeric_limits<uint64_t>::max()
            );
        }
    });
}

总结

要达到使用 AutoSingleLayer latch 未 signal buffer 的条件,必须全部满足:

  1. Fence 未 signal。
  2. LatchUnsignaledConfig 配置不为 Disabled。
  3. 事务只涉及一个图层(numStates == 1)。
  4. 配置为 AutoSingleLayer 时:
    1. 必须是该图层的首个事务(firstTransaction == true)。
    2. 当前 Vsync 模式不是 Early(!isVsyncConfigEarly())。
  5. 该 layer 必须为 简单 buffer 更新(isSimpleBufferUpdate(s))。
  6. 在 commit 阶段,这个事务是唯一要执行的事务(本轮 flush 没有其他 ready 事务)。

可见想要达成使用条件是不太容易的。

只有纯粹的“换了一帧画面”,且不伴随任何图层结构调整、属性变化、视觉效果变化的事务,才会被认为是简单 buffer 更新。 这就是为什么它配合 AutoSingleLayer 机制,可以安全地提前 latch 未 signal buffer,因为这样的事务合成代价非常低、风险很小。

谷歌官方介绍

使用 AutoSingleLayer 进行无信号缓冲区锁存 | Android Open Source Project

推荐关注大佬@王小二的技术栈