bc2709c3eef96c96b196d7012befbf414dd5a6a1
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / compositor_impl_android.cc
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
52 namespace {
53
54 const unsigned int kMaxSwapBuffers = 2U;
55
56 // Used to override capabilities_.adjust_deadline_for_parent to false
57 class 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
97 class 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 };
160 base::LazyInstance<SurfaceTextureTrackerImpl> g_surface_texture_tracker =
161     LAZY_INSTANCE_INITIALIZER;
162
163 static bool g_initialized = false;
164
165 } // anonymous namespace
166
167 namespace content {
168
169 // static
170 Compositor* Compositor::Create(CompositorClient* client,
171                                gfx::NativeWindow root_window) {
172   return client ? new CompositorImpl(client, root_window) : NULL;
173 }
174
175 // static
176 void 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
185 bool CompositorImpl::IsInitialized() {
186   return g_initialized;
187 }
188
189 // static
190 int 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
203 void CompositorImpl::DestroyAllSurfaceTextures(int child_process_id) {
204   g_surface_texture_tracker.Pointer()->RemoveAllSurfaceTextures(
205       child_process_id);
206 }
207
208 CompositorImpl::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
231 CompositorImpl::~CompositorImpl() {
232   root_window_->DetachCompositor();
233   ImageTransportFactoryAndroid::RemoveObserver(this);
234   // Clean-up any surface references.
235   SetSurface(NULL);
236 }
237
238 void 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
298 void 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
353 UIResourceProvider& CompositorImpl::GetUIResourceProvider() {
354   return ui_resource_provider_;
355 }
356
357 ui::SystemUIResourceManager& CompositorImpl::GetSystemUIResourceManager() {
358   return ui_resource_provider_.GetSystemUIResourceManager();
359 }
360
361 void 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
372 void 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
394 void 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
419 void 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
477 void CompositorImpl::setDeviceScaleFactor(float factor) {
478   device_scale_factor_ = factor;
479   if (host_)
480     host_->SetDeviceScaleFactor(factor);
481 }
482
483 void 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
493 void CompositorImpl::SetHasTransparentBackground(bool flag) {
494   has_transparent_background_ = flag;
495   if (host_)
496     host_->set_has_transparent_background(flag);
497 }
498
499 void CompositorImpl::SetNeedsComposite() {
500   if (!host_.get())
501     return;
502   DCHECK(!needs_composite_ || WillComposite());
503
504   needs_composite_ = true;
505   PostComposite(COMPOSITE_IMMEDIATELY);
506 }
507
508 static scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
509 CreateGpuProcessViewContext(
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
540 void CompositorImpl::Layout() {
541   ignore_schedule_composite_ = true;
542   client_->Layout();
543   ignore_schedule_composite_ = false;
544 }
545
546 void 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
563 void 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
592 void CompositorImpl::PopulateGpuCapabilities(
593     gpu::Capabilities gpu_capabilities) {
594   ui_resource_provider_.SetSupportsETC1NonPowerOfTwo(
595       gpu_capabilities.texture_format_etc1_npot);
596 }
597
598 void CompositorImpl::OnLostResources() {
599   client_->DidLoseResources();
600 }
601
602 void 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
614 void 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
626 void CompositorImpl::DidPostSwapBuffers() {
627   TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers");
628   did_post_swapbuffers_ = true;
629 }
630
631 void 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
639 void 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
648 void CompositorImpl::DidCommit() {
649   root_window_->OnCompositingDidCommit();
650 }
651
652 void CompositorImpl::AttachLayerForReadback(scoped_refptr<cc::Layer> layer) {
653   root_layer_->AddChild(layer);
654 }
655
656 void CompositorImpl::RequestCopyOfOutputOnRootLayer(
657     scoped_ptr<cc::CopyOutputRequest> request) {
658   root_layer_->RequestCopyOfOutput(request.Pass());
659 }
660
661 void 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
684 void CompositorImpl::SetNeedsAnimate() {
685   if (!host_)
686     return;
687
688   host_->SetNeedsAnimate();
689 }
690
691 }  // namespace content