Merge "Improve RS error handling.  On errors RS will now store the error and a message that can be read from the app.  RS will then not continue rendering frames while an unchecked error is present until new state is received."
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index cd8361c..d280f50 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -202,6 +202,12 @@
     RS_PRIMITIVE_TRIANGLE_FAN
 };
 
+enum RsError {
+    RS_ERROR_NONE,
+    RS_ERROR_BAD_SHADER,
+    RS_ERROR_BAD_SCRIPT
+};
+
 #ifndef NO_RS_FUNCS
 #include "rsgApiFuncDecl.h"
 #endif
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 4d97c0f..cb9937c 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -36,6 +36,11 @@
 	param int32_t bits
 }
 
+ContextGetError {
+	param RsError *err
+	ret const char *
+	}
+
 ContextSetPriority {
 	param int32_t priority
 	}
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index cc3a74fb..d8a9a99 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -178,6 +178,11 @@
     uint32_t ret = runScript(mRootScript.get(), 0);
 
     checkError("runRootScript");
+    if (mError != RS_ERROR_NONE) {
+        // If we have an error condition we stop rendering until
+        // somthing changes that might fix it.
+        ret = 0;
+    }
     return ret;
 }
 
@@ -240,10 +245,13 @@
     }
 }
 
-void Context::setupCheck()
+bool Context::setupCheck()
 {
     if (checkVersion2_0()) {
-        mShaderCache.lookup(this, mVertex.get(), mFragment.get());
+        if (!mShaderCache.lookup(this, mVertex.get(), mFragment.get())) {
+            LOGE("Context::setupCheck() 1 fail");
+            return false;
+        }
 
         mFragmentStore->setupGL2(this, &mStateFragmentStore);
         mFragment->setupGL2(this, &mStateFragment, &mShaderCache);
@@ -256,6 +264,7 @@
         mRaster->setupGL(this, &mStateRaster);
         mVertex->setupGL(this, &mStateVertex);
     }
+    return true;
 }
 
 static bool getProp(const char *str)
@@ -389,6 +398,9 @@
     mUseDepth = useDepth;
     mPaused = false;
     mObjHead = NULL;
+    mError = RS_ERROR_NONE;
+    mErrorMsg = NULL;
+
     memset(&mEGL, 0, sizeof(mEGL));
     memset(&mGL, 0, sizeof(mGL));
     mIsGraphicsContext = isGraphics;
@@ -764,6 +776,23 @@
     mIO.mToClient.shutdown();
 }
 
+const char * Context::getError(RsError *err)
+{
+    *err = mError;
+    mError = RS_ERROR_NONE;
+    if (*err != RS_ERROR_NONE) {
+        return mErrorMsg;
+    }
+    return NULL;
+}
+
+void Context::setError(RsError e, const char *msg)
+{
+    mError = e;
+    mErrorMsg = msg;
+}
+
+
 void Context::dumpDebug() const
 {
     LOGE("RS Context debug %p", this);
@@ -874,6 +903,15 @@
     ObjectBase::dumpAll(rsc);
 }
 
+const char * rsi_ContextGetError(Context *rsc, RsError *e)
+{
+    const char *msg = rsc->getError(e);
+    if (*e != RS_ERROR_NONE) {
+        LOGE("RS Error %i %s", *e, msg);
+    }
+    return msg;
+}
+
 }
 }
 
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 04bd748..82c3687 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -93,7 +93,7 @@
     const ProgramRaster * getRaster() {return mRaster.get();}
     const ProgramVertex * getVertex() {return mVertex.get();}
 
-    void setupCheck();
+    bool setupCheck();
     bool checkDriver() const {return mEGL.mSurface != 0;}
 
     void pause();
@@ -160,6 +160,8 @@
 
     void dumpDebug() const;
     void checkError(const char *) const;
+    const char * getError(RsError *);
+    void setError(RsError e, const char *msg);
 
     mutable const ObjectBase * mObjHead;
 
@@ -211,6 +213,8 @@
     bool mExit;
     bool mUseDepth;
     bool mPaused;
+    RsError mError;
+    const char *mErrorMsg;
 
     pthread_t mThreadId;
     pid_t mNativeThreadId;
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 656a3c3..478a6dc 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -39,6 +39,7 @@
     mInputCount = 0;
     mOutputCount = 0;
     mConstantCount = 0;
+    mIsValid = false;
 }
 
 Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
@@ -216,6 +217,7 @@
                 }
                 glDeleteShader(mShaderID);
                 mShaderID = 0;
+                rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
                 return false;
             }
         }
@@ -224,6 +226,7 @@
     if (rsc->props.mLogShaders) {
         LOGV("--Shader load result %x ", glGetError());
     }
+    mIsValid = true;
     return true;
 }
 
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index a34e89f..86f85fb 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -59,6 +59,8 @@
     String8 getGLSLOutputString() const;
     String8 getGLSLConstantString() const;
 
+    bool isValid() const {return mIsValid;}
+
 protected:
     // Components not listed in "in" will be passed though
     // unless overwritten by components in out.
@@ -68,6 +70,7 @@
     uint32_t mInputCount;
     uint32_t mOutputCount;
     uint32_t mConstantCount;
+    bool mIsValid;
 
     ObjectBaseRef<Allocation> mConstants[MAX_UNIFORMS];
 
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index cb1436b..a33933b 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -96,6 +96,10 @@
 void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot)
 {
     Script *s = static_cast<Script *>(vs);
+    if (s->mEnviroment.mInvokables[slot] == NULL) {
+        rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
+        return;
+    }
     s->setupScript();
     s->mEnviroment.mInvokables[slot]();
 }
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index b7e0b86..1f23773 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -62,6 +62,11 @@
 
 uint32_t ScriptC::run(Context *rsc, uint32_t launchIndex)
 {
+    if (mProgram.mScript == NULL) {
+        rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
+        return 0;
+    }
+
     Context::ScriptTLSStruct * tls =
     (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
     rsAssert(tls);
@@ -154,7 +159,9 @@
         ACCchar buf[4096];
         ACCsizei len;
         accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf);
-        LOGV(buf);
+        LOGE(buf);
+        rsc->setError(RS_ERROR_BAD_SCRIPT, "Error compiling user script.");
+        return;
     }
 
     if (s->mProgram.mInit) {
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 235c153..202ca3d 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -683,7 +683,9 @@
                         float x2, float y2, float z2)
 {
     GET_TLS();
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
 
     float vtx[] = { x1, y1, z1, x2, y2, z2 };
     VertexArray va;
@@ -700,7 +702,9 @@
 static void SC_drawPoint(float x, float y, float z)
 {
     GET_TLS();
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
 
     float vtx[] = { x, y, z };
 
@@ -725,7 +729,9 @@
                                  float u4, float v4)
 {
     GET_TLS();
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
 
     //LOGE("Quad");
     //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
@@ -782,7 +788,9 @@
         float cx0, float cy0, float cx1, float cy1)
 {
     GET_TLS();
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
 
     GLint crop[4] = {cx0, cy0, cx1, cy1};
     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
@@ -831,7 +839,9 @@
 {
     GET_TLS();
     SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
     sm->render(rsc);
 }
 
@@ -839,7 +849,9 @@
 {
     GET_TLS();
     SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
     sm->renderRange(rsc, start, len);
 }
 
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 3a1f370..4711d1b 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -123,6 +123,8 @@
                 }
             }
             glDeleteProgram(pgm);
+            rsc->setError(RS_ERROR_BAD_SHADER, "Error linking GL Programs");
+            return false;
         }
         if (vtx->isUserProgram()) {
             for (uint32_t ct=0; ct < vtx->getAttribCount(); ct++) {
@@ -146,6 +148,7 @@
         }
     }
 
+    e->mIsValid = true;
     //LOGV("SC made program %i", e->program);
     glUseProgram(e->program);
     mEntryCount++;
diff --git a/libs/rs/rsShaderCache.h b/libs/rs/rsShaderCache.h
index 7aa8183..df99ccc 100644
--- a/libs/rs/rsShaderCache.h
+++ b/libs/rs/rsShaderCache.h
@@ -56,6 +56,7 @@
         int32_t mFragAttribSlots[Program::MAX_ATTRIBS];
         int32_t mFragUniformSlots[Program::MAX_UNIFORMS];
         bool mUserVertexProgram;
+        bool mIsValid;
     } entry_t;
     entry_t *mEntries;
     entry_t *mCurrent;
diff --git a/libs/rs/spec.l b/libs/rs/spec.l
index d81d47e..6a9010fe 100644
--- a/libs/rs/spec.l
+++ b/libs/rs/spec.l
@@ -148,6 +148,9 @@
     BEGIN(api_entry2);
     }
 
+<api_entry2>"*" {
+    currType->ptrLevel ++;
+    }
 
 <api_entry2>"}" {
     apiCount++;