• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       next_frame_is_newly_committed_frame_(false),
36       inside_draw_(false) {
37   TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
38   DCHECK(Proxy::IsMainThread());
39   DCHECK(layer_tree_host);
40 
41   // Impl-side painting not supported without threaded compositing.
42   CHECK(!layer_tree_host->settings().impl_side_painting)
43       << "Threaded compositing must be enabled to use impl-side painting.";
44 }
45 
Start()46 void SingleThreadProxy::Start() {
47   DebugScopedSetImplThread impl(this);
48   layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
49 }
50 
~SingleThreadProxy()51 SingleThreadProxy::~SingleThreadProxy() {
52   TRACE_EVENT0("cc", "SingleThreadProxy::~SingleThreadProxy");
53   DCHECK(Proxy::IsMainThread());
54   // Make sure Stop() got called or never Started.
55   DCHECK(!layer_tree_host_impl_);
56 }
57 
FinishAllRendering()58 void SingleThreadProxy::FinishAllRendering() {
59   TRACE_EVENT0("cc", "SingleThreadProxy::FinishAllRendering");
60   DCHECK(Proxy::IsMainThread());
61   {
62     DebugScopedSetImplThread impl(this);
63     layer_tree_host_impl_->FinishAllRendering();
64   }
65 }
66 
IsStarted() const67 bool SingleThreadProxy::IsStarted() const {
68   DCHECK(Proxy::IsMainThread());
69   return layer_tree_host_impl_;
70 }
71 
SetLayerTreeHostClientReady()72 void SingleThreadProxy::SetLayerTreeHostClientReady() {
73   TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
74   // Scheduling is controlled by the embedder in the single thread case, so
75   // nothing to do.
76 }
77 
SetVisible(bool visible)78 void SingleThreadProxy::SetVisible(bool visible) {
79   TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible");
80   DebugScopedSetImplThread impl(this);
81   layer_tree_host_impl_->SetVisible(visible);
82 
83   // Changing visibility could change ShouldComposite().
84   UpdateBackgroundAnimateTicking();
85 }
86 
CreateAndInitializeOutputSurface()87 void SingleThreadProxy::CreateAndInitializeOutputSurface() {
88   TRACE_EVENT0(
89       "cc", "SingleThreadProxy::CreateAndInitializeOutputSurface");
90   DCHECK(Proxy::IsMainThread());
91   DCHECK(layer_tree_host_->output_surface_lost());
92 
93   scoped_ptr<OutputSurface> output_surface =
94       layer_tree_host_->CreateOutputSurface();
95 
96   renderer_capabilities_for_main_thread_ = RendererCapabilities();
97 
98   bool success = !!output_surface;
99   if (success) {
100     DebugScopedSetMainThreadBlocked main_thread_blocked(this);
101     DebugScopedSetImplThread impl(this);
102     layer_tree_host_->DeleteContentsTexturesOnImplThread(
103         layer_tree_host_impl_->resource_provider());
104     success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
105   }
106 
107   layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
108 
109   if (!success) {
110     // Force another recreation attempt to happen by requesting another commit.
111     SetNeedsCommit();
112   }
113 }
114 
GetRendererCapabilities() const115 const RendererCapabilities& SingleThreadProxy::GetRendererCapabilities() const {
116   DCHECK(Proxy::IsMainThread());
117   DCHECK(!layer_tree_host_->output_surface_lost());
118   return renderer_capabilities_for_main_thread_;
119 }
120 
SetNeedsAnimate()121 void SingleThreadProxy::SetNeedsAnimate() {
122   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
123   DCHECK(Proxy::IsMainThread());
124   client_->ScheduleAnimation();
125 }
126 
SetNeedsUpdateLayers()127 void SingleThreadProxy::SetNeedsUpdateLayers() {
128   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
129   DCHECK(Proxy::IsMainThread());
130   client_->ScheduleComposite();
131 }
132 
DoCommit(scoped_ptr<ResourceUpdateQueue> queue)133 void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) {
134   TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
135   DCHECK(Proxy::IsMainThread());
136   // Commit immediately.
137   {
138     DebugScopedSetMainThreadBlocked main_thread_blocked(this);
139     DebugScopedSetImplThread impl(this);
140 
141     // This CapturePostTasks should be destroyed before CommitComplete() is
142     // called since that goes out to the embedder, and we want the embedder
143     // to receive its callbacks before that.
144     BlockingTaskRunner::CapturePostTasks blocked;
145 
146     layer_tree_host_impl_->BeginCommit();
147 
148     if (PrioritizedResourceManager* contents_texture_manager =
149         layer_tree_host_->contents_texture_manager()) {
150       contents_texture_manager->PushTexturePrioritiesToBackings();
151     }
152     layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
153 
154     scoped_ptr<ResourceUpdateController> update_controller =
155         ResourceUpdateController::Create(
156             NULL,
157             Proxy::MainThreadTaskRunner(),
158             queue.Pass(),
159             layer_tree_host_impl_->resource_provider());
160     update_controller->Finalize();
161 
162     if (layer_tree_host_impl_->EvictedUIResourcesExist())
163       layer_tree_host_->RecreateUIResources();
164 
165     layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
166 
167     layer_tree_host_impl_->CommitComplete();
168 
169 #if DCHECK_IS_ON
170     // In the single-threaded case, the scale and scroll deltas should never be
171     // touched on the impl layer tree.
172     scoped_ptr<ScrollAndScaleSet> scroll_info =
173         layer_tree_host_impl_->ProcessScrollDeltas();
174     DCHECK(!scroll_info->scrolls.size());
175     DCHECK_EQ(1.f, scroll_info->page_scale_delta);
176 #endif
177 
178     RenderingStatsInstrumentation* stats_instrumentation =
179         layer_tree_host_->rendering_stats_instrumentation();
180     BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent(
181         stats_instrumentation->main_thread_rendering_stats());
182     stats_instrumentation->AccumulateAndClearMainThreadStats();
183   }
184   layer_tree_host_->CommitComplete();
185   next_frame_is_newly_committed_frame_ = true;
186 }
187 
SetNeedsCommit()188 void SingleThreadProxy::SetNeedsCommit() {
189   DCHECK(Proxy::IsMainThread());
190   client_->ScheduleComposite();
191 }
192 
SetNeedsRedraw(const gfx::Rect & damage_rect)193 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
194   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
195   SetNeedsRedrawRectOnImplThread(damage_rect);
196   client_->ScheduleComposite();
197 }
198 
SetNextCommitWaitsForActivation()199 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
200   // There is no activation here other than commit. So do nothing.
201 }
202 
SetDeferCommits(bool defer_commits)203 void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
204   // Thread-only feature.
205   NOTREACHED();
206 }
207 
CommitRequested() const208 bool SingleThreadProxy::CommitRequested() const { return false; }
209 
BeginMainFrameRequested() const210 bool SingleThreadProxy::BeginMainFrameRequested() const { return false; }
211 
MaxPartialTextureUpdates() const212 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
213   return std::numeric_limits<size_t>::max();
214 }
215 
Stop()216 void SingleThreadProxy::Stop() {
217   TRACE_EVENT0("cc", "SingleThreadProxy::stop");
218   DCHECK(Proxy::IsMainThread());
219   {
220     DebugScopedSetMainThreadBlocked main_thread_blocked(this);
221     DebugScopedSetImplThread impl(this);
222 
223     BlockingTaskRunner::CapturePostTasks blocked;
224     layer_tree_host_->DeleteContentsTexturesOnImplThread(
225         layer_tree_host_impl_->resource_provider());
226     layer_tree_host_impl_.reset();
227   }
228   layer_tree_host_ = NULL;
229 }
230 
OnCanDrawStateChanged(bool can_draw)231 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
232   TRACE_EVENT1(
233       "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
234   DCHECK(Proxy::IsImplThread());
235   UpdateBackgroundAnimateTicking();
236 }
237 
NotifyReadyToActivate()238 void SingleThreadProxy::NotifyReadyToActivate() {
239   // Thread-only feature.
240   NOTREACHED();
241 }
242 
SetNeedsRedrawOnImplThread()243 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
244   client_->ScheduleComposite();
245 }
246 
SetNeedsAnimateOnImplThread()247 void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
248   SetNeedsRedrawOnImplThread();
249 }
250 
SetNeedsManageTilesOnImplThread()251 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
252   // Thread-only/Impl-side-painting-only feature.
253   NOTREACHED();
254 }
255 
SetNeedsRedrawRectOnImplThread(const gfx::Rect & damage_rect)256 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
257     const gfx::Rect& damage_rect) {
258   // TODO(brianderson): Once we move render_widget scheduling into this class,
259   // we can treat redraw requests more efficiently than CommitAndRedraw
260   // requests.
261   layer_tree_host_impl_->SetViewportDamage(damage_rect);
262   SetNeedsCommit();
263 }
264 
DidInitializeVisibleTileOnImplThread()265 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
266   // Impl-side painting only.
267   NOTREACHED();
268 }
269 
SetNeedsCommitOnImplThread()270 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
271   client_->ScheduleComposite();
272 }
273 
PostAnimationEventsToMainThreadOnImplThread(scoped_ptr<AnimationEventsVector> events)274 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
275     scoped_ptr<AnimationEventsVector> events) {
276   TRACE_EVENT0(
277       "cc", "SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
278   DCHECK(Proxy::IsImplThread());
279   DebugScopedSetMainThread main(this);
280   layer_tree_host_->SetAnimationEvents(events.Pass());
281 }
282 
ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes,int priority_cutoff)283 bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
284     size_t limit_bytes,
285     int priority_cutoff) {
286   DCHECK(IsImplThread());
287   PrioritizedResourceManager* contents_texture_manager =
288       layer_tree_host_->contents_texture_manager();
289 
290   ResourceProvider* resource_provider =
291       layer_tree_host_impl_->resource_provider();
292 
293   if (!contents_texture_manager || !resource_provider)
294     return false;
295 
296   return contents_texture_manager->ReduceMemoryOnImplThread(
297       limit_bytes, priority_cutoff, resource_provider);
298 }
299 
IsInsideDraw()300 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
301 
UpdateRendererCapabilitiesOnImplThread()302 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
303   DCHECK(IsImplThread());
304   renderer_capabilities_for_main_thread_ =
305       layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
306 }
307 
DidLoseOutputSurfaceOnImplThread()308 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
309   TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread");
310   // Cause a commit so we can notice the lost context.
311   SetNeedsCommitOnImplThread();
312   client_->DidAbortSwapBuffers();
313 }
314 
DidSwapBuffersOnImplThread()315 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
316   client_->DidPostSwapBuffers();
317 }
318 
DidSwapBuffersCompleteOnImplThread()319 void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() {
320   TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
321   client_->DidCompleteSwapBuffers();
322 }
323 
324 // Called by the legacy scheduling path (e.g. where render_widget does the
325 // scheduling)
CompositeImmediately(base::TimeTicks frame_begin_time)326 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
327   TRACE_EVENT0("cc", "SingleThreadProxy::CompositeImmediately");
328   DCHECK(Proxy::IsMainThread());
329   DCHECK(!layer_tree_host_->output_surface_lost());
330 
331   layer_tree_host_->AnimateLayers(frame_begin_time);
332 
333   if (PrioritizedResourceManager* contents_texture_manager =
334           layer_tree_host_->contents_texture_manager()) {
335     contents_texture_manager->UnlinkAndClearEvictedBackings();
336     contents_texture_manager->SetMaxMemoryLimitBytes(
337         layer_tree_host_impl_->memory_allocation_limit_bytes());
338     contents_texture_manager->SetExternalPriorityCutoff(
339         layer_tree_host_impl_->memory_allocation_priority_cutoff());
340   }
341 
342   scoped_ptr<ResourceUpdateQueue> queue =
343       make_scoped_ptr(new ResourceUpdateQueue);
344   layer_tree_host_->UpdateLayers(queue.get());
345   layer_tree_host_->WillCommit();
346   DoCommit(queue.Pass());
347   layer_tree_host_->DidBeginMainFrame();
348 
349   LayerTreeHostImpl::FrameData frame;
350   if (DoComposite(frame_begin_time, &frame)) {
351     {
352       DebugScopedSetMainThreadBlocked main_thread_blocked(this);
353       DebugScopedSetImplThread impl(this);
354 
355       // This CapturePostTasks should be destroyed before
356       // DidCommitAndDrawFrame() is called since that goes out to the embedder,
357       // and we want the embedder to receive its callbacks before that.
358       // NOTE: This maintains consistent ordering with the ThreadProxy since
359       // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
360       // there as the main thread is not blocked, so any posted tasks inside
361       // the swap buffers will execute first.
362       BlockingTaskRunner::CapturePostTasks blocked;
363 
364       layer_tree_host_impl_->SwapBuffers(frame);
365     }
366     DidSwapFrame();
367   }
368 }
369 
AsValue() const370 scoped_ptr<base::Value> SingleThreadProxy::AsValue() const {
371   scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
372   {
373     // The following line casts away const modifiers because it is just
374     // setting debug state. We still want the AsValue() function and its
375     // call chain to be const throughout.
376     DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this));
377 
378     state->Set("layer_tree_host_impl",
379                layer_tree_host_impl_->AsValue().release());
380   }
381   return state.PassAs<base::Value>();
382 }
383 
ForceSerializeOnSwapBuffers()384 void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
385   {
386     DebugScopedSetImplThread impl(this);
387     if (layer_tree_host_impl_->renderer()) {
388       DCHECK(!layer_tree_host_->output_surface_lost());
389       layer_tree_host_impl_->renderer()->DoNoOp();
390     }
391   }
392 }
393 
ShouldComposite() const394 bool SingleThreadProxy::ShouldComposite() const {
395   DCHECK(Proxy::IsImplThread());
396   return layer_tree_host_impl_->visible() &&
397          layer_tree_host_impl_->CanDraw();
398 }
399 
UpdateBackgroundAnimateTicking()400 void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
401   DCHECK(Proxy::IsImplThread());
402   layer_tree_host_impl_->UpdateBackgroundAnimateTicking(
403       !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer());
404 }
405 
DoComposite(base::TimeTicks frame_begin_time,LayerTreeHostImpl::FrameData * frame)406 bool SingleThreadProxy::DoComposite(
407     base::TimeTicks frame_begin_time,
408     LayerTreeHostImpl::FrameData* frame) {
409   TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
410   DCHECK(!layer_tree_host_->output_surface_lost());
411 
412   bool lost_output_surface = false;
413   {
414     DebugScopedSetImplThread impl(this);
415     base::AutoReset<bool> mark_inside(&inside_draw_, true);
416 
417     // We guard PrepareToDraw() with CanDraw() because it always returns a valid
418     // frame, so can only be used when such a frame is possible. Since
419     // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
420     // CanDraw() as well.
421     if (!ShouldComposite()) {
422       UpdateBackgroundAnimateTicking();
423       return false;
424     }
425 
426     layer_tree_host_impl_->Animate(
427         layer_tree_host_impl_->CurrentFrameTimeTicks());
428     UpdateBackgroundAnimateTicking();
429 
430     if (!layer_tree_host_impl_->IsContextLost()) {
431       layer_tree_host_impl_->PrepareToDraw(frame);
432       layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);
433       layer_tree_host_impl_->DidDrawAllLayers(*frame);
434     }
435     lost_output_surface = layer_tree_host_impl_->IsContextLost();
436 
437     bool start_ready_animations = true;
438     layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
439 
440     layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame();
441   }
442 
443   if (lost_output_surface) {
444     layer_tree_host_->DidLoseOutputSurface();
445     return false;
446   }
447 
448   return true;
449 }
450 
DidSwapFrame()451 void SingleThreadProxy::DidSwapFrame() {
452   if (next_frame_is_newly_committed_frame_) {
453     next_frame_is_newly_committed_frame_ = false;
454     layer_tree_host_->DidCommitAndDrawFrame();
455   }
456 }
457 
CommitPendingForTesting()458 bool SingleThreadProxy::CommitPendingForTesting() { return false; }
459 
460 }  // namespace cc
461