Don't always sync all dirty object state on update.

This leads to a problem where we're synching objects out of order. For
instance, when we call SetImage, we need to sync the pack state. But
SetImage can affect the FBO state, so we need to sync the FBO only
after we've finished with SetImage.

Fix this by using a mask of dirty objects to sync instead of all of
them, always. This also has the side effect of deferring some syncs
that don't have to be processed immediately.

BUG=angleproject:1260

Change-Id: I5678d8f967930d11b42a4309d209215be2bae963
Reviewed-on: https://chromium-review.googlesource.com/327259
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 394502e..5aad808 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -217,6 +217,42 @@
     }
 
     mCompiler = new Compiler(mRenderer, getData());
+
+    // Initialize dirty bit masks
+    // TODO(jmadill): additional ES3 state
+    mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_ALIGNMENT);
+    mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_ROW_LENGTH);
+    mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_IMAGE_HEIGHT);
+    mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_SKIP_IMAGES);
+    mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_SKIP_ROWS);
+    mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_SKIP_PIXELS);
+    // No dirty objects.
+
+    // Readpixels uses the pack state and read FBO
+    mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_ALIGNMENT);
+    mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_REVERSE_ROW_ORDER);
+    mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_ROW_LENGTH);
+    mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_SKIP_ROWS);
+    mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_SKIP_PIXELS);
+    mReadPixelsDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER);
+
+    mClearDirtyBits.set(State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED);
+    mClearDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED);
+    mClearDirtyBits.set(State::DIRTY_BIT_SCISSOR);
+    mClearDirtyBits.set(State::DIRTY_BIT_VIEWPORT);
+    mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_COLOR);
+    mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_DEPTH);
+    mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_STENCIL);
+    mClearDirtyBits.set(State::DIRTY_BIT_COLOR_MASK);
+    mClearDirtyBits.set(State::DIRTY_BIT_DEPTH_MASK);
+    mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
+    mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_BACK);
+    mClearDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+
+    mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED);
+    mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR);
+    mBlitDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER);
+    mBlitDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);
 }
 
 Context::~Context()
@@ -2044,14 +2080,14 @@
     mState.syncDirtyObjects();
 }
 
-void Context::syncRendererState(const State::DirtyBits &bitMask)
+void Context::syncRendererState(const State::DirtyBits &bitMask,
+                                const State::DirtyObjects &objectMask)
 {
     const State::DirtyBits &dirtyBits = (mState.getDirtyBits() & bitMask);
     mRenderer->syncState(mState, dirtyBits);
     mState.clearDirtyBits(dirtyBits);
 
-    // TODO(jmadill): Filter objects by bitMask somehow?
-    mState.syncDirtyObjects();
+    mState.syncDirtyObjects(objectMask);
 }
 
 void Context::blitFramebuffer(GLint srcX0,
@@ -2074,7 +2110,7 @@
     Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0);
     Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
 
-    syncRendererState(mState.blitStateBitMask());
+    syncStateForBlit();
 
     Error error = drawFramebuffer->blit(mState, srcArea, dstArea, mask, filter, readFramebuffer);
     if (error.isError())
@@ -2086,8 +2122,7 @@
 
 void Context::clear(GLbitfield mask)
 {
-    // Sync the clear state
-    syncRendererState(mState.clearStateBitMask());
+    syncStateForClear();
 
     Error error = mState.getDrawFramebuffer()->clear(mData, mask);
     if (error.isError())
@@ -2098,8 +2133,7 @@
 
 void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values)
 {
-    // Sync the clear state
-    syncRendererState(mState.clearStateBitMask());
+    syncStateForClear();
 
     Error error = mState.getDrawFramebuffer()->clearBufferfv(mData, buffer, drawbuffer, values);
     if (error.isError())
@@ -2110,8 +2144,7 @@
 
 void Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values)
 {
-    // Sync the clear state
-    syncRendererState(mState.clearStateBitMask());
+    syncStateForClear();
 
     Error error = mState.getDrawFramebuffer()->clearBufferuiv(mData, buffer, drawbuffer, values);
     if (error.isError())
@@ -2122,8 +2155,7 @@
 
 void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values)
 {
-    // Sync the clear state
-    syncRendererState(mState.clearStateBitMask());
+    syncStateForClear();
 
     Error error = mState.getDrawFramebuffer()->clearBufferiv(mData, buffer, drawbuffer, values);
     if (error.isError())
@@ -2144,8 +2176,7 @@
         return;
     }
 
-    // Sync the clear state
-    syncRendererState(mState.clearStateBitMask());
+    syncStateForClear();
 
     Error error = framebufferObject->clearBufferfi(mData, buffer, drawbuffer, depth, stencil);
     if (error.isError())
@@ -2162,8 +2193,7 @@
                          GLenum type,
                          GLvoid *pixels)
 {
-    // Sync pack state
-    syncRendererState(mState.packStateBitMask());
+    syncStateForReadPixels();
 
     Framebuffer *framebufferObject = mState.getReadFramebuffer();
     ASSERT(framebufferObject);
@@ -2431,8 +2461,7 @@
                          GLenum type,
                          const GLvoid *pixels)
 {
-    // Sync the unpack state
-    syncRendererState(mState.unpackStateBitMask());
+    syncStateForTexImage();
 
     Extents size(width, height, 1);
     Texture *texture =
@@ -2456,8 +2485,7 @@
                          GLenum type,
                          const GLvoid *pixels)
 {
-    // Sync the unpack state
-    syncRendererState(mState.unpackStateBitMask());
+    syncStateForTexImage();
 
     Extents size(width, height, depth);
     Texture *texture = getTargetTexture(target);
@@ -2485,8 +2513,7 @@
         return;
     }
 
-    // Sync the unpack state
-    syncRendererState(mState.unpackStateBitMask());
+    syncStateForTexImage();
 
     Box area(xoffset, yoffset, 0, width, height, 1);
     Texture *texture =
@@ -2517,8 +2544,7 @@
         return;
     }
 
-    // Sync the unpack state
-    syncRendererState(mState.unpackStateBitMask());
+    syncStateForTexImage();
 
     Box area(xoffset, yoffset, zoffset, width, height, depth);
     Texture *texture = getTargetTexture(target);
@@ -2539,8 +2565,7 @@
                                    GLsizei imageSize,
                                    const GLvoid *data)
 {
-    // Sync the unpack state
-    syncRendererState(mState.unpackStateBitMask());
+    syncStateForTexImage();
 
     Extents size(width, height, 1);
     Texture *texture =
@@ -2564,8 +2589,7 @@
                                    GLsizei imageSize,
                                    const GLvoid *data)
 {
-    // Sync the unpack state
-    syncRendererState(mState.unpackStateBitMask());
+    syncStateForTexImage();
 
     Extents size(width, height, depth);
     Texture *texture = getTargetTexture(target);
@@ -2588,8 +2612,7 @@
                                       GLsizei imageSize,
                                       const GLvoid *data)
 {
-    // Sync the unpack state
-    syncRendererState(mState.unpackStateBitMask());
+    syncStateForTexImage();
 
     Box area(xoffset, yoffset, 0, width, height, 1);
     Texture *texture =
@@ -2621,8 +2644,7 @@
         return;
     }
 
-    // Sync the unpack state
-    syncRendererState(mState.unpackStateBitMask());
+    syncStateForTexImage();
 
     Box area(xoffset, yoffset, zoffset, width, height, depth);
     Texture *texture = getTargetTexture(target);
@@ -2635,4 +2657,24 @@
     }
 }
 
+void Context::syncStateForReadPixels()
+{
+    syncRendererState(mReadPixelsDirtyBits, mReadPixelsDirtyObjects);
+}
+
+void Context::syncStateForTexImage()
+{
+    syncRendererState(mTexImageDirtyBits, mTexImageDirtyObjects);
+}
+
+void Context::syncStateForClear()
+{
+    syncRendererState(mClearDirtyBits, mClearDirtyObjects);
+}
+
+void Context::syncStateForBlit()
+{
+    syncRendererState(mBlitDirtyBits, mBlitDirtyObjects);
+}
+
 }  // namespace gl
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index 6a81784..f283039 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -390,10 +390,13 @@
 
     State &getState() { return mState; }
 
-    void syncRendererState();
-    void syncRendererState(const State::DirtyBits &bitMask);
-
   private:
+    void syncRendererState();
+    void syncRendererState(const State::DirtyBits &bitMask, const State::DirtyObjects &objectMask);
+    void syncStateForReadPixels();
+    void syncStateForTexImage();
+    void syncStateForClear();
+    void syncStateForBlit();
     void checkVertexArrayAllocation(GLuint vertexArray);
     void checkTransformFeedbackAllocation(GLuint transformFeedback);
     Framebuffer *checkFramebufferAllocation(GLuint framebufferHandle);
@@ -467,6 +470,15 @@
     egl::Surface *mCurrentSurface;
 
     ResourceManager *mResourceManager;
+
+    State::DirtyBits mTexImageDirtyBits;
+    State::DirtyObjects mTexImageDirtyObjects;
+    State::DirtyBits mReadPixelsDirtyBits;
+    State::DirtyObjects mReadPixelsDirtyObjects;
+    State::DirtyBits mClearDirtyBits;
+    State::DirtyObjects mClearDirtyObjects;
+    State::DirtyBits mBlitDirtyBits;
+    State::DirtyObjects mBlitDirtyObjects;
 };
 
 }  // namespace gl
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index a1437b8..abd4558 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -44,35 +44,6 @@
       mActiveSampler(0),
       mPrimitiveRestart(false)
 {
-    // Initialize dirty bit masks
-    // TODO(jmadill): additional ES3 state
-    mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ALIGNMENT);
-    mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ROW_LENGTH);
-    mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_IMAGE_HEIGHT);
-    mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_IMAGES);
-    mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_ROWS);
-    mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_PIXELS);
-
-    mPackStateBitMask.set(DIRTY_BIT_PACK_ALIGNMENT);
-    mPackStateBitMask.set(DIRTY_BIT_PACK_REVERSE_ROW_ORDER);
-    mPackStateBitMask.set(DIRTY_BIT_PACK_ROW_LENGTH);
-    mPackStateBitMask.set(DIRTY_BIT_PACK_SKIP_ROWS);
-    mPackStateBitMask.set(DIRTY_BIT_PACK_SKIP_PIXELS);
-
-    mClearStateBitMask.set(DIRTY_BIT_RASTERIZER_DISCARD_ENABLED);
-    mClearStateBitMask.set(DIRTY_BIT_SCISSOR_TEST_ENABLED);
-    mClearStateBitMask.set(DIRTY_BIT_SCISSOR);
-    mClearStateBitMask.set(DIRTY_BIT_VIEWPORT);
-    mClearStateBitMask.set(DIRTY_BIT_CLEAR_COLOR);
-    mClearStateBitMask.set(DIRTY_BIT_CLEAR_DEPTH);
-    mClearStateBitMask.set(DIRTY_BIT_CLEAR_STENCIL);
-    mClearStateBitMask.set(DIRTY_BIT_COLOR_MASK);
-    mClearStateBitMask.set(DIRTY_BIT_DEPTH_MASK);
-    mClearStateBitMask.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
-    mClearStateBitMask.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
-
-    mBlitStateBitMask.set(DIRTY_BIT_SCISSOR_TEST_ENABLED);
-    mBlitStateBitMask.set(DIRTY_BIT_SCISSOR);
 }
 
 State::~State()
diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h
index e822d7e..4656432 100644
--- a/src/libANGLE/State.h
+++ b/src/libANGLE/State.h
@@ -364,12 +364,6 @@
     void syncDirtyObject(GLenum target);
     void setObjectDirty(GLenum target);
 
-    // Dirty bit masks
-    const DirtyBits &unpackStateBitMask() const { return mUnpackStateBitMask; }
-    const DirtyBits &packStateBitMask() const { return mPackStateBitMask; }
-    const DirtyBits &clearStateBitMask() const { return mClearStateBitMask; }
-    const DirtyBits &blitStateBitMask() const { return mBlitStateBitMask; }
-
   private:
     // Cached values from Context's caps
     GLuint mMaxDrawBuffers;
@@ -442,15 +436,10 @@
     Debug mDebug;
 
     DirtyBits mDirtyBits;
-    DirtyBits mUnpackStateBitMask;
-    DirtyBits mPackStateBitMask;
-    DirtyBits mClearStateBitMask;
-    DirtyBits mBlitStateBitMask;
-
     DirtyObjects mDirtyObjects;
 };
 
-}
+}  // namespace gl
 
 #endif // LIBANGLE_STATE_H_