mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
The current implementation only deals with Android devices and we'll add iOS devices support soon.
113 lines
3.9 KiB
C++
113 lines
3.9 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/arraysize.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/trace_event.h"
|
|
|
|
namespace shell {
|
|
|
|
static void ConsumePendingCallback(jlong java_baton,
|
|
fml::TimePoint frame_start_time,
|
|
fml::TimePoint frame_target_time);
|
|
|
|
static fml::jni::ScopedJavaGlobalRef<jclass>* g_vsync_waiter_class = nullptr;
|
|
static jmethodID g_async_wait_for_vsync_method_ = nullptr;
|
|
|
|
VsyncWaiterAndroid::VsyncWaiterAndroid(blink::TaskRunners task_runners)
|
|
: VsyncWaiter(std::move(task_runners)) {}
|
|
|
|
VsyncWaiterAndroid::~VsyncWaiterAndroid() = default;
|
|
|
|
// |shell::VsyncWaiter|
|
|
void VsyncWaiterAndroid::AwaitVSync() {
|
|
std::weak_ptr<VsyncWaiter>* 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 //
|
|
);
|
|
});
|
|
}
|
|
|
|
static void OnNativeVsync(JNIEnv* env,
|
|
jclass jcaller,
|
|
jlong frameTimeNanos,
|
|
jlong frameTargetTimeNanos,
|
|
jlong java_baton) {
|
|
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);
|
|
}
|
|
|
|
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/view/VsyncWaiter");
|
|
|
|
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, arraysize(methods)) == 0;
|
|
}
|
|
|
|
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");
|
|
// We can safely read this 32-bit float from Java in any thread because
|
|
// 32-bits read and write are guaranteed to be atomic:
|
|
// https://stackoverflow.com/questions/11459543/should-getters-and-setters-be-synchronized/11459616#11459616
|
|
return env->GetStaticFloatField(clazz, fid);
|
|
}
|
|
|
|
static void 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);
|
|
}
|
|
}
|
|
|
|
} // namespace shell
|