This source file includes following definitions.
- vertex_attributes_buffer_
 
- color_weights_location_
 
- Initialized
 
- subscaler_
 
- Execute
 
- Scale
 
- SrcSize
 
- SrcSubrect
 
- DstSize
 
- swizzle
 
- ConvertScalerOpsToScalerStages
 
- ComputeScalerStages
 
- CreateScaler
 
- CreatePlanarScaler
 
- CreateYuvMrtShader
 
- InitBuffer
 
- GetShaderProgram
 
- Setup
 
- UseProgram
 
#include "content/common/gpu/client/gl_helper_scaling.h"
#include <deque>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/time/time.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
using gpu::gles2::GLES2Interface;
namespace content {
GLHelperScaling::GLHelperScaling(GLES2Interface* gl, GLHelper* helper)
    : gl_(gl), helper_(helper), vertex_attributes_buffer_(gl_) {
  InitBuffer();
}
GLHelperScaling::~GLHelperScaling() {}
class ShaderProgram : public base::RefCounted<ShaderProgram> {
 public:
  ShaderProgram(GLES2Interface* gl, GLHelper* helper)
      : gl_(gl),
        helper_(helper),
        program_(gl_->CreateProgram()),
        position_location_(-1),
        texcoord_location_(-1),
        src_subrect_location_(-1),
        src_pixelsize_location_(-1),
        dst_pixelsize_location_(-1),
        scaling_vector_location_(-1),
        color_weights_location_(-1) {}
  
  void Setup(const GLchar* vertex_shader_text,
             const GLchar* fragment_shader_text);
  
  
  
  void UseProgram(const gfx::Size& src_size,
                  const gfx::Rect& src_subrect,
                  const gfx::Size& dst_size,
                  bool scale_x,
                  bool flip_y,
                  GLfloat color_weights[4]);
  bool Initialized() const { return position_location_ != -1; }
 private:
  friend class base::RefCounted<ShaderProgram>;
  ~ShaderProgram() { gl_->DeleteProgram(program_); }
  GLES2Interface* gl_;
  GLHelper* helper_;
  
  GLuint program_;
  
  GLint position_location_;
  
  GLint texcoord_location_;
  
  GLint texture_location_;
  
  
  GLint src_subrect_location_;
  
  GLint src_pixelsize_location_;
  
  GLint dst_pixelsize_location_;
  
  GLint scaling_vector_location_;
  
  GLint color_weights_location_;
  DISALLOW_COPY_AND_ASSIGN(ShaderProgram);
};
class ScalerImpl : public GLHelper::ScalerInterface,
                   public GLHelperScaling::ShaderInterface {
 public:
  
  
  
  
  
  
  
  
  
  
  ScalerImpl(GLES2Interface* gl,
             GLHelperScaling* scaler_helper,
             const GLHelperScaling::ScalerStage& scaler_stage,
             ScalerImpl* subscaler,
             const float* color_weights)
      : gl_(gl),
        scaler_helper_(scaler_helper),
        spec_(scaler_stage),
        intermediate_texture_(0),
        dst_framebuffer_(gl),
        subscaler_(subscaler) {
    if (color_weights) {
      color_weights_[0] = color_weights[0];
      color_weights_[1] = color_weights[1];
      color_weights_[2] = color_weights[2];
      color_weights_[3] = color_weights[3];
    } else {
      color_weights_[0] = 0.0;
      color_weights_[1] = 0.0;
      color_weights_[2] = 0.0;
      color_weights_[3] = 0.0;
    }
    shader_program_ =
        scaler_helper_->GetShaderProgram(spec_.shader, spec_.swizzle);
    if (subscaler_) {
      intermediate_texture_ = 0u;
      gl_->GenTextures(1, &intermediate_texture_);
      ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_,
                                                        intermediate_texture_);
      gl_->TexImage2D(GL_TEXTURE_2D,
                      0,
                      GL_RGBA,
                      spec_.src_size.width(),
                      spec_.src_size.height(),
                      0,
                      GL_RGBA,
                      GL_UNSIGNED_BYTE,
                      NULL);
    }
  }
  virtual ~ScalerImpl() {
    if (intermediate_texture_) {
      gl_->DeleteTextures(1, &intermediate_texture_);
    }
  }
  
  virtual void Execute(GLuint source_texture,
                       const std::vector<GLuint>& dest_textures) OVERRIDE {
    if (subscaler_) {
      subscaler_->Scale(source_texture, intermediate_texture_);
      source_texture = intermediate_texture_;
    }
    ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
        gl_, dst_framebuffer_);
    DCHECK_GT(dest_textures.size(), 0U);
    scoped_ptr<GLenum[]> buffers(new GLenum[dest_textures.size()]);
    for (size_t t = 0; t < dest_textures.size(); t++) {
      ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dest_textures[t]);
      gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
                                GL_COLOR_ATTACHMENT0 + t,
                                GL_TEXTURE_2D,
                                dest_textures[t],
                                0);
      buffers[t] = GL_COLOR_ATTACHMENT0 + t;
    }
    ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, source_texture);
    gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(
        gl_, scaler_helper_->vertex_attributes_buffer_);
    DCHECK(shader_program_->Initialized());
    shader_program_->UseProgram(spec_.src_size,
                                spec_.src_subrect,
                                spec_.dst_size,
                                spec_.scale_x,
                                spec_.vertically_flip_texture,
                                color_weights_);
    gl_->Viewport(0, 0, spec_.dst_size.width(), spec_.dst_size.height());
    if (dest_textures.size() > 1) {
      DCHECK_LE(static_cast<int>(dest_textures.size()),
                scaler_helper_->helper_->MaxDrawBuffers());
      gl_->DrawBuffersEXT(dest_textures.size(), buffers.get());
    }
    
    gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    if (dest_textures.size() > 1) {
      
      gl_->DrawBuffersEXT(1, &buffers[0]);
    }
  }
  
  virtual void Scale(GLuint source_texture, GLuint dest_texture) OVERRIDE {
    std::vector<GLuint> tmp(1);
    tmp[0] = dest_texture;
    Execute(source_texture, tmp);
  }
  virtual const gfx::Size& SrcSize() OVERRIDE {
    if (subscaler_) {
      return subscaler_->SrcSize();
    }
    return spec_.src_size;
  }
  virtual const gfx::Rect& SrcSubrect() OVERRIDE {
    if (subscaler_) {
      return subscaler_->SrcSubrect();
    }
    return spec_.src_subrect;
  }
  virtual const gfx::Size& DstSize() OVERRIDE { return spec_.dst_size; }
 private:
  GLES2Interface* gl_;
  GLHelperScaling* scaler_helper_;
  GLHelperScaling::ScalerStage spec_;
  GLfloat color_weights_[4];
  GLuint intermediate_texture_;
  scoped_refptr<ShaderProgram> shader_program_;
  ScopedFramebuffer dst_framebuffer_;
  scoped_ptr<ScalerImpl> subscaler_;
};
GLHelperScaling::ScalerStage::ScalerStage(ShaderType shader_,
                                          gfx::Size src_size_,
                                          gfx::Rect src_subrect_,
                                          gfx::Size dst_size_,
                                          bool scale_x_,
                                          bool vertically_flip_texture_,
                                          bool swizzle_)
    : shader(shader_),
      src_size(src_size_),
      src_subrect(src_subrect_),
      dst_size(dst_size_),
      scale_x(scale_x_),
      vertically_flip_texture(vertically_flip_texture_),
      swizzle(swizzle_) {}
void GLHelperScaling::ConvertScalerOpsToScalerStages(
    GLHelper::ScalerQuality quality,
    gfx::Size src_size,
    gfx::Rect src_subrect,
    const gfx::Size& dst_size,
    bool vertically_flip_texture,
    bool swizzle,
    std::deque<GLHelperScaling::ScaleOp>* x_ops,
    std::deque<GLHelperScaling::ScaleOp>* y_ops,
    std::vector<ScalerStage>* scaler_stages) {
  while (!x_ops->empty() || !y_ops->empty()) {
    gfx::Size intermediate_size = src_subrect.size();
    std::deque<ScaleOp>* current_queue = NULL;
    if (!y_ops->empty()) {
      current_queue = y_ops;
    } else {
      current_queue = x_ops;
    }
    ShaderType current_shader = SHADER_BILINEAR;
    switch (current_queue->front().scale_factor) {
      case 0:
        if (quality == GLHelper::SCALER_QUALITY_BEST) {
          current_shader = SHADER_BICUBIC_UPSCALE;
        }
        break;
      case 2:
        if (quality == GLHelper::SCALER_QUALITY_BEST) {
          current_shader = SHADER_BICUBIC_HALF_1D;
        }
        break;
      case 3:
        DCHECK(quality != GLHelper::SCALER_QUALITY_BEST);
        current_shader = SHADER_BILINEAR3;
        break;
      default:
        NOTREACHED();
    }
    bool scale_x = current_queue->front().scale_x;
    current_queue->front().UpdateSize(&intermediate_size);
    current_queue->pop_front();
    
    
    if (quality == GLHelper::SCALER_QUALITY_GOOD) {
      if (!current_queue->empty() && current_shader == SHADER_BILINEAR) {
        
        current_queue->front().UpdateSize(&intermediate_size);
        current_queue->pop_front();
        current_shader = SHADER_BILINEAR2;
        if (!current_queue->empty()) {
          
          current_queue->front().UpdateSize(&intermediate_size);
          current_queue->pop_front();
          current_shader = SHADER_BILINEAR4;
        }
      }
      
      
      
      
      
      
      
      
      
      
      if (!scale_x && x_ops->size() > 0 && x_ops->front().scale_factor <= 2) {
        int x_passes = 0;
        if (current_shader == SHADER_BILINEAR2 && x_ops->size() >= 2) {
          
          x_passes = 2;
          current_shader = SHADER_BILINEAR2X2;
        } else if (current_shader == SHADER_BILINEAR) {
          
          scale_x = true;
          switch (x_ops->size()) {
            case 0:
              NOTREACHED();
            case 1:
              if (x_ops->front().scale_factor == 3) {
                current_shader = SHADER_BILINEAR3;
              }
              x_passes = 1;
              break;
            case 2:
              x_passes = 2;
              current_shader = SHADER_BILINEAR2;
              break;
            default:
              x_passes = 3;
              current_shader = SHADER_BILINEAR4;
              break;
          }
        } else if (x_ops->front().scale_factor == 2) {
          
          x_passes = 1;
        }
        for (int i = 0; i < x_passes; i++) {
          x_ops->front().UpdateSize(&intermediate_size);
          x_ops->pop_front();
        }
      }
    }
    scaler_stages->push_back(ScalerStage(current_shader,
                                         src_size,
                                         src_subrect,
                                         intermediate_size,
                                         scale_x,
                                         vertically_flip_texture,
                                         swizzle));
    src_size = intermediate_size;
    src_subrect = gfx::Rect(intermediate_size);
    vertically_flip_texture = false;
    swizzle = false;
  }
}
void GLHelperScaling::ComputeScalerStages(
    GLHelper::ScalerQuality quality,
    const gfx::Size& src_size,
    const gfx::Rect& src_subrect,
    const gfx::Size& dst_size,
    bool vertically_flip_texture,
    bool swizzle,
    std::vector<ScalerStage>* scaler_stages) {
  if (quality == GLHelper::SCALER_QUALITY_FAST ||
      src_subrect.size() == dst_size) {
    scaler_stages->push_back(ScalerStage(SHADER_BILINEAR,
                                         src_size,
                                         src_subrect,
                                         dst_size,
                                         false,
                                         vertically_flip_texture,
                                         swizzle));
    return;
  }
  std::deque<GLHelperScaling::ScaleOp> x_ops, y_ops;
  GLHelperScaling::ScaleOp::AddOps(src_subrect.width(),
                                   dst_size.width(),
                                   true,
                                   quality == GLHelper::SCALER_QUALITY_GOOD,
                                   &x_ops);
  GLHelperScaling::ScaleOp::AddOps(src_subrect.height(),
                                   dst_size.height(),
                                   false,
                                   quality == GLHelper::SCALER_QUALITY_GOOD,
                                   &y_ops);
  ConvertScalerOpsToScalerStages(quality,
                                 src_size,
                                 src_subrect,
                                 dst_size,
                                 vertically_flip_texture,
                                 swizzle,
                                 &x_ops,
                                 &y_ops,
                                 scaler_stages);
}
GLHelper::ScalerInterface* GLHelperScaling::CreateScaler(
    GLHelper::ScalerQuality quality,
    gfx::Size src_size,
    gfx::Rect src_subrect,
    const gfx::Size& dst_size,
    bool vertically_flip_texture,
    bool swizzle) {
  std::vector<ScalerStage> scaler_stages;
  ComputeScalerStages(quality,
                      src_size,
                      src_subrect,
                      dst_size,
                      vertically_flip_texture,
                      swizzle,
                      &scaler_stages);
  ScalerImpl* ret = NULL;
  for (unsigned int i = 0; i < scaler_stages.size(); i++) {
    ret = new ScalerImpl(gl_, this, scaler_stages[i], ret, NULL);
  }
  return ret;
}
GLHelper::ScalerInterface* GLHelperScaling::CreatePlanarScaler(
    const gfx::Size& src_size,
    const gfx::Rect& src_subrect,
    const gfx::Size& dst_size,
    bool vertically_flip_texture,
    bool swizzle,
    const float color_weights[4]) {
  ScalerStage stage(SHADER_PLANAR,
                    src_size,
                    src_subrect,
                    dst_size,
                    true,
                    vertically_flip_texture,
                    swizzle);
  return new ScalerImpl(gl_, this, stage, NULL, color_weights);
}
GLHelperScaling::ShaderInterface* GLHelperScaling::CreateYuvMrtShader(
    const gfx::Size& src_size,
    const gfx::Rect& src_subrect,
    const gfx::Size& dst_size,
    bool vertically_flip_texture,
    bool swizzle,
    ShaderType shader) {
  DCHECK(shader == SHADER_YUV_MRT_PASS1 || shader == SHADER_YUV_MRT_PASS2);
  ScalerStage stage(shader,
                    src_size,
                    src_subrect,
                    dst_size,
                    true,
                    vertically_flip_texture,
                    swizzle);
  return new ScalerImpl(gl_, this, stage, NULL, NULL);
}
const GLfloat GLHelperScaling::kVertexAttributes[] = {
    -1.0f, -1.0f, 0.0f, 0.0f,     
    1.0f,  -1.0f, 1.0f, 0.0f,     
    -1.0f, 1.0f,  0.0f, 1.0f,     
    1.0f,  1.0f,  1.0f, 1.0f, };  
void GLHelperScaling::InitBuffer() {
  ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(gl_,
                                                    vertex_attributes_buffer_);
  gl_->BufferData(GL_ARRAY_BUFFER,
                  sizeof(kVertexAttributes),
                  kVertexAttributes,
                  GL_STATIC_DRAW);
}
scoped_refptr<ShaderProgram> GLHelperScaling::GetShaderProgram(ShaderType type,
                                                               bool swizzle) {
  ShaderProgramKeyType key(type, swizzle);
  scoped_refptr<ShaderProgram>& cache_entry(shader_programs_[key]);
  if (!cache_entry.get()) {
    cache_entry = new ShaderProgram(gl_, helper_);
    std::basic_string<GLchar> vertex_program;
    std::basic_string<GLchar> fragment_program;
    std::basic_string<GLchar> vertex_header;
    std::basic_string<GLchar> fragment_directives;
    std::basic_string<GLchar> fragment_header;
    std::basic_string<GLchar> shared_variables;
    vertex_header.append(
        "precision highp float;\n"
        "attribute vec2 a_position;\n"
        "attribute vec2 a_texcoord;\n"
        "uniform vec4 src_subrect;\n");
    fragment_header.append(
        "precision mediump float;\n"
        "uniform sampler2D s_texture;\n");
    vertex_program.append(
        "  gl_Position = vec4(a_position, 0.0, 1.0);\n"
        "  vec2 texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;\n");
    switch (type) {
      case SHADER_BILINEAR:
        shared_variables.append("varying vec2 v_texcoord;\n");
        vertex_program.append("  v_texcoord = texcoord;\n");
        fragment_program.append(
            "  gl_FragColor = texture2D(s_texture, v_texcoord);\n");
        break;
      case SHADER_BILINEAR2:
        
        
        
        shared_variables.append(
            "varying vec4 v_texcoords;\n");  
        vertex_header.append(
            "uniform vec2 scaling_vector;\n"
            "uniform vec2 dst_pixelsize;\n");
        vertex_program.append(
            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
            "  step /= 4.0;\n"
            "  v_texcoords.xy = texcoord + step;\n"
            "  v_texcoords.zw = texcoord - step;\n");
        fragment_program.append(
            "  gl_FragColor = (texture2D(s_texture, v_texcoords.xy) +\n"
            "                  texture2D(s_texture, v_texcoords.zw)) / 2.0;\n");
        break;
      case SHADER_BILINEAR3:
        
        
        shared_variables.append(
            "varying vec4 v_texcoords1;\n"  
            "varying vec2 v_texcoords2;\n");
        vertex_header.append(
            "uniform vec2 scaling_vector;\n"
            "uniform vec2 dst_pixelsize;\n");
        vertex_program.append(
            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
            "  step /= 3.0;\n"
            "  v_texcoords1.xy = texcoord + step;\n"
            "  v_texcoords1.zw = texcoord;\n"
            "  v_texcoords2 = texcoord - step;\n");
        fragment_program.append(
            "  gl_FragColor = (texture2D(s_texture, v_texcoords1.xy) +\n"
            "                  texture2D(s_texture, v_texcoords1.zw) +\n"
            "                  texture2D(s_texture, v_texcoords2)) / 3.0;\n");
        break;
      case SHADER_BILINEAR4:
        
        
        shared_variables.append("varying vec4 v_texcoords[2];\n");
        vertex_header.append(
            "uniform vec2 scaling_vector;\n"
            "uniform vec2 dst_pixelsize;\n");
        vertex_program.append(
            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
            "  step /= 8.0;\n"
            "  v_texcoords[0].xy = texcoord - step * 3.0;\n"
            "  v_texcoords[0].zw = texcoord - step;\n"
            "  v_texcoords[1].xy = texcoord + step;\n"
            "  v_texcoords[1].zw = texcoord + step * 3.0;\n");
        fragment_program.append(
            "  gl_FragColor = (\n"
            "      texture2D(s_texture, v_texcoords[0].xy) +\n"
            "      texture2D(s_texture, v_texcoords[0].zw) +\n"
            "      texture2D(s_texture, v_texcoords[1].xy) +\n"
            "      texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
        break;
      case SHADER_BILINEAR2X2:
        
        
        
        
        shared_variables.append("varying vec4 v_texcoords[2];\n");
        vertex_header.append("uniform vec2 dst_pixelsize;\n");
        vertex_program.append(
            "  vec2 step = src_subrect.zw / 4.0 / dst_pixelsize;\n"
            "  v_texcoords[0].xy = texcoord + vec2(step.x, step.y);\n"
            "  v_texcoords[0].zw = texcoord + vec2(step.x, -step.y);\n"
            "  v_texcoords[1].xy = texcoord + vec2(-step.x, step.y);\n"
            "  v_texcoords[1].zw = texcoord + vec2(-step.x, -step.y);\n");
        fragment_program.append(
            "  gl_FragColor = (\n"
            "      texture2D(s_texture, v_texcoords[0].xy) +\n"
            "      texture2D(s_texture, v_texcoords[0].zw) +\n"
            "      texture2D(s_texture, v_texcoords[1].xy) +\n"
            "      texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
        break;
      case SHADER_BICUBIC_HALF_1D:
        
        
        
        shared_variables.append(
            "const float CenterDist = 99.0 / 140.0;\n"
            "const float LobeDist = 11.0 / 4.0;\n"
            "const float CenterWeight = 35.0 / 64.0;\n"
            "const float LobeWeight = -3.0 / 64.0;\n"
            "varying vec4 v_texcoords[2];\n");
        vertex_header.append(
            "uniform vec2 scaling_vector;\n"
            "uniform vec2 src_pixelsize;\n");
        vertex_program.append(
            "  vec2 step = src_subrect.zw * scaling_vector / src_pixelsize;\n"
            "  v_texcoords[0].xy = texcoord - LobeDist * step;\n"
            "  v_texcoords[0].zw = texcoord - CenterDist * step;\n"
            "  v_texcoords[1].xy = texcoord + CenterDist * step;\n"
            "  v_texcoords[1].zw = texcoord + LobeDist * step;\n");
        fragment_program.append(
            "  gl_FragColor = \n"
            
            "      (texture2D(s_texture, v_texcoords[0].xy) +\n"
            "       texture2D(s_texture, v_texcoords[1].zw)) *\n"
            "          LobeWeight +\n"
            
            "      (texture2D(s_texture, v_texcoords[0].zw) +\n"
            "       texture2D(s_texture, v_texcoords[1].xy)) *\n"
            "          CenterWeight;\n");
        break;
      case SHADER_BICUBIC_UPSCALE:
        
        
        
        
        
        
        shared_variables.append("varying vec2 v_texcoord;\n");
        vertex_program.append("  v_texcoord = texcoord;\n");
        fragment_header.append(
            "uniform vec2 src_pixelsize;\n"
            "uniform vec2 scaling_vector;\n"
            "const float a = -0.5;\n"
            
            
            
            "vec4 filt4(float x) {\n"
            "  return vec4(x * x * x, x * x, x, 1) *\n"
            "         mat4(       a,      -2.0 * a,   a, 0.0,\n"
            "               a + 2.0,      -a - 3.0, 0.0, 1.0,\n"
            "              -a - 2.0, 3.0 + 2.0 * a,  -a, 0.0,\n"
            "                    -a,             a, 0.0, 0.0);\n"
            "}\n"
            "mat4 pixels_x(vec2 pos, vec2 step) {\n"
            "  return mat4(\n"
            "      texture2D(s_texture, pos - step),\n"
            "      texture2D(s_texture, pos),\n"
            "      texture2D(s_texture, pos + step),\n"
            "      texture2D(s_texture, pos + step * 2.0));\n"
            "}\n");
        fragment_program.append(
            "  vec2 pixel_pos = v_texcoord * src_pixelsize - \n"
            "      scaling_vector / 2.0;\n"
            "  float frac = fract(dot(pixel_pos, scaling_vector));\n"
            "  vec2 base = (floor(pixel_pos) + vec2(0.5)) / src_pixelsize;\n"
            "  vec2 step = scaling_vector / src_pixelsize;\n"
            "  gl_FragColor = pixels_x(base, step) * filt4(frac);\n");
        break;
      case SHADER_PLANAR:
        
        
        
        
        
        
        shared_variables.append("varying vec4 v_texcoords[2];\n");
        vertex_header.append(
            "uniform vec2 scaling_vector;\n"
            "uniform vec2 dst_pixelsize;\n");
        vertex_program.append(
            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
            "  step /= 4.0;\n"
            "  v_texcoords[0].xy = texcoord - step * 1.5;\n"
            "  v_texcoords[0].zw = texcoord - step * 0.5;\n"
            "  v_texcoords[1].xy = texcoord + step * 0.5;\n"
            "  v_texcoords[1].zw = texcoord + step * 1.5;\n");
        fragment_header.append("uniform vec4 color_weights;\n");
        fragment_program.append(
            "  gl_FragColor = color_weights * mat4(\n"
            "    vec4(texture2D(s_texture, v_texcoords[0].xy).rgb, 1.0),\n"
            "    vec4(texture2D(s_texture, v_texcoords[0].zw).rgb, 1.0),\n"
            "    vec4(texture2D(s_texture, v_texcoords[1].xy).rgb, 1.0),\n"
            "    vec4(texture2D(s_texture, v_texcoords[1].zw).rgb, 1.0));\n");
        break;
      case SHADER_YUV_MRT_PASS1:
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        shared_variables.append("varying vec4 v_texcoords[2];\n");
        vertex_header.append(
            "uniform vec2 scaling_vector;\n"
            "uniform vec2 dst_pixelsize;\n");
        vertex_program.append(
            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
            "  step /= 4.0;\n"
            "  v_texcoords[0].xy = texcoord - step * 1.5;\n"
            "  v_texcoords[0].zw = texcoord - step * 0.5;\n"
            "  v_texcoords[1].xy = texcoord + step * 0.5;\n"
            "  v_texcoords[1].zw = texcoord + step * 1.5;\n");
        fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n");
        fragment_header.append(
            "const vec3 kRGBtoY = vec3(0.257, 0.504, 0.098);\n"
            "const float kYBias = 0.0625;\n"
            
            "const vec3 kRGBtoU = vec3(-0.148, -0.291, 0.439) / 2.0;\n"
            "const vec3 kRGBtoV = vec3(0.439, -0.368, -0.071) / 2.0;\n"
            "const float kUVBias = 0.5;\n");
        fragment_program.append(
            "  vec3 pixel1 = texture2D(s_texture, v_texcoords[0].xy).rgb;\n"
            "  vec3 pixel2 = texture2D(s_texture, v_texcoords[0].zw).rgb;\n"
            "  vec3 pixel3 = texture2D(s_texture, v_texcoords[1].xy).rgb;\n"
            "  vec3 pixel4 = texture2D(s_texture, v_texcoords[1].zw).rgb;\n"
            "  vec3 pixel12 = pixel1 + pixel2;\n"
            "  vec3 pixel34 = pixel3 + pixel4;\n"
            "  gl_FragData[0] = vec4(dot(pixel1, kRGBtoY),\n"
            "                        dot(pixel2, kRGBtoY),\n"
            "                        dot(pixel3, kRGBtoY),\n"
            "                        dot(pixel4, kRGBtoY)) + kYBias;\n"
            "  gl_FragData[1] = vec4(dot(pixel12, kRGBtoU),\n"
            "                        dot(pixel34, kRGBtoU),\n"
            "                        dot(pixel12, kRGBtoV),\n"
            "                        dot(pixel34, kRGBtoV)) + kUVBias;\n");
        break;
      case SHADER_YUV_MRT_PASS2:
        
        
        
        shared_variables.append("varying vec4 v_texcoords;\n");
        vertex_header.append(
            "uniform vec2 scaling_vector;\n"
            "uniform vec2 dst_pixelsize;\n");
        vertex_program.append(
            "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
            "  step /= 2.0;\n"
            "  v_texcoords.xy = texcoord - step * 0.5;\n"
            "  v_texcoords.zw = texcoord + step * 0.5;\n");
        fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n");
        fragment_program.append(
            "  vec4 lo_uuvv = texture2D(s_texture, v_texcoords.xy);\n"
            "  vec4 hi_uuvv = texture2D(s_texture, v_texcoords.zw);\n"
            "  gl_FragData[0] = vec4(lo_uuvv.rg, hi_uuvv.rg);\n"
            "  gl_FragData[1] = vec4(lo_uuvv.ba, hi_uuvv.ba);\n");
        break;
    }
    if (swizzle) {
      switch(type) {
        case SHADER_YUV_MRT_PASS1:
          fragment_program.append("  gl_FragData[0] = gl_FragData[0].bgra;\n");
          break;
        case SHADER_YUV_MRT_PASS2:
          fragment_program.append("  gl_FragData[0] = gl_FragData[0].bgra;\n");
          fragment_program.append("  gl_FragData[1] = gl_FragData[1].bgra;\n");
          break;
        default:
          fragment_program.append("  gl_FragColor = gl_FragColor.bgra;\n");
          break;
      }
    }
    vertex_program = vertex_header + shared_variables + "void main() {\n" +
                     vertex_program + "}\n";
    fragment_program = fragment_directives + fragment_header +
                       shared_variables + "void main() {\n" + fragment_program +
                       "}\n";
    cache_entry->Setup(vertex_program.c_str(), fragment_program.c_str());
  }
  return cache_entry;
}
void ShaderProgram::Setup(const GLchar* vertex_shader_text,
                          const GLchar* fragment_shader_text) {
  
  GLuint vertex_shader =
      helper_->CompileShaderFromSource(vertex_shader_text, GL_VERTEX_SHADER);
  if (vertex_shader == 0)
    return;
  gl_->AttachShader(program_, vertex_shader);
  gl_->DeleteShader(vertex_shader);
  GLuint fragment_shader = helper_->CompileShaderFromSource(
      fragment_shader_text, GL_FRAGMENT_SHADER);
  if (fragment_shader == 0)
    return;
  gl_->AttachShader(program_, fragment_shader);
  gl_->DeleteShader(fragment_shader);
  gl_->LinkProgram(program_);
  GLint link_status = 0;
  gl_->GetProgramiv(program_, GL_LINK_STATUS, &link_status);
  if (!link_status)
    return;
  position_location_ = gl_->GetAttribLocation(program_, "a_position");
  texcoord_location_ = gl_->GetAttribLocation(program_, "a_texcoord");
  texture_location_ = gl_->GetUniformLocation(program_, "s_texture");
  src_subrect_location_ = gl_->GetUniformLocation(program_, "src_subrect");
  src_pixelsize_location_ = gl_->GetUniformLocation(program_, "src_pixelsize");
  dst_pixelsize_location_ = gl_->GetUniformLocation(program_, "dst_pixelsize");
  scaling_vector_location_ =
      gl_->GetUniformLocation(program_, "scaling_vector");
  color_weights_location_ = gl_->GetUniformLocation(program_, "color_weights");
  return;
}
void ShaderProgram::UseProgram(const gfx::Size& src_size,
                               const gfx::Rect& src_subrect,
                               const gfx::Size& dst_size,
                               bool scale_x,
                               bool flip_y,
                               GLfloat color_weights[4]) {
  gl_->UseProgram(program_);
  
  
  
  const void* offsets[2] = {
      0, reinterpret_cast<const void*>(2 * sizeof(GLfloat))
  };
  gl_->VertexAttribPointer(position_location_,
                           2,
                           GL_FLOAT,
                           GL_FALSE,
                           4 * sizeof(GLfloat),
                           offsets[0]);
  gl_->EnableVertexAttribArray(position_location_);
  gl_->VertexAttribPointer(texcoord_location_,
                           2,
                           GL_FLOAT,
                           GL_FALSE,
                           4 * sizeof(GLfloat),
                           offsets[1]);
  gl_->EnableVertexAttribArray(texcoord_location_);
  gl_->Uniform1i(texture_location_, 0);
  
  GLfloat src_subrect_texcoord[] = {
      static_cast<float>(src_subrect.x()) / src_size.width(),
      static_cast<float>(src_subrect.y()) / src_size.height(),
      static_cast<float>(src_subrect.width()) / src_size.width(),
      static_cast<float>(src_subrect.height()) / src_size.height(), };
  if (flip_y) {
    src_subrect_texcoord[1] += src_subrect_texcoord[3];
    src_subrect_texcoord[3] *= -1.0;
  }
  gl_->Uniform4fv(src_subrect_location_, 1, src_subrect_texcoord);
  gl_->Uniform2f(src_pixelsize_location_, src_size.width(), src_size.height());
  gl_->Uniform2f(dst_pixelsize_location_,
                 static_cast<float>(dst_size.width()),
                 static_cast<float>(dst_size.height()));
  gl_->Uniform2f(
      scaling_vector_location_, scale_x ? 1.0 : 0.0, scale_x ? 0.0 : 1.0);
  gl_->Uniform4fv(color_weights_location_, 1, color_weights);
}
}