| // 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 |