blob: 052de023b9a1293d15bd1ed9d1d8623cf5289dd4 [file] [log] [blame]
// Copyright 2016 The Chromium 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/platform/android/jni_util.h"
#include "flutter/fml/platform/android/scoped_java_ref.h"
#include "flutter/fml/trace_event.h"
#include "lib/fxl/arraysize.h"
#include "lib/fxl/logging.h"
namespace shell {
static jlong CreatePendingCallback(VsyncWaiter::Callback callback);
static void ConsumePendingCallback(jlong java_baton,
fxl::TimePoint frame_start_time,
fxl::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() {
auto java_baton =
CreatePendingCallback(std::bind(&VsyncWaiterAndroid::FireCallback, //
this, //
std::placeholders::_1, //
std::placeholders::_2 //
));
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 = fxl::TimePoint::FromEpochDelta(
fxl::TimeDelta::FromNanoseconds(frameTimeNanos));
auto target_time = fxl::TimePoint::FromEpochDelta(
fxl::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);
FXL_CHECK(!g_vsync_waiter_class->is_null());
g_async_wait_for_vsync_method_ = env->GetStaticMethodID(
g_vsync_waiter_class->obj(), "asyncWaitForVsync", "(J)V");
FXL_CHECK(g_async_wait_for_vsync_method_ != nullptr);
return env->RegisterNatives(clazz, methods, arraysize(methods)) == 0;
}
struct PendingCallbackData {
VsyncWaiter::Callback callback;
PendingCallbackData(VsyncWaiter::Callback p_callback)
: callback(std::move(p_callback)) {
FXL_DCHECK(callback);
}
};
static jlong CreatePendingCallback(VsyncWaiter::Callback callback) {
// This delete for this new is balanced in the consume call.
auto data = new PendingCallbackData(std::move(callback));
return reinterpret_cast<jlong>(data);
}
static void ConsumePendingCallback(jlong java_baton,
fxl::TimePoint frame_start_time,
fxl::TimePoint frame_target_time) {
auto data = reinterpret_cast<PendingCallbackData*>(java_baton);
data->callback(frame_start_time, frame_target_time);
delete data;
}
} // namespace shell