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 2deb35849e7b4ead535b74c524c13ef34e961407..8fa043cabb676e3a90e8e5478722a1e0ebfd8aee 100644 |
--- a/content/browser/renderer_host/compositor_impl_android.cc |
+++ b/content/browser/renderer_host/compositor_impl_android.cc |
@@ -57,6 +57,8 @@ class JavaBitmap; |
namespace { |
+const unsigned int kMaxSwapBuffers = 2U; |
+ |
// Used to override capabilities_.adjust_deadline_for_parent to false |
class OutputSurfaceWithoutParent : public cc::OutputSurface { |
public: |
@@ -242,10 +244,10 @@ CompositorImpl::CompositorImpl(CompositorClient* client, |
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) { |
+ needs_animate_(false), |
+ will_composite_immediately_(false), |
+ composite_on_vsync_trigger_(DO_NOT_COMPOSITE), |
+ pending_swapbuffers_(0U) { |
DCHECK(client); |
DCHECK(root_window); |
ImageTransportFactoryAndroid::AddObserver(this); |
@@ -259,69 +261,109 @@ CompositorImpl::~CompositorImpl() { |
SetSurface(NULL); |
} |
-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; |
+void CompositorImpl::PostComposite(CompositingTrigger trigger) { |
+ DCHECK(needs_composite_); |
+ DCHECK(trigger == COMPOSITE_IMMEDIATELY || trigger == COMPOSITE_EVENTUALLY); |
- if (trigger != COMPOSITE_ON_VSYNC && should_composite_on_vsync_) { |
- TRACE_EVENT0("compositor", "CompositorImpl_DeferCompositeToVSync"); |
- root_window_->RequestVSyncUpdate(); |
+ if (will_composite_immediately_ || |
+ (trigger == COMPOSITE_EVENTUALLY && WillComposite())) { |
+ // We will already composite soon enough. |
+ DCHECK(WillComposite()); |
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_) |
+ if (DidCompositeThisFrame()) { |
+ DCHECK(!WillCompositeThisFrame()); |
+ if (composite_on_vsync_trigger_ != COMPOSITE_IMMEDIATELY) { |
+ composite_on_vsync_trigger_ = trigger; |
root_window_->RequestVSyncUpdate(); |
- else |
- PostComposite(vsync_period_); |
+ } |
+ DCHECK(WillComposite()); |
return; |
} |
- const unsigned int kMaxSwapBuffers = 2U; |
+ base::TimeDelta delay; |
+ if (trigger == COMPOSITE_IMMEDIATELY) { |
+ will_composite_immediately_ = true; |
+ composite_on_vsync_trigger_ = DO_NOT_COMPOSITE; |
+ } else { |
+ DCHECK(!WillComposite()); |
+ const base::TimeDelta estimated_composite_time = vsync_period_ / 4; |
+ const base::TimeTicks now = base::TimeTicks::Now(); |
+ |
+ if (!last_vsync_.is_null() && (now - last_vsync_) < vsync_period_) { |
+ base::TimeTicks next_composite = |
+ last_vsync_ + vsync_period_ - estimated_composite_time; |
+ if (next_composite < now) { |
+ // It's too late, we will reschedule composite as needed on the next |
+ // vsync. |
+ composite_on_vsync_trigger_ = COMPOSITE_EVENTUALLY; |
+ root_window_->RequestVSyncUpdate(); |
+ DCHECK(WillComposite()); |
+ return; |
+ } |
+ |
+ delay = next_composite - now; |
+ } |
+ } |
+ TRACE_EVENT2("cc", "CompositorImpl::PostComposite", |
+ "trigger", trigger, |
+ "delay", delay.InMillisecondsF()); |
+ |
+ DCHECK(composite_on_vsync_trigger_ == DO_NOT_COMPOSITE); |
+ if (current_composite_task_) |
+ current_composite_task_->Cancel(); |
+ |
+ // Unretained because we cancel the task on shutdown. |
+ current_composite_task_.reset(new base::CancelableClosure( |
+ base::Bind(&CompositorImpl::Composite, base::Unretained(this), trigger))); |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, current_composite_task_->callback(), delay); |
+} |
+ |
+void CompositorImpl::Composite(CompositingTrigger trigger) { |
+ DCHECK(host_); |
+ DCHECK(trigger == COMPOSITE_IMMEDIATELY || trigger == COMPOSITE_EVENTUALLY); |
+ DCHECK(needs_composite_); |
+ DCHECK(!DidCompositeThisFrame()); |
+ |
+ if (trigger == COMPOSITE_IMMEDIATELY) |
+ will_composite_immediately_ = false; |
+ |
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. |
+ // Only allow compositing once per vsync. |
+ current_composite_task_->Cancel(); |
+ DCHECK(DidCompositeThisFrame() && !WillComposite()); |
+ |
+ // Ignore ScheduleComposite() from layer tree changes during layout and |
+ // animation updates that will already be reflected in the current frame |
+ // we are about to draw. |
ignore_schedule_composite_ = true; |
client_->Layout(); |
+ |
+ const base::TimeTicks frame_time = gfx::FrameTime::Now(); |
+ if (needs_animate_) { |
+ needs_animate_ = false; |
+ root_window_->Animate(frame_time); |
+ } |
ignore_schedule_composite_ = false; |
did_post_swapbuffers_ = false; |
- host_->Composite(gfx::FrameTime::Now()); |
+ host_->Composite(frame_time); |
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; |
+ // Need to track vsync to avoid compositing more than once per frame. |
+ root_window_->RequestVSyncUpdate(); |
} |
void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) { |
@@ -379,13 +421,15 @@ void CompositorImpl::SetSurface(jobject surface) { |
void CompositorImpl::SetVisible(bool visible) { |
if (!visible) { |
+ if (WillComposite()) |
+ CancelComposite(); |
ui_resource_map_.clear(); |
host_.reset(); |
client_->UIResourcesAreInvalid(); |
} else if (!host_) { |
+ DCHECK(!WillComposite()); |
needs_composite_ = false; |
- did_composite_this_frame_ = false; |
- should_composite_on_vsync_ = false; |
+ needs_animate_ = false; |
pending_swapbuffers_ = 0; |
cc::LayerTreeSettings settings; |
settings.refresh_rate = 60.0; |
@@ -443,14 +487,12 @@ bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) { |
} |
void CompositorImpl::SetNeedsComposite() { |
- if (!host_.get() || needs_composite_) |
+ if (!host_.get()) |
return; |
+ DCHECK(!needs_composite_ || WillComposite()); |
needs_composite_ = true; |
- |
- // For explicit requests we try to composite regularly on vsync. |
- should_composite_on_vsync_ = true; |
- root_window_->RequestVSyncUpdate(); |
+ PostComposite(COMPOSITE_EVENTUALLY); |
} |
cc::UIResourceId CompositorImpl::GenerateUIResourceFromUIResourceBitmap( |
@@ -580,19 +622,28 @@ void CompositorImpl::OnLostResources() { |
} |
void CompositorImpl::ScheduleComposite() { |
- if (needs_composite_ || ignore_schedule_composite_) |
+ DCHECK(!needs_composite_ || WillComposite()); |
+ if (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()); |
+ PostComposite(COMPOSITE_IMMEDIATELY); |
} |
void CompositorImpl::ScheduleAnimation() { |
- ScheduleComposite(); |
+ DCHECK(!needs_animate_ || needs_composite_); |
+ DCHECK(!needs_composite_ || WillComposite()); |
+ needs_animate_ = true; |
+ |
+ if (needs_composite_) |
+ return; |
+ |
+ TRACE_EVENT0("cc", "CompositorImpl::ScheduleAnimation"); |
+ needs_composite_ = true; |
+ PostComposite(COMPOSITE_EVENTUALLY); |
} |
void CompositorImpl::DidPostSwapBuffers() { |
@@ -603,13 +654,17 @@ void CompositorImpl::DidPostSwapBuffers() { |
void CompositorImpl::DidCompleteSwapBuffers() { |
TRACE_EVENT0("compositor", "CompositorImpl::DidCompleteSwapBuffers"); |
DCHECK_GT(pending_swapbuffers_, 0U); |
- client_->OnSwapBuffersCompleted(--pending_swapbuffers_); |
+ if (pending_swapbuffers_-- == kMaxSwapBuffers && needs_composite_) |
+ PostComposite(COMPOSITE_IMMEDIATELY); |
+ client_->OnSwapBuffersCompleted(pending_swapbuffers_); |
} |
void CompositorImpl::DidAbortSwapBuffers() { |
TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers"); |
DCHECK_GT(pending_swapbuffers_, 0U); |
- client_->OnSwapBuffersCompleted(--pending_swapbuffers_); |
+ if (pending_swapbuffers_-- == kMaxSwapBuffers && needs_composite_) |
+ PostComposite(COMPOSITE_IMMEDIATELY); |
+ client_->OnSwapBuffersCompleted(pending_swapbuffers_); |
} |
void CompositorImpl::DidCommit() { |
@@ -628,10 +683,29 @@ void CompositorImpl::RequestCopyOfOutputOnRootLayer( |
void CompositorImpl::OnVSync(base::TimeTicks frame_time, |
base::TimeDelta vsync_period) { |
vsync_period_ = vsync_period; |
- did_composite_this_frame_ = false; |
+ last_vsync_ = frame_time; |
+ |
+ if (WillCompositeThisFrame()) { |
+ // We somehow missed the last vsync interval, so reschedule immediately. |
+ CancelComposite(); |
+ composite_on_vsync_trigger_ = COMPOSITE_IMMEDIATELY; |
+ } else { |
+ current_composite_task_.reset(); |
+ } |
+ |
+ DCHECK(!DidCompositeThisFrame() && !WillCompositeThisFrame()); |
+ if (composite_on_vsync_trigger_ != DO_NOT_COMPOSITE) { |
+ CompositingTrigger trigger = composite_on_vsync_trigger_; |
+ composite_on_vsync_trigger_ = DO_NOT_COMPOSITE; |
+ PostComposite(trigger); |
+ } |
+} |
+ |
+void CompositorImpl::SetNeedsAnimate() { |
+ if (!host_) |
+ return; |
- if (should_composite_on_vsync_) |
- Composite(COMPOSITE_ON_VSYNC); |
+ host_->SetNeedsAnimate(); |
} |
} // namespace content |