1 // Copyright 2017 The Chromium 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 #ifndef COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_MANAGER_H_
6 #define COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_MANAGER_H_
7 
8 #include <memory>
9 #include <string>
10 #include <unordered_map>
11 #include <vector>
12 
13 #include "base/compiler_specific.h"
14 #include "base/containers/flat_map.h"
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/observer_list.h"
19 #include "base/optional.h"
20 #include "components/viz/common/surfaces/frame_sink_id.h"
21 #include "components/viz/host/client_frame_sink_video_capturer.h"
22 #include "components/viz/host/hit_test/hit_test_query.h"
23 #include "components/viz/host/hit_test/hit_test_region_observer.h"
24 #include "components/viz/host/host_frame_sink_client.h"
25 #include "components/viz/host/viz_host_export.h"
26 #include "mojo/public/cpp/bindings/pending_receiver.h"
27 #include "mojo/public/cpp/bindings/pending_remote.h"
28 #include "mojo/public/cpp/bindings/receiver.h"
29 #include "mojo/public/cpp/bindings/remote.h"
30 #include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h"
31 
32 namespace base {
33 class SingleThreadTaskRunner;
34 }
35 
36 namespace viz {
37 
38 class SurfaceInfo;
39 
40 enum class ReportFirstSurfaceActivation { kYes, kNo };
41 
42 // Browser side wrapper of mojom::FrameSinkManager, to be used from the
43 // UI thread. Manages frame sinks and is intended to replace all usage of
44 // FrameSinkManagerImpl.
45 class VIZ_HOST_EXPORT HostFrameSinkManager
46     : public mojom::FrameSinkManagerClient {
47  public:
48   using DisplayHitTestQueryMap =
49       base::flat_map<FrameSinkId, std::unique_ptr<HitTestQuery>>;
50 
51   HostFrameSinkManager();
52   ~HostFrameSinkManager() override;
53 
display_hit_test_query()54   const DisplayHitTestQueryMap& display_hit_test_query() const {
55     return display_hit_test_query_;
56   }
57 
58   // Sets a local FrameSinkManagerImpl instance and connects directly to it.
59   void SetLocalManager(mojom::FrameSinkManager* frame_sink_manager);
60 
61   // Binds |this| as a FrameSinkManagerClient for |receiver| on |task_runner|.
62   // On Mac |task_runner| will be the resize helper task runner. May only be
63   // called once. If |task_runner| is null, it uses the default mojo task runner
64   // for the thread this call is made on.
65   void BindAndSetManager(
66       mojo::PendingReceiver<mojom::FrameSinkManagerClient> receiver,
67       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
68       mojo::PendingRemote<mojom::FrameSinkManager> remote);
69 
70   // Sets a callback to be notified when the connection to the FrameSinkManager
71   // on |frame_sink_manager_remote_| is lost.
72   void SetConnectionLostCallback(base::RepeatingClosure callback);
73 
74   // Registers |frame_sink_id| so that a client can submit CompositorFrames
75   // using it. This must be called before creating a CompositorFrameSink or
76   // registering FrameSinkId hierarchy.
77   //
78   // When the client is done submitting CompositorFrames to |frame_sink_id| then
79   // InvalidateFrameSink() should be called.
80   void RegisterFrameSinkId(const FrameSinkId& frame_sink_id,
81                            HostFrameSinkClient* client,
82                            ReportFirstSurfaceActivation report_activation);
83 
84   // Returns true if RegisterFrameSinkId() was called with |frame_sink_id| and
85   // InvalidateFrameSinkId() has not been called.
86   bool IsFrameSinkIdRegistered(const FrameSinkId& frame_sink_id) const;
87 
88   // Invalidates |frame_sink_id| when the client is done submitting
89   // CompositorFrames. If there is a CompositorFrameSink for |frame_sink_id|
90   // then it will be destroyed and the message pipe to the client will be
91   // closed.
92   //
93   // It's expected, but not enforced, that RegisterFrameSinkId() will never be
94   // called for |frame_sink_id| again. This is to avoid problems with re-entrant
95   // code. If the same client wants to submit CompositorFrames later a new
96   // FrameSinkId should be allocated.
97   void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id);
98 
99   // |debug_label| is used when printing out the surface hierarchy so we know
100   // which clients are contributing which surfaces.
101   void SetFrameSinkDebugLabel(const FrameSinkId& frame_sink_id,
102                               const std::string& debug_label);
103 
104   // Creates a connection from a display root to viz. Provides the same
105   // interfaces as CreateCompositorFramesink() plus the priviledged
106   // DisplayPrivate and (if requested) ExternalBeginFrameController interfaces.
107   // When no longer needed, call InvalidateFrameSinkId().
108   //
109   // If there is already a CompositorFrameSink for |frame_sink_id| then calling
110   // this will destroy the existing CompositorFrameSink and create a new one.
111   void CreateRootCompositorFrameSink(
112       mojom::RootCompositorFrameSinkParamsPtr params);
113 
114   // Creates a connection from a client to viz, using |request| and |client|,
115   // that allows the client to submit CompositorFrames. When no longer needed,
116   // call InvalidateFrameSinkId().
117   //
118   // If there is already a CompositorFrameSink for |frame_sink_id| then calling
119   // this will destroy the existing CompositorFrameSink and create a new one.
120   void CreateCompositorFrameSink(
121       const FrameSinkId& frame_sink_id,
122       mojo::PendingReceiver<mojom::CompositorFrameSink> receiver,
123       mojo::PendingRemote<mojom::CompositorFrameSinkClient> client);
124 
125   // Registers FrameSink hierarchy. It's expected that the parent will embed
126   // the child. If |parent_frame_sink_id| is registered then it will be added as
127   // a parent of |child_frame_sink_id| and the function will return true. If
128   // |parent_frame_sink_id| is not registered then the function will return
129   // false. A frame sink can have multiple parents.
130   bool RegisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id,
131                                   const FrameSinkId& child_frame_sink_id);
132 
133   // Unregisters FrameSink hierarchy. Client must have registered frame sink
134   // hierarchy before unregistering.
135   void UnregisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id,
136                                     const FrameSinkId& child_frame_sink_id);
137 
138   // Returns true if RegisterFrameSinkHierarchy() was called with the supplied
139   // arguments.
140   bool IsFrameSinkHierarchyRegistered(
141       const FrameSinkId& parent_frame_sink_id,
142       const FrameSinkId& child_frame_sink_id) const;
143 
144   // Returns the first ancestor of |start| (including |start|) that is a root.
145   base::Optional<FrameSinkId> FindRootFrameSinkId(
146       const FrameSinkId& start) const;
147 
148   // Asks viz to send updates regarding video activity to |observer|.
149   void AddVideoDetectorObserver(
150       mojo::PendingRemote<mojom::VideoDetectorObserver> observer);
151 
152   // Creates a FrameSinkVideoCapturer instance in viz.
153   void CreateVideoCapturer(
154       mojo::PendingReceiver<mojom::FrameSinkVideoCapturer> receiver);
155 
156   // Creates a FrameSinkVideoCapturer instance in viz and returns a
157   // ClientFrameSinkVideoCapturer that's connected to it. Clients should prefer
158   // this version because ClientFrameSinkVideoCapturer is resilient to viz
159   // crashes.
160   std::unique_ptr<ClientFrameSinkVideoCapturer> CreateVideoCapturer();
161 
162   // Marks the given SurfaceIds for destruction.
163   void EvictSurfaces(const std::vector<SurfaceId>& surface_ids);
164 
165   // Takes snapshot of a |surface_id| or a newer surface with the same
166   // FrameSinkId. The FrameSinkId is used to identify which frame we're
167   // interested in. The snapshot will only be taken if the LocalSurfaceId is at
168   // least the given LocalSurfaceId (|surface_id.local_frame_id()|). If the
169   // LocalSurfaceId is lower than the given id, then the request is queued up to
170   // be executed later.
171   void RequestCopyOfOutput(const SurfaceId& surface_id,
172                            std::unique_ptr<CopyOutputRequest> request);
173 
174   // Starts throttling the frame sinks specified by |frame_sink_ids| and all
175   // their descendant sinks to send BeginFrames at an interval of |interval|.
176   // |interval| should be greater than zero. Previous throttling operation
177   // on any frame sinks must be ended by EndThrottling() before applying the
178   // current throttling operation.
179   void StartThrottling(const std::vector<FrameSinkId>& frame_sink_ids,
180                        base::TimeDelta interval);
181 
182   // Ends throttling of all previously throttled frame sinks.
183   void EndThrottling();
184 
185   // Add/Remove an observer to receive notifications of when the host receives
186   // new hit test data.
187   void AddHitTestRegionObserver(HitTestRegionObserver* observer);
188   void RemoveHitTestRegionObserver(HitTestRegionObserver* observer);
189 
190   void SetHitTestAsyncQueriedDebugRegions(
191       const FrameSinkId& root_frame_sink_id,
192       const std::vector<FrameSinkId>& hit_test_async_queried_debug_queue);
193 
194   // Preserves the back buffer associated with the |root_sink_id|, even after
195   // the associated Display has been torn down, and returns an id for this cache
196   // entry.
197   uint32_t CacheBackBufferForRootSink(const FrameSinkId& root_sink_id);
198   void EvictCachedBackBuffer(uint32_t cache_id);
199 
200   void UpdateDebugRendererSettings(const DebugRendererSettings& debug_settings);
201 
debug_renderer_settings()202   const DebugRendererSettings& debug_renderer_settings() const {
203     return debug_renderer_settings_;
204   }
205 
206  private:
207   friend class HostFrameSinkManagerTest;
208   friend class HostFrameSinkManagerTestApi;
209 
210   struct FrameSinkData {
211     FrameSinkData();
212     FrameSinkData(FrameSinkData&& other);
213     ~FrameSinkData();
214     FrameSinkData& operator=(FrameSinkData&& other);
215 
IsFrameSinkRegisteredFrameSinkData216     bool IsFrameSinkRegistered() const { return client != nullptr; }
217 
218     // Returns true if there is nothing in FrameSinkData and it can be deleted.
IsEmptyFrameSinkData219     bool IsEmpty() const {
220       return !IsFrameSinkRegistered() && !has_created_compositor_frame_sink &&
221              parents.empty() && children.empty();
222     }
223 
224     // The client to be notified of changes to this FrameSink.
225     HostFrameSinkClient* client = nullptr;
226 
227     // Indicates whether or not this client cares to receive
228     // FirstSurfaceActivation notifications.
229     ReportFirstSurfaceActivation report_activation =
230         ReportFirstSurfaceActivation::kYes;
231 
232     // The name of the HostFrameSinkClient used for debug purposes.
233     std::string debug_label;
234 
235     // If the frame sink is a root that corresponds to a Display.
236     bool is_root = false;
237 
238     // If a mojom::CompositorFrameSink was created for this FrameSinkId. This
239     // will always be false if not using Mojo.
240     bool has_created_compositor_frame_sink = false;
241 
242     // Track frame sink hierarchy in both directions.
243     std::vector<FrameSinkId> parents;
244     std::vector<FrameSinkId> children;
245 
246    private:
247     DISALLOW_COPY_AND_ASSIGN(FrameSinkData);
248   };
249 
250   // Handles connection loss to |frame_sink_manager_remote_|. This should only
251   // happen when the GPU process crashes.
252   void OnConnectionLost();
253 
254   // Registers FrameSinkId and FrameSink hierarchy again after connection loss.
255   void RegisterAfterConnectionLoss();
256 
257   // mojom::FrameSinkManagerClient:
258   void OnFrameTokenChanged(const FrameSinkId& frame_sink_id,
259                            uint32_t frame_token) override;
260   void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override;
261   void OnAggregatedHitTestRegionListUpdated(
262       const FrameSinkId& frame_sink_id,
263       const std::vector<AggregatedHitTestRegion>& hit_test_data) override;
264 
265   // This will point to |frame_sink_manager_remote_| if using mojo or it may
266   // point directly at FrameSinkManagerImpl in tests. Use this to make function
267   // calls.
268   mojom::FrameSinkManager* frame_sink_manager_ = nullptr;
269 
270   // Connections to/from FrameSinkManagerImpl.
271   mojo::Remote<mojom::FrameSinkManager> frame_sink_manager_remote_;
272   mojo::Receiver<mojom::FrameSinkManagerClient> receiver_{this};
273 
274   // Per CompositorFrameSink data.
275   std::unordered_map<FrameSinkId, FrameSinkData, FrameSinkIdHash>
276       frame_sink_data_map_;
277 
278   // If |frame_sink_manager_remote_| connection was lost.
279   bool connection_was_lost_ = false;
280 
281   base::RepeatingClosure connection_lost_callback_;
282 
283   DisplayHitTestQueryMap display_hit_test_query_;
284 
285   // TODO(jonross): Separate out all hit testing work into its own separate
286   // class.
287   base::ObserverList<HitTestRegionObserver>::Unchecked observers_;
288 
289   uint32_t next_cache_back_buffer_id_ = 1;
290   uint32_t min_valid_cache_back_buffer_id_ = 1;
291 
292   // This is kept in sync with implementation.
293   DebugRendererSettings debug_renderer_settings_;
294 
295   base::WeakPtrFactory<HostFrameSinkManager> weak_ptr_factory_{this};
296 
297   DISALLOW_COPY_AND_ASSIGN(HostFrameSinkManager);
298 };
299 
300 }  // namespace viz
301 
302 #endif  // COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_MANAGER_H_
303