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
的 Skia 实现中,RenderEngine
是 SurfaceFlinger 的 GPU 加速合成组件。该着色器也插入到libhwui
中,以便可以为TextureView
有效地执行 HDR 到 SDR 的色调映射。由于生成的字符串被内联到 Skia 使用的其他 SkSL 着色器中,因此该着色器必须遵守以下规则- 着色器字符串必须具有一个入口点,其签名为
float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)
,其中linearRGB
是线性空间中 RGB 像素的绝对尼特值,xyz
是转换为 XYZ 的linearRGB
。 - 着色器字符串使用的任何辅助方法都必须以字符串
libtonemap_
为前缀,以避免框架着色器定义冲突。同样,输入 uniform 变量必须以in_libtonemap_
为前缀。
- 着色器字符串必须具有一个入口点,其签名为
生成 SkSL uniform 变量
接口
ToneMapper::generateShaderSkSLUniforms()
返回以下内容,给定一个描述来自不同 HDR 标准和显示条件的元数据struct
SkSL 着色器绑定的 uniform 变量列表。
uniform 变量值
in_libtonemap_displayMaxLuminance
和in_libtonemap_inputMaxLuminance
。当将输入缩放到libtonemap
中以及在适用时对输出进行归一化时,框架着色器会使用这些值。
目前,生成 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>
常见问题
以下问题可能会在此实现中发生
当 GPU 合成使用的渲染目标精度低于 HDR 内容的典型值时,会导致条带化。例如,当 HWC 实现支持 HDR 的不透明 10 位格式(例如 RGBA1010102 或 P010),但要求 GPU 合成写入 8 位格式(如 RGBA8888)以支持 alpha 时,可能会发生条带化。
如果 DPU 以与 GPU 不同的精度运行,则量化差异会导致细微的颜色偏移。
这些问题都与底层硬件的相对精度差异有关。典型的解决方法是在较低精度路径中确保存在抖动步骤,从而使任何精度差异都不太容易被人察觉。