| // 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_PLATFORM_FUCHSIA_FLUTTER_GFX_SESSION_CONNECTION_H_ |
| #define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_GFX_SESSION_CONNECTION_H_ |
| |
| #include <fuchsia/scenic/scheduling/cpp/fidl.h> |
| #include <fuchsia/ui/scenic/cpp/fidl.h> |
| #include <lib/async/dispatcher.h> |
| #include <lib/fidl/cpp/interface_handle.h> |
| #include <lib/inspect/cpp/inspect.h> |
| #include <lib/ui/scenic/cpp/session.h> |
| |
| #include "flutter/fml/closure.h" |
| #include "flutter/fml/macros.h" |
| |
| #include "fml/time/time_delta.h" |
| #include "vsync_waiter.h" |
| |
| #include <mutex> |
| |
| namespace flutter_runner { |
| |
| using on_frame_presented_event = |
| std::function<void(fuchsia::scenic::scheduling::FramePresentedInfo)>; |
| |
| struct FlutterFrameTimes { |
| fml::TimePoint frame_start; |
| fml::TimePoint frame_target; |
| }; |
| |
| struct VsyncInfo { |
| fml::TimePoint presentation_time; |
| fml::TimeDelta presentation_interval; |
| }; |
| |
| // Assume a 60hz refresh rate before we have enough past |
| // |fuchsia::scenic::scheduling::PresentationInfo|s to calculate it ourselves. |
| static constexpr fml::TimeDelta kDefaultPresentationInterval = |
| fml::TimeDelta::FromSecondsF(1.0 / 60.0); |
| |
| // The component residing on the raster thread that is responsible for |
| // maintaining the Scenic session connection and presenting node updates. |
| class GfxSessionConnection final { |
| public: |
| static FlutterFrameTimes GetTargetTimes(fml::TimeDelta vsync_offset, |
| fml::TimeDelta vsync_interval, |
| fml::TimePoint last_targeted_vsync, |
| fml::TimePoint now, |
| fml::TimePoint next_vsync); |
| |
| static fml::TimePoint CalculateNextLatchPoint( |
| fml::TimePoint present_requested_time, |
| fml::TimePoint now, |
| fml::TimePoint last_latch_point_targeted, |
| fml::TimeDelta flutter_frame_build_time, |
| fml::TimeDelta vsync_interval, |
| std::deque<std::pair<fml::TimePoint, fml::TimePoint>>& |
| future_presentation_infos); |
| |
| static fml::TimePoint SnapToNextPhase( |
| const fml::TimePoint now, |
| const fml::TimePoint last_frame_presentation_time, |
| const fml::TimeDelta presentation_interval); |
| |
| // Update the next Vsync info to |next_presentation_info_|. This is expected |
| // to be called in |scenic::Session::Present2| immedaite callbacks with the |
| // presentation info provided by Scenic. Only the next vsync |
| // information will be saved (in order to handle edge cases involving |
| // multiple Scenic sessions in the same process). This function is safe to |
| // call from any thread. |
| static fuchsia::scenic::scheduling::PresentationInfo UpdatePresentationInfo( |
| fuchsia::scenic::scheduling::FuturePresentationTimes future_info, |
| fuchsia::scenic::scheduling::PresentationInfo& presentation_info); |
| |
| GfxSessionConnection(std::string debug_label, |
| inspect::Node inspect_node, |
| fuchsia::ui::scenic::SessionHandle session, |
| fml::closure session_error_callback, |
| on_frame_presented_event on_frame_presented_callback, |
| uint64_t max_frames_in_flight, |
| fml::TimeDelta vsync_offset); |
| |
| ~GfxSessionConnection(); |
| |
| scenic::Session* get() { return &session_wrapper_; } |
| |
| // Call to request that the all enqueued Session ops since the last |Present| |
| // be sent to Scenic. |
| void Present(); |
| |
| // Used to implement VsyncWaiter functionality. |
| void AwaitVsync(FireCallbackCallback callback); |
| void AwaitVsyncForSecondaryCallback(FireCallbackCallback callback); |
| |
| private: |
| void PresentSession(); |
| |
| void FireCallbackMaybe(); |
| |
| FlutterFrameTimes GetTargetTimesHelper(bool secondary_callback); |
| VsyncInfo GetCurrentVsyncInfo() const; |
| |
| scenic::Session session_wrapper_; |
| |
| inspect::Node inspect_node_; |
| inspect::UintProperty secondary_vsyncs_completed_; |
| inspect::UintProperty vsyncs_requested_; |
| inspect::UintProperty vsyncs_completed_; |
| inspect::UintProperty presents_requested_; |
| inspect::UintProperty presents_submitted_; |
| inspect::UintProperty presents_completed_; |
| inspect::IntProperty last_secondary_vsync_completed_; |
| inspect::IntProperty last_vsync_requested_; |
| inspect::IntProperty last_vsync_completed_; |
| inspect::IntProperty last_frame_requested_; |
| inspect::IntProperty last_frame_presented_; |
| inspect::IntProperty last_frame_completed_; |
| async_dispatcher_t* inspect_dispatcher_; |
| |
| on_frame_presented_event on_frame_presented_callback_; |
| |
| fml::TimePoint last_latch_point_targeted_; |
| fml::TimePoint present_requested_time_; |
| |
| std::deque<std::pair<fml::TimePoint, fml::TimePoint>> |
| future_presentation_infos_ = {}; |
| |
| bool initialized_ = false; |
| |
| // A flow event trace id for following |Session::Present| calls into |
| // Scenic. This will be incremented each |Session::Present| call. By |
| // convention, the Scenic side will also contain its own trace id that |
| // begins at 0, and is incremented each |Session::Present| call. |
| uint64_t next_present_trace_id_ = 0; |
| uint64_t next_present_session_trace_id_ = 0; |
| uint64_t processed_present_session_trace_id_ = 0; |
| |
| // The maximum number of frames Flutter sent to Scenic that it can have |
| // outstanding at any time. This is equivalent to how many times it has |
| // called Present2() before receiving an OnFramePresented() event. |
| const int kMaxFramesInFlight; |
| |
| int frames_in_flight_ = 0; |
| bool present_session_pending_ = false; |
| |
| // The time from vsync that the Flutter animator should begin its frames. This |
| // is non-zero so that Flutter and Scenic compete less for CPU and GPU time. |
| fml::TimeDelta vsync_offset_; |
| |
| // Variables for recording past and future vsync info, as reported by Scenic. |
| fml::TimePoint last_presentation_time_; |
| fuchsia::scenic::scheduling::PresentationInfo next_presentation_info_; |
| |
| // Flutter framework pipeline logic. |
| |
| // The following fields can be accessed from both the raster and UI threads, |
| // so guard them with this mutex. If performance dictates, this could probably |
| // be made lock-free, but it's much easier to reason about with this mutex. |
| std::mutex mutex_; |
| |
| // This is the last Vsync we submitted as the frame_target_time to |
| // FireCallback(). This value should be strictly increasing in order to |
| // guarantee that animation code that relies on target vsyncs works correctly, |
| // and that Flutter is not producing multiple frames in a small interval. |
| fml::TimePoint last_targeted_vsync_; |
| |
| // This is true iff AwaitVSync() was called but we could not schedule a frame. |
| bool fire_callback_request_pending_ = false; |
| |
| // The callback passed in from VsyncWaiter which eventually runs on the UI |
| // thread. |
| FireCallbackCallback fire_callback_; |
| |
| // Generates WeakPtrs to the instance of the class so callbacks can verify |
| // that the instance is still in-scope before accessing state. |
| // This must be the last field in the class. |
| fml::WeakPtrFactory<GfxSessionConnection> weak_factory_; |
| |
| FML_DISALLOW_COPY_AND_ASSIGN(GfxSessionConnection); |
| }; |
| |
| } // namespace flutter_runner |
| |
| #endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_GFX_SESSION_CONNECTION_H_ |