Index: content/browser/renderer_host/render_widget_host_view_aura.cc |
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc |
index f8565eee8930390b9190a23eae09d3e897e4b935..6987fcc95dab4f69a9d5887fe12e657529ad8d78 100644 |
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc |
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc |
@@ -198,11 +198,16 @@ class RenderWidgetHostViewAura::WindowObserver : public aura::WindowObserver { |
class RenderWidgetHostViewAura::ResizeLock { |
public: |
- ResizeLock(aura::RootWindow* root_window, const gfx::Size new_size) |
+ ResizeLock(aura::RootWindow* root_window, |
+ const gfx::Size new_size, |
+ bool defer_compositor_lock) |
: root_window_(root_window), |
new_size_(new_size), |
- compositor_lock_(root_window_->GetCompositorLock()), |
- weak_ptr_factory_(this) { |
+ compositor_lock_(defer_compositor_lock ? |
+ NULL : |
+ root_window_->compositor()->GetCompositorLock()), |
+ weak_ptr_factory_(this), |
+ defer_compositor_lock_(defer_compositor_lock) { |
root_window_->HoldMouseMoves(); |
BrowserThread::PostDelayedTask( |
@@ -217,6 +222,7 @@ class RenderWidgetHostViewAura::ResizeLock { |
} |
void UnlockCompositor() { |
+ defer_compositor_lock_ = false; |
compositor_lock_ = NULL; |
} |
@@ -232,11 +238,21 @@ class RenderWidgetHostViewAura::ResizeLock { |
return new_size_; |
} |
+ bool GrabDeferredLock() { |
+ if (root_window_ && defer_compositor_lock_) { |
+ compositor_lock_ = root_window_->compositor()->GetCompositorLock(); |
+ defer_compositor_lock_ = false; |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
private: |
aura::RootWindow* root_window_; |
gfx::Size new_size_; |
- scoped_refptr<aura::CompositorLock> compositor_lock_; |
+ scoped_refptr<ui::CompositorLock> compositor_lock_; |
base::WeakPtrFactory<ResizeLock> weak_ptr_factory_; |
+ bool defer_compositor_lock_; |
DISALLOW_COPY_AND_ASSIGN(ResizeLock); |
}; |
@@ -263,7 +279,8 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host) |
surface_route_id_(0), |
paint_canvas_(NULL), |
synthetic_move_sent_(false), |
- accelerated_compositing_state_changed_(false) { |
+ accelerated_compositing_state_changed_(false), |
+ can_lock_compositor_(YES) { |
host_->SetView(this); |
window_observer_.reset(new WindowObserver(this)); |
window_->AddObserver(window_observer_.get()); |
@@ -343,7 +360,7 @@ void RenderWidgetHostViewAura::WasShown() { |
if (!current_surface_ && host_->is_accelerated_compositing_active() && |
!released_front_lock_.get()) { |
- released_front_lock_ = window_->GetRootWindow()->GetCompositorLock(); |
+ released_front_lock_ = GetCompositor()->GetCompositorLock(); |
} |
AdjustSurfaceProtection(); |
@@ -388,9 +405,22 @@ void RenderWidgetHostViewAura::SetBounds(const gfx::Rect& rect) { |
if (window_->bounds().size() != rect.size() && |
host_->is_accelerated_compositing_active()) { |
aura::RootWindow* root_window = window_->GetRootWindow(); |
- if (root_window) { |
+ ui::Compositor* compositor = root_window ? |
+ root_window->compositor() : NULL; |
+ if (root_window && compositor) { |
+ // Listen to changes in the compositor lock state. |
+ if (!compositor->HasObserver(this)) |
+ compositor->AddObserver(this); |
+ |
+ bool defer_compositor_lock = |
+ can_lock_compositor_ == NO_PENDING_RENDERER_FRAME || |
+ can_lock_compositor_ == NO_PENDING_COMMIT; |
+ |
+ if (can_lock_compositor_ == YES) |
+ can_lock_compositor_ = YES_DID_LOCK; |
+ |
resize_locks_.push_back(make_linked_ptr( |
- new ResizeLock(root_window, rect.size()))); |
+ new ResizeLock(root_window, rect.size(), defer_compositor_lock))); |
} |
} |
window_->SetBounds(rect); |
@@ -695,6 +725,28 @@ void RenderWidgetHostViewAura::OnAcceleratedCompositingStateChange() { |
accelerated_compositing_state_changed_ = true; |
} |
+bool RenderWidgetHostViewAura::ShouldFastACK(uint64 surface_id) { |
+ ui::Texture* container = image_transport_clients_[surface_id]; |
+ DCHECK(container); |
+ |
+ if (can_lock_compositor_ == NO_PENDING_RENDERER_FRAME || |
+ can_lock_compositor_ == NO_PENDING_COMMIT || |
+ resize_locks_.empty()) |
+ return false; |
+ |
+ gfx::Size container_size = ConvertSizeToDIP(this, container->size()); |
+ ResizeLockList::iterator it = resize_locks_.begin(); |
+ while (it != resize_locks_.end()) { |
+ if ((*it)->expected_size() == container_size) |
+ break; |
+ ++it; |
+ } |
+ |
+ // We could be getting an unexpected frame due to an animation |
+ // (i.e. we start resizing but we get an old size frame first). |
+ return it == resize_locks_.end() || ++it != resize_locks_.end(); |
+} |
+ |
void RenderWidgetHostViewAura::UpdateExternalTexture() { |
// Delay processing accelerated compositing state change till here where we |
// act upon the state change. (Clear the external texture if switching to |
@@ -710,7 +762,6 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { |
if (!container) { |
resize_locks_.clear(); |
} else { |
- typedef std::vector<linked_ptr<ResizeLock> > ResizeLockList; |
ResizeLockList::iterator it = resize_locks_.begin(); |
while (it != resize_locks_.end()) { |
gfx::Size container_size = ConvertSizeToDIP(this, |
@@ -726,8 +777,8 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { |
// Delay the release of the lock until we've kicked a frame with the |
// new texture, to avoid resizing the UI before we have a chance to |
// draw a "good" frame. |
- locks_pending_draw_.insert( |
- locks_pending_draw_.begin(), resize_locks_.begin(), it); |
+ locks_pending_commit_.insert( |
+ locks_pending_commit_.begin(), resize_locks_.begin(), it); |
// However since we got the size we were looking for, unlock the |
// compositor. |
for (ResizeLockList::iterator it2 = resize_locks_.begin(); |
@@ -744,12 +795,12 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { |
window_->SetExternalTexture(NULL); |
if (ShouldReleaseFrontSurface() && |
host_->is_accelerated_compositing_active()) { |
- // The current surface may have pipelined gl commands, so always wait for |
- // the next composite to start. If the current surface is still null, |
- // then we really know its no longer in use. |
+ // We need to wait for a commit to clear to guarantee that all we |
+ // will not issue any more GL referencing the previous surface. |
ui::Compositor* compositor = GetCompositor(); |
if (compositor) { |
- on_compositing_will_start_callbacks_.push_back( |
+ can_lock_compositor_ = NO_PENDING_COMMIT; |
+ on_compositing_did_commit_callbacks_.push_back( |
base::Bind(&RenderWidgetHostViewAura:: |
SetSurfaceNotInUseByCompositor, |
AsWeakPtr())); |
@@ -771,15 +822,22 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( |
params_in_pixel.protection_state_id != protection_state_id_) { |
DCHECK(!current_surface_); |
if (!params_in_pixel.skip_ack) |
- InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); |
+ InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); |
+ return; |
+ } |
+ |
+ if (ShouldFastACK(params_in_pixel.surface_handle)) { |
+ if (!params_in_pixel.skip_ack) |
+ InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); |
return; |
} |
+ |
current_surface_ = params_in_pixel.surface_handle; |
// If we don't require an ACK that means the content is not a fresh updated |
- // new frame, rather we are just resetting our handle to some old content that |
- // we still hadn't discarded. Although we could display immediately, by not |
- // resetting the compositor lock here, we give us some time to get a fresh |
- // frame which means fewer content flashes. |
+ // new frame, rather we are just resetting our handle to some old content |
+ // that we still hadn't discarded. Although we could display immediately, |
+ // by not resetting the compositor lock here, we give us some time to get |
+ // a fresh frame which means fewer content flashes. |
if (!params_in_pixel.skip_ack) |
released_front_lock_ = NULL; |
@@ -787,46 +845,26 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( |
ui::Compositor* compositor = GetCompositor(); |
if (!compositor) { |
- // We have no compositor, so we have no way to display the surface. |
- // Must still send the ACK. |
if (!params_in_pixel.skip_ack) |
- InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); |
+ InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); |
} else { |
DCHECK(image_transport_clients_.find(params_in_pixel.surface_handle) != |
image_transport_clients_.end()); |
gfx::Size surface_size_in_pixel = |
image_transport_clients_[params_in_pixel.surface_handle]->size(); |
- gfx::Size surface_size = ConvertSizeToDIP(this, |
- surface_size_in_pixel); |
+ gfx::Size surface_size = ConvertSizeToDIP(this, surface_size_in_pixel); |
window_->SchedulePaintInRect(gfx::Rect(surface_size)); |
if (!params_in_pixel.skip_ack) { |
- if (!resize_locks_.empty()) { |
- // If we are waiting for the resize, fast-track the ACK. |
- if (compositor->IsThreaded()) { |
- // We need the compositor thread to pick up the active buffer before |
- // ACKing. |
- on_compositing_did_commit_callbacks_.push_back( |
- base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
- params_in_pixel.route_id, |
- gpu_host_id)); |
- if (!compositor->HasObserver(this)) |
- compositor->AddObserver(this); |
- } else { |
- // The compositor will pickup the active buffer during a draw, so we |
- // can ACK immediately. |
- InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, |
- compositor); |
- } |
- } else { |
- // Add sending an ACK to the list of things to do OnCompositingWillStart |
- on_compositing_will_start_callbacks_.push_back( |
- base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
- params_in_pixel.route_id, |
- gpu_host_id)); |
- if (!compositor->HasObserver(this)) |
- compositor->AddObserver(this); |
- } |
+ // Add sending an ACK to the list of things to do OnCompositingDidCommit |
+ can_lock_compositor_ = NO_PENDING_COMMIT; |
+ on_compositing_did_commit_callbacks_.push_back( |
+ base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
+ params_in_pixel.route_id, |
+ gpu_host_id, |
+ true)); |
+ if (!compositor->HasObserver(this)) |
+ compositor->AddObserver(this); |
} |
} |
} |
@@ -840,9 +878,15 @@ void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( |
if (params_in_pixel.protection_state_id && |
params_in_pixel.protection_state_id != protection_state_id_) { |
DCHECK(!current_surface_); |
- InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); |
+ InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); |
+ return; |
+ } |
+ |
+ if (ShouldFastACK(params_in_pixel.surface_handle)) { |
+ InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); |
return; |
} |
+ |
current_surface_ = params_in_pixel.surface_handle; |
released_front_lock_ = NULL; |
DCHECK(current_surface_); |
@@ -850,9 +894,7 @@ void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( |
ui::Compositor* compositor = GetCompositor(); |
if (!compositor) { |
- // We have no compositor, so we have no way to display the surface |
- // Must still send the ACK |
- InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); |
+ InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); |
} else { |
DCHECK(image_transport_clients_.find(params_in_pixel.surface_handle) != |
image_transport_clients_.end()); |
@@ -875,32 +917,15 @@ void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( |
window_->SchedulePaintInRect(rect_to_paint); |
- if (!resize_locks_.empty()) { |
- // If we are waiting for the resize, fast-track the ACK. |
- if (compositor->IsThreaded()) { |
- // We need the compositor thread to pick up the active buffer before |
- // ACKing. |
- on_compositing_did_commit_callbacks_.push_back( |
- base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
- params_in_pixel.route_id, |
- gpu_host_id)); |
- if (!compositor->HasObserver(this)) |
- compositor->AddObserver(this); |
- } else { |
- // The compositor will pickup the active buffer during a draw, so we |
- // can ACK immediately. |
- InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, |
- compositor); |
- } |
- } else { |
- // Add sending an ACK to the list of things to do OnCompositingWillStart |
- on_compositing_will_start_callbacks_.push_back( |
- base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
- params_in_pixel.route_id, |
- gpu_host_id)); |
- if (!compositor->HasObserver(this)) |
- compositor->AddObserver(this); |
- } |
+ // Add sending an ACK to the list of things to do OnCompositingDidCommit |
+ can_lock_compositor_ = NO_PENDING_COMMIT; |
+ on_compositing_did_commit_callbacks_.push_back( |
+ base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
+ params_in_pixel.route_id, |
+ gpu_host_id, |
+ true)); |
+ if (!compositor->HasObserver(this)) |
+ compositor->AddObserver(this); |
} |
} |
@@ -1653,17 +1678,19 @@ void RenderWidgetHostViewAura::OnLostActive() { |
void RenderWidgetHostViewAura::OnCompositingDidCommit( |
ui::Compositor* compositor) { |
+ if (can_lock_compositor_ == NO_PENDING_COMMIT) { |
+ can_lock_compositor_ = YES; |
+ for (ResizeLockList::iterator it = resize_locks_.begin(); |
+ it != resize_locks_.end(); ++it) |
+ if ((*it)->GrabDeferredLock()) |
+ can_lock_compositor_ = YES_DID_LOCK; |
+ } |
RunCompositingDidCommitCallbacks(compositor); |
-} |
- |
-void RenderWidgetHostViewAura::OnCompositingWillStart( |
- ui::Compositor* compositor) { |
- RunCompositingWillStartCallbacks(compositor); |
+ locks_pending_commit_.clear(); |
} |
void RenderWidgetHostViewAura::OnCompositingStarted( |
ui::Compositor* compositor) { |
- locks_pending_draw_.clear(); |
} |
void RenderWidgetHostViewAura::OnCompositingEnded( |
@@ -1674,6 +1701,15 @@ void RenderWidgetHostViewAura::OnCompositingAborted( |
ui::Compositor* compositor) { |
} |
+void RenderWidgetHostViewAura::OnCompositingLockStateChanged( |
+ ui::Compositor* compositor) { |
+ // A compositor lock that is part of a resize lock timed out. We |
+ // should display a renderer frame. |
+ if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) { |
+ can_lock_compositor_ = NO_PENDING_RENDERER_FRAME; |
+ } |
+} |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation: |
@@ -1685,7 +1721,7 @@ void RenderWidgetHostViewAura::OnLostResources() { |
current_surface_in_use_by_compositor_ = true; |
surface_route_id_ = 0; |
UpdateExternalTexture(); |
- locks_pending_draw_.clear(); |
+ locks_pending_commit_.clear(); |
DCHECK(!shared_surface_handle_.is_null()); |
ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
@@ -1832,19 +1868,10 @@ void RenderWidgetHostViewAura::RunCompositingDidCommitCallbacks( |
on_compositing_did_commit_callbacks_.clear(); |
} |
-void RenderWidgetHostViewAura::RunCompositingWillStartCallbacks( |
- ui::Compositor* compositor) { |
- for (std::vector< base::Callback<void(ui::Compositor*)> >::const_iterator |
- it = on_compositing_will_start_callbacks_.begin(); |
- it != on_compositing_will_start_callbacks_.end(); ++it) { |
- it->Run(compositor); |
- } |
- on_compositing_will_start_callbacks_.clear(); |
-} |
- |
// static |
void RenderWidgetHostViewAura::InsertSyncPointAndACK( |
- int32 route_id, int gpu_host_id, ui::Compositor* compositor) { |
+ int32 route_id, int gpu_host_id, bool presented, |
+ ui::Compositor* compositor) { |
uint32 sync_point = 0; |
// If we have no compositor, so we must still send the ACK. A zero |
// sync point will not be waited for in the GPU process. |
@@ -1854,7 +1881,7 @@ void RenderWidgetHostViewAura::InsertSyncPointAndACK( |
} |
RenderWidgetHostImpl::AcknowledgeBufferPresent( |
- route_id, gpu_host_id, sync_point); |
+ route_id, gpu_host_id, presented, sync_point); |
} |
void RenderWidgetHostViewAura::RemovingFromRootWindow() { |
@@ -1866,8 +1893,7 @@ void RenderWidgetHostViewAura::RemovingFromRootWindow() { |
// composited data. |
ui::Compositor* compositor = GetCompositor(); |
RunCompositingDidCommitCallbacks(compositor); |
- RunCompositingWillStartCallbacks(compositor); |
- locks_pending_draw_.clear(); |
+ locks_pending_commit_.clear(); |
if (compositor && compositor->HasObserver(this)) |
compositor->RemoveObserver(this); |
DetachFromInputMethod(); |