render进程创建的是off-screen surface(不能显示在屏幕上)。渲染到off-screen surface是通过
framebuffer object进行的,实际渲染目标是attach在framebuffer object上的texture或renderbuffer。
framebuffer object 有三个attachment point:
color attachment point:可以是mip-level的2D texture,也可以是renderbuffer object;
depth attachment point:可以是mip-level的2D texture,也可以是renderbuffer object;
stencil attachment point:只能是renderbuffer object.
render进程的渲染过程完成后,网页内容将被渲染到attach在framebuffer object上的textures上。
这些textures随后通过mailbox被传给了browser进程,browser进程的作用就是合成这些texture到
on-srceen surface上,即将包含网页内容的这些textures合成到on-screen surface对应的back buffer上,
当browser进程调用eglswapbuffer,前后buffer互换,下次屏幕刷新时,在front buffer中的网页内容就会显示
在屏幕上,browser进程中的渲染过程在下一篇介绍。
我把Render进程的整个处理流程分成五个大的子流程:
一.发生在主线程中,网页内容绘制命令被存储在LayerTreeHostImpl包含的LayerTreeImpl中。
二.发生在实现线程中,网页内容的光栅化,即流程一中的绘制命令的实际绘制过程,这个过程是在cpu上执行的,
绘制过程完成后,网页内容以像素形式存储在一块SharedMemory上,注意,这块SharedMemory可以跨进程使用。
三.光栅化后,流程二中存储网页内容的SharedMemory在GPU进程中作为纹理数据的源上传给gpu,
实现纹理贴图(glTexImage2D)。chromium是分块渲染的策略,TileManager管理的每个Tile最终都对应着一块
texture(ResourceProvider负责分配的),SharedMemory中的网页内容通过glTexImage2D最终渲染到了Tile
对应的texture上。
四.LayerTreeHostImpl::CalculateRenderPasses()记录已经光栅化的需要绘制的Tile的信息,
为LayerTreeHostImpl::DrawLayers()做准备.
五.LayerTreeHostImpl::DrawLayers()触发的实际的绘制过程。(glDrawElements).
这个过程会先调用glFramebufferTexture2DEXT,将texture attach到render进程创建的off-screen surface对应的
framebuffer object上,再接着对每个Tile对应的texture调用glDrawElements,这个过程完成后,
网页内容就被渲染到了attach到framebuffer上的textures上了,这些texture会被传递给browser进程。
我们分别看这五个子流程的具体实现。
一. 发生在主线程中,网页内容绘制命令被存储在LayerTreeHostImpl包含的LayerTreeImpl中。
网页内容更新(比如网页滚动,页面刷新,js动画等)时,会触发WebKit::RenderLayer::setBackingNeedsRepaintInRect()的执行。
chromium for android render进程结构分析中介绍过,网页内容绘制命令先被存储在cc::PictureLayer结构中。
chromium for android render进程结构分析的第二部分给出了如下类关系:
WebKit::RenderLayer::setBackingNeedsRepaintInRect()触发cc::PictureLayer::SetNeedsDisplayRect的过程如下图:
这样网页内容更新的处理转移到了cc模块中。
cc模块中由cc::PictureLayer::SetNeedsDisplayRect()函数开始的处理过程如下图:
ThreadProxy::BeginFrameOnMainThread()中顺序调用了如下几个重要函数:
其中:
2.LayerTreeHost::Layout()会触发webkit中包含页面内容的RenderLayerTree的Layout,
RenderLayerTree的Layout会确定网页上每个元素的大小,位置等信息,从而为绘制做准备。
3.LayerTreeHost::UpdateLayers()会触发webkit中包含页面内容的RenderLayerTree的绘制,
这里的绘制指的是将RenderLayerTree中包含的网页内容的绘制命令
存储到GraphicsLayer间接包含的PictureLayer中。
5.ThreadProxy::StartCommitOnImplThread()最终会使LayerTreeHost中维护的含有网页绘制命令的Layer Tree,提交给LayTreeHostImpl中维护的LayerTreeImpl。
下面依次看这三个函数的执行流程。
LayerTreeHost::Layout()触发的流程
LayerTreeHost::Layout()会触发webkit中包含页面内容的RenderLayerTree的Layout,
RenderLayerTree的Layout会确定网页上每个元素的大小,位置等信息,从而为绘制做准备。
这个触发过程如下图:
RenderView是RenderLayerTree的根节点,RenderView开始的Layout会触发整个RenderLayerTree的Layout.
LayerTreeHost::UpdateLayers()触发的流程
LayerTreeHost::UpdateLayers()会触发webkit中包含页面内容的RenderLayerTree的绘制,这里的绘制指的是将RenderLayerTree中包含的网页内容的绘制命令
存储到GraphicsLayer间接包含的PictureLayer中。
由LayerTreeHost::UpdateLayers()开始的流程如下图:
Picture::Record()中主要做了两件事情:
1).创建具有后端存储(SKBitmap)的SKCanvas;
2).将1)中创建的SKCanvas作为参数,调用WebContentLayerImpl::PaintContents(),触发webkit中网页内容的绘制命令记录到SKCanvas.
下面看这两件事的具体实现。
1).创建具有后端存储(SKBitmap)的SKCanvas,具体过程如下:
Picture::Record()函数中,先创建了skia::SkTileGridPictur