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
30using gpu::gles2::GLES2Interface;
31
32namespace {
33
34class 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.
48class 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.
83class 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
107namespace content {
108typedef GLHelperReadbackSupport::FormatSupport FormatSupport;
109
110// Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
111// the data needed for it.
112class 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
369GLHelper::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
384GLuint 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
427GLuint 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
464void 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
504void 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
608void 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
636void 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
670GLuint 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
686void 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
727void 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
744void GLHelper::CopyTextureToImpl::CancelRequests() {
745  while (!request_queue_.empty()) {
746    Request* request = request_queue_.front();
747    FinishRequest(request, false);
748  }
749}
750
751FormatSupport 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
761GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
762    : gl_(gl),
763      context_support_(context_support),
764      readback_support_(new GLHelperReadbackSupport(gl)) {}
765
766GLHelper::~GLHelper() {}
767
768void 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
788void 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
810void 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
818void 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
832GLuint 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
838GLuint 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
848GLuint 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
871void 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
878void GLHelper::InitScalerImpl() {
879  // Lazily initialize |scaler_impl_|
880  if (!scaler_impl_)
881    scaler_impl_.reset(new GLHelperScaling(gl_, this));
882}
883
884GLint GLHelper::MaxDrawBuffers() {
885  InitCopyTextToImpl();
886  return copy_texture_to_impl_->MaxDrawBuffers();
887}
888
889void 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
919GLuint 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
930void GLHelper::DeleteTexture(GLuint texture_id) {
931  gl_->DeleteTextures(1, &texture_id);
932}
933
934uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
935
936void GLHelper::WaitSyncPoint(uint32 sync_point) {
937  gl_->WaitSyncPointCHROMIUM(sync_point);
938}
939
940gpu::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
948GLuint 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
959void 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
972void 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
984void 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
990void GLHelper::Flush() {
991  gl_->Flush();
992}
993
994void 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
1015const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
1016    0.257f, 0.504f, 0.098f, 0.0625f};
1017const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
1018    -0.148f, -0.291f, 0.439f, 0.5f};
1019const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
1020    0.439f, -0.368f, -0.071f, 0.5f};
1021const 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.
1026GLHelper::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
1092static 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
1099void 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.
1153GLHelper::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
1223void 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
1289bool 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
1299ReadbackYUVInterface* 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
1345ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
1346    ScalerQuality quality,
1347    const gfx::Size& src_size,
1348    const gfx::Rect& src_subrect,
1349    const gfx::Size& dst_size,
1350    const gfx::Rect& dst_subrect,
1351    bool flip_vertically,
1352    bool use_mrt) {
1353  InitCopyTextToImpl();
1354  return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality,
1355                                                          src_size,
1356                                                          src_subrect,
1357                                                          dst_size,
1358                                                          dst_subrect,
1359                                                          flip_vertically,
1360                                                          use_mrt);
1361}
1362
1363}  // namespace content
1364