blend后颜色异常问题(glBlendFunc & glBlendFuncSeparate)
1. 问题描述
应用中显示投屏小窗部分的颜色值与预期不一致,预期为纯白色 [0xFF],而实际显示偏黑 [0xDE]
相同渲染合成逻辑在X86平台测试显示为正常色彩 [0xFF]
各个layer叠加顺序如下(简化层级可以说明问题即可):
- 应用使用GPU渲染各个对象后进行blending合成输出到Overlay 01:
- media
- bottom
- 投屏画面输出到Overlay 02;
PS:Overlay 是指Display Process Unit中硬件图层,由硬件进行叠加混合,提高效率;
2. 问题分析
- 按照使用blending 公式计算理论值,是否与显示颜色一致,排除应用处理异常问题;
- 由于有做对比实验,同样render & blend 过程在PC上无问题,则排查差异部分:
- GPU 差别,对于实现库是否有差异?
- 显示模块的差异
- 异常机器使用DRM架构,而PC机不是;
- 异常机器有使用硬件Overlay ,而对比机器没有;
根据上述过程,由于GPU和DRM均为标准库,出问题概率较小,则先排查另外两项:
2.1 计算确认GPU输出理论值是否一致
-
根据应用使用的两张图片的RGB值计算数据如下(使用glBlendFunc接口):
Bottom(0xFF, 0xFF, 0xFF, 0xFF)和media(0xD9, 0xFF, 0xFF, 0xFF)合成- RGB:(0xD9 * 0xFF + 0xFF * (0xFF - 0xD9))/ 0xFF = 0xFF
- A:(0xD9 * 0xD9 + 0xFF * (0xFF - 0xD9))/ 0xFF = 0xDE
从这两张图片的计算结果来看,应用经过GPU渲染合成后输出的RGB值应该为0xFF,即纯白色;
-
dump GPU 吐出的buffer数据,查看其ARGB值与上述计算出来的数据一致
则根据上述两步分析可以得到如下结论:
- 应用使用render和blend的逻辑输出的RGB值符合预期;
- GPU 处理后输出值与预期相符,则说明GPU 底层处理符合标准(即这部分怀疑的优先级一般都放低一些)
- 问题出现在显示后端,由于DRM也属于标准框架内容,首要怀疑overlay合成部分
- 注意到上述计算出来的A 为0xDE,则需要确认Overlay的合成是如何做的?
PS:计算公式详见第四小节blend使用接口介绍;
2.2 排查Overlay合成
基于上述实验分析,需要确认硬件Overlay是如何做的硬件合成操作:
- 与designer沟通确认,硬件中为固定算法进行合成
- 默认与glBlendFunc参数设置为GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA时相符;
- 相当于合成 ARGB 背景色(0xFF, 0x00, 0x00, 0x00)和 ARGB GPU Output (0xDE, 0xFF, 0xFF, 0xFF)
- RGB:(0xFF * 0xDE + 0x00 * (0xFF - 0xDE))/ 0xFF = 0xDE
- A:(0xDE * 0xDE + 0xFF * (0xFF - 0xDE))/ 0xFF = 0xE2
根据上述公式计算出来最终要显示的RGB颜色为0xDE 并非0xFF,与实际上屏颜色相符;
则问题已经明确,应用端没有考虑到平台DPU后端仍会做一次硬件的blend合成,输出A颜色值并非为0xFF,导致问题出现
3. 问题处理方案
基于上述分析,问题原因已经明确:
-
平台中进行了两次blend计算
- 由于blend公式特性决定,其所有图层必须按照一定顺序进行叠加计算否则会计算异常,比如上述过程应该按照如下顺序:
- ARGB 背景色(0xFF, 0x00, 0x00, 0x00)和 bottom(0xFF, 0xFF, 0xFF, 0xFF)
RGB:(0xFF * 0xFF + 0x00 * (0xFF - 0xFF))/ 0xFF = 0xFF
A:(0xFF * 0xFF + 0xFF * (0xFF - 0xFF))/ 0xFF = 0xFF - ARGB Output (0xFF, 0xFF, 0xFF, 0xFF) 和 media(0xD9, 0xFF, 0xFF, 0xFF)
RGB:(0xFF * 0xD9 + 0xFF * (0xFF - 0xD9))/ 0xFF = 0xFF
A:(0xD9 * 0xD9 + 0xFF * (0xFF - 0xD9))/ 0xFF = 0xDE
按照顺序叠加出来的RGB是符合预期输出的
-
存在上述进行两次blend过程的情况,则需要保证第一次blend输出后的A分量符合我们预期要求,针对此case,我们要求 GPU Output A为0xFF,openGL中提供接口进行单独计算:
void glBlendFuncSeparate( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); //与上述差别在于将rgb与a分量独立使用不同的计算公式
使用上述公式计算bottom和media合成:
Bottom(0xFF, 0xFF, 0xFF, 0xFF)和media(0xD9, 0xFF, 0xFF, 0xFF)合成
RGB:(0xD9 * 0xFF + 0xFF * (0xFF - 0xD9))/ 0xFF = 0xFF
A:(0xD9 * (0xFF - 0xFF) + 0xFF * 0xFF)/ 0xFF = 0xFF使用此接口独立计算即可解决问题
PS:相关blend接口和参数介绍详见第四小节
4. blend 使用接口介绍
4.1 概念说明
blend 即使用输入(Src)RGBA分量数据与帧缓冲区中已有RGBA值(Dst)进行计算来得到最终输出RGBA值得过程;
- 实现角度为通过一定公式来计算RGBA的值;
- 理解角度为根据透明度将两层layer的数据叠加到一起显示;
名词 | 说明 |
---|---|
Src | 输入的layer数据,由于blend计算过程为从下往上,则src就是相对位置在上方的layer |
Dst | 帧缓冲区中已有的layer数据,两层合成是相对位置在下方的layer |
4.2 接口说明
-
glBlendFunc
void glBlendFunc(GLenum sfactor,GLenum dfactor);
名词 说明 sfactor 源因子,即src分量的计算公式 dfactor 目标因子,dst分量的计算公式 -
glBlendFuncSeparate
void glBlendFuncSeparate( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
相较于glBlendFunc将rgb与a分量的计算因子拆分了出来
4.3 参数说明
合系数枚举值 | fR fG fB | fA |
---|---|---|
GL_ZERO | 0,0,0 | 0 |
GL_ONE | 1,1,1 | 1 |
GL_SRC_COLOR | Rs,Gs,Bs | As |
GL_ONE_MINUS_SRC_COLOR | 1-Rs,1-Gs,1-Bs | 1-As |
GL_SRC_ALPHA | As,As,As | As |
GL_ONE_MINUS_SRC_ALPHA | 1-As,1-As,1-As | 1-As |
GL_DST_COLOR | Rd,Gd,Bd | Ad |
GL_ONE_MINUS_DST_COLOR | 1-Rd,1-Gd,1-Bd | 1-Ad |
GL_DST_ALPHA | Ad,Ad,Ad | Ad |
GL_ONE_MINUS_DST_ALPHA | 1-Ad,1-Ad,1-Ad | 1-Ad |
GL_CONSTANT_COLOR | Rc,Gc,Bc | Ac |
GL_ONE_MINUS_CONSTANT_COLOR | 1-Rc,1-Gc,1-Bc | 1-Ac |
GL_CONSTANT_ALPHA | Ac,Ac,Ac | Ac |
GL_ONE_MINUS_CONSTANT_ALPHA | 1-Ac,1-Ac,1-Ac | 1-Ac |
GL_SRC_ALPHA_SATURATE | min(As,1-Ad) | 1 |
其中斜体标记的为上述例子中使用的参数,在此处作为举例说明:
-
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
表示源颜色乘以自身的alpha 值,目标颜色乘以1.0减去源颜色的alpha值
- ARGB = ( Rs * As + Rd * (1-As) ) 以R分量举例
-
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA)
表示源颜色乘以自身的alpha 值,目标颜色乘以1.0减去源颜色的alpha值
源alpha乘以1.0减去目标的alpha值,目标alpha乘以目标alpha值
- RGB = ( Rs * As + Rd * (1-As) ) 以R分量举例
- A = ( As * ( 1 - Ad ) + Ad * Ad )
根据这些公式再去看上述问题描述中的计算过程就比较清晰了
5. 附录
此问题的发生暴露了此前对于blend 的理解以及blend接口理解的不足,以此记录供后续查阅参考
本地编辑完成后导入CSDN就会出现各种排版问题,先将就看吧,如果大家有好的办法,麻烦分享下 0.0