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_scaling.h"
     19 #include "gpu/command_buffer/client/context_support.h"
     20 #include "gpu/command_buffer/common/mailbox.h"
     21 #include "media/base/video_frame.h"
     22 #include "media/base/video_util.h"
     23 #include "third_party/WebKit/public/platform/WebCString.h"
     24 #include "third_party/skia/include/core/SkRegion.h"
     25 #include "ui/gfx/rect.h"
     26 #include "ui/gfx/size.h"
     27 #include "ui/gl/gl_bindings.h"
     28 
     29 using blink::WebGLId;
     30 using blink::WebGraphicsContext3D;
     31 
     32 namespace {
     33 
     34 // Helper class for allocating and holding an RGBA texture of a given
     35 // size and an associated framebuffer.
     36 class TextureFrameBufferPair {
     37  public:
     38   TextureFrameBufferPair(WebGraphicsContext3D* context,
     39                          gfx::Size size)
     40       : texture_(context, context->createTexture()),
     41         framebuffer_(context, context->createFramebuffer()),
     42         size_(size) {
     43     content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context,
     44                                                                texture_);
     45     context->texImage2D(GL_TEXTURE_2D,
     46                         0,
     47                         GL_RGBA,
     48                         size.width(),
     49                         size.height(),
     50                         0,
     51                         GL_RGBA,
     52                         GL_UNSIGNED_BYTE,
     53                         NULL);
     54     content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
     55         context,
     56         framebuffer_);
     57     context->framebufferTexture2D(GL_FRAMEBUFFER,
     58                                   GL_COLOR_ATTACHMENT0,
     59                                   GL_TEXTURE_2D,
     60                                   texture_,
     61                                   0);
     62   }
     63 
     64   WebGLId texture() const { return texture_.id(); }
     65   WebGLId framebuffer() const { return framebuffer_.id(); }
     66   gfx::Size size() const { return size_; }
     67 
     68  private:
     69   content::ScopedTexture texture_;
     70   content::ScopedFramebuffer framebuffer_;
     71   gfx::Size size_;
     72 
     73   DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair);
     74 };
     75 
     76 // Helper class for holding a scaler, a texture for the output of that
     77 // scaler and an associated frame buffer. This is inteded to be used
     78 // when the output of a scaler is to be sent to a readback.
     79 class ScalerHolder {
     80  public:
     81   ScalerHolder(WebGraphicsContext3D* context,
     82                content::GLHelper::ScalerInterface *scaler)
     83       : texture_and_framebuffer_(context, scaler->DstSize()),
     84         scaler_(scaler) {
     85   }
     86 
     87   void Scale(blink::WebGLId src_texture) {
     88     scaler_->Scale(src_texture, texture_and_framebuffer_.texture());
     89   }
     90 
     91   content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); }
     92   TextureFrameBufferPair *texture_and_framebuffer() {
     93     return &texture_and_framebuffer_;
     94   }
     95   WebGLId texture() const { return texture_and_framebuffer_.texture(); }
     96 
     97  private:
     98   TextureFrameBufferPair texture_and_framebuffer_;
     99   scoped_ptr<content::GLHelper::ScalerInterface> scaler_;
    100 
    101   DISALLOW_COPY_AND_ASSIGN(ScalerHolder);
    102 };
    103 
    104 }  // namespace
    105 
    106 namespace content {
    107 
    108 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
    109 // the data needed for it.
    110 class GLHelper::CopyTextureToImpl :
    111       public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
    112  public:
    113   CopyTextureToImpl(WebGraphicsContext3D* context,
    114                     gpu::ContextSupport* context_support,
    115                     GLHelper* helper)
    116       : context_(context),
    117         context_support_(context_support),
    118         helper_(helper),
    119         flush_(context),
    120         max_draw_buffers_(0) {
    121     std::string extensions_string = " " +
    122         UTF16ToASCII(context_->getString(GL_EXTENSIONS)) + " ";
    123     if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) {
    124       context_->getIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers_);
    125     }
    126   }
    127   ~CopyTextureToImpl() {
    128     CancelRequests();
    129   }
    130 
    131   WebGLId ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
    132                                   uint32 sync_point) {
    133     return helper_->ConsumeMailboxToTexture(mailbox, sync_point);
    134   }
    135 
    136   void CropScaleReadbackAndCleanTexture(
    137       WebGLId src_texture,
    138       const gfx::Size& src_size,
    139       const gfx::Rect& src_subrect,
    140       const gfx::Size& dst_size,
    141       unsigned char* out,
    142       const base::Callback<void(bool)>& callback,
    143       GLHelper::ScalerQuality quality);
    144 
    145   void ReadbackTextureSync(WebGLId texture,
    146                            const gfx::Rect& src_rect,
    147                            unsigned char* out);
    148 
    149   // Reads back bytes from the currently bound frame buffer.
    150   // Note that dst_size is specified in bytes, not pixels.
    151   void ReadbackAsync(
    152       const gfx::Size& dst_size,
    153       int32 bytes_per_row,     // generally dst_size.width() * 4
    154       int32 row_stride_bytes,  // generally dst_size.width() * 4
    155       unsigned char* out,
    156       const base::Callback<void(bool)>& callback);
    157 
    158   void ReadbackPlane(TextureFrameBufferPair* source,
    159                      const scoped_refptr<media::VideoFrame>& target,
    160                      int plane,
    161                      int size_shift,
    162                      const gfx::Rect& dst_subrect,
    163                      const base::Callback<void(bool)>& callback);
    164 
    165   blink::WebGLId CopyAndScaleTexture(WebGLId texture,
    166                                       const gfx::Size& src_size,
    167                                       const gfx::Size& dst_size,
    168                                       bool vertically_flip_texture,
    169                                       GLHelper::ScalerQuality quality);
    170 
    171   ReadbackYUVInterface* CreateReadbackPipelineYUV(
    172       GLHelper::ScalerQuality quality,
    173       const gfx::Size& src_size,
    174       const gfx::Rect& src_subrect,
    175       const gfx::Size& dst_size,
    176       const gfx::Rect& dst_subrect,
    177       bool flip_vertically,
    178       bool use_mrt);
    179 
    180   // Returns the maximum number of draw buffers available,
    181   // 0 if GL_EXT_draw_buffers is not available.
    182   blink::WGC3Dint MaxDrawBuffers() const {
    183     return max_draw_buffers_;
    184   }
    185 
    186  private:
    187   // A single request to CropScaleReadbackAndCleanTexture.
    188   // The main thread can cancel the request, before it's handled by the helper
    189   // thread, by resetting the texture and pixels fields. Alternatively, the
    190   // thread marks that it handles the request by resetting the pixels field
    191   // (meaning it guarantees that the callback with be called).
    192   // In either case, the callback must be called exactly once, and the texture
    193   // must be deleted by the main thread context.
    194   struct Request {
    195     Request(const gfx::Size& size_,
    196             int32 bytes_per_row_,
    197             int32 row_stride_bytes_,
    198             unsigned char* pixels_,
    199             const base::Callback<void(bool)>& callback_)
    200         : done(false),
    201           size(size_),
    202           bytes_per_row(bytes_per_row_),
    203           row_stride_bytes(row_stride_bytes_),
    204           pixels(pixels_),
    205           callback(callback_),
    206           buffer(0),
    207           query(0) {
    208     }
    209 
    210     bool done;
    211     gfx::Size size;
    212     int bytes_per_row;
    213     int row_stride_bytes;
    214     unsigned char* pixels;
    215     base::Callback<void(bool)> callback;
    216     GLuint buffer;
    217     blink::WebGLId query;
    218   };
    219 
    220   // A readback pipeline that also converts the data to YUV before
    221   // reading it back.
    222   class ReadbackYUVImpl : public ReadbackYUVInterface {
    223    public:
    224     ReadbackYUVImpl(WebGraphicsContext3D* context,
    225                     CopyTextureToImpl* copy_impl,
    226                     GLHelperScaling* scaler_impl,
    227                     GLHelper::ScalerQuality quality,
    228                     const gfx::Size& src_size,
    229                     const gfx::Rect& src_subrect,
    230                     const gfx::Size& dst_size,
    231                     const gfx::Rect& dst_subrect,
    232                     bool flip_vertically);
    233 
    234     virtual void ReadbackYUV(
    235         const gpu::Mailbox& mailbox,
    236         uint32 sync_point,
    237         const scoped_refptr<media::VideoFrame>& target,
    238         const base::Callback<void(bool)>& callback) OVERRIDE;
    239 
    240     virtual ScalerInterface* scaler() OVERRIDE {
    241       return scaler_.scaler();
    242     }
    243 
    244    private:
    245     WebGraphicsContext3D* context_;
    246     CopyTextureToImpl* copy_impl_;
    247     gfx::Size dst_size_;
    248     gfx::Rect dst_subrect_;
    249     ScalerHolder scaler_;
    250     ScalerHolder y_;
    251     ScalerHolder u_;
    252     ScalerHolder v_;
    253 
    254     DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl);
    255   };
    256 
    257   // A readback pipeline that also converts the data to YUV before
    258   // reading it back. This one uses Multiple Render Targets, which
    259   // may not be supported on all platforms.
    260   class ReadbackYUV_MRT : public ReadbackYUVInterface {
    261    public:
    262     ReadbackYUV_MRT(WebGraphicsContext3D* context,
    263                     CopyTextureToImpl* copy_impl,
    264                     GLHelperScaling* scaler_impl,
    265                     GLHelper::ScalerQuality quality,
    266                     const gfx::Size& src_size,
    267                     const gfx::Rect& src_subrect,
    268                     const gfx::Size& dst_size,
    269                     const gfx::Rect& dst_subrect,
    270                     bool flip_vertically);
    271 
    272     virtual void ReadbackYUV(
    273         const gpu::Mailbox& mailbox,
    274         uint32 sync_point,
    275         const scoped_refptr<media::VideoFrame>& target,
    276         const base::Callback<void(bool)>& callback) OVERRIDE;
    277 
    278     virtual ScalerInterface* scaler() OVERRIDE {
    279       return scaler_.scaler();
    280     }
    281 
    282    private:
    283     WebGraphicsContext3D* context_;
    284     CopyTextureToImpl* copy_impl_;
    285     gfx::Size dst_size_;
    286     gfx::Rect dst_subrect_;
    287     GLHelper::ScalerQuality quality_;
    288     ScalerHolder scaler_;
    289     scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
    290     scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
    291     TextureFrameBufferPair y_;
    292     ScopedTexture uv_;
    293     TextureFrameBufferPair u_;
    294     TextureFrameBufferPair v_;
    295 
    296     DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT);
    297   };
    298 
    299   // Copies the block of pixels specified with |src_subrect| from |src_texture|,
    300   // scales it to |dst_size|, writes it into a texture, and returns its ID.
    301   // |src_size| is the size of |src_texture|.
    302   WebGLId ScaleTexture(WebGLId src_texture,
    303                        const gfx::Size& src_size,
    304                        const gfx::Rect& src_subrect,
    305                        const gfx::Size& dst_size,
    306                        bool vertically_flip_texture,
    307                        bool swizzle,
    308                        GLHelper::ScalerQuality quality);
    309 
    310   static void nullcallback(bool success) {}
    311   void ReadbackDone(Request *request);
    312   void FinishRequest(Request* request, bool result);
    313   void CancelRequests();
    314 
    315   static const float kRGBtoYColorWeights[];
    316   static const float kRGBtoUColorWeights[];
    317   static const float kRGBtoVColorWeights[];
    318 
    319   WebGraphicsContext3D* context_;
    320   gpu::ContextSupport* context_support_;
    321   GLHelper* helper_;
    322 
    323   // A scoped flush that will ensure all resource deletions are flushed when
    324   // this object is destroyed. Must be declared before other Scoped* fields.
    325   ScopedFlush flush_;
    326 
    327   std::queue<Request*> request_queue_;
    328   blink::WGC3Dint max_draw_buffers_;
    329 };
    330 
    331 GLHelper::ScalerInterface* GLHelper::CreateScaler(
    332     ScalerQuality quality,
    333     const gfx::Size& src_size,
    334     const gfx::Rect& src_subrect,
    335     const gfx::Size& dst_size,
    336     bool vertically_flip_texture,
    337     bool swizzle) {
    338   InitScalerImpl();
    339   return scaler_impl_->CreateScaler(quality,
    340                                     src_size,
    341                                     src_subrect,
    342                                     dst_size,
    343                                     vertically_flip_texture,
    344                                     swizzle);
    345 }
    346 
    347 WebGLId GLHelper::CopyTextureToImpl::ScaleTexture(
    348     WebGLId src_texture,
    349     const gfx::Size& src_size,
    350     const gfx::Rect& src_subrect,
    351     const gfx::Size& dst_size,
    352     bool vertically_flip_texture,
    353     bool swizzle,
    354     GLHelper::ScalerQuality quality) {
    355   scoped_ptr<ScalerInterface> scaler(
    356       helper_->CreateScaler(quality,
    357                             src_size,
    358                             src_subrect,
    359                             dst_size,
    360                             vertically_flip_texture,
    361                             swizzle));
    362 
    363   WebGLId dst_texture = context_->createTexture();
    364   {
    365     ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, dst_texture);
    366     context_->texImage2D(GL_TEXTURE_2D,
    367                          0,
    368                          GL_RGBA,
    369                          dst_size.width(),
    370                          dst_size.height(),
    371                          0,
    372                          GL_RGBA,
    373                          GL_UNSIGNED_BYTE,
    374                          NULL);
    375   }
    376   scaler->Scale(src_texture, dst_texture);
    377   return dst_texture;
    378 }
    379 
    380 void GLHelper::CopyTextureToImpl::ReadbackAsync(
    381     const gfx::Size& dst_size,
    382     int32 bytes_per_row,
    383     int32 row_stride_bytes,
    384     unsigned char* out,
    385     const base::Callback<void(bool)>& callback) {
    386   Request* request = new Request(dst_size,
    387                                  bytes_per_row,
    388                                  row_stride_bytes,
    389                                  out,
    390                                  callback);
    391   request_queue_.push(request);
    392   request->buffer = context_->createBuffer();
    393   context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
    394                        request->buffer);
    395   context_->bufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
    396                        4 * dst_size.GetArea(),
    397                        NULL,
    398                        GL_STREAM_READ);
    399 
    400   request->query = context_->createQueryEXT();
    401   context_->beginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM,
    402                           request->query);
    403   context_->readPixels(0, 0, dst_size.width(), dst_size.height(),
    404                        GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    405   context_->endQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
    406   context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
    407   context_support_->SignalQuery(
    408       request->query,
    409       base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), request));
    410 }
    411 
    412 
    413 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
    414     WebGLId src_texture,
    415     const gfx::Size& src_size,
    416     const gfx::Rect& src_subrect,
    417     const gfx::Size& dst_size,
    418     unsigned char* out,
    419     const base::Callback<void(bool)>& callback,
    420     GLHelper::ScalerQuality quality) {
    421   WebGLId texture = ScaleTexture(src_texture,
    422                                  src_size,
    423                                  src_subrect,
    424                                  dst_size,
    425                                  true,
    426 #if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT
    427                                  true,
    428 #else
    429                                  false,
    430 #endif
    431                                  quality);
    432   ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer());
    433   ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_,
    434                                                              dst_framebuffer);
    435   ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
    436   context_->framebufferTexture2D(GL_FRAMEBUFFER,
    437                                  GL_COLOR_ATTACHMENT0,
    438                                  GL_TEXTURE_2D,
    439                                  texture,
    440                                  0);
    441   ReadbackAsync(dst_size,
    442                 dst_size.width() * 4,
    443                 dst_size.width() * 4,
    444                 out,
    445                 callback);
    446   context_->deleteTexture(texture);
    447 }
    448 
    449 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
    450     WebGLId texture,
    451     const gfx::Rect& src_rect,
    452     unsigned char* out) {
    453   ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer());
    454   ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_,
    455                                                              dst_framebuffer);
    456   ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
    457   context_->framebufferTexture2D(GL_FRAMEBUFFER,
    458                                  GL_COLOR_ATTACHMENT0,
    459                                  GL_TEXTURE_2D,
    460                                  texture,
    461                                  0);
    462   context_->readPixels(src_rect.x(),
    463                        src_rect.y(),
    464                        src_rect.width(),
    465                        src_rect.height(),
    466                        GL_RGBA,
    467                        GL_UNSIGNED_BYTE,
    468                        out);
    469 }
    470 
    471 blink::WebGLId GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
    472     WebGLId src_texture,
    473     const gfx::Size& src_size,
    474     const gfx::Size& dst_size,
    475     bool vertically_flip_texture,
    476     GLHelper::ScalerQuality quality) {
    477   return ScaleTexture(src_texture,
    478                       src_size,
    479                       gfx::Rect(src_size),
    480                       dst_size,
    481                       vertically_flip_texture,
    482                       false,
    483                       quality);
    484 }
    485 
    486 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request) {
    487   TRACE_EVENT0("mirror",
    488                "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
    489   finished_request->done = true;
    490 
    491   // We process transfer requests in the order they were received, regardless
    492   // of the order we get the callbacks in.
    493   while (!request_queue_.empty()) {
    494     Request* request = request_queue_.front();
    495     if (!request->done) {
    496       break;
    497     }
    498 
    499     bool result = false;
    500     if (request->buffer != 0) {
    501       context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
    502                            request->buffer);
    503       unsigned char* data = static_cast<unsigned char *>(
    504           context_->mapBufferCHROMIUM(
    505               GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
    506       if (data) {
    507         result = true;
    508         if (request->bytes_per_row == request->size.width() * 4 &&
    509             request->bytes_per_row == request->row_stride_bytes) {
    510           memcpy(request->pixels, data, request->size.GetArea() * 4);
    511         } else {
    512           unsigned char* out = request->pixels;
    513           for (int y = 0; y < request->size.height(); y++) {
    514             memcpy(out, data, request->bytes_per_row);
    515             out += request->row_stride_bytes;
    516             data += request->size.width() * 4;
    517           }
    518         }
    519         context_->unmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
    520       }
    521       context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
    522     }
    523 
    524     FinishRequest(request, result);
    525   }
    526 }
    527 
    528 void GLHelper::CopyTextureToImpl::FinishRequest(Request* request,
    529                                                 bool result) {
    530   TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
    531   DCHECK(request_queue_.front() == request);
    532   request_queue_.pop();
    533   request->callback.Run(result);
    534   ScopedFlush flush(context_);
    535   if (request->query != 0) {
    536     context_->deleteQueryEXT(request->query);
    537     request->query = 0;
    538   }
    539   if (request->buffer != 0) {
    540     context_->deleteBuffer(request->buffer);
    541     request->buffer = 0;
    542   }
    543   delete request;
    544 }
    545 
    546 void GLHelper::CopyTextureToImpl::CancelRequests() {
    547   while (!request_queue_.empty()) {
    548     Request* request = request_queue_.front();
    549     FinishRequest(request, false);
    550   }
    551 }
    552 
    553 GLHelper::GLHelper(blink::WebGraphicsContext3D* context,
    554                    gpu::ContextSupport* context_support)
    555     : context_(context),
    556       context_support_(context_support) {
    557 }
    558 
    559 GLHelper::~GLHelper() {
    560 }
    561 
    562 void GLHelper::CropScaleReadbackAndCleanTexture(
    563     WebGLId src_texture,
    564     const gfx::Size& src_size,
    565     const gfx::Rect& src_subrect,
    566     const gfx::Size& dst_size,
    567     unsigned char* out,
    568     const base::Callback<void(bool)>& callback) {
    569   InitCopyTextToImpl();
    570   copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(
    571       src_texture,
    572       src_size,
    573       src_subrect,
    574       dst_size,
    575       out,
    576       callback,
    577       GLHelper::SCALER_QUALITY_FAST);
    578 }
    579 
    580 void GLHelper::CropScaleReadbackAndCleanMailbox(
    581     const gpu::Mailbox& src_mailbox,
    582     uint32 sync_point,
    583     const gfx::Size& src_size,
    584     const gfx::Rect& src_subrect,
    585     const gfx::Size& dst_size,
    586     unsigned char* out,
    587     const base::Callback<void(bool)>& callback) {
    588   WebGLId mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point);
    589   CropScaleReadbackAndCleanTexture(
    590       mailbox_texture, src_size, src_subrect, dst_size, out, callback);
    591   context_->deleteTexture(mailbox_texture);
    592 }
    593 
    594 void GLHelper::ReadbackTextureSync(blink::WebGLId texture,
    595                                    const gfx::Rect& src_rect,
    596                                    unsigned char* out) {
    597   InitCopyTextToImpl();
    598   copy_texture_to_impl_->ReadbackTextureSync(texture,
    599                                              src_rect,
    600                                              out);
    601 }
    602 
    603 blink::WebGLId GLHelper::CopyTexture(blink::WebGLId texture,
    604                                       const gfx::Size& size) {
    605   InitCopyTextToImpl();
    606   return copy_texture_to_impl_->CopyAndScaleTexture(
    607       texture,
    608       size,
    609       size,
    610       false,
    611       GLHelper::SCALER_QUALITY_FAST);
    612 }
    613 
    614 blink::WebGLId GLHelper::CopyAndScaleTexture(
    615     blink::WebGLId texture,
    616     const gfx::Size& src_size,
    617     const gfx::Size& dst_size,
    618     bool vertically_flip_texture,
    619     ScalerQuality quality) {
    620   InitCopyTextToImpl();
    621   return copy_texture_to_impl_->CopyAndScaleTexture(texture,
    622                                                     src_size,
    623                                                     dst_size,
    624                                                     vertically_flip_texture,
    625                                                     quality);
    626 }
    627 
    628 WebGLId GLHelper::CompileShaderFromSource(
    629     const blink::WGC3Dchar* source,
    630     blink::WGC3Denum type) {
    631   ScopedShader shader(context_, context_->createShader(type));
    632   context_->shaderSource(shader, source);
    633   context_->compileShader(shader);
    634   blink::WGC3Dint compile_status = 0;
    635   context_->getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
    636   if (!compile_status) {
    637     LOG(ERROR) << std::string(context_->getShaderInfoLog(shader).utf8());
    638     return 0;
    639   }
    640   return shader.Detach();
    641 }
    642 
    643 void GLHelper::InitCopyTextToImpl() {
    644   // Lazily initialize |copy_texture_to_impl_|
    645   if (!copy_texture_to_impl_)
    646     copy_texture_to_impl_.reset(
    647         new CopyTextureToImpl(context_, context_support_, this));
    648 }
    649 
    650 void GLHelper::InitScalerImpl() {
    651   // Lazily initialize |scaler_impl_|
    652   if (!scaler_impl_)
    653     scaler_impl_.reset(new GLHelperScaling(context_, this));
    654 }
    655 
    656 blink::WGC3Dint GLHelper::MaxDrawBuffers() {
    657   InitCopyTextToImpl();
    658   return copy_texture_to_impl_->MaxDrawBuffers();
    659 }
    660 
    661 void GLHelper::CopySubBufferDamage(blink::WebGLId texture,
    662                                    blink::WebGLId previous_texture,
    663                                    const SkRegion& new_damage,
    664                                    const SkRegion& old_damage) {
    665   SkRegion region(old_damage);
    666   if (region.op(new_damage, SkRegion::kDifference_Op)) {
    667     ScopedFramebuffer dst_framebuffer(context_,
    668                                       context_->createFramebuffer());
    669     ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_,
    670                                                                dst_framebuffer);
    671     ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
    672     context_->framebufferTexture2D(GL_FRAMEBUFFER,
    673                                    GL_COLOR_ATTACHMENT0,
    674                                    GL_TEXTURE_2D,
    675                                    previous_texture,
    676                                    0);
    677     for (SkRegion::Iterator it(region); !it.done(); it.next()) {
    678       const SkIRect& rect = it.rect();
    679       context_->copyTexSubImage2D(GL_TEXTURE_2D, 0,
    680                                   rect.x(), rect.y(),
    681                                   rect.x(), rect.y(),
    682                                   rect.width(), rect.height());
    683     }
    684     context_->flush();
    685   }
    686 }
    687 
    688 blink::WebGLId GLHelper::CreateTexture() {
    689   blink::WebGLId texture = context_->createTexture();
    690   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_,
    691                                                              texture);
    692   context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    693   context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    694   context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    695   context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    696   return texture;
    697 }
    698 
    699 void GLHelper::DeleteTexture(blink::WebGLId texture_id) {
    700   context_->deleteTexture(texture_id);
    701 }
    702 
    703 uint32 GLHelper::InsertSyncPoint() { return context_->insertSyncPoint(); }
    704 
    705 void GLHelper::WaitSyncPoint(uint32 sync_point) {
    706   context_->waitSyncPoint(sync_point);
    707 }
    708 
    709 gpu::Mailbox GLHelper::ProduceMailboxFromTexture(blink::WebGLId texture_id,
    710                                                  uint32* sync_point) {
    711   gpu::Mailbox mailbox;
    712   context_->genMailboxCHROMIUM(mailbox.name);
    713   if (mailbox.IsZero()) {
    714     *sync_point = 0;
    715     return mailbox;
    716   }
    717   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_,
    718                                                              texture_id);
    719   context_->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    720   *sync_point = context_->insertSyncPoint();
    721   return mailbox;
    722 }
    723 
    724 blink::WebGLId GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
    725                                                   uint32 sync_point) {
    726   if (mailbox.IsZero())
    727     return 0;
    728   if (sync_point)
    729     context_->waitSyncPoint(sync_point);
    730   blink::WebGLId texture = CreateTexture();
    731   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_,
    732                                                              texture);
    733   context_->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    734   return texture;
    735 }
    736 
    737 void GLHelper::ResizeTexture(blink::WebGLId texture, const gfx::Size& size) {
    738   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
    739   context_->texImage2D(GL_TEXTURE_2D, 0, GL_RGB,
    740                        size.width(), size.height(), 0,
    741                        GL_RGB, GL_UNSIGNED_BYTE, NULL);
    742 }
    743 
    744 void GLHelper::CopyTextureSubImage(blink::WebGLId texture,
    745                                    const gfx::Rect& rect) {
    746   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
    747   context_->copyTexSubImage2D(GL_TEXTURE_2D, 0,
    748                               rect.x(), rect.y(),
    749                               rect.x(), rect.y(), rect.width(), rect.height());
    750 }
    751 
    752 void GLHelper::CopyTextureFullImage(blink::WebGLId texture,
    753                                     const gfx::Size& size) {
    754   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
    755   context_->copyTexImage2D(GL_TEXTURE_2D, 0,
    756                            GL_RGB,
    757                            0, 0,
    758                            size.width(), size.height(), 0);
    759 }
    760 
    761 void GLHelper::CopyTextureToImpl::ReadbackPlane(
    762     TextureFrameBufferPair* source,
    763     const scoped_refptr<media::VideoFrame>& target,
    764     int plane,
    765     int size_shift,
    766     const gfx::Rect& dst_subrect,
    767     const base::Callback<void(bool)>& callback) {
    768   context_->bindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
    769   size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) +
    770       (dst_subrect.x() >> size_shift);
    771   ReadbackAsync(
    772       source->size(),
    773       dst_subrect.width() >> size_shift,
    774       target->stride(plane),
    775       target->data(plane) + offset,
    776       callback);
    777 }
    778 
    779 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
    780   0.257f, 0.504f, 0.098f, 0.0625f
    781 };
    782 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
    783   -0.148f, -0.291f, 0.439f, 0.5f
    784 };
    785 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
    786   0.439f, -0.368f, -0.071f, 0.5f
    787 };
    788 
    789 // YUV readback constructors. Initiates the main scaler pipeline and
    790 // one planar scaler for each of the Y, U and V planes.
    791 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
    792     WebGraphicsContext3D* context,
    793     CopyTextureToImpl* copy_impl,
    794     GLHelperScaling* scaler_impl,
    795     GLHelper::ScalerQuality quality,
    796     const gfx::Size& src_size,
    797     const gfx::Rect& src_subrect,
    798     const gfx::Size& dst_size,
    799     const gfx::Rect& dst_subrect,
    800     bool flip_vertically)
    801     : context_(context),
    802       copy_impl_(copy_impl),
    803       dst_size_(dst_size),
    804       dst_subrect_(dst_subrect),
    805       scaler_(context, scaler_impl->CreateScaler(
    806           quality,
    807           src_size,
    808           src_subrect,
    809           dst_subrect.size(),
    810           flip_vertically,
    811           false)),
    812       y_(context, scaler_impl->CreatePlanarScaler(
    813           dst_subrect.size(),
    814           gfx::Rect(0, 0,
    815                     (dst_subrect.width() + 3) & ~3,
    816                     dst_subrect.height()),
    817           gfx::Size((dst_subrect.width() + 3) / 4,
    818                     dst_subrect.height()),
    819           false,
    820           kRGBtoYColorWeights)),
    821       u_(context, scaler_impl->CreatePlanarScaler(
    822           dst_subrect.size(),
    823           gfx::Rect(0, 0,
    824                     (dst_subrect.width() + 7) & ~7,
    825                     (dst_subrect.height() + 1) & ~1),
    826           gfx::Size((dst_subrect.width() + 7) / 8,
    827                     (dst_subrect.height() + 1) / 2),
    828           false,
    829           kRGBtoUColorWeights)),
    830       v_(context, scaler_impl->CreatePlanarScaler(
    831           dst_subrect.size(),
    832           gfx::Rect(0, 0,
    833                     (dst_subrect.width() + 7) & ~7,
    834                     (dst_subrect.height() + 1) & ~1),
    835           gfx::Size((dst_subrect.width() + 7) / 8,
    836                     (dst_subrect.height() + 1) / 2),
    837           false,
    838           kRGBtoVColorWeights)) {
    839   DCHECK(!(dst_size.width() & 1));
    840   DCHECK(!(dst_size.height() & 1));
    841   DCHECK(!(dst_subrect.width() & 1));
    842   DCHECK(!(dst_subrect.height() & 1));
    843   DCHECK(!(dst_subrect.x() & 1));
    844   DCHECK(!(dst_subrect.y() & 1));
    845 }
    846 
    847 static void CallbackKeepingVideoFrameAlive(
    848     scoped_refptr<media::VideoFrame> video_frame,
    849     const base::Callback<void(bool)>& callback,
    850     bool success) {
    851   callback.Run(success);
    852 }
    853 
    854 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
    855     const gpu::Mailbox& mailbox,
    856     uint32 sync_point,
    857     const scoped_refptr<media::VideoFrame>& target,
    858     const base::Callback<void(bool)>& callback) {
    859   WebGLId mailbox_texture =
    860       copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
    861 
    862   // Scale texture to right size.
    863   scaler_.Scale(mailbox_texture);
    864   context_->deleteTexture(mailbox_texture);
    865 
    866   // Convert the scaled texture in to Y, U and V planes.
    867   y_.Scale(scaler_.texture());
    868   u_.Scale(scaler_.texture());
    869   v_.Scale(scaler_.texture());
    870 
    871   if (target->coded_size() != dst_size_) {
    872     DCHECK(target->coded_size() == dst_size_);
    873     LOG(ERROR) << "ReadbackYUV size error!";
    874     callback.Run(false);
    875     return;
    876   }
    877 
    878   // Read back planes, one at a time. Keep the video frame alive while doing the
    879   // readback.
    880   copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(),
    881                             target,
    882                             media::VideoFrame::kYPlane,
    883                             0,
    884                             dst_subrect_,
    885                             base::Bind(&nullcallback));
    886   copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(),
    887                             target,
    888                             media::VideoFrame::kUPlane,
    889                             1,
    890                             dst_subrect_,
    891                             base::Bind(&nullcallback));
    892   copy_impl_->ReadbackPlane(v_.texture_and_framebuffer(),
    893                             target,
    894                             media::VideoFrame::kVPlane,
    895                             1,
    896                             dst_subrect_,
    897                             base::Bind(&CallbackKeepingVideoFrameAlive,
    898                                        target,
    899                                        callback));
    900   context_->bindFramebuffer(GL_FRAMEBUFFER, 0);
    901   media::LetterboxYUV(target, dst_subrect_);
    902 }
    903 
    904 // YUV readback constructors. Initiates the main scaler pipeline and
    905 // one planar scaler for each of the Y, U and V planes.
    906 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
    907     WebGraphicsContext3D* context,
    908     CopyTextureToImpl* copy_impl,
    909     GLHelperScaling* scaler_impl,
    910     GLHelper::ScalerQuality quality,
    911     const gfx::Size& src_size,
    912     const gfx::Rect& src_subrect,
    913     const gfx::Size& dst_size,
    914     const gfx::Rect& dst_subrect,
    915     bool flip_vertically)
    916     : context_(context),
    917       copy_impl_(copy_impl),
    918       dst_size_(dst_size),
    919       dst_subrect_(dst_subrect),
    920       quality_(quality),
    921       scaler_(context, scaler_impl->CreateScaler(
    922           quality,
    923           src_size,
    924           src_subrect,
    925           dst_subrect.size(),
    926           false,
    927           false)),
    928       pass1_shader_(scaler_impl->CreateYuvMrtShader(
    929           dst_subrect.size(),
    930           gfx::Rect(0, 0,
    931                     (dst_subrect.width() + 3) & ~3,
    932                     dst_subrect.height()),
    933           gfx::Size((dst_subrect.width() + 3) / 4,
    934                     dst_subrect.height()),
    935           flip_vertically,
    936           GLHelperScaling::SHADER_YUV_MRT_PASS1)),
    937       pass2_shader_(scaler_impl->CreateYuvMrtShader(
    938           gfx::Size((dst_subrect.width() + 3) / 4,
    939                     dst_subrect.height()),
    940           gfx::Rect(0, 0,
    941                     (dst_subrect.width() + 7) / 8 * 2,
    942                     dst_subrect.height()),
    943           gfx::Size((dst_subrect.width() + 7) / 8,
    944                     (dst_subrect.height() + 1) / 2),
    945           false,
    946           GLHelperScaling::SHADER_YUV_MRT_PASS2)),
    947       y_(context, gfx::Size((dst_subrect.width() + 3) / 4,
    948                             dst_subrect.height())),
    949       uv_(context, context->createTexture()),
    950       u_(context, gfx::Size((dst_subrect.width() + 7) / 8,
    951                             (dst_subrect.height() + 1) / 2)),
    952       v_(context, gfx::Size((dst_subrect.width() + 7) / 8,
    953                             (dst_subrect.height() + 1) / 2)) {
    954 
    955   content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context, uv_);
    956   context->texImage2D(GL_TEXTURE_2D,
    957                       0,
    958                       GL_RGBA,
    959                       (dst_subrect.width() + 3) / 4,
    960                       dst_subrect.height(),
    961                       0,
    962                       GL_RGBA,
    963                       GL_UNSIGNED_BYTE,
    964                       NULL);
    965 
    966   DCHECK(!(dst_size.width() & 1));
    967   DCHECK(!(dst_size.height() & 1));
    968   DCHECK(!(dst_subrect.width() & 1));
    969   DCHECK(!(dst_subrect.height() & 1));
    970   DCHECK(!(dst_subrect.x() & 1));
    971   DCHECK(!(dst_subrect.y() & 1));
    972 }
    973 
    974 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
    975     const gpu::Mailbox& mailbox,
    976     uint32 sync_point,
    977     const scoped_refptr<media::VideoFrame>& target,
    978     const base::Callback<void(bool)>& callback) {
    979   WebGLId mailbox_texture =
    980       copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
    981 
    982   WebGLId texture;
    983   if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
    984     // Optimization: SCALER_QUALITY_FAST is just a single bilinear
    985     // pass, which pass1_shader_ can do just as well, so let's skip
    986     // the actual scaling in that case.
    987     texture = mailbox_texture;
    988   } else {
    989     // Scale texture to right size.
    990     scaler_.Scale(mailbox_texture);
    991     texture = scaler_.texture();
    992   }
    993 
    994 
    995   std::vector<blink::WebGLId> outputs(2);
    996   // Convert the scaled texture in to Y, U and V planes.
    997   outputs[0] = y_.texture();
    998   outputs[1] = uv_;
    999   pass1_shader_->Execute(texture, outputs);
   1000 
   1001   context_->deleteTexture(mailbox_texture);
   1002 
   1003   outputs[0] = u_.texture();
   1004   outputs[1] = v_.texture();
   1005   pass2_shader_->Execute(uv_, outputs);
   1006 
   1007   if (target->coded_size() != dst_size_) {
   1008     DCHECK(target->coded_size() == dst_size_);
   1009     LOG(ERROR) << "ReadbackYUV size error!";
   1010     callback.Run(false);
   1011     return;
   1012   }
   1013 
   1014   // Read back planes, one at a time.
   1015   copy_impl_->ReadbackPlane(&y_,
   1016                             target,
   1017                             media::VideoFrame::kYPlane,
   1018                             0,
   1019                             dst_subrect_,
   1020                             base::Bind(&nullcallback));
   1021   copy_impl_->ReadbackPlane(&u_,
   1022                             target,
   1023                             media::VideoFrame::kUPlane,
   1024                             1,
   1025                             dst_subrect_,
   1026                             base::Bind(&nullcallback));
   1027   copy_impl_->ReadbackPlane(&v_,
   1028                             target,
   1029                             media::VideoFrame::kVPlane,
   1030                             1,
   1031                             dst_subrect_,
   1032                             base::Bind(&CallbackKeepingVideoFrameAlive,
   1033                                        target,
   1034                                        callback));
   1035   context_->bindFramebuffer(GL_FRAMEBUFFER, 0);
   1036   media::LetterboxYUV(target, dst_subrect_);
   1037 }
   1038 
   1039 ReadbackYUVInterface*
   1040 GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
   1041     GLHelper::ScalerQuality quality,
   1042     const gfx::Size& src_size,
   1043     const gfx::Rect& src_subrect,
   1044     const gfx::Size& dst_size,
   1045     const gfx::Rect& dst_subrect,
   1046     bool flip_vertically,
   1047     bool use_mrt) {
   1048   helper_->InitScalerImpl();
   1049   if (max_draw_buffers_ >= 2 && use_mrt) {
   1050     return new ReadbackYUV_MRT(
   1051         context_,
   1052         this,
   1053         helper_->scaler_impl_.get(),
   1054         quality,
   1055         src_size,
   1056         src_subrect,
   1057         dst_size,
   1058         dst_subrect,
   1059         flip_vertically);
   1060   }
   1061   return new ReadbackYUVImpl(
   1062       context_,
   1063       this,
   1064       helper_->scaler_impl_.get(),
   1065       quality,
   1066       src_size,
   1067       src_subrect,
   1068       dst_size,
   1069       dst_subrect,
   1070       flip_vertically);
   1071 }
   1072 
   1073 ReadbackYUVInterface*
   1074 GLHelper::CreateReadbackPipelineYUV(
   1075     ScalerQuality quality,
   1076     const gfx::Size& src_size,
   1077     const gfx::Rect& src_subrect,
   1078     const gfx::Size& dst_size,
   1079     const gfx::Rect& dst_subrect,
   1080     bool flip_vertically,
   1081     bool use_mrt) {
   1082   InitCopyTextToImpl();
   1083   return copy_texture_to_impl_->CreateReadbackPipelineYUV(
   1084       quality,
   1085       src_size,
   1086       src_subrect,
   1087       dst_size,
   1088       dst_subrect,
   1089       flip_vertically,
   1090       use_mrt);
   1091 }
   1092 
   1093 }  // namespace content
   1094