Framework sinkronisasi

Framework sinkronisasi secara eksplisit menjelaskan dependensi antara berbagai operasi asinkron dalam sistem grafis Android. Framework ini menyediakan API yang memungkinkan komponen menunjukkan kapan buffering dirilis. Framework ini juga memungkinkan primitif sinkronisasi untuk diteruskan antara driver dari kernel ke ruang pengguna dan antara proses userspace itu sendiri.

Misalnya, aplikasi dapat mengantrekan pekerjaan yang akan dilakukan di GPU. GPU mulai menggambar gambar tersebut. Meskipun gambar belum digambar ke dalam memori, pointer buffer diteruskan ke komposer jendela beserta pagar yang menunjukkan kapan pekerjaan GPU akan selesai. Kompositor jendela mulai memproses terlebih dahulu dan meneruskan pekerjaan ke pengontrol tampilan. Dengan cara yang sama, pekerjaan CPU dilakukan terlebih dahulu. Setelah GPU selesai, pengontrol tampilan akan segera menampilkan gambar.

Framework sinkronisasi juga memungkinkan pengimplementasi memanfaatkan resource sinkronisasi di komponen hardware mereka sendiri. Terakhir, framework memberikan visibilitas ke dalam pipeline grafis untuk membantu proses proses debug.

Sinkronisasi eksplisit

Sinkronisasi eksplisit memungkinkan produsen dan konsumen buffering grafis memberi sinyal saat mereka selesai menggunakan buffering. Sinkronisasi eksplisit diimplementasikan di ruang kernel.

Manfaat sinkronisasi eksplisit meliputi:

  • Variasi perilaku yang lebih sedikit antar-perangkat
  • Dukungan proses debug yang lebih baik
  • Metrik pengujian yang ditingkatkan

Framework sinkronisasi memiliki tiga jenis objek:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline adalah linimasa yang meningkat secara monoton yang harus diterapkan vendor untuk setiap instance driver, seperti konteks GL, pengontrol tampilan, atau blitter 2D. sync_timeline menghitung tugas yang dikirim ke kernel untuk hardware tertentu. sync_timeline memberikan jaminan tentang urutan operasi dan memungkinkan implementasi khusus hardware.

Ikuti panduan ini saat menerapkan sync_timeline:

  • Berikan nama yang berguna untuk semua driver, linimasa, dan fence guna menyederhanakan proses debug.
  • Terapkan operator timeline_value_str dan pt_value_str dalam linimasa agar output proses debug lebih mudah dibaca.
  • Terapkan driver_data isi untuk memberi library ruang pengguna, seperti library GL, akses ke data linimasa pribadi, jika diinginkan. data_driver memungkinkan vendor meneruskan informasi tentang sync_fence dan sync_pts yang tidak dapat diubah untuk membuat command line berdasarkan informasi tersebut.
  • Jangan izinkan ruang pengguna membuat atau memberi sinyal pagar secara eksplisit. Membuat sinyal/pagar secara eksplisit akan mengakibatkan serangan denial of service yang menghentikan fungsi pipeline.
  • Jangan akses elemen sync_timeline, sync_pt, atau sync_fence secara eksplisit. API ini menyediakan semua fungsi yang diperlukan.

sync_pt

sync_pt adalah nilai atau titik tunggal pada sync_timeline. Titik memiliki tiga status: aktif, diberi sinyal, dan error. Titik dimulai dalam status aktif dan bertransisi ke status sinyal atau error. Misalnya, saat konsumen gambar tidak lagi memerlukan buffer, sync_pt akan diberi sinyal sehingga produsen gambar tahu bahwa buffer dapat ditulis lagi.

sync_fence

sync_fence adalah kumpulan nilai sync_pt yang sering memiliki induk sync_timeline yang berbeda (seperti untuk pengontrol layar dan GPU). sync_fence, sync_pt, dan sync_timeline adalah primitif utama yang digunakan driver dan ruang pengguna untuk mengomunikasikan dependensinya. Saat pagar diberi sinyal, semua perintah yang dikeluarkan sebelum pagar dijamin akan selesai karena driver kernel atau blok hardware mengeksekusi perintah secara berurutan.

Framework sinkronisasi memungkinkan beberapa konsumen atau produsen memberikan sinyal saat mereka selesai menggunakan buffering, yang menyampaikan informasi dependensi dengan satu parameter fungsi. Pagar didukung oleh deskriptor file dan diteruskan dari ruang kernel ke ruang pengguna. Misalnya, fence dapat berisi dua nilai sync_pt yang menandakan bahwa dua konsumen gambar terpisah selesai membaca buffer. Saat fence diberi sinyal, produsen gambar tahu bahwa kedua konsumen sudah selesai mengonsumsi.

Pagar, seperti nilai sync_pt, mulai aktif dan mengubah status berdasarkan status titiknya. Jika semua nilai sync_pt diberi sinyal, sync_fence akan diberi sinyal. Jika satu sync_pt berada dalam status error, seluruh sync_fence akan memiliki status error.

Keanggotaan di sync_fence tidak dapat diubah setelah pagar dibuat. Untuk mendapatkan lebih dari satu titik dalam pagar, penggabungan dilakukan dengan menambahkan titik dari dua pagar yang berbeda ke pagar ketiga. Jika salah satu titik tersebut diberi sinyal di pagar asal dan yang lainnya tidak, pagar ketiga juga tidak akan berada dalam status diberi sinyal.

Untuk menerapkan sinkronisasi eksplisit, sediakan hal berikut:

  • Subsistem ruang kernel yang menerapkan framework sinkronisasi untuk driver hardware tertentu. Driver yang perlu mengetahui pagar umumnya adalah apa pun yang mengakses atau berkomunikasi dengan Hardware Composer. File utama meliputi:
    • Penerapan inti:
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • Dokumentasi di kernel/common/Documentation/sync.txt
    • Library untuk berkomunikasi dengan ruang kernel di platform/system/core/libsync
  • Vendor harus menyediakan pagar sinkronisasi yang sesuai sebagai parameter ke fungsi validateDisplay() dan presentDisplay() di HAL.
  • Dua ekstensi GL terkait pagar (EGL_ANDROID_native_fence_sync dan EGL_ANDROID_wait_sync) serta dukungan pagar di driver grafik.

Studi kasus: Mengimplementasikan driver tampilan

Untuk menggunakan API yang mendukung fungsi sinkronisasi, kembangkan driver tampilan yang memiliki fungsi buffering tampilan. Sebelum framework sinkronisasi ada, fungsi ini akan menerima objek dma-buf, menempatkan buffering tersebut di layar, dan memblokir saat buffering terlihat. Contoh:

/*
 * assumes buffer is ready to be displayed.  returns when buffer is no longer on
 * screen.
 */
void display_buffer(struct dma_buf *buffer);

Dengan framework sinkronisasi, fungsi display_buffer menjadi lebih kompleks. Saat menampilkan buffering, buffering dikaitkan dengan pagar yang menunjukkan kapan buffering akan siap. Anda dapat mengantrekan dan memulai pekerjaan setelah pagar dihapus.

Membuat antrean dan memulai pekerjaan setelah pagar dihapus tidak akan memblokir apa pun. Anda segera menampilkan pagar Anda sendiri, yang menjamin kapan buffering akan dinonaktifkan dari layar. Saat Anda mengantrekan buffer, kernel akan mencantumkan dependensi dengan framework sinkronisasi:

/*
 * displays buffer when fence is signaled.  returns immediately with a fence
 * that signals when buffer is no longer displayed.
 */
struct sync_fence* display_buffer(struct dma_buf *buffer, struct sync_fence
*fence);

Integrasi sinkronisasi

Bagian ini menjelaskan cara mengintegrasikan framework sinkronisasi ruang kernel dengan bagian ruang pengguna dari framework Android dan driver yang harus berkomunikasi satu sama lain. Objek ruang kernel direpresentasikan sebagai deskripsi file di ruang pengguna.

Konvensi integrasi

Ikuti konvensi antarmuka HAL Android:

  • Jika API menyediakan deskripsi file yang merujuk ke sync_pt, driver vendor atau HAL yang menggunakan API harus menutup deskripsi file.
  • Jika driver vendor atau HAL meneruskan deskriptor file yang berisi sync_pt ke fungsi API, driver vendor atau HAL tidak boleh menutup deskriptor file.
  • Untuk terus menggunakan deskripsi file pagar, driver vendor atau HAL harus menduplikasi deskripsi.

Objek pagar diganti namanya setiap kali melewati BufferQueue. Dukungan pagar kernel memungkinkan pagar memiliki string untuk nama, sehingga framework sinkronisasi menggunakan nama jendela dan indeks buffering yang diantrekan untuk memberi nama pagar, seperti SurfaceView:0. Hal ini berguna dalam proses debug untuk mengidentifikasi sumber deadlock saat nama muncul dalam output /d/sync dan laporan bug.

Integrasi ANativeWindow

ANativeWindow mendukung pagar. dequeueBuffer, queueBuffer, dan cancelBuffer memiliki parameter fence.

Integrasi OpenGL ES

Integrasi sinkronisasi OpenGL ES bergantung pada dua ekstensi EGL:

  • EGL_ANDROID_native_fence_sync menyediakan cara untuk menggabungkan atau membuat deskriptor file pagar Android native dalam objek EGLSyncKHR.
  • EGL_ANDROID_wait_sync memungkinkan jeda sisi GPU, bukan sisi CPU, sehingga GPU menunggu EGLSyncKHR. Ekstensi EGL_ANDROID_wait_sync sama dengan ekstensi EGL_KHR_wait_sync.

Untuk menggunakan ekstensi ini secara independen, terapkan ekstensi EGL_ANDROID_native_fence_sync beserta dukungan kernel terkait. Selanjutnya, aktifkan ekstensi EGL_ANDROID_wait_sync di driver Anda. Ekstensi EGL_ANDROID_native_fence_sync terdiri dari jenis objek EGLSyncKHR pagar native yang berbeda. Akibatnya, ekstensi yang berlaku untuk jenis objek EGLSyncKHR yang ada tidak selalu berlaku untuk objek EGL_ANDROID_native_fence, sehingga menghindari interaksi yang tidak diinginkan.

Ekstensi EGL_ANDROID_native_fence_sync menggunakan atribut deskripsi file pagar native yang sesuai yang hanya dapat ditetapkan pada waktu pembuatan dan tidak dapat dikueri secara langsung dari objek sinkronisasi yang ada. Atribut ini dapat disetel ke salah satu dari dua mode:

  • Deskriptor file fence yang valid menggabungkan deskriptor file fence Android native yang ada dalam objek EGLSyncKHR.
  • -1 membuat deskriptor file pagar Android native dari objek EGLSyncKHR.

Gunakan panggilan fungsi DupNativeFenceFD() untuk mengekstrak objek EGLSyncKHR dari deskripsi file pagar Android native. Tindakan ini memiliki hasil yang sama dengan mengkueri atribut yang ditetapkan, tetapi mematuhi konvensi bahwa penerima menutup pagar (sehingga operasi duplikasi). Terakhir, menghancurkan objek EGLSyncKHR akan menutup atribut pagar internal.

Integrasi Hardware Composer

Hardware Composer menangani tiga jenis pembatas sinkronisasi:

  • Fence akuisisi diteruskan bersama buffer input ke panggilan setLayerBuffer dan setClientTarget. Ini mewakili penulisan yang tertunda ke buffer dan harus memberikan sinyal sebelum SurfaceFlinger atau HWC mencoba membaca dari buffer terkait untuk melakukan komposisi.
  • Pagar rilis diambil setelah panggilan ke presentDisplay menggunakan panggilan getReleaseFences. Ini mewakili pembacaan yang tertunda dari buffering sebelumnya di lapisan yang sama. Pagar rilis akan memberikan sinyal saat HWC tidak lagi menggunakan buffer sebelumnya karena buffer saat ini telah menggantikan buffer sebelumnya di layar. fence rilis diteruskan kembali ke aplikasi bersama dengan buffer sebelumnya yang akan diganti selama komposisi saat ini. Aplikasi harus menunggu hingga sinyal pagar rilis sebelum menulis konten baru ke buffer yang ditampilkan kepada mereka.
  • Present fences ditampilkan, satu per frame, sebagai bagian dari panggilan ke presentDisplay. Pagar yang ditampilkan menunjukkan kapan komposisi frame ini telah selesai, atau sebagai alternatif, saat hasil komposisi frame sebelumnya tidak lagi diperlukan. Untuk tampilan fisik, presentDisplay menampilkan fence yang ada saat frame saat ini muncul di layar. Setelah fence yang ada ditampilkan, Anda dapat menulis ke buffer target SurfaceFlinger lagi dengan aman, jika berlaku. Untuk tampilan virtual, fence yang ada akan ditampilkan jika aman untuk dibaca dari buffer output.