Komponent HWC (Hardware Composer) tworzy kompozycję warstw otrzymanych z SurfaceFlinger, co zmniejsza ilość operacji komponowania wykonywanych przez OpenGL ES (GLES) i procesor graficzny.
HWC abstrakcyjnie przetwarza obiekty, takie jak nakładki i blitarny 2D, na złożone powierzchnie, a także komunikuje się ze specjalistycznym sprzętem do tworzenia kompozycji okien, aby tworzyć kompozycje okien. Użyj HWC do składania okien zamiast składania przez SurfaceFlinger z GPU. Większość procesorów graficznych nie jest zoptymalizowana pod kątem kompozycji, a gdy GPU składa warstwy z SurfaceFlingera, aplikacje nie mogą używać GPU do własnego renderowania.
Implementacje HWC powinny obsługiwać:
- Co najmniej 4 nakładki:
- Pasek stanu
- Pasek systemu
- Aplikacja
- Tapeta/tłoko
- warstwy większe niż wyświetlacz (np. tapeta);
- jednoczesne premultipliede mieszanie alfa na poziomie pikseli i mieszanie alfa na poziomie płaszczyzny
- Sprzętowa ścieżka do odtwarzania chronionych filmów
- kolejność pakowania RGBA, formaty YUV oraz właściwości układania, przemieszania i stride;
Aby wdrożyć HWC:
- Wdrożyć niedziałający HWC i przekazać całą pracę związaną z kompozycją do GLES.
- Wdrożyć algorytm, który stopniowo deleguje tworzenie kompozycji do HWC. Na przykład możesz przekazać do wyświetlania nakładki tylko pierwsze 3 lub 4 powierzchnie sprzętu w HWC.
- Optymalizacja HWC. Może to obejmować:
- Wybieranie powierzchni, które zmaksymalizują obciążenie procesora graficznego i przesyłanie ich do HWC.
- wykrywanie, czy ekran jest aktualizowany; Jeśli tak nie jest, powierz kompozycję GLES zamiast HWC, aby oszczędzać energię. Gdy ekran ponownie się zaktualizuje, kontynuuj przenoszenie kompozycji do HWC.
- Przygotowanie do typowych zastosowań, takich jak:
- ekran główny, który zawiera pasek stanu, pasek systemu, okno aplikacji i tapety na żywo;
- gry w trybie pełnoekranowym w orientacji pionowej i poziomej.
- Film w trybie pełnoekranowym z napisami i elementami sterowania odtwarzaniem
- Odtwarzanie chronionych filmów
- Wielozadaniowość na podzielonym ekranie
Elementy podstawowe HWC
HWC udostępnia 2 elementy: warstwy i wyświetlacze, które reprezentują kompozycję i jej interakcję z wyświetlaczem sprzętowym. HWC zapewnia też kontrolę nad VSync oraz wywołanie zwrotne do SurfaceFlinger, aby powiadomić go o wystąpieniu zdarzenia VSync.
Interfejs HIDL
Android 8.0 i nowsze korzysta z interfejsu HIDL o nazwie Composer HAL do obsługi interfejsu IPC w ramach bindera między HWC a SurfaceFlinger. Interfejs Composer HAL zastępuje stary interfejs hwcomposer2.h
. Jeśli dostawcy udostępniają implementację Composer HAL dla HWC, Composer HAL bezpośrednio akceptuje wywołania HIDL z SurfaceFlingera. Jeśli dostawcy udostępniają starsze implementacje HWC, kompozytor HAL wczytuje wskaźniki funkcji z hwcomposer2.h
, przekazując wywołania HIDL do wywołań wskaźników funkcji.
HWC udostępnia funkcje umożliwiające określenie właściwości danego wyświetlacza, przełączanie się między różnymi konfiguracjami wyświetlacza (np. rozdzielczość 4K lub 1080p) i trybami kolorów (np. domyślny kolor lub prawdziwy sRGB) oraz włączanie, wyłączanie wyświetlacza lub przełączanie go w tryb niskiego poboru mocy (jeśli jest obsługiwany).
Wskaźniki funkcji
Jeśli dostawcy implementują interfejs HAL usługi Composer bezpośrednio, SurfaceFlinger wywołuje jej funkcje za pomocą interfejsu HIDL IPC. Na przykład do utworzenia warstwy SurfaceFlinger wywołuje funkcję createLayer()
w komponencie HAL usługi Composer.
Jeśli dostawcy implementują interfejs hwcomposer2.h
, Composer HAL wywołuje wskaźniki funkcji hwcomposer2.h
. W komentarzach hwcomposer2.h
funkcje interfejsu HWC są określane nazwami w formacie małej litery, które nie występują w interfejsie jako pola nazwane. Prawie każda funkcja jest wczytywana przez wysłanie żądania wskazującego funkcję za pomocą funkcji getFunction
, która jest dostarczana przez funkcję 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
przekazana zostaje wartością zagregowana HWC2_FUNCTION_CREATE_LAYER
.
Szczegółową dokumentację funkcji HAL w Composerze i funkcji przekazywania funkcji HWC znajdziesz w artykule composer
. Szczegółową dokumentację dotyczącą wskaźników funkcji HWC znajdziesz w hwcomposer2.h
.
Uchwyty warstw i wyświetlaczy
Warstwy i wyświetlacze są modyfikowane przez uchwyty generowane przez HWC. Narzędzia SurfaceFlinger nie mają dostępu do uchwytów.
Gdy SurfaceFlinger tworzy nową warstwę, wywołuje funkcję createLayer
, która zwraca typ Layer
w przypadku bezpośrednich implementacji lub hwc2_layer_t
w przypadku implementacji z przekazywaniem. Gdy SurfaceFlinger modyfikuje właściwość tej warstwy, przekazuje wartość hwc2_layer_t
do odpowiedniej funkcji modyfikacji wraz z innymi informacjami potrzebnymi do wprowadzenia zmiany. Typ hwc2_layer_t
jest wystarczająco duży, aby przechowywać wskaźnik lub indeks.
Fizyczne wyświetlacze są tworzone przez podłączenie. Gdy fizyczny wyświetlacz zostanie podłączony, HWC tworzy uchwyt i przekazuje go do SurfaceFlingera za pomocą wywołania zwrotnego hotplug. Wyświetlacze wirtualne są tworzone przez SurfaceFlingera, który wywołuje funkcję createVirtualDisplay()
, aby poprosić o wyświetlanie. Jeśli HWC obsługuje wirtualną kompozycję wyświetlacza, zwraca uchwyt. Następnie SurfaceFlinger deleguje kompozycję wyświetlaczy do HWC. Jeśli HWC nie obsługuje kompozycji wyświetlacza wirtualnego, SurfaceFlinger tworzy uchwyt i kompiluje wyświetlacz.
Operacje dotyczące wyświetlania kompozycji
Raz na VSync SurfaceFlinger budzi się, jeśli ma nowe treści do złożenia. Nowe treści mogą być nowymi buforami obrazów z aplikacji lub zmianą właściwości co najmniej 1 warstwy. Gdy SurfaceFlinger go aktywuje:
- Obsługuje transakcje, jeśli występują.
- Blokuje nowe bufory graficzne, jeśli są dostępne.
- Jeśli w efekcie kroku 1 lub 2 nastąpiła zmiana treści wyświetlanych na ekranie, zostanie utworzona nowa kompozycja.
Aby wykonać nową kompozycję, SurfaceFlinger tworzy i niszczy warstwy lub modyfikuje ich stany. Zaktualizuje też warstwy, stosując do nich bieżące treści za pomocą wywołań takich jak setLayerBuffer
lub setLayerColor
. Gdy wszystkie warstwy zostaną zaktualizowane, SurfaceFlinger wywołuje funkcję validateDisplay
, która informuje HWC, aby zweryfikował stan warstw i określił sposób dalszego działania. Domyślnie SurfaceFlinger próbuje skonfigurować każdą warstwę tak, aby była ona złożona przez HWC. W niektórych okolicznościach SurfaceFlinger składa warstwy za pomocą GPU.
Po wywołaniu funkcji validateDisplay
funkcja SurfaceFlinger wywołuje funkcję getChangedCompositionTypes
, aby sprawdzić, czy przed wykonaniem kompozycji HWC chce zmienić typ kompozycji warstw. Aby zaakceptować zmiany, SurfaceFlinger wywołuje funkcję acceptDisplayChanges
.
Jeśli jakiekolwiek warstwy są oznaczone do skompilowania przez SurfaceFlinger, narzędzie to skompiluje je do bufora docelowego. Następnie SurfaceFlinger wywołuje funkcję setClientTarget
, aby przekazać bufor do wyświetlacza, dzięki czemu bufor może być wyświetlany na ekranie lub dalej łączony z warstwami, które nie zostały oznaczone do kompozycji przez SurfaceFlinger. Jeśli żadne warstwy nie są oznaczone do kompozycji w SurfaceFlinger, narzędzie to pomija etap tworzenia kompozycji.
Na koniec SurfaceFlinger wywołuje funkcję presentDisplay
, aby zlecić HWC dokończenie procesu tworzenia kompozycji i wyświetlenie ostatecznego wyniku.
Wiele wyświetlaczy
Android 10 obsługuje wiele fizycznych wyświetlaczy. Podczas projektowania implementacji HWC przeznaczonej do użycia w Androidzie 7.0 lub nowszym obowiązują pewne ograniczenia, których nie ma w definicji HWC:
- Zakłada się, że jest dokładnie 1 wyświetlacz wewnętrzny. Wyświetlacz wewnętrzny to wyświetlacz, który początkowo zgłasza hotplug podczas uruchamiania. Po podłączeniu wyświetlacza wewnętrznego nie można go odłączyć.
- Oprócz wyświetlacza wewnętrznego podczas normalnej pracy urządzenia można podłączyć dowolną liczbę wyświetlaczy zewnętrznych. Framework zakłada, że wszystkie
hotplugi po pierwszym wewnętrznym wyświetlaczu są wyświetlaczami zewnętrznymi, więc jeśli dodasz więcej
wewnętrznych wyświetlaczy, zostaną one nieprawidłowo sklasyfikowane jako
Display.TYPE_HDMI
zamiastDisplay.TYPE_BUILT_IN
.
Chociaż operacje SurfaceFlinger opisane powyżej są wykonywane na poszczególnych wyświetlaczach, są one wykonywane sekwencyjnie na wszystkich aktywnych wyświetlaczach, nawet jeśli treści są aktualizowane tylko na jednym wyświetlaczu.
Jeśli na przykład wyświetlacz zewnętrzny jest aktualizowany, kolejność jest następująca:
// 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>)
Wirtualna kompozycja wyświetlania
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. Komponent HWC zapisuje dane wyjściowe w buforze, udostępnia ogrodzenie do ukończenia i wysyła bufor do odbiorcy (np. do kodera wideo, procesora graficznego, procesora centralnego itp.). Wyświetlacze wirtualne mogą używać 2D/Blitter lub nakładek, jeśli potok wyświetlania zapisuje dane w pamięci.
Tryby
Po wywołaniu przez SurfaceFlingera metody validateDisplay()
HWC każdy obraz jest w jednym z 3 trybów:
- GLES – GPU łączy wszystkie warstwy, zapisując dane bezpośrednio do bufora wyjściowego. HWC nie uczestniczy w kompozycji.
- MIXED (mieszany) – GPU składa niektóre warstwy do framebuffera, a HWC składa framebuffer i pozostałe warstwy, zapisując dane bezpośrednio do bufora wyjściowego.
- HWC – HWC łączy wszystkie warstwy i zapisuje je bezpośrednio w buforze wyjściowym.
Format wyjściowy
Formaty danych wyjściowych wirtualnego bufora wyświetlacza zależą od trybu:
- Tryb GLES – sterownik EGL ustawia format bufora wyjściowego na
dequeueBuffer()
, zwykleRGBA_8888
. Konsument musi być w stanie zaakceptować format wyjściowy ustawiony przez sterownik, w przeciwnym razie bufor nie będzie mógł być odczytany. - Tryby MIXED i HWC – jeśli konsument potrzebuje dostępu do procesora, to on określa 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 konsument jest koderem wideo, a HWC może efektywnie zapisać ten format.
Ograniczenia synchronizacji
Ogrodzenia synchronizacji są kluczowym elementem systemu graficznego Androida. Ogrodzenia umożliwiają niezależne działanie procesora od równoległej pracy GPU, blokując je tylko wtedy, gdy istnieje prawdziwa zależność.
Na przykład, gdy aplikacja przesyła bufor tworzony na GPU, przesyła też obiekt synchronizacji. Ten sygnał informuje, że GPU zakończyło zapisywanie danych do bufora.
HWC wymaga, aby GPU ukończyło zapisywanie buforów przed ich wyświetleniem. Ogrodzenia synchronizacji są przekazywane przez rdzeń graficzny wraz z buforami i sygnałem, gdy bufory są zapisywane. Przed wyświetleniem bufora HWC sprawdza, czy sygnał synchronizacji został wysłany. Jeśli tak, wyświetla bufor.
Więcej informacji o ogrodach synchronizacji znajdziesz w artykule Integracja z komponentem Hardware Composer.