| // 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/common/vsync_waiter.h" |
| |
| #include "flutter/fml/task_runner.h" |
| #include "flutter/fml/trace_event.h" |
| |
| namespace shell { |
| |
| #if defined(OS_FUCHSIA) |
| // In general, traces on Fuchsia are recorded across the whole system. |
| // Because of this, emitting a "VSYNC" event per flutter process is |
| // undesirable, as the events will collide with each other. We |
| // instead let another area of the system emit them. |
| static constexpr const char* kVsyncTraceName = "vsync callback"; |
| #else // defined(OS_FUCHSIA) |
| // Note: The tag name must be "VSYNC" (it is special) so that the |
| // "Highlight Vsync" checkbox in the timeline can be enabled. |
| static constexpr const char* kVsyncTraceName = "VSYNC"; |
| #endif // defined(OS_FUCHSIA) |
| |
| static constexpr const char* kVsyncFlowName = "VsyncFlow"; |
| |
| VsyncWaiter::VsyncWaiter(blink::TaskRunners task_runners) |
| : task_runners_(std::move(task_runners)) {} |
| |
| VsyncWaiter::~VsyncWaiter() = default; |
| |
| // Public method invoked by the animator. |
| void VsyncWaiter::AsyncWaitForVsync(Callback callback) { |
| if (!callback) { |
| return; |
| } |
| |
| TRACE_EVENT0("flutter", "AsyncWaitForVsync"); |
| |
| { |
| std::lock_guard<std::mutex> lock(callback_mutex_); |
| if (callback_) { |
| // The animator may request a frame more than once within a frame |
| // interval. Multiple calls to request frame must result in a single |
| // callback per frame interval. |
| TRACE_EVENT_INSTANT0("flutter", "MultipleCallsToVsyncInFrameInterval"); |
| return; |
| } |
| callback_ = std::move(callback); |
| } |
| AwaitVSync(); |
| } |
| |
| void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, |
| fml::TimePoint frame_target_time) { |
| Callback callback; |
| |
| { |
| std::lock_guard<std::mutex> lock(callback_mutex_); |
| callback = std::move(callback_); |
| } |
| |
| if (!callback) { |
| // This means that the vsync waiter implementation fired a callback for a |
| // request we did not make. This is a paranoid check but we still want to |
| // make sure we catch misbehaving vsync implementations. |
| TRACE_EVENT_INSTANT0("flutter", "MismatchedFrameCallback"); |
| return; |
| } |
| |
| auto flow_identifier = fml::tracing::TraceNonce(); |
| |
| // The base trace ensures that flows have a root to begin from if one does not |
| // exist. The trace viewer will ignore traces that have no base event trace. |
| // While all our message loops insert a base trace trace |
| // (MessageLoop::RunExpiredTasks), embedders may not. |
| TRACE_EVENT0("flutter", "VsyncFireCallback"); |
| |
| TRACE_FLOW_BEGIN("flutter", kVsyncFlowName, flow_identifier); |
| |
| task_runners_.GetUITaskRunner()->PostTaskForTime( |
| [callback, flow_identifier, frame_start_time, frame_target_time]() { |
| FML_TRACE_EVENT("flutter", kVsyncTraceName, "StartTime", |
| frame_start_time, "TargetTime", frame_target_time); |
| fml::tracing::TraceEventAsyncComplete( |
| "flutter", "VsyncSchedulingOverhead", fml::TimePoint::Now(), |
| frame_start_time); |
| callback(frame_start_time, frame_target_time); |
| TRACE_FLOW_END("flutter", kVsyncFlowName, flow_identifier); |
| }, |
| frame_start_time); |
| } |
| |
| float VsyncWaiter::GetDisplayRefreshRate() const { |
| return kUnknownRefreshRateFPS; |
| } |
| |
| } // namespace shell |