2020AV天堂网,午夜色色视频,美女黄片免费观看,欧美黄色电影网站,亚洲人在线

其他新聞

其他新聞

ios關(guān)鍵詞排名優(yōu)化的方式(ios掉榜關(guān)鍵詞如何優(yōu)化)

時(shí)間:2023-11-09 信途科技其他新聞
背景

Apple 在今年推出了支持 ProMotion 屏幕的 iPhone 設(shè)備,讓 App 在 iPhone 13 Pro 和 iPhone 13 Pro Max 上的最大刷新幀率可到達(dá) 120Hz,極大優(yōu)化了應(yīng)用滑動(dòng)/動(dòng)畫(huà)的流暢度體驗(yàn)。

ProMotion 并不是一個(gè)新的概念,早在 2017 年,Apple 推出的第二代 iPad Pro 便搭載了這一刷新率最高可達(dá) 120Hz 的屏幕。在 iPad 上,高刷新率默認(rèn)對(duì)所有 App 啟用。而也許是出于能耗的考慮,在 iPhone 上,Apple 并未將這個(gè)能力自動(dòng)對(duì)所有 App 啟用,而是需要開(kāi)發(fā)者手動(dòng)添加配置項(xiàng)來(lái)進(jìn)行適配。

近期有消息指出 iOS 15.4 beta 修正了這一行為(https://xintu.macrumors.com/2022/01/27/ios-15-4-apps-120-hz-promotion/),經(jīng)過(guò)筆者驗(yàn)證額外的配置項(xiàng)依然是需要的,并且本文內(nèi)容依然適用。

本文介紹了在 iPhone 上對(duì) ProMotion 動(dòng)態(tài)幀率的適配時(shí)觀察到的現(xiàn)象和遇到的問(wèn)題,嘗試推測(cè)了背后的原理,并探討了解決問(wèn)題的可能思路,最終基于調(diào)研結(jié)果在國(guó)際化短視頻業(yè)務(wù)上線優(yōu)化方案,取得了核心業(yè)務(wù)指標(biāo)的收益。

什么是幀率

在深入探究 ProMotion 屏幕所帶來(lái)的變化之前,我們先回顧一個(gè)似乎耳熟能詳?shù)母拍睿?/p>

什么是幀率?

眾所周知,顯示器并不能顯示真正動(dòng)態(tài)的畫(huà)面,所有動(dòng)畫(huà)效果都是靠高速播放一幀幀靜態(tài)畫(huà)面欺騙人類(lèi)視覺(jué)所造成的假象。那么幀率最基本的定義便是屏幕內(nèi)容的變化頻率,是一個(gè)物理意義上的指標(biāo)。這種變化頻率又由以下兩個(gè)值共同決定:

刷新幀率:由屏幕硬件規(guī)格控制,傳統(tǒng)顯示設(shè)備一般為 59.94Hz,決定了幀率的上限。渲染幀率:由 CPU -> GPU 渲染管線的執(zhí)行速率控制,決定了幀率的下限。

理想情況下,渲染幀率和刷新幀率最好完全匹配,或者渲染幀率是刷新幀率的整數(shù)倍,這樣實(shí)際展現(xiàn)的內(nèi)容不會(huì)出現(xiàn)任何異常。但現(xiàn)實(shí)中二者往往會(huì)出現(xiàn)不匹配的情況,卡頓就是其中之一:

卡頓

當(dāng) CPU -> GPU 的渲染管線遇到瓶頸,導(dǎo)致某一幀的渲染耗時(shí)大于屏幕的刷新間隔時(shí),上一幀畫(huà)面會(huì)在屏幕上多停留數(shù)幀的時(shí)間。當(dāng)這個(gè)滯留時(shí)間過(guò)長(zhǎng),用戶感知到畫(huà)面更新的延遲,這稱(chēng)為卡頓。這也是 iOS 開(kāi)發(fā)過(guò)程中會(huì)遇到的主要性能問(wèn)題之一。

實(shí)際幀率

幀率并不等同于刷新率,它和所展示的內(nèi)容息息相關(guān):

展示靜態(tài)畫(huà)面時(shí),理想情況只需要進(jìn)行一次渲染,盡管屏幕仍然以 60Hz 或者更高的頻率進(jìn)行刷新,每次刷新所展示的內(nèi)容(FrameBuffer)也未改變,用戶感知到的實(shí)際幀率依然接近 0。展示固定幀率的元素,例如 24FPS 的電影視頻時(shí),用戶感知到的實(shí)際幀率自然也是 24 FPS 左右。展示超高幀率的內(nèi)容,例如 CS:GO 不鎖幀跑 >200 FPS,但由于顯示設(shè)備刷新率限制,用戶感知到的幀率依然不會(huì)超過(guò)硬件幀率的上限。什么是動(dòng)態(tài)刷新率

ProMotion 本質(zhì)上是對(duì) Adaptive-Sync 顯示標(biāo)準(zhǔn)的一種實(shí)現(xiàn)。

Ref: https://en.wikipedia.org/wiki/Variable_refresh_rate

根據(jù) Apple 官方文檔顯示,ProMotion 屏幕支持的刷新率是可變的。

具體來(lái)說(shuō),對(duì) iPhone 而言:

The iPhone 13 Pro and iPhone 13 Pro Max ProMotion displays can present content on the display using the following refresh rates and timings:

120Hz (8ms), 80Hz (12ms), 60Hz (16ms), 48Hz (20ms), 40Hz (25ms), 30Hz (33ms), 24Hz (41ms), 20Hz (50ms), 16Hz (62ms), 15Hz (66ms), 12Hz (83ms), 10Hz (100ms)

而對(duì) iPad Pro 來(lái)說(shuō):

The iPad Pro’s ProMotion display can present content on the display using the following refresh rates and timings:

120Hz (8ms), 60Hz (16ms), 40Hz (25ms), 30Hz (33ms), 24Hz (41ms)

這其實(shí)是 Apple 對(duì) VESA 定制的 Adaptive-Sync 技術(shù)標(biāo)準(zhǔn)的一種實(shí)現(xiàn),在游戲業(yè)界已經(jīng)實(shí)裝多年,類(lèi)似的實(shí)現(xiàn)還有 AMD 的 FreeSync 和 Nivida 的 G-Sync。這種新的顯示技術(shù)有著以下優(yōu)點(diǎn):

減少可感知的卡頓

對(duì)于固定刷新率的屏幕而言,當(dāng)某一幀的渲染耗時(shí)出現(xiàn)異常,在 VSync 信號(hào)到來(lái)之后才完成渲染,那么當(dāng)前內(nèi)容便會(huì)滯留在屏幕上,這一幀需要再等一次 VSync 信號(hào)才能被渲染展示給用戶。

而 Adaptive-Sync 技術(shù)可以避免這一點(diǎn),在該幀渲染結(jié)束后盡快進(jìn)行展示,從而減少顯示卡頓時(shí)長(zhǎng):

減少移動(dòng)設(shè)備的屏幕功耗

在搭載了固定刷新率屏幕的設(shè)備上,當(dāng)顯示靜態(tài)內(nèi)容或者幀率較低(例如視頻)的內(nèi)容時(shí),GPU 的渲染頻率比實(shí)際頻率刷新率會(huì)更低。但是固定刷新率的屏幕依然會(huì)已最高速率進(jìn)行刷新,重復(fù)展示之前的內(nèi)容,造成了額外的電量消耗。

ProMotion 屏幕在這種情況下可以主動(dòng)降低刷新率,減少屏幕功耗,這對(duì)于移動(dòng)設(shè)備來(lái)說(shuō)尤其重要。

動(dòng)態(tài)刷新率的表現(xiàn)形式

The iPhone 13 Pro, the iPhone 13 Pro Max, and the iPad Pro ProMotion displays are capable of dynamically switching between:

Faster refresh rates up to 120Hz

Slower refresh rates down to 24Hz or 10Hz

已知,ProMotion 屏幕的刷新幀率并不固定,系統(tǒng)會(huì)實(shí)時(shí)地根據(jù)當(dāng)前顯示內(nèi)容的類(lèi)型和狀態(tài)來(lái)動(dòng)態(tài)切換屏幕的刷新幀率。為了更好地理解這種動(dòng)態(tài)幀率的表現(xiàn)形式,筆者分別在

iPhone XR - 無(wú) ProMotioniPhone 13 Pro - 有 ProMotion 默認(rèn)鎖頻

上對(duì)一些典型渲染場(chǎng)景進(jìn)行了測(cè)試,發(fā)現(xiàn)搭載了 ProMotion 屏幕的設(shè)備上運(yùn)行 App 時(shí),不同的場(chǎng)景下的各種統(tǒng)計(jì)口徑的幀率指標(biāo)確實(shí)展示出了有趣的變化。

具體而言,筆者分別在以下幾種場(chǎng)景:

測(cè)試場(chǎng)景靜態(tài)頁(yè)面

靜態(tài)的 UIView,無(wú)動(dòng)畫(huà)/視頻等元素

2.滑動(dòng)中的頁(yè)面

包含靜態(tài) Cell 的 UITableView,僅觀察滑動(dòng)中的表現(xiàn)

3.Core Animation 默認(rèn)刷新率動(dòng)畫(huà)

顯示基于 CABasicAnimation 實(shí)現(xiàn)的簡(jiǎn)單位移動(dòng)畫(huà)

4.Core Animation 120Hz 高刷新率動(dòng)畫(huà)

僅在 ProMotion 設(shè)備上測(cè)試,基于 CABasicAnimation 實(shí)現(xiàn)的簡(jiǎn)單位移動(dòng)畫(huà),同時(shí)解鎖了 CADisableMinimumFrameDurationOnPhone 和 preferredFrameRateRange 幀率限制。(關(guān)于此限制下文會(huì)有具體介紹)

5.Metal 渲染 30Hz/60Hz 視頻

使用基于 MTKView 進(jìn)行渲染的播放器,播放源幀率分別為 30Hz/60Hz 的視頻文件

并使用以下幾種統(tǒng)計(jì)口徑的幀率指標(biāo)進(jìn)行測(cè)試:

測(cè)試指標(biāo)CADisplayLink 計(jì)算幀率

iOS 中主要的幀率統(tǒng)計(jì)手段。

根據(jù) CADisplayLink.h 頭文件中描述,CADisplayLink 是一個(gè) ”Class representing a timer bound to the display vsync “。在回調(diào)中比較當(dāng)前幀/前一幀的時(shí)間戳,可以計(jì)算出上一幀的渲染耗時(shí)(ts),其倒數(shù)(1/ts)即為當(dāng)前的實(shí)時(shí)幀率。

2.Xcode GPU Report 幀率

Xcode -> Show Debug Navigator -> FPS 中顯示的幀率。這個(gè)只能統(tǒng)計(jì)當(dāng)前應(yīng)用直接通過(guò) OpenGL ES 或者 Metal 進(jìn)行繪制的幀率,例如游戲渲染/視頻播放,無(wú)法統(tǒng)計(jì) Core Animation 的幀率(眾所周知,后者通過(guò) backboardd 進(jìn)行繪制)。

3.Instruments Core Animation FPS

Instruments 中 Core Animation FPS 工具所顯示的幀率。這個(gè)統(tǒng)計(jì)的是 Core Animation 的幀率,即 Render Server backboardd 繪制的頻率。目前該工具有 BUG 無(wú)法顯示高于 60 FPS 的幀率。

4.Instruments Display/VSync 信號(hào)頻率

Instruments 中 Display 工具所顯示的 Surface/VSync 信號(hào)時(shí)間戳。如下圖所示:

Display:指對(duì)應(yīng)顯示器的單個(gè) Surface 上屏持續(xù)的時(shí)間,對(duì)應(yīng) CPU-GPU 管線的渲染頻率VSync:指垂直同步信號(hào)時(shí)間戳,對(duì)應(yīng)屏幕硬件的刷新頻率

在 60Hz 屏幕上,iOS 設(shè)備默認(rèn)采用雙緩沖刷新機(jī)制,也就是前幀緩存和后幀緩存。GPU 總是在后幀緩存上進(jìn)行當(dāng)前幀的繪制。當(dāng) VSync 信號(hào)到來(lái)時(shí),交換前后幀緩存的指針(Swap FrameBuffer),屏幕刷新顯示新的內(nèi)容。

而當(dāng)屏幕以 120Hz 顯示內(nèi)容時(shí),iOS 會(huì)切換成三緩沖刷新機(jī)制(見(jiàn)上圖中三種顏色的 Surface),這減少渲染管線的壓力,但同時(shí)會(huì)增加一定的渲染上屏延遲。

Metal 應(yīng)用可以通過(guò)設(shè)置 -[CAMetalLayer setMaximumDrawableCount:] 為 2 來(lái)在 120Hz 屏幕上強(qiáng)制啟用雙緩沖機(jī)制,避免這種延遲。

如果屏幕顯示內(nèi)容未發(fā)生變化,Surface 則不會(huì)發(fā)生交換,一個(gè) Surface 的 Display 可能持續(xù)數(shù)個(gè) VSync 間隔,但多余的 VSync 信號(hào)依然代表著硬件層額外的屏幕刷新,造成額外的電量消耗。

非 ProMotion 設(shè)備

首先讓我們看看傳統(tǒng)的固定刷新率的設(shè)備的情況。

VSync 信號(hào)間隔固定為 16.67ms

XR 的屏幕刷新率為固定的 60Hz,這一點(diǎn)對(duì)應(yīng)的具體指標(biāo)是 VSync 信號(hào)的間隔,而在任何場(chǎng)景下,XR 的 VSync 信號(hào)的間隔均為固定的 16.67ms。

此外,在顯示靜態(tài)內(nèi)容時(shí),由于視圖 Layer Tree 無(wú)變化,Core Animation 不會(huì)有提交新的事務(wù)提交,backboardd 不會(huì)進(jìn)行刷新,所以對(duì)應(yīng)這一幀的 Surface 也長(zhǎng)時(shí)間(數(shù)十秒)未被交換下去,Core Animation FPS 的值顯示為 0。

但由于 VSync 信號(hào)仍然以 60Hz 的頻率持續(xù)觸發(fā),屏幕此時(shí)正在不停重復(fù)展示同樣的 Frame Buffer,消耗了額外的電量。

CADisplayLink 基本完全跟隨 VSync 信號(hào)

根據(jù)過(guò)去對(duì) iOS 系統(tǒng)的認(rèn)知,我們知道 CADisplayLink 是由 VSync 信號(hào)驅(qū)動(dòng)的:

默認(rèn)配置的 CADisplayLink 的回調(diào)應(yīng)該與 VSync 信號(hào)基本同時(shí)。

這一點(diǎn)在 XR 上得到了驗(yàn)證,用 Instruments 記錄一次主線程發(fā)生的卡頓,得到:

其中:

第一行 runloop 記錄每次 RunLoop AfterWaiting -> BeforeWaiting 的間隔第二行 tick 記錄默認(rèn)配置的 CADisplayLink 回調(diào)間的間隔最下面則是硬件 Display/VSync 事件時(shí)序圖

可以觀察到下述現(xiàn)象,符合我們之前的對(duì) DisplayLink 的認(rèn)識(shí):

沒(méi)有卡頓的情況下,VSync 信號(hào)和 RunLoop 的喚醒 & CADisplayLink 回調(diào)的觸發(fā)嚴(yán)格一一對(duì)應(yīng)。RunLoop 卡頓,無(wú)法處理 Source 1 信號(hào),DisplayLink 回調(diào)被延遲到卡頓結(jié)束時(shí)。在此過(guò)程中 VSync 信號(hào)間隔始終保持不變。ProMotion 設(shè)備

下面看看 ProMotion 設(shè)備的測(cè)試結(jié)果。

VSync 信號(hào)間隔可變

在 ProMotion 屏幕上 VSync 信號(hào)間隔是可變的,具體而言:

顯示靜態(tài)內(nèi)容時(shí),屏幕降頻,最低以 10Hz 的頻率進(jìn)行刷新顯示 Core Animation 動(dòng)畫(huà)時(shí),系統(tǒng)會(huì)適配動(dòng)畫(huà)的幀率設(shè)置改變刷新率

*通過(guò) preferredFrameRateRange 可以設(shè)置 hint 請(qǐng)求高刷,但并不一定生效,詳見(jiàn)下文“動(dòng)態(tài)幀率的應(yīng)用場(chǎng)景”部分。

顯示滑動(dòng)中內(nèi)容時(shí),刷新率在 80Hz 左右波動(dòng),并且跟隨滑動(dòng)速度變化而變化??旎瑫r(shí)刷新率升高,慢滑時(shí)降低。顯示視頻時(shí),刷新率和視頻幀率維持一致

可以看到 VSync 信號(hào)間隔能主動(dòng)跟隨顯示內(nèi)容的渲染幀率的改變而改變。

減少卡頓造成的顯示延遲

在主線程發(fā)生卡頓導(dǎo)致滑動(dòng)中某一幀渲染耗時(shí)過(guò)長(zhǎng)時(shí),系統(tǒng)會(huì)改變這一幀所對(duì)應(yīng)的 VSync 信號(hào)間隔(下圖 Surface 5),減小從渲染到展示的延時(shí),從而減緩用戶感知到的卡頓時(shí)長(zhǎng)。

DisplayLink 不完全跟隨 VSync 信號(hào)

如圖是一張滑動(dòng)中場(chǎng)景的 CADisplayLink 回調(diào) 和 Display/VSync 事件對(duì)照記錄。和之前不同的是,再 ProMotion 設(shè)備上 DisplayLink 和 VSync 信號(hào)之間沒(méi)有表現(xiàn)出明顯的跟隨關(guān)系:

具體而言:

第三個(gè)箭頭所指向的 DisplayLink 的回調(diào)并不及時(shí)。在這之前主線程的卡頓已經(jīng)結(jié)束,并且額外執(zhí)行了兩次 RunLoop,但直到第三次才調(diào)用了 DisplayLink 的回調(diào)。不僅僅是時(shí)機(jī)不匹配,也存在收到 VSync 但不觸發(fā) DisplayLink 回調(diào)的情況(并且主線程處于空閑狀態(tài)),例如上圖中的 ? 處。解除 DisplayLink 的幀數(shù)限制

我們知道,在 iOS 15 上 Apple 對(duì)第三方應(yīng)用的顯示幀率默認(rèn)做了限制。第三方應(yīng)用需要在 Info.plist 中添加<key>CADisableMinimumFrameDurationOnPhone</key><true/> 字段才可以解鎖 120Hz 的刷新率。

于此同時(shí),在 iOS 15 中,CADisplayLink 等動(dòng)畫(huà)相關(guān) API 也新增了一個(gè)用于配置偏好幀率的屬性:

/* Defines the range of desired callback rate in frames-per-second for this display link. If the range contains the same minimum and maximum frame rate, this property is identical as preferredFramesPerSecond. Otherwise, the actual callback rate will be dynamically adjusted to better align with other animation sources. */@property(nonatomic) CAFrameRateRange preferredFrameRateRange API_AVAILABLE(ios(15.0), watchos(8.0), tvos(15.0));

為了進(jìn)一步探究新設(shè)備上 DisplayLink 和 VSync 信號(hào)之間的關(guān)系,筆者將測(cè)試 App 的 Core Animation 的幀率限制解除,并配置對(duì)應(yīng)的 API,分別在不同的場(chǎng)景重新進(jìn)行測(cè)試:

顯示動(dòng)態(tài)內(nèi)容的場(chǎng)景動(dòng)畫(huà)場(chǎng)景

展示一個(gè)速度中等的位移動(dòng)畫(huà),得到下圖:

可以很直觀地發(fā)現(xiàn),DisplayLink 解鎖幀率后的屏幕刷新率基本穩(wěn)定在 120Hz。并且 VSync 和 DisplayLink 的關(guān)系似乎又重新一一對(duì)應(yīng)了起來(lái)。

但是,將動(dòng)畫(huà)速度減慢,筆者發(fā)現(xiàn)這種對(duì)應(yīng)關(guān)系發(fā)生了變化:

可以觀察到在播放慢速動(dòng)畫(huà)時(shí),DisplayLink 的頻率依然是配置的 120Hz,但是實(shí)際的屏幕刷新率卻只有 30Hz。

滑動(dòng)場(chǎng)景

讓我們換一種場(chǎng)景再次進(jìn)行測(cè)試,快速滑動(dòng)視圖,在 Instruments 中得到下圖:

可以發(fā)現(xiàn),DisplayLink 解鎖幀率后,屏幕刷新率同樣基本穩(wěn)定在 120Hz,僅在丟幀時(shí)有降頻。

需要注意的是筆者在 CADisplayLink 的回調(diào)中除了調(diào)用 os_signpost 上報(bào) log 外無(wú)任何 UI 改動(dòng)。即便筆者展示的 TableView 極其簡(jiǎn)單,上圖中仍然可以觀察到丟幀,無(wú)法在滑動(dòng)中完美穩(wěn)定 120Hz。這也許說(shuō)明 UIKit 的渲染性能在 120Hz 下會(huì)有某種程度上的原生瓶頸。

然后降低滑動(dòng)屏幕的速度,得到了和慢速動(dòng)畫(huà)相似的結(jié)果,盡管 DisplayLink 回調(diào)速度不減,但是 VSync 信號(hào)頻率一直保持在較低的水平:

卡頓場(chǎng)景

上面兩次測(cè)試都接近理想情況,即整個(gè) Render Loop 執(zhí)行幾乎沒(méi)有延遲與卡頓。但是現(xiàn)實(shí)中應(yīng)用的運(yùn)行總是有著各種各樣的或大或小的卡頓問(wèn)題。

為了驗(yàn)證更接近現(xiàn)實(shí)情況下,DisplayLink 和 VSync 信號(hào)之間的關(guān)系,在連續(xù)滑動(dòng)的情況下筆者人為加入了一個(gè) 20ms 的微小卡頓進(jìn)行測(cè)試:

上圖中可以看到,ProMotion 屏幕很好的處理了這次卡頓,由于三緩沖機(jī)制的存在,再 Render Loop 渲染 Surface 4 卡頓期間,通過(guò)改變 VSync 間隔,系統(tǒng)嘗試將緩沖區(qū)中的 Surface 283 與 Surface 250 延遲上屏,盡量縮短了用戶看到靜止畫(huà)面的時(shí)長(zhǎng)。

隨后,主線程恢復(fù)執(zhí)行,可以看到 DisplayLink 的回調(diào)頻率很快恢復(fù)至卡頓前的高水平。而此時(shí) VSync 信號(hào)由于前述卡頓減緩機(jī)制的存在頻率其實(shí)有所降低。此時(shí)二者頻率并不吻合。

這和之前播放慢速動(dòng)畫(huà)/慢速滑動(dòng)的情況很相似,由于卡頓加上緩沖機(jī)制的存在導(dǎo)致短時(shí)間內(nèi)系統(tǒng)將屏幕的刷新頻率降低,但在 CPU 側(cè)依然維持了 DisplayLink 的高速回調(diào),滿足了使用方對(duì) preferredFrameRateRange 這一 API 的設(shè)置。

為了進(jìn)一步分析了這種機(jī)制的本質(zhì),筆者接下來(lái)會(huì)嘗試逆向分析 iOS 15 中的系統(tǒng)庫(kù)相關(guān)實(shí)現(xiàn)的改動(dòng)。

逆向分析DisplayLink 驅(qū)動(dòng)方式的變化

在 CADisplayLink 回調(diào)方法上設(shè)置斷點(diǎn),分別在 iOS 14 和 15 ProMotion 設(shè)備上運(yùn)行,可以得到:

在 iOS 14 上,CADisplayLink 是通過(guò) Source 1 mach_port 直接接受 VSync 信號(hào)驅(qū)動(dòng)的

在 iOS 15 ProMotion 設(shè)備上,CADisplayLink 不再由 VSync 信號(hào)驅(qū)動(dòng),而是由一個(gè) UIKit 內(nèi)部的 Source0 信號(hào)驅(qū)動(dòng)

在 15 中,CADisplayLink 第一次創(chuàng)建并添加至 RunLoop 的時(shí)候,會(huì)注冊(cè)一個(gè) Source 1 信號(hào),這和 14 中行為一致。

其 callout 回調(diào)地址對(duì)應(yīng)符號(hào)為同樣為 display_timer_callback,同樣和 14 中的一致。

這也可以解釋為什么 15 上 VSync 信號(hào)確實(shí)會(huì)喚醒一次 RunLoop,只是這次喚醒并不一定觸發(fā) DisplayLink 的回調(diào),這就說(shuō)明 display_timer_callback 行為和 14 相比一定發(fā)生了某種變化。

display_timer_callback邏輯的變化

使用 Hopper 分析 display_timer_callback 的實(shí)現(xiàn),發(fā)現(xiàn) 15 和 14 的實(shí)現(xiàn)并無(wú)區(qū)別。使用 LLDB 進(jìn)行 debug,逐步分析,觀察到后續(xù)調(diào)用函數(shù)為 CA::Display::DisplayLink::callback,其關(guān)鍵反匯編代碼如下圖所示:

觀察反匯編代碼可以發(fā)現(xiàn),如果 CA::display_link_will_fire_handler 這個(gè) block 返回了 NO,則這次 VSync 信號(hào)回調(diào)不會(huì)觸發(fā)后續(xù)的 CA::DisplayLink::dispatch_items 調(diào)用。

實(shí)際上在 LLDB 中也驗(yàn)證了這點(diǎn):

注意上圖中的 _CFRunLoopCurrentIsMain 和上圖紅框代碼接近,后續(xù)的 blraa 指令看起來(lái)很明顯是調(diào)用了一個(gè) block(上面的 ldr x9 [x8, #0x10] 就是把 invoke 指針從 block 結(jié)構(gòu)體中取出的意思)。tbz 指令中 w0 寄存器為 block 執(zhí)行的返回值,為 0(即 NO)時(shí)跳轉(zhuǎn)至 0x1848dbc08,而 0x1848dbc08 剛好在 dispatch_items 的調(diào)用之后,跳過(guò)了該調(diào)用。

通過(guò)對(duì)上圖中 blraa 指令 step in,我們發(fā)現(xiàn)這個(gè) block 實(shí)際上是由 UIKitCore 注冊(cè)的:

找到引用了該符號(hào)的 UIKit 的私有方法 __UIUpdateCycleSchedulerStart ,反匯編結(jié)果也驗(yàn)證了這點(diǎn)。

同時(shí)發(fā)現(xiàn)這個(gè) block 的返回值固定為 0x0。

而同樣的 symbol 在之前的 iOS 版本上并不存在,也就是說(shuō)這個(gè)應(yīng)該是 iOS 15 的變動(dòng)。換安裝了 iOS 15 的非 ProMotion 設(shè)備,重走上面的逆向流程發(fā)現(xiàn),該設(shè)備的 CA::display_link_will_fire_handler 為 nil,未注冊(cè):

這里 cbz 執(zhí)行了跳轉(zhuǎn),說(shuō)明 x0 為 nil,而 x0 是由 ldr x0, [x8, #0x1c8] 得到。

可以看到 x0 就是 CA::display_link_will_fire_handler。繼續(xù)分析之前找到的私有符號(hào) __UIUpdateCycleSchedulerStart 的相關(guān)實(shí)現(xiàn),可以知道這是因?yàn)樵诜?ProMotion 設(shè)備上 _UIUpdateCycleEnabled 返回了 NO 導(dǎo)致的。

在返回 NO 的情況下 __UIUpdateCycleSchedulerStart 方法不會(huì)執(zhí)行,CA::display_link_will_fire_handler 也就不會(huì)被注冊(cè)。

_UIUpdateCycleEnabled 所帶來(lái)的變化

繼續(xù)研究 _UIUpdateCycleEnabled 相關(guān)的代碼,筆者發(fā)現(xiàn)這個(gè)的改動(dòng)并不是僅僅影響 DisplayLink 驅(qū)動(dòng)方式那么簡(jiǎn)單。

當(dāng) _UIUpdateCycleEnabled 返回 YES 時(shí),UIKit 會(huì)在 UIApplicationMain 中執(zhí)行 _UIUpdateCycleSchedulerStart。分析該函數(shù),發(fā)現(xiàn) _UIUpdateCycleEnabled 啟用時(shí)會(huì)調(diào)用 [CATransaction setDisableRunLoopObserverCommits:YES]。

Core Animation 是絕大部分 iOS 應(yīng)用的渲染引擎,熟悉 iOS 渲染流程的同學(xué)想必都知道它的執(zhí)行也是由 MainRunLoop 驅(qū)動(dòng),大致為:

MainRunLoop 因?yàn)橛脩舨僮?Timer/GCD 等被喚醒,派發(fā)相應(yīng)的事件/回調(diào)回調(diào)中應(yīng)用修改 Layer Tree,觸發(fā) setNeedsLayout 或 setNeedsDisplayMainRunLoop 即將完成本次執(zhí)行,在即將休眠前向 Observer 派發(fā) BeforeWaiting 事件BeforeWaiting 中觸發(fā) Core Animation 注冊(cè)的 MainRunLoop Observer,觸發(fā)事務(wù)提交 CA::Transaction::commit():自頂向下觸發(fā)各種 Layout/Display 等邏輯,更新布局/內(nèi)容Core Animation 將更新后的 Layer Tree 打包發(fā)送給 Render Server

5.隨后 MainRunLoop 進(jìn)入休眠

6.Render Server 將打包好的 Layer Tree 解碼,生成并提交對(duì)應(yīng)的 draw calls

7.GPU 執(zhí)行渲染指令,渲染出 FrameBuffer,待后續(xù) VSync 信號(hào)來(lái)臨時(shí)上屏展示

上圖中 +[CATransaction setDisableRunLoopObserverCommits:YES] 這個(gè)調(diào)用給了筆者提示,讓我們驗(yàn)證一下 CA::Transaction::commit() 在 iOS 15 ProMotion 設(shè)備上的執(zhí)行時(shí)機(jī),會(huì)發(fā)現(xiàn)確實(shí)不再由 BeforeWaiting 事件驅(qū)動(dòng)了:

實(shí)際上同樣的 Source 0 信號(hào)同時(shí)也驅(qū)動(dòng)了 CADisplayLink 的回調(diào):

關(guān)注這個(gè) Source 0 的回調(diào)符號(hào) runloopSourceCallback,會(huì)發(fā)現(xiàn)這個(gè) Source0 是由 signalChanges 函數(shù)驅(qū)動(dòng):

而 signalChanges 又是由多個(gè)回調(diào)所驅(qū)動(dòng):

其中:

runloopObserverCallback 為一個(gè) BeforeWaiting 的 MainRunLoop observer 驅(qū)動(dòng)。runloopTimerCallback 由 mk_timer 驅(qū)動(dòng),對(duì)應(yīng)的 mach_port 不明,測(cè)試發(fā)現(xiàn)其回調(diào)頻率在 1Hz 左右,但也會(huì)不斷變化,猜測(cè)是某種系統(tǒng)計(jì)時(shí)器。inputGroupSignaledCallback 由 mk_timer 驅(qū)動(dòng),對(duì)應(yīng)的 mach_port 正是 VSync 信號(hào)。

4.requestRegistrySignaledCallback 由 UIScrollView 在即將開(kāi)始滑動(dòng)時(shí)驅(qū)動(dòng)。

通過(guò)上面的分析,筆者有理由認(rèn)為在 iOS 15 上應(yīng)用的渲染驅(qū)動(dòng)機(jī)制出現(xiàn)了比較大的變化。其中之一便是 DisplayLink 的驅(qū)動(dòng)源的改變。

結(jié)論iOS 15 上 Apple 改變了在 ProMotion 設(shè)備的渲染事件循環(huán)的驅(qū)動(dòng)方式,CoreAnimation 的事務(wù)提交不再由完全由 RunLoop 驅(qū)動(dòng),而是涉及了多個(gè)信號(hào)源系統(tǒng)動(dòng)態(tài)幀率選擇的機(jī)制會(huì)綜合考慮使用方設(shè)置的 API(如 preferredFrameRateRange)和實(shí)際展示的內(nèi)容的變化頻率。具體對(duì) CADisplayLink 而言:內(nèi)容低速變化時(shí),CADisplayLink 解鎖高刷新率僅影響自身的回調(diào)頻率,系統(tǒng)仍可能選擇較低的屏幕刷新率來(lái)降低功耗內(nèi)容中高速變化時(shí),CADisplayLink 解鎖高刷新率可以讓系統(tǒng)選擇更高的刷新頻率,甚至實(shí)現(xiàn)鎖定 120Hz 的刷新

關(guān)于如何界定低速/中高速,筆者在下文中 CAAnimation 設(shè)置動(dòng)態(tài)幀率 部分做了一些試驗(yàn),可作為參考。

同時(shí),默認(rèn)配置的 CADisplayLink 回調(diào)頻率最高為 60Hz,無(wú)法監(jiān)控更高頻率的刷新事件。

3.ProMotion 設(shè)備中,DisplayLink 不再由 VSync 信號(hào)直接驅(qū)動(dòng),而是在新引入的渲染事件循環(huán)中執(zhí)行。新版本 iOS 系統(tǒng)實(shí)現(xiàn)了某種更復(fù)雜的機(jī)制來(lái)盡可能滿足使用者設(shè)置的偏好頻率進(jìn)行回調(diào),但并不保證它與 VSync 信號(hào)的強(qiáng)關(guān)聯(lián)性。這意味著默認(rèn)的 CADisplayLink 的回調(diào)頻率與實(shí)際幀率并不匹配,之前基于 CADisplayLink 進(jìn)行幀率監(jiān)控的方案在 ProMotion 設(shè)備上變得不再可行。

動(dòng)態(tài)幀率的應(yīng)用場(chǎng)景監(jiān)控動(dòng)態(tài)幀率下的流暢度表現(xiàn)

業(yè)界中一般采用 CADisplayLink 對(duì)應(yīng)用的流暢度進(jìn)行監(jiān)控。由于 CADisplayLink 的行為在 iOS 15 上的變化,原先的監(jiān)控方案無(wú)法評(píng)估 ProMotion 屏幕在超過(guò) 60Hz 時(shí)的表現(xiàn)。

根據(jù)上面的探索結(jié)論,目前筆者設(shè)想了三種針對(duì) ProMotion 設(shè)備的兼容性修改方案:

方案一 [Pass]

對(duì)于任何設(shè)備都以 60Hz 為優(yōu)化目標(biāo),只考慮刷新間隔長(zhǎng)于 16.67ms 的情況。換句話說(shuō),在屏幕以 120Hz 刷新時(shí),對(duì)于丟 1 幀的情況也認(rèn)為不丟幀,因?yàn)榇藭r(shí)兩幀之間的間隔仍然小于 16.67ms,理論上用戶感知不大。

優(yōu)點(diǎn):

方案簡(jiǎn)單,僅需設(shè)置 preferredFramesPerSecond 為固定值 60 即可兼容之前的指標(biāo)。依然可以計(jì)算 FPS 指標(biāo),對(duì)于刷新率高于 60Hz 的情況統(tǒng)一認(rèn)為刷新率為 60Hz

缺點(diǎn):

由于只能監(jiān)控最高 60Hz 的情況,無(wú)法評(píng)估更高刷新率下一些微小丟幀對(duì)用戶體驗(yàn)帶來(lái)的影響,也無(wú)法評(píng)估對(duì)高刷屏的一些優(yōu)化所帶來(lái)的技術(shù)影響在低刷新率時(shí),MainRunLoop 依然會(huì)以 60Hz 運(yùn)行,對(duì)功耗有一定影響方案二 [Pass]

通過(guò)一些手段,可以替換驅(qū)動(dòng) display_timer_callback 的 Source 1 信號(hào)的回調(diào),使用它來(lái)準(zhǔn)確監(jiān)聽(tīng) VSync 信號(hào),實(shí)現(xiàn)對(duì)動(dòng)態(tài)幀率的準(zhǔn)確監(jiān)控。

優(yōu)點(diǎn):

理論上最精確的監(jiān)控方案對(duì)功耗的影響最小,回調(diào)頻率只有在屏幕刷新率實(shí)際升高時(shí)才會(huì)隨之提升

缺點(diǎn):

使用了私有 APIFPS 指標(biāo)從此不再適用VSync 信號(hào)目前和渲染流程不完全匹配,雖然精確但不一定實(shí)用方案三 [Pick]

通過(guò)在 CADisplayLink 回調(diào)中確認(rèn) duration 參數(shù),計(jì)算得到當(dāng)前屏幕的實(shí)時(shí)刷新率,并修改 preferredFrameRateRange 來(lái)進(jìn)行跟蹤。

優(yōu)點(diǎn):

方案相對(duì)簡(jiǎn)單,只需在每次回調(diào)中更新 DisplayLink 對(duì)象的 preferredFrameRateRange 屬性即可

缺點(diǎn):

由于動(dòng)態(tài)幀率的存在,F(xiàn)PS 指標(biāo)可以反映實(shí)時(shí)屏幕刷新情況,但是聚合后的意義不大,消費(fèi)時(shí)需要區(qū)分特定機(jī)型/場(chǎng)景觀察到目前的最小回調(diào)頻率為 60Hz,也就是說(shuō)無(wú)法確認(rèn) ProMotion 屏幕在 48Hz、30Hz 甚至更低刷新率下的表現(xiàn)在低刷新率時(shí),MainRunLoop 依然會(huì)以 60Hz 運(yùn)行,對(duì)功耗有一定影響

需要注意的是,CADisplayLink 的 preferredFrameRateRange 需要以類(lèi)似一下格式進(jìn)行設(shè)置:

NSInteger currentFPS = (NSInteger)ceil(1.0 / displayLink.duration);displayLink.preferredFrameRateRange = CAFrameRateRangeMake(10.0, currentFPS, 0.0);

CAFrameRateRange.minimum 傳最小值 10.0,preferred 傳 0.0,可以讓該 CADisplayLink 只用于監(jiān)控當(dāng)前的系統(tǒng)幀率,而不影響幀率的動(dòng)態(tài)選擇。

相比前兩個(gè)方案,方案三改動(dòng)小,不使用私有 API,監(jiān)控準(zhǔn)確性也較高,缺點(diǎn)相對(duì)來(lái)說(shuō)可以接受。

FPS 的替代指標(biāo)

考慮到在 ProMotion 屏幕上 FPS 指標(biāo)不再與應(yīng)用運(yùn)行是否流暢直接相關(guān),它的聚合值參考價(jià)值不大,有必要尋找一個(gè)新指標(biāo)作為替換。

Apple 官方在 WWDC20 - 10077 Eliminate animation hitches with XCTest 中介紹了 Hitch Time Ratio 這一概念,并著重說(shuō)明了它比單純的 FPS 更能適配不同刷新率的場(chǎng)景。

在 XCTest 框架中,蘋(píng)果提供了 API XCTOSSignpostMetric 幫助開(kāi)發(fā)者在單測(cè)中即時(shí)地獲取該指標(biāo),但相關(guān) API 盡在單測(cè)中提供,線上無(wú)法使用。而 MetricKit 中的 MXAnimationMetric 盡管可以在線上獲取,但卻不是實(shí)時(shí)的,無(wú)法滿足大型 App 對(duì)不同場(chǎng)景的監(jiān)控需求。

因此,遵循下面 Apple 對(duì) Hitch Ratio 的定義:

Hitch time:

Time in ms that a frame is late to display.

Hitch time ratio:

Hitch time in ms per second for a given duration.

筆者嘗試實(shí)現(xiàn)了基于 CADisplayLink 的 (Scroll) Hitch Time Ratio 的計(jì)算方案:

計(jì)算上一幀的幀時(shí)間戳與上上一幀的目標(biāo)幀時(shí)間戳得到上一幀的 Hitch Time確定該幀是否是在滑動(dòng)中渲染累計(jì)得到整體的 Hitch Frame,與累積的幀間隔相比,得到 (Scroll) Hitch Time Ratio關(guān)鍵場(chǎng)景提升幀率

在測(cè)試過(guò)程中筆者發(fā)現(xiàn),系統(tǒng) App 滑動(dòng)時(shí)是穩(wěn)定以最高刷新率 120Hz 運(yùn)行的:

而第三方 App 即便設(shè)置了 CADisableMinimumFrameDurationOnPhone 為 true 也無(wú)法穩(wěn)定以滿幀率滑動(dòng)(經(jīng)過(guò)驗(yàn)證,這一點(diǎn)在 iOS 15.4 beta 系統(tǒng)上依然成立)。

通過(guò)利用 iOS 15 引入的新 API,我們可以在關(guān)鍵場(chǎng)景如滑動(dòng)、轉(zhuǎn)場(chǎng)、動(dòng)畫(huà)過(guò)程中主動(dòng)解鎖更高/限制更低的動(dòng)態(tài)幀率,從而優(yōu)化流暢度或者優(yōu)化功率,提升用戶體驗(yàn)?zāi)繕?biāo)。

滑動(dòng)中穩(wěn)定 120Hz

首先,筆者希望非系統(tǒng) App 也可以盡可能實(shí)現(xiàn)滑動(dòng)中穩(wěn)定 120Hz 刷新。

結(jié)合上述分析,這一點(diǎn)可以用 CADisplayLink 來(lái)實(shí)現(xiàn)。這里筆者提出兩種可能方案僅供參考:

創(chuàng)建 CADisplayLink,配置其 preferredFramesPerSecond 為 120,然后將其添加到 UITrackingRunLoopMode 中。CADisplayLink *dp = ...dp.preferredFramesPerSecond = 120;// 或者dp.preferredFrameRateRange = CAFrameRateRangeMake(120.0, 120.0, 0.0);[dp addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode];

在滑動(dòng)中,該 CADisplayLink 被激活,系統(tǒng)鎖定當(dāng)前幀率為最高 120Hz(僅在內(nèi)容中高速變化時(shí)生效)。停止滑動(dòng)時(shí)則恢復(fù)正常幀率。

添加 CADisplayLink 至 CommonModes 中,分別在開(kāi)始/停止滑動(dòng)時(shí)啟用/暫停 CADisplayLink,并修改對(duì)應(yīng)的 preferredFramesPerSecond等屬性,觸發(fā)幀率變化。CADisplayLink *dp = ...dp.paused = YES;[dp addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];CFRunLoopAddObserver(CFRunLoopGetMain(), CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopEntry | kCFRunLoopExit, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { if (activity == kCFRunLoopEntry) { dp.paused = NO; dp.preferredFramePerSecond = 120; } else { dp.paused = YES; dp.preferredFramePerSecond = 0; } }), (__bridge CFStringRef)UITrackingRunLoopMode);

在實(shí)踐中,由于也存在需要在非滑動(dòng)狀態(tài)下解鎖幀率上限的情況,所以方案 2 的通用性會(huì)更好。

CAAnimation 設(shè)置動(dòng)態(tài)幀率

目前蘋(píng)果只提供了修改 CAAnimation 動(dòng)畫(huà)幀率的 API,設(shè)置 CAAnimation.preferredFrameRateRange 即可改變其對(duì)屏幕刷新率的影響。

對(duì)于用戶感知明顯的,如轉(zhuǎn)場(chǎng)動(dòng)畫(huà),可以設(shè)置為 120Hz。對(duì)于感知不明顯的,如旋轉(zhuǎn)動(dòng)畫(huà),可以降低其幀率,比如設(shè)置為 30Hz。

但是,和 DisplayLink 相同,過(guò)上述 API 的設(shè)置雖然會(huì)“影響”系統(tǒng)的動(dòng)態(tài)幀率的選擇,但這種影響并不是絕對(duì)的。在實(shí)際使用中,筆者發(fā)現(xiàn)屏幕選擇的刷新率和 CAAnimation 在屏幕上變化的速度有關(guān)。

關(guān)于此點(diǎn),以 iPhone 13 Pro 為例,筆者使用了一個(gè)簡(jiǎn)單的、偏好幀率為固定 120Hz 平移動(dòng)畫(huà)進(jìn)行說(shuō)明:

CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];CGFloat speed = 170.0/330.0;anim.toValue = @(100);anim.fromValue = @(0);anim.duration = 10.0;anim.repeatCount = FLT_MAX;anim.preferredFrameRateRange = CAFrameRateRangeMake(120, 120, 120);

其中 speed 變量為平移的速度,單位為 pt/s,試驗(yàn)發(fā)現(xiàn):

speed 取 (0, 160] 時(shí),屏幕刷新率為 60Hzspeed 取 [161, 320] 時(shí),屏幕刷新率為 80Hzspeed 取 [321, +∞) 時(shí),屏幕刷新率為 120Hz

筆者僅在 iPhone 13 Pro 上測(cè)試了平移動(dòng)畫(huà)的場(chǎng)景,以上數(shù)據(jù)僅供參考。

最后,對(duì)于其他的常見(jiàn)的動(dòng)畫(huà) API,例如 UIView.animateWithDuration、UIViewPropertyAnimator 等,則沒(méi)有提供對(duì)應(yīng) API 進(jìn)行修改。理論上也可以通過(guò)某些手段拿到這些上層 API 所創(chuàng)建的 CAAnimation 對(duì)象來(lái)實(shí)現(xiàn)修改。

手勢(shì)/轉(zhuǎn)場(chǎng)等其他場(chǎng)景解鎖 120Hz

其他場(chǎng)景需要控制動(dòng)態(tài)幀率的也可以通過(guò)手動(dòng)修改 CADisplayLink 的 preferredFramePerSecond/preferredFrameRateRange 屬性來(lái)實(shí)現(xiàn),其實(shí)現(xiàn)和通過(guò)監(jiān)聽(tīng) RunLoop 來(lái)修改滑動(dòng)幀率基本相同。

UIGestureRecognizer 常被用于實(shí)現(xiàn)的交互式動(dòng)畫(huà)。經(jīng)過(guò)測(cè)試,發(fā)現(xiàn)在觸發(fā)手勢(shì)回調(diào)的同時(shí)啟用一個(gè)解鎖了頻率的 CADisplayLink 也可以間接提高 UIGestureRecognizer 的回調(diào)頻率,從而實(shí)現(xiàn)更高幀率的交互動(dòng)畫(huà)。

對(duì)于轉(zhuǎn)場(chǎng)的場(chǎng)景,一個(gè)簡(jiǎn)單的方案是 swizzle UIViewController 的生命周期消息,在出現(xiàn)/消失的節(jié)點(diǎn)啟用/停用 CADisplayLink 幀率的解鎖,從而實(shí)現(xiàn)通用的頁(yè)面轉(zhuǎn)場(chǎng)動(dòng)畫(huà)幀率解鎖方案。

Flutter 官方也計(jì)劃提供類(lèi)似 API 讓?xiě)?yīng)用側(cè)可以針對(duì)不同的場(chǎng)景(滑動(dòng)、動(dòng)畫(huà) etc)動(dòng)態(tài)切換屏幕刷新率:https://github.com/flutter/flutter/issues/90675

上線收益

基于上述思路,筆者所在團(tuán)隊(duì)在國(guó)際化短視頻業(yè)務(wù)落地了優(yōu)化項(xiàng)目,經(jīng)過(guò)實(shí)驗(yàn)驗(yàn)證:

大盤(pán)滑動(dòng)幀率 P50 從 81.57 上升至 112.2核心業(yè)務(wù)指標(biāo)也有一定收益結(jié)語(yǔ)

近年來(lái),Apple 生態(tài)中軟硬件的發(fā)展日新月異,有軟件層的 dyld 的持續(xù)優(yōu)化和 iOS 15 新引入的 Prewarm 機(jī)制,也有新的 ProMotion 屏幕,可以看到 Apple 一直致力于打造更絲滑流暢的用戶體驗(yàn)。

Apple 提供的系統(tǒng)級(jí)優(yōu)化方案一般通用而無(wú)感知,但通用往往也意味著一定的局限性,可能預(yù)留了額外優(yōu)化空間,應(yīng)用開(kāi)發(fā)者們可以進(jìn)一步去研究如何更好地適配。

例如本文中,筆者通過(guò)研究新引入的 ProMotion 屏幕背后的機(jī)制,透過(guò)表象/深入?yún)R編管中窺豹看到一部分本質(zhì),最終落地了監(jiān)控 + 優(yōu)化的方案,讓大盤(pán)滑動(dòng)幀率 P50 從 80 上升至 112 左右,取得了額外的業(yè)務(wù)收益。

最后,筆者認(rèn)為,我們普通開(kāi)發(fā)者作為 Apple 生態(tài)鏈中的一環(huán),在享受系統(tǒng)級(jí)別優(yōu)化自動(dòng)帶來(lái)的收益的同時(shí),也應(yīng)該主動(dòng)去了解上述優(yōu)化背后的底層原理。一方面,了解與學(xué)習(xí) Apple 的成熟優(yōu)化思路可以提升我們作為工程師的眼界。另一方面,對(duì)系統(tǒng)底層原理的了解可以拓充我們的“彈藥庫(kù)”,對(duì)業(yè)務(wù)價(jià)值交付的全鏈路了解越廣越深,越有可能抓住潛在的優(yōu)化點(diǎn),從而在性能優(yōu)化工程師這條職業(yè)道路上走得更遠(yuǎn)更好。

參考資料WWDC20 - 10077 Eliminate animation hitches with XCTest

https://developer.apple.com/videos/play/wwdc2020/10077

WWDC21 - 10147 Optimize for variable refresh rate displays

https://developer.apple.com/videos/play/wwdc2021/10147/

Optimizing ProMotion Refresh Rates for iPhone 13 Pro and iPad Pro

https://developer.apple.com/documentation/quartzcore/optimizing_promotion_refresh_rates_for_iphone_13_pro_and_ipad_pro?language=objc

What is Adaptive Sync?

https://xintu.viewsonic.com/library/tech/explained/what-is-adaptive-sync/

https://github.com/flutter/flutter/issues/90675加入我們

我們是字節(jié)國(guó)際化短視頻基礎(chǔ)技術(shù)團(tuán)隊(duì),是一個(gè)深度追求極致的團(tuán)隊(duì),我們專(zhuān)注于性能、架構(gòu)、包大小、穩(wěn)定性、自動(dòng)化測(cè)試、基礎(chǔ)庫(kù)、編譯構(gòu)建等方向的深耕,保障超大規(guī)模團(tuán)隊(duì)的研發(fā)效率和全球數(shù)億用戶的使用體驗(yàn)。目前上海、杭州、新加坡、美國(guó)都有大量人才需要,歡迎有志之士與我們共同建設(shè)億級(jí)用戶全球化 APP!

可以點(diǎn)擊「鏈接」,進(jìn)入字節(jié)跳動(dòng)招聘官網(wǎng)投遞簡(jiǎn)歷,也可以郵件聯(lián)系:kazec.liu@bytedance.com 咨詢相關(guān)信息或者直接發(fā)送簡(jiǎn)歷內(nèi)推!

掃描二維碼推送至手機(jī)訪問(wèn)。

版權(quán)聲明:本文由信途科技轉(zhuǎn)載于網(wǎng)絡(luò),如有侵權(quán)聯(lián)系站長(zhǎng)刪除。

轉(zhuǎn)載請(qǐng)注明出處http://m.quickersubmitter.com/xintu/60133.html

相關(guān)文章

「seo優(yōu)化文檔」SeO優(yōu)化

信途科技今天給各位分享seo優(yōu)化文檔的知識(shí),其中也會(huì)對(duì)SeO優(yōu)化進(jìn)行解釋?zhuān)绻芘銮山鉀Q你現(xiàn)在面臨的問(wèn)題,別忘了關(guān)注和分享本站。本文導(dǎo)讀目錄: 1、如何進(jìn)行DOC、PDF等文檔的seo搜索引擎優(yōu)化呢?...

上海網(wǎng)站建設(shè)的,怎么查自己的安全b證

怎么查自己的安全b證,要是住建局發(fā)的建筑施工管理B證,到省級(jí)住建官網(wǎng)可以查詢 要是安監(jiān)局發(fā)的證(一般安監(jiān)局發(fā)證也不分A.B.C類(lèi),),到國(guó)家安監(jiān)總局官網(wǎng)可以查到。官網(wǎng)上都有專(zhuān)門(mén)的安全管理資格證查詢項(xiàng)。...

關(guān)鍵詞競(jìng)價(jià)排名的優(yōu)缺點(diǎn)(關(guān)鍵詞競(jìng)價(jià)排名推廣)

今天聊一下關(guān)鍵詞,聊關(guān)鍵詞之前,繞不開(kāi)官網(wǎng)或者新媒體。首先說(shuō)說(shuō)官網(wǎng)吧。有一個(gè)奇怪的現(xiàn)象,越是大型的企業(yè)越在乎自己的官網(wǎng),而越是小的企業(yè)越不在乎自身企業(yè)的官網(wǎng)。按照企業(yè)主的話來(lái)說(shuō),反正就是個(gè)小公司,也不...

批量查詢國(guó)際站關(guān)鍵詞排名(國(guó)際站關(guān)鍵詞排名優(yōu)化)

相信很多人找資源還在問(wèn)度娘,但大部分內(nèi)容都是自己不滿意的。今天就給大家分享10個(gè)私藏已久的資源網(wǎng)站,個(gè)個(gè)都很厲害,你想要的資源基本上全都有。01*Slidego網(wǎng)址:https://slidesgo....

「微信公眾平臺(tái)定制」微信公眾平臺(tái)設(shè)計(jì)

信途科技今天給各位分享微信公眾平臺(tái)定制的知識(shí),其中也會(huì)對(duì)微信公眾平臺(tái)設(shè)計(jì)進(jìn)行解釋?zhuān)绻芘銮山鉀Q你現(xiàn)在面臨的問(wèn)題,別忘了關(guān)注和分享本站。本文導(dǎo)讀目錄: 1、為什么要對(duì)微信公眾號(hào)進(jìn)行定制開(kāi)發(fā) 2、如...

青島網(wǎng)站建設(shè)哪家好,查詢青島招聘信息的網(wǎng)站有哪些

查詢青島招聘信息的網(wǎng)站有哪些青島本地的一些招聘網(wǎng)站,像:1、中國(guó)青島人才網(wǎng)2、青島應(yīng)屆生求職網(wǎng)3、齊魯人才網(wǎng)4、青島招聘網(wǎng)5、青島才好網(wǎng)6、中國(guó)青島人才招聘網(wǎng)具有全國(guó)性質(zhì)的一些招聘軟件:1、上啥班(短...

現(xiàn)在,非常期待與您的又一次邂逅

我們努力讓每一次邂逅總能超越期待

  • 效果付費(fèi)
    效果付費(fèi)

    先出效果再付費(fèi)

  • 極速交付
    極速交付

    響應(yīng)速度快,有效節(jié)省客戶時(shí)間

  • 1對(duì)1服務(wù)
    1對(duì)1服務(wù)

    專(zhuān)屬客服對(duì)接咨詢

  • 持續(xù)更新
    持續(xù)更新

    不斷升級(jí)維護(hù),更好服務(wù)用戶