เฟรมเวิร์กการซิงค์

เฟรมเวิร์กการซิงค์จะอธิบายการพึ่งพาระหว่างการดำเนินการแบบไม่พร้อมกันที่แตกต่างกันในระบบกราฟิก 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 อีกครั้ง (หากมี) สําหรับจอแสดงผลเสมือน ระบบจะแสดงรั้วที่แสดงอยู่เมื่ออ่านจากบัฟเฟอร์เอาต์พุตได้อย่างปลอดภัย