Smart caching of VAO input layout.

Don't recompute the cached attribute layout for a program if the
vertex array info hasn't changed. We can use the Serial class to
know when a vertex array has identical state.

BUG=angleproject:1156

Change-Id: Ia11f6ac268f63c3299f6d6d80c2866009cb8429c
Reviewed-on: https://chromium-review.googlesource.com/529768
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index 77432c2..86424cd 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -1102,6 +1102,8 @@
         {
             newProgram->addRef();
         }
+        mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
+        mDirtyBits.set(DIRTY_BIT_PROGRAM_BINDING);
     }
 }
 
@@ -2154,9 +2156,6 @@
                 ASSERT(mVertexArray);
                 mVertexArray->syncImplState(context);
                 break;
-            case DIRTY_OBJECT_PROGRAM:
-                // TODO(jmadill): implement this
-                break;
             default:
                 UNREACHABLE();
                 break;
@@ -2185,9 +2184,6 @@
         case GL_VERTEX_ARRAY:
             localSet.set(DIRTY_OBJECT_VERTEX_ARRAY);
             break;
-        case GL_PROGRAM:
-            localSet.set(DIRTY_OBJECT_PROGRAM);
-            break;
     }
 
     syncDirtyObjects(context, localSet);
@@ -2210,9 +2206,18 @@
         case GL_VERTEX_ARRAY:
             mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
             break;
-        case GL_PROGRAM:
-            mDirtyObjects.set(DIRTY_OBJECT_PROGRAM);
-            break;
+    }
+}
+
+void State::onProgramExecutableChange(Program *program)
+{
+    // OpenGL Spec:
+    // "If LinkProgram or ProgramBinary successfully re-links a program object
+    //  that was already in use as a result of a previous call to UseProgram, then the
+    //  generated executable code will be installed as part of the current rendering state."
+    if (program->isLinked() && mProgram == program)
+    {
+        mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
     }
 }