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 diteruskan di antara driver dari kernel ke ruang pengguna dan di antara proses ruang pengguna itu sendiri.

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

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

Sinkronisasi eksplisit

Sinkronisasi eksplisit memungkinkan produser dan konsumen buffer grafis untuk memberi sinyal ketika mereka selesai menggunakan {i>buffer<i}. Sinkronisasi eksplisit diimplementasikan di ruang kernel.

Manfaat sinkronisasi eksplisit meliputi:

  • Variasi perilaku yang lebih sedikit antar-perangkat
  • Dukungan proses debug yang lebih baik
  • Peningkatan metrik pengujian

Framework sinkronisasi memiliki tiga jenis objek:

  • sync_timeline
  • sync_pt
  • sync_fence

linimasa_sinkronisasi

sync_timeline adalah linimasa yang meningkat secara monoton yang yang harus diimplementasikan vendor untuk setiap {i> driver<i}, seperti konteks GL, pengontrol tampilan, atau blitter 2D. sync_timeline jumlah tugas yang dikirimkan ke {i>kernel<i} untuk perangkat keras 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 pagar untuk menyederhanakan proses debug.
  • Mengimplementasikan timeline_value_str dan pt_value_str operator 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 userspace untuk membuat atau memberi sinyal fence secara eksplisit. Eksplisit menghasilkan sinyal/{i>fence<i} menyebabkan serangan {i>denial-of-service<i} yang menghentikan fungsi pipeline.
  • Jangan akses 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 memberi sinyal saat mereka selesai menggunakan buffer, mengomunikasikan informasi dependensi dengan satu fungsi . Pagar didukung oleh deskriptor file dan diteruskan dari {i>kernel<i} ke ruang pengguna. Misalnya, pagar dapat berisi dua nilai sync_pt yang menunjukkan kapan dua konsumen gambar terpisah selesai membaca buffering. Ketika fence diberi sinyal, produser gambar tahu bahwa baik dikonsumsi oleh konsumen.

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 jatuh menjadi status error, seluruh sync_fence akan memiliki status error.

Keanggotaan di sync_fence tidak dapat diubah setelah fence dibuat. Untuk mendapatkan lebih dari satu titik dalam fence, penggabungan adalah dilakukan di mana titik dari dua pagar yang berbeda ditambahkan ke pagar ketiga. Jika salah satu titik itu diberi sinyal di pagar awal dan yang lainnya tidak, pagar ketiga juga tidak akan berada dalam status 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
    • {i>Library<i} untuk berkomunikasi dengan ruang {i>kernel<i} di platform/system/core/libsync
  • Vendor harus menyediakan sinkronisasi yang sesuai fence sebagai parameter untuk validateDisplay() dan Fungsi presentDisplay() di HAL.
  • Dua ekstensi GL terkait fence (EGL_ANDROID_native_fence_sync) dan EGL_ANDROID_wait_sync) serta dukungan fence dalam grafis {i>driver<i}.

Studi kasus: Mengimplementasikan driver tampilan

Untuk menggunakan API yang mendukung fungsi sinkronisasi, mengembangkan driver tampilan yang memiliki fungsi buffer 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 buffer, buffer dikaitkan dengan fence yang menunjukkan kapan {i>buffer<i} akan siap. Anda dapat mengantrekan dan memulai pekerjaan setelah pagar dihapus.

Mengantre dan memulai pekerjaan setelah {i>pagar<i} dibersihkan tidak akan menghambat apa pun. Anda segera menampilkan pagar Anda sendiri, yang menjamin kapan buffering akan dinonaktifkan dari layar. Saat Anda mengantrekan buffering, kernel 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 {i>kernel<i} direpresentasikan sebagai deskriptor file di {i>userspace<i}.

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 deskripsi file yang berisi sync_pt ke fungsi API, driver vendor atau HAL tidak boleh menutup deskripsi 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. Ini sangat membantu dalam {i>debugging<i} untuk mengidentifikasi sumber {i>deadlock<i} ketika nama muncul pada 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 fence Android native EGLSyncKHR objek.
  • EGL_ANDROID_wait_sync memungkinkan kios sisi GPU bukan sisi CPU, sehingga GPU akan menunggu EGLSyncKHR. Ekstensi EGL_ANDROID_wait_sync sama dengan ekstensi EGL_KHR_wait_sync.

Untuk menggunakan ekstensi ini secara terpisah, terapkan EGL_ANDROID_native_fence_sync beserta ekstensi terkait dukungan {i>kernel<i}. Selanjutnya, aktifkan ekstensi EGL_ANDROID_wait_sync di driver Anda. EGL_ANDROID_native_fence_sync ekstensi terdiri dari objek EGLSyncKHR fence 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 ditetapkan ke salah satu dari dua mode:

  • Deskriptor file fence yang valid menggabungkan native yang ada Deskriptor file fence Android 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 operasi tulis yang tertunda ke dalam buffer dan harus memberikan sinyal sebelum SurfaceFlinger atau HWC mencoba membaca dari {i>buffer<i} terkait ke melakukan komposisi.
  • Release fence diambil setelah panggilan ke presentDisplay menggunakan panggilan getReleaseFences. Ini mewakili pembacaan tertunda dari buffer sebelumnya pada 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. Pagar rilis diteruskan kembali ke aplikasi bersama dengan buffer sebelumnya yang akan diganti selama komposisi saat ini. Aplikasi harus menunggu sampai melepaskan sinyal {i>fence<i} sebelum menulis konten baru ke dalam {i>buffer<i} yang dikembalikan kepada mereka.
  • Present fences ditampilkan, satu per frame, sebagai bagian dari panggilan ke presentDisplay. Pagar yang ada menunjukkan kapan komposisi bingkai ini telah selesai, atau alternatifnya, ketika hasil komposisi frame sebelumnya tidak lagi diperlukan. Untuk fisik menampilkan, presentDisplay akan menampilkan fence yang ada saat {i>frame <i}saat ini akan muncul di layar. Setelah pagar yang ada ditampilkan, Anda dapat menulis ke buffer target SurfaceFlinger lagi, jika berlaku. Untuk tampilan virtual, fence yang ada akan ditampilkan saat aman untuk dibaca dari buffer output.