1. 程式人生 > >chromium for android硬體渲染流程全解析(render程序)

chromium for android硬體渲染流程全解析(render程序)

這篇部落格分析的是網頁內容更新時(比如滾動),render程序將新的網頁內容渲染到off-screen surface的完整流程。
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結構中。

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程序。

DirectRenderer::DrawFrame()->GLRenderer::BeginDrawingFrame()->
GLRenderer::EnsureBackbuffer()->
MailboxOutputSurface::EnsureBackbuffer(){
current_backing_.texture_id = context3d_->createTexture();
current_backing_.size = size_;
context3d_->genMailboxCHROMIUM(current_backing_.mailbox.name);
context3d_->bindTexture(GL_TEXTURE_2D, current_backing_.texture_id);
}
EnsureBackbuffer()中生成一個texture,為這個texture生成一個mailbox,繫結這個texture.
這個texture會在MailboxOutputSurface::BindFramebuffer(){
context3d_->framebufferTexture2D(
      GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
      current_backing_.texture_id, 0);
}中attach到framebuffer object的color attachment上。
以下是MailboxOutputSurface::BindFramebuffer()的觸發流程:
DirectRenderer::DrawRenderPass()->DirectRenderer::UseRenderPass()->
GLRenderer::BindFramebufferToOutputSurface()->
MailboxOutputSurface::BindFramebuffer().
上述過程完成後,就可以對流程四中每個Texture進行實際的渲染過程,即呼叫glDrawElements。
GLRenderer::DoDrawQuad()呼叫GLRenderer::DrawTileQuad().
GLRenderer::DrawQuadGeometry()呼叫
WebGraphicsContext3DCommandBufferImpl->drawElements()最終會呼叫到
GLES2DecoderImpl::HandleDrawElements().
GLES2DecoderImpl::HandleDrawElements()會呼叫GLES2DecoderImpl::DoDrawElements()。
GLES2DecoderImpl::DoDrawElements()定義在gles2_cmd_decoder.cc中。
GLES2DecoderImpl::DoDrawElements()會呼叫glDrawElements進行實際的渲染。
這個過程執行完,網頁內容就渲染到了MailboxOutputSurface::EnsureBackbuffer()
中建立的texture上。
渲染結結束後DirectRenderer::DrawFrame()->GLRenderer::FinishDrawingFrame()
->MailboxOutputSurface::SendFrameToParentCompositor(){
 frame->gl_frame_data.reset(new GLFrameData());
  DCHECK(!size_.IsEmpty());
  DCHECK(size_ == current_backing_.size);
  DCHECK(!current_backing_.mailbox.IsZero());
 context3d_->framebufferTexture2D(
      GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
  context3d_->bindFramebuffer(GL_FRAMEBUFFER, 0);
  context3d_->bindTexture(GL_TEXTURE_2D, current_backing_.texture_id);
   context3d_->produceTextureCHROMIUM(
      GL_TEXTURE_2D, current_backing_.mailbox.name);
  frame->gl_frame_data->mailbox = current_backing_.mailbox;
  frame->gl_frame_data->size = current_backing_.size;
  context3d_->flush();
  frame->gl_frame_data->sync_point = context3d_->insertSyncPoint();
  CompositorOutputSurface::SendFrameToParentCompositor(frame);
 pending_textures_.push_back(current_backing_);
  current_backing_ = TransferableFrame();
}
其中:
1.context3d_->produceTextureCHROMIUM()產生可被Browser程序消耗的Texture,
即render程序中渲染到的目標texture;
2.將包含目標texture的mailbox name設定在frame變數中,並通過
CompositorOutputSurface::SendFrameToParentCompositor(frame)傳送給browser程序。
browser程序通過mailbox name找到Render程序產生的texture.這個過程下一篇寫。

相關推薦

chromium for android硬體渲染流程解析(render程序)

這篇部落格分析的是網頁內容更新時(比如滾動),render程序將新的網頁內容渲染到off-screen surface的完整流程。 render程序建立的是off-screen surface(不能顯示在螢幕上)。渲染到off-screen surface是通過 frame

Android異步載入解析之開篇瞎扯淡

com des turn pro 能夠 eat launch 卡頓 ring Android異步載入概述 Android異步載入在Android中使用的很廣泛,除了是由於避免在主線程中做網絡操作。更是為了避免在顯示時由於時間太長而造成ANR,添加顯示的流暢性,特別是像Li

Android檢視繪製流程完全解析,帶你一步步深入瞭解View(二)

在上一篇文章中,我帶著大家一起剖析了一下LayoutInflater的工作原理,可以算是對View進行深入瞭解的第一步吧。那麼本篇文章中,我們將繼續對View進行深入探究,看一看它的繪製流程到底是什麼樣的。如果你還沒有看過我的上一篇文章,可以先去閱讀 Android Layo

Netty 進階:write流程解析

1. ChannelOutboundBuffer 1.1 ChannelOutboundBuffer概述 在分析write前,有必要介紹一下ChannelOutboundBuffer,顧名思義該類是用來快取寫向Socket的資料。每個 ChannelSocke

build chromium for android

Get the code 下載安裝depot_tools clone depot_tools, 並新增到PATH裡面去: $ git clone https://chromium.googlesource.com/chromium/tools/de

Chromium for android 1 原始碼獲取

最近發現 chromium 開源專案可以編譯出來一個 shell 了,看來離 chrome for android 的正式開源的日期越來越近。 今天就整理一下如何下載原始碼、編譯、執行 以下內容在 ubuntu 12.04 64-bit 上面實踐,工作目錄在 Public 獲

3秒鐘不懂你砍我:RecyclerView下拉重新整理和上拉載入更多(開源中國List業務流程解析

這裡以開源中國開源資訊頁面為例子。 這個頁面資料的url:http://www.oschina.net/action/apiv2/news?pageToken= 是這樣的 json資料的結構: NewsBean返回成功與否的code和msg。 ResultBean返回的

Android AOP實現原理解析

     前天早晨在公交車上,知乎搜尋了下Android的最新技術,回答還是很多的,我們搞技術的,永遠不能落後,要隨時與市場保持同步,這樣才能跟上市場的步伐。有朋友提到了一個AOP的面向切面的程式設計技術,從這個名字上,大概就可以知道是幹什麼的,也有很多朋友舉例就是在日誌列

Android系統啟動流程(一)解析init進程啟動過程

option 寫入 android change failed miss 通知 target sna 前言 作為“Android框架層”這個大系列中的第一個系列,我們首先要了解的是Android系統啟動流程,在這個流程中會涉及到很多重要的知識點,這個系列我們就來一一講解它們

Android: 在native中訪問assets解析

lock mp4 cpp sets 這樣的 內容 jniexport opencl href 本文總結在Android Native C++開發中訪問APK中的assets資源的方法 在CMake中添加相關NDK LIB的 依賴 因為我們接下來用到的一些函數實現在NDK庫l

Android圖片載入框架最解析(四),玩轉Glide的回撥與監聽(筆記)

參考原文:Android圖片載入框架最全解析(四),玩轉Glide的回撥與監聽 回撥的原始碼實現 的Target物件傳入到GenericRequest當中,而Glide在圖片載入完成之後又會回撥GenericRequest的onResourceReady()方法,onReso

Android圖片載入框架最解析(五),Glide強大的圖片變換功能(筆記)

參考原文:Android圖片載入框架最全解析(五),Glide強大的圖片變換功能 一個問題 百度這張logo圖片的尺寸只有540258畫素,但是我的手機的解析度卻是10801920畫素,而我們將ImageView的寬高設定的都是wrap_content,那麼圖片的寬度應該只有

Android圖片載入框架最解析(三),深入探究Glide的快取機制(筆記)

原文地址:Android圖片載入框架最全解析(三),深入探究Glide的快取機制 筆記: 1.Glide快取簡介 2.快取Key EngineKey 重寫了equals()和hashCode()方法,保證只有傳入EngineKey的所有引數都相同的情況下才認為是

Android圖片載入框架最解析(七),實現帶進度的Glide圖片載入功能(筆記)

參考原文:Android圖片載入框架最全解析(七),實現帶進度的Glide圖片載入功能 擴充套件目標 對Glide進行功能擴充套件,使其支援監聽圖片下載進度的功能 開始 dependencies { compile 'com.github.bumptech.glid

Android圖片載入框架最解析(六),探究Glide的自定義模組功能(筆記)

參考原文:Android圖片載入框架最全解析(六),探究Glide的自定義模組功能 自定義模組的基本用法 自定義模組功能可以將更改Glide配置,替換Glide元件等操作獨立出來,使得我們能輕鬆地對Glide的各種配置進行自定義,並且又和Glide的圖片載入邏輯沒有任何交集,

Android動畫機制解析

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android中system server程序啟動流程原始碼解析 系統服務啟動

system server 前言 System Server fork SystemServer SystemServer.main() SystemServer.createSystemContext SystemSe

vlc for android 不能屏,或者畫面不能鋪滿的問題。

做視訊開發的時候,肯定會遇到,小視窗播放,然後支援全屏播放。    我遇到的問題,有兩個。 一:小視窗視訊有黑邊。就是還是沒充滿。 二:全屏畫面也是鋪不滿,而且跟小視窗的畫面大小是一樣的。 要解決這些問題,先介紹一下要用到的vlc的三個介面 vide

Android——Json資料解析

前言 在現如今的Android開發中,尤其是網際網路軟體,客戶端與伺服器端的互動可謂是家常便飯,而在Android端,通過訪問介面接收到伺服器端返回的Json格式的資料的情形幾乎百分之九十的開發者都會遇到,這篇文章就對一些基本的到複雜的Json資料的解析進行一個