概览

  • 将上一节中UI线程生成了laytertree,交给GPU线程的rasterizer
  • 调用LayerTree的Preroll、Paint2个方法,完成所有Layer的绘制前准备以及绘制操作
  • 将纹理化的结果,上屏

Layer类型

绘制流程的核心基本都是围绕Layer进行操作,所以,首先要搞清楚Layer设计的定位是什么,有什么作用,才能更好的理解整段逻辑。下面这张图是native定义的Layer类型和结构图。

大概有这么些个Layer,他们都是干什么的呢?我们先看基类Layer的说明

A layer is the lowest-level rendering primitive. It represents an atomic painting command.

直译过来就是: 图层是最低级别的渲染原语,它代表一个原子绘画命令。划重点,layer代表的是一个绘画命令,而不是字面意义上的绘制图层

比如以往命令式进行绘制

final ui.SceneBuilder sceneBuilder = ui.SceneBuilder()
    //位移操作
    ..pushOffset(centerX, centerY)
    //绘制图像
    ..addPicture(ui.Offset.zero, picture)

对应使用Layer的写法

//创建一个位移命令的layer,对应pushOffset(centerX, centerY)
OffsetLayer offsetLayer = new OffsetLayer(offset: Offset(centerX, centerY));
rootLayer.append(offsetLayer);

//创建一个绘图命令的layer
PictureLayer pictureLayer = new PictureLayer(Rect.zero);
pictureLayer.picture = xxx;
offsetLayer.append(pictureLayer);

rootLayer.addToScene(sceneBuilder);

//这里底层会调用各种layer的方法,达到和上面命令式一样的效果
ui.window.render(sceneBuilder.build());

在看一眼layer里面的代码,就更清楚了

void ClipPathLayer::Paint(PaintContext& context) const {
  //调用SkCanvas的clipPath方法
  context.internal_nodes_canvas->clipPath(..);
}

所以很明显,flutter把绘制指令分为了几类(Layer),这些Layer中保存的实际上是对应skia绘制指令的调用

  • 位移操作类
    • TransformLayer
  • 透明操作类
    • OpacityLayer
  • 阴影、蒙板操作类
    • PhysicalShapeLayer
    • ShaderMaskLayer
  • 裁剪操作类
    • ClipPathLayer
  • 纹理操作
    • TextureLayer
  • 平台显示相关
    • PlatformViewLayer

这一部分内容,可以参考Flutter完整开发实战详解(二十一、 Flutter 画面渲染的全面解析)这篇文章中,关于layer的阐释,讲的非常清楚

流程

ok,明白了layer的作用和定位,我们回过头来,继续看GPU线程的整体工作流程

进入rasterizer->Draw(pipeline);

//rasterizer.cc
void Rasterizer::Draw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) {  
      //....
      raster_status = DoDraw(std::move(layer_tree));
}

RasterStatus Rasterizer::DoDraw(...) {
    DrawToSurface(*layer_tree);
}

跳来跳去,最终最终调用到核心函数DrawToSurfacea

//rasterizer.cc
RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
  FML_DCHECK(surface_);

  //申请一个frame
  auto frame = surface_->AcquireFrame(layer_tree.frame_size());

  //获取frame上的canvas
  auto root_surface_canvas =
      embedder_root_canvas ? embedder_root_canvas : frame->SkiaCanvas();

  //根据canvas等参数生成compositor_frame对象
  auto compositor_frame = compositor_context_->AcquireFrame(...,root_surface_canvas);

  if (compositor_frame) {
    //使用compositor_frame将layertree纹理化
    RasterStatus raster_status = compositor_frame->Raster(layer_tree, false);
    //上传给gpu
    frame->Submit();
  }
}

这个函数是主要的流程函数

  • 向surface申请一块frame
  • 根据frame上的canvas生成compositor_frame对象
  • 使用compositor_frame对layertree进行纹理化操作
  • 最终调用frame->Submit将纹理化后的数据上屏

明确surface_和android_surface_对象类型

首先要明确这个surface_是什么,初始化触发点在NotifyCreated中

//platform_view.cc
void PlatformView::NotifyCreated() {
  //in gpu task
    surface = platform_view->CreateRenderingSurface();
}

//platform_view_android.cc
std::unique_ptr<Surface> PlatformViewAndroid::CreateRenderingSurface() {
  return android_surface_->CreateGPUSurface();
}

好了,又蹦出来个android_surface_,android_surface_对象会在FlutterEngine启动时,随着PlatformViewAndroid的初始化而创建

//platform_view_android.cc  初始化android_surface_对象

PlatformViewAndroid::PlatformViewAndroid(
      android_surface_(AndroidSurface::Create(...)) {
}

跟进去Create函数

//android_surface.cc
std::unique_ptr<AndroidSurface> AndroidSurface::Create(
    bool use_software_rendering) {
  if (use_software_rendering) {
    auto software_surface = std::make_unique<AndroidSurfaceSoftware>();
    return software_surface->IsValid() ? std::move(software_surface) : nullptr;
  }
#if SHELL_ENABLE_VULKAN
  auto vulkan_surface = std::make_unique<AndroidSurfaceVulkan>();
  return vulkan_surface->IsValid() ? std::move(vulkan_surface) : nullptr;
#else   // SHELL_ENABLE_VULKAN
  auto gl_surface = std::make_unique<AndroidSurfaceGL>();
  return gl_surface->IsOffscreenContextValid() ? std::move(gl_surface)
                                               : nullptr;
#endif  // SHELL_ENABLE_VULKAN
}

这里有一堆宏定义,根据不同的宏来确定AndroidSurface具体的实现方式

  • AndroidSurfaceVulkan 使用Vulkan api方式
  • AndroidSurfaceSoftware 软解
  • AndroidSurfaceGL 一般真机的默认选择

确定了android_surface_的类型,继续看CreateGPUSurface方法返回的surface_是什么对象

//android_surface_gl.cc

std::unique_ptr<Surface> AndroidSurfaceGL::CreateGPUSurface() {
  //上文中的surface_实际上是GPUSurfaceGL对象
  auto surface = std::make_unique<GPUSurfaceGL>(this, true);
  return surface->IsValid() ? std::move(surface) : nullptr;
}

ok,到目前为止,我们确定了在android真机环境下surface_和android_surface_的实际类型

对象实际
surface_GPUSurfaceGL
android_surface_AndroidSurfaceGL

向surface申请一块frame

进入GPUSurfaceGL.AcquireFrame看一下实现

//gpu_surface_gl.cc  

std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(...) {

   sk_sp<SkSurface> surface =
      AcquireRenderSurface(size, root_surface_transformation);

  SurfaceFrame::SubmitCallback submit_callback =
      [...](...) {
        return weak ? weak->PresentSurface(canvas) : false;
      };

  return std::make_unique<SurfaceFrame>(surface, submit_callback);
}

实际上生成了一个SurfaceFrame对象,并且将创建的2个比较重要的对象挂载在SurfaceFrame上

  • SkSurface (skia的surface对象)
  • SubmitCallback

生成compositor_frame对象

std::unique_ptr<ScopedFrame> CompositorContext::AcquireFrame(..) {
  return std::make_unique<ScopedFrame>(
      *this, gr_context, canvas, view_embedder, root_surface_transformation,
      instrumentation_enabled, gpu_thread_merger);
}

生成了一个ScopedFrame对象,保存了gr_context、canvas这些对象,不纠结具体实现,继续往下看

使用ScopedFrame对layertree进行纹理化操作

//compositor_context_.cc

flutter::RasterStatus Raster(flutter::LayerTree& layer_tree,...) {
  //... this是ScopedFrame对象
  layer_tree.Preroll(*this, ignore_raster_cache);
  //...
  layer_tree.Paint(*this, ignore_raster_cache); 
}

函数Raster的作用主要是调用LayerTree的2个函数Preroll和Paint来完成纹理化的操作

  • Preroll 做一些绘制前的准备工作
  • Paint 执行layer的绘制方法(执行不同类别layer中对应的skia绘制指令)

LayerTree.Preroll

void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
                        bool ignore_raster_cache) {
  //...
  root_layer_->Preroll(&context, frame.root_surface_transformation());
}

调用root_layer_的Preroll方法,layer类型有很多种.假设这里的root_layer_是ContainerLayer

void ContainerLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
  SkRect child_paint_bounds = SkRect::MakeEmpty();
  //调用子layer的Preroll方法
  PrerollChildren(context, matrix, &child_paint_bounds);
  //设置绘制边界
  set_paint_bounds(child_paint_bounds);
}
  • 调用子layer的Preroll方法
  • 根据返回结果,设置当前layer的绘制比边界
void ContainerLayer::PrerollChildren(PrerollContext* context,
                                     const SkMatrix& child_matrix,
                                     SkRect* child_paint_bounds) {
  for (auto& layer : layers_) {
    layer->Preroll(context, child_matrix);
  }
}

遍历调用子layer的Preroll方法,假设其中有一个PictureLayer,看下具体实现

//picture_layer.cc
void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
  SkPicture* sk_picture = picture();

  if (auto* cache = context->raster_cache) {
    SkMatrix ctm = matrix;
    //矩阵Translate操作
    ctm.postTranslate(offset_.x(), offset_.y());
    cache->Prepare(context->gr_context, sk_picture, ctm,
                   context->dst_color_space, is_complex_, will_change_);
  }

  SkRect bounds = sk_picture->cullRect().makeOffset(offset_.x(), offset_.y());
  //设置绘制边界
  set_paint_bounds(bounds);
}

LayerTree.Paint

在Preroll后,就会调用到LayerTree的Paint方法

void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
                      bool ignore_raster_cache) const {
  if (root_layer_->needs_painting())
    root_layer_->Paint(context);
}

仍然以PictureLayer为例,看一下Paint方法做了什么

void PictureLayer::Paint(PaintContext& context) const {
  //leaf_nodes_canvas实际上是skia的SkCanvas指针
  SkAutoCanvasRestore save(context.leaf_nodes_canvas, true);

  context.leaf_nodes_canvas->translate(offset_.x(), offset_.y());
  context.leaf_nodes_canvas->drawPicture(picture());
}

调用SkCanvas的相关接口

  • save操作
  • translate偏移量操作
  • drawPicture,绘制图像内容

frame提交纹理化后的数据上屏

将LayerTree纹理化(raster)后,调用frame.Submit进行纹理上传上屏操作

bool SurfaceFrame::Submit() 
  submitted_ = PerformSubmit();
  return submitted_;
}

bool SurfaceFrame::PerformSubmit() {
    //submit_callback_ = PresentSurface
  submit_callback_(*this, SkiaCanvas());
}

submit_callback_其实是上面GPUSurfaceGL::AcquireFrame中生成SurfaceFrame时创建的callbak,

SurfaceFrame::SubmitCallback submit_callback =[...](...) {
    return weak ? weak->PresentSurface(canvas) : false;
};

继续看PresentSurface函数

//gpu_surface_gl.cc 
bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
    //将canvas上的数据flush到gpu上 (见SkCanva实现)
    onscreen_surface_->getCanvas()->flush();
    //缓存交换
    if (!delegate_->GLContextPresent()) {
        return false;
    }
    //交换surface对象,下一帧使用
    auto new_onscreen_surface =(...);
    onscreen_surface_ = std::move(new_onscreen_surface);
    return true;
}

flush

//将canvas上的数据flush到gpu上

//SkCanvas
void SkCanvas::flush() {
    this->onFlush();
}

void SkCanvas::onFlush() {
    SkBaseDevice* device = this->getDevice();
    if (device) {
        device->flush();
    }
}

GLContextPresent

交换缓存(内存-屏幕 内容)

//android_surface_gl.cc
bool AndroidSurfaceGL::GLContextPresent() {
  return onscreen_context_->SwapBuffers();
}

//android_context_gl.cc
bool AndroidContextGL::SwapBuffers() {
  return eglSwapBuffers(environment_->Display(), surface_);
}