[M85 Dev][EFL] Fix for white screen on launch
[platform/framework/web/chromium-efl.git] / cc / mojo_embedder / async_layer_tree_frame_sink.cc
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_base.h"
12 #include "base/metrics/histogram_functions.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/trace_event/trace_event.h"
15 #include "cc/base/histograms.h"
16 #include "cc/trees/layer_tree_frame_sink_client.h"
17 #include "components/viz/common/features.h"
18 #include "components/viz/common/frame_sinks/begin_frame_args.h"
19 #include "components/viz/common/hit_test/hit_test_region_list.h"
20 #include "components/viz/common/quads/compositor_frame.h"
21
22 namespace {
23
24 base::HistogramBase* GetHistogramNamed(const char* histogram_name_format,
25                                        const char* client_name) {
26   if (!client_name)
27     return nullptr;
28
29   return base::LinearHistogram::FactoryMicrosecondsTimeGet(
30       base::StringPrintf(histogram_name_format, client_name),
31       base::TimeDelta::FromMicroseconds(1),
32       base::TimeDelta::FromMilliseconds(200), 50,
33       base::HistogramBase::kUmaTargetedHistogramFlag);
34 }
35 }  // namespace
36
37 namespace cc {
38 namespace mojo_embedder {
39
40 AsyncLayerTreeFrameSink::PipelineReporting::PipelineReporting(
41     const viz::BeginFrameArgs args,
42     base::TimeTicks now,
43     base::HistogramBase* submit_begin_frame_histogram)
44     : trace_id_(args.trace_id),
45       frame_time_(now),
46       submit_begin_frame_histogram_(submit_begin_frame_histogram) {}
47
48 AsyncLayerTreeFrameSink::PipelineReporting::~PipelineReporting() = default;
49
50 void AsyncLayerTreeFrameSink::PipelineReporting::Report() {
51   TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
52                          TRACE_ID_GLOBAL(trace_id_),
53                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
54                          "step", "SubmitCompositorFrame");
55   auto report_time = base::TimeTicks::Now() - frame_time_;
56
57   if (submit_begin_frame_histogram_)
58     submit_begin_frame_histogram_->AddTimeMicrosecondsGranularity(report_time);
59 }
60
61 AsyncLayerTreeFrameSink::InitParams::InitParams() = default;
62 AsyncLayerTreeFrameSink::InitParams::~InitParams() = default;
63
64 AsyncLayerTreeFrameSink::UnboundMessagePipes::UnboundMessagePipes() = default;
65 AsyncLayerTreeFrameSink::UnboundMessagePipes::~UnboundMessagePipes() = default;
66
67 bool AsyncLayerTreeFrameSink::UnboundMessagePipes::HasUnbound() const {
68   return client_receiver.is_valid() &&
69          (compositor_frame_sink_remote.is_valid() ^
70           compositor_frame_sink_associated_remote.is_valid());
71 }
72
73 AsyncLayerTreeFrameSink::UnboundMessagePipes::UnboundMessagePipes(
74     UnboundMessagePipes&& other) = default;
75
76 AsyncLayerTreeFrameSink::AsyncLayerTreeFrameSink(
77     scoped_refptr<viz::ContextProvider> context_provider,
78     scoped_refptr<viz::RasterContextProvider> worker_context_provider,
79     InitParams* params)
80     : LayerTreeFrameSink(std::move(context_provider),
81                          std::move(worker_context_provider),
82                          std::move(params->compositor_task_runner),
83                          params->gpu_memory_buffer_manager),
84       synthetic_begin_frame_source_(
85           std::move(params->synthetic_begin_frame_source)),
86       pipes_(std::move(params->pipes)),
87       wants_animate_only_begin_frames_(params->wants_animate_only_begin_frames),
88       receive_begin_frame_histogram_(
89           GetHistogramNamed("GraphicsPipeline.%s.ReceivedBeginFrame",
90                             params->client_name)),
91       submit_begin_frame_histogram_(GetHistogramNamed(
92           "GraphicsPipeline.%s.SubmitCompositorFrameAfterBeginFrame",
93           params->client_name)) {
94   DETACH_FROM_THREAD(thread_checker_);
95 }
96
97 AsyncLayerTreeFrameSink::~AsyncLayerTreeFrameSink() {}
98
99 bool AsyncLayerTreeFrameSink::BindToClient(LayerTreeFrameSinkClient* client) {
100   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
101
102   if (!LayerTreeFrameSink::BindToClient(client))
103     return false;
104
105   DCHECK(pipes_.HasUnbound());
106   if (pipes_.compositor_frame_sink_remote.is_valid()) {
107     compositor_frame_sink_.Bind(std::move(pipes_.compositor_frame_sink_remote));
108     compositor_frame_sink_.set_disconnect_with_reason_handler(
109         base::BindOnce(&AsyncLayerTreeFrameSink::OnMojoConnectionError,
110                        weak_factory_.GetWeakPtr()));
111     compositor_frame_sink_ptr_ = compositor_frame_sink_.get();
112   } else if (pipes_.compositor_frame_sink_associated_remote.is_valid()) {
113     compositor_frame_sink_associated_.Bind(
114         std::move(pipes_.compositor_frame_sink_associated_remote));
115     compositor_frame_sink_associated_.set_disconnect_with_reason_handler(
116         base::BindOnce(&AsyncLayerTreeFrameSink::OnMojoConnectionError,
117                        weak_factory_.GetWeakPtr()));
118     compositor_frame_sink_ptr_ = compositor_frame_sink_associated_.get();
119   }
120   client_receiver_.Bind(std::move(pipes_.client_receiver),
121                         compositor_task_runner_);
122
123   if (synthetic_begin_frame_source_) {
124     client->SetBeginFrameSource(synthetic_begin_frame_source_.get());
125   } else {
126     begin_frame_source_ = std::make_unique<viz::ExternalBeginFrameSource>(this);
127     begin_frame_source_->OnSetBeginFrameSourcePaused(begin_frames_paused_);
128     client->SetBeginFrameSource(begin_frame_source_.get());
129   }
130
131   if (wants_animate_only_begin_frames_)
132     compositor_frame_sink_->SetWantsAnimateOnlyBeginFrames();
133
134   compositor_frame_sink_ptr_->InitializeCompositorFrameSinkType(
135       viz::mojom::CompositorFrameSinkType::kLayerTree);
136
137   return true;
138 }
139
140 void AsyncLayerTreeFrameSink::DetachFromClient() {
141   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
142   client_->SetBeginFrameSource(nullptr);
143   begin_frame_source_.reset();
144   synthetic_begin_frame_source_.reset();
145   client_receiver_.reset();
146   compositor_frame_sink_.reset();
147   compositor_frame_sink_associated_.reset();
148   compositor_frame_sink_ptr_ = nullptr;
149   LayerTreeFrameSink::DetachFromClient();
150 }
151
152 void AsyncLayerTreeFrameSink::SetLocalSurfaceId(
153     const viz::LocalSurfaceId& local_surface_id) {
154   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
155   DCHECK(local_surface_id.is_valid());
156   local_surface_id_ = local_surface_id;
157 }
158
159 void AsyncLayerTreeFrameSink::SubmitCompositorFrame(
160     viz::CompositorFrame frame,
161     bool hit_test_data_changed,
162     bool show_hit_test_borders) {
163   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
164   DCHECK(compositor_frame_sink_ptr_);
165   DCHECK(frame.metadata.begin_frame_ack.has_damage);
166   DCHECK(frame.metadata.begin_frame_ack.frame_id.IsSequenceValid());
167
168   // It's possible to request an immediate composite from cc which will bypass
169   // BeginFrame. In that case, we cannot collect full graphics pipeline data.
170   auto it = pipeline_reporting_frame_times_.find(
171       frame.metadata.begin_frame_ack.trace_id);
172   if (it != pipeline_reporting_frame_times_.end()) {
173     it->second.Report();
174     pipeline_reporting_frame_times_.erase(it);
175   }
176
177 #if defined(USE_EFL)
178   local_surface_id_ = viz::LocalSurfaceId(viz::kInitialParentSequenceNumber,
179                                           viz::kInitialChildSequenceNumber,
180                                           base::UnguessableToken::Create());
181 #else
182   if (local_surface_id_ == last_submitted_local_surface_id_) {
183     DCHECK_EQ(last_submitted_device_scale_factor_, frame.device_scale_factor());
184     DCHECK_EQ(last_submitted_size_in_pixels_.height(),
185               frame.size_in_pixels().height());
186     DCHECK_EQ(last_submitted_size_in_pixels_.width(),
187               frame.size_in_pixels().width());
188   }
189 #endif
190   base::Optional<viz::HitTestRegionList> hit_test_region_list =
191       client_->BuildHitTestData();
192
193   if (show_hit_test_borders && hit_test_region_list)
194     hit_test_region_list->flags |= viz::HitTestRegionFlags::kHitTestDebug;
195
196   // If |hit_test_data_changed| was set or local_surface_id has been updated,
197   // we always send hit-test data; otherwise we check for equality with the
198   // last submitted hit-test data for possible optimization.
199   if (!hit_test_region_list) {
200     last_hit_test_data_ = viz::HitTestRegionList();
201   } else if (!hit_test_data_changed &&
202              local_surface_id_ == last_submitted_local_surface_id_) {
203     if (viz::HitTestRegionList::IsEqual(*hit_test_region_list,
204                                         last_hit_test_data_)) {
205       DCHECK(!viz::HitTestRegionList::IsEqual(*hit_test_region_list,
206                                               viz::HitTestRegionList()));
207       hit_test_region_list = base::nullopt;
208     } else {
209       last_hit_test_data_ = *hit_test_region_list;
210     }
211
212     UMA_HISTOGRAM_BOOLEAN("Event.VizHitTest.HitTestDataIsEqualAccuracy",
213                           !hit_test_region_list);
214   } else {
215     last_hit_test_data_ = *hit_test_region_list;
216   }
217
218   if (last_submitted_local_surface_id_ != local_surface_id_) {
219     last_submitted_local_surface_id_ = local_surface_id_;
220     last_submitted_device_scale_factor_ = frame.device_scale_factor();
221     last_submitted_size_in_pixels_ = frame.size_in_pixels();
222
223     // These traces are split into two due to the incoming flow using
224     // TRACE_ID_LOCAL, and the outgoing flow using TRACE_ID_GLOBAL. This is
225     // needed to ensure the incoming flow is not messed up. The outgoing flow is
226     // going to a different process.
227     TRACE_EVENT_WITH_FLOW2(
228         TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
229         "LocalSurfaceId.Submission.Flow",
230         TRACE_ID_LOCAL(local_surface_id_.submission_trace_id()),
231         TRACE_EVENT_FLAG_FLOW_IN, "step", "SubmitCompositorFrame", "surface_id",
232         local_surface_id_.ToString());
233     TRACE_EVENT_WITH_FLOW2(
234         TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
235         "LocalSurfaceId.Submission.Flow",
236         TRACE_ID_GLOBAL(local_surface_id_.submission_trace_id()),
237         TRACE_EVENT_FLAG_FLOW_OUT, "step", "SubmitCompositorFrame",
238         "surface_id", local_surface_id_.ToString());
239   }
240
241   // The trace_id is negated in order to keep the Graphics.Pipeline and
242   // Event.Pipeline flows separated.
243   const int64_t trace_id = ~frame.metadata.begin_frame_ack.trace_id;
244   TRACE_EVENT_WITH_FLOW1(TRACE_DISABLED_BY_DEFAULT("viz.hit_testing_flow"),
245                          "Event.Pipeline", TRACE_ID_GLOBAL(trace_id),
246                          TRACE_EVENT_FLAG_FLOW_OUT, "step",
247                          "SubmitHitTestData");
248
249   compositor_frame_sink_ptr_->SubmitCompositorFrame(
250       local_surface_id_, std::move(frame), std::move(hit_test_region_list), 0);
251 }
252
253 void AsyncLayerTreeFrameSink::DidNotProduceFrame(
254     const viz::BeginFrameAck& ack) {
255   DCHECK(compositor_frame_sink_ptr_);
256   DCHECK(!ack.has_damage);
257   DCHECK(ack.frame_id.IsSequenceValid());
258
259   // TODO(yiyix): Remove duplicated calls of DidNotProduceFrame from the same
260   // BeginFrames. https://crbug.com/881949
261   auto it = pipeline_reporting_frame_times_.find(ack.trace_id);
262   if (it != pipeline_reporting_frame_times_.end()) {
263     TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
264                            TRACE_ID_GLOBAL(ack.trace_id),
265                            TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
266                            "step", "DidNotProduceFrame");
267     compositor_frame_sink_ptr_->DidNotProduceFrame(ack);
268     pipeline_reporting_frame_times_.erase(it);
269   }
270 }
271
272 void AsyncLayerTreeFrameSink::DidAllocateSharedBitmap(
273     base::ReadOnlySharedMemoryRegion region,
274     const viz::SharedBitmapId& id) {
275   DCHECK(compositor_frame_sink_ptr_);
276   compositor_frame_sink_ptr_->DidAllocateSharedBitmap(std::move(region), id);
277 }
278
279 void AsyncLayerTreeFrameSink::DidDeleteSharedBitmap(
280     const viz::SharedBitmapId& id) {
281   DCHECK(compositor_frame_sink_ptr_);
282   compositor_frame_sink_ptr_->DidDeleteSharedBitmap(id);
283 }
284
285 void AsyncLayerTreeFrameSink::DidReceiveCompositorFrameAck(
286     const std::vector<viz::ReturnedResource>& resources) {
287   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
288   client_->ReclaimResources(resources);
289   client_->DidReceiveCompositorFrameAck();
290 }
291
292 void AsyncLayerTreeFrameSink::OnBeginFrame(
293     const viz::BeginFrameArgs& args,
294     const viz::FrameTimingDetailsMap& timing_details) {
295   for (const auto& pair : timing_details) {
296     client_->DidPresentCompositorFrame(pair.first, pair.second);
297   }
298
299   DCHECK_LE(pipeline_reporting_frame_times_.size(), 25u);
300   if (args.trace_id != -1) {
301     base::TimeTicks current_time = base::TimeTicks::Now();
302     PipelineReporting report(args, current_time, submit_begin_frame_histogram_);
303     pipeline_reporting_frame_times_.emplace(args.trace_id, report);
304     // Missed BeginFrames use the frame time of the last received BeginFrame
305     // which is bogus from a reporting perspective if nothing has been updating
306     // on screen for a while.
307     if (args.type != viz::BeginFrameArgs::MISSED) {
308       base::TimeDelta frame_difference = current_time - args.frame_time;
309
310       if (receive_begin_frame_histogram_) {
311         receive_begin_frame_histogram_->AddTimeMicrosecondsGranularity(
312             frame_difference);
313       }
314     }
315   }
316   if (!needs_begin_frames_) {
317     TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
318                            TRACE_ID_GLOBAL(args.trace_id),
319                            TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
320                            "step", "ReceiveBeginFrameDiscard");
321     // We had a race with SetNeedsBeginFrame(false) and still need to let the
322     // sink know that we didn't use this BeginFrame. OnBeginFrame() can also be
323     // called to deliver presentation feedback.
324     DidNotProduceFrame(viz::BeginFrameAck(args, false));
325     return;
326   }
327   TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
328                          TRACE_ID_GLOBAL(args.trace_id),
329                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
330                          "step", "ReceiveBeginFrame");
331
332   if (begin_frame_source_)
333     begin_frame_source_->OnBeginFrame(args);
334 }
335
336 void AsyncLayerTreeFrameSink::OnBeginFramePausedChanged(bool paused) {
337   begin_frames_paused_ = paused;
338   if (begin_frame_source_)
339     begin_frame_source_->OnSetBeginFrameSourcePaused(paused);
340 }
341
342 void AsyncLayerTreeFrameSink::ReclaimResources(
343     const std::vector<viz::ReturnedResource>& resources) {
344   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
345   client_->ReclaimResources(resources);
346 }
347
348 void AsyncLayerTreeFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
349   DCHECK(compositor_frame_sink_ptr_);
350   if (needs_begin_frames_ != needs_begin_frames) {
351     if (needs_begin_frames_) {
352       TRACE_EVENT_ASYNC_END0("cc,benchmark", "NeedsBeginFrames", this);
353     } else {
354       TRACE_EVENT_ASYNC_BEGIN0("cc,benchmark", "NeedsBeginFrames", this);
355     }
356   }
357   needs_begin_frames_ = needs_begin_frames;
358   compositor_frame_sink_ptr_->SetNeedsBeginFrame(needs_begin_frames);
359 }
360
361 void AsyncLayerTreeFrameSink::OnMojoConnectionError(
362     uint32_t custom_reason,
363     const std::string& description) {
364   if (custom_reason)
365     DLOG(FATAL) << description;
366   if (client_)
367     client_->DidLoseLayerTreeFrameSink();
368 }
369
370 }  // namespace mojo_embedder
371 }  // namespace cc