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