android R Variable Refresh Rate 可变帧率 VRR


前言

本文代码基于Android R r1版本。如果不是这个版本的代码,可能会有部分代码上的差异。

API简述

Surface.setFrameRate(float frameRate, int compatibility)
//frameworks/base/core/java/android/view/Surface.java

SurfaceControl.Transaction.setFrameRate(float frameRate, int compatibility)
//frameworks/base/core/java/android/view/SurfaceControl.java

ANativeWindow_setFrameRate(float frameRate, int8_t compatibility)
//frameworks/native/libs/nativewindow/ANativeWindow.cpp

ASurfaceTransaction_setFrameRate(float frameRate, int8_t compatibility)
//frameworks/base/native/android/surface_control.cpp

分别有两个参数:
参数frameRate表示要设置的帧率,设置0表示接受系统刷新率,设置其余的整数都可以,系统会默认适配一个正确的刷新率。
参数compatibility有两个值可选,分别是
FRAME_RATE_COMPATIBILITY_DEFAULT和
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE。
其中FRAME_RATE_COMPATIBILITY_DEFAULT被设置之后,不能保证设置的帧率一定生效,app要保证在未生效的刷新率下正常运行,同时这个参数只能被用在非视频场景下。FRAME_RATE_COMPATIBILITY_FIXED_SOURCE这个值只能在视频场景下被使用。

Graphics相关代码分析

1.用户设置刷新率流程

无论是SDK中的接口还是NDK中的接口最终都会调用到surfaceflinger中。

status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
                                      int8_t compatibility)

进入setFrameRate之后,首先是判断参数的有效性。这个判断就是验证frameRate的值是否大于0,是否为浮点数。然后再判断compatibility的值是否为两个枚举值。

bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) {
    const char* functionName = inFunctionName != nullptr ? inFunctionName : "call";
    int floatClassification = std::fpclassify(frameRate);
    if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) {
        ALOGE("%s failed - invalid frame rate %f", functionName, frameRate);
        return false;
    }

    if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
        compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) {
        ALOGE("%s failed - invalid compatibility value %d", functionName, compatibility);
        return false;
    }

    return true;
}

接下来就是一个lamda表达式。

    static_cast<void>(schedule([=] {
        Mutex::Autolock lock(mStateLock);
        if (authenticateSurfaceTextureLocked(surface)) {
            sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
            if (layer->setFrameRate(
                        Layer::FrameRate(frameRate,
                                         Layer::FrameRate::convertCompatibility(compatibility)))) {
                setTransactionFlags(eTraversalNeeded);
            }
        } else {
            ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer");
            return BAD_VALUE;
        }
        return NO_ERROR;
    }));

调用的surfaceflinger.cpp中的模板方法。

template <typename F, typename T>
inline std::future<T> SurfaceFlinger::schedule(F&& f) {
    auto [task, future] = makeTask(std::move(f));
    mEventQueue->postMessage(std::move(task));
    return std::move(future);
}

makeTask定义在MessageQueue.h中。

template <typename F>
class Task : public MessageHandler {
    template <typename G>
    friend auto makeTask(G&&);

    explicit Task(F&& f) : mTask(std::move(f)) {}

    void handleMessage(const Message&) override { mTask(); }

    using T = std::invoke_result_t<F>;
    std::packaged_task<T()> mTask;
};

template <typename F>
inline auto makeTask(F&& f) {
    sp<Task<F>> task = new Task<F>(std::move(f));
    return std::make_pair(task, task->mTask.get_future());
}

setFrameRate中的lambda表达式被封装成MessageHander之后postMessage到MessageQueue中去。再Looper中pollOnce的时候被取出来执行。这个时候才会真正调用setFrameRate中的lambda表达式。再看这个表达式是怎么写的。authenticateSurfaceTextureLocked就是判断producer是否存在。然后在调用layer的setFrameRate。

bool Layer::setFrameRate(FrameRate frameRate) {
    if (!mFlinger->useFrameRateApi) {
        return false;
    }
    if (mCurrentState.frameRate == frameRate) {
        return false;
    }

    // Activate the layer in Scheduler's LayerHistory
    mFlinger->mScheduler->recordLayerHistory(this, systemTime(),
                                             LayerHistory::LayerUpdateType::SetFrameRate);

    mCurrentState.sequence++;
    mCurrentState.frameRate = frameRate;
    mCurrentState.modified = true;

    updateTreeHasFrameRateVote();

    setTransactionFlags(eTransactionNeeded);
    return true;
}

首先是调用scheduler的layerhistory,实现在LayerHistoryV2中。

void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
                            LayerUpdateType updateType) {
    std::lock_guard lock(mLock);

    const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
                                 [layer](const auto& pair) { return pair.first == layer; });
    LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);

    const auto& info = it->second;
    info->setLastPresentTime(presentTime, now, updateType, mConfigChangePending);

    // Activate layer if inactive.
    if (const auto end = activeLayers().end(); it >= end) {
        std::iter_swap(it, end);
        mActiveLayersEnd++;
    }
}

根据layer从mLayerInfos中取出对应的LayerPair,LayerPair就是一个Layer和LayerInfo的pair。然后将参数中的各种属性设置到LayerInfoV2的setLastPresentTime中去。

void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now,
                                     LayerUpdateType updateType, bool pendingConfigChange) {
    lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));

    mLastUpdatedTime = std::max(lastPresentTime, now);
    switch (updateType) {
        case LayerUpdateType::AnimationTX:
            mLastAnimationTime = std::max(lastPresentTime, now);
            break;
        case LayerUpdateType::SetFrameRate:
        case LayerUpdateType::Buffer:
            FrameTimeData frameTime = {.presetTime = lastPresentTime,
                                       .queueTime = mLastUpdatedTime,
                                       .pendingConfigChange = pendingConfigChange};
            mFrameTimes.push_back(frameTime);
            if (mFrameTimes.size() > HISTORY_SIZE) {
                mFrameTimes.pop_front();
            }
            break;
    }
}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值