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::SkTileGridPicture,SkTileGridPicture继承自SKPicture.
接着调用SkTileGridPicture::beginRecording(),实际调用的是SkPicture::beginRecording().
SkPicture::beginRecording()的作用就是申请一块SKBitmap,并以这块SKBitmap作为后端存储创建SkPictureRecord,SkPictureRecord继承自SKCanvas.
Picture::Record()调用完SkPicture::beginRecording()后就得到了一块拥有SKBitmap的SKCanvas.
2).将1)中创建的SKCanvas作为参数,调用WebContentLayerImpl::PaintContents(),触发webkit中网页内容的绘制命令记录到SKCanvas上.具体过程如下图:
Picture::Record()调用WebContentLayerImpl::PaintContents(),同时将新创建的SKCanvas传入。
WebContentLayerImpl::PaintContents()接着调用OpaqueRectTrackingContentLayerDelegate::paintContents(),SKCanvas作为参数传入。
OpaqueRectTrackingContentLayerDelegate::paintContents()中以SkPicture::beginRecording()创建的SKCanvas为参数创建了GraphicsContext。
OpaqueRectTrackingContentLayerDelegate::paintContents()接着调用
GraphicsLayer::paint(),同时新创建的GraphicsContext作为参数传入。
GraphicsLayer::paint()调用GraphicsLayer::paintGraphicsLayerContents()。
注意这里的GraphicsLayer实例是包含在RenderLayerBacking中的成员变量OwnPtr<GraphicsLayer> m_graphicsLayer;
GraphicsLayer::paintGraphicsLayerContents()接着调用RenderLayerBacking::paintContents(),接着调用
RenderLayerBacking::paintIntoLayer(),接着调用RenderLayer::paintLayerContents().
这样,就进入了RenderLayerTree的绘制过程,RenderLayer中包含的网页内容的绘制命令保存在了GraphicsContext中封装的SKCanvas上。
前面的讲解,我们知道这块SKCanvas是在SKPicture中创建的,SKPicture包含在Picture中,Picture又包含在PicturePile中,PicturePile包含在PictureLayer中。
PictureLayer包含在LayerTreeHost的成员变量scoped_refptr<Layer> root_layer_为根结点的Layer Tree中。
这样,当LayerTreeHost::UpdateLayers()执行完后,各层网页内容的绘制命令就包含在了LayerTreeHost的成员变量scoped_refptr<Layer> root_layer_为根节点的Layer Tree中.
SKPicture,Picture,PicturePile,PictureLayer,layertreehost之间的关系图如下:
ThreadProxy::BeginFrameOnMainThread()触发的流程
ThreadProxy::BeginFrameOnMainThread()调用ThreadProxy::StartCommitOnImplThread()触发的流程如下图:
ThreadProxy::ScheduledActionCommit()中会顺序调用LayerTreeHost的两个重要函数,
LayerTreeHost::BeginCommitOnImplThread();
LayerTreeHost::FinishCommitOnImplThread();
LayerTreeHost::FinishCommitOnImplThread()的任务是将LayerTreeHost中维护的含有网页绘制命令的Layer Tree,提交给LayTreeHostImpl中维护的LayerTreeImpl.
具体的讲,就是LayerTreeHost的root_layer_指向的PictureLayer中存储网页内容绘制命令的PicturePileBase,传给了LayerTreeHostImpl的root_layer_指向的
PictureLayerImpl中存储网页内容绘制命令的PicturePileBase.
PictureLayer包含PicturePile,PicturePile继承自PicturePileBase;
PictureLayerImpl包含PicturePileImpl,PicturePileImpl继承自PicturePileBase;
PicturePileBase中包含实际的网页绘制命令。
上述类之间的关系如下图:
完成上述过程的关键语句如下:
LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl){
if (needs_full_tree_sync_)
sync_tree->SetRootLayer(TreeSynchronizer::SynchronizeTrees(
root_layer(), sync_tree->DetachLayerTree(), sync_tree));
{
TRACE_EVENT0("cc", "LayerTreeHost::PushProperties");
TreeSynchronizer::PushProperties(root_layer(), sync_tree->root_layer());
}
}
TreeSynchronizer::SynchronizeTrees()复制Layer tree的结构到LayerImpl tree.
TreeSynchronizer::PushProperties()中完成了将
LayerTreeHost的root_layer_指向的PictureLayer中存储网页内容绘制命令的PicturePileBase,传给了LayerTreeHostImpl的root_layer_指向的
PictureLayerImpl中存储网页内容绘制命令的PicturePileBase.
我们看TreeSynchronizer::PushProperties()的具体实现:
TreeSynchronizer::PushProperties()实际调用的是void PictureLayer::PushPropertiesTo(LayerImpl* base_layer);
void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
Layer::PushPropertiesTo(base_layer);
PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
// This should be first so others can use it.
layer_impl->UpdateTwinLayer();
layer_impl->SetIsMask(is_mask_);
layer_impl->CreateTilingSet();
// Unlike other properties, invalidation must always be set on layer_impl.
// See PictureLayerImpl::PushPropertiesTo for more details.
layer_impl->invalidation_.Clear();
layer_impl->invalidation_.Swap(&pile_invalidation_);
layer_impl->pile_ = PicturePileImpl::CreateFromOther(
pile_.get(), layer_impl->is_using_lcd_text_);
layer_impl->SyncFromActiveLayer();
}
重点看:
layer_impl->pile_ = PicturePileImpl::CreateFromOther(
pile_.get(), layer_impl->is_using_lcd_text_);
scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther(
const PicturePileBase* other,
bool enable_lcd_text) {
return make_scoped_refptr(new PicturePileImpl(other, enable_lcd_text));
}
PicturePileImpl::PicturePileImpl(const PicturePileBase* other,
bool enable_lcd_text)
: PicturePileBase(other),
enable_lcd_text_(enable_lcd_text),
clones_for_drawing_(ClonesForDrawing(this, num_raster_threads())) {
}
上面的流程说明PictureLayerImpl中包含的PicturePileImpl的基类实例PicturePileBase与PicturePlayer中包含的PicturePile的基类实例是同一个。
前面对LayerTreeHost::Layout()的分析我们知道,网页的绘制命令就存储在PicturePlayer中包含的PicturePile的基类实例PicturePileBase中。
所以,LayerTreeHost::FinishCommitOnImplThread()执行完后,包含网页绘制命令的结构PicturePileBase被提交给了LayerTreeHostImpl的LayerTreeImpl.
二.发生在实现线程中,网页内容的光栅化,即流程一中的绘制命令
的实际绘制过程,这个过程是在cpu上执行的,绘制过程完成后,
网页内容以像素形式存储在一块SharedMemory上,
这块SharedMemory可以跨进程使用。
ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw)会触发网页内容的实际绘制过程。
网页的绘制过程大致分为:计算坐标变换,光栅化,gl绘制。
ThreadProxy::ScheduledActionDrawAndSwapInternal()中顺序调用了LayerTreeHostImpl的几个重要函数:
LayerTreeHostImpl::PrepareToDraw();
LayerTreeHostImpl::DrawLayers();
LayerTreeHostImpl::SwapBuffers();
LayerTreeHostImpl::PrepareToDraw()触发坐标变换和光栅化的过程如下图:
layer_tree_host_common.cc定义的全局函数:
template <typename LayerType, typename LayerList, typename RenderSurfaceType>
static void CalculateDrawPropertiesInternal();
会先计算必要的变换,然后调用UpdateTilePrioritiesForLayer()触发光栅化过程。
UpdateTilePrioritiesForLayer()是定义在layer_tree_host_common.cc的全局函数。
我们重点看光栅化过程的触发和具体实现。
1)创建可以覆盖当前Layer更新区域的多个Tile.
这个过程涉及的类图如下:
调用流程如下图:
PictureLayerTiling::UpdateTilePriorities()先调用PictureLayerTiling::SetLiveTilesRect()创建Tile,
再为每个Tile设置优先级。
2)为1中创建的每个Tile创建光栅化任务。
这个过程涉及的类图如下:
调用流程如下图:
TileManager和PicturePileImpl之间的关系如下图:
下面我们看TileManager::CreateRasterTask()的具体实现。
TileManager::CreateRasterTask(Tile* tile)首先为tile申请ResourcePool::Resource.
ResourcePool::Resource对应着一个实际的纹理索引,这个纹理索引由glGenTexture生成。
ResourcePool::AcquireResource()会导致ResourceProvider::CreateManagedResource()被调用。
过程如下图:
ResourceProvider::CreateManagedResource()会触发真正的glGenTexture的调用,产生Texture的索引.
过程如下图:
GLES2Implementation::GenTextures()定义在gles2_implementation_impl_autogen.h中,这个文件是自动生成的。
GenTexturesImmediate()定义在gles2_cmd_helper_autogen.h中,这个文件是自动生成的。
GenTexturesImmediate()会发送gles2::cmds::GenTexturesImmediate,
最终调用到GLES2DecoderImpl::HandleGenTexturesImmediate()。定义在gles2_cmd_decoder_autogen.h中,这个文件是自动生成的。
GLES2DecoderImpl::HandleGenTexturesImmediate()调用GLES2DecoderImpl::GenTexturesHelper().
GLES2DecoderImpl::GenTexturesHelper()调用glGenTextures生成纹理索引。
ResourcePool::Resource创建完成后,对应的纹理索引保存在Resource::id_中。
TileManager::CreateRasterTask()中,可以看到这个索引值同时保存在Tile的ManagedTileState::TileVersion::resource_id_中。
TileManager::CreateRasterTask()接着调用RasterWorkerPool::RasterTask的构造函数创建RasterTask.
asterWorkerPool::RasterTask的构造函数需要5个参数,其中第3,4个参数是函数指针:
typedef base::Callback<bool(SkDevice* device, PicturePileImpl* picture_pile)> Callback;
typedef base::Callback<void(bool was_canceled)> Reply;
TileManager::CreateRasterTask()调用RasterWorkerPool::RasterTask的构造函数是第三个参数为:
base::Bind(&TileManager::RunAnalyzeAndRasterTask,
base::Bind(&TileManager::RunAnalyzeTask,
analysis,
tile->content_rect(),
tile->contents_scale(),
use_color_estimator_,
GetRasterTaskMetadata(*tile),
rendering_stats_instrumentation_),
base::Bind(&TileManager::RunRasterTask,
analysis,
tile->content_rect(),
tile->contents_scale(),
GetRasterTaskMetadata(*tile),
rendering_stats_instrumentation_)),
即RasterWorkerPool::RasterTask的Callback函数指针实际指向的是TileManager::RunAnalyzeAndRasterTask。
3)调度执行光栅化的过程。
TileManager::ScheduleTasks()先为每个Tile创建光栅化任务,再调用raster_worker_pool_->ScheduleTasks(&tasks);调度光栅化任务的执行。
光栅化任务触发的流程如下图:
PixelBufferRasterWorkerPool::ScheduleMoreTasks()中调用
resource_provider_->AcquirePixelBuffer(task->resource()->id());创建了Buffer.
接着调用resource_provider_->MapPixelBuffer()得到一块buffer.这块buffer作为参数传递给了
PixelBufferWorkerPoolTaskImpl的构造函数,保存在变量buffer_中。
PixelBufferWorkerPoolTaskImpl定义在pixel_buffer_raster_worker_pool.cc中。
PixelBufferWorkerPoolTaskImpl::RunOnThread()中以buffer_为后端存储创建了SkDevice,并将这个SKDevice传递给了
RasterWorkerPoolTaskImpl::RunOnThread().
RasterWorkerPoolTaskImpl::RunOnThread()调用了TileManager::RunAnalyzeAndRasterTask,并将SKDevice作为参数传入。
这样,resource_provider_->MapPixelBuffer()得到的buffer,就以SKDevice的形式传递到了TileManager::RunRasterTask().
TileManager::RunRasterTask()中以传递进来的SKDevice为参数创建了SKCavas实例。SKCanvas实例作为参数传递给了
PicturePileImpl::RasterToBitmap().完成真正的光栅化过程。光栅化完成后,每个Tile覆盖的当前Layer的内容就以像素的形式存储在
resource_provider_->MapPixelBuffer()得到的那块buffer上了。PicturePileImpl::RasterToBitmap->PicturePileImpl::RasterCommon
->Picture::Raster()->SKPicture::draw()完成具体绘制过程。
4)resource_provider_->MapPixelBuffer()得到的buffer的具体来源。
buffer的创建流程如下图:
这里分配的SharedMemory的一部分一TileManager管理的Tile对应的texture是一一对应的关系,SharedMemory会作为纹理数据源传给Tile对应的Texture.
三.光栅化后,流程二中存储网页内容的SharedMemory在GPU进程中作为
纹理数据的源上传给gpu,实现纹理贴图(glTexImage2D)。
chromium采用分块渲染的策略,TileManager管理的每个Tile最终
都对应着一块texture(ResourceProvider负责分配).
SharedMemory中的网页内容通过glTexImage2D最终渲染到了Tile对应的texture上。
1)将光栅化后包含像素的buffer作为纹理数据上传给gpu的过程(glTexImage2D)。
光栅化完成后会调用PixelBufferRasterWorkerPool::OnRasterTaskCompleted(),PixelBufferRasterWorkerPool::OnRasterTaskCompleted()调用
ResourceProvider::BeginSetPixels(),会顺序调用以下重要函数:
context3d->bindTexture();
context3d->bindBuffer();
其中context3d->bindTexture()绑定当前resource对应的Texture.
context3d->bindBuffer()设置当前resource对应的buffer的id.
context3d->asyncTexImage2DCHROMIUM()将光栅化到Buffer上的像素上传给texture。
context3d->asyncTexImage2DCHROMIUM()->GLES2Implementation::AsyncTexImage2DCHROMIUM().
GLES2Implementation::AsyncTexImage2DCHROMIUM(){
helper_->AsyncTexImage2DCHROMIUM(
target, level, internalformat, width, height, border, format, type,
buffer->shm_id(), buffer->shm_offset() + offset);
}可以看到SharedMemory的封装类BufferTracker::Buffer的地址传给了helper_->AsyncTexImage2DCHROMIUM。
helper_->AsyncTexImage2DCHROMIUM最终会调用到GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM()定义在gles2_cmd_decoder.cc中。
GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM()会调用AsyncPixelTransferDelegateEGL::AsyncTexImage2D(),
AsyncPixelTransferDelegateEGL::AsyncTexImage2D()会接着调用TransferStateInternal::PerformAsyncTexImage2D()定义在Async_Pixel_Transfer_Delegate_egl.cc中。
TransferStateInternal::PerformAsyncTexImage2D()最终会调用glTexImage2D或glTexSubImage2D。将光栅化到Buffer上的像素上传给纹理映射。
glTexImage2D加载图像数据。
四.LayerTreeHostImpl::CalculateRenderPasses()记录已经光栅化的需要绘制的Tile的信息,为LayerTreeHostImpl::DrawLayers()做准备.
LayerTreeHostImpl::PrepareToDraw()调用完 active_tree_->UpdateDrawProperties();触发了光栅化并将网页数据上传给Tile对应的texture之后,调用
LayerTreeHostImpl::CalculateRenderPasses()为LayerTreeHostImpl::DrawLayers()做准备。
LayerTreeHostImpl::CalculateRenderPasses()主要作用是为二中每个texture中已经加载了纹理数据的Tile创建TileDrawQuad并添加到FrameData类型的变量中。
LayerTreeHostImpl::DrawLayers()最终绘制的就是包含在FrameData类型的变量中的TileDrawQuad对应的texture。
TileDrawQuad包含的信息是需要渲染的已经加载了网页数据的texture的信息。
LayerTreeHostImpl::CalculateRenderPasses()首先为每一个LayerImpl中包含的RenderSurfaceImpl变量调用AppendRenderPasses创建一个RenderPass,
并添加到FrameData类型变量中。
接着对FrameData中包含的所有LayerImpl调用AppendQuadsForLayer(),AppendQuadsForLayer定义在Layer_tree_host_impl.cc中的全局函数。
AppendQuadsForLayer()调用具体LayerImpl的AppendQuads().
对于Render进程LayerImpl的具体类型是PictureLayerImpl;对于Brower进程LayerImpl的具体类型是TextureLayerImpl。
PictureLayerImpl::AppendQuads()中会遍历PictureLayerTilingSet类型的变量tilings_,为每一个对应texture已经加载了网页数据的Tile创建一个TileDrawQuad实例,
这个实例被添加到FrameData类型变量间接包含的QuadList中。
这个过程中涉及的类关系图如下:
LayerTreeHostImpl::CalculateRenderPasses()执行完后,对应texture已经加载了网页数据的Tile的信息以TileDrawQuad的形式包含在FrameData类型的变量中。
这个FrameData类型的变量被传递给了LayerTreeHostImpl::DrawLayers()。
五.LayerTreeHostImpl::DrawLayers()触发的实际的绘制过程。(glDrawElements).
这个过程会先调用glFramebufferTexture2DEXT,将texture attach到render进程
创建的off-screen surface对应的framebuffer object上,再接着对每个Tile
对应的texture调用glDrawElements,这个过程完成后,网页内容就被渲染到了
attach到framebuffer上的textures上了,这些texture会被传递给browser进程。