Apple Metal di MAPS.ME

gambar Halo semuanya!

Di dunia ada sejumlah besar aplikasi di OpenGL, dan tampaknya Apple tidak setuju dengan ini. Dimulai dengan iOS 12 dan MacOS Mojave, OpenGL telah ditinggalkan. Kami telah mengintegrasikan Apple Metal di MAPS.ME dan siap untuk berbagi pengalaman dan hasil kami. Kami akan memberi tahu Anda bagaimana mesin grafis kami refactored, kesulitan apa yang harus kami hadapi dan, yang paling penting, berapa banyak FPS yang kami miliki sekarang.

Semua orang yang tertarik atau mempertimbangkan untuk menambahkan dukungan Apple Metal ke mesin grafis dipersilakan untuk kucing.

Masalah


Mesin grafis kami dirancang sebagai lintas-platform, dan karena OpenGL, pada kenyataannya, satu-satunya API grafis lintas-platform untuk set platform yang kami minati (iOS, Android, MacOS dan Linux), kami memilihnya sebagai dasarnya. Kami tidak membuat level abstraksi tambahan yang akan menyembunyikan fitur-fitur khusus untuk OpenGL, tetapi, untungnya, meninggalkan potensi untuk implementasinya.

Dengan munculnya generasi baru API grafis Apple Metal dan Vulkan, kami, tentu saja, mempertimbangkan kemungkinan kemunculannya dalam aplikasi kami, namun, kami dihentikan oleh yang berikut:

  1. Vulkan hanya bisa bekerja di Android dan Linux, dan Apple Metal hanya bisa bekerja di iOS dan MacOS. Kami tidak ingin kehilangan lintas-platformness pada tingkat API grafik, ini akan mempersulit pengembangan dan proses debugging, akan meningkatkan jumlah pekerjaan.
  2. Aplikasi di Apple Metal tidak dapat dibangun dan dijalankan pada simulator iOS (omong-omong, sampai sekarang), yang juga akan mempersulit pengembangan kami dan tidak akan memungkinkan kami untuk sepenuhnya menyingkirkan OpenGL.
  3. Kerangka Qt, yang kami gunakan untuk membuat alat internal, hanya mendukung OpenGL ( Vulkan sekarang didukung ).
  4. Apple Metal tidak memiliki dan tidak memiliki C ++ API, yang akan memaksa kami untuk membuat abstraksi tidak hanya untuk runtime, tetapi juga untuk fase pembuatan aplikasi, ketika bagian dari mesin dikompilasi dalam Objective-C ++, dan yang lain, secara substansial lebih besar, di C ++.
  5. Kami tidak siap untuk membuat mesin terpisah atau cabang kode terpisah khusus untuk iOS.
  6. Implementasi dievaluasi setidaknya enam bulan dalam pekerjaan satu pengembang grafis.

Ketika pada musim semi tahun 2018 Apple mengumumkan transfer OpenGL ke status yang ditinggalkan, menjadi jelas bahwa tidak mungkin lagi untuk menunda, dan masalah di atas perlu dipecahkan dengan satu atau lain cara. Selain itu, kami telah lama berupaya mengoptimalkan kecepatan aplikasi dan konsumsi daya, dan Apple Metal tampaknya dapat membantu.

Pemilihan keputusan


Hampir segera kami memperhatikan MoltenVK . Kerangka kerja ini mengemulasi Vulkan API menggunakan Apple Metal, dan kode sumbernya baru-baru ini dibuka. Menggunakan MoltenVK, tampaknya, akan memungkinkan penggantian OpenGL dengan Vulkan, dan tidak harus berurusan dengan integrasi Apple Metal yang terpisah sama sekali. Selain itu, pengembang Qt telah menolak dukungan terpisah untuk rendering di Apple Metal yang mendukung MoltenVK. Namun, kami dihentikan:

  • kebutuhan untuk mendukung perangkat Android di mana Vulkan tidak tersedia;
  • ketidakmampuan untuk memulai pada simulator iOS tanpa kehadiran fallback pada OpenGL;
  • ketidakmampuan untuk menggunakan alat Apple untuk debugging, profil dan mengkompilasi shader, karena MoltenVK menghasilkan shader real-time untuk Apple Metal dari kode sumber SPIR-V atau GLSL;
  • kebutuhan untuk menunggu pembaruan dan perbaikan bug MoltenVK ketika versi baru Logam dirilis;
  • ketidakmungkinan pengoptimalan halus khusus untuk Logam, tetapi tidak spesifik atau tidak ada untuk Vulkan.

Ternyata kami perlu menyimpan OpenGL, yang berarti kami tidak dapat melakukannya tanpa mengabstraksikan mesin dari API grafis. Apple Metal, OpenGL ES, dan di masa depan Vulkan, akan digunakan untuk membuat komponen internal independen dari mesin grafis, yang dapat sepenuhnya dipertukarkan. OpenGL akan memainkan peran opsi mundur ketika Metal atau Vulkan tidak tersedia karena satu dan lain alasan.

Rencana implementasi adalah sebagai berikut:

  1. Refactoring mesin grafis untuk abstrak API grafik yang digunakan.
  2. Render ke Apple Metal untuk versi aplikasi iOS.
  3. Buat tolok ukur yang tepat untuk kecepatan render dan konsumsi daya untuk melihat apakah API grafik modern tingkat rendah dapat menguntungkan produk.

Perbedaan utama antara OpenGL dan Logam


Untuk memahami bagaimana cara abstrak API grafis, pertama mari kita tentukan apa perbedaan konseptual utama antara OpenGL dan Logam.

  1. Dipercaya, dan bukan tanpa alasan, bahwa Logam adalah API tingkat rendah. Namun, ini tidak berarti bahwa Anda harus menulis di assembler atau mengimplementasikan rasterisasi sendiri. Logam dapat disebut API tingkat rendah dalam arti bahwa ia melakukan sejumlah kecil tindakan implisit, yaitu, hampir semua tindakan harus ditulis kepada programmer sendiri. OpenGL melakukan banyak hal secara implisit, mulai dari mendukung referensi implisit ke konteks OpenGL dan menghubungkan konteks ini ke aliran di mana ia dibuat.
  2. Dalam Logam, "tidak" validasi waktu-nyata dari tim. Dalam mode debug, validasi, tentu saja, ada dan dibuat jauh lebih baik daripada di banyak API lain, sebagian besar karena integrasi yang erat dengan Xcode. Tetapi ketika program dikirim ke pengguna, maka tidak ada validasi lagi, program hanya crash pada kesalahan pertama. Tidak perlu dikatakan, OpenGL hanya crash dalam kasus yang paling ekstrim. Praktik yang paling umum: untuk mengabaikan kesalahan dan terus bekerja.
  3. Logam dapat mengkompilasi shader dan membangun perpustakaan dari mereka. Di OpenGL, shader dikompilasi dari sumber dalam proses program, karena ini bertanggung jawab atas implementasi OpenGL tingkat rendah yang spesifik pada perangkat tertentu. Perbedaan dan / atau kesalahan dalam implementasi shader compiler kadang-kadang menyebabkan bug yang fantastis, terutama pada perangkat Android merek Cina.
  4. OpenGL aktif menggunakan mesin negara, yang menambahkan efek samping ke hampir setiap fungsi. Dengan demikian, fungsi OpenGL bukan fungsi murni, dan urutan dan riwayat panggilan seringkali penting. Logam tidak menggunakan status secara implisit dan tidak mempertahankannya lebih lama dari yang diperlukan untuk rendering. Negara ada sebagai objek yang dibuat sebelumnya dan gagal.

Mesin grafis refactoring dan embedding Metal


Proses refactoring mesin grafis pada dasarnya terdiri dari menemukan solusi terbaik untuk menghilangkan fitur OpenGL yang telah digunakan mesin kami secara aktif. Embedding Metal, mulai dari salah satu tahapan, berjalan paralel.

  • Seperti yang sudah disebutkan, OpenGL API memiliki entitas implisit yang disebut konteks. Konteksnya dikaitkan dengan utas tertentu, dan fungsi OpenGL yang dipanggil utas itu sendiri menemukan dan menggunakan konteks ini. Logam, Vulkan (ya, dan API lainnya, misalnya, Direct3D) tidak berfungsi dengan cara ini, mereka memiliki objek eksplisit serupa yang disebut perangkat atau instance. Pengguna sendiri menciptakan objek-objek ini dan bertanggung jawab atas transfer mereka ke berbagai subsistem. Melalui objek-objek ini semua panggilan ke perintah grafis dilakukan.

    Kami menyebut objek abstrak kami konteks grafis, dan dalam kasus OpenGL itu hanya menghiasi panggilan perintah OpenGL, dan dalam kasus Logam itu berisi antarmuka MTLDevice root melalui mana perintah Logam dipanggil.

    Tentu saja, saya harus mendistribusikan objek ini (dan karena kami memiliki rendering multi-threaded, maka bahkan beberapa objek seperti itu) di semua subsistem.

    Kami menyembunyikan penciptaan antrian perintah, penyandi, dan manajemennya di dalam konteks grafik, agar tidak menyebar entitas yang tidak ada di OpenGL.
  • Prospek hilangnya validasi perintah grafis pada perangkat pengguna tidak secara terbuka menyenangkan bagi kami. Berbagai perangkat dan versi OS tidak dapat sepenuhnya dicakup oleh departemen QA kami. Oleh karena itu, kami harus menambahkan log terperinci di mana kami sebelumnya menerima kesalahan yang berarti dari API grafis. Tentu saja, validasi ini ditambahkan hanya ke lokasi yang berpotensi berbahaya dan kritis dari mesin grafis, karena mencakup seluruh mesin dengan kode diagnostik praktis tidak mungkin dan umumnya berbahaya bagi kinerja. Kenyataan baru adalah bahwa pengujian pengguna dan debugging dengan log sekarang di masa lalu, setidaknya dalam hal rendering.
  • Sistem shader kami sebelumnya tidak cocok untuk refactoring, saya harus menulis ulang sepenuhnya. Intinya di sini bukan hanya kompilasi dari shader dan validasinya pada tahap perakitan proyek. OpenGL menggunakan apa yang disebut variabel seragam untuk meneruskan parameter ke shader. Transfer data terstruktur hanya tersedia dengan OpenGL ES 3.0, dan karena kami masih mendukung OpenGL ES 2.0, kami sama sekali tidak menggunakan metode ini. Logam membuat kami menggunakan struktur data untuk melewati parameter, dan untuk OpenGL kami harus membuat bidang struktur pemetaan ke variabel yang seragam. Selain itu, saya harus menulis ulang setiap shader dalam Bahasa Shading Metal.
  • Saat menggunakan objek keadaan, kami harus mencari trik. Di OpenGL, semua negara, sebagai aturan, ditetapkan segera sebelum rendering, dan dalam Metal ini harus objek yang dibuat dan divalidasi sebelumnya. Mesin kami, jelas, menggunakan pendekatan OpenGL, dan refactoring dengan penciptaan awal objek negara sebanding dengan penulisan ulang lengkap mesin. Untuk memotong simpul ini, kami membuat cache negara di dalam konteks grafis. Pertama kali kombinasi unik dari parameter status dihasilkan, objek state dibuat dalam Logam dan ditempatkan di cache. Untuk waktu kedua dan selanjutnya, objek hanya diambil dari cache. Ini berfungsi di peta kami, karena jumlah kombinasi parameter negara yang berbeda tidak terlalu besar (sekitar 20-30). Untuk mesin grafis gim yang kompleks, metode ini tidak cocok.

Hasilnya, setelah sekitar 5 bulan bekerja, kami dapat meluncurkan MAPS.ME untuk pertama kalinya dengan perenderan penuh pada Apple Metal. Sudah waktunya untuk mencari tahu apa yang terjadi.

Pengujian Kecepatan Rendering


Teknik eksperimental


Kami menggunakan berbagai generasi perangkat Apple dalam percobaan. Semuanya diperbarui ke iOS 12. Skrip pengguna yang sama dijalankan pada semua - navigasi peta (bergerak dan penskalaan). Script ditulis untuk menjamin identitas proses yang hampir lengkap dalam aplikasi setiap kali dimulai pada setiap perangkat. Sebagai lokasi pengujian, kami memilih area Los Angeles - salah satu area yang paling banyak dimuat di MAPS.ME.

Pertama, skrip dijalankan dengan rendering pada OpenGL ES 3.0, kemudian pada perangkat yang sama dengan rendering pada Apple Metal. Antara awal, aplikasi benar-benar dibongkar dari memori.
Indikator-indikator berikut diukur:

  • FPS (bingkai per detik) untuk seluruh bingkai;
  • FPS untuk bagian frame yang hanya bergerak dalam rendering, tidak termasuk persiapan data dan operasi frame-by-frame lainnya;
  • Persentase frame lambat (lebih dari ~ 30 ms), mis. yang oleh mata manusia bisa dianggap sebagai tersentak.

Saat mengukur FPS, menggambar langsung pada layar perangkat tidak termasuk, karena sinkronisasi vertikal dengan kecepatan refresh layar tidak memungkinkan memperoleh hasil yang andal. Karena itu, bingkai itu ditarik ke dalam tekstur dalam memori. Untuk menyinkronkan CPU dan GPU, OpenGL menggunakan panggilan tambahan untuk glFinish , sementara Apple Metal menggunakan waitUntilCompleted untuk MTLFrameCommandBuffer .

iPhone 6siPhone 7+iPhone 8
OpenglLogamOpenglLogamOpenglLogam
Fps106160159221196298
FPS (render saja)157596247597271833
Fraksi bingkai lambat (<30 fps)4,13%1,25%5,45%0,76%1,5%0,29%

iPhone XiPad Pro 12.9 '
OpenglLogamOpenglLogam
Fps145210104137
FPS (render saja)248705147463
Fraksi bingkai lambat (<30 fps)0,15%0,15%17,52%4,46%

iPhone 6siPhone 7+iPhone 8iPhone XiPad Pro 12.9 '
Akselerasi bingkai pada Logam (N kali)1,51.391,521.451.32
Akselerasi rendering pada Logam (N kali)3.782.413.072.843.15
Peningkatan frame lambat (N kali)3.37.175.1713.93

Analisis Hasil


Rata-rata, peningkatan kinerja bingkai menggunakan Apple Metal adalah 43%. Nilai minimum ditetapkan pada iPad Pro 12.9 '- 32%, maksimum - 52% di iPhone 8. Ada ketergantungan: semakin rendah resolusi layar, semakin Apple Metal melampaui OpenGL ES 3.0.

Jika kami mengevaluasi bagian frame yang secara langsung bertanggung jawab untuk rendering, maka kecepatan rendering rata-rata pada Apple Metal telah meningkat 3 kali lipat. Ini menunjukkan organisasi yang jauh lebih baik, dan, sebagai hasilnya, efisiensi Apple Metal API dibandingkan dengan OpenGL ES 3.0.

Jumlah frame lambat (lebih dari ~ 30 ms) pada Apple Metal berkurang sekitar 4 kali. Ini berarti bahwa persepsi animasi dan bergerak di sekitar peta menjadi lebih halus. Hasil terburuk tercatat pada iPad Pro 12.9 'dengan resolusi 2732 x 2048 piksel: OpenGL ES 3.0 memberikan sekitar 17,5% bingkai lambat, sementara Apple Metal - hanya 4,5%.

Pengujian daya


Teknik eksperimental


Konsumsi daya diuji pada iPhone 8 di iOS 12. Skenario pengguna yang sama dijalankan - navigasi peta (bergerak dan penskalaan) selama 1 jam. Script ditulis untuk menjamin identitas proses yang hampir lengkap dalam aplikasi pada setiap permulaan. Wilayah Los Angeles juga dipilih sebagai lokasi uji.

Kami menggunakan pendekatan berikut untuk mengukur konsumsi energi. Perangkat tidak terhubung ke pengisian daya. Dalam pengaturan pengembang, pencatatan daya diaktifkan. Sebelum memulai percobaan, perangkat terisi penuh. Percobaan berakhir di akhir skrip. Pada akhir percobaan, kondisi pengisian baterai dicatat, dan log konsumsi daya diimpor ke utilitas untuk membuat profil baterai dalam Xcode. Kami mencatat berapa banyak biaya yang dihabiskan untuk GPU. Selain itu, di sini kami juga mempertimbangkan rendering dengan memasukkan tampilan skema metro dan antialiasing layar penuh.

Kecerahan layar tidak berubah dalam semua kasus. Tidak ada proses lain kecuali sistem dan MAPS.ME dieksekusi. Mode pesawat dihidupkan, Wi-Fi dan GPS dimatikan. Selain itu, beberapa pengukuran kontrol dilakukan.

Akibatnya, untuk masing-masing indikator, perbandingan Logam dengan OpenGL dibentuk, dan kemudian rasio dirata-rata untuk mendapatkan satu perkiraan agregat.

OpenglLogamKeuntungan
Menguras baterai32%28%12,5%
Membuat Profil Penggunaan Baterai di Xcode1,95%1,83%6,16%

Analisis Hasil


Rata-rata, konsumsi daya versi rendering pada Apple Metal telah sedikit meningkat. Konsumsi daya aplikasi GPU kami tidak terlalu terpengaruh, sekitar 2%, karena MAPS.ME tidak dapat disebut sangat sarat dalam hal menggunakan GPU. Keuntungan kecil mungkin dicapai dengan mengurangi biaya komputasi ketika menyiapkan instruksi untuk GPU pada CPU, yang, sayangnya, tidak dapat dibedakan dengan bantuan alat profiling.

Ringkasan


Menanamkan logam menghabiskan biaya 5 bulan untuk pengembangan. Namun, dua pengembang melakukan ini hampir selalu bergantian. Jelas, kami menang secara signifikan dalam menghasilkan kinerja, kami memenangkan sedikit dalam konsumsi energi. Selain itu, kami mendapat kesempatan untuk menyematkan API grafis baru, khususnya Vulkan, dengan upaya yang jauh lebih sedikit. Hampir sepenuhnya "memilah" mesin grafis, sebagai hasilnya, kami menemukan dan memperbaiki beberapa bug lama dan masalah kinerja.

Untuk pertanyaan apakah proyek kami benar-benar perlu dirender di Apple Metal, kami siap menjawab dengan persetujuan. Bukan karena kita mencintai inovasi, atau Apple akhirnya dapat meninggalkan OpenGL. Ini hanya 2018, dan OpenGL muncul di tahun 1997 yang jauh, sekarang saatnya untuk mengambil langkah berikutnya.

PS Sampai kami meluncurkan fitur di semua perangkat iOS. Untuk mengaktifkannya secara manual, ketik ?metal di bilah pencarian dan mulai ulang aplikasi. Untuk mengembalikan rendering ke OpenGL, masukkan perintah ?gl dan restart aplikasi.

PPS MAPS.ME adalah proyek sumber terbuka. Anda dapat membaca kode sumber di github .

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


All Articles