gl_helper.h revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
17namespace gfx {
18class Rect;
19class Size;
20}
21
22namespace gpu {
23class ContextSupport;
24struct Mailbox;
25}
26
27namespace media {
28class VideoFrame;
29};
30
31class SkRegion;
32
33namespace content {
34
35class GLHelperScaling;
36
37class 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
67class 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
75class 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
83class 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
91template <GLenum Target>
92class 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
110template <GLenum Target>
111class ScopedBufferBinder : ScopedBinder<Target> {
112 public:
113  ScopedBufferBinder(gpu::gles2::GLES2Interface* gl, GLuint id)
114      : ScopedBinder<Target>(gl, id, &gpu::gles2::GLES2Interface::BindBuffer) {}
115};
116
117template <GLenum Target>
118class 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
126template <GLenum Target>
127class 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
134class ScopedFlush {
135 public:
136  explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
137
138  ~ScopedFlush() { gl_->Flush(); }
139
140 private:
141  gpu::gles2::GLES2Interface* gl_;
142
143  DISALLOW_COPY_AND_ASSIGN(ScopedFlush);
144};
145
146class ReadbackYUVInterface;
147
148// Provides higher level operations on top of the gpu::gles2::GLES2Interface
149// interfaces.
150class CONTENT_EXPORT GLHelper {
151 public:
152  GLHelper(gpu::gles2::GLES2Interface* gl,
153           gpu::ContextSupport* context_support);
154  ~GLHelper();
155
156  enum ScalerQuality {
157    // Bilinear single pass, fastest possible.
158    SCALER_QUALITY_FAST = 1,
159
160    // Bilinear upscale + N * 50% bilinear downscales.
161    // This is still fast enough for most purposes and
162    // Image quality is nearly as good as the BEST option.
163    SCALER_QUALITY_GOOD = 2,
164
165    // Bicubic upscale + N * 50% bicubic downscales.
166    // Produces very good quality scaled images, but it's
167    // 2-8x slower than the "GOOD" quality, so it's not always
168    // worth it.
169    SCALER_QUALITY_BEST = 3,
170  };
171
172  // Copies the block of pixels specified with |src_subrect| from |src_texture|,
173  // scales it to |dst_size|, and writes it into |out|.
174  // |src_size| is the size of |src_texture|. The result is of format GL_BGRA
175  // and is potentially flipped vertically to make it a correct image
176  // representation.  |callback| is invoked with the copy result when the copy
177  // operation has completed.
178  // Note that the src_texture will have the min/mag filter set to GL_LINEAR
179  // and wrap_s/t set to CLAMP_TO_EDGE in this call.
180  void CropScaleReadbackAndCleanTexture(
181      GLuint src_texture,
182      const gfx::Size& src_size,
183      const gfx::Rect& src_subrect,
184      const gfx::Size& dst_size,
185      unsigned char* out,
186      const SkBitmap::Config config,
187      const base::Callback<void(bool)>& callback);
188
189  // Copies the block of pixels specified with |src_subrect| from |src_mailbox|,
190  // scales it to |dst_size|, and writes it into |out|.
191  // |src_size| is the size of |src_mailbox|. The result is of format GL_BGRA
192  // and is potentially flipped vertically to make it a correct image
193  // representation.  |callback| is invoked with the copy result when the copy
194  // operation has completed.
195  // Note that the texture bound to src_mailbox will have the min/mag filter set
196  // to GL_LINEAR and wrap_s/t set to CLAMP_TO_EDGE in this call. src_mailbox is
197  // assumed to be GL_TEXTURE_2D.
198  void CropScaleReadbackAndCleanMailbox(
199      const gpu::Mailbox& src_mailbox,
200      uint32 sync_point,
201      const gfx::Size& src_size,
202      const gfx::Rect& src_subrect,
203      const gfx::Size& dst_size,
204      unsigned char* out,
205      const SkBitmap::Config config,
206      const base::Callback<void(bool)>& callback);
207
208  // Copies the texture data out of |texture| into |out|.  |size| is the
209  // size of the texture.  No post processing is applied to the pixels.  The
210  // texture is assumed to have a format of GL_RGBA with a pixel type of
211  // GL_UNSIGNED_BYTE.  This is a blocking call that calls glReadPixels on the
212  // current OpenGL context.
213  void ReadbackTextureSync(GLuint texture,
214                           const gfx::Rect& src_rect,
215                           unsigned char* out,
216                           SkBitmap::Config format);
217
218  void ReadbackTextureAsync(GLuint texture,
219                            const gfx::Size& dst_size,
220                            unsigned char* out,
221                            SkBitmap::Config config,
222                            const base::Callback<void(bool)>& callback);
223
224  // Creates a copy of the specified texture. |size| is the size of the texture.
225  // Note that the src_texture will have the min/mag filter set to GL_LINEAR
226  // and wrap_s/t set to CLAMP_TO_EDGE in this call.
227  GLuint CopyTexture(GLuint texture, const gfx::Size& size);
228
229  // Creates a scaled copy of the specified texture. |src_size| is the size of
230  // the texture and |dst_size| is the size of the resulting copy.
231  // Note that the src_texture will have the min/mag filter set to GL_LINEAR
232  // and wrap_s/t set to CLAMP_TO_EDGE in this call.
233  GLuint CopyAndScaleTexture(GLuint texture,
234                             const gfx::Size& src_size,
235                             const gfx::Size& dst_size,
236                             bool vertically_flip_texture,
237                             ScalerQuality quality);
238
239  // Returns the shader compiled from the source.
240  GLuint CompileShaderFromSource(const GLchar* source, GLenum type);
241
242  // Copies all pixels from |previous_texture| into |texture| that are
243  // inside the region covered by |old_damage| but not part of |new_damage|.
244  void CopySubBufferDamage(GLuint texture,
245                           GLuint previous_texture,
246                           const SkRegion& new_damage,
247                           const SkRegion& old_damage);
248
249  // Simply creates a texture.
250  GLuint CreateTexture();
251  // Deletes a texture.
252  void DeleteTexture(GLuint texture_id);
253
254  // Insert a sync point into the GL command buffer.
255  uint32 InsertSyncPoint();
256  // Wait for the sync point before executing further GL commands.
257  void WaitSyncPoint(uint32 sync_point);
258
259  // Creates a mailbox holder that is attached to the given texture id, with a
260  // sync point to wait on before using the mailbox. Returns a holder with an
261  // empty mailbox on failure.
262  // Note the texture is assumed to be GL_TEXTURE_2D.
263  gpu::MailboxHolder ProduceMailboxHolderFromTexture(GLuint texture_id);
264
265  // Creates a texture and consumes a mailbox into it. Returns 0 on failure.
266  // Note the mailbox is assumed to be GL_TEXTURE_2D.
267  GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
268                                 uint32 sync_point);
269
270  // Resizes the texture's size to |size|.
271  void ResizeTexture(GLuint texture, const gfx::Size& size);
272
273  // Copies the framebuffer data given in |rect| to |texture|.
274  void CopyTextureSubImage(GLuint texture, const gfx::Rect& rect);
275
276  // Copies the all framebuffer data to |texture|. |size| specifies the
277  // size of the framebuffer.
278  void CopyTextureFullImage(GLuint texture, const gfx::Size& size);
279
280  // Check whether rgb565 readback is supported or not.
281  bool CanUseRgb565Readback();
282
283  // A scaler will cache all intermediate textures and programs
284  // needed to scale from a specified size to a destination size.
285  // If the source or destination sizes changes, you must create
286  // a new scaler.
287  class CONTENT_EXPORT ScalerInterface {
288   public:
289    ScalerInterface() {}
290    virtual ~ScalerInterface() {}
291
292    // Note that the src_texture will have the min/mag filter set to GL_LINEAR
293    // and wrap_s/t set to CLAMP_TO_EDGE in this call.
294    virtual void Scale(GLuint source_texture, GLuint dest_texture) = 0;
295    virtual const gfx::Size& SrcSize() = 0;
296    virtual const gfx::Rect& SrcSubrect() = 0;
297    virtual const gfx::Size& DstSize() = 0;
298  };
299
300  // Note that the quality may be adjusted down if texture
301  // allocations fail or hardware doesn't support the requtested
302  // quality. Note that ScalerQuality enum is arranged in
303  // numerical order for simplicity.
304  ScalerInterface* CreateScaler(ScalerQuality quality,
305                                const gfx::Size& src_size,
306                                const gfx::Rect& src_subrect,
307                                const gfx::Size& dst_size,
308                                bool vertically_flip_texture,
309                                bool swizzle);
310
311  // Create a readback pipeline that will scale a subsection of the source
312  // texture, then convert it to YUV422 planar form and then read back that.
313  // This reduces the amount of memory read from GPU to CPU memory by a factor
314  // 2.6, which can be quite handy since readbacks have very limited speed
315  // on some platforms. All values in |dst_size| and |dst_subrect| must be
316  // a multiple of two. If |use_mrt| is true, the pipeline will try to optimize
317  // the YUV conversion using the multi-render-target extension. |use_mrt|
318  // should only be set to false for testing.
319  ReadbackYUVInterface* CreateReadbackPipelineYUV(ScalerQuality quality,
320                                                  const gfx::Size& src_size,
321                                                  const gfx::Rect& src_subrect,
322                                                  const gfx::Size& dst_size,
323                                                  const gfx::Rect& dst_subrect,
324                                                  bool flip_vertically,
325                                                  bool use_mrt);
326
327  // Returns the maximum number of draw buffers available,
328  // 0 if GL_EXT_draw_buffers is not available.
329  GLint MaxDrawBuffers();
330
331 protected:
332  class CopyTextureToImpl;
333
334  // Creates |copy_texture_to_impl_| if NULL.
335  void InitCopyTextToImpl();
336  // Creates |scaler_impl_| if NULL.
337  void InitScalerImpl();
338
339  gpu::gles2::GLES2Interface* gl_;
340  gpu::ContextSupport* context_support_;
341  scoped_ptr<CopyTextureToImpl> copy_texture_to_impl_;
342  scoped_ptr<GLHelperScaling> scaler_impl_;
343  bool initialized_565_format_check_;
344  bool support_565_format_;
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.
356class 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