OLD | NEW |
| (Empty) |
1 // Copyright 2015 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/trees/proxy_main.h" | |
6 | |
7 #include <algorithm> | |
8 #include <string> | |
9 | |
10 #include "base/trace_event/trace_event.h" | |
11 #include "base/trace_event/trace_event_argument.h" | |
12 #include "base/trace_event/trace_event_synthetic_delay.h" | |
13 #include "cc/debug/benchmark_instrumentation.h" | |
14 #include "cc/debug/devtools_instrumentation.h" | |
15 #include "cc/output/output_surface.h" | |
16 #include "cc/output/swap_promise.h" | |
17 #include "cc/trees/blocking_task_runner.h" | |
18 #include "cc/trees/layer_tree_host.h" | |
19 #include "cc/trees/scoped_abort_remaining_swap_promises.h" | |
20 #include "cc/trees/threaded_channel.h" | |
21 | |
22 namespace cc { | |
23 | |
24 scoped_ptr<ProxyMain> ProxyMain::CreateThreaded( | |
25 LayerTreeHost* layer_tree_host, | |
26 TaskRunnerProvider* task_runner_provider, | |
27 scoped_ptr<BeginFrameSource> external_begin_frame_source) { | |
28 scoped_ptr<ProxyMain> proxy_main( | |
29 new ProxyMain(layer_tree_host, task_runner_provider, | |
30 std::move(external_begin_frame_source))); | |
31 proxy_main->SetChannel( | |
32 ThreadedChannel::Create(proxy_main.get(), task_runner_provider)); | |
33 return proxy_main; | |
34 } | |
35 | |
36 ProxyMain::ProxyMain(LayerTreeHost* layer_tree_host, | |
37 TaskRunnerProvider* task_runner_provider, | |
38 scoped_ptr<BeginFrameSource> external_begin_frame_source) | |
39 : layer_tree_host_(layer_tree_host), | |
40 task_runner_provider_(task_runner_provider), | |
41 layer_tree_host_id_(layer_tree_host->id()), | |
42 max_requested_pipeline_stage_(NO_PIPELINE_STAGE), | |
43 current_pipeline_stage_(NO_PIPELINE_STAGE), | |
44 final_pipeline_stage_(NO_PIPELINE_STAGE), | |
45 commit_waits_for_activation_(false), | |
46 started_(false), | |
47 defer_commits_(false), | |
48 external_begin_frame_source_(std::move(external_begin_frame_source)) { | |
49 TRACE_EVENT0("cc", "ProxyMain::ProxyMain"); | |
50 DCHECK(task_runner_provider_); | |
51 DCHECK(IsMainThread()); | |
52 DCHECK(!layer_tree_host_->settings().use_external_begin_frame_source || | |
53 external_begin_frame_source_); | |
54 } | |
55 | |
56 ProxyMain::~ProxyMain() { | |
57 TRACE_EVENT0("cc", "ProxyMain::~ProxyMain"); | |
58 DCHECK(IsMainThread()); | |
59 DCHECK(!started_); | |
60 } | |
61 | |
62 void ProxyMain::SetChannel(scoped_ptr<ChannelMain> channel_main) { | |
63 DCHECK(!channel_main_); | |
64 channel_main_ = std::move(channel_main); | |
65 } | |
66 | |
67 void ProxyMain::DidCompleteSwapBuffers() { | |
68 DCHECK(IsMainThread()); | |
69 layer_tree_host_->DidCompleteSwapBuffers(); | |
70 } | |
71 | |
72 void ProxyMain::SetRendererCapabilities( | |
73 const RendererCapabilities& capabilities) { | |
74 DCHECK(IsMainThread()); | |
75 renderer_capabilities_ = capabilities; | |
76 } | |
77 | |
78 void ProxyMain::BeginMainFrameNotExpectedSoon() { | |
79 TRACE_EVENT0("cc", "ProxyMain::BeginMainFrameNotExpectedSoon"); | |
80 DCHECK(IsMainThread()); | |
81 layer_tree_host_->BeginMainFrameNotExpectedSoon(); | |
82 } | |
83 | |
84 void ProxyMain::DidCommitAndDrawFrame() { | |
85 DCHECK(IsMainThread()); | |
86 layer_tree_host_->DidCommitAndDrawFrame(); | |
87 } | |
88 | |
89 void ProxyMain::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) { | |
90 TRACE_EVENT0("cc", "ProxyMain::SetAnimationEvents"); | |
91 DCHECK(IsMainThread()); | |
92 layer_tree_host_->SetAnimationEvents(std::move(events)); | |
93 } | |
94 | |
95 void ProxyMain::DidLoseOutputSurface() { | |
96 TRACE_EVENT0("cc", "ProxyMain::DidLoseOutputSurface"); | |
97 DCHECK(IsMainThread()); | |
98 layer_tree_host_->DidLoseOutputSurface(); | |
99 } | |
100 | |
101 void ProxyMain::RequestNewOutputSurface() { | |
102 DCHECK(IsMainThread()); | |
103 layer_tree_host_->RequestNewOutputSurface(); | |
104 } | |
105 | |
106 void ProxyMain::DidInitializeOutputSurface( | |
107 bool success, | |
108 const RendererCapabilities& capabilities) { | |
109 TRACE_EVENT0("cc", "ProxyMain::DidInitializeOutputSurface"); | |
110 DCHECK(IsMainThread()); | |
111 | |
112 if (!success) { | |
113 layer_tree_host_->DidFailToInitializeOutputSurface(); | |
114 return; | |
115 } | |
116 renderer_capabilities_ = capabilities; | |
117 layer_tree_host_->DidInitializeOutputSurface(); | |
118 } | |
119 | |
120 void ProxyMain::DidCompletePageScaleAnimation() { | |
121 DCHECK(IsMainThread()); | |
122 layer_tree_host_->DidCompletePageScaleAnimation(); | |
123 } | |
124 | |
125 void ProxyMain::PostFrameTimingEventsOnMain( | |
126 scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, | |
127 scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) { | |
128 DCHECK(IsMainThread()); | |
129 layer_tree_host_->RecordFrameTimingEvents(std::move(composite_events), | |
130 std::move(main_frame_events)); | |
131 } | |
132 | |
133 void ProxyMain::BeginMainFrame( | |
134 scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) { | |
135 benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task( | |
136 benchmark_instrumentation::kDoBeginFrame, | |
137 begin_main_frame_state->begin_frame_id); | |
138 | |
139 base::TimeTicks begin_main_frame_start_time = base::TimeTicks::Now(); | |
140 | |
141 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame"); | |
142 DCHECK(IsMainThread()); | |
143 DCHECK_EQ(NO_PIPELINE_STAGE, current_pipeline_stage_); | |
144 | |
145 if (defer_commits_) { | |
146 TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit", | |
147 TRACE_EVENT_SCOPE_THREAD); | |
148 channel_main_->BeginMainFrameAbortedOnImpl( | |
149 CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT, | |
150 begin_main_frame_start_time); | |
151 return; | |
152 } | |
153 | |
154 // If the commit finishes, LayerTreeHost will transfer its swap promises to | |
155 // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the | |
156 // remaining swap promises. | |
157 ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host_); | |
158 | |
159 final_pipeline_stage_ = max_requested_pipeline_stage_; | |
160 max_requested_pipeline_stage_ = NO_PIPELINE_STAGE; | |
161 | |
162 if (!layer_tree_host_->visible()) { | |
163 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD); | |
164 channel_main_->BeginMainFrameAbortedOnImpl( | |
165 CommitEarlyOutReason::ABORTED_NOT_VISIBLE, begin_main_frame_start_time); | |
166 return; | |
167 } | |
168 | |
169 if (layer_tree_host_->output_surface_lost()) { | |
170 TRACE_EVENT_INSTANT0("cc", "EarlyOut_OutputSurfaceLost", | |
171 TRACE_EVENT_SCOPE_THREAD); | |
172 channel_main_->BeginMainFrameAbortedOnImpl( | |
173 CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST, | |
174 begin_main_frame_start_time); | |
175 return; | |
176 } | |
177 | |
178 current_pipeline_stage_ = ANIMATE_PIPELINE_STAGE; | |
179 | |
180 layer_tree_host_->ApplyScrollAndScale( | |
181 begin_main_frame_state->scroll_info.get()); | |
182 | |
183 layer_tree_host_->WillBeginMainFrame(); | |
184 | |
185 layer_tree_host_->BeginMainFrame(begin_main_frame_state->begin_frame_args); | |
186 layer_tree_host_->AnimateLayers( | |
187 begin_main_frame_state->begin_frame_args.frame_time); | |
188 | |
189 // Recreate all UI resources if there were evicted UI resources when the impl | |
190 // thread initiated the commit. | |
191 if (begin_main_frame_state->evicted_ui_resources) | |
192 layer_tree_host_->RecreateUIResources(); | |
193 | |
194 layer_tree_host_->RequestMainFrameUpdate(); | |
195 TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame"); | |
196 | |
197 bool can_cancel_this_commit = final_pipeline_stage_ < COMMIT_PIPELINE_STAGE && | |
198 !begin_main_frame_state->evicted_ui_resources; | |
199 | |
200 current_pipeline_stage_ = UPDATE_LAYERS_PIPELINE_STAGE; | |
201 bool should_update_layers = | |
202 final_pipeline_stage_ >= UPDATE_LAYERS_PIPELINE_STAGE; | |
203 bool updated = should_update_layers && layer_tree_host_->UpdateLayers(); | |
204 | |
205 layer_tree_host_->WillCommit(); | |
206 devtools_instrumentation::ScopedCommitTrace commit_task( | |
207 layer_tree_host_->id()); | |
208 | |
209 current_pipeline_stage_ = COMMIT_PIPELINE_STAGE; | |
210 if (!updated && can_cancel_this_commit) { | |
211 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD); | |
212 channel_main_->BeginMainFrameAbortedOnImpl( | |
213 CommitEarlyOutReason::FINISHED_NO_UPDATES, begin_main_frame_start_time); | |
214 | |
215 // Although the commit is internally aborted, this is because it has been | |
216 // detected to be a no-op. From the perspective of an embedder, this commit | |
217 // went through, and input should no longer be throttled, etc. | |
218 current_pipeline_stage_ = NO_PIPELINE_STAGE; | |
219 layer_tree_host_->CommitComplete(); | |
220 layer_tree_host_->DidBeginMainFrame(); | |
221 layer_tree_host_->BreakSwapPromises(SwapPromise::COMMIT_NO_UPDATE); | |
222 return; | |
223 } | |
224 | |
225 // Notify the impl thread that the main thread is ready to commit. This will | |
226 // begin the commit process, which is blocking from the main thread's | |
227 // point of view, but asynchronously performed on the impl thread, | |
228 // coordinated by the Scheduler. | |
229 { | |
230 TRACE_EVENT0("cc", "ProxyMain::BeginMainFrame::commit"); | |
231 | |
232 DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); | |
233 | |
234 // This CapturePostTasks should be destroyed before CommitComplete() is | |
235 // called since that goes out to the embedder, and we want the embedder | |
236 // to receive its callbacks before that. | |
237 BlockingTaskRunner::CapturePostTasks blocked( | |
238 task_runner_provider_->blocking_main_thread_task_runner()); | |
239 | |
240 bool hold_commit_for_activation = commit_waits_for_activation_; | |
241 commit_waits_for_activation_ = false; | |
242 CompletionEvent completion; | |
243 channel_main_->StartCommitOnImpl(&completion, layer_tree_host_, | |
244 begin_main_frame_start_time, | |
245 hold_commit_for_activation); | |
246 completion.Wait(); | |
247 } | |
248 | |
249 current_pipeline_stage_ = NO_PIPELINE_STAGE; | |
250 layer_tree_host_->CommitComplete(); | |
251 layer_tree_host_->DidBeginMainFrame(); | |
252 } | |
253 | |
254 void ProxyMain::FinishAllRendering() { | |
255 DCHECK(IsMainThread()); | |
256 DCHECK(!defer_commits_); | |
257 | |
258 // Make sure all GL drawing is finished on the impl thread. | |
259 DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); | |
260 CompletionEvent completion; | |
261 channel_main_->FinishAllRenderingOnImpl(&completion); | |
262 completion.Wait(); | |
263 } | |
264 | |
265 bool ProxyMain::IsStarted() const { | |
266 DCHECK(IsMainThread()); | |
267 return started_; | |
268 } | |
269 | |
270 bool ProxyMain::CommitToActiveTree() const { | |
271 // With ProxyMain, we use a pending tree and activate it once it's ready to | |
272 // draw to allow input to modify the active tree and draw during raster. | |
273 return false; | |
274 } | |
275 | |
276 void ProxyMain::SetOutputSurface(OutputSurface* output_surface) { | |
277 channel_main_->InitializeOutputSurfaceOnImpl(output_surface); | |
278 } | |
279 | |
280 void ProxyMain::SetVisible(bool visible) { | |
281 TRACE_EVENT1("cc", "ProxyMain::SetVisible", "visible", visible); | |
282 channel_main_->SetVisibleOnImpl(visible); | |
283 } | |
284 | |
285 void ProxyMain::SetThrottleFrameProduction(bool throttle) { | |
286 TRACE_EVENT1("cc", "ProxyMain::SetThrottleFrameProduction", "throttle", | |
287 throttle); | |
288 channel_main_->SetThrottleFrameProductionOnImpl(throttle); | |
289 } | |
290 | |
291 const RendererCapabilities& ProxyMain::GetRendererCapabilities() const { | |
292 DCHECK(IsMainThread()); | |
293 DCHECK(!layer_tree_host_->output_surface_lost()); | |
294 return renderer_capabilities_; | |
295 } | |
296 | |
297 void ProxyMain::SetNeedsAnimate() { | |
298 DCHECK(IsMainThread()); | |
299 if (SendCommitRequestToImplThreadIfNeeded(ANIMATE_PIPELINE_STAGE)) { | |
300 TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsAnimate", | |
301 TRACE_EVENT_SCOPE_THREAD); | |
302 } | |
303 } | |
304 | |
305 void ProxyMain::SetNeedsUpdateLayers() { | |
306 DCHECK(IsMainThread()); | |
307 // If we are currently animating, make sure we also update the layers. | |
308 if (current_pipeline_stage_ == ANIMATE_PIPELINE_STAGE) { | |
309 final_pipeline_stage_ = | |
310 std::max(final_pipeline_stage_, UPDATE_LAYERS_PIPELINE_STAGE); | |
311 return; | |
312 } | |
313 if (SendCommitRequestToImplThreadIfNeeded(UPDATE_LAYERS_PIPELINE_STAGE)) { | |
314 TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsUpdateLayers", | |
315 TRACE_EVENT_SCOPE_THREAD); | |
316 } | |
317 } | |
318 | |
319 void ProxyMain::SetNeedsCommit() { | |
320 DCHECK(IsMainThread()); | |
321 // If we are currently animating, make sure we don't skip the commit. Note | |
322 // that requesting a commit during the layer update stage means we need to | |
323 // schedule another full commit. | |
324 if (current_pipeline_stage_ == ANIMATE_PIPELINE_STAGE) { | |
325 final_pipeline_stage_ = | |
326 std::max(final_pipeline_stage_, COMMIT_PIPELINE_STAGE); | |
327 return; | |
328 } | |
329 if (SendCommitRequestToImplThreadIfNeeded(COMMIT_PIPELINE_STAGE)) { | |
330 TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsCommit", | |
331 TRACE_EVENT_SCOPE_THREAD); | |
332 } | |
333 } | |
334 | |
335 void ProxyMain::SetNeedsRedraw(const gfx::Rect& damage_rect) { | |
336 TRACE_EVENT0("cc", "ProxyMain::SetNeedsRedraw"); | |
337 DCHECK(IsMainThread()); | |
338 channel_main_->SetNeedsRedrawOnImpl(damage_rect); | |
339 } | |
340 | |
341 void ProxyMain::SetNextCommitWaitsForActivation() { | |
342 DCHECK(IsMainThread()); | |
343 commit_waits_for_activation_ = true; | |
344 } | |
345 | |
346 void ProxyMain::NotifyInputThrottledUntilCommit() { | |
347 DCHECK(IsMainThread()); | |
348 channel_main_->SetInputThrottledUntilCommitOnImpl(true); | |
349 } | |
350 | |
351 void ProxyMain::SetDeferCommits(bool defer_commits) { | |
352 DCHECK(IsMainThread()); | |
353 if (defer_commits_ == defer_commits) | |
354 return; | |
355 | |
356 defer_commits_ = defer_commits; | |
357 if (defer_commits_) | |
358 TRACE_EVENT_ASYNC_BEGIN0("cc", "ProxyMain::SetDeferCommits", this); | |
359 else | |
360 TRACE_EVENT_ASYNC_END0("cc", "ProxyMain::SetDeferCommits", this); | |
361 | |
362 channel_main_->SetDeferCommitsOnImpl(defer_commits); | |
363 } | |
364 | |
365 bool ProxyMain::CommitRequested() const { | |
366 DCHECK(IsMainThread()); | |
367 // TODO(skyostil): Split this into something like CommitRequested() and | |
368 // CommitInProgress(). | |
369 return current_pipeline_stage_ != NO_PIPELINE_STAGE || | |
370 max_requested_pipeline_stage_ >= COMMIT_PIPELINE_STAGE; | |
371 } | |
372 | |
373 bool ProxyMain::BeginMainFrameRequested() const { | |
374 DCHECK(IsMainThread()); | |
375 return max_requested_pipeline_stage_ != NO_PIPELINE_STAGE; | |
376 } | |
377 | |
378 void ProxyMain::MainThreadHasStoppedFlinging() { | |
379 DCHECK(IsMainThread()); | |
380 channel_main_->MainThreadHasStoppedFlingingOnImpl(); | |
381 } | |
382 | |
383 void ProxyMain::Start() { | |
384 DCHECK(IsMainThread()); | |
385 DCHECK(task_runner_provider_->HasImplThread()); | |
386 DCHECK(channel_main_); | |
387 | |
388 // Create LayerTreeHostImpl. | |
389 channel_main_->SynchronouslyInitializeImpl( | |
390 layer_tree_host_, std::move(external_begin_frame_source_)); | |
391 | |
392 started_ = true; | |
393 } | |
394 | |
395 void ProxyMain::Stop() { | |
396 TRACE_EVENT0("cc", "ProxyMain::Stop"); | |
397 DCHECK(IsMainThread()); | |
398 DCHECK(started_); | |
399 | |
400 channel_main_->SynchronouslyCloseImpl(); | |
401 | |
402 layer_tree_host_ = nullptr; | |
403 started_ = false; | |
404 } | |
405 | |
406 bool ProxyMain::SupportsImplScrolling() const { | |
407 return true; | |
408 } | |
409 | |
410 bool ProxyMain::MainFrameWillHappenForTesting() { | |
411 DCHECK(IsMainThread()); | |
412 bool main_frame_will_happen = false; | |
413 { | |
414 DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); | |
415 CompletionEvent completion; | |
416 channel_main_->MainFrameWillHappenOnImplForTesting(&completion, | |
417 &main_frame_will_happen); | |
418 completion.Wait(); | |
419 } | |
420 return main_frame_will_happen; | |
421 } | |
422 | |
423 void ProxyMain::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { | |
424 NOTREACHED() << "Only used by SingleThreadProxy"; | |
425 } | |
426 | |
427 void ProxyMain::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) { | |
428 NOTREACHED() << "Only used by SingleProxyMain"; | |
429 } | |
430 | |
431 void ProxyMain::ReleaseOutputSurface() { | |
432 DCHECK(IsMainThread()); | |
433 DCHECK(layer_tree_host_->output_surface_lost()); | |
434 | |
435 DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); | |
436 CompletionEvent completion; | |
437 channel_main_->ReleaseOutputSurfaceOnImpl(&completion); | |
438 completion.Wait(); | |
439 } | |
440 | |
441 void ProxyMain::UpdateTopControlsState(TopControlsState constraints, | |
442 TopControlsState current, | |
443 bool animate) { | |
444 DCHECK(IsMainThread()); | |
445 channel_main_->UpdateTopControlsStateOnImpl(constraints, current, animate); | |
446 } | |
447 | |
448 bool ProxyMain::SendCommitRequestToImplThreadIfNeeded( | |
449 CommitPipelineStage required_stage) { | |
450 DCHECK(IsMainThread()); | |
451 DCHECK_NE(NO_PIPELINE_STAGE, required_stage); | |
452 bool already_posted = max_requested_pipeline_stage_ != NO_PIPELINE_STAGE; | |
453 max_requested_pipeline_stage_ = | |
454 std::max(max_requested_pipeline_stage_, required_stage); | |
455 if (already_posted) | |
456 return false; | |
457 channel_main_->SetNeedsCommitOnImpl(); | |
458 return true; | |
459 } | |
460 | |
461 bool ProxyMain::IsMainThread() const { | |
462 return task_runner_provider_->IsMainThread(); | |
463 } | |
464 | |
465 } // namespace cc | |
OLD | NEW |