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::lookupTonemapGainist eine CPU Implementierung des inlibtonemap_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ürRenderEngineeingefügt, die GPU-beschleunigte Kompositionskomponente für SurfaceFlinger. 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
float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)Signatur haben, wobeilinearRGBder Wert der absoluten Nits der RGB-Pixel im linearen Raum ist undxyzder in XYZ konvertierte Wert vonlinearRGBist. - 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äfixin_libtonemap_haben.
- Der Shader-String muss einen Einstiegspunkt mit der
SkSL-Uniforms generieren
Die Schnittstelle
ToneMapper::generateShaderSkSLUniforms()gibt Folgendes zurück, wenn eine Metadaten-structmit 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_displayMaxLuminanceundin_libtonemap_inputMaxLuminance. Diese Werte werden von Framework-Shadern verwendet, wenn die Eingabe inlibtonemapskaliert 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
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 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.