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 #include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/metrics/histogram.h"
11 #include "base/metrics/histogram_functions.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/trace_event/trace_event.h"
14 #include "cc/base/histograms.h"
15 #include "cc/trees/layer_tree_frame_sink_client.h"
16 #include "components/viz/common/features.h"
17 #include "components/viz/common/frame_sinks/begin_frame_args.h"
18 #include "components/viz/common/hit_test/hit_test_region_list.h"
19 #include "components/viz/common/quads/compositor_frame.h"
20 
21 namespace cc {
22 namespace mojo_embedder {
23 
24 AsyncLayerTreeFrameSink::InitParams::InitParams() = default;
25 AsyncLayerTreeFrameSink::InitParams::~InitParams() = default;
26 
27 AsyncLayerTreeFrameSink::UnboundMessagePipes::UnboundMessagePipes() = default;
28 AsyncLayerTreeFrameSink::UnboundMessagePipes::~UnboundMessagePipes() = default;
29 
HasUnbound() const30 bool AsyncLayerTreeFrameSink::UnboundMessagePipes::HasUnbound() const {
31   return client_receiver.is_valid() &&
32          (compositor_frame_sink_remote.is_valid() ^
33           compositor_frame_sink_associated_remote.is_valid());
34 }
35 
36 AsyncLayerTreeFrameSink::UnboundMessagePipes::UnboundMessagePipes(
37     UnboundMessagePipes&& other) = default;
38 
AsyncLayerTreeFrameSink(scoped_refptr<viz::ContextProvider> context_provider,scoped_refptr<viz::RasterContextProvider> worker_context_provider,InitParams * params)39 AsyncLayerTreeFrameSink::AsyncLayerTreeFrameSink(
40     scoped_refptr<viz::ContextProvider> context_provider,
41     scoped_refptr<viz::RasterContextProvider> worker_context_provider,
42     InitParams* params)
43     : LayerTreeFrameSink(std::move(context_provider),
44                          std::move(worker_context_provider),
45                          std::move(params->compositor_task_runner),
46                          params->gpu_memory_buffer_manager),
47       synthetic_begin_frame_source_(
48           std::move(params->synthetic_begin_frame_source)),
49       pipes_(std::move(params->pipes)),
50       wants_animate_only_begin_frames_(
51           params->wants_animate_only_begin_frames) {
52   DETACH_FROM_THREAD(thread_checker_);
53 }
54 
~AsyncLayerTreeFrameSink()55 AsyncLayerTreeFrameSink::~AsyncLayerTreeFrameSink() {}
56 
BindToClient(LayerTreeFrameSinkClient * client)57 bool AsyncLayerTreeFrameSink::BindToClient(LayerTreeFrameSinkClient* client) {
58   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
59 
60   if (!LayerTreeFrameSink::BindToClient(client))
61     return false;
62 
63   DCHECK(pipes_.HasUnbound());
64   if (pipes_.compositor_frame_sink_remote.is_valid()) {
65     compositor_frame_sink_.Bind(std::move(pipes_.compositor_frame_sink_remote));
66     compositor_frame_sink_.set_disconnect_with_reason_handler(
67         base::BindOnce(&AsyncLayerTreeFrameSink::OnMojoConnectionError,
68                        weak_factory_.GetWeakPtr()));
69     compositor_frame_sink_ptr_ = compositor_frame_sink_.get();
70   } else if (pipes_.compositor_frame_sink_associated_remote.is_valid()) {
71     compositor_frame_sink_associated_.Bind(
72         std::move(pipes_.compositor_frame_sink_associated_remote));
73     compositor_frame_sink_associated_.set_disconnect_with_reason_handler(
74         base::BindOnce(&AsyncLayerTreeFrameSink::OnMojoConnectionError,
75                        weak_factory_.GetWeakPtr()));
76     compositor_frame_sink_ptr_ = compositor_frame_sink_associated_.get();
77   }
78   client_receiver_.Bind(std::move(pipes_.client_receiver),
79                         compositor_task_runner_);
80 
81   if (synthetic_begin_frame_source_) {
82     client->SetBeginFrameSource(synthetic_begin_frame_source_.get());
83   } else {
84     begin_frame_source_ = std::make_unique<viz::ExternalBeginFrameSource>(this);
85     begin_frame_source_->OnSetBeginFrameSourcePaused(begin_frames_paused_);
86     client->SetBeginFrameSource(begin_frame_source_.get());
87   }
88 
89   if (wants_animate_only_begin_frames_)
90     compositor_frame_sink_->SetWantsAnimateOnlyBeginFrames();
91 
92   compositor_frame_sink_ptr_->InitializeCompositorFrameSinkType(
93       viz::mojom::CompositorFrameSinkType::kLayerTree);
94 
95   return true;
96 }
97 
DetachFromClient()98 void AsyncLayerTreeFrameSink::DetachFromClient() {
99   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
100   client_->SetBeginFrameSource(nullptr);
101   begin_frame_source_.reset();
102   synthetic_begin_frame_source_.reset();
103   client_receiver_.reset();
104   compositor_frame_sink_.reset();
105   compositor_frame_sink_associated_.reset();
106   compositor_frame_sink_ptr_ = nullptr;
107   LayerTreeFrameSink::DetachFromClient();
108 }
109 
SetLocalSurfaceId(const viz::LocalSurfaceId & local_surface_id)110 void AsyncLayerTreeFrameSink::SetLocalSurfaceId(
111     const viz::LocalSurfaceId& local_surface_id) {
112   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
113   DCHECK(local_surface_id.is_valid());
114   local_surface_id_ = local_surface_id;
115 }
116 
SubmitCompositorFrame(viz::CompositorFrame frame,bool hit_test_data_changed,bool show_hit_test_borders)117 void AsyncLayerTreeFrameSink::SubmitCompositorFrame(
118     viz::CompositorFrame frame,
119     bool hit_test_data_changed,
120     bool show_hit_test_borders) {
121   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
122   DCHECK(compositor_frame_sink_ptr_);
123   DCHECK(frame.metadata.begin_frame_ack.has_damage);
124   DCHECK(frame.metadata.begin_frame_ack.frame_id.IsSequenceValid());
125 
126   TRACE_EVENT_WITH_FLOW1(
127       "viz,benchmark", "Graphics.Pipeline",
128       TRACE_ID_GLOBAL(frame.metadata.begin_frame_ack.trace_id),
129       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
130       "SubmitCompositorFrame");
131 
132   if (local_surface_id_ == last_submitted_local_surface_id_) {
133     DCHECK_EQ(last_submitted_device_scale_factor_, frame.device_scale_factor());
134     DCHECK_EQ(last_submitted_size_in_pixels_.height(),
135               frame.size_in_pixels().height());
136     DCHECK_EQ(last_submitted_size_in_pixels_.width(),
137               frame.size_in_pixels().width());
138   }
139 
140   base::Optional<viz::HitTestRegionList> hit_test_region_list =
141       client_->BuildHitTestData();
142 
143   if (show_hit_test_borders && hit_test_region_list)
144     hit_test_region_list->flags |= viz::HitTestRegionFlags::kHitTestDebug;
145 
146   // If |hit_test_data_changed| was set or local_surface_id has been updated,
147   // we always send hit-test data; otherwise we check for equality with the
148   // last submitted hit-test data for possible optimization.
149   if (!hit_test_region_list) {
150     last_hit_test_data_ = viz::HitTestRegionList();
151   } else if (!hit_test_data_changed &&
152              local_surface_id_ == last_submitted_local_surface_id_) {
153     if (viz::HitTestRegionList::IsEqual(*hit_test_region_list,
154                                         last_hit_test_data_)) {
155       DCHECK(!viz::HitTestRegionList::IsEqual(*hit_test_region_list,
156                                               viz::HitTestRegionList()));
157       hit_test_region_list = base::nullopt;
158     } else {
159       last_hit_test_data_ = *hit_test_region_list;
160     }
161 
162     UMA_HISTOGRAM_BOOLEAN("Event.VizHitTest.HitTestDataIsEqualAccuracy",
163                           !hit_test_region_list);
164   } else {
165     last_hit_test_data_ = *hit_test_region_list;
166   }
167 
168   if (last_submitted_local_surface_id_ != local_surface_id_) {
169     last_submitted_local_surface_id_ = local_surface_id_;
170     last_submitted_device_scale_factor_ = frame.device_scale_factor();
171     last_submitted_size_in_pixels_ = frame.size_in_pixels();
172 
173     // These traces are split into two due to the incoming flow using
174     // TRACE_ID_LOCAL, and the outgoing flow using TRACE_ID_GLOBAL. This is
175     // needed to ensure the incoming flow is not messed up. The outgoing flow is
176     // going to a different process.
177     TRACE_EVENT_WITH_FLOW2(
178         TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
179         "LocalSurfaceId.Submission.Flow",
180         TRACE_ID_LOCAL(local_surface_id_.submission_trace_id()),
181         TRACE_EVENT_FLAG_FLOW_IN, "step", "SubmitCompositorFrame", "surface_id",
182         local_surface_id_.ToString());
183     TRACE_EVENT_WITH_FLOW2(
184         TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
185         "LocalSurfaceId.Submission.Flow",
186         TRACE_ID_GLOBAL(local_surface_id_.submission_trace_id()),
187         TRACE_EVENT_FLAG_FLOW_OUT, "step", "SubmitCompositorFrame",
188         "surface_id", local_surface_id_.ToString());
189   }
190 
191   // The trace_id is negated in order to keep the Graphics.Pipeline and
192   // Event.Pipeline flows separated.
193   const int64_t trace_id = ~frame.metadata.begin_frame_ack.trace_id;
194   TRACE_EVENT_WITH_FLOW1(TRACE_DISABLED_BY_DEFAULT("viz.hit_testing_flow"),
195                          "Event.Pipeline", TRACE_ID_GLOBAL(trace_id),
196                          TRACE_EVENT_FLAG_FLOW_OUT, "step",
197                          "SubmitHitTestData");
198 
199   compositor_frame_sink_ptr_->SubmitCompositorFrame(
200       local_surface_id_, std::move(frame), std::move(hit_test_region_list), 0);
201 }
202 
DidNotProduceFrame(const viz::BeginFrameAck & ack)203 void AsyncLayerTreeFrameSink::DidNotProduceFrame(
204     const viz::BeginFrameAck& ack) {
205   DCHECK(compositor_frame_sink_ptr_);
206   DCHECK(!ack.has_damage);
207   DCHECK(ack.frame_id.IsSequenceValid());
208   TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
209                          TRACE_ID_GLOBAL(ack.trace_id),
210                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
211                          "step", "DidNotProduceFrame");
212   compositor_frame_sink_ptr_->DidNotProduceFrame(ack);
213 }
214 
DidAllocateSharedBitmap(base::ReadOnlySharedMemoryRegion region,const viz::SharedBitmapId & id)215 void AsyncLayerTreeFrameSink::DidAllocateSharedBitmap(
216     base::ReadOnlySharedMemoryRegion region,
217     const viz::SharedBitmapId& id) {
218   DCHECK(compositor_frame_sink_ptr_);
219   compositor_frame_sink_ptr_->DidAllocateSharedBitmap(std::move(region), id);
220 }
221 
DidDeleteSharedBitmap(const viz::SharedBitmapId & id)222 void AsyncLayerTreeFrameSink::DidDeleteSharedBitmap(
223     const viz::SharedBitmapId& id) {
224   DCHECK(compositor_frame_sink_ptr_);
225   compositor_frame_sink_ptr_->DidDeleteSharedBitmap(id);
226 }
227 
DidReceiveCompositorFrameAck(const std::vector<viz::ReturnedResource> & resources)228 void AsyncLayerTreeFrameSink::DidReceiveCompositorFrameAck(
229     const std::vector<viz::ReturnedResource>& resources) {
230   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
231   client_->ReclaimResources(resources);
232   client_->DidReceiveCompositorFrameAck();
233 }
234 
OnBeginFrame(const viz::BeginFrameArgs & args,const viz::FrameTimingDetailsMap & timing_details)235 void AsyncLayerTreeFrameSink::OnBeginFrame(
236     const viz::BeginFrameArgs& args,
237     const viz::FrameTimingDetailsMap& timing_details) {
238   for (const auto& pair : timing_details) {
239     client_->DidPresentCompositorFrame(pair.first, pair.second);
240   }
241 
242   if (!needs_begin_frames_) {
243     TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
244                            TRACE_ID_GLOBAL(args.trace_id),
245                            TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
246                            "step", "ReceiveBeginFrameDiscard");
247     // We had a race with SetNeedsBeginFrame(false) and still need to let the
248     // sink know that we didn't use this BeginFrame. OnBeginFrame() can also be
249     // called to deliver presentation feedback.
250     DidNotProduceFrame(viz::BeginFrameAck(args, false));
251     return;
252   }
253   TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
254                          TRACE_ID_GLOBAL(args.trace_id),
255                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
256                          "step", "ReceiveBeginFrame");
257 
258   if (begin_frame_source_)
259     begin_frame_source_->OnBeginFrame(args);
260 }
261 
OnBeginFramePausedChanged(bool paused)262 void AsyncLayerTreeFrameSink::OnBeginFramePausedChanged(bool paused) {
263   begin_frames_paused_ = paused;
264   if (begin_frame_source_)
265     begin_frame_source_->OnSetBeginFrameSourcePaused(paused);
266 }
267 
ReclaimResources(const std::vector<viz::ReturnedResource> & resources)268 void AsyncLayerTreeFrameSink::ReclaimResources(
269     const std::vector<viz::ReturnedResource>& resources) {
270   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
271   client_->ReclaimResources(resources);
272 }
273 
OnNeedsBeginFrames(bool needs_begin_frames)274 void AsyncLayerTreeFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
275   DCHECK(compositor_frame_sink_ptr_);
276   if (needs_begin_frames_ != needs_begin_frames) {
277     if (needs_begin_frames_) {
278       TRACE_EVENT_ASYNC_END0("cc,benchmark", "NeedsBeginFrames", this);
279     } else {
280       TRACE_EVENT_ASYNC_BEGIN0("cc,benchmark", "NeedsBeginFrames", this);
281     }
282   }
283   needs_begin_frames_ = needs_begin_frames;
284   compositor_frame_sink_ptr_->SetNeedsBeginFrame(needs_begin_frames);
285 }
286 
OnMojoConnectionError(uint32_t custom_reason,const std::string & description)287 void AsyncLayerTreeFrameSink::OnMojoConnectionError(
288     uint32_t custom_reason,
289     const std::string& description) {
290   // TODO(sgilhuly): Use DLOG(FATAL) once crbug.com/1043899 is resolved.
291   if (custom_reason)
292     DLOG(ERROR) << description;
293   if (client_)
294     client_->DidLoseLayerTreeFrameSink();
295 }
296 
297 }  // namespace mojo_embedder
298 }  // namespace cc
299