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