Framework sinkronisasi

Kerangka kerja sinkronisasi secara eksplisit menjelaskan dependensi antara berbagai operasi asinkron dalam sistem grafis Android. Kerangka kerja menyediakan API yang memungkinkan komponen untuk menunjukkan kapan buffer dirilis. Kerangka kerja ini juga memungkinkan primitif sinkronisasi untuk diteruskan di antara {i>driver<i} dari {i>kernel<i} ke ruang pengguna dan di antara proses ruang pengguna itu sendiri.

Misalnya, aplikasi dapat mengantrekan pekerjaan yang harus 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. {i>Window compositor<i} mulai memproses terlebih dahulu dan meneruskan pekerjaan ke pengontrol tampilan. Dengan cara yang sama, CPU bekerja dilakukan sebelumnya. Setelah GPU selesai, pengontrol tampilan langsung menampilkan gambar.

Framework sinkronisasi juga memungkinkan pengimplementasi memanfaatkan sinkronisasi sumber daya dalam komponen perangkat kerasnya 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 adalah diimplementasikan dalam kernel-space.

Manfaat sinkronisasi eksplisit meliputi:

  • Lebih sedikit variasi perilaku 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 yang spesifik untuk hardware.

Ikuti panduan ini saat menerapkan sync_timeline:

  • Berikan nama yang berguna untuk semua pengemudi, linimasa, dan pembatas untuk menyederhanakan proses debug.
  • Mengimplementasikan timeline_value_str dan pt_value_str operator dalam linimasa agar output proses debug lebih mudah dibaca.
  • Implementasikan isian driver_data untuk memberikan library userspace, seperti library GL, akses ke data linimasa pribadi, jika diinginkan. data_driver memungkinkan vendor meneruskan informasi tentang elemen yang tidak dapat diubah sync_fence dan sync_pts untuk membuat command line berdasarkan rekomendasi 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 menyediakan semua hal yang diperlukan fungsi-fungsi lainnya.

sinkronisasi_pt

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

sync_fence

sync_fence adalah kumpulan nilai sync_pt yang sering memiliki induk sync_timeline yang berbeda (seperti untuk layar pengontrol dan GPU). sync_fence, sync_pt, dan sync_timeline adalah primitif utama yang dibutuhkan driver dan userspace gunakan untuk mengkomunikasikan dependensi mereka. Ketika pagar menjadi sinyal, semua perintah yang dikeluarkan sebelum fence dijamin lengkap karena {i>driver<i} {i>kernel<i} atau blok perangkat keras 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, sebuah pagar dapat berisi dua Nilai sync_pt yang menandakan bahwa dua konsumen gambar terpisah selesai untuk membaca {i>buffer.<i} Ketika fence diberi sinyal, produser gambar tahu bahwa baik dikonsumsi oleh konsumen.

Pagar, seperti nilai sync_pt, mulai aktif dan mengubah status berdasarkan status poin mereka. Jika semua nilai sync_pt menjadi sinyal, sync_fence menjadi sinyal. Jika satu sync_pt jatuh menjadi 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 kernel-space yang mengimplementasikan framework sinkronisasi untuk {i>driver<i} perangkat keras tertentu. Pengemudi yang perlu waspada terhadap pagar pada umumnya semua hal yang mengakses atau berkomunikasi dengan {i>Hardware Composer<i}. File utama meliputi:
    • Implementasi 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 sudah ada, fungsi ini akan menerima dma-buf objek tersebut, letakkan buffer tersebut di layar, dan blokir saat buffer 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 lebih kompleks. Saat menampilkan buffer, buffer dikaitkan dengan fence yang menunjukkan kapan {i>buffer<i} akan siap. Anda dapat mengantrekan dan memulai pekerjaan setelah {i>pagar<i} dibersihkan.

Mengantre dan memulai pekerjaan setelah {i>pagar<i} dibersihkan tidak akan menghambat apa pun. Anda segera mengembalikan fence Anda sendiri, yang menjamin saat buffer akan berada di luar layar. Saat Anda mengantrekan {i>buffer<i}, {i>kernel<i} 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 kerangka kerja sinkronisasi {i>kernel<i} dengan bagian userspace dari kerangka kerja Android dan {i>driver<i} yang harus 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 deskriptor file yang merujuk ke sync_pt, {i>driver<i} vendor atau HAL yang menggunakan API harus menutup deskriptor file.
  • Jika {i>driver<i} 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 deskriptor file fence, driver vendor, atau HAL harus menduplikasi deskriptor.

Nama objek fence diganti setiap kali melewati BufferQueue. Dukungan fence kernel memungkinkan fence memiliki string untuk nama, sehingga sinkronisasi menggunakan nama jendela dan indeks buffer yang diantrekan untuk diberi 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 mengenali fence. 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. Tujuan Ekstensi EGL_ANDROID_wait_sync sama dengan EGL_KHR_wait_sync.

Untuk menggunakan ekstensi ini secara terpisah, terapkan EGL_ANDROID_native_fence_sync beserta ekstensi terkait dukungan {i>kernel<i}. Berikutnya, aktifkan EGL_ANDROID_wait_sync di {i>driver<i} Anda. EGL_ANDROID_native_fence_sync ekstensi terdiri dari objek EGLSyncKHR fence native yang berbeda . Oleh karena itu, ekstensi yang berlaku untuk EGLSyncKHR yang sudah ada jenis objek belum tentu berlaku untuk EGL_ANDROID_native_fence objek, menghindari interaksi yang tidak diinginkan.

Ekstensi EGL_ANDROID_native_fence_sync menggunakan native yang sesuai atribut deskriptor file {i>fence<i} yang hanya dapat ditetapkan pada waktu pembuatan dan tidak dapat langsung dikueri dari objek sinkronisasi yang sudah ada. Atribut ini dapat disetel 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 fence Android native dari Objek EGLSyncKHR.

Gunakan panggilan fungsi DupNativeFenceFD() untuk mengekstrak EGLSyncKHR dari deskriptor file fence Android native. Ini memiliki hasil yang sama dengan kueri atribut {i>set<i}, tetapi mematuhi sesuai dengan konvensi bahwa penerima menutup pagar (oleh karena itu duplikat operasi). Terakhir, menghancurkan objek EGLSyncKHR akan menutup atribut fence internal.

Integrasi Hardware Composer

Hardware Composer menangani tiga jenis fence sinkronisasi:

  • Acquire fence diteruskan bersama dengan buffer input untuk 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. J melepaskan sinyal {i>fence <i}saat HWC tidak lagi menggunakan {i>buffer <i}sebelumnya karena {i>buffer<i} saat ini telah menggantikan penyangga sebelumnya pada 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.
  • Pagar yang ada 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 dikembalikan, aman untuk menulis ke {i> buffer <i}target SurfaceFlinger lagi, jika berlaku. Untuk tampilan virtual, fence yang ada akan ditampilkan saat aman untuk dibaca dari buffer output.