Zaimplementuj HAL Hardware Composer

Hardware Composer (HWC) HAL łączy warstwy otrzymane z SurfaceFlinger, zmniejszając ilość kompozycji wykonywanej przez OpenGL ES (GLES) i procesor graficzny.

HWC przenosi obiekty, takie jak nakładki i blitery 2D, na powierzchnie kompozytowe i komunikuje się ze specjalistycznym sprzętem do tworzenia kompozycji okien w celu uzyskania okien kompozytowych. Użyj HWC do łączenia okien zamiast korzystania z kompozytu SurfaceFlinger z procesorem graficznym. Większość procesorów graficznych nie jest zoptymalizowana pod kątem kompozycji, a gdy procesor graficzny tworzy warstwy z SurfaceFlinger, aplikacje nie mogą używać procesora graficznego do własnego renderowania.

Wdrożenia HWC powinny wspierać:

  • Co najmniej cztery nakładki:
    • Pasek stanu
    • Pasek systemowy
    • Aplikacja
    • Tapeta/tło
  • Warstwy większe niż wyświetlacz (na przykład tapeta)
  • Jednoczesne, wstępnie pomnożone mieszanie alfa na piksel i mieszanie alfa na płaszczyznę
  • Ścieżka sprzętowa do chronionego odtwarzania wideo
  • Kolejność pakowania RGBA, formaty YUV oraz właściwości kafelkowania, swizzlingu i kroku

Aby wdrożyć HWC:

  1. Zaimplementuj nieoperacyjny HWC i wyślij wszystkie prace związane z kompozycją do GLES.
  2. Zaimplementuj algorytm stopniowego delegowania kompozycji do HWC. Na przykład oddeleguj tylko pierwsze trzy lub cztery powierzchnie do sprzętu nakładkowego HWC.
  3. Zoptymalizuj HWC. Może to obejmować:
    • Wybieranie powierzchni, które maksymalizują obciążenie zdjęte z GPU i wysyłanie ich do HWC.
    • Wykrywanie, czy ekran się aktualizuje. Jeśli tak nie jest, przekaż kompozycję GLES zamiast HWC, aby oszczędzać energię. Gdy ekran ponownie się zaktualizuje, kontynuuj przesyłanie kompozycji do HWC.
    • Przygotowanie do typowych przypadków użycia, takich jak:
      • Ekran główny, który zawiera pasek stanu, pasek systemowy, okno aplikacji i animowane tapety
      • Gry pełnoekranowe w trybie pionowym i poziomym
      • Wideo na pełnym ekranie z napisami i kontrolą odtwarzania
      • Chronione odtwarzanie wideo
      • Wiele okien z podzielonym ekranem

Prymitywy HWC

HWC zapewnia dwa prymitywy, warstwy i wyświetlacze , do reprezentowania pracy nad kompozycją i jej interakcji ze sprzętem wyświetlającym. HWC zapewnia również kontrolę nad VSYNC i wywołanie zwrotne do SurfaceFlinger w celu powiadomienia go, gdy wystąpi zdarzenie VSYNC.

Interfejs HIDL

Android 8.0 i nowsze wersje korzystają z interfejsu HIDL o nazwie Composer HAL dla spoiwowych IPC pomiędzy HWC i SurfaceFlinger. Composer HAL zastępuje dotychczasowy interfejs hwcomposer2.h . Jeśli dostawcy zapewniają implementację HWC Composer HAL, Composer HAL bezpośrednio akceptuje wywołania HIDL z SurfaceFlinger. Jeśli dostawcy zapewniają starszą implementację HWC, Composer HAL ładuje 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 między różnymi konfiguracjami wyświetlania (takimi jak rozdzielczość 4k lub 1080p) i trybami kolorów (takimi jak kolor natywny lub prawdziwy sRGB); oraz aby włączyć, wyłączyć wyświetlacz lub przejść w tryb niskiego poboru mocy, jeśli jest to obsługiwane.

Wskaźniki funkcji

Jeśli dostawcy bezpośrednio wdrażają Composer HAL, SurfaceFlinger wywołuje jego funkcje poprzez HIDL IPC. Na przykład, aby utworzyć warstwę, SurfaceFlinger wywołuje funkcję createLayer() w warstwie HAL 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 za pomocą nazw lessCamelCase, które nie istnieją w interfejsie jako nazwane pola. Prawie każda funkcja jest ładowana poprzez żądanie wskaźnika funkcji za pomocą 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 wyliczona wartość HWC2_FUNCTION_CREATE_LAYER jest przekazywana do getFunction .

Aby uzyskać szczegółową dokumentację funkcji Composer HAL i funkcji przejścia funkcji HWC, zobacz composer . Aby uzyskać szczegółową dokumentację wskaźników funkcji HWC, zobacz hwcomposer2.h .

Warstwa i wyświetlanie uchwytów

Warstwy i wyświetlacze są manipulowane za pomocą uchwytów generowanych przez HWC. Uchwyty są nieprzezroczyste dla SurfaceFlinger.

Gdy SurfaceFlinger tworzy nową warstwę, wywołuje createLayer , która zwraca typ Layer w przypadku implementacji bezpośrednich lub hwc2_layer_t w przypadku implementacji przekazujących. Gdy SurfaceFlinger modyfikuje właściwość tej warstwy, SurfaceFlinger przekazuje wartość hwc2_layer_t do odpowiedniej funkcji modyfikującej wraz z innymi informacjami niezbędnymi do wprowadzenia modyfikacji. Typ hwc2_layer_t jest wystarczająco duży, aby pomieścić wskaźnik lub indeks.

Wyświetlacze fizyczne są tworzone poprzez podłączanie na gorąco. Kiedy fizyczny wyświetlacz jest podłączany podczas pracy, HWC tworzy uchwyt i przekazuje go do SurfaceFlinger poprzez wywołanie zwrotne typu hotplug. Wirtualne wyświetlacze są tworzone przez SurfaceFlinger wywołujący metodę createVirtualDisplay() w celu zażądania wyświetlenia. Jeśli HWC obsługuje kompozycję wyświetlania wirtualnego, zwraca uchwyt. Następnie SurfaceFlinger deleguje kompozycję wyświetlaczy do HWC. Jeśli HWC nie obsługuje kompozycji wirtualnego wyświetlacza, SurfaceFlinger tworzy uchwyt i składa wyświetlacz.

Wyświetl operacje kompozycji

Raz na VSYNC SurfaceFlinger budzi się, jeśli ma nową zawartość do złożenia. Ta nowa zawartość może obejmować nowe bufory obrazów z aplikacji lub zmianę właściwości jednej lub większej liczby warstw. Kiedy SurfaceFlinger go budzi:

  1. Obsługuje transakcje, jeśli są obecne.
  2. Blokuje nowe bufory graficzne, jeśli są obecne.
  3. Wykonuje nową kompozycję, jeśli krok 1 lub 2 spowodował zmianę zawartości wyświetlacza.

Aby wykonać nową kompozycję, SurfaceFlinger tworzy i niszczy warstwy lub modyfikuje stany warstw, stosownie do potrzeb. Aktualizuje także warstwy o ich bieżącą zawartość, używając wywołań takich jak setLayerBuffer lub setLayerColor . Po zaktualizowaniu wszystkich warstw SurfaceFlinger wywołuje validateDisplay , który informuje HWC, aby sprawdził stan warstw i określił, jak będzie przebiegać kompozycja. Domyślnie SurfaceFlinger próbuje skonfigurować każdą warstwę w taki sposób, aby warstwa była komponowana przez HWC; chociaż w pewnych okolicznościach SurfaceFlinger łączy warstwy poprzez rezerwę GPU.

Po wywołaniu metody validateDisplay SurfaceFlinger wywołuje getChangedCompositionTypes , aby sprawdzić, czy HWC chce zmienić którykolwiek z typów kompozycji warstw przed wykonaniem kompozycji. Aby zaakceptować zmiany, SurfaceFlinger wywołuje acceptDisplayChanges .

Jeśli jakiekolwiek warstwy są zaznaczone do kompozycji SurfaceFlinger, SurfaceFlinger łączy je w buforze docelowym. SurfaceFlinger następnie wywołuje setClientTarget , aby udostępnić bufor wyświetlaczowi, dzięki czemu bufor może zostać wyświetlony na ekranie lub dalej skomponowany z warstwami, które nie zostały oznaczone do kompozycji SurfaceFlinger. Jeśli dla kompozycji SurfaceFlinger nie są zaznaczone żadne warstwy, SurfaceFlinger pomija etap kompozycji.

Na koniec SurfaceFlinger wywołuje presentDisplay , aby poinformować HWC o dokończeniu procesu komponowania i wyświetleniu wyniku końcowego.

Wiele wyświetlaczy

Android 10 obsługuje wiele wyświetlaczy fizycznych. Projektując implementację HWC przeznaczoną do użytku w systemie Android 7.0 i nowszych, istnieją pewne ograniczenia, których nie ma w definicji HWC:

  • Zakłada się, że jest dokładnie jeden wyświetlacz wewnętrzny . Wyświetlacz wewnętrzny to wyświetlacz, który raportuje początkowa wtyczka typu hotplug podczas rozruchu. Po podłączeniu wyświetlacza wewnętrznego podczas pracy 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. Struktura zakłada, że ​​wszystkie wtyczki typu hotplug po pierwszym wyświetlaczu wewnętrznym są wyświetlaczami zewnętrznymi, więc jeśli dodane zostaną kolejne wyświetlacze wewnętrzne, zostaną one nieprawidłowo sklasyfikowane jako Display.TYPE_HDMI zamiast Display.TYPE_BUILT_IN .

Chociaż opisane powyżej operacje SurfaceFlinger są wykonywane na każdym wyświetlaczu, są one wykonywane sekwencyjnie dla wszystkich aktywnych wyświetlaczy, nawet jeśli aktualizowana jest zawartość tylko jednego wyświetlacza.

Na przykład, jeśli wyświetlacz zewnętrzny jest aktualizowany, sekwencja 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świetlacza

Skład wyświetlacza wirtualnego jest podobny do składu wyświetlacza zewnętrznego. Różnica między układem wyświetlacza wirtualnego a układem wyświetlacza fizycznego polega na tym, że wyświetlacze wirtualne wysyłają dane wyjściowe do bufora Gralloc zamiast na ekran. Hardware Composer (HWC) zapisuje dane wyjściowe w buforze, udostępnia barierę zakończenia i wysyła bufor do konsumenta (takiego jak koder wideo, procesor graficzny, procesor itd.). Wirtualne wyświetlacze mogą korzystać z 2D/blittera lub nakładek, jeśli potok wyświetlania zapisuje do pamięci.

Tryby

Każda ramka znajduje się w jednym z trzech trybów po wywołaniu przez SurfaceFlinger metody validateDisplay() HWC:

  • GLES — GPU łączy wszystkie warstwy, zapisując bezpośrednio do bufora wyjściowego. HWC nie bierze udziału w komponowaniu.
  • MIESZANE — Procesor graficzny łączy niektóre warstwy z buforem ramki, a HWC łączy bufor ramki z pozostałymi warstwami, zapisując bezpośrednio do bufora wyjściowego.
  • HWC — HWC łączy wszystkie warstwy i zapisuje bezpośrednio do bufora wyjściowego.

Format wyjściowy

Formaty wyjściowe bufora wyświetlacza wirtualnego zależą od ich trybu:

  • Tryb GLES — sterownik EGL ustawia format bufora wyjściowego w dequeueBuffer() , zazwyczaj RGBA_8888 . Konsument musi być w stanie zaakceptować format wyjściowy ustawiony przez sterownik, w przeciwnym razie bufor nie będzie mógł zostać odczytany.
  • Tryby MIESZANE i HWC — jeśli odbiorca potrzebuje dostępu do procesora, ustawia format. W przeciwnym razie format to IMPLEMENTATION_DEFINED , a Gralloc ustawia najlepszy format w oparciu o flagi użycia. Na przykład Gralloc ustawia format YCbCr, jeśli konsument jest koderem wideo, a HWC może efektywnie zapisać format.

Ogrodzenia synchronizacyjne

Ogrodzenia synchronizacji (synchronizacji) są kluczowym aspektem systemu graficznego Androida. Ogrodzenia umożliwiają pracę procesora niezależnie od jednoczesnej pracy procesora graficznego, blokując tylko wtedy, gdy istnieje prawdziwa zależność.

Na przykład, gdy aplikacja przesyła bufor tworzony na procesorze graficznym, przesyła również obiekt ogrodzenia synchronizacji. To ogrodzenie sygnalizuje, że procesor graficzny zakończył zapisywanie w buforze.

HWC wymaga, aby procesor graficzny zakończył zapisywanie buforów przed ich wyświetleniem. Ogrodzenia synchronizacji są przepuszczane przez potok graficzny z buforami i sygnalizują zapisanie buforów. Przed wyświetleniem bufora HWC sprawdza, czy zabezpieczenie synchronizacji przesłało sygnał i jeśli tak, wyświetla bufor.

Aby uzyskać więcej informacji na temat ogrodzeń synchronizacji, zobacz Integracja narzędzia Hardware Composer .