กรอบงานการซิงโครไนซ์อธิบายการขึ้นต่อกันอย่างชัดเจนระหว่างการดำเนินการอะซิงโครนัสที่แตกต่างกันในระบบกราฟิก Android กรอบงานจัดเตรียม API ที่ช่วยให้ส่วนประกอบสามารถระบุได้ว่าเมื่อใดที่บัฟเฟอร์ถูกปล่อยออกมา เฟรมเวิร์กยังอนุญาตให้ส่งผ่านการซิงโครไนซ์ดั้งเดิมระหว่างไดรเวอร์จากเคอร์เนลไปยังพื้นที่ผู้ใช้และระหว่างกระบวนการของพื้นที่ผู้ใช้เอง
ตัวอย่างเช่น แอปพลิเคชันอาจจัดคิวงานที่จะดำเนินการใน GPU GPU เริ่มวาดภาพนั้น แม้ว่ารูปภาพจะยังไม่ได้ถูกวาดลงในหน่วยความจำ ตัวชี้บัฟเฟอร์จะถูกส่งผ่านไปยังตัวสร้างหน้าต่างพร้อมกับรั้วที่ระบุว่าเมื่อใดที่การทำงานของ GPU จะเสร็จสิ้น ตัวสร้างหน้าต่างเริ่มประมวลผลล่วงหน้าและส่งงานไปยังตัวควบคุมการแสดงผล ในทำนองเดียวกัน งาน CPU จะดำเนินการก่อนเวลาอันควร เมื่อ GPU เสร็จสิ้น ตัวควบคุมการแสดงผลจะแสดงภาพทันที
กรอบงานการซิงโครไนซ์ยังช่วยให้ผู้ใช้งานใช้ประโยชน์จากทรัพยากรการซิงโครไนซ์ในส่วนประกอบฮาร์ดแวร์ของตนเอง สุดท้ายนี้ กรอบงานจะช่วยให้มองเห็นไปป์ไลน์กราฟิกเพื่อช่วยในการแก้ไขจุดบกพร่อง
การซิงโครไนซ์ที่ชัดเจน
การซิงโครไนซ์อย่างชัดเจนช่วยให้ผู้ผลิตและผู้บริโภคบัฟเฟอร์กราฟิกสามารถส่งสัญญาณเมื่อพวกเขาใช้บัฟเฟอร์เสร็จแล้ว การซิงโครไนซ์ที่ชัดเจนถูกนำไปใช้ในพื้นที่เคอร์เนล
ประโยชน์ของการซิงโครไนซ์อย่างชัดเจน ได้แก่:
- การเปลี่ยนแปลงพฤติกรรมระหว่างอุปกรณ์น้อยลง
- รองรับการดีบักที่ดีขึ้น
- ปรับปรุงการวัดการทดสอบ
กรอบงานการซิงค์มีออบเจ็กต์สามประเภท:
-
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
จุดมีสามสถานะ: ใช้งานอยู่, ส่งสัญญาณ และผิดพลาด คะแนนเริ่มต้นในสถานะใช้งานและเปลี่ยนเป็นสถานะสัญญาณหรือข้อผิดพลาด ตัวอย่างเช่น เมื่อผู้บริโภครูปภาพไม่ต้องการบัฟเฟอร์อีกต่อไป sync_pt
จะถูกส่งสัญญาณเพื่อให้ผู้สร้างรูปภาพรู้ว่าคุณสามารถเขียนลงในบัฟเฟอร์อีกครั้งได้
sync_fence
sync_fence
คือชุดของค่า sync_pt
ที่มักจะมีพาเรนต์ sync_timeline
ที่แตกต่างกัน (เช่น สำหรับตัวควบคุมการแสดงผลและ GPU) sync_fence
, sync_pt
และ sync_timeline
เป็นคุณสมบัติพื้นฐานหลักที่ไดรเวอร์และพื้นที่ผู้ใช้ใช้เพื่อสื่อสารการขึ้นต่อกัน เมื่อรั้วส่งสัญญาณ คำสั่งทั้งหมดที่ออกก่อนที่รั้วจะรับประกันว่าจะเสร็จสมบูรณ์ เนื่องจากไดรเวอร์เคอร์เนลหรือบล็อกฮาร์ดแวร์ดำเนินการคำสั่งตามลำดับ
กรอบงานการซิงค์ช่วยให้ผู้บริโภคหรือผู้ผลิตหลายรายส่งสัญญาณเมื่อพวกเขาใช้บัฟเฟอร์เสร็จแล้ว โดยสื่อสารข้อมูลการขึ้นต่อกันด้วยพารามิเตอร์ฟังก์ชันเดียว รั้วได้รับการสนับสนุนโดยตัวอธิบายไฟล์และถูกส่งผ่านจากพื้นที่เคอร์เนลไปยังพื้นที่ผู้ใช้ ตัวอย่างเช่น รั้วสามารถมีค่า 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 จะแสดงเป็นตัวอธิบายไฟล์ในพื้นที่ผู้ใช้
อนุสัญญาบูรณาการ
ปฏิบัติตามข้อตกลงอินเทอร์เฟซ Android HAL:
- หาก 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 สองรายการ:
-
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
จะปิดแอตทริบิวต์รั้วภายใน
การรวมฮาร์ดแวร์นักแต่งเพลง
Hardware Composer จัดการกับรั้วการซิงค์สามประเภท:
- การรับรั้ว จะถูกส่งผ่านพร้อมกับบัฟเฟอร์อินพุตไปยังการเรียก
setLayerBuffer
และsetClientTarget
สิ่งเหล่านี้แสดงถึงการเขียนที่รอดำเนินการลงในบัฟเฟอร์ และต้องส่งสัญญาณก่อนที่ SurfaceFlinger หรือ HWC จะพยายามอ่านจากบัฟเฟอร์ที่เกี่ยวข้องเพื่อดำเนินการจัดองค์ประกอบ - Release Fences จะถูกดึงข้อมูลหลังจากการเรียกไปยัง
presentDisplay
โดยใช้การเรียกgetReleaseFences
สิ่งเหล่านี้แสดงถึงการอ่านที่รอดำเนินการจากบัฟเฟอร์ก่อนหน้าบนเลเยอร์เดียวกัน กรอบปลดล็อคจะส่งสัญญาณเมื่อ HWC ไม่ได้ใช้บัฟเฟอร์ก่อนหน้าอีกต่อไป เนื่องจากบัฟเฟอร์ปัจจุบันได้แทนที่บัฟเฟอร์ก่อนหน้าบนจอแสดงผล กรอบการเผยแพร่จะถูกส่งกลับไปยังแอปพร้อมกับบัฟเฟอร์ก่อนหน้าซึ่งจะถูกแทนที่ระหว่างองค์ประกอบปัจจุบัน แอปต้องรอจนกว่าสัญญาณรั้วการเปิดตัวจึงจะเขียนเนื้อหาใหม่ลงในบัฟเฟอร์ที่ถูกส่งกลับมาได้ - รั้วปัจจุบัน จะถูกส่งกลับ หนึ่งรายการต่อเฟรม ซึ่งเป็นส่วนหนึ่งของการเรียกไปยัง
presentDisplay
รั้วปัจจุบันแสดงถึงเมื่อองค์ประกอบของเฟรมนี้เสร็จสมบูรณ์แล้ว หรือสลับกัน เมื่อไม่จำเป็นต้องใช้ผลการจัดองค์ประกอบของเฟรมก่อนหน้าอีกต่อไป สำหรับการแสดงผลทางกายภาพpresentDisplay
จะส่งคืนรั้วปัจจุบันเมื่อเฟรมปัจจุบันปรากฏบนหน้าจอ หลังจากคืนรั้วปัจจุบันแล้ว คุณสามารถเขียนไปยังบัฟเฟอร์เป้าหมาย SurfaceFlinger อีกครั้งได้อย่างปลอดภัย หากมี สำหรับจอแสดงผลเสมือน รั้วปัจจุบันจะถูกส่งกลับเมื่ออ่านจากบัฟเฟอร์เอาต์พุตได้อย่างปลอดภัย