Tone Mapping HDR-Helligkeit in einem SDR-kompatiblen Bereich

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-Implementierungen (HWC) geteilt wird. Mit dieser Funktion können OEMs ihre Tone-Mapping-Algorithmen für Displays definieren und zwischen dem Framework und den Anbietern teilen, wodurch Abweichungen beim Tone-Mapping reduziert werden.

Vor Android 13 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 Details zu Schnittstelle, Anpassung und Validierung der libtonemap-Bibliothek beschrieben.

Schnittstelle zur Tone-Mapping-Bibliothek

Die libtonemap Bibliothek enthält CPU-basierte Implementierungen und SkSL-Shader, die von SurfaceFlinger für die GPU-basierte Komposition und von HWC zum Generieren einer Tone-Mapping-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_LookupTonemapGain() definierten Shaders. Sie wird von Unit-Tests im Framework verwendet und kann von Partnern verwendet 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 RenderEngineeingefügt, die GPU-beschleunigte Kompositionskomponente für SurfaceFlinger. Der Shader wird auch in libhwui eingefügt, damit das Tone-Mapping von HDR zu SDR für TextureView effizient 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 float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz) Signatur haben, wobei linearRGB der Wert der absoluten Nits der RGB-Pixel im linearen Raum ist und xyz der in XYZ konvertierte Wert von linearRGB ist.
    • Allen Hilfsmethoden, die vom Shader-String verwendet werden, muss das Präfix libtonemap_ vorangestellt werden, damit es keine Konflikte mit Shader-Definitionen des Frameworks gibt. Ebenso müssen Eingabe-Uniforms das Präfix in_libtonemap_ haben.
  • 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 an einen SkSL-Shader gebunden sind.

    • 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.

    Derzeit ist der Prozess zum Generieren von Uniforms unabhängig vom Eingabe- und Ausgabedatenspace.

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 einen der folgenden Schritte 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 Präzision 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 die GPU-Komposition in ein 8-Bit-Format wie RGBA8888 schreiben muss, um Alpha zu unterstützen.

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

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