เฟรมเวิร์กการซิงค์จะอธิบายการขึ้นต่อกันระหว่าง การดำเนินการแบบอะซิงโครนัสต่างๆ ในระบบกราฟิกของ Android อย่างชัดเจน เฟรมเวิร์ก มี API ที่ช่วยให้คอมโพเนนต์ระบุได้เมื่อมีการเผยแพร่บัฟเฟอร์ เฟรมเวิร์กยัง อนุญาตให้ส่งผ่าน Primitive การซิงค์ระหว่างไดรเวอร์จากเคอร์เนล ไปยัง Userspace และระหว่างกระบวนการ Userspace ด้วยกันเอง
เช่น แอปพลิเคชันอาจจัดคิวงานที่จะดำเนินการใน GPU GPU จะเริ่มวาดรูปภาพนั้น แม้ว่าระบบจะยังไม่ได้วาดรูปภาพลงในหน่วยความจำ แต่จะส่งตัวชี้บัฟเฟอร์ไปยังคอมโพสิตเตอร์หน้าต่างพร้อมกับฟันดาบที่ระบุเวลาที่งานของ GPU จะเสร็จสิ้น คอมโพสิตเตอร์หน้าต่างจะเริ่มประมวลผลล่วงหน้าและ ส่งงานไปยังตัวควบคุมการแสดงผล ในทำนองเดียวกัน งานของ CPU จะดำเนินการล่วงหน้า เมื่อ GPU ทำงานเสร็จแล้ว ตัวควบคุมการแสดงผล จะแสดงรูปภาพทันที
เฟรมเวิร์กการซิงค์ยังช่วยให้ผู้ใช้ประโยชน์จาก ทรัพยากรการซิงค์ในคอมโพเนนต์ฮาร์ดแวร์ของตนเองได้ด้วย สุดท้ายนี้ เฟรมเวิร์กจะให้การมองเห็นไปที่ไปป์ไลน์กราฟิกเพื่อช่วยในการ แก้ไขข้อบกพร่อง
การซิงค์อย่างชัดเจน
การซิงค์ที่ชัดเจนช่วยให้ผู้ผลิตและผู้ใช้บัฟเฟอร์กราฟิก สามารถส่งสัญญาณเมื่อใช้บัฟเฟอร์เสร็จแล้ว การซิงค์ที่ชัดเจนจะ ได้รับการติดตั้งใช้งานในพื้นที่เคอร์เนล
ประโยชน์ของการซิงค์อย่างชัดเจนมีดังนี้
- ลักษณะการทำงานระหว่างอุปกรณ์มีความแตกต่างกันน้อยลง
- การสนับสนุนการแก้ไขข้อบกพร่องที่ดีขึ้น
- เมตริกการทดสอบที่ปรับปรุงแล้ว
เฟรมเวิร์กการซิงค์มีออบเจ็กต์ 3 ประเภท ได้แก่
sync_timeline
sync_pt
sync_fence
sync_timeline
sync_timeline
คือไทม์ไลน์ที่เพิ่มขึ้นอย่างเดียว ซึ่งผู้ให้บริการควรใช้กับอินสแตนซ์ไดรเวอร์แต่ละรายการ เช่น บริบท GL, ตัวควบคุมการแสดงผล หรือ Blitter 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
เป็นองค์ประกอบหลักที่ไดรเวอร์และพื้นที่ผู้ใช้
ใช้เพื่อสื่อสารการอ้างอิง เมื่อมีการส่งสัญญาณรั้วกั้น ระบบจะรับประกันว่าคำสั่งทั้งหมดที่ออกก่อนรั้วกั้นจะเสร็จสมบูรณ์ เนื่องจากไดรเวอร์เคอร์เนลหรือบล็อกฮาร์ดแวร์จะดำเนินการตามคำสั่งตามลำดับ
เฟรมเวิร์กการซิงค์ช่วยให้ผู้ใช้หรือผู้ผลิตหลายรายส่งสัญญาณได้เมื่อใช้บัฟเฟอร์เสร็จแล้ว โดยจะสื่อสารข้อมูลการอ้างอิงด้วยพารามิเตอร์ฟังก์ชันเดียว รั้วได้รับการสนับสนุนโดยตัวอธิบายไฟล์และส่งจาก
พื้นที่เคอร์เนลไปยังพื้นที่ผู้ใช้ เช่น รั้วอาจมีค่า 2 ค่า
sync_pt
ซึ่งบ่งบอกว่าเมื่อใดที่ผู้ใช้รูปภาพ 2 รายแยกกันอ่านบัฟเฟอร์เสร็จแล้ว
เมื่อมีการส่งสัญญาณรั้ว ผู้ผลิตรูปภาพจะทราบว่าทั้ง
ผู้บริโภคได้บริโภคเนื้อหาเสร็จสิ้นแล้ว
รั้วจะเริ่มใช้งานและเปลี่ยนสถานะตามสถานะของจุดต่างๆ เช่น ค่า sync_pt
หากค่า sync_pt
ทั้งหมดกลายเป็นค่าที่ส่งสัญญาณ
sync_fence
จะกลายเป็นค่าที่ส่งสัญญาณ หาก sync_pt
ใดsync_pt
หนึ่งมีข้อผิดพลาด sync_fence
ทั้งหมดจะมีข้อผิดพลาด
การเป็นสมาชิกใน sync_fence
จะเปลี่ยนแปลงไม่ได้หลังจากสร้างรั้วแล้ว
หากต้องการรับคะแนนมากกว่า 1 คะแนนในรั้ว จะต้องมีการผสาน
โดยเพิ่มคะแนนจากรั้ว 2 รั้วที่แตกต่างกันลงในรั้วที่ 3
หากจุดใดจุดหนึ่งมีการส่งสัญญาณในรั้วต้นทาง แต่อีกจุดไม่มี
รั้วที่ 3 ก็จะไม่อยู่ในสถานะที่ส่งสัญญาณด้วย
หากต้องการใช้การซิงค์ที่ชัดเจน ให้ระบุข้อมูลต่อไปนี้
- ระบบย่อยในพื้นที่เคอร์เนลที่ใช้เฟรมเวิร์กการซิงค์
สำหรับไดรเวอร์ฮาร์ดแวร์ที่เฉพาะเจาะจง โดยทั่วไปแล้ว ไดรเวอร์ที่ต้องรับรู้ถึงรั้วคือไดรเวอร์ที่เข้าถึงหรือสื่อสารกับ Hardware Composer
ไฟล์สำคัญ ได้แก่
- การติดตั้งใช้งานหลัก
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
การรองรับฟีเจอร์ Fence ของเคอร์เนลช่วยให้ Fence มีสตริงสำหรับชื่อได้ ดังนั้นเฟรมเวิร์กการซิงค์
จึงใช้ชื่อหน้าต่างและดัชนีบัฟเฟอร์ที่อยู่ในคิวเพื่อตั้งชื่อ
ให้ Fence เช่น 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
ใช้แอตทริบิวต์ตัวอธิบายไฟล์รั้วแบบเนทีฟที่เกี่ยวข้อง ซึ่งตั้งค่าได้เฉพาะตอนสร้างและ
ไม่สามารถค้นหาโดยตรงจากออบเจ็กต์การซิงค์ที่มีอยู่ แอตทริบิวต์นี้
ตั้งค่าได้ 2 โหมดดังนี้
- ตัวอธิบายไฟล์รั้วที่ถูกต้องจะห่อหุ้มตัวอธิบายไฟล์รั้ว Android ดั้งเดิมที่มีอยู่ไว้ในออบเจ็กต์
EGLSyncKHR
- -1 สร้างตัวอธิบายไฟล์รั้ว Android เนทีฟจากออบเจ็กต์
EGLSyncKHR
ใช้DupNativeFenceFD()
การเรียกใช้ฟังก์ชันเพื่อดึงออบเจ็กต์
EGLSyncKHR
จากตัวอธิบายไฟล์รั้วของ Android เนทีฟ
ซึ่งให้ผลลัพธ์เช่นเดียวกับการค้นหาแอตทริบิวต์ที่ตั้งค่าไว้ แต่เป็นไปตาม
รูปแบบที่ผู้รับปิดกั้น (จึงทำให้มีการดำเนินการซ้ำ) สุดท้าย การทำลายออบเจ็กต์ EGLSyncKHR
จะปิด
แอตทริบิวต์รั้วภายใน
การผสานรวมฮาร์ดแวร์คอมโพสเซอร์
Hardware Composer จัดการรั้วการซิงค์ 3 ประเภท ได้แก่
- Acquire fences จะส่งพร้อมกับบัฟเฟอร์อินพุตไปยังการเรียกใช้
setLayerBuffer
และsetClientTarget
ซึ่งแสดงถึงการเขียนที่รอดำเนินการลงในบัฟเฟอร์และต้องส่งสัญญาณก่อนที่ SurfaceFlinger หรือ HWC จะพยายามอ่านจากบัฟเฟอร์ที่เชื่อมโยงเพื่อ ทำการคอมโพสิต - รั้วเผยแพร่จะได้รับการดึงข้อมูลหลังจากการโทรไปยัง
presentDisplay
โดยใช้การโทรgetReleaseFences
ซึ่งแสดงถึงการอ่านที่รอดำเนินการจากบัฟเฟอร์ก่อนหน้าในเลเยอร์เดียวกัน ฟันดาบการเผยแพร่จะส่งสัญญาณเมื่อ HWC ไม่ได้ใช้บัฟเฟอร์ก่อนหน้าอีกต่อไป เนื่องจากบัฟเฟอร์ปัจจุบันได้แทนที่บัฟเฟอร์ก่อนหน้าบนจอแสดงผลแล้ว ระบบจะส่งรั้วการเผยแพร่กลับไปยังแอปพร้อมกับบัฟเฟอร์ก่อนหน้าซึ่งจะถูกแทนที่ในระหว่างการคอมโพสปัจจุบัน แอปต้องรอจนกว่าจะได้รับสัญญาณ release fence ก่อนจึงจะเขียนเนื้อหาใหม่ลงในบัฟเฟอร์ที่ ส่งคืนให้ - ระบบจะแสดงผลรั้วปัจจุบัน 1 รายการต่อเฟรม ซึ่งเป็นส่วนหนึ่งของ
การเรียกใช้
presentDisplay
รั้วปัจจุบันแสดงเมื่อการ คอมโพสิตของเฟรมนี้เสร็จสมบูรณ์ หรืออีกทางหนึ่งคือเมื่อ ผลลัพธ์ของคอมโพสิตของเฟรมก่อนหน้าไม่จำเป็นอีกต่อไป สำหรับจอแสดงผลจริงpresentDisplay
จะแสดงผลรั้วปัจจุบันเมื่อเฟรมปัจจุบันปรากฏบนหน้าจอ หลังจากที่รั้วปัจจุบันกลับมาแล้ว คุณจะเขียนไปยังบัฟเฟอร์เป้าหมายของ SurfaceFlinger อีกครั้งได้อย่างปลอดภัย หาก เกี่ยวข้อง สำหรับจอแสดงผลเสมือน ระบบจะแสดงรั้วปัจจุบันเมื่อ อ่านจากบัฟเฟอร์เอาต์พุตได้อย่างปลอดภัย