กรอบการซิงโครไนซ์

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