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

Joe Medley
Joe Medley

Ekran kalemi oluşturmadaki farklılıklar

Web için tasarlanmış, ekran kalemi tabanlı çizim uygulamaları, web sayfasının grafik güncellemelerini DOM ile senkronize etmesi gerektiğinden uzun süredir gecikme sorunlarından muzdariptir. Herhangi bir çizim uygulamasında 50 milisaniyeden uzun gecikmeler, kullanıcının el-göz koordinasyonunu etkileyerek uygulamaların kullanımını zorlaştırabilir.

canvas.getContext() için desynchronized ipucu, normal DOM güncelleme mekanizmasını atlayan farklı bir kod yolunu çağırır. Bunun yerine ipucu, temel sistemden mümkün olduğunca fazla kompozisyon atlamasını ister ve bazı durumlarda kanvasın temel arabelleği doğrudan ekranın görüntü kontrolörüne gönderilir. Bu sayede, oluşturma aracısı derleyici sırasının kullanılmasından kaynaklanan gecikmeler ortadan kaldırılır.

Ne kadar iyi?

Sintel'in eş zamanlı oluşturulması

Kodu görmek için aşağı kaydırın. Bu özelliğin nasıl çalıştığını görmek için dokunmatik ekranlı bir cihaza ve tercihen bir ekran kalemine ihtiyacınız vardır. (Parmaklar da kullanılabilir.) Varsa 2d veya webgl örneklerini deneyin. Bu özelliği uygulayan mühendislerden biri olan Miguel Casas'ın bu demosuna göz atın. Demoyu açın, oynat düğmesine basın ve ardından kaydırma çubuğunu rastgele ve hızlı bir şekilde ileri geri hareket ettirin.

Bu örnekte, Blender açık film projesi Durian'ın Sintel kısa filminden bir dakika yirmi bir saniyelik bir klip kullanılmıştır. Bu örnekte, film bir <video> öğesinde oynatılır ve içeriği aynı anda bir <canvas> öğesinde oluşturulur. Çoğu cihaz bunu yırtılma olmadan yapabilir ancak ChromeOS gibi ön tampon oluşturma özelliğine sahip cihazlarda yırtılma olabilir. (Film harika ama kalbinizi burkuyor. Bunu gördükten sonra bir saat boyunca hiçbir şey yapamadım. Uyarıldınız.)

İpucunu kullanma

Düşük gecikmeyi kullanmanın canvas.getContext()'a desynchronized eklemekten daha fazlası vardır. Sorunları tek tek ele alacağım.

Kanvası oluşturma

Başka bir API'de önce özellik algılamayı tartışırdım. desynchronized ipucunu kullanmak için önce kanvası oluşturmanız gerekir. canvas.getContext() işlevini çağırın ve true değerine sahip 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 özellikler nesnesinde desynchronized özelliği varsa bunu test edin.

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

Titremeyi önleme

Kodu doğru şekilde yazmamanız durumunda titreşime neden olabilecek iki durum vardır.

Chrome da dahil olmak üzere bazı tarayıcılar, kareler arasında WebGL tuvallerini temizler. Ekran denetleyicisinin, boşken arabelleği okuması ve bunun sonucunda resmin titremesine neden olması mümkündür. 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
});

Titreşim, kendi çizim kodunuzda ekran bağlamını temizlediğinizde de ortaya çıkabilir. Temizlemeniz gerekiyorsa ekran dışı bir çerçeve önbelleği çizin ve ardından bunu ekrana kopyalayın.

Alfa kanalları

Alfa değerinin doğru olarak ayarlandığı yarı saydam bir kanvas öğesi yine de senkronize edilebilir ancak üzerinde başka DOM öğeleri bulunmamalıdır.

Yalnızca bir tane

canvas.getContext() çağrısı yapıldıktan sonra bağlam özelliklerini değiştiremezsiniz. Bu durum her zaman geçerlidir ancak bu konuyu tekrar hatırlatmak, bu konuda bilgi sahibi değilseniz veya unutmuşsanız can sıkıcı durumların önüne geçebilir .

Örneğin, bir bağlam aldığımı ve alpha değerini false olarak belirttiğimi, ardından kodumun daha ileri bir yerinde alpha değerini aşağıda gösterildiği gibi true olarak ayarlayarak canvas.getContext() işlevini ikinci kez çağırdığımı varsayalım.

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'un aynı nesne olduğu açık değildir. Alfa değeri hâlâ yanlıştır ve alfa değeri doğru olan bir bağlam hiçbir zaman oluşturulmaz.

Desteklenen tuval türleri

getContext() işlevine iletilen ilk parametre contextType olur. getContext() ile zaten aşina iseniz "2D" bağlam türleri dışında başka bir şeyin desteklenip desteklenmediğini merak ediyorsunuzdur. Aşağıdaki tabloda, desynchronized özelliğini destekleyen bağlam türleri gösterilmektedir.

contextType Bağlam türü nesnesi

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

Sonuç

Daha fazlasını görmek için örneklere göz atın. Daha önce açıklanan video örneğine ek olarak hem '2d' hem de 'webgl' bağlamlarını gösteren örnekler de vardır.