Wdrażanie HAL usługi Hardware Composer

Komponent HWC (Hardware Composer) tworzy kompozycję warstw otrzymanych z SurfaceFlinger, co zmniejsza ilość operacji komponowania wykonywanych przez OpenGL ES (GLES) i procesor graficzny.

HWC wyodrębnia obiekty, takie jak nakładki i blittery 2D, do warstw zespolonych, a następnie komunikuje się ze specjalistycznym sprzętem do tworzenia kompozycji okien z oknami kompozycyjnymi. 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 postępu
    • Pasek systemowy
    • Aplikacja
    • Tapeta/tłoko
  • warstwy większe niż ekran (np. tapeta);
  • Jednoczesne mnożenie wstępnie na piksel i mieszanie alfa na płaszczyźnie alfa
  • Sprzętowa ścieżka do odtwarzania chronionych filmów
  • kolejność pakowania RGBA, formaty YUV oraz właściwości kafelkowania, przemieszania i skoku;

Aby wdrożyć HWC:

  1. Wdróż nieoperacyjne urządzenie HWC i wyślij do GLES całą pracę związaną z kompozycją.
  2. Wdrożyć algorytm, który stopniowo deleguje tworzenie kompozycji do HWC. Na przykład możesz przypisać do sprzętu nakładki HWC tylko pierwsze 3 lub 4 powierzchnie.
  3. Optymalizacja HWC. Może to obejmować:
    • Wybieram platformy, które maksymalizują obciążenie GPU, i wysyłam je 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 zawierający pasek stanu, pasek systemu, okno aplikacji i animowane tapety
      • Gry pełnoekranowe w orientacji pionowej i poziomej
      • Film na pełnym ekranie z napisami i sterowaniem odtwarzaniem
      • Odtwarzanie chronionych filmów
      • Tryb wielu okien na podzielonym ekranie

Podstawowe elementy sprzętowe HWC

HWC udostępnia 2 elementy podstawowe – warstwy i wyświetlacze – reprezentujące pracę kompozycji i jej interakcję ze sprzętem do wyświetlania. HWC zapewnia też kontrolę nad VSYNC i wywołanie zwrotne do SurfaceFlinger w celu powiadomienia go o wystąpieniu zdarzenia VSYNC.

Interfejs HIDL

Android 8.0 i nowsze używa interfejsu HIDL o nazwie Composer HAL do obsługi interfejsu IPC w ramach bindera między HWC a SurfaceFlinger. Interfejs HAL usługi Composer zastępuje starszy interfejs hwcomposer2.h. Jeśli dostawcy udostępniają implementację HWC w usłudze Composer, usługa ta bezpośrednio akceptuje wywołania HIDL z SurfaceFlinger. Jeśli dostawcy udostępniają starsze wersje implementacji 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 bezpośrednio wdrażają HAL Composer, SurfaceFlinger wywołuje swoje funkcje za pomocą 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 stylu „małaCamelCase”, 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ą parametru getFunction, który jest przekazywany 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ą za pomocą funkcji HWC2_FUNCTION_CREATE_LAYER.

Szczegółową dokumentację funkcji HAL i funkcji przekazywania funkcji HWC w usłudze Composer znajdziesz tutaj: composer. Szczegółową dokumentację dotyczącą wskaźników funkcji HWC znajdziesz w hwcomposer2.h.

uchwyty warstw i wyświetlania,

Warstwy i wyświetlacze są modyfikowane przez uchwyty wygenerowane przez interfejs HWC. Uchwyty są nieprzezroczyste dla SurfaceFlinger.

Gdy SurfaceFlinger tworzy nową warstwę, wywołuje funkcję createLayer, która zwraca typ Layer w przypadku implementacji bezpośrednich lub hwc2_layer_t w przypadku implementacji przekazywania. 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 SurfaceFlinger wywołując funkcję createVirtualDisplay() w celu zażądania wyświetlenia. 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 nick i komponuje 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 jednej warstwy. Po wybudzeniu przez SurfaceFlinger:

  1. Obsługuje transakcje, jeśli występują.
  2. Blokuje nowe bufory graficzne, jeśli są dostępne.
  3. 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 odpowiednio zmienia ich stany. Aktualizuje także warstwy o aktualną zawartość, używając wywołań takich jak setLayerBuffer lub setLayerColor. Po zaktualizowaniu wszystkich warstw SurfaceFlinger wywołuje validateDisplay, który informuje HWC, że ma sprawdzić stan warstw i określić sposób zachowania kompozycji. 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 usługa SurfaceFlinger wywołuje getChangedCompositionTypes, by sprawdzić, czy HWC przed wykonaniem kompozycji chce zmienić którykolwiek z typów 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 złożony z warstw, które nie zostały oznaczone do kompozycji przez SurfaceFlinger. Jeśli żadne warstwy nie są oznaczone do kompozycji za pomocą 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 wyniku końcowego.

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 ekranie są ekranami zewnętrznymi, więc jeśli dodasz więcej ekranów wewnętrznych, zostaną one nieprawidłowo sklasyfikowane jako Display.TYPE_HDMI zamiast Display.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>)

Kompozycja wyświetlacza wirtualnego

Kompozycja wyświetlacza wirtualnego jest podobna do kompozycji wyświetlacza zewnętrznego. Różnica między kompozycją ekranu wirtualnego a kompozycją wyświetlacza fizycznego polega na tym, że wyświetlacze wirtualne wysyłają dane wyjściowe do bufora Gralloca, a nie na ekran. Hardware Composer (HWC) zapisuje dane wyjściowe w buforze, zapewnia granicę zakończenia i wysyła bufor do konsumenta (np. kodera wideo, GPU, procesora itd.). 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 i zapisuje je bezpośrednio w buforze wyjściowym. 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 bezpośrednio do bufora wyjściowego.
  • HWC – HWC komponuje 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 w dequeueBuffer(), zwykle RGBA_8888. Użytkownik musi być w stanie zaakceptować format wyjściowy ustawiony przez sterownik, w przeciwnym razie bufor nie będzie można odczytać.
  • Tryby mieszane i HWC – jeśli konsument potrzebuje dostępu do procesora, ustawia format. W przeciwnym razie format to IMPLEMENTATION_DEFINED, a Gralloc ustawia najlepszy format na podstawie flag wykorzystania. 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ą procesorowi działanie niezależnie od równoległego działania procesora graficznego, 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 skończyło zapisywanie buforów przed ich wyświetleniem. Ogrodzenia synchronizacji są przekazywane przez potok graficzny z buforami i sygnalizują, gdy bufory są zapisywane. Przed wyświetleniem bufora HWC sprawdza, czy ogrodzenie synchronizacji ma sygnał. Jeśli tak, wyświetla bufor.

Więcej informacji o ogrodach synchronizacji znajdziesz w artykule Integracja z komponentem Hardware Composer.