mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Chrome Trace viewer treats events labeled "VSYNC" as special and highlights them (when the "Highlight Vsync" checkbox is enabled). Ideally VSYNC events are generated by the host system at their source. System VSYNC events are indeed present in full-system systraces. Flutter-level traces (as seen in Observatory/Flutter devtools) do not contain the system VSYNC events, so we rely on the engine to generate them (as close to where they would be generated by the system ideally). Currently the common (platform-independent code) generates VSYNC events at the time when the UI thread starts processing a frame. This has two drawbacks: 1. The traces are generated with a delay (we wait for the callback to be have been scheduled on the UI thread instead of tracing as soon as the system notified us. 2. When inspecting system-wide traces we'll have both the system and the Flutter app (or potentially multiple Flutter apps) generate VSYNC events at the same time. This confuses both the developers and the trace viewer. This change moves the VSYNC event generation to the platform-specific embedder implementations: 1. On Android/iOS we always generate the VSYNC event since Android/iOS developers use Flutter tools to debug the apps. 2. On Fuchsia we do not generate VSYNC events since the systraces always contain them. 3. In the Embedder wrapper we don not generate VSYNC events and rely on the actual embedder to do this in a way appropriate for the target system.
111 lines
3.5 KiB
C++
111 lines
3.5 KiB
C++
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "flutter/shell/platform/android/vsync_waiter_android.h"
|
|
|
|
#include <cmath>
|
|
#include <utility>
|
|
|
|
#include "flutter/common/task_runners.h"
|
|
#include "flutter/fml/logging.h"
|
|
#include "flutter/fml/platform/android/jni_util.h"
|
|
#include "flutter/fml/platform/android/scoped_java_ref.h"
|
|
#include "flutter/fml/size.h"
|
|
#include "flutter/fml/trace_event.h"
|
|
|
|
namespace flutter {
|
|
|
|
static fml::jni::ScopedJavaGlobalRef<jclass>* g_vsync_waiter_class = nullptr;
|
|
static jmethodID g_async_wait_for_vsync_method_ = nullptr;
|
|
|
|
VsyncWaiterAndroid::VsyncWaiterAndroid(flutter::TaskRunners task_runners)
|
|
: VsyncWaiter(std::move(task_runners)) {}
|
|
|
|
VsyncWaiterAndroid::~VsyncWaiterAndroid() = default;
|
|
|
|
// |VsyncWaiter|
|
|
void VsyncWaiterAndroid::AwaitVSync() {
|
|
auto* weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this());
|
|
jlong java_baton = reinterpret_cast<jlong>(weak_this);
|
|
|
|
task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() {
|
|
JNIEnv* env = fml::jni::AttachCurrentThread();
|
|
env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), //
|
|
g_async_wait_for_vsync_method_, //
|
|
java_baton //
|
|
);
|
|
});
|
|
}
|
|
|
|
float VsyncWaiterAndroid::GetDisplayRefreshRate() const {
|
|
JNIEnv* env = fml::jni::AttachCurrentThread();
|
|
if (g_vsync_waiter_class == nullptr) {
|
|
return kUnknownRefreshRateFPS;
|
|
}
|
|
jclass clazz = g_vsync_waiter_class->obj();
|
|
if (clazz == nullptr) {
|
|
return kUnknownRefreshRateFPS;
|
|
}
|
|
jfieldID fid = env->GetStaticFieldID(clazz, "refreshRateFPS", "F");
|
|
return env->GetStaticFloatField(clazz, fid);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// static
|
|
void VsyncWaiterAndroid::ConsumePendingCallback(
|
|
jlong java_baton,
|
|
fml::TimePoint frame_start_time,
|
|
fml::TimePoint frame_target_time) {
|
|
auto* weak_this = reinterpret_cast<std::weak_ptr<VsyncWaiter>*>(java_baton);
|
|
auto shared_this = weak_this->lock();
|
|
delete weak_this;
|
|
|
|
if (shared_this) {
|
|
shared_this->FireCallback(frame_start_time, frame_target_time);
|
|
}
|
|
}
|
|
|
|
// static
|
|
bool VsyncWaiterAndroid::Register(JNIEnv* env) {
|
|
static const JNINativeMethod methods[] = {{
|
|
.name = "nativeOnVsync",
|
|
.signature = "(JJJ)V",
|
|
.fnPtr = reinterpret_cast<void*>(&OnNativeVsync),
|
|
}};
|
|
|
|
jclass clazz = env->FindClass("io/flutter/embedding/engine/FlutterJNI");
|
|
|
|
if (clazz == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
g_vsync_waiter_class = new fml::jni::ScopedJavaGlobalRef<jclass>(env, clazz);
|
|
|
|
FML_CHECK(!g_vsync_waiter_class->is_null());
|
|
|
|
g_async_wait_for_vsync_method_ = env->GetStaticMethodID(
|
|
g_vsync_waiter_class->obj(), "asyncWaitForVsync", "(J)V");
|
|
|
|
FML_CHECK(g_async_wait_for_vsync_method_ != nullptr);
|
|
|
|
return env->RegisterNatives(clazz, methods, fml::size(methods)) == 0;
|
|
}
|
|
|
|
} // namespace flutter
|