// 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. #ifndef FLUTTER_SHELL_COMMON_ANIMATOR_H_ #define FLUTTER_SHELL_COMMON_ANIMATOR_H_ #include #include "flutter/common/task_runners.h" #include "flutter/flow/frame_timings.h" #include "flutter/fml/memory/ref_ptr.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/fml/synchronization/semaphore.h" #include "flutter/fml/time/time_point.h" #include "flutter/shell/common/pipeline.h" #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/vsync_waiter.h" namespace flutter { namespace testing { class ShellTest; } /// Executor of animations. /// /// In conjunction with the |VsyncWaiter| it allows callers (typically Dart /// code) to schedule work that ends up generating a |LayerTree|. class Animator final { public: class Delegate { public: virtual void OnAnimatorBeginFrame(fml::TimePoint frame_target_time, uint64_t frame_number) = 0; virtual void OnAnimatorNotifyIdle(fml::TimeDelta deadline) = 0; virtual void OnAnimatorUpdateLatestFrameTargetTime( fml::TimePoint frame_target_time) = 0; virtual void OnAnimatorDraw(std::shared_ptr pipeline) = 0; virtual void OnAnimatorDrawLastLayerTrees( std::unique_ptr frame_timings_recorder) = 0; }; Animator(Delegate& delegate, const TaskRunners& task_runners, std::unique_ptr waiter); ~Animator(); void RequestFrame(bool regenerate_layer_trees = true); //-------------------------------------------------------------------------- /// @brief Tells the Animator that all views that should render for this /// frame have been rendered. /// /// In regular frames, since all `Render` calls must take place /// during a vsync task, the Animator knows that all views have /// been rendered at the end of the vsync task, therefore calling /// this method is not needed. /// /// However, the engine might decide to start it a bit earlier, for /// example, if the engine decides that no more views can be /// rendered, so that the rasterization can start a bit earlier. /// /// This method is also useful in warm-up frames. In a warm up /// frame, `Animator::Render` is called out of vsync tasks, and /// Animator requires an explicit end-of-frame call to know when to /// send the layer trees to the pipeline. /// /// For more about warm up frames, see /// `PlatformDispatcher.scheduleWarmUpFrame`. /// void OnAllViewsRendered(); //-------------------------------------------------------------------------- /// @brief Tells the Animator that this frame needs to render another view. /// /// This method must be called during a vsync callback, or /// technically, between Animator::BeginFrame and Animator::EndFrame /// (both private methods). Otherwise, this call will be ignored. /// void Render(int64_t view_id, std::unique_ptr layer_tree, float device_pixel_ratio); const std::weak_ptr GetVsyncWaiter() const; //-------------------------------------------------------------------------- /// @brief Schedule a secondary callback to be executed right after the /// main `VsyncWaiter::AsyncWaitForVsync` callback (which is added /// by `Animator::RequestFrame`). /// /// Like the callback in `AsyncWaitForVsync`, this callback is /// only scheduled to be called once, and it's supposed to be /// called in the UI thread. If there is no AsyncWaitForVsync /// callback (`Animator::RequestFrame` is not called), this /// secondary callback will still be executed at vsync. /// /// This callback is used to provide the vsync signal needed by /// `SmoothPointerDataDispatcher`, and for our own flow events. /// /// @see `PointerDataDispatcher::ScheduleSecondaryVsyncCallback`. void ScheduleSecondaryVsyncCallback(uintptr_t id, const fml::closure& callback); // Enqueue |trace_flow_id| into |trace_flow_ids_|. The flow event will be // ended at either the next frame, or the next vsync interval with no active // rendering. void EnqueueTraceFlowId(uint64_t trace_flow_id); private: // Animator's work during a vsync is split into two methods, BeginFrame and // EndFrame. The two methods should be called synchronously back-to-back to // avoid being interrupted by a regular vsync. The reason to split them is to // allow ShellTest::PumpOneFrame to insert a Render in between. void BeginFrame(std::unique_ptr frame_timings_recorder); void EndFrame(); bool CanReuseLastLayerTrees(); void DrawLastLayerTrees( std::unique_ptr frame_timings_recorder); void AwaitVSync(); // Clear |trace_flow_ids_| if |frame_scheduled_| is false. void ScheduleMaybeClearTraceFlowIds(); Delegate& delegate_; TaskRunners task_runners_; std::shared_ptr waiter_; std::unique_ptr frame_timings_recorder_; std::unordered_map> layer_trees_tasks_; uint64_t frame_request_number_ = 1; fml::TimeDelta dart_frame_deadline_; std::shared_ptr layer_tree_pipeline_; fml::Semaphore pending_frame_semaphore_; FramePipeline::ProducerContinuation producer_continuation_; bool regenerate_layer_trees_ = false; bool frame_scheduled_ = false; std::deque trace_flow_ids_; bool has_rendered_ = false; fml::WeakPtrFactory weak_factory_; friend class testing::ShellTest; FML_DISALLOW_COPY_AND_ASSIGN(Animator); }; } // namespace flutter #endif // FLUTTER_SHELL_COMMON_ANIMATOR_H_