เฟรมเวิร์กการซิงค์อธิบายการพึ่งพากันระหว่างการดำเนินการแบบไม่พร้อมกันต่างๆ ในระบบกราฟิกของ Android อย่างชัดเจน เฟรมเวิร์กมี API ที่ช่วยให้คอมโพเนนต์ระบุได้ว่าเมื่อใดที่บัฟเฟอร์จะได้รับการเผยแพร่ นอกจากนี้ เฟรมเวิร์กยังอนุญาตให้ส่งผ่าน Primitive การซิงค์ระหว่างไดรเวอร์จากเคอร์เนลไปยัง Userspace และระหว่างกระบวนการ Userspace เอง
ตัวอย่างเช่น แอปพลิเคชันอาจจัดคิวงานที่จะดำเนินการใน GPU GPU จะเริ่มวาดรูปภาพนั้น แม้ว่ารูปภาพจะยังไม่ได้วาดลงในหน่วยความจำ แต่ระบบจะส่งตัวชี้บัฟเฟอร์ไปยังคอมโพสิตเตอร์หน้าต่างพร้อมกับ Fence ที่ระบุเวลาที่งานของ GPU จะเสร็จสมบูรณ์ คอมโพสิตเตอร์หน้าต่างจะเริ่มประมวลผลล่วงหน้าและส่งงานไปยังตัวควบคุมจอแสดงผล ในลักษณะเดียวกัน งานของ CPU จะดำเนินการล่วงหน้า เมื่อ GPU ทำงานเสร็จ ตัวควบคุมจอแสดงผลจะแสดงรูปภาพทันที
เฟรมเวิร์กการซิงค์ยังช่วยให้ผู้ติดตั้งใช้งานใช้ทรัพยากรการซิงค์ในคอมโพเนนต์ฮาร์ดแวร์ของตนเองได้ด้วย สุดท้าย เฟรมเวิร์กจะให้การมองเห็นไปป์ไลน์กราฟิกเพื่อช่วยในการแก้ไขข้อบกพร่อง
การซิงค์อย่างชัดเจน
การซิงค์อย่างชัดเจนช่วยให้ผู้ผลิตและผู้ใช้บัฟเฟอร์กราฟิกส่งสัญญาณได้เมื่อใช้บัฟเฟอร์เสร็จแล้ว การซิงค์อย่างชัดเจนจะใช้งานใน Kernel-Space
ข้อดีของการซิงค์อย่างชัดเจนมีดังนี้
- ความแตกต่างของลักษณะการทำงานระหว่างอุปกรณ์น้อยลง
- การสนับสนุนการแก้ไขข้อบกพร่องที่ดีขึ้น
- เมตริกการทดสอบที่ปรับปรุงให้ดีขึ้น
เฟรมเวิร์กการซิงค์มีออบเจ็กต์ 3 ประเภท ได้แก่
sync_timelinesync_ptsync_fence
sync_timeline
sync_timeline เป็นไทม์ไลน์ที่เพิ่มขึ้นอย่างต่อเนื่องซึ่งผู้ให้บริการควรติดตั้งใช้งานสำหรับอินสแตนซ์ไดรเวอร์แต่ละรายการ เช่น บริบท GL, ตัวควบคุมจอแสดงผล หรือ Blitter 2 มิติ sync_timeline จะนับงานที่ส่งไปยังเคอร์เนลสำหรับฮาร์ดแวร์ชิ้นหนึ่งๆ
sync_timeline ช่วยให้มั่นใจได้ถึงลำดับการดำเนินการและช่วยให้การติดตั้งใช้งานเฉพาะฮาร์ดแวร์เป็นไปได้
ทำตามหลักเกณฑ์ต่อไปนี้เมื่อติดตั้งใช้งาน sync_timeline
- ตั้งชื่อที่มีประโยชน์สำหรับไดรเวอร์ ไทม์ไลน์ และ Fence ทั้งหมดเพื่อลดความซับซ้อนในการแก้ไขข้อบกพร่อง
- ติดตั้งใช้งานโอเปอเรเตอร์
timeline_value_strและpt_value_strในไทม์ไลน์เพื่อให้เอาต์พุตการแก้ไขข้อบกพร่องอ่านง่ายขึ้น - ติดตั้งใช้งาน
driver_dataที่เติมข้อมูลเพื่ออนุญาตให้ไลบรารี Userspace เช่น ไลบรารี GL เข้าถึงข้อมูลไทม์ไลน์ส่วนตัวได้ หากจำเป็นdata_driverช่วยให้ผู้ให้บริการส่งข้อมูลเกี่ยวกับsync_fenceและsync_ptsที่เปลี่ยนแปลงไม่ได้เพื่อสร้างบรรทัดคำสั่ง ตามข้อมูลดังกล่าว - ไม่อนุญาตให้ Userspace สร้างหรือส่งสัญญาณ Fence อย่างชัดเจน การสร้างสัญญาณ/Fence อย่างชัดเจน จะส่งผลให้เกิดการโจมตีแบบปฏิเสธการให้บริการซึ่ง จะหยุดฟังก์ชันการทำงานของไปป์ไลน์
- อย่าเข้าถึงองค์ประกอบ
sync_timeline,sync_pt, หรือsync_fenceอย่างชัดเจน API มีฟังก์ชันที่จำเป็นทั้งหมด
sync_pt
sync_pt คือค่าหรือจุดเดียวใน sync_timeline จุดมี 3 สถานะ ได้แก่ ใช้งานอยู่ ส่งสัญญาณ และข้อผิดพลาด จุดจะเริ่มต้นในสถานะใช้งานอยู่และเปลี่ยนไปเป็นสถานะส่งสัญญาณหรือข้อผิดพลาด ตัวอย่างเช่น เมื่อผู้ใช้รูปภาพไม่ต้องการบัฟเฟอร์อีกต่อไป ระบบจะส่งสัญญาณ sync_pt เพื่อให้ผู้ผลิตรูปภาพทราบว่าสามารถเขียนลงในบัฟเฟอร์ได้อีกครั้ง
sync_fence
sync_fence คือคอลเล็กชันของค่า sync_pt ซึ่งมักจะมี sync_timeline ระดับบนสุดที่แตกต่างกัน (เช่น สำหรับตัวควบคุมจอแสดงผลและ GPU) sync_fence, sync_pt และ sync_timeline เป็น Primitive หลักที่ไดรเวอร์และ Userspace ใช้เพื่อสื่อสารการพึ่งพากัน เมื่อ Fence ได้รับสัญญาณ คำสั่งทั้งหมดที่ออกก่อน Fence จะเสร็จสมบูรณ์เนื่องจากไดรเวอร์เคอร์เนลหรือบล็อกฮาร์ดแวร์จะดำเนินการคำสั่งตามลำดับ
เฟรมเวิร์กการซิงค์อนุญาตให้ผู้ใช้หรือผู้ผลิตหลายรายส่งสัญญาณได้เมื่อใช้บัฟเฟอร์เสร็จแล้ว โดยจะสื่อสารข้อมูลทรัพยากร Dependency ด้วยพารามิเตอร์ฟังก์ชันเดียว Fence ได้รับการสนับสนุนโดยตัวระบุไฟล์และส่งผ่านจาก Kernel-Space ไปยัง Userspace ตัวอย่างเช่น Fence สามารถมีค่า sync_pt 2 ค่าที่บ่งบอกว่าผู้ใช้รูปภาพ 2 รายแยกกันอ่านบัฟเฟอร์เสร็จแล้ว เมื่อ Fence ได้รับสัญญาณ ผู้ผลิตรูปภาพจะทราบว่าผู้ใช้ทั้ง 2 รายใช้รูปภาพเสร็จแล้ว
Fence เช่น ค่า sync_pt จะเริ่มต้นใช้งานอยู่และเปลี่ยนสถานะตามสถานะของจุด หากค่า sync_pt ทั้งหมดได้รับสัญญาณ sync_fence จะได้รับสัญญาณ หาก sync_pt รายการใดรายการหนึ่งอยู่ในสถานะข้อผิดพลาด sync_fence ทั้งหมดจะอยู่ในสถานะข้อผิดพลาด
การเป็นสมาชิกใน sync_fence จะเปลี่ยนแปลงไม่ได้หลังจากสร้าง Fence แล้ว หากต้องการรับจุดมากกว่า 1 จุดใน Fence ระบบจะผสานจุดจาก Fence 2 รายการที่แตกต่างกันลงใน Fence รายการที่ 3
หากจุดใดจุดหนึ่งได้รับสัญญาณใน Fence ต้นทางและอีกจุดไม่ได้รับ Fence รายการที่ 3 ก็จะไม่อยู่ในสถานะได้รับสัญญาณด้วย
หากต้องการติดตั้งใช้งานการซิงค์อย่างชัดเจน ให้ระบุข้อมูลต่อไปนี้
- ระบบย่อย Kernel-Space ที่ติดตั้งใช้งานเฟรมเวิร์กการซิงค์สำหรับไดรเวอร์ฮาร์ดแวร์หนึ่งๆ โดยทั่วไป ไดรเวอร์ที่ต้องรับรู้ Fence คือไดรเวอร์ที่เข้าถึงหรือสื่อสารกับ Hardware Composer (HWC)
ไฟล์สำคัญ ได้แก่
- การติดตั้งใช้งานหลัก
kernel/common/include/linux/sync.hkernel/common/drivers/base/sync.c
- เอกสารประกอบที่
kernel/common/Documentation/sync.txt - ไลบรารีสำหรับสื่อสารกับ Kernel-Space ใน
platform/system/core/libsync
- การติดตั้งใช้งานหลัก
- ผู้ให้บริการต้องระบุ Fence การซิงค์ที่เหมาะสมเป็นพารามิเตอร์สำหรับฟังก์ชัน
validateDisplay()และpresentDisplay()ในระดับชั้นการจัดการฮาร์ดแวร์โดยตรง (HAL) - ส่วนขยาย GL 2 รายการที่เกี่ยวข้องกับ Fence (
EGL_ANDROID_native_fence_syncและEGL_ANDROID_wait_sync) และการสนับสนุน Fence ในไดรเวอร์กราฟิก
กรณีศึกษา: ติดตั้งใช้งานไดรเวอร์จอแสดงผล
หากต้องการใช้ API ที่รองรับฟังก์ชันการซิงค์ ให้พัฒนาไดรเวอร์จอแสดงผลที่มีฟังก์ชันบัฟเฟอร์จอแสดงผล ก่อนที่จะมีเฟรมเวิร์กการซิงค์ ฟังก์ชันนี้จะรับออบเจ็กต์ dma-buf ใส่บัฟเฟอร์เหล่านั้นบนจอแสดงผล และบล็อกขณะที่บัฟเฟอร์ปรากฏ ตัวอย่างเช่น
/* * assumes buffer is ready to be displayed. returns when buffer is no longer on * screen. */ void display_buffer(struct dma_buf *buffer);
เมื่อมีเฟรมเวิร์กการซิงค์ ฟังก์ชัน display_buffer จะซับซ้อนมากขึ้น ขณะใส่บัฟเฟอร์บนจอแสดงผล บัฟเฟอร์จะเชื่อมโยงกับ Fence ที่ระบุเวลาที่บัฟเฟอร์จะพร้อม คุณสามารถจัดคิวและเริ่มงานได้หลังจาก Fence ล้างแล้ว
การจัดคิวและเริ่มงานหลังจาก Fence ล้างแล้วจะไม่บล็อกสิ่งใด คุณจะส่งคืน Fence ของคุณเองทันที ซึ่งจะส่งสัญญาณเมื่อบัฟเฟอร์จะไม่อยู่บนจอแสดงผล เมื่อคุณจัดคิวบัฟเฟอร์ เคอร์เนลจะแสดงการพึ่งพากันด้วยเฟรมเวิร์กการซิงค์ดังนี้
/* * 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);
การผสานรวมการซิงค์
ส่วนนี้จะอธิบายวิธีผสานรวมเฟรมเวิร์กการซิงค์ Kernel-Space กับส่วน Userspace ของเฟรมเวิร์ก Android และไดรเวอร์ที่ต้องสื่อสารกัน ออบเจ็กต์ Kernel-Space จะแสดงเป็นตัวระบุไฟล์ใน Userspace
กฎการผสานรวม
ทำตามกฎอินเทอร์เฟซ Android HAL ดังนี้
- หาก API มีตัวบอกไฟล์ที่อ้างอิง
sync_pt, ไดรเวอร์ของผู้ให้บริการหรือ HAL ที่ใช้ API ต้องปิดตัวบอกไฟล์ - หากไดรเวอร์ของผู้ให้บริการหรือ HAL ส่งตัวบอกไฟล์ที่มี a
sync_ptไปยังฟังก์ชัน API ไดรเวอร์ของผู้ให้บริการหรือ HAL ต้องไม่ ปิดตัวบอกไฟล์ - หากต้องการใช้ตัวระบุไฟล์ Fence ต่อไป ไดรเวอร์ของผู้ให้บริการหรือ HAL ต้องทำซ้ำตัวระบุ
ระบบจะเปลี่ยนชื่อออบเจ็กต์ Fence ทุกครั้งที่ผ่าน BufferQueue
การสนับสนุน Fence ของเคอร์เนลอนุญาตให้ Fence มีสตริงสำหรับชื่อ ดังนั้นเฟรมเวิร์กการซิงค์จึงใช้ชื่อหน้าต่างและดัชนีบัฟเฟอร์ที่จัดคิวเพื่อตั้งชื่อ Fence เช่น SurfaceView:0 ซึ่งจะเป็นประโยชน์ในการแก้ไขข้อบกพร่องเพื่อระบุแหล่งที่มาของการติดตายเนื่องจากชื่อจะปรากฏในเอาต์พุตของ /d/sync และรายงานข้อบกพร่อง
การผสานรวม ANativeWindow
ANativeWindow รับรู้ Fence dequeueBuffer,
queueBuffer และ cancelBuffer มีพารามิเตอร์ Fence
การผสานรวม OpenGL ES
การผสานรวมการซิงค์ OpenGL ES อาศัยส่วนขยาย EGL 2 รายการ ได้แก่
EGL_ANDROID_native_fence_syncมีวิธี ห่อหรือสร้างตัวระบุไฟล์ Fence แบบเนทีฟของ Android ในEGLSyncKHRออบเจ็กต์EGL_ANDROID_wait_syncอนุญาตให้ GPU หยุดชั่วคราวแทนที่จะเป็น CPU ทำให้ GPU รอEGLSyncKHRส่วนขยายEGL_ANDROID_wait_syncเหมือนกับส่วนขยายEGL_KHR_wait_sync
หากต้องการใช้ส่วนขยายเหล่านี้แยกกัน ให้ติดตั้งใช้งานส่วนขยาย EGL_ANDROID_native_fence_sync พร้อมกับการสนับสนุนเคอร์เนลที่เกี่ยวข้อง จากนั้นเปิดใช้ส่วนขยาย EGL_ANDROID_wait_sync ในไดรเวอร์ ส่วนขยาย EGL_ANDROID_native_fence_sync ประกอบด้วยประเภทออบเจ็กต์ EGLSyncKHR Fence แบบเนทีฟที่แตกต่างกัน ด้วยเหตุนี้ ส่วนขยายที่ใช้กับประเภทออบเจ็กต์ EGLSyncKHR ที่มีอยู่จึงไม่จำเป็นต้องใช้กับออบเจ็กต์ EGL_ANDROID_native_fence ซึ่งจะหลีกเลี่ยงการโต้ตอบที่ไม่ต้องการ
ส่วนขยาย EGL_ANDROID_native_fence_sync ใช้แอตทริบิวต์ตัวบอกไฟล์ Fence แบบเนทีฟที่เกี่ยวข้อง ซึ่งตั้งค่าได้เฉพาะตอนสร้างและไม่สามารถค้นหาโดยตรงจากออบเจ็กต์การซิงค์ที่มีอยู่ แอตทริบิวต์นี้สามารถตั้งค่าเป็นโหมดใดโหมดหนึ่งจาก 2 โหมดต่อไปนี้
- ตัวระบุไฟล์ Fence ที่ถูกต้อง จะห่อตัวระบุไฟล์ Fence แบบเนทีฟของ Android ที่มีอยู่ในออบเจ็กต์
EGLSyncKHR - -1 จะสร้างตัวบอกไฟล์ Fence แบบเนทีฟของ Android จากออบเจ็กต์
EGLSyncKHR
ใช้การเรียกใช้ฟังก์ชัน DupNativeFenceFD() เพื่อแยกออบเจ็กต์ EGLSyncKHR ออกจากตัวบอกไฟล์ Fence แบบเนทีฟของ Android
ซึ่งให้ผลลัพธ์เหมือนกับการค้นหาแอตทริบิวต์ที่ตั้งค่าไว้ แต่เป็นไปตามกฎที่ผู้รับจะปิด Fence (จึงต้องดำเนินการซ้ำ) สุดท้าย การทำลายออบเจ็กต์ EGLSyncKHR จะปิดแอตทริบิวต์ Fence ภายใน
การผสานรวม Hardware Composer
HWC จัดการ Fence การซิงค์ 3 ประเภท ได้แก่
- Fence การรับ จะส่งผ่านพร้อมกับบัฟเฟอร์อินพุตไปยัง
การเรียก
setLayerBufferและsetClientTargetซึ่งแสดงถึงการเขียนที่รอดำเนินการลงในบัฟเฟอร์และต้องส่งสัญญาณก่อนที่ SurfaceFlinger หรือ HWC จะพยายามอ่านจากบัฟเฟอร์ที่เชื่อมโยงเพื่อ ทำการคอมโพสิต - Fence การเผยแพร่ จะดึงข้อมูลหลังจากการเรียก
presentDisplayโดยใช้การเรียกgetReleaseFencesซึ่งแสดงถึงการอ่านที่รอดำเนินการจากบัฟเฟอร์ก่อนหน้าในเลเยอร์เดียวกัน Fence การเผยแพร่จะส่งสัญญาณเมื่อ HWC ไม่ได้ใช้บัฟเฟอร์ก่อนหน้าอีกต่อไปเนื่องจากบัฟเฟอร์ปัจจุบันได้แทนที่บัฟเฟอร์ก่อนหน้าบนจอแสดงผล ระบบจะส่ง Fence การเผยแพร่กลับไปยังแอปพร้อมกับบัฟเฟอร์ก่อนหน้าที่จะถูกแทนที่ระหว่างการคอมโพสิตปัจจุบัน แอปต้องรอจนกว่า Fence การเผยแพร่จะส่งสัญญาณก่อนที่จะเขียนเนื้อหาใหม่ลงในบัฟเฟอร์ที่ ส่งคืนให้ - Fence ปัจจุบัน จะแสดงผล 1 รายการต่อเฟรม ซึ่งเป็นส่วนหนึ่งของ
การเรียก
presentDisplayFence ปัจจุบันแสดงถึงเวลาที่การ คอมโพสิตของเฟรมนี้เสร็จสมบูรณ์ หรืออีกทางหนึ่งคือเมื่อไม่จำเป็นต้องใช้ผลการ คอมโพสิตของเฟรมก่อนหน้าอีกต่อไป สำหรับจอแสดงผลจริงpresentDisplayจะแสดงผล Fence ปัจจุบันเมื่อเฟรมปัจจุบันปรากฏบนหน้าจอ หลังจากแสดงผล Fence ปัจจุบันแล้ว คุณจะเขียนลงในบัฟเฟอร์เป้าหมาย SurfaceFlinger อีกครั้งได้อย่างปลอดภัย หาก มี สำหรับจอแสดงผลเสมือน ระบบจะแสดงผล Fence ปัจจุบันเมื่ออ่านจากบัฟเฟอร์เอาต์พุตได้อย่างปลอดภัย