Support constant and varying colors in ProgramFragment.

Change-Id: I16ce84ff427016f3a1923594efc718eca32dd7f2
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
index d06d768..04091a3 100644
--- a/graphics/java/android/renderscript/ProgramFragment.java
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -66,6 +66,7 @@
         public static final int MAX_TEXTURE = 2;
         RenderScript mRS;
         boolean mPointSpriteEnable;
+        boolean mVaryingColorEnable;
 
         public enum EnvMode {
             REPLACE (1),
@@ -120,9 +121,14 @@
             return this;
         }
 
+        public Builder setVaryingColor(boolean enable) {
+            mVaryingColorEnable = enable;
+            return this;
+        }
+
         public ProgramFragment create() {
             mRS.validate();
-            int[] tmp = new int[MAX_TEXTURE * 2 + 1];
+            int[] tmp = new int[MAX_TEXTURE * 2 + 2];
             if (mSlots[0] != null) {
                 tmp[0] = mSlots[0].env.mID;
                 tmp[1] = mSlots[0].format.mID;
@@ -132,6 +138,7 @@
                 tmp[3] = mSlots[1].format.mID;
             }
             tmp[4] = mPointSpriteEnable ? 1 : 0;
+            tmp[5] = mVaryingColorEnable ? 1 : 0;
             int id = mRS.nProgramFragmentCreate(tmp);
             ProgramFragment pf = new ProgramFragment(id, mRS);
             pf.mTextureCount = MAX_TEXTURE;
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index bff7273..297ea07 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -34,6 +34,10 @@
         mRS = rs;
         mRes = res;
 
+        ProgramFragment.Builder pfb = new ProgramFragment.Builder(rs);
+        pfb.setVaryingColor(true);
+        rs.contextBindProgramFragment(pfb.create());
+
         ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
 
         Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs b/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs
index f87ef59..812cb7a 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs
+++ b/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs
@@ -3,6 +3,8 @@
 
 #pragma rs java_package_name(com.android.fountain)
 
+#pragma stateFragment(parent)
+
 #include "rs_graphics.rsh"
 
 static int newPart = 0;
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index e58d8b1..a741adc 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -379,12 +379,12 @@
 
 void FontState::initRenderState()
 {
-    uint32_t tmp[5] = {
+    uint32_t tmp[] = {
         RS_TEX_ENV_MODE_REPLACE, 1,
         RS_TEX_ENV_MODE_NONE, 0,
-        0
+        0, 0
     };
-    ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 5);
+    ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 6);
     mFontShaderF.set(pf);
     mFontShaderF->init(mRSC);
 
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index cbe33c7..056863c 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -38,13 +38,21 @@
 {
     mAllocFile = __FILE__;
     mAllocLine = __LINE__;
-    rsAssert(paramLength = 5);
+    rsAssert(paramLength == 6);
+
+    mConstantColor[0] = 1.f;
+    mConstantColor[1] = 1.f;
+    mConstantColor[2] = 1.f;
+    mConstantColor[3] = 1.f;
 
     mEnvModes[0] = (RsTexEnvMode)params[0];
     mTextureFormats[0] = params[1];
     mEnvModes[1] = (RsTexEnvMode)params[2];
     mTextureFormats[1] = params[3];
     mPointSpriteEnable = params[4] != 0;
+    mVaryingColor = false;
+    if (paramLength > 5)
+        mVaryingColor = params[5] != 0;
 
     mTextureEnableMask = 0;
     if (mEnvModes[0]) {
@@ -53,7 +61,17 @@
     if (mEnvModes[1]) {
         mTextureEnableMask |= 2;
     }
-    init(rsc);
+
+    mUniformCount = 0;
+    mUniformNames[mUniformCount++].setTo("uni_Tex0");
+    mUniformNames[mUniformCount++].setTo("uni_Tex1");
+
+    mConstantColorUniformIndex = -1;
+    //if (!mVaryingColor) {
+        mConstantColorUniformIndex = mUniformCount;
+        mUniformNames[mUniformCount++].setTo("uni_Color");
+    //}
+    createShader();
 }
 
 ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText,
@@ -64,7 +82,19 @@
     mAllocFile = __FILE__;
     mAllocLine = __LINE__;
 
-    init(rsc);
+    mConstantColor[0] = 1.f;
+    mConstantColor[1] = 1.f;
+    mConstantColor[2] = 1.f;
+    mConstantColor[3] = 1.f;
+
+    LOGE("Custom FP");
+
+    mUniformCount = 2;
+    mUniformNames[0].setTo("uni_Tex0");
+    mUniformNames[1].setTo("uni_Tex1");
+
+    createShader();
+
     mTextureEnableMask = (1 << mTextureCount) -1;
 }
 
@@ -73,79 +103,17 @@
 {
 }
 
+void ProgramFragment::setConstantColor(float r, float g, float b, float a)
+{
+    mConstantColor[0] = r;
+    mConstantColor[1] = g;
+    mConstantColor[2] = b;
+    mConstantColor[3] = a;
+    mDirty = true;
+}
+
 void ProgramFragment::setupGL(const Context *rsc, ProgramFragmentState *state)
 {
-    if ((state->mLast.get() == this) && !mDirty) {
-        return;
-    }
-    state->mLast.set(this);
-
-    for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
-        glActiveTexture(GL_TEXTURE0 + ct);
-        if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) {
-            glDisable(GL_TEXTURE_2D);
-            continue;
-        }
-
-        glEnable(GL_TEXTURE_2D);
-        if (rsc->checkVersion1_1()) {
-#ifndef ANDROID_RS_BUILD_FOR_HOST // These are GLES only
-            if (mPointSpriteEnable) {
-                glEnable(GL_POINT_SPRITE_OES);
-            } else {
-                glDisable(GL_POINT_SPRITE_OES);
-            }
-            glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, mPointSpriteEnable);
-#endif //ANDROID_RS_BUILD_FOR_HOST
-
-        }
-        mTextures[ct]->uploadCheck(rsc);
-        glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
-
-        switch(mEnvModes[ct]) {
-        case RS_TEX_ENV_MODE_NONE:
-            rsAssert(0);
-            break;
-        case RS_TEX_ENV_MODE_REPLACE:
-            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-            break;
-        case RS_TEX_ENV_MODE_MODULATE:
-            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-            break;
-        case RS_TEX_ENV_MODE_DECAL:
-            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
-            break;
-        }
-
-        if (mSamplers[ct].get()) {
-            mSamplers[ct]->setupGL(rsc, mTextures[ct]->getType()->getIsNp2());
-        } else {
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-        }
-
-        // Gross hack.
-        if (ct == 2) {
-            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-
-            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
-            glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
-            glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
-            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
-
-            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
-            glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
-            glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
-            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
-        }
-    }
-    glActiveTexture(GL_TEXTURE0);
-    mDirty = false;
-    rsc->checkError("ProgramFragment::setupGL");
 }
 
 void ProgramFragment::setupGL2(const Context *rsc, ProgramFragmentState *state, ShaderCache *sc)
@@ -158,6 +126,14 @@
     state->mLast.set(this);
 
     rsc->checkError("ProgramFragment::setupGL2 start");
+
+    if (!mVaryingColor &&
+        (sc->fragUniformSlot(mConstantColorUniformIndex) >= 0)) {
+        //LOGE("mConstantColorUniformIndex %i %i", mConstantColorUniformIndex, sc->fragUniformSlot(mConstantColorUniformIndex));
+        glUniform4fv(sc->fragUniformSlot(mConstantColorUniformIndex), 1, mConstantColor);
+        rsc->checkError("ProgramFragment::color setup");
+    }
+
     for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
         glActiveTexture(GL_TEXTURE0 + ct);
         if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) {
@@ -195,6 +171,7 @@
     mShader.setTo("precision mediump float;\n");
     mShader.append("varying vec4 varColor;\n");
     mShader.append("varying vec4 varTex0;\n");
+    mShader.append("uniform vec4 uni_Color;\n");
 
     if (mUserShader.length() > 1) {
         for (uint32_t ct=0; ct < mTextureCount; ct++) {
@@ -221,7 +198,11 @@
 
 
         mShader.append("void main() {\n");
-        mShader.append("  vec4 col = varColor;\n");
+        if (mVaryingColor) {
+            mShader.append("  vec4 col = varColor;\n");
+        } else {
+            mShader.append("  vec4 col = uni_Color;\n");
+        }
 
         if (mTextureEnableMask) {
             if (mPointSpriteEnable) {
@@ -291,11 +272,6 @@
 
 void ProgramFragment::init(Context *rsc)
 {
-    mUniformCount = 2;
-    mUniformNames[0].setTo("uni_Tex0");
-    mUniformNames[1].setTo("uni_Tex1");
-
-    createShader();
 }
 
 void ProgramFragment::serialize(OStream *stream) const
@@ -321,12 +297,12 @@
 
 void ProgramFragmentState::init(Context *rsc)
 {
-    uint32_t tmp[5] = {
+    uint32_t tmp[] = {
         RS_TEX_ENV_MODE_NONE, 0,
         RS_TEX_ENV_MODE_NONE, 0,
-        0
+        0, 0
     };
-    ProgramFragment *pf = new ProgramFragment(rsc, tmp, 5);
+    ProgramFragment *pf = new ProgramFragment(rsc, tmp, 6);
     mDefault.set(pf);
     pf->init(rsc);
 }
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index e5bbe1b..7c1598e 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -44,6 +44,8 @@
     virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_FRAGMENT; }
     static ProgramFragment *createFromStream(Context *rsc, IStream *stream);
 
+    void setConstantColor(float, float, float, float);
+
 protected:
     // Hacks to create a program for now
     uint32_t mTextureFormats[MAX_TEXTURE];
@@ -51,6 +53,10 @@
     RsTexEnvMode mEnvModes[MAX_TEXTURE];
     uint32_t mTextureEnableMask;
     bool mPointSpriteEnable;
+    bool mVaryingColor;
+
+    float mConstantColor[4];
+    int32_t mConstantColorUniformIndex;
 };
 
 class ProgramFragmentState
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 5558007..60de04a 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -221,7 +221,6 @@
     }
 
     rsc->checkError("ProgramVertex::setupGL2 start");
-    glVertexAttrib4f(1, state->color[0], state->color[1], state->color[2], state->color[3]);
 
     const float *f = static_cast<const float *>(mConstants[0]->getPtr());
 
@@ -405,11 +404,6 @@
     pv->init(rsc);
     pv->bindAllocation(alloc, 0);
 
-    color[0] = 1.f;
-    color[1] = 1.f;
-    color[2] = 1.f;
-    color[3] = 1.f;
-
     updateSize(rsc);
 #endif //ANDROID_RS_BUILD_FOR_HOST
 
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index cb93eaf..1c8b9c8 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -83,9 +83,6 @@
     ObjectBaseRef<Allocation> mDefaultAlloc;
 
     ObjectBaseRef<Type> mAllocType;
-
-
-    float color[4];
 };
 
 
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 22b0945..f5e59534 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -110,6 +110,13 @@
 }
 
 
+static void SC_pfConstantColor(RsProgramFragment vpf, float r, float g, float b, float a)
+{
+    //GET_TLS();
+    ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+    pf->setConstantColor(r, g, b, a);
+}
+
 
 //////////////////////////////////////////////////////////////////////////////
 // Drawing
@@ -253,13 +260,8 @@
 static void SC_color(float r, float g, float b, float a)
 {
     GET_TLS();
-    rsc->mStateVertex.color[0] = r;
-    rsc->mStateVertex.color[1] = g;
-    rsc->mStateVertex.color[2] = b;
-    rsc->mStateVertex.color[3] = a;
-    if (!rsc->checkVersion2_0()) {
-        glColor4f(r, g, b, a);
-    }
+    ProgramFragment *pf = (ProgramFragment *)rsc->getFragment();
+    pf->setConstantColor(r, g, b, a);
 }
 
 static void SC_uploadToTexture2(RsAllocation va, uint32_t baseMipLevel)
@@ -371,6 +373,8 @@
     { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadModelMatrix },
     { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadTextureMatrix },
 
+    { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_pfConstantColor },
+
     { "_Z11rsgGetWidthv", (void *)&SC_getWidth },
     { "_Z12rsgGetHeightv", (void *)&SC_getHeight },
 
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index 4f53963..fd0491c 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -26,6 +26,9 @@
 extern void __attribute__((overloadable))
     rsgProgramVertexLoadTextureMatrix(const rs_matrix4x4 *);
 
+extern void __attribute__((overloadable))
+    rsgProgramFragmentConstantColor(rs_program_fragment, float, float, float, float);
+
 extern uint __attribute__((overloadable))
     rsgGetWidth(void);
 extern uint __attribute__((overloadable))
@@ -76,6 +79,8 @@
 
 ///////////////////////////////////////////////////////
 // misc
+
+// Depricated
 extern void __attribute__((overloadable))
     color(float, float, float, float);