Index: content/renderer/render_widget.cc |
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc |
index cd50991e3b785568574b54c74d85b9582145bc7e..1add63b9de8952688edf575d5d3769ea1d45c68a 100644 |
--- a/content/renderer/render_widget.cc |
+++ b/content/renderer/render_widget.cc |
@@ -11,6 +11,7 @@ |
#include "base/memory/scoped_ptr.h" |
#include "base/message_loop.h" |
#include "base/metrics/histogram.h" |
+#include "base/stl_util.h" |
#include "base/utf_string_conversions.h" |
#include "build/build_config.h" |
#include "content/common/swapped_out_messages.h" |
@@ -103,6 +104,7 @@ RenderWidget::RenderWidget(WebKit::WebPopupType popup_type) |
RenderWidget::~RenderWidget() { |
DCHECK(!webwidget_) << "Leaking our WebWidget!"; |
+ STLDeleteElements(&updates_pending_swap_); |
if (current_paint_buf_) { |
RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); |
current_paint_buf_ = NULL; |
@@ -355,7 +357,7 @@ void RenderWidget::OnRequestMoveAck() { |
void RenderWidget::OnUpdateRectAck() { |
TRACE_EVENT0("renderer", "RenderWidget::OnUpdateRectAck"); |
- DCHECK(update_reply_pending()); |
+ DCHECK(update_reply_pending_); |
update_reply_pending_ = false; |
// If we sent an UpdateRect message with a zero-sized bitmap, then we should |
@@ -388,6 +390,14 @@ bool RenderWidget::SupportsAsynchronousSwapBuffers() |
void RenderWidget::OnSwapBuffersAborted() |
{ |
TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersAborted"); |
+ while (!updates_pending_swap_.empty()) { |
+ ViewHostMsg_UpdateRect* msg = updates_pending_swap_.front(); |
+ updates_pending_swap_.pop_front(); |
+ // msg can be NULL if the swap doesn't correspond to an DoDeferredUpdate |
+ // compositing pass, hence doesn't require an UpdateRect message. |
+ if (msg) |
+ Send(msg); |
+ } |
num_swapbuffers_complete_pending_ = 0; |
using_asynchronous_swapbuffers_ = false; |
// Schedule another frame so the compositor learns about it. |
@@ -396,8 +406,19 @@ void RenderWidget::OnSwapBuffersAborted() |
void RenderWidget::OnSwapBuffersPosted() { |
TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersPosted"); |
- if (using_asynchronous_swapbuffers_) |
+ |
+ if (using_asynchronous_swapbuffers_) { |
+ ViewHostMsg_UpdateRect* msg = NULL; |
+ // pending_update_params_ can be NULL if the swap doesn't correspond to an |
+ // DoDeferredUpdate compositing pass, hence doesn't require an UpdateRect |
+ // message. |
+ if (pending_update_params_.get()) { |
+ msg = new ViewHostMsg_UpdateRect(routing_id_, *pending_update_params_); |
+ pending_update_params_.reset(); |
+ } |
+ updates_pending_swap_.push_back(msg); |
num_swapbuffers_complete_pending_++; |
+ } |
} |
void RenderWidget::OnSwapBuffersComplete() { |
@@ -408,6 +429,13 @@ void RenderWidget::OnSwapBuffersComplete() { |
TRACE_EVENT0("renderer", "EarlyOut_ZeroSwapbuffersPending"); |
return; |
} |
+ DCHECK(!updates_pending_swap_.empty()); |
+ ViewHostMsg_UpdateRect* msg = updates_pending_swap_.front(); |
+ updates_pending_swap_.pop_front(); |
+ // msg can be NULL if the swap doesn't correspond to an DoDeferredUpdate |
+ // compositing pass, hence doesn't require an UpdateRect message. |
+ if (msg) |
+ Send(msg); |
num_swapbuffers_complete_pending_--; |
// If update reply is still pending, then defer the update until that reply |
@@ -694,7 +722,7 @@ void RenderWidget::DoDeferredUpdate() { |
if (!webwidget_) |
return; |
- if (update_reply_pending()) { |
+ if (update_reply_pending_) { |
TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending"); |
return; |
} |
@@ -758,9 +786,6 @@ void RenderWidget::DoDeferredUpdate() { |
gfx::Rect scroll_damage = update.GetScrollDamage(); |
gfx::Rect bounds = update.GetPaintBounds().Union(scroll_damage); |
- // Compositing the page may disable accelerated compositing. |
- bool accelerated_compositing_was_active = is_accelerated_compositing_active_; |
- |
// A plugin may be able to do an optimized paint. First check this, in which |
// case we can skip all of the bitmap generation and regular paint code. |
// This optimization allows PPAPI plugins that declare themselves on top of |
@@ -772,19 +797,30 @@ void RenderWidget::DoDeferredUpdate() { |
// This optimization only works when the entire invalid region is contained |
// within the plugin. There is a related optimization in PaintRect for the |
// case where there may be multiple invalid regions. |
- TransportDIB::Id dib_id = TransportDIB::Id(); |
TransportDIB* dib = NULL; |
- std::vector<gfx::Rect> copy_rects; |
gfx::Rect optimized_copy_rect, optimized_copy_location; |
+ DCHECK(!pending_update_params_.get()); |
+ pending_update_params_.reset(new ViewHostMsg_UpdateRect_Params); |
+ pending_update_params_->dx = update.scroll_delta.x(); |
+ pending_update_params_->dy = update.scroll_delta.y(); |
+ pending_update_params_->scroll_rect = update.scroll_rect; |
+ pending_update_params_->view_size = size_; |
+ pending_update_params_->resizer_rect = resizer_rect_; |
+ pending_update_params_->plugin_window_moves.swap(plugin_window_moves_); |
+ pending_update_params_->flags = next_paint_flags_; |
+ pending_update_params_->scroll_offset = GetScrollOffset(); |
+ pending_update_params_->needs_ack = true; |
+ next_paint_flags_ = 0; |
+ |
if (update.scroll_rect.IsEmpty() && |
!is_accelerated_compositing_active_ && |
GetBitmapForOptimizedPluginPaint(bounds, &dib, &optimized_copy_location, |
&optimized_copy_rect)) { |
// Only update the part of the plugin that actually changed. |
optimized_copy_rect = optimized_copy_rect.Intersect(bounds); |
- bounds = optimized_copy_location; |
- copy_rects.push_back(optimized_copy_rect); |
- dib_id = dib->id(); |
+ pending_update_params_->bitmap = dib->id(); |
+ pending_update_params_->bitmap_rect = optimized_copy_location; |
+ pending_update_params_->copy_rects.push_back(optimized_copy_rect); |
} else if (!is_accelerated_compositing_active_) { |
// Compute a buffer for painting and cache it. |
scoped_ptr<skia::PlatformCanvas> canvas( |
@@ -804,6 +840,10 @@ void RenderWidget::DoDeferredUpdate() { |
HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size()); |
+ pending_update_params_->bitmap = current_paint_buf_->id(); |
+ pending_update_params_->bitmap_rect = bounds; |
+ |
+ std::vector<gfx::Rect>& copy_rects = pending_update_params_->copy_rects; |
// The scroll damage is just another rectangle to paint and copy. |
copy_rects.swap(update.paint_rects); |
if (!scroll_damage.IsEmpty()) |
@@ -811,37 +851,29 @@ void RenderWidget::DoDeferredUpdate() { |
for (size_t i = 0; i < copy_rects.size(); ++i) |
PaintRect(copy_rects[i], bounds.origin(), canvas.get()); |
- |
- dib_id = current_paint_buf_->id(); |
} else { // Accelerated compositing path |
// Begin painting. |
+ // If painting is done via the gpu process then we don't set any damage |
+ // rects to save the browser process from doing unecessary work. |
+ pending_update_params_->bitmap_rect = bounds; |
+ pending_update_params_->scroll_rect = gfx::Rect(); |
+ // We don't need an ack, because we're not sharing a DIB with the browser. |
+ // If it needs to (e.g. composited UI), the GPU process does its own ACK |
+ // with the browser for the GPU surface. |
+ pending_update_params_->needs_ack = false; |
webwidget_->composite(false); |
} |
- // sending an ack to browser process that the paint is complete... |
- ViewHostMsg_UpdateRect_Params params; |
- params.bitmap = dib_id; |
- params.bitmap_rect = bounds; |
- params.dx = update.scroll_delta.x(); |
- params.dy = update.scroll_delta.y(); |
- if (accelerated_compositing_was_active) { |
- // If painting is done via the gpu process then we clear out all damage |
- // rects to save the browser process from doing unecessary work. |
- params.scroll_rect = gfx::Rect(); |
- params.copy_rects.clear(); |
- } else { |
- params.scroll_rect = update.scroll_rect; |
- params.copy_rects.swap(copy_rects); // TODO(darin): clip to bounds? |
+ // If composite() called SwapBuffers, pending_update_params_ will be reset (in |
+ // OnSwapBuffersPosted), meaning a message has been added to the |
+ // updates_pending_swap_ queue, that will be sent later. Otherwise, we send |
+ // the message now. |
+ if (pending_update_params_.get()) { |
+ // sending an ack to browser process that the paint is complete... |
+ update_reply_pending_ = pending_update_params_->needs_ack; |
+ Send(new ViewHostMsg_UpdateRect(routing_id_, *pending_update_params_)); |
+ pending_update_params_.reset(); |
} |
- params.view_size = size_; |
- params.resizer_rect = resizer_rect_; |
- params.plugin_window_moves.swap(plugin_window_moves_); |
- params.flags = next_paint_flags_; |
- params.scroll_offset = GetScrollOffset(); |
- |
- update_reply_pending_ = true; |
- Send(new ViewHostMsg_UpdateRect(routing_id_, params)); |
- next_paint_flags_ = 0; |
UpdateTextInputState(); |
UpdateSelectionBounds(); |
@@ -867,7 +899,7 @@ void RenderWidget::didInvalidateRect(const WebRect& rect) { |
return; |
if (!paint_aggregator_.HasPendingUpdate()) |
return; |
- if (update_reply_pending() || |
+ if (update_reply_pending_ || |
num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) |
return; |
@@ -905,7 +937,7 @@ void RenderWidget::didScrollRect(int dx, int dy, const WebRect& clip_rect) { |
return; |
if (!paint_aggregator_.HasPendingUpdate()) |
return; |
- if (update_reply_pending() || |
+ if (update_reply_pending_ || |
num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) |
return; |
@@ -936,6 +968,18 @@ void RenderWidget::didActivateCompositor(int compositor_identifier) { |
if (compositor_thread) |
compositor_thread->AddCompositor(routing_id_, compositor_identifier); |
+ if (!is_accelerated_compositing_active_) { |
+ // When not in accelerated compositing mode, in certain cases (e.g. waiting |
+ // for a resize or if no backing store) the RenderWidgetHost is blocking the |
+ // browser's UI thread for some time, waiting for an UpdateRect. If we are |
+ // going to switch to accelerated compositing, the GPU process may need |
+ // round-trips to the browser's UI thread before finishing the frame, |
+ // causing deadlocks if we delay the UpdateRect until we receive the |
+ // OnSwapBuffersComplete. So send a dummy message that will unblock the |
+ // browser's UI thread. |
+ Send(new ViewHostMsg_UpdateIsDelayed(routing_id_)); |
+ } |
+ |
is_accelerated_compositing_active_ = true; |
Send(new ViewHostMsg_DidActivateAcceleratedCompositing( |
routing_id_, is_accelerated_compositing_active_)); |
@@ -963,7 +1007,7 @@ void RenderWidget::didCommitAndDrawCompositorFrame() { |
} |
void RenderWidget::didCompleteSwapBuffers() { |
- if (update_reply_pending()) |
+ if (update_reply_pending_) |
return; |
if (!next_paint_flags_ && !plugin_window_moves_.size()) |