Home | History | Annotate | Download | only in renderer_host
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/renderer_host/compositing_iosurface_mac.h"
      6 
      7 #include <OpenGL/CGLRenderers.h>
      8 #include <OpenGL/OpenGL.h>
      9 
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "base/command_line.h"
     13 #include "base/debug/trace_event.h"
     14 #include "base/logging.h"
     15 #include "base/mac/mac_util.h"
     16 #include "base/message_loop/message_loop.h"
     17 #include "base/threading/platform_thread.h"
     18 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
     19 #include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
     20 #include "content/browser/renderer_host/compositing_iosurface_transformer_mac.h"
     21 #include "content/browser/renderer_host/render_widget_host_impl.h"
     22 #include "content/browser/renderer_host/render_widget_host_view_mac.h"
     23 #include "content/common/content_constants_internal.h"
     24 #include "content/port/browser/render_widget_host_view_frame_subscriber.h"
     25 #include "gpu/command_buffer/service/gpu_switches.h"
     26 #include "media/base/video_util.h"
     27 #include "third_party/skia/include/core/SkBitmap.h"
     28 #include "ui/gfx/rect.h"
     29 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
     30 #include "ui/gfx/size_conversions.h"
     31 #include "ui/gl/gl_context.h"
     32 #include "ui/gl/io_surface_support_mac.h"
     33 
     34 #ifdef NDEBUG
     35 #define CHECK_GL_ERROR()
     36 #define CHECK_AND_SAVE_GL_ERROR()
     37 #else
     38 #define CHECK_GL_ERROR() do {                                           \
     39     GLenum gl_error = glGetError();                                     \
     40     LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
     41   } while (0)
     42 #define CHECK_AND_SAVE_GL_ERROR() do {                                  \
     43     GLenum gl_error = GetAndSaveGLError();                              \
     44     LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
     45   } while (0)
     46 #endif
     47 
     48 namespace content {
     49 namespace {
     50 
     51 // How many times to test if asynchronous copy has completed.
     52 // This value is chosen such that we allow at most 1 second to finish a copy.
     53 const int kFinishCopyRetryCycles = 100;
     54 
     55 // Time in milliseconds to allow asynchronous copy to finish.
     56 // This value is shorter than 16ms such that copy can complete within a vsync.
     57 const int kFinishCopyPollingPeriodMs = 10;
     58 
     59 bool HasAppleFenceExtension() {
     60   static bool initialized_has_fence = false;
     61   static bool has_fence = false;
     62 
     63   if (!initialized_has_fence) {
     64     has_fence =
     65         strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)),
     66                "GL_APPLE_fence") != NULL;
     67     initialized_has_fence = true;
     68   }
     69   return has_fence;
     70 }
     71 
     72 bool HasPixelBufferObjectExtension() {
     73   static bool initialized_has_pbo = false;
     74   static bool has_pbo = false;
     75 
     76   if (!initialized_has_pbo) {
     77     has_pbo =
     78         strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)),
     79                "GL_ARB_pixel_buffer_object") != NULL;
     80     initialized_has_pbo = true;
     81   }
     82   return has_pbo;
     83 }
     84 
     85 // Helper function to reverse the argument order.  Also takes ownership of
     86 // |bitmap_output| for the life of the binding.
     87 void ReverseArgumentOrder(
     88     const base::Callback<void(bool, const SkBitmap&)>& callback,
     89     scoped_ptr<SkBitmap> bitmap_output, bool success) {
     90   callback.Run(success, *bitmap_output);
     91 }
     92 
     93 // Called during an async GPU readback with a pointer to the pixel buffer.  In
     94 // the snapshot path, we just memcpy the data into our output bitmap since the
     95 // width, height, and stride should all be equal.
     96 bool MapBufferToSkBitmap(const SkBitmap* output, const void* buf, int ignored) {
     97   TRACE_EVENT0("browser", "MapBufferToSkBitmap");
     98 
     99   if (buf) {
    100     SkAutoLockPixels output_lock(*output);
    101     memcpy(output->getPixels(), buf, output->getSize());
    102   }
    103   return buf != NULL;
    104 }
    105 
    106 // Copies tightly-packed scanlines from |buf| to |region_in_frame| in the given
    107 // |target| VideoFrame's |plane|.  Assumption: |buf|'s width is
    108 // |region_in_frame.width()| and its stride is always in 4-byte alignment.
    109 //
    110 // TODO(miu): Refactor by moving this function into media/video_util.
    111 // http://crbug.com/219779
    112 bool MapBufferToVideoFrame(
    113     const scoped_refptr<media::VideoFrame>& target,
    114     const gfx::Rect& region_in_frame,
    115     const void* buf,
    116     int plane) {
    117   COMPILE_ASSERT(media::VideoFrame::kYPlane == 0, VideoFrame_kYPlane_mismatch);
    118   COMPILE_ASSERT(media::VideoFrame::kUPlane == 1, VideoFrame_kUPlane_mismatch);
    119   COMPILE_ASSERT(media::VideoFrame::kVPlane == 2, VideoFrame_kVPlane_mismatch);
    120 
    121   TRACE_EVENT1("browser", "MapBufferToVideoFrame", "plane", plane);
    122 
    123   // Apply black-out in the regions surrounding the view area (for
    124   // letterboxing/pillarboxing).  Only do this once, since this is performed on
    125   // all planes in the VideoFrame here.
    126   if (plane == 0)
    127     media::LetterboxYUV(target.get(), region_in_frame);
    128 
    129   if (buf) {
    130     int packed_width = region_in_frame.width();
    131     int packed_height = region_in_frame.height();
    132     // For planes 1 and 2, the width and height are 1/2 size (rounded up).
    133     if (plane > 0) {
    134       packed_width = (packed_width + 1) / 2;
    135       packed_height = (packed_height + 1) / 2;
    136     }
    137     const uint8* src = reinterpret_cast<const uint8*>(buf);
    138     const int src_stride = (packed_width % 4 == 0 ?
    139                                 packed_width :
    140                                 (packed_width + 4 - (packed_width % 4)));
    141     const uint8* const src_end = src + packed_height * src_stride;
    142 
    143     // Calculate starting offset and stride into the destination buffer.
    144     const int dst_stride = target->stride(plane);
    145     uint8* dst = target->data(plane);
    146     if (plane == 0)
    147       dst += (region_in_frame.y() * dst_stride) + region_in_frame.x();
    148     else
    149       dst += (region_in_frame.y() / 2 * dst_stride) + (region_in_frame.x() / 2);
    150 
    151     // Copy each row, accounting for strides in the source and destination.
    152     for (; src < src_end; src += src_stride, dst += dst_stride)
    153       memcpy(dst, src, packed_width);
    154   }
    155   return buf != NULL;
    156 }
    157 
    158 }  // namespace
    159 
    160 CVReturn DisplayLinkCallback(CVDisplayLinkRef display_link,
    161                              const CVTimeStamp* now,
    162                              const CVTimeStamp* output_time,
    163                              CVOptionFlags flags_in,
    164                              CVOptionFlags* flags_out,
    165                              void* context) {
    166   CompositingIOSurfaceMac* surface =
    167       static_cast<CompositingIOSurfaceMac*>(context);
    168   surface->DisplayLinkTick(display_link, output_time);
    169   return kCVReturnSuccess;
    170 }
    171 
    172 CompositingIOSurfaceMac::CopyContext::CopyContext(
    173     const scoped_refptr<CompositingIOSurfaceContext>& context)
    174   : transformer(new CompositingIOSurfaceTransformer(
    175         GL_TEXTURE_RECTANGLE_ARB, true, context->shader_program_cache())),
    176     output_readback_format(GL_BGRA),
    177     num_outputs(0),
    178     fence(0),
    179     cycles_elapsed(0) {
    180   memset(output_textures, 0, sizeof(output_textures));
    181   memset(frame_buffers, 0, sizeof(frame_buffers));
    182   memset(pixel_buffers, 0, sizeof(pixel_buffers));
    183 }
    184 
    185 CompositingIOSurfaceMac::CopyContext::~CopyContext() {
    186   DCHECK_EQ(frame_buffers[0], 0u) << "Failed to call ReleaseCachedGLObjects().";
    187 }
    188 
    189 void CompositingIOSurfaceMac::CopyContext::ReleaseCachedGLObjects() {
    190   // No outstanding callbacks should be pending.
    191   DCHECK(map_buffer_callback.is_null());
    192   DCHECK(done_callback.is_null());
    193 
    194   // For an asynchronous read-back, there are more objects to delete:
    195   if (fence) {
    196     glDeleteBuffers(arraysize(pixel_buffers), pixel_buffers); CHECK_GL_ERROR();
    197     memset(pixel_buffers, 0, sizeof(pixel_buffers));
    198     glDeleteFencesAPPLE(1, &fence); CHECK_GL_ERROR();
    199     fence = 0;
    200   }
    201 
    202   glDeleteFramebuffersEXT(arraysize(frame_buffers), frame_buffers);
    203   CHECK_GL_ERROR();
    204   memset(frame_buffers, 0, sizeof(frame_buffers));
    205 
    206   // Note: |output_textures| are owned by the transformer.
    207   if (transformer)
    208     transformer->ReleaseCachedGLObjects();
    209 }
    210 
    211 void CompositingIOSurfaceMac::CopyContext::PrepareReadbackFramebuffers() {
    212   for (int i = 0; i < num_outputs; ++i) {
    213     if (!frame_buffers[i]) {
    214       glGenFramebuffersEXT(1, &frame_buffers[i]); CHECK_GL_ERROR();
    215     }
    216   }
    217 }
    218 
    219 void CompositingIOSurfaceMac::CopyContext::PrepareForAsynchronousReadback() {
    220   PrepareReadbackFramebuffers();
    221   if (!fence) {
    222     glGenFencesAPPLE(1, &fence); CHECK_GL_ERROR();
    223   }
    224   for (int i = 0; i < num_outputs; ++i) {
    225     if (!pixel_buffers[i]) {
    226       glGenBuffersARB(1, &pixel_buffers[i]); CHECK_GL_ERROR();
    227     }
    228   }
    229 }
    230 
    231 
    232 // static
    233 CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create(
    234     const scoped_refptr<CompositingIOSurfaceContext>& context) {
    235   IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
    236   if (!io_surface_support) {
    237     LOG(ERROR) << "No IOSurface support";
    238     return NULL;
    239   }
    240 
    241   return new CompositingIOSurfaceMac(io_surface_support,
    242                                      context);
    243 }
    244 
    245 CompositingIOSurfaceMac::CompositingIOSurfaceMac(
    246     IOSurfaceSupport* io_surface_support,
    247     const scoped_refptr<CompositingIOSurfaceContext>& context)
    248     : io_surface_support_(io_surface_support),
    249       context_(context),
    250       io_surface_handle_(0),
    251       scale_factor_(1.f),
    252       texture_(0),
    253       finish_copy_timer_(
    254           FROM_HERE,
    255           base::TimeDelta::FromMilliseconds(kFinishCopyPollingPeriodMs),
    256           base::Bind(&CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished,
    257                      base::Unretained(this),
    258                      false),
    259           true),
    260       display_link_(0),
    261       display_link_stop_timer_(FROM_HERE, base::TimeDelta::FromSeconds(1),
    262                                this, &CompositingIOSurfaceMac::StopDisplayLink),
    263       vsync_interval_numerator_(0),
    264       vsync_interval_denominator_(0),
    265       initialized_is_intel_(false),
    266       is_intel_(false),
    267       screen_(0),
    268       gl_error_(GL_NO_ERROR) {
    269   CHECK(context_);
    270 }
    271 
    272 void CompositingIOSurfaceMac::SetupCVDisplayLink() {
    273   if (display_link_) {
    274     LOG(ERROR) << "DisplayLink already setup";
    275     return;
    276   }
    277 
    278   CVDisplayLinkRef display_link;
    279   CVReturn ret = CVDisplayLinkCreateWithActiveCGDisplays(&display_link);
    280   if (ret != kCVReturnSuccess) {
    281     LOG(WARNING) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret;
    282     return;
    283   }
    284 
    285   display_link_ = display_link;
    286 
    287   ret = CVDisplayLinkSetOutputCallback(display_link_,
    288                                        &DisplayLinkCallback, this);
    289   DCHECK(ret == kCVReturnSuccess)
    290       << "CVDisplayLinkSetOutputCallback failed: " << ret;
    291 
    292   StartOrContinueDisplayLink();
    293 
    294   CVTimeStamp cv_time;
    295   ret = CVDisplayLinkGetCurrentTime(display_link_, &cv_time);
    296   DCHECK(ret == kCVReturnSuccess)
    297       << "CVDisplayLinkGetCurrentTime failed: " << ret;
    298 
    299   {
    300     base::AutoLock lock(lock_);
    301     CalculateVsyncParametersLockHeld(&cv_time);
    302   }
    303 
    304   // Stop display link for now, it will be started when needed during Draw.
    305   StopDisplayLink();
    306 }
    307 
    308 void CompositingIOSurfaceMac::SetContext(
    309     const scoped_refptr<CompositingIOSurfaceContext>& new_context) {
    310   CHECK(new_context);
    311 
    312   if (context_ == new_context)
    313     return;
    314 
    315   // Asynchronous copies must complete in the same context they started in.
    316   CheckIfAllCopiesAreFinished(true);
    317   CGLSetCurrentContext(context_->cgl_context());
    318   DestroyAllCopyContextsWithinContext();
    319   CGLSetCurrentContext(0);
    320 
    321   context_ = new_context;
    322 }
    323 
    324 bool CompositingIOSurfaceMac::is_vsync_disabled() const {
    325   return context_->is_vsync_disabled();
    326 }
    327 
    328 void CompositingIOSurfaceMac::GetVSyncParameters(base::TimeTicks* timebase,
    329                                                  uint32* interval_numerator,
    330                                                  uint32* interval_denominator) {
    331   base::AutoLock lock(lock_);
    332   *timebase = vsync_timebase_;
    333   *interval_numerator = vsync_interval_numerator_;
    334   *interval_denominator = vsync_interval_denominator_;
    335 }
    336 
    337 CompositingIOSurfaceMac::~CompositingIOSurfaceMac() {
    338   FailAllCopies();
    339   CVDisplayLinkRelease(display_link_);
    340   CGLSetCurrentContext(context_->cgl_context());
    341   DestroyAllCopyContextsWithinContext();
    342   UnrefIOSurfaceWithContextCurrent();
    343   CGLSetCurrentContext(0);
    344   context_ = NULL;
    345 }
    346 
    347 bool CompositingIOSurfaceMac::SetIOSurface(
    348     uint64 io_surface_handle,
    349     const gfx::Size& size,
    350     float scale_factor,
    351     const ui::LatencyInfo& latency_info) {
    352   pixel_io_surface_size_ = size;
    353   scale_factor_ = scale_factor;
    354   dip_io_surface_size_ = gfx::ToFlooredSize(
    355       gfx::ScaleSize(pixel_io_surface_size_, 1.0 / scale_factor_));
    356 
    357   CGLError cgl_error = CGLSetCurrentContext(context_->cgl_context());
    358   if (cgl_error != kCGLNoError) {
    359     LOG(ERROR) << "CGLSetCurrentContext error in SetIOSurface: " << cgl_error;
    360     return false;
    361   }
    362   bool result = MapIOSurfaceToTexture(io_surface_handle);
    363   CGLSetCurrentContext(0);
    364   latency_info_.MergeWith(latency_info);
    365   return result;
    366 }
    367 
    368 int CompositingIOSurfaceMac::GetRendererID() {
    369   GLint current_renderer_id = -1;
    370   if (CGLGetParameter(context_->cgl_context(),
    371                       kCGLCPCurrentRendererID,
    372                       &current_renderer_id) == kCGLNoError)
    373     return current_renderer_id & kCGLRendererIDMatchingMask;
    374   return -1;
    375 }
    376 
    377 bool CompositingIOSurfaceMac::DrawIOSurface(
    378     const gfx::Size& window_size,
    379     float window_scale_factor,
    380     RenderWidgetHostViewFrameSubscriber* frame_subscriber,
    381     bool using_core_animation) {
    382   bool result = true;
    383 
    384   if (display_link_ == NULL)
    385     SetupCVDisplayLink();
    386 
    387   bool has_io_surface = HasIOSurface();
    388   TRACE_EVENT1("browser", "CompositingIOSurfaceMac::DrawIOSurface",
    389                "has_io_surface", has_io_surface);
    390 
    391   gfx::Size pixel_window_size = gfx::ToFlooredSize(
    392       gfx::ScaleSize(window_size, window_scale_factor));
    393   glViewport(0, 0, pixel_window_size.width(), pixel_window_size.height());
    394 
    395   SurfaceQuad quad;
    396   quad.set_size(dip_io_surface_size_, pixel_io_surface_size_);
    397 
    398   glMatrixMode(GL_PROJECTION);
    399   glLoadIdentity();
    400 
    401   // Note that the projection keeps things in view units, so the use of
    402   // window_size / dip_io_surface_size_ (as opposed to the pixel_ variants)
    403   // below is correct.
    404   glOrtho(0, window_size.width(), window_size.height(), 0, -1, 1);
    405   glMatrixMode(GL_MODELVIEW);
    406   glLoadIdentity();
    407 
    408   glDisable(GL_DEPTH_TEST);
    409   glDisable(GL_BLEND);
    410 
    411   if (has_io_surface) {
    412     context_->shader_program_cache()->UseBlitProgram();
    413     glActiveTexture(GL_TEXTURE0);
    414     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
    415 
    416     DrawQuad(quad);
    417 
    418     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
    419 
    420     // Fill the resize gutters with white.
    421     if (window_size.width() > dip_io_surface_size_.width() ||
    422         window_size.height() > dip_io_surface_size_.height()) {
    423       context_->shader_program_cache()->UseSolidWhiteProgram();
    424       SurfaceQuad filler_quad;
    425       if (window_size.width() > dip_io_surface_size_.width()) {
    426         // Draw right-side gutter down to the bottom of the window.
    427         filler_quad.set_rect(dip_io_surface_size_.width(), 0.0f,
    428                              window_size.width(), window_size.height());
    429         DrawQuad(filler_quad);
    430       }
    431       if (window_size.height() > dip_io_surface_size_.height()) {
    432         // Draw bottom gutter to the width of the IOSurface.
    433         filler_quad.set_rect(
    434             0.0f, dip_io_surface_size_.height(),
    435             dip_io_surface_size_.width(), window_size.height());
    436         DrawQuad(filler_quad);
    437       }
    438     }
    439 
    440     // Workaround for issue 158469. Issue a dummy draw call with texture_ not
    441     // bound to blit_rgb_sampler_location_, in order to shake all references
    442     // to the IOSurface out of the driver.
    443     glBegin(GL_TRIANGLES);
    444     glEnd();
    445 
    446     glUseProgram(0); CHECK_AND_SAVE_GL_ERROR();
    447   } else {
    448     // Should match the clear color of RenderWidgetHostViewMac.
    449     glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    450     glClear(GL_COLOR_BUFFER_BIT);
    451   }
    452 
    453   static bool initialized_workaround = false;
    454   static bool force_on_workaround = false;
    455   static bool force_off_workaround = false;
    456   if (!initialized_workaround) {
    457     force_on_workaround = CommandLine::ForCurrentProcess()->HasSwitch(
    458         switches::kForceGLFinishWorkaround);
    459     force_off_workaround = CommandLine::ForCurrentProcess()->HasSwitch(
    460         switches::kDisableGpuDriverBugWorkarounds);
    461 
    462     initialized_workaround = true;
    463   }
    464 
    465   const bool workaround_needed =
    466       IsVendorIntel() && !base::mac::IsOSMountainLionOrLater();
    467   const bool use_glfinish_workaround =
    468       (workaround_needed || force_on_workaround) && !force_off_workaround;
    469 
    470   if (use_glfinish_workaround) {
    471     TRACE_EVENT0("gpu", "glFinish");
    472     // http://crbug.com/123409 : work around bugs in graphics driver on
    473     // MacBook Air with Intel HD graphics, and possibly on other models,
    474     // by forcing the graphics pipeline to be completely drained at this
    475     // point.
    476     // This workaround is not necessary on Mountain Lion.
    477     glFinish();
    478   }
    479 
    480   base::Closure copy_done_callback;
    481   if (frame_subscriber) {
    482     const base::Time present_time = base::Time::Now();
    483     scoped_refptr<media::VideoFrame> frame;
    484     RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
    485     if (frame_subscriber->ShouldCaptureFrame(present_time, &frame, &callback)) {
    486       copy_done_callback = CopyToVideoFrameWithinContext(
    487           gfx::Rect(pixel_io_surface_size_), true, frame,
    488           base::Bind(callback, present_time));
    489     }
    490   }
    491 
    492   if (!using_core_animation) {
    493     CGLError cgl_error =  CGLFlushDrawable(context_->cgl_context());
    494     if (cgl_error != kCGLNoError) {
    495       LOG(ERROR) << "CGLFlushDrawable error in DrawIOSurface: " << cgl_error;
    496       result = false;
    497     }
    498   }
    499 
    500   latency_info_.swap_timestamp = base::TimeTicks::HighResNow();
    501   RenderWidgetHostImpl::CompositorFrameDrawn(latency_info_);
    502   latency_info_.Clear();
    503 
    504   // Try to finish previous copy requests after flush to get better pipelining.
    505   std::vector<base::Closure> copy_done_callbacks;
    506   CheckIfAllCopiesAreFinishedWithinContext(false, &copy_done_callbacks);
    507 
    508   // Check if any of the drawing calls result in an error.
    509   GetAndSaveGLError();
    510   if (gl_error_ != GL_NO_ERROR) {
    511     LOG(ERROR) << "GL error in DrawIOSurface: " << gl_error_;
    512     result = false;
    513   }
    514 
    515   if (!using_core_animation)
    516     CGLSetCurrentContext(0);
    517 
    518   if (!copy_done_callback.is_null())
    519     copy_done_callbacks.push_back(copy_done_callback);
    520   for (size_t i = 0; i < copy_done_callbacks.size(); ++i)
    521     copy_done_callbacks[i].Run();
    522 
    523   StartOrContinueDisplayLink();
    524 
    525   return result;
    526 }
    527 
    528 void CompositingIOSurfaceMac::CopyTo(
    529       const gfx::Rect& src_pixel_subrect,
    530       const gfx::Size& dst_pixel_size,
    531       const base::Callback<void(bool, const SkBitmap&)>& callback) {
    532   scoped_ptr<SkBitmap> output(new SkBitmap());
    533   output->setConfig(SkBitmap::kARGB_8888_Config,
    534                     dst_pixel_size.width(), dst_pixel_size.height());
    535   if (!output->allocPixels()) {
    536     DLOG(ERROR) << "Failed to allocate SkBitmap pixels!";
    537     callback.Run(false, *output);
    538     return;
    539   }
    540   DCHECK_EQ(output->rowBytesAsPixels(), dst_pixel_size.width())
    541       << "Stride is required to be equal to width for GPU readback.";
    542   output->setIsOpaque(true);
    543 
    544   CGLSetCurrentContext(context_->cgl_context());
    545   const base::Closure copy_done_callback = CopyToSelectedOutputWithinContext(
    546       src_pixel_subrect, gfx::Rect(dst_pixel_size), false,
    547       output.get(), NULL,
    548       base::Bind(&ReverseArgumentOrder, callback, base::Passed(&output)));
    549   CGLSetCurrentContext(0);
    550   if (!copy_done_callback.is_null())
    551     copy_done_callback.Run();
    552 }
    553 
    554 void CompositingIOSurfaceMac::CopyToVideoFrame(
    555     const gfx::Rect& src_pixel_subrect,
    556     const scoped_refptr<media::VideoFrame>& target,
    557     const base::Callback<void(bool)>& callback) {
    558   CGLSetCurrentContext(context_->cgl_context());
    559   const base::Closure copy_done_callback = CopyToVideoFrameWithinContext(
    560       src_pixel_subrect, false, target, callback);
    561   CGLSetCurrentContext(0);
    562   if (!copy_done_callback.is_null())
    563     copy_done_callback.Run();
    564 }
    565 
    566 base::Closure CompositingIOSurfaceMac::CopyToVideoFrameWithinContext(
    567     const gfx::Rect& src_pixel_subrect,
    568     bool called_within_draw,
    569     const scoped_refptr<media::VideoFrame>& target,
    570     const base::Callback<void(bool)>& callback) {
    571   gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
    572       gfx::Rect(target->coded_size()), src_pixel_subrect.size());
    573   // Make coordinates and sizes even because we letterbox in YUV space right
    574   // now (see CopyRGBToVideoFrame). They need to be even for the UV samples to
    575   // line up correctly.
    576   region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
    577                               region_in_frame.y() & ~1,
    578                               region_in_frame.width() & ~1,
    579                               region_in_frame.height() & ~1);
    580   DCHECK_LE(region_in_frame.right(), target->coded_size().width());
    581   DCHECK_LE(region_in_frame.bottom(), target->coded_size().height());
    582 
    583   return CopyToSelectedOutputWithinContext(
    584       src_pixel_subrect, region_in_frame, called_within_draw,
    585       NULL, target, callback);
    586 }
    587 
    588 bool CompositingIOSurfaceMac::MapIOSurfaceToTexture(
    589     uint64 io_surface_handle) {
    590   if (io_surface_.get() && io_surface_handle == io_surface_handle_)
    591     return true;
    592 
    593   TRACE_EVENT0("browser", "CompositingIOSurfaceMac::MapIOSurfaceToTexture");
    594   UnrefIOSurfaceWithContextCurrent();
    595 
    596   io_surface_.reset(io_surface_support_->IOSurfaceLookup(
    597       static_cast<uint32>(io_surface_handle)));
    598   // Can fail if IOSurface with that ID was already released by the gpu
    599   // process.
    600   if (!io_surface_) {
    601     UnrefIOSurfaceWithContextCurrent();
    602     return false;
    603   }
    604 
    605   io_surface_handle_ = io_surface_handle;
    606 
    607   // Actual IOSurface size is rounded up to reduce reallocations during window
    608   // resize. Get the actual size to properly map the texture.
    609   gfx::Size rounded_size(
    610       io_surface_support_->IOSurfaceGetWidth(io_surface_),
    611       io_surface_support_->IOSurfaceGetHeight(io_surface_));
    612 
    613   glGenTextures(1, &texture_);
    614   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
    615   glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    616   glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    617   CHECK_AND_SAVE_GL_ERROR();
    618   GLuint plane = 0;
    619   CGLError cgl_error = io_surface_support_->CGLTexImageIOSurface2D(
    620       context_->cgl_context(),
    621       GL_TEXTURE_RECTANGLE_ARB,
    622       GL_RGBA,
    623       rounded_size.width(),
    624       rounded_size.height(),
    625       GL_BGRA,
    626       GL_UNSIGNED_INT_8_8_8_8_REV,
    627       io_surface_.get(),
    628       plane);
    629   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
    630   if (cgl_error != kCGLNoError) {
    631     LOG(ERROR) << "CGLTexImageIOSurface2D: " << cgl_error;
    632     UnrefIOSurfaceWithContextCurrent();
    633     return false;
    634   }
    635   GetAndSaveGLError();
    636   if (gl_error_ != GL_NO_ERROR) {
    637     LOG(ERROR) << "GL error in MapIOSurfaceToTexture: " << gl_error_;
    638     UnrefIOSurfaceWithContextCurrent();
    639     return false;
    640   }
    641   return true;
    642 }
    643 
    644 void CompositingIOSurfaceMac::UnrefIOSurface() {
    645   CGLSetCurrentContext(context_->cgl_context());
    646   UnrefIOSurfaceWithContextCurrent();
    647   CGLSetCurrentContext(0);
    648 }
    649 
    650 void CompositingIOSurfaceMac::DrawQuad(const SurfaceQuad& quad) {
    651   glEnableClientState(GL_VERTEX_ARRAY); CHECK_AND_SAVE_GL_ERROR();
    652   glEnableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_AND_SAVE_GL_ERROR();
    653 
    654   glVertexPointer(2, GL_FLOAT, sizeof(SurfaceVertex), &quad.verts_[0].x_);
    655   glTexCoordPointer(2, GL_FLOAT, sizeof(SurfaceVertex), &quad.verts_[0].tx_);
    656   glDrawArrays(GL_QUADS, 0, 4); CHECK_AND_SAVE_GL_ERROR();
    657 
    658   glDisableClientState(GL_VERTEX_ARRAY);
    659   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    660 }
    661 
    662 bool CompositingIOSurfaceMac::IsVendorIntel() {
    663   GLint screen;
    664   CGLGetVirtualScreen(context_->cgl_context(), &screen);
    665   if (screen != screen_)
    666     initialized_is_intel_ = false;
    667   screen_ = screen;
    668   if (!initialized_is_intel_) {
    669     is_intel_ = strstr(reinterpret_cast<const char*>(glGetString(GL_VENDOR)),
    670                       "Intel") != NULL;
    671     initialized_is_intel_ = true;
    672   }
    673   return is_intel_;
    674 }
    675 
    676 void CompositingIOSurfaceMac::UnrefIOSurfaceWithContextCurrent() {
    677   if (texture_) {
    678     glDeleteTextures(1, &texture_);
    679     texture_ = 0;
    680   }
    681 
    682   io_surface_.reset();
    683 
    684   // Forget the ID, because even if it is still around when we want to use it
    685   // again, OSX may have reused the same ID for a new tab and we don't want to
    686   // blit random tab contents.
    687   io_surface_handle_ = 0;
    688 }
    689 
    690 void CompositingIOSurfaceMac::DisplayLinkTick(CVDisplayLinkRef display_link,
    691                                               const CVTimeStamp* time) {
    692   TRACE_EVENT0("gpu", "CompositingIOSurfaceMac::DisplayLinkTick");
    693   base::AutoLock lock(lock_);
    694   CalculateVsyncParametersLockHeld(time);
    695 }
    696 
    697 void CompositingIOSurfaceMac::CalculateVsyncParametersLockHeld(
    698     const CVTimeStamp* time) {
    699   lock_.AssertAcquired();
    700   vsync_interval_numerator_ = static_cast<uint32>(time->videoRefreshPeriod);
    701   vsync_interval_denominator_ = time->videoTimeScale;
    702   // Verify that videoRefreshPeriod is 32 bits.
    703   DCHECK((time->videoRefreshPeriod & ~0xffffFFFFull) == 0ull);
    704 
    705   vsync_timebase_ =
    706       base::TimeTicks::FromInternalValue(time->hostTime / 1000);
    707 }
    708 
    709 void CompositingIOSurfaceMac::StartOrContinueDisplayLink() {
    710   if (display_link_ == NULL)
    711     return;
    712 
    713   if (!CVDisplayLinkIsRunning(display_link_)) {
    714     CVDisplayLinkStart(display_link_);
    715   }
    716   display_link_stop_timer_.Reset();
    717 }
    718 
    719 void CompositingIOSurfaceMac::StopDisplayLink() {
    720   if (display_link_ == NULL)
    721     return;
    722 
    723   if (CVDisplayLinkIsRunning(display_link_))
    724     CVDisplayLinkStop(display_link_);
    725 }
    726 
    727 bool CompositingIOSurfaceMac::IsAsynchronousReadbackSupported() {
    728   // Using PBO crashes on Intel drivers but not on newer Mountain Lion
    729   // systems. See bug http://crbug.com/152225.
    730   const bool forced_synchronous = CommandLine::ForCurrentProcess()->HasSwitch(
    731                                       switches::kForceSynchronousGLReadPixels);
    732   return (!forced_synchronous &&
    733           HasAppleFenceExtension() &&
    734           HasPixelBufferObjectExtension() &&
    735           (base::mac::IsOSMountainLionOrLater() || !IsVendorIntel()));
    736 }
    737 
    738 base::Closure CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext(
    739     const gfx::Rect& src_pixel_subrect,
    740     const gfx::Rect& dst_pixel_rect,
    741     bool called_within_draw,
    742     const SkBitmap* bitmap_output,
    743     const scoped_refptr<media::VideoFrame>& video_frame_output,
    744     const base::Callback<void(bool)>& done_callback) {
    745   DCHECK_NE(bitmap_output != NULL, video_frame_output.get() != NULL);
    746   DCHECK(!done_callback.is_null());
    747 
    748   // SWIZZLE_RGBA_FOR_ASYNC_READPIXELS workaround: Fall-back to synchronous
    749   // readback for SkBitmap output since the Blit shader program doesn't support
    750   // switchable output formats.
    751   const bool require_sync_copy_for_workaround = bitmap_output &&
    752       context_->shader_program_cache()->rgb_to_yv12_output_format() == GL_RGBA;
    753   const bool async_copy = !require_sync_copy_for_workaround &&
    754       IsAsynchronousReadbackSupported();
    755   TRACE_EVENT2(
    756       "browser", "CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext",
    757       "output", bitmap_output ? "SkBitmap (ARGB)" : "VideoFrame (YV12)",
    758       "async_readback", async_copy);
    759 
    760   const gfx::Rect src_rect = IntersectWithIOSurface(src_pixel_subrect);
    761   if (src_rect.IsEmpty() || dst_pixel_rect.IsEmpty())
    762     return base::Bind(done_callback, false);
    763 
    764   CopyContext* copy_context;
    765   if (copy_context_pool_.empty()) {
    766     // Limit the maximum number of simultaneous copies to two.  Rationale:
    767     // Really, only one should ever be in-progress at a time, as we should
    768     // depend on the speed of the hardware to rate-limit the copying naturally.
    769     // In the asynchronous read-back case, the one currently in-flight copy is
    770     // highly likely to have finished by this point (i.e., it's just waiting for
    771     // us to make a glMapBuffer() call).  Therefore, we allow a second copy to
    772     // be started here.
    773     if (copy_requests_.size() >= 2)
    774       return base::Bind(done_callback, false);
    775     copy_context = new CopyContext(context_);
    776   } else {
    777     copy_context = copy_context_pool_.back();
    778     copy_context_pool_.pop_back();
    779   }
    780 
    781   if (!HasIOSurface())
    782     return base::Bind(done_callback, false);
    783 
    784   // Send transform commands to the GPU.
    785   copy_context->num_outputs = 0;
    786   if (bitmap_output) {
    787     if (copy_context->transformer->ResizeBilinear(
    788             texture_, src_rect, dst_pixel_rect.size(),
    789             &copy_context->output_textures[0])) {
    790       copy_context->output_readback_format = GL_BGRA;
    791       copy_context->num_outputs = 1;
    792       copy_context->output_texture_sizes[0] = dst_pixel_rect.size();
    793     }
    794   } else {
    795     if (copy_context->transformer->TransformRGBToYV12(
    796             texture_, src_rect, dst_pixel_rect.size(),
    797             &copy_context->output_textures[0],
    798             &copy_context->output_textures[1],
    799             &copy_context->output_textures[2],
    800             &copy_context->output_texture_sizes[0],
    801             &copy_context->output_texture_sizes[1])) {
    802       copy_context->output_readback_format =
    803           context_->shader_program_cache()->rgb_to_yv12_output_format();
    804       copy_context->num_outputs = 3;
    805       copy_context->output_texture_sizes[2] =
    806           copy_context->output_texture_sizes[1];
    807     }
    808   }
    809   if (!copy_context->num_outputs)
    810     return base::Bind(done_callback, false);
    811 
    812   // In the asynchronous case, issue commands to the GPU and return a null
    813   // closure here.  In the synchronous case, perform a blocking readback and
    814   // return a callback to be run outside the CGL context to indicate success.
    815   if (async_copy) {
    816     copy_context->done_callback = done_callback;
    817     AsynchronousReadbackForCopy(
    818         dst_pixel_rect, called_within_draw, copy_context, bitmap_output,
    819         video_frame_output);
    820     copy_requests_.push_back(copy_context);
    821     if (!finish_copy_timer_.IsRunning())
    822       finish_copy_timer_.Reset();
    823     return base::Closure();
    824   } else {
    825     const bool success = SynchronousReadbackForCopy(
    826         dst_pixel_rect, copy_context, bitmap_output, video_frame_output);
    827     return base::Bind(done_callback, success);
    828   }
    829 }
    830 
    831 void CompositingIOSurfaceMac::AsynchronousReadbackForCopy(
    832     const gfx::Rect& dst_pixel_rect,
    833     bool called_within_draw,
    834     CopyContext* copy_context,
    835     const SkBitmap* bitmap_output,
    836     const scoped_refptr<media::VideoFrame>& video_frame_output) {
    837   copy_context->PrepareForAsynchronousReadback();
    838 
    839   // Copy the textures to their corresponding PBO.
    840   for (int i = 0; i < copy_context->num_outputs; ++i) {
    841     TRACE_EVENT1(
    842         "browser", "CompositingIOSurfaceMac::AsynchronousReadbackForCopy",
    843         "plane", i);
    844 
    845     // Attach the output texture to the FBO.
    846     glBindFramebufferEXT(
    847         GL_READ_FRAMEBUFFER_EXT, copy_context->frame_buffers[i]);
    848     glFramebufferTexture2DEXT(
    849         GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
    850         GL_TEXTURE_RECTANGLE_ARB, copy_context->output_textures[i], 0);
    851     DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
    852                GL_FRAMEBUFFER_COMPLETE_EXT);
    853 
    854     // Create a PBO and issue an asynchronous read-back.
    855     glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context->pixel_buffers[i]);
    856     CHECK_AND_SAVE_GL_ERROR();
    857     glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
    858                     copy_context->output_texture_sizes[i].GetArea() * 4,
    859                     NULL, GL_STREAM_READ_ARB);
    860     CHECK_AND_SAVE_GL_ERROR();
    861     glReadPixels(0, 0,
    862                  copy_context->output_texture_sizes[i].width(),
    863                  copy_context->output_texture_sizes[i].height(),
    864                  copy_context->output_readback_format,
    865                  GL_UNSIGNED_INT_8_8_8_8_REV, 0);
    866     CHECK_AND_SAVE_GL_ERROR();
    867   }
    868 
    869   glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
    870   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); CHECK_AND_SAVE_GL_ERROR();
    871 
    872   glSetFenceAPPLE(copy_context->fence); CHECK_GL_ERROR();
    873   copy_context->cycles_elapsed = 0;
    874 
    875   // When this asynchronous copy happens in a draw operaton there is no need
    876   // to explicitly flush because there will be a swap buffer and this flush
    877   // hurts performance.
    878   if (!called_within_draw) {
    879     glFlush(); CHECK_AND_SAVE_GL_ERROR();
    880   }
    881 
    882   copy_context->map_buffer_callback = bitmap_output ?
    883       base::Bind(&MapBufferToSkBitmap, bitmap_output) :
    884       base::Bind(&MapBufferToVideoFrame, video_frame_output, dst_pixel_rect);
    885 }
    886 
    887 void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished(
    888     bool block_until_finished) {
    889   std::vector<base::Closure> done_callbacks;
    890   CGLSetCurrentContext(context_->cgl_context());
    891   CheckIfAllCopiesAreFinishedWithinContext(
    892       block_until_finished, &done_callbacks);
    893   CGLSetCurrentContext(0);
    894   for (size_t i = 0; i < done_callbacks.size(); ++i)
    895     done_callbacks[i].Run();
    896 }
    897 
    898 void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinishedWithinContext(
    899     bool block_until_finished,
    900     std::vector<base::Closure>* done_callbacks) {
    901   while (!copy_requests_.empty()) {
    902     CopyContext* const copy_context = copy_requests_.front();
    903 
    904     if (copy_context->fence && !glTestFenceAPPLE(copy_context->fence)) {
    905       CHECK_AND_SAVE_GL_ERROR();
    906       // Doing a glFinishFenceAPPLE can cause transparent window flashes when
    907       // switching tabs, so only do it when required.
    908       if (block_until_finished) {
    909         glFinishFenceAPPLE(copy_context->fence);
    910         CHECK_AND_SAVE_GL_ERROR();
    911       } else if (copy_context->cycles_elapsed < kFinishCopyRetryCycles) {
    912         ++copy_context->cycles_elapsed;
    913         // This copy has not completed there is no need to test subsequent
    914         // requests.
    915         break;
    916       }
    917     }
    918     CHECK_AND_SAVE_GL_ERROR();
    919 
    920     bool success = true;
    921     for (int i = 0; success && i < copy_context->num_outputs; ++i) {
    922       TRACE_EVENT1(
    923         "browser",
    924         "CompositingIOSurfaceMac::CheckIfAllCopiesAreFinishedWithinContext",
    925         "plane", i);
    926 
    927       glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context->pixel_buffers[i]);
    928       CHECK_AND_SAVE_GL_ERROR();
    929 
    930       void* buf = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
    931       CHECK_AND_SAVE_GL_ERROR();
    932       success &= copy_context->map_buffer_callback.Run(buf, i);
    933       glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); CHECK_AND_SAVE_GL_ERROR();
    934     }
    935     copy_context->map_buffer_callback.Reset();
    936     glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
    937 
    938     copy_requests_.pop_front();
    939     done_callbacks->push_back(base::Bind(copy_context->done_callback, success));
    940     copy_context->done_callback.Reset();
    941     copy_context_pool_.push_back(copy_context);
    942   }
    943   if (copy_requests_.empty())
    944     finish_copy_timer_.Stop();
    945 
    946   CHECK(copy_requests_.empty() || !block_until_finished);
    947 }
    948 
    949 bool CompositingIOSurfaceMac::SynchronousReadbackForCopy(
    950     const gfx::Rect& dst_pixel_rect,
    951     CopyContext* copy_context,
    952     const SkBitmap* bitmap_output,
    953     const scoped_refptr<media::VideoFrame>& video_frame_output) {
    954   bool success = true;
    955   copy_context->PrepareReadbackFramebuffers();
    956   for (int i = 0; i < copy_context->num_outputs; ++i) {
    957     TRACE_EVENT1(
    958         "browser", "CompositingIOSurfaceMac::SynchronousReadbackForCopy",
    959         "plane", i);
    960 
    961     // Attach the output texture to the FBO.
    962     glBindFramebufferEXT(
    963         GL_READ_FRAMEBUFFER_EXT, copy_context->frame_buffers[i]);
    964     glFramebufferTexture2DEXT(
    965         GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
    966         GL_TEXTURE_RECTANGLE_ARB, copy_context->output_textures[i], 0);
    967     DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
    968                GL_FRAMEBUFFER_COMPLETE_EXT);
    969 
    970     // Blocking read-back of pixels from textures.
    971     void* buf;
    972     // When data must be transferred into a VideoFrame one scanline at a time,
    973     // it is necessary to allocate a separate buffer for glReadPixels() that can
    974     // be populated one-shot.
    975     //
    976     // TODO(miu): Don't keep allocating/deleting this buffer for every frame.
    977     // Keep it cached, allocated on first use.
    978     scoped_ptr<uint32[]> temp_readback_buffer;
    979     if (bitmap_output) {
    980       // The entire SkBitmap is populated, never a region within.  So, read the
    981       // texture directly into the bitmap's pixel memory.
    982       buf = bitmap_output->getPixels();
    983     } else {
    984       // Optimization: If the VideoFrame is letterboxed (not pillarboxed), and
    985       // its stride is equal to the stride of the data being read back, then
    986       // readback directly into the VideoFrame's buffer to save a round of
    987       // memcpy'ing.
    988       //
    989       // TODO(miu): Move these calculations into VideoFrame (need a CalcOffset()
    990       // method).  http://crbug.com/219779
    991       const int src_stride = copy_context->output_texture_sizes[i].width() * 4;
    992       const int dst_stride = video_frame_output->stride(i);
    993       if (src_stride == dst_stride && dst_pixel_rect.x() == 0) {
    994         const int y_offset = dst_pixel_rect.y() / (i == 0 ? 1 : 2);
    995         buf = video_frame_output->data(i) + y_offset * dst_stride;
    996       } else {
    997         // Create and readback into a temporary buffer because the data must be
    998         // transferred to VideoFrame's pixel memory one scanline at a time.
    999         temp_readback_buffer.reset(
   1000             new uint32[copy_context->output_texture_sizes[i].GetArea()]);
   1001         buf = temp_readback_buffer.get();
   1002       }
   1003     }
   1004     glReadPixels(0, 0,
   1005                  copy_context->output_texture_sizes[i].width(),
   1006                  copy_context->output_texture_sizes[i].height(),
   1007                  copy_context->output_readback_format,
   1008                  GL_UNSIGNED_INT_8_8_8_8_REV, buf);
   1009     CHECK_AND_SAVE_GL_ERROR();
   1010     if (video_frame_output.get()) {
   1011       if (!temp_readback_buffer) {
   1012         // Apply letterbox black-out around view region.
   1013         media::LetterboxYUV(video_frame_output.get(), dst_pixel_rect);
   1014       } else {
   1015         // Copy from temporary buffer and fully render the VideoFrame.
   1016         success &= MapBufferToVideoFrame(video_frame_output, dst_pixel_rect,
   1017                                          temp_readback_buffer.get(), i);
   1018       }
   1019     }
   1020   }
   1021 
   1022   glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); CHECK_AND_SAVE_GL_ERROR();
   1023   copy_context_pool_.push_back(copy_context);
   1024   return success;
   1025 }
   1026 
   1027 void CompositingIOSurfaceMac::FailAllCopies() {
   1028   for (size_t i = 0; i < copy_requests_.size(); ++i) {
   1029     copy_requests_[i]->map_buffer_callback.Reset();
   1030 
   1031     base::Callback<void(bool)>& done_callback =
   1032         copy_requests_[i]->done_callback;
   1033     if (!done_callback.is_null()) {
   1034       done_callback.Run(false);
   1035       done_callback.Reset();
   1036     }
   1037   }
   1038 }
   1039 
   1040 void CompositingIOSurfaceMac::DestroyAllCopyContextsWithinContext() {
   1041   // Move all in-flight copies, if any, back into the pool.  Then, destroy all
   1042   // the CopyContexts in the pool.
   1043   copy_context_pool_.insert(copy_context_pool_.end(),
   1044                             copy_requests_.begin(), copy_requests_.end());
   1045   copy_requests_.clear();
   1046   while (!copy_context_pool_.empty()) {
   1047     scoped_ptr<CopyContext> copy_context(copy_context_pool_.back());
   1048     copy_context_pool_.pop_back();
   1049     copy_context->ReleaseCachedGLObjects();
   1050   }
   1051 }
   1052 
   1053 gfx::Rect CompositingIOSurfaceMac::IntersectWithIOSurface(
   1054     const gfx::Rect& rect) const {
   1055   return gfx::IntersectRects(rect,
   1056       gfx::ToEnclosingRect(gfx::Rect(pixel_io_surface_size_)));
   1057 }
   1058 
   1059 GLenum CompositingIOSurfaceMac::GetAndSaveGLError() {
   1060   GLenum gl_error = glGetError();
   1061   if (gl_error_ == GL_NO_ERROR)
   1062     gl_error_ = gl_error;
   1063   return gl_error;
   1064 }
   1065 
   1066 }  // namespace content
   1067