GPU在Chrome中扮演着重要的角色,主要体现在两个方面:对WebGL的支持和加速绘制的合成。我们将从几个方面来看一下Chrome对GPU的使用:
1)Chrome中GPU部分的总体架构,弄清楚GPU是如何整合到Chrome的整体结构的。
2)底层实现,学习Chrome是如何将GPU封装成平台无关的Command Buffer提供给上层使用的。
3)网页绘制中的加速合成,理解GPU是如何在网页绘制中起到加速效果。
先从第一个开始。Chrome采用了独立的GPU进程结构,如下图:
GPU Process是一个Server进程,在Chrome所有的进程里面,只有这个进程能够直接调用系统提供的图形接口(OpenGL或DirectX)。其他的进程如果要使用图形接口,只能作为GPU Server的一个Client,通过跨进程的协议,间接调用。例如Render进程的网页渲染和Plugin进程对GPU的使用等等。GPU进程的渲染结果将会直接被输出到目标窗口上。
这个跨进程的通信协议叫做Command Buffer,本质上一块共享内存,Client将对图形接口的调用转化成命令,然后将命令和命令使用的一些数据(贴图,顶点)等等写入共享内存,GPU Server拿到之后,再调用对应的接口,这方面的而实现细节将在下一篇展开讨论。
Chrome选择这种架构调用GPU,是基于以下几方面的考虑:
1)安全性。GPU原本的使命是快速绘制图像,因此在进行接口设计时,最先要保证的是速度。因此,在图形接口上就遗留了一定的安全隐患。例如,通过图形接口对内存(显存)进行操作的时候,并不做边界检查。因此,可能通过图形接口越界拿到内存中的一些敏感信息(如用户名,密码等等)。如果这些接口通过浏览器暴露给Web,就很可能被当做漏洞利用。这也是当时微软反对WebGL标准的重要理由之一。
通过独立进程的方式,可以规避这个问题,因为在GPU进程中,用户态的内存都是用来做渲染的,没有其他信息,即使拿到也没用。而且通过Command Buffer对图形接口的封装,所有的调用都是间接的,这也提高了安全性。
再者,将GPU独立出来之后,就可以严格的限制render进程和plugin进程,使其不能调用图形接口。也提高了这些进程的安全性。
2)健壮性。如果某些显卡在某些系统上支持的不好,在调用OpenGL或者DirectX时,会出现崩溃,独立GPU进程结构,能保证在其崩溃之后,不影响其他页面内容的显示。
3)标准化。DirectX在Windows上的强势,使得Chrome不得不选择使用它进行渲染。GPU进程在内部对DirectX和OpenGL进行归一化,向Client提供统一的OpenGL ES 2.0接口,这样使用起来就更加方便。
4)并行性。绝大部分的图形接口都是单向的,不需要关注返回值,这样调用方就没有必要等待调用返回。这样把图形调用丢给另外一个进程执行,可以提高图形渲染的并行性,提高整体效率。
这里简单说明一下并行性和对GPU使用的关系。GPU在设计之初就被定义为SIMD类型的处理器,因为这符合图形处理的特点。例如一个茶壶有1000个顶点,如果对他进行旋转,在图形学中就是将每一个顶点去乘以一个旋转矩阵。也就是说对每个顶点的操作都是一样的。因此,GPU的特点就是单指令多数据结构。这样,越能够并行化的任务,在GPU上执行的就越快。
GPU发展到今天,并行化计算能力已经非常强大,下图是Nvidia GF100架构(2009年推出),共有16个SM,每个SM有32个CUDA处理核心,每个CUDA核心都有独立的ALU和FPU处理单元。可以粗略的认为有16*32=512个核。而且通过SM的调度优化,每个SM的处理线程可以达到1024个。也就是可以处理1024*16=16384个并行线程。当然这都是理论上的计算,但可以窥见到GPU强大的并行处理能力。
GPU的使用场景:
1)页面渲染的加速合成,这个是目前GPU最广泛的使用场景。如果要看加速合成的细节,可以在启动时加入命令行 –show-composited-layer-borders。
2)WebGL & 2D Canvas,这是两个HTML5标准,WebGL和Canvas提供给js的图形接口是OpenGL的子集,因此对于这两种页面的渲染并不经过普通的合成路线,而是将调用转化成Command Buffer,直接在GPU中调用对应的实现。
3)为PPAPI的Plugin3D渲染提供支持。
前面只是粗略的把GPU的基本结构描述了一下,具体部分会在后面的篇幅中展开。