flutter UI渲染源码解析之Engin绘制过程(二)

engin绘制过程

上文中我们讲到了VSYNC的注册,注册之后会等待vsync信号回调doframe,然后回调到了FlutterJNI.nativeOnVsync(frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie);,因为JNILoad的时候将FlutterJNI#nativeOnVsyncVsyncWaiterAndroid#OnNativeVsync做了绑定,此时会被回调到OnNativeVsync中

  • 1.vsnyc_waiter_android.cc VsyncWaiterAndroid::OnNativeVsync
/// static
void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env,
                                       jclass jcaller,
                                       jlong frameTimeNanos,
                                       jlong frameTargetTimeNanos,
                                       jlong java_baton) {
  TRACE_EVENT0("flutter", "VSYNC");

  auto frame_time = fml::TimePoint::FromEpochDelta(
      fml::TimeDelta::FromNanoseconds(frameTimeNanos));
  auto target_time = fml::TimePoint::FromEpochDelta(
      fml::TimeDelta::FromNanoseconds(frameTargetTimeNanos));

  ConsumePendingCallback(java_baton, frame_time, target_time);
}

这里的target_time = frame_time+屏幕刷新时间(fps)
float fps = windowManager.getDefaultDisplay().getRefreshRate();
long refreshPeriodNanos = (long) (1000000000.0 / fps);
一般的屏幕刷新率每秒60次,fps =16.7

  • 2.vsnyc_waiter_android.cc VsyncWaiterAndroid:: ConsumePendingCallback
// static
void VsyncWaiterAndroid::ConsumePendingCallback(
    jlong java_baton,
    fml::TimePoint frame_start_time,
    fml::TimePoint frame_target_time) {
  auto* weak_this = reinterpret_cast*>(java_baton);
  auto shared_this = weak_this->lock();
  delete weak_this;

  if (shared_this) {
    shared_this->FireCallback(frame_start_time, frame_target_time);
  }
}
  • 3.vsync_waiter.cc VsyncWaiter:: FireCallback
void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
                               fml::TimePoint frame_target_time) {
  Callback callback;
  fml::closure secondary_callback;
  {
    std::scoped_lock lock(callback_mutex_);
    callback = std::move(callback_);
    secondary_callback = std::move(secondary_callback_);
  }
  if (!callback && !secondary_callback) {
   //判断之前设置的callback是否被设置为null了,若设置为null了也就没必要回调了
    TRACE_EVENT_INSTANT0("flutter", "MismatchedFrameCallback");
    return;
  }
  if (callback) {
    auto flow_identifier = fml::tracing::TraceNonce();
    TRACE_EVENT0("flutter", "VsyncFireCallback");
    TRACE_FLOW_BEGIN("flutter", kVsyncFlowName, flow_identifier);
    //向UI线程中post VSYNC的信号回调
    task_runners_.GetUITaskRunner()->PostTaskForTime(
        [callback, flow_identifier, frame_start_time, frame_target_time]() {
          FML_TRACE_EVENT("flutter", kVsyncTraceName, "StartTime",
                          frame_start_time, "TargetTime", frame_target_time);
          fml::tracing::TraceEventAsyncComplete(
              "flutter", "VsyncSchedulingOverhead", fml::TimePoint::Now(),
              frame_start_time);
          //执行callback
          callback(frame_start_time, frame_target_time);
          TRACE_FLOW_END("flutter", kVsyncFlowName, flow_identifier);
        },
        frame_start_time);
  }

  if (secondary_callback) {
    task_runners_.GetUITaskRunner()->PostTaskForTime(
        std::move(secondary_callback), frame_start_time);
  }
}

这里的回调信号会post到UI线程中执行,同时UI线程会在MessageLoop::RunExpiredTasks将消息取出来执行。

  • 4.message_loop.cc MessageLoop::RunExpiredTasksNow
void MessageLoop::RunExpiredTasksNow() {
  loop_->RunExpiredTasksNow();
}
  • 5.message_loop_impl.cc
void MessageLoopImpl::RunExpiredTasksNow() {
  FlushTasks(FlushType::kAll);
}

void MessageLoopImpl::FlushTasks(FlushType type) {
  TRACE_EVENT0("fml", "MessageLoop::FlushTasks");
  std::vector invocations;
  //取出task中的消息
  task_queue_->GetTasksToRunNow(queue_id_, type, invocations);
  //执行取出的消息
  for (const auto& invocation : invocations) {
    invocation();
    std::vector observers =
        task_queue_->GetObserversToNotify(queue_id_);
    for (const auto& observer : observers) {
      observer();
    }
  }
}

从task_queue 中取出对应的消息,并执行invocation,此方法将真正执行对应的callback( AsyncWaitForVsync中的callback)

  • 6.message_loop_tast_queues.cc MessageLoopTaskQueues::GetTasksToRunNow
void MessageLoopTaskQueues::GetTasksToRunNow(
    TaskQueueId queue_id,
    FlushType type,
    std::vector& invocations) {
  std::lock_guard guard(queue_mutex_);
  //是否有挂起的task
  if (!HasPendingTasksUnlocked(queue_id)) {
    return;
  }

  const auto now = fml::TimePoint::Now();
  //判断是否有挂起的任务,有取出来并判断时间是否到了,到了立马执行
  while (HasPendingTasksUnlocked(queue_id)) {
    TaskQueueId top_queue = _kUnmerged;
    const auto& top = PeekNextTaskUnlocked(queue_id, top_queue);
    //判断队列的头时间是否可以执行,不可以执行break
    if (top.GetTargetTime() > now) {
      break;
    }
    //将挂起的放到列表里面
    invocations.emplace_back(top.GetTask());
    queue_entries_.at(top_queue)->delayed_tasks.pop();
    if (type == FlushType::kSingle) {
      break;
    }
  }

  
  if (!HasPendingTasksUnlocked(queue_id)) {
    //若没有挂起的task睡眠当前loop,直到下一次message的到来
    WakeUpUnlocked(queue_id, fml::TimePoint::Max());
  } else {
    //若有挂起的task,执行并设置下次唤醒的时间
    WakeUpUnlocked(queue_id, GetNextWakeTimeUnlocked(queue_id));
  }
}

//为当前队列设置wakeup的唤醒时间
void MessageLoopTaskQueues::WakeUpUnlocked(TaskQueueId queue_id,
                                           fml::TimePoint time) const {
  if (queue_entries_.at(queue_id)->wakeable) {
    queue_entries_.at(queue_id)->wakeable->WakeUp(time);
  }
}

此方法会从消息队列中循环取出队列的消息
1.若没有挂起的task消息,那么将当前的loop进行睡眠直到新的消息到来唤醒(time = fml::TimePoint::Max())
2.若有挂起的task消息,但是时间没有到top.GetTargetTime() > now,那么将当前的loop进行睡眠到message执行的时间
3.若有挂起的task且时间是top.GetTargetTime() <= now,那么将执行此消息。然后将loop睡眠到下个message执行的时间

  • 7.animator.cc Animator::AwaitVSync callback的位置
void Animator::AwaitVSync() {
  waiter_->AsyncWaitForVsync(
      [self = weak_factory_.GetWeakPtr()](fml::TimePoint frame_start_time,
                                          fml::TimePoint frame_target_time) {
        if (self) {
          if (self->CanReuseLastLayerTree()) {
            self->DrawLastLayerTree();
          } else {
            self->BeginFrame(frame_start_time, frame_target_time);
          }
        }
      });

  delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_);
}
  • 8.animator.cc#DrawLastLayerTree
///复用上一次的图层库
void Animator::DrawLastLayerTree() {
   //释放信号量,vsync信号可再次注册
  pending_frame_semaphore_.Signal();
  delegate_.OnAnimatorDrawLastLayerTree();
}

注意:delgate此处表示的是shell.cc:shell同时继承了PlatformView::Delegate,Animator::Delegate,Engine::Delegate,所以在Engine,Animator,PlatformView中的成员变量delegate_都是指Shell对象。

    1. shell.cc#OnAnimatorDrawLastLayerTree
void Shell::OnAnimatorDrawLastLayerTree() {
  FML_DCHECK(is_setup_);
//将任务交给Raster线程(draw过程并为GPU下发指令的线程)处理
  task_runners_.GetRasterTaskRunner()->PostTask(
      [rasterizer = rasterizer_->GetWeakPtr()]() {
        if (rasterizer) {
          rasterizer->DrawLastLayerTree();
        }
      });
}

这里的Raster线程是对LayerTree进行draw操作并将要draw内容下发给GPU进行渲染。Raster的处理过程后边文章介绍,本篇不进行介绍。

  • 10.animator.cc Animator::BeginFrame
void Animator::BeginFrame(fml::TimePoint frame_start_time,
                          fml::TimePoint frame_target_time) {
  TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", frame_number_++);

  TRACE_EVENT0("flutter", "Animator::BeginFrame");
  while (!trace_flow_ids_.empty()) {
    uint64_t trace_flow_id = trace_flow_ids_.front();
    TRACE_FLOW_END("flutter", "PointerEvent", trace_flow_id);
    trace_flow_ids_.pop_front();
  }

  frame_scheduled_ = false;
  notify_idle_task_id_++;
  regenerate_layer_tree_ = false;
//非负信号量,容量1,每次获取会减1,释放加1。控制vysnc的注册`pending_frame_semaphore_(1),`
//此处+1
  pending_frame_semaphore_.Signal();

  if (!producer_continuation_) {
    //若之前的layertree并没有执行Animation :: Render,此次直接启用便可
    //layer_tree_pipeline_(fml::MakeRefCounted(2)) 这里的管道是最大深度是2,即最大的执行laytree为2,每次UI线程执行poduce会减一,Raster线程执行Comsume之后会执行一次加一操作。
    producer_continuation_ = layer_tree_pipeline_->Produce();
    if (!producer_continuation_) {
    //pipeline已满,说明GPU线程繁忙,则结束本次UI绘制,重新注册Vsync
      RequestFrame();
      return;
    }
  }

  FML_DCHECK(producer_continuation_);

//从pipeline中获取有效的continuation,并准备为可能的frame服务
  last_frame_begin_time_ = frame_start_time;
//获取当前帧绘制截止时间,用于告知可GC的空闲时长
  last_frame_target_time_ = frame_target_time;
  dart_frame_deadline_ = FxlToDartOrEarlier(frame_target_time);
  {
    TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame",
                 FrameParity());
    //执行绘制
    delegate_.OnAnimatorBeginFrame(frame_target_time);
  }

  if (!frame_scheduled_) {
     //执行完绘制之后需要通知UI,闲置
    task_runners_.GetUITaskRunner()->PostDelayedTask(
        [self = weak_factory_.GetWeakPtr(),
         notify_idle_task_id = notify_idle_task_id_]() {
          if (!self.get()) {
            return;
          }
        //如果我们(此任务的)任务ID与当前任务ID相同(表示发布此任务的| BeginFrame |调用没有后续框架)并且当前没有可处理的frame,通知引擎当前处于空闲状态 100ms
          if (notify_idle_task_id == self->notify_idle_task_id_ &&
              !self->frame_scheduled_) {
            TRACE_EVENT0("flutter", "BeginFrame idle callback");
            self->delegate_.OnAnimatorNotifyIdle(Dart_TimelineGetMicros() +
                                                 100000);
          }
        },
      //等待51毫秒(比60hz的3帧多1毫秒)
        kNotifyIdleTaskWaitTime);
  }
}

此处kNotifyIdleTaskWaitTime等于51ms,等于3帧的时间+1ms,之所以这样设计是由于在某些工作负载下(比如父视图调整大小,通过viewport metrics事件传达给子视图)实际上还没有schedule帧,尽管在下一个vsync会生成一帧(将在收到viewport事件后schedule),因此推迟调用OnAnimatorNotifyIdle一点点,从而避免可能垃圾回收在不希望的时间触发。

  • 11.shell.cc Shell::OnAnimatorNotifyIdle 以下都是一系列调用过程
// |Animator::Delegate|
void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time) {
  FML_DCHECK(is_setup_);
  FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());

  // record the target time for use by rasterizer.
  {
    std::scoped_lock time_recorder_lock(time_recorder_mutex_);
    latest_frame_target_time_.emplace(frame_target_time);
  }
  if (engine_) {
    engine_->BeginFrame(frame_target_time);
  }
}
  • 12.engine.cc Engine::BeginFrame
void Engine::BeginFrame(fml::TimePoint frame_time) {
  TRACE_EVENT0("flutter", "Engine::BeginFrame");
  runtime_controller_->BeginFrame(frame_time);
}
  • 13.runtim_controller.cc RuntimeController::BeginFrame
bool RuntimeController::BeginFrame(fml::TimePoint frame_time) {
  if (auto* window = GetWindowIfAvailable()) {
    window->BeginFrame(frame_time);
    return true;
  }
  return false;
}
  • 14.window.cc Window::BeginFrame
void Window::BeginFrame(fml::TimePoint frameTime) {
  std::shared_ptr dart_state = library_.dart_state().lock();
  if (!dart_state)
    return;
  tonic::DartState::Scope scope(dart_state);

  int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds();

  tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_beginFrame",
                                           {
                                               Dart_NewInteger(microseconds),
                                           }));

  UIDartState::Current()->FlushMicrotasksNow();

  tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_drawFrame", {}));
}

之前交代过window.cc 中的方法跟window.dart是对应的。
BeginFrame 方法此时执行了
1._beginFrame 执行到了window.dart的onBeginFrame
2.FlushMicrotasksNow 这里便是我们平常使用的scheduleMicrotask异步事件,这里进行了执行,所以我们的Microtask本身耗时的话会阻塞我们的UI线程
3._drawFrame 执行到了window.dart的onDrawFrame

从hooks.dart 中可以知道

@pragma('vm:entry-point')
// ignore: unused_element
void _beginFrame(int microseconds) {
  _invoke1(window.onBeginFrame, window._onBeginFrameZone, Duration(microseconds: microseconds));
}

@pragma('vm:entry-point')
// ignore: unused_element
void _drawFrame() {
  _invoke(window.onDrawFrame, window._onDrawFrameZone);
}

你可能感兴趣的:(flutter UI渲染源码解析之Engin绘制过程(二))