应用中显示投屏小窗部分的颜色值与预期不一致,预期为纯白色 [0xFF],而实际显示偏黑 [0xDE]
相同渲染合成逻辑在X86平台测试显示为正常色彩 [0xFF]
各个layer叠加顺序如下(简化层级可以说明问题即可):
PS:Overlay 是指Display Process Unit中硬件图层,由硬件进行叠加混合,提高效率;
根据上述过程,由于GPU和DRM均为标准库,出问题概率较小,则先排查另外两项:
根据应用使用的两张图片的RGB值计算数据如下(使用glBlendFunc接口):
Bottom(0xFF, 0xFF, 0xFF, 0xFF)和media(0xD9, 0xFF, 0xFF, 0xFF)合成
从这两张图片的计算结果来看,应用经过GPU渲染合成后输出的RGB值应该为0xFF,即纯白色;
dump GPU 吐出的buffer数据,查看其ARGB值与上述计算出来的数据一致
则根据上述两步分析可以得到如下结论:
PS:计算公式详见第四小节blend使用接口介绍;
基于上述实验分析,需要确认硬件Overlay是如何做的硬件合成操作:
根据上述公式计算出来最终要显示的RGB颜色为0xDE 并非0xFF,与实际上屏颜色相符;
则问题已经明确,应用端没有考虑到平台DPU后端仍会做一次硬件的blend合成,输出A颜色值并非为0xFF,导致问题出现
基于上述分析,问题原因已经明确:
平台中进行了两次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接口和参数介绍详见第四小节
blend 即使用输入(Src)RGBA分量数据与帧缓冲区中已有RGBA值(Dst)进行计算来得到最终输出RGBA值得过程;
名词 | 说明 |
---|---|
Src | 输入的layer数据,由于blend计算过程为从下往上,则src就是相对位置在上方的layer |
Dst | 帧缓冲区中已有的layer数据,两层合成是相对位置在下方的layer |
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分量的计算因子拆分了出来
合系数枚举值 | 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值
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值
根据这些公式再去看上述问题描述中的计算过程就比较清晰了
此问题的发生暴露了此前对于blend 的理解以及blend接口理解的不足,以此记录供后续查阅参考
本地编辑完成后导入CSDN就会出现各种排版问题,先将就看吧,如果大家有好的办法,麻烦分享下 0.0