一歩下がってすでにある機能に手を加えることで、パフォーマンスを大きく向上させることができる場合があります。今回の 速さと好奇心の投稿では、どのように Android 版 Chrome のスクロール操作を改善し、遅いスクロールによるジャンクを最終的に半分に減らすことができたかについて説明します。どのように問題を発見して評価したか、そしてそれがどのように今後のブラウザ エクスペリエンス設計の向上に役立ったかについて、お読みください。
ブラウザのパフォーマンスを測定するときは、ページ読み込み速度やウェブに関する指標を考えるのが一般的です。折りたたみ式などの新しいフォーム ファクタを含め、タッチ操作が一般的なモバイルでは、常にスムーズで応答性が高くなるようにするため、Chrome とのインタラクションも重視しています。特に最近力を入れているのが、スクロール時のジャンクを減らすことです。
先日は、ノイズをフィルタリングして、画面に表示されるコンテンツが瞬間的に移動するように見える現象を減らすことで、Android 版 Chrome のスクロール操作の指標を 2 倍に向上しました。この結果を得るためには、一歩下がって、Android 版 Chrome が iOS 版 Chrome に遅れをとっている理由を理解する必要がありました。
プラットフォーム間で Chrome を比較したところ、あることがわかりました。iOS 版 Chrome のスクロールは一貫してスムーズでしたが、Android 版の Chrome のスクロールは、そこまで指に追従する感じではありませんでした。しかし、指標を確認したところ、ジャンクは時々起こるものの、iOS 版 Chrome と比較したときに感じたほど頻繁に発生するものではありませんでした。つまり、調査が求められる謎の現象が発生したということです。
入出力レートの調査
この指標が示していたのは、入力を受け取るレートが一貫していない場合が多いということです。しかし、入力レートはディスプレイのフレームレートよりも大きいため、通常は少なくとも 1 つの入力イベントで、表示するフレームの生成がトリガーされていました。ただし、このフレームが受け取る入力イベントが少なかったり多かったりすると、たとえ一定の速度でスクロールしていたとしても、画面のコンテンツが一貫性のない形で移動してしまう場合があります。
入力レートとフレームレートが異なるというこの問題は、以前に Chrome で対処しなければならなかった問題です。内部的には、入力を再サンプリングして、生成するフレームに対して相対的な一貫したポイントにおいて指があった場所を予測および推定しています。そのため、各フレームが一定の時間を表すようになり、スクロールは入力イベントのノイズに関係なくスムーズになるはずです。理想的なシナリオを次の図に示します。青い点は実際の入力イベント、緑は再サンプリング後の入力イベントです。再サンプリングしたものではなく、実際の入力イベントを使った場合、画面がスクロールする差分量は変動します。
すでに再サンプリングを行っているのに、問題が発生するのはなぜでしょうか?
苦難と再実装のストーリー
Chrome(と Android)に入力の再サンプリングが追加されたのは、90 Hz デバイスが登場し、上記の問題が目立ち始めた 2019 年です(フレームあたりの入力イベントが 2 つと 1 つで振動します。60 Hz デバイスでは、フレームあたり常に 2 つの入力イベントが一般的です)。Android には複数の再サンプリング アルゴリズム(カルマン、線形など)が実装されていますが、今回のユースケースには、線形再サンプリング(2 点間を線で結んで速度を計算し、指定されたタイムスタンプを補完する)で十分であるという結論に達しました。これにより、ほとんどの Android アプリの問題は修正されましたが、Chrome の問題には対処できませんでした。
これまでの経緯や未加工の入力に対するウェブ仕様の要件の関係で、Chrome ではバッファリングされていない入力が使われています。そのため、入力に適合しないサンプリング レートのデバイスが登場し始めたときに、Chrome になんらかのバージョンの再サンプリングを実装する必要が生じました。下の図から、各フレーム(入力から表示までの時間を測定したもの)が受け取る入力イベントの数は異なることがわかります(最初のフレームは 2 つ、2 番目のフレームは 3 つ、3 番目のフレームは 1 つ)。入力が一貫して到着し、それぞれが正確に 30 ピクセルの変位であれば、次に示すように、1 フレームあたり 60 ピクセルに平滑化するのが理想です。
しかし、もともとの謎を調査している間にわかったのは、現実は上の理想的な状況とは大きく異なることでした。実際の画面の入力の動きは急激で(予想以上に)一貫性がなく、予測によって多少は改善されているものの、期待したほどではありませんでした。左は画面上の実際の指の変位(各点は入力イベント)、右は平滑化後の実際のコンテンツのオフセットの予測結果(各点はフレーム)です。
右側ではフレームは一貫して表示されていますが、互いの変位スパイクのレートは一貫していません(最も激しいのは、-50、-40、-52 の部分です)。人間の指は、(フレームレベルの精度で)このような不連続な動きにはなりません。むしろ、徐々に加速したり減速したりしながら、少しずつ移動したり方向を変えたりします。そのため、ここに問題があると考えました。Chrome の実装を詳しく調べたところ、そこに根本的な違いがあることがわかりました(Android の実装をコピーしたものだと思われます)。