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