diff options
author | ccameron@chromium.org <ccameron@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-05 18:50:12 +0000 |
---|---|---|
committer | ccameron@chromium.org <ccameron@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-05 18:50:12 +0000 |
commit | 30ca75e25a30803e11bfa0673556dcb6731adeca (patch) | |
tree | c9dfefd740749e98893f7603c6ff908b8f7b0b6c | |
parent | b9c26780e3d0637b920de98a0a7b6d2bad544fbc (diff) | |
download | chromium_src-30ca75e25a30803e11bfa0673556dcb6731adeca.zip chromium_src-30ca75e25a30803e11bfa0673556dcb6731adeca.tar.gz chromium_src-30ca75e25a30803e11bfa0673556dcb6731adeca.tar.bz2 |
Merge 265842 "CoreAnimation: Evict IOSurfaces after use"
> CoreAnimation: Evict IOSurfaces after use
>
> CoreAnimation stores contents in CALayers, so it is
> not necessary to keep around IOSurfaces after they
> have been drawn (except in the case of being
> backgrounded and then made visible again).
>
> Discard these IOSurfaces if we have more than 8 of
> them around. Only discard surfaces when they have
> been drawn and the have no pending copy requests.
>
> This relieves an increase in virtual address space used
> by CoreAnimation.
>
> Also move where size and scale factor are assigned so
> that the size of the IOSurface can be un-set when it
> is freed.
>
> BUG=364808
>
> Review URL: https://codereview.chromium.org/243133008
TBR=ccameron@chromium.org
Review URL: https://codereview.chromium.org/266273002
git-svn-id: svn://svn.chromium.org/chrome/branches/1916/src@268233 0039d316-1c4b-4281-b951-d872f2087c98
4 files changed, 123 insertions, 13 deletions
diff --git a/content/browser/renderer_host/compositing_iosurface_layer_mac.mm b/content/browser/renderer_host/compositing_iosurface_layer_mac.mm index 08d3d4d..eaa8bbb 100644 --- a/content/browser/renderer_host/compositing_iosurface_layer_mac.mm +++ b/content/browser/renderer_host/compositing_iosurface_layer_mac.mm @@ -116,7 +116,8 @@ if (!context_ || (context_ && context_->cgl_context() != glContext) || !renderWidgetHostView_ || - !renderWidgetHostView_->compositing_iosurface_) { + !renderWidgetHostView_->compositing_iosurface_ || + !renderWidgetHostView_->compositing_iosurface_->HasIOSurface()) { glClearColor(1, 1, 1, 1); glClear(GL_COLOR_BUFFER_BIT); return; diff --git a/content/browser/renderer_host/compositing_iosurface_mac.h b/content/browser/renderer_host/compositing_iosurface_mac.h index 78401ab..db228089 100644 --- a/content/browser/renderer_host/compositing_iosurface_mac.h +++ b/content/browser/renderer_host/compositing_iosurface_mac.h @@ -6,12 +6,14 @@ #define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_ #include <deque> +#include <list> #include <vector> #import <Cocoa/Cocoa.h> #include <QuartzCore/QuartzCore.h> #include "base/callback.h" +#include "base/lazy_instance.h" #include "base/mac/scoped_cftyperef.h" #include "base/memory/scoped_ptr.h" #include "base/time/time.h" @@ -213,6 +215,8 @@ class CompositingIOSurfaceMac { // Returns true if IOSurface is ready to render. False otherwise. bool MapIOSurfaceToTextureWithContextCurrent( const scoped_refptr<CompositingIOSurfaceContext>& current_context, + const gfx::Size pixel_size, + float scale_factor, uint64 io_surface_handle) WARN_UNUSED_RESULT; void UnrefIOSurfaceWithContextCurrent(); @@ -303,6 +307,26 @@ class CompositingIOSurfaceMac { // Error saved by GetAndSaveGLError GLint gl_error_; + + // Aggressive IOSurface eviction logic. When using CoreAnimation, IOSurfaces + // are used only transiently to transfer from the GPU process to the browser + // process. Once the IOSurface has been drawn to its CALayer, the CALayer + // will not need updating again until its view is hidden and re-shown. + // Aggressively evict surfaces when more than 8 (the number allowed by the + // memory manager for fast tab switching) are allocated. + enum { + kMaximumUnevictedSurfaces = 8, + }; + typedef std::list<CompositingIOSurfaceMac*> EvictionQueue; + void EvictionMarkUpdated(); + void EvictionMarkEvicted(); + EvictionQueue::iterator eviction_queue_iterator_; + bool eviction_has_been_drawn_since_updated_; + + static void EvictionScheduleDoEvict(); + static void EvictionDoEvict(); + static base::LazyInstance<EvictionQueue> eviction_queue_; + static bool eviction_scheduled_; }; } // namespace content diff --git a/content/browser/renderer_host/compositing_iosurface_mac.mm b/content/browser/renderer_host/compositing_iosurface_mac.mm index 45f4758..d3574c7 100644 --- a/content/browser/renderer_host/compositing_iosurface_mac.mm +++ b/content/browser/renderer_host/compositing_iosurface_mac.mm @@ -253,7 +253,9 @@ CompositingIOSurfaceMac::CompositingIOSurfaceMac( base::Unretained(this), false), true), - gl_error_(GL_NO_ERROR) { + gl_error_(GL_NO_ERROR), + eviction_queue_iterator_(eviction_queue_.Get().end()), + eviction_has_been_drawn_since_updated_(false) { CHECK(offscreen_context_); } @@ -266,6 +268,7 @@ CompositingIOSurfaceMac::~CompositingIOSurfaceMac() { UnrefIOSurfaceWithContextCurrent(); } offscreen_context_ = NULL; + DCHECK(eviction_queue_iterator_ == eviction_queue_.Get().end()); } bool CompositingIOSurfaceMac::SetIOSurfaceWithContextCurrent( @@ -273,12 +276,9 @@ bool CompositingIOSurfaceMac::SetIOSurfaceWithContextCurrent( uint64 io_surface_handle, const gfx::Size& size, float scale_factor) { - pixel_io_surface_size_ = size; - scale_factor_ = scale_factor; - dip_io_surface_size_ = gfx::ToFlooredSize( - gfx::ScaleSize(pixel_io_surface_size_, 1.0 / scale_factor_)); bool result = MapIOSurfaceToTextureWithContextCurrent( - current_context, io_surface_handle); + current_context, size, scale_factor, io_surface_handle); + EvictionMarkUpdated(); return result; } @@ -401,6 +401,7 @@ bool CompositingIOSurfaceMac::DrawIOSurface( glGetError(); } + eviction_has_been_drawn_since_updated_ = true; return result; } @@ -475,12 +476,24 @@ base::Closure CompositingIOSurfaceMac::CopyToVideoFrameWithinContext( bool CompositingIOSurfaceMac::MapIOSurfaceToTextureWithContextCurrent( const scoped_refptr<CompositingIOSurfaceContext>& current_context, + const gfx::Size pixel_size, + float scale_factor, uint64 io_surface_handle) { - if (io_surface_.get() && io_surface_handle == io_surface_handle_) - return true; - TRACE_EVENT0("browser", "CompositingIOSurfaceMac::MapIOSurfaceToTexture"); - UnrefIOSurfaceWithContextCurrent(); + + if (!io_surface_ || io_surface_handle != io_surface_handle_) + UnrefIOSurfaceWithContextCurrent(); + + pixel_io_surface_size_ = pixel_size; + scale_factor_ = scale_factor; + dip_io_surface_size_ = gfx::ToFlooredSize( + gfx::ScaleSize(pixel_io_surface_size_, 1.0 / scale_factor_)); + + // Early-out if the IOSurface has not changed. Note that because IOSurface + // sizes are rounded, the same IOSurface may have two different sizes + // associated with it. + if (io_surface_ && io_surface_handle == io_surface_handle_) + return true; io_surface_.reset(io_surface_support_->IOSurfaceLookup( static_cast<uint32>(io_surface_handle))); @@ -555,13 +568,17 @@ void CompositingIOSurfaceMac::UnrefIOSurfaceWithContextCurrent() { glDeleteTextures(1, &texture_); texture_ = 0; } - + pixel_io_surface_size_ = gfx::Size(); + scale_factor_ = 1; + dip_io_surface_size_ = gfx::Size(); io_surface_.reset(); // Forget the ID, because even if it is still around when we want to use it // again, OSX may have reused the same ID for a new tab and we don't want to // blit random tab contents. io_surface_handle_ = 0; + + EvictionMarkEvicted(); } bool CompositingIOSurfaceMac::IsAsynchronousReadbackSupported() { @@ -918,4 +935,70 @@ GLenum CompositingIOSurfaceMac::GetAndSaveGLError() { return gl_error; } +void CompositingIOSurfaceMac::EvictionMarkUpdated() { + EvictionMarkEvicted(); + eviction_queue_.Get().push_back(this); + eviction_queue_iterator_ = --eviction_queue_.Get().end(); + eviction_has_been_drawn_since_updated_ = false; + EvictionScheduleDoEvict(); +} + +void CompositingIOSurfaceMac::EvictionMarkEvicted() { + if (eviction_queue_iterator_ == eviction_queue_.Get().end()) + return; + eviction_queue_.Get().erase(eviction_queue_iterator_); + eviction_queue_iterator_ = eviction_queue_.Get().end(); + eviction_has_been_drawn_since_updated_ = false; +} + +// static +void CompositingIOSurfaceMac::EvictionScheduleDoEvict() { + if (GetCoreAnimationStatus() == CORE_ANIMATION_DISABLED) + return; + if (eviction_scheduled_) + return; + if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces) + return; + + eviction_scheduled_ = true; + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&CompositingIOSurfaceMac::EvictionDoEvict)); +} + +// static +void CompositingIOSurfaceMac::EvictionDoEvict() { + eviction_scheduled_ = false; + // Walk the list of allocated surfaces from least recently used to most + // recently used. + for (EvictionQueue::iterator it = eviction_queue_.Get().begin(); + it != eviction_queue_.Get().end();) { + CompositingIOSurfaceMac* surface = *it; + ++it; + + // If the number of IOSurfaces allocated is less than the threshold, + // stop walking the list of surfaces. + if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces) + break; + + // Don't evict anything that has not yet been drawn. + if (!surface->eviction_has_been_drawn_since_updated_) + continue; + + // Don't evict anything with pending copy requests. + if (!surface->copy_requests_.empty()) + continue; + + // Evict the surface. + surface->UnrefIOSurface(); + } +} + +// static +base::LazyInstance<CompositingIOSurfaceMac::EvictionQueue> + CompositingIOSurfaceMac::eviction_queue_; + +// static +bool CompositingIOSurfaceMac::eviction_scheduled_ = false; + } // namespace content diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 9cdbc07..f807fa2 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm @@ -2268,7 +2268,9 @@ void RenderWidgetHostViewMac::LayoutLayers() { EnsureCompositedIOSurfaceLayer(); } } - if (compositing_iosurface_ && compositing_iosurface_layer_) { + if (compositing_iosurface_ && + compositing_iosurface_->HasIOSurface() && + compositing_iosurface_layer_) { CGRect layer_bounds = CGRectMake( 0, 0, |