低延遲轉譯與未同步提示

Joe Medley
Joe Medley

觸控筆算繪的差異

專為網路建構的觸控筆繪圖應用程式長期以來,一直受到延遲問題造成的困擾,因為網頁必須同步處理圖形更新與 DOM。在任何繪圖應用程式中,超過 50 毫秒的延遲時間可能會幹擾使用者的手眼協調,導致應用程式難以使用。

canvas.getContext()desynchronized 提示叫用了可略過一般 DOM 更新機制的不同程式碼路徑。而是指示基礎系統盡可能略過組合,在某些情況下,畫布的基礎緩衝區會直接傳送至螢幕的顯示控制器。這樣可以消除使用轉譯器合成器佇列所造成的延遲時間。

評價如何?

同時算繪 Sintel

如要查看驗證碼,請向下捲動。如要查看實際運作情形,您需要一部配備觸控螢幕的裝置,而且最好使用觸控筆。(手指也能使用)。如有,請嘗試使用 2dwebgl 範例。至於其他部分,請觀看Miguel Casas 提供的示範影片,這是實作這項功能的工程師之一。開啟試用版並按下播放按鈕 然後隨機快速地來回移動滑桿

這個範例使用《Blender (Blender) 開放式電影專案 Durian 的 Durian 這個短片 Sintel 的 1 分 21 秒片段。在此範例中,電影透過 <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
});

如果在自己的繪圖程式碼中清除畫面內容,也可能會發生閃爍情形。如果一定要清除,請繪製至螢幕外 framebuffer,然後複製到螢幕上。

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' 兩種背景資訊的範例。