Implement type generation for user uniforms in vertex shader.
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index b7639be..b528c46 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -95,7 +95,9 @@
 
 Program::~Program()
 {
-    bindAllocation(NULL);
+    for (uint32_t ct=0; ct < MAX_UNIFORMS; ct++) {
+        bindAllocation(NULL, ct);
+    }
 
     delete[] mInputElements;
     delete[] mOutputElements;
@@ -106,15 +108,16 @@
 }
 
 
-void Program::bindAllocation(Allocation *alloc)
+void Program::bindAllocation(Allocation *alloc, uint32_t slot)
 {
-    if (mConstants.get() == alloc) {
+    LOGE("bind alloc %p %i", alloc, slot);
+    if (mConstants[slot].get() == alloc) {
         return;
     }
-    if (mConstants.get()) {
-        mConstants.get()->removeProgramToDirty(this);
+    if (mConstants[slot].get()) {
+        mConstants[slot].get()->removeProgramToDirty(this);
     }
-    mConstants.set(alloc);
+    mConstants[slot].set(alloc);
     if (alloc) {
         alloc->addProgramToDirty(this);
     }
@@ -239,7 +242,7 @@
 void rsi_ProgramBindConstants(Context *rsc, RsProgram vp, uint32_t slot, RsAllocation constants)
 {
     Program *p = static_cast<Program *>(vp);
-    p->bindAllocation(static_cast<Allocation *>(constants));
+    p->bindAllocation(static_cast<Allocation *>(constants), slot);
 }
 
 void rsi_ProgramBindTexture(Context *rsc, RsProgram vpf, uint32_t slot, RsAllocation a)
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index 4bb7802..a34e89f 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -39,7 +39,7 @@
                        const uint32_t * params, uint32_t paramLength);
     virtual ~Program();
 
-    void bindAllocation(Allocation *);
+    void bindAllocation(Allocation *, uint32_t slot);
     virtual void createShader();
 
     bool isUserProgram() const {return mUserShader.size() > 0;}
@@ -69,7 +69,7 @@
     uint32_t mOutputCount;
     uint32_t mConstantCount;
 
-    ObjectBaseRef<Allocation> mConstants;
+    ObjectBaseRef<Allocation> mConstants[MAX_UNIFORMS];
 
     mutable bool mDirty;
     String8 mShader;
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 8e59bc2..8849bda 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -69,7 +69,7 @@
     }
     state->mLast.set(this);
 
-    const float *f = static_cast<const float *>(mConstants->getPtr());
+    const float *f = static_cast<const float *>(mConstants[0]->getPtr());
 
     glMatrixMode(GL_TEXTURE);
     if (mTextureMatrixEnable) {
@@ -116,16 +116,37 @@
 {
     mShader.setTo("");
 
-    for (uint32_t ct=0; ct < mUniformCount; ct++) {
-        mShader.append("uniform mat4 ");
-        mShader.append(mUniformNames[ct]);
-        mShader.append(";\n");
-    }
-
     mShader.append("varying vec4 varColor;\n");
     mShader.append("varying vec4 varTex0;\n");
 
     if (mUserShader.length() > 1) {
+        mShader.append("uniform mat4 ");
+        mShader.append(mUniformNames[0]);
+        mShader.append(";\n");
+
+        LOGE("constant %i ", mConstantCount);
+        for (uint32_t ct=0; ct < mConstantCount; ct++) {
+            const Element *e = mConstantTypes[ct]->getElement();
+            for (uint32_t field=0; field < e->getFieldCount(); field++) {
+                const Element *f = e->getField(field);
+
+                // Cannot be complex
+                rsAssert(!f->getFieldCount());
+                switch(f->getComponent().getVectorSize()) {
+                case 1: mShader.append("uniform float UNI_"); break;
+                case 2: mShader.append("uniform vec2 UNI_"); break;
+                case 3: mShader.append("uniform vec3 UNI_"); break;
+                case 4: mShader.append("uniform vec4 UNI_"); break;
+                default:
+                    rsAssert(0);
+                }
+
+                mShader.append(e->getFieldName(field));
+                mShader.append(";\n");
+            }
+        }
+
+
         for (uint32_t ct=0; ct < mInputCount; ct++) {
             const Element *e = mInputElements[ct].get();
             for (uint32_t field=0; field < e->getFieldCount(); field++) {
@@ -148,6 +169,12 @@
         }
         mShader.append(mUserShader);
     } else {
+        for (uint32_t ct=0; ct < mUniformCount; ct++) {
+            mShader.append("uniform mat4 ");
+            mShader.append(mUniformNames[ct]);
+            mShader.append(";\n");
+        }
+
         for (uint32_t ct=VertexArray::POSITION; ct < mAttribCount; ct++) {
             mShader.append("attribute vec4 ");
             mShader.append(mAttribNames[ct]);
@@ -155,12 +182,12 @@
         }
 
         mShader.append("void main() {\n");
-        mShader.append("  gl_Position = uni_MVP * ATTRIB_Position;\n");
+        mShader.append("  gl_Position = UNI_MVP * ATTRIB_Position;\n");
         mShader.append("  gl_PointSize = ATTRIB_PointSize.x;\n");
 
         mShader.append("  varColor = ATTRIB_Color;\n");
         if (mTextureMatrixEnable) {
-            mShader.append("  varTex0 = uni_TexMatrix * ATTRIB_Texture;\n");
+            mShader.append("  varTex0 = UNI_TexMatrix * ATTRIB_Texture;\n");
         } else {
             mShader.append("  varTex0 = ATTRIB_Texture;\n");
         }
@@ -180,7 +207,7 @@
 
     glVertexAttrib4f(1, state->color[0], state->color[1], state->color[2], state->color[3]);
 
-    const float *f = static_cast<const float *>(mConstants->getPtr());
+    const float *f = static_cast<const float *>(mConstants[0]->getPtr());
 
     Matrix mvp;
     mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
@@ -194,6 +221,54 @@
                            &f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]);
     }
 
+    uint32_t uidx = 1;
+    for (uint32_t ct=0; ct < mConstantCount; ct++) {
+        Allocation *alloc = mConstants[ct+1].get();
+        if (!alloc) {
+            continue;
+        }
+
+        const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
+        const Element *e = mConstantTypes[ct]->getElement();
+        for (uint32_t field=0; field < e->getFieldCount(); field++) {
+            const Element *f = e->getField(field);
+            uint32_t offset = e->getFieldOffsetBytes(field);
+            int32_t slot = sc->vtxUniformSlot(uidx);
+
+            const float *fd = reinterpret_cast<const float *>(&data[offset]);
+
+            //LOGE("Uniform  slot=%i, offset=%i, constant=%i, field=%i, uidx=%i", slot, offset, ct, field, uidx);
+            if (slot >= 0) {
+                switch(f->getComponent().getVectorSize()) {
+                case 1:
+                    //LOGE("Uniform 1 = %f", fd[0]);
+                    glUniform1fv(slot, 1, fd);
+                    break;
+                case 2:
+                    //LOGE("Uniform 2 = %f %f", fd[0], fd[1]);
+                    glUniform2fv(slot, 1, fd);
+                    break;
+                case 3:
+                    //LOGE("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
+                    glUniform3fv(slot, 1, fd);
+                    break;
+                case 4:
+                    //LOGE("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
+                    glUniform4fv(slot, 1, fd);
+                    break;
+                default:
+                    rsAssert(0);
+                }
+            }
+            uidx ++;
+        }
+    }
+
+    for (uint32_t ct=0; ct < mConstantCount; ct++) {
+        uint32_t glSlot = sc->vtxUniformSlot(ct + 1);
+
+    }
+
     state->mLast.set(this);
     rsc->checkError("ProgramVertex::setupGL2");
 }
@@ -208,46 +283,46 @@
 
 void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const
 {
-    float *f = static_cast<float *>(mConstants->getPtr());
+    float *f = static_cast<float *>(mConstants[0]->getPtr());
     memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
     mDirty = true;
 }
 
 void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const
 {
-    float *f = static_cast<float *>(mConstants->getPtr());
+    float *f = static_cast<float *>(mConstants[0]->getPtr());
     memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
     mDirty = true;
 }
 
 void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const
 {
-    float *f = static_cast<float *>(mConstants->getPtr());
+    float *f = static_cast<float *>(mConstants[0]->getPtr());
     memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
     mDirty = true;
 }
 
 void ProgramVertex::transformToScreen(const Context *rsc, float *v4out, const float *v3in) const
 {
-    float *f = static_cast<float *>(mConstants->getPtr());
+    float *f = static_cast<float *>(mConstants[0]->getPtr());
     Matrix mvp;
     mvp.loadMultiply((Matrix *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET],
                      (Matrix *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
     mvp.vectorMultiply(v4out, v3in);
 }
 
-void ProgramVertex::initAddUserAttrib(const Element *e)
+void ProgramVertex::initAddUserElement(const Element *e, String8 *names, uint32_t *count, const char *prefix)
 {
     rsAssert(e->getFieldCount());
     for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
         const Element *ce = e->getField(ct);
         if (ce->getFieldCount()) {
-            initAddUserAttrib(ce);
+            initAddUserElement(ce, names, count, prefix);
         } else {
-            String8 tmp("ATTRIB_");
+            String8 tmp(prefix);
             tmp.append(e->getFieldName(ct));
-            mAttribNames[mAttribCount].setTo(tmp.string());
-            mAttribCount++;
+            names[*count].setTo(tmp.string());
+            (*count)++;
         }
     }
 }
@@ -257,7 +332,13 @@
     if (mUserShader.size() > 0) {
         mAttribCount = 0;
         for (uint32_t ct=0; ct < mInputCount; ct++) {
-            initAddUserAttrib(mInputElements[ct].get());
+            initAddUserElement(mInputElements[ct].get(), mAttribNames, &mAttribCount, "ATTRIB_");
+        }
+
+        mUniformCount = 1;
+        mUniformNames[0].setTo("UNI_MVP");
+        for (uint32_t ct=0; ct < mInputCount; ct++) {
+            initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, &mUniformCount, "UNI_");
         }
     } else {
         mAttribCount = 5;
@@ -266,11 +347,11 @@
         mAttribNames[2].setTo("ATTRIB_Normal");
         mAttribNames[3].setTo("ATTRIB_PointSize");
         mAttribNames[4].setTo("ATTRIB_Texture");
-    }
 
-    mUniformCount = 2;
-    mUniformNames[0].setTo("uni_MVP");
-    mUniformNames[1].setTo("uni_TexMatrix");
+        mUniformCount = 2;
+        mUniformNames[0].setTo("UNI_MVP");
+        mUniformNames[1].setTo("UNI_TexMatrix");
+    }
 
     createShader();
 }
@@ -299,7 +380,7 @@
     mDefaultAlloc.set(alloc);
     mDefault.set(pv);
     pv->init(rsc);
-    pv->bindAllocation(alloc);
+    pv->bindAllocation(alloc, 0);
 
     color[0] = 1.f;
     color[1] = 1.f;
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index dcb988c..28554cc 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -61,7 +61,7 @@
     bool mTextureMatrixEnable;
 
 private:
-    void initAddUserAttrib(const Element *e);
+    void initAddUserElement(const Element *e, String8 *names, uint32_t *count, const char *prefix);
 };
 
 
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 8a0ab71..3ba9cee 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -973,6 +973,13 @@
     rsi_AllocationUploadToBufferObject(rsc, va);
 }
 
+static void SC_syncToGL(RsAllocation va)
+{
+    GET_TLS();
+    Allocation *a = static_cast<Allocation *>(va);
+
+}
+
 static void SC_ClearColor(float r, float g, float b, float a)
 {
     //LOGE("c %f %f %f %f", r, g, b, a);
@@ -1321,6 +1328,9 @@
     { "uploadToBufferObject", (void *)&SC_uploadToBufferObject,
         "void", "(int)" },
 
+    { "syncToGL", (void *)&SC_syncToGL,
+        "void", "(int)" },
+
     { "colorFloatRGBAtoUNorm8", (void *)&SC_colorFloatRGBAtoUNorm8,
         "int", "(float, float, float, float)" },
     { "colorFloatRGBto565", (void *)&SC_colorFloatRGBAto565,
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 0d9863de..8ac2487 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -132,7 +132,7 @@
                 LOGV("vtx U, %s = %d\n", vtx->getUniformName(ct).string(), e->mVtxUniformSlots[ct]);
             }
         }
-        for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
+        for (uint32_t ct=0; ct < frag->getUniformCount(); ct++) {
             e->mFragUniformSlots[ct] = glGetUniformLocation(pgm, frag->getUniformName(ct));
             if (rsc->props.mLogShaders) {
                 LOGV("frag U, %s = %d\n", frag->getUniformName(ct).string(), e->mFragUniformSlots[ct]);