GL backend: Only synchronize transform feedback state when it changes.

BUG=angleproject:2188

Change-Id: I5bfcc038c887dde0770564d103eb3cb234b248c9
Reviewed-on: https://chromium-review.googlesource.com/794100
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index f87e963..eaa7930 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -1157,6 +1157,7 @@
                                         TransformFeedback *transformFeedback)
 {
     mTransformFeedback.set(context, transformFeedback);
+    mDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING);
 }
 
 TransformFeedback *State::getCurrentTransformFeedback() const
diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h
index ad0b779..f61e2f7 100644
--- a/src/libANGLE/State.h
+++ b/src/libANGLE/State.h
@@ -399,6 +399,7 @@
         // TODO(jmadill): Fine-grained dirty bits for each texture/sampler.
         DIRTY_BIT_TEXTURE_BINDINGS,
         DIRTY_BIT_SAMPLER_BINDINGS,
+        DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING,
         DIRTY_BIT_MULTISAMPLING,
         DIRTY_BIT_SAMPLE_ALPHA_TO_ONE,
         DIRTY_BIT_COVERAGE_MODULATION,         // CHROMIUM_framebuffer_mixed_samples
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.cpp b/src/libANGLE/renderer/gl/StateManagerGL.cpp
index 258b874..416c5f5 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.cpp
+++ b/src/libANGLE/renderer/gl/StateManagerGL.cpp
@@ -85,8 +85,8 @@
       mSamplers(rendererCaps.maxCombinedTextureImageUnits, 0),
       mImages(rendererCaps.maxImageUnits, ImageUnitBinding()),
       mTransformFeedback(0),
+      mCurrentTransformFeedback(nullptr),
       mQueries(),
-      mPrevDrawTransformFeedback(nullptr),
       mCurrentQueries(),
       mPrevDrawContext(0),
       mUnpackAlignment(4),
@@ -353,10 +353,10 @@
             bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
         }
 
-        if (mPrevDrawTransformFeedback != nullptr &&
-            mPrevDrawTransformFeedback->getTransformFeedbackID() == transformFeedback)
+        if (mCurrentTransformFeedback != nullptr &&
+            mCurrentTransformFeedback->getTransformFeedbackID() == transformFeedback)
         {
-            mPrevDrawTransformFeedback = nullptr;
+            mCurrentTransformFeedback = nullptr;
         }
 
         mFunctions->deleteTransformFeedbacks(1, &transformFeedback);
@@ -645,18 +645,24 @@
         // Pause the current transform feedback if one is active.
         // To handle virtualized contexts, StateManagerGL needs to be able to bind a new transform
         // feedback at any time, even if there is one active.
-        if (mPrevDrawTransformFeedback != nullptr &&
-            mPrevDrawTransformFeedback->getTransformFeedbackID() != transformFeedback)
+        if (mCurrentTransformFeedback != nullptr &&
+            mCurrentTransformFeedback->getTransformFeedbackID() != transformFeedback)
         {
-            mPrevDrawTransformFeedback->syncPausedState(true);
-            mPrevDrawTransformFeedback = nullptr;
+            mCurrentTransformFeedback->syncPausedState(true);
+            mCurrentTransformFeedback = nullptr;
         }
 
         mTransformFeedback = transformFeedback;
         mFunctions->bindTransformFeedback(type, mTransformFeedback);
+        onTransformFeedbackStateChange();
     }
 }
 
+void StateManagerGL::onTransformFeedbackStateChange()
+{
+    mLocalDirtyBits.set(gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING);
+}
+
 void StateManagerGL::beginQuery(GLenum type, GLuint query)
 {
     // Make sure this is a valid query type and there is no current active query of this type
@@ -761,9 +767,10 @@
 
 void StateManagerGL::pauseTransformFeedback()
 {
-    if (mPrevDrawTransformFeedback != nullptr)
+    if (mCurrentTransformFeedback != nullptr)
     {
-        mPrevDrawTransformFeedback->syncPausedState(true);
+        mCurrentTransformFeedback->syncPausedState(true);
+        onTransformFeedbackStateChange();
     }
 }
 
@@ -820,7 +827,7 @@
         ANGLE_TRY(pauseAllQueries());
     }
     mCurrentQueries.clear();
-    mPrevDrawTransformFeedback = nullptr;
+    onTransformFeedbackStateChange();
     mPrevDrawContext           = contextID;
 
     // Set the current query state
@@ -1006,24 +1013,6 @@
     FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
     bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebufferGL->getFramebufferID());
 
-    // Set the current transform feedback state
-    gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
-    if (transformFeedback)
-    {
-        TransformFeedbackGL *transformFeedbackGL =
-            GetImplAs<TransformFeedbackGL>(transformFeedback);
-        bindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackGL->getTransformFeedbackID());
-        transformFeedbackGL->syncActiveState(transformFeedback->isActive(),
-                                             transformFeedback->getPrimitiveMode());
-        transformFeedbackGL->syncPausedState(transformFeedback->isPaused());
-        mPrevDrawTransformFeedback = transformFeedbackGL;
-    }
-    else
-    {
-        bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
-        mPrevDrawTransformFeedback = nullptr;
-    }
-
     if (context->getExtensions().webglCompatibility)
     {
         auto activeOutputs = glState.getProgram()->getState().getActiveOutputVariables();
@@ -1946,6 +1935,9 @@
             case gl::State::DIRTY_BIT_SAMPLER_BINDINGS:
                 mProgramTexturesAndSamplersDirty = true;
                 break;
+            case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
+                syncTransformFeedbackState(context);
+                break;
             case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
                 mProgramTexturesAndSamplersDirty = true;
                 propagateNumViewsToVAO(state.getProgram(),
@@ -2235,4 +2227,25 @@
         }
     }
 }
+
+void StateManagerGL::syncTransformFeedbackState(const gl::Context *context)
+{
+    // Set the current transform feedback state
+    gl::TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback();
+    if (transformFeedback)
+    {
+        TransformFeedbackGL *transformFeedbackGL =
+            GetImplAs<TransformFeedbackGL>(transformFeedback);
+        bindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackGL->getTransformFeedbackID());
+        transformFeedbackGL->syncActiveState(transformFeedback->isActive(),
+                                             transformFeedback->getPrimitiveMode());
+        transformFeedbackGL->syncPausedState(transformFeedback->isPaused());
+        mCurrentTransformFeedback = transformFeedbackGL;
+    }
+    else
+    {
+        bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
+        mCurrentTransformFeedback = nullptr;
+    }
+}
 }
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.h b/src/libANGLE/renderer/gl/StateManagerGL.h
index 9153067..245af23 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.h
+++ b/src/libANGLE/renderer/gl/StateManagerGL.h
@@ -75,6 +75,7 @@
     void bindFramebuffer(GLenum type, GLuint framebuffer);
     void bindRenderbuffer(GLenum type, GLuint renderbuffer);
     void bindTransformFeedback(GLenum type, GLuint transformFeedback);
+    void onTransformFeedbackStateChange();
     void beginQuery(GLenum type, GLuint query);
     void endQuery(GLenum type, GLuint query);
     void onBeginQuery(QueryGL *query);
@@ -199,6 +200,8 @@
 
     void updateProgramTextureAndSamplerBindings(const gl::Context *context);
 
+    void syncTransformFeedbackState(const gl::Context *context);
+
     enum MultiviewDirtyBitType
     {
         MULTIVIEW_DIRTY_BIT_SIDE_BY_SIDE_LAYOUT,
@@ -246,10 +249,9 @@
     std::vector<ImageUnitBinding> mImages;
 
     GLuint mTransformFeedback;
+    TransformFeedbackGL *mCurrentTransformFeedback;
 
     std::map<GLenum, GLuint> mQueries;
-
-    TransformFeedbackGL *mPrevDrawTransformFeedback;
     std::set<QueryGL *> mCurrentQueries;
     gl::ContextID mPrevDrawContext;
 
diff --git a/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp b/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp
index 33354f8..7c95ccd 100644
--- a/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp
+++ b/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp
@@ -38,22 +38,27 @@
 
 void TransformFeedbackGL::begin(GLenum primitiveMode)
 {
-    // Do not begin directly, StateManagerGL will handle beginning and resuming transform feedback.
+    mStateManager->onTransformFeedbackStateChange();
 }
 
 void TransformFeedbackGL::end()
 {
+    mStateManager->onTransformFeedbackStateChange();
+
+    // Immediately end the transform feedback so that the results are visible.
     syncActiveState(false, GL_NONE);
 }
 
 void TransformFeedbackGL::pause()
 {
+    mStateManager->onTransformFeedbackStateChange();
+
     syncPausedState(true);
 }
 
 void TransformFeedbackGL::resume()
 {
-    // Do not resume directly, StateManagerGL will handle beginning and resuming transform feedback.
+    mStateManager->onTransformFeedbackStateChange();
 }
 
 void TransformFeedbackGL::bindGenericBuffer(const gl::BindingPointer<gl::Buffer> &binding)
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index 8b9dcc1..bf422e0 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -709,6 +709,9 @@
             case gl::State::DIRTY_BIT_SAMPLER_BINDINGS:
                 dirtyTextures = true;
                 break;
+            case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
+                WARN() << "DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING unimplemented";
+                break;
             case gl::State::DIRTY_BIT_MULTISAMPLING:
                 WARN() << "DIRTY_BIT_MULTISAMPLING unimplemented";
                 break;