SDR 対応範囲への HDR 輝度のトーン マッピング

Android 13 では、トーン マッピング操作を定義する libtonemap というベンダー構成可能な静的ライブラリが導入されており、SurfaceFlinger のプロセスと Hardware Composer(HWC)の実装と共有されています。この機能を使用すると、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 の両方で、絶対非正規化線形空間の色値を受け取り、線形空間での入力色への乗算量を表す浮動小数点数を返します。

  • SkSL シェーダーを生成する

    インターフェース ToneMapper::generateTonemapGainShaderSkSL() は、送信元と送信先のデータ空間が与えられると、SkSL シェーダー文字列を返します。SkSL シェーダーは、SurfaceFlinger の GPU 加速合成コンポーネントである RenderEngine の Skia 実装に接続されています。また、シェーダーは libhwui にもプラグインされるため、TextureView の HDR から SDR へのトーン マッピングを効率的に実行できます。生成された文字列は、Skia が使用する他の SkSL シェーダーにインライン挿入されるため、シェーダーは次のルールに従う必要があります。

    • シェーダー文字列には、float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz) 署名を持つエントリ ポイントが必要です。ここで、linearRGB は線形空間の RGB ピクセルの絶対ニットの値で、xyzlinearRGB を XYZ に変換したものです。
    • シェーダー文字列で使用されるヘルパー メソッドには、フレームワーク シェーダーの定義が競合しないように、先頭に文字列 libtonemap_ を付ける必要があります。同様に、入力ユニフォームには in_libtonemap_ という接頭辞を付ける必要があります。
  • SkSL ユニフォームを生成する

    さまざまな HDR 標準と表示条件のメタデータを記述するメタデータ struct を指定すると、インターフェース ToneMapper::generateShaderSkSLUniforms() が次のものを返します。

    • SkSL シェーダーでバインドされたユニフォームのリスト。

    • ユニフォームの値 in_libtonemap_displayMaxLuminancein_libtonemap_inputMaxLuminance。これらの値は、入力を libtonemap にスケールし、必要に応じて出力を正規化するときに、フレームワーク シェーダーによって使用されます。

    現在、ユニフォームを生成するプロセスは、入力データと出力データ空間に依存しません。

カスタマイズ

libtonemap ライブラリのリファレンス実装は、許容可能な結果を生成します。ただし、GPU 合成で使用されるトーン マッピング アルゴリズムは、DPU 合成で使用されるトーン マッピング アルゴリズムとは異なる場合があるため、リファレンス実装を使用すると、回転アニメーションなどの一部のシナリオでちらつきが発生する可能性があります。カスタマイズによって、そのようなベンダー固有の画質の問題を解決できます。

OEM は libtonemap の実装をオーバーライドして、getToneMapper() で返される独自の ToneMapper サブクラスを定義することを強くおすすめします。実装をカスタマイズする場合、次のいずれかを行うことが期待されます。

  • libtonemap の実装を直接変更します。
  • 独自の静的ライブラリを定義して、ライブラリをスタンドアロンとしてコンパイルし、libtonemap ライブラリの .a ファイルをカスタム ライブラリから生成されたファイルに置き換えます。

ベンダーはカーネルコードを変更する必要はありませんが、適切な実装を行うために、複数のベンダーが DPU トーン マッピング アルゴリズムの詳細を伝える必要があります。

検証

次の手順に従って実装を検証します。

  1. HLG、HDR10、HDR10+、DolbyVision など、ディスプレイ システムがサポートする任意の HDR 規格の画面で HDR 動画を再生します。

  2. GPU 合成を切り替えて、ユーザーが知覚できるちらつきがないことを確認します。

    次の adb コマンドを使用して、GPU 合成を切り替えます。

    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 と異なる精度で動作する場合、量子化の違いによるわずかな色の変化が生じます。

これらの問題はそれぞれ、基盤となるハードウェアの相対的な精度の違いに起因しています。一般的な回避策は、精度の低いパスにディザリング ステップを含めることです。これにより、精度の違いが知覚されにくくなります。