Android 13 では、トーン マッピング操作を定義し、SurfaceFlinger プロセスおよび Hardware Composer (HWC) 実装と共有されるlibtonemap
というベンダー構成可能な静的ライブラリが導入されています。この機能により、OEM はフレームワークとベンダーの間でディスプレイ トーン マッピング アルゴリズムを定義して共有できるため、トーン マッピングの不一致が少なくなります。
Android 13 より前は、ディスプレイ固有のトーン マッピング操作は、HWC、SurfaceFlinger、アプリの間で共有されていませんでした。レンダリング パスによっては、HDR コンテンツの場合、HDR コンテンツがさまざまな方法で出力空間にトーン マッピングされる場合に、画質の不一致が発生しました。これは、コンポジション戦略が GPU と DPU の間で変化する画面の回転などのシナリオや、TextureView と SurfaceView の間のレンダリング動作の違いで認識できました。
このページでは、 libtonemap
ライブラリのインターフェイス、カスタマイズ、および検証の詳細について説明します。
トーン マッピング ライブラリへのインターフェイス
libtonemap
ライブラリには、CPU を利用した実装と SkSL シェーダーが含まれており、これらは GPU バックエンド構成用の SurfaceFlinger と、トーン マッピング ルックアップ テーブル (LUT) を生成するための HWC によってプラグインできます。 libtonemap
へのエントリ ポイントはandroid::tonemap::getToneMapper()
で、 ToneMapper
インターフェースを実装するオブジェクトを返します。
ToneMapper
インターフェイスは、次の機能をサポートしています。
トーン マッピング LUT を生成する
インターフェイス
ToneMapper::lookupTonemapGain
は、libtonemap_LookupTonemapGain()
で定義されたシェーダーの CPU 実装です。これは、フレームワーク内の単体テストで使用され、パートナーがカラー パイプライン内でトーン マッピング LUT を生成するのを支援するために使用できます。libtonemap_LookupTonemapGain()
は、線形 RGB と XYZ の両方で、正規化されていない絶対線形空間でカラー値を受け取り、入力カラーを線形空間でどれだけ乗算するかを表す float を返します。SkSL シェーダーを生成する
インターフェイス
ToneMapper::generateTonemapGainShaderSkSL()
は、ソース データスペースとデスティネーション データスペースを指定すると、SkSL シェーダー文字列を返します。 SkSL シェーダーは、RenderEngine
の GPU 高速化合成コンポーネントである RenderEngine の Skia 実装にプラグインされています。シェーダーはlibhwui
にもプラグインされているため、 HDR から SDR へのトーン マッピングをTextureView
に対して効率的に実行できます。生成された文字列は Skia で使用される他の SkSL シェーダーにインライン化されるため、シェーダーは次の規則に従う必要があります。- シェーダ文字列には、
float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)
シグネチャを持つエントリ ポイントが必要です。ここで、linearRGB
は線形空間の RGB ピクセルの絶対ニットの値であり、xyz
は XYZ に変換されたlinearRGB
です。 - シェーダー文字列で使用されるヘルパー メソッドには、フレームワーク シェーダー定義が競合しないように、文字列
libtonemap_
をプレフィックスとして付ける必要があります。同様に、入力ユニフォームにはin_libtonemap_
をプレフィックスとして付ける必要があります。
- シェーダ文字列には、
SkSL ユニフォームの生成
インターフェイス
ToneMapper::generateShaderSkSLUniforms()
は、さまざまな HDR 規格と表示条件からのメタデータを記述するメタデータstruct
を指定すると、次を返します。SkSL シェーダーによってバインドされているユニフォームのリスト。
in_libtonemap_displayMaxLuminance
とin_libtonemap_inputMaxLuminance
の均一な値。これらの値は、入力をlibtonemap
にスケーリングし、必要に応じて出力を正規化するときに、フレームワーク シェーダーによって使用されます。
現在、ユニフォームを生成するプロセスは、入力および出力データスペースに依存しません。
カスタマイズ
libtonemap
ライブラリの参照実装では、許容できる結果が得られます。ただし、GPU コンポジションで使用されるトーン マッピング アルゴリズムは DPU コンポジションで使用されるものとは異なる可能性があるため、参照実装を使用すると、回転アニメーションなどの一部のシナリオでちらつきが発生する可能性があります。カスタマイズにより、このようなベンダー固有の画質の問題を解決できます。
OEM は、 libtonemap
の実装をオーバーライドして、 getToneMapper()
によって返される独自のToneMapper
サブクラスを定義することを強くお勧めします。実装をカスタマイズする場合、パートナーは次のいずれかを行うことが期待されます。
-
libtonemap
の実装を直接変更します。 - 独自のスタティック ライブラリを定義し、ライブラリをスタンドアロンとしてコンパイルし、
libtonemap
ライブラリの.a
ファイルをカスタム ライブラリから生成されたファイルに置き換えます。
ベンダーはカーネル コードを変更する必要はありませんが、適切に実装するために、複数のベンダーが DPU トーン マッピング アルゴリズムの詳細を伝える必要があります。
検証
次の手順に従って、実装を検証します。
HLG、HDR10、HDR10+、DolbyVision など、ディスプレイ システムがサポートする任意の HDR 標準の画面で HDR ビデオを再生します。
GPU コンポジションを切り替えて、ユーザーが知覚できるちらつきがないことを確認します。
GPU 構成を切り替えるには、次の
adb
コマンドを使用します。adb shell service call SurfaceFlinger 1008 i32 <0 to enable HWC composition, 1 to force GPU composition>
一般的な問題
この実装では、次の問題が発生する可能性があります。
バンディングは、GPU コンポジションで使用されるレンダー ターゲットの精度が HDR コンテンツの一般的な値よりも低い場合に発生します。たとえば、HWC 実装が RGBA1010102 や P010 などの HDR 用の不透明な 10 ビット フォーマットをサポートしているが、アルファをサポートするために GPU コンポジションが RGBA8888 のような 8 ビット フォーマットに書き込む必要がある場合、バンディングが発生する可能性があります。
DPU が GPU とは異なる精度で動作する場合、量子化の違いによって微妙なカラー シフトが発生します。
これらの問題はそれぞれ、基盤となるハードウェアの相対的な精度の違いに関連しています。典型的な回避策は、精度の低いパスにディザリング ステップがあることを確認し、精度の違いを人間が認識しにくくすることです。