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/single_thread_proxy.h"
6
7 #include "base/auto_reset.h"
8 #include "base/debug/trace_event.h"
9 #include "cc/debug/benchmark_instrumentation.h"
10 #include "cc/output/context_provider.h"
11 #include "cc/output/output_surface.h"
12 #include "cc/quads/draw_quad.h"
13 #include "cc/resources/prioritized_resource_manager.h"
14 #include "cc/resources/resource_update_controller.h"
15 #include "cc/trees/blocking_task_runner.h"
16 #include "cc/trees/layer_tree_host.h"
17 #include "cc/trees/layer_tree_host_single_thread_client.h"
18 #include "cc/trees/layer_tree_impl.h"
19 #include "ui/gfx/frame_time.h"
20
21 namespace cc {
22
Create(LayerTreeHost * layer_tree_host,LayerTreeHostSingleThreadClient * client)23 scoped_ptr<Proxy> SingleThreadProxy::Create(
24 LayerTreeHost* layer_tree_host,
25 LayerTreeHostSingleThreadClient* client) {
26 return make_scoped_ptr(
27 new SingleThreadProxy(layer_tree_host, client)).PassAs<Proxy>();
28 }
29
SingleThreadProxy(LayerTreeHost * layer_tree_host,LayerTreeHostSingleThreadClient * client)30 SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host,
31 LayerTreeHostSingleThreadClient* client)
32 : Proxy(NULL),
33 layer_tree_host_(layer_tree_host),
34 client_(client),
35 created_offscreen_context_provider_(false),
36 next_frame_is_newly_committed_frame_(false),
37 inside_draw_(false) {
38 TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
39 DCHECK(Proxy::IsMainThread());
40 DCHECK(layer_tree_host);
41
42 // Impl-side painting not supported without threaded compositing.
43 CHECK(!layer_tree_host->settings().impl_side_painting)
44 << "Threaded compositing must be enabled to use impl-side painting.";
45 }
46
Start(scoped_ptr<OutputSurface> first_output_surface)47 void SingleThreadProxy::Start(scoped_ptr<OutputSurface> first_output_surface) {
48 DCHECK(first_output_surface);
49 DebugScopedSetImplThread impl(this);
50 layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
51 first_output_surface_ = first_output_surface.Pass();
52 }
53
~SingleThreadProxy()54 SingleThreadProxy::~SingleThreadProxy() {
55 TRACE_EVENT0("cc", "SingleThreadProxy::~SingleThreadProxy");
56 DCHECK(Proxy::IsMainThread());
57 // Make sure Stop() got called or never Started.
58 DCHECK(!layer_tree_host_impl_);
59 }
60
CompositeAndReadback(void * pixels,gfx::Rect rect)61 bool SingleThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) {
62 TRACE_EVENT0("cc", "SingleThreadProxy::CompositeAndReadback");
63 DCHECK(Proxy::IsMainThread());
64
65 gfx::Rect device_viewport_damage_rect = rect;
66
67 LayerTreeHostImpl::FrameData frame;
68 if (!CommitAndComposite(gfx::FrameTime::Now(),
69 device_viewport_damage_rect,
70 true, // for_readback
71 &frame))
72 return false;
73
74 {
75 DebugScopedSetImplThread impl(this);
76 layer_tree_host_impl_->Readback(pixels, rect);
77
78 if (layer_tree_host_impl_->IsContextLost())
79 return false;
80 }
81
82 return true;
83 }
84
FinishAllRendering()85 void SingleThreadProxy::FinishAllRendering() {
86 DCHECK(Proxy::IsMainThread());
87 {
88 DebugScopedSetImplThread impl(this);
89 layer_tree_host_impl_->FinishAllRendering();
90 }
91 }
92
IsStarted() const93 bool SingleThreadProxy::IsStarted() const {
94 DCHECK(Proxy::IsMainThread());
95 return layer_tree_host_impl_;
96 }
97
SetLayerTreeHostClientReady()98 void SingleThreadProxy::SetLayerTreeHostClientReady() {
99 // Scheduling is controlled by the embedder in the single thread case, so
100 // nothing to do.
101 }
102
SetVisible(bool visible)103 void SingleThreadProxy::SetVisible(bool visible) {
104 DebugScopedSetImplThread impl(this);
105 layer_tree_host_impl_->SetVisible(visible);
106
107 // Changing visibility could change ShouldComposite().
108 UpdateBackgroundAnimateTicking();
109 }
110
CreateAndInitializeOutputSurface()111 void SingleThreadProxy::CreateAndInitializeOutputSurface() {
112 TRACE_EVENT0(
113 "cc", "SingleThreadProxy::CreateAndInitializeOutputSurface");
114 DCHECK(Proxy::IsMainThread());
115
116 scoped_ptr<OutputSurface> output_surface = first_output_surface_.Pass();
117 if (!output_surface)
118 output_surface = layer_tree_host_->CreateOutputSurface();
119 if (!output_surface) {
120 OnOutputSurfaceInitializeAttempted(false);
121 return;
122 }
123
124 scoped_refptr<ContextProvider> offscreen_context_provider;
125 if (created_offscreen_context_provider_) {
126 offscreen_context_provider =
127 layer_tree_host_->client()->OffscreenContextProvider();
128 if (!offscreen_context_provider.get() ||
129 !offscreen_context_provider->BindToCurrentThread()) {
130 OnOutputSurfaceInitializeAttempted(false);
131 return;
132 }
133 }
134
135 {
136 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
137 DebugScopedSetImplThread impl(this);
138 layer_tree_host_->DeleteContentsTexturesOnImplThread(
139 layer_tree_host_impl_->resource_provider());
140 }
141
142 bool initialized;
143 {
144 DebugScopedSetImplThread impl(this);
145
146 DCHECK(output_surface);
147 initialized = layer_tree_host_impl_->InitializeRenderer(
148 output_surface.Pass());
149 if (!initialized && offscreen_context_provider.get()) {
150 offscreen_context_provider->VerifyContexts();
151 offscreen_context_provider = NULL;
152 }
153
154 layer_tree_host_impl_->SetOffscreenContextProvider(
155 offscreen_context_provider);
156 }
157
158 OnOutputSurfaceInitializeAttempted(initialized);
159 }
160
OnOutputSurfaceInitializeAttempted(bool success)161 void SingleThreadProxy::OnOutputSurfaceInitializeAttempted(bool success) {
162 LayerTreeHost::CreateResult result =
163 layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
164 if (result == LayerTreeHost::CreateFailedButTryAgain) {
165 // Force another recreation attempt to happen by requesting another commit.
166 SetNeedsCommit();
167 }
168 }
169
GetRendererCapabilities() const170 const RendererCapabilities& SingleThreadProxy::GetRendererCapabilities() const {
171 DCHECK(Proxy::IsMainThread());
172 DCHECK(!layer_tree_host_->output_surface_lost());
173 return renderer_capabilities_for_main_thread_;
174 }
175
SetNeedsAnimate()176 void SingleThreadProxy::SetNeedsAnimate() {
177 DCHECK(Proxy::IsMainThread());
178 client_->ScheduleAnimation();
179 }
180
SetNeedsUpdateLayers()181 void SingleThreadProxy::SetNeedsUpdateLayers() {
182 DCHECK(Proxy::IsMainThread());
183 client_->ScheduleComposite();
184 }
185
DoCommit(scoped_ptr<ResourceUpdateQueue> queue)186 void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) {
187 DCHECK(Proxy::IsMainThread());
188 // Commit immediately.
189 {
190 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
191 DebugScopedSetImplThread impl(this);
192
193 // This CapturePostTasks should be destroyed before CommitComplete() is
194 // called since that goes out to the embedder, and we want the embedder
195 // to receive its callbacks before that.
196 BlockingTaskRunner::CapturePostTasks blocked;
197
198 layer_tree_host_impl_->BeginCommit();
199
200 if (PrioritizedResourceManager* contents_texture_manager =
201 layer_tree_host_->contents_texture_manager()) {
202 contents_texture_manager->PushTexturePrioritiesToBackings();
203 }
204 layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
205
206 scoped_ptr<ResourceUpdateController> update_controller =
207 ResourceUpdateController::Create(
208 NULL,
209 Proxy::MainThreadTaskRunner(),
210 queue.Pass(),
211 layer_tree_host_impl_->resource_provider());
212 update_controller->Finalize();
213
214 if (layer_tree_host_impl_->EvictedUIResourcesExist())
215 layer_tree_host_->RecreateUIResources();
216
217 layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
218
219 layer_tree_host_impl_->CommitComplete();
220
221 #ifndef NDEBUG
222 // In the single-threaded case, the scale and scroll deltas should never be
223 // touched on the impl layer tree.
224 scoped_ptr<ScrollAndScaleSet> scroll_info =
225 layer_tree_host_impl_->ProcessScrollDeltas();
226 DCHECK(!scroll_info->scrolls.size());
227 DCHECK_EQ(1.f, scroll_info->page_scale_delta);
228 #endif
229
230 RenderingStatsInstrumentation* stats_instrumentation =
231 layer_tree_host_->rendering_stats_instrumentation();
232 BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent(
233 stats_instrumentation->main_thread_rendering_stats());
234 stats_instrumentation->AccumulateAndClearMainThreadStats();
235 }
236 layer_tree_host_->CommitComplete();
237 next_frame_is_newly_committed_frame_ = true;
238 }
239
SetNeedsCommit()240 void SingleThreadProxy::SetNeedsCommit() {
241 DCHECK(Proxy::IsMainThread());
242 client_->ScheduleComposite();
243 }
244
SetNeedsRedraw(gfx::Rect damage_rect)245 void SingleThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) {
246 SetNeedsRedrawRectOnImplThread(damage_rect);
247 client_->ScheduleComposite();
248 }
249
SetNextCommitWaitsForActivation()250 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
251 // There is no activation here other than commit. So do nothing.
252 }
253
SetDeferCommits(bool defer_commits)254 void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
255 // Thread-only feature.
256 NOTREACHED();
257 }
258
CommitRequested() const259 bool SingleThreadProxy::CommitRequested() const { return false; }
260
BeginMainFrameRequested() const261 bool SingleThreadProxy::BeginMainFrameRequested() const { return false; }
262
MaxPartialTextureUpdates() const263 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
264 return std::numeric_limits<size_t>::max();
265 }
266
Stop()267 void SingleThreadProxy::Stop() {
268 TRACE_EVENT0("cc", "SingleThreadProxy::stop");
269 DCHECK(Proxy::IsMainThread());
270 {
271 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
272 DebugScopedSetImplThread impl(this);
273
274 layer_tree_host_->DeleteContentsTexturesOnImplThread(
275 layer_tree_host_impl_->resource_provider());
276 layer_tree_host_impl_.reset();
277 }
278 layer_tree_host_ = NULL;
279 }
280
OnCanDrawStateChanged(bool can_draw)281 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
282 DCHECK(Proxy::IsImplThread());
283 UpdateBackgroundAnimateTicking();
284 }
285
NotifyReadyToActivate()286 void SingleThreadProxy::NotifyReadyToActivate() {
287 // Thread-only feature.
288 NOTREACHED();
289 }
290
SetNeedsRedrawOnImplThread()291 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
292 client_->ScheduleComposite();
293 }
294
SetNeedsManageTilesOnImplThread()295 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
296 // Thread-only/Impl-side-painting-only feature.
297 NOTREACHED();
298 }
299
SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect)300 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) {
301 // TODO(brianderson): Once we move render_widget scheduling into this class,
302 // we can treat redraw requests more efficiently than CommitAndRedraw
303 // requests.
304 layer_tree_host_impl_->SetViewportDamage(damage_rect);
305 SetNeedsCommit();
306 }
307
DidInitializeVisibleTileOnImplThread()308 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
309 // Impl-side painting only.
310 NOTREACHED();
311 }
312
SetNeedsCommitOnImplThread()313 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
314 client_->ScheduleComposite();
315 }
316
PostAnimationEventsToMainThreadOnImplThread(scoped_ptr<AnimationEventsVector> events,base::Time wall_clock_time)317 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
318 scoped_ptr<AnimationEventsVector> events,
319 base::Time wall_clock_time) {
320 DCHECK(Proxy::IsImplThread());
321 DebugScopedSetMainThread main(this);
322 layer_tree_host_->SetAnimationEvents(events.Pass(), wall_clock_time);
323 }
324
ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes,int priority_cutoff)325 bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
326 size_t limit_bytes,
327 int priority_cutoff) {
328 DCHECK(IsImplThread());
329 PrioritizedResourceManager* contents_texture_manager =
330 layer_tree_host_->contents_texture_manager();
331
332 ResourceProvider* resource_provider =
333 layer_tree_host_impl_->resource_provider();
334
335 if (!contents_texture_manager || !resource_provider)
336 return false;
337
338 return contents_texture_manager->ReduceMemoryOnImplThread(
339 limit_bytes, priority_cutoff, resource_provider);
340 }
341
SendManagedMemoryStats()342 void SingleThreadProxy::SendManagedMemoryStats() {
343 DCHECK(Proxy::IsImplThread());
344 if (!layer_tree_host_impl_)
345 return;
346 PrioritizedResourceManager* contents_texture_manager =
347 layer_tree_host_->contents_texture_manager();
348 if (!contents_texture_manager)
349 return;
350
351 layer_tree_host_impl_->SendManagedMemoryStats(
352 contents_texture_manager->MemoryVisibleBytes(),
353 contents_texture_manager->MemoryVisibleAndNearbyBytes(),
354 contents_texture_manager->MemoryUseBytes());
355 }
356
IsInsideDraw()357 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
358
UpdateRendererCapabilitiesOnImplThread()359 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
360 DCHECK(IsImplThread());
361 renderer_capabilities_for_main_thread_ =
362 layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
363 }
364
DidLoseOutputSurfaceOnImplThread()365 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
366 // Cause a commit so we can notice the lost context.
367 SetNeedsCommitOnImplThread();
368 client_->DidAbortSwapBuffers();
369 }
370
DidSwapBuffersOnImplThread()371 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
372 client_->DidPostSwapBuffers();
373 }
374
OnSwapBuffersCompleteOnImplThread()375 void SingleThreadProxy::OnSwapBuffersCompleteOnImplThread() {
376 client_->DidCompleteSwapBuffers();
377 }
378
379 // Called by the legacy scheduling path (e.g. where render_widget does the
380 // scheduling)
CompositeImmediately(base::TimeTicks frame_begin_time)381 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
382 gfx::Rect device_viewport_damage_rect;
383
384 LayerTreeHostImpl::FrameData frame;
385 if (CommitAndComposite(frame_begin_time,
386 device_viewport_damage_rect,
387 false, // for_readback
388 &frame)) {
389 {
390 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
391 DebugScopedSetImplThread impl(this);
392
393 // This CapturePostTasks should be destroyed before
394 // DidCommitAndDrawFrame() is called since that goes out to the embedder,
395 // and we want the embedder to receive its callbacks before that.
396 // NOTE: This maintains consistent ordering with the ThreadProxy since
397 // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
398 // there as the main thread is not blocked, so any posted tasks inside
399 // the swap buffers will execute first.
400 BlockingTaskRunner::CapturePostTasks blocked;
401
402 layer_tree_host_impl_->SwapBuffers(frame);
403 }
404 DidSwapFrame();
405 }
406 }
407
AsValue() const408 scoped_ptr<base::Value> SingleThreadProxy::AsValue() const {
409 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
410 {
411 // The following line casts away const modifiers because it is just
412 // setting debug state. We still want the AsValue() function and its
413 // call chain to be const throughout.
414 DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this));
415
416 state->Set("layer_tree_host_impl",
417 layer_tree_host_impl_->AsValue().release());
418 }
419 return state.PassAs<base::Value>();
420 }
421
ForceSerializeOnSwapBuffers()422 void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
423 {
424 DebugScopedSetImplThread impl(this);
425 if (layer_tree_host_impl_->renderer()) {
426 DCHECK(!layer_tree_host_->output_surface_lost());
427 layer_tree_host_impl_->renderer()->DoNoOp();
428 }
429 }
430 }
431
CommitAndComposite(base::TimeTicks frame_begin_time,gfx::Rect device_viewport_damage_rect,bool for_readback,LayerTreeHostImpl::FrameData * frame)432 bool SingleThreadProxy::CommitAndComposite(
433 base::TimeTicks frame_begin_time,
434 gfx::Rect device_viewport_damage_rect,
435 bool for_readback,
436 LayerTreeHostImpl::FrameData* frame) {
437 DCHECK(Proxy::IsMainThread());
438
439 if (!layer_tree_host_->InitializeOutputSurfaceIfNeeded())
440 return false;
441
442 layer_tree_host_->AnimateLayers(frame_begin_time);
443
444 if (PrioritizedResourceManager* contents_texture_manager =
445 layer_tree_host_->contents_texture_manager()) {
446 contents_texture_manager->UnlinkAndClearEvictedBackings();
447 contents_texture_manager->SetMaxMemoryLimitBytes(
448 layer_tree_host_impl_->memory_allocation_limit_bytes());
449 contents_texture_manager->SetExternalPriorityCutoff(
450 layer_tree_host_impl_->memory_allocation_priority_cutoff());
451 }
452
453 scoped_ptr<ResourceUpdateQueue> queue =
454 make_scoped_ptr(new ResourceUpdateQueue);
455 layer_tree_host_->UpdateLayers(queue.get());
456
457 layer_tree_host_->WillCommit();
458
459 scoped_refptr<ContextProvider> offscreen_context_provider;
460 if (renderer_capabilities_for_main_thread_.using_offscreen_context3d &&
461 layer_tree_host_->needs_offscreen_context()) {
462 offscreen_context_provider =
463 layer_tree_host_->client()->OffscreenContextProvider();
464 if (offscreen_context_provider.get() &&
465 !offscreen_context_provider->BindToCurrentThread())
466 offscreen_context_provider = NULL;
467
468 if (offscreen_context_provider.get())
469 created_offscreen_context_provider_ = true;
470 }
471
472 DoCommit(queue.Pass());
473 bool result = DoComposite(offscreen_context_provider,
474 frame_begin_time,
475 device_viewport_damage_rect,
476 for_readback,
477 frame);
478 layer_tree_host_->DidBeginMainFrame();
479 return result;
480 }
481
ShouldComposite() const482 bool SingleThreadProxy::ShouldComposite() const {
483 DCHECK(Proxy::IsImplThread());
484 return layer_tree_host_impl_->visible() &&
485 layer_tree_host_impl_->CanDraw();
486 }
487
UpdateBackgroundAnimateTicking()488 void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
489 DCHECK(Proxy::IsImplThread());
490 layer_tree_host_impl_->UpdateBackgroundAnimateTicking(
491 !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer());
492 }
493
DoComposite(scoped_refptr<ContextProvider> offscreen_context_provider,base::TimeTicks frame_begin_time,gfx::Rect device_viewport_damage_rect,bool for_readback,LayerTreeHostImpl::FrameData * frame)494 bool SingleThreadProxy::DoComposite(
495 scoped_refptr<ContextProvider> offscreen_context_provider,
496 base::TimeTicks frame_begin_time,
497 gfx::Rect device_viewport_damage_rect,
498 bool for_readback,
499 LayerTreeHostImpl::FrameData* frame) {
500 DCHECK(!layer_tree_host_->output_surface_lost());
501
502 bool lost_output_surface = false;
503 {
504 DebugScopedSetImplThread impl(this);
505 base::AutoReset<bool> mark_inside(&inside_draw_, true);
506
507 layer_tree_host_impl_->SetOffscreenContextProvider(
508 offscreen_context_provider);
509
510 bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels();
511
512 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
513 // frame, so can only be used when such a frame is possible. Since
514 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
515 // CanDraw() as well.
516 if (!ShouldComposite() || (for_readback && !can_do_readback)) {
517 UpdateBackgroundAnimateTicking();
518 return false;
519 }
520
521 layer_tree_host_impl_->Animate(
522 layer_tree_host_impl_->CurrentFrameTimeTicks(),
523 layer_tree_host_impl_->CurrentFrameTime());
524 UpdateBackgroundAnimateTicking();
525
526 if (!layer_tree_host_impl_->IsContextLost()) {
527 layer_tree_host_impl_->PrepareToDraw(frame, device_viewport_damage_rect);
528 layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);
529 layer_tree_host_impl_->DidDrawAllLayers(*frame);
530 }
531 lost_output_surface = layer_tree_host_impl_->IsContextLost();
532
533 bool start_ready_animations = true;
534 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
535
536 layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame();
537 }
538
539 if (lost_output_surface) {
540 ContextProvider* offscreen_contexts =
541 layer_tree_host_impl_->offscreen_context_provider();
542 if (offscreen_contexts)
543 offscreen_contexts->VerifyContexts();
544 layer_tree_host_->DidLoseOutputSurface();
545 return false;
546 }
547
548 return true;
549 }
550
DidSwapFrame()551 void SingleThreadProxy::DidSwapFrame() {
552 if (next_frame_is_newly_committed_frame_) {
553 next_frame_is_newly_committed_frame_ = false;
554 layer_tree_host_->DidCommitAndDrawFrame();
555 }
556 }
557
CommitPendingForTesting()558 bool SingleThreadProxy::CommitPendingForTesting() { return false; }
559
560 } // namespace cc
561