问题现象
MIUI系统安装腾讯视频APP,搜索并且播放《长津湖之水门桥》,播放的视频出现闪烁的绿点
问题分析
- 设置选项中关闭HW Overlay 功能,也就是将所有的图层强制使用GPU合成,此问题不再复现
- kernel 的log中存在ACE的 error,表明 DPU(Display Processing Unit)出现了错误,引发了错误的中断
问题原因
在花屏的时间点,dumpsys SurfaceFlinger 观察到:
看到 AFBCCrop 的区域(0,4,32,134) (left,top,right,bottom);实际的buffer 宽高是864x374
AFBC 的super block size 分为 16x16 和 32x8 两种;根据 Tile 和 Linear 的不同,对于宽高的对齐要求也不一样
如果是 Tile mode,Tile mode是对四个相邻的 superblock 一起解码,对齐要求是:
Align_width = superblock_width x 4
Align_height = superblock_height x 4
Linear Mode,Linear Mode 下对单独的 superblock 进行解码:
Align_width = superblock_width
Align_height = superblock_height
如果输入 buffer 的实际宽高不满足对齐要求,Gralloc 分配Buffer 时会进行自动对齐,理论上,对齐的宽高不会超过一个 Tile 或者 superblock 的宽高,Tile 模式下 padding_width 和 padding_height 最高不超出128;上面的 AFBC crop 的134显得很异常
根据上面的 flags选项,可以看到 AFBC flag信息:
MALIDP_BUFFER_AFBC = 0x00000001
MALIDP_BUFFER_AFBC_WIDEBLK = 0x00000002
MALIDP_BUFFER_AFBC_SPLITBLK = 0x00000004
MALIDP_BUFFER_AFBC_YTR = 0x00000008
MALIDP_BUFFER_AFBC_SPARSE_MODE = 0x00000010
MALIDP_BUFFER_AFBC_SOLID_COLOR = 0x00000020
MALIDP_BUFFER_AFBC_TILED_HEADERS = 0x00000040
一般 RGBA 的 buffer flag=95(DEC) = 0x5F(HEX)拥有除了solid color 之外的所有属性
上面 YUV NV12 的flag 为 24641,包含tiled 和 AFBC属性
实际原因是 media codec 产生AFBC buffer 和实际下的AFBC参数是不一致的,导致解码错误
dump AFBC buffer 发现:
按照 alloc_height=384计算:
Buffer header size = (896*384)/256 x 16 = 0x5400. 由于需要page(4K)对齐,和32byte的文件头,文件中payload的起始地址是0x60020.
按照 alloc_height=512计算:
Buffer header size = (896*512)/256 x16 = 0x7000. 由于需要page对齐(4K),和32byte的文件头,文件中payload的起始地址是0x70020.
计算方法:superblock_count *16 Bytes,superblock_count 等于 align 之后的width * align 之后的height
从dump的AFBC文件来看,payload的offset是0x60020, 所以VPU是按照384 buffer_height编码afbc buffer而不是gralloc中定义的512;需要修改VPU对AFBC编码部分的处理。
864x374 NV12_AFBC 格式的对齐要求是怎样的?
根据 flag,NV12_AFBC是 Tiled,所以
Align_width = 16x4 = 64
Align_height= 16x4 = 64
对齐后的宽高为896x384