Home | History | Annotate | Download | only in trees
      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 
     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 
     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 
     46 void SingleThreadProxy::Start() {
     47   DebugScopedSetImplThread impl(this);
     48   layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
     49 }
     50 
     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 
     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 
     67 bool SingleThreadProxy::IsStarted() const {
     68   DCHECK(Proxy::IsMainThread());
     69   return layer_tree_host_impl_;
     70 }
     71 
     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 
     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 
     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 
    115 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 
    121 void SingleThreadProxy::SetNeedsAnimate() {
    122   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
    123   DCHECK(Proxy::IsMainThread());
    124   client_->ScheduleAnimation();
    125 }
    126 
    127 void SingleThreadProxy::SetNeedsUpdateLayers() {
    128   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
    129   DCHECK(Proxy::IsMainThread());
    130   client_->ScheduleComposite();
    131 }
    132 
    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 
    188 void SingleThreadProxy::SetNeedsCommit() {
    189   DCHECK(Proxy::IsMainThread());
    190   client_->ScheduleComposite();
    191 }
    192 
    193 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
    194   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
    195   SetNeedsRedrawRectOnImplThread(damage_rect);
    196   client_->ScheduleComposite();
    197 }
    198 
    199 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
    200   // There is no activation here other than commit. So do nothing.
    201 }
    202 
    203 void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
    204   // Thread-only feature.
    205   NOTREACHED();
    206 }
    207 
    208 bool SingleThreadProxy::CommitRequested() const { return false; }
    209 
    210 bool SingleThreadProxy::BeginMainFrameRequested() const { return false; }
    211 
    212 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
    213   return std::numeric_limits<size_t>::max();
    214 }
    215 
    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 
    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 
    238 void SingleThreadProxy::NotifyReadyToActivate() {
    239   // Thread-only feature.
    240   NOTREACHED();
    241 }
    242 
    243 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
    244   client_->ScheduleComposite();
    245 }
    246 
    247 void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
    248   SetNeedsRedrawOnImplThread();
    249 }
    250 
    251 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
    252   // Thread-only/Impl-side-painting-only feature.
    253   NOTREACHED();
    254 }
    255 
    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 
    265 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
    266   // Impl-side painting only.
    267   NOTREACHED();
    268 }
    269 
    270 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
    271   client_->ScheduleComposite();
    272 }
    273 
    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 
    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 
    300 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
    301 
    302 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
    303   DCHECK(IsImplThread());
    304   renderer_capabilities_for_main_thread_ =
    305       layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
    306 }
    307 
    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 
    315 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
    316   client_->DidPostSwapBuffers();
    317 }
    318 
    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)
    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 
    370 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 
    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 
    394 bool SingleThreadProxy::ShouldComposite() const {
    395   DCHECK(Proxy::IsImplThread());
    396   return layer_tree_host_impl_->visible() &&
    397          layer_tree_host_impl_->CanDraw();
    398 }
    399 
    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 
    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 
    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 
    458 bool SingleThreadProxy::CommitPendingForTesting() { return false; }
    459 
    460 }  // namespace cc
    461