Triển khai HAL của Trình soạn nhạc phần cứng

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 tóm tắt 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 chuyên dụng cho thành phần cửa sổ để kết 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 việc 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.

Việ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:

  1. Triển khai một HWC không hoạt động và gửi tất cả công việc kết hợp đến GLES.
  2. Triển khai thuật toán để uỷ quyền thành phần kết hợp cho HWC theo từng bước. 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.
  3. Tối ưu hoá HWC. Những nội dung 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 video được bảo vệ
      • Chế độ nhiều cửa sổ chia đôi màn hình

Nguyên hàm HWC

HWC cung cấp hai thành phần gốc là lớpmà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 của Compose thay thế giao diện hwcomposer2.h cũ. Nếu nhà cung cấp cung cấp một phương thức 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 phương thức 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 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); cũng như để 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, SurfaceFlinger sẽ gọi các hàm của Composer HAL 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, thì Composer HAL 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à 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 HAL của Composer và các hàm truyền hàm qua 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.

Tay cầm lớp và màn hình

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 được tạo bằng cách 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 của màn hình 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ị các thao tác kết hợp

Một lần cho mỗi VSYNC, SurfaceFlinger sẽ thức dậy 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 một thay đổi trong thuộc tính của một hoặc nhiều lớp. Khi SurfaceFlinger đánh thức:

  1. Xử lý các giao dịch (nếu có).
  2. Khoá các bộ đệm đồ hoạ mới nếu có.
  3. 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ó). Phương thức này cũng cập nhật các lớp bằng nội dung hiện tại của các lớp đó, 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. 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 lệnh gọi đến validateDisplay, SurfaceFlinger sẽ gọi getChangedCompositionTypes để xem liệu HWC có muốn thay đổi bất kỳ loại thành phần lớp nào trước khi thực hiện thành phần 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ả sử 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 đầu tiên đều 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 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ả 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 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 tổng 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 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/blitter 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 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 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 cần quyền truy cập vào CPU, thì đối tượng sử 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à 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á (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 GPU đồng thời, chỉ chặn khi có phần 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 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 vùng đệm và tín hiệu khi vùng đệm được ghi. 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 phần Tích hợp trình tổng hợp phần cứng.