• 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       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