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       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 
     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 
     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 
     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 
     85 void SingleThreadProxy::FinishAllRendering() {
     86   DCHECK(Proxy::IsMainThread());
     87   {
     88     DebugScopedSetImplThread impl(this);
     89     layer_tree_host_impl_->FinishAllRendering();
     90   }
     91 }
     92 
     93 bool SingleThreadProxy::IsStarted() const {
     94   DCHECK(Proxy::IsMainThread());
     95   return layer_tree_host_impl_;
     96 }
     97 
     98 void SingleThreadProxy::SetLayerTreeHostClientReady() {
     99   // Scheduling is controlled by the embedder in the single thread case, so
    100   // nothing to do.
    101 }
    102 
    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 
    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 
    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 
    170 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 
    176 void SingleThreadProxy::SetNeedsAnimate() {
    177   DCHECK(Proxy::IsMainThread());
    178   client_->ScheduleAnimation();
    179 }
    180 
    181 void SingleThreadProxy::SetNeedsUpdateLayers() {
    182   DCHECK(Proxy::IsMainThread());
    183   client_->ScheduleComposite();
    184 }
    185 
    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 
    240 void SingleThreadProxy::SetNeedsCommit() {
    241   DCHECK(Proxy::IsMainThread());
    242   client_->ScheduleComposite();
    243 }
    244 
    245 void SingleThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) {
    246   SetNeedsRedrawRectOnImplThread(damage_rect);
    247   client_->ScheduleComposite();
    248 }
    249 
    250 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
    251   // There is no activation here other than commit. So do nothing.
    252 }
    253 
    254 void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
    255   // Thread-only feature.
    256   NOTREACHED();
    257 }
    258 
    259 bool SingleThreadProxy::CommitRequested() const { return false; }
    260 
    261 bool SingleThreadProxy::BeginMainFrameRequested() const { return false; }
    262 
    263 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
    264   return std::numeric_limits<size_t>::max();
    265 }
    266 
    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 
    281 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
    282   DCHECK(Proxy::IsImplThread());
    283   UpdateBackgroundAnimateTicking();
    284 }
    285 
    286 void SingleThreadProxy::NotifyReadyToActivate() {
    287   // Thread-only feature.
    288   NOTREACHED();
    289 }
    290 
    291 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
    292   client_->ScheduleComposite();
    293 }
    294 
    295 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
    296   // Thread-only/Impl-side-painting-only feature.
    297   NOTREACHED();
    298 }
    299 
    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 
    308 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
    309   // Impl-side painting only.
    310   NOTREACHED();
    311 }
    312 
    313 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
    314   client_->ScheduleComposite();
    315 }
    316 
    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 
    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 
    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 
    357 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
    358 
    359 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
    360   DCHECK(IsImplThread());
    361   renderer_capabilities_for_main_thread_ =
    362       layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
    363 }
    364 
    365 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
    366   // Cause a commit so we can notice the lost context.
    367   SetNeedsCommitOnImplThread();
    368   client_->DidAbortSwapBuffers();
    369 }
    370 
    371 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
    372   client_->DidPostSwapBuffers();
    373 }
    374 
    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)
    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 
    408 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 
    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 
    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 
    482 bool SingleThreadProxy::ShouldComposite() const {
    483   DCHECK(Proxy::IsImplThread());
    484   return layer_tree_host_impl_->visible() &&
    485          layer_tree_host_impl_->CanDraw();
    486 }
    487 
    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 
    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 
    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 
    558 bool SingleThreadProxy::CommitPendingForTesting() { return false; }
    559 
    560 }  // namespace cc
    561