gl_helper.h revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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
15namespace gfx {
16class Rect;
17class Size;
18}
19
20namespace gpu {
21class ContextSupport;
22struct Mailbox;
23}
24
25namespace media {
26class VideoFrame;
27};
28
29class SkRegion;
30
31namespace content {
32
33class GLHelperScaling;
34
35class ScopedWebGLId {
36 public:
37  typedef void (WebKit::WebGraphicsContext3D::*DeleteFunc)(WebGLId);
38  ScopedWebGLId(WebKit::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  WebKit::WebGraphicsContext3D* context_;
66  WebGLId id_;
67  DeleteFunc delete_func_;
68
69  DISALLOW_COPY_AND_ASSIGN(ScopedWebGLId);
70};
71
72class ScopedBuffer : public ScopedWebGLId {
73 public:
74  ScopedBuffer(WebKit::WebGraphicsContext3D* context,
75               WebGLId id)
76      : ScopedWebGLId(context,
77                      id,
78                      &WebKit::WebGraphicsContext3D::deleteBuffer) {}
79};
80
81class ScopedFramebuffer : public ScopedWebGLId {
82 public:
83  ScopedFramebuffer(WebKit::WebGraphicsContext3D* context,
84                    WebGLId id)
85      : ScopedWebGLId(context,
86                      id,
87                      &WebKit::WebGraphicsContext3D::deleteFramebuffer) {}
88};
89
90class ScopedProgram : public ScopedWebGLId {
91 public:
92  ScopedProgram(WebKit::WebGraphicsContext3D* context,
93                WebGLId id)
94      : ScopedWebGLId(context,
95                      id,
96                      &WebKit::WebGraphicsContext3D::deleteProgram) {}
97};
98
99class ScopedShader : public ScopedWebGLId {
100 public:
101  ScopedShader(WebKit::WebGraphicsContext3D* context,
102               WebGLId id)
103      : ScopedWebGLId(context,
104                      id,
105                      &WebKit::WebGraphicsContext3D::deleteShader) {}
106};
107
108class ScopedTexture : public ScopedWebGLId {
109 public:
110  ScopedTexture(WebKit::WebGraphicsContext3D* context,
111                WebGLId id)
112      : ScopedWebGLId(context,
113                      id,
114                      &WebKit::WebGraphicsContext3D::deleteTexture) {}
115};
116
117template <WebKit::WGC3Denum target>
118class ScopedBinder {
119 public:
120  typedef void (WebKit::WebGraphicsContext3D::*BindFunc)(WebKit::WGC3Denum,
121                                                         WebGLId);
122  ScopedBinder(WebKit::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  WebKit::WebGraphicsContext3D* context_;
136  BindFunc bind_func_;
137
138  DISALLOW_COPY_AND_ASSIGN(ScopedBinder);
139};
140
141template <WebKit::WGC3Denum target>
142class ScopedBufferBinder : ScopedBinder<target> {
143 public:
144  ScopedBufferBinder(WebKit::WebGraphicsContext3D* context,
145                     WebGLId id)
146      : ScopedBinder<target>(
147          context,
148          id,
149          &WebKit::WebGraphicsContext3D::bindBuffer) {}
150};
151
152template <WebKit::WGC3Denum target>
153class ScopedFramebufferBinder : ScopedBinder<target> {
154 public:
155  ScopedFramebufferBinder(WebKit::WebGraphicsContext3D* context,
156                          WebGLId id)
157      : ScopedBinder<target>(
158          context,
159          id,
160          &WebKit::WebGraphicsContext3D::bindFramebuffer) {}
161};
162
163template <WebKit::WGC3Denum target>
164class ScopedTextureBinder : ScopedBinder<target> {
165 public:
166  ScopedTextureBinder(WebKit::WebGraphicsContext3D* context,
167                      WebGLId id)
168      : ScopedBinder<target>(
169          context,
170          id,
171          &WebKit::WebGraphicsContext3D::bindTexture) {}
172};
173
174class ScopedFlush {
175 public:
176  explicit ScopedFlush(WebKit::WebGraphicsContext3D* context)
177      : context_(context) {
178  }
179
180  ~ScopedFlush() {
181    context_->flush();
182  }
183
184 private:
185  WebKit::WebGraphicsContext3D* context_;
186
187  DISALLOW_COPY_AND_ASSIGN(ScopedFlush);
188};
189
190
191class ReadbackYUVInterface;
192
193// Provides higher level operations on top of the WebKit::WebGraphicsContext3D
194// interfaces.
195class CONTENT_EXPORT GLHelper {
196 public:
197  GLHelper(WebKit::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      WebKit::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(WebKit::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  WebKit::WebGLId CopyTexture(WebKit::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  WebKit::WebGLId CopyAndScaleTexture(
272      WebKit::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  WebKit::WebGLId CompileShaderFromSource(const WebKit::WGC3Dchar* source,
280                                          WebKit::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(WebKit::WebGLId texture,
285                           WebKit::WebGLId previous_texture,
286                           const SkRegion& new_damage,
287                           const SkRegion& old_damage);
288
289  // Simply creates a texture.
290  WebKit::WebGLId CreateTexture();
291
292  // Creates a texture and consumes a mailbox into it. Returns 0 on failure.
293  // Note the mailbox is assumed to be GL_TEXTURE_2D.
294  WebKit::WebGLId ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
295                                          uint32 sync_point);
296
297  // Resizes the texture's size to |size|.
298  void ResizeTexture(WebKit::WebGLId texture, const gfx::Size& size);
299
300  // Copies the framebuffer data given in |rect| to |texture|.
301  void CopyTextureSubImage(WebKit::WebGLId texture, const gfx::Rect& rect);
302
303  // Copies the all framebuffer data to |texture|. |size| specifies the
304  // size of the framebuffer.
305  void CopyTextureFullImage(WebKit::WebGLId texture, const gfx::Size& size);
306
307  // A scaler will cache all intermediate textures and programs
308  // needed to scale from a specified size to a destination size.
309  // If the source or destination sizes changes, you must create
310  // a new scaler.
311  class CONTENT_EXPORT ScalerInterface {
312   public:
313    ScalerInterface() {}
314    virtual ~ScalerInterface() {}
315
316    // Note that the src_texture will have the min/mag filter set to GL_LINEAR
317    // and wrap_s/t set to CLAMP_TO_EDGE in this call.
318    virtual void Scale(WebKit::WebGLId source_texture,
319                       WebKit::WebGLId dest_texture) = 0;
320    virtual const gfx::Size& SrcSize() = 0;
321    virtual const gfx::Rect& SrcSubrect() = 0;
322    virtual const gfx::Size& DstSize() = 0;
323  };
324
325  // Note that the quality may be adjusted down if texture
326  // allocations fail or hardware doesn't support the requtested
327  // quality. Note that ScalerQuality enum is arranged in
328  // numerical order for simplicity.
329  ScalerInterface* CreateScaler(ScalerQuality quality,
330                                const gfx::Size& src_size,
331                                const gfx::Rect& src_subrect,
332                                const gfx::Size& dst_size,
333                                bool vertically_flip_texture,
334                                bool swizzle);
335
336  // Create a readback pipeline that will scale a subsection of the source
337  // texture, then convert it to YUV422 planar form and then read back that.
338  // This reduces the amount of memory read from GPU to CPU memory by a factor
339  // 2.6, which can be quite handy since readbacks have very limited speed
340  // on some platforms. All values in |dst_size| and |dst_subrect| must be
341  // a multiple of two. If |use_mrt| is true, the pipeline will try to optimize
342  // the YUV conversion using the multi-render-target extension. |use_mrt|
343  // should only be set to false for testing.
344  ReadbackYUVInterface* CreateReadbackPipelineYUV(
345      ScalerQuality quality,
346      const gfx::Size& src_size,
347      const gfx::Rect& src_subrect,
348      const gfx::Size& dst_size,
349      const gfx::Rect& dst_subrect,
350      bool flip_vertically,
351      bool use_mrt);
352
353  // Returns the maximum number of draw buffers available,
354  // 0 if GL_EXT_draw_buffers is not available.
355  WebKit::WGC3Dint MaxDrawBuffers();
356
357 protected:
358  class CopyTextureToImpl;
359
360  // Creates |copy_texture_to_impl_| if NULL.
361  void InitCopyTextToImpl();
362  // Creates |scaler_impl_| if NULL.
363  void InitScalerImpl();
364
365  WebKit::WebGraphicsContext3D* context_;
366  gpu::ContextSupport* context_support_;
367  scoped_ptr<CopyTextureToImpl> copy_texture_to_impl_;
368  scoped_ptr<GLHelperScaling> scaler_impl_;
369
370  DISALLOW_COPY_AND_ASSIGN(GLHelper);
371};
372
373// Similar to a ScalerInterface, a yuv readback pipeline will
374// cache a scaler and all intermediate textures and frame buffers
375// needed to scale, crop, letterbox and read back a texture from
376// the GPU into CPU-accessible RAM. A single readback pipeline
377// can handle multiple outstanding readbacks at the same time, but
378// if the source or destination sizes change, you'll need to create
379// a new readback pipeline.
380class CONTENT_EXPORT ReadbackYUVInterface {
381public:
382  ReadbackYUVInterface() {}
383  virtual ~ReadbackYUVInterface() {}
384
385  // Note that |target| must use YV12 format.
386  virtual void ReadbackYUV(
387      const gpu::Mailbox& mailbox,
388      uint32 sync_point,
389      const scoped_refptr<media::VideoFrame>& target,
390      const base::Callback<void(bool)>& callback) = 0;
391  virtual GLHelper::ScalerInterface* scaler() = 0;
392};
393
394}  // namespace content
395
396#endif  // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_
397