Mapowanie tonów w zakresie luminancji HDR do zakresu zgodnego z SDR

Android 13 wprowadza statyczną bibliotekę konfigurowaną przez dostawcę o nazwie libtonemap, która definiuje operacje mapowania odcieni i jest udostępniana procesowi SurfaceFlinger oraz implementacjom kompozytora sprzętowego (HWC). Ta funkcja umożliwia producentom OEM definiowanie i udostępnianie algorytmów mapowania odcieni wyświetlacza między platformą a dostawcami, co zmniejsza rozbieżności w mapowaniu odcieni.

Przed Androidem 13 operacje mapowania odcieni specyficzne dla wyświetlacza nie były udostępniane między HWC, SurfaceFlinger i aplikacjami. W zależności od ścieżki renderowania w przypadku treści HDR powodowało to rozbieżności w jakości obrazu, ponieważ treści HDR były mapowane tonalnie do przestrzeni wyjściowej na różne sposoby. Było to widoczne w scenariuszach takich jak obracanie ekranu, w których strategia kompozycji zmienia się między procesorem graficznym a procesorem DPU, oraz w różnicach w zachowaniu renderowania między elementami TextureView i SurfaceView.

Na tej stronie znajdziesz opis interfejsu, dostosowywania i szczegółów weryfikacji biblioteki libtonemap.

.

Interfejs biblioteki mapowania tonalnego

Biblioteka libtonemap zawiera implementacje oparte na procesorze i shadery SkSL, które mogą być podłączane przez SurfaceFlinger do kompozycji opartej na GPU i przez HWC do generowania tabeli LUT mapowania odcieni. Punktem wejścia do libtonemap jest android::tonemap::getToneMapper(), który zwraca obiekt implementujący interfejs ToneMapper.

Interfejs ToneMapper obsługuje te funkcje:

  • Generowanie tabeli LUT mapowania tonalnego

    Interfejs ToneMapper::lookupTonemapGain to implementacja procesora shaderów zdefiniowanego w libtonemap_LookupTonemapGain(). Jest on używany przez testy jednostkowe w ramach platformy i może być używany przez partnerów do generowania tabeli LUT mapowania odcieni w ich potoku kolorów.

    libtonemap_LookupTonemapGain() przyjmuje wartości kolorów w bezwzględnej, nieznormalizowanej przestrzeni liniowej, zarówno w liniowej przestrzeni RGB, jak i XYZ, i zwraca liczbę zmiennoprzecinkową opisującą, przez jaką wartość należy pomnożyć kolory wejściowe w przestrzeni liniowej.

  • Generowanie shadera SkSL

    Interfejs ToneMapper::generateTonemapGainShaderSkSL() zwraca ciąg cieniowania SkSL na podstawie źródłowej i docelowej przestrzeni danych. Shader SkSL jest podłączony do implementacji Skia dla RenderEngine, komponentu komponowania z akceleracją GPU dla SurfaceFlingera. Shader jest też podłączony do libhwui, dzięki czemu można wydajnie przeprowadzać mapowanie tonów z HDR na SDR w przypadku TextureView. Wygenerowany ciąg znaków jest wstawiany do innych shaderów SkSL używanych przez Skia, dlatego shader musi być zgodny z tymi regułami:

    • Ciąg cieniowania musi mieć punkt wejścia o sygnaturze float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz), gdzie linearRGB to wartość bezwzględnych nitów pikseli RGB w przestrzeni liniowej, a xyz to wartość linearRGB przekonwertowana na XYZ.
    • Wszystkie metody pomocnicze używane przez ciąg cieniowania muszą mieć prefiks libtonemap_, aby definicje cieniowania platformy nie powodowały konfliktów. Podobnie zmienne uniform w shaderze wejściowym muszą mieć przedrostek in_libtonemap_.
  • Generowanie zmiennych uniform w języku SkSL

    Interfejs ToneMapper::generateShaderSkSLUniforms() zwraca te informacje, gdy otrzyma metadane struct opisujące metadane z różnych standardów HDR i warunków wyświetlania:

    • Lista zmiennych uniform, które są powiązane z shaderem SkSL.

    • Wartości jednolite in_libtonemap_displayMaxLuminancein_libtonemap_inputMaxLuminance. Te wartości są używane przez shadery platformy podczas skalowania danych wejściowych do zakresu libtonemap i normalizowania danych wyjściowych w odpowiedni sposób.

    Obecnie proces generowania jednolitych danych nie zależy od przestrzeni danych wejściowych ani wyjściowych.

Dostosowywanie

Implementacja referencyjna biblioteki libtonemap generuje akceptowalne wyniki. Jednak algorytm mapowania tonów używany przez kompozycję GPU może się różnić od algorytmu używanego przez kompozycję DPU, więc w niektórych przypadkach, np. podczas animacji obrotu, użycie implementacji referencyjnej może powodować migotanie. Dostosowanie może rozwiązać takie problemy z jakością obrazu, które są specyficzne dla danego dostawcy.

Zdecydowanie zalecamy producentom OEM zastąpienie implementacji libtonemap, aby zdefiniować własną podklasę ToneMapper, która jest zwracana przez getToneMapper(). Dostosowując wdrożenie, partnerzy powinni wykonać jedną z tych czynności:

  • bezpośrednio modyfikować wdrożenie libtonemap,
  • zdefiniować własną bibliotekę statyczną, skompilować ją jako samodzielną i zastąpić plik libtonemap biblioteki .a plikiem wygenerowanym z własnej biblioteki.

Dostawcy nie muszą modyfikować żadnego kodu jądra, ale wielu dostawców musi przekazywać szczegóły dotyczące algorytmów mapowania tonów DPU, aby zapewnić prawidłowe wdrożenie.

Weryfikacja

Aby sprawdzić wdrożenie:

  1. Odtwarzaj filmy HDR na ekranie w dowolnym standardzie HDR, który obsługuje Twój system wyświetlania, np. HLG, HDR10, HDR10+ lub DolbyVision.

  2. Przełącz kompozycję GPU, aby upewnić się, że nie występuje migotanie widoczne dla użytkownika.

    Aby przełączyć kompozycję GPU, użyj tego polecenia adb:

    adb shell service call SurfaceFlinger 1008 i32 <0 to enable HWC composition,
    1 to force GPU composition>
    
    

Typowe problemy

W przypadku tej implementacji mogą wystąpić te problemy:

  • Paski powstają, gdy docelowy element renderowania używany przez kompozycję GPU ma niższą precyzję niż typowa wartość dla treści HDR. Na przykład pasy mogą pojawiać się, gdy implementacja HWC obsługuje nieprzezroczyste 10-bitowe formaty HDR, takie jak RGBA1010102 lub P010, ale wymaga, aby kompozycja GPU zapisywała dane w 8-bitowym formacie, takim jak RGBA8888, w celu obsługi kanału alfa.

  • Subtelna zmiana koloru jest spowodowana różnicami w kwantyzacji, jeśli DPU działa z inną precyzją niż GPU.

Każdy z tych problemów jest związany z różnicami w precyzji względnej sprzętu. Typowym obejściem jest zapewnienie, że na ścieżkach o niższej precyzji występuje etap ditheringu, dzięki czemu wszelkie różnice w precyzji są mniej zauważalne dla człowieka.