Home | History | Annotate | Download | only in client
      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/common/gpu/client/gl_helper.h"
      6 
      7 #include <queue>
      8 #include <string>
      9 
     10 #include "base/bind.h"
     11 #include "base/debug/trace_event.h"
     12 #include "base/lazy_instance.h"
     13 #include "base/logging.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/strings/string_util.h"
     17 #include "base/time/time.h"
     18 #include "content/common/gpu/client/gl_helper_readback_support.h"
     19 #include "content/common/gpu/client/gl_helper_scaling.h"
     20 #include "gpu/GLES2/gl2extchromium.h"
     21 #include "gpu/command_buffer/client/context_support.h"
     22 #include "gpu/command_buffer/common/mailbox.h"
     23 #include "gpu/command_buffer/common/mailbox_holder.h"
     24 #include "media/base/video_frame.h"
     25 #include "media/base/video_util.h"
     26 #include "third_party/skia/include/core/SkRegion.h"
     27 #include "ui/gfx/rect.h"
     28 #include "ui/gfx/size.h"
     29 
     30 using gpu::gles2::GLES2Interface;
     31 
     32 namespace {
     33 
     34 class ScopedFlush {
     35  public:
     36   explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
     37 
     38   ~ScopedFlush() { gl_->Flush(); }
     39 
     40  private:
     41   gpu::gles2::GLES2Interface* gl_;
     42 
     43   DISALLOW_COPY_AND_ASSIGN(ScopedFlush);
     44 };
     45 
     46 // Helper class for allocating and holding an RGBA texture of a given
     47 // size and an associated framebuffer.
     48 class TextureFrameBufferPair {
     49  public:
     50   TextureFrameBufferPair(GLES2Interface* gl, gfx::Size size)
     51       : texture_(gl), framebuffer_(gl), size_(size) {
     52     content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_);
     53     gl->TexImage2D(GL_TEXTURE_2D,
     54                    0,
     55                    GL_RGBA,
     56                    size.width(),
     57                    size.height(),
     58                    0,
     59                    GL_RGBA,
     60                    GL_UNSIGNED_BYTE,
     61                    NULL);
     62     content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
     63         gl, framebuffer_);
     64     gl->FramebufferTexture2D(
     65         GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
     66   }
     67 
     68   GLuint texture() const { return texture_.id(); }
     69   GLuint framebuffer() const { return framebuffer_.id(); }
     70   gfx::Size size() const { return size_; }
     71 
     72  private:
     73   content::ScopedTexture texture_;
     74   content::ScopedFramebuffer framebuffer_;
     75   gfx::Size size_;
     76 
     77   DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair);
     78 };
     79 
     80 // Helper class for holding a scaler, a texture for the output of that
     81 // scaler and an associated frame buffer. This is inteded to be used
     82 // when the output of a scaler is to be sent to a readback.
     83 class ScalerHolder {
     84  public:
     85   ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler)
     86       : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {}
     87 
     88   void Scale(GLuint src_texture) {
     89     scaler_->Scale(src_texture, texture_and_framebuffer_.texture());
     90   }
     91 
     92   content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); }
     93   TextureFrameBufferPair* texture_and_framebuffer() {
     94     return &texture_and_framebuffer_;
     95   }
     96   GLuint texture() const { return texture_and_framebuffer_.texture(); }
     97 
     98  private:
     99   TextureFrameBufferPair texture_and_framebuffer_;
    100   scoped_ptr<content::GLHelper::ScalerInterface> scaler_;
    101 
    102   DISALLOW_COPY_AND_ASSIGN(ScalerHolder);
    103 };
    104 
    105 }  // namespace
    106 
    107 namespace content {
    108 typedef GLHelperReadbackSupport::FormatSupport FormatSupport;
    109 
    110 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
    111 // the data needed for it.
    112 class GLHelper::CopyTextureToImpl
    113     : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
    114  public:
    115   CopyTextureToImpl(GLES2Interface* gl,
    116                     gpu::ContextSupport* context_support,
    117                     GLHelper* helper)
    118       : gl_(gl),
    119         context_support_(context_support),
    120         helper_(helper),
    121         flush_(gl),
    122         max_draw_buffers_(0) {
    123     const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS);
    124     if (!extensions)
    125       return;
    126     std::string extensions_string =
    127         " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
    128     if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) {
    129       gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
    130     }
    131   }
    132   ~CopyTextureToImpl() { CancelRequests(); }
    133 
    134   GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
    135                                  uint32 sync_point) {
    136     return helper_->ConsumeMailboxToTexture(mailbox, sync_point);
    137   }
    138 
    139   void CropScaleReadbackAndCleanTexture(
    140       GLuint src_texture,
    141       const gfx::Size& src_size,
    142       const gfx::Rect& src_subrect,
    143       const gfx::Size& dst_size,
    144       unsigned char* out,
    145       const SkColorType out_color_type,
    146       const base::Callback<void(bool)>& callback,
    147       GLHelper::ScalerQuality quality);
    148 
    149   void ReadbackTextureSync(GLuint texture,
    150                            const gfx::Rect& src_rect,
    151                            unsigned char* out,
    152                            SkColorType format);
    153 
    154   void ReadbackTextureAsync(GLuint texture,
    155                             const gfx::Size& dst_size,
    156                             unsigned char* out,
    157                             SkColorType color_type,
    158                             const base::Callback<void(bool)>& callback);
    159 
    160   // Reads back bytes from the currently bound frame buffer.
    161   // Note that dst_size is specified in bytes, not pixels.
    162   void ReadbackAsync(const gfx::Size& dst_size,
    163                      int32 bytes_per_row,     // generally dst_size.width() * 4
    164                      int32 row_stride_bytes,  // generally dst_size.width() * 4
    165                      unsigned char* out,
    166                      GLenum format,
    167                      GLenum type,
    168                      size_t bytes_per_pixel,
    169                      const base::Callback<void(bool)>& callback);
    170 
    171   void ReadbackPlane(TextureFrameBufferPair* source,
    172                      const scoped_refptr<media::VideoFrame>& target,
    173                      int plane,
    174                      int size_shift,
    175                      const gfx::Rect& dst_subrect,
    176                      ReadbackSwizzle swizzle,
    177                      const base::Callback<void(bool)>& callback);
    178 
    179   GLuint CopyAndScaleTexture(GLuint texture,
    180                              const gfx::Size& src_size,
    181                              const gfx::Size& dst_size,
    182                              bool vertically_flip_texture,
    183                              GLHelper::ScalerQuality quality);
    184 
    185   ReadbackYUVInterface* CreateReadbackPipelineYUV(
    186       GLHelper::ScalerQuality quality,
    187       const gfx::Size& src_size,
    188       const gfx::Rect& src_subrect,
    189       const gfx::Size& dst_size,
    190       const gfx::Rect& dst_subrect,
    191       bool flip_vertically,
    192       bool use_mrt);
    193 
    194   // Returns the maximum number of draw buffers available,
    195   // 0 if GL_EXT_draw_buffers is not available.
    196   GLint MaxDrawBuffers() const { return max_draw_buffers_; }
    197 
    198   FormatSupport GetReadbackConfig(SkColorType color_type,
    199                                   bool can_swizzle,
    200                                   GLenum* format,
    201                                   GLenum* type,
    202                                   size_t* bytes_per_pixel);
    203 
    204  private:
    205   // A single request to CropScaleReadbackAndCleanTexture.
    206   // The main thread can cancel the request, before it's handled by the helper
    207   // thread, by resetting the texture and pixels fields. Alternatively, the
    208   // thread marks that it handles the request by resetting the pixels field
    209   // (meaning it guarantees that the callback with be called).
    210   // In either case, the callback must be called exactly once, and the texture
    211   // must be deleted by the main thread gl.
    212   struct Request {
    213     Request(const gfx::Size& size_,
    214             int32 bytes_per_row_,
    215             int32 row_stride_bytes_,
    216             unsigned char* pixels_,
    217             const base::Callback<void(bool)>& callback_)
    218         : done(false),
    219           size(size_),
    220           bytes_per_row(bytes_per_row_),
    221           row_stride_bytes(row_stride_bytes_),
    222           pixels(pixels_),
    223           callback(callback_),
    224           buffer(0),
    225           query(0) {}
    226 
    227     bool done;
    228     gfx::Size size;
    229     int bytes_per_row;
    230     int row_stride_bytes;
    231     unsigned char* pixels;
    232     base::Callback<void(bool)> callback;
    233     GLuint buffer;
    234     GLuint query;
    235   };
    236 
    237   // A readback pipeline that also converts the data to YUV before
    238   // reading it back.
    239   class ReadbackYUVImpl : public ReadbackYUVInterface {
    240    public:
    241     ReadbackYUVImpl(GLES2Interface* gl,
    242                     CopyTextureToImpl* copy_impl,
    243                     GLHelperScaling* scaler_impl,
    244                     GLHelper::ScalerQuality quality,
    245                     const gfx::Size& src_size,
    246                     const gfx::Rect& src_subrect,
    247                     const gfx::Size& dst_size,
    248                     const gfx::Rect& dst_subrect,
    249                     bool flip_vertically,
    250                     ReadbackSwizzle swizzle);
    251 
    252     virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
    253                              uint32 sync_point,
    254                              const scoped_refptr<media::VideoFrame>& target,
    255                              const base::Callback<void(bool)>& callback)
    256         OVERRIDE;
    257 
    258     virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); }
    259 
    260    private:
    261     GLES2Interface* gl_;
    262     CopyTextureToImpl* copy_impl_;
    263     gfx::Size dst_size_;
    264     gfx::Rect dst_subrect_;
    265     ReadbackSwizzle swizzle_;
    266     ScalerHolder scaler_;
    267     ScalerHolder y_;
    268     ScalerHolder u_;
    269     ScalerHolder v_;
    270 
    271     DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl);
    272   };
    273 
    274   // A readback pipeline that also converts the data to YUV before
    275   // reading it back. This one uses Multiple Render Targets, which
    276   // may not be supported on all platforms.
    277   class ReadbackYUV_MRT : public ReadbackYUVInterface {
    278    public:
    279     ReadbackYUV_MRT(GLES2Interface* gl,
    280                     CopyTextureToImpl* copy_impl,
    281                     GLHelperScaling* scaler_impl,
    282                     GLHelper::ScalerQuality quality,
    283                     const gfx::Size& src_size,
    284                     const gfx::Rect& src_subrect,
    285                     const gfx::Size& dst_size,
    286                     const gfx::Rect& dst_subrect,
    287                     bool flip_vertically,
    288                     ReadbackSwizzle swizzle);
    289 
    290     virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
    291                              uint32 sync_point,
    292                              const scoped_refptr<media::VideoFrame>& target,
    293                              const base::Callback<void(bool)>& callback)
    294         OVERRIDE;
    295 
    296     virtual ScalerInterface* scaler() OVERRIDE { return scaler_.scaler(); }
    297 
    298    private:
    299     GLES2Interface* gl_;
    300     CopyTextureToImpl* copy_impl_;
    301     gfx::Size dst_size_;
    302     gfx::Rect dst_subrect_;
    303     GLHelper::ScalerQuality quality_;
    304     ReadbackSwizzle swizzle_;
    305     ScalerHolder scaler_;
    306     scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
    307     scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
    308     TextureFrameBufferPair y_;
    309     ScopedTexture uv_;
    310     TextureFrameBufferPair u_;
    311     TextureFrameBufferPair v_;
    312 
    313     DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT);
    314   };
    315 
    316   // Copies the block of pixels specified with |src_subrect| from |src_texture|,
    317   // scales it to |dst_size|, writes it into a texture, and returns its ID.
    318   // |src_size| is the size of |src_texture|.
    319   GLuint ScaleTexture(GLuint src_texture,
    320                       const gfx::Size& src_size,
    321                       const gfx::Rect& src_subrect,
    322                       const gfx::Size& dst_size,
    323                       bool vertically_flip_texture,
    324                       bool swizzle,
    325                       SkColorType color_type,
    326                       GLHelper::ScalerQuality quality);
    327 
    328   // Converts each four consecutive pixels of the source texture into one pixel
    329   // in the result texture with each pixel channel representing the grayscale
    330   // color of one of the four original pixels:
    331   // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4
    332   // The resulting texture is still an RGBA texture (which is ~4 times narrower
    333   // than the original). If rendered directly, it wouldn't show anything useful,
    334   // but the data in it can be used to construct a grayscale image.
    335   // |encoded_texture_size| is the exact size of the resulting RGBA texture. It
    336   // is equal to src_size.width()/4 rounded upwards. Some channels in the last
    337   // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain
    338   // useful data.
    339   // If swizzle is set to true, the transformed pixels are reordered:
    340   // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4.
    341   GLuint EncodeTextureAsGrayscale(GLuint src_texture,
    342                                   const gfx::Size& src_size,
    343                                   gfx::Size* const encoded_texture_size,
    344                                   bool vertically_flip_texture,
    345                                   bool swizzle);
    346 
    347   static void nullcallback(bool success) {}
    348   void ReadbackDone(Request *request, int bytes_per_pixel);
    349   void FinishRequest(Request* request, bool result);
    350   void CancelRequests();
    351 
    352   static const float kRGBtoYColorWeights[];
    353   static const float kRGBtoUColorWeights[];
    354   static const float kRGBtoVColorWeights[];
    355   static const float kRGBtoGrayscaleColorWeights[];
    356 
    357   GLES2Interface* gl_;
    358   gpu::ContextSupport* context_support_;
    359   GLHelper* helper_;
    360 
    361   // A scoped flush that will ensure all resource deletions are flushed when
    362   // this object is destroyed. Must be declared before other Scoped* fields.
    363   ScopedFlush flush_;
    364 
    365   std::queue<Request*> request_queue_;
    366   GLint max_draw_buffers_;
    367 };
    368 
    369 GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality,
    370                                                   const gfx::Size& src_size,
    371                                                   const gfx::Rect& src_subrect,
    372                                                   const gfx::Size& dst_size,
    373                                                   bool vertically_flip_texture,
    374                                                   bool swizzle) {
    375   InitScalerImpl();
    376   return scaler_impl_->CreateScaler(quality,
    377                                     src_size,
    378                                     src_subrect,
    379                                     dst_size,
    380                                     vertically_flip_texture,
    381                                     swizzle);
    382 }
    383 
    384 GLuint GLHelper::CopyTextureToImpl::ScaleTexture(
    385     GLuint src_texture,
    386     const gfx::Size& src_size,
    387     const gfx::Rect& src_subrect,
    388     const gfx::Size& dst_size,
    389     bool vertically_flip_texture,
    390     bool swizzle,
    391     SkColorType color_type,
    392     GLHelper::ScalerQuality quality) {
    393   GLuint dst_texture = 0u;
    394   gl_->GenTextures(1, &dst_texture);
    395   {
    396     GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE;
    397     ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
    398 
    399     // Use GL_RGBA for destination/temporary texture unless we're working with
    400     // 16-bit data
    401     if (color_type == kRGB_565_SkColorType) {
    402       format = GL_RGB;
    403       type = GL_UNSIGNED_SHORT_5_6_5;
    404     }
    405 
    406     gl_->TexImage2D(GL_TEXTURE_2D,
    407                     0,
    408                     format,
    409                     dst_size.width(),
    410                     dst_size.height(),
    411                     0,
    412                     format,
    413                     type,
    414                     NULL);
    415   }
    416   scoped_ptr<ScalerInterface> scaler(
    417       helper_->CreateScaler(quality,
    418                             src_size,
    419                             src_subrect,
    420                             dst_size,
    421                             vertically_flip_texture,
    422                             swizzle));
    423   scaler->Scale(src_texture, dst_texture);
    424   return dst_texture;
    425 }
    426 
    427 GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale(
    428     GLuint src_texture,
    429     const gfx::Size& src_size,
    430     gfx::Size* const encoded_texture_size,
    431     bool vertically_flip_texture,
    432     bool swizzle) {
    433   GLuint dst_texture = 0u;
    434   gl_->GenTextures(1, &dst_texture);
    435   // The size of the encoded texture.
    436   *encoded_texture_size =
    437       gfx::Size((src_size.width() + 3) / 4, src_size.height());
    438   {
    439     ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
    440     gl_->TexImage2D(GL_TEXTURE_2D,
    441                     0,
    442                     GL_RGBA,
    443                     encoded_texture_size->width(),
    444                     encoded_texture_size->height(),
    445                     0,
    446                     GL_RGBA,
    447                     GL_UNSIGNED_BYTE,
    448                     NULL);
    449   }
    450 
    451   helper_->InitScalerImpl();
    452   scoped_ptr<ScalerInterface> grayscale_scaler(
    453       helper_->scaler_impl_.get()->CreatePlanarScaler(
    454           src_size,
    455           gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()),
    456           *encoded_texture_size,
    457           vertically_flip_texture,
    458           swizzle,
    459           kRGBtoGrayscaleColorWeights));
    460   grayscale_scaler->Scale(src_texture, dst_texture);
    461   return dst_texture;
    462 }
    463 
    464 void GLHelper::CopyTextureToImpl::ReadbackAsync(
    465     const gfx::Size& dst_size,
    466     int32 bytes_per_row,
    467     int32 row_stride_bytes,
    468     unsigned char* out,
    469     GLenum format,
    470     GLenum type,
    471     size_t bytes_per_pixel,
    472     const base::Callback<void(bool)>& callback) {
    473   TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync");
    474   Request* request =
    475       new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback);
    476   request_queue_.push(request);
    477   request->buffer = 0u;
    478 
    479   gl_->GenBuffers(1, &request->buffer);
    480   gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
    481   gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
    482                   bytes_per_pixel * dst_size.GetArea(),
    483                   NULL,
    484                   GL_STREAM_READ);
    485 
    486   request->query = 0u;
    487   gl_->GenQueriesEXT(1, &request->query);
    488   gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query);
    489   gl_->ReadPixels(0,
    490                   0,
    491                   dst_size.width(),
    492                   dst_size.height(),
    493                   format,
    494                   type,
    495                   NULL);
    496   gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
    497   gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
    498   context_support_->SignalQuery(
    499       request->query,
    500       base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(),
    501                  request, bytes_per_pixel));
    502 }
    503 
    504 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
    505     GLuint src_texture,
    506     const gfx::Size& src_size,
    507     const gfx::Rect& src_subrect,
    508     const gfx::Size& dst_size,
    509     unsigned char* out,
    510     const SkColorType out_color_type,
    511     const base::Callback<void(bool)>& callback,
    512     GLHelper::ScalerQuality quality) {
    513   GLenum format, type;
    514   size_t bytes_per_pixel;
    515   SkColorType readback_color_type = out_color_type;
    516   // Single-component textures are not supported by all GPUs, so  we implement
    517   // kAlpha_8_SkColorType support here via a special encoding (see below) using
    518   // a 32-bit texture to represent an 8-bit image.
    519   // Thus we use generic 32-bit readback in this case.
    520   if (out_color_type == kAlpha_8_SkColorType) {
    521     readback_color_type = kRGBA_8888_SkColorType;
    522   }
    523 
    524   FormatSupport supported = GetReadbackConfig(
    525       readback_color_type, true, &format, &type, &bytes_per_pixel);
    526 
    527   if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
    528     callback.Run(false);
    529     return;
    530   }
    531 
    532   GLuint texture = src_texture;
    533 
    534   // Scale texture if needed
    535   // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we
    536   // can do just as well in EncodeTextureAsGrayscale, which we will do if
    537   // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step
    538   // in that case.
    539   bool scale_texture = out_color_type != kAlpha_8_SkColorType ||
    540                        quality != GLHelper::SCALER_QUALITY_FAST;
    541   if (scale_texture) {
    542     // Don't swizzle during the scale step for kAlpha_8_SkColorType.
    543     // We will swizzle in the encode step below if needed.
    544     bool scale_swizzle = out_color_type == kAlpha_8_SkColorType
    545                              ? false
    546                              : supported == GLHelperReadbackSupport::SWIZZLE;
    547     texture =
    548         ScaleTexture(src_texture,
    549                      src_size,
    550                      src_subrect,
    551                      dst_size,
    552                      true,
    553                      scale_swizzle,
    554                      out_color_type == kAlpha_8_SkColorType ? kN32_SkColorType
    555                                                             : out_color_type,
    556                      quality);
    557     DCHECK(texture);
    558   }
    559 
    560   gfx::Size readback_texture_size = dst_size;
    561   // Encode texture to grayscale if needed.
    562   if (out_color_type == kAlpha_8_SkColorType) {
    563     // Do the vertical flip here if we haven't already done it when we scaled
    564     // the texture.
    565     bool encode_as_grayscale_vertical_flip = !scale_texture;
    566     // EncodeTextureAsGrayscale by default creates a texture which should be
    567     // read back as RGBA, so need to swizzle if the readback format is BGRA.
    568     bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT;
    569     GLuint tmp_texture =
    570         EncodeTextureAsGrayscale(texture,
    571                                  dst_size,
    572                                  &readback_texture_size,
    573                                  encode_as_grayscale_vertical_flip,
    574                                  encode_as_grayscale_swizzle);
    575     // If the scaled texture was created - delete it
    576     if (scale_texture)
    577       gl_->DeleteTextures(1, &texture);
    578     texture = tmp_texture;
    579     DCHECK(texture);
    580   }
    581 
    582   // Readback the pixels of the resulting texture
    583   ScopedFramebuffer dst_framebuffer(gl_);
    584   ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
    585                                                              dst_framebuffer);
    586   ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
    587   gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
    588                             GL_COLOR_ATTACHMENT0,
    589                             GL_TEXTURE_2D,
    590                             texture,
    591                             0);
    592 
    593   int32 bytes_per_row = out_color_type == kAlpha_8_SkColorType
    594                             ? dst_size.width()
    595                             : dst_size.width() * bytes_per_pixel;
    596 
    597   ReadbackAsync(readback_texture_size,
    598                 bytes_per_row,
    599                 bytes_per_row,
    600                 out,
    601                 format,
    602                 type,
    603                 bytes_per_pixel,
    604                 callback);
    605   gl_->DeleteTextures(1, &texture);
    606 }
    607 
    608 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
    609     GLuint texture,
    610     const gfx::Rect& src_rect,
    611     unsigned char* out,
    612     SkColorType color_type) {
    613   GLenum format, type;
    614   size_t bytes_per_pixel;
    615   FormatSupport supported =
    616       GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
    617   if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
    618     return;
    619   }
    620 
    621   ScopedFramebuffer dst_framebuffer(gl_);
    622   ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
    623                                                              dst_framebuffer);
    624   ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
    625   gl_->FramebufferTexture2D(
    626       GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    627   gl_->ReadPixels(src_rect.x(),
    628                   src_rect.y(),
    629                   src_rect.width(),
    630                   src_rect.height(),
    631                   format,
    632                   type,
    633                   out);
    634 }
    635 
    636 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
    637     GLuint texture,
    638     const gfx::Size& dst_size,
    639     unsigned char* out,
    640     SkColorType color_type,
    641     const base::Callback<void(bool)>& callback) {
    642   GLenum format, type;
    643   size_t bytes_per_pixel;
    644   FormatSupport supported =
    645       GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
    646   if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
    647     callback.Run(false);
    648     return;
    649   }
    650 
    651   ScopedFramebuffer dst_framebuffer(gl_);
    652   ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
    653                                                              dst_framebuffer);
    654   ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
    655   gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
    656                             GL_COLOR_ATTACHMENT0,
    657                             GL_TEXTURE_2D,
    658                             texture,
    659                             0);
    660   ReadbackAsync(dst_size,
    661                 dst_size.width() * bytes_per_pixel,
    662                 dst_size.width() * bytes_per_pixel,
    663                 out,
    664                 format,
    665                 type,
    666                 bytes_per_pixel,
    667                 callback);
    668 }
    669 
    670 GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
    671     GLuint src_texture,
    672     const gfx::Size& src_size,
    673     const gfx::Size& dst_size,
    674     bool vertically_flip_texture,
    675     GLHelper::ScalerQuality quality) {
    676   return ScaleTexture(src_texture,
    677                       src_size,
    678                       gfx::Rect(src_size),
    679                       dst_size,
    680                       vertically_flip_texture,
    681                       false,
    682                       kRGBA_8888_SkColorType,  // GL_RGBA
    683                       quality);
    684 }
    685 
    686 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
    687                                                int bytes_per_pixel) {
    688   TRACE_EVENT0("mirror",
    689                "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
    690   finished_request->done = true;
    691 
    692   // We process transfer requests in the order they were received, regardless
    693   // of the order we get the callbacks in.
    694   while (!request_queue_.empty()) {
    695     Request* request = request_queue_.front();
    696     if (!request->done) {
    697       break;
    698     }
    699 
    700     bool result = false;
    701     if (request->buffer != 0) {
    702       gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
    703       unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM(
    704           GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
    705       if (data) {
    706         result = true;
    707         if (request->bytes_per_row == request->size.width() * bytes_per_pixel &&
    708             request->bytes_per_row == request->row_stride_bytes) {
    709           memcpy(request->pixels, data,
    710                  request->size.GetArea() * bytes_per_pixel);
    711         } else {
    712           unsigned char* out = request->pixels;
    713           for (int y = 0; y < request->size.height(); y++) {
    714             memcpy(out, data, request->bytes_per_row);
    715             out += request->row_stride_bytes;
    716             data += request->size.width() * bytes_per_pixel;
    717           }
    718         }
    719         gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
    720       }
    721       gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
    722     }
    723     FinishRequest(request, result);
    724   }
    725 }
    726 
    727 void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) {
    728   TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
    729   DCHECK(request_queue_.front() == request);
    730   request_queue_.pop();
    731   request->callback.Run(result);
    732   ScopedFlush flush(gl_);
    733   if (request->query != 0) {
    734     gl_->DeleteQueriesEXT(1, &request->query);
    735     request->query = 0;
    736   }
    737   if (request->buffer != 0) {
    738     gl_->DeleteBuffers(1, &request->buffer);
    739     request->buffer = 0;
    740   }
    741   delete request;
    742 }
    743 
    744 void GLHelper::CopyTextureToImpl::CancelRequests() {
    745   while (!request_queue_.empty()) {
    746     Request* request = request_queue_.front();
    747     FinishRequest(request, false);
    748   }
    749 }
    750 
    751 FormatSupport GLHelper::CopyTextureToImpl::GetReadbackConfig(
    752     SkColorType color_type,
    753     bool can_swizzle,
    754     GLenum* format,
    755     GLenum* type,
    756     size_t* bytes_per_pixel) {
    757   return helper_->readback_support_->GetReadbackConfig(
    758       color_type, can_swizzle, format, type, bytes_per_pixel);
    759 }
    760 
    761 GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
    762     : gl_(gl),
    763       context_support_(context_support),
    764       readback_support_(new GLHelperReadbackSupport(gl)) {}
    765 
    766 GLHelper::~GLHelper() {}
    767 
    768 void GLHelper::CropScaleReadbackAndCleanTexture(
    769     GLuint src_texture,
    770     const gfx::Size& src_size,
    771     const gfx::Rect& src_subrect,
    772     const gfx::Size& dst_size,
    773     unsigned char* out,
    774     const SkColorType out_color_type,
    775     const base::Callback<void(bool)>& callback,
    776     GLHelper::ScalerQuality quality) {
    777   InitCopyTextToImpl();
    778   copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture,
    779                                                           src_size,
    780                                                           src_subrect,
    781                                                           dst_size,
    782                                                           out,
    783                                                           out_color_type,
    784                                                           callback,
    785                                                           quality);
    786 }
    787 
    788 void GLHelper::CropScaleReadbackAndCleanMailbox(
    789     const gpu::Mailbox& src_mailbox,
    790     uint32 sync_point,
    791     const gfx::Size& src_size,
    792     const gfx::Rect& src_subrect,
    793     const gfx::Size& dst_size,
    794     unsigned char* out,
    795     const SkColorType out_color_type,
    796     const base::Callback<void(bool)>& callback,
    797     GLHelper::ScalerQuality quality) {
    798   GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point);
    799   CropScaleReadbackAndCleanTexture(mailbox_texture,
    800                                    src_size,
    801                                    src_subrect,
    802                                    dst_size,
    803                                    out,
    804                                    out_color_type,
    805                                    callback,
    806                                    quality);
    807   gl_->DeleteTextures(1, &mailbox_texture);
    808 }
    809 
    810 void GLHelper::ReadbackTextureSync(GLuint texture,
    811                                    const gfx::Rect& src_rect,
    812                                    unsigned char* out,
    813                                    SkColorType format) {
    814   InitCopyTextToImpl();
    815   copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format);
    816 }
    817 
    818 void GLHelper::ReadbackTextureAsync(
    819     GLuint texture,
    820     const gfx::Size& dst_size,
    821     unsigned char* out,
    822     SkColorType color_type,
    823     const base::Callback<void(bool)>& callback) {
    824   InitCopyTextToImpl();
    825   copy_texture_to_impl_->ReadbackTextureAsync(texture,
    826                                               dst_size,
    827                                               out,
    828                                               color_type,
    829                                               callback);
    830 }
    831 
    832 GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) {
    833   InitCopyTextToImpl();
    834   return copy_texture_to_impl_->CopyAndScaleTexture(
    835       texture, size, size, false, GLHelper::SCALER_QUALITY_FAST);
    836 }
    837 
    838 GLuint GLHelper::CopyAndScaleTexture(GLuint texture,
    839                                      const gfx::Size& src_size,
    840                                      const gfx::Size& dst_size,
    841                                      bool vertically_flip_texture,
    842                                      ScalerQuality quality) {
    843   InitCopyTextToImpl();
    844   return copy_texture_to_impl_->CopyAndScaleTexture(
    845       texture, src_size, dst_size, vertically_flip_texture, quality);
    846 }
    847 
    848 GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) {
    849   GLuint shader = gl_->CreateShader(type);
    850   GLint length = strlen(source);
    851   gl_->ShaderSource(shader, 1, &source, &length);
    852   gl_->CompileShader(shader);
    853   GLint compile_status = 0;
    854   gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
    855   if (!compile_status) {
    856     GLint log_length = 0;
    857     gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
    858     if (log_length) {
    859       scoped_ptr<GLchar[]> log(new GLchar[log_length]);
    860       GLsizei returned_log_length = 0;
    861       gl_->GetShaderInfoLog(
    862           shader, log_length, &returned_log_length, log.get());
    863       LOG(ERROR) << std::string(log.get(), returned_log_length);
    864     }
    865     gl_->DeleteShader(shader);
    866     return 0;
    867   }
    868   return shader;
    869 }
    870 
    871 void GLHelper::InitCopyTextToImpl() {
    872   // Lazily initialize |copy_texture_to_impl_|
    873   if (!copy_texture_to_impl_)
    874     copy_texture_to_impl_.reset(
    875         new CopyTextureToImpl(gl_, context_support_, this));
    876 }
    877 
    878 void GLHelper::InitScalerImpl() {
    879   // Lazily initialize |scaler_impl_|
    880   if (!scaler_impl_)
    881     scaler_impl_.reset(new GLHelperScaling(gl_, this));
    882 }
    883 
    884 GLint GLHelper::MaxDrawBuffers() {
    885   InitCopyTextToImpl();
    886   return copy_texture_to_impl_->MaxDrawBuffers();
    887 }
    888 
    889 void GLHelper::CopySubBufferDamage(GLuint texture,
    890                                    GLuint previous_texture,
    891                                    const SkRegion& new_damage,
    892                                    const SkRegion& old_damage) {
    893   SkRegion region(old_damage);
    894   if (region.op(new_damage, SkRegion::kDifference_Op)) {
    895     ScopedFramebuffer dst_framebuffer(gl_);
    896     ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
    897                                                                dst_framebuffer);
    898     ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
    899     gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
    900                               GL_COLOR_ATTACHMENT0,
    901                               GL_TEXTURE_2D,
    902                               previous_texture,
    903                               0);
    904     for (SkRegion::Iterator it(region); !it.done(); it.next()) {
    905       const SkIRect& rect = it.rect();
    906       gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
    907                              0,
    908                              rect.x(),
    909                              rect.y(),
    910                              rect.x(),
    911                              rect.y(),
    912                              rect.width(),
    913                              rect.height());
    914     }
    915     gl_->Flush();
    916   }
    917 }
    918 
    919 GLuint GLHelper::CreateTexture() {
    920   GLuint texture = 0u;
    921   gl_->GenTextures(1, &texture);
    922   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
    923   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    924   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    925   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    926   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    927   return texture;
    928 }
    929 
    930 void GLHelper::DeleteTexture(GLuint texture_id) {
    931   gl_->DeleteTextures(1, &texture_id);
    932 }
    933 
    934 uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
    935 
    936 void GLHelper::WaitSyncPoint(uint32 sync_point) {
    937   gl_->WaitSyncPointCHROMIUM(sync_point);
    938 }
    939 
    940 gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture(
    941     GLuint texture_id) {
    942   gpu::Mailbox mailbox;
    943   gl_->GenMailboxCHROMIUM(mailbox.name);
    944   gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name);
    945   return gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, InsertSyncPoint());
    946 }
    947 
    948 GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
    949                                          uint32 sync_point) {
    950   if (mailbox.IsZero())
    951     return 0;
    952   if (sync_point)
    953     WaitSyncPoint(sync_point);
    954   GLuint texture =
    955       gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    956   return texture;
    957 }
    958 
    959 void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) {
    960   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
    961   gl_->TexImage2D(GL_TEXTURE_2D,
    962                   0,
    963                   GL_RGB,
    964                   size.width(),
    965                   size.height(),
    966                   0,
    967                   GL_RGB,
    968                   GL_UNSIGNED_BYTE,
    969                   NULL);
    970 }
    971 
    972 void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) {
    973   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
    974   gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
    975                          0,
    976                          rect.x(),
    977                          rect.y(),
    978                          rect.x(),
    979                          rect.y(),
    980                          rect.width(),
    981                          rect.height());
    982 }
    983 
    984 void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) {
    985   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
    986   gl_->CopyTexImage2D(
    987       GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0);
    988 }
    989 
    990 void GLHelper::Flush() {
    991   gl_->Flush();
    992 }
    993 
    994 void GLHelper::CopyTextureToImpl::ReadbackPlane(
    995     TextureFrameBufferPair* source,
    996     const scoped_refptr<media::VideoFrame>& target,
    997     int plane,
    998     int size_shift,
    999     const gfx::Rect& dst_subrect,
   1000     ReadbackSwizzle swizzle,
   1001     const base::Callback<void(bool)>& callback) {
   1002   gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
   1003   size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) +
   1004       (dst_subrect.x() >> size_shift);
   1005   ReadbackAsync(source->size(),
   1006                 dst_subrect.width() >> size_shift,
   1007                 target->stride(plane),
   1008                 target->data(plane) + offset,
   1009                 (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA,
   1010                 GL_UNSIGNED_BYTE,
   1011                 4,
   1012                 callback);
   1013 }
   1014 
   1015 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
   1016     0.257f, 0.504f, 0.098f, 0.0625f};
   1017 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
   1018     -0.148f, -0.291f, 0.439f, 0.5f};
   1019 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
   1020     0.439f, -0.368f, -0.071f, 0.5f};
   1021 const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = {
   1022     0.213f, 0.715f, 0.072f, 0.0f};
   1023 
   1024 // YUV readback constructors. Initiates the main scaler pipeline and
   1025 // one planar scaler for each of the Y, U and V planes.
   1026 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
   1027     GLES2Interface* gl,
   1028     CopyTextureToImpl* copy_impl,
   1029     GLHelperScaling* scaler_impl,
   1030     GLHelper::ScalerQuality quality,
   1031     const gfx::Size& src_size,
   1032     const gfx::Rect& src_subrect,
   1033     const gfx::Size& dst_size,
   1034     const gfx::Rect& dst_subrect,
   1035     bool flip_vertically,
   1036     ReadbackSwizzle swizzle)
   1037     : gl_(gl),
   1038       copy_impl_(copy_impl),
   1039       dst_size_(dst_size),
   1040       dst_subrect_(dst_subrect),
   1041       swizzle_(swizzle),
   1042       scaler_(gl,
   1043               scaler_impl->CreateScaler(quality,
   1044                                         src_size,
   1045                                         src_subrect,
   1046                                         dst_subrect.size(),
   1047                                         flip_vertically,
   1048                                         false)),
   1049       y_(gl,
   1050          scaler_impl->CreatePlanarScaler(
   1051              dst_subrect.size(),
   1052              gfx::Rect(0,
   1053                        0,
   1054                        (dst_subrect.width() + 3) & ~3,
   1055                        dst_subrect.height()),
   1056              gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
   1057              false,
   1058              (swizzle == kSwizzleBGRA),
   1059              kRGBtoYColorWeights)),
   1060       u_(gl,
   1061          scaler_impl->CreatePlanarScaler(
   1062              dst_subrect.size(),
   1063              gfx::Rect(0,
   1064                        0,
   1065                        (dst_subrect.width() + 7) & ~7,
   1066                        (dst_subrect.height() + 1) & ~1),
   1067              gfx::Size((dst_subrect.width() + 7) / 8,
   1068                        (dst_subrect.height() + 1) / 2),
   1069              false,
   1070              (swizzle == kSwizzleBGRA),
   1071              kRGBtoUColorWeights)),
   1072       v_(gl,
   1073          scaler_impl->CreatePlanarScaler(
   1074              dst_subrect.size(),
   1075              gfx::Rect(0,
   1076                        0,
   1077                        (dst_subrect.width() + 7) & ~7,
   1078                        (dst_subrect.height() + 1) & ~1),
   1079              gfx::Size((dst_subrect.width() + 7) / 8,
   1080                        (dst_subrect.height() + 1) / 2),
   1081              false,
   1082              (swizzle == kSwizzleBGRA),
   1083              kRGBtoVColorWeights)) {
   1084   DCHECK(!(dst_size.width() & 1));
   1085   DCHECK(!(dst_size.height() & 1));
   1086   DCHECK(!(dst_subrect.width() & 1));
   1087   DCHECK(!(dst_subrect.height() & 1));
   1088   DCHECK(!(dst_subrect.x() & 1));
   1089   DCHECK(!(dst_subrect.y() & 1));
   1090 }
   1091 
   1092 static void CallbackKeepingVideoFrameAlive(
   1093     scoped_refptr<media::VideoFrame> video_frame,
   1094     const base::Callback<void(bool)>& callback,
   1095     bool success) {
   1096   callback.Run(success);
   1097 }
   1098 
   1099 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
   1100     const gpu::Mailbox& mailbox,
   1101     uint32 sync_point,
   1102     const scoped_refptr<media::VideoFrame>& target,
   1103     const base::Callback<void(bool)>& callback) {
   1104   GLuint mailbox_texture =
   1105       copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
   1106 
   1107   // Scale texture to right size.
   1108   scaler_.Scale(mailbox_texture);
   1109   gl_->DeleteTextures(1, &mailbox_texture);
   1110 
   1111   // Convert the scaled texture in to Y, U and V planes.
   1112   y_.Scale(scaler_.texture());
   1113   u_.Scale(scaler_.texture());
   1114   v_.Scale(scaler_.texture());
   1115 
   1116   if (target->coded_size() != dst_size_) {
   1117     DCHECK(target->coded_size() == dst_size_);
   1118     LOG(ERROR) << "ReadbackYUV size error!";
   1119     callback.Run(false);
   1120     return;
   1121   }
   1122 
   1123   // Read back planes, one at a time. Keep the video frame alive while doing the
   1124   // readback.
   1125   copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(),
   1126                             target,
   1127                             media::VideoFrame::kYPlane,
   1128                             0,
   1129                             dst_subrect_,
   1130                             swizzle_,
   1131                             base::Bind(&nullcallback));
   1132   copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(),
   1133                             target,
   1134                             media::VideoFrame::kUPlane,
   1135                             1,
   1136                             dst_subrect_,
   1137                             swizzle_,
   1138                             base::Bind(&nullcallback));
   1139   copy_impl_->ReadbackPlane(
   1140       v_.texture_and_framebuffer(),
   1141       target,
   1142       media::VideoFrame::kVPlane,
   1143       1,
   1144       dst_subrect_,
   1145       swizzle_,
   1146       base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
   1147   gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
   1148   media::LetterboxYUV(target.get(), dst_subrect_);
   1149 }
   1150 
   1151 // YUV readback constructors. Initiates the main scaler pipeline and
   1152 // one planar scaler for each of the Y, U and V planes.
   1153 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
   1154     GLES2Interface* gl,
   1155     CopyTextureToImpl* copy_impl,
   1156     GLHelperScaling* scaler_impl,
   1157     GLHelper::ScalerQuality quality,
   1158     const gfx::Size& src_size,
   1159     const gfx::Rect& src_subrect,
   1160     const gfx::Size& dst_size,
   1161     const gfx::Rect& dst_subrect,
   1162     bool flip_vertically,
   1163     ReadbackSwizzle swizzle)
   1164     : gl_(gl),
   1165       copy_impl_(copy_impl),
   1166       dst_size_(dst_size),
   1167       dst_subrect_(dst_subrect),
   1168       quality_(quality),
   1169       swizzle_(swizzle),
   1170       scaler_(gl,
   1171               scaler_impl->CreateScaler(quality,
   1172                                         src_size,
   1173                                         src_subrect,
   1174                                         dst_subrect.size(),
   1175                                         false,
   1176                                         false)),
   1177       pass1_shader_(scaler_impl->CreateYuvMrtShader(
   1178           dst_subrect.size(),
   1179           gfx::Rect(0, 0, (dst_subrect.width() + 3) & ~3, dst_subrect.height()),
   1180           gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
   1181           flip_vertically,
   1182           (swizzle == kSwizzleBGRA),
   1183           GLHelperScaling::SHADER_YUV_MRT_PASS1)),
   1184       pass2_shader_(scaler_impl->CreateYuvMrtShader(
   1185           gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
   1186           gfx::Rect(0,
   1187                     0,
   1188                     (dst_subrect.width() + 7) / 8 * 2,
   1189                     dst_subrect.height()),
   1190           gfx::Size((dst_subrect.width() + 7) / 8,
   1191                     (dst_subrect.height() + 1) / 2),
   1192           false,
   1193           (swizzle == kSwizzleBGRA),
   1194           GLHelperScaling::SHADER_YUV_MRT_PASS2)),
   1195       y_(gl, gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height())),
   1196       uv_(gl),
   1197       u_(gl,
   1198          gfx::Size((dst_subrect.width() + 7) / 8,
   1199                    (dst_subrect.height() + 1) / 2)),
   1200       v_(gl,
   1201          gfx::Size((dst_subrect.width() + 7) / 8,
   1202                    (dst_subrect.height() + 1) / 2)) {
   1203 
   1204   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_);
   1205   gl->TexImage2D(GL_TEXTURE_2D,
   1206                  0,
   1207                  GL_RGBA,
   1208                  (dst_subrect.width() + 3) / 4,
   1209                  dst_subrect.height(),
   1210                  0,
   1211                  GL_RGBA,
   1212                  GL_UNSIGNED_BYTE,
   1213                  NULL);
   1214 
   1215   DCHECK(!(dst_size.width() & 1));
   1216   DCHECK(!(dst_size.height() & 1));
   1217   DCHECK(!(dst_subrect.width() & 1));
   1218   DCHECK(!(dst_subrect.height() & 1));
   1219   DCHECK(!(dst_subrect.x() & 1));
   1220   DCHECK(!(dst_subrect.y() & 1));
   1221 }
   1222 
   1223 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
   1224     const gpu::Mailbox& mailbox,
   1225     uint32 sync_point,
   1226     const scoped_refptr<media::VideoFrame>& target,
   1227     const base::Callback<void(bool)>& callback) {
   1228   GLuint mailbox_texture =
   1229       copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
   1230 
   1231   GLuint texture;
   1232   if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
   1233     // Optimization: SCALER_QUALITY_FAST is just a single bilinear
   1234     // pass, which pass1_shader_ can do just as well, so let's skip
   1235     // the actual scaling in that case.
   1236     texture = mailbox_texture;
   1237   } else {
   1238     // Scale texture to right size.
   1239     scaler_.Scale(mailbox_texture);
   1240     texture = scaler_.texture();
   1241   }
   1242 
   1243   std::vector<GLuint> outputs(2);
   1244   // Convert the scaled texture in to Y, U and V planes.
   1245   outputs[0] = y_.texture();
   1246   outputs[1] = uv_;
   1247   pass1_shader_->Execute(texture, outputs);
   1248 
   1249   gl_->DeleteTextures(1, &mailbox_texture);
   1250 
   1251   outputs[0] = u_.texture();
   1252   outputs[1] = v_.texture();
   1253   pass2_shader_->Execute(uv_, outputs);
   1254 
   1255   if (target->coded_size() != dst_size_) {
   1256     DCHECK(target->coded_size() == dst_size_);
   1257     LOG(ERROR) << "ReadbackYUV size error!";
   1258     callback.Run(false);
   1259     return;
   1260   }
   1261 
   1262   // Read back planes, one at a time.
   1263   copy_impl_->ReadbackPlane(&y_,
   1264                             target,
   1265                             media::VideoFrame::kYPlane,
   1266                             0,
   1267                             dst_subrect_,
   1268                             swizzle_,
   1269                             base::Bind(&nullcallback));
   1270   copy_impl_->ReadbackPlane(&u_,
   1271                             target,
   1272                             media::VideoFrame::kUPlane,
   1273                             1,
   1274                             dst_subrect_,
   1275                             swizzle_,
   1276                             base::Bind(&nullcallback));
   1277   copy_impl_->ReadbackPlane(
   1278       &v_,
   1279       target,
   1280       media::VideoFrame::kVPlane,
   1281       1,
   1282       dst_subrect_,
   1283       swizzle_,
   1284       base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
   1285   gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
   1286   media::LetterboxYUV(target.get(), dst_subrect_);
   1287 }
   1288 
   1289 bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) {
   1290   DCHECK(readback_support_.get());
   1291   GLenum format, type;
   1292   size_t bytes_per_pixel;
   1293   FormatSupport support = readback_support_->GetReadbackConfig(
   1294       color_type, false, &format, &type, &bytes_per_pixel);
   1295 
   1296   return (support == GLHelperReadbackSupport::SUPPORTED);
   1297 }
   1298 
   1299 ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
   1300     GLHelper::ScalerQuality quality,
   1301     const gfx::Size& src_size,
   1302     const gfx::Rect& src_subrect,
   1303     const gfx::Size& dst_size,
   1304     const gfx::Rect& dst_subrect,
   1305     bool flip_vertically,
   1306     bool use_mrt) {
   1307   helper_->InitScalerImpl();
   1308   // Just query if the best readback configuration needs a swizzle In
   1309   // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle
   1310   GLenum format, type;
   1311   size_t bytes_per_pixel;
   1312   FormatSupport supported = GetReadbackConfig(
   1313       kRGBA_8888_SkColorType, true, &format, &type, &bytes_per_pixel);
   1314   DCHECK((format == GL_RGBA || format == GL_BGRA_EXT) &&
   1315          type == GL_UNSIGNED_BYTE);
   1316 
   1317   ReadbackSwizzle swizzle = kSwizzleNone;
   1318   if (supported == GLHelperReadbackSupport::SWIZZLE)
   1319     swizzle = kSwizzleBGRA;
   1320 
   1321   if (max_draw_buffers_ >= 2 && use_mrt) {
   1322     return new ReadbackYUV_MRT(gl_,
   1323                                this,
   1324                                helper_->scaler_impl_.get(),
   1325                                quality,
   1326                                src_size,
   1327                                src_subrect,
   1328                                dst_size,
   1329                                dst_subrect,
   1330                                flip_vertically,
   1331                                swizzle);
   1332   }
   1333   return new ReadbackYUVImpl(gl_,
   1334                              this,
   1335                              helper_->scaler_impl_.get(),
   1336                              quality,
   1337                              src_size,
   1338                              src_subrect,
   1339                              dst_size,
   1340                              dst_subrect,
   1341                              flip_vertically,
   1342                              swizzle);
   1343 }
   1344 
   1345 ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
   1346     ScalerQuality quality,
   1347     const gfx::Size& src_size,
   1348     const gfx::Rect& src_subrect,
   1349     const gfx::Size& dst_size,
   1350     const gfx::Rect& dst_subrect,
   1351     bool flip_vertically,
   1352     bool use_mrt) {
   1353   InitCopyTextToImpl();
   1354   return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality,
   1355                                                           src_size,
   1356                                                           src_subrect,
   1357                                                           dst_size,
   1358                                                           dst_subrect,
   1359                                                           flip_vertically,
   1360                                                           use_mrt);
   1361 }
   1362 
   1363 }  // namespace content
   1364