Support cube map dest target for CopyTextureCHROMIUM extension

DIRECT_DRAW path isn't available for cube map dest texture if it isn't
cube map complete. So, use DRAW_AND_COPY path in this scenario, i.e.
draw to a 2D intemediate texture first, then copy from the 2d texture to
the cube map dest texture.

Also, this CL makes DIRECT_COPY and DRAW_AND_COPY path work well for cube
map dest texture.

BUG=612542
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/2656563002
Cr-Commit-Position: refs/heads/master@{#446940}
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
index 6133380b..e3c9d86 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -551,15 +551,18 @@
                       GLsizei height,
                       GLuint framebuffer) {
   DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), source_target);
-  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), dest_target);
+  GLenum dest_binding_target =
+      gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(dest_target);
+  DCHECK(dest_binding_target == GL_TEXTURE_2D ||
+         dest_binding_target == GL_TEXTURE_CUBE_MAP);
   DCHECK(source_level == 0 || decoder->GetFeatureInfo()->IsES3Capable());
   if (BindFramebufferTexture2D(source_target, source_id, source_level,
                                framebuffer)) {
-    glBindTexture(dest_target, dest_id);
-    glTexParameterf(dest_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterf(dest_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameteri(dest_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(dest_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glBindTexture(dest_binding_target, dest_id);
+    glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(dest_binding_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(dest_binding_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glCopyTexImage2D(dest_target, dest_level, dest_internal_format, 0 /* x */,
                      0 /* y */, width, height, 0 /* border */);
   }
@@ -587,15 +590,18 @@
                          GLuint framebuffer) {
   DCHECK(source_target == GL_TEXTURE_2D ||
          source_target == GL_TEXTURE_RECTANGLE_ARB);
-  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), dest_target);
+  GLenum dest_binding_target =
+      gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(dest_target);
+  DCHECK(dest_binding_target == GL_TEXTURE_2D ||
+         dest_binding_target == GL_TEXTURE_CUBE_MAP);
   DCHECK(source_level == 0 || decoder->GetFeatureInfo()->IsES3Capable());
   if (BindFramebufferTexture2D(source_target, source_id, source_level,
                                framebuffer)) {
-    glBindTexture(dest_target, dest_id);
-    glTexParameterf(dest_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterf(dest_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameteri(dest_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(dest_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glBindTexture(dest_binding_target, dest_id);
+    glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(dest_binding_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(dest_binding_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glCopyTexSubImage2D(dest_target, dest_level, xoffset, yoffset, source_x,
                         source_y, source_width, source_height);
   }
@@ -713,10 +719,14 @@
     bool unpremultiply_alpha,
     CopyTextureMethod method) {
   bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha;
+  GLenum dest_binding_target =
+      gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(dest_target);
 
   // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
-  // so restrict this to GL_TEXTURE_2D.
-  if (source_target == GL_TEXTURE_2D && dest_target == GL_TEXTURE_2D &&
+  // so restrict this to GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP.
+  if (source_target == GL_TEXTURE_2D &&
+      (dest_binding_target == GL_TEXTURE_2D ||
+       dest_binding_target == GL_TEXTURE_CUBE_MAP) &&
       !flip_y && !premultiply_alpha_change && method == DIRECT_COPY) {
     DoCopyTexImage2D(decoder, source_target, source_id, source_level,
                      dest_target, dest_id, dest_level, dest_internal_format,
@@ -724,12 +734,16 @@
     return;
   }
 
+  // Draw to level 0 of an intermediate GL_TEXTURE_2D texture.
   GLuint dest_texture = dest_id;
   GLuint intermediate_texture = 0;
   GLint original_dest_level = dest_level;
+  GLenum original_dest_target = dest_target;
+  GLenum original_internal_format = dest_internal_format;
   if (method == DRAW_AND_COPY) {
     GLenum adjusted_internal_format =
         getIntermediateFormat(dest_internal_format);
+    dest_target = GL_TEXTURE_2D;
     glGenTextures(1, &intermediate_texture);
     glBindTexture(dest_target, intermediate_texture);
     GLenum format = TextureManager::ExtractFormatFromStorageFormat(
@@ -751,10 +765,9 @@
 
   if (method == DRAW_AND_COPY) {
     source_level = 0;
-    dest_level = original_dest_level;
     DoCopyTexImage2D(decoder, dest_target, intermediate_texture, source_level,
-                     dest_target, dest_id, dest_level, dest_internal_format,
-                     width, height, framebuffer_);
+                     original_dest_target, dest_id, original_dest_level,
+                     original_internal_format, width, height, framebuffer_);
     glDeleteTextures(1, &intermediate_texture);
   }
 }
@@ -792,26 +805,32 @@
   use_gl_copy_tex_sub_image_2d = false;
 #endif
   bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha;
+  GLenum dest_binding_target =
+      gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(dest_target);
 
   // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
-  // so restrict this to GL_TEXTURE_2D.
+  // so restrict this to GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP.
   if (use_gl_copy_tex_sub_image_2d && source_target == GL_TEXTURE_2D &&
-      dest_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change &&
-      method == DIRECT_COPY) {
+      (dest_binding_target == GL_TEXTURE_2D ||
+       dest_binding_target == GL_TEXTURE_CUBE_MAP) &&
+      !flip_y && !premultiply_alpha_change && method == DIRECT_COPY) {
     DoCopyTexSubImage2D(decoder, source_target, source_id, source_level,
                         dest_target, dest_id, dest_level, xoffset, yoffset, x,
                         y, width, height, framebuffer_);
     return;
   }
 
+  // Draw to level 0 of an intermediate GL_TEXTURE_2D texture.
   GLint dest_xoffset = xoffset;
   GLint dest_yoffset = yoffset;
   GLuint dest_texture = dest_id;
   GLint original_dest_level = dest_level;
+  GLenum original_dest_target = dest_target;
   GLuint intermediate_texture = 0;
   if (method == DRAW_AND_COPY) {
     GLenum adjusted_internal_format =
         getIntermediateFormat(dest_internal_format);
+    dest_target = GL_TEXTURE_2D;
     glGenTextures(1, &intermediate_texture);
     glBindTexture(dest_target, intermediate_texture);
     GLenum format = TextureManager::ExtractFormatFromStorageFormat(
@@ -839,10 +858,10 @@
 
   if (method == DRAW_AND_COPY) {
     source_level = 0;
-    dest_level = original_dest_level;
     DoCopyTexSubImage2D(decoder, dest_target, intermediate_texture,
-                        source_level, dest_target, dest_id, dest_level, xoffset,
-                        yoffset, 0, 0, width, height, framebuffer_);
+                        source_level, original_dest_target, dest_id,
+                        original_dest_level, xoffset, yoffset, 0, 0, width,
+                        height, framebuffer_);
     glDeleteTextures(1, &intermediate_texture);
   }
 }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 09ac49c..02e464c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -16434,13 +16434,16 @@
   // then copy from the fbo to dest texture level with glCopyTexImage2D.
   // For WebGL 1.0 or OpenGL ES 2.0, DIRECT_DRAW path isn't available for
   // dest_level > 0 due to level > 0 isn't supported by glFramebufferTexture2D
-  // in ES2 context. Go to DRAW_AND_COPY path in this case.
+  // in ES2 context. DIRECT_DRAW path isn't available for cube map dest texture
+  // either due to it may be cube map incomplete. Go to DRAW_AND_COPY path in
+  // these cases.
   // TODO(qiankun.miao@intel.com): for WebGL 2.0 or OpenGL ES 3.0, both
   // DIRECT_DRAW path for dest_level > 0 and DIRECT_COPY path for source_level >
   // 0 are not available due to a framebuffer completeness bug:
   // crbug.com/678526. Once the bug is fixed, the limitation for WebGL 2.0 and
   // OpenGL ES 3.0 can be lifted.
-  if ((dest_level > 0 && method == DIRECT_DRAW) ||
+  if (((dest_level > 0 || dest_binding_target == GL_TEXTURE_CUBE_MAP) &&
+       method == DIRECT_DRAW) ||
       (source_level > 0 && method == DIRECT_COPY)) {
     method = DRAW_AND_COPY;
   }
@@ -16698,13 +16701,16 @@
   // then copy from the fbo to dest texture level with glCopyTexImage2D.
   // For WebGL 1.0 or OpenGL ES 2.0, DIRECT_DRAW path isn't available for
   // dest_level > 0 due to level > 0 isn't supported by glFramebufferTexture2D
-  // in ES2 context. Go to DRAW_AND_COPY path in this case.
+  // in ES2 context. DIRECT_DRAW path isn't available for cube map dest texture
+  // either due to it may be cube map incomplete. Go to DRAW_AND_COPY path in
+  // these cases.
   // TODO(qiankun.miao@intel.com): for WebGL 2.0 or OpenGL ES 3.0, both
   // DIRECT_DRAW path for dest_level > 0 and DIRECT_COPY path for source_level >
   // 0 are not available due to a framebuffer completeness bug:
   // crbug.com/678526. Once the bug is fixed, the limitation for WebGL 2.0 and
   // OpenGL ES 3.0 can be lifted.
-  if ((dest_level > 0 && method == DIRECT_DRAW) ||
+  if (((dest_level > 0 || dest_binding_target == GL_TEXTURE_CUBE_MAP) &&
+       method == DIRECT_DRAW) ||
       (source_level > 0 && method == DIRECT_COPY)) {
     method = DRAW_AND_COPY;
   }
diff --git a/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc b/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc
index 1e24863..050fc42c 100644
--- a/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc
+++ b/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc
@@ -168,9 +168,9 @@
     glViewport(0, 0, width, height);
     std::string fragment_shader_source =
         GetFragmentShaderSource(dest_target, gfx::Size(width, height));
-    GLTestHelper::DrawTextureQuad(kSimpleVertexShader,
+    GLTestHelper::DrawTextureQuad(dest_target, kSimpleVertexShader,
                                   fragment_shader_source.c_str(), "a_position",
-                                  "u_texture");
+                                  "u_texture", nullptr);
 
     // Verify.
     const uint8_t* expected = expectations[i];
diff --git a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
index 879fac3..cdaaab26 100644
--- a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
+++ b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
@@ -13,8 +13,11 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
 #include "gpu/command_buffer/tests/gl_manager.h"
 #include "gpu/command_buffer/tests/gl_test_utils.h"
+#include "gpu/config/gpu_switches.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_version_info.h"
@@ -52,7 +55,7 @@
     "  v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5;\n"
     "}\n";
 
-std::string GetFragmentShaderSource(GLenum format, bool is_es3) {
+std::string GetFragmentShaderSource(GLenum target, GLenum format, bool is_es3) {
   std::string source;
   if (is_es3) {
     source +=
@@ -63,35 +66,85 @@
   } else {
     source +=
         "#define VARYING varying\n"
-        "#define FRAGCOLOR gl_FragColor\n"
-        "#define TextureLookup texture2D\n";
+        "#define FRAGCOLOR gl_FragColor\n";
+    if (target == GL_TEXTURE_CUBE_MAP) {
+      source += "#define TextureLookup textureCube\n";
+    } else {
+      source += "#define TextureLookup texture2D\n";
+    }
   }
   source += "precision mediump float;\n";
 
   if (gles2::GLES2Util::IsSignedIntegerFormat(format)) {
-    source += std::string("#define SamplerType isampler2D\n");
-    source += std::string("#define TextureType ivec4\n");
-    source += std::string("#define ScaleValue 255.0\n");
+    if (target == GL_TEXTURE_CUBE_MAP) {
+      source += "#define SamplerType isamplerCube\n";
+    } else {
+      source += "#define SamplerType isampler2D\n";
+    }
+    source += "#define TextureType ivec4\n";
+    source += "#define ScaleValue 255.0\n";
   } else if (gles2::GLES2Util::IsUnsignedIntegerFormat(format)) {
-    source += std::string("#define SamplerType usampler2D\n");
-    source += std::string("#define TextureType uvec4\n");
-    source += std::string("#define ScaleValue 255.0\n");
+    if (target == GL_TEXTURE_CUBE_MAP) {
+      source += "#define SamplerType usamplerCube\n";
+    } else {
+      source += "#define SamplerType usampler2D\n";
+    }
+    source += "#define TextureType uvec4\n";
+    source += "#define ScaleValue 255.0\n";
   } else {
-    source += std::string("#define SamplerType sampler2D\n");
-    source += std::string("#define TextureType vec4\n");
-    source += std::string("#define ScaleValue 1.0\n");
+    if (target == GL_TEXTURE_CUBE_MAP) {
+      source += "#define SamplerType samplerCube\n";
+    } else {
+      source += "#define SamplerType sampler2D\n";
+    }
+    source += "#define TextureType vec4\n";
+    source += "#define ScaleValue 1.0\n";
   }
 
   if (is_es3)
     source += "out vec4 frag_color;\n";
 
-  source += std::string(
+  if (target == GL_TEXTURE_CUBE_MAP)
+    source += "uniform highp int u_face;\n";
+
+  source +=
       "uniform mediump SamplerType u_texture;\n"
       "VARYING vec2 v_texCoord;\n"
-      "void main() {\n"
-      "  TextureType color = TextureLookup(u_texture, v_texCoord);\n"
+      "void main() {\n";
+
+  if (target == GL_TEXTURE_CUBE_MAP) {
+    source +=
+        "  vec3 texCube;\n"
+        // Transform [0, 1] to [-1, 1].
+        "  vec2 texCoord = (v_texCoord * 2.0) - 1.0;\n"
+        // Transform 2d tex coord to each face of TEXTURE_CUBE_MAP coord.
+        // TEXTURE_CUBE_MAP_POSITIVE_X
+        "  if (u_face == 34069) {\n"
+        "    texCube = vec3(1.0, -texCoord.y, -texCoord.x);\n"
+        // TEXTURE_CUBE_MAP_NEGATIVE_X
+        "  } else if (u_face == 34070) {\n"
+        "    texCube = vec3(-1.0, -texCoord.y, texCoord.x);\n"
+        // TEXTURE_CUBE_MAP_POSITIVE_Y
+        "  } else if (u_face == 34071) {\n"
+        "    texCube = vec3(texCoord.x, 1.0, texCoord.y);\n"
+        // TEXTURE_CUBE_MAP_NEGATIVE_Y
+        "  } else if (u_face == 34072) {\n"
+        "    texCube = vec3(texCoord.x, -1.0, -texCoord.y);\n"
+        // TEXTURE_CUBE_MAP_POSITIVE_Z
+        "  } else if (u_face == 34073) {\n"
+        "    texCube = vec3(texCoord.x, -texCoord.y, 1.0);\n"
+        // TEXTURE_CUBE_MAP_NEGATIVE_Z
+        "  } else if (u_face == 34074) {\n"
+        "    texCube = vec3(-texCoord.x, -texCoord.y, -1.0);\n"
+        "  }\n"
+        "  TextureType color = TextureLookup(u_texture, texCube);\n";
+  } else {
+    source += "  TextureType color = TextureLookup(u_texture, v_texCoord);\n";
+  }
+
+  source +=
       "  FRAGCOLOR = vec4(color) / ScaleValue;\n"
-      "}\n");
+      "}\n";
   return source;
 }
 
@@ -262,7 +315,7 @@
     glBindTexture(target, texture);
     glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    CreateBackingForTexture(GL_TEXTURE_2D, width, height);
+    CreateBackingForTexture(target, width, height);
     return texture;
   }
 
@@ -289,7 +342,7 @@
     }
   }
 
-  void RunCopyTexture(GLenum target,
+  void RunCopyTexture(GLenum dest_target,
                       CopyType copy_type,
                       FormatType src_format_type,
                       GLint source_level,
@@ -310,85 +363,109 @@
                      dest_format_type.internal_format, color, expected_color,
                      mask);
 
+    GLenum source_target = GL_TEXTURE_2D;
     glGenTextures(2, textures_);
-    glBindTexture(target, textures_[0]);
-    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glBindTexture(source_target, textures_[0]);
+    glTexParameteri(source_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(source_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 #if defined(OS_MACOSX)
     // TODO(qiankun.miao@intel.com): Remove this workaround for Mac OSX, once
     // integer texture rendering bug is fixed on Mac OSX: crbug.com/679639.
-    glTexImage2D(target, 0, src_format_type.internal_format,
+    glTexImage2D(source_target, 0, src_format_type.internal_format,
                  width_ << source_level, height_ << source_level, 0,
                  src_format_type.format, src_format_type.type, nullptr);
 #endif
-    glTexImage2D(target, source_level, src_format_type.internal_format, width_,
-                 height_, 0, src_format_type.format, src_format_type.type,
-                 pixels.get());
+    glTexImage2D(source_target, source_level, src_format_type.internal_format,
+                 width_, height_, 0, src_format_type.format,
+                 src_format_type.type, pixels.get());
     EXPECT_TRUE(glGetError() == GL_NO_ERROR);
-    glBindTexture(target, textures_[1]);
-    glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    GLenum dest_binding_target =
+        gles2::GLES2Util::GLFaceTargetToTextureTarget(dest_target);
+    glBindTexture(dest_binding_target, textures_[1]);
+    glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(dest_binding_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     // This hack makes dest texture complete in ES2 and ES3 context
     // respectively. With this, sampling from the dest texture is correct.
     if (is_es3) {
-      glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-      glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, dest_level);
+      glTexParameteri(dest_binding_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+      glTexParameteri(dest_binding_target, GL_TEXTURE_BASE_LEVEL, dest_level);
+      // For cube map textures, make the texture cube complete.
+      if (dest_binding_target == GL_TEXTURE_CUBE_MAP) {
+        for (int i = 0; i < 6; ++i) {
+          GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
+          glTexImage2D(face, dest_level, dest_format_type.internal_format,
+                       width_, height_, 0, dest_format_type.format,
+                       dest_format_type.type, nullptr);
+        }
+      }
 #if defined(OS_MACOSX)
       // TODO(qiankun.miao@intel.com): Remove this workaround for Mac OSX, once
       // framebuffer complete bug is fixed on Mac OSX: crbug.com/678526.
-      glTexImage2D(target, 0, dest_format_type.internal_format,
+      glTexImage2D(dest_target, 0, dest_format_type.internal_format,
                    width_ << dest_level, height_ << dest_level, 0,
                    dest_format_type.format, dest_format_type.type, nullptr);
 #endif
     } else {
-      glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
-      glTexImage2D(target, 0, dest_format_type.internal_format,
-                   width_ << dest_level, height_ << dest_level, 0,
-                   dest_format_type.format, dest_format_type.type, nullptr);
-      glGenerateMipmap(target);
+      glTexParameteri(dest_binding_target, GL_TEXTURE_MIN_FILTER,
+                      GL_NEAREST_MIPMAP_NEAREST);
+      // For cube map textures, make the texture cube complete.
+      if (dest_binding_target == GL_TEXTURE_CUBE_MAP) {
+        for (int i = 0; i < 6; ++i) {
+          GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
+          glTexImage2D(face, 0, dest_format_type.internal_format,
+                       width_ << dest_level, height_ << dest_level, 0,
+                       dest_format_type.format, dest_format_type.type, nullptr);
+        }
+      } else {
+        glTexImage2D(dest_target, 0, dest_format_type.internal_format,
+                     width_ << dest_level, height_ << dest_level, 0,
+                     dest_format_type.format, dest_format_type.type, nullptr);
+      }
+      glGenerateMipmap(dest_binding_target);
     }
     EXPECT_TRUE(glGetError() == GL_NO_ERROR);
 
     if (copy_type == TexImage) {
-      glCopyTextureCHROMIUM(textures_[0], source_level, target, textures_[1],
-                            dest_level, dest_format_type.internal_format,
+      glCopyTextureCHROMIUM(textures_[0], source_level, dest_target,
+                            textures_[1], dest_level,
+                            dest_format_type.internal_format,
                             dest_format_type.type, false, false, false);
     } else {
-      glBindTexture(target, textures_[1]);
-      glTexImage2D(target, dest_level, dest_format_type.internal_format, width_,
-                   height_, 0, dest_format_type.format, dest_format_type.type,
-                   nullptr);
+      glBindTexture(dest_binding_target, textures_[1]);
+      glTexImage2D(dest_target, dest_level, dest_format_type.internal_format,
+                   width_, height_, 0, dest_format_type.format,
+                   dest_format_type.type, nullptr);
 
-      glCopySubTextureCHROMIUM(textures_[0], source_level, target, textures_[1],
-                               dest_level, 0, 0, 0, 0, width_, height_, false,
-                               false, false);
+      glCopySubTextureCHROMIUM(textures_[0], source_level, dest_target,
+                               textures_[1], dest_level, 0, 0, 0, 0, width_,
+                               height_, false, false, false);
     }
     EXPECT_TRUE(glGetError() == GL_NO_ERROR);
 
-    // Draw destination texture to a fbo with a texture attachment in RGBA
-    // format.
-    GLuint texture = CreateDrawingTexture(target, width_, height_);
-    GLuint framebuffer = CreateDrawingFBO(target, texture);
+    // Draw destination texture to a fbo with a TEXTURE_2D texture attachment
+    // in RGBA format.
+    GLuint texture = CreateDrawingTexture(GL_TEXTURE_2D, width_, height_);
+    GLuint framebuffer = CreateDrawingFBO(GL_TEXTURE_2D, texture);
     EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
               glCheckFramebufferStatus(GL_FRAMEBUFFER));
     glViewport(0, 0, width_, height_);
 
-    glBindTexture(target, textures_[1]);
-    std::string fragment_shader_source =
-        GetFragmentShaderSource(dest_format_type.internal_format, is_es3);
+    glBindTexture(dest_binding_target, textures_[1]);
+    std::string fragment_shader_source = GetFragmentShaderSource(
+        dest_binding_target, dest_format_type.internal_format, is_es3);
     GLTestHelper::DrawTextureQuad(
-        is_es3 ? kSimpleVertexShaderES3 : kSimpleVertexShaderES2,
-        fragment_shader_source.c_str(), "a_position", "u_texture");
+        dest_target, is_es3 ? kSimpleVertexShaderES3 : kSimpleVertexShaderES2,
+        fragment_shader_source.c_str(), "a_position", "u_texture", "u_face");
     EXPECT_TRUE(GL_NO_ERROR == glGetError());
 
     uint8_t tolerance = dest_format_type.internal_format == GL_RGBA4 ? 20 : 7;
     EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, width_, height_, tolerance,
                                           expected_color, mask))
+        << " dest_target : " << gles2::GLES2Util::GetStringEnum(dest_target)
         << " src_internal_format: "
         << gles2::GLES2Util::GetStringEnum(src_format_type.internal_format)
-        << " source_level: " << source_level
-        << " dest_internal_format: "
+        << " source_level: " << source_level << " dest_internal_format: "
         << gles2::GLES2Util::GetStringEnum(dest_format_type.internal_format)
         << " dest_level: " << dest_level;
 
@@ -410,7 +487,15 @@
     GLManager::Options options;
     options.context_type = gles2::CONTEXT_TYPE_OPENGLES3;
     options.size = gfx::Size(64, 64);
-    gl_.Initialize(options);
+    base::CommandLine command_line(*base::CommandLine::ForCurrentProcess());
+#if defined(OS_MACOSX)
+    // Sampling of seamless integer cube map texture has bug on Intel GEN7 gpus
+    // on Mac OSX, see crbug.com/658930.
+    command_line.AppendSwitchASCII(
+        switches::kGpuDriverBugWorkarounds,
+        base::IntToString(gpu::DISABLE_TEXTURE_CUBE_MAP_SEAMLESS));
+#endif
+    gl_.InitializeWithCommandLine(options, command_line);
 
     width_ = 8;
     height_ = 8;
@@ -794,6 +879,54 @@
   }
 }
 
+TEST_P(GLCopyTextureCHROMIUMTest, CopyTextureCubeMap) {
+  CopyType copy_type = GetParam();
+
+  GLenum dest_targets[] = {
+      GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+      GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+      GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z};
+  FormatType src_format_type = {GL_RGB, GL_RGB, GL_UNSIGNED_BYTE};
+  FormatType dest_format_types[] = {
+      {GL_RGB, GL_RGB, GL_UNSIGNED_BYTE}, {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE},
+  };
+  GLint source_level = 0;
+  GLint dest_level = 0;
+
+  for (auto dest_format_type : dest_format_types) {
+    for (auto dest_target : dest_targets) {
+      RunCopyTexture(dest_target, copy_type, src_format_type, source_level,
+                     dest_format_type, dest_level, false);
+    }
+  }
+}
+
+TEST_P(GLCopyTextureCHROMIUMES3Test, CopyTextureCubeMap) {
+  if (ShouldSkipTest())
+    return;
+  CopyType copy_type = GetParam();
+
+  GLenum dest_targets[] = {
+      GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+      GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+      GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z};
+  FormatType src_format_type = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE};
+  FormatType dest_format_types[] = {
+      {GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE},
+      {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},
+      {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE},
+  };
+  GLint source_level = 0;
+  GLint dest_level = 0;
+
+  for (auto dest_format_type : dest_format_types) {
+    for (auto dest_target : dest_targets) {
+      RunCopyTexture(dest_target, copy_type, src_format_type, source_level,
+                     dest_format_type, dest_level, true);
+    }
+  }
+}
+
 // Test to ensure that the destination texture is redefined if the properties
 // are different.
 TEST_F(GLCopyTextureCHROMIUMTest, RedefineDestinationTexture) {
diff --git a/gpu/command_buffer/tests/gl_test_utils.cc b/gpu/command_buffer/tests/gl_test_utils.cc
index 6fc8ff8..402a9694 100644
--- a/gpu/command_buffer/tests/gl_test_utils.cc
+++ b/gpu/command_buffer/tests/gl_test_utils.cc
@@ -11,6 +11,7 @@
 #include <memory>
 #include <string>
 
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -277,10 +278,12 @@
   return true;
 }
 
-void GLTestHelper::DrawTextureQuad(const char* vertex_src,
+void GLTestHelper::DrawTextureQuad(const GLenum texture_target,
+                                   const char* vertex_src,
                                    const char* fragment_src,
                                    const char* position_name,
-                                   const char* sampler_name) {
+                                   const char* sampler_name,
+                                   const char* face_name) {
   GLuint program = GLTestHelper::LoadProgram(vertex_src, fragment_src);
   EXPECT_NE(program, 0u);
   glUseProgram(program);
@@ -289,6 +292,14 @@
   GLint sampler_location = glGetUniformLocation(program, sampler_name);
   ASSERT_NE(position_loc, -1);
   ASSERT_NE(sampler_location, -1);
+  GLint face_loc = -1;
+  if (gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(texture_target) ==
+      GL_TEXTURE_CUBE_MAP) {
+    ASSERT_NE(face_name, nullptr);
+    face_loc = glGetUniformLocation(program, face_name);
+    ASSERT_NE(face_loc, -1);
+    glUniform1i(face_loc, texture_target);
+  }
 
   GLuint vertex_buffer = GLTestHelper::SetupUnitQuad(position_loc);
   ASSERT_NE(vertex_buffer, 0u);
diff --git a/gpu/command_buffer/tests/gl_test_utils.h b/gpu/command_buffer/tests/gl_test_utils.h
index e89fbfb..3a1641e 100644
--- a/gpu/command_buffer/tests/gl_test_utils.h
+++ b/gpu/command_buffer/tests/gl_test_utils.h
@@ -68,10 +68,12 @@
   // Uses ReadPixels to save an area of the current FBO/Backbuffer.
   static bool SaveBackbufferAsBMP(const char* filename, int width, int height);
 
-  static void DrawTextureQuad(const char* vertex_src,
+  static void DrawTextureQuad(const GLenum texture_target,
+                              const char* vertex_src,
                               const char* fragment_src,
                               const char* position_name,
-                              const char* sampler_name);
+                              const char* sampler_name,
+                              const char* face_name);
 };
 
 #endif  // GPU_COMMAND_BUFFER_TESTS_GL_TEST_UTILS_H_