D3D11: Re-check disabled attribs on VAO switch.

When switching VAOs, if we switch to a VAO which has disabled
attributes, we could occasionally in some edge cases not have a buffer
initialized to render with. Fix this by re-checking the current
value (disabled) attributes every VAO switch.

Probably a regression caused by d28758d:
"D3D11: Re-enable updateVertexBuffer dirty bits."

BUG=chromium:778689

Change-Id: I01814bafa1d6e3a7d6a5c03bc5d058f39346f087
Reviewed-on: https://chromium-review.googlesource.com/748426
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
index 364607d..a5ecb38 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -680,6 +680,10 @@
                 break;
             case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
                 invalidateVertexBuffer();
+                // Force invalidate the current value attributes, since the VertexArray11 keeps an
+                // internal cache of TranslatedAttributes, and they CurrentValue attributes are
+                // owned by the StateManager11/Context.
+                mDirtyCurrentValueAttribs.set();
                 break;
             case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
                 invalidateVertexBuffer();
diff --git a/src/tests/gl_tests/StateChangeTest.cpp b/src/tests/gl_tests/StateChangeTest.cpp
index 0ae1ef7..1a4d9fa 100644
--- a/src/tests/gl_tests/StateChangeTest.cpp
+++ b/src/tests/gl_tests/StateChangeTest.cpp
@@ -601,6 +601,145 @@
     EXPECT_GL_NO_ERROR();
 }
 
+// Tests that D3D11 dirty bit updates don't forget about BufferSubData attrib updates.
+TEST_P(StateChangeTest, VertexBufferUpdatedAfterDraw)
+{
+    const std::string vs =
+        "attribute vec2 position;\n"
+        "attribute vec4 color;\n"
+        "varying vec4 outcolor;\n"
+        "void main()\n"
+        "{\n"
+        "    gl_Position = vec4(position, 0, 1);\n"
+        "    outcolor = color;\n"
+        "}";
+    const std::string fs =
+        "varying mediump vec4 outcolor;\n"
+        "void main()\n"
+        "{\n"
+        "    gl_FragColor = outcolor;\n"
+        "}";
+
+    ANGLE_GL_PROGRAM(program, vs, fs);
+    glUseProgram(program);
+
+    GLint colorLoc = glGetAttribLocation(program, "color");
+    ASSERT_NE(-1, colorLoc);
+    GLint positionLoc = glGetAttribLocation(program, "position");
+    ASSERT_NE(-1, positionLoc);
+
+    setupQuadVertexBuffer(0.5f, 1.0f);
+    glEnableVertexAttribArray(positionLoc);
+    glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
+
+    GLBuffer colorBuf;
+    glBindBuffer(GL_ARRAY_BUFFER, colorBuf);
+    glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
+    glEnableVertexAttribArray(colorLoc);
+
+    // Fill with green.
+    std::vector<GLColor> colorData(6, GLColor::green);
+    glBufferData(GL_ARRAY_BUFFER, colorData.size() * sizeof(GLColor), colorData.data(),
+                 GL_STATIC_DRAW);
+
+    // Draw, expect green.
+    glDrawArrays(GL_TRIANGLES, 0, 6);
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+    ASSERT_GL_NO_ERROR();
+
+    // Update buffer with red.
+    std::fill(colorData.begin(), colorData.end(), GLColor::red);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, colorData.size() * sizeof(GLColor), colorData.data());
+
+    // Draw, expect red.
+    glDrawArrays(GL_TRIANGLES, 0, 6);
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+    ASSERT_GL_NO_ERROR();
+}
+
+// Test that switching VAOs keeps the disabled "current value" attributes up-to-date.
+TEST_P(StateChangeTestES3, VertexArrayObjectAndDisabledAttributes)
+{
+    const std::string singleVertexShader =
+        "attribute vec4 position; void main() { gl_Position = position; }";
+    const std::string singleFragmentShader = "void main() { gl_FragColor = vec4(1, 0, 0, 1); }";
+    ANGLE_GL_PROGRAM(singleProgram, singleVertexShader, singleFragmentShader);
+
+    const std::string dualVertexShader =
+        "#version 300 es\n"
+        "in vec4 position;\n"
+        "in vec4 color;\n"
+        "out vec4 varyColor;\n"
+        "void main()\n"
+        "{\n"
+        "    gl_Position = position;\n"
+        "    varyColor = color;\n"
+        "}";
+    const std::string dualFragmentShader =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "in vec4 varyColor;\n"
+        "out vec4 colorOut;\n"
+        "void main()\n"
+        "{\n"
+        "    colorOut = varyColor;\n"
+        "}";
+    ANGLE_GL_PROGRAM(dualProgram, dualVertexShader, dualFragmentShader);
+    GLint positionLocation = glGetAttribLocation(dualProgram, "position");
+    ASSERT_NE(-1, positionLocation);
+    GLint colorLocation = glGetAttribLocation(dualProgram, "color");
+    ASSERT_NE(-1, colorLocation);
+
+    GLint singlePositionLocation = glGetAttribLocation(singleProgram, "position");
+    ASSERT_NE(-1, singlePositionLocation);
+
+    glUseProgram(singleProgram);
+
+    // Initialize position vertex buffer.
+    const auto &quadVertices = GetQuadVertices();
+
+    GLBuffer vertexBuffer;
+    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 6, quadVertices.data(), GL_STATIC_DRAW);
+
+    // Initialize a VAO. Draw with single program.
+    GLVertexArray vertexArray;
+    glBindVertexArray(vertexArray);
+    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
+    glVertexAttribPointer(singlePositionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
+    glEnableVertexAttribArray(singlePositionLocation);
+
+    // Should draw red.
+    glDrawArrays(GL_TRIANGLES, 0, 6);
+    ASSERT_GL_NO_ERROR();
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+
+    // Draw with a green buffer attribute, without the VAO.
+    glBindVertexArray(0);
+    glUseProgram(dualProgram);
+    glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
+    glEnableVertexAttribArray(positionLocation);
+
+    std::vector<GLColor> greenColors(6, GLColor::green);
+    GLBuffer greenBuffer;
+    glBindBuffer(GL_ARRAY_BUFFER, greenBuffer);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 6, greenColors.data(), GL_STATIC_DRAW);
+
+    glVertexAttribPointer(colorLocation, 4, GL_UNSIGNED_BYTE, GL_FALSE, 4, nullptr);
+    glEnableVertexAttribArray(colorLocation);
+
+    glDrawArrays(GL_TRIANGLES, 0, 6);
+    ASSERT_GL_NO_ERROR();
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+
+    // Re-bind VAO and try to draw with different program, without changing state.
+    // Should draw black since current value is not initialized.
+    glBindVertexArray(vertexArray);
+    glDrawArrays(GL_TRIANGLES, 0, 6);
+    ASSERT_GL_NO_ERROR();
+    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
+}
+
 ANGLE_INSTANTIATE_TEST(StateChangeTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL());
 ANGLE_INSTANTIATE_TEST(StateChangeRenderTest,
                        ES2_D3D9(),