HDR-Leuchtdichte mit Tonmapping in einen SDR-kompatiblen Bereich umwandeln

In Android 13 wird eine vom Anbieter konfigurierbare statische Bibliothek namens libtonemap eingeführt, die Tone-Mapping-Vorgänge definiert und mit dem SurfaceFlinger-Prozess und den Hardware Composer (HWC)-Implementierungen gemeinsam genutzt wird. Mit dieser Funktion können OEMs ihre Tone-Mapping-Algorithmen für Displays definieren und zwischen dem Framework und den Anbietern freigeben, wodurch Abweichungen beim Tone Mapping reduziert werden.

In Android 12 und niedriger wurden displayspezifische Tone-Mapping-Vorgänge nicht zwischen HWC, SurfaceFlinger und Apps geteilt. Je nach Rendering-Pfad führte dies bei HDR-Inhalten zu Abweichungen bei der Bildqualität, da die HDR-Inhalte auf unterschiedliche Weise auf einen Ausgaberaum abgebildet wurden. Dies war in Szenarien wie der Bildschirmrotation spürbar, bei der sich die Kompositionsstrategie zwischen GPU und DPU ändert, und bei Unterschieden im Rendering-Verhalten zwischen TextureView und SurfaceView.

Auf dieser Seite werden die Schnittstelle, die Anpassung und die Validierungsdetails der libtonemap-Bibliothek beschrieben.

Schnittstelle zur Tone-Mapping-Bibliothek

Die libtonemap Bibliothek enthält CPU-gestützte Implementierungen und SkSL-Shader, die von SurfaceFlinger für die GPU-Backend-Komposition und vom HWC zum Generieren einer Tone-Mapping-Look-up-Tabelle (LUT) verwendet werden können. Der Einstiegspunkt für libtonemap ist android::tonemap::getToneMapper, das ein Objekt zurückgibt, das die ToneMapper Schnittstelle implementiert.

Die ToneMapper-Schnittstelle unterstützt die folgenden Funktionen:

  • Tone-Mapping-LUT generieren

    Die Schnittstelle ToneMapper::lookupTonemapGain ist eine CPU-Implementierung des in libtonemap_LookupTonemapGaindefinierten Shaders. Sie wird von Unit-Tests im Framework verwendet und kann von Partnern genutzt werden, um eine Tone-Mapping-LUT in ihrer Farbpipeline zu generieren.

    libtonemap_LookupTonemapGain verwendet Farbwerte im absoluten, nicht normalisierten linearen Raum, sowohl in linearem RGB als auch in XYZ, und gibt einen Float-Wert zurück, der angibt, um wie viel die Eingabefarben im linearen Raum multipliziert werden müssen.

  • SkSL-Shader generieren

    Die Schnittstelle ToneMapper::generateTonemapGainShaderSkSL gibt einen SkSL-Shader-String zurück, der eine Quell- und eine Ziel-Datenspace enthält. Der SkSL-Shader wird in die Skia-Implementierung für RenderEngine, die GPU-beschleunigte Kompositionskomponente für SurfaceFlinger eingefügt. Der Shader wird auch in libhwuieingefügt, damit das Tone Mapping von HDR zu SDR für TextureVieweffizient durchgeführt werden kann. Da der generierte String in andere SkSL-Shader eingefügt wird, die von Skia verwendet werden, muss der Shader die folgenden Regeln einhalten:

    • Der Shader-String muss einen Einstiegspunkt mit der Signatur float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz) haben, wobei linearRGB der Wert der absoluten Nits der RGB-Pixel im linearen Raum und xyz der in XYZ konvertierte Wert von linearRGB ist.
    • Allen Hilfsmethoden, die vom Shader-String verwendet werden, muss der String libtonemap_ vorangestellt werden, damit es keine Konflikte mit Shader-Definitionen des Frameworks gibt. Ebenso muss allen Eingabe-Uniforms das Präfix in_libtonemap_ vorangestellt werden.
  • SkSL-Uniforms generieren

    Die Schnittstelle ToneMapper::generateShaderSkSLUniforms gibt Folgendes zurück, wenn eine Metadaten-struct mit Metadaten aus verschiedenen HDR-Standards und Displaybedingungen angegeben wird:

    • Eine Liste von Uniforms, die von einem SkSL-Shader gebunden werden.

    • Die Uniform-Werte in_libtonemap_displayMaxLuminance und in_libtonemap_inputMaxLuminance. Diese Werte werden von Framework-Shadern verwendet, wenn die Eingabe in libtonemap skaliert und die Ausgabe gegebenenfalls normalisiert wird.

      Der Prozess zum Generieren von Uniforms ist unabhängig vom Eingabe- und Ausgabedatenraum.

Anpassung

Die Referenzimplementierung der libtonemap Bibliothek liefert akzeptable Ergebnisse. Da sich der von der GPU-Komposition verwendete Tone-Mapping-Algorithmus jedoch von dem der DPU-Komposition unterscheiden kann, kann die Verwendung der Referenzimplementierung in einigen Szenarien wie der Rotationsanimation zu Flimmern führen. Durch die Anpassung können solche anbieterspezifischen Probleme mit der Bildqualität behoben werden.

OEMs wird dringend empfohlen, die Implementierung von libtonemap zu überschreiben, um eine eigene ToneMapper Unterklasse zu definieren, die von getToneMapper zurückgegeben wird. Bei der Anpassung der Implementierung müssen Partner eine der folgenden Aktionen ausführen:

  • Die Implementierung von libtonemap direkt ändern.
  • Eine eigene statische Bibliothek definieren, die Bibliothek als eigenständige Bibliothek kompilieren und die .a-Datei der libtonemap-Bibliothek durch die aus der benutzerdefinierten Bibliothek generierte Datei ersetzen.

Anbieter müssen keinen Kernel-Code ändern. Mehrere Anbieter müssen jedoch Details zu den DPU-Tone-Mapping-Algorithmen für die korrekte Implementierung austauschen.

Validierung

So validieren Sie Ihre Implementierung:

  1. Spielen Sie HDR-Videos auf einem Bildschirm mit beliebigen HDR-Standards ab, die Ihr Displaysystem unterstützt, z. B. HLG, HDR10, HDR10+ oder DolbyVision.

  2. Aktivieren und deaktivieren Sie die GPU-Komposition, um sicherzustellen, dass kein für den Nutzer sichtbares Flimmern auftritt.

    Verwenden Sie den folgenden adb-Befehl, um die GPU-Komposition zu aktivieren oder zu deaktivieren:

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

Häufige Probleme

Bei dieser Implementierung können die folgenden Probleme auftreten:

  • Banding tritt auf, wenn das von der GPU-Komposition verwendete Rendering-Ziel eine geringere Genauigkeit als der typische Wert für HDR-Inhalte hat. Banding kann beispielsweise auftreten, wenn eine HWC-Implementierung undurchsichtige 10-Bit-Formate für HDR wie RGBA1010102 oder P010 unterstützt, aber erfordert, dass die GPU-Komposition in ein 8-Bit-Format wie RGBA8888 schreibt, um Alpha zu unterstützen.

  • Eine subtile Farbverschiebung wird durch Quantisierungsunterschiede verursacht, wenn die DPU mit einer anderen Genauigkeit als die GPU arbeitet.

Jedes dieser Probleme hängt mit den relativen Unterschieden in der Genauigkeit der zugrunde liegenden Hardware zusammen. Eine typische Problemumgehung besteht darin, sicherzustellen, dass in den Pfaden mit geringerer Genauigkeit ein Dithering-Schritt erfolgt, wodurch Unterschiede in der Genauigkeit für den Menschen weniger wahrnehmbar sind.