Prevent redundant uniform updates
TRAC #12154
Signed-off-by: Shannon Woods
Signed-off-by: Daniel Koch

Author:    Nicolas Capens

git-svn-id: https://angleproject.googlecode.com/svn/trunk@255 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Program.cpp b/src/libGLESv2/Program.cpp
index 395622d..c18ee92 100644
--- a/src/libGLESv2/Program.cpp
+++ b/src/libGLESv2/Program.cpp
@@ -17,12 +17,14 @@
 
 namespace gl
 {
+unsigned int Program::mCurrentSerial = 1;
+
 Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
 {
     int bytes = UniformTypeSize(type) * arraySize;
-
-    this->data = new unsigned char[bytes];
-    memset(this->data, 0, bytes);
+    data = new unsigned char[bytes];
+    memset(data, 0, bytes);
+    dirty = true;
 }
 
 Uniform::~Uniform()
@@ -53,6 +55,8 @@
     unlink();
 
     mDeleteStatus = false;
+
+    mSerial = issueSerial();
 }
 
 Program::~Program()
@@ -215,9 +219,11 @@
         subscript = atoi(subscrStr.c_str());
     }
 
+    nameStr = decorate(nameStr);
+
     for (unsigned int location = 0; location < mUniformIndex.size(); location++)
     {
-        if (mUniformIndex[location].name == decorate(nameStr) &&
+        if (mUniformIndex[location].name == nameStr &&
             mUniformIndex[location].element == subscript)
         {
             return location;
@@ -235,6 +241,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type == GL_FLOAT)
     {
@@ -291,6 +298,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type == GL_FLOAT_VEC2)
     {
@@ -348,6 +356,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type == GL_FLOAT_VEC3)
     {
@@ -404,6 +413,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type == GL_FLOAT_VEC4)
     {
@@ -460,6 +470,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type != GL_FLOAT_MAT2)
     {
@@ -487,6 +498,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type != GL_FLOAT_MAT3)
     {
@@ -514,6 +526,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type != GL_FLOAT_MAT4)
     {
@@ -541,6 +554,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type == GL_INT)
     {
@@ -597,6 +611,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type == GL_INT_VEC2)
     {
@@ -653,6 +668,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type == GL_INT_VEC3)
     {
@@ -709,6 +725,7 @@
     }
 
     Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+    targetUniform->dirty = true;
 
     if (targetUniform->type == GL_INT_VEC4)
     {
@@ -843,6 +860,14 @@
     return true;
 }
 
+void Program::dirtyAllUniforms()
+{
+    for (unsigned int index = 0; index < mUniforms.size(); index++)
+    {
+        mUniforms[index]->dirty = true;
+    }
+}
+
 // Applies all the uniforms set for this program object to the Direct3D 9 device
 void Program::applyUniforms()
 {
@@ -855,31 +880,35 @@
 
         Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
 
-        int arraySize = targetUniform->arraySize;
-        GLfloat *f = (GLfloat*)targetUniform->data;
-        GLint *i = (GLint*)targetUniform->data;
-        GLboolean *b = (GLboolean*)targetUniform->data;
-
-        switch (targetUniform->type)
+        if (targetUniform->dirty)
         {
-          case GL_BOOL:       applyUniform1bv(location, arraySize, b);       break;
-          case GL_BOOL_VEC2:  applyUniform2bv(location, arraySize, b);       break;
-          case GL_BOOL_VEC3:  applyUniform3bv(location, arraySize, b);       break;
-          case GL_BOOL_VEC4:  applyUniform4bv(location, arraySize, b);       break;
-          case GL_FLOAT:      applyUniform1fv(location, arraySize, f);       break;
-          case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f);       break;
-          case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f);       break;
-          case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f);       break;
-          case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
-          case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
-          case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
-          case GL_INT:        applyUniform1iv(location, arraySize, i);       break;
-          case GL_INT_VEC2:   applyUniform2iv(location, arraySize, i);       break;
-          case GL_INT_VEC3:   applyUniform3iv(location, arraySize, i);       break;
-          case GL_INT_VEC4:   applyUniform4iv(location, arraySize, i);       break;
-          default:
-            UNIMPLEMENTED();   // FIXME
-            UNREACHABLE();
+            int arraySize = targetUniform->arraySize;
+            GLfloat *f = (GLfloat*)targetUniform->data;
+            GLint *i = (GLint*)targetUniform->data;
+            GLboolean *b = (GLboolean*)targetUniform->data;
+
+            switch (targetUniform->type)
+            {
+              case GL_BOOL:       applyUniform1bv(location, arraySize, b);       break;
+              case GL_BOOL_VEC2:  applyUniform2bv(location, arraySize, b);       break;
+              case GL_BOOL_VEC3:  applyUniform3bv(location, arraySize, b);       break;
+              case GL_BOOL_VEC4:  applyUniform4bv(location, arraySize, b);       break;
+              case GL_FLOAT:      applyUniform1fv(location, arraySize, f);       break;
+              case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f);       break;
+              case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f);       break;
+              case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f);       break;
+              case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
+              case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
+              case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
+              case GL_INT:        applyUniform1iv(location, arraySize, i);       break;
+              case GL_INT_VEC2:   applyUniform2iv(location, arraySize, i);       break;
+              case GL_INT_VEC3:   applyUniform3iv(location, arraySize, i);       break;
+              case GL_INT_VEC4:   applyUniform4iv(location, arraySize, i);       break;
+              default:
+                UNREACHABLE();
+            }
+
+            targetUniform->dirty = false;
         }
     }
 }
@@ -2004,6 +2033,16 @@
     return mValidated;
 }
 
+unsigned int Program::getSerial() const
+{
+    return mSerial;
+}
+
+unsigned int Program::issueSerial()
+{
+    return mCurrentSerial++;
+}
+
 int Program::getInfoLogLength() const
 {
     if (!mInfoLog)