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