Implemented support for DX11 uniform arrays.

TRAC #22239
Signed-off-by: Daniel Koch
Signed-off-by: Shannon Woods
Author: Nicolas Capens

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1629 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index 76dc108..3bafe9f 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -237,12 +237,12 @@
 
     if (targetUniform->type == GL_FLOAT)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
         GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
 
@@ -258,12 +258,12 @@
     }
     else if (targetUniform->type == GL_BOOL)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
         GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
 
         for (int i = 0; i < count; ++i)
@@ -298,12 +298,12 @@
 
     if (targetUniform->type == GL_FLOAT_VEC2)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
         GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
 
@@ -319,12 +319,12 @@
     }
     else if (targetUniform->type == GL_BOOL_VEC2)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
         GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
 
@@ -360,12 +360,12 @@
 
     if (targetUniform->type == GL_FLOAT_VEC3)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
         GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
 
@@ -381,12 +381,12 @@
     }
     else if (targetUniform->type == GL_BOOL_VEC3)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
         GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
 
         for (int i = 0; i < count * 3; ++i)
@@ -421,24 +421,24 @@
 
     if (targetUniform->type == GL_FLOAT_VEC4)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
         memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
                v, 4 * sizeof(GLfloat) * count);
     }
     else if (targetUniform->type == GL_BOOL_VEC4)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
         GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
 
         for (int i = 0; i < count * 4; ++i)
@@ -507,12 +507,12 @@
         return false;
     }
 
-    int arraySize = targetUniform->arraySize;
+    int elementCount = targetUniform->elementCount();
 
-    if (arraySize == 1 && count > 1)
+    if (elementCount == 1 && count > 1)
         return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-    count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
     GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
     for (int i = 0; i < count; i++)
@@ -540,12 +540,12 @@
         return false;
     }
 
-    int arraySize = targetUniform->arraySize;
+    int elementCount = targetUniform->elementCount();
 
-    if (arraySize == 1 && count > 1)
+    if (elementCount == 1 && count > 1)
         return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-    count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
     GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
     for (int i = 0; i < count; i++)
@@ -574,12 +574,12 @@
         return false;
     }
 
-    int arraySize = targetUniform->arraySize;
+    int elementCount = targetUniform->elementCount();
 
-    if (arraySize == 1 && count > 1)
+    if (elementCount == 1 && count > 1)
         return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-    count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
     GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
     for (int i = 0; i < count; i++)
@@ -606,24 +606,24 @@
         targetUniform->type == GL_SAMPLER_2D ||
         targetUniform->type == GL_SAMPLER_CUBE)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
         memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
                v, sizeof(GLint) * count);
     }
     else if (targetUniform->type == GL_BOOL)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
         GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element;
 
         for (int i = 0; i < count; ++i)
@@ -658,24 +658,24 @@
 
     if (targetUniform->type == GL_INT_VEC2)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
         memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
                v, 2 * sizeof(GLint) * count);
     }
     else if (targetUniform->type == GL_BOOL_VEC2)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
         GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2;
 
         for (int i = 0; i < count * 2; ++i)
@@ -710,24 +710,24 @@
 
     if (targetUniform->type == GL_INT_VEC3)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
         memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
                v, 3 * sizeof(GLint) * count);
     }
     else if (targetUniform->type == GL_BOOL_VEC3)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
         GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3;
 
         for (int i = 0; i < count * 3; ++i)
@@ -762,24 +762,24 @@
 
     if (targetUniform->type == GL_INT_VEC4)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
 
         memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
                v, 4 * sizeof(GLint) * count);
     }
     else if (targetUniform->type == GL_BOOL_VEC4)
     {
-        int arraySize = targetUniform->arraySize;
+        int elementCount = targetUniform->elementCount();
 
-        if (arraySize == 1 && count > 1)
+        if (elementCount == 1 && count > 1)
             return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
 
-        count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+        count = std::min(elementCount - (int)mUniformIndex[location].element, count);
         GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4;
 
         for (int i = 0; i < count * 4; ++i)
@@ -968,7 +968,7 @@
             if (targetUniform->type == GL_SAMPLER_2D || 
                 targetUniform->type == GL_SAMPLER_CUBE)
             {
-                int count = targetUniform->arraySize;
+                int count = targetUniform->elementCount();
                 GLint *v = (GLint*)targetUniform->data;
 
                 if (targetUniform->ps.registerCount)
@@ -2112,45 +2112,49 @@
 
 bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant)
 {
-    ASSERT(constant.arraySize <= 1);   // FIXME: UNIMPLEMENTED
-    Uniform *uniform = new Uniform(constant.type, constant.name, 1 /*constant.arraySize*/);
+    Uniform *uniform = NULL;
+    GLint location = getUniformLocation(constant.name);
+
+    if (location >= 0)   // Previously defined, types must match
+    {
+        uniform = mUniforms[mUniformIndex[location].index];
+
+        if (uniform->type != constant.type)
+        {
+            return false;
+        }
+    }
+    else
+    {
+        uniform = new Uniform(constant.type, constant.name, constant.arraySize);
+    }
 
     if (!uniform)
     {
         return false;
     }
 
-    // Check if already defined
-    GLint location = getUniformLocation(uniform->name);
-    GLenum type = uniform->type;
-
-    if (location >= 0)
-    {
-        delete uniform;
-        uniform = mUniforms[mUniformIndex[location].index];
-    }
-
     if (shader == GL_FRAGMENT_SHADER)
     {
         uniform->ps.registerIndex = constant.registerIndex;
-        uniform->ps.registerCount = 1 /*constant.arraySize*/;
+        uniform->ps.registerCount = uniform->registerCount();
     }
     else if (shader == GL_VERTEX_SHADER)
     {
         uniform->vs.registerIndex = constant.registerIndex;
-        uniform->vs.registerCount = 1 /*constant.arraySize*/;
+        uniform->vs.registerCount = uniform->registerCount();
     }
     else UNREACHABLE();
 
     if (location >= 0)
     {
-        return uniform->type == type;
+        return uniform->type == constant.type;
     }
 
     mUniforms.push_back(uniform);
     unsigned int uniformIndex = mUniforms.size() - 1;
 
-    for (unsigned int i = 0; i < uniform->arraySize; i++)
+    for (unsigned int i = 0; i < uniform->elementCount(); i++)
     {
         mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
     }
@@ -2339,7 +2343,7 @@
         }
     }
 
-    *size = mUniforms[index]->arraySize;
+    *size = mUniforms[index]->elementCount();
 
     *type = mUniforms[index]->type;
 }
diff --git a/src/libGLESv2/Uniform.cpp b/src/libGLESv2/Uniform.cpp
index b7f2e62..0412ce9 100644
--- a/src/libGLESv2/Uniform.cpp
+++ b/src/libGLESv2/Uniform.cpp
@@ -14,7 +14,7 @@
 Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize)

     : type(type), _name(_name), name(undecorate(_name)), arraySize(arraySize)

 {

-    int bytes = gl::UniformInternalSize(type) * arraySize;

+    int bytes = gl::UniformInternalSize(type) * elementCount();

     data = new unsigned char[bytes];

     memset(data, 0, bytes);

     dirty = true;

@@ -25,12 +25,29 @@
     delete[] data;

 }

 

-bool Uniform::isArray()

+bool Uniform::isArray() const

 {

-    size_t dot = _name.find_last_of('.');

-    if (dot == std::string::npos) dot = -1;

+    if (name != _name)   // D3D9_REPLACE

+    {

+        size_t dot = _name.find_last_of('.');

+        if (dot == std::string::npos) dot = -1;

 

-    return _name.compare(dot + 1, dot + 4, "ar_") == 0;

+        return _name.compare(dot + 1, dot + 4, "ar_") == 0;

+    }

+    else

+    {

+        return arraySize > 0;

+    }

+}

+

+unsigned int Uniform::elementCount() const

+{

+    return arraySize > 0 ? arraySize : 1;

+}

+

+unsigned int Uniform::registerCount() const

+{

+    return VariableRowCount(type) * elementCount();

 }

 

 std::string Uniform::undecorate(const std::string &_name)

diff --git a/src/libGLESv2/Uniform.h b/src/libGLESv2/Uniform.h
index 06836e1..a936d2f 100644
--- a/src/libGLESv2/Uniform.h
+++ b/src/libGLESv2/Uniform.h
@@ -25,7 +25,9 @@
 

     ~Uniform();

 

-    bool isArray();

+    bool isArray() const;

+    unsigned int elementCount() const;

+    unsigned int registerCount() const;

     static std::string Uniform::undecorate(const std::string &_name);

 

     const GLenum type;

@@ -45,7 +47,7 @@
         }

 

         int registerIndex;

-        int registerCount;

+        unsigned int registerCount;

     };

 

     RegisterInfo ps;

diff --git a/src/libGLESv2/renderer/Renderer11.cpp b/src/libGLESv2/renderer/Renderer11.cpp
index d3c5b17..e623a28 100644
--- a/src/libGLESv2/renderer/Renderer11.cpp
+++ b/src/libGLESv2/renderer/Renderer11.cpp
@@ -837,7 +837,7 @@
           case GL_FLOAT_MAT4:
             if (uniform->vs.registerCount)
             {
-                for (int i = 0; i < uniform->vs.registerCount; i++)
+                for (unsigned int i = 0; i < uniform->vs.registerCount; i++)
                 {
                     cVS[uniform->vs.registerIndex + i][0] = f[i][0];
                     cVS[uniform->vs.registerIndex + i][1] = f[i][1];
@@ -847,7 +847,7 @@
             }
             if (uniform->ps.registerCount)
             {
-                for (int i = 0; i < uniform->ps.registerCount; i++)
+                for (unsigned int i = 0; i < uniform->ps.registerCount; i++)
                 {
                     cPS[uniform->ps.registerIndex + i][0] = f[i][0];
                     cPS[uniform->ps.registerIndex + i][1] = f[i][1];
diff --git a/src/libGLESv2/renderer/Renderer9.cpp b/src/libGLESv2/renderer/Renderer9.cpp
index 62bc874..786bc69 100644
--- a/src/libGLESv2/renderer/Renderer9.cpp
+++ b/src/libGLESv2/renderer/Renderer9.cpp
@@ -1471,7 +1471,7 @@
 
         if (targetUniform->dirty)
         {
-            int arraySize = targetUniform->arraySize;
+            int count = targetUniform->elementCount();
             GLfloat *f = (GLfloat*)targetUniform->data;
             GLint *i = (GLint*)targetUniform->data;
             GLboolean *b = (GLboolean*)targetUniform->data;
@@ -1481,21 +1481,21 @@
               case GL_SAMPLER_2D:
               case GL_SAMPLER_CUBE:
                   break;
-              case GL_BOOL:       applyUniformnbv(targetUniform, arraySize, 1, b);    break;
-              case GL_BOOL_VEC2:  applyUniformnbv(targetUniform, arraySize, 2, b);    break;
-              case GL_BOOL_VEC3:  applyUniformnbv(targetUniform, arraySize, 3, b);    break;
-              case GL_BOOL_VEC4:  applyUniformnbv(targetUniform, arraySize, 4, b);    break;
+              case GL_BOOL:       applyUniformnbv(targetUniform, count, 1, b);    break;
+              case GL_BOOL_VEC2:  applyUniformnbv(targetUniform, count, 2, b);    break;
+              case GL_BOOL_VEC3:  applyUniformnbv(targetUniform, count, 3, b);    break;
+              case GL_BOOL_VEC4:  applyUniformnbv(targetUniform, count, 4, b);    break;
               case GL_FLOAT:
               case GL_FLOAT_VEC2:
               case GL_FLOAT_VEC3:
               case GL_FLOAT_VEC4:
               case GL_FLOAT_MAT2:
               case GL_FLOAT_MAT3:
-              case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f);                  break;
-              case GL_INT:        applyUniform1iv(targetUniform, arraySize, i);       break;
-              case GL_INT_VEC2:   applyUniform2iv(targetUniform, arraySize, i);       break;
-              case GL_INT_VEC3:   applyUniform3iv(targetUniform, arraySize, i);       break;
-              case GL_INT_VEC4:   applyUniform4iv(targetUniform, arraySize, i);       break;
+              case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f);              break;
+              case GL_INT:        applyUniform1iv(targetUniform, count, i);       break;
+              case GL_INT_VEC2:   applyUniform2iv(targetUniform, count, i);       break;
+              case GL_INT_VEC3:   applyUniform3iv(targetUniform, count, i);       break;
+              case GL_INT_VEC4:   applyUniform4iv(targetUniform, count, i);       break;
               default:
                 UNREACHABLE();
             }