Các lớp tổng hợp HAL của Trình tổng hợp phần cứng (HWC) nhận được từ SurfaceFlinger, giúp giảm lượng thành phần 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à vùng phủ 2D, thành các bề mặt kết hợp và giao tiếp với phần cứng kết hợp cửa sổ chuyên dụng để tổng hợp các cửa sổ. Sử dụng HWC để kết hợp các cửa sổ thay vì kết hợp SurfaceFlinger với GPU. Hầu hết GPU không được tối ưu hoá cho quá trình 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 để kết xuất riêng.
Các phương thức 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/nền
- Các lớp lớn hơn màn hình (ví dụ: hình nền)
- Phối alpha được nhân trước đồng thời trên mỗi pixel và trên mỗi mặt phẳng
- Đườ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 kề, xáo trộn và bước
Cách triển khai HWC:
- Triển khai HWC không hoạt động và gửi tất cả tác vụ kết hợp đến GLES.
- Triển khai một thuật toán để uỷ quyền thành phần kết hợp cho HWC theo cách tăng dần. Ví dụ: chỉ uỷ quyền 3 hoặc 4 nền tảng đầu tiên cho phần cứng lớp phủ của HWC.
- Tối ưu hoá HWC. Điều này có thể bao gồm:
- Chọn các nền tảng giúp tối đa hoá tải được lấy ra khỏi GPU và gửi các nền tảng đó đế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 cho thành phần hiển thị với 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 thành phần kết hợp sang HWC.
- Chuẩn bị cho các trường hợp sử dụng phổ biế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 chạy ở chế độ toàn màn hình theo hướng dọc và ngang
- Video ở chế độ toàn màn hình có phụ đề và chế độ điều khiển phát
- Phát lại video được bảo vệ
- Nhiều cửa sổ chia đôi màn hình
Nguyên hàm HWC
HWC cung cấp hai lớp gốc là lớp và màn hình để biểu thị công việc kết hợp và hoạt động tương tác của công việc đó với phần cứng hiển thị. BCH cũng cung cấp quyền kiểm soát đối với VSYNC và lệnh gọi lại đến SurfaceFlinger để thông báo cho SurfaceFlinger khi xảy ra sự kiện VSYNC.
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 liên kết giữa HWC và SurfaceFlinger. HAL (Lớp trừu tượng phần cứng) cho Composer thay thế giao diện hwcomposer2.h
cũ. Nếu nhà cung cấp cung cấp phương thức triển khai HAL cho Trình soạn thảo của HWC, thì HAL của Trình soạn thảo sẽ trực tiếp chấp nhận các lệnh gọi HIDL qua SurfaceFlinger. Nếu nhà cung cấp cung cấp phương thức triển khai cũ của HWC, Composer HAL sẽ tải con trỏ hàm từ hwcomposer2.h
, chuyển tiếp các lệnh gọi HIDL vào 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 HAL của Trình soạn thảo, SurfaceFlinger sẽ gọi các hàm thông qua HIDL IPC. Ví dụ: để tạo một lớp, SurfaceFlinger gọi createLayer()
trên Composer HAL.
Nếu nhà cung cấp triển khai giao diện hwcomposer2.h
, HAL của trình soạn thảo sẽ gọi vào con trỏ hàm hwcomposer2.h
. Trong các nhận xét hwcomposer2.h
, các hàm giao diện HWC được tham chiếu bằng 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 hết 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à một con trỏ hàm thuộc loại HWC2_PFN_CREATE_LAYER
. Hàm này đượ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 HAL của trình soạn thảo và hàm truyền qua hàm HWC, 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à hiển thị
Các lớp và màn hình được thao tác bằng các tay điều khiển do HWC tạo. Các tay cầm này không rõ ràng đối với SurfaceFlinger.
Khi tạo một lớp mới, SurfaceFlinger sẽ gọi createLayer
. Lớp này sẽ trả về loại Layer
để triển khai trực tiếp hoặc hwc2_layer_t
để 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 thực tế được tạo ra bằng cách được cắm nóng. Khi màn hình thực được cắm nóng, HWC sẽ tạo một tay điều khiển và truyền tay điều khiển đó đến SurfaceFlinger thông qua lệnh gọi lại hotplug. Màn hình ảo được tạo bằng cách SurfaceFlinger gọi createVirtualDisplay()
để yêu cầu hiển thị. Nếu HWC hỗ trợ thành phần hiển thị ảo, thì thành phần này sẽ trả về một handle. Sau đó, SurfaceFlinger sẽ uỷ quyền thành phần hiển thị cho HWC. Nếu HWC không hỗ trợ thành phần hiển thị ảo, SurfaceFlinger sẽ tạo tay điều khiển và kết hợp màn hình.
Hiển thị hoạt động kết hợp
Một lần trên mỗi VSYNC, SurfaceFlinger sẽ thức dậy nếu có nội dung mới để tổng 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 một thay đổi trong thuộc tính của một hoặc nhiều lớp. Khi SurfaceFlinger đánh thức:
- Xử lý các giao dịch (nếu có).
- Khoá các bộ đệm đồ hoạ mới nếu có.
- Thực hiện một thành phần kết hợp mới, nếu bước 1 hoặc 2 dẫn đến thay đổi nội dung hiển thị.
Để thực hiện một thành phầ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ó). Ứng dụng này cũng cập nhật nội dung hiện tại của các lớp bằ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
. Lệnh này sẽ yêu cầu HWC kiểm tra trạng thái của các lớp và xác định cách tiến hành kết hợp. Theo mặc định, SurfaceFlinger cố gắng định cấu hình mọi lớp sao cho lớp được kết hợp bởi HWC; mặc dù trong một số trường hợp, SurfaceFlinger kết hợp các lớp thông qua phương thức dự phòng GPU.
Sau khi thực hiện lệnh gọi đến validateDisplay
, SurfaceFlinger sẽ gọi getChangedCompositionTypes
để xem HWC có muốn thay đổi bất kỳ kiểu thành phần lớp nào trước khi thực hiện quá trình kết hợp hay không. Để chấp nhận các thay đổi, SurfaceFlinger gọi
acceptDisplayChanges
.
Nếu có lớp nào được đánh dấu cho thành phần SurfaceFlinger, thì SurfaceFlinger sẽ kết hợp các lớp đó vào vùng đệm mục tiêu. Sau đó, SurfaceFlinger gọi setClientTarget
để cung cấp vùng đệm cho màn hình để vùng đệm có thể 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 cho thành phần SurfaceFlinger. Nếu không có lớp nào được đánh dấu cho thành phần SurfaceFlinger, thì SurfaceFlinger sẽ bỏ qua bước kết hợp.
Cuối cùng, SurfaceFlinger 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 thực. 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ả định rằng có đúng một màn hình nội bộ. Màn hình nội bộ là màn hình mà tính năng hotplug ban đầu báo cáo trong quá trình khởi động. Sau khi màn hình trong được cắm nóng, bạn không thể ngắt kết nối màn hình này.
- Ngoài màn hình trong, 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 này giả định rằng tất cả các màn hình cắm nóng sau màn hình trong cùng là màn hình ngoài. Vì vậy, nếu thêm bất kỳ màn hình trong 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_HDMI
thay vìDisplay.TYPE_BUILT_IN
.
Mặc dù các thao tác SurfaceFlinger được mô tả ở trên được thực hiện cho 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ả 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, 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>)
Cấu trúc màn hình ảo
Cấu trúc màn hình ảo tương tự như cấu trúc màn hình bên ngoài. Sự khác biệt giữa thành phần hiển thị ảo và thành phần hiển thị thực là màn hình ảo gửi đầu ra đến vùng đệm Gralloc thay vì màn hình. Trình soạn phần cứng (HWC) ghi đầu ra vào một vùng đệm, cung cấp hàng rào hoàn thành 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 2D/bộ quét hoặc lớp phủ nếu quy trình hiển thị ghi vào bộ nhớ.
Chế độ
Mỗi khung hình sẽ ở một trong ba chế độ sau khi SurfaceFlinger gọi phương thức validateDisplay()
HWC:
- GLES – GPU tổng hợp tất cả các lớp, ghi trực tiếp vào vùng đệm đầu ra. HWC không liên quan đến thành phần hiển thị.
- MIXED (KẾT HỢP) – GPU kết hợp một số lớp vào vùng đệm khung hình và HWC kết hợp vùng đệm khung hình với 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 hiển thị ảo phụ thuộc vào chế độ của vùng đệm:
- 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 dùng phải 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 dùng cần quyền truy cập vào CPU, thì người tiêu dùng sẽ đặt định dạng. Nếu không, định dạng sẽ là
IMPLEMENTATION_DEFINED
và 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 dùng là trình 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á (sync) là một khía cạnh quan trọng của hệ thống đồ hoạ Android. Hàng rào cho phép CPU hoạt động độc lập với công việc đồng thời của GPU, chỉ chặn khi có phần phụ thuộc thực sự.
Ví dụ: khi một ứng dụng gửi một vùng đệm đang được tạo trên GPU, ứng dụng đó cũng gửi một đối tượng hàng rào đồng bộ hoá. Hàng rào này báo hiệu thời điểm GPU hoàn tất quá trình ghi vào vùng đệm.
HWC yêu cầu GPU hoàn tất việc ghi vùng đệm trước khi vùng đệm được hiển thị. Hàng rào đồng bộ hoá được truyền qua quy trình đồ hoạ bằng các vùng đệm và tín hiệu khi ghi vùng đệm. Trước khi hiển thị vùng đệm, HWC sẽ kiểm tra xem hàng rào đồng bộ hoá có báo hiệu hay không. Nếu có, vùng đệm sẽ hiển thị.
Để biết thêm thông tin về hàng rào đồng bộ hoá, hãy xem bài viết Tích hợp Trình soạn thảo phần cứng.