Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / service / gles2_cmd_copy_texture_chromium.cc
index 5ce4a22..bda65ac 100644 (file)
 
 #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
 
-#include <string.h>
+#include <algorithm>
+
 #include "base/basictypes.h"
-#include "gpu/command_buffer/common/types.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 
-#define SHADER0(src) \
-    "#ifdef GL_ES\n"\
-    "precision mediump float;\n"\
-    "#endif\n"\
-    #src
-#define SHADER(src) { false, SHADER0(src), }
-#define SHADER_EXTERNAL_OES0(src) \
-    "#extension GL_OES_EGL_image_external : require\n"\
-    "#ifdef GL_ES\n"\
-    "precision mediump float;\n"\
-    "#endif\n"\
-    #src
-#define SHADER_EXTERNAL_OES(src) { true, SHADER_EXTERNAL_OES0(src), }
+#define SHADER(src)                     \
+  "#ifdef GL_ES\n"                      \
+  "precision mediump float;\n"          \
+  "#define TexCoordPrecision mediump\n" \
+  "#else\n"                             \
+  "#define TexCoordPrecision\n"         \
+  "#endif\n" #src
+#define SHADER_2D(src)              \
+  "#define SamplerType sampler2D\n" \
+  "#define TextureLookup texture2D\n" SHADER(src)
+#define SHADER_RECTANGLE_ARB(src)     \
+  "#define SamplerType samplerRect\n" \
+  "#define TextureLookup textureRect\n" SHADER(src)
+#define SHADER_EXTERNAL_OES(src)                     \
+  "#extension GL_OES_EGL_image_external : require\n" \
+  "#define SamplerType samplerExternalOES\n"         \
+  "#define TextureLookup texture2D\n" SHADER(src)
+#define FRAGMENT_SHADERS(src) \
+  SHADER_2D(src), SHADER_RECTANGLE_ARB(src), SHADER_EXTERNAL_OES(src)
 
 namespace {
 
-const GLfloat kQuadVertices[] = { -1.0f, -1.0f, 0.0f, 1.0f,
-                                   1.0f, -1.0f, 0.0f, 1.0f,
-                                   1.0f,  1.0f, 0.0f, 1.0f,
-                                  -1.0f,  1.0f, 0.0f, 1.0f };
-
-enum ProgramId {
-  PROGRAM_COPY_TEXTURE,
-  PROGRAM_COPY_TEXTURE_FLIP_Y,
-  PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA,
-  PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA,
-  PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIPY,
-  PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIPY,
-  PROGRAM_COPY_TEXTURE_OES,
-  PROGRAM_COPY_TEXTURE_OES_FLIP_Y,
-  PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA,
-  PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA,
-  PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA_FLIPY,
-  PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA_FLIPY,
+enum VertexShaderId {
+  VERTEX_SHADER_COPY_TEXTURE,
+  VERTEX_SHADER_COPY_TEXTURE_FLIP_Y,
+  NUM_VERTEX_SHADERS,
 };
 
-struct ShaderInfo {
-  bool needs_egl_image_external;
-  const char* source;
+enum FragmentShaderId {
+  FRAGMENT_SHADER_COPY_TEXTURE_2D,
+  FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB,
+  FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES,
+  FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_2D,
+  FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_RECTANGLE_ARB,
+  FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_EXTERNAL_OES,
+  FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_2D,
+  FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_RECTANGLE_ARB,
+  FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_EXTERNAL_OES,
+  NUM_FRAGMENT_SHADERS,
 };
 
-const ShaderInfo shader_infos[] = {
-  // VERTEX_SHADER_POS_TEX
+const char* vertex_shader_source[NUM_VERTEX_SHADERS] = {
+  // VERTEX_SHADER_COPY_TEXTURE
   SHADER(
     uniform mat4 u_matrix;
+    uniform vec2 u_half_size;
     attribute vec4 a_position;
-    varying vec2 v_uv;
+    varying TexCoordPrecision vec2 v_uv;
     void main(void) {
       gl_Position = u_matrix * a_position;
-      v_uv = a_position.xy * 0.5 + vec2(0.5, 0.5);
+      v_uv = a_position.xy * vec2(u_half_size.s, u_half_size.t) +
+             vec2(u_half_size.s, u_half_size.t);
     }),
-  // FRAGMENT_SHADER_TEX
+  // VERTEX_SHADER_COPY_TEXTURE_FLIP_Y
   SHADER(
-    uniform sampler2D u_texSampler;
-    varying vec2 v_uv;
-    void main(void) {
-      gl_FragColor = texture2D(u_texSampler, v_uv.st);
-    }),
-  // FRAGMENT_SHADER_TEX_FLIP_Y
-  SHADER(
-    uniform sampler2D u_texSampler;
-    varying vec2 v_uv;
-    void main(void) {
-      gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
-    }),
-  // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA
-  SHADER(
-    uniform sampler2D u_texSampler;
-    varying vec2 v_uv;
+    uniform mat4 u_matrix;
+    uniform vec2 u_half_size;
+    attribute vec4 a_position;
+    varying TexCoordPrecision vec2 v_uv;
     void main(void) {
-      gl_FragColor = texture2D(u_texSampler, v_uv.st);
-      gl_FragColor.rgb *= gl_FragColor.a;
+      gl_Position = u_matrix * a_position;
+      v_uv = a_position.xy * vec2(u_half_size.s, -u_half_size.t) +
+             vec2(u_half_size.s, u_half_size.t);
     }),
-  // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA
-  SHADER(
-    uniform sampler2D u_texSampler;
-    varying vec2 v_uv;
+};
+
+const char* fragment_shader_source[NUM_FRAGMENT_SHADERS] = {
+  // FRAGMENT_SHADER_COPY_TEXTURE_*
+  FRAGMENT_SHADERS(
+    uniform SamplerType u_sampler;
+    varying TexCoordPrecision vec2 v_uv;
     void main(void) {
-      gl_FragColor = texture2D(u_texSampler, v_uv.st);
-      if (gl_FragColor.a > 0.0)
-        gl_FragColor.rgb /= gl_FragColor.a;
+      gl_FragColor = TextureLookup(u_sampler, v_uv.st);
     }),
-  // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA_FLIP_Y
-  SHADER(
-    uniform sampler2D u_texSampler;
-    varying vec2 v_uv;
+  // FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_*
+  FRAGMENT_SHADERS(
+    uniform SamplerType u_sampler;
+    varying TexCoordPrecision vec2 v_uv;
     void main(void) {
-      gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
+      gl_FragColor = TextureLookup(u_sampler, v_uv.st);
       gl_FragColor.rgb *= gl_FragColor.a;
     }),
-  // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA_FLIP_Y
-  SHADER(
-    uniform sampler2D u_texSampler;
-    varying vec2 v_uv;
-    void main(void) {
-      gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
-      if (gl_FragColor.a > 0.0)
-        gl_FragColor.rgb /= gl_FragColor.a;
-    }),
-  // FRAGMENT_SHADER_TEX_OES
-  SHADER_EXTERNAL_OES(
-    precision mediump float;
-    uniform samplerExternalOES u_texSampler;
-    varying vec2 v_uv;
+  // FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_*
+  FRAGMENT_SHADERS(
+    uniform SamplerType u_sampler;
+    varying TexCoordPrecision vec2 v_uv;
     void main(void) {
-      gl_FragColor = texture2D(u_texSampler, v_uv.st);
-    }),
-  // FRAGMENT_SHADER_TEX_OES_FLIP_Y
-  SHADER_EXTERNAL_OES(
-     precision mediump float;
-     uniform samplerExternalOES u_texSampler;
-     varying vec2 v_uv;
-     void main(void) {
-       gl_FragColor =
-           texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
-     }),
-  // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA
-  SHADER_EXTERNAL_OES(
-     precision mediump float;
-     uniform samplerExternalOES u_texSampler;
-     varying vec2 v_uv;
-     void main(void) {
-       gl_FragColor = texture2D(u_texSampler, v_uv.st);
-       gl_FragColor.rgb *= gl_FragColor.a;
-     }),
-  // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA
-  SHADER_EXTERNAL_OES(
-    precision mediump float;
-    uniform samplerExternalOES u_texSampler;
-    varying vec2 v_uv;
-    void main(void) {
-      gl_FragColor = texture2D(u_texSampler, v_uv.st);
+      gl_FragColor = TextureLookup(u_sampler, v_uv.st);
       if (gl_FragColor.a > 0.0)
         gl_FragColor.rgb /= gl_FragColor.a;
     }),
-  // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA_FLIP_Y
-  SHADER_EXTERNAL_OES(
-      precision mediump float;
-      uniform samplerExternalOES u_texSampler;
-      varying vec2 v_uv;
-      void main(void) {
-        gl_FragColor =
-            texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
-        gl_FragColor.rgb *= gl_FragColor.a;
-      }),
-  // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA_FLIP_Y
-  SHADER_EXTERNAL_OES(
-      precision mediump float;
-      uniform samplerExternalOES u_texSampler;
-      varying vec2 v_uv;
-      void main(void) {
-        gl_FragColor =
-            texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
-        if (gl_FragColor.a > 0.0)
-          gl_FragColor.rgb /= gl_FragColor.a;
-      }),
 };
 
-const int kNumShaders = arraysize(shader_infos);
+// Returns the correct vertex shader id to evaluate the copy operation for
+// the CHROMIUM_flipy setting.
+VertexShaderId GetVertexShaderId(bool flip_y) {
+  // bit 0: flip y
+  static VertexShaderId shader_ids[] = {
+      VERTEX_SHADER_COPY_TEXTURE,
+      VERTEX_SHADER_COPY_TEXTURE_FLIP_Y,
+  };
 
-// Returns the correct program to evaluate the copy operation for
-// the CHROMIUM_flipy and premultiply alpha pixel store settings.
-ProgramId GetProgram(
-    bool flip_y,
-    bool premultiply_alpha,
-    bool unpremultiply_alpha,
-    bool is_source_external_oes) {
-  // If both pre-multiply and unpremultiply are requested, then perform no
-  // alpha manipulation.
-  if (premultiply_alpha && unpremultiply_alpha) {
-    premultiply_alpha = false;
-    unpremultiply_alpha = false;
-  }
+  unsigned index = flip_y ? 1 : 0;
+  return shader_ids[index];
+}
 
-  // bit 0: Flip_y
-  // bit 1: Premult
-  // bit 2: Unpremult
-  // bit 3: External_oes
-  static ProgramId program_ids[] = {
-    PROGRAM_COPY_TEXTURE,
-    PROGRAM_COPY_TEXTURE_FLIP_Y,                         // F
-    PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA,              //   P
-    PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIPY,        // F P
-    PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA,            //     U
-    PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIPY,      // F   U
-    PROGRAM_COPY_TEXTURE,                                //   P U
-    PROGRAM_COPY_TEXTURE,                                // F P U
-    PROGRAM_COPY_TEXTURE_OES,                            //       E
-    PROGRAM_COPY_TEXTURE_OES_FLIP_Y,                     // F     E
-    PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA,          //   P   E
-    PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA_FLIPY,    // F P   E
-    PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA,        //     U E
-    PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA_FLIPY,  // F   U E
-    PROGRAM_COPY_TEXTURE_OES,                            //   P U E
-    PROGRAM_COPY_TEXTURE_OES,                            // F P U E
+// Returns the correct fragment shader id to evaluate the copy operation for
+// the premultiply alpha pixel store settings and target.
+FragmentShaderId GetFragmentShaderId(bool premultiply_alpha,
+                                     bool unpremultiply_alpha,
+                                     GLenum target) {
+  enum {
+    SAMPLER_2D,
+    SAMPLER_RECTANGLE_ARB,
+    SAMPLER_EXTERNAL_OES,
+    NUM_SAMPLERS
   };
 
-  unsigned index = (flip_y                 ? (1 << 0) : 0) |
-                   (premultiply_alpha      ? (1 << 1) : 0) |
-                   (unpremultiply_alpha    ? (1 << 2) : 0) |
-                   (is_source_external_oes ? (1 << 3) : 0);
-  return program_ids[index];
+  // bit 0: premultiply alpha
+  // bit 1: unpremultiply alpha
+  static FragmentShaderId shader_ids[][NUM_SAMPLERS] = {
+      {
+       FRAGMENT_SHADER_COPY_TEXTURE_2D,
+       FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB,
+       FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES,
+      },
+      {
+       FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_2D,
+       FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_RECTANGLE_ARB,
+       FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_EXTERNAL_OES,
+      },
+      {
+       FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_2D,
+       FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_RECTANGLE_ARB,
+       FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_EXTERNAL_OES,
+      },
+      {
+       FRAGMENT_SHADER_COPY_TEXTURE_2D,
+       FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB,
+       FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES,
+      }};
+
+  unsigned index = (premultiply_alpha   ? (1 << 0) : 0) |
+                   (unpremultiply_alpha ? (1 << 1) : 0);
+
+  switch (target) {
+    case GL_TEXTURE_2D:
+      return shader_ids[index][SAMPLER_2D];
+    case GL_TEXTURE_RECTANGLE_ARB:
+      return shader_ids[index][SAMPLER_RECTANGLE_ARB];
+    case GL_TEXTURE_EXTERNAL_OES:
+      return shader_ids[index][SAMPLER_EXTERNAL_OES];
+    default:
+      break;
+  }
+
+  NOTREACHED();
+  return shader_ids[index][SAMPLER_2D];
+}
+
+void CompileShader(GLuint shader, const char* shader_source) {
+  glShaderSource(shader, 1, &shader_source, 0);
+  glCompileShader(shader);
+#ifndef NDEBUG
+  GLint compile_status;
+  glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
+  if (GL_TRUE != compile_status)
+    DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure.";
+#endif
+}
+
+void DeleteShader(GLuint shader) {
+  if (shader)
+    glDeleteShader(shader);
 }
 
 }  // namespace
@@ -219,15 +191,13 @@ ProgramId GetProgram(
 namespace gpu {
 
 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
-  : initialized_(false),
-    buffer_id_(0),
-    framebuffer_(0) {
-  for (int i = 0; i < kNumPrograms; ++i) {
-    programs_[i] = 0;
-    matrix_handle_[i] = 0;
-    sampler_locations_[i] = 0;
-  }
-}
+    : initialized_(false),
+      vertex_shaders_(NUM_VERTEX_SHADERS, 0u),
+      fragment_shaders_(NUM_FRAGMENT_SHADERS, 0u),
+      buffer_id_(0u),
+      framebuffer_(0u) {}
+
+CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {}
 
 void CopyTextureCHROMIUMResourceManager::Initialize(
     const gles2::GLES2Decoder* decoder) {
@@ -235,70 +205,18 @@ void CopyTextureCHROMIUMResourceManager::Initialize(
       kVertexPositionAttrib == 0u,
       Position_attribs_must_be_0);
 
-  const char* extensions =
-      reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
-  bool have_egl_image_external = extensions &&
-      strstr(extensions, "GL_OES_EGL_image_external");
-
   // Initialize all of the GPU resources required to perform the copy.
   glGenBuffersARB(1, &buffer_id_);
   glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
-  glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices,
-               GL_STATIC_DRAW);
+  const GLfloat kQuadVertices[] = {-1.0f, -1.0f,
+                                    1.0f, -1.0f,
+                                    1.0f,  1.0f,
+                                   -1.0f,  1.0f};
+  glBufferData(
+      GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
 
   glGenFramebuffersEXT(1, &framebuffer_);
 
-  // TODO(gman): Init these on demand.
-  GLuint shaders[kNumShaders];
-  for (int shader = 0; shader < kNumShaders; ++shader) {
-    shaders[shader] = glCreateShader(
-        shader == 0 ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
-    const ShaderInfo& info = shader_infos[shader];
-    if (info.needs_egl_image_external && !have_egl_image_external) {
-      continue;
-    }
-    const char* shader_source = shader_infos[shader].source;
-    glShaderSource(shaders[shader], 1, &shader_source, 0);
-    glCompileShader(shaders[shader]);
-#ifndef NDEBUG
-    GLint compile_status;
-    glGetShaderiv(shaders[shader], GL_COMPILE_STATUS, &compile_status);
-    if (GL_TRUE != compile_status)
-      DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure.";
-#endif
-  }
-
-  // TODO(gman): Init these on demand.
-  for (int program = 0; program < kNumPrograms; ++program) {
-    const ShaderInfo& info = shader_infos[program + 1];
-    if (info.needs_egl_image_external && !have_egl_image_external) {
-      continue;
-    }
-    programs_[program] = glCreateProgram();
-    glAttachShader(programs_[program], shaders[0]);
-    glAttachShader(programs_[program], shaders[program + 1]);
-
-    glBindAttribLocation(programs_[program], kVertexPositionAttrib,
-                         "a_position");
-
-    glLinkProgram(programs_[program]);
-#ifndef NDEBUG
-    GLint linked;
-    glGetProgramiv(programs_[program], GL_LINK_STATUS, &linked);
-    if (!linked)
-      DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure.";
-#endif
-
-    sampler_locations_[program] = glGetUniformLocation(programs_[program],
-                                                      "u_texSampler");
-
-    matrix_handle_[program] = glGetUniformLocation(programs_[program],
-                                                   "u_matrix");
-  }
-
-  for (int shader = 0; shader < kNumShaders; ++shader)
-    glDeleteShader(shaders[shader]);
-
   decoder->RestoreBufferBindings();
 
   initialized_ = true;
@@ -310,9 +228,14 @@ void CopyTextureCHROMIUMResourceManager::Destroy() {
 
   glDeleteFramebuffersEXT(1, &framebuffer_);
 
-  for (int program = 0; program < kNumPrograms; ++program) {
-    if (programs_[program])
-      glDeleteProgram(programs_[program]);
+  std::for_each(vertex_shaders_.begin(), vertex_shaders_.end(), DeleteShader);
+  std::for_each(
+      fragment_shaders_.begin(), fragment_shaders_.end(), DeleteShader);
+
+  for (ProgramMap::const_iterator it = programs_.begin(); it != programs_.end();
+       ++it) {
+    const ProgramInfo& info = it->second;
+    glDeleteProgram(info.program);
   }
 
   glDeleteBuffersARB(1, &buffer_id_);
@@ -354,28 +277,66 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
     bool unpremultiply_alpha,
     const GLfloat transform_matrix[16]) {
   DCHECK(source_target == GL_TEXTURE_2D ||
+         source_target == GL_TEXTURE_RECTANGLE_ARB ||
          source_target == GL_TEXTURE_EXTERNAL_OES);
   if (!initialized_) {
     DLOG(ERROR) << "CopyTextureCHROMIUM: Uninitialized manager.";
     return;
   }
 
-  GLuint program = GetProgram(
-      flip_y, premultiply_alpha, unpremultiply_alpha,
-      source_target == GL_TEXTURE_EXTERNAL_OES);
-  glUseProgram(programs_[program]);
+  VertexShaderId vertex_shader_id = GetVertexShaderId(flip_y);
+  DCHECK_LT(static_cast<size_t>(vertex_shader_id), vertex_shaders_.size());
+  GLuint* vertex_shader = &vertex_shaders_[vertex_shader_id];
+  if (!*vertex_shader) {
+    *vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+    CompileShader(*vertex_shader, vertex_shader_source[vertex_shader_id]);
+  }
+
+  FragmentShaderId fragment_shader_id = GetFragmentShaderId(
+      premultiply_alpha, unpremultiply_alpha, source_target);
+  DCHECK_LT(static_cast<size_t>(fragment_shader_id), fragment_shaders_.size());
+  GLuint* fragment_shader = &fragment_shaders_[fragment_shader_id];
+  if (!*fragment_shader) {
+    *fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+    CompileShader(*fragment_shader, fragment_shader_source[fragment_shader_id]);
+  }
 
+  ProgramMapKey key(vertex_shader_id, fragment_shader_id);
+  ProgramInfo* info = &programs_[key];
+  // Create program if necessary.
+  if (!info->program) {
+    info->program = glCreateProgram();
+    glAttachShader(info->program, *vertex_shader);
+    glAttachShader(info->program, *fragment_shader);
+    glBindAttribLocation(info->program, kVertexPositionAttrib, "a_position");
+    glLinkProgram(info->program);
 #ifndef NDEBUG
-  glValidateProgram(programs_[program]);
+    GLint linked;
+    glGetProgramiv(info->program, GL_LINK_STATUS, &linked);
+    if (!linked)
+      DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure.";
+#endif
+    info->matrix_handle = glGetUniformLocation(info->program, "u_matrix");
+    info->half_size_handle = glGetUniformLocation(info->program, "u_half_size");
+    info->sampler_handle = glGetUniformLocation(info->program, "u_sampler");
+  }
+  glUseProgram(info->program);
+
+#ifndef NDEBUG
+  glValidateProgram(info->program);
   GLint validation_status;
-  glGetProgramiv(programs_[program], GL_VALIDATE_STATUS, &validation_status);
+  glGetProgramiv(info->program, GL_VALIDATE_STATUS, &validation_status);
   if (GL_TRUE != validation_status) {
     DLOG(ERROR) << "CopyTextureCHROMIUM: Invalid shader.";
     return;
   }
 #endif
 
-  glUniformMatrix4fv(matrix_handle_[program], 1, GL_FALSE, transform_matrix);
+  glUniformMatrix4fv(info->matrix_handle, 1, GL_FALSE, transform_matrix);
+  if (source_target == GL_TEXTURE_RECTANGLE_ARB)
+    glUniform2f(info->half_size_handle, width / 2.0f, height / 2.0f);
+  else
+    glUniform2f(info->half_size_handle, 0.5f, 0.5f);
   glActiveTexture(GL_TEXTURE0);
   glBindTexture(GL_TEXTURE_2D, dest_id);
   // NVidia drivers require texture settings to be a certain way
@@ -399,10 +360,9 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
     glEnableVertexAttribArray(kVertexPositionAttrib);
 
     glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
-    glVertexAttribPointer(kVertexPositionAttrib, 4, GL_FLOAT, GL_FALSE,
-                          4 * sizeof(GLfloat), 0);
+    glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
 
-    glUniform1i(sampler_locations_[program], 0);
+    glUniform1i(info->sampler_handle, 0);
 
     glBindTexture(source_target, source_id);
     glTexParameterf(source_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -433,5 +393,4 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
   decoder->RestoreGlobalState();
 }
 
-}  // namespace
-
+}  // namespace gpu