Implement dirty bits for RendererGL's basic state.

BUG=angleproject:1040
TEST=angle_end2end_tests,angle_perftests,WebGL

Change-Id: I72beaf7e178e042440337fbb8b9669638c5ad016
Reviewed-on: https://chromium-review.googlesource.com/289558
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 2a24990..3923a2e 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -186,6 +186,9 @@
         mHasBeenCurrent = true;
     }
 
+    // TODO(jmadill): Rework this when we support ContextImpl
+    mState.setAllDirtyBits();
+
     // Update default framebuffer
     Framebuffer *defaultFBO = mFramebufferMap[0];
 
@@ -1237,6 +1240,7 @@
 
 Error Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances)
 {
+    syncRendererState();
     Error error = mRenderer->drawArrays(getData(), mode, first, count, instances);
     if (error.isError())
     {
@@ -1263,6 +1267,7 @@
                             const GLvoid *indices, GLsizei instances,
                             const RangeUI &indexRange)
 {
+    syncRendererState();
     return mRenderer->drawElements(getData(), mode, count, type, indices, instances, indexRange);
 }
 
@@ -1661,4 +1666,23 @@
     }
 }
 
+void Context::syncRendererState()
+{
+    const State::DirtyBits &dirtyBits = mState.getDirtyBits();
+    if (dirtyBits.any())
+    {
+        mRenderer->syncState(mState, dirtyBits);
+        mState.clearDirtyBits();
+    }
+}
+
+void Context::syncRendererState(const State::DirtyBits &bitMask)
+{
+    const State::DirtyBits &dirtyBits = (mState.getDirtyBits() & bitMask);
+    if (dirtyBits.any())
+    {
+        mRenderer->syncState(mState, dirtyBits);
+        mState.clearDirtyBits(dirtyBits);
+    }
+}
 }
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index 367a922..6ad3b78 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -204,6 +204,8 @@
     const State &getState() const { return mState; }
 
     const Data &getData() const { return mData; }
+    void syncRendererState();
+    void syncRendererState(const State::DirtyBits &bitMask);
 
   private:
     void detachBuffer(GLuint buffer);
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index 07c40f6..398c980 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -511,29 +511,57 @@
     return mImpl->invalidateSub(count, attachments, area);
 }
 
-Error Framebuffer::clear(const gl::Data &data, GLbitfield mask)
+Error Framebuffer::clear(Context *context, GLbitfield mask)
 {
-    return mImpl->clear(data, mask);
+    // Sync the clear state
+    context->syncRendererState(context->getState().clearStateBitMask());
+
+    return mImpl->clear(context->getData(), mask);
 }
 
-Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
+Error Framebuffer::clearBufferfv(Context *context,
+                                 GLenum buffer,
+                                 GLint drawbuffer,
+                                 const GLfloat *values)
 {
-    return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
+    // Sync the clear state
+    context->syncRendererState(context->getState().clearStateBitMask());
+
+    return mImpl->clearBufferfv(context->getState(), buffer, drawbuffer, values);
 }
 
-Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
+Error Framebuffer::clearBufferuiv(Context *context,
+                                  GLenum buffer,
+                                  GLint drawbuffer,
+                                  const GLuint *values)
 {
-    return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
+    // Sync the clear state
+    context->syncRendererState(context->getState().clearStateBitMask());
+
+    return mImpl->clearBufferuiv(context->getState(), buffer, drawbuffer, values);
 }
 
-Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
+Error Framebuffer::clearBufferiv(Context *context,
+                                 GLenum buffer,
+                                 GLint drawbuffer,
+                                 const GLint *values)
 {
-    return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
+    // Sync the clear state
+    context->syncRendererState(context->getState().clearStateBitMask());
+
+    return mImpl->clearBufferiv(context->getState(), buffer, drawbuffer, values);
 }
 
-Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+Error Framebuffer::clearBufferfi(Context *context,
+                                 GLenum buffer,
+                                 GLint drawbuffer,
+                                 GLfloat depth,
+                                 GLint stencil)
 {
-    return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
+    // Sync the clear state
+    context->syncRendererState(context->getState().clearStateBitMask());
+
+    return mImpl->clearBufferfi(context->getState(), buffer, drawbuffer, depth, stencil);
 }
 
 GLenum Framebuffer::getImplementationColorReadFormat() const
@@ -546,8 +574,17 @@
     return mImpl->getImplementationColorReadType();
 }
 
-Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
+Error Framebuffer::readPixels(Context *context,
+                              const gl::Rectangle &area,
+                              GLenum format,
+                              GLenum type,
+                              GLvoid *pixels) const
 {
+    const State &state = context->getState();
+
+    // Sync pack state
+    context->syncRendererState(state.packStateBitMask());
+
     Error error = mImpl->readPixels(state, area, format, type, pixels);
     if (error.isError())
     {
diff --git a/src/libANGLE/Framebuffer.h b/src/libANGLE/Framebuffer.h
index 428789c..3b132a3 100644
--- a/src/libANGLE/Framebuffer.h
+++ b/src/libANGLE/Framebuffer.h
@@ -32,6 +32,7 @@
 
 namespace gl
 {
+class Context;
 class Renderbuffer;
 class State;
 class Texture;
@@ -121,15 +122,23 @@
     Error invalidate(size_t count, const GLenum *attachments);
     Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area);
 
-    Error clear(const gl::Data &data, GLbitfield mask);
-    Error clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values);
-    Error clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values);
-    Error clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values);
-    Error clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+    Error clear(Context *context, GLbitfield mask);
+    Error clearBufferfv(Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values);
+    Error clearBufferuiv(Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values);
+    Error clearBufferiv(Context *context, GLenum buffer, GLint drawbuffer, const GLint *values);
+    Error clearBufferfi(Context *context,
+                        GLenum buffer,
+                        GLint drawbuffer,
+                        GLfloat depth,
+                        GLint stencil);
 
     GLenum getImplementationColorReadFormat() const;
     GLenum getImplementationColorReadType() const;
-    Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const;
+    Error readPixels(Context *context,
+                     const gl::Rectangle &area,
+                     GLenum format,
+                     GLenum type,
+                     GLvoid *pixels) const;
 
     Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
                GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer);
diff --git a/src/libANGLE/Image_unittest.cpp b/src/libANGLE/Image_unittest.cpp
index 45614cd..c9de26f 100644
--- a/src/libANGLE/Image_unittest.cpp
+++ b/src/libANGLE/Image_unittest.cpp
@@ -90,8 +90,8 @@
     EXPECT_CALL(*textureImpl, setImage(_, _, _, _, _, _, _, _))
         .WillOnce(Return(gl::Error(GL_NO_ERROR)))
         .RetiresOnSaturation();
-    texture->setImage(GL_TEXTURE_2D, 0, GL_RGBA8, gl::Extents(1, 1, 1), GL_RGBA, GL_UNSIGNED_BYTE,
-                      gl::PixelUnpackState(), nullptr);
+    texture->setImage(nullptr, GL_TEXTURE_2D, 0, GL_RGBA8, gl::Extents(1, 1, 1), GL_RGBA,
+                      GL_UNSIGNED_BYTE, nullptr);
 
     rx::MockImageImpl *imageImpl = new rx::MockImageImpl();
     egl::Image *image = new egl::Image(imageImpl, EGL_GL_TEXTURE_2D, texture, egl::AttributeMap());
@@ -110,8 +110,8 @@
         .WillOnce(Return(gl::Error(GL_NO_ERROR)))
         .RetiresOnSaturation();
 
-    texture->setImage(GL_TEXTURE_2D, 0, GL_RGBA8, gl::Extents(1, 1, 1), GL_RGBA, GL_UNSIGNED_BYTE,
-                      gl::PixelUnpackState(), nullptr);
+    texture->setImage(nullptr, GL_TEXTURE_2D, 0, GL_RGBA8, gl::Extents(1, 1, 1), GL_RGBA,
+                      GL_UNSIGNED_BYTE, nullptr);
 
     EXPECT_EQ(texture->getRefCount(), 1u);
     EXPECT_EQ(image->getRefCount(), 1u);
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index 6790356..3e8ec36 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -23,6 +23,24 @@
 {
     mMaxDrawBuffers = 0;
     mMaxCombinedTextureImageUnits = 0;
+
+    // Initialize dirty bit masks
+    // TODO(jmadill): additional ES3 state
+    mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ALIGNMENT);
+    mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ROW_LENGTH);
+    mPackStateBitMask.set(DIRTY_BIT_PACK_ALIGNMENT);
+    mPackStateBitMask.set(DIRTY_BIT_PACK_REVERSE_ROW_ORDER);
+    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);
 }
 
 State::~State()
@@ -183,6 +201,9 @@
     mUnpack.pixelBuffer.set(NULL);
 
     mProgram = NULL;
+
+    // TODO(jmadill): Is this necessary?
+    setAllDirtyBits();
 }
 
 const RasterizerState &State::getRasterizerState() const
@@ -206,16 +227,19 @@
     mColorClearValue.green = green;
     mColorClearValue.blue = blue;
     mColorClearValue.alpha = alpha;
+    mDirtyBits.set(DIRTY_BIT_CLEAR_COLOR);
 }
 
 void State::setDepthClearValue(float depth)
 {
     mDepthClearValue = depth;
+    mDirtyBits.set(DIRTY_BIT_CLEAR_DEPTH);
 }
 
 void State::setStencilClearValue(int stencil)
 {
     mStencilClearValue = stencil;
+    mDirtyBits.set(DIRTY_BIT_CLEAR_STENCIL);
 }
 
 void State::setColorMask(bool red, bool green, bool blue, bool alpha)
@@ -224,11 +248,13 @@
     mBlend.colorMaskGreen = green;
     mBlend.colorMaskBlue = blue;
     mBlend.colorMaskAlpha = alpha;
+    mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
 }
 
 void State::setDepthMask(bool mask)
 {
     mDepthStencil.depthMask = mask;
+    mDirtyBits.set(DIRTY_BIT_DEPTH_MASK);
 }
 
 bool State::isRasterizerDiscardEnabled() const
@@ -239,6 +265,7 @@
 void State::setRasterizerDiscard(bool enabled)
 {
     mRasterizer.rasterizerDiscard = enabled;
+    mDirtyBits.set(DIRTY_BIT_RASTERIZER_DISCARD_ENABLED);
 }
 
 bool State::isCullFaceEnabled() const
@@ -249,16 +276,19 @@
 void State::setCullFace(bool enabled)
 {
     mRasterizer.cullFace = enabled;
+    mDirtyBits.set(DIRTY_BIT_CULL_FACE_ENABLED);
 }
 
 void State::setCullMode(GLenum mode)
 {
     mRasterizer.cullMode = mode;
+    mDirtyBits.set(DIRTY_BIT_CULL_FACE);
 }
 
 void State::setFrontFace(GLenum front)
 {
     mRasterizer.frontFace = front;
+    mDirtyBits.set(DIRTY_BIT_FRONT_FACE);
 }
 
 bool State::isDepthTestEnabled() const
@@ -269,17 +299,20 @@
 void State::setDepthTest(bool enabled)
 {
     mDepthStencil.depthTest = enabled;
+    mDirtyBits.set(DIRTY_BIT_DEPTH_TEST_ENABLED);
 }
 
 void State::setDepthFunc(GLenum depthFunc)
 {
      mDepthStencil.depthFunc = depthFunc;
+     mDirtyBits.set(DIRTY_BIT_DEPTH_FUNC);
 }
 
 void State::setDepthRange(float zNear, float zFar)
 {
     mNearZ = zNear;
     mFarZ = zFar;
+    mDirtyBits.set(DIRTY_BIT_DEPTH_RANGE);
 }
 
 float State::getNearPlane() const
@@ -300,6 +333,7 @@
 void State::setBlend(bool enabled)
 {
     mBlend.blend = enabled;
+    mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
 }
 
 void State::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha)
@@ -308,6 +342,7 @@
     mBlend.destBlendRGB = destRGB;
     mBlend.sourceBlendAlpha = sourceAlpha;
     mBlend.destBlendAlpha = destAlpha;
+    mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS);
 }
 
 void State::setBlendColor(float red, float green, float blue, float alpha)
@@ -316,12 +351,14 @@
     mBlendColor.green = green;
     mBlendColor.blue = blue;
     mBlendColor.alpha = alpha;
+    mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
 }
 
 void State::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation)
 {
     mBlend.blendEquationRGB = rgbEquation;
     mBlend.blendEquationAlpha = alphaEquation;
+    mDirtyBits.set(DIRTY_BIT_BLEND_EQUATIONS);
 }
 
 const ColorF &State::getBlendColor() const
@@ -337,6 +374,7 @@
 void State::setStencilTest(bool enabled)
 {
     mDepthStencil.stencilTest = enabled;
+    mDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED);
 }
 
 void State::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask)
@@ -344,6 +382,7 @@
     mDepthStencil.stencilFunc = stencilFunc;
     mStencilRef = (stencilRef > 0) ? stencilRef : 0;
     mDepthStencil.stencilMask = stencilMask;
+    mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
 }
 
 void State::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask)
@@ -351,16 +390,19 @@
     mDepthStencil.stencilBackFunc = stencilBackFunc;
     mStencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0;
     mDepthStencil.stencilBackMask = stencilBackMask;
+    mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
 }
 
 void State::setStencilWritemask(GLuint stencilWritemask)
 {
     mDepthStencil.stencilWritemask = stencilWritemask;
+    mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
 }
 
 void State::setStencilBackWritemask(GLuint stencilBackWritemask)
 {
     mDepthStencil.stencilBackWritemask = stencilBackWritemask;
+    mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
 }
 
 void State::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass)
@@ -368,6 +410,7 @@
     mDepthStencil.stencilFail = stencilFail;
     mDepthStencil.stencilPassDepthFail = stencilPassDepthFail;
     mDepthStencil.stencilPassDepthPass = stencilPassDepthPass;
+    mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
 }
 
 void State::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass)
@@ -375,6 +418,7 @@
     mDepthStencil.stencilBackFail = stencilBackFail;
     mDepthStencil.stencilBackPassDepthFail = stencilBackPassDepthFail;
     mDepthStencil.stencilBackPassDepthPass = stencilBackPassDepthPass;
+    mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
 }
 
 GLint State::getStencilRef() const
@@ -394,7 +438,8 @@
 
 void State::setPolygonOffsetFill(bool enabled)
 {
-     mRasterizer.polygonOffsetFill = enabled;
+    mRasterizer.polygonOffsetFill = enabled;
+    mDirtyBits.set(DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED);
 }
 
 void State::setPolygonOffsetParams(GLfloat factor, GLfloat units)
@@ -402,6 +447,7 @@
     // An application can pass NaN values here, so handle this gracefully
     mRasterizer.polygonOffsetFactor = factor != factor ? 0.0f : factor;
     mRasterizer.polygonOffsetUnits = units != units ? 0.0f : units;
+    mDirtyBits.set(DIRTY_BIT_POLYGON_OFFSET);
 }
 
 bool State::isSampleAlphaToCoverageEnabled() const
@@ -412,6 +458,7 @@
 void State::setSampleAlphaToCoverage(bool enabled)
 {
     mBlend.sampleAlphaToCoverage = enabled;
+    mDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED);
 }
 
 bool State::isSampleCoverageEnabled() const
@@ -422,12 +469,14 @@
 void State::setSampleCoverage(bool enabled)
 {
     mSampleCoverage = enabled;
+    mDirtyBits.set(DIRTY_BIT_SAMPLE_COVERAGE_ENABLED);
 }
 
 void State::setSampleCoverageParams(GLclampf value, bool invert)
 {
     mSampleCoverageValue = value;
     mSampleCoverageInvert = invert;
+    mDirtyBits.set(DIRTY_BIT_SAMPLE_COVERAGE);
 }
 
 GLclampf State::getSampleCoverageValue() const
@@ -448,6 +497,7 @@
 void State::setScissorTest(bool enabled)
 {
     mScissorTest = enabled;
+    mDirtyBits.set(DIRTY_BIT_SCISSOR_TEST_ENABLED);
 }
 
 void State::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height)
@@ -456,6 +506,7 @@
     mScissor.y = y;
     mScissor.width = width;
     mScissor.height = height;
+    mDirtyBits.set(DIRTY_BIT_SCISSOR);
 }
 
 const Rectangle &State::getScissor() const
@@ -471,6 +522,7 @@
 void State::setDither(bool enabled)
 {
     mBlend.dither = enabled;
+    mDirtyBits.set(DIRTY_BIT_DITHER_ENABLED);
 }
 
 bool State::isPrimitiveRestartEnabled() const
@@ -481,6 +533,7 @@
 void State::setPrimitiveRestart(bool enabled)
 {
     mPrimitiveRestart = enabled;
+    mDirtyBits.set(DIRTY_BIT_PRIMITIVE_RESTART_ENABLED);
 }
 
 void State::setEnableFeature(GLenum feature, bool enabled)
@@ -524,6 +577,7 @@
 void State::setLineWidth(GLfloat width)
 {
     mLineWidth = width;
+    mDirtyBits.set(DIRTY_BIT_LINE_WIDTH);
 }
 
 float State::getLineWidth() const
@@ -534,11 +588,13 @@
 void State::setGenerateMipmapHint(GLenum hint)
 {
     mGenerateMipmapHint = hint;
+    mDirtyBits.set(DIRTY_BIT_GENERATE_MIPMAP_HINT);
 }
 
 void State::setFragmentShaderDerivativeHint(GLenum hint)
 {
     mFragmentShaderDerivativeHint = hint;
+    mDirtyBits.set(DIRTY_BIT_SHADER_DERIVATIVE_HINT);
     // TODO: Propagate the hint to shader translator so we can write
     // ddx, ddx_coarse, or ddx_fine depending on the hint.
     // Ignore for now. It is valid for implementations to ignore hint.
@@ -550,6 +606,7 @@
     mViewport.y = y;
     mViewport.width = width;
     mViewport.height = height;
+    mDirtyBits.set(DIRTY_BIT_VIEWPORT);
 }
 
 const Rectangle &State::getViewport() const
@@ -1034,6 +1091,7 @@
 void State::setPackAlignment(GLint alignment)
 {
     mPack.alignment = alignment;
+    mDirtyBits.set(DIRTY_BIT_PACK_ALIGNMENT);
 }
 
 GLint State::getPackAlignment() const
@@ -1044,6 +1102,7 @@
 void State::setPackReverseRowOrder(bool reverseRowOrder)
 {
     mPack.reverseRowOrder = reverseRowOrder;
+    mDirtyBits.set(DIRTY_BIT_PACK_REVERSE_ROW_ORDER);
 }
 
 bool State::getPackReverseRowOrder() const
@@ -1064,6 +1123,7 @@
 void State::setUnpackAlignment(GLint alignment)
 {
     mUnpack.alignment = alignment;
+    mDirtyBits.set(DIRTY_BIT_UNPACK_ALIGNMENT);
 }
 
 GLint State::getUnpackAlignment() const
@@ -1074,6 +1134,7 @@
 void State::setUnpackRowLength(GLint rowLength)
 {
     mUnpack.rowLength = rowLength;
+    mDirtyBits.set(DIRTY_BIT_UNPACK_ROW_LENGTH);
 }
 
 GLint State::getUnpackRowLength() const
diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h
index 90e757d..dad3b6e 100644
--- a/src/libANGLE/State.h
+++ b/src/libANGLE/State.h
@@ -9,15 +9,17 @@
 #ifndef LIBANGLE_STATE_H_
 #define LIBANGLE_STATE_H_
 
+#include <bitset>
+
 #include "common/angleutils.h"
+#include "libANGLE/Program.h"
 #include "libANGLE/RefCountObject.h"
-#include "libANGLE/angletypes.h"
-#include "libANGLE/VertexAttribute.h"
 #include "libANGLE/Renderbuffer.h"
+#include "libANGLE/Sampler.h"
 #include "libANGLE/Texture.h"
 #include "libANGLE/TransformFeedback.h"
-#include "libANGLE/Program.h"
-#include "libANGLE/Sampler.h"
+#include "libANGLE/VertexAttribute.h"
+#include "libANGLE/angletypes.h"
 
 namespace gl
 {
@@ -252,6 +254,73 @@
 
     bool hasMappedBuffer(GLenum target) const;
 
+    enum DirtyBitType
+    {
+        DIRTY_BIT_SCISSOR_TEST_ENABLED,
+        DIRTY_BIT_SCISSOR,
+        DIRTY_BIT_VIEWPORT,
+        DIRTY_BIT_DEPTH_RANGE,
+        DIRTY_BIT_BLEND_ENABLED,
+        DIRTY_BIT_BLEND_COLOR,
+        DIRTY_BIT_BLEND_FUNCS,
+        DIRTY_BIT_BLEND_EQUATIONS,
+        DIRTY_BIT_COLOR_MASK,
+        DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED,
+        DIRTY_BIT_SAMPLE_COVERAGE_ENABLED,
+        DIRTY_BIT_SAMPLE_COVERAGE,
+        DIRTY_BIT_DEPTH_TEST_ENABLED,
+        DIRTY_BIT_DEPTH_FUNC,
+        DIRTY_BIT_DEPTH_MASK,
+        DIRTY_BIT_STENCIL_TEST_ENABLED,
+        DIRTY_BIT_STENCIL_FUNCS_FRONT,
+        DIRTY_BIT_STENCIL_FUNCS_BACK,
+        DIRTY_BIT_STENCIL_OPS_FRONT,
+        DIRTY_BIT_STENCIL_OPS_BACK,
+        DIRTY_BIT_STENCIL_WRITEMASK_FRONT,
+        DIRTY_BIT_STENCIL_WRITEMASK_BACK,
+        DIRTY_BIT_CULL_FACE_ENABLED,
+        DIRTY_BIT_CULL_FACE,
+        DIRTY_BIT_FRONT_FACE,
+        DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED,
+        DIRTY_BIT_POLYGON_OFFSET,
+        DIRTY_BIT_MULTISAMPLE_ENABLED,
+        DIRTY_BIT_RASTERIZER_DISCARD_ENABLED,
+        DIRTY_BIT_LINE_WIDTH,
+        DIRTY_BIT_PRIMITIVE_RESTART_ENABLED,
+        DIRTY_BIT_CLEAR_COLOR,
+        DIRTY_BIT_CLEAR_DEPTH,
+        DIRTY_BIT_CLEAR_STENCIL,
+        DIRTY_BIT_UNPACK_ALIGNMENT,
+        DIRTY_BIT_UNPACK_ROW_LENGTH,
+        DIRTY_BIT_PACK_ALIGNMENT,
+        DIRTY_BIT_PACK_REVERSE_ROW_ORDER,
+        DIRTY_BIT_DITHER_ENABLED,
+        DIRTY_BIT_GENERATE_MIPMAP_HINT,
+        DIRTY_BIT_SHADER_DERIVATIVE_HINT,
+        DIRTY_BIT_READ_FRAMEBUFFER_BINDING,
+        DIRTY_BIT_READ_FRAMEBUFFER_OBJECT,
+        DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING,
+        DIRTY_BIT_DRAW_FRAMEBUFFER_OBJECT,
+        DIRTY_BIT_RENDERBUFFER_BINDING,
+        DIRTY_BIT_VERTEX_ARRAY_BINDING,
+        DIRTY_BIT_VERTEX_ARRAY_OBJECT,
+        DIRTY_BIT_PROGRAM_BINDING,
+        DIRTY_BIT_PROGRAM_OBJECT,
+        DIRTY_BIT_INVALID,
+        DIRTY_BIT_MAX = DIRTY_BIT_INVALID,
+    };
+
+    typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
+    const DirtyBits &getDirtyBits() const { return mDirtyBits; }
+    void clearDirtyBits() { mDirtyBits.reset(); }
+    void clearDirtyBits(const DirtyBits &bitset) { mDirtyBits &= ~bitset; }
+    void setAllDirtyBits() { mDirtyBits.set(); }
+
+    // Dirty bit masks
+    const DirtyBits &unpackStateBitMask() const { return mUnpackStateBitMask; }
+    const DirtyBits &packStateBitMask() const { return mPackStateBitMask; }
+    const DirtyBits &clearStateBitMask() const { return mClearStateBitMask; }
+
   private:
     // Cached values from Context's caps
     GLuint mMaxDrawBuffers;
@@ -320,6 +389,11 @@
     PixelPackState mPack;
 
     bool mPrimitiveRestart;
+
+    DirtyBits mDirtyBits;
+    DirtyBits mUnpackStateBitMask;
+    DirtyBits mPackStateBitMask;
+    DirtyBits mClearStateBitMask;
 };
 
 }
diff --git a/src/libANGLE/Texture.cpp b/src/libANGLE/Texture.cpp
index 2668478..f532797 100644
--- a/src/libANGLE/Texture.cpp
+++ b/src/libANGLE/Texture.cpp
@@ -11,6 +11,7 @@
 #include "common/mathutil.h"
 #include "common/utilities.h"
 #include "libANGLE/Config.h"
+#include "libANGLE/Context.h"
 #include "libANGLE/Data.h"
 #include "libANGLE/Image.h"
 #include "libANGLE/Surface.h"
@@ -189,8 +190,14 @@
     return mBoundSurface;
 }
 
-Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
-                        const PixelUnpackState &unpack, const uint8_t *pixels)
+Error Texture::setImage(Context *context,
+                        GLenum target,
+                        size_t level,
+                        GLenum internalFormat,
+                        const Extents &size,
+                        GLenum format,
+                        GLenum type,
+                        const uint8_t *pixels)
 {
     ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
 
@@ -198,6 +205,15 @@
     releaseTexImageInternal();
     orphanImages();
 
+    // Hack: allow nullptr for testing
+    if (context != nullptr)
+    {
+        // Sync the unpack state
+        context->syncRendererState(context->getState().unpackStateBitMask());
+    }
+
+    const PixelUnpackState &unpack =
+        context ? context->getState().getUnpackState() : PixelUnpackState();
     Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
     if (error.isError())
     {
@@ -209,16 +225,30 @@
     return Error(GL_NO_ERROR);
 }
 
-Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
-                           const PixelUnpackState &unpack, const uint8_t *pixels)
+Error Texture::setSubImage(Context *context,
+                           GLenum target,
+                           size_t level,
+                           const Box &area,
+                           GLenum format,
+                           GLenum type,
+                           const uint8_t *pixels)
 {
     ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
 
+    // Sync the unpack state
+    context->syncRendererState(context->getState().unpackStateBitMask());
+
+    const PixelUnpackState &unpack = context->getState().getUnpackState();
     return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
 }
 
-Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
-                                  const PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
+Error Texture::setCompressedImage(Context *context,
+                                  GLenum target,
+                                  size_t level,
+                                  GLenum internalFormat,
+                                  const Extents &size,
+                                  size_t imageSize,
+                                  const uint8_t *pixels)
 {
     ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
 
@@ -226,6 +256,10 @@
     releaseTexImageInternal();
     orphanImages();
 
+    // Sync the unpack state
+    context->syncRendererState(context->getState().unpackStateBitMask());
+
+    const PixelUnpackState &unpack = context->getState().getUnpackState();
     Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, imageSize, pixels);
     if (error.isError())
     {
@@ -237,11 +271,20 @@
     return Error(GL_NO_ERROR);
 }
 
-Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
-                                     const PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
+Error Texture::setCompressedSubImage(Context *context,
+                                     GLenum target,
+                                     size_t level,
+                                     const Box &area,
+                                     GLenum format,
+                                     size_t imageSize,
+                                     const uint8_t *pixels)
 {
     ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
 
+    // Sync the unpack state
+    context->syncRendererState(context->getState().unpackStateBitMask());
+
+    const PixelUnpackState &unpack = context->getState().getUnpackState();
     return mTexture->setCompressedSubImage(target, level, area, format, unpack, imageSize, pixels);
 }
 
diff --git a/src/libANGLE/Texture.h b/src/libANGLE/Texture.h
index 735b6d5..c01cf00 100644
--- a/src/libANGLE/Texture.h
+++ b/src/libANGLE/Texture.h
@@ -29,6 +29,7 @@
 
 namespace gl
 {
+class Context;
 class Framebuffer;
 struct Data;
 
@@ -38,8 +39,7 @@
 {
   public:
     Texture(rx::TextureImpl *impl, GLuint id, GLenum target);
-
-    virtual ~Texture();
+    ~Texture();
 
     GLenum getTarget() const;
 
@@ -59,26 +59,53 @@
     bool isCubeComplete() const;
     size_t getMipCompleteLevels() const;
 
-    virtual Error setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
-                           const PixelUnpackState &unpack, const uint8_t *pixels);
-    virtual Error setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
-                              const PixelUnpackState &unpack, const uint8_t *pixels);
+    Error setImage(Context *context,
+                   GLenum target,
+                   size_t level,
+                   GLenum internalFormat,
+                   const Extents &size,
+                   GLenum format,
+                   GLenum type,
+                   const uint8_t *pixels);
+    Error setSubImage(Context *context,
+                      GLenum target,
+                      size_t level,
+                      const Box &area,
+                      GLenum format,
+                      GLenum type,
+                      const uint8_t *pixels);
 
-    virtual Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
-                                     const PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels);
-    virtual Error setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
-                                        const PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels);
+    Error setCompressedImage(Context *context,
+                             GLenum target,
+                             size_t level,
+                             GLenum internalFormat,
+                             const Extents &size,
+                             size_t imageSize,
+                             const uint8_t *pixels);
+    Error setCompressedSubImage(Context *context,
+                                GLenum target,
+                                size_t level,
+                                const Box &area,
+                                GLenum format,
+                                size_t imageSize,
+                                const uint8_t *pixels);
 
-    virtual Error copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
-                            const Framebuffer *source);
-    virtual Error copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
-                              const Framebuffer *source);
+    Error copyImage(GLenum target,
+                    size_t level,
+                    const Rectangle &sourceArea,
+                    GLenum internalFormat,
+                    const Framebuffer *source);
+    Error copySubImage(GLenum target,
+                       size_t level,
+                       const Offset &destOffset,
+                       const Rectangle &sourceArea,
+                       const Framebuffer *source);
 
-    virtual Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size);
+    Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size);
 
     Error setEGLImageTarget(GLenum target, egl::Image *imageTarget);
 
-    virtual Error generateMipmaps();
+    Error generateMipmaps();
 
     bool isImmutable() const;
     GLsizei immutableLevelCount();
diff --git a/src/libANGLE/renderer/Renderer.h b/src/libANGLE/renderer/Renderer.h
index 6663455..ae12c42 100644
--- a/src/libANGLE/renderer/Renderer.h
+++ b/src/libANGLE/renderer/Renderer.h
@@ -13,6 +13,7 @@
 #include "libANGLE/Caps.h"
 #include "libANGLE/Error.h"
 #include "libANGLE/Framebuffer.h"
+#include "libANGLE/State.h"
 #include "libANGLE/Uniform.h"
 #include "libANGLE/angletypes.h"
 #include "libANGLE/renderer/ImplFactory.h"
@@ -29,12 +30,6 @@
 class Surface;
 }
 
-namespace gl
-{
-class Buffer;
-struct Data;
-}
-
 namespace rx
 {
 struct TranslatedIndexData;
@@ -72,6 +67,8 @@
     virtual void pushGroupMarker(GLsizei length, const char *marker) = 0;
     virtual void popGroupMarker() = 0;
 
+    virtual void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits) = 0;
+
     // Renderer capabilities
     const gl::Caps &getRendererCaps() const;
     const gl::TextureCapsMap &getRendererTextureCaps() const;
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/libANGLE/renderer/d3d/RendererD3D.cpp
index c5c949b..4c7ebb4 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.cpp
+++ b/src/libANGLE/renderer/d3d/RendererD3D.cpp
@@ -545,20 +545,26 @@
     {
         const GLubyte color[] = { 0, 0, 0, 255 };
         const gl::Extents colorSize(1, 1, 1);
-        const gl::PixelUnpackState incompleteUnpackState(1, 0);
+        const gl::PixelUnpackState unpack(1, 0);
+        const gl::Box area(0, 0, 0, 1, 1, 1);
 
-        gl::Texture* t = new gl::Texture(createTexture(type), std::numeric_limits<GLuint>::max(), type);
+        // Skip the API layer to avoid needing to pass the Context and mess with dirty bits.
+        gl::Texture *t =
+            new gl::Texture(createTexture(type), std::numeric_limits<GLuint>::max(), type);
+        t->setStorage(type, 1, GL_RGBA8, colorSize);
 
         if (type == GL_TEXTURE_CUBE_MAP)
         {
             for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
             {
-                t->setImage(face, 0, GL_RGBA, colorSize, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+                t->getImplementation()->setSubImage(face, 0, area, GL_RGBA8, GL_UNSIGNED_BYTE,
+                                                    unpack, color);
             }
         }
         else
         {
-            t->setImage(type, 0, GL_RGBA, colorSize, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+            t->getImplementation()->setSubImage(type, 0, area, GL_RGBA8, GL_UNSIGNED_BYTE, unpack,
+                                                color);
         }
 
         mIncompleteTextures[type].set(t);
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.h b/src/libANGLE/renderer/d3d/RendererD3D.h
index 441e8bc..2397efa 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -194,6 +194,11 @@
     virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget,
                                               GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) = 0;
 
+    void syncState(const gl::State & /*state*/, const gl::State::DirtyBits &bitmask) override
+    {
+        // TODO(jmadill): implement state sync for D3D renderers;
+    }
+
     // Device lost
     void notifyDeviceLost() override;
     virtual bool resetDevice() = 0;
diff --git a/src/libANGLE/renderer/gl/FramebufferGL.cpp b/src/libANGLE/renderer/gl/FramebufferGL.cpp
index 61f55eb..6c2101a 100644
--- a/src/libANGLE/renderer/gl/FramebufferGL.cpp
+++ b/src/libANGLE/renderer/gl/FramebufferGL.cpp
@@ -185,28 +185,14 @@
 
 gl::Error FramebufferGL::clear(const gl::Data &data, GLbitfield mask)
 {
-    mStateManager->setClearState(*data.state, mask);
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clear(mask);
 
     return gl::Error(GL_NO_ERROR);
 }
 
-static GLbitfield GetClearBufferMask(GLenum buffer)
-{
-    switch (buffer)
-    {
-      case GL_COLOR:          return GL_COLOR_BUFFER_BIT;
-      case GL_DEPTH:          return GL_DEPTH_BUFFER_BIT;
-      case GL_STENCIL:        return GL_STENCIL_BUFFER_BIT;
-      case GL_DEPTH_STENCIL:  return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
-      default: UNREACHABLE(); return 0;
-    }
-}
-
 gl::Error FramebufferGL::clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
 {
-    mStateManager->setClearState(state, GetClearBufferMask(buffer));
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clearBufferfv(buffer, drawbuffer, values);
 
@@ -215,7 +201,6 @@
 
 gl::Error FramebufferGL::clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
 {
-    mStateManager->setClearState(state, GetClearBufferMask(buffer));
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clearBufferuiv(buffer, drawbuffer, values);
 
@@ -224,7 +209,6 @@
 
 gl::Error FramebufferGL::clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
 {
-    mStateManager->setClearState(state, GetClearBufferMask(buffer));
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clearBufferiv(buffer, drawbuffer, values);
 
@@ -233,7 +217,6 @@
 
 gl::Error FramebufferGL::clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
 {
-    mStateManager->setClearState(state, GetClearBufferMask(buffer));
     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
     mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil);
 
@@ -263,7 +246,6 @@
     {
         UNIMPLEMENTED();
     }
-    mStateManager->setPixelPackState(packState.alignment, packState.rowLength, packState.skipRows, packState.skipPixels);
 
     mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferID);
     mFunctions->readPixels(area.x, area.y, area.width, area.height, format, type, pixels);
diff --git a/src/libANGLE/renderer/gl/RendererGL.cpp b/src/libANGLE/renderer/gl/RendererGL.cpp
index db8ed00..f4d6562 100644
--- a/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -324,4 +324,8 @@
     nativegl_gl::GenerateCaps(mFunctions, outCaps, outTextureCaps, outExtensions, &mMaxSupportedESVersion);
 }
 
+void RendererGL::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits)
+{
+    mStateManager->syncState(state, dirtyBits);
+}
 }
diff --git a/src/libANGLE/renderer/gl/RendererGL.h b/src/libANGLE/renderer/gl/RendererGL.h
index 55591ec..4687a7a 100644
--- a/src/libANGLE/renderer/gl/RendererGL.h
+++ b/src/libANGLE/renderer/gl/RendererGL.h
@@ -77,6 +77,8 @@
     std::string getVendorString() const override;
     std::string getRendererDescription() const override;
 
+    void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits) override;
+
     const gl::Version &getMaxSupportedESVersion() const;
 
   private:
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.cpp b/src/libANGLE/renderer/gl/StateManagerGL.cpp
index a45ab2d..87307cd 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.cpp
+++ b/src/libANGLE/renderer/gl/StateManagerGL.cpp
@@ -8,6 +8,7 @@
 
 #include "libANGLE/renderer/gl/StateManagerGL.h"
 
+#include "common/BitSetIterator.h"
 #include "libANGLE/Data.h"
 #include "libANGLE/Framebuffer.h"
 #include "libANGLE/VertexArray.h"
@@ -250,6 +251,17 @@
     }
 }
 
+void StateManagerGL::setPixelUnpackState(const gl::PixelUnpackState &unpack)
+{
+    const gl::Buffer *unpackBuffer = unpack.pixelBuffer.get();
+    if (unpackBuffer != nullptr)
+    {
+        UNIMPLEMENTED();
+    }
+    setPixelUnpackState(unpack.alignment, unpack.rowLength, unpack.skipRows, unpack.skipPixels,
+                        unpack.imageHeight, unpack.skipImages);
+}
+
 void StateManagerGL::setPixelUnpackState(GLint alignment, GLint rowLength, GLint skipRows, GLint skipPixels,
                                          GLint imageHeight, GLint skipImages)
 {
@@ -290,6 +302,16 @@
     }
 }
 
+void StateManagerGL::setPixelPackState(const gl::PixelPackState &pack)
+{
+    const gl::Buffer *packBuffer = pack.pixelBuffer.get();
+    if (packBuffer != nullptr)
+    {
+        UNIMPLEMENTED();
+    }
+    setPixelPackState(pack.alignment, pack.rowLength, pack.skipRows, pack.skipPixels);
+}
+
 void StateManagerGL::setPixelPackState(GLint alignment, GLint rowLength, GLint skipRows, GLint skipPixels)
 {
     if (mPackAlignment != alignment)
@@ -351,44 +373,6 @@
     }
 }
 
-void StateManagerGL::setClearState(const gl::State &state, GLbitfield mask)
-{
-    // Only apply the state required to do a clear
-    const gl::RasterizerState &rasterizerState = state.getRasterizerState();
-    setRasterizerDiscardEnabled(rasterizerState.rasterizerDiscard);
-    if (!rasterizerState.rasterizerDiscard)
-    {
-        setScissorTestEnabled(state.isScissorTestEnabled());
-        if (state.isScissorTestEnabled())
-        {
-            setScissor(state.getScissor());
-        }
-
-        setViewport(state.getViewport());
-
-        if ((mask & GL_COLOR_BUFFER_BIT) != 0)
-        {
-            setClearColor(state.getColorClearValue());
-
-            const gl::BlendState &blendState = state.getBlendState();
-            setColorMask(blendState.colorMaskRed, blendState.colorMaskGreen, blendState.colorMaskBlue, blendState.colorMaskAlpha);
-        }
-
-        if ((mask & GL_DEPTH_BUFFER_BIT) != 0)
-        {
-            setClearDepth(state.getDepthClearValue());
-            setDepthMask(state.getDepthStencilState().depthMask);
-        }
-
-        if ((mask & GL_STENCIL_BUFFER_BIT) != 0)
-        {
-            setClearStencil(state.getStencilClearValue());
-            setStencilFrontWritemask(state.getDepthStencilState().stencilWritemask);
-            setStencilBackWritemask(state.getDepthStencilState().stencilBackWritemask);
-        }
-    }
-}
-
 gl::Error StateManagerGL::setDrawArraysState(const gl::Data &data, GLint first, GLsizei count)
 {
     const gl::State &state = *data.state;
@@ -489,67 +473,6 @@
     const FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
     bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebufferGL->getFramebufferID());
 
-    setScissorTestEnabled(state.isScissorTestEnabled());
-    if (state.isScissorTestEnabled())
-    {
-        setScissor(state.getScissor());
-    }
-
-    setViewport(state.getViewport());
-    setDepthRange(state.getNearPlane(), state.getFarPlane());
-
-    const gl::BlendState &blendState = state.getBlendState();
-    setBlendEnabled(blendState.blend);
-    if (blendState.blend)
-    {
-        setBlendColor(state.getBlendColor());
-        setBlendFuncs(blendState.sourceBlendRGB, blendState.destBlendRGB, blendState.sourceBlendAlpha, blendState.destBlendAlpha);
-        setBlendEquations(blendState.blendEquationRGB, blendState.blendEquationAlpha);
-    }
-    setColorMask(blendState.colorMaskRed, blendState.colorMaskGreen, blendState.colorMaskBlue, blendState.colorMaskAlpha);
-    setSampleAlphaToCoverageEnabled(blendState.sampleAlphaToCoverage);
-    setSampleCoverageEnabled(state.isSampleCoverageEnabled());
-    setSampleCoverage(state.getSampleCoverageValue(), state.getSampleCoverageInvert());
-
-    const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
-    setDepthTestEnabled(depthStencilState.depthTest);
-    if (depthStencilState.depthTest)
-    {
-        setDepthFunc(depthStencilState.depthFunc);
-    }
-    setDepthMask(depthStencilState.depthMask);
-
-    setStencilTestEnabled(depthStencilState.stencilTest);
-    if (depthStencilState.stencilTest)
-    {
-        setStencilFrontFuncs(depthStencilState.stencilFunc, state.getStencilRef(), depthStencilState.stencilMask);
-        setStencilBackFuncs(depthStencilState.stencilBackFunc, state.getStencilBackRef(), depthStencilState.stencilBackMask);
-        setStencilFrontOps(depthStencilState.stencilFail, depthStencilState.stencilPassDepthFail, depthStencilState.stencilPassDepthPass);
-        setStencilBackOps(depthStencilState.stencilBackFail, depthStencilState.stencilBackPassDepthFail, depthStencilState.stencilBackPassDepthPass);
-    }
-    setStencilFrontWritemask(state.getDepthStencilState().stencilWritemask);
-    setStencilBackWritemask(state.getDepthStencilState().stencilBackWritemask);
-
-    const gl::RasterizerState &rasterizerState = state.getRasterizerState();
-    setCullFaceEnabled(rasterizerState.cullFace);
-    if (rasterizerState.cullFace)
-    {
-        setCullFace(rasterizerState.cullMode);
-    }
-    setFrontFace(rasterizerState.frontFace);
-
-    setPolygonOffsetFillEnabled(rasterizerState.polygonOffsetFill);
-    if (rasterizerState.polygonOffsetFill)
-    {
-        setPolygonOffset(rasterizerState.polygonOffsetFactor, rasterizerState.polygonOffsetUnits);
-    }
-
-    setMultisampleEnabled(rasterizerState.multiSample);
-    setRasterizerDiscardEnabled(rasterizerState.rasterizerDiscard);
-    setLineWidth(state.getLineWidth());
-
-    setPrimitiveRestartEnabled(state.isPrimitiveRestartEnabled());
-
     return gl::Error(GL_NO_ERROR);
 }
 
@@ -974,4 +897,203 @@
     }
 }
 
+void StateManagerGL::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits)
+{
+    for (unsigned int dirtyBit : angle::IterateBitSet(dirtyBits))
+    {
+        switch (dirtyBit)
+        {
+            case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
+                setScissorTestEnabled(state.isScissorTestEnabled());
+                break;
+            case gl::State::DIRTY_BIT_SCISSOR:
+                setScissor(state.getScissor());
+                break;
+            case gl::State::DIRTY_BIT_VIEWPORT:
+                setViewport(state.getViewport());
+                break;
+            case gl::State::DIRTY_BIT_DEPTH_RANGE:
+                setDepthRange(state.getNearPlane(), state.getFarPlane());
+                break;
+            case gl::State::DIRTY_BIT_BLEND_ENABLED:
+                setBlendEnabled(state.isBlendEnabled());
+                break;
+            case gl::State::DIRTY_BIT_BLEND_COLOR:
+                setBlendColor(state.getBlendColor());
+                break;
+            case gl::State::DIRTY_BIT_BLEND_FUNCS:
+            {
+                const auto &blendState = state.getBlendState();
+                setBlendFuncs(blendState.sourceBlendRGB, blendState.destBlendRGB,
+                              blendState.sourceBlendAlpha, blendState.destBlendAlpha);
+                break;
+            }
+            case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
+            {
+                const auto &blendState = state.getBlendState();
+                setBlendEquations(blendState.blendEquationRGB, blendState.blendEquationAlpha);
+                break;
+            }
+            case gl::State::DIRTY_BIT_COLOR_MASK:
+            {
+                const auto &blendState = state.getBlendState();
+                setColorMask(blendState.colorMaskRed, blendState.colorMaskGreen,
+                             blendState.colorMaskBlue, blendState.colorMaskAlpha);
+                break;
+            }
+            case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
+                setSampleAlphaToCoverageEnabled(state.isSampleAlphaToCoverageEnabled());
+                break;
+            case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED:
+                setSampleCoverageEnabled(state.isSampleCoverageEnabled());
+                break;
+            case gl::State::DIRTY_BIT_SAMPLE_COVERAGE:
+                setSampleCoverage(state.getSampleCoverageValue(), state.getSampleCoverageInvert());
+                break;
+            case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
+                setDepthTestEnabled(state.isDepthTestEnabled());
+                break;
+            case gl::State::DIRTY_BIT_DEPTH_FUNC:
+                setDepthFunc(state.getDepthStencilState().depthFunc);
+                break;
+            case gl::State::DIRTY_BIT_DEPTH_MASK:
+                setDepthMask(state.getDepthStencilState().depthMask);
+                break;
+            case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED:
+                setStencilTestEnabled(state.isStencilTestEnabled());
+                break;
+            case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT:
+            {
+                const auto &depthStencilState = state.getDepthStencilState();
+                setStencilFrontFuncs(depthStencilState.stencilFunc, state.getStencilRef(),
+                                     depthStencilState.stencilMask);
+                break;
+            }
+            case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK:
+            {
+                const auto &depthStencilState = state.getDepthStencilState();
+                setStencilBackFuncs(depthStencilState.stencilBackFunc, state.getStencilBackRef(),
+                                    depthStencilState.stencilBackMask);
+                break;
+            }
+            case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT:
+            {
+                const auto &depthStencilState = state.getDepthStencilState();
+                setStencilFrontOps(depthStencilState.stencilFail,
+                                   depthStencilState.stencilPassDepthFail,
+                                   depthStencilState.stencilPassDepthPass);
+                break;
+            }
+            case gl::State::DIRTY_BIT_STENCIL_OPS_BACK:
+            {
+                const auto &depthStencilState = state.getDepthStencilState();
+                setStencilBackOps(depthStencilState.stencilBackFail,
+                                  depthStencilState.stencilBackPassDepthFail,
+                                  depthStencilState.stencilBackPassDepthPass);
+                break;
+            }
+            case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
+                setStencilFrontWritemask(state.getDepthStencilState().stencilWritemask);
+                break;
+            case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
+                setStencilBackWritemask(state.getDepthStencilState().stencilBackWritemask);
+                break;
+            case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
+                setCullFaceEnabled(state.isCullFaceEnabled());
+                break;
+            case gl::State::DIRTY_BIT_CULL_FACE:
+                setCullFace(state.getRasterizerState().cullMode);
+                break;
+            case gl::State::DIRTY_BIT_FRONT_FACE:
+                setFrontFace(state.getRasterizerState().frontFace);
+                break;
+            case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
+                setPolygonOffsetFillEnabled(state.isPolygonOffsetFillEnabled());
+                break;
+            case gl::State::DIRTY_BIT_POLYGON_OFFSET:
+            {
+                const auto &rasterizerState = state.getRasterizerState();
+                setPolygonOffset(rasterizerState.polygonOffsetFactor,
+                                 rasterizerState.polygonOffsetUnits);
+                break;
+            }
+            case gl::State::DIRTY_BIT_MULTISAMPLE_ENABLED:
+                setMultisampleEnabled(state.getRasterizerState().multiSample);
+                break;
+            case gl::State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED:
+                setRasterizerDiscardEnabled(state.isRasterizerDiscardEnabled());
+                break;
+            case gl::State::DIRTY_BIT_LINE_WIDTH:
+                setLineWidth(state.getLineWidth());
+                break;
+            case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED:
+                setPrimitiveRestartEnabled(state.isPrimitiveRestartEnabled());
+                break;
+            case gl::State::DIRTY_BIT_CLEAR_COLOR:
+                setClearColor(state.getColorClearValue());
+                break;
+            case gl::State::DIRTY_BIT_CLEAR_DEPTH:
+                setClearDepth(state.getDepthClearValue());
+                break;
+            case gl::State::DIRTY_BIT_CLEAR_STENCIL:
+                setClearStencil(state.getStencilClearValue());
+                break;
+            case gl::State::DIRTY_BIT_UNPACK_ALIGNMENT:
+                // TODO(jmadill): split this
+                setPixelUnpackState(state.getUnpackState());
+                break;
+            case gl::State::DIRTY_BIT_UNPACK_ROW_LENGTH:
+                // TODO(jmadill): split this
+                setPixelUnpackState(state.getUnpackState());
+                break;
+            case gl::State::DIRTY_BIT_PACK_ALIGNMENT:
+                // TODO(jmadill): split this
+                setPixelPackState(state.getPackState());
+                break;
+            case gl::State::DIRTY_BIT_PACK_REVERSE_ROW_ORDER:
+                // TODO(jmadill): split this
+                setPixelPackState(state.getPackState());
+                break;
+            case gl::State::DIRTY_BIT_DITHER_ENABLED:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_GENERATE_MIPMAP_HINT:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_SHADER_DERIVATIVE_HINT:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_READ_FRAMEBUFFER_OBJECT:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_OBJECT:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_VERTEX_ARRAY_OBJECT:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_PROGRAM_BINDING:
+                // TODO(jmadill): implement this
+                break;
+            case gl::State::DIRTY_BIT_PROGRAM_OBJECT:
+                // TODO(jmadill): implement this
+                break;
+            default:
+                UNREACHABLE();
+                break;
+        }
+    }
+}
 }
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.h b/src/libANGLE/renderer/gl/StateManagerGL.h
index 14050f4..a38c3ec 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.h
+++ b/src/libANGLE/renderer/gl/StateManagerGL.h
@@ -11,6 +11,7 @@
 
 #include "common/debug.h"
 #include "libANGLE/Error.h"
+#include "libANGLE/State.h"
 #include "libANGLE/angletypes.h"
 #include "libANGLE/renderer/gl/functionsgl_typedefs.h"
 
@@ -28,7 +29,7 @@
 
 class FunctionsGL;
 
-class StateManagerGL : angle::NonCopyable
+class StateManagerGL final : angle::NonCopyable
 {
   public:
     StateManagerGL(const FunctionsGL *functions, const gl::Caps &rendererCaps);
@@ -45,18 +46,15 @@
     void bindBuffer(GLenum type, GLuint buffer);
     void activeTexture(size_t unit);
     void bindTexture(GLenum type, GLuint texture);
-    void setPixelUnpackState(GLint alignment, GLint rowLength, GLint skipRows, GLint skipPixels,
-                             GLint imageHeight, GLint skipImages);
-    void setPixelPackState(GLint alignment, GLint rowLength, GLint skipRows, GLint skipPixels);
     void bindFramebuffer(GLenum type, GLuint framebuffer);
     void bindRenderbuffer(GLenum type, GLuint renderbuffer);
 
-    void setClearState(const gl::State &state, GLbitfield mask);
-
     gl::Error setDrawArraysState(const gl::Data &data, GLint first, GLsizei count);
     gl::Error setDrawElementsState(const gl::Data &data, GLsizei count, GLenum type, const GLvoid *indices,
                                    const GLvoid **outIndices);
 
+    void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits);
+
   private:
     gl::Error setGenericDrawState(const gl::Data &data);
 
@@ -103,6 +101,16 @@
     void setClearDepth(float clearDepth);
     void setClearStencil(GLint clearStencil);
 
+    void setPixelUnpackState(const gl::PixelUnpackState &unpack);
+    void setPixelUnpackState(GLint alignment,
+                             GLint rowLength,
+                             GLint skipRows,
+                             GLint skipPixels,
+                             GLint imageHeight,
+                             GLint skipImages);
+    void setPixelPackState(const gl::PixelPackState &pack);
+    void setPixelPackState(GLint alignment, GLint rowLength, GLint skipRows, GLint skipPixels);
+
     const FunctionsGL *mFunctions;
 
     GLuint mProgram;
diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp
index 590a7a8..6dca94a 100644
--- a/src/libANGLE/renderer/gl/TextureGL.cpp
+++ b/src/libANGLE/renderer/gl/TextureGL.cpp
@@ -23,17 +23,6 @@
 namespace rx
 {
 
-static void SetUnpackStateForTexImage(StateManagerGL *stateManager, const gl::PixelUnpackState &unpack)
-{
-    const gl::Buffer *unpackBuffer = unpack.pixelBuffer.get();
-    if (unpackBuffer != nullptr)
-    {
-        UNIMPLEMENTED();
-    }
-    stateManager->setPixelUnpackState(unpack.alignment, unpack.rowLength, unpack.skipRows,
-                                      unpack.skipPixels, unpack.imageHeight, unpack.skipImages);
-}
-
 static bool UseTexImage2D(GLenum textureType)
 {
     return textureType == GL_TEXTURE_2D || textureType == GL_TEXTURE_CUBE_MAP;
@@ -93,8 +82,6 @@
     UNUSED_ASSERTION_VARIABLE(&CompatibleTextureTarget); // Reference this function to avoid warnings.
     ASSERT(CompatibleTextureTarget(mTextureType, target));
 
-    SetUnpackStateForTexImage(mStateManager, unpack);
-
     nativegl::TexImageFormat texImageFormat =
         nativegl::GetTexImageFormat(mFunctions, mWorkarounds, internalFormat, format, type);
 
@@ -124,8 +111,6 @@
 {
     ASSERT(CompatibleTextureTarget(mTextureType, target));
 
-    SetUnpackStateForTexImage(mStateManager, unpack);
-
     nativegl::TexSubImageFormat texSubImageFormat =
         nativegl::GetTexSubImageFormat(mFunctions, mWorkarounds, format, type);
 
@@ -155,8 +140,6 @@
 {
     ASSERT(CompatibleTextureTarget(mTextureType, target));
 
-    SetUnpackStateForTexImage(mStateManager, unpack);
-
     nativegl::CompressedTexImageFormat compressedTexImageFormat =
         nativegl::GetCompressedTexImageFormat(mFunctions, mWorkarounds, internalFormat);
 
@@ -185,8 +168,6 @@
 {
     ASSERT(CompatibleTextureTarget(mTextureType, target));
 
-    SetUnpackStateForTexImage(mStateManager, unpack);
-
     nativegl::CompressedTexSubImageFormat compressedTexSubImageFormat =
         nativegl::GetCompressedSubTexImageFormat(mFunctions, mWorkarounds, format);
 
diff --git a/src/libGLESv2/entry_points_gles_2_0.cpp b/src/libGLESv2/entry_points_gles_2_0.cpp
index 2773de5..64bbdc8 100644
--- a/src/libGLESv2/entry_points_gles_2_0.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0.cpp
@@ -628,7 +628,7 @@
             return;
         }
 
-        Error error = framebufferObject->clear(context->getData(), mask);
+        Error error = framebufferObject->clear(context, mask);
         if (error.isError())
         {
             context->recordError(error);
@@ -743,8 +743,9 @@
 
         Extents size(width, height, 1);
         Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
-        Error error = texture->setCompressedImage(target, level, internalformat, size, context->getState().getUnpackState(), 
-                                                  imageSize, reinterpret_cast<const uint8_t *>(data));
+        Error error =
+            texture->setCompressedImage(context, target, level, internalformat, size, imageSize,
+                                        reinterpret_cast<const uint8_t *>(data));
         if (error.isError())
         {
             context->recordError(error);
@@ -785,11 +786,11 @@
             return;
         }
 
-
         Box area(xoffset, yoffset, 0, width, height, 1);
         Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
-        Error error = texture->setCompressedSubImage(target, level, area, format, context->getState().getUnpackState(),
-                                                     imageSize, reinterpret_cast<const uint8_t *>(data));
+        Error error =
+            texture->setCompressedSubImage(context, target, level, area, format, imageSize,
+                                           reinterpret_cast<const uint8_t *>(data));
         if (error.isError())
         {
             context->recordError(error);
@@ -3319,7 +3320,7 @@
         ASSERT(framebufferObject);
 
         Rectangle area(x, y, width, height);
-        Error error = framebufferObject->readPixels(context->getState(), area, format, type, pixels);
+        Error error = framebufferObject->readPixels(context, area, format, type, pixels);
         if (error.isError())
         {
             context->recordError(error);
@@ -3657,7 +3658,7 @@
 
         Extents size(width, height, 1);
         Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
-        Error error = texture->setImage(target, level, internalformat, size, format, type, context->getState().getUnpackState(),
+        Error error = texture->setImage(context, target, level, internalformat, size, format, type,
                                         reinterpret_cast<const uint8_t *>(pixels));
         if (error.isError())
         {
@@ -3810,7 +3811,7 @@
 
         Box area(xoffset, yoffset, 0, width, height, 1);
         Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
-        Error error = texture->setSubImage(target, level, area, format, type, context->getState().getUnpackState(),
+        Error error = texture->setSubImage(context, target, level, area, format, type,
                                            reinterpret_cast<const uint8_t *>(pixels));
         if (error.isError())
         {
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
index 851da08..f611092 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
@@ -496,7 +496,7 @@
         ASSERT(framebufferObject);
 
         Rectangle area(x, y, width, height);
-        Error error = framebufferObject->readPixels(context->getState(), area, format, type, data);
+        Error error = framebufferObject->readPixels(context, area, format, type, data);
         if (error.isError())
         {
             context->recordError(error);
diff --git a/src/libGLESv2/entry_points_gles_3_0.cpp b/src/libGLESv2/entry_points_gles_3_0.cpp
index f22d520..59f736e 100644
--- a/src/libGLESv2/entry_points_gles_3_0.cpp
+++ b/src/libGLESv2/entry_points_gles_3_0.cpp
@@ -109,7 +109,7 @@
 
         Extents size(width, height, depth);
         Texture *texture = context->getTargetTexture(target);
-        Error error = texture->setImage(target, level, internalformat, size, format, type, context->getState().getUnpackState(),
+        Error error = texture->setImage(context, target, level, internalformat, size, format, type,
                                         reinterpret_cast<const uint8_t *>(pixels));
         if (error.isError())
         {
@@ -151,7 +151,7 @@
 
         Box area(xoffset, yoffset, zoffset, width, height, depth);
         Texture *texture = context->getTargetTexture(target);
-        Error error = texture->setSubImage(target, level, area, format, type, context->getState().getUnpackState(),
+        Error error = texture->setSubImage(context, target, level, area, format, type,
                                            reinterpret_cast<const uint8_t *>(pixels));
         if (error.isError())
         {
@@ -214,8 +214,9 @@
 
         Extents size(width, height, depth);
         Texture *texture = context->getTargetTexture(target);
-        Error error = texture->setCompressedImage(target, level, internalformat, size, context->getState().getUnpackState(),
-                                                  imageSize, reinterpret_cast<const uint8_t *>(data));
+        Error error =
+            texture->setCompressedImage(context, target, level, internalformat, size, imageSize,
+                                        reinterpret_cast<const uint8_t *>(data));
         if (error.isError())
         {
             context->recordError(error);
@@ -268,8 +269,9 @@
 
         Box area(xoffset, yoffset, zoffset, width, height, depth);
         Texture *texture = context->getTargetTexture(target);
-        Error error = texture->setCompressedSubImage(target, level, area, format, context->getState().getUnpackState(),
-                                                     imageSize, reinterpret_cast<const uint8_t *>(data));
+        Error error =
+            texture->setCompressedSubImage(context, target, level, area, format, imageSize,
+                                           reinterpret_cast<const uint8_t *>(data));
         if (error.isError())
         {
             context->recordError(error);
@@ -1731,7 +1733,7 @@
         Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
         ASSERT(framebufferObject);
 
-        Error error = framebufferObject->clearBufferiv(context->getState(), buffer, drawbuffer, value);
+        Error error = framebufferObject->clearBufferiv(context, buffer, drawbuffer, value);
         if (error.isError())
         {
             context->recordError(error);
@@ -1771,7 +1773,7 @@
         Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
         ASSERT(framebufferObject);
 
-        Error error = framebufferObject->clearBufferuiv(context->getState(), buffer, drawbuffer, value);
+        Error error = framebufferObject->clearBufferuiv(context, buffer, drawbuffer, value);
         if (error.isError())
         {
             context->recordError(error);
@@ -1819,7 +1821,7 @@
         Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
         ASSERT(framebufferObject);
 
-        Error error = framebufferObject->clearBufferfv(context->getState(), buffer, drawbuffer, value);
+        Error error = framebufferObject->clearBufferfv(context, buffer, drawbuffer, value);
         if (error.isError())
         {
             context->recordError(error);
@@ -1865,7 +1867,7 @@
             return;
         }
 
-        Error error = framebufferObject->clearBufferfi(context->getState(), buffer, drawbuffer, depth, stencil);
+        Error error = framebufferObject->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
         if (error.isError())
         {
             context->recordError(error);