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

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

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

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

การซิงโครไนซ์ที่ชัดเจน

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

ประโยชน์ของการซิงโครไนซ์อย่างชัดเจน ได้แก่:

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

กรอบงานการซิงค์มีออบเจ็กต์สามประเภท:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

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