2025 年 3 月 27 日より、AOSP のビルドとコントリビューションには aosp-main
ではなく android-latest-release
を使用することをおすすめします。詳細については、AOSP の変更をご覧ください。
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 ピクセルの絶対ニットの値で、xyz
は linearRGB
を XYZ に変換したものです。
- シェーダー文字列で使用されるヘルパー メソッドには、フレームワーク シェーダーの定義が競合しないように、先頭に文字列
libtonemap_
を付ける必要があります。同様に、入力ユニフォームには in_libtonemap_
という接頭辞を付ける必要があります。
SkSL ユニフォームを生成する
さまざまな HDR 標準と表示条件のメタデータを記述するメタデータ struct
を指定すると、インターフェース ToneMapper::generateShaderSkSLUniforms()
が次のものを返します。
現在、ユニフォームを生成するプロセスは、入力データと出力データ空間に依存しません。
カスタマイズ
libtonemap
ライブラリのリファレンス実装は、許容可能な結果を生成します。ただし、GPU 合成で使用されるトーン マッピング アルゴリズムは、DPU 合成で使用されるトーン マッピング アルゴリズムとは異なる場合があるため、リファレンス実装を使用すると、回転アニメーションなどの一部のシナリオでちらつきが発生する可能性があります。カスタマイズによって、そのようなベンダー固有の画質の問題を解決できます。
OEM は libtonemap
の実装をオーバーライドして、getToneMapper()
で返される独自の ToneMapper
サブクラスを定義することを強くおすすめします。実装をカスタマイズする場合、次のいずれかを行うことが期待されます。
libtonemap
の実装を直接変更します。
- 独自の静的ライブラリを定義して、ライブラリをスタンドアロンとしてコンパイルし、
libtonemap
ライブラリの .a
ファイルをカスタム ライブラリから生成されたファイルに置き換えます。
ベンダーはカーネルコードを変更する必要はありませんが、適切な実装を行うために、複数のベンダーが DPU トーン マッピング アルゴリズムの詳細を伝える必要があります。
検証
次の手順に従って実装を検証します。
HLG、HDR10、HDR10+、DolbyVision など、ディスプレイ システムがサポートする任意の HDR 規格の画面で HDR 動画を再生します。
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 と異なる精度で動作する場合、量子化の違いによるわずかな色の変化が生じます。
これらの問題はそれぞれ、基盤となるハードウェアの相対的な精度の違いに起因しています。一般的な回避策は、精度の低いパスにディザリング ステップを含めることです。これにより、精度の違いが知覚されにくくなります。
このページのコンテンツやコードサンプルは、コンテンツ ライセンスに記載のライセンスに従います。Java および OpenJDK は Oracle および関連会社の商標または登録商標です。
最終更新日 2025-04-04 UTC。
[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["必要な情報がない","missingTheInformationINeed","thumb-down"],["複雑すぎる / 手順が多すぎる","tooComplicatedTooManySteps","thumb-down"],["最新ではない","outOfDate","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["サンプル / コードに問題がある","samplesCodeIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-04-04 UTC。"],[],[],null,["# Tone Mapping HDR Luminance to an SDR-compatible Range\n\nAndroid 13 introduces a vendor-configurable static\nlibrary called `libtonemap`, which defines tone mapping operations and is shared\nwith the SurfaceFlinger process and Hardware Composer (HWC) implementations.\nThis feature enables OEMs to define and share their display tone mapping\nalgorithms between the framework and vendors, lessening a mismatch in tone\nmapping.\n\nPrior to Android 13, display-specific tone mapping\noperations weren't shared between the HWC, SurfaceFlinger, and apps. Depending\non the rendering path, for HDR content, this led to mismatches in image quality,\nwhere the HDR content was tone mapped to an output space in different ways. This\nwas perceptible in scenarios such as screen rotation, where the composition\nstrategy changes between the GPU and the DPU, and in differences in rendering\nbehavior between TextureView and SurfaceView.\n\nThis page describes the interface, customization, and validation details of the\n`libtonemap` library.\n| **Note:** Android 16 introduces a new HDR tone mapping method called Look-up Table (LUT) for HDR video outputs instead of using `libtonemap`. LUTs primarily resolve the fragmentation issue with HDR video outputs, especially for HLG and PQ, across a diverse range of Android devices. See the AIDL API [`android.hardware.graphics.composer3.DisplayLuts`](https://cs.android.com/android/platform/superproject/+/android-latest-release:hardware/interfaces/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl) for more information.\n\nInterface to the tone mapping library\n-------------------------------------\n\nThe [`libtonemap`](https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android16-release/libs/tonemap/)\nlibrary contains CPU-backed implementations and SkSL shaders, which can be\nplugged in by SurfaceFlinger for GPU-backend composition and by the HWC for\ngenerating a tone mapping look-up table (LUT). The entry point to `libtonemap`\nis [`android::tonemap::getToneMapper()`](https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android16-release/libs/tonemap/tonemap.cpp#733), which returns an object that\nimplements the [`ToneMapper`](https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android16-release/libs/tonemap/include/tonemap/tonemap.h#86) interface.\n\nThe `ToneMapper` interface supports the following capabilities:\n\n- Generate a tone-mapping LUT\n\n The interface [`ToneMapper::lookupTonemapGain`](https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android16-release/libs/tonemap/include/tonemap/tonemap.h#147) is a CPU\n implementation of the shader defined in `libtonemap_LookupTonemapGain()`. This\n is used by unit tests in the framework, and can be used by partners for\n assistance with generating a tone-mapping LUT inside their color pipeline.\n\n `libtonemap_LookupTonemapGain()` takes in color values in absolute,\n unnormalized linear space, both in linear RGB and in XYZ, and returns a float\n describing how much to multiply the input colors in linear space.\n- Generate an SkSL shader\n\n The interface [`ToneMapper::generateTonemapGainShaderSkSL()`](https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android16-release/libs/tonemap/include/tonemap/tonemap.h#122) returns an\n SkSL shader string, given a source and destination dataspace. The SkSL shader is\n plugged into the Skia implementation for [`RenderEngine`](https://cs.android.com/android/platform/superproject/+/android-latest-release:frameworks/native/libs/renderengine/),\n the GPU-accelerated compositing component for SurfaceFlinger. The shader is also\n plugged into [`libhwui`](https://cs.android.com/android/platform/superproject/+/android-latest-release:frameworks/base/libs/hwui),\n so that HDR-to-SDR tone mapping can be performed efficiently for `TextureView`.\n Because the generated string is in-lined into other SkSL shaders used by Skia,\n the shader must adhere to the following rules:\n - The shader string must have an entry point with the `float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)` signature, where `linearRGB` is the value of the absolute nits of the RGB pixels in linear space and `xyz` is `linearRGB` converted into XYZ.\n - Any helper methods used by the shader string must be prefixed with the string `libtonemap_` so that framework shader definitions don't conflict. Similarly, input uniforms must be prefixed with `in_libtonemap_`.\n- Generate SkSL uniforms\n\n The interface [`ToneMapper::generateShaderSkSLUniforms()`](https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android16-release/libs/tonemap/include/tonemap/tonemap.h#136) returns the\n following, given a metadata `struct` describing metadata from different HDR\n standards and display conditions:\n - A list of uniforms that are bound by an SkSL shader.\n\n - The uniform values `in_libtonemap_displayMaxLuminance` and\n `in_libtonemap_inputMaxLuminance`. These values are used by framework shaders\n when scaling the input into `libtonemap`, and normalizing the output as\n applicable.\n\n Currently the process of generating uniforms is agnostic to the input and\n output dataspace.\n\n### Customization\n\nThe reference implementation of the [`libtonemap`](https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android16-release/libs/tonemap/) library produces acceptable results. However,\nbecause the tone mapping algorithm used by GPU composition can differ from that\nused by the DPU composition, using the reference implementation can cause\nflicker in some scenarios such as the rotation animation. Customization can\nresolve such vendor-specific image quality issues.\n\nOEMs are strongly encouraged to override the implementation of `libtonemap` to\ndefine their own `ToneMapper` subclass, which is returned by `getToneMapper()`.\nWhen customizing the implementation, partners are expected to do one of the\nfollowing:\n\n- Modify the implementation of `libtonemap` directly.\n- Define their own static library, compile the library as a standalone, and replace `libtonemap` library's `.a` file with the one generated from their custom library.\n\nVendors don't need to modify any kernel code, but multiple vendors must\ncommunicate details about the DPU tone-mapping algorithms for proper\nimplementation.\n\n### Validation\n\nFollow these steps to validate your implementation:\n\n1. Play HDR videos on screen of any HDR standards that your [display system supports](https://developer.android.com/reference/android/view/Display#getHdrCapabilities()),\n such as HLG, HDR10, HDR10+, or DolbyVision.\n\n2. Toggle GPU composition to ensure that there's no user perceptible flicker.\n\n Use the following `adb` command to toggle the GPU composition: \n\n adb shell service call SurfaceFlinger 1008 i32 \u003c0 to enable HWC composition,\n 1 to force GPU composition\u003e\n\n### Common issues\n\nThe following issues can occur with this implementation:\n\n- Banding is caused when the render target used by GPU composition is of lower\n precision than the typical value for HDR content. For instance, banding can\n occur when an HWC implementation supports opaque 10-bit formats for HDR such as\n RGBA1010102 or P010, but requires that GPU composition writes to an 8-bit format\n like RGBA8888 to support alpha.\n\n- A subtle color shift is caused by quantization differences if the DPU\n operates at a different precision than the GPU.\n\nEach of these issues is related to the relative precision differences of the\nunderlying hardware. A typical workaround is to ensure that there's a dithering\nstep in the lower precision paths, making any precision differences less human\nperceptible."]]