Cara menggambar browser. Laporan Yandex

Sampai baru-baru ini, saya bekerja di tim Yandex.Browser dan membuat presentasi di konferensi YaTalks setelah pengalaman ini. Laporan itu tentang apa yang dimiliki browser di bawah tenda dan bagaimana halaman Anda berubah menjadi piksel di layar. Frontend minimum, hanya bagian dalam browser, hanya hardcore.



- Halo semuanya, nama saya Kostya. Anehnya, sekarang saya bekerja di tim jaringan virtual Yandex.Cloud. Sebelum itu, saya telah bekerja di tim Browser selama lebih dari lima tahun, jadi hari ini saya akan berbicara tentang hal-hal yang umum bagi kami dan Anda.

Seperti yang Anda duga, saya tidak begitu mengerti di bagian depan. Jika Anda berbicara kepada saya tentang Bereaksi atau hal lain seperti itu, saya mungkin tidak akan mengerti Anda. Tetapi saya melakukan banyak hal di browser: decoding video, logika bisnis. Termasuk saya menghabiskan banyak waktu melakukan hal-hal yang berbeda dalam rendering browser. Hari ini kita akan memiliki, misalnya, program pendidikan tentang perangkat internal browser. Saya akan mencoba membahas hal-hal paling menarik yang kami lakukan di Yandex.Browser atau Google di Chromium.



Jika kita berbicara tentang rendering di browser, maka ini adalah hal yang sangat rumit, yang terdiri dari sejumlah besar komponen. Pertama-tama, Anda harus mengunduh sumber daya untuk menunjukkannya. Maka Anda harus mengurai mereka, membangun pohon DOM, gaya, tata letak, dll. Tiga poin pertama kemungkinan besar akrab bagi Anda. Laporan saya akan lebih fokus pada tiga bagian lainnya: Lukisan, Rasterisasi, dan Penggabungan - apa yang terjadi di bawah tenda ketika Anda sudah menulis tata letak. Hanya dengan kata-kata saja sepertinya itu tentang hal yang sama - pada kenyataannya, ini adalah komponen yang sama sekali berbeda.



Mari kita mulai dengan Pengecatan dan Pengomposisian. Tentang apa semua ini? Mari kita kembali ke banyak, bertahun-tahun yang lalu, ketika web tidak serumit sekarang, ketika tidak ada semua jenis 3D, animasi CSS dan hal-hal lainnya. Lalu bagaimana menggambar browser? Bayangkan bahwa Anda memiliki halaman Anda, di atasnya beberapa elemen indah, gambar, dll. Browser dicat semua ini pada satu tekstur yang kuat, dalam blok memori yang besar. Dia tahu cara menggambar setiap elemen, dan jika kami memiliki perubahan, mereka disorot dengan warna kuning, sesuatu seperti yang berikut terjadi.

Browser mengumpulkan mereka di area yang ditunjukkan di sini dengan warna biru. Ada perubahan di area ini, mari kita gambarkan kembali. Semua yang ada di area ini digambar ulang dan disalin ke teksturnya.

Itu bekerja untuk dirinya sendiri. Kemudian orang-orang pintar datang dengan animasi CSS 3D, hal-hal lain. Kami dapat memiliki banyak rendering di tempat yang berbeda. Jika kita memutar satu pemintal, menggambar ulang seluruh elemen pie yang berada di bawahnya tidak terlalu efektif.



Kemudian orang pintar lainnya memutuskan untuk mengulang semuanya sedikit. Kami memiliki semacam pohon DOM, kami membangunnya di memori. Ini adalah objek plus, mereka dibandingkan dengan tata letak apa yang Anda tulis.



Dan kemudian keajaiban mulai terjadi. Browser mengonversi seluruh pohon DOM ke pohon Objek Render. Hal ini tahu cara menggambar setiap elemen DOM tertentu. Artinya, dia tahu apa yang perlu dilakukan agar sesuatu muncul di layar alih-alih pohon atau elemen-P Anda.



Pohon berikutnya adalah pohon lapisan. Apa ini Setiap elemen kami dapat dikaitkan dengan satu lapisan, dan satu Lapisan Render dapat berisi beberapa objek sekaligus. Mengapa ini dilakukan? Ini ditunjukkan dengan sangat baik di sini. Kami menghasilkan seperangkat lapisan, masing-masing memiliki elemen tertentu. Sekarang, anggaplah sesuatu berubah pada salah satu layer - animasi terjadi, elemen cap terbang. Lalu kita menggambar ulang hanya satu lapisan, dan sisanya, misalnya latar belakang, tetap tidak berubah. Kami kemudian hanya menempelkannya ke komposit dan pada output kami mendapatkan gambar akhir - kerangka animasi saat ini.



Ada sekumpulan alasan untuk membuat layer baru. Misalnya, sebuah layer dibuat untuk menyajikan animasi CSS 3D, kanvas, elemen video di atasnya - secara umum, sesuatu yang berkaitan dengan animasi berat, cocok untuk menggambar ulang secara terpisah dari semua konten lainnya.



Namun pendekatan ini memiliki beberapa masalah. Sekarang Anda perlu menyalakan bahan bakar. Pikirkan tentang apa yang akan digambarkan di sini? Hanya ada dua elemen.



Di sini Meskipun, tampaknya, unsur-unsur itu terletak satu per satu. Mengapa kanvas terbang? Di negara kami, mereka diatur secara berurutan, saya tidak mengatur pesanan apa pun.



Mari menyulitkan. Di sini kita memiliki div lain, seperti ini.



Secara umum, perilaku yang diharapkan. Kami memiliki div di atas div, tetapi kanvas untuk beberapa alasan di atas. Keajaiban! Oke, mari kita tambahkan contoh ini lagi.



Tepat satu baris telah berubah, saya menambahkan transformasi.



Dan sekarang kita memiliki segalanya yang terletak dengan benar - setidaknya dalam hal kanvas dan div. Tetapi div ini masih terletak di bawah, meskipun itu adalah elemen berikutnya dalam tata letak kita.

Ini disebut bug pengomposisian fundamental. Jika Anda mencari pelacak Chromium, Anda akan melihat banyak bug yang ditautkan dengan yang kuno. Dia disebut itu.



Jadi apa yang terjadi? Seperti yang saya katakan, beberapa elemen diberikan pada Layer Render, beberapa tidak. Beberapa ditarik bersama dengan yang lain. Berikut ini terjadi: elemen div tetap di lapisan yang sama dengan latar belakang. Kanvas menabrak lapisan yang terpisah. Dan z-pemesanan hanya dilakukan antar lapisan. Karena kami memiliki latar belakang dan div di satu layer dan kanvas di layer lain, kami mendapatkan bug: kanvas tumpang tindih dengan div.

Tapi begitu kita memindahkan elemen div ini ke layer terpisah dan mulai menggunakan z-order secara normal, ia juga mulai memahami siapa yang ada di belakang siapa. Dan di sini semuanya diterjemahkan "normal".



Dan salah satu inisiatif terakhir yang telah dikembangkan selama beberapa tahun adalah yang disebut Slimming Paint, yang seharusnya memperbaikinya. Artinya adalah bahwa kita perlu memisahkan Lukisan dari pementasan, yaitu, memahami apa yang perlu dilakukan untuk menggambar elemen-elemen ini, dari bagaimana kemudian menyusun mereka satu sama lain. Jika kita memiliki tata letak yang sederhana, itu berubah menjadi sesuatu seperti itu. Ada daftar perintah sederhana yang perlu Anda lakukan untuk mendapatkan konten halaman. Dan jika kita kembali ke contoh ini, akan terlihat seperti ini.



Yaitu, kami katakan: ini cat untuk Anda, ini isinya untuk Anda - tolong beri saya sesuatu. Itu memberikan daftar untuk rendering, yang pergi ke Kompositor, dan Kompositor memahami bagaimana membagi semua konten menjadi beberapa lapisan sehingga mereka biasanya berada relatif satu sama lain.

Dan jika Anda belum menyadarinya, ini adalah tangkapan layar dari Chrome. Saya membuatnya sekitar dua minggu yang lalu, yaitu, bug itu masih hidup. Proyek belum selesai, sekarang sedang dalam proses pengembangan.



Yaitu, Kompositor dari daftar ini dan beberapa pengetahuan rahasia yang lolos dapat memahami bagaimana cara meletakkannya ke dalam lapisan.



Selain fakta bahwa pendekatan ini pada dasarnya akan memperbaiki bug ini, kami juga mendapatkan perubahan rendering yang cukup murah. Misalkan kita memiliki daftar perintah draw dan perubahan terjadi - misalkan elemen B pergi, elemen E ditambahkan. Kemudian kita bisa menyimpan kedua daftar bersama tanpa khawatir tentang pohon, dll. Pada output kita mendapatkan daftar elemen baru untuk rendering, dan, mungkin, daftar layer baru yang akan dikompilasi di masa depan.

Ini adalah cerita pendek tentang apa yang terjadi ketika browser mengimplementasikan Paint, dan apa yang terjadi setelah ia mencoba membuat layer.

Mari kita beralih ke topik lain: Rasterisasi. Hanya dalam Rasterisasi di Yandex.Browser, banyak hal telah dilakukan, dan saya juga melakukan ini. Apa arti rasterisasi? Pada output dari tahap sebelumnya, ketika kita melakukan Paint, ada daftar perintah yang harus kita implementasikan untuk mendapatkan beberapa jenis gambar. Rasterisasi adalah transformasi daftar perintah menjadi piksel nyata.





Jika Anda membuka More tools → tab Rendering di inspektur browser, maka ada tanda centang Batas layer. Dan Anda melihat grid seperti itu. Apa yang sedang terjadi di sini? Saat browser menggambar halaman, itu sebenarnya tidak melakukan semuanya sekarang. Browser mengambil dan memecah setiap lapisan menjadi sejumlah kotak kecil seperti itu. Secara historis, mereka berukuran 256 x 256 piksel. Artinya, setiap lapisan dibagi menjadi begitu banyak tekstur yang terpisah. Isi dari ubin saat ini kemudian ditarik ke setiap tekstur, dan kemudian mereka semua direkatkan menjadi satu tekstur besar.



Ini sangat membantu. Pertama-tama, kita hanya dapat menggambar ulang ubin yang telah diubah. Tetapi itu juga memungkinkan kita untuk memprioritaskan rendering. Artinya, pertama-tama, ubin yang dilihat pengguna, yang disebut viewport, harus digambar. Maka kita harus segera menggambar perbatasan, inilah yang ada di sekitar viewport. Selanjutnya adalah arah dari gulungan: jika digulir ke bawah, kita menarik sebanyak mungkin ke bawah. Jika naik - gambarlah sebanyak mungkin ke atas. Jika kita masih memiliki kuota memori, kita akan menggambar sesuatu yang lain, tetapi bukan fakta bahwa itu akan tetap pada titik ini.



Jadi kami mendapatkan pembaruan konten yang cukup murah di halaman. Misalkan kita mengambil bingkai saat ini dan pengguna menonaktifkan sesuatu - misalnya, teks yang disorot. Kemudian kami hanya menggambar ubin yang telah berubah.



Yaitu, ubin hijau adalah ubin yang tetap dari rendering sebelumnya, yang merah yang kami gambarkan kembali. Namun pendekatan ini memiliki kelebihan lain.



Kita dapat melakukan - dan Chrome melakukannya - yang disebut optimasi redraws kecil. Misalkan Anda memiliki semacam pendorong, kursor, atau sesuatu seperti itu melakukan sedikit menggambar ulang dalam persegi panjang kecil. Maka kita tidak perlu menggambar ulang seluruh kotak. Ini logis. Misalnya, jika kursor kami berkedip, maka hanya kursor yang digambar ulang. Ini sangat menghemat CPU.



Optimasi selanjutnya telah mereka lakukan. Di mana bisa ada inefisiensi? Apakah ubinnya digeser? Ide bagus, tapi saya cenderung ke yang lain. Ini hanya kotak putih. Ini adalah ubin putih di mana tidak ada satu piksel pun yang diambil. Tapi itu adalah tekstur. Membutuhkan memori 256 hingga 256 kali empat byte.



Optimalisasi lain yang ditemukan di Chrome: dan mari kita ambil petak-petak ini, satu warna, dan menyandikannya bukan dengan sekelompok piksel, tetapi, pada kenyataannya, dengan koordinator, ukuran dan warna. Internet sekarang penuh dengan halaman dengan banyak area monokrom untuk monitor besar. Dan halaman seperti itu dioptimalkan sesuai, kami mendapatkan banyak penghematan memori.

Kami di Yandex melangkah lebih jauh dan memutuskan untuk melakukan percobaan yang lebih spesifik. Menurut Anda di mana Anda bisa menabung lebih banyak?

Kami memiliki ubin. Konten di dalamnya terletak di beberapa area kecil - sebuah strip, kata Yandex. Mengapa kita perlu menggambar secara keseluruhan, jika kontennya sangat kecil, dan yang lainnya monokrom?



Apa yang telah kita lakukan Inilah yang secara spesifik saya lakukan. Kami membagi setiap ubin menjadi lima ubin. Jika konten di dalamnya hanya di tengah, maka kami memilih tekstur untuk konten ini hanya untuk apa yang dilakukan di tengah. Ini area merah. Segala sesuatu yang lain kita kode dengan cara yang sama - ukuran, koordinat, dan warna.



Artinya, khususnya di halaman ini, semua area ini sekarang menjadi non-tekstur. Bukan byte dalam memori yang digunakan, tetapi hanya perintah tentang apa yang perlu kita gambar di sini, isi dengan satu warna. Ini memberi kami penghematan rata-rata sekitar 40% pada memori GPU per pengguna.



Pada halaman yang lebih kompleks, terlihat seperti ini. Mengingat bahwa halaman yang lebih kompleks menggunakan lebih banyak lapisan, dan setiap lapisan adalah ubin yang terpisah, Anda dapat menyimpan sedikit di setiap lapisan.

Jika Anda mengaktifkan tanda centang ini sekarang, Anda tidak akan melihat kotak persegi panjang seperti itu, tetapi yang ini.



Apa itu, mengapa ubin begitu luas di sini, dan mengapa jumlahnya sedikit? Arti di sini adalah sebagai berikut. Di Chrome, mereka berpikir: mengapa kita tidak hanya mengkomposisikan perangkat keras, tetapi juga merender perangkat keras. Apa yang mereka lakukan Kami memiliki daftar perintah tentang apa yang perlu dilakukan: menggambar persegi panjang, isi dengan warna, dll. Semua ini berlaku untuk GPU, dan GPU menarik tekstur seperti itu. Redrawing sangat cepat, jadi ubin juga bisa dibuat besar. Berikut ini adalah sedikit video serigala, tetapi itu menunjukkan dengan sangat baik keuntungan yang terjadi pada ponsel karena fakta bahwa rendering menjadi perangkat keras dipercepat. Saya pikir perbedaannya di sini sangat, sangat nyata.

Komunikasi antara pengembang browser dan vendor front-end tampaknya sangat berguna bagi saya. Ini tidak sering terjadi, tetapi memberi banyak manfaat. Karena itu, ketika kolega kami dari departemen lain datang kepada kami dan bertanya bagaimana membuat tata letak lebih cepat dan lebih baik, kami mencoba untuk membantu mereka dan berbicara tentang tempat-tempat di mana ada sesuatu yang tidak optimal dan Anda dapat mempercepat.

Dan saya tidak akan bosan mengulangi saran saya. (Saya tidak akan mengutip di sini, ada laporan besar terpisah tentang hal ini. - Komentar penulis.)

Di sini saya telah menyusun satu set tautan yang bermanfaat, tentang rendering dan tidak hanya, tetapi juga sedikit tentang Yandex.Browser. Terima kasih

Source: https://habr.com/ru/post/id468165/


All Articles