跳到主要内容

光栅化

浏览器的光栅化(Rasterization)是将网页中的各种元素(如文本、图形和图像)转换成屏幕上实际像素的过程。这是浏览器渲染管线的一个重要环节,它发生在布局(Reflow/Layout)和绘制(Paint)之后,最终结果是在屏幕上生成可视化的内容。

光栅化的工作流程:

  1. 布局(Layout/Reflow):确定每个页面元素的确切位置和大小。这些元素的尺寸和位置信息会被用于光栅化过程。
  2. 绘制(Paint):在布局阶段完成之后,浏览器会通过生成一系列的绘制记录(Paint Records)来描述如何绘制页面的各个部分。这些记录包括文本、颜色、图像等信息。
  3. 图层分割(Layering):为了优化渲染性能,浏览器通过光栅线程会将页面分割成多个图层(Layer),每个图层可以单独进行光栅化和合成。
  4. 光栅化(Rasterization):浏览器将绘制记录转换成实际的像素数据,这个过程通常在GPU上完成,因为GPU擅长处理并行任务,可以快速完成大量像素数据的计算。
  5. 合成(Compositing):最后,光栅化完成后, 浏览器会将合成线程会收集(被称为draw quads)图块信息用于创建合成帧;

CPU光栅化

其实Chromium内核是使用Skia库进行光栅化的, 这个库通过扫描线算法创建位图(这是一个非常线性的方法). 要将结果发送到CUP以在屏幕上绘制, 正常我们可以通过glTexImage2D()这个API来进行提交数据的.

零拷贝光栅化

其实这种方式是CPU光栅化的一种优化, 说白了也就是说, 光栅化的方式与之前相同, 只不过将光栅化后生成的位图信息保存在我们的主内从当中, 为了最大程度减少传输到CPU过程当中的压力, 这次采用的方式不是手动通过glTexImage2D()API去上传, 而是告诉GPU映射的位图在主内存中的位置, 让GPU自己去读取.

GPU光栅化

由于GPU非线性运行的, 比较善于并发处理数据, GPU光栅化最直接的改变就是将CPU的负载转移到了GPU上. 所有多边形都必须使用 OpenGL 基元(三角形和线)进行渲染, 这也是由Skia通过名为Skia Ganesh的GPU后端执行的, 结果永远不会保存在主内存当中, 而是保存在CPU的显存(我们买显卡说的6GB显存, 8GB现存就是干这个用的)当中, 因此不用复制到任何地方, 也节省了主内存的空间.

其实GPU渲染也不是完美的, 由于GPU渲染最大的瓶颈就是现实字体或者小而复杂的形状. OpenGL没有任何原生文本渲染单元, 如果使用三角形来表述字符, 那么以汉语为例, 那需要多少个三角形才能组成一篇文章呢, 想想都是个灾难性的工程.

优化光栅化:

  • 按需光栅化:只对视口内的元素进行光栅化,滚动时动态光栅化新出现的内容。
  • 图层缓存:对不经常变动的图层进行缓存,当页面滚动或发生其他操作时,可以直接复用这些图层的光栅化结果,而无需重新光栅化。
  • GPU加速:利用GPU的并行处理能力,加速光栅化和图像处理任务,特别是对于复杂的视觉效果(如阴影、渐变和动画)。

合成帧(Frame Compositing)

它发生在浏览器的渲染管线的最后阶段,目的是将多个独立渲染的图层(Layers)合并成最终显示在屏幕上的单一图像。这个过程对于提升页面滚动、动画和其他视觉效果的性能和流畅性非常关键。

合成帧的过程

  1. 图层创建:浏览器会根据页面的结构和CSS属性(如动画、过渡、3D变换、滚动等)将页面分割成多个图层。每个图层可以独立渲染,这样可以提高效率,特别是对于动态改变的内容。
  2. 图层绘制:每个图层会独立进行绘制(Painting)和光栅化(Rasterization),生成图层的像素数据。
  3. 图层合成:在所有图层都准备好之后,合成器(Compositor)会将它们按照正确的顺序和透明度叠加起来,生成最终的帧。这个过程通常在GPU上进行,因为GPU擅长处理这种类型的并行图形操作。
  4. 显示:最后生成的帧会发送给显示设备,呈现给用户。

合成帧的优势

  • 性能提升:通过只重绘和合成页面的变化部分,而不是整个页面,可以大幅减少计算量和提高渲染性能。
  • 流畅的动画和交互:动画和过渡效果可以被分配到独立的图层,这意味着它们可以在不影响页面其他部分的情况下快速且平滑地渲染。
  • 减少闪烁:由于合成过程是在GPU上完成的,减少了CPU的负担,从而减少了页面重绘导致的闪烁问题。