非同期ヒントを使用した低レイテンシのレンダリング

Joe Medley
Joe Medley

タッチペンのレンダリングの違い

ウェブ用に構築されたタッチペン ベースの描画アプリケーションでは、ウェブページがグラフィックの更新を DOM と同期させる必要があるため、レイテンシの問題に長年悩まされてきました。描画アプリでは、レイテンシが 50 ミリ秒を超えると、ユーザーの操作が妨げられ、アプリが使いにくくなる可能性があります。

canvas.getContext()desynchronized ヒントは、通常の DOM 更新メカニズムをバイパスする別のコードパスを呼び出します。その代わりに、基となるシステムは可能な限り合成をスキップし、場合によっては、キャンバスの基になるバッファが画面のディスプレイ コントローラに直接送られます。これにより、レンダラ コンポジタ キューの使用で発生するレイテンシがなくなります。

評価を教えてください。

Sintel の同時レンダリング

コードを表示するには、先にスクロールしてください。実際の動作を確認するには、タッチ スクリーンを備えたデバイスが必要です。可能であればタッチペンが必要です。(指でも効果を発揮します)。存在する場合は、2d または webgl サンプルを試してください。その他の方は、この機能を実装したエンジニアの 1 人である Miguel Casas によるデモをご覧ください。デモを開いて再生ボタンを押し スライダーを前後に素早く動かします

この例では、Blender のオープン ムービー プロジェクト、Durian の短編映画「Sintel」の 1 分 21 秒のクリップを使用します。この例では、映画は <video> 要素で再生されます。この要素の内容は同時に <canvas> 要素にレンダリングされます。多くのデバイスでは、テアリングなしでこの処理を行うことができます。ただし、たとえば ChromeOS など、フロント バッファ レンダリングを使用するデバイスではテアリングが発生する可能性があります。(映画も素晴らしいけれど、胸が痛くなります。 見ただけで 1 時間は役に立たなかった。事前に警告されたことをご考慮ください)。

ヒントの使用

低レイテンシを使用するメリットは、canvas.getContext()desynchronized を追加することだけではありません。1 つずつ問題を確認していきます

キャンバスを作成する

別の API では、特徴検出について説明します。desynchronized ヒントでは、まずキャンバスを作成する必要があります。canvas.getContext() を呼び出し、値が true の新しい desynchronized ヒントを渡します。

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('2d', {
  desynchronized: true,
  // Other options. See below.
});

機能検出

次に、getContextAttributes() を呼び出します。返された属性オブジェクトに desynchronized プロパティがある場合は、テストします。

if (ctx.getContextAttributes().desynchronized) {
  console.log('Low latency canvas supported. Yay!');
} else {
  console.log('Low latency canvas not supported. Boo!');
}

ちらつきの回避

コードを正しく記述しないと、ちらつきが発生する場合が 2 つあります。

Chrome を含む一部のブラウザでは、フレーム間の WebGL キャンバスがクリアされます。空のときにディスプレイ コントローラがバッファを読み取ると、画像がちらつく可能性があります。これを回避するには、preserveDrawingBuffertrue に設定します。

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('webgl', {
  desynchronized: true,
  preserveDrawingBuffer: true
});

独自の描画コードで画面のコンテキストをクリアした場合にも、ちらつきが発生することがあります。クリアする必要がある場合は、画面外のフレームバッファに描画してから画面にコピーします。

アルファ版チャンネル

半透明のキャンバス要素(アルファが true に設定されている要素)は引き続き非同期にできますが、その上に他の DOM 要素を含めることはできません。

1 つのみ

canvas.getContext() の最初の呼び出し後にコンテキスト属性を変更することはできません。これは常に当てはまることですが、これを繰り返すと、知らない場合や忘れてしまった場合にイライラするかもしれません。

たとえば、コンテキストを取得し、alpha を false に指定したとします。コードの後の部分で、以下に示すように alpha を true に設定して canvas.getContext() を 2 回呼び出します。

const canvas = document.querySelector('myCanvas');
const ctx1 = canvas.getContext('2d', {
  alpha: false,
  desynchronized: true,
});

//Some time later, in another corner of code.
const ctx2 = canvas.getContext('2d', {
  alpha: true,
  desynchronized: true,
});

ctx1ctx2 が同じオブジェクトであることは明らかではありません。alpha は引き続き false であり、alpha が true のコンテキストは作成されません。

サポートされているキャンバス タイプ

getContext() に渡される最初のパラメータは contextType です。getContext() についてすでによくご存じであれば、「2d」コンテキスト タイプ以外のものがサポートされていることでしょう。次の表に、desynchronized をサポートするコンテキスト タイプを示します。

contextType Context タイプ オブジェクト

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

おわりに

詳細を確認したい場合は、サンプルをご覧ください。前述の動画の例に加えて、2dwebgl の両方のコンテキストを示す例があります。