blob: 89a852ae8ff339c053a07e216003b0c634d9d1a3 [file] [log] [blame]
// 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/impeller/toolkit/android/choreographer.h"
#include "flutter/fml/message_loop.h"
namespace impeller::android {
Choreographer& Choreographer::GetInstance() {
static thread_local Choreographer tChoreographer;
return tChoreographer;
}
Choreographer::Choreographer() {
if (!IsAvailableOnPlatform()) {
return;
}
// We need a message loop on the current thread for the choreographer to
// schedule callbacks for us on.
fml::MessageLoop::EnsureInitializedForCurrentThread();
instance_ = GetProcTable().AChoreographer_getInstance();
}
Choreographer::~Choreographer() = default;
bool Choreographer::IsValid() const {
return !!instance_;
}
static Choreographer::FrameTimePoint ClockMonotonicNanosToFrameTimePoint(
int64_t p_nanos) {
return Choreographer::FrameTimePoint{std::chrono::nanoseconds(p_nanos)};
}
bool Choreographer::PostFrameCallback(FrameCallback callback) const {
if (!callback || !IsValid()) {
return false;
}
struct InFlightData {
FrameCallback callback;
};
auto data = std::make_unique<InFlightData>();
data->callback = std::move(callback);
const auto& table = GetProcTable();
if (table.AChoreographer_postFrameCallback64) {
table.AChoreographer_postFrameCallback64(
const_cast<AChoreographer*>(instance_),
[](int64_t nanos, void* p_data) {
auto data = reinterpret_cast<InFlightData*>(p_data);
data->callback(ClockMonotonicNanosToFrameTimePoint(nanos));
delete data;
},
data.release());
return true;
} else if (table.AChoreographer_postFrameCallback) {
table.AChoreographer_postFrameCallback(
const_cast<AChoreographer*>(instance_),
[](long /*NOLINT*/ nanos, void* p_data) {
auto data = reinterpret_cast<InFlightData*>(p_data);
data->callback(ClockMonotonicNanosToFrameTimePoint(nanos));
delete data;
},
data.release());
return true;
}
// The validity check should have tripped by now.
FML_UNREACHABLE();
return false;
}
bool Choreographer::IsAvailableOnPlatform() {
return GetProcTable().AChoreographer_getInstance &&
(GetProcTable().AChoreographer_postFrameCallback64 ||
GetProcTable().AChoreographer_postFrameCallback);
}
} // namespace impeller::android