Index: content/browser/renderer_host/compositor_impl_android.cc |
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc |
index 2e8e8825d31f4c3f7804e9d1fc078e0362ac75a6..fcd0a7b3bdd8568029e12ab39c2e8e32659dfc97 100644 |
--- a/content/browser/renderer_host/compositor_impl_android.cc |
+++ b/content/browser/renderer_host/compositor_impl_android.cc |
@@ -238,7 +238,14 @@ CompositorImpl::CompositorImpl(CompositorClient* client, |
window_(NULL), |
surface_id_(0), |
client_(client), |
- root_window_(root_window) { |
+ root_window_(root_window), |
+ did_post_swapbuffers_(false), |
+ ignore_schedule_composite_(false), |
+ needs_composite_(false), |
+ should_composite_on_vsync_(false), |
+ did_composite_this_frame_(false), |
+ pending_swapbuffers_(0U), |
+ weak_factory_(this) { |
DCHECK(client); |
DCHECK(root_window); |
ImageTransportFactoryAndroid::AddObserver(this); |
@@ -252,9 +259,69 @@ CompositorImpl::~CompositorImpl() { |
SetSurface(NULL); |
} |
-void CompositorImpl::Composite() { |
- if (host_) |
- host_->Composite(gfx::FrameTime::Now()); |
+void CompositorImpl::PostComposite(base::TimeDelta delay) { |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&CompositorImpl::Composite, |
+ weak_factory_.GetWeakPtr(), |
+ COMPOSITE_IMMEDIATELY), |
+ delay); |
+} |
+ |
+void CompositorImpl::Composite(CompositingTrigger trigger) { |
+ if (!host_) |
+ return; |
+ |
+ if (!needs_composite_) |
+ return; |
+ |
+ if (trigger != COMPOSITE_ON_VSYNC && should_composite_on_vsync_) { |
+ TRACE_EVENT0("compositor", "CompositorImpl_DeferCompositeToVSync"); |
+ root_window_->RequestVSyncUpdate(); |
+ return; |
+ } |
+ |
+ // Don't Composite more than once in between vsync ticks. |
+ if (did_composite_this_frame_) { |
+ TRACE_EVENT0("compositor", "CompositorImpl_ThrottleComposite"); |
+ if (should_composite_on_vsync_) |
+ root_window_->RequestVSyncUpdate(); |
+ else |
+ PostComposite(vsync_period_); |
+ return; |
+ } |
+ |
+ const unsigned int kMaxSwapBuffers = 2U; |
+ DCHECK_LE(pending_swapbuffers_, kMaxSwapBuffers); |
+ if (pending_swapbuffers_ == kMaxSwapBuffers) { |
+ TRACE_EVENT0("compositor", "CompositorImpl_SwapLimit"); |
+ if (should_composite_on_vsync_) |
+ root_window_->RequestVSyncUpdate(); |
+ else |
+ PostComposite(vsync_period_); |
+ return; |
+ } |
+ |
+ // Reset state before Layout+Composite since that might create more |
+ // requests to Composite that we need to respect. |
+ needs_composite_ = false; |
+ should_composite_on_vsync_ = false; |
+ |
+ // Ignore ScheduleComposite() from layer tree changes during Layout. |
+ ignore_schedule_composite_ = true; |
+ client_->Layout(); |
+ ignore_schedule_composite_ = false; |
+ |
+ did_post_swapbuffers_ = false; |
+ host_->Composite(gfx::FrameTime::Now()); |
+ if (did_post_swapbuffers_) |
+ pending_swapbuffers_++; |
+ |
+ if (trigger != COMPOSITE_ON_VSYNC) { |
+ // Need to track vsync to avoid compositing more than once per frame. |
+ root_window_->RequestVSyncUpdate(); |
+ } |
+ did_composite_this_frame_ = true; |
} |
void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) { |
@@ -316,6 +383,10 @@ void CompositorImpl::SetVisible(bool visible) { |
host_.reset(); |
client_->UIResourcesAreInvalid(); |
} else if (!host_) { |
+ needs_composite_ = false; |
+ did_composite_this_frame_ = false; |
+ should_composite_on_vsync_ = false; |
+ pending_swapbuffers_ = 0; |
cc::LayerTreeSettings settings; |
settings.refresh_rate = 60.0; |
settings.impl_side_painting = false; |
@@ -374,6 +445,17 @@ bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) { |
return false; |
} |
+void CompositorImpl::SetNeedsComposite() { |
+ if (!host_.get() || needs_composite_) |
+ return; |
+ |
+ needs_composite_ = true; |
+ |
+ // For explicit requests we try to composite regularly on vsync. |
+ should_composite_on_vsync_ = true; |
+ root_window_->RequestVSyncUpdate(); |
+} |
+ |
cc::UIResourceId CompositorImpl::GenerateUIResourceFromUIResourceBitmap( |
const cc::UIResourceBitmap& bitmap, |
bool is_transient) { |
@@ -468,6 +550,13 @@ CreateGpuProcessViewContext( |
NULL)); |
} |
+void CompositorImpl::Layout() { |
+ // TODO: If we get this callback from the SingleThreadProxy, we need |
+ // to stop calling it ourselves in CompositorImpl::Composite(). |
+ NOTREACHED(); |
+ client_->Layout(); |
+} |
+ |
scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface( |
bool fallback) { |
blink::WebGraphicsContext3D::Attributes attrs; |
@@ -493,12 +582,16 @@ void CompositorImpl::OnLostResources() { |
client_->DidLoseResources(); |
} |
-void CompositorImpl::DidCompleteSwapBuffers() { |
- client_->OnSwapBuffersCompleted(); |
-} |
- |
void CompositorImpl::ScheduleComposite() { |
- client_->ScheduleComposite(); |
+ if (needs_composite_ || ignore_schedule_composite_) |
+ return; |
+ |
+ needs_composite_ = true; |
+ |
+ // We currently expect layer tree invalidations at most once per frame |
+ // during normal operation and therefore try to composite immediately |
+ // to minimize latency. |
+ PostComposite(base::TimeDelta()); |
} |
void CompositorImpl::ScheduleAnimation() { |
@@ -507,12 +600,19 @@ void CompositorImpl::ScheduleAnimation() { |
void CompositorImpl::DidPostSwapBuffers() { |
TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers"); |
- client_->OnSwapBuffersPosted(); |
+ did_post_swapbuffers_ = true; |
+} |
+ |
+void CompositorImpl::DidCompleteSwapBuffers() { |
+ TRACE_EVENT0("compositor", "CompositorImpl::DidCompleteSwapBuffers"); |
+ DCHECK_GT(pending_swapbuffers_, 0U); |
+ client_->OnSwapBuffersCompleted(pending_swapbuffers_--); |
} |
void CompositorImpl::DidAbortSwapBuffers() { |
TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers"); |
- client_->OnSwapBuffersCompleted(); |
+ DCHECK_GT(pending_swapbuffers_, 0U); |
+ client_->OnSwapBuffersCompleted(pending_swapbuffers_--); |
} |
void CompositorImpl::DidCommit() { |
@@ -523,4 +623,13 @@ void CompositorImpl::AttachLayerForReadback(scoped_refptr<cc::Layer> layer) { |
root_layer_->AddChild(layer); |
} |
+void CompositorImpl::OnVSync(base::TimeTicks frame_time, |
+ base::TimeDelta vsync_period) { |
+ vsync_period_ = vsync_period; |
+ did_composite_this_frame_ = false; |
+ |
+ if (should_composite_on_vsync_) |
+ Composite(COMPOSITE_ON_VSYNC); |
+} |
+ |
} // namespace content |