เฟรมเวิร์กการซิงค์จะอธิบายการพึ่งพาระหว่างการดำเนินการแบบไม่พร้อมกันที่แตกต่างกันในระบบกราฟิก Android อย่างชัดเจน เฟรมเวิร์กนี้มี API ที่ช่วยคอมโพเนนต์ระบุเวลาที่ปล่อยบัฟเฟอร์ เฟรมเวิร์กนี้ยังอนุญาตให้ส่งข้อมูลเบื้องต้นของการซิงค์ระหว่างไดรเวอร์จากเคอร์เนลไปยังพื้นที่ผู้ใช้ และระหว่างกระบวนการในพื้นที่ผู้ใช้ด้วย
เช่น แอปพลิเคชันอาจจัดคิวงานที่จะดำเนินการใน GPU GPU จะเริ่มวาดรูปภาพนั้น แม้ว่าระบบจะยังไม่ได้วาดรูปภาพลงในหน่วยความจำ แต่ระบบจะส่งตัวชี้บัฟเฟอร์ไปยังคอมโพสิตหน้าต่างพร้อมกับ Fence ที่ระบุเวลาที่ GPU จะทำงานเสร็จ คอมโพสิตหน้าต่างจะเริ่มประมวลผลล่วงหน้าและส่งงานไปยังตัวควบคุมจอแสดงผล ในทำนองเดียวกัน การทำงานของ CPU ก็จะเสร็จล่วงหน้า เมื่อ GPU ทำงานเสร็จแล้ว ตัวควบคุมจอแสดงผลจะแสดงภาพทันที
เฟรมเวิร์กการซิงค์ยังช่วยให้ผู้ติดตั้งใช้งานใช้ประโยชน์จากทรัพยากรการซิงค์ในคอมโพเนนต์ฮาร์ดแวร์ของตนเองได้ด้วย สุดท้าย เฟรมเวิร์กนี้จะให้ข้อมูลเกี่ยวกับไปป์ไลน์กราฟิกเพื่อช่วยแก้ไขข้อบกพร่อง
การซิงค์ที่ชัดเจน
การซิงค์ข้อมูลที่ชัดเจนช่วยให้ผู้ผลิตและผู้บริโภคบัฟเฟอร์กราฟิก สามารถส่งสัญญาณแจ้งเมื่อเสร็จสิ้นการใช้บัฟเฟอร์ มีการใช้การซิงค์ข้อมูล ที่ชัดเจนใน Kernel-space
ประโยชน์ของการซิงค์ที่ชัดเจน ได้แก่
- ลักษณะการทำงานที่หลากหลายน้อยลงระหว่างอุปกรณ์
- การสนับสนุนการแก้ไขข้อบกพร่องที่ดียิ่งขึ้น
- เมตริกการทดสอบที่ปรับปรุงแล้ว
เฟรมเวิร์กการซิงค์มีออบเจกต์ 3 ประเภท ได้แก่
sync_timeline
sync_pt
sync_fence
sync_timeline
sync_timeline
คือไทม์ไลน์ที่เพิ่มขึ้นอย่างเดียวซึ่งผู้ให้บริการควรนำมาใช้กับอินสแตนซ์ของไดรเวอร์แต่ละรายการ เช่น บริบท GL, ตัวควบคุมการแสดงผล หรือ 2D blitter sync_timeline
นับงานที่ส่งไปยังเคอร์เนลสำหรับฮาร์ดแวร์ที่เฉพาะเจาะจง
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
คือค่าพื้นฐานหลักที่ไดรเวอร์และพื้นที่ผู้ใช้ใช้ในการสื่อสารทรัพยากร Dependency เมื่อมีการแจ้งสัญญาณของรั้ว คำสั่งทั้งหมดที่ออกก่อนรั้วจะเสร็จสมบูรณ์อย่างแน่นอน เนื่องจากไดรเวอร์เคอร์เนลหรือบล็อกฮาร์ดแวร์จะดำเนินการตามคำสั่งตามลำดับ
เฟรมเวิร์กการซิงค์ช่วยให้ผู้บริโภคหรือผู้ผลิตหลายรายส่งสัญญาณได้เมื่อใช้บัฟเฟอร์เสร็จแล้ว โดยสื่อสารข้อมูลการพึ่งพาด้วยพารามิเตอร์ฟังก์ชันเดียว รั้วได้รับการสนับสนุนโดยตัวระบุไฟล์และส่งผ่านจากพื้นที่เคอร์เนลไปยังพื้นที่ผู้ใช้ เช่น รั้วอาจมีค่า 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
A NativeWindow จะคำนึงถึงระดับรั้ว 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 สร้างข้อบ่งชี้ไฟล์ Fence เนทีฟจากออบเจ็กต์
EGLSyncKHR
ใช้การเรียกฟังก์ชัน DupNativeFenceFD()
เพื่อดึงออบเจ็กต์ EGLSyncKHR
จากข้อบ่งชี้ไฟล์ Fence ที่มาพร้อมเครื่อง Android
ซึ่งมีผลลัพธ์เหมือนกับการค้นหาแอตทริบิวต์ set แต่เป็นไปตามกฎที่ว่าผู้รับปิดรั้ว (ดังนั้นจะมีการดำเนินการที่ซ้ำกัน) สุดท้าย การทำลายออบเจ็กต์ EGLSyncKHR
จะปิดแอตทริบิวต์รั้วภายใน
การผสานรวมฮาร์ดแวร์คอมโพสเซอร์
เครื่องมือประกอบฮาร์ดแวร์จัดการรั้วการซิงค์ 3 ประเภท ได้แก่
- ระบบจะส่งการจองรั้วไปพร้อมกับบัฟเฟอร์อินพุตไปยังการเรียกใช้
setLayerBuffer
และsetClientTarget
ซึ่งแสดงถึงการเขียนที่รอดำเนินการในบัฟเฟอร์และต้องส่งสัญญาณก่อนที่ SurfaceFlinger หรือ HWC จะพยายามอ่านจากบัฟเฟอร์ที่เกี่ยวข้องเพื่อเขียนองค์ประกอบ - ระบบจะดึงข้อมูลรั้วที่ปล่อยหลังจากการเรียกใช้
presentDisplay
โดยใช้การเรียกใช้getReleaseFences
ซึ่งแสดงการอ่านที่รอดำเนินการจากบัฟเฟอร์ก่อนหน้าในเลเยอร์เดียวกัน สัญญาณการปล่อยรั้วจะส่งสัญญาณเมื่อ HWC ไม่ได้ใช้บัฟเฟอร์ก่อนหน้าอีกต่อไปเนื่องจากบัฟเฟอร์ปัจจุบันได้แทนที่บัฟเฟอร์ก่อนหน้าบนจอแสดงผลแล้ว ระบบจะส่งรั้วการปล่อยกลับไปยังแอปพร้อมกับบัฟเฟอร์ก่อนหน้าที่จะแทนที่ระหว่างการจัดวางปัจจุบัน แอปต้องรอจนกว่าสัญญาณการปลดปล่อยรั้วจะปรากฏขึ้นก่อนที่จะเขียนเนื้อหาใหม่ลงในบัฟเฟอร์ที่ส่งคืน - ระบบจะแสดงผลรั้วที่แสดงอยู่ 1 รั้วต่อเฟรมเป็นส่วนหนึ่งของการเรียกใช้
presentDisplay
รั้วปัจจุบันแสดงถึงเวลาที่การคอมโพสเฟรมนี้เสร็จสมบูรณ์ หรือเมื่อไม่จําเป็นต้องใช้ผลลัพธ์การคอมโพสของเฟรมก่อนหน้าอีกต่อไป สําหรับจอแสดงผลจริงpresentDisplay
จะแสดงผลรั้วที่ปรากฏอยู่เมื่อเฟรมปัจจุบันปรากฏบนหน้าจอ หลังจากส่งคืนรั้วที่มีอยู่แล้ว สามารถเขียนไปยังบัฟเฟอร์เป้าหมายของ SurfaceFlinger อีกครั้ง (หากมี) สําหรับจอแสดงผลเสมือน ระบบจะแสดงรั้วที่แสดงอยู่เมื่ออ่านจากบัฟเฟอร์เอาต์พุตได้อย่างปลอดภัย