Merge "State based shader recompile to support camera input."
diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp
index 30a4c5f..a96a5f9 100644
--- a/libs/rs/driver/rsdProgram.cpp
+++ b/libs/rs/driver/rsdProgram.cpp
@@ -71,10 +71,10 @@
     if(pv->mHal.drv) {
         drv = (RsdShader*)pv->mHal.drv;
         if (rsc->props.mLogShaders) {
-            ALOGV("Destroying vertex shader with ID %u", drv->getShaderID());
+            ALOGV("Destroying vertex shader with ID %u", (uint32_t)pv);
         }
-        if (drv->getShaderID()) {
-            dc->gl.shaderCache->cleanupVertex(drv->getShaderID());
+        if (drv->getStateBasedIDCount()) {
+            dc->gl.shaderCache->cleanupVertex(drv);
         }
         delete drv;
     }
@@ -105,10 +105,10 @@
     if(pf->mHal.drv) {
         drv = (RsdShader*)pf->mHal.drv;
         if (rsc->props.mLogShaders) {
-            ALOGV("Destroying fragment shader with ID %u", drv->getShaderID());
+            ALOGV("Destroying fragment shader with ID %u", (uint32_t)pf);
         }
-        if (drv->getShaderID()) {
-            dc->gl.shaderCache->cleanupFragment(drv->getShaderID());
+        if (drv->getStateBasedIDCount()) {
+            dc->gl.shaderCache->cleanupFragment(drv);
         }
         delete drv;
     }
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index a386735..6d9fa90 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -46,30 +46,74 @@
 }
 
 RsdShader::~RsdShader() {
-    if (mShaderID) {
-        glDeleteShader(mShaderID);
+    for (uint32_t i = 0; i < mStateBasedShaders.size(); i ++) {
+        StateBasedKey *state = mStateBasedShaders.itemAt(i);
+        if (state->mShaderID) {
+            glDeleteShader(state->mShaderID);
+        }
+        delete state;
     }
 
     delete[] mAttribNames;
     delete[] mUniformNames;
     delete[] mUniformArraySizes;
-    delete[] mTextureTargets;
 }
 
 void RsdShader::initMemberVars() {
     mDirty = true;
-    mShaderID = 0;
     mAttribCount = 0;
     mUniformCount = 0;
 
     mAttribNames = NULL;
     mUniformNames = NULL;
     mUniformArraySizes = NULL;
-    mTextureTargets = NULL;
+    mCurrentState = NULL;
 
     mIsValid = false;
 }
 
+RsdShader::StateBasedKey *RsdShader::getExistingState() {
+    RsdShader::StateBasedKey *returnKey = NULL;
+
+    for (uint32_t i = 0; i < mStateBasedShaders.size(); i ++) {
+        returnKey = mStateBasedShaders.itemAt(i);
+
+        for (uint32_t ct = 0; ct < mRSProgram->mHal.state.texturesCount; ct ++) {
+            uint32_t texType = 0;
+            if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
+                Allocation *a = mRSProgram->mHal.state.textures[ct];
+                if (a && a->mHal.state.surfaceTextureID) {
+                    texType = GL_TEXTURE_EXTERNAL_OES;
+                } else {
+                    texType = GL_TEXTURE_2D;
+                }
+            } else {
+                texType = GL_TEXTURE_CUBE_MAP;
+            }
+            if (texType != returnKey->mTextureTargets[ct]) {
+                returnKey = NULL;
+                break;
+            }
+        }
+    }
+    return returnKey;
+}
+
+uint32_t RsdShader::getStateBasedShaderID(const Context *rsc) {
+    StateBasedKey *state = getExistingState();
+    if (state != NULL) {
+        mCurrentState = state;
+        return mCurrentState->mShaderID;
+    }
+    // We have not created a shader for this particular state yet
+    state = new StateBasedKey(mTextureCount);
+    mCurrentState = state;
+    mStateBasedShaders.add(state);
+    createShader();
+    loadShader(rsc);
+    return mCurrentState->mShaderID;
+}
+
 void RsdShader::init(const char** textureNames, size_t textureNamesCount,
                      const size_t *textureNamesLength) {
     uint32_t attribCount = 0;
@@ -155,14 +199,14 @@
                     appendUsing = false;
                 }
                 mShader.append("uniform samplerExternalOES UNI_");
-                mTextureTargets[ct] = GL_TEXTURE_EXTERNAL_OES;
+                mCurrentState->mTextureTargets[ct] = GL_TEXTURE_EXTERNAL_OES;
             } else {
                 mShader.append("uniform sampler2D UNI_");
-                mTextureTargets[ct] = GL_TEXTURE_2D;
+                mCurrentState->mTextureTargets[ct] = GL_TEXTURE_2D;
             }
         } else {
             mShader.append("uniform samplerCube UNI_");
-            mTextureTargets[ct] = GL_TEXTURE_CUBE_MAP;
+            mCurrentState->mTextureTargets[ct] = GL_TEXTURE_CUBE_MAP;
         }
 
         mShader.append(mTextureNames[ct]);
@@ -171,6 +215,7 @@
 }
 
 bool RsdShader::createShader() {
+    mShader.clear();
     if (mType == GL_FRAGMENT_SHADER) {
         mShader.append("precision mediump float;\n");
     }
@@ -183,37 +228,37 @@
 }
 
 bool RsdShader::loadShader(const Context *rsc) {
-    mShaderID = glCreateShader(mType);
-    rsAssert(mShaderID);
+    mCurrentState->mShaderID = glCreateShader(mType);
+    rsAssert(mCurrentState->mShaderID);
 
     if(!mShader.length()) {
         createShader();
     }
 
     if (rsc->props.mLogShaders) {
-        ALOGV("Loading shader type %x, ID %i", mType, mShaderID);
+        ALOGV("Loading shader type %x, ID %i", mType, mCurrentState->mShaderID);
         ALOGV("%s", mShader.string());
     }
 
-    if (mShaderID) {
+    if (mCurrentState->mShaderID) {
         const char * ss = mShader.string();
-        RSD_CALL_GL(glShaderSource, mShaderID, 1, &ss, NULL);
-        RSD_CALL_GL(glCompileShader, mShaderID);
+        RSD_CALL_GL(glShaderSource, mCurrentState->mShaderID, 1, &ss, NULL);
+        RSD_CALL_GL(glCompileShader, mCurrentState->mShaderID);
 
         GLint compiled = 0;
-        RSD_CALL_GL(glGetShaderiv, mShaderID, GL_COMPILE_STATUS, &compiled);
+        RSD_CALL_GL(glGetShaderiv, mCurrentState->mShaderID, GL_COMPILE_STATUS, &compiled);
         if (!compiled) {
             GLint infoLen = 0;
-            RSD_CALL_GL(glGetShaderiv, mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
+            RSD_CALL_GL(glGetShaderiv, mCurrentState->mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
             if (infoLen) {
                 char* buf = (char*) malloc(infoLen);
                 if (buf) {
-                    RSD_CALL_GL(glGetShaderInfoLog, mShaderID, infoLen, NULL, buf);
+                    RSD_CALL_GL(glGetShaderInfoLog, mCurrentState->mShaderID, infoLen, NULL, buf);
                     rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
                     free(buf);
                 }
-                RSD_CALL_GL(glDeleteShader, mShaderID);
-                mShaderID = 0;
+                RSD_CALL_GL(glDeleteShader, mCurrentState->mShaderID);
+                mCurrentState->mShaderID = 0;
                 return false;
             }
         }
@@ -430,7 +475,7 @@
 
         if (!mRSProgram->mHal.state.textures[ct]) {
             // if nothing is bound, reset to default GL texture
-            RSD_CALL_GL(glBindTexture, mTextureTargets[ct], 0);
+            RSD_CALL_GL(glBindTexture, mCurrentState->mTextureTargets[ct], 0);
             continue;
         }
 
@@ -537,9 +582,6 @@
     }
 
     mTextureCount = mRSProgram->mHal.state.texturesCount;
-    if (mTextureCount) {
-        mTextureTargets = new uint32_t[mTextureCount];
-    }
 }
 
 void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths,
diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h
index 6c0b616..2680b3e 100644
--- a/libs/rs/driver/rsdShader.h
+++ b/libs/rs/driver/rsdShader.h
@@ -44,9 +44,13 @@
               const size_t *textureNamesLength);
     virtual ~RsdShader();
 
-    bool createShader();
+    uint32_t getStateBasedShaderID(const android::renderscript::Context *);
 
-    uint32_t getShaderID() const {return mShaderID;}
+    // Add ability to get all ID's to clean up the cached program objects
+    uint32_t getStateBasedIDCount() const { return mStateBasedShaders.size(); }
+    uint32_t getStateBasedID(uint32_t index) const {
+        return mStateBasedShaders.itemAt(index)->mShaderID;
+    }
 
     uint32_t getAttribCount() const {return mAttribCount;}
     uint32_t getUniformCount() const {return mUniformCount;}
@@ -64,6 +68,21 @@
 
 protected:
 
+    class StateBasedKey {
+    public:
+        StateBasedKey(uint32_t texCount) : mShaderID(0) {
+            mTextureTargets = new uint32_t[texCount];
+        }
+        ~StateBasedKey() {
+            delete[] mTextureTargets;
+        }
+        uint32_t mShaderID;
+        uint32_t *mTextureTargets;
+    };
+
+    bool createShader();
+    StateBasedKey *getExistingState();
+
     const android::renderscript::Program *mRSProgram;
     bool mIsValid;
 
@@ -87,11 +106,10 @@
     mutable bool mDirty;
     android::String8 mShader;
     android::String8 mUserShader;
-    uint32_t mShaderID;
     uint32_t mType;
 
     uint32_t mTextureCount;
-    uint32_t *mTextureTargets;
+    StateBasedKey *mCurrentState;
     uint32_t mAttribCount;
     uint32_t mUniformCount;
     android::String8 *mAttribNames;
@@ -100,6 +118,8 @@
 
     android::Vector<android::String8> mTextureNames;
 
+    android::Vector<StateBasedKey*> mStateBasedShaders;
+
     int32_t mTextureUniformIndexStart;
 
     void logUniform(const android::renderscript::Element *field,
diff --git a/libs/rs/driver/rsdShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
index 50cb9f9..69b43fc 100644
--- a/libs/rs/driver/rsdShaderCache.cpp
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -108,21 +108,17 @@
 
     RsdShader *vtx = mVertex;
     RsdShader *frag = mFragment;
-    if (!vtx->getShaderID()) {
-        vtx->loadShader(rsc);
-    }
-    if (!frag->getShaderID()) {
-        frag->loadShader(rsc);
-    }
+
+    uint32_t vID = vtx->getStateBasedShaderID(rsc);
+    uint32_t fID = frag->getStateBasedShaderID(rsc);
 
     // Don't try to cache if shaders failed to load
-    if (!vtx->getShaderID() || !frag->getShaderID()) {
+    if (!vID || !fID) {
         return false;
     }
     uint32_t entryCount = mEntries.size();
     for (uint32_t ct = 0; ct < entryCount; ct ++) {
-        if ((mEntries[ct]->vtx == vtx->getShaderID()) &&
-            (mEntries[ct]->frag == frag->getShaderID())) {
+        if ((mEntries[ct]->vtx == vID) && (mEntries[ct]->frag == fID)) {
 
             //ALOGV("SC using program %i", mEntries[ct]->program);
             glUseProgram(mEntries[ct]->program);
@@ -138,14 +134,14 @@
                                        frag->getUniformCount());
     mEntries.push(e);
     mCurrent = e;
-    e->vtx = vtx->getShaderID();
-    e->frag = frag->getShaderID();
+    e->vtx = vID;
+    e->frag = fID;
     e->program = glCreateProgram();
     if (e->program) {
         GLuint pgm = e->program;
-        glAttachShader(pgm, vtx->getShaderID());
+        glAttachShader(pgm, vID);
         //ALOGE("e1 %x", glGetError());
-        glAttachShader(pgm, frag->getShaderID());
+        glAttachShader(pgm, fID);
 
         glBindAttribLocation(pgm, 0, "ATTRIB_position");
         glBindAttribLocation(pgm, 1, "ATTRIB_color");
@@ -241,30 +237,38 @@
     return -1;
 }
 
-void RsdShaderCache::cleanupVertex(uint32_t id) {
+void RsdShaderCache::cleanupVertex(RsdShader *s) {
     int32_t numEntries = (int32_t)mEntries.size();
-    for (int32_t ct = 0; ct < numEntries; ct ++) {
-        if (mEntries[ct]->vtx == id) {
-            glDeleteProgram(mEntries[ct]->program);
+    uint32_t numShaderIDs = s->getStateBasedIDCount();
+    for (uint32_t sId = 0; sId < numShaderIDs; sId ++) {
+        uint32_t id = s->getStateBasedID(sId);
+        for (int32_t ct = 0; ct < numEntries; ct ++) {
+            if (mEntries[ct]->vtx == id) {
+                glDeleteProgram(mEntries[ct]->program);
 
-            delete mEntries[ct];
-            mEntries.removeAt(ct);
-            numEntries = (int32_t)mEntries.size();
-            ct --;
+                delete mEntries[ct];
+                mEntries.removeAt(ct);
+                numEntries = (int32_t)mEntries.size();
+                ct --;
+            }
         }
     }
 }
 
-void RsdShaderCache::cleanupFragment(uint32_t id) {
+void RsdShaderCache::cleanupFragment(RsdShader *s) {
     int32_t numEntries = (int32_t)mEntries.size();
-    for (int32_t ct = 0; ct < numEntries; ct ++) {
-        if (mEntries[ct]->frag == id) {
-            glDeleteProgram(mEntries[ct]->program);
+    uint32_t numShaderIDs = s->getStateBasedIDCount();
+    for (uint32_t sId = 0; sId < numShaderIDs; sId ++) {
+        uint32_t id = s->getStateBasedID(sId);
+        for (int32_t ct = 0; ct < numEntries; ct ++) {
+            if (mEntries[ct]->frag == id) {
+                glDeleteProgram(mEntries[ct]->program);
 
-            delete mEntries[ct];
-            mEntries.removeAt(ct);
-            numEntries = (int32_t)mEntries.size();
-            ct --;
+                delete mEntries[ct];
+                mEntries.removeAt(ct);
+                numEntries = (int32_t)mEntries.size();
+                ct --;
+            }
         }
     }
 }
diff --git a/libs/rs/driver/rsdShaderCache.h b/libs/rs/driver/rsdShaderCache.h
index 1192916..88aa32d 100644
--- a/libs/rs/driver/rsdShaderCache.h
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -49,8 +49,8 @@
 
     bool setup(const android::renderscript::Context *rsc);
 
-    void cleanupVertex(uint32_t id);
-    void cleanupFragment(uint32_t id);
+    void cleanupVertex(RsdShader *s);
+    void cleanupFragment(RsdShader *s);
 
     void cleanupAll();