[069]PLL_CLK引发的降帧问题

前言

一个新的项目不管在什么情况下,画面都只能维持30帧左右,不能达到60帧。
一般这种问题首先是转给性能组分析,那就让我开始分析吧。

一、最简单的demo

首先我写了一个最简单的demo,看看能不能达到60帧,结果无法只能达到30帧。


1.1 dequeueBuffer时间长

一般就是没有可用的buffer,SurfaceFlinger的消费能力有问题,需要去看SurfaceFlinger的Trace。

1.2 waiting for GPU completion时间长

一般是GPU的性能不行导致了绘制时间过长,但是我的demo就画了一根线,不可能是GPU性能的问题,有可能是GPU没有及时signal,导致了timeout。虽然我没有找到GPU绘制完成signal代码,但是我很快就放弃了这个思路。因为waitForever中虽然有3000ms的timeout温馨提示,但是最后还是会继续等,而且是timeout never。

status_t Fence::waitForever(const char* logname) {
    ATRACE_CALL();
    if (mFenceFd == -1) {
        return NO_ERROR;
    }
    int warningTimeout = 3000;//温馨提示3000ms,
    int err = sync_wait(mFenceFd, warningTimeout);
    if (err < 0 && errno == ETIME) {
        ALOGE("waitForever: %s: fence %d didn't signal in %u ms", logname, mFenceFd.get(),
              warningTimeout);
        ...
        err = sync_wait(mFenceFd, TIMEOUT_NEVER);//这里是time out never
    }
    return err < 0 ? -errno : status_t(NO_ERROR);
}

加入waiting for HWC release以后,原来是release的fence信号signal慢了,导致的GPU completion的时间也变长了(S平台和之前的平台对于release buffer的流程有所差异)。
为什么waiting for HWC release会慢就需要去看SurfaceFlinger了。


1.3 小结

两个问题点最后都需要指向到SurfaceFlinger,我们继续查看SF的Trace。
PS:以后遇到waiting for GPU completion时间长的问题,不能直接下定论是GPU性能不行。

二、SurfaceFlinger分析

一看SurfaceFlinger发现非常奇怪的事情,sf竟然绘制一帧,丢一帧。


丢一帧的原因是framePending为true,hwcFrameMissed为true,gpuFrameMissed为false。
然后满足了提前return的条件。

void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime) {
    ....
    // Pending frames may trigger backpressure propagation.
    const TracedOrdinal<bool> framePending = {"PrevFramePending",
                                              previousFramePending(graceTimeForPresentFenceMs)};
    const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
                                             framePending ||
                                                     (previousPresentTime >= 0 &&
                                                      (lastScheduledPresentTime <
                                                       previousPresentTime - frameMissedSlop))};
    const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
                                                mHadDeviceComposition && frameMissed};
    const TracedOrdinal<bool> gpuFrameMissed = {"PrevGpuFrameMissed",
                                                mHadClientComposition && frameMissed};
     ....
    // framePending true
    // frameMissed true
    // hwcFrameMissed true
    // gpuFrameMissed false
    if (framePending) {
        if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) {
            signalLayerUpdate();
            return;//满足条件提前返回。
        }
    }
    ...
}

而且从图中看到,waiting for presentFence,而且整个wait过程竟然需要27.4ms。也就说sf合成后到开始刷新这一帧到屏幕需要27ms。一时,我也无法继续跟踪下去了,因为对HWC我不是很熟悉。

三、PLL_CLK值有问题

好在驱动工程师突然告诉我说PLL_CLK有问题,从475改成了560问题就解决了。
当时我就一面懵逼,PLL_CLK是什么东西,这个数值代表什么意思。

3.1 PLL_CLK是什么

PLL_CLK就是图中CLK的那段波的频率,也就每秒一次高低电频发生的次数。


转自诺比亚团队

3.2 CMD屏PLL_CLK计算公式

(Data rate) = width * height * 1.2 * total_bit_per_pixel * frame_per_second / total_lane_num
DSI采用的是双边采样,则clk等于数据速率的一半,也就是说一个clk周期内传送2位,所以你计算出来的值还要除以2
即PLL_CLOCK = Data rate / 2 (单位是MHZ)
PS:其中1.2应该是一个经验值。

经过计算我们屏幕PLL_CLK合适的值应该是559左右

width = 1080 (屏幕分辨率是1080 * 2400)
height = 2400
total_bit_per_pixel = 24 (RGB值,每个字节是8位,三个字节)
frame_per_second = 60 (60帧的屏幕)
total_lane_num = 4(4根线)
Data rate = 1080 * 2400 * 1.2 * 24 * 60 / 4 = 1119744000
即PLL_CLOCK = Data rate / 2 = 559872000 = 559.872MHZ

公式可能看不明白,这样子解释你就明白了。

1秒内60hz的手机需要传递的数据是多少。
屏幕的宽x屏幕的高x每个像素点的数据量x每秒的帧率。
1080x2400x24x60
由于有4根传输线,并且一次高低电频可以传输2次,所以PLL_CLOCK至少要达到以下数值
1080x2400x24x60/4/2
但是不能那么小气,加上一个经验值1.2
1080x2400x24x60x1.2/4/2 = 559872000 = 559.872MHZ

3.3 小结

之前设置的PLL_CLK值过小,传输速率过低,导致前一帧无法在一个vsync周期内将屏幕的数据传输给屏幕,导致这一帧的presentFence等待signal时间过久,然后sf主动丢了一帧,从而导致屏幕从60fps降为了30fps。但是目前presentFence和传输数据给屏幕之前的关系,我还没有找到对应的代码,因为我对驱动不是很熟悉。

四、整个过程还原

可以用已经掌握的知识来还原整个上层的流程,整个过程更加清晰了。


总结

整个问题还是非常有意思的,强烈推荐大家阅读参考资料中的文章,让我对屏幕显示画面有了更加深入的理解,而且也终于理解了为什么画面会有出现撕裂。

参考资料

https://www.jianshu.com/p/df46e4b39428
这几个图画的是真好,仍不住转载一下

可以看到DSI有4根线,就是total_lane_num

如果写的速度慢于扫描的速度,就有可能花屏

尾巴

当然有时间还是想去看看显示驱动那块的代码,给自己留几个问题。
有知道朋友欢迎留言解惑。

presentFence          唤醒的代码位置
GPU completion        唤醒的代码位置
HWC release           唤醒的代码位置
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容