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