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 标准和显示条件的元数据structSkSL 着色器绑定的 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 不同的精度运行,则量化差异会导致细微的颜色偏移。
这些问题都与底层硬件的相对精度差异有关。典型的解决方法是在较低精度路径中确保存在抖动步骤,从而使任何精度差异都不太容易被人察觉。