Rendering latensi rendah dengan petunjuk yang tidak disinkronkan

Joe Medley
Joe Medley

Perbedaan rendering stilus

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

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

Seberapa bagus produk tersebut?

Rendering Sintel secara bersamaan

Jika Anda ingin sampai ke kodenya, scroll ke depan. Untuk melihatnya cara kerjanya, Anda memerlukan perangkat dengan layar sentuh, dan sebaiknya stilus. (Jari jari juga bisa.) Jika Anda memilikinya, coba sampel 2d atau webgl. Untuk Anda yang lainnya, lihat demo oleh Miguel Casas ini, salah satu engineer yang menerapkan fitur ini. Buka demo, tekan putar, lalu gerakkan {i>slider<i} bolak-balik secara acak dan cepat.

Contoh ini menggunakan klip berdurasi satu menit dua puluh satu detik dari film pendek Sintel karya 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 menimbulkan kerusakan, meskipun perangkat dengan rendering buffer depan seperti ChromeOS misalnya, mungkin mengalami kerusakan. (Filmnya bagus, tapi patah hati. Aku tidak berguna selama satu jam setelah melihatnya. Anggap diri Anda sudah diberi peringatan.)

Menggunakan petunjuk

Ada lebih banyak hal dalam menggunakan latensi rendah daripada menambahkan desynchronized ke canvas.getContext(). Saya akan membahas masalah ini satu per satu.

Membuat kanvas

Di 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, ujilah.

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 Anda berkedip jika tidak membuat kode dengan benar.

Beberapa browser termasuk Chrome menghapus kanvas WebGL di antara frame. Pengontrol tampilan dapat membaca buffer saat kosong yang menyebabkan gambar digambar 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 offscreen, lalu salin ke layar.

Saluran alfa

Elemen kanvas transparan, dengan alfa yang disetel ke benar (true), masih dapat didesinkronisasi, 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 dapat menghilangkan rasa frustrasi jika Anda tidak menyadarinya atau lupa .

Misalnya, saya mendapatkan konteks dan menetapkan alfa sebagai false, lalu di suatu tempat dalam kode saya, saya akan memanggil canvas.getContext() untuk kedua kalinya dengan alfa ditetapkan ke true seperti yang ditunjukkan di bawah ini.

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 yang sama dengan benar tidak akan pernah dibuat.

Jenis kanvas yang didukung

Parameter pertama yang diteruskan ke getContext() adalah contextType. Jika Anda 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 lagi, lihat contohnya. Selain contoh video yang sudah dijelaskan ada contoh yang menampilkan konteks '2d' dan 'webgl'.