Chromium硬件加速渲染的GPU数据上传机制分析解析.doc
文本预览下载声明
Chromium硬件加速渲染的GPU数据上传机制分析
在Chromium中,WebGL端、Render端和Browser端通过命令缓冲区将GPU命令发送给GPU进程执行。GPU命令携带的简单参数也通过命令缓冲区发送给GPU进程,但复杂参数,例如纹理数据,有可能太大,以致于命令缓冲区无法容纳,因此要通过其它机制传递给GPU进程。本文接下来就主要以纹理数据上传为例,分析WebGL端、Render端和Browser端将GPU命令数据传递给GPU进程的机制。
WebGL端、Render端和Browser端将GPU命令附携带的大数据传递给GPU进程的基本思路通过其它的共享缓冲区进行传递。也就是先将GPU命令携带的大数据写入到共享缓冲区中,然后再将GPU命令携带的大数据参数修改为前面已经写入了数据的共享缓冲区的ID。GPU进程通过这个ID就可以找到对应的共享缓冲区,进而得到真正的GPU命令数据,最后就可以执行对应的OpenGL函数。
有些操作系统对能创建的共享内存的大小有限制。当一个GPU命令携带的数据的大小超过这个限制的时候,那么就不能通过一块共享缓冲区一次性将数据传递给GPU进程。这时候就需要对数据进行分块传输。有些GPU命令的数据本身就支持分块传输,这种情况的处理就比较简单。例如,对于纹理上传命令gles2::cmds::TexImage2D,可以通过gles2::cmds::TexSubImage2D命令对其携带的纹理数据进行分块传输,如图1所示:
在图1中,我们假设一个gles2::cmds::TexImage2D命令要上传的纹理数据可以划分为1、2和3三个子块,每一个子块都可以通过一块共享缓冲区进行传递。这时候一个gles2::cmds::TexImage2D命令就被分拆成三个gles2::cmds::TexSubImage2D子命令,每一个gles2::cmds::TexSubImage2D子命令负责处理一个子数据块。这些gles2::cmds::TexSubImage2D子命令最终在GPU进程中转化为OpenGL函数glTexSubImage2D调用,每一个glTexSubImage2D函数都负责上传一个数据子块到GPU中。
很不幸,并不是所有的GPU命令都像gles2::cmds::TexImage2D命令一样,存在对应的子命令,例如gles2::cmds::ShaderSource命令,它不存在对应的gles2::cmds::ShaderSubSource子命令。这时候就需要使用一种称为Bucket的机制来分块上传GPU命令数据。以gles2::cmds::ShaderSource命令为例,它携带的Shader源代码的分块上传机制如图2所示:
在图2中,我们同样假设gles2::cmds::ShaderSource命令要上传的数据可以划分为1、2和3三个子块,每一个子都可以通过一块共享缓冲区进行传递。每一个数据子块都是通过一个gles2::cmds::SetBucketData命令保存在GPU进程中的同一个Bucket中的。每一个Bucket都具有一个ID,前面已经准备好了数据的Bucket的ID接下来再通过一个gles2::cmds::ShaderSourceBucket命令传递给GPU进程。GPU进程有了这个Bucket的ID之后,就可以获得它里面的数据,进而可以调用OpenGL函数glShaderSource,从而完成对gles2::cmds::ShaderSource命令的处理。
不难发现,上面描述的两种GPU命令数据分块上传机制都是通过共享缓冲区进行的,这就涉及到这些共享缓冲区的管理问题,也就是分配和释放的问题。为了更好地认识这个问题,我们首先简单介绍一下Chromium的纹理上传机制。Chromium提供了同步和异步纹理上传机制。
我们知道,在Chromium中,所有的GPU命令都是在GPU进程的一个线程中执行的,这个线程称为GPU主线程。将纹理上传命令全部交给GPU主线程执行就称为同步纹理上传,如图3所示:
在图3中,我们假设一个命令缓冲区有五个GPU命令需要执行,其中第一个GPU命令是同步纹理上传命令gles2::cmds::TexImage2D,对应的OpenGL函数是glTexImage2D。由于使用的是同步纹理上传方式,因此,在纹理上传命令执行完成之前,后面的四个命令是不能执行的。
与GPU的图形计算和渲染速度相比,将数据从CPU传递到GPU的速度是相当慢的。这就使得纹理上传操作是GPU的一个瓶颈,特别是数据量很大的纹理。对于图3来说,就会造成后面的四个命令需要等待比较长时间才会被执行。
显示全部