1// Copyright (c) 2013 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_SCALING_H_
6#define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_H_
7
8#include <deque>
9#include <map>
10#include <vector>
11
12#include "content/common/gpu/client/gl_helper.h"
13#include "ui/gfx/rect.h"
14#include "ui/gfx/size.h"
15
16namespace content {
17
18class ShaderProgram;
19class ScalerImpl;
20class GLHelperTest;
21
22// Implements GPU texture scaling methods.
23// Note that you should probably not use this class directly.
24// See gl_helper.cc::CreateScaler instead.
25class CONTENT_EXPORT GLHelperScaling {
26 public:
27  enum ShaderType {
28    SHADER_BILINEAR,
29    SHADER_BILINEAR2,
30    SHADER_BILINEAR3,
31    SHADER_BILINEAR4,
32    SHADER_BILINEAR2X2,
33    SHADER_BICUBIC_UPSCALE,
34    SHADER_BICUBIC_HALF_1D,
35    SHADER_PLANAR,
36    SHADER_YUV_MRT_PASS1,
37    SHADER_YUV_MRT_PASS2,
38  };
39
40  // Similar to ScalerInterface, but can generate multiple outputs.
41  // Used for YUV conversion in gl_helper.c
42  class CONTENT_EXPORT ShaderInterface {
43   public:
44    ShaderInterface() {}
45    virtual ~ShaderInterface() {}
46    // Note that the src_texture will have the min/mag filter set to GL_LINEAR
47    // and wrap_s/t set to CLAMP_TO_EDGE in this call.
48    virtual void Execute(GLuint source_texture,
49                         const std::vector<GLuint>& dest_textures) = 0;
50  };
51
52  typedef std::pair<ShaderType, bool> ShaderProgramKeyType;
53
54  GLHelperScaling(gpu::gles2::GLES2Interface* gl,
55                  GLHelper* helper);
56  ~GLHelperScaling();
57  void InitBuffer();
58
59  GLHelper::ScalerInterface* CreateScaler(
60      GLHelper::ScalerQuality quality,
61      gfx::Size src_size,
62      gfx::Rect src_subrect,
63      const gfx::Size& dst_size,
64      bool vertically_flip_texture,
65      bool swizzle);
66
67  GLHelper::ScalerInterface* CreatePlanarScaler(
68      const gfx::Size& src_size,
69      const gfx::Rect& src_subrect,
70      const gfx::Size& dst_size,
71      bool vertically_flip_texture,
72      bool swizzle,
73      const float color_weights[4]);
74
75  ShaderInterface* CreateYuvMrtShader(
76      const gfx::Size& src_size,
77      const gfx::Rect& src_subrect,
78      const gfx::Size& dst_size,
79      bool vertically_flip_texture,
80      bool swizzle,
81      ShaderType shader);
82
83 private:
84  // A ScaleOp represents a pass in a scaler pipeline, in one dimension.
85  // Note that when quality is GOOD, multiple scaler passes will be
86  // combined into one operation for increased performance.
87  // Exposed in the header file for testing purposes.
88  struct ScaleOp {
89    ScaleOp(int factor, bool x, int size)
90        : scale_factor(factor), scale_x(x), scale_size(size) {
91    }
92
93    // Calculate a set of ScaleOp needed to convert an image of size
94    // |src| into an image of size |dst|. If |scale_x| is true, then
95    // the calculations are for the X axis of the image, otherwise Y.
96    // If |allow3| is true, we can use a SHADER_BILINEAR3 to replace
97    // a scale up and scale down with a 3-tap bilinear scale.
98    // The calculated ScaleOps are added to |ops|.
99    static void AddOps(int src,
100                       int dst,
101                       bool scale_x,
102                       bool allow3,
103                       std::deque<ScaleOp>* ops) {
104      int num_downscales = 0;
105      if (allow3 && dst * 3 >= src && dst * 2 < src) {
106        // Technically, this should be a scale up and then a
107        // scale down, but it makes the optimization code more
108        // complicated.
109        ops->push_back(ScaleOp(3, scale_x, dst));
110        return;
111      }
112      while ((dst << num_downscales) < src) {
113        num_downscales++;
114      }
115      if ((dst << num_downscales) != src) {
116        ops->push_back(ScaleOp(0, scale_x, dst << num_downscales));
117      }
118      while (num_downscales) {
119        num_downscales--;
120        ops->push_back(ScaleOp(2, scale_x, dst << num_downscales));
121      }
122    }
123
124    // Update |size| to its new size. Before calling this function
125    // |size| should be the size of the input image. After calling it,
126    // |size| will be the size of the image after this particular
127    // scaling operation.
128    void UpdateSize(gfx::Size* subrect) {
129      if (scale_x) {
130        subrect->set_width(scale_size);
131      } else {
132        subrect->set_height(scale_size);
133      }
134    }
135
136    // A scale factor of 0 means upscale
137    // 2 means 50% scale
138    // 3 means 33% scale, etc.
139    int scale_factor;
140    bool scale_x;  // Otherwise y
141    int scale_size;  // Size to scale to.
142  };
143
144  // Full specification for a single scaling stage.
145  struct ScalerStage {
146    ScalerStage(ShaderType shader_,
147                gfx::Size src_size_,
148                gfx::Rect src_subrect_,
149                gfx::Size dst_size_,
150                bool scale_x_,
151                bool vertically_flip_texture_,
152                bool swizzle_);
153    ShaderType shader;
154    gfx::Size src_size;
155    gfx::Rect src_subrect;
156    gfx::Size dst_size;
157    bool scale_x;
158    bool vertically_flip_texture;
159    bool swizzle;
160  };
161
162  // Compute a vector of scaler stages for a particular
163  // set of input/output parameters.
164  void ComputeScalerStages(GLHelper::ScalerQuality quality,
165                           const gfx::Size& src_size,
166                           const gfx::Rect& src_subrect,
167                           const gfx::Size& dst_size,
168                           bool vertically_flip_texture,
169                           bool swizzle,
170                           std::vector<ScalerStage> *scaler_stages);
171
172  // Take two queues of ScaleOp structs and generate a
173  // vector of scaler stages. This is the second half of
174  // ComputeScalerStages.
175  void ConvertScalerOpsToScalerStages(
176      GLHelper::ScalerQuality quality,
177      gfx::Size src_size,
178      gfx::Rect src_subrect,
179      const gfx::Size& dst_size,
180      bool vertically_flip_texture,
181      bool swizzle,
182      std::deque<GLHelperScaling::ScaleOp>* x_ops,
183      std::deque<GLHelperScaling::ScaleOp>* y_ops,
184      std::vector<ScalerStage> *scaler_stages);
185
186
187  scoped_refptr<ShaderProgram> GetShaderProgram(ShaderType type, bool swizzle);
188
189  // Interleaved array of 2-dimentional vertex positions (x, y) and
190  // 2-dimentional texture coordinates (s, t).
191  static const GLfloat kVertexAttributes[];
192
193  gpu::gles2::GLES2Interface* gl_;
194  GLHelper* helper_;
195
196  // The buffer that holds the vertices and the texture coordinates data for
197  // drawing a quad.
198  ScopedBuffer vertex_attributes_buffer_;
199
200  std::map<ShaderProgramKeyType,
201           scoped_refptr<ShaderProgram> > shader_programs_;
202
203  friend class ShaderProgram;
204  friend class ScalerImpl;
205  friend class GLHelperTest;
206  DISALLOW_COPY_AND_ASSIGN(GLHelperScaling);
207};
208
209
210}  // namespace content
211
212#endif  // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_H_
213