自 2025 年 3 月 27 日起,我們建議您使用 android-latest-release
而非 aosp-main
建構及貢獻 AOSP。詳情請參閱「Android 開放原始碼計畫變更」。
映射 HDR 亮度與 SDR 相容範圍
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
Android 13 導入名為 libtonemap
的供應商可設定靜態程式庫,定義色調對應作業,並與 SurfaceFlinger 程序和硬體合成器 (HWC) 實作項目共用。這項功能可讓原始設備製造商在架構和供應商之間定義及共用顯示色調對應演算法,減少色調對應不符的情況。
在 Android 13 之前,HWC、SurfaceFlinger 和應用程式之間不會共用顯示器專屬的色調對應作業。視算繪路徑而定,這會導致 HDR 內容的影像品質不一致,因為 HDR 內容會以不同方式色調對應至輸出空間。在螢幕旋轉等情況下,這種差異會很明顯,因為組合策略會在 GPU 和 DPU 之間變更,而且 TextureView 和 SurfaceView 之間的算繪行為也會有所不同。
本頁說明 libtonemap
程式庫的介面、自訂項目和驗證詳細資料。
色調對應程式庫的介面
libtonemap
程式庫包含 CPU 支援的實作項目和 SkSL 著色器,SurfaceFlinger 可插入這些項目,用於 GPU 後端合成,HWC 則可插入這些項目,用於產生色調對應查閱表 (LUT)。libtonemap
的進入點是 android::tonemap::getToneMapper()
,會傳回實作 ToneMapper
介面的物件。
ToneMapper
介面支援下列功能:
產生色調對應 LUT
介面 ToneMapper::lookupTonemapGain
是 libtonemap_LookupTonemapGain()
中定義的著色器 CPU 實作項目。架構中的單元測試會使用這個方法,合作夥伴也可以使用這個方法,在色彩管道中產生色調對應 LUT。
libtonemap_LookupTonemapGain()
會接收絕對、未標準化的線性空間中的顏色值 (線性 RGB 和 XYZ),並傳回浮點數,說明線性空間中輸入顏色要乘上的值。
生成 SkSL 著色器
介面 ToneMapper::generateTonemapGainShaderSkSL()
會傳回 SkSL 著色器字串,並提供來源和目的地資料空間。SkSL 著色器會插入 Skia 實作項目,用於 RenderEngine
,這是 SurfaceFlinger 的 GPU 加速合成元件。著色器也會插入 libhwui
,以便有效率地對 TextureView
執行 HDR 到 SDR 的色調對應。由於產生的字串會內嵌至 Skia 使用的其他 SkSL 著色器,因此著色器必須遵守下列規則:
- 著色器字串必須具有
float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)
簽章的進入點,其中 linearRGB
是線性空間中 RGB 像素的絕對亮度值,而 xyz
是轉換為 XYZ 的 linearRGB
。
- 著色器字串使用的任何輔助方法都必須加上
libtonemap_
字串前置字元,以免架構著色器定義發生衝突。同樣地,輸入制服必須以 in_libtonemap_
為前置字串。
產生 SkSL 統一資源
介面 ToneMapper::generateShaderSkSLUniforms()
會傳回下列項目,並提供中繼資料 struct
,說明不同 HDR 標準和顯示條件的中繼資料:
目前,產生制服的程序與輸入和輸出資料空間無關。
自訂
libtonemap
程式庫的參考實作會產生可接受的結果。不過,由於 GPU 合成使用的色調對應演算法可能與 DPU 合成使用的演算法不同,因此在某些情況下 (例如旋轉動畫),使用參考實作可能會導致閃爍。自訂功能可解決這類供應商專屬的影像品質問題。
強烈建議 OEM 覆寫 libtonemap
的實作項目,定義自己的 ToneMapper
子類別,該子類別會由 getToneMapper()
傳回。自訂實作項目時,合作夥伴應執行下列其中一項操作:
- 直接修改
libtonemap
的實作方式。
- 自行定義靜態程式庫、將程式庫編譯為獨立程式庫,然後將
libtonemap
程式庫的 .a
檔案替換為從自訂程式庫產生的檔案。
供應商不需要修改任何核心程式碼,但多個供應商必須溝通 DPU 色調對應演算法的詳細資料,才能正確實作。
驗證
請按照下列步驟驗證導入作業:
在顯示系統支援的任何 HDR 標準螢幕上播放 HDR 影片,例如 HLG、HDR10、HDR10+ 或 DolbyVision。
切換 GPU 合成,確保使用者不會察覺閃爍。
使用下列 adb
指令切換 GPU 合成:
adb shell service call SurfaceFlinger 1008 i32 <0 to enable HWC composition,
1 to force GPU composition>
常見問題
這種做法可能會導致下列問題:
這些問題都與基礎硬體的相對精確度差異有關。常見的解決方法是確保低精確度路徑中有抖動步驟,讓任何精確度差異較不易被人察覺。
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-07-27 (世界標準時間)。
[[["容易理解","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-07-27 (世界標準時間)。"],[],[],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."]]