美文网首页
Flutter与Vsync信号

Flutter与Vsync信号

作者: Wi1ls努力努力再努力 | 来源:发表于2020-10-20 18:32 被阅读0次

在FlutterEngine的构造函数的调用链中,会执行startInitialization(Context,Settings)@FlutterLoader.java

public void startInitialization(Context applicationContext, Settings settings){
  ...
  VsyncWaiter.getInstance((WindowManager)applicationContext.getSystemService(Context.WINDOW_SERVICE)).init();
  ...
}


@VsyncWaiter.java
private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate = new FlutterJNI.AsyncWaitForVsyncDelegate(){
  public void asyncWaitForVsync(long cookie){
    Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback(){
      public void doFrame(long frameTimeNanos){
        ...
        FlutterJNI.nativeOnVsync(frameTimeNanos, frameTimeNanos+refreshPeriodNanos, cookie);
      }
    });
  }
}

public void init(){
  FlutterJNI.setAsyncWaitForVsyncDelegate(asyncWaitForVsyncDelegate);
  ...
}

来看FlutterJNI对于这个asyncWaitForVsyncDelegate的使用

@FlutterJNI.java
//Called by native
private static void asyncWaitForVsync(final long cookie){
  if(asyncWaitForVsyncDelegate != null){
    asyncWaitForVsyncDelegate.asyncWaitForVsync(cookie);
  }
}

public static native void nativeOnVsync(long frameTimeNanos, long frameTargetTimeNanos, long cookie);

上面对于asyncWaitForVsync()的那句注释Calledbynative是Flutter原始注释,说明这个方法会在某个native节点进行调用。
该native方法是注册啊vsync_wait_android.cc中[engine源码],对应的方法为onNativeVsync()
现在假定它被调用了。

//./shell/platform/android/vsync_waiter_android.cc
void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env, jclass jcaller, jlong frameTimeNanos, jlong frameTargetTimeNanos, jlong java_baton){
  ...
  ConsumePendingCallback(java_baton, frame_time, target_time);
}

void VsyncWaiterAndroid::ConsumePendingCallback(jlong java_baton, fml::TimePoint frame_start_time, fml::TimePoint frame_target_time){
  ...
  //VsyncWaiter类
  shared_this->FireCallback(frame_start_time, frame_target_time);
}

//vsync_waiter.cc
void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, fml_TimePoint frame_target_time){
  Callback callback=std::move(callback_);
  ...
  task_runners.GetUITaskRunner()->PostTakForTime(
    [callback, flow_identifier, frame_start_time, frame_start_time](){
      callback(frame_start_time, frame_target_time);
    },frame_start_time);
)
}

上面就是将callback 抛到UI线程进行执行,callback_是在VsyncWaiter::AsyncWaitForVsync(Callback)中进行赋值,而该函数在animatior.cc中进行调用

//animatior.cc
void Animator::AwaitVSync(){
  waiter_->AsyncWaitForVsync([self=weak_factory_.GetWeakPtr()](fml::TimePoint frame_start_time, fml::TimePoint frame_target_time){
    //这里是self就是animator对象
    if(self){
      if(self->CanReuseLastLayerTree()){
        self->DrawLastLayerTree();
      }else{
        self->BeginFrame(frame_start_time, frame_target_time);
      }
    }
  });
AwaitVsync();
}

这里需要提一句,Animator::AwaitVsync()是在由Animator:RequestFrame()调用,而后者是在Engine::ScheduleFrame()调用。

这里的AwaitVsync()指向VsyncWaiterAndroid::AwaitVsync();

//vsync_waiter_android.cc
void VsyncWaiterAndroid::AwaitSync(){
  ...
  task_runners_.GetPlatformTaskRunner()->PostTask([java_baton](){
    JNIEnv* env = fml::jni::AttachCurrentThread();
    //从该类不难得出,该方法反射调用asyncWaitForVsync()@FluuterJNI.java,即我们分析的源头。
    env->CallStaicVoidMethod(g_vsync_waiter_class->obj(), g_async_wait_for_vsync_method_, java_baton);
  });
}

现在有一环跑通了,从Engine::.scheduleFrame()到Animator::RequestFrame()到Animator::AwaitVsync()其实就是注册这个VSYNC回调的过程,而每次执行完self->DrawLastLayerTree()或self->BeginFrame()后,又重新注册vsync,即每次VSYNC到来(不发生掉帧)都会进行一次回调Animator::DrawLastLayerTree()或Animator::BeginFrame(),Animator::DrawLastLayerTree()就是绘制上一次的视图,现在重点看Animator::BeginFrame();

//animator.cc
void Animator::BeginFrame(fml::TimePoint frame_start_time, fml::TimePoint frame_target_time){
  ...
  //delegate_为shell.cc对象
  delegate_.onAnimatorBeginFrame(last_begin_frame_time_);
}

//shell.cc
void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_time){
  engine_->BeginFrame(frame_time); 
}

//engine.cc
void Engine::BeginFrame(fml::TimePoint frame_time){
  runtime_control_->BeginFrame(frame_time);
}

//runtime_controller.cc
bool RuntimeController::BeginFrame(fml::TimePoint frame_time){
  window->BeginFrame(frame_time);
}

//window.cc
void Window::BeginFrame(fml::TimePoint frameTime){
  //该反射会调用onBeginFrame()@window.dart
  tonic::DartInvokeFiled(library_.value(), "_beginFrame",{Dart_NewInteger(microseconds),}));
  //执行microtask
  UIDartState::Current()->FlushMicrotaskNow();
  //该反射会调用onDrawFrame()@window.dart
  tonic::DartInvokeField(library_.value(),"_drawFrame",{})';
}

可以看到microtask位于beginFrame和drawFrame之间,耗时会影响ui绘制。

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

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

window.onBeginFrame与onDrawFrame在ScheduleBinding(binding.dart中注册),在flutter_run_app_analyze中已经有提及了,

//scheduler/binding.dart
void _handleBeginFrame(Duration rawTimeStamp){
  handleBeginFrame(rawTimeStamp);
}

void _handleDrawFrame(){
  handleDrawFrame(rawTimeStamp);
}

关于handleBeginFrame()与handleDrawFrame()另外其文章分析。

相关文章

  • Flutter与Vsync信号

    在FlutterEngine的构造函数的调用链中,会执行startInitialization(Context,S...

  • runloop与Vsync 信号

    在多数博客中提到的runloop 在即将休眠前的屏幕绘制和接收到VSync 信号后的屏幕绘制,它们之间是什么关系呢...

  • Vsync 信号与 Runloop

    1.什么是Vsync 信号? GPU 通常有一个机制叫做垂直同步(简写也是 V-Sync),当开启垂直同步后,GP...

  • Vsync同步机制 二

    SurfaceFlinger Vsync初始化过程 DispVsync是软件Vsync的信号源, 是Surface...

  • FPS 检测

    iOS 的显示系统是由 VSync 信号驱动的,VSync 信号由硬件时钟生成,每秒钟发出 60 次(这个值取决设...

  • vSync信号和屏幕成像基本流程分析

    背景 最近在做Flutter知识学习的时候,有时间会看到vsync信号,不知道所谓何物,所以专门抽时间简单学习了一...

  • Vsync同步机制 一

    什么是Vsync同步机制? Vsync(垂直同步信号量),用来同步渲染,让AppUI和SurfaceFlinger...

  • Android性能优化-UI优化

    一、Android渲染机制 Android系统每隔16ms就会发送一个VSYNC信号(VSYNC:vertical...

  • Flutter 开发遇到的问题

    1. AnimationController has lost it's vsync 在升级 Flutter 1....

  • Android 三重缓冲

    1、系统每隔1/60秒发出VSYNC信号; 2、当绘制系统收到VSYNC信号后,CPU和GPU依次开始对下一帧的数...

网友评论

      本文标题:Flutter与Vsync信号

      本文链接:https://www.haomeiwen.com/subject/bbfdmktx.html