Home | History | Annotate | Download | only in renderer_host
      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 "content/browser/renderer_host/compositor_impl_android.h"
      6 
      7 #include <android/bitmap.h>
      8 #include <android/native_window_jni.h>
      9 
     10 #include "base/android/jni_android.h"
     11 #include "base/android/scoped_java_ref.h"
     12 #include "base/bind.h"
     13 #include "base/command_line.h"
     14 #include "base/containers/hash_tables.h"
     15 #include "base/lazy_instance.h"
     16 #include "base/logging.h"
     17 #include "base/single_thread_task_runner.h"
     18 #include "base/synchronization/lock.h"
     19 #include "base/threading/thread.h"
     20 #include "base/threading/thread_checker.h"
     21 #include "cc/base/switches.h"
     22 #include "cc/input/input_handler.h"
     23 #include "cc/layers/layer.h"
     24 #include "cc/output/compositor_frame.h"
     25 #include "cc/output/context_provider.h"
     26 #include "cc/output/output_surface.h"
     27 #include "cc/trees/layer_tree_host.h"
     28 #include "content/browser/android/child_process_launcher_android.h"
     29 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
     30 #include "content/browser/gpu/gpu_surface_tracker.h"
     31 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
     32 #include "content/common/gpu/client/context_provider_command_buffer.h"
     33 #include "content/common/gpu/client/gl_helper.h"
     34 #include "content/common/gpu/client/gpu_channel_host.h"
     35 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
     36 #include "content/common/gpu/gpu_process_launch_causes.h"
     37 #include "content/common/host_shared_bitmap_manager.h"
     38 #include "content/public/browser/android/compositor_client.h"
     39 #include "gpu/command_buffer/client/gles2_interface.h"
     40 #include "third_party/khronos/GLES2/gl2.h"
     41 #include "third_party/khronos/GLES2/gl2ext.h"
     42 #include "third_party/skia/include/core/SkMallocPixelRef.h"
     43 #include "ui/base/android/window_android.h"
     44 #include "ui/gfx/android/device_display_info.h"
     45 #include "ui/gfx/frame_time.h"
     46 #include "ui/gl/android/surface_texture.h"
     47 #include "ui/gl/android/surface_texture_tracker.h"
     48 #include "webkit/common/gpu/context_provider_in_process.h"
     49 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
     50 
     51 namespace {
     52 
     53 const unsigned int kMaxSwapBuffers = 2U;
     54 
     55 // Used to override capabilities_.adjust_deadline_for_parent to false
     56 class OutputSurfaceWithoutParent : public cc::OutputSurface {
     57  public:
     58   OutputSurfaceWithoutParent(const scoped_refptr<
     59       content::ContextProviderCommandBuffer>& context_provider)
     60       : cc::OutputSurface(context_provider) {
     61     capabilities_.adjust_deadline_for_parent = false;
     62   }
     63 
     64   virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE {
     65     content::ContextProviderCommandBuffer* provider_command_buffer =
     66         static_cast<content::ContextProviderCommandBuffer*>(
     67             context_provider_.get());
     68     content::CommandBufferProxyImpl* command_buffer_proxy =
     69         provider_command_buffer->GetCommandBufferProxy();
     70     DCHECK(command_buffer_proxy);
     71     command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
     72 
     73     OutputSurface::SwapBuffers(frame);
     74   }
     75 };
     76 
     77 class SurfaceTextureTrackerImpl : public gfx::SurfaceTextureTracker {
     78  public:
     79   SurfaceTextureTrackerImpl() : next_surface_texture_id_(1) {
     80     thread_checker_.DetachFromThread();
     81   }
     82 
     83   // Overridden from gfx::SurfaceTextureTracker:
     84   virtual scoped_refptr<gfx::SurfaceTexture> AcquireSurfaceTexture(
     85       int primary_id,
     86       int secondary_id) OVERRIDE {
     87     base::AutoLock lock(surface_textures_lock_);
     88     SurfaceTextureMapKey key(primary_id, secondary_id);
     89     SurfaceTextureMap::iterator it = surface_textures_.find(key);
     90     if (it == surface_textures_.end())
     91       return scoped_refptr<gfx::SurfaceTexture>();
     92     scoped_refptr<gfx::SurfaceTexture> surface_texture = it->second;
     93     surface_textures_.erase(it);
     94     return surface_texture;
     95   }
     96 
     97   int AddSurfaceTexture(gfx::SurfaceTexture* surface_texture,
     98                         int child_process_id) {
     99     DCHECK(thread_checker_.CalledOnValidThread());
    100     int surface_texture_id = next_surface_texture_id_++;
    101     if (next_surface_texture_id_ == INT_MAX)
    102       next_surface_texture_id_ = 1;
    103 
    104     base::AutoLock lock(surface_textures_lock_);
    105     SurfaceTextureMapKey key(surface_texture_id, child_process_id);
    106     DCHECK(surface_textures_.find(key) == surface_textures_.end());
    107     surface_textures_[key] = surface_texture;
    108     content::RegisterChildProcessSurfaceTexture(
    109         surface_texture_id,
    110         child_process_id,
    111         surface_texture->j_surface_texture().obj());
    112     return surface_texture_id;
    113   }
    114 
    115   void RemoveAllSurfaceTextures(int child_process_id) {
    116     DCHECK(thread_checker_.CalledOnValidThread());
    117     base::AutoLock lock(surface_textures_lock_);
    118     SurfaceTextureMap::iterator it = surface_textures_.begin();
    119     while (it != surface_textures_.end()) {
    120       if (it->first.second == child_process_id) {
    121         content::UnregisterChildProcessSurfaceTexture(it->first.first,
    122                                                       it->first.second);
    123         surface_textures_.erase(it++);
    124       } else {
    125         ++it;
    126       }
    127     }
    128   }
    129 
    130  private:
    131   typedef std::pair<int, int> SurfaceTextureMapKey;
    132   typedef base::hash_map<SurfaceTextureMapKey,
    133                          scoped_refptr<gfx::SurfaceTexture> >
    134       SurfaceTextureMap;
    135   SurfaceTextureMap surface_textures_;
    136   mutable base::Lock surface_textures_lock_;
    137   int next_surface_texture_id_;
    138   base::ThreadChecker thread_checker_;
    139 };
    140 base::LazyInstance<SurfaceTextureTrackerImpl> g_surface_texture_tracker =
    141     LAZY_INSTANCE_INITIALIZER;
    142 
    143 static bool g_initialized = false;
    144 
    145 } // anonymous namespace
    146 
    147 namespace content {
    148 
    149 // static
    150 Compositor* Compositor::Create(CompositorClient* client,
    151                                gfx::NativeWindow root_window) {
    152   return client ? new CompositorImpl(client, root_window) : NULL;
    153 }
    154 
    155 // static
    156 void Compositor::Initialize() {
    157   DCHECK(!CompositorImpl::IsInitialized());
    158   // SurfaceTextureTracker instance must be set before we create a GPU thread
    159   // that could be using it to initialize GLImage instances.
    160   gfx::SurfaceTextureTracker::InitInstance(g_surface_texture_tracker.Pointer());
    161   g_initialized = true;
    162 }
    163 
    164 // static
    165 bool CompositorImpl::IsInitialized() {
    166   return g_initialized;
    167 }
    168 
    169 // static
    170 int CompositorImpl::CreateSurfaceTexture(int child_process_id) {
    171   // Note: this needs to be 0 as the surface texture implemenation will take
    172   // ownership of the texture and call glDeleteTextures when the GPU service
    173   // attaches the surface texture to a real texture id. glDeleteTextures
    174   // silently ignores 0.
    175   const int kDummyTextureId = 0;
    176   scoped_refptr<gfx::SurfaceTexture> surface_texture =
    177       gfx::SurfaceTexture::Create(kDummyTextureId);
    178   return g_surface_texture_tracker.Pointer()->AddSurfaceTexture(
    179       surface_texture.get(), child_process_id);
    180 }
    181 
    182 // static
    183 void CompositorImpl::DestroyAllSurfaceTextures(int child_process_id) {
    184   g_surface_texture_tracker.Pointer()->RemoveAllSurfaceTextures(
    185       child_process_id);
    186 }
    187 
    188 CompositorImpl::CompositorImpl(CompositorClient* client,
    189                                gfx::NativeWindow root_window)
    190     : root_layer_(cc::Layer::Create()),
    191       has_transparent_background_(false),
    192       device_scale_factor_(1),
    193       window_(NULL),
    194       surface_id_(0),
    195       client_(client),
    196       root_window_(root_window),
    197       did_post_swapbuffers_(false),
    198       ignore_schedule_composite_(false),
    199       needs_composite_(false),
    200       needs_animate_(false),
    201       will_composite_immediately_(false),
    202       composite_on_vsync_trigger_(DO_NOT_COMPOSITE),
    203       pending_swapbuffers_(0U),
    204       weak_factory_(this) {
    205   DCHECK(client);
    206   DCHECK(root_window);
    207   ImageTransportFactoryAndroid::AddObserver(this);
    208   root_window->AttachCompositor(this);
    209 }
    210 
    211 CompositorImpl::~CompositorImpl() {
    212   root_window_->DetachCompositor();
    213   ImageTransportFactoryAndroid::RemoveObserver(this);
    214   // Clean-up any surface references.
    215   SetSurface(NULL);
    216 }
    217 
    218 void CompositorImpl::PostComposite(CompositingTrigger trigger) {
    219   DCHECK(needs_composite_);
    220   DCHECK(trigger == COMPOSITE_IMMEDIATELY || trigger == COMPOSITE_EVENTUALLY);
    221 
    222   if (will_composite_immediately_ ||
    223       (trigger == COMPOSITE_EVENTUALLY && WillComposite())) {
    224     // We will already composite soon enough.
    225     DCHECK(WillComposite());
    226     return;
    227   }
    228 
    229   if (DidCompositeThisFrame()) {
    230     DCHECK(!WillCompositeThisFrame());
    231     if (composite_on_vsync_trigger_ != COMPOSITE_IMMEDIATELY) {
    232       composite_on_vsync_trigger_ = trigger;
    233       root_window_->RequestVSyncUpdate();
    234     }
    235     DCHECK(WillComposite());
    236     return;
    237   }
    238 
    239   base::TimeDelta delay;
    240   if (trigger == COMPOSITE_IMMEDIATELY) {
    241     will_composite_immediately_ = true;
    242     composite_on_vsync_trigger_ = DO_NOT_COMPOSITE;
    243   } else {
    244     DCHECK(!WillComposite());
    245     const base::TimeDelta estimated_composite_time = vsync_period_ / 4;
    246     const base::TimeTicks now = base::TimeTicks::Now();
    247 
    248     if (!last_vsync_.is_null() && (now - last_vsync_) < vsync_period_) {
    249       base::TimeTicks next_composite =
    250           last_vsync_ + vsync_period_ - estimated_composite_time;
    251       if (next_composite < now) {
    252         // It's too late, we will reschedule composite as needed on the next
    253         // vsync.
    254         composite_on_vsync_trigger_ = COMPOSITE_EVENTUALLY;
    255         root_window_->RequestVSyncUpdate();
    256         DCHECK(WillComposite());
    257         return;
    258       }
    259 
    260       delay = next_composite - now;
    261     }
    262   }
    263   TRACE_EVENT2("cc", "CompositorImpl::PostComposite",
    264                "trigger", trigger,
    265                "delay", delay.InMillisecondsF());
    266 
    267   DCHECK(composite_on_vsync_trigger_ == DO_NOT_COMPOSITE);
    268   if (current_composite_task_)
    269     current_composite_task_->Cancel();
    270 
    271   // Unretained because we cancel the task on shutdown.
    272   current_composite_task_.reset(new base::CancelableClosure(
    273       base::Bind(&CompositorImpl::Composite, base::Unretained(this), trigger)));
    274   base::MessageLoop::current()->PostDelayedTask(
    275       FROM_HERE, current_composite_task_->callback(), delay);
    276 }
    277 
    278 void CompositorImpl::Composite(CompositingTrigger trigger) {
    279   BrowserGpuChannelHostFactory* factory =
    280       BrowserGpuChannelHostFactory::instance();
    281   if (!factory->GetGpuChannel() || factory->GetGpuChannel()->IsLost()) {
    282     CauseForGpuLaunch cause =
    283         CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
    284     factory->EstablishGpuChannel(
    285         cause,
    286         base::Bind(&CompositorImpl::OnGpuChannelEstablished,
    287                    weak_factory_.GetWeakPtr()));
    288     return;
    289   }
    290 
    291   DCHECK(host_);
    292   DCHECK(trigger == COMPOSITE_IMMEDIATELY || trigger == COMPOSITE_EVENTUALLY);
    293   DCHECK(needs_composite_);
    294   DCHECK(!DidCompositeThisFrame());
    295 
    296   if (trigger == COMPOSITE_IMMEDIATELY)
    297     will_composite_immediately_ = false;
    298 
    299   DCHECK_LE(pending_swapbuffers_, kMaxSwapBuffers);
    300   if (pending_swapbuffers_ == kMaxSwapBuffers) {
    301     TRACE_EVENT0("compositor", "CompositorImpl_SwapLimit");
    302     return;
    303   }
    304 
    305   // Reset state before Layout+Composite since that might create more
    306   // requests to Composite that we need to respect.
    307   needs_composite_ = false;
    308 
    309   // Only allow compositing once per vsync.
    310   current_composite_task_->Cancel();
    311   DCHECK(DidCompositeThisFrame() && !WillComposite());
    312 
    313   // Ignore ScheduleComposite() from layer tree changes during layout and
    314   // animation updates that will already be reflected in the current frame
    315   // we are about to draw.
    316   ignore_schedule_composite_ = true;
    317   client_->Layout();
    318 
    319   const base::TimeTicks frame_time = gfx::FrameTime::Now();
    320   if (needs_animate_) {
    321     needs_animate_ = false;
    322     root_window_->Animate(frame_time);
    323   }
    324   ignore_schedule_composite_ = false;
    325 
    326   did_post_swapbuffers_ = false;
    327   host_->Composite(frame_time);
    328   if (did_post_swapbuffers_)
    329     pending_swapbuffers_++;
    330 
    331   // Need to track vsync to avoid compositing more than once per frame.
    332   root_window_->RequestVSyncUpdate();
    333 }
    334 
    335 void CompositorImpl::OnGpuChannelEstablished() {
    336   ScheduleComposite();
    337 }
    338 
    339 UIResourceProvider& CompositorImpl::GetUIResourceProvider() {
    340   return ui_resource_provider_;
    341 }
    342 
    343 void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) {
    344   if (subroot_layer_) {
    345     subroot_layer_->RemoveFromParent();
    346     subroot_layer_ = NULL;
    347   }
    348   if (root_layer) {
    349     subroot_layer_ = root_layer;
    350     root_layer_->AddChild(root_layer);
    351   }
    352 }
    353 
    354 void CompositorImpl::SetWindowSurface(ANativeWindow* window) {
    355   GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
    356 
    357   if (window_) {
    358     tracker->RemoveSurface(surface_id_);
    359     ANativeWindow_release(window_);
    360     window_ = NULL;
    361     surface_id_ = 0;
    362     SetVisible(false);
    363   }
    364 
    365   if (window) {
    366     window_ = window;
    367     ANativeWindow_acquire(window);
    368     surface_id_ = tracker->AddSurfaceForNativeWidget(window);
    369     tracker->SetSurfaceHandle(
    370         surface_id_,
    371         gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NATIVE_DIRECT));
    372     SetVisible(true);
    373   }
    374 }
    375 
    376 void CompositorImpl::SetSurface(jobject surface) {
    377   JNIEnv* env = base::android::AttachCurrentThread();
    378   base::android::ScopedJavaLocalRef<jobject> j_surface(env, surface);
    379 
    380   // First, cleanup any existing surface references.
    381   if (surface_id_)
    382     content::UnregisterViewSurface(surface_id_);
    383   SetWindowSurface(NULL);
    384 
    385   // Now, set the new surface if we have one.
    386   ANativeWindow* window = NULL;
    387   if (surface) {
    388     // Note: This ensures that any local references used by
    389     // ANativeWindow_fromSurface are released immediately. This is needed as a
    390     // workaround for https://code.google.com/p/android/issues/detail?id=68174
    391     base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
    392     window = ANativeWindow_fromSurface(env, surface);
    393   }
    394   if (window) {
    395     SetWindowSurface(window);
    396     ANativeWindow_release(window);
    397     content::RegisterViewSurface(surface_id_, j_surface.obj());
    398   }
    399 }
    400 
    401 void CompositorImpl::SetVisible(bool visible) {
    402   if (!visible) {
    403     if (WillComposite())
    404       CancelComposite();
    405     ui_resource_provider_.SetLayerTreeHost(NULL);
    406     host_.reset();
    407   } else if (!host_) {
    408     DCHECK(!WillComposite());
    409     needs_composite_ = false;
    410     needs_animate_ = false;
    411     pending_swapbuffers_ = 0;
    412     cc::LayerTreeSettings settings;
    413     settings.refresh_rate = 60.0;
    414     settings.impl_side_painting = false;
    415     settings.allow_antialiasing = false;
    416     settings.calculate_top_controls_position = false;
    417     settings.top_controls_height = 0.f;
    418     settings.highp_threshold_min = 2048;
    419 
    420     CommandLine* command_line = CommandLine::ForCurrentProcess();
    421     settings.initial_debug_state.SetRecordRenderingStats(
    422         command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
    423     settings.initial_debug_state.show_fps_counter =
    424         command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
    425 
    426     host_ = cc::LayerTreeHost::CreateSingleThreaded(
    427         this, this, HostSharedBitmapManager::current(), settings);
    428     host_->SetRootLayer(root_layer_);
    429 
    430     host_->SetVisible(true);
    431     host_->SetLayerTreeHostClientReady();
    432     host_->SetViewportSize(size_);
    433     host_->set_has_transparent_background(has_transparent_background_);
    434     host_->SetDeviceScaleFactor(device_scale_factor_);
    435     ui_resource_provider_.SetLayerTreeHost(host_.get());
    436   }
    437 }
    438 
    439 void CompositorImpl::setDeviceScaleFactor(float factor) {
    440   device_scale_factor_ = factor;
    441   if (host_)
    442     host_->SetDeviceScaleFactor(factor);
    443 }
    444 
    445 void CompositorImpl::SetWindowBounds(const gfx::Size& size) {
    446   if (size_ == size)
    447     return;
    448 
    449   size_ = size;
    450   if (host_)
    451     host_->SetViewportSize(size);
    452   root_layer_->SetBounds(size);
    453 }
    454 
    455 void CompositorImpl::SetHasTransparentBackground(bool flag) {
    456   has_transparent_background_ = flag;
    457   if (host_)
    458     host_->set_has_transparent_background(flag);
    459 }
    460 
    461 void CompositorImpl::SetNeedsComposite() {
    462   if (!host_.get())
    463     return;
    464   DCHECK(!needs_composite_ || WillComposite());
    465 
    466   needs_composite_ = true;
    467   PostComposite(COMPOSITE_IMMEDIATELY);
    468 }
    469 
    470 static scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
    471 CreateGpuProcessViewContext(
    472     const scoped_refptr<GpuChannelHost>& gpu_channel_host,
    473     const blink::WebGraphicsContext3D::Attributes attributes,
    474     int surface_id) {
    475   DCHECK(gpu_channel_host);
    476 
    477   GURL url("chrome://gpu/Compositor::createContext3D");
    478   static const size_t kBytesPerPixel = 4;
    479   gfx::DeviceDisplayInfo display_info;
    480   size_t full_screen_texture_size_in_bytes =
    481       display_info.GetDisplayHeight() *
    482       display_info.GetDisplayWidth() *
    483       kBytesPerPixel;
    484   WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
    485   limits.command_buffer_size = 64 * 1024;
    486   limits.start_transfer_buffer_size = 64 * 1024;
    487   limits.min_transfer_buffer_size = 64 * 1024;
    488   limits.max_transfer_buffer_size = std::min(
    489       3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
    490   limits.mapped_memory_reclaim_limit = 2 * 1024 * 1024;
    491   bool lose_context_when_out_of_memory = true;
    492   return make_scoped_ptr(
    493       new WebGraphicsContext3DCommandBufferImpl(surface_id,
    494                                                 url,
    495                                                 gpu_channel_host.get(),
    496                                                 attributes,
    497                                                 lose_context_when_out_of_memory,
    498                                                 limits,
    499                                                 NULL));
    500 }
    501 
    502 void CompositorImpl::Layout() {
    503   // TODO: If we get this callback from the SingleThreadProxy, we need
    504   // to stop calling it ourselves in CompositorImpl::Composite().
    505   NOTREACHED();
    506   client_->Layout();
    507 }
    508 
    509 scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface(
    510     bool fallback) {
    511   blink::WebGraphicsContext3D::Attributes attrs;
    512   attrs.shareResources = true;
    513   attrs.noAutomaticFlushes = true;
    514   pending_swapbuffers_ = 0;
    515 
    516   DCHECK(window_);
    517   DCHECK(surface_id_);
    518 
    519   scoped_refptr<ContextProviderCommandBuffer> context_provider;
    520   BrowserGpuChannelHostFactory* factory =
    521       BrowserGpuChannelHostFactory::instance();
    522   scoped_refptr<GpuChannelHost> gpu_channel_host = factory->GetGpuChannel();
    523   if (gpu_channel_host && !gpu_channel_host->IsLost()) {
    524     context_provider = ContextProviderCommandBuffer::Create(
    525         CreateGpuProcessViewContext(gpu_channel_host, attrs, surface_id_),
    526         "BrowserCompositor");
    527   }
    528   if (!context_provider.get()) {
    529     LOG(ERROR) << "Failed to create 3D context for compositor.";
    530     return scoped_ptr<cc::OutputSurface>();
    531   }
    532 
    533   return scoped_ptr<cc::OutputSurface>(
    534       new OutputSurfaceWithoutParent(context_provider));
    535 }
    536 
    537 void CompositorImpl::OnLostResources() {
    538   client_->DidLoseResources();
    539   ui_resource_provider_.UIResourcesAreInvalid();
    540 }
    541 
    542 void CompositorImpl::ScheduleComposite() {
    543   DCHECK(!needs_composite_ || WillComposite());
    544   if (ignore_schedule_composite_)
    545     return;
    546 
    547   needs_composite_ = true;
    548   // We currently expect layer tree invalidations at most once per frame
    549   // during normal operation and therefore try to composite immediately
    550   // to minimize latency.
    551   PostComposite(COMPOSITE_IMMEDIATELY);
    552 }
    553 
    554 void CompositorImpl::ScheduleAnimation() {
    555   DCHECK(!needs_animate_ || needs_composite_);
    556   DCHECK(!needs_composite_ || WillComposite());
    557   needs_animate_ = true;
    558 
    559   if (needs_composite_)
    560     return;
    561 
    562   TRACE_EVENT0("cc", "CompositorImpl::ScheduleAnimation");
    563   needs_composite_ = true;
    564   PostComposite(COMPOSITE_EVENTUALLY);
    565 }
    566 
    567 void CompositorImpl::DidPostSwapBuffers() {
    568   TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers");
    569   did_post_swapbuffers_ = true;
    570 }
    571 
    572 void CompositorImpl::DidCompleteSwapBuffers() {
    573   TRACE_EVENT0("compositor", "CompositorImpl::DidCompleteSwapBuffers");
    574   DCHECK_GT(pending_swapbuffers_, 0U);
    575   if (pending_swapbuffers_-- == kMaxSwapBuffers && needs_composite_)
    576     PostComposite(COMPOSITE_IMMEDIATELY);
    577   client_->OnSwapBuffersCompleted(pending_swapbuffers_);
    578 }
    579 
    580 void CompositorImpl::DidAbortSwapBuffers() {
    581   TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers");
    582   // This really gets called only once from
    583   // SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() when the
    584   // context was lost.
    585   client_->OnSwapBuffersCompleted(0);
    586 }
    587 
    588 void CompositorImpl::DidCommit() {
    589   root_window_->OnCompositingDidCommit();
    590 }
    591 
    592 void CompositorImpl::AttachLayerForReadback(scoped_refptr<cc::Layer> layer) {
    593   root_layer_->AddChild(layer);
    594 }
    595 
    596 void CompositorImpl::RequestCopyOfOutputOnRootLayer(
    597     scoped_ptr<cc::CopyOutputRequest> request) {
    598   root_layer_->RequestCopyOfOutput(request.Pass());
    599 }
    600 
    601 void CompositorImpl::OnVSync(base::TimeTicks frame_time,
    602                              base::TimeDelta vsync_period) {
    603   vsync_period_ = vsync_period;
    604   last_vsync_ = frame_time;
    605 
    606   if (WillCompositeThisFrame()) {
    607     // We somehow missed the last vsync interval, so reschedule for deadline.
    608     // We cannot schedule immediately, or will get us out-of-phase with new
    609     // renderer frames.
    610     CancelComposite();
    611     composite_on_vsync_trigger_ = COMPOSITE_EVENTUALLY;
    612   } else {
    613     current_composite_task_.reset();
    614   }
    615 
    616   DCHECK(!DidCompositeThisFrame() && !WillCompositeThisFrame());
    617   if (composite_on_vsync_trigger_ != DO_NOT_COMPOSITE) {
    618     CompositingTrigger trigger = composite_on_vsync_trigger_;
    619     composite_on_vsync_trigger_ = DO_NOT_COMPOSITE;
    620     PostComposite(trigger);
    621   }
    622 }
    623 
    624 void CompositorImpl::SetNeedsAnimate() {
    625   if (!host_)
    626     return;
    627 
    628   host_->SetNeedsAnimate();
    629 }
    630 
    631 }  // namespace content
    632