| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 #include "content/browser/compositor/gl_helper_scaling.h" | 
|  | 6 | 
|  | 7 #include <stddef.h> | 
|  | 8 | 
|  | 9 #include <deque> | 
|  | 10 #include <string> | 
|  | 11 #include <vector> | 
|  | 12 | 
|  | 13 #include "base/bind.h" | 
|  | 14 #include "base/lazy_instance.h" | 
|  | 15 #include "base/logging.h" | 
|  | 16 #include "base/macros.h" | 
|  | 17 #include "base/memory/ref_counted.h" | 
|  | 18 #include "base/message_loop/message_loop.h" | 
|  | 19 #include "base/time/time.h" | 
|  | 20 #include "base/trace_event/trace_event.h" | 
|  | 21 #include "gpu/command_buffer/client/gles2_interface.h" | 
|  | 22 #include "third_party/skia/include/core/SkRegion.h" | 
|  | 23 #include "ui/gfx/geometry/rect.h" | 
|  | 24 #include "ui/gfx/geometry/size.h" | 
|  | 25 | 
|  | 26 using gpu::gles2::GLES2Interface; | 
|  | 27 | 
|  | 28 namespace content { | 
|  | 29 | 
|  | 30 GLHelperScaling::GLHelperScaling(GLES2Interface* gl, GLHelper* helper) | 
|  | 31     : gl_(gl), helper_(helper), vertex_attributes_buffer_(gl_) { | 
|  | 32   InitBuffer(); | 
|  | 33 } | 
|  | 34 | 
|  | 35 GLHelperScaling::~GLHelperScaling() {} | 
|  | 36 | 
|  | 37 // Used to keep track of a generated shader program. The program | 
|  | 38 // is passed in as text through Setup and is used by calling | 
|  | 39 // UseProgram() with the right parameters. Note that |gl_| | 
|  | 40 // and |helper_| are assumed to live longer than this program. | 
|  | 41 class ShaderProgram : public base::RefCounted<ShaderProgram> { | 
|  | 42  public: | 
|  | 43   ShaderProgram(GLES2Interface* gl, GLHelper* helper) | 
|  | 44       : gl_(gl), | 
|  | 45         helper_(helper), | 
|  | 46         program_(gl_->CreateProgram()), | 
|  | 47         position_location_(-1), | 
|  | 48         texcoord_location_(-1), | 
|  | 49         src_subrect_location_(-1), | 
|  | 50         src_pixelsize_location_(-1), | 
|  | 51         dst_pixelsize_location_(-1), | 
|  | 52         scaling_vector_location_(-1), | 
|  | 53         color_weights_location_(-1) {} | 
|  | 54 | 
|  | 55   // Compile shader program. | 
|  | 56   void Setup(const GLchar* vertex_shader_text, | 
|  | 57              const GLchar* fragment_shader_text); | 
|  | 58 | 
|  | 59   // UseProgram must be called with GL_TEXTURE_2D bound to the | 
|  | 60   // source texture and GL_ARRAY_BUFFER bound to a vertex | 
|  | 61   // attribute buffer. | 
|  | 62   void UseProgram(const gfx::Size& src_size, | 
|  | 63                   const gfx::Rect& src_subrect, | 
|  | 64                   const gfx::Size& dst_size, | 
|  | 65                   bool scale_x, | 
|  | 66                   bool flip_y, | 
|  | 67                   GLfloat color_weights[4]); | 
|  | 68 | 
|  | 69   bool Initialized() const { return position_location_ != -1; } | 
|  | 70 | 
|  | 71  private: | 
|  | 72   friend class base::RefCounted<ShaderProgram>; | 
|  | 73   ~ShaderProgram() { gl_->DeleteProgram(program_); } | 
|  | 74 | 
|  | 75   GLES2Interface* gl_; | 
|  | 76   GLHelper* helper_; | 
|  | 77 | 
|  | 78   // A program for copying a source texture into a destination texture. | 
|  | 79   GLuint program_; | 
|  | 80 | 
|  | 81   // The location of the position in the program. | 
|  | 82   GLint position_location_; | 
|  | 83   // The location of the texture coordinate in the program. | 
|  | 84   GLint texcoord_location_; | 
|  | 85   // The location of the source texture in the program. | 
|  | 86   GLint texture_location_; | 
|  | 87   // The location of the texture coordinate of | 
|  | 88   // the sub-rectangle in the program. | 
|  | 89   GLint src_subrect_location_; | 
|  | 90   // Location of size of source image in pixels. | 
|  | 91   GLint src_pixelsize_location_; | 
|  | 92   // Location of size of destination image in pixels. | 
|  | 93   GLint dst_pixelsize_location_; | 
|  | 94   // Location of vector for scaling direction. | 
|  | 95   GLint scaling_vector_location_; | 
|  | 96   // Location of color weights. | 
|  | 97   GLint color_weights_location_; | 
|  | 98 | 
|  | 99   DISALLOW_COPY_AND_ASSIGN(ShaderProgram); | 
|  | 100 }; | 
|  | 101 | 
|  | 102 // Implementation of a single stage in a scaler pipeline. If the pipeline has | 
|  | 103 // multiple stages, it calls Scale() on the subscaler, then further scales the | 
|  | 104 // output. Caches textures and framebuffers to avoid allocating/deleting | 
|  | 105 // them once per frame, which can be expensive on some drivers. | 
|  | 106 class ScalerImpl : public GLHelper::ScalerInterface, | 
|  | 107                    public GLHelperScaling::ShaderInterface { | 
|  | 108  public: | 
|  | 109   // |gl| and |copy_impl| are expected to live longer than this object. | 
|  | 110   // |src_size| is the size of the input texture in pixels. | 
|  | 111   // |dst_size| is the size of the output texutre in pixels. | 
|  | 112   // |src_subrect| is the portion of the src to copy to the output texture. | 
|  | 113   // If |scale_x| is true, we are scaling along the X axis, otherwise Y. | 
|  | 114   // If we are scaling in both X and Y, |scale_x| is ignored. | 
|  | 115   // If |vertically_flip_texture| is true, output will be upside-down. | 
|  | 116   // If |swizzle| is true, RGBA will be transformed into BGRA. | 
|  | 117   // |color_weights| are only used together with SHADER_PLANAR to specify | 
|  | 118   //   how to convert RGB colors into a single value. | 
|  | 119   ScalerImpl(GLES2Interface* gl, | 
|  | 120              GLHelperScaling* scaler_helper, | 
|  | 121              const GLHelperScaling::ScalerStage& scaler_stage, | 
|  | 122              ScalerImpl* subscaler, | 
|  | 123              const float* color_weights) | 
|  | 124       : gl_(gl), | 
|  | 125         scaler_helper_(scaler_helper), | 
|  | 126         spec_(scaler_stage), | 
|  | 127         intermediate_texture_(0), | 
|  | 128         dst_framebuffer_(gl), | 
|  | 129         subscaler_(subscaler) { | 
|  | 130     if (color_weights) { | 
|  | 131       color_weights_[0] = color_weights[0]; | 
|  | 132       color_weights_[1] = color_weights[1]; | 
|  | 133       color_weights_[2] = color_weights[2]; | 
|  | 134       color_weights_[3] = color_weights[3]; | 
|  | 135     } else { | 
|  | 136       color_weights_[0] = 0.0; | 
|  | 137       color_weights_[1] = 0.0; | 
|  | 138       color_weights_[2] = 0.0; | 
|  | 139       color_weights_[3] = 0.0; | 
|  | 140     } | 
|  | 141     shader_program_ = | 
|  | 142         scaler_helper_->GetShaderProgram(spec_.shader, spec_.swizzle); | 
|  | 143 | 
|  | 144     if (subscaler_) { | 
|  | 145       intermediate_texture_ = 0u; | 
|  | 146       gl_->GenTextures(1, &intermediate_texture_); | 
|  | 147       ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, | 
|  | 148                                                         intermediate_texture_); | 
|  | 149       gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, spec_.src_size.width(), | 
|  | 150                       spec_.src_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, | 
|  | 151                       NULL); | 
|  | 152     } | 
|  | 153   } | 
|  | 154 | 
|  | 155   ~ScalerImpl() override { | 
|  | 156     if (intermediate_texture_) { | 
|  | 157       gl_->DeleteTextures(1, &intermediate_texture_); | 
|  | 158     } | 
|  | 159   } | 
|  | 160 | 
|  | 161   // GLHelperShader::ShaderInterface implementation. | 
|  | 162   void Execute(GLuint source_texture, | 
|  | 163                const std::vector<GLuint>& dest_textures) override { | 
|  | 164     if (subscaler_) { | 
|  | 165       subscaler_->Scale(source_texture, intermediate_texture_); | 
|  | 166       source_texture = intermediate_texture_; | 
|  | 167     } | 
|  | 168 | 
|  | 169     ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( | 
|  | 170         gl_, dst_framebuffer_); | 
|  | 171     DCHECK_GT(dest_textures.size(), 0U); | 
|  | 172     std::unique_ptr<GLenum[]> buffers(new GLenum[dest_textures.size()]); | 
|  | 173     for (size_t t = 0; t < dest_textures.size(); t++) { | 
|  | 174       ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dest_textures[t]); | 
|  | 175       gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + t, | 
|  | 176                                 GL_TEXTURE_2D, dest_textures[t], 0); | 
|  | 177       buffers[t] = GL_COLOR_ATTACHMENT0 + t; | 
|  | 178     } | 
|  | 179     ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, source_texture); | 
|  | 180 | 
|  | 181     gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 
|  | 182     gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 
|  | 183     gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 
|  | 184     gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 
|  | 185 | 
|  | 186     ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder( | 
|  | 187         gl_, scaler_helper_->vertex_attributes_buffer_); | 
|  | 188     shader_program_->UseProgram(spec_.src_size, spec_.src_subrect, | 
|  | 189                                 spec_.dst_size, spec_.scale_x, | 
|  | 190                                 spec_.vertically_flip_texture, color_weights_); | 
|  | 191     gl_->Viewport(0, 0, spec_.dst_size.width(), spec_.dst_size.height()); | 
|  | 192 | 
|  | 193     if (dest_textures.size() > 1) { | 
|  | 194       DCHECK_LE(static_cast<int>(dest_textures.size()), | 
|  | 195                 scaler_helper_->helper_->MaxDrawBuffers()); | 
|  | 196       gl_->DrawBuffersEXT(dest_textures.size(), buffers.get()); | 
|  | 197     } | 
|  | 198     // Conduct texture mapping by drawing a quad composed of two triangles. | 
|  | 199     gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 
|  | 200     if (dest_textures.size() > 1) { | 
|  | 201       // Set the draw buffers back to not confuse others. | 
|  | 202       gl_->DrawBuffersEXT(1, &buffers[0]); | 
|  | 203     } | 
|  | 204   } | 
|  | 205 | 
|  | 206   // GLHelper::ScalerInterface implementation. | 
|  | 207   void Scale(GLuint source_texture, GLuint dest_texture) override { | 
|  | 208     std::vector<GLuint> tmp(1); | 
|  | 209     tmp[0] = dest_texture; | 
|  | 210     Execute(source_texture, tmp); | 
|  | 211   } | 
|  | 212 | 
|  | 213   const gfx::Size& SrcSize() override { | 
|  | 214     if (subscaler_) { | 
|  | 215       return subscaler_->SrcSize(); | 
|  | 216     } | 
|  | 217     return spec_.src_size; | 
|  | 218   } | 
|  | 219   const gfx::Rect& SrcSubrect() override { | 
|  | 220     if (subscaler_) { | 
|  | 221       return subscaler_->SrcSubrect(); | 
|  | 222     } | 
|  | 223     return spec_.src_subrect; | 
|  | 224   } | 
|  | 225   const gfx::Size& DstSize() override { return spec_.dst_size; } | 
|  | 226 | 
|  | 227  private: | 
|  | 228   GLES2Interface* gl_; | 
|  | 229   GLHelperScaling* scaler_helper_; | 
|  | 230   GLHelperScaling::ScalerStage spec_; | 
|  | 231   GLfloat color_weights_[4]; | 
|  | 232   GLuint intermediate_texture_; | 
|  | 233   scoped_refptr<ShaderProgram> shader_program_; | 
|  | 234   ScopedFramebuffer dst_framebuffer_; | 
|  | 235   std::unique_ptr<ScalerImpl> subscaler_; | 
|  | 236 }; | 
|  | 237 | 
|  | 238 GLHelperScaling::ScalerStage::ScalerStage(ShaderType shader_, | 
|  | 239                                           gfx::Size src_size_, | 
|  | 240                                           gfx::Rect src_subrect_, | 
|  | 241                                           gfx::Size dst_size_, | 
|  | 242                                           bool scale_x_, | 
|  | 243                                           bool vertically_flip_texture_, | 
|  | 244                                           bool swizzle_) | 
|  | 245     : shader(shader_), | 
|  | 246       src_size(src_size_), | 
|  | 247       src_subrect(src_subrect_), | 
|  | 248       dst_size(dst_size_), | 
|  | 249       scale_x(scale_x_), | 
|  | 250       vertically_flip_texture(vertically_flip_texture_), | 
|  | 251       swizzle(swizzle_) {} | 
|  | 252 | 
|  | 253 GLHelperScaling::ScalerStage::ScalerStage(const ScalerStage& other) = default; | 
|  | 254 | 
|  | 255 // The important inputs for this function is |x_ops| and | 
|  | 256 // |y_ops|. They represent scaling operations to be done | 
|  | 257 // on an imag of size |src_size|. If |quality| is SCALER_QUALITY_BEST, | 
|  | 258 // then we will interpret these scale operations literally and we'll | 
|  | 259 // create one scaler stage for each ScaleOp.  However, if |quality| | 
|  | 260 // is SCALER_QUALITY_GOOD, then we can do a whole bunch of optimizations | 
|  | 261 // by combining two or more ScaleOps in to a single scaler stage. | 
|  | 262 // Normally we process ScaleOps from |y_ops| first and |x_ops| after | 
|  | 263 // all |y_ops| are processed, but sometimes we can combine one or more | 
|  | 264 // operation from both queues essentially for free. This is the reason | 
|  | 265 // why |x_ops| and |y_ops| aren't just one single queue. | 
|  | 266 void GLHelperScaling::ConvertScalerOpsToScalerStages( | 
|  | 267     GLHelper::ScalerQuality quality, | 
|  | 268     gfx::Size src_size, | 
|  | 269     gfx::Rect src_subrect, | 
|  | 270     const gfx::Size& dst_size, | 
|  | 271     bool vertically_flip_texture, | 
|  | 272     bool swizzle, | 
|  | 273     std::deque<GLHelperScaling::ScaleOp>* x_ops, | 
|  | 274     std::deque<GLHelperScaling::ScaleOp>* y_ops, | 
|  | 275     std::vector<ScalerStage>* scaler_stages) { | 
|  | 276   while (!x_ops->empty() || !y_ops->empty()) { | 
|  | 277     gfx::Size intermediate_size = src_subrect.size(); | 
|  | 278     std::deque<ScaleOp>* current_queue = NULL; | 
|  | 279 | 
|  | 280     if (!y_ops->empty()) { | 
|  | 281       current_queue = y_ops; | 
|  | 282     } else { | 
|  | 283       current_queue = x_ops; | 
|  | 284     } | 
|  | 285 | 
|  | 286     ShaderType current_shader = SHADER_BILINEAR; | 
|  | 287     switch (current_queue->front().scale_factor) { | 
|  | 288       case 0: | 
|  | 289         if (quality == GLHelper::SCALER_QUALITY_BEST) { | 
|  | 290           current_shader = SHADER_BICUBIC_UPSCALE; | 
|  | 291         } | 
|  | 292         break; | 
|  | 293       case 2: | 
|  | 294         if (quality == GLHelper::SCALER_QUALITY_BEST) { | 
|  | 295           current_shader = SHADER_BICUBIC_HALF_1D; | 
|  | 296         } | 
|  | 297         break; | 
|  | 298       case 3: | 
|  | 299         DCHECK(quality != GLHelper::SCALER_QUALITY_BEST); | 
|  | 300         current_shader = SHADER_BILINEAR3; | 
|  | 301         break; | 
|  | 302       default: | 
|  | 303         NOTREACHED(); | 
|  | 304     } | 
|  | 305     bool scale_x = current_queue->front().scale_x; | 
|  | 306     current_queue->front().UpdateSize(&intermediate_size); | 
|  | 307     current_queue->pop_front(); | 
|  | 308 | 
|  | 309     // Optimization: Sometimes we can combine 2-4 scaling operations into | 
|  | 310     // one operation. | 
|  | 311     if (quality == GLHelper::SCALER_QUALITY_GOOD) { | 
|  | 312       if (!current_queue->empty() && current_shader == SHADER_BILINEAR) { | 
|  | 313         // Combine two steps in the same dimension. | 
|  | 314         current_queue->front().UpdateSize(&intermediate_size); | 
|  | 315         current_queue->pop_front(); | 
|  | 316         current_shader = SHADER_BILINEAR2; | 
|  | 317         if (!current_queue->empty()) { | 
|  | 318           // Combine three steps in the same dimension. | 
|  | 319           current_queue->front().UpdateSize(&intermediate_size); | 
|  | 320           current_queue->pop_front(); | 
|  | 321           current_shader = SHADER_BILINEAR4; | 
|  | 322         } | 
|  | 323       } | 
|  | 324       // Check if we can combine some steps in the other dimension as well. | 
|  | 325       // Since all shaders currently use GL_LINEAR, we can easily scale up | 
|  | 326       // or scale down by exactly 2x at the same time as we do another | 
|  | 327       // operation. Currently, the following mergers are supported: | 
|  | 328       // * 1 bilinear Y-pass with 1 bilinear X-pass (up or down) | 
|  | 329       // * 2 bilinear Y-passes with 2 bilinear X-passes | 
|  | 330       // * 1 bilinear Y-pass with N bilinear X-pass | 
|  | 331       // * N bilinear Y-passes with 1 bilinear X-pass (down only) | 
|  | 332       // Measurements indicate that generalizing this for 3x3 and 4x4 | 
|  | 333       // makes it slower on some platforms, such as the Pixel. | 
|  | 334       if (!scale_x && x_ops->size() > 0 && x_ops->front().scale_factor <= 2) { | 
|  | 335         int x_passes = 0; | 
|  | 336         if (current_shader == SHADER_BILINEAR2 && x_ops->size() >= 2) { | 
|  | 337           // 2y + 2x passes | 
|  | 338           x_passes = 2; | 
|  | 339           current_shader = SHADER_BILINEAR2X2; | 
|  | 340         } else if (current_shader == SHADER_BILINEAR) { | 
|  | 341           // 1y + Nx passes | 
|  | 342           scale_x = true; | 
|  | 343           switch (x_ops->size()) { | 
|  | 344             case 0: | 
|  | 345               NOTREACHED(); | 
|  | 346             case 1: | 
|  | 347               if (x_ops->front().scale_factor == 3) { | 
|  | 348                 current_shader = SHADER_BILINEAR3; | 
|  | 349               } | 
|  | 350               x_passes = 1; | 
|  | 351               break; | 
|  | 352             case 2: | 
|  | 353               x_passes = 2; | 
|  | 354               current_shader = SHADER_BILINEAR2; | 
|  | 355               break; | 
|  | 356             default: | 
|  | 357               x_passes = 3; | 
|  | 358               current_shader = SHADER_BILINEAR4; | 
|  | 359               break; | 
|  | 360           } | 
|  | 361         } else if (x_ops->front().scale_factor == 2) { | 
|  | 362           // Ny + 1x-downscale | 
|  | 363           x_passes = 1; | 
|  | 364         } | 
|  | 365 | 
|  | 366         for (int i = 0; i < x_passes; i++) { | 
|  | 367           x_ops->front().UpdateSize(&intermediate_size); | 
|  | 368           x_ops->pop_front(); | 
|  | 369         } | 
|  | 370       } | 
|  | 371     } | 
|  | 372 | 
|  | 373     scaler_stages->push_back(ScalerStage(current_shader, src_size, src_subrect, | 
|  | 374                                          intermediate_size, scale_x, | 
|  | 375                                          vertically_flip_texture, swizzle)); | 
|  | 376     src_size = intermediate_size; | 
|  | 377     src_subrect = gfx::Rect(intermediate_size); | 
|  | 378     vertically_flip_texture = false; | 
|  | 379     swizzle = false; | 
|  | 380   } | 
|  | 381 } | 
|  | 382 | 
|  | 383 void GLHelperScaling::ComputeScalerStages( | 
|  | 384     GLHelper::ScalerQuality quality, | 
|  | 385     const gfx::Size& src_size, | 
|  | 386     const gfx::Rect& src_subrect, | 
|  | 387     const gfx::Size& dst_size, | 
|  | 388     bool vertically_flip_texture, | 
|  | 389     bool swizzle, | 
|  | 390     std::vector<ScalerStage>* scaler_stages) { | 
|  | 391   if (quality == GLHelper::SCALER_QUALITY_FAST || | 
|  | 392       src_subrect.size() == dst_size) { | 
|  | 393     scaler_stages->push_back(ScalerStage(SHADER_BILINEAR, src_size, src_subrect, | 
|  | 394                                          dst_size, false, | 
|  | 395                                          vertically_flip_texture, swizzle)); | 
|  | 396     return; | 
|  | 397   } | 
|  | 398 | 
|  | 399   std::deque<GLHelperScaling::ScaleOp> x_ops, y_ops; | 
|  | 400   GLHelperScaling::ScaleOp::AddOps(src_subrect.width(), dst_size.width(), true, | 
|  | 401                                    quality == GLHelper::SCALER_QUALITY_GOOD, | 
|  | 402                                    &x_ops); | 
|  | 403   GLHelperScaling::ScaleOp::AddOps( | 
|  | 404       src_subrect.height(), dst_size.height(), false, | 
|  | 405       quality == GLHelper::SCALER_QUALITY_GOOD, &y_ops); | 
|  | 406 | 
|  | 407   ConvertScalerOpsToScalerStages(quality, src_size, src_subrect, dst_size, | 
|  | 408                                  vertically_flip_texture, swizzle, &x_ops, | 
|  | 409                                  &y_ops, scaler_stages); | 
|  | 410 } | 
|  | 411 | 
|  | 412 GLHelper::ScalerInterface* GLHelperScaling::CreateScaler( | 
|  | 413     GLHelper::ScalerQuality quality, | 
|  | 414     gfx::Size src_size, | 
|  | 415     gfx::Rect src_subrect, | 
|  | 416     const gfx::Size& dst_size, | 
|  | 417     bool vertically_flip_texture, | 
|  | 418     bool swizzle) { | 
|  | 419   std::vector<ScalerStage> scaler_stages; | 
|  | 420   ComputeScalerStages(quality, src_size, src_subrect, dst_size, | 
|  | 421                       vertically_flip_texture, swizzle, &scaler_stages); | 
|  | 422 | 
|  | 423   ScalerImpl* ret = NULL; | 
|  | 424   for (unsigned int i = 0; i < scaler_stages.size(); i++) { | 
|  | 425     ret = new ScalerImpl(gl_, this, scaler_stages[i], ret, NULL); | 
|  | 426   } | 
|  | 427   return ret; | 
|  | 428 } | 
|  | 429 | 
|  | 430 GLHelper::ScalerInterface* GLHelperScaling::CreatePlanarScaler( | 
|  | 431     const gfx::Size& src_size, | 
|  | 432     const gfx::Rect& src_subrect, | 
|  | 433     const gfx::Size& dst_size, | 
|  | 434     bool vertically_flip_texture, | 
|  | 435     bool swizzle, | 
|  | 436     const float color_weights[4]) { | 
|  | 437   ScalerStage stage(SHADER_PLANAR, src_size, src_subrect, dst_size, true, | 
|  | 438                     vertically_flip_texture, swizzle); | 
|  | 439   return new ScalerImpl(gl_, this, stage, NULL, color_weights); | 
|  | 440 } | 
|  | 441 | 
|  | 442 GLHelperScaling::ShaderInterface* GLHelperScaling::CreateYuvMrtShader( | 
|  | 443     const gfx::Size& src_size, | 
|  | 444     const gfx::Rect& src_subrect, | 
|  | 445     const gfx::Size& dst_size, | 
|  | 446     bool vertically_flip_texture, | 
|  | 447     bool swizzle, | 
|  | 448     ShaderType shader) { | 
|  | 449   DCHECK(shader == SHADER_YUV_MRT_PASS1 || shader == SHADER_YUV_MRT_PASS2); | 
|  | 450   ScalerStage stage(shader, src_size, src_subrect, dst_size, true, | 
|  | 451                     vertically_flip_texture, swizzle); | 
|  | 452   return new ScalerImpl(gl_, this, stage, NULL, NULL); | 
|  | 453 } | 
|  | 454 | 
|  | 455 const GLfloat GLHelperScaling::kVertexAttributes[] = { | 
|  | 456     -1.0f, -1.0f, 0.0f, 0.0f,  // vertex 0 | 
|  | 457     1.0f,  -1.0f, 1.0f, 0.0f,  // vertex 1 | 
|  | 458     -1.0f, 1.0f,  0.0f, 1.0f,  // vertex 2 | 
|  | 459     1.0f,  1.0f,  1.0f, 1.0f, | 
|  | 460 };  // vertex 3 | 
|  | 461 | 
|  | 462 void GLHelperScaling::InitBuffer() { | 
|  | 463   ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(gl_, | 
|  | 464                                                     vertex_attributes_buffer_); | 
|  | 465   gl_->BufferData(GL_ARRAY_BUFFER, sizeof(kVertexAttributes), kVertexAttributes, | 
|  | 466                   GL_STATIC_DRAW); | 
|  | 467 } | 
|  | 468 | 
|  | 469 scoped_refptr<ShaderProgram> GLHelperScaling::GetShaderProgram(ShaderType type, | 
|  | 470                                                                bool swizzle) { | 
|  | 471   ShaderProgramKeyType key(type, swizzle); | 
|  | 472   scoped_refptr<ShaderProgram>& cache_entry(shader_programs_[key]); | 
|  | 473   if (!cache_entry.get()) { | 
|  | 474     cache_entry = new ShaderProgram(gl_, helper_); | 
|  | 475     std::basic_string<GLchar> vertex_program; | 
|  | 476     std::basic_string<GLchar> fragment_program; | 
|  | 477     std::basic_string<GLchar> vertex_header; | 
|  | 478     std::basic_string<GLchar> fragment_directives; | 
|  | 479     std::basic_string<GLchar> fragment_header; | 
|  | 480     std::basic_string<GLchar> shared_variables; | 
|  | 481 | 
|  | 482     vertex_header.append( | 
|  | 483         "precision highp float;\n" | 
|  | 484         "attribute vec2 a_position;\n" | 
|  | 485         "attribute vec2 a_texcoord;\n" | 
|  | 486         "uniform vec4 src_subrect;\n"); | 
|  | 487 | 
|  | 488     fragment_header.append( | 
|  | 489         "precision mediump float;\n" | 
|  | 490         "uniform sampler2D s_texture;\n"); | 
|  | 491 | 
|  | 492     vertex_program.append( | 
|  | 493         "  gl_Position = vec4(a_position, 0.0, 1.0);\n" | 
|  | 494         "  vec2 texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;\n"); | 
|  | 495 | 
|  | 496     switch (type) { | 
|  | 497       case SHADER_BILINEAR: | 
|  | 498         shared_variables.append("varying vec2 v_texcoord;\n"); | 
|  | 499         vertex_program.append("  v_texcoord = texcoord;\n"); | 
|  | 500         fragment_program.append( | 
|  | 501             "  gl_FragColor = texture2D(s_texture, v_texcoord);\n"); | 
|  | 502         break; | 
|  | 503 | 
|  | 504       case SHADER_BILINEAR2: | 
|  | 505         // This is equivialent to two passes of the BILINEAR shader above. | 
|  | 506         // It can be used to scale an image down 1.0x-2.0x in either dimension, | 
|  | 507         // or exactly 4x. | 
|  | 508         shared_variables.append( | 
|  | 509             "varying vec4 v_texcoords;\n");  // 2 texcoords packed in one quad | 
|  | 510         vertex_header.append( | 
|  | 511             "uniform vec2 scaling_vector;\n" | 
|  | 512             "uniform vec2 dst_pixelsize;\n"); | 
|  | 513         vertex_program.append( | 
|  | 514             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" | 
|  | 515             "  step /= 4.0;\n" | 
|  | 516             "  v_texcoords.xy = texcoord + step;\n" | 
|  | 517             "  v_texcoords.zw = texcoord - step;\n"); | 
|  | 518 | 
|  | 519         fragment_program.append( | 
|  | 520             "  gl_FragColor = (texture2D(s_texture, v_texcoords.xy) +\n" | 
|  | 521             "                  texture2D(s_texture, v_texcoords.zw)) / 2.0;\n"); | 
|  | 522         break; | 
|  | 523 | 
|  | 524       case SHADER_BILINEAR3: | 
|  | 525         // This is kind of like doing 1.5 passes of the BILINEAR shader. | 
|  | 526         // It can be used to scale an image down 1.5x-3.0x, or exactly 6x. | 
|  | 527         shared_variables.append( | 
|  | 528             "varying vec4 v_texcoords1;\n"  // 2 texcoords packed in one quad | 
|  | 529             "varying vec2 v_texcoords2;\n"); | 
|  | 530         vertex_header.append( | 
|  | 531             "uniform vec2 scaling_vector;\n" | 
|  | 532             "uniform vec2 dst_pixelsize;\n"); | 
|  | 533         vertex_program.append( | 
|  | 534             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" | 
|  | 535             "  step /= 3.0;\n" | 
|  | 536             "  v_texcoords1.xy = texcoord + step;\n" | 
|  | 537             "  v_texcoords1.zw = texcoord;\n" | 
|  | 538             "  v_texcoords2 = texcoord - step;\n"); | 
|  | 539         fragment_program.append( | 
|  | 540             "  gl_FragColor = (texture2D(s_texture, v_texcoords1.xy) +\n" | 
|  | 541             "                  texture2D(s_texture, v_texcoords1.zw) +\n" | 
|  | 542             "                  texture2D(s_texture, v_texcoords2)) / 3.0;\n"); | 
|  | 543         break; | 
|  | 544 | 
|  | 545       case SHADER_BILINEAR4: | 
|  | 546         // This is equivialent to three passes of the BILINEAR shader above, | 
|  | 547         // It can be used to scale an image down 2.0x-4.0x or exactly 8x. | 
|  | 548         shared_variables.append("varying vec4 v_texcoords[2];\n"); | 
|  | 549         vertex_header.append( | 
|  | 550             "uniform vec2 scaling_vector;\n" | 
|  | 551             "uniform vec2 dst_pixelsize;\n"); | 
|  | 552         vertex_program.append( | 
|  | 553             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" | 
|  | 554             "  step /= 8.0;\n" | 
|  | 555             "  v_texcoords[0].xy = texcoord - step * 3.0;\n" | 
|  | 556             "  v_texcoords[0].zw = texcoord - step;\n" | 
|  | 557             "  v_texcoords[1].xy = texcoord + step;\n" | 
|  | 558             "  v_texcoords[1].zw = texcoord + step * 3.0;\n"); | 
|  | 559         fragment_program.append( | 
|  | 560             "  gl_FragColor = (\n" | 
|  | 561             "      texture2D(s_texture, v_texcoords[0].xy) +\n" | 
|  | 562             "      texture2D(s_texture, v_texcoords[0].zw) +\n" | 
|  | 563             "      texture2D(s_texture, v_texcoords[1].xy) +\n" | 
|  | 564             "      texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n"); | 
|  | 565         break; | 
|  | 566 | 
|  | 567       case SHADER_BILINEAR2X2: | 
|  | 568         // This is equivialent to four passes of the BILINEAR shader above. | 
|  | 569         // Two in each dimension. It can be used to scale an image down | 
|  | 570         // 1.0x-2.0x in both X and Y directions. Or, it could be used to | 
|  | 571         // scale an image down by exactly 4x in both dimensions. | 
|  | 572         shared_variables.append("varying vec4 v_texcoords[2];\n"); | 
|  | 573         vertex_header.append("uniform vec2 dst_pixelsize;\n"); | 
|  | 574         vertex_program.append( | 
|  | 575             "  vec2 step = src_subrect.zw / 4.0 / dst_pixelsize;\n" | 
|  | 576             "  v_texcoords[0].xy = texcoord + vec2(step.x, step.y);\n" | 
|  | 577             "  v_texcoords[0].zw = texcoord + vec2(step.x, -step.y);\n" | 
|  | 578             "  v_texcoords[1].xy = texcoord + vec2(-step.x, step.y);\n" | 
|  | 579             "  v_texcoords[1].zw = texcoord + vec2(-step.x, -step.y);\n"); | 
|  | 580         fragment_program.append( | 
|  | 581             "  gl_FragColor = (\n" | 
|  | 582             "      texture2D(s_texture, v_texcoords[0].xy) +\n" | 
|  | 583             "      texture2D(s_texture, v_texcoords[0].zw) +\n" | 
|  | 584             "      texture2D(s_texture, v_texcoords[1].xy) +\n" | 
|  | 585             "      texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n"); | 
|  | 586         break; | 
|  | 587 | 
|  | 588       case SHADER_BICUBIC_HALF_1D: | 
|  | 589         // This scales down texture by exactly half in one dimension. | 
|  | 590         // directions in one pass. We use bilinear lookup to reduce | 
|  | 591         // the number of texture reads from 8 to 4 | 
|  | 592         shared_variables.append( | 
|  | 593             "const float CenterDist = 99.0 / 140.0;\n" | 
|  | 594             "const float LobeDist = 11.0 / 4.0;\n" | 
|  | 595             "const float CenterWeight = 35.0 / 64.0;\n" | 
|  | 596             "const float LobeWeight = -3.0 / 64.0;\n" | 
|  | 597             "varying vec4 v_texcoords[2];\n"); | 
|  | 598         vertex_header.append( | 
|  | 599             "uniform vec2 scaling_vector;\n" | 
|  | 600             "uniform vec2 src_pixelsize;\n"); | 
|  | 601         vertex_program.append( | 
|  | 602             "  vec2 step = src_subrect.zw * scaling_vector / src_pixelsize;\n" | 
|  | 603             "  v_texcoords[0].xy = texcoord - LobeDist * step;\n" | 
|  | 604             "  v_texcoords[0].zw = texcoord - CenterDist * step;\n" | 
|  | 605             "  v_texcoords[1].xy = texcoord + CenterDist * step;\n" | 
|  | 606             "  v_texcoords[1].zw = texcoord + LobeDist * step;\n"); | 
|  | 607         fragment_program.append( | 
|  | 608             "  gl_FragColor = \n" | 
|  | 609             // Lobe pixels | 
|  | 610             "      (texture2D(s_texture, v_texcoords[0].xy) +\n" | 
|  | 611             "       texture2D(s_texture, v_texcoords[1].zw)) *\n" | 
|  | 612             "          LobeWeight +\n" | 
|  | 613             // Center pixels | 
|  | 614             "      (texture2D(s_texture, v_texcoords[0].zw) +\n" | 
|  | 615             "       texture2D(s_texture, v_texcoords[1].xy)) *\n" | 
|  | 616             "          CenterWeight;\n"); | 
|  | 617         break; | 
|  | 618 | 
|  | 619       case SHADER_BICUBIC_UPSCALE: | 
|  | 620         // When scaling up, we need 4 texture reads, but we can | 
|  | 621         // save some instructions because will know in which range of | 
|  | 622         // the bicubic function each call call to the bicubic function | 
|  | 623         // will be in. | 
|  | 624         // Also, when sampling the bicubic function like this, the sum | 
|  | 625         // is always exactly one, so we can skip normalization as well. | 
|  | 626         shared_variables.append("varying vec2 v_texcoord;\n"); | 
|  | 627         vertex_program.append("  v_texcoord = texcoord;\n"); | 
|  | 628         fragment_header.append( | 
|  | 629             "uniform vec2 src_pixelsize;\n" | 
|  | 630             "uniform vec2 scaling_vector;\n" | 
|  | 631             "const float a = -0.5;\n" | 
|  | 632             // This function is equivialent to calling the bicubic | 
|  | 633             // function with x-1, x, 1-x and 2-x | 
|  | 634             // (assuming 0 <= x < 1) | 
|  | 635             "vec4 filt4(float x) {\n" | 
|  | 636             "  return vec4(x * x * x, x * x, x, 1) *\n" | 
|  | 637             "         mat4(       a,      -2.0 * a,   a, 0.0,\n" | 
|  | 638             "               a + 2.0,      -a - 3.0, 0.0, 1.0,\n" | 
|  | 639             "              -a - 2.0, 3.0 + 2.0 * a,  -a, 0.0,\n" | 
|  | 640             "                    -a,             a, 0.0, 0.0);\n" | 
|  | 641             "}\n" | 
|  | 642             "mat4 pixels_x(vec2 pos, vec2 step) {\n" | 
|  | 643             "  return mat4(\n" | 
|  | 644             "      texture2D(s_texture, pos - step),\n" | 
|  | 645             "      texture2D(s_texture, pos),\n" | 
|  | 646             "      texture2D(s_texture, pos + step),\n" | 
|  | 647             "      texture2D(s_texture, pos + step * 2.0));\n" | 
|  | 648             "}\n"); | 
|  | 649         fragment_program.append( | 
|  | 650             "  vec2 pixel_pos = v_texcoord * src_pixelsize - \n" | 
|  | 651             "      scaling_vector / 2.0;\n" | 
|  | 652             "  float frac = fract(dot(pixel_pos, scaling_vector));\n" | 
|  | 653             "  vec2 base = (floor(pixel_pos) + vec2(0.5)) / src_pixelsize;\n" | 
|  | 654             "  vec2 step = scaling_vector / src_pixelsize;\n" | 
|  | 655             "  gl_FragColor = pixels_x(base, step) * filt4(frac);\n"); | 
|  | 656         break; | 
|  | 657 | 
|  | 658       case SHADER_PLANAR: | 
|  | 659         // Converts four RGBA pixels into one pixel. Each RGBA | 
|  | 660         // pixel will be dot-multiplied with the color weights and | 
|  | 661         // then placed into a component of the output. This is used to | 
|  | 662         // convert RGBA textures into Y, U and V textures. We do this | 
|  | 663         // because single-component textures are not renderable on all | 
|  | 664         // architectures. | 
|  | 665         shared_variables.append("varying vec4 v_texcoords[2];\n"); | 
|  | 666         vertex_header.append( | 
|  | 667             "uniform vec2 scaling_vector;\n" | 
|  | 668             "uniform vec2 dst_pixelsize;\n"); | 
|  | 669         vertex_program.append( | 
|  | 670             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" | 
|  | 671             "  step /= 4.0;\n" | 
|  | 672             "  v_texcoords[0].xy = texcoord - step * 1.5;\n" | 
|  | 673             "  v_texcoords[0].zw = texcoord - step * 0.5;\n" | 
|  | 674             "  v_texcoords[1].xy = texcoord + step * 0.5;\n" | 
|  | 675             "  v_texcoords[1].zw = texcoord + step * 1.5;\n"); | 
|  | 676         fragment_header.append("uniform vec4 color_weights;\n"); | 
|  | 677         fragment_program.append( | 
|  | 678             "  gl_FragColor = color_weights * mat4(\n" | 
|  | 679             "    vec4(texture2D(s_texture, v_texcoords[0].xy).rgb, 1.0),\n" | 
|  | 680             "    vec4(texture2D(s_texture, v_texcoords[0].zw).rgb, 1.0),\n" | 
|  | 681             "    vec4(texture2D(s_texture, v_texcoords[1].xy).rgb, 1.0),\n" | 
|  | 682             "    vec4(texture2D(s_texture, v_texcoords[1].zw).rgb, 1.0));\n"); | 
|  | 683         break; | 
|  | 684 | 
|  | 685       case SHADER_YUV_MRT_PASS1: | 
|  | 686         // RGB24 to YV12 in two passes; writing two 8888 targets each pass. | 
|  | 687         // | 
|  | 688         // YV12 is full-resolution luma and half-resolution blue/red chroma. | 
|  | 689         // | 
|  | 690         //                  (original) | 
|  | 691         //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX | 
|  | 692         //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX | 
|  | 693         //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX | 
|  | 694         //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX | 
|  | 695         //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX | 
|  | 696         //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX | 
|  | 697         //      | | 
|  | 698         //      |      (y plane)    (temporary) | 
|  | 699         //      |      YYYY YYYY     UUVV UUVV | 
|  | 700         //      +--> { YYYY YYYY  +  UUVV UUVV } | 
|  | 701         //             YYYY YYYY     UUVV UUVV | 
|  | 702         //   First     YYYY YYYY     UUVV UUVV | 
|  | 703         //    pass     YYYY YYYY     UUVV UUVV | 
|  | 704         //             YYYY YYYY     UUVV UUVV | 
|  | 705         //                              | | 
|  | 706         //                              |  (u plane) (v plane) | 
|  | 707         //   Second                     |      UUUU   VVVV | 
|  | 708         //     pass                     +--> { UUUU + VVVV } | 
|  | 709         //                                     UUUU   VVVV | 
|  | 710         // | 
|  | 711         shared_variables.append("varying vec4 v_texcoords[2];\n"); | 
|  | 712         vertex_header.append( | 
|  | 713             "uniform vec2 scaling_vector;\n" | 
|  | 714             "uniform vec2 dst_pixelsize;\n"); | 
|  | 715         vertex_program.append( | 
|  | 716             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" | 
|  | 717             "  step /= 4.0;\n" | 
|  | 718             "  v_texcoords[0].xy = texcoord - step * 1.5;\n" | 
|  | 719             "  v_texcoords[0].zw = texcoord - step * 0.5;\n" | 
|  | 720             "  v_texcoords[1].xy = texcoord + step * 0.5;\n" | 
|  | 721             "  v_texcoords[1].zw = texcoord + step * 1.5;\n"); | 
|  | 722         fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n"); | 
|  | 723         fragment_header.append( | 
|  | 724             "const vec3 kRGBtoY = vec3(0.257, 0.504, 0.098);\n" | 
|  | 725             "const float kYBias = 0.0625;\n" | 
|  | 726             // Divide U and V by two to compensate for averaging below. | 
|  | 727             "const vec3 kRGBtoU = vec3(-0.148, -0.291, 0.439) / 2.0;\n" | 
|  | 728             "const vec3 kRGBtoV = vec3(0.439, -0.368, -0.071) / 2.0;\n" | 
|  | 729             "const float kUVBias = 0.5;\n"); | 
|  | 730         fragment_program.append( | 
|  | 731             "  vec3 pixel1 = texture2D(s_texture, v_texcoords[0].xy).rgb;\n" | 
|  | 732             "  vec3 pixel2 = texture2D(s_texture, v_texcoords[0].zw).rgb;\n" | 
|  | 733             "  vec3 pixel3 = texture2D(s_texture, v_texcoords[1].xy).rgb;\n" | 
|  | 734             "  vec3 pixel4 = texture2D(s_texture, v_texcoords[1].zw).rgb;\n" | 
|  | 735             "  vec3 pixel12 = pixel1 + pixel2;\n" | 
|  | 736             "  vec3 pixel34 = pixel3 + pixel4;\n" | 
|  | 737             "  gl_FragData[0] = vec4(dot(pixel1, kRGBtoY),\n" | 
|  | 738             "                        dot(pixel2, kRGBtoY),\n" | 
|  | 739             "                        dot(pixel3, kRGBtoY),\n" | 
|  | 740             "                        dot(pixel4, kRGBtoY)) + kYBias;\n" | 
|  | 741             "  gl_FragData[1] = vec4(dot(pixel12, kRGBtoU),\n" | 
|  | 742             "                        dot(pixel34, kRGBtoU),\n" | 
|  | 743             "                        dot(pixel12, kRGBtoV),\n" | 
|  | 744             "                        dot(pixel34, kRGBtoV)) + kUVBias;\n"); | 
|  | 745         break; | 
|  | 746 | 
|  | 747       case SHADER_YUV_MRT_PASS2: | 
|  | 748         // We're just sampling two pixels and unswizzling them.  There's | 
|  | 749         // no need to do vertical scaling with math, since bilinear | 
|  | 750         // interpolation in the sampler takes care of that. | 
|  | 751         shared_variables.append("varying vec4 v_texcoords;\n"); | 
|  | 752         vertex_header.append( | 
|  | 753             "uniform vec2 scaling_vector;\n" | 
|  | 754             "uniform vec2 dst_pixelsize;\n"); | 
|  | 755         vertex_program.append( | 
|  | 756             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" | 
|  | 757             "  step /= 2.0;\n" | 
|  | 758             "  v_texcoords.xy = texcoord - step * 0.5;\n" | 
|  | 759             "  v_texcoords.zw = texcoord + step * 0.5;\n"); | 
|  | 760         fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n"); | 
|  | 761         fragment_program.append( | 
|  | 762             "  vec4 lo_uuvv = texture2D(s_texture, v_texcoords.xy);\n" | 
|  | 763             "  vec4 hi_uuvv = texture2D(s_texture, v_texcoords.zw);\n" | 
|  | 764             "  gl_FragData[0] = vec4(lo_uuvv.rg, hi_uuvv.rg);\n" | 
|  | 765             "  gl_FragData[1] = vec4(lo_uuvv.ba, hi_uuvv.ba);\n"); | 
|  | 766         break; | 
|  | 767     } | 
|  | 768     if (swizzle) { | 
|  | 769       switch (type) { | 
|  | 770         case SHADER_YUV_MRT_PASS1: | 
|  | 771           fragment_program.append("  gl_FragData[0] = gl_FragData[0].bgra;\n"); | 
|  | 772           break; | 
|  | 773         case SHADER_YUV_MRT_PASS2: | 
|  | 774           fragment_program.append("  gl_FragData[0] = gl_FragData[0].bgra;\n"); | 
|  | 775           fragment_program.append("  gl_FragData[1] = gl_FragData[1].bgra;\n"); | 
|  | 776           break; | 
|  | 777         default: | 
|  | 778           fragment_program.append("  gl_FragColor = gl_FragColor.bgra;\n"); | 
|  | 779           break; | 
|  | 780       } | 
|  | 781     } | 
|  | 782 | 
|  | 783     vertex_program = vertex_header + shared_variables + "void main() {\n" + | 
|  | 784                      vertex_program + "}\n"; | 
|  | 785 | 
|  | 786     fragment_program = fragment_directives + fragment_header + | 
|  | 787                        shared_variables + "void main() {\n" + fragment_program + | 
|  | 788                        "}\n"; | 
|  | 789 | 
|  | 790     cache_entry->Setup(vertex_program.c_str(), fragment_program.c_str()); | 
|  | 791   } | 
|  | 792   return cache_entry; | 
|  | 793 } | 
|  | 794 | 
|  | 795 void ShaderProgram::Setup(const GLchar* vertex_shader_text, | 
|  | 796                           const GLchar* fragment_shader_text) { | 
|  | 797   // Shaders to map the source texture to |dst_texture_|. | 
|  | 798   GLuint vertex_shader = | 
|  | 799       helper_->CompileShaderFromSource(vertex_shader_text, GL_VERTEX_SHADER); | 
|  | 800   if (vertex_shader == 0) | 
|  | 801     return; | 
|  | 802 | 
|  | 803   gl_->AttachShader(program_, vertex_shader); | 
|  | 804   gl_->DeleteShader(vertex_shader); | 
|  | 805 | 
|  | 806   GLuint fragment_shader = helper_->CompileShaderFromSource( | 
|  | 807       fragment_shader_text, GL_FRAGMENT_SHADER); | 
|  | 808   if (fragment_shader == 0) | 
|  | 809     return; | 
|  | 810   gl_->AttachShader(program_, fragment_shader); | 
|  | 811   gl_->DeleteShader(fragment_shader); | 
|  | 812 | 
|  | 813   gl_->LinkProgram(program_); | 
|  | 814 | 
|  | 815   GLint link_status = 0; | 
|  | 816   gl_->GetProgramiv(program_, GL_LINK_STATUS, &link_status); | 
|  | 817   if (!link_status) | 
|  | 818     return; | 
|  | 819 | 
|  | 820   position_location_ = gl_->GetAttribLocation(program_, "a_position"); | 
|  | 821   texcoord_location_ = gl_->GetAttribLocation(program_, "a_texcoord"); | 
|  | 822   texture_location_ = gl_->GetUniformLocation(program_, "s_texture"); | 
|  | 823   src_subrect_location_ = gl_->GetUniformLocation(program_, "src_subrect"); | 
|  | 824   src_pixelsize_location_ = gl_->GetUniformLocation(program_, "src_pixelsize"); | 
|  | 825   dst_pixelsize_location_ = gl_->GetUniformLocation(program_, "dst_pixelsize"); | 
|  | 826   scaling_vector_location_ = | 
|  | 827       gl_->GetUniformLocation(program_, "scaling_vector"); | 
|  | 828   color_weights_location_ = gl_->GetUniformLocation(program_, "color_weights"); | 
|  | 829   // The only reason fetching these attribute locations should fail is | 
|  | 830   // if the context was spontaneously lost (i.e., because the GPU | 
|  | 831   // process crashed, perhaps deliberately for testing). | 
|  | 832   DCHECK(Initialized() || gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR); | 
|  | 833 } | 
|  | 834 | 
|  | 835 void ShaderProgram::UseProgram(const gfx::Size& src_size, | 
|  | 836                                const gfx::Rect& src_subrect, | 
|  | 837                                const gfx::Size& dst_size, | 
|  | 838                                bool scale_x, | 
|  | 839                                bool flip_y, | 
|  | 840                                GLfloat color_weights[4]) { | 
|  | 841   gl_->UseProgram(program_); | 
|  | 842 | 
|  | 843   // OpenGL defines the last parameter to VertexAttribPointer as type | 
|  | 844   // "const GLvoid*" even though it is actually an offset into the buffer | 
|  | 845   // object's data store and not a pointer to the client's address space. | 
|  | 846   const void* offsets[2] = {0, | 
|  | 847                             reinterpret_cast<const void*>(2 * sizeof(GLfloat))}; | 
|  | 848 | 
|  | 849   gl_->VertexAttribPointer(position_location_, 2, GL_FLOAT, GL_FALSE, | 
|  | 850                            4 * sizeof(GLfloat), offsets[0]); | 
|  | 851   gl_->EnableVertexAttribArray(position_location_); | 
|  | 852 | 
|  | 853   gl_->VertexAttribPointer(texcoord_location_, 2, GL_FLOAT, GL_FALSE, | 
|  | 854                            4 * sizeof(GLfloat), offsets[1]); | 
|  | 855   gl_->EnableVertexAttribArray(texcoord_location_); | 
|  | 856 | 
|  | 857   gl_->Uniform1i(texture_location_, 0); | 
|  | 858 | 
|  | 859   // Convert |src_subrect| to texture coordinates. | 
|  | 860   GLfloat src_subrect_texcoord[] = { | 
|  | 861       static_cast<float>(src_subrect.x()) / src_size.width(), | 
|  | 862       static_cast<float>(src_subrect.y()) / src_size.height(), | 
|  | 863       static_cast<float>(src_subrect.width()) / src_size.width(), | 
|  | 864       static_cast<float>(src_subrect.height()) / src_size.height(), | 
|  | 865   }; | 
|  | 866   if (flip_y) { | 
|  | 867     src_subrect_texcoord[1] += src_subrect_texcoord[3]; | 
|  | 868     src_subrect_texcoord[3] *= -1.0; | 
|  | 869   } | 
|  | 870   gl_->Uniform4fv(src_subrect_location_, 1, src_subrect_texcoord); | 
|  | 871 | 
|  | 872   gl_->Uniform2f(src_pixelsize_location_, src_size.width(), src_size.height()); | 
|  | 873   gl_->Uniform2f(dst_pixelsize_location_, static_cast<float>(dst_size.width()), | 
|  | 874                  static_cast<float>(dst_size.height())); | 
|  | 875 | 
|  | 876   gl_->Uniform2f(scaling_vector_location_, scale_x ? 1.0 : 0.0, | 
|  | 877                  scale_x ? 0.0 : 1.0); | 
|  | 878   gl_->Uniform4fv(color_weights_location_, 1, color_weights); | 
|  | 879 } | 
|  | 880 | 
|  | 881 }  // namespace content | 
| OLD | NEW | 
|---|