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::lookupTonemapGainist eine CPU-Implementierung des inlibtonemap_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_LookupTonemapGainverwendet 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::generateTonemapGainShaderSkSLgibt einen SkSL-Shader-String zurück, der eine Quell- und eine Ziel-Datenspace enthält. Der SkSL-Shader wird in die Skia-Implementierung fürRenderEngine, die GPU-beschleunigte Kompositionskomponente für SurfaceFlinger eingefügt. Der Shader wird auch inlibhwuieingefügt, damit das Tone Mapping von HDR zu SDR fürTextureVieweffizient 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, wobeilinearRGBder Wert der absoluten Nits der RGB-Pixel im linearen Raum undxyzder in XYZ konvertierte Wert vonlinearRGBist. - 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äfixin_libtonemap_vorangestellt werden.
- Der Shader-String muss einen Einstiegspunkt mit der Signatur
SkSL-Uniforms generieren
Die Schnittstelle
ToneMapper::generateShaderSkSLUniformsgibt Folgendes zurück, wenn eine Metadaten-structmit 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_displayMaxLuminanceundin_libtonemap_inputMaxLuminance. Diese Werte werden von Framework-Shadern verwendet, wenn die Eingabe inlibtonemapskaliert 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
libtonemapdirekt ändern. - Eine eigene statische Bibliothek definieren, die Bibliothek als eigenständige Bibliothek kompilieren und die
.a-Datei derlibtonemap-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:
Spielen Sie HDR-Videos auf einem Bildschirm mit beliebigen HDR-Standards ab, die Ihr Displaysystem unterstützt, z. B. HLG, HDR10, HDR10+ oder DolbyVision.
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.