Trace/Replay: Add framebuffer change callback.

The perf tests can use this callback to instrument timer queries to
delineate render pass times on the device.

The new call pattern in the replay looks like this:

    glBindFramebuffer(GL_FRAMEBUFFER, gFramebufferMap[1]);
    OnFramebufferChange(GL_FRAMEBUFFER_OES, gFramebufferMap[1]);

Bug: angleproject:4433
Change-Id: Ice5150741d1d5becb26d60020e8c00e3a2fb6218
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2074337
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Cody Northrop <cnorthrop@google.com>
diff --git a/src/libANGLE/FrameCapture.cpp b/src/libANGLE/FrameCapture.cpp
index 3e9139e..cdeb78c 100644
--- a/src/libANGLE/FrameCapture.cpp
+++ b/src/libANGLE/FrameCapture.cpp
@@ -765,6 +765,12 @@
     header << "void SetupContext" << contextId << "Replay();\n";
     header << "void ReplayContext" << contextId << "Frame(uint32_t frameIndex);\n";
     header << "\n";
+    header << "using FramebufferChangeCallback = void(*)(void *userData, GLenum target, GLuint "
+              "framebuffer);\n";
+    header << "void SetFramebufferChangeCallback(void *userData, FramebufferChangeCallback "
+              "callback);\n";
+    header << "void OnFramebufferChange(GLenum target, GLuint framebuffer);\n";
+    header << "\n";
     for (uint32_t frameIndex = frameStart; frameIndex < frameEnd; ++frameIndex)
     {
         header << "void " << FmtReplayFunction(contextId, frameIndex) << ";\n";
@@ -800,6 +806,8 @@
     source << "}\n";
     source << "\n";
     source << "const char *gBinaryDataDir = \".\";\n";
+    source << "FramebufferChangeCallback gFramebufferChangeCallback;\n";
+    source << "void *gFramebufferChangeCallbackUserData;\n";
     source << "}  // namespace\n";
     source << "\n";
     source << "LocationsMap gUniformLocations;\n";
@@ -845,6 +853,21 @@
     header << "\n";
 
     source << "\n";
+    source << "void SetFramebufferChangeCallback(void *userData, FramebufferChangeCallback "
+              "callback)\n";
+    source << "{\n";
+    source << "    gFramebufferChangeCallbackUserData = userData;\n";
+    source << "    gFramebufferChangeCallback = callback;\n";
+    source << "}\n";
+    source << "\n";
+    source << "void OnFramebufferChange(GLenum target, GLuint framebuffer)\n";
+    source << "{\n";
+    source << "    if (gFramebufferChangeCallback)\n";
+    source << "        gFramebufferChangeCallback(gFramebufferChangeCallbackUserData, target, "
+              "framebuffer);\n";
+    source << "}\n";
+
+    source << "\n";
     source << "void ReplayContext" << contextId << "Frame(uint32_t frameIndex)\n";
     source << "{\n";
     source << "    switch (frameIndex)\n";
@@ -1046,6 +1069,16 @@
     callsOut->emplace_back("DeleteUniformLocations", std::move(params));
 }
 
+void CaptureOnFramebufferChange(GLenum target,
+                                gl::FramebufferID framebufferID,
+                                std::vector<CallCapture> *callsOut)
+{
+    ParamBuffer params;
+    params.addValueParam("target", ParamType::TGLenum, target);
+    params.addValueParam("framebuffer", ParamType::TFramebufferID, framebufferID);
+    callsOut->emplace_back("OnFramebufferChange", std::move(params));
+}
+
 void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut)
 {
     const CallCapture &call = callsOut->back();
@@ -2497,6 +2530,15 @@
             CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
             break;
         }
+        case gl::EntryPoint::BindFramebuffer:
+        {
+            const ParamCapture &target = lastCall.params.getParam("target", ParamType::TGLenum, 0);
+            const ParamCapture &framebuffer =
+                lastCall.params.getParam("framebufferPacked", ParamType::TFramebufferID, 1);
+            CaptureOnFramebufferChange(target.value.GLenumVal, framebuffer.value.FramebufferIDVal,
+                                       &mFrameCalls);
+            break;
+        }
         default:
             break;
     }