• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "session_connection.h"
6 
7 #include "flutter/fml/make_copyable.h"
8 #include "lib/fidl/cpp/optional.h"
9 #include "lib/ui/scenic/cpp/commands.h"
10 #include "vsync_recorder.h"
11 #include "vsync_waiter.h"
12 
13 namespace flutter_runner {
14 
SessionConnection(std::string debug_label,fuchsia::ui::views::ViewToken view_token,fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session,fml::closure session_error_callback,zx_handle_t vsync_event_handle)15 SessionConnection::SessionConnection(
16     std::string debug_label,
17     fuchsia::ui::views::ViewToken view_token,
18     fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session,
19     fml::closure session_error_callback,
20     zx_handle_t vsync_event_handle)
21     : debug_label_(std::move(debug_label)),
22       session_wrapper_(session.Bind(), nullptr),
23       root_view_(&session_wrapper_, std::move(view_token.value), debug_label),
24       root_node_(&session_wrapper_),
25       surface_producer_(
26           std::make_unique<VulkanSurfaceProducer>(&session_wrapper_)),
27       scene_update_context_(&session_wrapper_, surface_producer_.get()),
28       vsync_event_handle_(vsync_event_handle) {
29   session_wrapper_.set_error_handler(
30       [callback = session_error_callback](zx_status_t status) { callback(); });
31 
32   session_wrapper_.SetDebugName(debug_label_);
33 
34   // TODO(SCN-975): Re-enable.
35   //   view_->GetToken(std::bind(&PlatformView::ConnectSemanticsProvider, this,
36   //                             std::placeholders::_1));
37 
38   root_view_.AddChild(root_node_);
39   root_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask |
40                           fuchsia::ui::gfx::kSizeChangeHintEventMask);
41 
42   // Signal is initially high indicating availability of the session.
43   ToggleSignal(vsync_event_handle_, true);
44 
45   PresentSession();
46 }
47 
48 SessionConnection::~SessionConnection() = default;
49 
Present(flutter::CompositorContext::ScopedFrame & frame)50 void SessionConnection::Present(
51     flutter::CompositorContext::ScopedFrame& frame) {
52   TRACE_EVENT0("gfx", "SessionConnection::Present");
53   TRACE_FLOW_BEGIN("gfx", "SessionConnection::PresentSession",
54                    next_present_session_trace_id_);
55 
56   // Throttle vsync if presentation callback is already pending. This allows
57   // the paint tasks for this frame to execute in parallel with presentation
58   // of last frame but still provides back-pressure to prevent us from queuing
59   // even more work.
60   if (presentation_callback_pending_) {
61     present_session_pending_ = true;
62     ToggleSignal(vsync_event_handle_, false);
63   } else {
64     PresentSession();
65   }
66 
67   // Flush all session ops. Paint tasks have not yet executed but those are
68   // fenced. The compositor can start processing ops while we finalize paint
69   // tasks.
70   PresentSession();
71 
72   // Execute paint tasks and signal fences.
73   auto surfaces_to_submit = scene_update_context_.ExecutePaintTasks(frame);
74 
75   // Tell the surface producer that a present has occurred so it can perform
76   // book-keeping on buffer caches.
77   surface_producer_->OnSurfacesPresented(std::move(surfaces_to_submit));
78 }
79 
OnSessionSizeChangeHint(float width_change_factor,float height_change_factor)80 void SessionConnection::OnSessionSizeChangeHint(float width_change_factor,
81                                                 float height_change_factor) {
82   surface_producer_->OnSessionSizeChangeHint(width_change_factor,
83                                              height_change_factor);
84 }
85 
EnqueueClearOps()86 void SessionConnection::EnqueueClearOps() {
87   // We are going to be sending down a fresh node hierarchy every frame. So just
88   // enqueue a detach op on the imported root node.
89   session_wrapper_.Enqueue(scenic::NewDetachChildrenCmd(root_node_.id()));
90 }
91 
PresentSession()92 void SessionConnection::PresentSession() {
93   TRACE_EVENT0("gfx", "SessionConnection::PresentSession");
94   while (processed_present_session_trace_id_ < next_present_session_trace_id_) {
95     TRACE_FLOW_END("gfx", "SessionConnection::PresentSession",
96                    processed_present_session_trace_id_);
97     processed_present_session_trace_id_++;
98   }
99   TRACE_FLOW_BEGIN("gfx", "Session::Present", next_present_trace_id_);
100   next_present_trace_id_++;
101 
102   // Presentation callback is pending as a result of Present() call below.
103   presentation_callback_pending_ = true;
104 
105   // Flush all session ops. Paint tasks may not yet have executed but those are
106   // fenced. The compositor can start processing ops while we finalize paint
107   // tasks.
108   session_wrapper_.Present(
109       0,  // presentation_time. (placeholder).
110       [this, handle = vsync_event_handle_](
111           fuchsia::images::PresentationInfo presentation_info) {
112         presentation_callback_pending_ = false;
113         VsyncRecorder::GetInstance().UpdateVsyncInfo(presentation_info);
114         // Process pending PresentSession() calls.
115         if (present_session_pending_) {
116           present_session_pending_ = false;
117           PresentSession();
118         }
119         ToggleSignal(handle, true);
120       }  // callback
121   );
122 
123   // Prepare for the next frame. These ops won't be processed till the next
124   // present.
125   EnqueueClearOps();
126 }
127 
ToggleSignal(zx_handle_t handle,bool set)128 void SessionConnection::ToggleSignal(zx_handle_t handle, bool set) {
129   const auto signal = VsyncWaiter::SessionPresentSignal;
130   auto status = zx_object_signal(handle,            // handle
131                                  set ? 0 : signal,  // clear mask
132                                  set ? signal : 0   // set mask
133   );
134   if (status != ZX_OK) {
135     FML_LOG(ERROR) << "Could not toggle vsync signal: " << set;
136   }
137 }
138 
139 }  // namespace flutter_runner
140