diff options
author | mmocny@chromium.org <mmocny@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-16 00:35:55 +0000 |
---|---|---|
committer | mmocny@chromium.org <mmocny@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-16 00:35:55 +0000 |
commit | beb62f22a1da3abd0b0263309199dc1e7b6ad1da (patch) | |
tree | 33a44e9a16cc6d87503f56baa53ad730a1fc9bf1 | |
parent | 21f977570e42b26a9c50da35bf8d12e44645371a (diff) | |
download | chromium_src-beb62f22a1da3abd0b0263309199dc1e7b6ad1da.zip chromium_src-beb62f22a1da3abd0b0263309199dc1e7b6ad1da.tar.gz chromium_src-beb62f22a1da3abd0b0263309199dc1e7b6ad1da.tar.bz2 |
Drop frontbuffers with ui-use-gpu-process, synchronized with browser, decoupled from backbuffer drop.
On Aura, every time a tab is backgrounded, RenderWidgetHostViewAura will reset its handle to the front surface. If that tab is foregrounded again, that front surface will not be used until synchronizing with the gpu process to make sure that surface is still available. By doing this, the gpu process knows when it is safe to discard the front surface.
RWHVA sends a FrontSurfaceIsProtected(bool, int) message to the gpu process to keep it informed about front surface protection. The int is a state-of-the-world identifier to protect from ABA issues. RWHVA delays sending FrontSurfaceIsProtected(false) until after the current surface is certain to not be in use, namely after the compositor finishes the current frame and the browser thumbnailer is complete.
BUG=112842
TEST=Manual
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=142408
Review URL: https://chromiumcodereview.appspot.com/10052018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142541 0039d316-1c4b-4281-b951-d872f2087c98
17 files changed, 343 insertions, 60 deletions
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc index 636605d..d8f6d4b 100644 --- a/chrome/browser/chromeos/login/login_utils.cc +++ b/chrome/browser/chromeos/login/login_utils.cc @@ -724,6 +724,7 @@ std::string LoginUtilsImpl::GetOffTheRecordCommandLine( ::switches::kEnableGView, ::switches::kEnableLogging, ::switches::kEnablePartialSwap, + ::switches::kEnableUIReleaseFrontSurface, ::switches::kEnablePinch, ::switches::kEnableSmoothScrolling, ::switches::kEnableThreadedCompositing, diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index b81e494..ac48efc 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -756,6 +756,7 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) { switches::kTraceStartup, switches::kV, switches::kVModule, + switches::kEnableUIReleaseFrontSurface, #if defined(USE_AURA) switches::kUIPrioritizeInGpuProcess, #endif diff --git a/content/browser/gpu/gpu_process_host_ui_shim.cc b/content/browser/gpu/gpu_process_host_ui_shim.cc index e8cd609..edef780 100644 --- a/content/browser/gpu/gpu_process_host_ui_shim.cc +++ b/content/browser/gpu/gpu_process_host_ui_shim.cc @@ -309,7 +309,11 @@ void GpuProcessHostUIShim::OnAcceleratedSurfaceNew( TransportDIB::Handle shm_handle = TransportDIB::DefaultHandleValue(); view->AcceleratedSurfaceNew( - params.width, params.height, &surface_handle, &shm_handle); + params.width, + params.height, + &surface_handle, + &shm_handle, + params.route_id); delayed_send.Cancel(); Send(new AcceleratedSurfaceMsg_NewACK( params.route_id, surface_handle, shm_handle)); diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 069ece8..771e5c4 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -1859,6 +1859,21 @@ void RenderWidgetHostImpl::AcknowledgePostSubBuffer(int32 route_id, ui_shim->Send(new AcceleratedSurfaceMsg_PostSubBufferACK(route_id)); } +#if defined(USE_AURA) +// static +void RenderWidgetHostImpl::SendFrontSurfaceIsProtected( + bool is_protected, + uint32 protection_state_id, + int32 route_id, + int gpu_host_id) { + GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(gpu_host_id); + if (ui_shim) { + ui_shim->Send(new AcceleratedSurfaceMsg_SetFrontSurfaceIsProtected( + route_id, is_protected, protection_state_id)); + } +} +#endif + void RenderWidgetHostImpl::DelayedAutoResized() { gfx::Size new_size = new_auto_size_; // Clear the new_auto_size_ since the empty value is used as a flag to diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index e0ca4c5..0e8e432 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -156,6 +156,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, // having been hidden. void WasHidden(); void WasRestored(); + bool IsHidden() const { return is_hidden_; } // Called to notify the RenderWidget that its associated native window got // focused. @@ -360,6 +361,16 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, static void AcknowledgeSwapBuffers(int32 route_id, int gpu_host_id); static void AcknowledgePostSubBuffer(int32 route_id, int gpu_host_id); +#if defined(USE_AURA) + // Called by the view in response to visibility changes once the front surface + // is no longer in use by the ui (false), or when we expect to have a valid + // front surface for use by the ui (true). + static void SendFrontSurfaceIsProtected(bool is_protected, + uint32 protection_state_id, + int32 route_id, + int gpu_host_id); +#endif + // Signals that the compositing surface was updated, e.g. after a lost context // event. void CompositingSurfaceUpdated(); 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 a2a3608..515e9f9 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_aura.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) { @@ -271,15 +282,32 @@ RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const { } void RenderWidgetHostViewAura::DidBecomeSelected() { + if (!host_->IsHidden()) + 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_->IsHidden()) + return; + host_->WasHidden(); + released_front_lock_ = NULL; + + if (ShouldReleaseFrontSurface()) { + current_surface_ = 0; + UpdateExternalTexture(); + } + + AdjustSurfaceProtection(); } void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) { @@ -473,11 +501,18 @@ 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::OnAcceleratedCompositingStateChange() { @@ -494,14 +529,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(); @@ -538,6 +573,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(); } } @@ -545,36 +592,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.skip_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.skip_ack) + released_front_lock_ = NULL; + 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.skip_ack) { + 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.skip_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); + } } } } @@ -582,7 +655,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(); @@ -592,6 +676,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(); @@ -638,7 +724,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)); @@ -649,10 +736,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(); @@ -660,6 +751,45 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceRelease( image_transport_clients_.erase(surface_handle); } +void RenderWidgetHostViewAura::SetSurfaceNotInUseByCompositor() { + if (current_surface_ || !host_->IsHidden()) + 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_->IsHidden() || + (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::CopyFromCompositingSurfaceFinished( + base::Callback<void(bool)> callback, bool result) { + --pending_thumbnail_tasks_; + AdjustSurfaceProtection(); + callback.Run(result); +} + void RenderWidgetHostViewAura::SetBackground(const SkBitmap& background) { content::RenderWidgetHostViewBase::SetBackground(background); host_->SetBackground(background); @@ -1206,6 +1336,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(); diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 53268d3..2157b6e 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -12,6 +12,7 @@ #include "base/callback.h" #include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "content/browser/renderer_host/image_transport_factory.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/common/content_export.h" @@ -52,7 +53,8 @@ class RenderWidgetHostViewAura public ui::TextInputClient, public aura::WindowDelegate, public aura::client::ActivationDelegate, - public ImageTransportFactoryObserver { + public ImageTransportFactoryObserver, + public base::SupportsWeakPtr<RenderWidgetHostViewAura> { public: // RenderWidgetHostView implementation. virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE; @@ -116,7 +118,8 @@ class RenderWidgetHostViewAura int32 width_in_pixel, int32 height_in_pixel, uint64* surface_id, - TransportDIB::Handle* surface_handle) OVERRIDE; + TransportDIB::Handle* surface_handle, + int32 route_id) OVERRIDE; virtual void AcceleratedSurfaceRelease(uint64 surface_id) OVERRIDE; virtual void GetScreenInfo(WebKit::WebScreenInfo* results) OVERRIDE; virtual gfx::Rect GetRootWindowBounds() OVERRIDE; @@ -228,6 +231,22 @@ class RenderWidgetHostViewAura // Called when window_ is removed from the window tree. void RemovingFromRootWindow(); + // After resetting |current_surface_|, we must wait for any compositor pending + // draws finish to be sure the old surface is not in use. This is the callback + // that waits for OnCompositingEnded in such a case. + void SetSurfaceNotInUseByCompositor(); + + // This is called every time |current_surface_| usage changes (by thumbnailer, + // compositor draws, and tab visibility). Every time usage of current surface + // changes between "may be used" and "certain to not be used" by the ui, we + // inform the gpu process. + void AdjustSurfaceProtection(); + + // Called after async thumbnailer task completes. Used to call + // AdjustSurfaceProtection. + void CopyFromCompositingSurfaceFinished(base::Callback<void(bool)> callback, + bool result); + ui::Compositor* GetCompositor(); // Detaches |this| from the input method object. @@ -289,6 +308,20 @@ class RenderWidgetHostViewAura uint64 current_surface_; + // Protected means that the |current_surface_| may be in use by ui and cannot + // be safely discarded. Things to consider are thumbnailer, compositor draw + // pending, and tab visibility. + bool current_surface_is_protected_; + bool current_surface_in_use_by_compositor_; + + int pending_thumbnail_tasks_; + + // This id increments every time surface_is_protected changes. + // Keeps gpu/browser IPC messages relying on protection state in sync. + uint32 protection_state_id_; + + int32 surface_route_id_; + gfx::GLSurfaceHandle shared_surface_handle_; // If non-NULL we're in OnPaint() and this is the supplied canvas. diff --git a/content/browser/renderer_host/test_render_view_host.h b/content/browser/renderer_host/test_render_view_host.h index 56f474f..c0a9e03 100644 --- a/content/browser/renderer_host/test_render_view_host.h +++ b/content/browser/renderer_host/test_render_view_host.h @@ -148,7 +148,7 @@ class TestRenderWidgetHostView : public RenderWidgetHostViewBase { #if defined(USE_AURA) virtual void AcceleratedSurfaceNew( int32 width, int32 height, uint64* surface_id, - TransportDIB::Handle* surface_handle) OVERRIDE { } + TransportDIB::Handle* surface_handle, int32 route_id) OVERRIDE { } virtual void AcceleratedSurfaceRelease(uint64 surface_id) OVERRIDE { } #endif diff --git a/content/common/gpu/gpu_memory_manager_unittest.cc b/content/common/gpu/gpu_memory_manager_unittest.cc index 0e861aa..8a9a4fd 100644 --- a/content/common/gpu/gpu_memory_manager_unittest.cc +++ b/content/common/gpu/gpu_memory_manager_unittest.cc @@ -41,8 +41,6 @@ class FakeCommandBufferStub : public GpuCommandBufferStubBase { const GpuCommandBufferStubBase& stub) const { return false; } - virtual void SendMemoryAllocationToProxy(const GpuMemoryAllocation& alloc) { - } virtual void SetMemoryAllocation(const GpuMemoryAllocation& alloc) { allocation_ = alloc; } @@ -77,8 +75,6 @@ class FakeCommandBufferStubWithoutSurface : public GpuCommandBufferStubBase { share_group_.end(), &stub) != share_group_.end(); } - virtual void SendMemoryAllocationToProxy(const GpuMemoryAllocation& alloc) { - } virtual void SetMemoryAllocation(const GpuMemoryAllocation& alloc) { allocation_ = alloc; } diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h index 3d61a72..ddaaff1 100644 --- a/content/common/gpu/gpu_messages.h +++ b/content/common/gpu/gpu_messages.h @@ -58,6 +58,8 @@ IPC_STRUCT_BEGIN(GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params) #elif defined(OS_MACOSX) IPC_STRUCT_MEMBER(gfx::PluginWindowHandle, window) #endif + IPC_STRUCT_MEMBER(uint32, protection_state_id) + IPC_STRUCT_MEMBER(bool, skip_ack) IPC_STRUCT_END() #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT @@ -73,6 +75,7 @@ IPC_STRUCT_BEGIN(GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params) #if defined(OS_MACOSX) IPC_STRUCT_MEMBER(gfx::PluginWindowHandle, window) #endif + IPC_STRUCT_MEMBER(uint32, protection_state_id) IPC_STRUCT_END() IPC_STRUCT_BEGIN(GpuHostMsg_AcceleratedSurfaceRelease_Params) @@ -201,6 +204,11 @@ IPC_MESSAGE_ROUTED2(AcceleratedSurfaceMsg_NewACK, uint64 /* surface_handle */, TransportDIB::Handle /* shared memory buffer */) +// Tells the GPU process if it's worth suggesting release of the front surface. +IPC_MESSAGE_ROUTED2(AcceleratedSurfaceMsg_SetFrontSurfaceIsProtected, + bool /* is_protected */, + uint32 /* protection_state_id */) + // Tells the GPU process that the browser process handled the swap // buffers request. IPC_MESSAGE_ROUTED0(AcceleratedSurfaceMsg_BuffersSwappedACK) diff --git a/content/common/gpu/image_transport_surface.cc b/content/common/gpu/image_transport_surface.cc index 7e49b9f..4ab12d4 100644 --- a/content/common/gpu/image_transport_surface.cc +++ b/content/common/gpu/image_transport_surface.cc @@ -21,6 +21,10 @@ ImageTransportSurface::ImageTransportSurface() {} ImageTransportSurface::~ImageTransportSurface() {} +void ImageTransportSurface::OnSetFrontSurfaceIsProtected( + bool is_protected, uint32 protection_state_id) { +} + void ImageTransportSurface::GetRegionsToCopy( const gfx::Rect& previous_damage_rect, const gfx::Rect& new_damage_rect, @@ -96,6 +100,8 @@ bool ImageTransportHelper::OnMessageReceived(const IPC::Message& message) { OnPostSubBufferACK) IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_NewACK, OnNewSurfaceACK) + IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_SetFrontSurfaceIsProtected, + OnSetFrontSurfaceIsProtected) IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_ResizeViewACK, OnResizeViewACK); IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -201,6 +207,11 @@ void ImageTransportHelper::OnNewSurfaceACK( surface_->OnNewSurfaceACK(surface_handle, shm_handle); } +void ImageTransportHelper::OnSetFrontSurfaceIsProtected( + bool is_protected, uint32 protection_state_id) { + surface_->OnSetFrontSurfaceIsProtected(is_protected, protection_state_id); +} + void ImageTransportHelper::OnBuffersSwappedACK() { surface_->OnBuffersSwappedACK(); } diff --git a/content/common/gpu/image_transport_surface.h b/content/common/gpu/image_transport_surface.h index 019aa50..936f40d 100644 --- a/content/common/gpu/image_transport_surface.h +++ b/content/common/gpu/image_transport_surface.h @@ -67,6 +67,8 @@ class ImageTransportSurface { virtual void OnPostSubBufferACK() = 0; virtual void OnResizeViewACK() = 0; virtual void OnResize(gfx::Size size) = 0; + virtual void OnSetFrontSurfaceIsProtected(bool is_protected, + uint32 protection_state_id); // Creates the appropriate surface depending on the GL implementation. static scoped_refptr<gfx::GLSurface> @@ -138,6 +140,8 @@ class ImageTransportHelper : public IPC::Channel::Listener { void OnBuffersSwappedACK(); void OnPostSubBufferACK(); void OnResizeViewACK(); + void OnSetFrontSurfaceIsProtected(bool is_protected, + uint32 protection_state_id); // Backbuffer resize callback. void Resize(gfx::Size size); diff --git a/content/common/gpu/texture_image_transport_surface.cc b/content/common/gpu/texture_image_transport_surface.cc index ec81bbc..e5fd148 100644 --- a/content/common/gpu/texture_image_transport_surface.cc +++ b/content/common/gpu/texture_image_transport_surface.cc @@ -69,6 +69,8 @@ TextureImageTransportSurface::TextureImageTransportSurface( stub_destroyed_(false), backbuffer_suggested_allocation_(true), frontbuffer_suggested_allocation_(true), + frontbuffer_is_protected_(true), + protection_state_id_(0), handle_(handle), parent_stub_(NULL) { helper_.reset(new ImageTransportHelper(this, @@ -182,16 +184,36 @@ void TextureImageTransportSurface::SetBackbufferAllocation(bool allocation) { if (!helper_->MakeCurrent()) return; - if (backbuffer_suggested_allocation_) + if (backbuffer_suggested_allocation_) { + DCHECK(!textures_[back()].info->service_id() || + !textures_[back()].sent_to_client); CreateBackTexture(textures_[back()].size); - else - ReleaseBackTexture(); + } else { + ReleaseTexture(back()); + } } void TextureImageTransportSurface::SetFrontbufferAllocation(bool allocation) { if (frontbuffer_suggested_allocation_ == allocation) return; frontbuffer_suggested_allocation_ = allocation; + AdjustFrontBufferAllocation(); +} + +void TextureImageTransportSurface::AdjustFrontBufferAllocation() { + if (!helper_->MakeCurrent()) + return; + + if (!frontbuffer_suggested_allocation_ && !frontbuffer_is_protected_ && + textures_[front()].info->service_id()) { + ReleaseTexture(front()); + if (textures_[front()].sent_to_client) { + GpuHostMsg_AcceleratedSurfaceRelease_Params params; + params.identifier = textures_[front()].client_id; + helper_->SendAcceleratedSurfaceRelease(params); + textures_[front()].sent_to_client = false; + } + } } void* TextureImageTransportSurface::GetShareHandle() { @@ -232,7 +254,7 @@ void TextureImageTransportSurface::OnWillDestroyStub( bool TextureImageTransportSurface::SwapBuffers() { DCHECK(backbuffer_suggested_allocation_); - if (!frontbuffer_suggested_allocation_) + if (!frontbuffer_suggested_allocation_ || !frontbuffer_is_protected_) return true; if (!parent_stub_) { LOG(ERROR) << "SwapBuffers failed because no parent stub."; @@ -241,12 +263,14 @@ bool TextureImageTransportSurface::SwapBuffers() { glFlush(); front_ = back(); - previous_damage_rect_ = gfx::Rect(textures_[front_].size); + previous_damage_rect_ = gfx::Rect(textures_[front()].size); - DCHECK(textures_[front_].client_id != 0); + DCHECK(textures_[front()].client_id != 0); GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; - params.surface_handle = textures_[front_].client_id; + params.surface_handle = textures_[front()].client_id; + params.protection_state_id = protection_state_id_; + params.skip_ack = false; helper_->SendAcceleratedSurfaceBuffersSwapped(params); helper_->SetScheduled(false); return true; @@ -255,32 +279,30 @@ bool TextureImageTransportSurface::SwapBuffers() { bool TextureImageTransportSurface::PostSubBuffer( int x, int y, int width, int height) { DCHECK(backbuffer_suggested_allocation_); - if (!frontbuffer_suggested_allocation_) + DCHECK(textures_[back()].info->service_id()); + if (!frontbuffer_suggested_allocation_ || !frontbuffer_is_protected_) return true; // If we are recreating the frontbuffer with this swap, make sure we are // drawing a full frame. - DCHECK(textures_[front_].info->service_id() || + DCHECK(textures_[front()].info->service_id() || (!x && !y && gfx::Size(width, height) == textures_[back()].size)); if (!parent_stub_) { LOG(ERROR) << "PostSubBuffer failed because no parent stub."; return false; } - DCHECK(textures_[back()].info); - int back_texture_service_id = textures_[back()].info->service_id(); - - DCHECK(textures_[front_].info); - int front_texture_service_id = textures_[front_].info->service_id(); - - gfx::Size expected_size = textures_[back()].size; - bool surfaces_same_size = textures_[front_].size == expected_size; - const gfx::Rect new_damage_rect(x, y, width, height); // An empty damage rect is a successful no-op. if (new_damage_rect.IsEmpty()) return true; + int back_texture_service_id = textures_[back()].info->service_id(); + int front_texture_service_id = textures_[front()].info->service_id(); + + gfx::Size expected_size = textures_[back()].size; + bool surfaces_same_size = textures_[front()].size == expected_size; + if (surfaces_same_size) { std::vector<gfx::Rect> regions_to_copy; GetRegionsToCopy(previous_damage_rect_, new_damage_rect, ®ions_to_copy); @@ -307,17 +329,19 @@ bool TextureImageTransportSurface::PostSubBuffer( glFlush(); front_ = back(); + previous_damage_rect_ = new_damage_rect; + + DCHECK(textures_[front()].client_id); GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; - params.surface_handle = textures_[front_].client_id; + params.surface_handle = textures_[front()].client_id; params.x = x; params.y = y; params.width = width; params.height = height; + params.protection_state_id = protection_state_id_; helper_->SendAcceleratedSurfacePostSubBuffer(params); helper_->SetScheduled(false); - - previous_damage_rect_ = new_damage_rect; return true; } @@ -342,10 +366,35 @@ void TextureImageTransportSurface::OnNewSurfaceACK( uint64 surface_handle, TransportDIB::Handle /*shm_handle*/) { } +void TextureImageTransportSurface::OnSetFrontSurfaceIsProtected( + bool is_protected, uint32 protection_state_id) { + protection_state_id_ = protection_state_id; + if (frontbuffer_is_protected_ == is_protected) + return; + frontbuffer_is_protected_ = is_protected; + AdjustFrontBufferAllocation(); + + // If surface is set to protected, and we haven't actually released it yet, + // we can set the ui surface handle now just by sending a swap message. + if (is_protected && textures_[front()].info->service_id() && + textures_[front()].sent_to_client) { + GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; + params.surface_handle = textures_[front()].client_id; + params.protection_state_id = protection_state_id_; + params.skip_ack = true; + helper_->SendAcceleratedSurfaceBuffersSwapped(params); + } +} + void TextureImageTransportSurface::OnBuffersSwappedACK() { if (helper_->MakeCurrent()) { - if (textures_[front_].size != textures_[back()].size) { - CreateBackTexture(textures_[front_].size); + if (textures_[front()].size != textures_[back()].size || + !textures_[back()].info->service_id() || + !textures_[back()].sent_to_client) { + // We may get an ACK from a stale swap just to reschedule. In that case, + // we may not have a backbuffer suggestion and should not recreate one. + if (backbuffer_suggested_allocation_) + CreateBackTexture(textures_[front()].size); } else { AttachBackTextureToFBO(); } @@ -364,10 +413,11 @@ void TextureImageTransportSurface::OnResizeViewACK() { NOTREACHED(); } -void TextureImageTransportSurface::ReleaseBackTexture() { +void TextureImageTransportSurface::ReleaseTexture(int id) { if (!parent_stub_) return; - TextureInfo* info = textures_[back()].info; + Texture& texture = textures_[id]; + TextureInfo* info = texture.info; DCHECK(info); GLuint service_id = info->service_id(); @@ -392,7 +442,7 @@ void TextureImageTransportSurface::CreateBackTexture(const gfx::Size& size) { GLuint service_id = info->service_id(); - if (service_id && texture.size == size) + if (service_id && texture.size == size && texture.sent_to_client) return; if (!service_id) { @@ -443,13 +493,14 @@ void TextureImageTransportSurface::CreateBackTexture(const gfx::Size& size) { void TextureImageTransportSurface::AttachBackTextureToFBO() { if (!parent_stub_) return; - DCHECK(textures_[back()].info); + TextureInfo* info = textures_[back()].info; + DCHECK(info); ScopedFrameBufferBinder fbo_binder(fbo_id_); glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - textures_[back()].info->service_id(), + info->service_id(), 0); glFlush(); CHECK_GL_ERROR(); diff --git a/content/common/gpu/texture_image_transport_surface.h b/content/common/gpu/texture_image_transport_surface.h index 907bfa4..82869e7 100644 --- a/content/common/gpu/texture_image_transport_surface.h +++ b/content/common/gpu/texture_image_transport_surface.h @@ -48,6 +48,9 @@ class TextureImageTransportSurface : virtual void OnBuffersSwappedACK() OVERRIDE; virtual void OnPostSubBufferACK() OVERRIDE; virtual void OnResizeViewACK() OVERRIDE; + virtual void OnSetFrontSurfaceIsProtected( + bool is_protected, + uint32 protection_state_id) OVERRIDE; virtual void OnResize(gfx::Size size) OVERRIDE; // GpuCommandBufferStub::DestructionObserver implementation. @@ -74,9 +77,11 @@ class TextureImageTransportSurface : virtual ~TextureImageTransportSurface(); void CreateBackTexture(const gfx::Size& size); - void ReleaseBackTexture(); void AttachBackTextureToFBO(); + void ReleaseTexture(int id); void ReleaseParentStub(); + void AdjustFrontBufferAllocation(); + int front() const { return front_; } int back() const { return 1 - front_; } // The framebuffer that represents this surface (service id). Allocated lazily @@ -97,6 +102,9 @@ class TextureImageTransportSurface : bool backbuffer_suggested_allocation_; bool frontbuffer_suggested_allocation_; + bool frontbuffer_is_protected_; + uint32 protection_state_id_; + scoped_ptr<ImageTransportHelper> helper_; gfx::GLSurfaceHandle handle_; GpuCommandBufferStub* parent_stub_; diff --git a/content/port/browser/render_widget_host_view_port.h b/content/port/browser/render_widget_host_view_port.h index 3578a96..7cac201 100644 --- a/content/port/browser/render_widget_host_view_port.h +++ b/content/port/browser/render_widget_host_view_port.h @@ -220,7 +220,8 @@ class CONTENT_EXPORT RenderWidgetHostViewPort : public RenderWidgetHostView { int32 width_in_pixel, int32 height_in_pixel, uint64* surface_id, - TransportDIB::Handle* surface_handle) = 0; + TransportDIB::Handle* surface_handle, + int32 route_id) = 0; virtual void AcceleratedSurfaceRelease(uint64 surface_id) = 0; #endif diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 1ae248c..c279c76 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc @@ -303,6 +303,10 @@ const char kEnableOriginBoundCerts[] = "enable-origin-bound-certs"; // Enables partial swaps in the WK compositor on platforms that support it. const char kEnablePartialSwap[] = "enable-partial-swap"; +// Enables UI releasing handle to front surface for background tabs on platforms +// that support it. +const char kEnableUIReleaseFrontSurface[] = "enable-ui-release-front-surface"; + // Enables touch-screen pinch gestures. const char kEnablePinch[] = "enable-pinch"; diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index b9dfd35..ae7e1f3 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h @@ -103,6 +103,7 @@ extern const char kEnablePeerConnection[]; extern const char kEnableMonitorProfile[]; extern const char kEnableOriginBoundCerts[]; extern const char kEnablePartialSwap[]; +extern const char kEnableUIReleaseFrontSurface[]; extern const char kEnablePinch[]; extern const char kEnablePreparsedJsCaching[]; CONTENT_EXPORT extern const char kEnablePrivilegedWebGLExtensions[]; |