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