190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/common/gpu/client/gl_helper_scaling.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <deque>
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <string>
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <vector>
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/bind.h"
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/debug/trace_event.h"
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/lazy_instance.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/logging.h"
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/memory/ref_counted.h"
169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "gpu/command_buffer/client/gles2_interface.h"
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "third_party/skia/include/core/SkRegion.h"
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/rect.h"
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/size.h"
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using gpu::gles2::GLES2Interface;
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace content {
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GLHelperScaling::GLHelperScaling(GLES2Interface* gl, GLHelper* helper)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : gl_(gl), helper_(helper), vertex_attributes_buffer_(gl_) {
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  InitBuffer();
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GLHelperScaling::~GLHelperScaling() {}
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Used to keep track of a generated shader program. The program
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// is passed in as text through Setup and is used by calling
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// UseProgram() with the right parameters. Note that |gl_|
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// and |helper_| are assumed to live longer than this program.
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class ShaderProgram : public base::RefCounted<ShaderProgram> {
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShaderProgram(GLES2Interface* gl, GLHelper* helper)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : gl_(gl),
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        helper_(helper),
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        program_(gl_->CreateProgram()),
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        position_location_(-1),
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        texcoord_location_(-1),
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        src_subrect_location_(-1),
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        src_pixelsize_location_(-1),
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dst_pixelsize_location_(-1),
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        scaling_vector_location_(-1),
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        color_weights_location_(-1) {}
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Compile shader program.
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Setup(const GLchar* vertex_shader_text,
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             const GLchar* fragment_shader_text);
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // UseProgram must be called with GL_TEXTURE_2D bound to the
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // source texture and GL_ARRAY_BUFFER bound to a vertex
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // attribute buffer.
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void UseProgram(const gfx::Size& src_size,
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  const gfx::Rect& src_subrect,
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  const gfx::Size& dst_size,
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  bool scale_x,
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  bool flip_y,
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  GLfloat color_weights[4]);
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool Initialized() const { return position_location_ != -1; }
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  friend class base::RefCounted<ShaderProgram>;
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~ShaderProgram() { gl_->DeleteProgram(program_); }
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLES2Interface* gl_;
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GLHelper* helper_;
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // A program for copying a source texture into a destination texture.
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLuint program_;
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The location of the position in the program.
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLint position_location_;
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The location of the texture coordinate in the program.
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLint texcoord_location_;
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The location of the source texture in the program.
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLint texture_location_;
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The location of the texture coordinate of
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // the sub-rectangle in the program.
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLint src_subrect_location_;
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Location of size of source image in pixels.
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLint src_pixelsize_location_;
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Location of size of destination image in pixels.
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLint dst_pixelsize_location_;
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Location of vector for scaling direction.
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLint scaling_vector_location_;
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Location of color weights.
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLint color_weights_location_;
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShaderProgram);
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Implementation of a single stage in a scaler pipeline. If the pipeline has
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// multiple stages, it calls Scale() on the subscaler, then further scales the
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// output. Caches textures and framebuffers to avoid allocating/deleting
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// them once per frame, which can be expensive on some drivers.
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ScalerImpl : public GLHelper::ScalerInterface,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   public GLHelperScaling::ShaderInterface {
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |gl| and |copy_impl| are expected to live longer than this object.
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // |src_size| is the size of the input texture in pixels.
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // |dst_size| is the size of the output texutre in pixels.
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // |src_subrect| is the portion of the src to copy to the output texture.
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // If |scale_x| is true, we are scaling along the X axis, otherwise Y.
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // If we are scaling in both X and Y, |scale_x| is ignored.
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // If |vertically_flip_texture| is true, output will be upside-down.
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // If |swizzle| is true, RGBA will be transformed into BGRA.
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // |color_weights| are only used together with SHADER_PLANAR to specify
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  //   how to convert RGB colors into a single value.
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScalerImpl(GLES2Interface* gl,
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)             GLHelperScaling* scaler_helper,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             const GLHelperScaling::ScalerStage& scaler_stage,
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)             ScalerImpl* subscaler,
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             const float* color_weights)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : gl_(gl),
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        scaler_helper_(scaler_helper),
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        spec_(scaler_stage),
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        intermediate_texture_(0),
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dst_framebuffer_(gl),
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        subscaler_(subscaler) {
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (color_weights) {
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      color_weights_[0] = color_weights[0];
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      color_weights_[1] = color_weights[1];
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      color_weights_[2] = color_weights[2];
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      color_weights_[3] = color_weights[3];
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    } else {
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      color_weights_[0] = 0.0;
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      color_weights_[1] = 0.0;
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      color_weights_[2] = 0.0;
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      color_weights_[3] = 0.0;
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    shader_program_ =
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        scaler_helper_->GetShaderProgram(spec_.shader, spec_.swizzle);
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (subscaler_) {
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      intermediate_texture_ = 0u;
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gl_->GenTextures(1, &intermediate_texture_);
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_,
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                        intermediate_texture_);
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gl_->TexImage2D(GL_TEXTURE_2D,
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      0,
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      GL_RGBA,
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      spec_.src_size.width(),
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      spec_.src_size.height(),
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      0,
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      GL_RGBA,
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      GL_UNSIGNED_BYTE,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      NULL);
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~ScalerImpl() {
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (intermediate_texture_) {
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gl_->DeleteTextures(1, &intermediate_texture_);
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // GLHelperShader::ShaderInterface implementation.
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void Execute(GLuint source_texture,
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       const std::vector<GLuint>& dest_textures) OVERRIDE {
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (subscaler_) {
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      subscaler_->Scale(source_texture, intermediate_texture_);
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      source_texture = intermediate_texture_;
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        gl_, dst_framebuffer_);
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_GT(dest_textures.size(), 0U);
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<GLenum[]> buffers(new GLenum[dest_textures.size()]);
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (size_t t = 0; t < dest_textures.size(); t++) {
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dest_textures[t]);
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                GL_COLOR_ATTACHMENT0 + t,
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                GL_TEXTURE_2D,
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                dest_textures[t],
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                0);
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      buffers[t] = GL_COLOR_ATTACHMENT0 + t;
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, source_texture);
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        gl_, scaler_helper_->vertex_attributes_buffer_);
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(shader_program_->Initialized());
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    shader_program_->UseProgram(spec_.src_size,
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                spec_.src_subrect,
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                spec_.dst_size,
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                spec_.scale_x,
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                spec_.vertically_flip_texture,
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                color_weights_);
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gl_->Viewport(0, 0, spec_.dst_size.width(), spec_.dst_size.height());
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (dest_textures.size() > 1) {
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      DCHECK_LE(static_cast<int>(dest_textures.size()),
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                scaler_helper_->helper_->MaxDrawBuffers());
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gl_->DrawBuffersEXT(dest_textures.size(), buffers.get());
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Conduct texture mapping by drawing a quad composed of two triangles.
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (dest_textures.size() > 1) {
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // Set the draw buffers back to not confuse others.
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gl_->DrawBuffersEXT(1, &buffers[0]);
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // GLHelper::ScalerInterface implementation.
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void Scale(GLuint source_texture, GLuint dest_texture) OVERRIDE {
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<GLuint> tmp(1);
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    tmp[0] = dest_texture;
220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Execute(source_texture, tmp);
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual const gfx::Size& SrcSize() OVERRIDE {
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (subscaler_) {
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return subscaler_->SrcSize();
22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return spec_.src_size;
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual const gfx::Rect& SrcSubrect() OVERRIDE {
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (subscaler_) {
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return subscaler_->SrcSubrect();
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return spec_.src_subrect;
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual const gfx::Size& DstSize() OVERRIDE { return spec_.dst_size; }
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLES2Interface* gl_;
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GLHelperScaling* scaler_helper_;
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GLHelperScaling::ScalerStage spec_;
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  GLfloat color_weights_[4];
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLuint intermediate_texture_;
24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_refptr<ShaderProgram> shader_program_;
24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ScopedFramebuffer dst_framebuffer_;
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<ScalerImpl> subscaler_;
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GLHelperScaling::ScalerStage::ScalerStage(ShaderType shader_,
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          gfx::Size src_size_,
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          gfx::Rect src_subrect_,
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          gfx::Size dst_size_,
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          bool scale_x_,
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          bool vertically_flip_texture_,
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          bool swizzle_)
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : shader(shader_),
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      src_size(src_size_),
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      src_subrect(src_subrect_),
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      dst_size(dst_size_),
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      scale_x(scale_x_),
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      vertically_flip_texture(vertically_flip_texture_),
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      swizzle(swizzle_) {}
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// The important inputs for this function is |x_ops| and
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// |y_ops|. They represent scaling operations to be done
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// on an imag of size |src_size|. If |quality| is SCALER_QUALITY_BEST,
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// then we will interpret these scale operations literally and we'll
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// create one scaler stage for each ScaleOp.  However, if |quality|
26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// is SCALER_QUALITY_GOOD, then we can do a whole bunch of optimizations
26990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// by combining two or more ScaleOps in to a single scaler stage.
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Normally we process ScaleOps from |y_ops| first and |x_ops| after
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// all |y_ops| are processed, but sometimes we can combine one or more
27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// operation from both queues essentially for free. This is the reason
27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// why |x_ops| and |y_ops| aren't just one single queue.
27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GLHelperScaling::ConvertScalerOpsToScalerStages(
27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    GLHelper::ScalerQuality quality,
27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    gfx::Size src_size,
27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    gfx::Rect src_subrect,
27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const gfx::Size& dst_size,
27990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool vertically_flip_texture,
28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool swizzle,
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::deque<GLHelperScaling::ScaleOp>* x_ops,
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::deque<GLHelperScaling::ScaleOp>* y_ops,
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<ScalerStage>* scaler_stages) {
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  while (!x_ops->empty() || !y_ops->empty()) {
28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    gfx::Size intermediate_size = src_subrect.size();
28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::deque<ScaleOp>* current_queue = NULL;
28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!y_ops->empty()) {
28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      current_queue = y_ops;
29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else {
29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      current_queue = x_ops;
29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ShaderType current_shader = SHADER_BILINEAR;
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    switch (current_queue->front().scale_factor) {
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case 0:
29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (quality == GLHelper::SCALER_QUALITY_BEST) {
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          current_shader = SHADER_BICUBIC_UPSCALE;
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case 2:
30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (quality == GLHelper::SCALER_QUALITY_BEST) {
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          current_shader = SHADER_BICUBIC_HALF_1D;
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
30590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case 3:
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        DCHECK(quality != GLHelper::SCALER_QUALITY_BEST);
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        current_shader = SHADER_BILINEAR3;
30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      default:
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        NOTREACHED();
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool scale_x = current_queue->front().scale_x;
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    current_queue->front().UpdateSize(&intermediate_size);
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    current_queue->pop_front();
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Optimization: Sometimes we can combine 2-4 scaling operations into
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // one operation.
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (quality == GLHelper::SCALER_QUALITY_GOOD) {
32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (!current_queue->empty() && current_shader == SHADER_BILINEAR) {
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Combine two steps in the same dimension.
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        current_queue->front().UpdateSize(&intermediate_size);
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        current_queue->pop_front();
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        current_shader = SHADER_BILINEAR2;
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!current_queue->empty()) {
32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          // Combine three steps in the same dimension.
32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          current_queue->front().UpdateSize(&intermediate_size);
32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          current_queue->pop_front();
32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          current_shader = SHADER_BILINEAR4;
33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Check if we can combine some steps in the other dimension as well.
33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Since all shaders currently use GL_LINEAR, we can easily scale up
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // or scale down by exactly 2x at the same time as we do another
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // operation. Currently, the following mergers are supported:
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // * 1 bilinear Y-pass with 1 bilinear X-pass (up or down)
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // * 2 bilinear Y-passes with 2 bilinear X-passes
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // * 1 bilinear Y-pass with N bilinear X-pass
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // * N bilinear Y-passes with 1 bilinear X-pass (down only)
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Measurements indicate that generalizing this for 3x3 and 4x4
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // makes it slower on some platforms, such as the Pixel.
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!scale_x && x_ops->size() > 0 && x_ops->front().scale_factor <= 2) {
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        int x_passes = 0;
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (current_shader == SHADER_BILINEAR2 && x_ops->size() >= 2) {
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          // 2y + 2x passes
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          x_passes = 2;
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          current_shader = SHADER_BILINEAR2X2;
34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        } else if (current_shader == SHADER_BILINEAR) {
34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          // 1y + Nx passes
35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          scale_x = true;
35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          switch (x_ops->size()) {
35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            case 0:
35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              NOTREACHED();
35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            case 1:
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              if (x_ops->front().scale_factor == 3) {
35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                current_shader = SHADER_BILINEAR3;
35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              }
35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              x_passes = 1;
35990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              break;
36090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            case 2:
36190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              x_passes = 2;
36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              current_shader = SHADER_BILINEAR2;
36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              break;
36490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            default:
36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              x_passes = 3;
36690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              current_shader = SHADER_BILINEAR4;
36790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              break;
36890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          }
36990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        } else if (x_ops->front().scale_factor == 2) {
37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          // Ny + 1x-downscale
37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          x_passes = 1;
37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        for (int i = 0; i < x_passes; i++) {
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          x_ops->front().UpdateSize(&intermediate_size);
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          x_ops->pop_front();
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
38090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
38190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scaler_stages->push_back(ScalerStage(current_shader,
38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         src_size,
38390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         src_subrect,
38490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         intermediate_size,
38590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         scale_x,
38690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         vertically_flip_texture,
38790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         swizzle));
38890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    src_size = intermediate_size;
38990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    src_subrect = gfx::Rect(intermediate_size);
39090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    vertically_flip_texture = false;
39190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    swizzle = false;
39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
39490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
39590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GLHelperScaling::ComputeScalerStages(
39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    GLHelper::ScalerQuality quality,
39790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const gfx::Size& src_size,
39890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const gfx::Rect& src_subrect,
39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const gfx::Size& dst_size,
40090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool vertically_flip_texture,
40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool swizzle,
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<ScalerStage>* scaler_stages) {
40390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (quality == GLHelper::SCALER_QUALITY_FAST ||
40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      src_subrect.size() == dst_size) {
40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scaler_stages->push_back(ScalerStage(SHADER_BILINEAR,
40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         src_size,
40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         src_subrect,
40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         dst_size,
40990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         false,
41090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         vertically_flip_texture,
41190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         swizzle));
41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
41390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
41490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
41590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::deque<GLHelperScaling::ScaleOp> x_ops, y_ops;
41690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GLHelperScaling::ScaleOp::AddOps(src_subrect.width(),
41790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   dst_size.width(),
41890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   true,
41990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   quality == GLHelper::SCALER_QUALITY_GOOD,
42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   &x_ops);
42190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GLHelperScaling::ScaleOp::AddOps(src_subrect.height(),
42290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   dst_size.height(),
42390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   false,
42490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   quality == GLHelper::SCALER_QUALITY_GOOD,
42590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   &y_ops);
42690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ConvertScalerOpsToScalerStages(quality,
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 src_size,
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 src_subrect,
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 dst_size,
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 vertically_flip_texture,
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 swizzle,
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 &x_ops,
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 &y_ops,
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 scaler_stages);
43690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
43790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GLHelper::ScalerInterface* GLHelperScaling::CreateScaler(
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GLHelper::ScalerQuality quality,
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::Size src_size,
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::Rect src_subrect,
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const gfx::Size& dst_size,
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool vertically_flip_texture,
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool swizzle) {
44590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<ScalerStage> scaler_stages;
44690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ComputeScalerStages(quality,
44790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      src_size,
44890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      src_subrect,
44990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      dst_size,
45090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      vertically_flip_texture,
45190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      swizzle,
45290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      &scaler_stages);
45390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
45490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ScalerImpl* ret = NULL;
45590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (unsigned int i = 0; i < scaler_stages.size(); i++) {
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ret = new ScalerImpl(gl_, this, scaler_stages[i], ret, NULL);
45790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
45890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return ret;
45990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
46090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GLHelper::ScalerInterface* GLHelperScaling::CreatePlanarScaler(
462868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& src_size,
463868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Rect& src_subrect,
464868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& dst_size,
465868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    bool vertically_flip_texture,
466effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bool swizzle,
467868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const float color_weights[4]) {
468868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ScalerStage stage(SHADER_PLANAR,
469868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    src_size,
470868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    src_subrect,
471868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    dst_size,
472868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    true,
473868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    vertically_flip_texture,
474effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    swizzle);
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return new ScalerImpl(gl_, this, stage, NULL, color_weights);
476868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
477868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GLHelperScaling::ShaderInterface* GLHelperScaling::CreateYuvMrtShader(
479868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& src_size,
480868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Rect& src_subrect,
481868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Size& dst_size,
482868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    bool vertically_flip_texture,
483effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bool swizzle,
484868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ShaderType shader) {
485868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(shader == SHADER_YUV_MRT_PASS1 || shader == SHADER_YUV_MRT_PASS2);
486868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ScalerStage stage(shader,
487868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    src_size,
488868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    src_subrect,
489868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    dst_size,
490868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    true,
491868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    vertically_flip_texture,
492effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    swizzle);
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return new ScalerImpl(gl_, this, stage, NULL, NULL);
494868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
495868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const GLfloat GLHelperScaling::kVertexAttributes[] = {
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    -1.0f, -1.0f, 0.0f, 0.0f,     // vertex 0
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    1.0f,  -1.0f, 1.0f, 0.0f,     // vertex 1
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    -1.0f, 1.0f,  0.0f, 1.0f,     // vertex 2
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    1.0f,  1.0f,  1.0f, 1.0f, };  // vertex 3
50190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GLHelperScaling::InitBuffer() {
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(gl_,
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                    vertex_attributes_buffer_);
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->BufferData(GL_ARRAY_BUFFER,
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  sizeof(kVertexAttributes),
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  kVertexAttributes,
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  GL_STATIC_DRAW);
50990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
51090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_refptr<ShaderProgram> GLHelperScaling::GetShaderProgram(ShaderType type,
5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                               bool swizzle) {
51390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ShaderProgramKeyType key(type, swizzle);
51490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_refptr<ShaderProgram>& cache_entry(shader_programs_[key]);
515868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!cache_entry.get()) {
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    cache_entry = new ShaderProgram(gl_, helper_);
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::basic_string<GLchar> vertex_program;
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::basic_string<GLchar> fragment_program;
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::basic_string<GLchar> vertex_header;
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::basic_string<GLchar> fragment_directives;
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::basic_string<GLchar> fragment_header;
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::basic_string<GLchar> shared_variables;
52390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    vertex_header.append(
52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        "precision highp float;\n"
52690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        "attribute vec2 a_position;\n"
5273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        "attribute vec2 a_texcoord;\n"
5283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        "uniform vec4 src_subrect;\n");
52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    fragment_header.append(
53190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        "precision mediump float;\n"
53290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        "uniform sampler2D s_texture;\n");
53390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
53490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    vertex_program.append(
53590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        "  gl_Position = vec4(a_position, 0.0, 1.0);\n"
5367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        "  vec2 texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;\n");
53790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
53890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    switch (type) {
53990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SHADER_BILINEAR:
54090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        shared_variables.append("varying vec2 v_texcoord;\n");
54190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        vertex_program.append("  v_texcoord = texcoord;\n");
54290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        fragment_program.append(
54390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  gl_FragColor = texture2D(s_texture, v_texcoord);\n");
54490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
54690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SHADER_BILINEAR2:
54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // This is equivialent to two passes of the BILINEAR shader above.
54890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // It can be used to scale an image down 1.0x-2.0x in either dimension,
54990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // or exactly 4x.
55090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        shared_variables.append(
55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "varying vec4 v_texcoords;\n");  // 2 texcoords packed in one quad
5523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        vertex_header.append(
5533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 scaling_vector;\n"
5543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 dst_pixelsize;\n");
55590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        vertex_program.append(
5567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
557868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  step /= 4.0;\n"
55890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords.xy = texcoord + step;\n"
55990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords.zw = texcoord - step;\n");
56090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        fragment_program.append(
56290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  gl_FragColor = (texture2D(s_texture, v_texcoords.xy) +\n"
56390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "                  texture2D(s_texture, v_texcoords.zw)) / 2.0;\n");
5643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        break;
56590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SHADER_BILINEAR3:
56790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // This is kind of like doing 1.5 passes of the BILINEAR shader.
56890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // It can be used to scale an image down 1.5x-3.0x, or exactly 6x.
56990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        shared_variables.append(
57090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "varying vec4 v_texcoords1;\n"  // 2 texcoords packed in one quad
57190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "varying vec2 v_texcoords2;\n");
5723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        vertex_header.append(
5733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 scaling_vector;\n"
5743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 dst_pixelsize;\n");
57590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        vertex_program.append(
5767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
577868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  step /= 3.0;\n"
57890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords1.xy = texcoord + step;\n"
57990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords1.zw = texcoord;\n"
58090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords2 = texcoord - step;\n");
58190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        fragment_program.append(
58290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  gl_FragColor = (texture2D(s_texture, v_texcoords1.xy) +\n"
58390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "                  texture2D(s_texture, v_texcoords1.zw) +\n"
58490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "                  texture2D(s_texture, v_texcoords2)) / 3.0;\n");
5853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        break;
58690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
58790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SHADER_BILINEAR4:
58890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // This is equivialent to three passes of the BILINEAR shader above,
58990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // It can be used to scale an image down 2.0x-4.0x or exactly 8x.
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shared_variables.append("varying vec4 v_texcoords[2];\n");
5913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        vertex_header.append(
5923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 scaling_vector;\n"
5933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 dst_pixelsize;\n");
59490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        vertex_program.append(
5957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
596868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  step /= 8.0;\n"
59790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[0].xy = texcoord - step * 3.0;\n"
59890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[0].zw = texcoord - step;\n"
59990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[1].xy = texcoord + step;\n"
60090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[1].zw = texcoord + step * 3.0;\n");
60190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        fragment_program.append(
60290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  gl_FragColor = (\n"
60390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, v_texcoords[0].xy) +\n"
60490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, v_texcoords[0].zw) +\n"
60590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, v_texcoords[1].xy) +\n"
60690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
6073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        break;
60890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
60990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SHADER_BILINEAR2X2:
61090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // This is equivialent to four passes of the BILINEAR shader above.
61190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Two in each dimension. It can be used to scale an image down
61290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // 1.0x-2.0x in both X and Y directions. Or, it could be used to
61390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // scale an image down by exactly 4x in both dimensions.
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shared_variables.append("varying vec4 v_texcoords[2];\n");
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        vertex_header.append("uniform vec2 dst_pixelsize;\n");
61690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        vertex_program.append(
6177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "  vec2 step = src_subrect.zw / 4.0 / dst_pixelsize;\n"
61890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[0].xy = texcoord + vec2(step.x, step.y);\n"
61990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[0].zw = texcoord + vec2(step.x, -step.y);\n"
62090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[1].xy = texcoord + vec2(-step.x, step.y);\n"
62190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[1].zw = texcoord + vec2(-step.x, -step.y);\n");
62290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        fragment_program.append(
62390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  gl_FragColor = (\n"
62490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, v_texcoords[0].xy) +\n"
62590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, v_texcoords[0].zw) +\n"
62690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, v_texcoords[1].xy) +\n"
62790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
6283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        break;
62990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
63090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SHADER_BICUBIC_HALF_1D:
63190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // This scales down texture by exactly half in one dimension.
63290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // directions in one pass. We use bilinear lookup to reduce
63390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // the number of texture reads from 8 to 4
63490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        shared_variables.append(
63590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "const float CenterDist = 99.0 / 140.0;\n"
63690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "const float LobeDist = 11.0 / 4.0;\n"
63790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "const float CenterWeight = 35.0 / 64.0;\n"
63890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "const float LobeWeight = -3.0 / 64.0;\n"
63990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "varying vec4 v_texcoords[2];\n");
6403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        vertex_header.append(
6413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 scaling_vector;\n"
6423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 src_pixelsize;\n");
64390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        vertex_program.append(
6447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "  vec2 step = src_subrect.zw * scaling_vector / src_pixelsize;\n"
64590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[0].xy = texcoord - LobeDist * step;\n"
64690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[0].zw = texcoord - CenterDist * step;\n"
64790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[1].xy = texcoord + CenterDist * step;\n"
64890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  v_texcoords[1].zw = texcoord + LobeDist * step;\n");
64990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        fragment_program.append(
65090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  gl_FragColor = \n"
65190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            // Lobe pixels
65290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      (texture2D(s_texture, v_texcoords[0].xy) +\n"
65390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "       texture2D(s_texture, v_texcoords[1].zw)) *\n"
65490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "          LobeWeight +\n"
65590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            // Center pixels
65690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      (texture2D(s_texture, v_texcoords[0].zw) +\n"
65790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "       texture2D(s_texture, v_texcoords[1].xy)) *\n"
65890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "          CenterWeight;\n");
6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
66090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
66190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case SHADER_BICUBIC_UPSCALE:
66290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // When scaling up, we need 4 texture reads, but we can
66390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // save some instructions because will know in which range of
66490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // the bicubic function each call call to the bicubic function
66590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // will be in.
66690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // Also, when sampling the bicubic function like this, the sum
66790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // is always exactly one, so we can skip normalization as well.
6685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shared_variables.append("varying vec2 v_texcoord;\n");
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        vertex_program.append("  v_texcoord = texcoord;\n");
67090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        fragment_header.append(
6713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 src_pixelsize;\n"
6723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 scaling_vector;\n"
67390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "const float a = -0.5;\n"
67490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            // This function is equivialent to calling the bicubic
67590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            // function with x-1, x, 1-x and 2-x
67690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            // (assuming 0 <= x < 1)
67790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "vec4 filt4(float x) {\n"
67890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  return vec4(x * x * x, x * x, x, 1) *\n"
67990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "         mat4(       a,      -2.0 * a,   a, 0.0,\n"
68090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "               a + 2.0,      -a - 3.0, 0.0, 1.0,\n"
68190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "              -a - 2.0, 3.0 + 2.0 * a,  -a, 0.0,\n"
68290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "                    -a,             a, 0.0, 0.0);\n"
68390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "}\n"
68490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "mat4 pixels_x(vec2 pos, vec2 step) {\n"
68590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  return mat4(\n"
68690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, pos - step),\n"
68790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, pos),\n"
68890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, pos + step),\n"
68990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      texture2D(s_texture, pos + step * 2.0));\n"
69090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "}\n");
69190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        fragment_program.append(
69290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  vec2 pixel_pos = v_texcoord * src_pixelsize - \n"
69390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "      scaling_vector / 2.0;\n"
69490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  float frac = fract(dot(pixel_pos, scaling_vector));\n"
69590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  vec2 base = (floor(pixel_pos) + vec2(0.5)) / src_pixelsize;\n"
69690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  vec2 step = scaling_vector / src_pixelsize;\n"
69790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            "  gl_FragColor = pixels_x(base, step) * filt4(frac);\n");
69890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
699868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
700868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case SHADER_PLANAR:
701868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // Converts four RGBA pixels into one pixel. Each RGBA
702868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // pixel will be dot-multiplied with the color weights and
703868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // then placed into a component of the output. This is used to
704868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // convert RGBA textures into Y, U and V textures. We do this
705868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // because single-component textures are not renderable on all
706868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // architectures.
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shared_variables.append("varying vec4 v_texcoords[2];\n");
7083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        vertex_header.append(
7093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 scaling_vector;\n"
7103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 dst_pixelsize;\n");
711868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        vertex_program.append(
7127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
713868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  step /= 4.0;\n"
714868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords[0].xy = texcoord - step * 1.5;\n"
715868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords[0].zw = texcoord - step * 0.5;\n"
716868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords[1].xy = texcoord + step * 0.5;\n"
717868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords[1].zw = texcoord + step * 1.5;\n");
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        fragment_header.append("uniform vec4 color_weights;\n");
719868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        fragment_program.append(
720868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  gl_FragColor = color_weights * mat4(\n"
721868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "    vec4(texture2D(s_texture, v_texcoords[0].xy).rgb, 1.0),\n"
722868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "    vec4(texture2D(s_texture, v_texcoords[0].zw).rgb, 1.0),\n"
723868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "    vec4(texture2D(s_texture, v_texcoords[1].xy).rgb, 1.0),\n"
724868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "    vec4(texture2D(s_texture, v_texcoords[1].zw).rgb, 1.0));\n");
725868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        break;
726868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
727868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case SHADER_YUV_MRT_PASS1:
728868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // RGB24 to YV12 in two passes; writing two 8888 targets each pass.
729868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //
730868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // YV12 is full-resolution luma and half-resolution blue/red chroma.
731868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //
732868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //                  (original)
733868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
734868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
735868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
736868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
737868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
738868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //    RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
739868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //      |
740868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //      |      (y plane)    (temporary)
741868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //      |      YYYY YYYY     UUVV UUVV
742868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //      +--> { YYYY YYYY  +  UUVV UUVV }
743868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //             YYYY YYYY     UUVV UUVV
744868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //   First     YYYY YYYY     UUVV UUVV
745868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //    pass     YYYY YYYY     UUVV UUVV
746868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //             YYYY YYYY     UUVV UUVV
747868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //                              |
748868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //                              |  (u plane) (v plane)
749868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //   Second                     |      UUUU   VVVV
750868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //     pass                     +--> { UUUU + VVVV }
751868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //                                     UUUU   VVVV
752868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        //
7535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shared_variables.append("varying vec4 v_texcoords[2];\n");
7543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        vertex_header.append(
7553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 scaling_vector;\n"
7563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 dst_pixelsize;\n");
757868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        vertex_program.append(
7587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
759868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  step /= 4.0;\n"
760868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords[0].xy = texcoord - step * 1.5;\n"
761868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords[0].zw = texcoord - step * 0.5;\n"
762868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords[1].xy = texcoord + step * 0.5;\n"
763868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords[1].zw = texcoord + step * 1.5;\n");
7645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n");
765868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        fragment_header.append(
766868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "const vec3 kRGBtoY = vec3(0.257, 0.504, 0.098);\n"
767868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "const float kYBias = 0.0625;\n"
768868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            // Divide U and V by two to compensate for averaging below.
769868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "const vec3 kRGBtoU = vec3(-0.148, -0.291, 0.439) / 2.0;\n"
770868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "const vec3 kRGBtoV = vec3(0.439, -0.368, -0.071) / 2.0;\n"
771868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "const float kUVBias = 0.5;\n");
772868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        fragment_program.append(
773868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  vec3 pixel1 = texture2D(s_texture, v_texcoords[0].xy).rgb;\n"
774868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  vec3 pixel2 = texture2D(s_texture, v_texcoords[0].zw).rgb;\n"
775868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  vec3 pixel3 = texture2D(s_texture, v_texcoords[1].xy).rgb;\n"
776868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  vec3 pixel4 = texture2D(s_texture, v_texcoords[1].zw).rgb;\n"
777868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  vec3 pixel12 = pixel1 + pixel2;\n"
778868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  vec3 pixel34 = pixel3 + pixel4;\n"
779868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  gl_FragData[0] = vec4(dot(pixel1, kRGBtoY),\n"
780868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "                        dot(pixel2, kRGBtoY),\n"
781868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "                        dot(pixel3, kRGBtoY),\n"
782868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "                        dot(pixel4, kRGBtoY)) + kYBias;\n"
783868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  gl_FragData[1] = vec4(dot(pixel12, kRGBtoU),\n"
784868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "                        dot(pixel34, kRGBtoU),\n"
785868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "                        dot(pixel12, kRGBtoV),\n"
786868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "                        dot(pixel34, kRGBtoV)) + kUVBias;\n");
787868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        break;
788868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
789868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case SHADER_YUV_MRT_PASS2:
790868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // We're just sampling two pixels and unswizzling them.  There's
791868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // no need to do vertical scaling with math, since bilinear
792868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // interpolation in the sampler takes care of that.
7935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shared_variables.append("varying vec4 v_texcoords;\n");
7943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        vertex_header.append(
7953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 scaling_vector;\n"
7963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "uniform vec2 dst_pixelsize;\n");
797868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        vertex_program.append(
7987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
799868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  step /= 2.0;\n"
800868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords.xy = texcoord - step * 0.5;\n"
801868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  v_texcoords.zw = texcoord + step * 0.5;\n");
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n");
803868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        fragment_program.append(
804868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  vec4 lo_uuvv = texture2D(s_texture, v_texcoords.xy);\n"
805868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  vec4 hi_uuvv = texture2D(s_texture, v_texcoords.zw);\n"
806868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  gl_FragData[0] = vec4(lo_uuvv.rg, hi_uuvv.rg);\n"
807868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            "  gl_FragData[1] = vec4(lo_uuvv.ba, hi_uuvv.ba);\n");
808868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        break;
80990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
81090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (swizzle) {
811effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      switch(type) {
812effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        case SHADER_YUV_MRT_PASS1:
813effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          fragment_program.append("  gl_FragData[0] = gl_FragData[0].bgra;\n");
814effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          break;
815effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        case SHADER_YUV_MRT_PASS2:
816effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          fragment_program.append("  gl_FragData[0] = gl_FragData[0].bgra;\n");
817effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          fragment_program.append("  gl_FragData[1] = gl_FragData[1].bgra;\n");
818effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          break;
819effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        default:
820effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          fragment_program.append("  gl_FragColor = gl_FragColor.bgra;\n");
821effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          break;
822effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
82390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
82490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    vertex_program = vertex_header + shared_variables + "void main() {\n" +
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     vertex_program + "}\n";
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fragment_program = fragment_directives + fragment_header +
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       shared_variables + "void main() {\n" + fragment_program +
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       "}\n";
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    cache_entry->Setup(vertex_program.c_str(), fragment_program.c_str());
83390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
83490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return cache_entry;
83590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
83690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ShaderProgram::Setup(const GLchar* vertex_shader_text,
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const GLchar* fragment_shader_text) {
83990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Shaders to map the source texture to |dst_texture_|.
8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLuint vertex_shader =
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      helper_->CompileShaderFromSource(vertex_shader_text, GL_VERTEX_SHADER);
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (vertex_shader == 0)
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->AttachShader(program_, vertex_shader);
8465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->DeleteShader(vertex_shader);
8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLuint fragment_shader = helper_->CompileShaderFromSource(
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fragment_shader_text, GL_FRAGMENT_SHADER);
8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (fragment_shader == 0)
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
8525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->AttachShader(program_, fragment_shader);
8535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->DeleteShader(fragment_shader);
8545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->LinkProgram(program_);
8565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLint link_status = 0;
8585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->GetProgramiv(program_, GL_LINK_STATUS, &link_status);
8595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!link_status)
8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
8615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  position_location_ = gl_->GetAttribLocation(program_, "a_position");
8635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  texcoord_location_ = gl_->GetAttribLocation(program_, "a_texcoord");
8645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  texture_location_ = gl_->GetUniformLocation(program_, "s_texture");
8655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  src_subrect_location_ = gl_->GetUniformLocation(program_, "src_subrect");
8665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  src_pixelsize_location_ = gl_->GetUniformLocation(program_, "src_pixelsize");
8675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dst_pixelsize_location_ = gl_->GetUniformLocation(program_, "dst_pixelsize");
8685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scaling_vector_location_ =
8695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gl_->GetUniformLocation(program_, "scaling_vector");
8705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  color_weights_location_ = gl_->GetUniformLocation(program_, "color_weights");
8715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return;
87290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
87390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ShaderProgram::UseProgram(const gfx::Size& src_size,
8755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               const gfx::Rect& src_subrect,
8765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               const gfx::Size& dst_size,
8775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               bool scale_x,
8785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               bool flip_y,
8795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               GLfloat color_weights[4]) {
8805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->UseProgram(program_);
8815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // OpenGL defines the last parameter to VertexAttribPointer as type
8835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // "const GLvoid*" even though it is actually an offset into the buffer
8845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // object's data store and not a pointer to the client's address space.
8855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const void* offsets[2] = {
8865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      0, reinterpret_cast<const void*>(2 * sizeof(GLfloat))
8875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
8885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->VertexAttribPointer(position_location_,
8905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           2,
8915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           GL_FLOAT,
8925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           GL_FALSE,
8935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           4 * sizeof(GLfloat),
8945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           offsets[0]);
8955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->EnableVertexAttribArray(position_location_);
8965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->VertexAttribPointer(texcoord_location_,
8985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           2,
8995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           GL_FLOAT,
9005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           GL_FALSE,
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           4 * sizeof(GLfloat),
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           offsets[1]);
9035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->EnableVertexAttribArray(texcoord_location_);
9045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->Uniform1i(texture_location_, 0);
90690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
90790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Convert |src_subrect| to texture coordinates.
90890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GLfloat src_subrect_texcoord[] = {
9095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<float>(src_subrect.x()) / src_size.width(),
9105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<float>(src_subrect.y()) / src_size.height(),
9115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<float>(src_subrect.width()) / src_size.width(),
9125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<float>(src_subrect.height()) / src_size.height(), };
91390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (flip_y) {
91490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    src_subrect_texcoord[1] += src_subrect_texcoord[3];
91590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    src_subrect_texcoord[3] *= -1.0;
91690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->Uniform4fv(src_subrect_location_, 1, src_subrect_texcoord);
9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->Uniform2f(src_pixelsize_location_, src_size.width(), src_size.height());
9205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->Uniform2f(dst_pixelsize_location_,
9215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 static_cast<float>(dst_size.width()),
9225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 static_cast<float>(dst_size.height()));
9235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->Uniform2f(
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scaling_vector_location_, scale_x ? 1.0 : 0.0, scale_x ? 0.0 : 1.0);
9265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gl_->Uniform4fv(color_weights_location_, 1, color_weights);
92790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
92890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
92990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace content
930