Kerangka kerja sinkronisasi secara eksplisit menjelaskan ketergantungan antara berbagai operasi asinkron dalam sistem grafis Android. Kerangka kerja ini menyediakan API yang memungkinkan komponen menunjukkan kapan buffer dilepaskan. Kerangka kerja ini juga memungkinkan sinkronisasi primitif diteruskan antara driver dari kernel ke ruang pengguna dan antar proses ruang pengguna itu sendiri.
Misalnya, suatu aplikasi mungkin mengantri pekerjaan untuk dilakukan di GPU. GPU mulai menggambar gambar itu. Meskipun gambar belum dimasukkan ke dalam memori, penunjuk buffer diteruskan ke kompositor jendela bersama dengan pagar yang menunjukkan kapan pekerjaan GPU akan selesai. Kompositor jendela mulai memproses sebelumnya dan meneruskan pekerjaan ke pengontrol tampilan. Dengan cara yang sama, pekerjaan CPU dilakukan sebelumnya. Setelah GPU selesai, pengontrol tampilan segera menampilkan gambar.
Kerangka kerja sinkronisasi juga memungkinkan pelaksana memanfaatkan sumber daya sinkronisasi di komponen perangkat kerasnya sendiri. Terakhir, kerangka kerja ini memberikan visibilitas ke dalam pipeline grafis untuk membantu proses debug.
Sinkronisasi eksplisit
Sinkronisasi eksplisit memungkinkan produsen dan konsumen buffer grafis memberi sinyal ketika mereka selesai menggunakan buffer. Sinkronisasi eksplisit diimplementasikan di ruang kernel.
Manfaat sinkronisasi eksplisit meliputi:
- Variasi perilaku antar perangkat lebih sedikit
- Dukungan debugging yang lebih baik
- Metrik pengujian yang ditingkatkan
Framework sinkronisasi memiliki tiga tipe objek:
-
sync_timeline
-
sync_pt
-
sync_fence
sinkronisasi_garis waktu
sync_timeline
adalah garis waktu yang meningkat secara monoton yang harus diterapkan vendor untuk setiap instance driver, seperti konteks GL, pengontrol tampilan, atau blitter 2D. sync_timeline
menghitung pekerjaan yang dikirimkan ke kernel untuk perangkat keras tertentu. sync_timeline
memberikan jaminan tentang urutan operasi dan memungkinkan implementasi khusus perangkat keras.
Ikuti panduan berikut saat menerapkan sync_timeline
:
- Berikan nama yang berguna untuk semua driver, garis waktu, dan pagar untuk menyederhanakan proses debug.
- Terapkan operator
timeline_value_str
danpt_value_str
di timeline untuk membuat keluaran proses debug lebih mudah dibaca. - Terapkan pengisian
driver_data
untuk memberikan perpustakaan ruang pengguna, seperti perpustakaan GL, akses ke data garis waktu pribadi, jika diinginkan.data_driver
memungkinkan vendor menyampaikan informasi tentangsync_fence
dansync_pts
yang tidak dapat diubah untuk membuat baris perintah berdasarkan keduanya. - Jangan izinkan ruang pengguna untuk secara eksplisit membuat atau memberi sinyal pagar. Membuat sinyal/pagar secara eksplisit menghasilkan serangan penolakan layanan yang menghentikan fungsionalitas saluran pipa.
- Jangan mengakses elemen
sync_timeline
,sync_pt
, atausync_fence
secara eksplisit. API menyediakan semua fungsi yang diperlukan.
sinkronisasi_pt
sync_pt
adalah nilai atau titik tunggal pada sync_timeline
. Suatu titik mempunyai tiga keadaan: aktif, diberi sinyal, dan kesalahan. Poin dimulai dalam keadaan aktif dan transisi ke keadaan sinyal atau kesalahan. Misalnya, ketika konsumen gambar tidak lagi memerlukan buffer, sync_pt
diberi sinyal sehingga produsen gambar tahu bahwa tidak apa-apa untuk menulis ke buffer lagi.
sinkronisasi_pagar
sync_fence
adalah kumpulan nilai sync_pt
yang sering kali memiliki induk sync_timeline
berbeda (misalnya untuk pengontrol tampilan dan GPU). sync_fence
, sync_pt
, dan sync_timeline
adalah primitif utama yang digunakan driver dan ruang pengguna untuk mengomunikasikan dependensinya. Ketika pagar diberi sinyal, semua perintah yang dikeluarkan sebelum pagar dijamin selesai karena driver kernel atau blok perangkat keras menjalankan perintah secara berurutan.
Kerangka kerja sinkronisasi memungkinkan banyak konsumen atau produsen memberi sinyal ketika mereka selesai menggunakan buffer, mengomunikasikan informasi ketergantungan dengan satu parameter fungsi. Pagar didukung oleh deskriptor file dan diteruskan dari ruang kernel ke ruang pengguna. Misalnya, pagar dapat berisi dua nilai sync_pt
yang menandakan ketika dua konsumen gambar terpisah selesai membaca buffer. Ketika pagar diberi isyarat, produsen gambar mengetahui bahwa kedua konsumen sudah selesai mengonsumsi.
Pagar, seperti nilai sync_pt
, mulai aktif dan mengubah status berdasarkan status poinnya. Jika semua nilai sync_pt
menjadi sinyal, sync_fence
menjadi sinyal. Jika salah satu sync_pt
berada dalam status kesalahan, seluruh sync_fence
memiliki status kesalahan.
Keanggotaan di sync_fence
tidak dapat diubah setelah pagar dibuat. Untuk mendapatkan lebih dari satu titik dalam satu pagar, dilakukan penggabungan dimana titik-titik dari dua pagar berbeda ditambahkan ke pagar ketiga. Jika salah satu titik tersebut diberi isyarat di pagar asal dan yang lainnya tidak, pagar ketiga juga tidak akan berada dalam keadaan diberi isyarat.
Untuk menerapkan sinkronisasi eksplisit, berikan hal berikut:
- Subsistem ruang kernel yang mengimplementasikan kerangka sinkronisasi untuk driver perangkat keras tertentu. Driver yang perlu waspada pada umumnya adalah segala sesuatu yang mengakses atau berkomunikasi dengan Komposer Perangkat Keras. File-file utama meliputi:
- Implementasi inti:
-
kernel/common/include/linux/sync.h
-
kernel/common/drivers/base/sync.c
-
- Dokumentasi di
kernel/common/Documentation/sync.txt
- Perpustakaan untuk berkomunikasi dengan ruang kernel di
platform/system/core/libsync
- Implementasi inti:
- Vendor harus menyediakan pagar sinkronisasi yang sesuai sebagai parameter fungsi
validateDisplay()
danpresentDisplay()
di HAL. - Dua ekstensi GL terkait pagar (
EGL_ANDROID_native_fence_sync
danEGL_ANDROID_wait_sync
) dan dukungan pagar pada driver grafis.
Studi kasus: Menerapkan driver tampilan
Untuk menggunakan API yang mendukung fungsi sinkronisasi, kembangkan driver tampilan yang memiliki fungsi buffer tampilan. Sebelum kerangka sinkronisasi ada, fungsi ini akan menerima objek dma-buf
, menampilkan buffer tersebut, dan memblokir saat buffer terlihat. Misalnya:
/* * assumes buffer is ready to be displayed. returns when buffer is no longer on * screen. */ void display_buffer(struct dma_buf *buffer);
Dengan kerangka sinkronisasi, fungsi display_buffer
menjadi lebih kompleks. Saat menampilkan buffer, buffer dikaitkan dengan pagar yang menunjukkan kapan buffer akan siap. Anda dapat mengantri dan memulai pekerjaan setelah pagar dibersihkan.
Mengantri dan memulai pekerjaan setelah pagar dibersihkan tidak menghalangi apa pun. Anda segera mengembalikan pagar Anda sendiri, yang menjamin kapan buffer akan hilang dari tampilan. Saat Anda mengantri buffer, kernel mencantumkan dependensi dengan kerangka 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 sinkronisasi ruang kernel dengan bagian ruang pengguna kerangka Android dan driver yang harus berkomunikasi satu sama lain. Objek ruang kernel direpresentasikan sebagai deskriptor file di ruang pengguna.
Konvensi integrasi
Ikuti konvensi antarmuka Android HAL:
- Jika API menyediakan deskriptor file yang merujuk ke
sync_pt
, driver vendor atau HAL yang menggunakan API harus menutup deskriptor 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 deskriptor file pagar, driver vendor atau HAL harus menduplikasi deskriptor tersebut.
Objek pagar diganti namanya setiap kali melewati BufferQueue. Dukungan pagar kernel memungkinkan pagar memiliki string untuk nama, sehingga kerangka sinkronisasi menggunakan nama jendela dan indeks buffer yang sedang diantri untuk memberi nama pagar, seperti SurfaceView:0
. Hal ini berguna dalam proses debug untuk mengidentifikasi sumber kebuntuan saat nama muncul di keluaran /d/sync
dan laporan bug.
Integrasi ANativeWindow
ANativeWindow sadar akan pagar. dequeueBuffer
, queueBuffer
, dan cancelBuffer
memiliki parameter pagar.
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 asli di objekEGLSyncKHR
. -
EGL_ANDROID_wait_sync
memungkinkan terhentinya sisi GPU, bukan sisi CPU, sehingga membuat GPU menungguEGLSyncKHR
. EkstensiEGL_ANDROID_wait_sync
sama dengan ekstensiEGL_KHR_wait_sync
.
Untuk menggunakan ekstensi ini secara mandiri, terapkan ekstensi EGL_ANDROID_native_fence_sync
bersama dengan dukungan kernel terkait. Selanjutnya, aktifkan ekstensi EGL_ANDROID_wait_sync
di driver Anda. Ekstensi EGL_ANDROID_native_fence_sync
terdiri dari jenis objek pagar asli EGLSyncKHR
yang berbeda. Akibatnya, ekstensi yang berlaku untuk tipe objek EGLSyncKHR
yang ada belum tentu berlaku untuk objek EGL_ANDROID_native_fence
, sehingga menghindari interaksi yang tidak diinginkan.
Ekstensi EGL_ANDROID_native_fence_sync
menggunakan atribut deskriptor file pagar asli yang sesuai yang hanya dapat disetel pada waktu pembuatan dan tidak dapat ditanyakan secara langsung dari objek sinkronisasi yang ada. Atribut ini dapat diatur ke salah satu dari dua mode:
- Deskriptor file pagar yang valid menggabungkan deskriptor file pagar Android asli yang ada dalam objek
EGLSyncKHR
. - -1 membuat deskriptor file pagar Android asli dari objek
EGLSyncKHR
.
Gunakan panggilan fungsi DupNativeFenceFD()
untuk mengekstrak objek EGLSyncKHR
dari deskriptor file pagar Android asli. Ini memiliki hasil yang sama dengan menanyakan atribut set, tetapi mematuhi konvensi bahwa penerima menutup pagar (karenanya operasi duplikat). Terakhir, penghancuran objek EGLSyncKHR
akan menutup atribut pagar internal.
Integrasi Komposer Perangkat Keras
Komposer Perangkat Keras menangani tiga jenis pagar sinkronisasi:
- Pagar perolehan diteruskan bersama dengan buffer masukan ke panggilan
setLayerBuffer
dansetClientTarget
. Ini mewakili penulisan yang tertunda ke dalam buffer dan harus memberi sinyal sebelum SurfaceFlinger atau HWC mencoba membaca dari buffer terkait untuk melakukan komposisi. - Pagar rilis diambil setelah panggilan ke
presentDisplay
menggunakan panggilangetReleaseFences
. Ini mewakili pembacaan yang tertunda dari buffer sebelumnya pada lapisan yang sama. Pagar pelepas memberi sinyal ketika 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 hingga pagar rilis memberi sinyal sebelum menulis konten baru ke dalam buffer yang dikembalikan kepada mereka. - Pagar yang ada dikembalikan, satu pagar per frame, sebagai bagian dari panggilan ke
presentDisplay
. Pagar masa kini melambangkan ketika susunan bingkai ini telah selesai, atau secara bergantian, ketika hasil komposisi bingkai sebelumnya tidak diperlukan lagi. Untuk tampilan fisik,presentDisplay
mengembalikan pagar yang ada saat frame saat ini muncul di layar. Setelah pagar yang ada dikembalikan, aman untuk menulis lagi ke buffer target SurfaceFlinger, jika berlaku. Untuk tampilan virtual, pagar yang ada dikembalikan ketika sudah aman untuk dibaca dari buffer keluaran.