Hardware Composer (HWC) HAL จะรวมเลเยอร์ที่ได้รับจาก SurfaceFlinger ซึ่งช่วยลดปริมาณการรวม OpenGL ES (GLES) และการทำงานของ GPU
HWC จะสรุปออบเจ็กต์ เช่น โอเวอร์เลย์และ 2D Blitter เพื่อรวมพื้นผิว และสื่อสารกับฮาร์ดแวร์การรวมหน้าต่างเฉพาะเพื่อรวมหน้าต่าง ใช้ HWC เพื่อรวมหน้าต่างแทนการให้ SurfaceFlinger รวมกับ GPU GPU ส่วนใหญ่ไม่ได้ปรับให้เหมาะกับการรวม และเมื่อ GPU รวมเลเยอร์จาก SurfaceFlinger แอปจะใช้ GPU สำหรับการแสดงผลของตัวเองไม่ได้
การติดตั้งใช้งาน HWC ต้องรองรับสิ่งต่อไปนี้
- โอเวอร์เลย์อย่างน้อย 4 รายการ
- แถบสถานะ
- แถบระบบ
- แอป
- วอลเปเปอร์/พื้นหลัง
- เลเยอร์ที่มีขนาดใหญ่กว่าจอแสดงผล (เช่น วอลเปเปอร์)
- การผสมอัลฟ่าต่อพิกเซลแบบคูณล่วงหน้าและการผสมอัลฟ่าต่อระนาบ พร้อมกัน
- เส้นทางฮาร์ดแวร์สำหรับการเล่นวิดีโอที่มีการคุ้มครอง
- ลำดับการแพ็ก RGBA, รูปแบบ YUV รวมถึงพร็อพเพอร์ตี้การจัดเรียงเป็นไทล์ การสลับ และระยะห่าง พร็อพเพอร์ตี้
วิธีติดตั้งใช้งาน HWC
- ติดตั้งใช้งาน HWC ที่ไม่ทำงานและส่งงานการรวมทั้งหมดไปยัง GLES
- ติดตั้งใช้งานอัลกอริทึมเพื่อมอบหมายการรวมไปยัง HWC แบบค่อยเป็นค่อยไป เช่น มอบหมายเฉพาะพื้นผิว 3 หรือ 4 รายการแรกไปยังฮาร์ดแวร์โอเวอร์เลย์ ของ HWC
- เพิ่มประสิทธิภาพ HWC ซึ่งอาจรวมถึงสิ่งต่อไปนี้
- เลือกพื้นผิวที่ช่วยลดภาระงานของ GPU ได้มากที่สุดและ ส่งไปยัง HWC
- ตรวจหาว่าหน้าจอมีการอัปเดตหรือไม่ หากไม่มี ให้มอบหมาย การรวมไปยัง GLES แทน HWC เพื่อประหยัดพลังงาน เมื่อหน้าจอ อัปเดตอีกครั้ง ให้ดำเนินการมอบหมายการรวมไปยัง HWC ต่อไป
- เตรียมพร้อมสำหรับกรณีการใช้งานทั่วไป เช่น
- หน้าจอหลัก ซึ่งรวมถึงแถบสถานะ แถบระบบ หน้าต่างแอป และวอลเปเปอร์เคลื่อนไหว
- เกมแบบเต็มหน้าจอในโหมดแนวตั้งและแนวนอน
- วิดีโอแบบเต็มหน้าจอพร้อมคำบรรยายและตัวควบคุมการเล่น
- การเล่นวิดีโอที่มีการคุ้มครอง
- มัลติวินโดว์แบบแยกหน้าจอ
องค์ประกอบพื้นฐานของ HWC
HWC มีองค์ประกอบพื้นฐาน 2 อย่าง ได้แก่ เลเยอร์ และ จอแสดงผล เพื่อ แสดงงานการรวมและการโต้ตอบกับฮาร์ดแวร์จอแสดงผล นอกจากนี้ HWC ยังมีการควบคุม VSync และฟังก์ชันเรียกกลับไปยัง SurfaceFlinger เพื่อแจ้งให้ทราบเมื่อเกิดเหตุการณ์ VSync
อินเทอร์เฟซ HIDL
Android 8.0 ขึ้นไปใช้อินเทอร์เฟซ
HIDL ที่เรียกว่า Composer HAL สำหรับ
IPC แบบ Binder ระหว่าง 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 และฟังก์ชันการส่งผ่านฟังก์ชัน 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 จะสร้างแฮนเดิลและรวมจอแสดงผล
การดำเนินการรวมจอแสดงผล
SurfaceFlinger จะตื่นขึ้นทุกครั้งต่อ VSync หากมีเนื้อหาใหม่ที่จะรวม เนื้อหาใหม่นี้อาจเป็นบัฟเฟอร์รูปภาพใหม่จากแอปหรือการเปลี่ยนแปลงพร็อพเพอร์ตี้ของเลเยอร์อย่างน้อย 1 รายการ เมื่อ SurfaceFlinger ตื่นขึ้น ระบบจะดำเนินการต่อไปนี้
- จัดการธุรกรรม (หากมี)
- ล็อกบัฟเฟอร์กราฟิกใหม่ (หากมี)
- ทำการรวมใหม่ หากขั้นตอนที่ 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 ดังนี้
- ระบบจะถือว่ามีจอแสดงผล ภายใน 1 จอเท่านั้น จอแสดงผลภายในคือจอแสดงผลที่การเสียบและถอดออกขณะทำงานครั้งแรกรายงานระหว่างการบูต หลังจากเสียบจอแสดงผลภายในและถอดออกขณะทำงานแล้ว จะไม่สามารถยกเลิกการเชื่อมต่อได้
- นอกเหนือจากจอแสดงผลภายในแล้ว ยังสามารถเสียบจอแสดงผลภายนอกและถอดออกขณะทำงานได้ทุกจำนวนระหว่างการทำงานปกติของอุปกรณ์ เฟรมเวิร์กจะถือว่าการเสียบและถอดออกขณะทำงานทั้งหมดหลังจากจอแสดงผลภายในจอแรกเป็นจอแสดงผลภายนอก ดังนั้นหากมีการเพิ่มจอแสดงผลภายในอีก ระบบจะจัดหมวดหมู่จอแสดงผลเหล่านั้นเป็น
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/Blitter หรือโอเวอร์เลย์ได้หากไปป์ไลน์จอแสดงผลเขียนลงในหน่วยความจำ
โหมด
แต่ละเฟรมจะอยู่ใน 1 ใน 3 โหมดต่อไปนี้หลังจาก SurfaceFlinger เรียกเมธอด validateDisplay() HWC
- GLES \- GPU จะรวมเลเยอร์ทั้งหมดและเขียน ลงในบัฟเฟอร์เอาต์พุตโดยตรง HWC จะไม่เกี่ยวข้องกับการรวม
- MIXED \- GPU จะรวมเลเยอร์บางส่วนลงใน บัฟเฟอร์เฟรม และ HWC จะรวมบัฟเฟอร์เฟรมและเลเยอร์ที่เหลือ โดยเขียนลงในบัฟเฟอร์เอาต์พุตโดยตรง
- 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