Capture/Replay: Update CopyImageSubData params

The parameters to glCopyImageSubData are flexible and
can take a TextureID or a RenderbufferID as a GLuint.

Our replay needs to remap those values, so we'll convert the GLuint
based on the target.  This leads to a change like the following.

Before:

  glCopyImageSubData(138, 0x0DE1, 0, 0, 0, 0,
                     642, 0x0DE1, 1, 0, 0, 0,
                     256, 256, 1);

After:

  glCopyImageSubData(gTextureMap[138], 0x0DE1, 0, 0, 0, 0,
                     gTextureMap[642], 0x0DE1, 1, 0, 0, 0,
                     256, 256, 1);

Test: PUBG Mobile MEC
Bug: angleproject:6087
Bug: angleproject:6104
Change-Id: I5cd422e41ffbb4f08c8909e520bdce63e3008c5a
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2981464
Commit-Queue: Cody Northrop <cnorthrop@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Tim Van Patten <timvp@google.com>
diff --git a/src/libANGLE/capture/FrameCapture.cpp b/src/libANGLE/capture/FrameCapture.cpp
index f443007..2a5c66d 100644
--- a/src/libANGLE/capture/FrameCapture.cpp
+++ b/src/libANGLE/capture/FrameCapture.cpp
@@ -3710,13 +3710,25 @@
     // cached texture entry for use during mid-execution capture, rather than reading it back with
     // ANGLE_get_image.
 
-    GLuint srcName = call.params.getParam("srcName", ParamType::TGLuint, 0).value.GLuintVal;
+    GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
+    GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
+
+    // TODO(anglebug.com/6104): Type of incoming ID varies based on target type, but we're only
+    // handling textures for now. If either of these asserts fire, then we need to add renderbuffer
+    // support.
+    ASSERT(srcTarget == GL_TEXTURE_2D || srcTarget == GL_TEXTURE_2D_ARRAY ||
+           srcTarget == GL_TEXTURE_3D || srcTarget == GL_TEXTURE_CUBE_MAP);
+    ASSERT(dstTarget == GL_TEXTURE_2D || dstTarget == GL_TEXTURE_2D_ARRAY ||
+           dstTarget == GL_TEXTURE_3D || dstTarget == GL_TEXTURE_CUBE_MAP);
+
+    gl::TextureID srcName =
+        call.params.getParam("srcName", ParamType::TTextureID, 0).value.TextureIDVal;
     GLint srcLevel = call.params.getParam("srcLevel", ParamType::TGLint, 2).value.GLintVal;
-    GLuint dstName = call.params.getParam("dstName", ParamType::TGLuint, 6).value.GLuintVal;
+    gl::TextureID dstName =
+        call.params.getParam("dstName", ParamType::TTextureID, 6).value.TextureIDVal;
     GLint dstLevel = call.params.getParam("dstLevel", ParamType::TGLint, 8).value.GLintVal;
 
     // Look up the texture type
-    GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
     gl::TextureTarget dstTargetPacked = gl::PackParam<gl::TextureTarget>(dstTarget);
     gl::TextureType dstTextureType    = gl::TextureTargetToType(dstTargetPacked);
 
@@ -3729,7 +3741,7 @@
     if (dstFormat.compressed)
     {
         context->getShareGroup()->getFrameCaptureShared()->copyCachedTextureLevel(
-            context, {srcName}, srcLevel, {dstName}, dstLevel, call);
+            context, srcName, srcLevel, dstName, dstLevel, call);
     }
 }
 
@@ -3948,6 +3960,69 @@
     }
 }
 
+void FrameCapture::updateCopyImageSubData(CallCapture &call)
+{
+    // This call modifies srcName and dstName to no longer be object IDs (GLuint), but actual
+    // packed types that can remapped using gTextureMap and gRenderbufferMap
+
+    GLint srcName    = call.params.getParam("srcName", ParamType::TGLuint, 0).value.GLuintVal;
+    GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
+    switch (srcTarget)
+    {
+        case GL_RENDERBUFFER:
+        {
+            // Convert the GLuint to RenderbufferID
+            gl::RenderbufferID srcRenderbufferID = {static_cast<GLuint>(srcName)};
+            call.params.setValueParamAtIndex("srcName", ParamType::TRenderbufferID,
+                                             srcRenderbufferID, 0);
+            break;
+        }
+        case GL_TEXTURE_2D:
+        case GL_TEXTURE_2D_ARRAY:
+        case GL_TEXTURE_3D:
+        case GL_TEXTURE_CUBE_MAP:
+        {
+            // Convert the GLuint to TextureID
+            gl::TextureID srcTextureID = {static_cast<GLuint>(srcName)};
+            call.params.setValueParamAtIndex("srcName", ParamType::TTextureID, srcTextureID, 0);
+            break;
+        }
+        default:
+            ERR() << "Unhandled srcTarget = " << srcTarget;
+            UNREACHABLE();
+            break;
+    }
+
+    // Change dstName to the appropriate type based on dstTarget
+    GLint dstName    = call.params.getParam("dstName", ParamType::TGLuint, 6).value.GLuintVal;
+    GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
+    switch (dstTarget)
+    {
+        case GL_RENDERBUFFER:
+        {
+            // Convert the GLuint to RenderbufferID
+            gl::RenderbufferID dstRenderbufferID = {static_cast<GLuint>(dstName)};
+            call.params.setValueParamAtIndex("dstName", ParamType::TRenderbufferID,
+                                             dstRenderbufferID, 6);
+            break;
+        }
+        case GL_TEXTURE_2D:
+        case GL_TEXTURE_2D_ARRAY:
+        case GL_TEXTURE_3D:
+        case GL_TEXTURE_CUBE_MAP:
+        {
+            // Convert the GLuint to TextureID
+            gl::TextureID dstTextureID = {static_cast<GLuint>(dstName)};
+            call.params.setValueParamAtIndex("dstName", ParamType::TTextureID, dstTextureID, 6);
+            break;
+        }
+        default:
+            ERR() << "Unhandled dstTarget = " << dstTarget;
+            UNREACHABLE();
+            break;
+    }
+}
+
 void FrameCapture::maybeOverrideEntryPoint(const gl::Context *context, CallCapture &call)
 {
     switch (call.entryPoint)
@@ -3966,6 +4041,14 @@
             UNIMPLEMENTED();
             break;
         }
+        case EntryPoint::GLCopyImageSubData:
+        case EntryPoint::GLCopyImageSubDataEXT:
+        case EntryPoint::GLCopyImageSubDataOES:
+        {
+            // We must look at the src and dst target types to determine which remap table to use
+            updateCopyImageSubData(call);
+            break;
+        }
         default:
             break;
     }
diff --git a/src/libANGLE/capture/FrameCapture.h b/src/libANGLE/capture/FrameCapture.h
index 0967de2..30161ad 100644
--- a/src/libANGLE/capture/FrameCapture.h
+++ b/src/libANGLE/capture/FrameCapture.h
@@ -55,6 +55,8 @@
     template <typename T>
     void addValueParam(const char *paramName, ParamType paramType, T paramValue);
     template <typename T>
+    void setValueParamAtIndex(const char *paramName, ParamType paramType, T paramValue, int index);
+    template <typename T>
     void addEnumParam(const char *paramName,
                       gl::GLenumGroup enumGroup,
                       ParamType paramType,
@@ -390,6 +392,7 @@
     void maybeCaptureDrawElementsClientData(const gl::Context *context,
                                             CallCapture &call,
                                             size_t instanceCount);
+    void updateCopyImageSubData(CallCapture &call);
 
     static void ReplayCall(gl::Context *context,
                            ReplayContext *replayContext,
@@ -504,6 +507,19 @@
 }
 
 template <typename T>
+void ParamBuffer::setValueParamAtIndex(const char *paramName,
+                                       ParamType paramType,
+                                       T paramValue,
+                                       int index)
+{
+    ASSERT(mParamCaptures.size() > static_cast<size_t>(index));
+
+    ParamCapture capture(paramName, paramType);
+    InitParamValue(paramType, paramValue, &capture.value);
+    mParamCaptures[index] = std::move(capture);
+}
+
+template <typename T>
 void ParamBuffer::addEnumParam(const char *paramName,
                                gl::GLenumGroup enumGroup,
                                ParamType paramType,