HAL kompozytora sprzętowego (HWC) łączy warstwy otrzymane z SurfaceFlingera, zmniejszając ilość kompozycji OpenGL ES (GLES) i wydajność GPU.
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ą procesora graficznego. 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 muszą 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:
- Wdrożenie 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 pełnoekranowy 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łanie zwrotne do SurfaceFlinger, aby powiadamiać go o wystąpieniu zdarzenia VSync.
Interfejs HIDL
Android 8.0 i nowsze wersje korzystają z interfejsu HIDL o nazwie Composer HAL do komunikacji IPC opartej na binderze między HWC a SurfaceFlinger. HAL usługi Composer zastępuje starszy interfejs hwcomposer2.h. Jeśli dostawcy udostępniają implementację HWC w postaci Composer HAL, Composer HAL 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, przekazując 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ść 4K lub 1080p) i trybami kolorów (np. natywny kolor lub prawdziwy sRGB) oraz włączania, wyłączania lub przełączania wyświetlacza w tryb niskiego zużycia energii, jeśli jest to obsługiwane.
Wskaźniki funkcji
Jeśli dostawcy zaimplementują HAL usługi Composer 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, HAL usługi Composer wywoła 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ą funkcji getFunction udostępnianej 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 zostanie przekazana wartość wyliczeniowa HWC2_FUNCTION_CREATE_LAYER.
Szczegółową dokumentację funkcji HAL usługi Composer i funkcji przekazywania funkcji HWC znajdziesz w artykule composer. Szczegółową dokumentację wskaźników funkcji HWC znajdziesz w hwcomposer2.h.
Uchwyty warstw i wyświetlania
Warstwami i wyświetlaczami manipuluje się za pomocą uchwytów generowanych 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 zostanie podłączony 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 VSync 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 jednej lub kilku warstw. Gdy usługa SurfaceFlinger wybudzi urządzenie:
- 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 stany warstw (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świetlacza, tak aby można było go wyświetlić na ekranie lub dalej łączyć 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 zakończeniu procesu kompozycji i wyświetleniu 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 1 wyświetlacz wewnętrzny. Wyświetlacz wewnętrzny to wyświetlacz, który zgłasza pierwsze podłączenie podczas uruchamiania. Po podłączeniu wewnętrznego wyświetlacza 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_HDMIzamiastDisplay.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 wirtualnego wyświetlacza
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.). Wirtualne wyświetlacze 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 HWC każda ramka jest w jednym z 3 trybów:validateDisplay()
- GLES – procesor graficzny łączy wszystkie warstwy, zapisując je bezpośrednio w buforze wyjściowym. HWC nie uczestniczy w kompozycji.
- 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ń na procesorze niezależnie od równoczesnej pracy procesora graficznego, blokując 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ą, kiedy bufory są zapisywane. 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 kompozytorem sprzętowym.