HAL ของเครื่องมือแต่งภาพฮาร์ดแวร์ (HWC) จะคอมโพสเลเยอร์ที่ได้รับจาก SurfaceFlinger ซึ่งจะลดจำนวนการคอมโพส OpenGL ES (GLES) และการทำงานของ GPU
HWC จะแยกแยะออบเจ็กต์ เช่น การวางซ้อนและโปรแกรมแสดงผลภาพ 2 มิติ เพื่อคอมโพสพื้นผิวและสื่อสารกับฮาร์ดแวร์การจัดองค์ประกอบหน้าต่างเฉพาะเพื่อคอมโพสหน้าต่าง ใช้ 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 แบบ Binderized ระหว่าง HWC กับ SurfaceFlinger HAL ของ Composer จะมาแทนที่อินเทอร์เฟซ 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 ด้วยชื่อรูปแบบ CamelCase ตัวเล็กซึ่งไม่มีอยู่ในอินเทอร์เฟซเป็นช่องที่มีชื่อ เกือบทุกฟังก์ชันจะโหลดโดยขอตัวชี้ฟังก์ชันโดยใช้ getFunction
ที่ได้จาก hwc2_device_t
เช่น ฟังก์ชัน createLayer
เป็นพอยน์เตอร์ฟังก์ชันประเภท HWC2_PFN_CREATE_LAYER
ซึ่งจะแสดงผลเมื่อมีการผ่านค่าที่ระบุ HWC2_FUNCTION_CREATE_LAYER
ไปยัง getFunction
ดูเอกสารประกอบโดยละเอียดเกี่ยวกับฟังก์ชัน HAL ของ Composer และฟังก์ชันการส่งผ่านฟังก์ชัน 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 จะตื่นขึ้น 1 ครั้งต่อ 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 แทนที่จะส่งไปยังหน้าจอ เครื่องมือจัดระเบียบฮาร์ดแวร์ (HWC) จะเขียนเอาต์พุตลงในบัฟเฟอร์ ระบุรั้วการเสร็จสมบูรณ์ และส่งบัฟเฟอร์ไปยังผู้ใช้ (เช่น ตัวแปลงรหัสวิดีโอ, GPU, CPU และอื่นๆ) จอแสดงผลเสมือนสามารถใช้ 2D/Blitter หรือการวางซ้อนได้หากไปป์ไลน์การแสดงผลเขียนไปยังหน่วยความจำ
โหมด
เฟรมแต่ละเฟรมจะอยู่ในโหมดใดโหมดหนึ่งต่อไปนี้หลังจากที่ SurfaceFlinger เรียกใช้validateDisplay()
เมธอด HWC
- GLES — GPU จะคอมโพสเลเยอร์ทั้งหมดโดยเขียนลงในบัฟเฟอร์เอาต์พุตโดยตรง HWC ไม่มีส่วนเกี่ยวข้องกับการประพันธ์
- ผสม — GPU จะคอมโพสเลเยอร์บางเลเยอร์ลงในเฟรมบัฟเฟอร์ และ HWC จะคอมโพสเฟรมบัฟเฟอร์และเลเยอร์ที่เหลือ โดยเขียนลงในบัฟเฟอร์เอาต์พุตโดยตรง
- HWC - HWC จะคอมโพสเลเยอร์ทั้งหมดและเขียนไปยังบัฟเฟอร์เอาต์พุตโดยตรง
รูปแบบเอาต์พุต
รูปแบบเอาต์พุตบัฟเฟอร์การแสดงผลเสมือนจริงจะขึ้นอยู่กับโหมดของบัฟเฟอร์
- โหมด GLES — ไดรเวอร์ EGL จะตั้งค่ารูปแบบบัฟเฟอร์เอาต์พุตใน
dequeueBuffer()
ซึ่งโดยปกติจะเป็นRGBA_8888
ผู้บริโภคต้องยอมรับรูปแบบเอาต์พุตที่ไดรเวอร์กำหนด มิฉะนั้นระบบจะอ่านบัฟเฟอร์ไม่ได้ - โหมด MIXED และ HWC — หากผู้บริโภคต้องการสิทธิ์เข้าถึง CPU ผู้บริโภคจะเป็นผู้ตั้งค่ารูปแบบ มิเช่นนั้น รูปแบบจะเป็น
IMPLEMENTATION_DEFINED
และ Gralloc จะตั้งค่ารูปแบบที่ดีที่สุดตาม Flag การใช้งาน เช่น Gralloc จะตั้งค่ารูปแบบ YCbCr หากผู้บริโภคเป็นโปรแกรมเปลี่ยนไฟล์วิดีโอและ HWC สามารถเขียนรูปแบบได้อย่างมีประสิทธิภาพ
รั้วการซิงค์
รั้วการซิงค์ (การซิงค์) เป็นแง่มุมที่สําคัญของระบบกราฟิก Android รั้วช่วยให้ CPU ทํางานได้อิสระจากงาน GPU ที่ทํางานพร้อมกัน โดยจะบล็อกเฉพาะในกรณีที่มีความเกี่ยวข้องจริงเท่านั้น
เช่น เมื่อแอปส่งบัฟเฟอร์ที่สร้างขึ้นบน GPU ก็จะส่งออบเจ็กต์ Sync Fence ด้วย เฟนซ์นี้จะส่งสัญญาณเมื่อ GPU เขียนข้อมูลลงในบัฟเฟอร์เสร็จแล้ว
HWC กำหนดให้ GPU เขียนบัฟเฟอร์จนเสร็จก่อนจึงจะแสดงบัฟเฟอร์ได้ ระบบจะส่งรั้วการซิงค์ผ่านไปป์ไลน์กราฟิกพร้อมกับบัฟเฟอร์และสัญญาณเมื่อมีการเขียนบัฟเฟอร์ ก่อนที่จะแสดงบัฟเฟอร์ HWC จะตรวจสอบว่ารั้วการซิงค์ส่งสัญญาณหรือไม่ หากส่งสัญญาณ ก็จะแสดงบัฟเฟอร์
ดูข้อมูลเพิ่มเติมเกี่ยวกับรั้วการซิงค์ได้ที่การผสานรวม Hardware Composer