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