gpu: Extend CopyTextureCHROMIUM with support for copying part of source texture.

This makes it possible to specify the area of the source texture
that is copied to the destination texture.

BUG=490889
TEST=gl_tests
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Review URL: https://codereview.chromium.org/1143373004

Cr-Commit-Position: refs/heads/master@{#331326}
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 d41ee9db..974cbd7 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -250,6 +250,8 @@
                          GLuint dest_id,
                          GLint xoffset,
                          GLint yoffset,
+                         GLint source_x,
+                         GLint source_y,
                          GLsizei source_width,
                          GLsizei source_height,
                          GLuint framebuffer) {
@@ -262,7 +264,7 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glCopyTexSubImage2D(GL_TEXTURE_2D, 0 /* level */, xoffset, yoffset,
-                        0 /* x */, 0 /* y */, source_width, source_height);
+                        source_x, source_y, source_width, source_height);
   }
 
   decoder->RestoreTextureState(source_id);
@@ -398,6 +400,10 @@
     GLenum dest_internal_format,
     GLint xoffset,
     GLint yoffset,
+    GLint x,
+    GLint y,
+    GLsizei width,
+    GLsizei height,
     GLsizei dest_width,
     GLsizei dest_height,
     GLsizei source_width,
@@ -419,15 +425,15 @@
   if (source_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change &&
       source_format_contain_superset_of_dest_format) {
     DoCopyTexSubImage2D(decoder, source_target, source_id, dest_id, xoffset,
-                        yoffset, source_width, source_height, framebuffer_);
+                        yoffset, x, y, width, height, framebuffer_);
     return;
   }
 
-  // Use kIdentityMatrix if no transform passed in.
-  DoCopySubTextureWithTransform(
-      decoder, source_target, source_id, dest_id, xoffset, yoffset, dest_width,
-      dest_height, source_width, source_height, flip_y, premultiply_alpha,
-      unpremultiply_alpha, kIdentityMatrix);
+  DoCopyTextureInternal(decoder, source_target, source_id, dest_id, xoffset - x,
+                        yoffset - y, dest_width, dest_height, source_width,
+                        source_height, flip_y, premultiply_alpha,
+                        unpremultiply_alpha, kIdentityMatrix, xoffset, yoffset,
+                        width, height);
 }
 
 void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
@@ -446,28 +452,7 @@
   DoCopyTextureInternal(decoder, source_target, source_id, dest_id, 0, 0,
                         dest_width, dest_height, width, height, flip_y,
                         premultiply_alpha, unpremultiply_alpha,
-                        transform_matrix);
-}
-
-void CopyTextureCHROMIUMResourceManager::DoCopySubTextureWithTransform(
-    const gles2::GLES2Decoder* decoder,
-    GLenum source_target,
-    GLuint source_id,
-    GLuint dest_id,
-    GLint xoffset,
-    GLint yoffset,
-    GLsizei dest_width,
-    GLsizei dest_height,
-    GLsizei source_width,
-    GLsizei source_height,
-    bool flip_y,
-    bool premultiply_alpha,
-    bool unpremultiply_alpha,
-    const GLfloat transform_matrix[16]) {
-  DoCopyTextureInternal(decoder, source_target, source_id, dest_id, xoffset,
-                        yoffset, dest_width, dest_height, source_width,
-                        source_height, flip_y, premultiply_alpha,
-                        unpremultiply_alpha, transform_matrix);
+                        transform_matrix, 0, 0, dest_width, dest_height);
 }
 
 void CopyTextureCHROMIUMResourceManager::DoCopyTextureInternal(
@@ -484,7 +469,11 @@
     bool flip_y,
     bool premultiply_alpha,
     bool unpremultiply_alpha,
-    const GLfloat transform_matrix[16]) {
+    const GLfloat transform_matrix[16],
+    GLint scissor_x,
+    GLint scissor_y,
+    GLsizei scissor_width,
+    GLsizei scissor_height) {
   DCHECK(source_target == GL_TEXTURE_2D ||
          source_target == GL_TEXTURE_RECTANGLE_ARB ||
          source_target == GL_TEXTURE_EXTERNAL_OES);
@@ -580,13 +569,14 @@
     glTexParameteri(source_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
     glDisable(GL_DEPTH_TEST);
-    glDisable(GL_SCISSOR_TEST);
     glDisable(GL_STENCIL_TEST);
     glDisable(GL_CULL_FACE);
     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
     glDepthMask(GL_FALSE);
     glDisable(GL_BLEND);
 
+    glEnable(GL_SCISSOR_TEST);
+    glScissor(scissor_x, scissor_y, scissor_width, scissor_height);
     glViewport(0, 0, dest_width, dest_height);
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
   }
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
index 5c62141..8cba517 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
@@ -50,6 +50,10 @@
                         GLenum dest_internal_format,
                         GLint xoffset,
                         GLint yoffset,
+                        GLint x,
+                        GLint y,
+                        GLsizei width,
+                        GLsizei height,
                         GLsizei dest_width,
                         GLsizei dest_height,
                         GLsizei source_width,
@@ -71,21 +75,6 @@
                                   bool unpremultiply_alpha,
                                   const GLfloat transform_matrix[16]);
 
-  void DoCopySubTextureWithTransform(const gles2::GLES2Decoder* decoder,
-                                     GLenum source_target,
-                                     GLuint source_id,
-                                     GLuint dest_id,
-                                     GLint xoffset,
-                                     GLint yoffset,
-                                     GLsizei dest_width,
-                                     GLsizei dest_height,
-                                     GLsizei source_width,
-                                     GLsizei source_height,
-                                     bool flip_y,
-                                     bool premultiply_alpha,
-                                     bool unpremultiply_alpha,
-                                     const GLfloat transform_matrix[16]);
-
   // The attributes used during invocation of the extension.
   static const GLuint kVertexPositionAttrib = 0;
 
@@ -116,7 +105,11 @@
                              bool flip_y,
                              bool premultiply_alpha,
                              bool unpremultiply_alpha,
-                             const GLfloat transform_matrix[16]);
+                             const GLfloat transform_matrix[16],
+                             GLint scissor_x,
+                             GLint scissor_y,
+                             GLsizei scissor_width,
+                             GLsizei scissor_height);
 
   bool initialized_;
   typedef std::vector<GLuint> ShaderVector;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 9c4af2e7..f1880d1c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1013,7 +1013,11 @@
                                 GLuint source_id,
                                 GLuint dest_id,
                                 GLint xoffset,
-                                GLint yoffset);
+                                GLint yoffset,
+                                GLint x,
+                                GLint y,
+                                GLsizei width,
+                                GLsizei height);
 
   // Wrapper for TexStorage2DEXT.
   void DoTexStorage2DEXT(
@@ -11969,7 +11973,7 @@
 
   ScopedModifyPixels modify(dest_texture_ref);
 
-  // Try using GLImage::CopyTexImage when possible.
+  // Try using GLImage::CopyTexSubImage when possible.
   bool unpack_premultiply_alpha_change =
       unpack_premultiply_alpha_ ^ unpack_unpremultiply_alpha_;
   if (image && !unpack_flip_y_ && !unpack_premultiply_alpha_change) {
@@ -12007,7 +12011,11 @@
                                                 GLuint source_id,
                                                 GLuint dest_id,
                                                 GLint xoffset,
-                                                GLint yoffset) {
+                                                GLint yoffset,
+                                                GLint x,
+                                                GLint y,
+                                                GLsizei width,
+                                                GLsizei height) {
   TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoCopySubTextureCHROMIUM");
 
   TextureRef* source_texture_ref = GetTexture(source_id);
@@ -12048,6 +12056,13 @@
   GLenum source_internal_format = 0;
   source_texture->GetLevelType(source_texture->target(), 0, &source_type,
                                &source_internal_format);
+  if (!source_texture->ValidForTexture(source_texture->target(), 0, x, y, 0,
+                                       width, height, 1, source_type)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM",
+                       "source texture bad dimensions.");
+    return;
+  }
+
   GLenum dest_type = 0;
   GLenum dest_internal_format = 0;
   bool dest_level_defined = dest_texture->GetLevelType(
@@ -12058,8 +12073,7 @@
     return;
   }
   if (!dest_texture->ValidForTexture(dest_texture->target(), 0, xoffset,
-                                     yoffset, 0, source_width, source_height,
-                                     1, dest_type)) {
+                                     yoffset, 0, width, height, 1, dest_type)) {
     LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM",
                        "destination texture bad dimensions.");
     return;
@@ -12095,8 +12109,8 @@
   bool ok = dest_texture->GetLevelSize(
       GL_TEXTURE_2D, 0, &dest_width, &dest_height, nullptr);
   DCHECK(ok);
-  if (xoffset != 0 || yoffset != 0 || source_width != dest_width ||
-      source_height != dest_height) {
+  if (xoffset != 0 || yoffset != 0 || width != dest_width ||
+      height != dest_height) {
     if (!texture_manager()->ClearTextureLevel(this, dest_texture_ref, target,
                                               0)) {
       LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopySubTextureCHROMIUM",
@@ -12116,31 +12130,21 @@
   if (image && !unpack_flip_y_ && !unpack_premultiply_alpha_change) {
     glBindTexture(GL_TEXTURE_2D, dest_texture->service_id());
     if (image->CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(xoffset, yoffset),
-                               gfx::Rect(0, 0, source_width, source_height))) {
+                               gfx::Rect(x, y, source_width, source_height))) {
       return;
     }
   }
 
   DoWillUseTexImageIfNeeded(source_texture, source_texture->target());
 
-  // GL_TEXTURE_EXTERNAL_OES texture requires apply a transform matrix
-  // before presenting.
-  if (source_texture->target() == GL_TEXTURE_EXTERNAL_OES) {
-    // TODO(hkuang): get the StreamTexture transform matrix in GPU process
-    // instead of using kIdentityMatrix crbug.com/226218.
-    copy_texture_CHROMIUM_->DoCopySubTextureWithTransform(
-        this, source_texture->target(), source_texture->service_id(),
-        dest_texture->service_id(), xoffset, yoffset, dest_width, dest_height,
-        source_width, source_height, unpack_flip_y_, unpack_premultiply_alpha_,
-        unpack_unpremultiply_alpha_, kIdentityMatrix);
-  } else {
-    copy_texture_CHROMIUM_->DoCopySubTexture(
-        this, source_texture->target(), source_texture->service_id(),
-        source_internal_format, dest_texture->service_id(),
-        dest_internal_format, xoffset, yoffset, dest_width, dest_height,
-        source_width, source_height, unpack_flip_y_, unpack_premultiply_alpha_,
-        unpack_unpremultiply_alpha_);
-  }
+  // TODO(hkuang): get the StreamTexture transform matrix in GPU process.
+  // crbug.com/226218.
+  copy_texture_CHROMIUM_->DoCopySubTexture(
+      this, source_texture->target(), source_texture->service_id(),
+      source_internal_format, dest_texture->service_id(), dest_internal_format,
+      xoffset, yoffset, x, y, width, height, dest_width, dest_height,
+      source_width, source_height, unpack_flip_y_, unpack_premultiply_alpha_,
+      unpack_unpremultiply_alpha_);
 
   DoDidUseTexImageIfNeeded(source_texture, source_texture->target());
 }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 26c4782..09d07c0b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -4553,7 +4553,22 @@
   GLenum dest_id = static_cast<GLenum>(c.dest_id);
   GLint xoffset = static_cast<GLint>(c.xoffset);
   GLint yoffset = static_cast<GLint>(c.yoffset);
-  DoCopySubTextureCHROMIUM(target, source_id, dest_id, xoffset, yoffset);
+  GLint x = static_cast<GLint>(c.x);
+  GLint y = static_cast<GLint>(c.y);
+  GLsizei width = static_cast<GLsizei>(c.width);
+  GLsizei height = static_cast<GLsizei>(c.height);
+  if (width < 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM",
+                       "width < 0");
+    return error::kNoError;
+  }
+  if (height < 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM",
+                       "height < 0");
+    return error::kNoError;
+  }
+  DoCopySubTextureCHROMIUM(target, source_id, dest_id, xoffset, yoffset, x, y,
+                           width, height);
   return error::kNoError;
 }