ใช้ฮาร์ดแวร์นักแต่งเพลง HAL

เลเยอร์คอมโพสิต Hardware Composer (HWC) HAL ที่ได้รับจาก SurfaceFlinger ช่วยลดปริมาณองค์ประกอบ OpenGL ES (GLES) และประสิทธิภาพของ GPU

HWC จะสรุปวัตถุ เช่น ภาพซ้อนทับและ 2D Blitter ไปยังพื้นผิวคอมโพสิต และสื่อสารกับฮาร์ดแวร์องค์ประกอบหน้าต่างแบบพิเศษไปยังหน้าต่างคอมโพสิต ใช้ HWC เพื่อรวมหน้าต่างแทนที่จะมี SurfaceFlinger ประกอบกับ GPU GPU ส่วนใหญ่ไม่ได้รับการปรับให้เหมาะสมสำหรับการจัดองค์ประกอบ และเมื่อ GPU เขียนเลเยอร์จาก SurfaceFlinger แอปจะไม่สามารถใช้ GPU สำหรับการเรนเดอร์ของตัวเองได้

การใช้งาน HWC ควรสนับสนุน:

  • อย่างน้อยสี่ภาพซ้อนทับ:
    • แถบสถานะ
    • แถบระบบ
    • แอป
    • วอลเปเปอร์/พื้นหลัง
  • เลเยอร์ที่มีขนาดใหญ่กว่าจอแสดงผล (เช่น วอลเปเปอร์)
  • การผสมอัลฟ่าต่อพิกเซลแบบคูณล่วงหน้าพร้อมกันและการผสมอัลฟ่าต่อระนาบพร้อมกัน
  • เส้นทางฮาร์ดแวร์สำหรับการเล่นวิดีโอที่มีการป้องกัน
  • ลำดับการบรรจุ RGBA รูปแบบ YUV และคุณสมบัติการเรียง การสลับ และการก้าวย่าง

หากต้องการนำ HWC ไปใช้:

  1. ใช้ HWC ที่ไม่ได้ดำเนินการและส่งงานเรียบเรียงทั้งหมดไปที่ GLES
  2. ใช้อัลกอริทึมเพื่อมอบหมายองค์ประกอบให้กับ HWC แบบค่อยเป็นค่อยไป ตัวอย่างเช่น มอบหมายเฉพาะพื้นผิวสามหรือสี่พื้นผิวแรกให้กับฮาร์ดแวร์โอเวอร์เลย์ของ HWC
  3. ปรับ HWC ให้เหมาะสม ซึ่งอาจรวมถึง:
    • การเลือกพื้นผิวที่รับภาระสูงสุดจาก GPU และส่งไปยัง HWC
    • ตรวจสอบว่าหน้าจอกำลังอัปเดตอยู่หรือไม่ หากไม่เป็นเช่นนั้น ให้มอบหมายการจัดองค์ประกอบให้กับ GLES แทน HWC เพื่อประหยัดพลังงาน เมื่อหน้าจออัปเดตอีกครั้ง ให้ถ่ายองค์ประกอบไปยัง HWC ต่อไป
    • การเตรียมพร้อมสำหรับกรณีการใช้งานทั่วไป เช่น:
      • หน้าจอหลักซึ่งประกอบด้วยแถบสถานะ แถบระบบ หน้าต่างแอพ และวอลเปเปอร์เคลื่อนไหว
      • เกมเต็มหน้าจอในโหมดแนวตั้งและแนวนอน
      • วิดีโอแบบเต็มหน้าจอพร้อมคำบรรยายและการควบคุมการเล่น
      • การเล่นวิดีโอที่ได้รับการป้องกัน
      • มัลติวินโดว์แบบแยกหน้าจอ

HWC ดั้งเดิม

HWC มีพื้นฐานสองแบบ ได้แก่ เลเยอร์ และ จอแสดงผล เพื่อแสดงงานองค์ประกอบและการโต้ตอบกับฮาร์ดแวร์จอแสดงผล HWC ยังให้การควบคุม VSYNC และการเรียกกลับไปยัง SurfaceFlinger เพื่อแจ้งเตือนเมื่อมีเหตุการณ์ VSYNC เกิดขึ้น

อินเตอร์เฟซ HIDL

Android 8.0 และสูงกว่าใช้อินเทอร์เฟซ HIDL ที่เรียกว่า Composer HAL สำหรับ IPC ที่ถูกผูกไว้ระหว่าง HWC และ SurfaceFlinger Composer HAL แทนที่อินเทอร์เฟ hwcomposer2.h แบบเดิม หากผู้จำหน่ายจัดให้มีการนำ Composer HAL ไปใช้ HWC ทาง Composer HAL จะยอมรับการเรียก HIDL จาก SurfaceFlinger โดยตรง หากผู้จำหน่ายจัดให้มีการใช้งาน HWC แบบเดิม Composer HAL จะโหลดตัวชี้ฟังก์ชันจาก hwcomposer2.h โดยส่งต่อการเรียก HIDL ไปยังการเรียกตัวชี้ฟังก์ชัน

HWC มีฟังก์ชันเพื่อกำหนดคุณสมบัติของจอแสดงผลที่กำหนด เพื่อสลับระหว่างการกำหนดค่าการแสดงผลที่แตกต่างกัน (เช่น ความละเอียด 4k หรือ 1080p) และโหมดสี (เช่น สีดั้งเดิมหรือ sRGB จริง) และเพื่อเปิด ปิด หรือเข้าสู่โหมดพลังงานต่ำหากรองรับ

พอยน์เตอร์ฟังก์ชัน

หากผู้จำหน่ายใช้ Composer HAL โดยตรง SurfaceFlinger จะเรียกใช้ฟังก์ชันผ่าน HIDL IPC ตัวอย่างเช่น หากต้องการสร้างเลเยอร์ SurfaceFlinger จะเรียก createLayer() บน Composer HAL

หากผู้จำหน่ายใช้อินเทอร์เฟ hwcomposer2.h Composer HAL จะเรียกเข้าสู่ตัวชี้ฟังก์ชัน hwcomposer2.h ในความคิดเห็น hwcomposer2.h ฟังก์ชันอินเทอร์เฟซ HWC จะถูกอ้างอิงโดยชื่อ lowerCamelCase ที่ไม่มีอยู่ในอินเทอร์เฟซเป็นฟิลด์ที่มีชื่อ เกือบทุกฟังก์ชั่นจะถูกโหลดโดยการร้องขอตัวชี้ฟังก์ชั่นโดยใช้ getFunction ที่จัดทำโดย hwc2_device_t ตัวอย่างเช่น ฟังก์ชัน createLayer คือตัวชี้ฟังก์ชันประเภท HWC2_PFN_CREATE_LAYER ซึ่งจะถูกส่งกลับเมื่อค่าที่แจกแจง HWC2_FUNCTION_CREATE_LAYER ถูกส่งผ่านไปยัง getFunction

สำหรับเอกสารประกอบโดยละเอียดเกี่ยวกับฟังก์ชัน Composer HAL และฟังก์ชัน passthrough ของฟังก์ชัน HWC โปรดดูที่ composer สำหรับเอกสารประกอบโดยละเอียดเกี่ยวกับพอยน์เตอร์ฟังก์ชัน HWC โปรดดูที่ hwcomposer2.h

ที่จับเลเยอร์และจอแสดงผล

เลเยอร์และจอแสดงผลได้รับการจัดการโดยแฮนเดิลที่สร้างโดย HWC ที่จับไม่ทึบสำหรับ SurfaceFlinger

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

จอแสดงผลทางกายภาพถูกสร้างขึ้นโดยการเสียบปลั๊ก เมื่อจอแสดงผลทางกายภาพถูกเสียบปลั๊ก HWC จะสร้างหมายเลขอ้างอิงและส่งหมายเลขอ้างอิงไปยัง SurfaceFlinger ผ่านการเรียกกลับแบบปลั๊กร้อน จอแสดงผลเสมือนถูกสร้างขึ้นโดย SurfaceFlinger เรียก createVirtualDisplay() เพื่อขอจอแสดงผล ถ้า HWC สนับสนุนองค์ประกอบการแสดงผลเสมือน ก็จะส่งกลับหมายเลขอ้างอิง จากนั้น SurfaceFlinger จะมอบหมายองค์ประกอบของจอแสดงผลให้กับ HWC หาก HWC ไม่รองรับการจัดองค์ประกอบการแสดงผลเสมือน SurfaceFlinger จะสร้างที่จับและประกอบการแสดงผล

แสดงการดำเนินการจัดองค์ประกอบ

หนึ่งครั้งต่อ VSYNC SurfaceFlinger จะปลุกหากมีเนื้อหาใหม่ที่จะประกอบ เนื้อหาใหม่นี้อาจเป็นบัฟเฟอร์รูปภาพใหม่จากแอปหรือการเปลี่ยนแปลงคุณสมบัติของเลเยอร์ตั้งแต่หนึ่งเลเยอร์ขึ้นไป เมื่อ SurfaceFlinger ปลุกระบบ:

  1. จัดการธุรกรรม หากมี
  2. สลักบัฟเฟอร์กราฟิกใหม่ หากมี
  3. ดำเนินการจัดองค์ประกอบใหม่ หากขั้นตอนที่ 1 หรือ 2 ส่งผลให้เนื้อหาที่แสดงมีการเปลี่ยนแปลง

ในการจัดองค์ประกอบใหม่ SurfaceFlinger จะสร้างและทำลายเลเยอร์หรือแก้ไขสถานะของเลเยอร์ตามความเหมาะสม นอกจากนี้ยังอัปเดตเลเยอร์ด้วยเนื้อหาปัจจุบัน โดยใช้การเรียก เช่น setLayerBuffer หรือ setLayerColor หลังจากอัปเดตเลเยอร์ทั้งหมดแล้ว SurfaceFlinger จะเรียก validateDisplay ซึ่งบอกให้ HWC ตรวจสอบสถานะของเลเยอร์และพิจารณาว่าองค์ประกอบจะดำเนินการอย่างไร ตามค่าเริ่มต้น SurfaceFlinger จะพยายามกำหนดค่าทุกเลเยอร์เพื่อให้เลเยอร์ถูกประกอบโดย HWC แม้ว่าในบางกรณี SurfaceFlinger จะผสมเลเยอร์ผ่านทางเลือกสำรองของ GPU

หลังจากการเรียก validateDisplay แล้ว SurfaceFlinger จะเรียก getChangedCompositionTypes เพื่อดูว่า HWC ต้องการให้ประเภทการจัดองค์ประกอบเลเยอร์ใด ๆ เปลี่ยนแปลงก่อนที่จะดำเนินการจัดองค์ประกอบหรือไม่ หากต้องการยอมรับการเปลี่ยนแปลง SurfaceFlinger จะเรียก acceptDisplayChanges

หากมีการทำเครื่องหมายเลเยอร์ใดๆ สำหรับองค์ประกอบของ SurfaceFlinger SurfaceFlinger จะรวมเลเยอร์เหล่านั้นลงในบัฟเฟอร์เป้าหมาย จากนั้น SurfaceFlinger เรียก setClientTarget เพื่อมอบบัฟเฟอร์ให้กับจอแสดงผลเพื่อให้สามารถแสดงบัฟเฟอร์บนหน้าจอหรือรวมเข้ากับเลเยอร์เพิ่มเติมที่ไม่ได้ถูกทำเครื่องหมายสำหรับองค์ประกอบของ SurfaceFlinger ถ้าไม่มีการทำเครื่องหมายเลเยอร์สำหรับองค์ประกอบของ SurfaceFlinger แล้ว SurfaceFlinger จะข้ามขั้นตอนการประกอบ

สุดท้าย SurfaceFlinger เรียก presentDisplay เพื่อบอก HWC ให้เสร็จสิ้นกระบวนการจัดองค์ประกอบและแสดงผลลัพธ์สุดท้าย

จอแสดงผลหลายจอ

Android 10 รองรับการแสดงผลทางกายภาพหลายจอ เมื่อออกแบบการใช้งาน HWC ที่มีไว้สำหรับใช้กับ Android 7.0 และสูงกว่า มีข้อจำกัดบางประการที่ไม่ปรากฏในคำจำกัดความของ HWC:

  • สันนิษฐานว่ามีจอแสดงผล ภายใน เพียงจอเดียวเท่านั้น จอแสดงผลภายในคือจอแสดงผลที่ฮอตปลั๊กเริ่มต้นรายงานระหว่างการบูต หลังจากเสียบปลั๊กจอแสดงผลภายในแล้ว จะไม่สามารถถอดออกได้
  • นอกเหนือจากจอแสดงผลภายในแล้ว จอแสดงผลภายนอกจำนวนเท่าใดก็ได้อาจถูกเสียบปลั๊กระหว่างการทำงานปกติของอุปกรณ์ กรอบงานถือว่าฮอตปลั๊กทั้งหมดหลังจากจอแสดงผลภายในจอแรกเป็นจอแสดงผลภายนอก ดังนั้น หากมีการเพิ่มจอแสดงผลภายในเพิ่มเติม จอแสดงผลเหล่านั้นจะถูกจัดหมวดหมู่อย่างไม่ถูกต้องเป็น Display.TYPE_HDMI แทนที่จะเป็น Display.TYPE_BUILT_IN

แม้ว่าการทำงานของ SurfaceFlinger ที่อธิบายไว้ข้างต้นจะดำเนินการต่อจอแสดงผล แต่จะดำเนินการตามลำดับสำหรับจอแสดงผลที่ใช้งานอยู่ทั้งหมด แม้ว่าเนื้อหาของจอแสดงผลเพียงจอเดียวจะได้รับการอัปเดตก็ตาม

ตัวอย่างเช่น หากอัปเดตจอแสดงผลภายนอก ลำดับจะเป็น:

// In Android 9 and lower:

// Update state for internal display
// Update state for external display
validateDisplay(<internal display>)
validateDisplay(<external display>)
presentDisplay(<internal display>)
presentDisplay(<external display>)

// In Android 10 and higher:

// Update state for internal display
// Update state for external display
validateInternal(<internal display>)
presentInternal(<internal display>)
validateExternal(<external display>)
presentExternal(<external display>)

องค์ประกอบการแสดงผลเสมือนจริง

องค์ประกอบการแสดงผลเสมือนจะคล้ายกับองค์ประกอบการแสดงผลภายนอก ความแตกต่างระหว่างองค์ประกอบการแสดงผลเสมือนและองค์ประกอบการแสดงผลทางกายภาพก็คือ จอแสดงผลเสมือนจะส่งเอาต์พุตไปยังบัฟเฟอร์ Gralloc แทนที่จะส่งไปยังหน้าจอ Hardware Composer (HWC) เขียนเอาต์พุตลงในบัฟเฟอร์ จัดเตรียมรั้วการทำงานให้เสร็จสิ้น และส่งบัฟเฟอร์ไปยังผู้ใช้บริการ (เช่น ตัวเข้ารหัสวิดีโอ, GPU, CPU และอื่นๆ) จอแสดงผลเสมือนสามารถใช้ 2D/บลิตเตอร์ หรือโอเวอร์เลย์ได้ หากไปป์ไลน์ของจอแสดงผลเขียนลงในหน่วยความจำ

โหมด

แต่ละเฟรมอยู่ในหนึ่งในสามโหมดหลังจากที่ SurfaceFlinger เรียกใช้เมธอด validateDisplay() HWC:

  • GLES — GPU จะรวมทุกเลเยอร์ โดยเขียนโดยตรงไปยังบัฟเฟอร์เอาท์พุต HWC ไม่เกี่ยวข้องกับการแต่งเพลง
  • MIXED — GPU จะรวมบางเลเยอร์เข้ากับ framebuffer และ HWC จะรวม framebuffer และเลเยอร์ที่เหลือ โดยเขียนโดยตรงไปยังบัฟเฟอร์เอาท์พุต
  • HWC — HWC รวมเลเยอร์ทั้งหมดและเขียนโดยตรงไปยังบัฟเฟอร์เอาต์พุต

รูปแบบเอาต์พุต

รูปแบบเอาต์พุตบัฟเฟอร์การแสดงผลเสมือนขึ้นอยู่กับโหมด:

  • โหมด GLES — ไดรเวอร์ EGL จะตั้งค่ารูปแบบบัฟเฟอร์เอาต์พุตเป็น dequeueBuffer() โดยทั่วไปคือ RGBA_8888 ผู้ใช้บริการจะต้องสามารถยอมรับรูปแบบเอาต์พุตที่ไดรเวอร์ตั้งค่าไว้ ไม่เช่นนั้นจะไม่สามารถอ่านบัฟเฟอร์ได้
  • โหมด MIXED และ HWC — หากผู้ใช้บริการต้องการเข้าถึง CPU ผู้ใช้จะตั้งค่ารูปแบบ มิฉะนั้น รูปแบบจะเป็น IMPLEMENTATION_DEFINED และ Gralloc จะตั้งค่ารูปแบบที่ดีที่สุดตามแฟล็กการใช้งาน ตัวอย่างเช่น Gralloc จะตั้งค่ารูปแบบ YCbCr หากผู้บริโภคเป็นตัวเข้ารหัสวิดีโอ และ HWC สามารถเขียนรูปแบบได้อย่างมีประสิทธิภาพ

รั้วการซิงโครไนซ์

รั้วการซิงโครไนซ์ (ซิงค์) เป็นส่วนสำคัญของระบบกราฟิก Android รั้วทำให้ CPU ทำงานได้อย่างอิสระจากการทำงานของ GPU ที่เกิดขึ้นพร้อมกัน โดยจะบล็อกเมื่อมีการพึ่งพาอย่างแท้จริงเท่านั้น

ตัวอย่างเช่น เมื่อแอปส่งบัฟเฟอร์ที่สร้างบน GPU แอปจะส่งออบเจ็กต์รั้วการซิงค์ด้วย กรอบนี้จะส่งสัญญาณเมื่อ GPU เขียนลงในบัฟเฟอร์เสร็จแล้ว

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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับรั้วการซิงค์ โปรดดูที่ Hardware Composer Integration