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

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