低延遲轉譯與未同步提示

Joe Medley
Joe Medley

觸控筆算繪的差異

以觸控筆為基礎的繪圖應用程式在網頁上建構時,一直會遇到延遲問題,因為網頁必須將圖形更新內容與 DOM 同步。在任何繪圖應用程式中,延遲時間超過 50 毫秒可能會影響使用者的手眼協調能力,導致應用程式難以使用。

canvas.getContext()desynchronized 提示會叫用不同的程式碼路徑,以便略過一般 DOM 更新機制。相反地,提示會告知底層系統盡可能略過合成作業,在某些情況下,畫布的底層緩衝區會直接傳送至螢幕的顯示控制器。這可消除使用轉譯器合成器佇列所造成的延遲。

評價如何?

同時算繪 Sintel

如要查看程式碼,請向下捲動。如要實際操作,您需要使用具備觸控螢幕的裝置,最好還要搭配觸控筆。(手指也適用)。如果有,請試試 2DWebGL 範例。其他人請參閱 Miguel Casas 的示範影片,他是實作這項功能的工程師之一。開啟示範內容,按下播放鍵,然後快速隨機移動滑桿。

這個範例使用了 Blender 開放式電影專案 Durian 的短片「Sintel」Sintel中,長度為一分二十一秒的短片片段。在這個範例中,電影會在 <video> 元素中播放,而該元素的內容會同時算繪至 <canvas> 元素。許多裝置都能在不撕裂的情況下執行此操作,但具備前緩衝區轉譯功能的裝置 (例如 ChromeOS) 可能會出現撕裂情形。(這部電影很棒,但很令人心碎。看到這則訊息後,我花了一個小時才恢復正常。隨便你。)

使用提示

使用低延遲時間的做法不只限於將 desynchronized 新增至 canvas.getContext()。我會逐一檢查問題。

建立畫布

在另一個 API 上,我會先討論功能偵測。對於 desynchronized 提示,您必須先建立畫布。呼叫 canvas.getContext(),並傳遞新的 desynchronized 提示,其值為 true

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!');
}

避免閃爍

如果程式碼編寫不正確,可能會導致閃爍現象。

部分瀏覽器 (包括 Chrome) 會在影格之間清除 WebGL 畫布。顯示控制器可能會在緩衝區空白時讀取緩衝區,導致繪製的圖片閃爍。如要避免這種情況,請將 preserveDrawingBuffer 設為 true

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

在您自己的繪圖程式碼中清除螢幕內容時,也會發生閃爍現象。如果您必須清除,請繪製至螢幕外幀格緩衝區,然後將其複製到螢幕上。

Alpha 通道

半透明的畫布元素 (alpha 設為 true) 仍可解除同步,但不得在其上方放置任何其他 DOM 元素。

只能有一個

您無法在第一次呼叫 canvas.getContext() 後變更內容參照屬性。這一直都是事實,但如果您不清楚或忘記,重複說明可能會讓您少點挫折。

舉例來說,假設我取得了內容,並將 alpha 指定為 false,然後在程式碼的後面某處,我會再次呼叫 canvas.getContext(),並將 alpha 設為 true,如下所示。

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 背景資訊類型物件

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

結論

如要進一步瞭解這項功能,請查看範例。除了上述影片範例,我們也提供同時顯示 '2d''webgl' 情境的範例。