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