miniblink修复3D变换的两处渲染Bug

时间:2022-11-05 04:30:04

情况是这样的,有个群友让我试了下http://2.swiper.com.cn/demo/3dflow/index.html  里面的3D flow效果,发现miniblink画出来是个平的,没有3D效果···

于是赶紧调了下。原因很快就找到了,是我自己写的渲染层,对于layer的处理有问题。

详细来讲,是这样,blink在碰到这种3d网页,会开启硬件加速渲染模式,创建N个platform layer(平台相关层)。而这个 blink只负责告诉这些layer他们的位置、坐标变换,但具体怎么显示这些layer完全靠外部代码来实现,也就是说blink不管了。这也就是miniblink之所以搞了我这么久的原因,我完全自己撸了一个layer系统,而之前,这部分代码是chromium里的cc目录(cc的意思是chromium composition )实现的。

回到这个问题,这些3D 图形,导致blink创建的layer的坐标变换都是SkMatrix44的矩阵,这只是第一步,拿到矩阵后 ,还要考虑页面滚动、层的相对位置,再经过一系列运算才能得出层的屏幕位置。而这部分代码,在cc里,是一个超级复杂的函数来计算的:cc\trees\layer_tree_host_common.cc里的CalculateDrawPropertiesInternal。这个函数复杂到什么程度呢,光注释就100多行,整个函数超过1000行!整个函数的流程大概就是不挺根据各种坐标变换、位置等参数计算各种layer的真实位置之类的。之前也 研究过此函数,那时候就是为了把此函数精简,提取出一个最简化cc层真正需要的算法。但我之前的理解不够深刻,miniblink修复3D变换的两处渲染Bug

看这个函数其中一个矩阵运算部分,这里combined_transform应该会得出屏幕坐标系的矩阵。而我的精简版cc层里,拿到这个矩阵后,复制给了绘制的canvas。这里我犯了一个错误,就是canvas最终接收到的矩阵,不是4X4,而是退化成3x3了。也不知道谷歌为啥要这样搞,总之这里就丢失了部分矩阵数据。而chromium里的是把一系列数据,包括这个矩阵,存在一个从顶层传下来的数据结构data_from_ancestor里(这样说明一下,CalculateDrawPropertiesInternal是个递归调用的函数,用来不停计算所有layer的数据),所以这个4x4的矩阵就没丢失精度,只是最后绘制的是再退化。而我是给了canvas保存这个4x4矩阵。所以相当于丢失矩阵信息了。


这是第一个bug。第二个bug也让我改的很痛苦。

看这个效果图miniblink修复3D变换的两处渲染Bug

可以看到,第二张图在第一张图的下面。

而实际上,这两个图,每张图是一个layer。而且第二个layer,在blink里应该是在第一个之上的。

那么肯定,从blink到cc里,cc会在某个时刻调整这两个layer的绘制顺序。

这个点找了半天,终于在CalculateDrawPropertiesInternal这个极其复杂的函数的最下方找到。

miniblink修复3D变换的两处渲染Bug

这里可以看到对layer会进行重新排序。

而这个函数里面也非常复杂·····因为3D的重叠计算本来就很复杂,大意是检测变换之后的四边形的边界,看是怎么个交叉逻辑。不过这里谷歌偷懒了,两个layer可能会

交叉,而不是覆盖。

把相关代码LayerSorter移植到miniblink,终于把这两个bug给修复了,花了整整两天时间