Rendering latensi rendah dengan petunjuk yang tidak disinkronkan

Joe Medley
Joe Medley

Perbedaan dalam rendering stilus

Aplikasi gambar berbasis stilus yang dibuat untuk web telah lama mengalami masalah latensi karena halaman web harus menyinkronkan update grafis dengan DOM. Dalam aplikasi gambar apa pun, latensi yang lebih dari 50 milidetik dapat mengganggu koordinasi tangan-mata pengguna, sehingga aplikasi sulit digunakan.

Petunjuk desynchronized untuk canvas.getContext() memanggil jalur kode yang berbeda yang mengabaikan mekanisme pembaruan DOM biasa. Sebagai gantinya, petunjuk tersebut memberi tahu sistem yang mendasarinya untuk melewati sebanyak mungkin komposisi dan dalam beberapa kasus, buffer dasar kanvas dikirim langsung ke pengontrol tampilan layar. Hal ini menghilangkan latensi yang akan ditimbulkan oleh penggunaan antrean perender compositor.

Seberapa bagus produk ini?

Rendering simultan Sintel

Jika Anda ingin melihat kodenya, scroll ke depan. Untuk melihatnya beraksi, Anda memerlukan perangkat dengan layar sentuh, dan sebaiknya stilus. (Jari juga berfungsi.) Jika Anda memilikinya, coba contoh 2d atau webgl. Untuk Anda yang lain, lihat demo oleh Miguel Casas ini, salah satu engineer yang menerapkan fitur ini. Buka demo, tekan putar, lalu gerakkan penggeser bolak-balik secara acak dan cepat.

Contoh ini menggunakan klip berdurasi satu menit dua puluh satu detik dari film pendek Sintel oleh Durian, project film terbuka Blender. Dalam contoh ini, film diputar di elemen <video> yang kontennya dirender secara bersamaan ke elemen <canvas>. Banyak perangkat dapat melakukannya tanpa tearing, meskipun perangkat dengan rendering buffering depan seperti ChromeOS misalnya mungkin mengalami tearing. (Filmnya bagus, tetapi menyedihkan. Saya tidak berguna selama satu jam setelah melihatnya. Harap perhatikan.)

Menggunakan petunjuk

Ada lebih banyak hal yang dapat dilakukan untuk menggunakan latensi rendah selain menambahkan desynchronized ke canvas.getContext(). Saya akan membahas masalah satu per satu.

Membuat kanvas

Pada API lain, saya akan membahas deteksi fitur terlebih dahulu. Untuk petunjuk desynchronized, Anda harus membuat kanvas terlebih dahulu. Panggil canvas.getContext() dan teruskan petunjuk desynchronized baru dengan nilai true.

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

Deteksi fitur

Selanjutnya, panggil getContextAttributes(). Jika objek atribut yang ditampilkan memiliki properti desynchronized, uji objek tersebut.

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

Menghindari kedipan

Ada dua kasus yang dapat menyebabkan kedipan jika Anda tidak membuat kode dengan benar.

Beberapa browser, termasuk Chrome, menghapus kanvas WebGL di antara frame. Pengontrol layar dapat membaca buffer saat kosong sehingga gambar yang digambar akan berkedip. Untuk menghindari hal ini, tetapkan preserveDrawingBuffer ke true.

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

Flicker juga dapat terjadi saat Anda menghapus konteks layar dalam kode gambar Anda sendiri. Jika Anda harus menghapus, gambar ke framebuffer di luar layar, lalu salin ke layar.

Saluran alfa

Elemen kanvas transparan, yang alpha-nya disetel ke true, masih dapat didesinkronkan, tetapi tidak boleh memiliki elemen DOM lain di atasnya.

Hanya boleh ada satu

Anda tidak dapat mengubah atribut konteks setelah panggilan pertama ke canvas.getContext(). Hal ini selalu benar, tetapi mengulanginya mungkin dapat menghemat ketidaknyamanan jika Anda tidak mengetahui atau lupa .

Misalnya, misalkan saya mendapatkan konteks dan menentukan alpha sebagai salah, lalu di lain waktu dalam kode saya, saya memanggil canvas.getContext() untuk kedua kalinya dengan alpha ditetapkan ke benar seperti yang ditunjukkan di bawah.

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

Tidak jelas bahwa ctx1 dan ctx2 adalah objek yang sama. Alfa masih salah dan konteks dengan alfa sama dengan benar tidak pernah dibuat.

Jenis kanvas yang didukung

Parameter pertama yang diteruskan ke getContext() adalah contextType. Jika sudah terbiasa dengan getContext(), Anda pasti bertanya-tanya apakah ada hal lain selain jenis konteks '2d' yang didukung. Tabel di bawah menunjukkan jenis konteks yang mendukung desynchronized.

contextType Objek jenis konteks

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

Kesimpulan

Jika Anda ingin melihat lebih banyak hal ini, lihat contohnya. Selain contoh video yang telah dijelaskan, ada contoh yang menampilkan konteks '2d' dan 'webgl'.