OLD | NEW |
| (Empty) |
1 // Copyright 2011 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/thread_proxy.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/output/context_provider.h" | |
19 #include "cc/output/output_surface.h" | |
20 #include "cc/output/swap_promise.h" | |
21 #include "cc/quads/draw_quad.h" | |
22 #include "cc/resources/prioritized_resource_manager.h" | |
23 #include "cc/scheduler/commit_earlyout_reason.h" | |
24 #include "cc/scheduler/delay_based_time_source.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 #include "ui/gfx/frame_time.h" | |
32 | |
33 namespace cc { | |
34 | |
35 namespace { | |
36 | |
37 // Measured in seconds. | |
38 const double kSmoothnessTakesPriorityExpirationDelay = 0.25; | |
39 | |
40 unsigned int nextBeginFrameId = 0; | |
41 | |
42 } // namespace | |
43 | |
44 struct ThreadProxy::SchedulerStateRequest { | |
45 CompletionEvent completion; | |
46 scoped_ptr<base::Value> state; | |
47 }; | |
48 | |
49 scoped_ptr<Proxy> ThreadProxy::Create( | |
50 LayerTreeHost* layer_tree_host, | |
51 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | |
52 scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner, | |
53 scoped_ptr<BeginFrameSource> external_begin_frame_source) { | |
54 return make_scoped_ptr(new ThreadProxy(layer_tree_host, | |
55 main_task_runner, | |
56 impl_task_runner, | |
57 external_begin_frame_source.Pass())); | |
58 } | |
59 | |
60 ThreadProxy::ThreadProxy( | |
61 LayerTreeHost* layer_tree_host, | |
62 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | |
63 scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner, | |
64 scoped_ptr<BeginFrameSource> external_begin_frame_source) | |
65 : Proxy(main_task_runner, impl_task_runner), | |
66 main_thread_only_vars_unsafe_(this, layer_tree_host->id()), | |
67 main_thread_or_blocked_vars_unsafe_(layer_tree_host), | |
68 compositor_thread_vars_unsafe_( | |
69 this, | |
70 layer_tree_host->id(), | |
71 layer_tree_host->rendering_stats_instrumentation(), | |
72 external_begin_frame_source.Pass()) { | |
73 TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy"); | |
74 DCHECK(IsMainThread()); | |
75 DCHECK(this->layer_tree_host()); | |
76 } | |
77 | |
78 ThreadProxy::MainThreadOnly::MainThreadOnly(ThreadProxy* proxy, | |
79 int layer_tree_host_id) | |
80 : layer_tree_host_id(layer_tree_host_id), | |
81 animate_requested(false), | |
82 commit_requested(false), | |
83 commit_request_sent_to_impl_thread(false), | |
84 started(false), | |
85 prepare_tiles_pending(false), | |
86 can_cancel_commit(true), | |
87 defer_commits(false), | |
88 weak_factory(proxy) { | |
89 } | |
90 | |
91 ThreadProxy::MainThreadOnly::~MainThreadOnly() {} | |
92 | |
93 ThreadProxy::MainThreadOrBlockedMainThread::MainThreadOrBlockedMainThread( | |
94 LayerTreeHost* host) | |
95 : layer_tree_host(host), | |
96 commit_waits_for_activation(false), | |
97 main_thread_inside_commit(false) {} | |
98 | |
99 ThreadProxy::MainThreadOrBlockedMainThread::~MainThreadOrBlockedMainThread() {} | |
100 | |
101 PrioritizedResourceManager* | |
102 ThreadProxy::MainThreadOrBlockedMainThread::contents_texture_manager() { | |
103 return layer_tree_host->contents_texture_manager(); | |
104 } | |
105 | |
106 ThreadProxy::CompositorThreadOnly::CompositorThreadOnly( | |
107 ThreadProxy* proxy, | |
108 int layer_tree_host_id, | |
109 RenderingStatsInstrumentation* rendering_stats_instrumentation, | |
110 scoped_ptr<BeginFrameSource> external_begin_frame_source) | |
111 : layer_tree_host_id(layer_tree_host_id), | |
112 contents_texture_manager(NULL), | |
113 commit_completion_event(NULL), | |
114 completion_event_for_commit_held_on_tree_activation(NULL), | |
115 next_frame_is_newly_committed_frame(false), | |
116 inside_draw(false), | |
117 input_throttled_until_commit(false), | |
118 smoothness_priority_expiration_notifier( | |
119 proxy->ImplThreadTaskRunner(), | |
120 base::Bind(&ThreadProxy::RenewTreePriority, base::Unretained(proxy)), | |
121 base::TimeDelta::FromMilliseconds( | |
122 kSmoothnessTakesPriorityExpirationDelay * 1000)), | |
123 timing_history(rendering_stats_instrumentation), | |
124 external_begin_frame_source(external_begin_frame_source.Pass()), | |
125 weak_factory(proxy) { | |
126 } | |
127 | |
128 ThreadProxy::CompositorThreadOnly::~CompositorThreadOnly() {} | |
129 | |
130 ThreadProxy::~ThreadProxy() { | |
131 TRACE_EVENT0("cc", "ThreadProxy::~ThreadProxy"); | |
132 DCHECK(IsMainThread()); | |
133 DCHECK(!main().started); | |
134 } | |
135 | |
136 void ThreadProxy::FinishAllRendering() { | |
137 DCHECK(Proxy::IsMainThread()); | |
138 DCHECK(!main().defer_commits); | |
139 | |
140 // Make sure all GL drawing is finished on the impl thread. | |
141 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
142 CompletionEvent completion; | |
143 Proxy::ImplThreadTaskRunner()->PostTask( | |
144 FROM_HERE, | |
145 base::Bind(&ThreadProxy::FinishAllRenderingOnImplThread, | |
146 impl_thread_weak_ptr_, | |
147 &completion)); | |
148 completion.Wait(); | |
149 } | |
150 | |
151 bool ThreadProxy::IsStarted() const { | |
152 DCHECK(Proxy::IsMainThread()); | |
153 return main().started; | |
154 } | |
155 | |
156 bool ThreadProxy::CommitToActiveTree() const { | |
157 // With ThreadProxy and impl-side painting, we use a pending tree and activate | |
158 // it once it's ready to draw. | |
159 return !impl().layer_tree_host_impl->settings().impl_side_painting; | |
160 } | |
161 | |
162 void ThreadProxy::SetLayerTreeHostClientReady() { | |
163 TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReady"); | |
164 Proxy::ImplThreadTaskRunner()->PostTask( | |
165 FROM_HERE, | |
166 base::Bind(&ThreadProxy::SetLayerTreeHostClientReadyOnImplThread, | |
167 impl_thread_weak_ptr_)); | |
168 } | |
169 | |
170 void ThreadProxy::SetLayerTreeHostClientReadyOnImplThread() { | |
171 TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReadyOnImplThread"); | |
172 impl().scheduler->SetCanStart(); | |
173 } | |
174 | |
175 void ThreadProxy::SetVisible(bool visible) { | |
176 TRACE_EVENT1("cc", "ThreadProxy::SetVisible", "visible", visible); | |
177 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
178 | |
179 CompletionEvent completion; | |
180 Proxy::ImplThreadTaskRunner()->PostTask( | |
181 FROM_HERE, | |
182 base::Bind(&ThreadProxy::SetVisibleOnImplThread, | |
183 impl_thread_weak_ptr_, | |
184 &completion, | |
185 visible)); | |
186 completion.Wait(); | |
187 } | |
188 | |
189 void ThreadProxy::SetVisibleOnImplThread(CompletionEvent* completion, | |
190 bool visible) { | |
191 TRACE_EVENT1("cc", "ThreadProxy::SetVisibleOnImplThread", "visible", visible); | |
192 impl().layer_tree_host_impl->SetVisible(visible); | |
193 impl().scheduler->SetVisible(visible); | |
194 completion->Signal(); | |
195 } | |
196 | |
197 void ThreadProxy::SetThrottleFrameProduction(bool throttle) { | |
198 TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProduction", "throttle", | |
199 throttle); | |
200 Proxy::ImplThreadTaskRunner()->PostTask( | |
201 FROM_HERE, | |
202 base::Bind(&ThreadProxy::SetThrottleFrameProductionOnImplThread, | |
203 impl_thread_weak_ptr_, throttle)); | |
204 } | |
205 | |
206 void ThreadProxy::SetThrottleFrameProductionOnImplThread(bool throttle) { | |
207 TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProductionOnImplThread", | |
208 "throttle", throttle); | |
209 impl().scheduler->SetThrottleFrameProduction(throttle); | |
210 } | |
211 | |
212 void ThreadProxy::DidLoseOutputSurface() { | |
213 TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurface"); | |
214 DCHECK(IsMainThread()); | |
215 layer_tree_host()->DidLoseOutputSurface(); | |
216 | |
217 { | |
218 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
219 | |
220 // Return lost resources to their owners immediately. | |
221 BlockingTaskRunner::CapturePostTasks blocked( | |
222 blocking_main_thread_task_runner()); | |
223 | |
224 CompletionEvent completion; | |
225 Proxy::ImplThreadTaskRunner()->PostTask( | |
226 FROM_HERE, | |
227 base::Bind(&ThreadProxy::DeleteContentsTexturesOnImplThread, | |
228 impl_thread_weak_ptr_, | |
229 &completion)); | |
230 completion.Wait(); | |
231 } | |
232 } | |
233 | |
234 void ThreadProxy::RequestNewOutputSurface() { | |
235 DCHECK(IsMainThread()); | |
236 layer_tree_host()->RequestNewOutputSurface(); | |
237 } | |
238 | |
239 void ThreadProxy::SetOutputSurface(scoped_ptr<OutputSurface> output_surface) { | |
240 Proxy::ImplThreadTaskRunner()->PostTask( | |
241 FROM_HERE, | |
242 base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread, | |
243 impl_thread_weak_ptr_, base::Passed(&output_surface))); | |
244 } | |
245 | |
246 void ThreadProxy::DidInitializeOutputSurface( | |
247 bool success, | |
248 const RendererCapabilities& capabilities) { | |
249 TRACE_EVENT0("cc", "ThreadProxy::DidInitializeOutputSurface"); | |
250 DCHECK(IsMainThread()); | |
251 | |
252 if (!success) { | |
253 layer_tree_host()->DidFailToInitializeOutputSurface(); | |
254 return; | |
255 } | |
256 main().renderer_capabilities_main_thread_copy = capabilities; | |
257 layer_tree_host()->DidInitializeOutputSurface(); | |
258 } | |
259 | |
260 void ThreadProxy::SetRendererCapabilitiesMainThreadCopy( | |
261 const RendererCapabilities& capabilities) { | |
262 main().renderer_capabilities_main_thread_copy = capabilities; | |
263 } | |
264 | |
265 void ThreadProxy::SendCommitRequestToImplThreadIfNeeded() { | |
266 DCHECK(IsMainThread()); | |
267 if (main().commit_request_sent_to_impl_thread) | |
268 return; | |
269 main().commit_request_sent_to_impl_thread = true; | |
270 Proxy::ImplThreadTaskRunner()->PostTask( | |
271 FROM_HERE, | |
272 base::Bind(&ThreadProxy::SetNeedsCommitOnImplThread, | |
273 impl_thread_weak_ptr_)); | |
274 } | |
275 | |
276 void ThreadProxy::DidCompletePageScaleAnimation() { | |
277 DCHECK(IsMainThread()); | |
278 layer_tree_host()->DidCompletePageScaleAnimation(); | |
279 } | |
280 | |
281 const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const { | |
282 DCHECK(IsMainThread()); | |
283 DCHECK(!layer_tree_host()->output_surface_lost()); | |
284 return main().renderer_capabilities_main_thread_copy; | |
285 } | |
286 | |
287 void ThreadProxy::SetNeedsAnimate() { | |
288 DCHECK(IsMainThread()); | |
289 if (main().animate_requested) | |
290 return; | |
291 | |
292 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimate"); | |
293 main().animate_requested = true; | |
294 SendCommitRequestToImplThreadIfNeeded(); | |
295 } | |
296 | |
297 void ThreadProxy::SetNeedsUpdateLayers() { | |
298 DCHECK(IsMainThread()); | |
299 | |
300 if (main().commit_request_sent_to_impl_thread) | |
301 return; | |
302 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsUpdateLayers"); | |
303 | |
304 SendCommitRequestToImplThreadIfNeeded(); | |
305 } | |
306 | |
307 void ThreadProxy::SetNeedsCommit() { | |
308 DCHECK(IsMainThread()); | |
309 // Unconditionally set here to handle SetNeedsCommit calls during a commit. | |
310 main().can_cancel_commit = false; | |
311 | |
312 if (main().commit_requested) | |
313 return; | |
314 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommit"); | |
315 main().commit_requested = true; | |
316 | |
317 SendCommitRequestToImplThreadIfNeeded(); | |
318 } | |
319 | |
320 void ThreadProxy::UpdateRendererCapabilitiesOnImplThread() { | |
321 DCHECK(IsImplThread()); | |
322 Proxy::MainThreadTaskRunner()->PostTask( | |
323 FROM_HERE, | |
324 base::Bind(&ThreadProxy::SetRendererCapabilitiesMainThreadCopy, | |
325 main_thread_weak_ptr_, | |
326 impl() | |
327 .layer_tree_host_impl->GetRendererCapabilities() | |
328 .MainThreadCapabilities())); | |
329 } | |
330 | |
331 void ThreadProxy::DidLoseOutputSurfaceOnImplThread() { | |
332 TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurfaceOnImplThread"); | |
333 DCHECK(IsImplThread()); | |
334 Proxy::MainThreadTaskRunner()->PostTask( | |
335 FROM_HERE, | |
336 base::Bind(&ThreadProxy::DidLoseOutputSurface, main_thread_weak_ptr_)); | |
337 impl().scheduler->DidLoseOutputSurface(); | |
338 } | |
339 | |
340 void ThreadProxy::CommitVSyncParameters(base::TimeTicks timebase, | |
341 base::TimeDelta interval) { | |
342 impl().scheduler->CommitVSyncParameters(timebase, interval); | |
343 } | |
344 | |
345 void ThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { | |
346 impl().scheduler->SetEstimatedParentDrawTime(draw_time); | |
347 } | |
348 | |
349 void ThreadProxy::SetMaxSwapsPendingOnImplThread(int max) { | |
350 impl().scheduler->SetMaxSwapsPending(max); | |
351 } | |
352 | |
353 void ThreadProxy::DidSwapBuffersOnImplThread() { | |
354 impl().scheduler->DidSwapBuffers(); | |
355 } | |
356 | |
357 void ThreadProxy::DidSwapBuffersCompleteOnImplThread() { | |
358 TRACE_EVENT0("cc,benchmark", | |
359 "ThreadProxy::DidSwapBuffersCompleteOnImplThread"); | |
360 DCHECK(IsImplThread()); | |
361 impl().scheduler->DidSwapBuffersComplete(); | |
362 Proxy::MainThreadTaskRunner()->PostTask( | |
363 FROM_HERE, | |
364 base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_)); | |
365 } | |
366 | |
367 void ThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) { | |
368 impl().layer_tree_host_impl->WillBeginImplFrame(args); | |
369 } | |
370 | |
371 void ThreadProxy::OnCanDrawStateChanged(bool can_draw) { | |
372 TRACE_EVENT1( | |
373 "cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw); | |
374 DCHECK(IsImplThread()); | |
375 impl().scheduler->SetCanDraw(can_draw); | |
376 } | |
377 | |
378 void ThreadProxy::NotifyReadyToActivate() { | |
379 TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToActivate"); | |
380 impl().scheduler->NotifyReadyToActivate(); | |
381 } | |
382 | |
383 void ThreadProxy::NotifyReadyToDraw() { | |
384 TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToDraw"); | |
385 impl().scheduler->NotifyReadyToDraw(); | |
386 } | |
387 | |
388 void ThreadProxy::SetNeedsCommitOnImplThread() { | |
389 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread"); | |
390 DCHECK(IsImplThread()); | |
391 impl().scheduler->SetNeedsCommit(); | |
392 } | |
393 | |
394 void ThreadProxy::PostAnimationEventsToMainThreadOnImplThread( | |
395 scoped_ptr<AnimationEventsVector> events) { | |
396 TRACE_EVENT0("cc", | |
397 "ThreadProxy::PostAnimationEventsToMainThreadOnImplThread"); | |
398 DCHECK(IsImplThread()); | |
399 Proxy::MainThreadTaskRunner()->PostTask( | |
400 FROM_HERE, | |
401 base::Bind(&ThreadProxy::SetAnimationEvents, | |
402 main_thread_weak_ptr_, | |
403 base::Passed(&events))); | |
404 } | |
405 | |
406 bool ThreadProxy::ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes, | |
407 int priority_cutoff) { | |
408 DCHECK(IsImplThread()); | |
409 | |
410 if (!impl().contents_texture_manager) | |
411 return false; | |
412 if (!impl().layer_tree_host_impl->resource_provider()) | |
413 return false; | |
414 | |
415 bool reduce_result = | |
416 impl().contents_texture_manager->ReduceMemoryOnImplThread( | |
417 limit_bytes, | |
418 priority_cutoff, | |
419 impl().layer_tree_host_impl->resource_provider()); | |
420 if (!reduce_result) | |
421 return false; | |
422 | |
423 // The texture upload queue may reference textures that were just purged, | |
424 // clear them from the queue. | |
425 if (impl().current_resource_update_controller) { | |
426 impl() | |
427 .current_resource_update_controller->DiscardUploadsToEvictedResources(); | |
428 } | |
429 return true; | |
430 } | |
431 | |
432 bool ThreadProxy::IsInsideDraw() { return impl().inside_draw; } | |
433 | |
434 void ThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) { | |
435 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedraw"); | |
436 DCHECK(IsMainThread()); | |
437 Proxy::ImplThreadTaskRunner()->PostTask( | |
438 FROM_HERE, | |
439 base::Bind(&ThreadProxy::SetNeedsRedrawRectOnImplThread, | |
440 impl_thread_weak_ptr_, | |
441 damage_rect)); | |
442 } | |
443 | |
444 void ThreadProxy::SetNextCommitWaitsForActivation() { | |
445 DCHECK(IsMainThread()); | |
446 DCHECK(!blocked_main().main_thread_inside_commit); | |
447 blocked_main().commit_waits_for_activation = true; | |
448 } | |
449 | |
450 void ThreadProxy::SetDeferCommits(bool defer_commits) { | |
451 DCHECK(IsMainThread()); | |
452 if (main().defer_commits == defer_commits) | |
453 return; | |
454 | |
455 main().defer_commits = defer_commits; | |
456 if (main().defer_commits) | |
457 TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::SetDeferCommits", this); | |
458 else | |
459 TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::SetDeferCommits", this); | |
460 | |
461 Proxy::ImplThreadTaskRunner()->PostTask( | |
462 FROM_HERE, | |
463 base::Bind(&ThreadProxy::SetDeferCommitsOnImplThread, | |
464 impl_thread_weak_ptr_, | |
465 defer_commits)); | |
466 } | |
467 | |
468 void ThreadProxy::SetDeferCommitsOnImplThread(bool defer_commits) const { | |
469 DCHECK(IsImplThread()); | |
470 impl().scheduler->SetDeferCommits(defer_commits); | |
471 } | |
472 | |
473 bool ThreadProxy::CommitRequested() const { | |
474 DCHECK(IsMainThread()); | |
475 return main().commit_requested; | |
476 } | |
477 | |
478 bool ThreadProxy::BeginMainFrameRequested() const { | |
479 DCHECK(IsMainThread()); | |
480 return main().commit_request_sent_to_impl_thread; | |
481 } | |
482 | |
483 void ThreadProxy::SetNeedsRedrawOnImplThread() { | |
484 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedrawOnImplThread"); | |
485 DCHECK(IsImplThread()); | |
486 impl().scheduler->SetNeedsRedraw(); | |
487 } | |
488 | |
489 void ThreadProxy::SetNeedsAnimateOnImplThread() { | |
490 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimateOnImplThread"); | |
491 DCHECK(IsImplThread()); | |
492 impl().scheduler->SetNeedsAnimate(); | |
493 } | |
494 | |
495 void ThreadProxy::SetNeedsPrepareTilesOnImplThread() { | |
496 DCHECK(IsImplThread()); | |
497 impl().scheduler->SetNeedsPrepareTiles(); | |
498 } | |
499 | |
500 void ThreadProxy::SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) { | |
501 DCHECK(IsImplThread()); | |
502 impl().layer_tree_host_impl->SetViewportDamage(damage_rect); | |
503 SetNeedsRedrawOnImplThread(); | |
504 } | |
505 | |
506 void ThreadProxy::MainThreadHasStoppedFlinging() { | |
507 DCHECK(IsMainThread()); | |
508 Proxy::ImplThreadTaskRunner()->PostTask( | |
509 FROM_HERE, | |
510 base::Bind(&ThreadProxy::MainThreadHasStoppedFlingingOnImplThread, | |
511 impl_thread_weak_ptr_)); | |
512 } | |
513 | |
514 void ThreadProxy::MainThreadHasStoppedFlingingOnImplThread() { | |
515 DCHECK(IsImplThread()); | |
516 impl().layer_tree_host_impl->MainThreadHasStoppedFlinging(); | |
517 } | |
518 | |
519 void ThreadProxy::NotifyInputThrottledUntilCommit() { | |
520 DCHECK(IsMainThread()); | |
521 Proxy::ImplThreadTaskRunner()->PostTask( | |
522 FROM_HERE, | |
523 base::Bind(&ThreadProxy::SetInputThrottledUntilCommitOnImplThread, | |
524 impl_thread_weak_ptr_, | |
525 true)); | |
526 } | |
527 | |
528 void ThreadProxy::SetInputThrottledUntilCommitOnImplThread(bool is_throttled) { | |
529 DCHECK(IsImplThread()); | |
530 if (is_throttled == impl().input_throttled_until_commit) | |
531 return; | |
532 impl().input_throttled_until_commit = is_throttled; | |
533 RenewTreePriority(); | |
534 } | |
535 | |
536 LayerTreeHost* ThreadProxy::layer_tree_host() { | |
537 return blocked_main().layer_tree_host; | |
538 } | |
539 | |
540 const LayerTreeHost* ThreadProxy::layer_tree_host() const { | |
541 return blocked_main().layer_tree_host; | |
542 } | |
543 | |
544 ThreadProxy::MainThreadOnly& ThreadProxy::main() { | |
545 DCHECK(IsMainThread()); | |
546 return main_thread_only_vars_unsafe_; | |
547 } | |
548 const ThreadProxy::MainThreadOnly& ThreadProxy::main() const { | |
549 DCHECK(IsMainThread()); | |
550 return main_thread_only_vars_unsafe_; | |
551 } | |
552 | |
553 ThreadProxy::MainThreadOrBlockedMainThread& ThreadProxy::blocked_main() { | |
554 DCHECK(IsMainThread() || IsMainThreadBlocked()); | |
555 return main_thread_or_blocked_vars_unsafe_; | |
556 } | |
557 | |
558 const ThreadProxy::MainThreadOrBlockedMainThread& ThreadProxy::blocked_main() | |
559 const { | |
560 DCHECK(IsMainThread() || IsMainThreadBlocked()); | |
561 return main_thread_or_blocked_vars_unsafe_; | |
562 } | |
563 | |
564 ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() { | |
565 DCHECK(IsImplThread()); | |
566 return compositor_thread_vars_unsafe_; | |
567 } | |
568 | |
569 const ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() const { | |
570 DCHECK(IsImplThread()); | |
571 return compositor_thread_vars_unsafe_; | |
572 } | |
573 | |
574 void ThreadProxy::Start() { | |
575 DCHECK(IsMainThread()); | |
576 DCHECK(Proxy::HasImplThread()); | |
577 | |
578 // Create LayerTreeHostImpl. | |
579 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
580 CompletionEvent completion; | |
581 Proxy::ImplThreadTaskRunner()->PostTask( | |
582 FROM_HERE, | |
583 base::Bind(&ThreadProxy::InitializeImplOnImplThread, | |
584 base::Unretained(this), | |
585 &completion)); | |
586 completion.Wait(); | |
587 | |
588 main_thread_weak_ptr_ = main().weak_factory.GetWeakPtr(); | |
589 | |
590 main().started = true; | |
591 } | |
592 | |
593 void ThreadProxy::Stop() { | |
594 TRACE_EVENT0("cc", "ThreadProxy::Stop"); | |
595 DCHECK(IsMainThread()); | |
596 DCHECK(main().started); | |
597 | |
598 // Synchronously finishes pending GL operations and deletes the impl. | |
599 // The two steps are done as separate post tasks, so that tasks posted | |
600 // by the GL implementation due to the Finish can be executed by the | |
601 // renderer before shutting it down. | |
602 { | |
603 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
604 | |
605 CompletionEvent completion; | |
606 Proxy::ImplThreadTaskRunner()->PostTask( | |
607 FROM_HERE, | |
608 base::Bind(&ThreadProxy::FinishGLOnImplThread, | |
609 impl_thread_weak_ptr_, | |
610 &completion)); | |
611 completion.Wait(); | |
612 } | |
613 { | |
614 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
615 | |
616 CompletionEvent completion; | |
617 Proxy::ImplThreadTaskRunner()->PostTask( | |
618 FROM_HERE, | |
619 base::Bind(&ThreadProxy::LayerTreeHostClosedOnImplThread, | |
620 impl_thread_weak_ptr_, | |
621 &completion)); | |
622 completion.Wait(); | |
623 } | |
624 | |
625 main().weak_factory.InvalidateWeakPtrs(); | |
626 blocked_main().layer_tree_host = NULL; | |
627 main().started = false; | |
628 } | |
629 | |
630 void ThreadProxy::ForceSerializeOnSwapBuffers() { | |
631 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
632 CompletionEvent completion; | |
633 Proxy::ImplThreadTaskRunner()->PostTask( | |
634 FROM_HERE, | |
635 base::Bind(&ThreadProxy::ForceSerializeOnSwapBuffersOnImplThread, | |
636 impl_thread_weak_ptr_, | |
637 &completion)); | |
638 completion.Wait(); | |
639 } | |
640 | |
641 void ThreadProxy::ForceSerializeOnSwapBuffersOnImplThread( | |
642 CompletionEvent* completion) { | |
643 if (impl().layer_tree_host_impl->renderer()) | |
644 impl().layer_tree_host_impl->renderer()->DoNoOp(); | |
645 completion->Signal(); | |
646 } | |
647 | |
648 bool ThreadProxy::SupportsImplScrolling() const { | |
649 return true; | |
650 } | |
651 | |
652 void ThreadProxy::SetDebugState(const LayerTreeDebugState& debug_state) { | |
653 Proxy::ImplThreadTaskRunner()->PostTask( | |
654 FROM_HERE, | |
655 base::Bind(&ThreadProxy::SetDebugStateOnImplThread, | |
656 impl_thread_weak_ptr_, | |
657 debug_state)); | |
658 } | |
659 | |
660 void ThreadProxy::SetDebugStateOnImplThread( | |
661 const LayerTreeDebugState& debug_state) { | |
662 DCHECK(IsImplThread()); | |
663 impl().scheduler->SetContinuousPainting(debug_state.continuous_painting); | |
664 } | |
665 | |
666 void ThreadProxy::FinishAllRenderingOnImplThread(CompletionEvent* completion) { | |
667 TRACE_EVENT0("cc", "ThreadProxy::FinishAllRenderingOnImplThread"); | |
668 DCHECK(IsImplThread()); | |
669 impl().layer_tree_host_impl->FinishAllRendering(); | |
670 completion->Signal(); | |
671 } | |
672 | |
673 void ThreadProxy::ScheduledActionSendBeginMainFrame() { | |
674 unsigned int begin_frame_id = nextBeginFrameId++; | |
675 benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task( | |
676 benchmark_instrumentation::kSendBeginFrame, begin_frame_id); | |
677 scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state( | |
678 new BeginMainFrameAndCommitState); | |
679 begin_main_frame_state->begin_frame_id = begin_frame_id; | |
680 begin_main_frame_state->begin_frame_args = | |
681 impl().layer_tree_host_impl->CurrentBeginFrameArgs(); | |
682 begin_main_frame_state->scroll_info = | |
683 impl().layer_tree_host_impl->ProcessScrollDeltas(); | |
684 | |
685 if (!impl().layer_tree_host_impl->settings().impl_side_painting) { | |
686 DCHECK_GT(impl().layer_tree_host_impl->memory_allocation_limit_bytes(), 0u); | |
687 } | |
688 begin_main_frame_state->memory_allocation_limit_bytes = | |
689 impl().layer_tree_host_impl->memory_allocation_limit_bytes(); | |
690 begin_main_frame_state->memory_allocation_priority_cutoff = | |
691 impl().layer_tree_host_impl->memory_allocation_priority_cutoff(); | |
692 begin_main_frame_state->evicted_ui_resources = | |
693 impl().layer_tree_host_impl->EvictedUIResourcesExist(); | |
694 Proxy::MainThreadTaskRunner()->PostTask( | |
695 FROM_HERE, | |
696 base::Bind(&ThreadProxy::BeginMainFrame, | |
697 main_thread_weak_ptr_, | |
698 base::Passed(&begin_main_frame_state))); | |
699 devtools_instrumentation::DidRequestMainThreadFrame( | |
700 impl().layer_tree_host_id); | |
701 impl().timing_history.DidBeginMainFrame(); | |
702 } | |
703 | |
704 void ThreadProxy::SendBeginMainFrameNotExpectedSoon() { | |
705 Proxy::MainThreadTaskRunner()->PostTask( | |
706 FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameNotExpectedSoon, | |
707 main_thread_weak_ptr_)); | |
708 } | |
709 | |
710 void ThreadProxy::BeginMainFrame( | |
711 scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) { | |
712 benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task( | |
713 benchmark_instrumentation::kDoBeginFrame, | |
714 begin_main_frame_state->begin_frame_id); | |
715 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame"); | |
716 DCHECK(IsMainThread()); | |
717 | |
718 if (main().defer_commits) { | |
719 TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit", | |
720 TRACE_EVENT_SCOPE_THREAD); | |
721 Proxy::ImplThreadTaskRunner()->PostTask( | |
722 FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, | |
723 impl_thread_weak_ptr_, | |
724 CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT)); | |
725 return; | |
726 } | |
727 | |
728 // If the commit finishes, LayerTreeHost will transfer its swap promises to | |
729 // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the | |
730 // remaining swap promises. | |
731 ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host()); | |
732 | |
733 main().commit_requested = false; | |
734 main().commit_request_sent_to_impl_thread = false; | |
735 main().animate_requested = false; | |
736 | |
737 if (!layer_tree_host()->visible()) { | |
738 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD); | |
739 Proxy::ImplThreadTaskRunner()->PostTask( | |
740 FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, | |
741 impl_thread_weak_ptr_, | |
742 CommitEarlyOutReason::ABORTED_NOT_VISIBLE)); | |
743 return; | |
744 } | |
745 | |
746 if (layer_tree_host()->output_surface_lost()) { | |
747 TRACE_EVENT_INSTANT0( | |
748 "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD); | |
749 Proxy::ImplThreadTaskRunner()->PostTask( | |
750 FROM_HERE, | |
751 base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, | |
752 impl_thread_weak_ptr_, | |
753 CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST)); | |
754 return; | |
755 } | |
756 | |
757 // Do not notify the impl thread of commit requests that occur during | |
758 // the apply/animate/layout part of the BeginMainFrameAndCommit process since | |
759 // those commit requests will get painted immediately. Once we have done | |
760 // the paint, main().commit_requested will be set to false to allow new commit | |
761 // requests to be scheduled. | |
762 // On the other hand, the animate_requested flag should remain cleared | |
763 // here so that any animation requests generated by the apply or animate | |
764 // callbacks will trigger another frame. | |
765 main().commit_requested = true; | |
766 main().commit_request_sent_to_impl_thread = true; | |
767 | |
768 layer_tree_host()->ApplyScrollAndScale( | |
769 begin_main_frame_state->scroll_info.get()); | |
770 | |
771 layer_tree_host()->WillBeginMainFrame(); | |
772 | |
773 layer_tree_host()->BeginMainFrame(begin_main_frame_state->begin_frame_args); | |
774 layer_tree_host()->AnimateLayers( | |
775 begin_main_frame_state->begin_frame_args.frame_time); | |
776 | |
777 // Unlink any backings that the impl thread has evicted, so that we know to | |
778 // re-paint them in UpdateLayers. | |
779 if (blocked_main().contents_texture_manager()) { | |
780 blocked_main().contents_texture_manager()->UnlinkAndClearEvictedBackings(); | |
781 | |
782 blocked_main().contents_texture_manager()->SetMaxMemoryLimitBytes( | |
783 begin_main_frame_state->memory_allocation_limit_bytes); | |
784 blocked_main().contents_texture_manager()->SetExternalPriorityCutoff( | |
785 begin_main_frame_state->memory_allocation_priority_cutoff); | |
786 } | |
787 | |
788 // Recreate all UI resources if there were evicted UI resources when the impl | |
789 // thread initiated the commit. | |
790 if (begin_main_frame_state->evicted_ui_resources) | |
791 layer_tree_host()->RecreateUIResources(); | |
792 | |
793 layer_tree_host()->Layout(); | |
794 TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame"); | |
795 | |
796 // Clear the commit flag after updating animations and layout here --- objects | |
797 // that only layout when painted will trigger another SetNeedsCommit inside | |
798 // UpdateLayers. | |
799 main().commit_requested = false; | |
800 main().commit_request_sent_to_impl_thread = false; | |
801 bool can_cancel_this_commit = | |
802 main().can_cancel_commit && !begin_main_frame_state->evicted_ui_resources; | |
803 main().can_cancel_commit = true; | |
804 | |
805 scoped_ptr<ResourceUpdateQueue> queue = | |
806 make_scoped_ptr(new ResourceUpdateQueue); | |
807 | |
808 bool updated = layer_tree_host()->UpdateLayers(queue.get()); | |
809 | |
810 layer_tree_host()->WillCommit(); | |
811 devtools_instrumentation::ScopedCommitTrace commit_task( | |
812 layer_tree_host()->id()); | |
813 | |
814 // Before calling animate, we set main().animate_requested to false. If it is | |
815 // true now, it means SetNeedAnimate was called again, but during a state when | |
816 // main().commit_request_sent_to_impl_thread = true. We need to force that | |
817 // call to happen again now so that the commit request is sent to the impl | |
818 // thread. | |
819 if (main().animate_requested) { | |
820 // Forces SetNeedsAnimate to consider posting a commit task. | |
821 main().animate_requested = false; | |
822 SetNeedsAnimate(); | |
823 } | |
824 | |
825 if (!updated && can_cancel_this_commit) { | |
826 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD); | |
827 Proxy::ImplThreadTaskRunner()->PostTask( | |
828 FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, | |
829 impl_thread_weak_ptr_, | |
830 CommitEarlyOutReason::FINISHED_NO_UPDATES)); | |
831 | |
832 // Although the commit is internally aborted, this is because it has been | |
833 // detected to be a no-op. From the perspective of an embedder, this commit | |
834 // went through, and input should no longer be throttled, etc. | |
835 layer_tree_host()->CommitComplete(); | |
836 layer_tree_host()->DidBeginMainFrame(); | |
837 layer_tree_host()->BreakSwapPromises(SwapPromise::COMMIT_NO_UPDATE); | |
838 return; | |
839 } | |
840 | |
841 // Notify the impl thread that the main thread is ready to commit. This will | |
842 // begin the commit process, which is blocking from the main thread's | |
843 // point of view, but asynchronously performed on the impl thread, | |
844 // coordinated by the Scheduler. | |
845 { | |
846 TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame::commit"); | |
847 | |
848 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
849 | |
850 // This CapturePostTasks should be destroyed before CommitComplete() is | |
851 // called since that goes out to the embedder, and we want the embedder | |
852 // to receive its callbacks before that. | |
853 BlockingTaskRunner::CapturePostTasks blocked( | |
854 blocking_main_thread_task_runner()); | |
855 | |
856 CompletionEvent completion; | |
857 Proxy::ImplThreadTaskRunner()->PostTask( | |
858 FROM_HERE, | |
859 base::Bind(&ThreadProxy::StartCommitOnImplThread, | |
860 impl_thread_weak_ptr_, | |
861 &completion, | |
862 queue.release())); | |
863 completion.Wait(); | |
864 } | |
865 | |
866 layer_tree_host()->CommitComplete(); | |
867 layer_tree_host()->DidBeginMainFrame(); | |
868 } | |
869 | |
870 void ThreadProxy::BeginMainFrameNotExpectedSoon() { | |
871 TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameNotExpectedSoon"); | |
872 DCHECK(IsMainThread()); | |
873 layer_tree_host()->BeginMainFrameNotExpectedSoon(); | |
874 } | |
875 | |
876 void ThreadProxy::StartCommitOnImplThread(CompletionEvent* completion, | |
877 ResourceUpdateQueue* raw_queue) { | |
878 TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread"); | |
879 DCHECK(!impl().commit_completion_event); | |
880 DCHECK(IsImplThread() && IsMainThreadBlocked()); | |
881 DCHECK(impl().scheduler); | |
882 DCHECK(impl().scheduler->CommitPending()); | |
883 | |
884 if (!impl().layer_tree_host_impl) { | |
885 TRACE_EVENT_INSTANT0( | |
886 "cc", "EarlyOut_NoLayerTree", TRACE_EVENT_SCOPE_THREAD); | |
887 completion->Signal(); | |
888 return; | |
889 } | |
890 | |
891 // Ideally, we should inform to impl thread when BeginMainFrame is started. | |
892 // But, we can avoid a PostTask in here. | |
893 impl().scheduler->NotifyBeginMainFrameStarted(); | |
894 | |
895 scoped_ptr<ResourceUpdateQueue> queue(raw_queue); | |
896 | |
897 if (impl().contents_texture_manager) { | |
898 DCHECK_EQ(impl().contents_texture_manager, | |
899 blocked_main().contents_texture_manager()); | |
900 } else { | |
901 // Cache this pointer that was created on the main thread side to avoid a | |
902 // data race between creating it and using it on the compositor thread. | |
903 impl().contents_texture_manager = blocked_main().contents_texture_manager(); | |
904 } | |
905 | |
906 if (impl().contents_texture_manager) { | |
907 if (impl().contents_texture_manager->LinkedEvictedBackingsExist()) { | |
908 // Clear any uploads we were making to textures linked to evicted | |
909 // resources | |
910 queue->ClearUploadsToEvictedResources(); | |
911 // Some textures in the layer tree are invalid. Kick off another commit | |
912 // to fill them again. | |
913 SetNeedsCommitOnImplThread(); | |
914 } | |
915 | |
916 impl().contents_texture_manager->PushTexturePrioritiesToBackings(); | |
917 } | |
918 | |
919 impl().commit_completion_event = completion; | |
920 impl().current_resource_update_controller = ResourceUpdateController::Create( | |
921 this, | |
922 Proxy::ImplThreadTaskRunner(), | |
923 queue.Pass(), | |
924 impl().layer_tree_host_impl->resource_provider()); | |
925 impl().current_resource_update_controller->PerformMoreUpdates( | |
926 impl().scheduler->AnticipatedDrawTime()); | |
927 } | |
928 | |
929 void ThreadProxy::BeginMainFrameAbortedOnImplThread( | |
930 CommitEarlyOutReason reason) { | |
931 TRACE_EVENT1("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread", "reason", | |
932 CommitEarlyOutReasonToString(reason)); | |
933 DCHECK(IsImplThread()); | |
934 DCHECK(impl().scheduler); | |
935 DCHECK(impl().scheduler->CommitPending()); | |
936 DCHECK(!impl().layer_tree_host_impl->pending_tree()); | |
937 | |
938 if (CommitEarlyOutHandledCommit(reason)) | |
939 SetInputThrottledUntilCommitOnImplThread(false); | |
940 impl().layer_tree_host_impl->BeginMainFrameAborted(reason); | |
941 impl().scheduler->BeginMainFrameAborted(reason); | |
942 } | |
943 | |
944 void ThreadProxy::ScheduledActionAnimate() { | |
945 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionAnimate"); | |
946 DCHECK(IsImplThread()); | |
947 | |
948 // Don't animate if there is no root layer. | |
949 // TODO(mithro): Both Animate and UpdateAnimationState already have a | |
950 // "!active_tree_->root_layer()" check? | |
951 if (!impl().layer_tree_host_impl->active_tree()->root_layer()) { | |
952 return; | |
953 } | |
954 | |
955 impl().animation_time = | |
956 impl().layer_tree_host_impl->CurrentBeginFrameArgs().frame_time; | |
957 impl().layer_tree_host_impl->Animate(impl().animation_time); | |
958 | |
959 // If animations are not visible, update the state now as | |
960 // ScheduledActionDrawAndSwapIfPossible will never be called. | |
961 if (!impl().layer_tree_host_impl->AnimationsAreVisible()) { | |
962 impl().layer_tree_host_impl->UpdateAnimationState(true); | |
963 } | |
964 } | |
965 | |
966 void ThreadProxy::ScheduledActionCommit() { | |
967 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionCommit"); | |
968 DCHECK(IsImplThread()); | |
969 DCHECK(IsMainThreadBlocked()); | |
970 DCHECK(impl().commit_completion_event); | |
971 DCHECK(impl().current_resource_update_controller); | |
972 | |
973 // Complete all remaining texture updates. | |
974 impl().current_resource_update_controller->Finalize(); | |
975 impl().current_resource_update_controller = nullptr; | |
976 | |
977 blocked_main().main_thread_inside_commit = true; | |
978 impl().layer_tree_host_impl->BeginCommit(); | |
979 layer_tree_host()->BeginCommitOnImplThread(impl().layer_tree_host_impl.get()); | |
980 layer_tree_host()->FinishCommitOnImplThread( | |
981 impl().layer_tree_host_impl.get()); | |
982 blocked_main().main_thread_inside_commit = false; | |
983 | |
984 bool hold_commit = layer_tree_host()->settings().impl_side_painting && | |
985 blocked_main().commit_waits_for_activation; | |
986 blocked_main().commit_waits_for_activation = false; | |
987 | |
988 if (hold_commit) { | |
989 // For some layer types in impl-side painting, the commit is held until | |
990 // the sync tree is activated. It's also possible that the | |
991 // sync tree has already activated if there was no work to be done. | |
992 TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD); | |
993 impl().completion_event_for_commit_held_on_tree_activation = | |
994 impl().commit_completion_event; | |
995 impl().commit_completion_event = NULL; | |
996 } else { | |
997 impl().commit_completion_event->Signal(); | |
998 impl().commit_completion_event = NULL; | |
999 } | |
1000 | |
1001 // Delay this step until afer the main thread has been released as it's | |
1002 // often a good bit of work to update the tree and prepare the new frame. | |
1003 impl().layer_tree_host_impl->CommitComplete(); | |
1004 | |
1005 SetInputThrottledUntilCommitOnImplThread(false); | |
1006 | |
1007 impl().next_frame_is_newly_committed_frame = true; | |
1008 | |
1009 impl().timing_history.DidCommit(); | |
1010 } | |
1011 | |
1012 void ThreadProxy::ScheduledActionActivateSyncTree() { | |
1013 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivateSyncTree"); | |
1014 DCHECK(IsImplThread()); | |
1015 impl().layer_tree_host_impl->ActivateSyncTree(); | |
1016 } | |
1017 | |
1018 void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() { | |
1019 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionBeginOutputSurfaceCreation"); | |
1020 DCHECK(IsImplThread()); | |
1021 Proxy::MainThreadTaskRunner()->PostTask( | |
1022 FROM_HERE, | |
1023 base::Bind(&ThreadProxy::RequestNewOutputSurface, main_thread_weak_ptr_)); | |
1024 } | |
1025 | |
1026 DrawResult ThreadProxy::DrawSwapInternal(bool forced_draw) { | |
1027 TRACE_EVENT_SYNTHETIC_DELAY("cc.DrawAndSwap"); | |
1028 DrawResult result; | |
1029 | |
1030 DCHECK(IsImplThread()); | |
1031 DCHECK(impl().layer_tree_host_impl.get()); | |
1032 | |
1033 impl().timing_history.DidStartDrawing(); | |
1034 base::AutoReset<bool> mark_inside(&impl().inside_draw, true); | |
1035 | |
1036 if (impl().layer_tree_host_impl->pending_tree()) { | |
1037 bool update_lcd_text = false; | |
1038 impl().layer_tree_host_impl->pending_tree()->UpdateDrawProperties( | |
1039 update_lcd_text); | |
1040 } | |
1041 | |
1042 // This method is called on a forced draw, regardless of whether we are able | |
1043 // to produce a frame, as the calling site on main thread is blocked until its | |
1044 // request completes, and we signal completion here. If CanDraw() is false, we | |
1045 // will indicate success=false to the caller, but we must still signal | |
1046 // completion to avoid deadlock. | |
1047 | |
1048 // We guard PrepareToDraw() with CanDraw() because it always returns a valid | |
1049 // frame, so can only be used when such a frame is possible. Since | |
1050 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on | |
1051 // CanDraw() as well. | |
1052 | |
1053 LayerTreeHostImpl::FrameData frame; | |
1054 bool draw_frame = false; | |
1055 | |
1056 if (impl().layer_tree_host_impl->CanDraw()) { | |
1057 result = impl().layer_tree_host_impl->PrepareToDraw(&frame); | |
1058 draw_frame = forced_draw || result == DRAW_SUCCESS; | |
1059 } else { | |
1060 result = DRAW_ABORTED_CANT_DRAW; | |
1061 } | |
1062 | |
1063 if (draw_frame) { | |
1064 impl().layer_tree_host_impl->DrawLayers( | |
1065 &frame, impl().scheduler->LastBeginImplFrameTime()); | |
1066 result = DRAW_SUCCESS; | |
1067 } else { | |
1068 DCHECK_NE(DRAW_SUCCESS, result); | |
1069 } | |
1070 impl().layer_tree_host_impl->DidDrawAllLayers(frame); | |
1071 | |
1072 bool start_ready_animations = draw_frame; | |
1073 impl().layer_tree_host_impl->UpdateAnimationState(start_ready_animations); | |
1074 | |
1075 if (draw_frame) | |
1076 impl().layer_tree_host_impl->SwapBuffers(frame); | |
1077 | |
1078 // Tell the main thread that the the newly-commited frame was drawn. | |
1079 if (impl().next_frame_is_newly_committed_frame) { | |
1080 impl().next_frame_is_newly_committed_frame = false; | |
1081 Proxy::MainThreadTaskRunner()->PostTask( | |
1082 FROM_HERE, | |
1083 base::Bind(&ThreadProxy::DidCommitAndDrawFrame, main_thread_weak_ptr_)); | |
1084 } | |
1085 | |
1086 if (result == DRAW_SUCCESS) | |
1087 impl().timing_history.DidFinishDrawing(); | |
1088 | |
1089 DCHECK_NE(INVALID_RESULT, result); | |
1090 return result; | |
1091 } | |
1092 | |
1093 void ThreadProxy::ScheduledActionPrepareTiles() { | |
1094 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionPrepareTiles"); | |
1095 DCHECK(impl().layer_tree_host_impl->settings().impl_side_painting); | |
1096 impl().layer_tree_host_impl->PrepareTiles(); | |
1097 } | |
1098 | |
1099 DrawResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() { | |
1100 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap"); | |
1101 | |
1102 // SchedulerStateMachine::DidDrawIfPossibleCompleted isn't set up to | |
1103 // handle DRAW_ABORTED_CANT_DRAW. Moreover, the scheduler should | |
1104 // never generate this call when it can't draw. | |
1105 DCHECK(impl().layer_tree_host_impl->CanDraw()); | |
1106 | |
1107 bool forced_draw = false; | |
1108 return DrawSwapInternal(forced_draw); | |
1109 } | |
1110 | |
1111 DrawResult ThreadProxy::ScheduledActionDrawAndSwapForced() { | |
1112 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwapForced"); | |
1113 bool forced_draw = true; | |
1114 return DrawSwapInternal(forced_draw); | |
1115 } | |
1116 | |
1117 void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) { | |
1118 if (impl().current_resource_update_controller) | |
1119 impl().current_resource_update_controller->PerformMoreUpdates(time); | |
1120 } | |
1121 | |
1122 base::TimeDelta ThreadProxy::DrawDurationEstimate() { | |
1123 return impl().timing_history.DrawDurationEstimate(); | |
1124 } | |
1125 | |
1126 base::TimeDelta ThreadProxy::BeginMainFrameToCommitDurationEstimate() { | |
1127 return impl().timing_history.BeginMainFrameToCommitDurationEstimate(); | |
1128 } | |
1129 | |
1130 base::TimeDelta ThreadProxy::CommitToActivateDurationEstimate() { | |
1131 return impl().timing_history.CommitToActivateDurationEstimate(); | |
1132 } | |
1133 | |
1134 void ThreadProxy::DidBeginImplFrameDeadline() { | |
1135 impl().layer_tree_host_impl->ResetCurrentBeginFrameArgsForNextFrame(); | |
1136 } | |
1137 | |
1138 void ThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) { | |
1139 NOTREACHED() << "Only used by SingleThreadProxy"; | |
1140 } | |
1141 | |
1142 void ThreadProxy::ReadyToFinalizeTextureUpdates() { | |
1143 DCHECK(IsImplThread()); | |
1144 impl().scheduler->NotifyReadyToCommit(); | |
1145 } | |
1146 | |
1147 void ThreadProxy::DidCommitAndDrawFrame() { | |
1148 DCHECK(IsMainThread()); | |
1149 layer_tree_host()->DidCommitAndDrawFrame(); | |
1150 } | |
1151 | |
1152 void ThreadProxy::DidCompleteSwapBuffers() { | |
1153 DCHECK(IsMainThread()); | |
1154 layer_tree_host()->DidCompleteSwapBuffers(); | |
1155 } | |
1156 | |
1157 void ThreadProxy::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) { | |
1158 TRACE_EVENT0("cc", "ThreadProxy::SetAnimationEvents"); | |
1159 DCHECK(IsMainThread()); | |
1160 layer_tree_host()->SetAnimationEvents(events.Pass()); | |
1161 } | |
1162 | |
1163 void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { | |
1164 TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread"); | |
1165 DCHECK(IsImplThread()); | |
1166 impl().layer_tree_host_impl = | |
1167 layer_tree_host()->CreateLayerTreeHostImpl(this); | |
1168 SchedulerSettings scheduler_settings( | |
1169 layer_tree_host()->settings().ToSchedulerSettings()); | |
1170 impl().scheduler = Scheduler::Create( | |
1171 this, | |
1172 scheduler_settings, | |
1173 impl().layer_tree_host_id, | |
1174 ImplThreadTaskRunner(), | |
1175 impl().external_begin_frame_source.Pass()); | |
1176 impl().scheduler->SetVisible(impl().layer_tree_host_impl->visible()); | |
1177 impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr(); | |
1178 completion->Signal(); | |
1179 } | |
1180 | |
1181 void ThreadProxy::DeleteContentsTexturesOnImplThread( | |
1182 CompletionEvent* completion) { | |
1183 TRACE_EVENT0("cc", "ThreadProxy::DeleteContentsTexturesOnImplThread"); | |
1184 DCHECK(IsImplThread()); | |
1185 DCHECK(IsMainThreadBlocked()); | |
1186 layer_tree_host()->DeleteContentsTexturesOnImplThread( | |
1187 impl().layer_tree_host_impl->resource_provider()); | |
1188 completion->Signal(); | |
1189 } | |
1190 | |
1191 void ThreadProxy::InitializeOutputSurfaceOnImplThread( | |
1192 scoped_ptr<OutputSurface> output_surface) { | |
1193 TRACE_EVENT0("cc", "ThreadProxy::InitializeOutputSurfaceOnImplThread"); | |
1194 DCHECK(IsImplThread()); | |
1195 | |
1196 LayerTreeHostImpl* host_impl = impl().layer_tree_host_impl.get(); | |
1197 bool success = host_impl->InitializeRenderer(output_surface.Pass()); | |
1198 RendererCapabilities capabilities; | |
1199 if (success) { | |
1200 capabilities = | |
1201 host_impl->GetRendererCapabilities().MainThreadCapabilities(); | |
1202 } | |
1203 | |
1204 Proxy::MainThreadTaskRunner()->PostTask( | |
1205 FROM_HERE, | |
1206 base::Bind(&ThreadProxy::DidInitializeOutputSurface, | |
1207 main_thread_weak_ptr_, | |
1208 success, | |
1209 capabilities)); | |
1210 | |
1211 if (success) | |
1212 impl().scheduler->DidCreateAndInitializeOutputSurface(); | |
1213 } | |
1214 | |
1215 void ThreadProxy::FinishGLOnImplThread(CompletionEvent* completion) { | |
1216 TRACE_EVENT0("cc", "ThreadProxy::FinishGLOnImplThread"); | |
1217 DCHECK(IsImplThread()); | |
1218 if (impl().layer_tree_host_impl->output_surface()) { | |
1219 ContextProvider* context_provider = | |
1220 impl().layer_tree_host_impl->output_surface()->context_provider(); | |
1221 if (context_provider) | |
1222 context_provider->ContextGL()->Finish(); | |
1223 } | |
1224 completion->Signal(); | |
1225 } | |
1226 | |
1227 void ThreadProxy::LayerTreeHostClosedOnImplThread(CompletionEvent* completion) { | |
1228 TRACE_EVENT0("cc", "ThreadProxy::LayerTreeHostClosedOnImplThread"); | |
1229 DCHECK(IsImplThread()); | |
1230 DCHECK(IsMainThreadBlocked()); | |
1231 layer_tree_host()->DeleteContentsTexturesOnImplThread( | |
1232 impl().layer_tree_host_impl->resource_provider()); | |
1233 impl().current_resource_update_controller = nullptr; | |
1234 impl().scheduler = nullptr; | |
1235 impl().layer_tree_host_impl = nullptr; | |
1236 impl().weak_factory.InvalidateWeakPtrs(); | |
1237 // We need to explicitly shutdown the notifier to destroy any weakptrs it is | |
1238 // holding while still on the compositor thread. This also ensures any | |
1239 // callbacks holding a ThreadProxy pointer are cancelled. | |
1240 impl().smoothness_priority_expiration_notifier.Shutdown(); | |
1241 impl().contents_texture_manager = NULL; | |
1242 completion->Signal(); | |
1243 } | |
1244 | |
1245 size_t ThreadProxy::MaxPartialTextureUpdates() const { | |
1246 return ResourceUpdateController::MaxPartialTextureUpdates(); | |
1247 } | |
1248 | |
1249 ThreadProxy::BeginMainFrameAndCommitState::BeginMainFrameAndCommitState() | |
1250 : memory_allocation_limit_bytes(0), | |
1251 memory_allocation_priority_cutoff(0), | |
1252 evicted_ui_resources(false) {} | |
1253 | |
1254 ThreadProxy::BeginMainFrameAndCommitState::~BeginMainFrameAndCommitState() {} | |
1255 | |
1256 bool ThreadProxy::MainFrameWillHappenForTesting() { | |
1257 DCHECK(IsMainThread()); | |
1258 CompletionEvent completion; | |
1259 bool main_frame_will_happen = false; | |
1260 { | |
1261 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
1262 Proxy::ImplThreadTaskRunner()->PostTask( | |
1263 FROM_HERE, | |
1264 base::Bind(&ThreadProxy::MainFrameWillHappenOnImplThreadForTesting, | |
1265 impl_thread_weak_ptr_, | |
1266 &completion, | |
1267 &main_frame_will_happen)); | |
1268 completion.Wait(); | |
1269 } | |
1270 return main_frame_will_happen; | |
1271 } | |
1272 | |
1273 void ThreadProxy::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { | |
1274 NOTREACHED() << "Only used by SingleThreadProxy"; | |
1275 } | |
1276 | |
1277 void ThreadProxy::MainFrameWillHappenOnImplThreadForTesting( | |
1278 CompletionEvent* completion, | |
1279 bool* main_frame_will_happen) { | |
1280 DCHECK(IsImplThread()); | |
1281 if (impl().layer_tree_host_impl->output_surface()) { | |
1282 *main_frame_will_happen = impl().scheduler->MainFrameForTestingWillHappen(); | |
1283 } else { | |
1284 *main_frame_will_happen = false; | |
1285 } | |
1286 completion->Signal(); | |
1287 } | |
1288 | |
1289 void ThreadProxy::RenewTreePriority() { | |
1290 DCHECK(IsImplThread()); | |
1291 bool smoothness_takes_priority = | |
1292 impl().layer_tree_host_impl->pinch_gesture_active() || | |
1293 impl().layer_tree_host_impl->page_scale_animation_active() || | |
1294 impl().layer_tree_host_impl->IsActivelyScrolling(); | |
1295 | |
1296 // Schedule expiration if smoothness currently takes priority. | |
1297 if (smoothness_takes_priority) | |
1298 impl().smoothness_priority_expiration_notifier.Schedule(); | |
1299 | |
1300 // We use the same priority for both trees by default. | |
1301 TreePriority priority = SAME_PRIORITY_FOR_BOTH_TREES; | |
1302 | |
1303 // Smoothness takes priority if we have an expiration for it scheduled. | |
1304 if (impl().smoothness_priority_expiration_notifier.HasPendingNotification()) | |
1305 priority = SMOOTHNESS_TAKES_PRIORITY; | |
1306 | |
1307 // New content always takes priority when the active tree has | |
1308 // evicted resources or there is an invalid viewport size. | |
1309 if (impl().layer_tree_host_impl->active_tree()->ContentsTexturesPurged() || | |
1310 impl().layer_tree_host_impl->active_tree()->ViewportSizeInvalid() || | |
1311 impl().layer_tree_host_impl->EvictedUIResourcesExist() || | |
1312 impl().input_throttled_until_commit) { | |
1313 // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active | |
1314 // tree might be freed. We need to set RequiresHighResToDraw to ensure that | |
1315 // high res tiles will be required to activate pending tree. | |
1316 impl().layer_tree_host_impl->SetRequiresHighResToDraw(); | |
1317 priority = NEW_CONTENT_TAKES_PRIORITY; | |
1318 } | |
1319 | |
1320 impl().layer_tree_host_impl->SetTreePriority(priority); | |
1321 | |
1322 // Only put the scheduler in impl latency prioritization mode if we don't | |
1323 // have a scroll listener. This gives the scroll listener a better chance of | |
1324 // handling scroll updates within the same frame. The tree itself is still | |
1325 // kept in prefer smoothness mode to allow checkerboarding. | |
1326 impl().scheduler->SetImplLatencyTakesPriority( | |
1327 priority == SMOOTHNESS_TAKES_PRIORITY && | |
1328 !impl().layer_tree_host_impl->scroll_affects_scroll_handler()); | |
1329 | |
1330 // Notify the the client of this compositor via the output surface. | |
1331 // TODO(epenner): Route this to compositor-thread instead of output-surface | |
1332 // after GTFO refactor of compositor-thread (http://crbug/170828). | |
1333 if (impl().layer_tree_host_impl->output_surface()) { | |
1334 impl() | |
1335 .layer_tree_host_impl->output_surface() | |
1336 ->UpdateSmoothnessTakesPriority(priority == SMOOTHNESS_TAKES_PRIORITY); | |
1337 } | |
1338 } | |
1339 | |
1340 void ThreadProxy::PostDelayedAnimationTaskOnImplThread( | |
1341 const base::Closure& task, | |
1342 base::TimeDelta delay) { | |
1343 Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, task, delay); | |
1344 } | |
1345 | |
1346 void ThreadProxy::DidActivateSyncTree() { | |
1347 TRACE_EVENT0("cc", "ThreadProxy::DidActivateSyncTreeOnImplThread"); | |
1348 DCHECK(IsImplThread()); | |
1349 | |
1350 if (impl().completion_event_for_commit_held_on_tree_activation) { | |
1351 TRACE_EVENT_INSTANT0( | |
1352 "cc", "ReleaseCommitbyActivation", TRACE_EVENT_SCOPE_THREAD); | |
1353 DCHECK(impl().layer_tree_host_impl->settings().impl_side_painting); | |
1354 impl().completion_event_for_commit_held_on_tree_activation->Signal(); | |
1355 impl().completion_event_for_commit_held_on_tree_activation = NULL; | |
1356 } | |
1357 | |
1358 impl().timing_history.DidActivateSyncTree(); | |
1359 } | |
1360 | |
1361 void ThreadProxy::DidPrepareTiles() { | |
1362 DCHECK(IsImplThread()); | |
1363 impl().scheduler->DidPrepareTiles(); | |
1364 } | |
1365 | |
1366 void ThreadProxy::DidCompletePageScaleAnimationOnImplThread() { | |
1367 DCHECK(IsImplThread()); | |
1368 Proxy::MainThreadTaskRunner()->PostTask( | |
1369 FROM_HERE, base::Bind(&ThreadProxy::DidCompletePageScaleAnimation, | |
1370 main_thread_weak_ptr_)); | |
1371 } | |
1372 | |
1373 } // namespace cc | |
OLD | NEW |