Platforma synchronizacji

Struktura synchronizacji wyraźnie opisuje zależności między przy wykonywaniu różnych operacji asynchronicznych w systemie graficznym Androida. Struktura udostępnia interfejs API, który umożliwia komponentom wskazywanie momentów zwolnienia buforów. Platforma zapewnia również umożliwia przekazywanie podstawowych elementów synchronizacji między sterownikami w jądrze do przestrzeni użytkownika i między procesami w tej przestrzeni.

Aplikacja może na przykład umieszczać w kolejce zadania do wykonania w GPU. Procesor graficzny zaczyna rysować ten obraz. Chociaż obraz nie został narysowany, do pamięci, wskaźnik bufora jest przekazywany do okna kompozytora wraz z ogrodzeniem, które wskazuje, kiedy układ GPU . Kompozytor okien rozpoczyna przetwarzanie z wyprzedzeniem i przekazuje pracę kontrolerowi ekranu. W podobny sposób procesor trzeba wykonać wcześniej. Gdy GPU zakończy działanie, kontroler wyświetlacza od razu wyświetli obraz.

Platforma synchronizacji pozwala też wdrażającym zasobów synchronizacji w ich własnych komponentach sprzętowych. Pamiętaj też, że zapewnia wgląd w potok graficzny, co ułatwia i debugowaniu.

Jawna synchronizacja

Bezpośrednia synchronizacja umożliwia producentom i konsumentom korzystanie z buforów graficznych sygnalizuje zakończenie, używając bufora. Aktualna synchronizacja w środowisku jądra systemu operacyjnego.

Zalety bezpośredniej synchronizacji:

  • Mniejsze różnice w zachowaniu między urządzeniami
  • Lepsza obsługa debugowania
  • Ulepszone dane testowe

Platforma synchronizacji ma 3 typy obiektów:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline to monotonicznie rosnąca oś czasu, dostawcy powinni wdrożyć dla każdej instancji sterownika, np. kontekst GL, lub np. kontroler wyświetlacza 2D. Liczba operacji: sync_timeline do jądra systemu dla określonego urządzenia. sync_timeline zapewnia gwarancje dotyczące kolejności działań i umożliwia korzystanie ze sprzętu.

Przestrzegaj tych wskazówek przy implementacji sync_timeline:

  • Aby uprościć, podaj przydatne nazwy wszystkich kierowców, osi czasu i płodów i debugowaniu.
  • Wdróż timeline_value_str i pt_value_str operatory na osi czasu, aby dane wyjściowe debugowania były bardziej czytelne.
  • Zaimplementuj funkcję wypełnienia (driver_data), aby zapewnić biblioteki przestrzeni użytkownika. takich jak biblioteka GL, w razie potrzeby dostęp do prywatnych danych osi czasu. data_driver umożliwia dostawcom przekazywanie informacji o stałych sync_fence i sync_pts do tworzenia wierszy poleceń na ich podstawie.
  • Nie zezwalaj przestrzeni użytkownika na bezpośrednie tworzenie lub sygnalizowanie ogrodzenia. Wyraźnie tworzenie sygnałów/płodów skutkuje atakiem typu DoS, wstrzymuje działanie potoku.
  • Nie uzyskuj dostępu do usług sync_timeline, sync_pt lub sync_fence. Interfejs API udostępnia wszystkie wymagane funkcji.

synchronizacja_pt

sync_pt to pojedyncza wartość lub punkt na sync_timeline Punkt ma 3 stany: aktywny, sygnalizowany i błąd. Punkty zaczynają się w stanie aktywnym i przejściu do stanu sygnalizowania lub błędu. Jeśli na przykład obraz konsument nie potrzebuje już bufora, pojawia się sygnał sync_pt dzięki czemu producent obrazów wie, że można znowu zapisać w buforze.

granica_synchronizacji

sync_fence to zbiór wartości sync_pt często mają różne elementy nadrzędne sync_timeline (np. dla wyświetlacza kontroler i GPU). sync_fence, sync_pt i sync_timeline to główne podstawowe elementy, których sterowniki i przestrzeń użytkownika komunikują się z nimi. Gdy pojawi się sygnał, polecenia wydane przed ogrodzeniem są zapewne ukończone, ponieważ sterownik jądra lub blok sprzętowy wykonuje polecenia po kolei.

Platforma synchronizacji umożliwia wielu konsumentom lub producentom sygnalizowanie, że zakończyło działanie przy użyciu bufora, przekazując informacje o zależności za pomocą jednej funkcji . Ogrodzenia są wspierane przez deskryptor pliku i przekazywane z z jednego jądra systemu operacyjnego. Na przykład ogrodzenie może zawierać dwa Wartości sync_pt, które oznaczają występowanie 2 osobnych obrazów klienta czytanie bufora. Gdy ogrodzenie jest sygnalizowane, producenci obrazu wiedzą, przez konsumentów.

Ogrodzenia, takie jak wartości sync_pt, zaczynają być aktywne i zmieniają stan w zależności od tego, na stan ich punktów. Jeśli wszystkie wartości sync_pt zostaną zasygnalizowane, sync_fence otrzymuje sygnał. Jeśli sync_pt spadnie w stan błędu, cały element sync_fence zawiera stan błędu.

Członkostwa w domenie sync_fence nie można zmienić po tym, jak ogrodzenie jest Utworzono. Aby uzyskać więcej niż jeden punkt ogrodzenia, scalanie polega na tym, że do trzeciego ogrodzenia dodaje się punkty z dwóch różnych płotów. Jeśli jeden z tych punktów był sygnalizowany na początkowym ogrodzeniu, a drugi nie, Trzecie ogrodzenie też nie będzie zasygnalizowane.

Aby wdrożyć synchronizację jawną, podaj te informacje:

  • Podsystem jądra wykorzystujący platformę synchronizacji dla konkretnego sterownika sprzętowego. Kierowcy, którzy muszą mieć świadomość płotu, wszystko, co uzyskuje dostęp do narzędzia Hardware Composer lub się z nim komunikuje. Kluczowe pliki obejmują:
    • Implementacja podstawowa:
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • Dokumentacja na kernel/common/Documentation/sync.txt
    • Biblioteka do komunikacji z przestrzenią jądra w platform/system/core/libsync
  • Dostawca musi zapewnić odpowiednią synchronizację ogrodzenia jako parametry do validateDisplay() oraz presentDisplay() w funkcji HAL.
  • Dwa rozszerzenia GL związane z ogrodzeniami (EGL_ANDROID_native_fence_sync) i EGL_ANDROID_wait_sync) oraz obsługa ogrodzenia w grafice. sterownika.

Studium przypadku: wdrażanie sterowników dla reklam displayowych

Aby użyć interfejsu API obsługującego funkcję synchronizacji, opracować sterownik wyświetlacza z funkcją bufora wyświetlacza. Przed jeśli istniała platforma synchronizacji, ta funkcja otrzymałaby funkcję dma-buf obiektów, umieścić te bufory na wyświetlaczu i blokować je, gdy bufor jest widoczny. Dla: przykład:

/*
 * assumes buffer is ready to be displayed.  returns when buffer is no longer on
 * screen.
 */
void display_buffer(struct dma_buf *buffer);

W przypadku platformy synchronizacji funkcja display_buffer jest bardziej złożona. Po umieszczeniu bufora na wyświetlaczu zostaje on powiązany ogrodzeniem wskazującym, kiedy bufor będzie gotowy. Możesz dodać do kolejki i rozpocząć pracę po usunięciu płotu.

Dodawanie do kolejki i rozpoczynanie pracy po usunięciu płotu niczego nie blokuje. Natychmiast zwracasz własne ogrodzenie, co gwarantuje, że bufor zostanie wyłączony. Gdy umieszczasz bufory w kolejce, jądro wyświetla zależności w ramach platformy synchronizacji:

/*
 * displays buffer when fence is signaled.  returns immediately with a fence
 * that signals when buffer is no longer displayed.
 */
struct sync_fence* display_buffer(struct dma_buf *buffer, struct sync_fence
*fence);

Integracja z synchronizacją

Ta sekcja wyjaśnia, jak zintegrować platformę synchronizacji przestrzeni jądra z elementów platformy Androida i sterowników, które muszą się komunikować i otwierać przed sobą nawzajem. Obiekty przestrzeni jądra są reprezentowane jako deskryptory plików w przestrzeń użytkownika.

Konwencje integracji

Postępuj zgodnie z konwencjami interfejsu HAL Androida:

  • Jeśli interfejs API udostępnia deskryptor pliku odnoszący się do elementu sync_pt, sterownik dostawcy lub kod HAL korzystający z interfejsu API musi zamykać deskryptor pliku.
  • Jeśli sterownik dostawcy lub HAL przekazuje deskryptor pliku zawierający sync_pt do funkcji interfejsu API, sterownik dostawcy lub HAL nie mogą zamknij deskryptor pliku.
  • Aby nadal korzystać z deskryptora pliku ogrodzenia, sterownika dostawcy lub HAL musi zduplikować deskryptor.

Nazwa obiektu ogrodzenia zmienia się za każdym razem, gdy przechodzi przez BufferQueue. Obsługa jądra systemu operacyjnego sprawia, że ogrodzenie może mieć nazwane ciągi znaków dla nazw, platforma używa nazwy okna i indeksu bufora umieszczonego w kolejce do nazwy ogrodzenie, na przykład SurfaceView:0. Ten jest pomocne w debugowaniu w celu identyfikacji źródła zakleszczeń w postaci pojawiających się nazw w danych wyjściowych /d/sync i raportach o błędach.

Integracja ANativeWindow

ANativeWindow wykrywa ogrodzenie. dequeueBuffer, queueBuffer i cancelBuffer mają parametry ogrodzenia.

Integracja z platformą OpenGL ES

Integracja synchronizacji OpenGL ES korzysta z dwóch rozszerzeń EGL:

  • EGL_ANDROID_native_fence_sync umożliwia opakuj lub utwórz natywne deskryptory plików Android fence w EGLSyncKHR obiektów.
  • EGL_ANDROID_wait_sync zezwala na stoiska po stronie GPU a nie po stronie CPU, przez co GPU będzie czekać EGLSyncKHR. EGL_ANDROID_wait_sync rozszerzenie jest takie samo jak EGL_KHR_wait_sync.

Aby korzystać z tych rozszerzeń niezależnie, zaimplementuj tag EGL_ANDROID_native_fence_sync rozszerzenie i powiązane i obsługą jądra systemu operacyjnego. Następnie włącz: EGL_ANDROID_wait_sync w sterowniku. EGL_ANDROID_native_fence_sync rozszerzenie składa się z odrębnego natywnego obiektu ogrodzenia EGLSyncKHR typu. Dlatego rozszerzenia, które dotyczą obecnych EGLSyncKHR, typy obiektów nie muszą być stosowane do typu EGL_ANDROID_native_fence z obiektami, co pozwala uniknąć niechcianych interakcji.

Rozszerzenie EGL_ANDROID_native_fence_sync korzysta z odpowiedniego kodu natywnego atrybutu deskryptora pliku zabezpieczeń, który można ustawić tylko podczas tworzenia, nie mogą być wysyłane bezpośrednio z istniejącego obiektu synchronizacji. Ten atrybut można ustawić na jeden z dwóch trybów:

  • Prawidłowy deskryptor pliku ogrodzenia opakowuje istniejący kod natywny Deskryptor pliku Android fence w obiekcie EGLSyncKHR.
  • -1 tworzy natywny deskryptor pliku Android fence z tagu EGLSyncKHR obiekt.

Użyj wywołania funkcji DupNativeFenceFD(), aby wyodrębnić parametr Obiekt EGLSyncKHR z deskryptora natywnego pliku Android fence. Efekt jest taki sam jak w przypadku zapytania o atrybut set, ale jest zgodny z konwencja, zgodnie z którą odbiorca zamyka ogrodzenie (co oznacza duplikat, ). Na koniec zniszczenie obiektu EGLSyncKHR zostaje zamknięte z atrybutem ogrodzenia wewnętrznego.

Integracja z usługą Hardware Composer

Narzędzie Hardware Composer obsługuje trzy typy blokad synchronizacji:

  • Zdobywanie progów jest przekazywane wraz z buforami wejściowymi do połączenia setLayerBuffer i setClientTarget. Reprezentują one oczekujący zapis w buforze i muszą sygnalizować przed SurfaceFlinger lub HWC próbuje odczytać dane z powiązanego bufora w wykonać kompozycję.
  • Zwalnianie ogrodzenia jest pobierane po wywołaniu presentDisplay za pomocą wywołania getReleaseFences. Reprezentują one oczekujący odczyt z poprzedniego bufora w tej samej warstwie. O wyzwalanie sygnałów ogrodzenia, gdy HWC nie korzysta już z poprzedniego bufora bo bieżący bufor zastąpił poprzedni bufor na wyświetlaczu. Blokady wersji są przekazywane z powrotem do aplikacji razem z poprzednimi buforami, zostaną zastąpione w bieżącej kompozycji. Aplikacja musi poczekać do rozluźnić granicę przed zapisaniem w buforze nowej zawartości, które zostały im zwrócone.
  • Zwracane są ogrodzenia, po jednym na klatkę, w ramach parametru połączenie z numerem presentDisplay. Prezentuj ogrodzenia, pokazując, kiedy kompozycja tej klatki zakończy się lub na przemian, gdy nie jest już potrzebny wynik kompozycji poprzedniej klatki. Fizyczne wyświetla się, presentDisplay zwraca ogrodzenie obecne, gdy na ekranie zostanie wyświetlona bieżąca ramka. Po zwróceniu ogrodzenia bezpiecznie jest ponownie zapisać w buforze docelowym SurfaceFlinger, jeśli mają zastosowanie. W przypadku wyświetlaczy wirtualnych obecne ogrodzenia są zwracane, gdy są do odczytu z bufora wyjściowego.