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

เฟรมเวิร์กการซิงค์อธิบายการพึ่งพากันระหว่างการดำเนินการแบบไม่พร้อมกันต่างๆ ในระบบกราฟิกของ Android อย่างชัดเจน เฟรมเวิร์กมี API ที่ช่วยให้คอมโพเนนต์ระบุได้ว่าเมื่อใดที่บัฟเฟอร์จะได้รับการเผยแพร่ นอกจากนี้ เฟรมเวิร์กยังอนุญาตให้ส่งผ่าน Primitive การซิงค์ระหว่างไดรเวอร์จากเคอร์เนลไปยัง Userspace และระหว่างกระบวนการ Userspace เอง

ตัวอย่างเช่น แอปพลิเคชันอาจจัดคิวงานที่จะดำเนินการใน GPU GPU จะเริ่มวาดรูปภาพนั้น แม้ว่ารูปภาพจะยังไม่ได้วาดลงในหน่วยความจำ แต่ระบบจะส่งตัวชี้บัฟเฟอร์ไปยังคอมโพสิตเตอร์หน้าต่างพร้อมกับ Fence ที่ระบุเวลาที่งานของ GPU จะเสร็จสมบูรณ์ คอมโพสิตเตอร์หน้าต่างจะเริ่มประมวลผลล่วงหน้าและส่งงานไปยังตัวควบคุมจอแสดงผล ในลักษณะเดียวกัน งานของ CPU จะดำเนินการล่วงหน้า เมื่อ GPU ทำงานเสร็จ ตัวควบคุมจอแสดงผลจะแสดงรูปภาพทันที

เฟรมเวิร์กการซิงค์ยังช่วยให้ผู้ติดตั้งใช้งานใช้ทรัพยากรการซิงค์ในคอมโพเนนต์ฮาร์ดแวร์ของตนเองได้ด้วย สุดท้าย เฟรมเวิร์กจะให้การมองเห็นไปป์ไลน์กราฟิกเพื่อช่วยในการแก้ไขข้อบกพร่อง

การซิงค์อย่างชัดเจน

การซิงค์อย่างชัดเจนช่วยให้ผู้ผลิตและผู้ใช้บัฟเฟอร์กราฟิกส่งสัญญาณได้เมื่อใช้บัฟเฟอร์เสร็จแล้ว การซิงค์อย่างชัดเจนจะใช้งานใน Kernel-Space

ข้อดีของการซิงค์อย่างชัดเจนมีดังนี้

  • ความแตกต่างของลักษณะการทำงานระหว่างอุปกรณ์น้อยลง
  • การสนับสนุนการแก้ไขข้อบกพร่องที่ดีขึ้น
  • เมตริกการทดสอบที่ปรับปรุงให้ดีขึ้น

เฟรมเวิร์กการซิงค์มีออบเจ็กต์ 3 ประเภท ได้แก่

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline เป็นไทม์ไลน์ที่เพิ่มขึ้นอย่างต่อเนื่องซึ่งผู้ให้บริการควรติดตั้งใช้งานสำหรับอินสแตนซ์ไดรเวอร์แต่ละรายการ เช่น บริบท GL, ตัวควบคุมจอแสดงผล หรือ Blitter 2 มิติ sync_timeline จะนับงานที่ส่งไปยังเคอร์เนลสำหรับฮาร์ดแวร์ชิ้นหนึ่งๆ sync_timeline ช่วยให้มั่นใจได้ถึงลำดับการดำเนินการและช่วยให้การติดตั้งใช้งานเฉพาะฮาร์ดแวร์เป็นไปได้

ทำตามหลักเกณฑ์ต่อไปนี้เมื่อติดตั้งใช้งาน sync_timeline

  • ตั้งชื่อที่มีประโยชน์สำหรับไดรเวอร์ ไทม์ไลน์ และ Fence ทั้งหมดเพื่อลดความซับซ้อนในการแก้ไขข้อบกพร่อง
  • ติดตั้งใช้งานโอเปอเรเตอร์ timeline_value_str และ pt_value_str ในไทม์ไลน์เพื่อให้เอาต์พุตการแก้ไขข้อบกพร่องอ่านง่ายขึ้น
  • ติดตั้งใช้งาน driver_data ที่เติมข้อมูลเพื่ออนุญาตให้ไลบรารี Userspace เช่น ไลบรารี GL เข้าถึงข้อมูลไทม์ไลน์ส่วนตัวได้ หากจำเป็น data_driver ช่วยให้ผู้ให้บริการส่งข้อมูลเกี่ยวกับ sync_fence และ sync_pts ที่เปลี่ยนแปลงไม่ได้เพื่อสร้างบรรทัดคำสั่ง ตามข้อมูลดังกล่าว
  • ไม่อนุญาตให้ Userspace สร้างหรือส่งสัญญาณ Fence อย่างชัดเจน การสร้างสัญญาณ/Fence อย่างชัดเจน จะส่งผลให้เกิดการโจมตีแบบปฏิเสธการให้บริการซึ่ง จะหยุดฟังก์ชันการทำงานของไปป์ไลน์
  • อย่าเข้าถึงองค์ประกอบ 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 เป็น Primitive หลักที่ไดรเวอร์และ Userspace ใช้เพื่อสื่อสารการพึ่งพากัน เมื่อ Fence ได้รับสัญญาณ คำสั่งทั้งหมดที่ออกก่อน Fence จะเสร็จสมบูรณ์เนื่องจากไดรเวอร์เคอร์เนลหรือบล็อกฮาร์ดแวร์จะดำเนินการคำสั่งตามลำดับ

เฟรมเวิร์กการซิงค์อนุญาตให้ผู้ใช้หรือผู้ผลิตหลายรายส่งสัญญาณได้เมื่อใช้บัฟเฟอร์เสร็จแล้ว โดยจะสื่อสารข้อมูลทรัพยากร Dependency ด้วยพารามิเตอร์ฟังก์ชันเดียว Fence ได้รับการสนับสนุนโดยตัวระบุไฟล์และส่งผ่านจาก Kernel-Space ไปยัง Userspace ตัวอย่างเช่น Fence สามารถมีค่า sync_pt 2 ค่าที่บ่งบอกว่าผู้ใช้รูปภาพ 2 รายแยกกันอ่านบัฟเฟอร์เสร็จแล้ว เมื่อ Fence ได้รับสัญญาณ ผู้ผลิตรูปภาพจะทราบว่าผู้ใช้ทั้ง 2 รายใช้รูปภาพเสร็จแล้ว

Fence เช่น ค่า sync_pt จะเริ่มต้นใช้งานอยู่และเปลี่ยนสถานะตามสถานะของจุด หากค่า sync_pt ทั้งหมดได้รับสัญญาณ sync_fence จะได้รับสัญญาณ หาก sync_pt รายการใดรายการหนึ่งอยู่ในสถานะข้อผิดพลาด sync_fence ทั้งหมดจะอยู่ในสถานะข้อผิดพลาด

การเป็นสมาชิกใน sync_fence จะเปลี่ยนแปลงไม่ได้หลังจากสร้าง Fence แล้ว หากต้องการรับจุดมากกว่า 1 จุดใน Fence ระบบจะผสานจุดจาก Fence 2 รายการที่แตกต่างกันลงใน Fence รายการที่ 3 หากจุดใดจุดหนึ่งได้รับสัญญาณใน Fence ต้นทางและอีกจุดไม่ได้รับ Fence รายการที่ 3 ก็จะไม่อยู่ในสถานะได้รับสัญญาณด้วย

หากต้องการติดตั้งใช้งานการซิงค์อย่างชัดเจน ให้ระบุข้อมูลต่อไปนี้

  • ระบบย่อย Kernel-Space ที่ติดตั้งใช้งานเฟรมเวิร์กการซิงค์สำหรับไดรเวอร์ฮาร์ดแวร์หนึ่งๆ โดยทั่วไป ไดรเวอร์ที่ต้องรับรู้ Fence คือไดรเวอร์ที่เข้าถึงหรือสื่อสารกับ Hardware Composer (HWC) ไฟล์สำคัญ ได้แก่
    • การติดตั้งใช้งานหลัก
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • เอกสารประกอบที่ kernel/common/Documentation/sync.txt
    • ไลบรารีสำหรับสื่อสารกับ Kernel-Space ใน platform/system/core/libsync
  • ผู้ให้บริการต้องระบุ Fence การซิงค์ที่เหมาะสมเป็นพารามิเตอร์สำหรับฟังก์ชัน validateDisplay() และ presentDisplay() ในระดับชั้นการจัดการฮาร์ดแวร์โดยตรง (HAL)
  • ส่วนขยาย GL 2 รายการที่เกี่ยวข้องกับ Fence (EGL_ANDROID_native_fence_sync และ EGL_ANDROID_wait_sync) และการสนับสนุน Fence ในไดรเวอร์กราฟิก

กรณีศึกษา: ติดตั้งใช้งานไดรเวอร์จอแสดงผล

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

การจัดคิวและเริ่มงานหลังจาก Fence ล้างแล้วจะไม่บล็อกสิ่งใด คุณจะส่งคืน Fence ของคุณเองทันที ซึ่งจะส่งสัญญาณเมื่อบัฟเฟอร์จะไม่อยู่บนจอแสดงผล เมื่อคุณจัดคิวบัฟเฟอร์ เคอร์เนลจะแสดงการพึ่งพากันด้วยเฟรมเวิร์กการซิงค์ดังนี้

/*
 * 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);

การผสานรวมการซิงค์

ส่วนนี้จะอธิบายวิธีผสานรวมเฟรมเวิร์กการซิงค์ Kernel-Space กับส่วน Userspace ของเฟรมเวิร์ก Android และไดรเวอร์ที่ต้องสื่อสารกัน ออบเจ็กต์ Kernel-Space จะแสดงเป็นตัวระบุไฟล์ใน Userspace

กฎการผสานรวม

ทำตามกฎอินเทอร์เฟซ Android HAL ดังนี้

  • หาก API มีตัวบอกไฟล์ที่อ้างอิง sync_pt, ไดรเวอร์ของผู้ให้บริการหรือ HAL ที่ใช้ API ต้องปิดตัวบอกไฟล์
  • หากไดรเวอร์ของผู้ให้บริการหรือ HAL ส่งตัวบอกไฟล์ที่มี a sync_pt ไปยังฟังก์ชัน API ไดรเวอร์ของผู้ให้บริการหรือ HAL ต้องไม่ ปิดตัวบอกไฟล์
  • หากต้องการใช้ตัวระบุไฟล์ Fence ต่อไป ไดรเวอร์ของผู้ให้บริการหรือ HAL ต้องทำซ้ำตัวระบุ

ระบบจะเปลี่ยนชื่อออบเจ็กต์ Fence ทุกครั้งที่ผ่าน BufferQueue การสนับสนุน Fence ของเคอร์เนลอนุญาตให้ Fence มีสตริงสำหรับชื่อ ดังนั้นเฟรมเวิร์กการซิงค์จึงใช้ชื่อหน้าต่างและดัชนีบัฟเฟอร์ที่จัดคิวเพื่อตั้งชื่อ Fence เช่น SurfaceView:0 ซึ่งจะเป็นประโยชน์ในการแก้ไขข้อบกพร่องเพื่อระบุแหล่งที่มาของการติดตายเนื่องจากชื่อจะปรากฏในเอาต์พุตของ /d/sync และรายงานข้อบกพร่อง

การผสานรวม ANativeWindow

ANativeWindow รับรู้ Fence dequeueBuffer, queueBuffer และ cancelBuffer มีพารามิเตอร์ Fence

การผสานรวม OpenGL ES

การผสานรวมการซิงค์ OpenGL ES อาศัยส่วนขยาย EGL 2 รายการ ได้แก่

  • EGL_ANDROID_native_fence_sync มีวิธี ห่อหรือสร้างตัวระบุไฟล์ Fence แบบเนทีฟของ 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 Fence แบบเนทีฟที่แตกต่างกัน ด้วยเหตุนี้ ส่วนขยายที่ใช้กับประเภทออบเจ็กต์ EGLSyncKHR ที่มีอยู่จึงไม่จำเป็นต้องใช้กับออบเจ็กต์ EGL_ANDROID_native_fence ซึ่งจะหลีกเลี่ยงการโต้ตอบที่ไม่ต้องการ

ส่วนขยาย EGL_ANDROID_native_fence_sync ใช้แอตทริบิวต์ตัวบอกไฟล์ Fence แบบเนทีฟที่เกี่ยวข้อง ซึ่งตั้งค่าได้เฉพาะตอนสร้างและไม่สามารถค้นหาโดยตรงจากออบเจ็กต์การซิงค์ที่มีอยู่ แอตทริบิวต์นี้สามารถตั้งค่าเป็นโหมดใดโหมดหนึ่งจาก 2 โหมดต่อไปนี้

  • ตัวระบุไฟล์ Fence ที่ถูกต้อง จะห่อตัวระบุไฟล์ Fence แบบเนทีฟของ Android ที่มีอยู่ในออบเจ็กต์ EGLSyncKHR
  • -1 จะสร้างตัวบอกไฟล์ Fence แบบเนทีฟของ Android จากออบเจ็กต์ EGLSyncKHR

ใช้การเรียกใช้ฟังก์ชัน DupNativeFenceFD() เพื่อแยกออบเจ็กต์ EGLSyncKHR ออกจากตัวบอกไฟล์ Fence แบบเนทีฟของ Android ซึ่งให้ผลลัพธ์เหมือนกับการค้นหาแอตทริบิวต์ที่ตั้งค่าไว้ แต่เป็นไปตามกฎที่ผู้รับจะปิด Fence (จึงต้องดำเนินการซ้ำ) สุดท้าย การทำลายออบเจ็กต์ EGLSyncKHR จะปิดแอตทริบิวต์ Fence ภายใน

การผสานรวม Hardware Composer

HWC จัดการ Fence การซิงค์ 3 ประเภท ได้แก่

  • Fence การรับ จะส่งผ่านพร้อมกับบัฟเฟอร์อินพุตไปยัง การเรียก setLayerBuffer และ setClientTarget ซึ่งแสดงถึงการเขียนที่รอดำเนินการลงในบัฟเฟอร์และต้องส่งสัญญาณก่อนที่ SurfaceFlinger หรือ HWC จะพยายามอ่านจากบัฟเฟอร์ที่เชื่อมโยงเพื่อ ทำการคอมโพสิต
  • Fence การเผยแพร่ จะดึงข้อมูลหลังจากการเรียก presentDisplay โดยใช้การเรียก getReleaseFences ซึ่งแสดงถึงการอ่านที่รอดำเนินการจากบัฟเฟอร์ก่อนหน้าในเลเยอร์เดียวกัน Fence การเผยแพร่จะส่งสัญญาณเมื่อ HWC ไม่ได้ใช้บัฟเฟอร์ก่อนหน้าอีกต่อไปเนื่องจากบัฟเฟอร์ปัจจุบันได้แทนที่บัฟเฟอร์ก่อนหน้าบนจอแสดงผล ระบบจะส่ง Fence การเผยแพร่กลับไปยังแอปพร้อมกับบัฟเฟอร์ก่อนหน้าที่จะถูกแทนที่ระหว่างการคอมโพสิตปัจจุบัน แอปต้องรอจนกว่า Fence การเผยแพร่จะส่งสัญญาณก่อนที่จะเขียนเนื้อหาใหม่ลงในบัฟเฟอร์ที่ ส่งคืนให้
  • Fence ปัจจุบัน จะแสดงผล 1 รายการต่อเฟรม ซึ่งเป็นส่วนหนึ่งของ การเรียก presentDisplay Fence ปัจจุบันแสดงถึงเวลาที่การ คอมโพสิตของเฟรมนี้เสร็จสมบูรณ์ หรืออีกทางหนึ่งคือเมื่อไม่จำเป็นต้องใช้ผลการ คอมโพสิตของเฟรมก่อนหน้าอีกต่อไป สำหรับจอแสดงผลจริง presentDisplay จะแสดงผล Fence ปัจจุบันเมื่อเฟรมปัจจุบันปรากฏบนหน้าจอ หลังจากแสดงผล Fence ปัจจุบันแล้ว คุณจะเขียนลงในบัฟเฟอร์เป้าหมาย SurfaceFlinger อีกครั้งได้อย่างปลอดภัย หาก มี สำหรับจอแสดงผลเสมือน ระบบจะแสดงผล Fence ปัจจุบันเมื่ออ่านจากบัฟเฟอร์เอาต์พุตได้อย่างปลอดภัย