Index: content/browser/renderer_host/render_widget_host_impl.cc |
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc |
index d4779ae3cfd7a9dea43416593bc876ec2beaf7ef..60197e5dbffdc072a3d08cd67c2f40d805c0193f 100644 |
--- a/content/browser/renderer_host/render_widget_host_impl.cc |
+++ b/content/browser/renderer_host/render_widget_host_impl.cc |
@@ -65,7 +65,7 @@ namespace { |
// PaintRect message, when our backing-store is invalid, before giving up and |
// returning a null or incorrectly sized backing-store from GetBackingStore. |
// This timeout impacts the "choppiness" of our window resize perf. |
-static const int kPaintMsgTimeoutMS = 40; |
+static const int kPaintMsgTimeoutMS = 50; |
// How long to wait before we consider a renderer hung. |
static const int kHungRendererDelayMs = 20000; |
@@ -119,6 +119,7 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderProcessHost* process, |
is_unresponsive_(false), |
in_flight_event_count_(0), |
in_get_backing_store_(false), |
+ abort_get_backing_store_(false), |
view_being_painted_(false), |
ignore_input_events_(false), |
text_direction_updated_(false), |
@@ -257,6 +258,8 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) { |
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnMsgRequestMove) |
IPC_MESSAGE_HANDLER(ViewHostMsg_SetTooltipText, OnMsgSetTooltipText) |
IPC_MESSAGE_HANDLER(ViewHostMsg_PaintAtSize_ACK, OnMsgPaintAtSizeAck) |
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CompositorSurfaceBuffersSwapped, |
+ OnCompositorSurfaceBuffersSwapped) |
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnMsgUpdateRect) |
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateIsDelayed, OnMsgUpdateIsDelayed) |
IPC_MESSAGE_HANDLER(ViewHostMsg_HandleInputEvent_ACK, OnMsgInputEventAck) |
@@ -574,10 +577,38 @@ void RenderWidgetHostImpl::PaintAtSize(TransportDIB::Handle dib_handle, |
page_size, desired_size)); |
} |
+bool RenderWidgetHostImpl::TryGetBackingStore(const gfx::Size& desired_size, |
+ BackingStore** backing_store) { |
+ // Check if the view has an accelerated surface of the desired size. |
+ if (view_->HasAcceleratedSurface(desired_size)) { |
+ *backing_store = NULL; |
+ return true; |
+ } |
+ |
+ // Check for a software backing store of the desired size. |
+ *backing_store = BackingStoreManager::GetBackingStore(this, desired_size); |
+ return !!*backing_store; |
+} |
+ |
BackingStore* RenderWidgetHostImpl::GetBackingStore(bool force_create) { |
+ if (!view_) |
+ return NULL; |
+ |
+ // The view_size will be current_size_ for auto-sized views and otherwise the |
+ // size of the view_. (For auto-sized views, current_size_ is updated during |
+ // UpdateRect messages.) |
+ gfx::Size view_size = current_size_; |
+ if (!should_auto_resize_) { |
+ // Get the desired size from the current view bounds. |
+ gfx::Rect view_rect = view_->GetViewBounds(); |
+ if (view_rect.IsEmpty()) |
+ return NULL; |
+ view_size = view_rect.size(); |
+ } |
+ |
TRACE_EVENT2("renderer_host", "RenderWidgetHostImpl::GetBackingStore", |
- "width", base::IntToString(current_size_.width()), |
- "height", base::IntToString(current_size_.height())); |
+ "width", base::IntToString(view_size.width()), |
+ "height", base::IntToString(view_size.height())); |
// We should not be asked to paint while we are hidden. If we are hidden, |
// then it means that our consumer failed to call WasRestored. If we're not |
@@ -592,32 +623,58 @@ BackingStore* RenderWidgetHostImpl::GetBackingStore(bool force_create) { |
AutoReset<bool> auto_reset_in_get_backing_store(&in_get_backing_store_, true); |
// We might have a cached backing store that we can reuse! |
- BackingStore* backing_store = |
- BackingStoreManager::GetBackingStore(this, current_size_); |
- if (!force_create) |
+ BackingStore* backing_store = NULL; |
+ if (TryGetBackingStore(view_size, &backing_store) || !force_create) |
return backing_store; |
- // If we fail to find a backing store in the cache, send out a request |
- // to the renderer to paint the view if required. |
- if (!backing_store && !repaint_ack_pending_ && !resize_ack_pending_ && |
- !view_being_painted_) { |
+ // We do not have a suitable backing store in the cache, so send out a |
+ // request to the renderer to paint the view if required. |
+ if (!repaint_ack_pending_ && !resize_ack_pending_ && !view_being_painted_) { |
repaint_start_time_ = TimeTicks::Now(); |
repaint_ack_pending_ = true; |
- Send(new ViewMsg_Repaint(routing_id_, current_size_)); |
+ Send(new ViewMsg_Repaint(routing_id_, view_size)); |
} |
- // When we have asked the RenderWidget to resize, and we are still waiting on |
- // a response, block for a little while to see if we can't get a response |
- // before returning the old (incorrectly sized) backing store. |
- if (resize_ack_pending_ || !backing_store) { |
+ TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS); |
+ TimeTicks end_time = TimeTicks::Now() + max_delay; |
+ do { |
+ TRACE_EVENT0("renderer_host", "GetBackingStore::WaitForUpdate"); |
+ |
+ // When we have asked the RenderWidget to resize, and we are still waiting |
+ // on a response, block for a little while to see if we can't get a response |
+ // before returning the old (incorrectly sized) backing store. |
IPC::Message msg; |
- TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS); |
- if (process_->WaitForUpdateMsg(routing_id_, max_delay, &msg)) { |
+ if (process_->WaitForBackingStoreMsg(routing_id_, max_delay, &msg)) { |
OnMessageReceived(msg); |
- backing_store = BackingStoreManager::GetBackingStore(this, current_size_); |
+ |
+ // For auto-resized views, current_size_ determines the view_size and it |
+ // may have changed during the handling of an UpdateRect message. |
+ if (should_auto_resize_) |
+ view_size = current_size_; |
+ |
+ // Break now if we got a backing store or accelerated surface of the |
+ // correct size. |
+ if (TryGetBackingStore(view_size, &backing_store) || |
+ abort_get_backing_store_) { |
+ abort_get_backing_store_ = false; |
+ return backing_store; |
+ } |
+ } else { |
+ TRACE_EVENT0("renderer_host", "GetBackingStore::Timeout"); |
+ break; |
} |
- } |
+ // Loop if we still have time left and haven't gotten a properly sized |
+ // BackingStore yet. This is necessary to support the GPU path which |
+ // typically has multiple frames pipelined -- we may need to skip one or two |
+ // BackingStore messages to get to the latest. |
+ max_delay = end_time - TimeTicks::Now(); |
+ } while (max_delay > TimeDelta::FromSeconds(0)); |
+ |
+ // We have failed to get a backing store of view_size. Fall back on |
+ // current_size_ to avoid a white flash while resizing slow pages. |
+ if (view_size != current_size_) |
+ TryGetBackingStore(current_size_, &backing_store); |
return backing_store; |
} |
@@ -1143,6 +1200,32 @@ void RenderWidgetHostImpl::OnMsgPaintAtSizeAck(int tag, const gfx::Size& size) { |
Details<std::pair<int, gfx::Size> >(&details)); |
} |
+void RenderWidgetHostImpl::OnCompositorSurfaceBuffersSwapped( |
+ int32 surface_id, |
+ uint64 surface_handle, |
+ int32 route_id, |
+ int32 gpu_process_host_id) { |
+ TRACE_EVENT0("renderer_host", |
+ "RenderWidgetHostImpl::OnCompositorSurfaceBuffersSwapped"); |
+ if (!view_) { |
+ RenderWidgetHostImpl::AcknowledgeSwapBuffers(route_id, |
+ gpu_process_host_id); |
+ return; |
+ } |
+ GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params gpu_params; |
+ gpu_params.surface_id = surface_id; |
+ gpu_params.surface_handle = surface_handle; |
+ gpu_params.route_id = route_id; |
+#if defined(OS_MACOSX) |
+ // Compositor window is always gfx::kNullPluginWindow. |
+ // TODO(jbates) http://crbug.com/105344 This will be removed when there are no |
+ // plugin windows. |
+ gpu_params.window = gfx::kNullPluginWindow; |
+#endif |
+ view_->AcceleratedSurfaceBuffersSwapped(gpu_params, |
+ gpu_process_host_id); |
+} |
+ |
void RenderWidgetHostImpl::OnMsgUpdateRect( |
const ViewHostMsg_UpdateRect_Params& params) { |
TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::OnMsgUpdateRect"); |
@@ -1175,44 +1258,44 @@ void RenderWidgetHostImpl::OnMsgUpdateRect( |
DCHECK(!params.view_size.IsEmpty()); |
bool was_async = false; |
- if (!is_accelerated_compositing_active_) { |
+ |
+ // If this is a GPU UpdateRect, params.bitmap is invalid and dib will be NULL. |
+ TransportDIB* dib = process_->GetTransportDIB(params.bitmap); |
+ |
+ // If gpu process does painting, scroll_rect and copy_rects are always empty |
+ // and backing store is never used. |
+ if (dib) { |
DCHECK(!params.bitmap_rect.IsEmpty()); |
const size_t size = params.bitmap_rect.height() * |
params.bitmap_rect.width() * 4; |
- TransportDIB* dib = process_->GetTransportDIB(params.bitmap); |
- |
- // If gpu process does painting, scroll_rect and copy_rects are always empty |
- // and backing store is never used. |
- if (dib) { |
- if (dib->size() < size) { |
- DLOG(WARNING) << "Transport DIB too small for given rectangle"; |
- RecordAction(UserMetricsAction("BadMessageTerminate_RWH1")); |
- GetProcess()->ReceivedBadMessage(); |
- } else { |
- UNSHIPPED_TRACE_EVENT_INSTANT2("test_latency", "UpdateRect", |
- "x+y", params.bitmap_rect.x() + params.bitmap_rect.y(), |
- "color", 0xffffff & *static_cast<uint32*>(dib->memory())); |
- UNSHIPPED_TRACE_EVENT_INSTANT1("test_latency", "UpdateRectWidth", |
- "width", params.bitmap_rect.width()); |
- |
- // Scroll the backing store. |
- if (!params.scroll_rect.IsEmpty()) { |
- ScrollBackingStoreRect(params.dx, params.dy, |
- params.scroll_rect, |
- params.view_size); |
- } |
- |
- // Paint the backing store. This will update it with the |
- // renderer-supplied bits. The view will read out of the backing store |
- // later to actually draw to the screen. |
- was_async = PaintBackingStoreRect( |
- params.bitmap, |
- params.bitmap_rect, |
- params.copy_rects, |
- params.view_size, |
- base::Bind(&RenderWidgetHostImpl::DidUpdateBackingStore, |
- weak_factory_.GetWeakPtr(), params, paint_start)); |
+ if (dib->size() < size) { |
+ DLOG(WARNING) << "Transport DIB too small for given rectangle"; |
+ RecordAction(UserMetricsAction("BadMessageTerminate_RWH1")); |
+ GetProcess()->ReceivedBadMessage(); |
+ } else { |
+ UNSHIPPED_TRACE_EVENT_INSTANT2("test_latency", "UpdateRect", |
+ "x+y", params.bitmap_rect.x() + params.bitmap_rect.y(), |
+ "color", 0xffffff & *static_cast<uint32*>(dib->memory())); |
+ UNSHIPPED_TRACE_EVENT_INSTANT1("test_latency", "UpdateRectWidth", |
+ "width", params.bitmap_rect.width()); |
+ |
+ // Scroll the backing store. |
+ if (!params.scroll_rect.IsEmpty()) { |
+ ScrollBackingStoreRect(params.dx, params.dy, |
+ params.scroll_rect, |
+ params.view_size); |
} |
+ |
+ // Paint the backing store. This will update it with the |
+ // renderer-supplied bits. The view will read out of the backing store |
+ // later to actually draw to the screen. |
+ was_async = PaintBackingStoreRect( |
+ params.bitmap, |
+ params.bitmap_rect, |
+ params.copy_rects, |
+ params.view_size, |
+ base::Bind(&RenderWidgetHostImpl::DidUpdateBackingStore, |
+ weak_factory_.GetWeakPtr(), params, paint_start)); |
} |
} |
@@ -1239,7 +1322,8 @@ void RenderWidgetHostImpl::OnMsgUpdateRect( |
} |
void RenderWidgetHostImpl::OnMsgUpdateIsDelayed() { |
- // Nothing to do, this message was just to unblock the UI thread. |
+ if (in_get_backing_store_) |
+ abort_get_backing_store_ = true; |
} |
void RenderWidgetHostImpl::DidUpdateBackingStore( |
@@ -1286,11 +1370,8 @@ void RenderWidgetHostImpl::DidUpdateBackingStore( |
// If we got a resize ack, then perhaps we have another resize to send? |
bool is_resize_ack = |
ViewHostMsg_UpdateRect_Flags::is_resize_ack(params.flags); |
- if (is_resize_ack && view_) { |
- gfx::Rect view_bounds = view_->GetViewBounds(); |
- if (current_size_ != view_bounds.size()) |
- WasResized(); |
- } |
+ if (is_resize_ack) |
+ WasResized(); |
// Log the time delta for processing a paint message. |
TimeTicks now = TimeTicks::Now(); |