自 2025 年 3 月 27 日起,我们建议您使用 android-latest-release
而非 aosp-main
构建 AOSP 并为其做出贡献。如需了解详情,请参阅 AOSP 的变更。
将 HDR 亮度映射到 SDR 兼容的范围
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
Android 13 中引入了一个名为 libtonemap
的供应商可配置静态库,用于定义色调映射操作,并与 SurfaceFlinger 进程和硬件混合渲染器 (HWC) 实现共享。借助此功能,原始设备制造商 (OEM) 可以在框架和供应商之间定义和共享其屏幕色调映射算法,从而减少色调映射中的不匹配问题。
在 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 着色器会插入 RenderEngine
(适用于 SurfaceFlinger 的 GPU 加速合成组件)的 Skia 实现中。着色器也会插入 libhwui
,以便针对 TextureView
高效地执行从 HDR 到 SDR 的色调映射。由于生成的字符串内嵌在 Skia 使用的其他 SkSL 着色器中,因此着色器必须遵循以下规则:
- 着色器字符串必须具有带
float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)
签名的入口点,其中 linearRGB
是线性空间中 RGB 像素的绝对尼特值,xyz
是已转换为 XYZ 的 linearRGB
。
- 着色器字符串使用的任何辅助方法都必须以字符串
libtonemap_
为前缀,以免框架着色器定义发生冲突。同样,输入 uniform 必须带有 in_libtonemap_
前缀。
生成 SkSL uniform
鉴于描述不同 HDR 标准和显示条件的元数据的元数据 struct
,接口 ToneMapper::generateShaderSkSLUniforms()
会返回以下内容:
目前,生成 uniform 的过程与输入和输出数据空间无关。
自定义
libtonemap
库的参考实现会生成可接受的结果。不过,由于 GPU 合成使用的色调映射算法可能与 DPU 合成使用的色调映射算法不同,因此在某些场景(例如旋转动画)中使用参考实现可能会导致闪烁。自定义可以解决此类供应商特有的图片质量问题。
强烈建议 OEM 替换 libtonemap
的实现,以定义自己的 ToneMapper
子类(由 getToneMapper()
返回)。自定义实现时,合作伙伴应执行以下操作之一:
- 直接修改
libtonemap
的实现。
- 定义自己的静态库,将该库编译为独立的库,并将
libtonemap
库的 .a
文件替换为通过其自定义库生成的文件。
供应商无需修改任何内核代码,但多个供应商必须传达有关 DPU 色调映射算法的详细信息,才能正确实现。
验证
请按照以下步骤验证您的实现:
在符合显示系统支持的任何 HDR 标准(例如 HLG、HDR10、HDR10+ 或 DolbyVision)的屏幕上播放 HDR 视频。
切换 GPU 合成,以确保用户不会察觉到闪烁。
使用以下 adb
命令切换 GPU 合成:
adb shell service call SurfaceFlinger 1008 i32 <0 to enable HWC composition,
1 to force GPU composition>
常见问题
此实现可能会出现以下问题:
上述每个问题都与底层硬件的相对精度差异有关。典型的解决方法是确保精度较低的路径中存在一个抖动步骤,使所有精度差异都不易察觉。
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-04-04。
[null,null,["最后更新时间 (UTC):2025-04-04。"],[],[],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."]]