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