Senkronize edilmemiş ipucuyla düşük gecikmeli oluşturma

Joe Medley
Joe Medley

Ekran kalemi oluşturmadaki farklılıklar

Web için oluşturulan ekran kalemi tabanlı çizim uygulamalarında uzun süredir gecikme sorunları yaşanıyor. Bunun nedeni, web sayfasının grafik güncellemelerini DOM ile senkronize etmesidir. Çizim uygulamalarında 50 milisaniyeden uzun gecikmeler, kullanıcının el-göz koordinasyonunu engelleyerek uygulamaların kullanımını zorlaştırabilir.

canvas.getContext() için desynchronized ipucu, her zamanki DOM güncelleme mekanizmasını atlayan farklı bir kod yolu çağırır. Bunun yerine ipucu, temeldeki sisteme birleştirme işlemini mümkün olduğunca atlamasını söyler ve bazı durumlarda tuvalin temel arabelleği doğrudan ekranın ekran denetleyicisine gönderilir. Bu, oluşturucu birleştirici sırası kullanıldığında oluşabilecek gecikmeyi ortadan kaldırır.

Ne kadar iyi?

Sintel'in eş zamanlı oluşturulması

Koda ulaşmak istiyorsanız ileri kaydırın. Bunu çalışırken görmek için dokunmatik ekranlı bir cihaza ve tercihen bir ekran kalemine ihtiyacınız vardır. (Parmaklar da işe yarar.) Varsa 2d veya webgl örneklerini deneyin. Geri kalanlar için bu özelliği uygulayan mühendislerden biri olan Miguel Casas'ın hazırladığı bu demoya göz atın. Demoyu açın, oynat'a basın, ardından kaydırma çubuğunu rastgele ve hızlı bir şekilde ileri geri hareket ettirin.

Bu örnekte Blender açık film projesi olan Durian'ın Sintel adlı kısa filminden bir dakikalık, yirmi bir saniyelik bir klip kullanılmaktadır. Bu örnekte film, içeriği aynı anda bir <canvas> öğesine oluşturulan <video> öğesinde oynatılır. Birçok cihaz bu işlemi yırtılmadan yapabilir. Bununla birlikte, örneğin ChromeOS gibi ön arabellek oluşturma işlevi olan cihazlarda yırtılma görülebilir. (Film harika ama üzücü. Gördükten sonra bir saat boyunca işe yaramamıştım. Kendinizi uyarılmış olarak düşünün.)

İpucunu kullanma

Düşük gecikme süresi, canvas.getContext() uygulamasına desynchronized eklemekten daha fazlasıdır. Sorunları tek tek ele alacağım.

Tuvali oluştur

Başka bir API'de önce özellik algılamadan bahsedeceğim. desynchronized ipucu için önce kanvası oluşturmalısınız. canvas.getContext() işlevini çağırın ve buna true değeriyle yeni desynchronized ipucunu iletin.

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

Özellik algılama

Ardından getContextAttributes() numaralı telefonu arayın. Döndürülen özellik nesnesinin desynchronized özelliği varsa test edin.

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

Titreme önleniyor

Doğru şekilde kodlamazsanız titremenize yol açabilecek iki durum vardır.

Chrome'un da dahil olduğu bazı tarayıcılar, çerçeveler arasında WebGL tuvallerini temizler. Ekran denetleyicisinin arabelleği boşken okuması mümkündür ve bu da görüntünün titremesine yol açar. Bunu önlemek için preserveDrawingBuffer değerini true olarak ayarlayın.

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

Titreme, kendi çizim kodunuzda ekran bağlamını temizlediğinizde de ortaya çıkabilir. Temizlemeniz gerekirse ekran dışı bir çerçeve arabelleğine çizin ve daha sonra bunu ekrana kopyalayın.

Alfa kanalları

Alfanın true (doğru) değerine ayarlandığı yarı saydam bir tuval öğesinin senkronizasyonu yine de kaldırılabilir ancak üzerinde başka DOM öğesi olmamalıdır.

Yalnızca bir tane olabilir

canvas.getContext() için yapılan ilk çağrıdan sonra bağlam özelliklerini değiştiremezsiniz. Bu her zaman doğrudur, ancak farkında değilseniz veya unu unutursanız tekrar etmek sizi hayal kırıklığına uğratabilir .

Örneğin, bir bağlam aldığımı ve alfayı false (yanlış) olarak belirttiğimi, ardından kodumun ilerleyen bölümlerinde aşağıda gösterildiği gibi alfayı true (doğru) olarak ayarlamış ikinci kez canvas.getContext() çağırıyorum.

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,
});

ctx1 ve ctx2 öğelerinin aynı nesne olduğu açık değil. Alfa hâlâ yanlıştır ve alfanın doğru değerine eşit olduğu bir bağlam hiçbir zaman oluşturulmaz.

Desteklenen tuval türleri

getContext() parametresine iletilen ilk parametre contextType değeridir. getContext() hakkında zaten bilginiz varsa "2d" bağlam türleri dışında herhangi bir şeyin desteklenip desteklenmediğini merak edersiniz. Aşağıdaki tabloda, desynchronized destekleyen bağlam türleri gösterilmektedir.

contextType Bağlam türü nesnesi

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

Sonuç

Bunun daha fazlasını görmek isterseniz örneklere göz atın. Yukarıda açıklanan video örneğine ek olarak, hem "2d" hem de 'webgl' bağlamlarını gösteren örnekler bulunmaktadır.