เฟรมเวิร์กการซิงค์จะอธิบายการพึ่งพากันระหว่างการดำเนินการแบบอะซิงโครนัสที่แตกต่างกันในระบบกราฟิก Android อย่างชัดเจน เฟรมเวิร์กนี้มี API ที่ช่วยคอมโพเนนต์ระบุเวลาที่ปล่อยบัฟเฟอร์ นอกจากนี้ เฟรมเวิร์กยังอนุญาตให้ส่งพรอมิเตีการซิงค์ระหว่างไดรเวอร์จากเคอร์เนลไปยังพื้นที่ผู้ใช้ และระหว่างกระบวนการในพื้นที่ผู้ใช้ด้วย
เช่น แอปพลิเคชันอาจจัดคิวงานที่จะดำเนินการใน GPU GPU จะเริ่มวาดรูปภาพนั้น แม้ว่าระบบจะยังไม่ได้วาดภาพลงในหน่วยความจำ แต่ระบบจะส่งตัวชี้บัฟเฟอร์ไปยังคอมโพสิตเตอร์ของหน้าต่างพร้อมกับรั้วที่ระบุเวลาที่ GPU จะทำงานเสร็จ คอมโพสิตหน้าต่างจะเริ่มประมวลผลล่วงหน้าและส่งงานไปยังตัวควบคุมจอแสดงผล ในทำนองเดียวกัน การทำงานของ CPU ก็จะทำล่วงหน้า เมื่อ GPU ทำงานเสร็จแล้ว ตัวควบคุมจอแสดงผลจะแสดงภาพทันที
เฟรมเวิร์กการซิงค์ยังช่วยให้ผู้ติดตั้งใช้งานใช้ประโยชน์จากทรัพยากรการซิงค์ในคอมโพเนนต์ฮาร์ดแวร์ของตนเองได้ด้วย สุดท้าย เฟรมเวิร์กจะแสดงข้อมูลในไปป์ไลน์กราฟิกเพื่อช่วยในการแก้ไขข้อบกพร่อง
การซิงค์ที่ชัดเจน
การซิงค์ที่ชัดเจนช่วยให้ผู้ผลิตและผู้บริโภคบัฟเฟอร์กราฟิกส่งสัญญาณได้เมื่อใช้บัฟเฟอร์เสร็จแล้ว การซิงค์ที่ชัดเจนจะติดตั้งใช้งานในพื้นที่เคอร์เนล
ประโยชน์ของการซิงค์ที่ชัดเจนมีดังนี้
- ลักษณะการทำงานที่หลากหลายน้อยลงระหว่างอุปกรณ์
- การสนับสนุนการแก้ไขข้อบกพร่องที่ดีขึ้น
- เมตริกการทดสอบที่ปรับปรุงแล้ว
เฟรมเวิร์กการซิงค์มีออบเจกต์ 3 ประเภท ได้แก่
sync_timeline
sync_pt
sync_fence
sync_timeline
sync_timeline
คือไทม์ไลน์ที่เพิ่มขึ้นอย่างเดียวซึ่งผู้ให้บริการควรนำมาใช้กับอินสแตนซ์ของไดรเวอร์แต่ละรายการ เช่น บริบท GL, ตัวควบคุมการแสดงผล หรือโปรแกรมเปลี่ยนรูปแบบ 2 มิติ sync_timeline
counts
งานส่งไปยังเคอร์เนลสําหรับฮาร์ดแวร์หนึ่งๆ
sync_timeline
รับประกันเกี่ยวกับลําดับการดําเนินการ และช่วยให้ติดตั้งใช้งานกับฮาร์ดแวร์ได้
โปรดทำตามหลักเกณฑ์เหล่านี้เมื่อใช้ sync_timeline
- ตั้งชื่อที่เป็นประโยชน์สำหรับไดรเวอร์ ไทม์ไลน์ และรั้วทั้งหมดเพื่อลดความซับซ้อนในการแก้ไขข้อบกพร่อง
- ใช้โอเปอเรเตอร์
timeline_value_str
และpt_value_str
ในไทม์ไลน์เพื่อให้เอาต์พุตการแก้ไขข้อบกพร่องอ่านง่ายขึ้น - ใช้การเติม
driver_data
เพื่อให้คลังพื้นที่ผู้ใช้ เช่น คลัง GL มีสิทธิ์เข้าถึงข้อมูลไทม์ไลน์ส่วนตัว หากต้องการdata_driver
ช่วยให้ผู้ให้บริการส่งข้อมูลเกี่ยวกับsync_fence
และsync_pts
ที่ไม่เปลี่ยนแปลงเพื่อสร้างบรรทัดคำสั่งตามข้อมูลดังกล่าวได้ - ไม่อนุญาตให้พื้นที่ผู้ใช้สร้างหรือส่งสัญญาณรั้วอย่างชัดแจ้ง การสร้างสัญญาณ/รั้วอย่างชัดแจ้งจะส่งผลให้เกิดการโจมตีแบบปฏิเสธการให้บริการซึ่งจะหยุดฟังก์ชันการทำงานของไปป์ไลน์
- อย่าเข้าถึงองค์ประกอบ
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
เป็นองค์ประกอบพื้นฐานหลักที่ไดรเวอร์และพื้นที่ผู้ใช้ใช้เพื่อสื่อสารเกี่ยวกับสิ่งที่ต้องพึ่งพา เมื่อส่งสัญญาณเฟนซ์แล้ว ระบบจะรับประกันว่าคําสั่งทั้งหมดที่ออกก่อนเฟนซ์จะเสร็จสมบูรณ์ เนื่องจากไดรเวอร์เคอร์เนลหรือบล็อกฮาร์ดแวร์จะดําเนินการตามลําดับ
เฟรมเวิร์กการซิงค์ช่วยให้ผู้บริโภคหรือผู้ผลิตหลายรายส่งสัญญาณได้เมื่อใช้บัฟเฟอร์เสร็จแล้ว โดยสื่อสารข้อมูลการพึ่งพาด้วยพารามิเตอร์ฟังก์ชันเดียว รั้วได้รับการสนับสนุนโดยตัวระบุไฟล์และส่งผ่านจากพื้นที่เคอร์เนลไปยังพื้นที่ผู้ใช้ เช่น รั้วอาจมีค่า sync_pt
2 ค่าที่บ่งบอกว่าผู้บริโภครูปภาพ 2 รายแยกกันอ่านบัฟเฟอร์เสร็จแล้ว เมื่อส่งสัญญาณรั้ว ผู้ผลิตรูปภาพจะทราบว่าผู้บริโภคทั้ง 2 รายบริโภครูปภาพเสร็จแล้ว
รั้ว เช่น ค่า sync_pt
จะเริ่มต้นใช้งานและเปลี่ยนสถานะตามสถานะของจุด หากค่า sync_pt
ทั้งหมดมีสัญญาณ ระบบก็จะส่งสัญญาณให้กับ sync_fence
หาก sync_pt
รายการใดรายการหนึ่งอยู่ในสถานะข้อผิดพลาด sync_fence
ทั้งหมดจะอยู่ในสถานะข้อผิดพลาด
การเป็นสมาชิกใน sync_fence
จะเปลี่ยนแปลงไม่ได้หลังจากสร้างรั้วแล้ว หากต้องการจุดมากกว่า 1 จุดในรั้ว ระบบจะทำการผสานโดยเพิ่มจุดจากรั้ว 2 รั้วที่แตกต่างกันลงในรั้วรั้วที่ 3
หากจุดใดจุดหนึ่งได้รับการส่งสัญญาณในรั้วต้นทาง แต่อีกจุดหนึ่งไม่ได้รับการส่งสัญญาณ รั้วที่ 3 ก็จะไม่อยู่ในสถานะ "ส่งสัญญาณ" ด้วย
หากต้องการใช้การซิงค์ที่ชัดเจน ให้ระบุข้อมูลต่อไปนี้
- ระบบย่อยในพื้นที่เคอร์เนลที่ใช้เฟรมเวิร์กการซิงค์สำหรับไดรเวอร์ฮาร์ดแวร์หนึ่งๆ โดยปกติแล้ว ไดร์เวอร์ที่ต้องทราบเกี่ยวกับรั้วไฟฟ้าคือสิ่งที่เข้าถึงหรือสื่อสารกับเครื่องมือจัดระเบียบฮาร์ดแวร์
ไฟล์สำคัญ ได้แก่
- การติดตั้งใช้งานหลัก
kernel/common/include/linux/sync.h
kernel/common/drivers/base/sync.c
- เอกสารประกอบที่
kernel/common/Documentation/sync.txt
- ไลบรารีสำหรับสื่อสารกับพื้นที่เคอร์เนลใน
platform/system/core/libsync
- การติดตั้งใช้งานหลัก
- ผู้ให้บริการต้องระบุการจำกัดเวลาการซิงค์ที่เหมาะสมเป็นพารามิเตอร์ให้กับฟังก์ชัน
validateDisplay()
และpresentDisplay()
ใน HAL - ส่วนขยาย GL ที่เกี่ยวข้องกับรั้ว 2 รายการ (
EGL_ANDROID_native_fence_sync
และEGL_ANDROID_wait_sync
) และการรองรับรั้วในโปรแกรมควบคุมกราฟิก
กรณีศึกษา: ติดตั้งใช้งานโปรแกรมควบคุมการแสดงผล
หากต้องการใช้ 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
จะซับซ้อนมากขึ้นเมื่อใช้เฟรมเวิร์กการซิงค์ ขณะแสดงบัฟเฟอร์ บัฟเฟอร์จะเชื่อมโยงกับรั้วที่ระบุเวลาที่บัฟเฟอร์จะพร้อม คุณสามารถจัดคิวและเริ่มงานหลังจากที่รั้วว่างแล้ว
การจัดคิวและเริ่มทํางานหลังจากรั้วถูกล้างจะไม่บล็อกสิ่งใด คุณส่งรั้วของคุณเองกลับทันที ซึ่งรับประกันว่าบัฟเฟอร์จะออกจากจอแสดงผลเมื่อใด ขณะที่คุณจัดคิวบัฟเฟอร์ เคอร์เนลจะแสดงรายการพึ่งพากับเฟรมเวิร์กการซิงค์ ดังนี้
/* * 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);
การผสานรวมการซิงค์
ส่วนนี้จะอธิบายวิธีผสานรวมเฟรมเวิร์กการซิงค์พื้นที่เคอร์เนลกับส่วนพื้นที่ผู้ใช้ของเฟรมเวิร์ก Android และไดรเวอร์ที่ต้องสื่อสารกัน ออบเจ็กต์พื้นที่เคอร์เนลจะแสดงเป็นตัวระบุไฟล์ในพื้นที่ผู้ใช้
รูปแบบการผสานรวม
ทำตามรูปแบบอินเทอร์เฟซ HAL ของ Android ดังนี้
- หาก API มีตัวระบุไฟล์ที่อ้างอิงถึง
sync_pt
ไดร์เวอร์ของผู้ให้บริการหรือ HAL ที่ใช้ API นั้นต้องปิดตัวระบุไฟล์ - หากโปรแกรมควบคุมของผู้ให้บริการหรือ HAL ส่งตัวระบุไฟล์ที่มี
sync_pt
ไปยังฟังก์ชัน API โปรแกรมควบคุมของผู้ให้บริการหรือ HAL ต้องไม่ปิดตัวระบุไฟล์ - หากต้องการใช้ตัวบ่งชี้ไฟล์รั้วต่อไป ไดรเวอร์ของผู้ให้บริการหรือ HAL จะต้องทำซ้ำตัวบ่งชี้
ระบบจะเปลี่ยนชื่อออบเจ็กต์รั้วทุกครั้งที่ผ่าน BufferQueue
การรองรับรั้วเคอร์เนลช่วยให้รั้วมีสตริงสำหรับชื่อได้ ดังนั้นเฟรมเวิร์กการซิงค์จะใช้ชื่อกรอบเวลาและดัชนีบัฟเฟอร์ที่อยู่ในคิวเพื่อตั้งชื่อรั้ว เช่น SurfaceView:0
ซึ่งมีประโยชน์ในการแก้ไขข้อบกพร่องเพื่อระบุแหล่งที่มาของการล็อกตาย เนื่องจากชื่อจะปรากฏในเอาต์พุตของ /d/sync
และรายงานข้อบกพร่อง
การผสานรวม ANativeWindow
ANativeWindow รับรู้รั้ว dequeueBuffer
,
queueBuffer
และ cancelBuffer
มีพารามิเตอร์รั้ว
การผสานรวม OpenGL ES
การผสานรวมการซิงค์ OpenGL ES อาศัยส่วนขยาย EGL 2 รายการ ได้แก่
EGL_ANDROID_native_fence_sync
มีวิธีแพ็กหรือสร้างตัวบ่งชี้ไฟล์รั้วของ 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
เนทีฟที่ต่างกัน ด้วยเหตุนี้ ส่วนขยายที่ใช้กับEGLSyncKHR
ประเภทออบเจ็กต์ที่มีอยู่จึงไม่จำเป็นต้องใช้กับEGL_ANDROID_native_fence
ออบเจ็กต์ เพื่อหลีกเลี่ยงการโต้ตอบที่ไม่ต้องการ
ส่วนขยาย EGL_ANDROID_native_fence_sync
ใช้แอตทริบิวต์ตัวระบุไฟล์รั้วรอบขอบชิดแบบเนทีฟที่เกี่ยวข้องซึ่งตั้งค่าได้เฉพาะตอนสร้างเท่านั้น และไม่สามารถค้นหาจากออบเจ็กต์การซิงค์ที่มีอยู่ได้โดยตรง แอตทริบิวต์นี้สามารถตั้งค่าเป็นโหมดใดโหมดหนึ่งต่อไปนี้
- ตัวระบุไฟล์รั้วที่ถูกต้องจะรวมตัวระบุไฟล์รั้ว Android เดิมไว้ในออบเจ็กต์
EGLSyncKHR
- -1 สร้างตัวบ่งชี้ไฟล์รั้วของ Android ดั้งเดิมจากออบเจ็กต์
EGLSyncKHR
ใช้การเรียกใช้ฟังก์ชัน DupNativeFenceFD()
เพื่อดึงออบเจ็กต์ EGLSyncKHR
ออกจากตัวระบุไฟล์รั้วของ Android ดั้งเดิม
ซึ่งจะให้ผลลัพธ์เหมือนกับการค้นหาแอตทริบิวต์ชุด แต่เป็นไปตามแบบแผนที่ผู้รับปิดวงเล็บ (จึงเป็นการดำเนินการที่ซ้ำกัน) สุดท้าย การทำลายออบเจ็กต์ EGLSyncKHR
จะปิดแอตทริบิวต์รั้วภายใน
การผสานรวมฮาร์ดแวร์คอมโพสเซอร์
เครื่องมือประกอบฮาร์ดแวร์จัดการรั้วการซิงค์ 3 ประเภท ได้แก่
- ระบบจะส่ง Acquire fences ไปพร้อมกับบัฟเฟอร์อินพุตไปยังการเรียก
setLayerBuffer
และsetClientTarget
ซึ่งแสดงถึงการเขียนที่รอดำเนินการในบัฟเฟอร์ และต้องส่งสัญญาณก่อนที่ SurfaceFlinger หรือ HWC จะพยายามอ่านจากบัฟเฟอร์ที่เกี่ยวข้องเพื่อทำการคอมโพส - ระบบจะดึงข้อมูลรั้วที่ปล่อยหลังจากการเรียกใช้
presentDisplay
โดยใช้การเรียกใช้getReleaseFences
ซึ่งแสดงการอ่านที่รอดำเนินการจากบัฟเฟอร์ก่อนหน้าในเลเยอร์เดียวกัน สัญญาณการปล่อยรั้วจะส่งสัญญาณเมื่อ HWC ไม่ได้ใช้บัฟเฟอร์ก่อนหน้าอีกต่อไปเนื่องจากบัฟเฟอร์ปัจจุบันได้แทนที่บัฟเฟอร์ก่อนหน้าบนจอแสดงผลแล้ว ระบบจะส่งรั้วการปล่อยกลับไปยังแอปพร้อมกับบัฟเฟอร์ก่อนหน้าที่จะแทนที่ระหว่างการจัดวางปัจจุบัน แอปต้องรอจนกว่าสัญญาณการปลดปล่อยรั้วจะปรากฏขึ้นก่อนที่จะเขียนเนื้อหาใหม่ลงในบัฟเฟอร์ที่ส่งคืน - ระบบจะแสดงผลรั้วที่แสดงอยู่ 1 รั้วต่อเฟรมเป็นส่วนหนึ่งของการเรียกใช้
presentDisplay
รั้วปัจจุบันแสดงถึงเวลาที่การคอมโพสเฟรมนี้เสร็จสมบูรณ์ หรือเมื่อไม่จำเป็นต้องใช้ผลลัพธ์การคอมโพสของเฟรมก่อนหน้าอีกต่อไป สําหรับจอแสดงผลจริงpresentDisplay
จะแสดงผลรั้วที่ปรากฏอยู่เมื่อเฟรมปัจจุบันปรากฏบนหน้าจอ หลังจากระบบแสดงรั้วแล้ว คุณก็เขียนลงในบัฟเฟอร์เป้าหมายของ SurfaceFlinger อีกครั้งได้ (หากมี) สําหรับจอแสดงผลเสมือน ระบบจะแสดงรั้วที่แสดงอยู่เมื่ออ่านจากบัฟเฟอร์เอาต์พุตได้อย่างปลอดภัย