Home | History | Annotate | Download | only in compositor
      1 // Copyright (c) 2012 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 "ui/compositor/compositor.h"
      6 
      7 #include <algorithm>
      8 #include <deque>
      9 
     10 #include "base/bind.h"
     11 #include "base/command_line.h"
     12 #include "base/debug/trace_event.h"
     13 #include "base/memory/singleton.h"
     14 #include "base/message_loop/message_loop.h"
     15 #include "base/metrics/histogram.h"
     16 #include "base/run_loop.h"
     17 #include "base/strings/string_util.h"
     18 #include "base/sys_info.h"
     19 #include "base/threading/thread.h"
     20 #include "base/threading/thread_restrictions.h"
     21 #include "cc/base/latency_info_swap_promise.h"
     22 #include "cc/base/switches.h"
     23 #include "cc/input/input_handler.h"
     24 #include "cc/layers/layer.h"
     25 #include "cc/output/context_provider.h"
     26 #include "cc/trees/layer_tree_host.h"
     27 #include "third_party/skia/include/core/SkBitmap.h"
     28 #include "ui/compositor/compositor_observer.h"
     29 #include "ui/compositor/compositor_switches.h"
     30 #include "ui/compositor/dip_util.h"
     31 #include "ui/compositor/layer.h"
     32 #include "ui/gfx/frame_time.h"
     33 #include "ui/gl/gl_context.h"
     34 #include "ui/gl/gl_switches.h"
     35 
     36 namespace {
     37 
     38 const double kDefaultRefreshRate = 60.0;
     39 const double kTestRefreshRate = 200.0;
     40 
     41 enum SwapType {
     42   DRAW_SWAP,
     43   READPIXELS_SWAP,
     44 };
     45 
     46 bool g_compositor_initialized = false;
     47 base::Thread* g_compositor_thread = NULL;
     48 
     49 ui::ContextFactory* g_context_factory = NULL;
     50 
     51 const int kCompositorLockTimeoutMs = 67;
     52 
     53 class PendingSwap {
     54  public:
     55   PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps);
     56   ~PendingSwap();
     57 
     58   SwapType type() const { return type_; }
     59   bool posted() const { return posted_; }
     60 
     61  private:
     62   friend class ui::PostedSwapQueue;
     63 
     64   SwapType type_;
     65   bool posted_;
     66   ui::PostedSwapQueue* posted_swaps_;
     67 
     68   DISALLOW_COPY_AND_ASSIGN(PendingSwap);
     69 };
     70 
     71 }  // namespace
     72 
     73 namespace ui {
     74 
     75 // static
     76 ContextFactory* ContextFactory::GetInstance() {
     77   DCHECK(g_context_factory);
     78   return g_context_factory;
     79 }
     80 
     81 // static
     82 void ContextFactory::SetInstance(ContextFactory* instance) {
     83   g_context_factory = instance;
     84 }
     85 
     86 Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor)
     87     : size_(size),
     88       flipped_(flipped),
     89       device_scale_factor_(device_scale_factor) {
     90 }
     91 
     92 Texture::~Texture() {
     93 }
     94 
     95 std::string Texture::Produce() {
     96   return std::string();
     97 }
     98 
     99 CompositorLock::CompositorLock(Compositor* compositor)
    100     : compositor_(compositor) {
    101   base::MessageLoop::current()->PostDelayedTask(
    102       FROM_HERE,
    103       base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
    104       base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
    105 }
    106 
    107 CompositorLock::~CompositorLock() {
    108   CancelLock();
    109 }
    110 
    111 void CompositorLock::CancelLock() {
    112   if (!compositor_)
    113     return;
    114   compositor_->UnlockCompositor();
    115   compositor_ = NULL;
    116 }
    117 
    118 // static
    119 void DrawWaiterForTest::Wait(Compositor* compositor) {
    120   DrawWaiterForTest waiter;
    121   waiter.wait_for_commit_ = false;
    122   waiter.WaitImpl(compositor);
    123 }
    124 
    125 // static
    126 void DrawWaiterForTest::WaitForCommit(Compositor* compositor) {
    127   DrawWaiterForTest waiter;
    128   waiter.wait_for_commit_ = true;
    129   waiter.WaitImpl(compositor);
    130 }
    131 
    132 DrawWaiterForTest::DrawWaiterForTest() {
    133 }
    134 
    135 DrawWaiterForTest::~DrawWaiterForTest() {
    136 }
    137 
    138 void DrawWaiterForTest::WaitImpl(Compositor* compositor) {
    139   compositor->AddObserver(this);
    140   wait_run_loop_.reset(new base::RunLoop());
    141   wait_run_loop_->Run();
    142   compositor->RemoveObserver(this);
    143 }
    144 
    145 void DrawWaiterForTest::OnCompositingDidCommit(Compositor* compositor) {
    146   if (wait_for_commit_)
    147     wait_run_loop_->Quit();
    148 }
    149 
    150 void DrawWaiterForTest::OnCompositingStarted(Compositor* compositor,
    151                                              base::TimeTicks start_time) {
    152 }
    153 
    154 void DrawWaiterForTest::OnCompositingEnded(Compositor* compositor) {
    155   if (!wait_for_commit_)
    156     wait_run_loop_->Quit();
    157 }
    158 
    159 void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) {
    160 }
    161 
    162 void DrawWaiterForTest::OnCompositingLockStateChanged(Compositor* compositor) {
    163 }
    164 
    165 void DrawWaiterForTest::OnUpdateVSyncParameters(Compositor* compositor,
    166                                                 base::TimeTicks timebase,
    167                                                 base::TimeDelta interval) {
    168 }
    169 
    170 class PostedSwapQueue {
    171  public:
    172   PostedSwapQueue() : pending_swap_(NULL) {
    173   }
    174 
    175   ~PostedSwapQueue() {
    176     DCHECK(!pending_swap_);
    177   }
    178 
    179   SwapType NextPostedSwap() const {
    180     return queue_.front();
    181   }
    182 
    183   bool AreSwapsPosted() const {
    184     return !queue_.empty();
    185   }
    186 
    187   int NumSwapsPosted(SwapType type) const {
    188     int count = 0;
    189     for (std::deque<SwapType>::const_iterator it = queue_.begin();
    190          it != queue_.end(); ++it) {
    191       if (*it == type)
    192         count++;
    193     }
    194     return count;
    195   }
    196 
    197   void PostSwap() {
    198     DCHECK(pending_swap_);
    199     queue_.push_back(pending_swap_->type());
    200     pending_swap_->posted_ = true;
    201   }
    202 
    203   void EndSwap() {
    204     queue_.pop_front();
    205   }
    206 
    207  private:
    208   friend class ::PendingSwap;
    209 
    210   PendingSwap* pending_swap_;
    211   std::deque<SwapType> queue_;
    212 
    213   DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue);
    214 };
    215 
    216 }  // namespace ui
    217 
    218 namespace {
    219 
    220 PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps)
    221     : type_(type), posted_(false), posted_swaps_(posted_swaps) {
    222   // Only one pending swap in flight.
    223   DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_);
    224   posted_swaps_->pending_swap_ = this;
    225 }
    226 
    227 PendingSwap::~PendingSwap() {
    228   DCHECK_EQ(this, posted_swaps_->pending_swap_);
    229   posted_swaps_->pending_swap_ = NULL;
    230 }
    231 
    232 }  // namespace
    233 
    234 namespace ui {
    235 
    236 Compositor::Compositor(gfx::AcceleratedWidget widget)
    237     : root_layer_(NULL),
    238       widget_(widget),
    239       posted_swaps_(new PostedSwapQueue()),
    240       device_scale_factor_(0.0f),
    241       last_started_frame_(0),
    242       last_ended_frame_(0),
    243       next_draw_is_resize_(false),
    244       disable_schedule_composite_(false),
    245       compositor_lock_(NULL),
    246       defer_draw_scheduling_(false),
    247       waiting_on_compositing_end_(false),
    248       draw_on_compositing_end_(false),
    249       schedule_draw_factory_(this) {
    250   DCHECK(g_compositor_initialized)
    251       << "Compositor::Initialize must be called before creating a Compositor.";
    252 
    253   root_web_layer_ = cc::Layer::Create();
    254   root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
    255 
    256   CommandLine* command_line = CommandLine::ForCurrentProcess();
    257 
    258   cc::LayerTreeSettings settings;
    259   settings.refresh_rate =
    260       ContextFactory::GetInstance()->DoesCreateTestContexts()
    261       ? kTestRefreshRate
    262       : kDefaultRefreshRate;
    263   settings.deadline_scheduling_enabled =
    264       switches::IsUIDeadlineSchedulingEnabled();
    265   settings.partial_swap_enabled =
    266       !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap);
    267   settings.per_tile_painting_enabled =
    268       command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting);
    269 
    270   // These flags should be mirrored by renderer versions in content/renderer/.
    271   settings.initial_debug_state.show_debug_borders =
    272       command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders);
    273   settings.initial_debug_state.show_fps_counter =
    274       command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
    275   settings.initial_debug_state.show_layer_animation_bounds_rects =
    276       command_line->HasSwitch(cc::switches::kUIShowLayerAnimationBounds);
    277   settings.initial_debug_state.show_paint_rects =
    278       command_line->HasSwitch(switches::kUIShowPaintRects);
    279   settings.initial_debug_state.show_property_changed_rects =
    280       command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects);
    281   settings.initial_debug_state.show_surface_damage_rects =
    282       command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects);
    283   settings.initial_debug_state.show_screen_space_rects =
    284       command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects);
    285   settings.initial_debug_state.show_replica_screen_space_rects =
    286       command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects);
    287   settings.initial_debug_state.show_occluding_rects =
    288       command_line->HasSwitch(cc::switches::kUIShowOccludingRects);
    289   settings.initial_debug_state.show_non_occluding_rects =
    290       command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
    291 
    292   base::TimeTicks before_create = base::TimeTicks::Now();
    293   if (!!g_compositor_thread) {
    294     host_ = cc::LayerTreeHost::CreateThreaded(
    295         this, NULL, settings, g_compositor_thread->message_loop_proxy());
    296   } else {
    297     host_ = cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings);
    298   }
    299   UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor",
    300                       base::TimeTicks::Now() - before_create);
    301   host_->SetRootLayer(root_web_layer_);
    302   host_->SetLayerTreeHostClientReady();
    303 }
    304 
    305 Compositor::~Compositor() {
    306   TRACE_EVENT0("shutdown", "Compositor::destructor");
    307 
    308   DCHECK(g_compositor_initialized);
    309 
    310   CancelCompositorLock();
    311   DCHECK(!compositor_lock_);
    312 
    313   if (root_layer_)
    314     root_layer_->SetCompositor(NULL);
    315 
    316   // Stop all outstanding draws before telling the ContextFactory to tear
    317   // down any contexts that the |host_| may rely upon.
    318   host_.reset();
    319 
    320   ContextFactory::GetInstance()->RemoveCompositor(this);
    321 }
    322 
    323 // static
    324 void Compositor::Initialize() {
    325 #if defined(OS_CHROMEOS)
    326   bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch(
    327       switches::kUIDisableThreadedCompositing);
    328 #else
    329   bool use_thread =
    330       CommandLine::ForCurrentProcess()->HasSwitch(
    331           switches::kUIEnableThreadedCompositing) &&
    332       !CommandLine::ForCurrentProcess()->HasSwitch(
    333           switches::kUIDisableThreadedCompositing);
    334 #endif
    335   if (use_thread) {
    336     g_compositor_thread = new base::Thread("Browser Compositor");
    337     g_compositor_thread->Start();
    338   }
    339 
    340   DCHECK(!g_compositor_initialized) << "Compositor initialized twice.";
    341   g_compositor_initialized = true;
    342 }
    343 
    344 // static
    345 bool Compositor::WasInitializedWithThread() {
    346   DCHECK(g_compositor_initialized);
    347   return !!g_compositor_thread;
    348 }
    349 
    350 // static
    351 scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() {
    352   scoped_refptr<base::MessageLoopProxy> proxy;
    353   if (g_compositor_thread)
    354     proxy = g_compositor_thread->message_loop_proxy();
    355   return proxy;
    356 }
    357 
    358 // static
    359 void Compositor::Terminate() {
    360   if (g_compositor_thread) {
    361     g_compositor_thread->Stop();
    362     delete g_compositor_thread;
    363     g_compositor_thread = NULL;
    364   }
    365 
    366   DCHECK(g_compositor_initialized) << "Compositor::Initialize() didn't happen.";
    367   g_compositor_initialized = false;
    368 }
    369 
    370 void Compositor::ScheduleDraw() {
    371   if (g_compositor_thread) {
    372     host_->Composite(gfx::FrameTime::Now());
    373   } else if (!defer_draw_scheduling_) {
    374     defer_draw_scheduling_ = true;
    375     base::MessageLoop::current()->PostTask(
    376         FROM_HERE,
    377         base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr()));
    378   }
    379 }
    380 
    381 void Compositor::SetRootLayer(Layer* root_layer) {
    382   if (root_layer_ == root_layer)
    383     return;
    384   if (root_layer_)
    385     root_layer_->SetCompositor(NULL);
    386   root_layer_ = root_layer;
    387   if (root_layer_ && !root_layer_->GetCompositor())
    388     root_layer_->SetCompositor(this);
    389   root_web_layer_->RemoveAllChildren();
    390   if (root_layer_)
    391     root_web_layer_->AddChild(root_layer_->cc_layer());
    392 }
    393 
    394 void Compositor::SetHostHasTransparentBackground(
    395     bool host_has_transparent_background) {
    396   host_->set_has_transparent_background(host_has_transparent_background);
    397 }
    398 
    399 void Compositor::Draw() {
    400   DCHECK(!g_compositor_thread);
    401 
    402   defer_draw_scheduling_ = false;
    403   if (waiting_on_compositing_end_) {
    404     draw_on_compositing_end_ = true;
    405     return;
    406   }
    407   waiting_on_compositing_end_ = true;
    408 
    409   TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_ + 1);
    410 
    411   if (!root_layer_)
    412     return;
    413 
    414   last_started_frame_++;
    415   PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get());
    416   if (!IsLocked()) {
    417     // TODO(nduca): Temporary while compositor calls
    418     // compositeImmediately() directly.
    419     Layout();
    420     host_->Composite(gfx::FrameTime::Now());
    421 
    422 #if defined(OS_WIN)
    423     // While we resize, we are usually a few frames behind. By blocking
    424     // the UI thread here we minize the area that is mis-painted, specially
    425     // in the non-client area. See RenderWidgetHostViewAura::SetBounds for
    426     // more details and bug 177115.
    427     if (next_draw_is_resize_ && (last_ended_frame_ > 1)) {
    428       next_draw_is_resize_ = false;
    429       host_->FinishAllRendering();
    430     }
    431 #endif
    432 
    433   }
    434   if (!pending_swap.posted())
    435     NotifyEnd();
    436 }
    437 
    438 void Compositor::ScheduleFullRedraw() {
    439   host_->SetNeedsRedraw();
    440 }
    441 
    442 void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
    443   host_->SetNeedsRedrawRect(damage_rect);
    444 }
    445 
    446 void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
    447   scoped_ptr<cc::SwapPromise> swap_promise(
    448       new cc::LatencyInfoSwapPromise(latency_info));
    449   host_->QueueSwapPromise(swap_promise.Pass());
    450 }
    451 
    452 bool Compositor::ReadPixels(SkBitmap* bitmap,
    453                             const gfx::Rect& bounds_in_pixel) {
    454   if (bounds_in_pixel.right() > size().width() ||
    455       bounds_in_pixel.bottom() > size().height())
    456     return false;
    457   bitmap->setConfig(SkBitmap::kARGB_8888_Config,
    458                     bounds_in_pixel.width(), bounds_in_pixel.height());
    459   bitmap->allocPixels();
    460   SkAutoLockPixels lock_image(*bitmap);
    461   unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels());
    462   CancelCompositorLock();
    463   PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get());
    464   return host_->CompositeAndReadback(pixels, bounds_in_pixel);
    465 }
    466 
    467 void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
    468   DCHECK_GT(scale, 0);
    469   if (!size_in_pixel.IsEmpty()) {
    470     size_ = size_in_pixel;
    471     host_->SetViewportSize(size_in_pixel);
    472     root_web_layer_->SetBounds(size_in_pixel);
    473 
    474     next_draw_is_resize_ = true;
    475   }
    476   if (device_scale_factor_ != scale) {
    477     device_scale_factor_ = scale;
    478     if (root_layer_)
    479       root_layer_->OnDeviceScaleFactorChanged(scale);
    480   }
    481 }
    482 
    483 void Compositor::SetBackgroundColor(SkColor color) {
    484   host_->set_background_color(color);
    485   ScheduleDraw();
    486 }
    487 
    488 void Compositor::AddObserver(CompositorObserver* observer) {
    489   observer_list_.AddObserver(observer);
    490 }
    491 
    492 void Compositor::RemoveObserver(CompositorObserver* observer) {
    493   observer_list_.RemoveObserver(observer);
    494 }
    495 
    496 bool Compositor::HasObserver(CompositorObserver* observer) {
    497   return observer_list_.HasObserver(observer);
    498 }
    499 
    500 void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase,
    501                                          base::TimeDelta interval) {
    502   FOR_EACH_OBSERVER(CompositorObserver,
    503                     observer_list_,
    504                     OnUpdateVSyncParameters(this, timebase, interval));
    505 }
    506 
    507 void Compositor::Layout() {
    508   // We're sending damage that will be addressed during this composite
    509   // cycle, so we don't need to schedule another composite to address it.
    510   disable_schedule_composite_ = true;
    511   if (root_layer_)
    512     root_layer_->SendDamagedRects();
    513   disable_schedule_composite_ = false;
    514 }
    515 
    516 scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) {
    517   return ContextFactory::GetInstance()->CreateOutputSurface(this, fallback);
    518 }
    519 
    520 void Compositor::DidCommit() {
    521   DCHECK(!IsLocked());
    522   FOR_EACH_OBSERVER(CompositorObserver,
    523                     observer_list_,
    524                     OnCompositingDidCommit(this));
    525 }
    526 
    527 void Compositor::DidCommitAndDrawFrame() {
    528   base::TimeTicks start_time = gfx::FrameTime::Now();
    529   FOR_EACH_OBSERVER(CompositorObserver,
    530                     observer_list_,
    531                     OnCompositingStarted(this, start_time));
    532 }
    533 
    534 void Compositor::DidCompleteSwapBuffers() {
    535   if (g_compositor_thread) {
    536     NotifyEnd();
    537   } else {
    538     DCHECK(posted_swaps_->AreSwapsPosted());
    539     DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
    540     if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
    541       NotifyEnd();
    542     posted_swaps_->EndSwap();
    543   }
    544 }
    545 
    546 scoped_refptr<cc::ContextProvider> Compositor::OffscreenContextProvider() {
    547   return ContextFactory::GetInstance()->OffscreenCompositorContextProvider();
    548 }
    549 
    550 void Compositor::ScheduleComposite() {
    551   if (!disable_schedule_composite_)
    552     ScheduleDraw();
    553 }
    554 
    555 void Compositor::ScheduleAnimation() {
    556   ScheduleComposite();
    557 }
    558 
    559 void Compositor::DidPostSwapBuffers() {
    560   DCHECK(!g_compositor_thread);
    561   posted_swaps_->PostSwap();
    562 }
    563 
    564 void Compositor::DidAbortSwapBuffers() {
    565   if (!g_compositor_thread) {
    566     DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
    567 
    568     // We've just lost the context, so unwind all posted_swaps.
    569     while (posted_swaps_->AreSwapsPosted()) {
    570       if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
    571         NotifyEnd();
    572       posted_swaps_->EndSwap();
    573     }
    574   }
    575 
    576   FOR_EACH_OBSERVER(CompositorObserver,
    577                     observer_list_,
    578                     OnCompositingAborted(this));
    579 }
    580 
    581 const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
    582   return host_->debug_state();
    583 }
    584 
    585 void Compositor::SetLayerTreeDebugState(
    586     const cc::LayerTreeDebugState& debug_state) {
    587   host_->SetDebugState(debug_state);
    588 }
    589 
    590 scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
    591   if (!compositor_lock_) {
    592     compositor_lock_ = new CompositorLock(this);
    593     if (g_compositor_thread)
    594       host_->SetDeferCommits(true);
    595     FOR_EACH_OBSERVER(CompositorObserver,
    596                       observer_list_,
    597                       OnCompositingLockStateChanged(this));
    598   }
    599   return compositor_lock_;
    600 }
    601 
    602 void Compositor::UnlockCompositor() {
    603   DCHECK(compositor_lock_);
    604   compositor_lock_ = NULL;
    605   if (g_compositor_thread)
    606     host_->SetDeferCommits(false);
    607   FOR_EACH_OBSERVER(CompositorObserver,
    608                     observer_list_,
    609                     OnCompositingLockStateChanged(this));
    610 }
    611 
    612 void Compositor::CancelCompositorLock() {
    613   if (compositor_lock_)
    614     compositor_lock_->CancelLock();
    615 }
    616 
    617 void Compositor::NotifyEnd() {
    618   last_ended_frame_++;
    619   TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_);
    620   waiting_on_compositing_end_ = false;
    621   if (draw_on_compositing_end_) {
    622     draw_on_compositing_end_ = false;
    623 
    624     // Call ScheduleDraw() instead of Draw() in order to allow other
    625     // CompositorObservers to be notified before starting another
    626     // draw cycle.
    627     ScheduleDraw();
    628   }
    629   FOR_EACH_OBSERVER(CompositorObserver,
    630                     observer_list_,
    631                     OnCompositingEnded(this));
    632 }
    633 
    634 }  // namespace ui
    635