HAL Trình kết hợp phần cứng (HWC) kết hợp các lớp nhận được từ SurfaceFlinger, giảm lượng kết hợp OpenGL ES (GLES) và GPU thực hiện.
HWC trừu tượng hoá các đối tượng, chẳng hạn như lớp phủ và blitter 2D, để kết hợp các bề mặt và giao tiếp với phần cứng kết hợp cửa sổ chuyên dụng để kết hợp các cửa sổ. Hãy sử dụng HWC để kết hợp các cửa sổ thay vì để SurfaceFlinger kết hợp với GPU. Hầu hết GPU không được tối ưu hoá để kết hợp và khi GPU kết hợp các lớp từ SurfaceFlinger, các ứng dụng không thể sử dụng GPU cho quá trình kết xuất của riêng mình.
Các cách triển khai HWC phải hỗ trợ:
- Ít nhất 4 lớp phủ:
- Thanh trạng thái
- Thanh hệ thống
- Ứng dụng
- Hình nền
- Các lớp lớn hơn màn hình (ví dụ: hình nền)
- Kết hợp alpha theo từng pixel được nhân trước và kết hợp alpha theo từng mặt phẳng alpha đồng thời
- Đường dẫn phần cứng để phát video được bảo vệ
- Thứ tự đóng gói RGBA, định dạng YUV và các thuộc tính xếp ô, hoán đổi và bước
Cách triển khai HWC:
- Triển khai HWC không hoạt động và gửi tất cả công việc kết hợp đến GLES.
- Triển khai thuật toán để uỷ quyền kết hợp cho HWC theo cách tăng dần. Ví dụ: chỉ uỷ quyền 3 hoặc 4 bề mặt đầu tiên cho phần cứng lớp phủ của HWC.
- Tối ưu hoá HWC. Việc này có thể bao gồm:
- Chọn các bề mặt giúp tối đa hoá tải trọng được lấy ra khỏi GPU và gửi các bề mặt đó đến HWC.
- Phát hiện xem màn hình có đang cập nhật hay không. Nếu không, hãy uỷ quyền kết hợp cho GLES thay vì HWC để tiết kiệm pin. Khi màn hình cập nhật lại, hãy tiếp tục chuyển tải kết hợp sang HWC.
- Chuẩn bị cho các trường hợp sử dụng phổ biến, chẳng hạn như:
- Màn hình chính, bao gồm thanh trạng thái, thanh hệ thống, cửa sổ ứng dụng và hình nền động
- Trò chơi toàn màn hình ở chế độ dọc và ngang
- Video toàn màn hình có phụ đề và chế độ điều khiển phát
- Phát video được bảo vệ
- Cửa sổ chia đôi màn hình
Nguyên hàm HWC
HWC cung cấp 2 nguyên hàm, lớp và màn hình, để biểu thị công việc kết hợp và tương tác với phần cứng màn hình. HWC cũng cung cấp quyền kiểm soát VSync và lệnh gọi lại cho SurfaceFlinger để thông báo cho SurfaceFlinger khi sự kiện VSync xảy ra.
Giao diện HIDL
Android 8.0 trở lên sử dụng giao diện
HIDL có tên là Composer HAL cho
IPC được liên kết giữa HWC và SurfaceFlinger. Composer HAL thay thế giao diện hwcomposer2.h cũ. Nếu nhà cung cấp cung cấp cách triển khai Composer HAL của HWC, thì Composer HAL sẽ trực tiếp chấp nhận các lệnh gọi HIDL từ SurfaceFlinger. Nếu nhà cung cấp cung cấp cách triển khai cũ của HWC, thì Composer HAL sẽ tải con trỏ hàm từ hwcomposer2.h, chuyển tiếp các lệnh gọi HIDL thành lệnh gọi con trỏ hàm.
HWC cung cấp các hàm để xác định thuộc tính của một màn hình nhất định; để chuyển đổi giữa các cấu hình màn hình khác nhau (chẳng hạn như độ phân giải 4k hoặc 1080p) và chế độ màu (chẳng hạn như màu gốc hoặc sRGB thực); và để bật, tắt hoặc chuyển màn hình sang chế độ tiết kiệm pin nếu được hỗ trợ.
Con trỏ hàm
Nếu nhà cung cấp triển khai trực tiếp Composer HAL, thì SurfaceFlinger sẽ gọi các hàm của nó thông qua HIDL IPC. Ví dụ: để tạo một lớp, SurfaceFlinger sẽ gọi createLayer() trên Composer HAL.
Nếu nhà cung cấp triển khai giao diện hwcomposer2.h, thì Composer HAL sẽ gọi con trỏ hàm hwcomposer2.h. Trong nhận xét hwcomposer2.h, các hàm giao diện HWC được tham chiếu theo tên lowerCamelCase không tồn tại trong giao diện dưới dạng các trường được đặt tên. Hầu như mọi hàm đều được tải bằng cách yêu cầu con trỏ hàm bằng getFunction do hwc2_device_t cung cấp. Ví dụ: hàm createLayer là con trỏ hàm thuộc loại HWC2_PFN_CREATE_LAYER, được trả về khi giá trị được liệt kê HWC2_FUNCTION_CREATE_LAYER được truyền vào getFunction.
Để biết tài liệu chi tiết về các hàm Composer HAL và các hàm chuyển tiếp hàm HWC
hàm, hãy xem composer. Để biết tài liệu chi tiết về
con trỏ hàm HWC, hãy xem
hwcomposer2.h.
Xử lý lớp và màn hình
Các lớp và màn hình được thao tác bằng các trình xử lý do HWC tạo. Các trình xử lý này không rõ ràng đối với SurfaceFlinger.
Khi SurfaceFlinger tạo một lớp mới, lớp này sẽ gọi createLayer,
trả về loại Layer cho các cách triển khai trực tiếp
hoặc hwc2_layer_t cho các cách triển khai chuyển tiếp. Khi SurfaceFlinger sửa đổi một thuộc tính của lớp đó, SurfaceFlinger sẽ truyền giá trị hwc2_layer_t vào hàm sửa đổi thích hợp cùng với mọi thông tin khác cần thiết để thực hiện sửa đổi. Loại hwc2_layer_t đủ lớn để chứa con trỏ hoặc chỉ mục.
Màn hình vật lý được tạo bằng cách cắm nóng. Khi màn hình vật lý được cắm nóng, HWC sẽ tạo một trình xử lý và truyền trình xử lý đó đến SurfaceFlinger thông qua lệnh gọi lại cắm nóng. Màn hình ảo được tạo bằng cách SurfaceFlinger gọi createVirtualDisplay() để yêu cầu màn hình. Nếu HWC hỗ trợ kết hợp màn hình ảo, thì HWC sẽ trả về một trình xử lý. Sau đó, SurfaceFlinger sẽ uỷ quyền kết hợp màn hình cho HWC. Nếu HWC không hỗ trợ kết hợp màn hình ảo, thì SurfaceFlinger sẽ tạo trình xử lý và kết hợp màn hình.
Thao tác kết hợp màn hình
Mỗi lần VSync, SurfaceFlinger sẽ thức nếu có nội dung mới để kết hợp. Nội dung mới này có thể là vùng đệm hình ảnh mới từ các ứng dụng hoặc thay đổi trong thuộc tính của một hoặc nhiều lớp. Khi SurfaceFlinger thức, nó sẽ:
- Xử lý các giao dịch (nếu có).
- Kết nối các vùng đệm đồ hoạ mới (nếu có).
- Thực hiện kết hợp mới nếu bước 1 hoặc 2 dẫn đến thay đổi nội dung màn hình.
Để thực hiện kết hợp mới, SurfaceFlinger sẽ tạo và huỷ các lớp hoặc sửa đổi trạng thái lớp (nếu có). Lớp này cũng cập nhật các lớp bằng nội dung hiện tại của chúng, sử dụng các lệnh gọi như setLayerBuffer hoặc setLayerColor. Sau khi tất cả các lớp được cập nhật, SurfaceFlinger sẽ gọi validateDisplay, yêu cầu HWC kiểm tra trạng thái của các lớp và xác định cách kết hợp sẽ diễn ra. Theo mặc định, SurfaceFlinger cố gắng định cấu hình mọi lớp sao cho lớp đó được HWC kết hợp; mặc dù trong một số trường hợp, SurfaceFlinger sẽ kết hợp các lớp thông qua dự phòng GPU.
Sau khi gọi validateDisplay, SurfaceFlinger sẽ gọi getChangedCompositionTypes để xem HWC có muốn thay đổi bất kỳ loại kết hợp lớp nào trước khi thực hiện kết hợp hay không. Để chấp nhận các thay đổi, SurfaceFlinger sẽ gọi acceptDisplayChanges.
Nếu bất kỳ lớp nào được đánh dấu để kết hợp SurfaceFlinger, thì SurfaceFlinger sẽ kết hợp các lớp đó vào vùng đệm mục tiêu. Sau đó, SurfaceFlinger sẽ gọi setClientTarget để cung cấp vùng đệm cho màn hình để vùng đệm có thể được hiển thị trên màn hình hoặc kết hợp thêm với các lớp chưa được đánh dấu để kết hợp SurfaceFlinger. Nếu không có lớp nào được đánh dấu để kết hợp SurfaceFlinger, thì SurfaceFlinger sẽ bỏ qua bước kết hợp.
Cuối cùng, SurfaceFlinger sẽ gọi presentDisplay để yêu cầu HWC hoàn tất quá trình kết hợp và hiển thị kết quả cuối cùng.
Nhiều màn hình
Android 10 hỗ trợ nhiều màn hình vật lý. Khi thiết kế cách triển khai HWC để sử dụng trên Android 7.0 trở lên, có một số hạn chế không có trong định nghĩa HWC:
- Giả sử có chính xác một màn hình nội bộ. Màn hình nội bộ là màn hình mà báo cáo cắm nóng ban đầu trong quá trình khởi động. Sau khi màn hình nội bộ được cắm nóng, bạn không thể ngắt kết nối.
- Ngoài màn hình nội bộ, bạn có thể cắm nóng bất kỳ số lượng màn hình ngoài nào trong quá trình hoạt động bình thường của thiết bị. Khung giả định rằng tất cả các lần cắm nóng sau màn hình nội bộ đầu tiên đều là màn hình ngoài, vì vậy, nếu bạn thêm bất kỳ màn hình nội bộ nào khác, thì các màn hình đó sẽ được phân loại không chính xác là
Display.TYPE_HDMIthay vìDisplay.TYPE_BUILT_IN.
Mặc dù các thao tác SurfaceFlinger được mô tả ở trên được thực hiện trên mỗi màn hình, nhưng các thao tác này được thực hiện tuần tự cho tất cả các màn hình đang hoạt động, ngay cả khi nội dung của chỉ một màn hình được cập nhật.
Ví dụ: nếu màn hình ngoài được cập nhật, thì trình tự sẽ là:
// 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>)
Kết hợp màn hình ảo
Kết hợp màn hình ảo tương tự như kết hợp màn hình ngoài. Sự khác biệt giữa kết hợp màn hình ảo và kết hợp màn hình vật lý là màn hình ảo gửi đầu ra đến vùng đệm Gralloc thay vì đến màn hình. Trình kết hợp phần cứng (HWC) ghi đầu ra vào vùng đệm, cung cấp hàng rào hoàn tất và gửi vùng đệm đến người tiêu dùng (chẳng hạn như bộ mã hoá video, GPU, CPU, v.v.). Màn hình ảo có thể sử dụng lớp phủ hoặc blitter/2D nếu quy trình màn hình ghi vào bộ nhớ.
Chế độ
Mỗi khung hình ở một trong 3 chế độ sau khi SurfaceFlinger gọi phương thức HWC validateDisplay():
- GLES – GPU kết hợp tất cả các lớp, ghi trực tiếp vào vùng đệm đầu ra. HWC không tham gia vào quá trình kết hợp.
- MIXED – GPU kết hợp một số lớp vào bộ đệm khung và HWC kết hợp bộ đệm khung và các lớp còn lại, ghi trực tiếp vào vùng đệm đầu ra.
- HWC – HWC kết hợp tất cả các lớp và ghi trực tiếp vào vùng đệm đầu ra.
Định dạng đầu ra
Định dạng đầu ra của vùng đệm màn hình ảo phụ thuộc vào chế độ của chúng:
- Chế độ GLES – Trình điều khiển EGL đặt định dạng vùng đệm đầu ra
trong
dequeueBuffer(), thường làRGBA_8888. Người tiêu dùng phải có thể chấp nhận định dạng đầu ra mà trình điều khiển đặt hoặc không thể đọc vùng đệm. - Chế độ MIXED và HWC – Nếu người tiêu dùng cần quyền truy cập CPU, thì người tiêu dùng sẽ đặt định dạng. Nếu không, định dạng sẽ là
IMPLEMENTATION_DEFINEDvà Gralloc sẽ đặt định dạng tốt nhất dựa trên cờ sử dụng. Ví dụ: Gralloc đặt định dạng YCbCr nếu người tiêu dùng là bộ mã hoá video và HWC có thể ghi định dạng một cách hiệu quả.
Hàng rào đồng bộ hoá
Hàng rào đồng bộ hoá (đồng bộ) là một khía cạnh quan trọng của hệ thống đồ hoạ Android. Hàng rào cho phép công việc của CPU tiến hành độc lập với công việc đồng thời của GPU, chỉ chặn khi có sự phụ thuộc thực sự.
Ví dụ: khi một ứng dụng gửi vùng đệm đang được tạo trên GPU, ứng dụng đó cũng sẽ gửi đối tượng hàng rào đồng bộ. Hàng rào này báo hiệu khi GPU đã ghi xong vào vùng đệm.
HWC yêu cầu GPU hoàn tất việc ghi vùng đệm trước khi các vùng đệm được hiển thị. Hàng rào đồng bộ được truyền qua quy trình đồ hoạ với các vùng đệm và báo hiệu khi các vùng đệm được ghi. Trước khi vùng đệm được hiển thị, HWC sẽ kiểm tra xem hàng rào đồng bộ đã báo hiệu hay chưa và nếu có, thì HWC sẽ hiển thị vùng đệm.
Để biết thêm thông tin về hàng rào đồng bộ, hãy xem bài viết Tích hợp trình kết hợp phần cứng.