android R 可变帧率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;
}
}