Warstwa HAL kompozytora sprzętowego (HWC) łączy warstwy otrzymane z SurfaceFlingera, co zmniejsza ilość kompozycji OpenGL ES (GLES) i obciążenie procesora graficznego.
HWC abstrahuje obiekty, takie jak nakładki i blittery 2D, do powierzchni kompozytowych i komunikuje się ze specjalistycznym sprzętem do tworzenia kompozycji okien, aby tworzyć kompozycje okien. Użyj HWC do komponowania okien zamiast SurfaceFlinger, który komponuje za pomocą GPU. Większość procesorów graficznych nie jest zoptymalizowana pod kątem kompozycji, a gdy procesor graficzny tworzy warstwy z SurfaceFlingera, aplikacje nie mogą go używać do własnego renderowania.
Implementacje HWC powinny obsługiwać:
- Co najmniej 4 nakładki:
- Pasek stanu
- Pasek systemowy
- Aplikacja
- Tapeta/tło
- warstwy większe niż wyświetlacz (np. tapeta);
- Jednoczesne mieszanie alfa z wstępnym mnożeniem na poziomie piksela i mieszanie alfa na poziomie płaszczyzny
- Ścieżka sprzętowa do odtwarzania chronionych filmów
- Kolejność pakowania RGBA, formaty YUV oraz właściwości kafelkowania, mieszania i kroku
Aby wdrożyć HWC:
- Wdrażanie niedziałającego HWC i przesyłanie wszystkich zadań związanych z kompozycją do GLES.
- Wdróż algorytm, który będzie stopniowo przekazywać kompozycję do HWC. Możesz na przykład przekazać do sprzętu nakładki HWC tylko pierwsze 3–4 powierzchnie.
- Zoptymalizuj HWC. Może to obejmować:
- Wybieranie powierzchni, które maksymalizują obciążenie procesora graficznego, i przesyłanie ich do HWC.
- wykrywanie, czy ekran jest aktualizowany; Jeśli nie, deleguj kompozycję do GLES zamiast do HWC, aby oszczędzać energię. Gdy ekran ponownie się zaktualizuje, kontynuuj przenoszenie kompozycji do HWC.
- Przygotowanie na typowe przypadki użycia, takie jak:
- ekran główny, który obejmuje pasek stanu, pasek systemowy, okno aplikacji i animowane tapety;
- Gry na pełnym ekranie w trybie pionowym i poziomym
- Film na pełnym ekranie z napisami i sterowaniem odtwarzaniem
- Odtwarzanie chronionych filmów
- Wielookienkowość na podzielonym ekranie
Elementy podstawowe HWC
HWC udostępnia 2 podstawowe elementy: warstwy i wyświetlacze, które reprezentują kompozycję i jej interakcję ze sprzętem wyświetlacza. HWC zapewnia też kontrolę nad VSync i wywołuje zwrotne SurfaceFlinger, aby powiadomić go o wystąpieniu zdarzenia VSync.
Interfejs HIDL
Android 8.0 i nowsze wersje korzystają z interfejsu HIDL o nazwie Composer HAL na potrzeby IPC opartego na binderze między HWC a SurfaceFlinger. Warstwa HAL Composer zastępuje starszy interfejs hwcomposer2.h
. Jeśli dostawcy udostępniają implementację HWC w postaci HAL kompozytora, HAL kompozytora bezpośrednio akceptuje wywołania HIDL z SurfaceFlingera. Jeśli dostawcy udostępniają starszą implementację HWC, Composer HAL wczytuje wskaźniki funkcji z hwcomposer2.h
i przekazuje wywołania HIDL do wywołań wskaźników funkcji.
HWC udostępnia funkcje do określania właściwości danego wyświetlacza, przełączania się między różnymi konfiguracjami wyświetlania (np. rozdzielczością 4K lub 1080p) i trybami kolorów (np. natywnym lub sRGB) oraz włączania, wyłączania i przełączania wyświetlacza w tryb niskiego zużycia energii (jeśli jest obsługiwany).
Wskaźniki funkcji
Jeśli dostawcy zaimplementują Composer HAL bezpośrednio, SurfaceFlinger wywoła jego funkcje za pomocą HIDL IPC. Na przykład, aby utworzyć warstwę, SurfaceFlinger wywołuje
createLayer()
w Composer HAL.
Jeśli dostawcy zaimplementują interfejs hwcomposer2.h
, warstwa HAL kompozytora wywołuje wskaźniki funkcji hwcomposer2.h
. W hwcomposer2.h
komentarzach funkcje interfejsu HWC są określane za pomocą nazw w formacie lowerCamelCase, które nie występują w interfejsie jako nazwane pola. Prawie każda funkcja jest wczytywana przez wysłanie żądania wskaźnika funkcji za pomocą getFunction
udostępnionego przez hwc2_device_t
. Na przykład funkcja createLayer
jest wskaźnikiem funkcji typu HWC2_PFN_CREATE_LAYER
, który jest zwracany, gdy do funkcji getFunction
przekazywana jest wartość wyliczeniowa HWC2_FUNCTION_CREATE_LAYER
.
Szczegółową dokumentację funkcji Composer HAL i funkcji przekazywania HWC znajdziesz w composer
. Szczegółową dokumentację wskaźników funkcji HWC znajdziesz w hwcomposer2.h
.
Uchwyty warstw i wyświetlania
Warstwy i wyświetlacze są obsługiwane przez uchwyty generowane przez HWC. Uchwyty są nieprzezroczyste dla usługi SurfaceFlinger.
Gdy SurfaceFlinger tworzy nową warstwę, wywołuje funkcję createLayer
, która zwraca wartość typu Layer
w przypadku implementacji bezpośrednich lub hwc2_layer_t
w przypadku implementacji przekazywanych. Gdy SurfaceFlinger modyfikuje właściwość tej warstwy, przekazuje wartość hwc2_layer_t
do odpowiedniej funkcji modyfikacji wraz z wszelkimi innymi informacjami potrzebnymi do wprowadzenia zmiany. Typ
hwc2_layer_t
jest wystarczająco duży, aby pomieścić wskaźnik lub indeks.
Wyświetlacze fizyczne są tworzone przez podłączenie na gorąco. Gdy wyświetlacz fizyczny jest podłączany na gorąco, HWC tworzy uchwyt i przekazuje go do SurfaceFlinger za pomocą wywołania zwrotnego hotplug. Wirtualne wyświetlacze są tworzone przez SurfaceFlinger, który wywołuje createVirtualDisplay()
, aby poprosić o wyświetlacz. Jeśli HWC obsługuje kompozycję wyświetlacza wirtualnego, zwraca uchwyt. Następnie SurfaceFlinger
przekazuje kompozycję wyświetlacza do HWC. Jeśli HWC nie obsługuje kompozycji wirtualnego wyświetlacza, SurfaceFlinger tworzy uchwyt i komponuje wyświetlacz.
Operacje dotyczące kompozycji wyświetlania
Raz na synchronizację pionową SurfaceFlinger wznawia działanie, jeśli ma nowe treści do połączenia. Nowe treści mogą być nowymi buforami obrazów z aplikacji lub zmianą właściwości co najmniej jednej warstwy. Gdy usługa SurfaceFlinger wznawia działanie:
- Obsługuje transakcje, jeśli są dostępne.
- Zatrzaskuje nowe bufory graficzne, jeśli są dostępne.
- Wykonuje nową kompozycję, jeśli w kroku 1 lub 2 nastąpiła zmiana wyświetlanych treści.
Aby wykonać nowe komponowanie, SurfaceFlinger tworzy i usuwa warstwy lub modyfikuje ich stany, w zależności od potrzeb. Aktualizuje też warstwy z ich bieżącą zawartością, używając wywołań takich jak setLayerBuffer
lub setLayerColor
. Po zaktualizowaniu wszystkich warstw SurfaceFlinger wywołuje funkcję validateDisplay
, która informuje HWC o sprawdzeniu stanu warstw i określeniu sposobu kompozycji. Domyślnie SurfaceFlinger próbuje skonfigurować każdą warstwę tak, aby była ona komponowana przez HWC. W niektórych przypadkach jednak SurfaceFlinger komponuje warstwy za pomocą GPU.
Po wywołaniu funkcji validateDisplay
SurfaceFlinger wywołuje funkcję getChangedCompositionTypes
, aby sprawdzić, czy HWC chce zmienić któryś z typów kompozycji warstw przed wykonaniem kompozycji. Aby zaakceptować zmiany, SurfaceFlinger wywołuje
acceptDisplayChanges
.
Jeśli jakiekolwiek warstwy są oznaczone do kompozycji SurfaceFlinger, SurfaceFlinger
łączy je w buforze docelowym. Następnie SurfaceFlinger wywołuje
setClientTarget
, aby przekazać bufor do wyświetlenia, tak aby bufor mógł być wyświetlany na ekranie lub dalej łączony z warstwami, które nie zostały oznaczone do kompozycji SurfaceFlinger. Jeśli żadne warstwy nie są oznaczone do kompozycji SurfaceFlinger, SurfaceFlinger pomija krok kompozycji.
Na koniec SurfaceFlinger wywołuje presentDisplay
, aby poinformować HWC o konieczności zakończenia procesu kompozycji i wyświetlenia ostatecznego wyniku.
Wiele reklam displayowych
Android 10 obsługuje wiele wyświetlaczy fizycznych. Podczas projektowania implementacji HWC przeznaczonej do użytku na urządzeniach z Androidem 7.0 i nowszym obowiązują pewne ograniczenia, które nie występują w definicji HWC:
- Zakładamy, że jest dokładnie jeden wyświetlacz wewnętrzny. Wewnętrzny wyświetlacz to wyświetlacz, który zgłasza pierwsze podłączenie podczas uruchamiania. Po podłączeniu wyświetlacza wewnętrznego nie można go odłączyć.
- Oprócz wyświetlacza wewnętrznego podczas normalnego działania urządzenia można podłączyć dowolną liczbę wyświetlaczy zewnętrznych. Zakłada on, że wszystkie urządzenia podłączane na gorąco po pierwszym wyświetlaczu wewnętrznym są wyświetlaczami zewnętrznymi. Jeśli więc dodasz więcej wyświetlaczy wewnętrznych, zostaną one nieprawidłowo sklasyfikowane jako
Display.TYPE_HDMI
zamiastDisplay.TYPE_BUILT_IN
.
Opisane powyżej operacje SurfaceFlingera są wykonywane na każdym wyświetlaczu, ale sekwencyjnie na wszystkich aktywnych wyświetlaczach, nawet jeśli zawartość tylko jednego z nich jest aktualizowana.
Jeśli na przykład wyświetlacz zewnętrzny zostanie zaktualizowany, sekwencja będzie wyglądać tak:
// 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>)
Kompozycja wyświetlacza wirtualnego
Kompozycja wyświetlacza wirtualnego jest podobna do kompozycji wyświetlacza zewnętrznego. Różnica między kompozycją wyświetlacza wirtualnego a kompozycją wyświetlacza fizycznego polega na tym, że wyświetlacze wirtualne wysyłają dane wyjściowe do bufora Gralloc zamiast na ekran. Kompozytor sprzętowy (HWC) zapisuje dane wyjściowe w buforze, udostępnia barierę zakończenia i wysyła bufor do odbiorcy (np. kodera wideo, procesora graficznego, procesora itp.). Wyświetlacze wirtualne mogą korzystać z 2D/blitter lub nakładek, jeśli potok wyświetlania zapisuje dane w pamięci.
Tryby
Po wywołaniu przez SurfaceFlinger metody validateDisplay()
HWC każda ramka jest w jednym z 3 trybów:
- GLES – procesor graficzny łączy wszystkie warstwy, zapisując je bezpośrednio w buforze wyjściowym. HWC nie uczestniczy w komponowaniu.
- MIXED – procesor graficzny łączy niektóre warstwy w buforze ramki, a HWC łączy bufor ramki i pozostałe warstwy, zapisując je bezpośrednio w buforze wyjściowym.
- HWC – HWC łączy wszystkie warstwy i zapisuje je bezpośrednio w buforze wyjściowym.
Format wyjściowy
Formaty wyjściowe bufora wirtualnego wyświetlacza zależą od trybu:
- Tryb GLES – sterownik EGL ustawia format bufora wyjściowego w
dequeueBuffer()
, zwykleRGBA_8888
. Użytkownik musi zaakceptować format wyjściowy ustawiony przez sterownik, w przeciwnym razie bufora nie będzie można odczytać. - Tryby MIXED i HWC – jeśli konsument potrzebuje dostępu do procesora, sam ustawia format. W przeciwnym razie format to
IMPLEMENTATION_DEFINED
, a Gralloc ustawia najlepszy format na podstawie flag użycia. Na przykład Gralloc ustawia format YCbCr, jeśli odbiorcą jest koder wideo, a HWC może efektywnie zapisywać ten format.
Bariery synchronizacji
Bariery synchronizacji są kluczowym elementem systemu graficznego Androida. Ogrodzenia umożliwiają wykonywanie zadań przez procesor niezależnie od równoległych zadań procesora graficznego, blokując je tylko wtedy, gdy istnieje prawdziwa zależność.
Na przykład, gdy aplikacja przesyła bufor, który jest generowany na GPU, przesyła też obiekt bariery synchronizacji. Ten sygnał informuje, kiedy procesor graficzny zakończył zapisywanie w buforze.
HWC wymaga, aby procesor graficzny zakończył zapisywanie buforów przed ich wyświetleniem. Ogrodzenia synchronizacji są przekazywane przez potok graficzny z buforami i sygnalizują zapisanie buforów. Zanim zostanie wyświetlony bufor, HWC sprawdza, czy sygnał ogrodzenia synchronizacji został wysłany. Jeśli tak, wyświetla bufor.
Więcej informacji o barierach synchronizacji znajdziesz w sekcji Integracja z kompozycją sprzętową.