Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / compositing_iosurface_mac.mm
index 07bd795..d3574c7 100644 (file)
 #include "base/mac/mac_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/threading/platform_thread.h"
+#include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
 #include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
 #include "content/browser/renderer_host/compositing_iosurface_transformer_mac.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_mac.h"
 #include "content/common/content_constants_internal.h"
-#include "content/port/browser/render_widget_host_view_frame_subscriber.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
 #include "media/base/video_util.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/rect.h"
 #else
 #define CHECK_GL_ERROR() do {                                           \
     GLenum gl_error = glGetError();                                     \
-    LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
+    LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error" << gl_error; \
   } while (0)
 #define CHECK_AND_SAVE_GL_ERROR() do {                                  \
     GLenum gl_error = GetAndSaveGLError();                              \
-    LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
+    LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error" << gl_error; \
   } while (0)
 #endif
 
@@ -157,18 +158,6 @@ bool MapBufferToVideoFrame(
 
 }  // namespace
 
-CVReturn DisplayLinkCallback(CVDisplayLinkRef display_link,
-                             const CVTimeStamp* now,
-                             const CVTimeStamp* output_time,
-                             CVOptionFlags flags_in,
-                             CVOptionFlags* flags_out,
-                             void* context) {
-  CompositingIOSurfaceMac* surface =
-      static_cast<CompositingIOSurfaceMac*>(context);
-  surface->DisplayLinkTick(display_link, output_time);
-  return kCVReturnSuccess;
-}
-
 CompositingIOSurfaceMac::CopyContext::CopyContext(
     const scoped_refptr<CompositingIOSurfaceContext>& context)
   : transformer(new CompositingIOSurfaceTransformer(
@@ -230,23 +219,30 @@ void CompositingIOSurfaceMac::CopyContext::PrepareForAsynchronousReadback() {
 
 
 // static
-CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create(
-    const scoped_refptr<CompositingIOSurfaceContext>& context) {
+CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create() {
   IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
   if (!io_surface_support) {
     LOG(ERROR) << "No IOSurface support";
     return NULL;
   }
 
+  scoped_refptr<CompositingIOSurfaceContext> offscreen_context =
+      CompositingIOSurfaceContext::Get(
+          CompositingIOSurfaceContext::kOffscreenContextWindowNumber);
+  if (!offscreen_context) {
+    LOG(ERROR) << "Failed to create context for offscreen operations";
+    return NULL;
+  }
+
   return new CompositingIOSurfaceMac(io_surface_support,
-                                     context);
+                                     offscreen_context);
 }
 
 CompositingIOSurfaceMac::CompositingIOSurfaceMac(
     IOSurfaceSupport* io_surface_support,
-    const scoped_refptr<CompositingIOSurfaceContext>& context)
+    const scoped_refptr<CompositingIOSurfaceContext>& offscreen_context)
     : io_surface_support_(io_surface_support),
-      context_(context),
+      offscreen_context_(offscreen_context),
       io_surface_handle_(0),
       scale_factor_(1.f),
       texture_(0),
@@ -257,117 +253,38 @@ CompositingIOSurfaceMac::CompositingIOSurfaceMac(
                      base::Unretained(this),
                      false),
           true),
-      display_link_(0),
-      display_link_stop_timer_(FROM_HERE, base::TimeDelta::FromSeconds(1),
-                               this, &CompositingIOSurfaceMac::StopDisplayLink),
-      vsync_interval_numerator_(0),
-      vsync_interval_denominator_(0),
-      initialized_is_intel_(false),
-      is_intel_(false),
-      screen_(0),
-      gl_error_(GL_NO_ERROR) {
-  CHECK(context_);
-}
-
-void CompositingIOSurfaceMac::SetupCVDisplayLink() {
-  if (display_link_) {
-    LOG(ERROR) << "DisplayLink already setup";
-    return;
-  }
-
-  CVDisplayLinkRef display_link;
-  CVReturn ret = CVDisplayLinkCreateWithActiveCGDisplays(&display_link);
-  if (ret != kCVReturnSuccess) {
-    LOG(WARNING) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret;
-    return;
-  }
-
-  display_link_ = display_link;
-
-  ret = CVDisplayLinkSetOutputCallback(display_link_,
-                                       &DisplayLinkCallback, this);
-  DCHECK(ret == kCVReturnSuccess)
-      << "CVDisplayLinkSetOutputCallback failed: " << ret;
-
-  StartOrContinueDisplayLink();
-
-  CVTimeStamp cv_time;
-  ret = CVDisplayLinkGetCurrentTime(display_link_, &cv_time);
-  DCHECK(ret == kCVReturnSuccess)
-      << "CVDisplayLinkGetCurrentTime failed: " << ret;
-
-  {
-    base::AutoLock lock(lock_);
-    CalculateVsyncParametersLockHeld(&cv_time);
-  }
-
-  // Stop display link for now, it will be started when needed during Draw.
-  StopDisplayLink();
-}
-
-void CompositingIOSurfaceMac::SetContext(
-    const scoped_refptr<CompositingIOSurfaceContext>& new_context) {
-  CHECK(new_context);
-
-  if (context_ == new_context)
-    return;
-
-  // Asynchronous copies must complete in the same context they started in.
-  CheckIfAllCopiesAreFinished(true);
-  CGLSetCurrentContext(context_->cgl_context());
-  DestroyAllCopyContextsWithinContext();
-  CGLSetCurrentContext(0);
-
-  context_ = new_context;
-}
-
-bool CompositingIOSurfaceMac::is_vsync_disabled() const {
-  return context_->is_vsync_disabled();
-}
-
-void CompositingIOSurfaceMac::GetVSyncParameters(base::TimeTicks* timebase,
-                                                 uint32* interval_numerator,
-                                                 uint32* interval_denominator) {
-  base::AutoLock lock(lock_);
-  *timebase = vsync_timebase_;
-  *interval_numerator = vsync_interval_numerator_;
-  *interval_denominator = vsync_interval_denominator_;
+      gl_error_(GL_NO_ERROR),
+      eviction_queue_iterator_(eviction_queue_.Get().end()),
+      eviction_has_been_drawn_since_updated_(false) {
+  CHECK(offscreen_context_);
 }
 
 CompositingIOSurfaceMac::~CompositingIOSurfaceMac() {
   FailAllCopies();
-  CVDisplayLinkRelease(display_link_);
-  CGLSetCurrentContext(context_->cgl_context());
-  DestroyAllCopyContextsWithinContext();
-  UnrefIOSurfaceWithContextCurrent();
-  CGLSetCurrentContext(0);
-  context_ = NULL;
+  {
+    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+        offscreen_context_->cgl_context());
+    DestroyAllCopyContextsWithinContext();
+    UnrefIOSurfaceWithContextCurrent();
+  }
+  offscreen_context_ = NULL;
+  DCHECK(eviction_queue_iterator_ == eviction_queue_.Get().end());
 }
 
-bool CompositingIOSurfaceMac::SetIOSurface(
+bool CompositingIOSurfaceMac::SetIOSurfaceWithContextCurrent(
+    scoped_refptr<CompositingIOSurfaceContext> current_context,
     uint64 io_surface_handle,
     const gfx::Size& size,
-    float scale_factor,
-    const ui::LatencyInfo& latency_info) {
-  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_));
-
-  CGLError cgl_error = CGLSetCurrentContext(context_->cgl_context());
-  if (cgl_error != kCGLNoError) {
-    LOG(ERROR) << "CGLSetCurrentContext error in SetIOSurface: " << cgl_error;
-    return false;
-  }
-  bool result = MapIOSurfaceToTexture(io_surface_handle);
-  CGLSetCurrentContext(0);
-  latency_info_.MergeWith(latency_info);
+    float scale_factor) {
+  bool result = MapIOSurfaceToTextureWithContextCurrent(
+      current_context, size, scale_factor, io_surface_handle);
+  EvictionMarkUpdated();
   return result;
 }
 
 int CompositingIOSurfaceMac::GetRendererID() {
   GLint current_renderer_id = -1;
-  if (CGLGetParameter(context_->cgl_context(),
+  if (CGLGetParameter(offscreen_context_->cgl_context(),
                       kCGLCPCurrentRendererID,
                       &current_renderer_id) == kCGLNoError)
     return current_renderer_id & kCGLRendererIDMatchingMask;
@@ -375,22 +292,21 @@ int CompositingIOSurfaceMac::GetRendererID() {
 }
 
 bool CompositingIOSurfaceMac::DrawIOSurface(
-    const gfx::Size& window_size,
+    scoped_refptr<CompositingIOSurfaceContext> drawing_context,
+    const gfx::Rect& window_rect,
     float window_scale_factor,
-    RenderWidgetHostViewFrameSubscriber* frame_subscriber,
-    bool using_core_animation) {
-  bool result = true;
-
-  if (display_link_ == NULL)
-    SetupCVDisplayLink();
+    bool flush_drawable) {
+  DCHECK_EQ(CGLGetCurrentContext(), drawing_context->cgl_context());
 
   bool has_io_surface = HasIOSurface();
   TRACE_EVENT1("browser", "CompositingIOSurfaceMac::DrawIOSurface",
                "has_io_surface", has_io_surface);
 
-  gfx::Size pixel_window_size = gfx::ToFlooredSize(
-      gfx::ScaleSize(window_size, window_scale_factor));
-  glViewport(0, 0, pixel_window_size.width(), pixel_window_size.height());
+  gfx::Rect pixel_window_rect =
+      ToNearestRect(gfx::ScaleRect(window_rect, window_scale_factor));
+  glViewport(
+      pixel_window_rect.x(), pixel_window_rect.y(),
+      pixel_window_rect.width(), pixel_window_rect.height());
 
   SurfaceQuad quad;
   quad.set_size(dip_io_surface_size_, pixel_io_surface_size_);
@@ -399,9 +315,9 @@ bool CompositingIOSurfaceMac::DrawIOSurface(
   glLoadIdentity();
 
   // Note that the projection keeps things in view units, so the use of
-  // window_size / dip_io_surface_size_ (as opposed to the pixel_ variants)
+  // window_rect / dip_io_surface_size_ (as opposed to the pixel_ variants)
   // below is correct.
-  glOrtho(0, window_size.width(), window_size.height(), 0, -1, 1);
+  glOrtho(0, window_rect.width(), window_rect.height(), 0, -1, 1);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
 
@@ -409,7 +325,7 @@ bool CompositingIOSurfaceMac::DrawIOSurface(
   glDisable(GL_BLEND);
 
   if (has_io_surface) {
-    context_->shader_program_cache()->UseBlitProgram();
+    drawing_context->shader_program_cache()->UseBlitProgram();
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
 
@@ -418,21 +334,21 @@ bool CompositingIOSurfaceMac::DrawIOSurface(
     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
 
     // Fill the resize gutters with white.
-    if (window_size.width() > dip_io_surface_size_.width() ||
-        window_size.height() > dip_io_surface_size_.height()) {
-      context_->shader_program_cache()->UseSolidWhiteProgram();
+    if (window_rect.width() > dip_io_surface_size_.width() ||
+        window_rect.height() > dip_io_surface_size_.height()) {
+      drawing_context->shader_program_cache()->UseSolidWhiteProgram();
       SurfaceQuad filler_quad;
-      if (window_size.width() > dip_io_surface_size_.width()) {
+      if (window_rect.width() > dip_io_surface_size_.width()) {
         // Draw right-side gutter down to the bottom of the window.
         filler_quad.set_rect(dip_io_surface_size_.width(), 0.0f,
-                             window_size.width(), window_size.height());
+                             window_rect.width(), window_rect.height());
         DrawQuad(filler_quad);
       }
-      if (window_size.height() > dip_io_surface_size_.height()) {
+      if (window_rect.height() > dip_io_surface_size_.height()) {
         // Draw bottom gutter to the width of the IOSurface.
         filler_quad.set_rect(
             0.0f, dip_io_surface_size_.height(),
-            dip_io_surface_size_.width(), window_size.height());
+            dip_io_surface_size_.width(), window_rect.height());
         DrawQuad(filler_quad);
       }
     }
@@ -450,79 +366,42 @@ bool CompositingIOSurfaceMac::DrawIOSurface(
     glClear(GL_COLOR_BUFFER_BIT);
   }
 
-  static bool initialized_workaround = false;
-  static bool force_on_workaround = false;
-  static bool force_off_workaround = false;
-  if (!initialized_workaround) {
-    force_on_workaround = CommandLine::ForCurrentProcess()->HasSwitch(
-        switches::kForceGLFinishWorkaround);
-    force_off_workaround = CommandLine::ForCurrentProcess()->HasSwitch(
-        switches::kDisableGpuDriverBugWorkarounds);
-
-    initialized_workaround = true;
-  }
-
-  const bool workaround_needed =
-      IsVendorIntel() && !base::mac::IsOSMountainLionOrLater();
-  const bool use_glfinish_workaround =
-      (workaround_needed || force_on_workaround) && !force_off_workaround;
+  bool workaround_needed =
+      GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
+          gpu::FORCE_GL_FINISH_AFTER_COMPOSITING);
+  // Note that this is not necessary when flushing the drawable in Mavericks
+  // or later if we are in one of the two following situations:
+  // - we are drawing an underlay, and we will call glFinish() when drawing
+  //   the overlay.
+  // - we are using CoreAnimation, where this bug does not manifest.
+  if (workaround_needed && !flush_drawable && base::mac::IsOSMavericksOrLater())
+    workaround_needed = false;
 
-  if (use_glfinish_workaround) {
+  if (workaround_needed) {
     TRACE_EVENT0("gpu", "glFinish");
-    // http://crbug.com/123409 : work around bugs in graphics driver on
-    // MacBook Air with Intel HD graphics, and possibly on other models,
-    // by forcing the graphics pipeline to be completely drained at this
-    // point.
-    // This workaround is not necessary on Mountain Lion.
     glFinish();
   }
 
-  base::Closure copy_done_callback;
-  if (frame_subscriber) {
-    const base::Time present_time = base::Time::Now();
-    scoped_refptr<media::VideoFrame> frame;
-    RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
-    if (frame_subscriber->ShouldCaptureFrame(present_time, &frame, &callback)) {
-      copy_done_callback = CopyToVideoFrameWithinContext(
-          gfx::Rect(pixel_io_surface_size_), true, frame,
-          base::Bind(callback, present_time));
-    }
-  }
-
-  if (!using_core_animation) {
-    CGLError cgl_error =  CGLFlushDrawable(context_->cgl_context());
-    if (cgl_error != kCGLNoError) {
-      LOG(ERROR) << "CGLFlushDrawable error in DrawIOSurface: " << cgl_error;
-      result = false;
-    }
+  bool result = true;
+  if (flush_drawable) {
+    TRACE_EVENT0("gpu", "flushBuffer");
+    [drawing_context->nsgl_context() flushBuffer];
   }
 
-  latency_info_.AddLatencyNumber(
-      ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
-  RenderWidgetHostImpl::CompositorFrameDrawn(latency_info_);
-  latency_info_.Clear();
-
-  // Try to finish previous copy requests after flush to get better pipelining.
-  std::vector<base::Closure> copy_done_callbacks;
-  CheckIfAllCopiesAreFinishedWithinContext(false, &copy_done_callbacks);
-
   // Check if any of the drawing calls result in an error.
   GetAndSaveGLError();
   if (gl_error_ != GL_NO_ERROR) {
     LOG(ERROR) << "GL error in DrawIOSurface: " << gl_error_;
     result = false;
+    // If there was an error, clear the screen to a light grey to avoid
+    // rendering artifacts. If we're in a really bad way, this too may
+    // generate an error. Clear the GL error afterwards just in case.
+    glClearColor(0.8, 0.8, 0.8, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT);
+    glGetError();
   }
 
-  if (!using_core_animation)
-    CGLSetCurrentContext(0);
-
-  if (!copy_done_callback.is_null())
-    copy_done_callbacks.push_back(copy_done_callback);
-  for (size_t i = 0; i < copy_done_callbacks.size(); ++i)
-    copy_done_callbacks[i].Run();
-
-  StartOrContinueDisplayLink();
-
+  eviction_has_been_drawn_since_updated_ = true;
   return result;
 }
 
@@ -532,7 +411,11 @@ void CompositingIOSurfaceMac::CopyTo(
       const base::Callback<void(bool, const SkBitmap&)>& callback) {
   scoped_ptr<SkBitmap> output(new SkBitmap());
   output->setConfig(SkBitmap::kARGB_8888_Config,
-                    dst_pixel_size.width(), dst_pixel_size.height());
+                    dst_pixel_size.width(),
+                    dst_pixel_size.height(),
+                    0,
+                    kOpaque_SkAlphaType);
+
   if (!output->allocPixels()) {
     DLOG(ERROR) << "Failed to allocate SkBitmap pixels!";
     callback.Run(false, *output);
@@ -540,14 +423,16 @@ void CompositingIOSurfaceMac::CopyTo(
   }
   DCHECK_EQ(output->rowBytesAsPixels(), dst_pixel_size.width())
       << "Stride is required to be equal to width for GPU readback.";
-  output->setIsOpaque(true);
-
-  CGLSetCurrentContext(context_->cgl_context());
-  const base::Closure copy_done_callback = CopyToSelectedOutputWithinContext(
-      src_pixel_subrect, gfx::Rect(dst_pixel_size), false,
-      output.get(), NULL,
-      base::Bind(&ReverseArgumentOrder, callback, base::Passed(&output)));
-  CGLSetCurrentContext(0);
+
+  base::Closure copy_done_callback;
+  {
+    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+        offscreen_context_->cgl_context());
+    copy_done_callback = CopyToSelectedOutputWithinContext(
+        src_pixel_subrect, gfx::Rect(dst_pixel_size), false,
+        output.get(), NULL,
+        base::Bind(&ReverseArgumentOrder, callback, base::Passed(&output)));
+  }
   if (!copy_done_callback.is_null())
     copy_done_callback.Run();
 }
@@ -556,10 +441,13 @@ void CompositingIOSurfaceMac::CopyToVideoFrame(
     const gfx::Rect& src_pixel_subrect,
     const scoped_refptr<media::VideoFrame>& target,
     const base::Callback<void(bool)>& callback) {
-  CGLSetCurrentContext(context_->cgl_context());
-  const base::Closure copy_done_callback = CopyToVideoFrameWithinContext(
-      src_pixel_subrect, false, target, callback);
-  CGLSetCurrentContext(0);
+  base::Closure copy_done_callback;
+  {
+    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+        offscreen_context_->cgl_context());
+    copy_done_callback = CopyToVideoFrameWithinContext(
+        src_pixel_subrect, false, target, callback);
+  }
   if (!copy_done_callback.is_null())
     copy_done_callback.Run();
 }
@@ -586,13 +474,26 @@ base::Closure CompositingIOSurfaceMac::CopyToVideoFrameWithinContext(
       NULL, target, callback);
 }
 
-bool CompositingIOSurfaceMac::MapIOSurfaceToTexture(
+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)));
@@ -618,7 +519,7 @@ bool CompositingIOSurfaceMac::MapIOSurfaceToTexture(
   CHECK_AND_SAVE_GL_ERROR();
   GLuint plane = 0;
   CGLError cgl_error = io_surface_support_->CGLTexImageIOSurface2D(
-      context_->cgl_context(),
+      current_context->cgl_context(),
       GL_TEXTURE_RECTANGLE_ARB,
       GL_RGBA,
       rounded_size.width(),
@@ -643,12 +544,14 @@ bool CompositingIOSurfaceMac::MapIOSurfaceToTexture(
 }
 
 void CompositingIOSurfaceMac::UnrefIOSurface() {
-  CGLSetCurrentContext(context_->cgl_context());
+  gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+      offscreen_context_->cgl_context());
   UnrefIOSurfaceWithContextCurrent();
-  CGLSetCurrentContext(0);
 }
 
 void CompositingIOSurfaceMac::DrawQuad(const SurfaceQuad& quad) {
+  TRACE_EVENT0("gpu", "CompositingIOSurfaceMac::DrawQuad");
+
   glEnableClientState(GL_VERTEX_ARRAY); CHECK_AND_SAVE_GL_ERROR();
   glEnableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_AND_SAVE_GL_ERROR();
 
@@ -660,80 +563,41 @@ void CompositingIOSurfaceMac::DrawQuad(const SurfaceQuad& quad) {
   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 }
 
-bool CompositingIOSurfaceMac::IsVendorIntel() {
-  GLint screen;
-  CGLGetVirtualScreen(context_->cgl_context(), &screen);
-  if (screen != screen_)
-    initialized_is_intel_ = false;
-  screen_ = screen;
-  if (!initialized_is_intel_) {
-    is_intel_ = strstr(reinterpret_cast<const char*>(glGetString(GL_VENDOR)),
-                      "Intel") != NULL;
-    initialized_is_intel_ = true;
-  }
-  return is_intel_;
-}
-
 void CompositingIOSurfaceMac::UnrefIOSurfaceWithContextCurrent() {
   if (texture_) {
     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;
-}
 
-void CompositingIOSurfaceMac::DisplayLinkTick(CVDisplayLinkRef display_link,
-                                              const CVTimeStamp* time) {
-  TRACE_EVENT0("gpu", "CompositingIOSurfaceMac::DisplayLinkTick");
-  base::AutoLock lock(lock_);
-  CalculateVsyncParametersLockHeld(time);
-}
-
-void CompositingIOSurfaceMac::CalculateVsyncParametersLockHeld(
-    const CVTimeStamp* time) {
-  lock_.AssertAcquired();
-  vsync_interval_numerator_ = static_cast<uint32>(time->videoRefreshPeriod);
-  vsync_interval_denominator_ = time->videoTimeScale;
-  // Verify that videoRefreshPeriod is 32 bits.
-  DCHECK((time->videoRefreshPeriod & ~0xffffFFFFull) == 0ull);
-
-  vsync_timebase_ =
-      base::TimeTicks::FromInternalValue(time->hostTime / 1000);
-}
-
-void CompositingIOSurfaceMac::StartOrContinueDisplayLink() {
-  if (display_link_ == NULL)
-    return;
-
-  if (!CVDisplayLinkIsRunning(display_link_)) {
-    CVDisplayLinkStart(display_link_);
-  }
-  display_link_stop_timer_.Reset();
-}
-
-void CompositingIOSurfaceMac::StopDisplayLink() {
-  if (display_link_ == NULL)
-    return;
-
-  if (CVDisplayLinkIsRunning(display_link_))
-    CVDisplayLinkStop(display_link_);
+  EvictionMarkEvicted();
 }
 
 bool CompositingIOSurfaceMac::IsAsynchronousReadbackSupported() {
-  // Using PBO crashes on Intel drivers but not on newer Mountain Lion
-  // systems. See bug http://crbug.com/152225.
   const bool forced_synchronous = CommandLine::ForCurrentProcess()->HasSwitch(
-                                      switches::kForceSynchronousGLReadPixels);
-  return (!forced_synchronous &&
-          HasAppleFenceExtension() &&
-          HasPixelBufferObjectExtension() &&
-          (base::mac::IsOSMountainLionOrLater() || !IsVendorIntel()));
+      switches::kForceSynchronousGLReadPixels);
+  if (forced_synchronous)
+    return false;
+  if (!HasAppleFenceExtension() && HasPixelBufferObjectExtension())
+    return false;
+  // Using PBO crashes or generates invalid output for machines using
+  // Snow Leopard (10.6).
+  // See bug crbug.com/152225 and crbug.com/348256.
+  if (!base::mac::IsOSMountainLionOrLater())
+    return false;
+  return true;
+}
+
+bool CompositingIOSurfaceMac::HasBeenPoisoned() const {
+  return offscreen_context_->HasBeenPoisoned();
 }
 
 base::Closure CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext(
@@ -750,7 +614,8 @@ base::Closure CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext(
   // readback for SkBitmap output since the Blit shader program doesn't support
   // switchable output formats.
   const bool require_sync_copy_for_workaround = bitmap_output &&
-      context_->shader_program_cache()->rgb_to_yv12_output_format() == GL_RGBA;
+      offscreen_context_->shader_program_cache()->rgb_to_yv12_output_format() ==
+          GL_RGBA;
   const bool async_copy = !require_sync_copy_for_workaround &&
       IsAsynchronousReadbackSupported();
   TRACE_EVENT2(
@@ -773,7 +638,7 @@ base::Closure CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext(
     // be started here.
     if (copy_requests_.size() >= 2)
       return base::Bind(done_callback, false);
-    copy_context = new CopyContext(context_);
+    copy_context = new CopyContext(offscreen_context_);
   } else {
     copy_context = copy_context_pool_.back();
     copy_context_pool_.pop_back();
@@ -801,7 +666,8 @@ base::Closure CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext(
             &copy_context->output_texture_sizes[0],
             &copy_context->output_texture_sizes[1])) {
       copy_context->output_readback_format =
-          context_->shader_program_cache()->rgb_to_yv12_output_format();
+          offscreen_context_->shader_program_cache()->
+              rgb_to_yv12_output_format();
       copy_context->num_outputs = 3;
       copy_context->output_texture_sizes[2] =
           copy_context->output_texture_sizes[1];
@@ -887,11 +753,16 @@ void CompositingIOSurfaceMac::AsynchronousReadbackForCopy(
 
 void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished(
     bool block_until_finished) {
+  if (copy_requests_.empty())
+    return;
+
   std::vector<base::Closure> done_callbacks;
-  CGLSetCurrentContext(context_->cgl_context());
-  CheckIfAllCopiesAreFinishedWithinContext(
-      block_until_finished, &done_callbacks);
-  CGLSetCurrentContext(0);
+  {
+    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+        offscreen_context_->cgl_context());
+    CheckIfAllCopiesAreFinishedWithinContext(
+        block_until_finished, &done_callbacks);
+  }
   for (size_t i = 0; i < done_callbacks.size(); ++i)
     done_callbacks[i].Run();
 }
@@ -1064,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