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