single_thread_proxy.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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) {
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) {
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    layer_tree_host_->contents_texture_manager()->
189        PushTexturePrioritiesToBackings();
190    layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
191
192    scoped_ptr<ResourceUpdateController> update_controller =
193        ResourceUpdateController::Create(
194            NULL,
195            Proxy::MainThread(),
196            queue.Pass(),
197            layer_tree_host_impl_->resource_provider());
198    update_controller->Finalize();
199
200    layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
201
202    layer_tree_host_impl_->CommitComplete();
203
204#ifndef NDEBUG
205    // In the single-threaded case, the scroll deltas should never be
206    // touched on the impl layer tree.
207    scoped_ptr<ScrollAndScaleSet> scroll_info =
208        layer_tree_host_impl_->ProcessScrollDeltas();
209    DCHECK(!scroll_info->scrolls.size());
210#endif
211
212    base::TimeDelta duration = stats_instrumentation->EndRecording(start_time);
213    stats_instrumentation->AddCommit(duration);
214  }
215  layer_tree_host_->CommitComplete();
216  next_frame_is_newly_committed_frame_ = true;
217}
218
219void SingleThreadProxy::SetNeedsCommit() {
220  DCHECK(Proxy::IsMainThread());
221  layer_tree_host_->ScheduleComposite();
222}
223
224void SingleThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) {
225  SetNeedsRedrawRectOnImplThread(damage_rect);
226}
227
228void SingleThreadProxy::OnHasPendingTreeStateChanged(bool have_pending_tree) {
229  // Thread-only feature.
230  NOTREACHED();
231}
232
233void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
234  // Thread-only feature.
235  NOTREACHED();
236}
237
238bool SingleThreadProxy::CommitRequested() const { return false; }
239
240size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
241  return std::numeric_limits<size_t>::max();
242}
243
244void SingleThreadProxy::Stop() {
245  TRACE_EVENT0("cc", "SingleThreadProxy::stop");
246  DCHECK(Proxy::IsMainThread());
247  {
248    DebugScopedSetMainThreadBlocked mainThreadBlocked(this);
249    DebugScopedSetImplThread impl(this);
250
251    layer_tree_host_->DeleteContentsTexturesOnImplThread(
252        layer_tree_host_impl_->resource_provider());
253    layer_tree_host_impl_.reset();
254  }
255  layer_tree_host_ = NULL;
256}
257
258void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
259  DCHECK(Proxy::IsImplThread());
260  layer_tree_host_impl_->UpdateBackgroundAnimateTicking(!ShouldComposite());
261}
262
263void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
264  layer_tree_host_->ScheduleComposite();
265}
266
267void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) {
268  // FIXME: Once we move render_widget scheduling into this class, we can
269  // treat redraw requests more efficiently than CommitAndRedraw requests.
270  layer_tree_host_impl_->SetViewportDamage(damage_rect);
271  SetNeedsCommit();
272}
273
274void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
275  // Impl-side painting only.
276  NOTREACHED();
277}
278
279void SingleThreadProxy::SetNeedsCommitOnImplThread() {
280  layer_tree_host_->ScheduleComposite();
281}
282
283void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
284  layer_tree_host_->ScheduleComposite();
285}
286
287void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
288    scoped_ptr<AnimationEventsVector> events,
289    base::Time wall_clock_time) {
290  DCHECK(Proxy::IsImplThread());
291  DebugScopedSetMainThread main(this);
292  layer_tree_host_->SetAnimationEvents(events.Pass(), wall_clock_time);
293}
294
295bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
296    size_t limit_bytes,
297    int priority_cutoff) {
298  DCHECK(IsImplThread());
299  if (!layer_tree_host_->contents_texture_manager())
300    return false;
301
302  return layer_tree_host_->contents_texture_manager()->ReduceMemoryOnImplThread(
303      limit_bytes, priority_cutoff, layer_tree_host_impl_->resource_provider());
304}
305
306void SingleThreadProxy::ReduceWastedContentsTextureMemoryOnImplThread() {
307  // Impl-side painting only.
308  NOTREACHED();
309}
310
311void SingleThreadProxy::SendManagedMemoryStats() {
312  DCHECK(Proxy::IsImplThread());
313  if (!layer_tree_host_impl_)
314    return;
315  if (!layer_tree_host_->contents_texture_manager())
316    return;
317
318  PrioritizedResourceManager* contents_texture_manager =
319      layer_tree_host_->contents_texture_manager();
320  layer_tree_host_impl_->SendManagedMemoryStats(
321      contents_texture_manager->MemoryVisibleBytes(),
322      contents_texture_manager->MemoryVisibleAndNearbyBytes(),
323      contents_texture_manager->MemoryUseBytes());
324}
325
326bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
327
328void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
329  // Cause a commit so we can notice the lost context.
330  SetNeedsCommitOnImplThread();
331}
332
333// Called by the legacy scheduling path (e.g. where render_widget does the
334// scheduling)
335void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
336  gfx::Rect device_viewport_damage_rect;
337
338  LayerTreeHostImpl::FrameData frame;
339  if (CommitAndComposite(frame_begin_time,
340                         device_viewport_damage_rect,
341                         false,  // for_readback
342                         &frame)) {
343    layer_tree_host_impl_->SwapBuffers(frame);
344    DidSwapFrame();
345  }
346}
347
348scoped_ptr<base::Value> SingleThreadProxy::AsValue() const {
349  scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
350  {
351    // The following line casts away const modifiers because it is just
352    // setting debug state. We still want the AsValue() function and its
353    // call chain to be const throughout.
354    DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this));
355
356    state->Set("layer_tree_host_impl",
357               layer_tree_host_impl_->AsValue().release());
358  }
359  return state.PassAs<base::Value>();
360}
361
362void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
363  {
364    DebugScopedSetImplThread impl(this);
365    if (layer_tree_host_impl_->renderer()) {
366      DCHECK(!layer_tree_host_->output_surface_lost());
367      layer_tree_host_impl_->renderer()->DoNoOp();
368    }
369  }
370}
371
372bool SingleThreadProxy::CommitAndComposite(
373    base::TimeTicks frame_begin_time,
374    gfx::Rect device_viewport_damage_rect,
375    bool for_readback,
376    LayerTreeHostImpl::FrameData* frame) {
377  DCHECK(Proxy::IsMainThread());
378
379  if (!layer_tree_host_->InitializeOutputSurfaceIfNeeded())
380    return false;
381
382  layer_tree_host_->AnimateLayers(frame_begin_time);
383
384  scoped_refptr<cc::ContextProvider> offscreen_context_provider;
385  if (renderer_capabilities_for_main_thread_.using_offscreen_context3d &&
386      layer_tree_host_->needs_offscreen_context()) {
387    offscreen_context_provider =
388        layer_tree_host_->client()->OffscreenContextProviderForMainThread();
389    if (offscreen_context_provider)
390      created_offscreen_context_provider_ = true;
391  }
392
393  layer_tree_host_->contents_texture_manager()->UnlinkAndClearEvictedBackings();
394
395  scoped_ptr<ResourceUpdateQueue> queue =
396      make_scoped_ptr(new ResourceUpdateQueue);
397  layer_tree_host_->UpdateLayers(
398      queue.get(), layer_tree_host_impl_->memory_allocation_limit_bytes());
399
400  layer_tree_host_->WillCommit();
401  DoCommit(queue.Pass());
402  bool result = DoComposite(offscreen_context_provider,
403                            frame_begin_time,
404                            device_viewport_damage_rect,
405                            for_readback,
406                            frame);
407  layer_tree_host_->DidBeginFrame();
408  return result;
409}
410
411bool SingleThreadProxy::ShouldComposite() const {
412  DCHECK(Proxy::IsImplThread());
413  return layer_tree_host_impl_->visible() &&
414         layer_tree_host_impl_->CanDraw();
415}
416
417bool SingleThreadProxy::DoComposite(
418    scoped_refptr<cc::ContextProvider> offscreen_context_provider,
419    base::TimeTicks frame_begin_time,
420    gfx::Rect device_viewport_damage_rect,
421    bool for_readback,
422    LayerTreeHostImpl::FrameData* frame) {
423  DCHECK(!layer_tree_host_->output_surface_lost());
424
425  bool lost_output_surface = false;
426  {
427    DebugScopedSetImplThread impl(this);
428    base::AutoReset<bool> mark_inside(&inside_draw_, true);
429
430    layer_tree_host_impl_->resource_provider()->
431        set_offscreen_context_provider(offscreen_context_provider);
432
433    bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels();
434
435    // We guard PrepareToDraw() with CanDraw() because it always returns a valid
436    // frame, so can only be used when such a frame is possible. Since
437    // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
438    // CanDraw() as well.
439    if (!ShouldComposite() || (for_readback && !can_do_readback)) {
440      layer_tree_host_impl_->UpdateBackgroundAnimateTicking(true);
441      return false;
442    }
443
444    layer_tree_host_impl_->Animate(
445        layer_tree_host_impl_->CurrentFrameTimeTicks(),
446        layer_tree_host_impl_->CurrentFrameTime());
447    layer_tree_host_impl_->UpdateBackgroundAnimateTicking(false);
448
449    layer_tree_host_impl_->PrepareToDraw(frame, device_viewport_damage_rect);
450    layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);
451    layer_tree_host_impl_->DidDrawAllLayers(*frame);
452    lost_output_surface = layer_tree_host_impl_->IsContextLost();
453
454    bool start_ready_animations = true;
455    layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
456
457    layer_tree_host_impl_->BeginNextFrame();
458  }
459
460  if (lost_output_surface) {
461    cc::ContextProvider* offscreen_contexts = layer_tree_host_impl_->
462        resource_provider()->offscreen_context_provider();
463    if (offscreen_contexts)
464      offscreen_contexts->VerifyContexts();
465    layer_tree_host_->DidLoseOutputSurface();
466    return false;
467  }
468
469  return true;
470}
471
472void SingleThreadProxy::DidSwapFrame() {
473  if (next_frame_is_newly_committed_frame_) {
474    next_frame_is_newly_committed_frame_ = false;
475    layer_tree_host_->DidCommitAndDrawFrame();
476  }
477}
478
479bool SingleThreadProxy::CommitPendingForTesting() { return false; }
480
481skia::RefPtr<SkPicture> SingleThreadProxy::CapturePicture() {
482  // Impl-side painting only.
483  NOTREACHED();
484  return skia::RefPtr<SkPicture>();
485}
486
487}  // namespace cc
488