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 4c27d8f7872a16bfb4162c4ed2866a5ea8a5fa44..c2e06c6c01b73eb7cbb57c7b6f8252bc3fa88682 100644 |
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc |
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc |
@@ -8,7 +8,6 @@ |
#include "base/bind_helpers.h" |
#include "base/command_line.h" |
#include "base/logging.h" |
-#include "base/memory/weak_ptr.h" |
#include "base/message_loop.h" |
#include "base/string_number_conversions.h" |
#include "content/browser/renderer_host/backing_store_skia.h" |
@@ -213,6 +212,11 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host) |
can_compose_inline_(true), |
has_composition_text_(false), |
current_surface_(0), |
+ route_id_(0), |
+ gpu_host_id_(0), |
+ weak_factory_(this), |
+ current_valid_release_front_request_id_(0), |
+ is_thumbnailing_(false), |
paint_canvas_(NULL), |
synthetic_move_sent_(false), |
needs_update_texture_(false) { |
@@ -236,6 +240,7 @@ RenderWidgetHostViewAura::~RenderWidgetHostViewAura() { |
popup_parent_host_view_->popup_child_host_view_ = NULL; |
} |
aura::client::SetTooltipText(window_, NULL); |
+ weak_factory_.InvalidateWeakPtrs(); |
} |
//////////////////////////////////////////////////////////////////////////////// |
@@ -283,10 +288,22 @@ RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const { |
void RenderWidgetHostViewAura::DidBecomeSelected() { |
host_->WasRestored(); |
+ InvalidatePendingRequestReleaseFrontRequest(); |
+ if (!route_id_ || !gpu_host_id_) |
+ return; |
+ RenderWidgetHostImpl::SendFrontSurfaceIsProtected(true, |
+ route_id_, |
+ gpu_host_id_); |
} |
void RenderWidgetHostViewAura::WasHidden() { |
host_->WasHidden(); |
+ InvalidatePendingRequestReleaseFrontRequest(); |
+ if (!route_id_ || !gpu_host_id_) |
+ return; |
+ RenderWidgetHostImpl::SendFrontSurfaceIsProtected(false, |
+ route_id_, |
+ gpu_host_id_); |
} |
void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) { |
@@ -449,6 +466,9 @@ void RenderWidgetHostViewAura::CopyFromCompositingSurface( |
skia::PlatformCanvas* output, |
base::Callback<void(bool)> callback) { |
base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); |
+ if (is_thumbnailing_) |
+ return; |
+ |
ui::Compositor* compositor = GetCompositor(); |
if (!compositor) |
return; |
@@ -474,11 +494,25 @@ void RenderWidgetHostViewAura::CopyFromCompositingSurface( |
unsigned char* addr = static_cast<unsigned char*>( |
output->getTopDevice()->accessBitmap(true).getPixels()); |
scoped_callback_runner.Release(); |
+ is_thumbnailing_ = true; |
+ base::Callback<void(bool)> internal_callback = base::Bind( |
+ &RenderWidgetHostViewAura::CopyFromCompositingSurfaceFinished, |
+ weak_factory_.GetWeakPtr(), |
+ callback); |
gl_helper->CopyTextureTo(container->texture_id(), |
container->size(), |
size_in_pixel, |
addr, |
- callback); |
+ internal_callback); |
+} |
+ |
+void RenderWidgetHostViewAura::CopyFromCompositingSurfaceFinished( |
+ base::Callback<void(bool)> callback, bool result) { |
+ is_thumbnailing_ = false; |
+ for (size_t i = 0; i != delayed_release_front_acks_.size(); ++i) |
+ delayed_release_front_acks_[i].Run(); |
+ delayed_release_front_acks_.clear(); |
+ callback.Run(result); |
} |
void RenderWidgetHostViewAura::OnAcceleratedCompositingStateChange() { |
@@ -551,6 +585,7 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { |
void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( |
const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel, |
int gpu_host_id) { |
+ InvalidatePendingRequestReleaseFrontRequest(); |
current_surface_ = params_in_pixel.surface_handle; |
UpdateExternalTexture(); |
@@ -588,6 +623,7 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( |
void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( |
const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel, |
int gpu_host_id) { |
+ InvalidatePendingRequestReleaseFrontRequest(); |
current_surface_ = params_in_pixel.surface_handle; |
UpdateExternalTexture(); |
@@ -598,6 +634,8 @@ void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( |
RenderWidgetHostImpl::AcknowledgePostSubBuffer( |
params_in_pixel.route_id, gpu_host_id); |
} 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(); |
@@ -644,7 +682,9 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceNew( |
int32 width_in_pixel, |
int32 height_in_pixel, |
uint64* surface_handle, |
- TransportDIB::Handle* shm_handle) { |
+ TransportDIB::Handle* shm_handle, |
+ int32 route_id, |
+ int gpu_host_id) { |
ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
scoped_refptr<ImageTransportClient> surface(factory->CreateTransportClient( |
gfx::Size(width_in_pixel, height_in_pixel), surface_handle)); |
@@ -655,6 +695,12 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceNew( |
*shm_handle = surface->Handle(); |
image_transport_clients_[*surface_handle] = surface; |
+ |
+ route_id_ = route_id; |
+ gpu_host_id_ = gpu_host_id; |
+ RenderWidgetHostImpl::SendFrontSurfaceIsProtected(host_->IsVisible(), |
+ route_id_, |
+ gpu_host_id_); |
} |
void RenderWidgetHostViewAura::AcceleratedSurfaceRelease( |
@@ -666,6 +712,118 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceRelease( |
image_transport_clients_.erase(surface_handle); |
} |
+void RenderWidgetHostViewAura::AcceleratedSurfaceRequestReleaseFront( |
+ uint64 surface_handle, |
+ int request_id, |
+ int retry_count, |
+ int32 route_id, |
+ int gpu_host_id) { |
+ // TODO(mmocny): Once we have implemented smooth tab switching on aura |
+ // (crbug.com/126526) then this flag should switch to enabled by default, or |
+ // be removed altogether. |
+ if (!CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kEnableUIReleaseFrontSurface)) |
+ return; |
+ |
+ // This request id becomes the only valid id. We use this id to for request |
+ // invalidation and to protect against visibility state ABA issues. |
+ current_valid_release_front_request_id_ = request_id; |
+ |
+ // This surface may have already been released if multiple suggestions were |
+ // sent. Always send a reply since previous response may have been discarded. |
+ if (image_transport_clients_.find(surface_handle) == |
+ image_transport_clients_.end()) { |
+ SendRequestReleaseFrontAckAfterThumbnailIfNecessary(request_id, |
+ retry_count, |
+ true, |
+ route_id, |
+ gpu_host_id); |
+ return; |
+ } |
+ DCHECK(current_surface_ == surface_handle); |
+ |
+ // Confirm that the surface is not in use, by making sure the tab is not |
+ // visible (visibility can change since the time the request was sent out). |
+ if (host_->IsVisible()) { |
+ // Send an ACK informing the gpu that we are ignoring this request. |
+ RenderWidgetHostImpl::AcknowledgeRequestReleaseFront( |
+ request_id, retry_count, false, route_id, gpu_host_id); |
+ return; |
+ } |
+ |
+ base::Callback<void(void)> send_ack_if_valid_callback = |
+ base::Bind(&RenderWidgetHostViewAura::ReleaseFrontSurfaceIfStillValid, |
+ weak_factory_.GetWeakPtr(), |
+ surface_handle, |
+ request_id, |
+ retry_count, |
+ route_id, |
+ gpu_host_id); |
+ |
+ ui::Compositor* compositor = GetCompositor(); |
+ // We may still be using the surface for the duration of a composite, so check |
+ // that we aren't currently in the middle of one. |
+ if (!compositor->CurrentlyCompositing()) { |
+ send_ack_if_valid_callback.Run(); |
+ return; |
+ } |
+ |
+ // We are in the middle of a composite, so we must delay reply. |
+ on_compositing_ended_callbacks_.push_back(send_ack_if_valid_callback); |
+ if (!compositor->HasObserver(this)) |
+ compositor->AddObserver(this); |
+} |
+ |
+void RenderWidgetHostViewAura::InvalidatePendingRequestReleaseFrontRequest() { |
+ current_valid_release_front_request_id_ = 0; |
+} |
+ |
+void RenderWidgetHostViewAura::ReleaseFrontSurfaceIfStillValid( |
+ uint64 surface_handle, |
+ int request_id, |
+ int retry_count, |
+ int32 route_id, |
+ int gpu_host_id) { |
+ // Check if this request_id is valid. No need to send an ACK if not, since |
+ // the newer, currently valid request will send one. |
+ if (current_valid_release_front_request_id_ != request_id) |
+ return; |
+ |
+ DCHECK(!host_->IsVisible()); |
+ DCHECK(current_surface_ == surface_handle); |
+ |
+ // Release our handle to the surface. |
+ AcceleratedSurfaceRelease(surface_handle); |
+ DCHECK(!current_surface_); |
+ |
+ // Now reply to the gpu process, potentially delayed during thumbnailing. |
+ SendRequestReleaseFrontAckAfterThumbnailIfNecessary(request_id, |
+ retry_count, |
+ true, |
+ route_id, |
+ gpu_host_id); |
+} |
+ |
+void RenderWidgetHostViewAura:: |
+ SendRequestReleaseFrontAckAfterThumbnailIfNecessary( |
+ int request_id, |
+ int retry_count, |
+ bool was_released, |
+ int32 route_id, |
+ int gpu_host_id) { |
+ base::Callback<void(void)> request_release_front_ack = |
+ base::Bind(&RenderWidgetHostImpl::AcknowledgeRequestReleaseFront, |
+ request_id, |
+ retry_count, |
+ was_released, |
+ route_id, |
+ gpu_host_id); |
+ if (is_thumbnailing_) |
+ delayed_release_front_acks_.push_back(request_release_front_ack); |
+ else |
+ request_release_front_ack.Run(); |
+} |
+ |
void RenderWidgetHostViewAura::SetBackground(const SkBitmap& background) { |
content::RenderWidgetHostViewBase::SetBackground(background); |
host_->SetBackground(background); |
@@ -1196,6 +1354,11 @@ void RenderWidgetHostViewAura::OnCompositingEnded(ui::Compositor* compositor) { |
void RenderWidgetHostViewAura::OnLostResources(ui::Compositor* compositor) { |
image_transport_clients_.clear(); |
current_surface_ = 0; |
+ route_id_ = 0; |
+ gpu_host_id_ = 0; |
+ current_valid_release_front_request_id_ = 0; |
+ is_thumbnailing_ = 0; |
+ delayed_release_front_acks_.clear(); |
UpdateExternalTexture(); |
locks_pending_draw_.clear(); |