Chromium Code Reviews| 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 4e5bbe8f90afe5820c6d54971172b9d6b2c45fe4..a74213c9b934c19e8530974b82dc02191f616442 100644 |
| --- a/content/browser/renderer_host/render_widget_host_view_aura.cc |
| +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc |
| @@ -9,7 +9,6 @@ |
| #include "base/command_line.h" |
| #include "base/debug/trace_event.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" |
| @@ -134,6 +133,13 @@ bool ShouldSendPinchGesture() { |
| return pinch_allowed; |
| } |
| +bool ShouldReleaseFrontSurface() { |
| + static bool release_front_surface_allowed = |
| + CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kEnableUIReleaseFrontSurface); |
| + return release_front_surface_allowed; |
| +} |
| + |
| } // namespace |
| // We have to implement the WindowObserver interface on a separate object |
| @@ -215,6 +221,11 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host) |
| can_compose_inline_(true), |
| has_composition_text_(false), |
| current_surface_(0), |
| + current_surface_is_protected_(true), |
| + current_surface_in_use_by_compositor_(true), |
| + pending_thumbnail_tasks_(0), |
| + protection_state_id_(0), |
| + surface_route_id_(0), |
| paint_canvas_(NULL), |
| synthetic_move_sent_(false), |
| needs_update_texture_(false) { |
| @@ -286,15 +297,32 @@ RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const { |
| } |
| void RenderWidgetHostViewAura::DidBecomeSelected() { |
| + if (host_->IsVisible()) |
| + return; |
| + |
| host_->WasRestored(); |
| + |
| if (!current_surface_ && host_->is_accelerated_compositing_active() && |
| !released_front_lock_.get()) |
| released_front_lock_ = window_->GetRootWindow()->GetCompositorLock(); |
| + |
| + AdjustSurfaceProtection(); |
| } |
| void RenderWidgetHostViewAura::WasHidden() { |
| + if (!host_->IsVisible()) |
| + return; |
| + |
| host_->WasHidden(); |
| + |
| released_front_lock_ = NULL; |
| + |
| + if (ShouldReleaseFrontSurface()) { |
| + current_surface_ = 0; |
| + UpdateExternalTexture(); |
| + } |
| + |
| + AdjustSurfaceProtection(); |
| } |
| void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) { |
| @@ -482,11 +510,25 @@ void RenderWidgetHostViewAura::CopyFromCompositingSurface( |
| unsigned char* addr = static_cast<unsigned char*>( |
| output->getTopDevice()->accessBitmap(true).getPixels()); |
| scoped_callback_runner.Release(); |
| + // Wrap the callback with an internal handler so that we can inject our |
| + // own completion handlers (where we can call AdjustSurfaceProtection). |
| + base::Callback<void(bool)> wrapper_callback = base::Bind( |
| + &RenderWidgetHostViewAura::CopyFromCompositingSurfaceFinished, |
| + AsWeakPtr(), |
| + callback); |
| + ++pending_thumbnail_tasks_; |
| gl_helper->CopyTextureTo(container->texture_id(), |
| container->size(), |
| size_in_pixel, |
| addr, |
| - callback); |
| + wrapper_callback); |
| +} |
| + |
| +void RenderWidgetHostViewAura::CopyFromCompositingSurfaceFinished( |
| + base::Callback<void(bool)> callback, bool result) { |
| + --pending_thumbnail_tasks_; |
| + AdjustSurfaceProtection(); |
| + callback.Run(result); |
| } |
| void RenderWidgetHostViewAura::OnAcceleratedCompositingStateChange() { |
| @@ -503,14 +545,14 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { |
| needs_update_texture_ = false; |
| if (current_surface_ != 0 && |
| host_->is_accelerated_compositing_active()) { |
| - |
| + DCHECK(image_transport_clients_.find(current_surface_) != |
| + image_transport_clients_.end()); |
| ImageTransportClient* container = |
| image_transport_clients_[current_surface_]; |
| if (container) |
| container->Update(); |
| window_->SetExternalTexture(container); |
| - |
| - released_front_lock_ = NULL; |
| + current_surface_in_use_by_compositor_ = true; |
| if (!container) { |
| resize_locks_.clear(); |
| @@ -547,6 +589,18 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { |
| } |
| } else { |
| window_->SetExternalTexture(NULL); |
| + ui::Compositor* compositor = GetCompositor(); |
| + if (!compositor->DrawPending()) { |
| + current_surface_in_use_by_compositor_ = false; |
| + AdjustSurfaceProtection(); |
| + } else { |
| + on_compositing_ended_callbacks_.push_back( |
| + base::Bind(&RenderWidgetHostViewAura:: |
| + SetSurfaceNotInUseByCompositor, |
| + AsWeakPtr())); |
| + if (!compositor->HasObserver(this)) |
| + compositor->AddObserver(this); |
| + } |
| resize_locks_.clear(); |
| } |
| } |
| @@ -554,36 +608,62 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { |
| void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( |
| const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel, |
| int gpu_host_id) { |
| + // If protection state changed, then this swap is stale. We must still ACK but |
| + // do not update current_surface_ since it may have been discarded. |
| + if (params_in_pixel.protection_state_id && |
| + params_in_pixel.protection_state_id != protection_state_id_) { |
| + DCHECK(!current_surface_); |
| + if (params_in_pixel.require_ack) { |
| + RenderWidgetHostImpl::AcknowledgeSwapBuffers( |
| + params_in_pixel.route_id, gpu_host_id); |
| + } |
| + 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. |
| + if (params_in_pixel.require_ack) |
| + released_front_lock_ = NULL; |
| + |
| + DCHECK(current_surface_); |
| UpdateExternalTexture(); |
| ui::Compositor* compositor = GetCompositor(); |
| if (!compositor) { |
| // We have no compositor, so we have no way to display the surface. |
| // Must still send the ACK. |
| - RenderWidgetHostImpl::AcknowledgeSwapBuffers(params_in_pixel.route_id, |
| - gpu_host_id); |
| + if (params_in_pixel.require_ack) |
|
piman
2012/06/12 23:05:12
nit: braces
|
| + RenderWidgetHostImpl::AcknowledgeSwapBuffers(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(); |
| gfx::Size surface_size = content::ConvertSizeToDIP(this, |
| surface_size_in_pixel); |
| window_->SchedulePaintInRect(gfx::Rect(surface_size)); |
| - if (!resize_locks_.empty() && !compositor->DrawPending()) { |
| - // If we are waiting for the resize, fast-track the ACK. |
| - // However only do so if we're not between the Draw() and the |
| - // OnCompositingEnded(), because out-of-order execution in the GPU process |
| - // might corrupt the "front buffer" for the currently issued frame. |
| - RenderWidgetHostImpl::AcknowledgeSwapBuffers( |
| - params_in_pixel.route_id, gpu_host_id); |
| - } else { |
| - // Add sending an ACK to the list of things to do OnCompositingEnded |
| - on_compositing_ended_callbacks_.push_back( |
| - base::Bind(&RenderWidgetHostImpl::AcknowledgeSwapBuffers, |
| - params_in_pixel.route_id, gpu_host_id)); |
| - if (!compositor->HasObserver(this)) |
| - compositor->AddObserver(this); |
| + if (params_in_pixel.require_ack) { |
| + if (!resize_locks_.empty() && !compositor->DrawPending()) { |
| + // If we are waiting for the resize, fast-track the ACK. |
| + // However only do so if we're not between the Draw() and the |
| + // OnCompositingEnded(), because out-of-order execution in the GPU |
| + // process might corrupt the "front buffer" for the currently issued |
| + // frame. |
| + RenderWidgetHostImpl::AcknowledgeSwapBuffers( |
| + params_in_pixel.route_id, gpu_host_id); |
| + } else { |
| + // Add sending an ACK to the list of things to do OnCompositingEnded |
| + on_compositing_ended_callbacks_.push_back( |
| + base::Bind(&RenderWidgetHostImpl::AcknowledgeSwapBuffers, |
| + params_in_pixel.route_id, gpu_host_id)); |
| + if (!compositor->HasObserver(this)) |
| + compositor->AddObserver(this); |
| + } |
| } |
| } |
| } |
| @@ -591,7 +671,18 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( |
| void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( |
| const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel, |
| int gpu_host_id) { |
| + // If visible state changed, then this PSB is stale. We must still ACK but |
| + // do not update current_surface_. |
| + if (params_in_pixel.protection_state_id && |
| + params_in_pixel.protection_state_id != protection_state_id_) { |
| + DCHECK(!current_surface_); |
| + RenderWidgetHostImpl::AcknowledgePostSubBuffer(params_in_pixel.route_id, |
| + gpu_host_id); |
| + return; |
| + } |
| current_surface_ = params_in_pixel.surface_handle; |
| + released_front_lock_ = NULL; |
| + DCHECK(current_surface_); |
| UpdateExternalTexture(); |
| ui::Compositor* compositor = GetCompositor(); |
| @@ -601,6 +692,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(); |
| @@ -647,7 +740,8 @@ 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) { |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| scoped_refptr<ImageTransportClient> surface(factory->CreateTransportClient( |
| gfx::Size(width_in_pixel, height_in_pixel), surface_handle)); |
| @@ -658,10 +752,14 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceNew( |
| *shm_handle = surface->Handle(); |
| image_transport_clients_[*surface_handle] = surface; |
| + |
| + surface_route_id_ = route_id; |
| } |
| void RenderWidgetHostViewAura::AcceleratedSurfaceRelease( |
| uint64 surface_handle) { |
| + DCHECK(image_transport_clients_.find(surface_handle) != |
| + image_transport_clients_.end()); |
| if (current_surface_ == surface_handle) { |
| current_surface_ = 0; |
| UpdateExternalTexture(); |
| @@ -669,6 +767,38 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceRelease( |
| image_transport_clients_.erase(surface_handle); |
| } |
| +void RenderWidgetHostViewAura::SetSurfaceNotInUseByCompositor() { |
| + if (current_surface_ || host_->IsVisible()) |
| + return; |
| + current_surface_in_use_by_compositor_ = false; |
| + AdjustSurfaceProtection(); |
| +} |
| + |
| +void RenderWidgetHostViewAura::AdjustSurfaceProtection() { |
| + // If the current surface is non null, it is protected. |
| + // If we are visible, it is protected. |
| + // If we are not visible and current surface is null, still stay protected |
| + // until we finish thumbnailing and compositing. |
| + bool surface_is_protected = |
| + current_surface_ || |
| + host_->IsVisible() || |
| + (current_surface_is_protected_ && |
| + (pending_thumbnail_tasks_ || current_surface_in_use_by_compositor_)); |
| + if (current_surface_is_protected_ == surface_is_protected) |
| + return; |
| + current_surface_is_protected_ = surface_is_protected; |
| + ++protection_state_id_; |
| + |
| + if (!surface_route_id_ || !shared_surface_handle_.parent_gpu_process_id) |
| + return; |
| + |
| + RenderWidgetHostImpl::SendFrontSurfaceIsProtected( |
| + surface_is_protected, |
| + protection_state_id_, |
| + surface_route_id_, |
| + shared_surface_handle_.parent_gpu_process_id); |
| +} |
| + |
| void RenderWidgetHostViewAura::SetBackground(const SkBitmap& background) { |
| content::RenderWidgetHostViewBase::SetBackground(background); |
| host_->SetBackground(background); |
| @@ -1209,6 +1339,10 @@ void RenderWidgetHostViewAura::OnCompositingAborted( |
| void RenderWidgetHostViewAura::OnLostResources(ui::Compositor* compositor) { |
| image_transport_clients_.clear(); |
| current_surface_ = 0; |
| + protection_state_id_ = 0; |
| + current_surface_is_protected_ = true; |
| + current_surface_in_use_by_compositor_ = true; |
| + surface_route_id_ = 0; |
| UpdateExternalTexture(); |
| locks_pending_draw_.clear(); |