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 GPU_COMMAND_BUFFER_CLIENT_GL_HELPER_SCALING_H_
6 #define GPU_COMMAND_BUFFER_CLIENT_GL_HELPER_SCALING_H_
7 
8 #include <map>
9 #include <vector>
10 
11 #include "base/containers/circular_deque.h"
12 #include "base/macros.h"
13 #include "gpu/command_buffer/client/gl_helper.h"
14 #include "gpu/gpu_export.h"
15 #include "ui/gfx/geometry/vector2d.h"
16 
17 namespace gpu {
18 
19 class GLHelperTest;
20 class ScalerImpl;
21 class ShaderProgram;
22 
23 // Implements GPU texture scaling methods.
24 // Note that you should probably not use this class directly.
25 // See gl_helper.cc::CreateScaler instead.
26 class GPU_EXPORT GLHelperScaling {
27  public:
28   enum ShaderType {
29     SHADER_BILINEAR,
30     SHADER_BILINEAR2,
31     SHADER_BILINEAR3,
32     SHADER_BILINEAR4,
33     SHADER_BILINEAR2X2,
34     SHADER_BICUBIC_UPSCALE,
35     SHADER_BICUBIC_HALF_1D,
36     SHADER_PLANAR,
37     SHADER_YUV_MRT_PASS1,
38     SHADER_YUV_MRT_PASS2,
39   };
40 
41   using ShaderProgramKeyType = std::pair<ShaderType, bool>;
42 
43   GLHelperScaling(gles2::GLES2Interface* gl, GLHelper* helper);
44   ~GLHelperScaling();
45   void InitBuffer();
46 
47   // Returns null on invalid arguments.
48   std::unique_ptr<GLHelper::ScalerInterface> CreateScaler(
49       GLHelper::ScalerQuality quality,
50       const gfx::Vector2d& scale_from,
51       const gfx::Vector2d& scale_to,
52       bool flipped_source,
53       bool flip_output,
54       bool swizzle);
55 
56   // These convert source textures with RGBA pixel data into a single-color-
57   // channel planar format. Used for grayscale and I420 format conversion.
58   //
59   // While these output RGBA pixels in the destination texture(s), each RGBA
60   // pixel is actually a container for 4 consecutive pixels in the result.
61   std::unique_ptr<GLHelper::ScalerInterface> CreateGrayscalePlanerizer(
62       bool flipped_source,
63       bool flip_output,
64       bool swizzle);
65   std::unique_ptr<GLHelper::ScalerInterface> CreateI420Planerizer(
66       int plane,  // 0=Y, 1=U, 2=V
67       bool flipped_source,
68       bool flip_output,
69       bool swizzle);
70 
71   // These are a faster path to I420 planerization, if the platform supports
72   // it. The first pass draws to two outputs simultaneously: the Y plane and an
73   // interim UV plane that is used as the input to the second pass. Then, the
74   // second pass splits the UV plane, drawing to two outputs: the final U plane
75   // and final V plane. Thus, clients should call ScaleToMultipleOutputs() on
76   // the returned instance.
77   std::unique_ptr<GLHelper::ScalerInterface> CreateI420MrtPass1Planerizer(
78       bool flipped_source,
79       bool flip_output,
80       bool swizzle);
81   std::unique_ptr<GLHelper::ScalerInterface> CreateI420MrtPass2Planerizer(
82       bool swizzle);
83 
84  private:
85   // A ScaleOp represents a pass in a scaler pipeline, in one dimension.
86   // Note that when quality is GOOD, multiple scaler passes will be
87   // combined into one operation for increased performance.
88   // Exposed in the header file for testing purposes.
89   struct ScaleOp {
ScaleOpScaleOp90     ScaleOp(int factor, bool x, int size)
91         : scale_factor(factor), scale_x(x), scale_size(size) {}
92 
93     // Calculates the sequence of ScaleOp needed to convert an image of
94     // relative size |src| into an image of relative size |dst|. If |scale_x| is
95     // true, then 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|.
AddOpsScaleOp99     static void AddOps(int src,
100                        int dst,
101                        bool scale_x,
102                        bool allow3,
103                        base::circular_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 either the X or Y component of |scale| to the match the relative
125     // result size of this ScaleOp.
UpdateScaleScaleOp126     void UpdateScale(gfx::Vector2d* scale) {
127       if (scale_x) {
128         scale->set_x(scale_size);
129       } else {
130         scale->set_y(scale_size);
131       }
132     }
133 
134     // A scale factor of 0 means upscale
135     // 2 means 50% scale
136     // 3 means 33% scale, etc.
137     int scale_factor;
138     bool scale_x;    // Otherwise y
139     int scale_size;  // Size to scale to.
140   };
141 
142   // Full specification for a single scaling stage.
143   struct ScalerStage {
144     ShaderType shader;
145     gfx::Vector2d scale_from;
146     gfx::Vector2d scale_to;
147     bool scale_x;
148     bool flipped_source;
149     bool flip_output;
150     bool swizzle;
151   };
152 
153   // Compute a vector of scaler stages for a particular
154   // set of input/output parameters.
155   static void ComputeScalerStages(GLHelper::ScalerQuality quality,
156                                   const gfx::Vector2d& scale_from,
157                                   const gfx::Vector2d& scale_to,
158                                   bool flipped_source,
159                                   bool flip_output,
160                                   bool swizzle,
161                                   std::vector<ScalerStage>* scaler_stages);
162 
163   // Take two queues of ScaleOp structs and generate a
164   // vector of scaler stages. This is the second half of
165   // ComputeScalerStages.
166   static void ConvertScalerOpsToScalerStages(
167       GLHelper::ScalerQuality quality,
168       gfx::Vector2d scale_from,
169       base::circular_deque<GLHelperScaling::ScaleOp>* x_ops,
170       base::circular_deque<GLHelperScaling::ScaleOp>* y_ops,
171       std::vector<ScalerStage>* scaler_stages);
172 
173   scoped_refptr<ShaderProgram> GetShaderProgram(ShaderType type, bool swizzle);
174 
175   // Interleaved array of 2-dimentional vertex positions (x, y) and
176   // 2-dimentional texture coordinates (s, t).
177   static const GLfloat kVertexAttributes[];
178 
179   gles2::GLES2Interface* gl_;
180   GLHelper* helper_;
181 
182   // The buffer that holds the vertices and the texture coordinates data for
183   // drawing a quad.
184   ScopedBuffer vertex_attributes_buffer_;
185 
186   std::map<ShaderProgramKeyType, scoped_refptr<ShaderProgram>> shader_programs_;
187 
188   friend class ShaderProgram;
189   friend class ScalerImpl;
190   friend class GLHelperBenchmark;
191   friend class GLHelperTest;
192   DISALLOW_COPY_AND_ASSIGN(GLHelperScaling);
193 };
194 
195 }  // namespace gpu
196 
197 #endif  // GPU_COMMAND_BUFFER_CLIENT_GL_HELPER_SCALING_H_
198