Home | History | Annotate | Download | only in client
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_
      6 #define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_
      7 
      8 #include "base/atomicops.h"
      9 #include "base/basictypes.h"
     10 #include "base/callback.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "content/common/content_export.h"
     13 #include "gpu/command_buffer/client/gles2_interface.h"
     14 #include "gpu/command_buffer/common/mailbox_holder.h"
     15 #include "third_party/skia/include/core/SkBitmap.h"
     16 
     17 namespace gfx {
     18 class Rect;
     19 class Size;
     20 }
     21 
     22 namespace gpu {
     23 class ContextSupport;
     24 struct Mailbox;
     25 }
     26 
     27 namespace media {
     28 class VideoFrame;
     29 };
     30 
     31 class SkRegion;
     32 
     33 namespace content {
     34 
     35 class GLHelperScaling;
     36 
     37 class ScopedGLuint {
     38  public:
     39   typedef void (gpu::gles2::GLES2Interface::*GenFunc)(GLsizei n, GLuint* ids);
     40   typedef void (gpu::gles2::GLES2Interface::*DeleteFunc)(GLsizei n,
     41                                                          const GLuint* ids);
     42   ScopedGLuint(gpu::gles2::GLES2Interface* gl,
     43                GenFunc gen_func,
     44                DeleteFunc delete_func)
     45       : gl_(gl), id_(0u), delete_func_(delete_func) {
     46     (gl_->*gen_func)(1, &id_);
     47   }
     48 
     49   operator GLuint() const { return id_; }
     50 
     51   GLuint id() const { return id_; }
     52 
     53   ~ScopedGLuint() {
     54     if (id_ != 0) {
     55       (gl_->*delete_func_)(1, &id_);
     56     }
     57   }
     58 
     59  private:
     60   gpu::gles2::GLES2Interface* gl_;
     61   GLuint id_;
     62   DeleteFunc delete_func_;
     63 
     64   DISALLOW_COPY_AND_ASSIGN(ScopedGLuint);
     65 };
     66 
     67 class ScopedBuffer : public ScopedGLuint {
     68  public:
     69   explicit ScopedBuffer(gpu::gles2::GLES2Interface* gl)
     70       : ScopedGLuint(gl,
     71                      &gpu::gles2::GLES2Interface::GenBuffers,
     72                      &gpu::gles2::GLES2Interface::DeleteBuffers) {}
     73 };
     74 
     75 class ScopedFramebuffer : public ScopedGLuint {
     76  public:
     77   explicit ScopedFramebuffer(gpu::gles2::GLES2Interface* gl)
     78       : ScopedGLuint(gl,
     79                      &gpu::gles2::GLES2Interface::GenFramebuffers,
     80                      &gpu::gles2::GLES2Interface::DeleteFramebuffers) {}
     81 };
     82 
     83 class ScopedTexture : public ScopedGLuint {
     84  public:
     85   explicit ScopedTexture(gpu::gles2::GLES2Interface* gl)
     86       : ScopedGLuint(gl,
     87                      &gpu::gles2::GLES2Interface::GenTextures,
     88                      &gpu::gles2::GLES2Interface::DeleteTextures) {}
     89 };
     90 
     91 template <GLenum Target>
     92 class ScopedBinder {
     93  public:
     94   typedef void (gpu::gles2::GLES2Interface::*BindFunc)(GLenum target,
     95                                                        GLuint id);
     96   ScopedBinder(gpu::gles2::GLES2Interface* gl, GLuint id, BindFunc bind_func)
     97       : gl_(gl), bind_func_(bind_func) {
     98     (gl_->*bind_func_)(Target, id);
     99   }
    100 
    101   virtual ~ScopedBinder() { (gl_->*bind_func_)(Target, 0); }
    102 
    103  private:
    104   gpu::gles2::GLES2Interface* gl_;
    105   BindFunc bind_func_;
    106 
    107   DISALLOW_COPY_AND_ASSIGN(ScopedBinder);
    108 };
    109 
    110 template <GLenum Target>
    111 class ScopedBufferBinder : ScopedBinder<Target> {
    112  public:
    113   ScopedBufferBinder(gpu::gles2::GLES2Interface* gl, GLuint id)
    114       : ScopedBinder<Target>(gl, id, &gpu::gles2::GLES2Interface::BindBuffer) {}
    115 };
    116 
    117 template <GLenum Target>
    118 class ScopedFramebufferBinder : ScopedBinder<Target> {
    119  public:
    120   ScopedFramebufferBinder(gpu::gles2::GLES2Interface* gl, GLuint id)
    121       : ScopedBinder<Target>(gl,
    122                              id,
    123                              &gpu::gles2::GLES2Interface::BindFramebuffer) {}
    124 };
    125 
    126 template <GLenum Target>
    127 class ScopedTextureBinder : ScopedBinder<Target> {
    128  public:
    129   ScopedTextureBinder(gpu::gles2::GLES2Interface* gl, GLuint id)
    130       : ScopedBinder<Target>(gl, id, &gpu::gles2::GLES2Interface::BindTexture) {
    131   }
    132 };
    133 
    134 class ReadbackYUVInterface;
    135 class GLHelperReadbackSupport;
    136 
    137 // Provides higher level operations on top of the gpu::gles2::GLES2Interface
    138 // interfaces.
    139 class CONTENT_EXPORT GLHelper {
    140  public:
    141   GLHelper(gpu::gles2::GLES2Interface* gl,
    142            gpu::ContextSupport* context_support);
    143   ~GLHelper();
    144 
    145   enum ScalerQuality {
    146     // Bilinear single pass, fastest possible.
    147     SCALER_QUALITY_FAST = 1,
    148 
    149     // Bilinear upscale + N * 50% bilinear downscales.
    150     // This is still fast enough for most purposes and
    151     // Image quality is nearly as good as the BEST option.
    152     SCALER_QUALITY_GOOD = 2,
    153 
    154     // Bicubic upscale + N * 50% bicubic downscales.
    155     // Produces very good quality scaled images, but it's
    156     // 2-8x slower than the "GOOD" quality, so it's not always
    157     // worth it.
    158     SCALER_QUALITY_BEST = 3,
    159   };
    160 
    161   // Copies the block of pixels specified with |src_subrect| from |src_texture|,
    162   // scales it to |dst_size|, and writes it into |out|.
    163   // |src_size| is the size of |src_texture|. The result is in |out_color_type|
    164   // format and is potentially flipped vertically to make it a correct image
    165   // representation.  |callback| is invoked with the copy result when the copy
    166   // operation has completed.
    167   // Note that the src_texture will have the min/mag filter set to GL_LINEAR
    168   // and wrap_s/t set to CLAMP_TO_EDGE in this call.
    169   void CropScaleReadbackAndCleanTexture(
    170       GLuint src_texture,
    171       const gfx::Size& src_size,
    172       const gfx::Rect& src_subrect,
    173       const gfx::Size& dst_size,
    174       unsigned char* out,
    175       const SkColorType out_color_type,
    176       const base::Callback<void(bool)>& callback,
    177       GLHelper::ScalerQuality quality);
    178 
    179   // Copies the block of pixels specified with |src_subrect| from |src_mailbox|,
    180   // scales it to |dst_size|, and writes it into |out|.
    181   // |src_size| is the size of |src_mailbox|. The result is in |out_color_type|
    182   // format and is potentially flipped vertically to make it a correct image
    183   // representation.  |callback| is invoked with the copy result when the copy
    184   // operation has completed.
    185   // Note that the texture bound to src_mailbox will have the min/mag filter set
    186   // to GL_LINEAR and wrap_s/t set to CLAMP_TO_EDGE in this call. src_mailbox is
    187   // assumed to be GL_TEXTURE_2D.
    188   void CropScaleReadbackAndCleanMailbox(
    189       const gpu::Mailbox& src_mailbox,
    190       uint32 sync_point,
    191       const gfx::Size& src_size,
    192       const gfx::Rect& src_subrect,
    193       const gfx::Size& dst_size,
    194       unsigned char* out,
    195       const SkColorType out_color_type,
    196       const base::Callback<void(bool)>& callback,
    197       GLHelper::ScalerQuality quality);
    198 
    199   // Copies the texture data out of |texture| into |out|.  |size| is the
    200   // size of the texture.  No post processing is applied to the pixels.  The
    201   // texture is assumed to have a format of GL_RGBA with a pixel type of
    202   // GL_UNSIGNED_BYTE.  This is a blocking call that calls glReadPixels on the
    203   // current OpenGL context.
    204   void ReadbackTextureSync(GLuint texture,
    205                            const gfx::Rect& src_rect,
    206                            unsigned char* out,
    207                            SkColorType format);
    208 
    209   void ReadbackTextureAsync(GLuint texture,
    210                             const gfx::Size& dst_size,
    211                             unsigned char* out,
    212                             SkColorType color_type,
    213                             const base::Callback<void(bool)>& callback);
    214 
    215   // Creates a copy of the specified texture. |size| is the size of the texture.
    216   // Note that the src_texture will have the min/mag filter set to GL_LINEAR
    217   // and wrap_s/t set to CLAMP_TO_EDGE in this call.
    218   GLuint CopyTexture(GLuint texture, const gfx::Size& size);
    219 
    220   // Creates a scaled copy of the specified texture. |src_size| is the size of
    221   // the texture and |dst_size| is the size of the resulting copy.
    222   // Note that the src_texture will have the min/mag filter set to GL_LINEAR
    223   // and wrap_s/t set to CLAMP_TO_EDGE in this call.
    224   GLuint CopyAndScaleTexture(GLuint texture,
    225                              const gfx::Size& src_size,
    226                              const gfx::Size& dst_size,
    227                              bool vertically_flip_texture,
    228                              ScalerQuality quality);
    229 
    230   // Returns the shader compiled from the source.
    231   GLuint CompileShaderFromSource(const GLchar* source, GLenum type);
    232 
    233   // Copies all pixels from |previous_texture| into |texture| that are
    234   // inside the region covered by |old_damage| but not part of |new_damage|.
    235   void CopySubBufferDamage(GLuint texture,
    236                            GLuint previous_texture,
    237                            const SkRegion& new_damage,
    238                            const SkRegion& old_damage);
    239 
    240   // Simply creates a texture.
    241   GLuint CreateTexture();
    242   // Deletes a texture.
    243   void DeleteTexture(GLuint texture_id);
    244 
    245   // Insert a sync point into the GL command buffer.
    246   uint32 InsertSyncPoint();
    247   // Wait for the sync point before executing further GL commands.
    248   void WaitSyncPoint(uint32 sync_point);
    249 
    250   // Creates a mailbox holder that is attached to the given texture id, with a
    251   // sync point to wait on before using the mailbox. Returns a holder with an
    252   // empty mailbox on failure.
    253   // Note the texture is assumed to be GL_TEXTURE_2D.
    254   gpu::MailboxHolder ProduceMailboxHolderFromTexture(GLuint texture_id);
    255 
    256   // Creates a texture and consumes a mailbox into it. Returns 0 on failure.
    257   // Note the mailbox is assumed to be GL_TEXTURE_2D.
    258   GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
    259                                  uint32 sync_point);
    260 
    261   // Resizes the texture's size to |size|.
    262   void ResizeTexture(GLuint texture, const gfx::Size& size);
    263 
    264   // Copies the framebuffer data given in |rect| to |texture|.
    265   void CopyTextureSubImage(GLuint texture, const gfx::Rect& rect);
    266 
    267   // Copies the all framebuffer data to |texture|. |size| specifies the
    268   // size of the framebuffer.
    269   void CopyTextureFullImage(GLuint texture, const gfx::Size& size);
    270 
    271   // Flushes GL commands.
    272   void Flush();
    273 
    274 
    275   // A scaler will cache all intermediate textures and programs
    276   // needed to scale from a specified size to a destination size.
    277   // If the source or destination sizes changes, you must create
    278   // a new scaler.
    279   class CONTENT_EXPORT ScalerInterface {
    280    public:
    281     ScalerInterface() {}
    282     virtual ~ScalerInterface() {}
    283 
    284     // Note that the src_texture will have the min/mag filter set to GL_LINEAR
    285     // and wrap_s/t set to CLAMP_TO_EDGE in this call.
    286     virtual void Scale(GLuint source_texture, GLuint dest_texture) = 0;
    287     virtual const gfx::Size& SrcSize() = 0;
    288     virtual const gfx::Rect& SrcSubrect() = 0;
    289     virtual const gfx::Size& DstSize() = 0;
    290   };
    291 
    292   // Note that the quality may be adjusted down if texture
    293   // allocations fail or hardware doesn't support the requtested
    294   // quality. Note that ScalerQuality enum is arranged in
    295   // numerical order for simplicity.
    296   ScalerInterface* CreateScaler(ScalerQuality quality,
    297                                 const gfx::Size& src_size,
    298                                 const gfx::Rect& src_subrect,
    299                                 const gfx::Size& dst_size,
    300                                 bool vertically_flip_texture,
    301                                 bool swizzle);
    302 
    303   // Create a readback pipeline that will scale a subsection of the source
    304   // texture, then convert it to YUV422 planar form and then read back that.
    305   // This reduces the amount of memory read from GPU to CPU memory by a factor
    306   // 2.6, which can be quite handy since readbacks have very limited speed
    307   // on some platforms. All values in |dst_size| and |dst_subrect| must be
    308   // a multiple of two. If |use_mrt| is true, the pipeline will try to optimize
    309   // the YUV conversion using the multi-render-target extension. |use_mrt|
    310   // should only be set to false for testing.
    311   ReadbackYUVInterface* CreateReadbackPipelineYUV(ScalerQuality quality,
    312                                                   const gfx::Size& src_size,
    313                                                   const gfx::Rect& src_subrect,
    314                                                   const gfx::Size& dst_size,
    315                                                   const gfx::Rect& dst_subrect,
    316                                                   bool flip_vertically,
    317                                                   bool use_mrt);
    318 
    319   // Returns the maximum number of draw buffers available,
    320   // 0 if GL_EXT_draw_buffers is not available.
    321   GLint MaxDrawBuffers();
    322 
    323   // Checks whether the readbback is supported for texture with the
    324   // matching config. This doesnt check for cross format readbacks.
    325   bool IsReadbackConfigSupported(SkColorType texture_format);
    326 
    327  protected:
    328   class CopyTextureToImpl;
    329 
    330   // Creates |copy_texture_to_impl_| if NULL.
    331   void InitCopyTextToImpl();
    332   // Creates |scaler_impl_| if NULL.
    333   void InitScalerImpl();
    334 
    335   enum ReadbackSwizzle {
    336     kSwizzleNone = 0,
    337     kSwizzleBGRA
    338   };
    339 
    340   gpu::gles2::GLES2Interface* gl_;
    341   gpu::ContextSupport* context_support_;
    342   scoped_ptr<CopyTextureToImpl> copy_texture_to_impl_;
    343   scoped_ptr<GLHelperScaling> scaler_impl_;
    344   scoped_ptr<GLHelperReadbackSupport> readback_support_;
    345 
    346   DISALLOW_COPY_AND_ASSIGN(GLHelper);
    347 };
    348 
    349 // Similar to a ScalerInterface, a yuv readback pipeline will
    350 // cache a scaler and all intermediate textures and frame buffers
    351 // needed to scale, crop, letterbox and read back a texture from
    352 // the GPU into CPU-accessible RAM. A single readback pipeline
    353 // can handle multiple outstanding readbacks at the same time, but
    354 // if the source or destination sizes change, you'll need to create
    355 // a new readback pipeline.
    356 class CONTENT_EXPORT ReadbackYUVInterface {
    357  public:
    358   ReadbackYUVInterface() {}
    359   virtual ~ReadbackYUVInterface() {}
    360 
    361   // Note that |target| must use YV12 format.
    362   virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
    363                            uint32 sync_point,
    364                            const scoped_refptr<media::VideoFrame>& target,
    365                            const base::Callback<void(bool)>& callback) = 0;
    366   virtual GLHelper::ScalerInterface* scaler() = 0;
    367 };
    368 
    369 }  // namespace content
    370 
    371 #endif  // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_
    372