กรอบงานการซิงโครไนซ์อธิบายการขึ้นต่อกันระหว่างการดำเนินการแบบอะซิงโครนัสต่างๆ ในระบบกราฟิก Android อย่างชัดเจน กรอบงานมี API ที่ช่วยให้ส่วนประกอบสามารถระบุได้เมื่อมีการปล่อยบัฟเฟอร์ กรอบงานยังอนุญาตให้ส่งผ่านพื้นฐานการซิงโครไนซ์ระหว่างไดรเวอร์จากเคอร์เนลไปยังพื้นที่ผู้ใช้และระหว่างกระบวนการของพื้นที่ผู้ใช้เอง
ตัวอย่างเช่น แอปพลิเคชันอาจจัดคิวงานที่จะดำเนินการใน GPU GPU เริ่มวาดภาพนั้น แม้ว่ารูปภาพจะยังไม่ได้วาดลงในหน่วยความจำ แต่ตัวชี้บัฟเฟอร์จะถูกส่งไปยังตัวสร้างหน้าต่างพร้อมกับรั้วที่ระบุว่างาน GPU จะเสร็จสิ้นเมื่อใด ตัวสร้างหน้าต่างเริ่มประมวลผลล่วงหน้าและส่งงานไปยังตัวควบคุมการแสดงผล ในทำนองเดียวกัน งานของ CPU จะเสร็จสิ้นก่อนเวลา เมื่อ GPU เสร็จสิ้น ตัวควบคุมการแสดงผลจะแสดงภาพทันที
กรอบงานการซิงโครไนซ์ยังช่วยให้ผู้ดำเนินการใช้ประโยชน์จากทรัพยากรการซิงโครไนซ์ในส่วนประกอบฮาร์ดแวร์ของตนเอง สุดท้าย เฟรมเวิร์กช่วยให้มองเห็นไปป์ไลน์กราฟิกเพื่อช่วยในการแก้ไขจุดบกพร่อง
การซิงโครไนซ์ที่ชัดเจน
การซิงโครไนซ์อย่างชัดแจ้งช่วยให้ผู้ผลิตและผู้บริโภคของบัฟเฟอร์กราฟิกสามารถส่งสัญญาณเมื่อเสร็จสิ้นโดยใช้บัฟเฟอร์ การซิงโครไนซ์อย่างชัดแจ้งถูกนำมาใช้ในเคอร์เนลสเปซ
ประโยชน์ของการซิงโครไนซ์อย่างชัดแจ้ง ได้แก่:
- การเปลี่ยนแปลงพฤติกรรมระหว่างอุปกรณ์น้อยลง
- รองรับการดีบักที่ดีขึ้น
- ปรับปรุงเมตริกการทดสอบ
กรอบงานการซิงค์มีสามประเภทอ็อบเจ็กต์:
-
sync_timeline
-
sync_pt
-
sync_fence
sync_timeline
sync_timeline
เป็นไทม์ไลน์ที่เพิ่มขึ้นแบบโมโนโทนที่ผู้ขายควรใช้สำหรับอินสแตนซ์ของไดรเวอร์แต่ละรายการ เช่น บริบท GL, ตัวควบคุมการแสดงผล หรือบลิตเตอร์ 2 มิติ sync_timeline
นับงานที่ส่งไปยังเคอร์เนลสำหรับฮาร์ดแวร์ชิ้นใดชิ้นหนึ่ง sync_timeline
ให้การรับประกันเกี่ยวกับลำดับของการดำเนินการและเปิดใช้งานการใช้งานเฉพาะฮาร์ดแวร์
ปฏิบัติตามหลักเกณฑ์เหล่านี้เมื่อใช้งาน sync_timeline
:
- ระบุชื่อที่เป็นประโยชน์สำหรับไดรเวอร์ ไทม์ไลน์ และรั้วทั้งหมดเพื่อทำให้การดีบักง่ายขึ้น
- ใช้ตัวดำเนินการ
timeline_value_str
และpt_value_str
ในไทม์ไลน์เพื่อทำให้เอาต์พุตการดีบักอ่านง่ายขึ้น - ใช้การเติม
driver_data
เพื่อให้ไลบรารี userspace เช่น ไลบรารี GL เข้าถึงข้อมูลไทม์ไลน์ส่วนตัว หากต้องการdata_driver
ช่วยให้ผู้ขายส่งข้อมูลเกี่ยวกับsync_fence
และsync_pts
ที่ไม่เปลี่ยนรูปเพื่อสร้างบรรทัดคำสั่งตามข้อมูลเหล่านั้น - ไม่อนุญาตให้ userspace สร้างหรือส่งสัญญาณรั้วอย่างชัดเจน การสร้างสัญญาณ/รั้วอย่างชัดแจ้งส่งผลให้เกิดการโจมตีแบบปฏิเสธการให้บริการซึ่งจะหยุดการทำงานของไปป์ไลน์
- อย่าเข้าถึง
sync_timeline
,sync_pt
หรือsync_fence
อย่างชัดแจ้ง API มีฟังก์ชันที่จำเป็นทั้งหมด
sync_pt
sync_pt
เป็นค่าเดียวหรือจุดบน sync_timeline
จุดมีสามสถานะ: ใช้งานอยู่ สัญญาณ และข้อผิดพลาด คะแนนเริ่มต้นในสถานะใช้งานอยู่และเปลี่ยนเป็นสถานะสัญญาณหรือสถานะข้อผิดพลาด ตัวอย่างเช่น เมื่อผู้บริโภครูปภาพไม่ต้องการบัฟเฟอร์อีกต่อไป sync_pt
จะถูกส่งสัญญาณเพื่อให้ผู้ผลิตรูปภาพรู้ว่าการเขียนลงในบัฟเฟอร์อีกครั้งนั้นเป็นเรื่องปกติ
sync_fence
sync_fence
คือคอลเล็กชันของค่า sync_pt
ที่มักจะมี sync_timeline
ที่แตกต่างกัน (เช่น สำหรับตัวควบคุมการแสดงผลและ GPU) sync_fence
, sync_pt
และ sync_timeline
เป็นพื้นฐานหลักที่ไดรเวอร์และพื้นที่ผู้ใช้ใช้เพื่อสื่อสารการพึ่งพาของพวกเขา เมื่อรั้วส่งสัญญาณ คำสั่งทั้งหมดที่ออกก่อนรั้วจะรับประกันว่าจะสมบูรณ์ เนื่องจากไดรเวอร์เคอร์เนลหรือบล็อกฮาร์ดแวร์ดำเนินการคำสั่งตามลำดับ
กรอบงานการซิงค์ช่วยให้ผู้บริโภคหรือผู้ผลิตหลายรายส่งสัญญาณเมื่อพวกเขาใช้บัฟเฟอร์เสร็จแล้ว โดยจะสื่อสารข้อมูลการขึ้นต่อกันด้วยพารามิเตอร์ฟังก์ชันเดียว รั้วได้รับการสนับสนุนโดย file descriptor และส่งผ่านจากพื้นที่เคอร์เนลไปยังพื้นที่ผู้ใช้ ตัวอย่างเช่น รั้วสามารถมีค่า sync_pt
สองค่าที่มีความหมายเมื่อผู้ใช้รูปภาพแยกกันสองคนอ่านบัฟเฟอร์เสร็จแล้ว เมื่อมีการส่งสัญญาณรั้ว ผู้ผลิตภาพรู้ว่าผู้บริโภคทั้งสองบริโภคหมดสิ้นแล้ว
รั้ว เช่น ค่า sync_pt
เริ่มใช้งานและเปลี่ยนสถานะตามสถานะของคะแนน ถ้าค่า sync_pt
ทั้งหมดถูกส่งสัญญาณ sync_fence
จะกลายเป็นสัญญาณ หาก sync_pt
หนึ่งรายการอยู่ในสถานะข้อผิดพลาด sync_fence
ทั้งหมดจะมีสถานะข้อผิดพลาด
การเป็นสมาชิกใน sync_fence
จะไม่เปลี่ยนรูปหลังจากสร้างรั้วแล้ว เพื่อให้ได้มากกว่าหนึ่งจุดในรั้ว การผสานจะดำเนินการโดยเพิ่มจุดจากรั้วที่แตกต่างกันสองจุดในรั้วที่สาม หากจุดใดจุดหนึ่งส่งสัญญาณในรั้วต้นทางและอีกจุดหนึ่งไม่มี รั้วที่สามก็จะไม่อยู่ในสถานะส่งสัญญาณด้วย
ในการใช้การซิงโครไนซ์อย่างชัดแจ้ง ให้จัดเตรียมสิ่งต่อไปนี้:
- ระบบย่อยพื้นที่เคอร์เนลที่ใช้เฟรมเวิร์กการซิงค์สำหรับไดรเวอร์ฮาร์ดแวร์เฉพาะ ไดรเวอร์ที่ต้องตระหนักถึงรั้วโดยทั่วไปคือสิ่งที่เข้าถึงหรือสื่อสารกับ 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 ที่เกี่ยวข้องกับรั้วสองรายการ (
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 และไดรเวอร์ที่ต้องสื่อสารระหว่างกัน ออบเจ็กต์ Kernel-space จะแสดงเป็นตัวอธิบายไฟล์ใน userspace
อนุสัญญาบูรณาการ
ปฏิบัติตามข้อตกลงอินเทอร์เฟซ Android HAL:
- หาก API จัดเตรียม file descriptor ที่อ้างถึง
sync_pt
ไดรเวอร์ของผู้ขายหรือ HAL ที่ใช้ API จะต้องปิด file descriptor - หากไดรเวอร์ของผู้ขายหรือ HAL ส่งตัวอธิบายไฟล์ที่มี
sync_pt
ไปยังฟังก์ชัน API ไดรเวอร์ของผู้ขายหรือ HAL จะต้องไม่ปิดตัวอธิบายไฟล์ - หากต้องการใช้ตัวอธิบายไฟล์ Fence ต่อไป ไดรเวอร์ของผู้จำหน่ายหรือ HAL จะต้องทำซ้ำตัวอธิบาย
วัตถุรั้วจะเปลี่ยนชื่อทุกครั้งที่ผ่าน BufferQueue การสนับสนุนรั้วเคอร์เนลช่วยให้รั้วมีสตริงสำหรับชื่อ ดังนั้นเฟรมเวิร์กการซิงค์จึงใช้ชื่อหน้าต่างและดัชนีบัฟเฟอร์ที่จัดคิวเพื่อตั้งชื่อรั้ว เช่น SurfaceView:0
สิ่งนี้มีประโยชน์ในการดีบักเพื่อระบุแหล่งที่มาของการชะงักงันเนื่องจากชื่อปรากฏในเอาต์พุตของ /d/sync
และรายงานจุดบกพร่อง
การรวม ANativeWindow
ANativeWindow ตระหนักถึงรั้ว dequeueBuffer
, queueBuffer
และ cancelBuffer
มีพารามิเตอร์รั้ว
การรวม OpenGL ES
การรวมการซิงค์ OpenGL ES อาศัยส่วนขยาย EGL สองรายการ:
-
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 ดั้งเดิม มีผลลัพธ์เหมือนกับการสอบถามแอตทริบิวต์ set แต่เป็นไปตามข้อตกลงที่ผู้รับปิดรั้ว (ด้วยเหตุนี้การดำเนินการซ้ำกัน) สุดท้าย การทำลายวัตถุ EGLSyncKHR
จะปิดแอตทริบิวต์รั้วภายใน
การรวมฮาร์ดแวร์ Composer
Hardware Composer จัดการการซิงค์รั้วสามประเภท:
- การ รับรั้ว จะถูกส่งต่อพร้อมกับบัฟเฟอร์อินพุตไปยังการเรียก
setLayerBuffer
และsetClientTarget
สิ่งเหล่านี้แสดงถึงการเขียนที่ค้างอยู่ในบัฟเฟอร์และต้องส่งสัญญาณก่อนที่ SurfaceFlinger หรือ HWC จะพยายามอ่านจากบัฟเฟอร์ที่เกี่ยวข้องเพื่อดำเนินการองค์ประกอบ - รั้วที่ปล่อย จะถูกดึงออกมาหลังจากการเรียกไปยัง
presentDisplay
โดยใช้การเรียกgetReleaseFences
สิ่งเหล่านี้แสดงถึงการอ่านที่รออ่านจากบัฟเฟอร์ก่อนหน้าในเลเยอร์เดียวกัน แนวกั้นปล่อยจะส่งสัญญาณเมื่อ HWC ไม่ได้ใช้บัฟเฟอร์ก่อนหน้าอีกต่อไป เนื่องจากบัฟเฟอร์ปัจจุบันได้แทนที่บัฟเฟอร์ก่อนหน้าบนจอแสดงผล รั้วปล่อยจะถูกส่งกลับไปยังแอปพร้อมกับบัฟเฟอร์ก่อนหน้าซึ่งจะถูกแทนที่ระหว่างองค์ประกอบปัจจุบัน แอปต้องรอจนกว่ารั้วปล่อยจะส่งสัญญาณก่อนที่จะเขียนเนื้อหาใหม่ลงในบัฟเฟอร์ที่ส่งคืน - รั้วปัจจุบัน จะถูกส่งคืน หนึ่งรายการต่อเฟรม โดยเป็นส่วนหนึ่งของการเรียกไปยัง
presentDisplay
รั้วปัจจุบันแสดงเมื่อองค์ประกอบของเฟรมนี้เสร็จสมบูรณ์ หรืออีกทางหนึ่ง เมื่อไม่ต้องการผลการจัดองค์ประกอบของเฟรมก่อนหน้าอีกต่อไป สำหรับการแสดงผลทางกายภาพpresentDisplay
จะคืนค่ารั้วปัจจุบันเมื่อเฟรมปัจจุบันปรากฏขึ้นบนหน้าจอ หลังจากที่รั้วปัจจุบันถูกส่งกลับแล้ว จะปลอดภัยที่จะเขียนไปยังบัฟเฟอร์เป้าหมายของ SurfaceFlinger อีกครั้ง หากมี สำหรับจอแสดงผลเสมือน รั้วปัจจุบันจะถูกส่งคืนเมื่ออ่านจากบัฟเฟอร์เอาต์พุตได้อย่างปลอดภัย