Add RS watchdog.

Change-Id: I4c912beb84fa8a37ada0088049f7776132e994b6
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index 17dd931..2ebfe0a 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -73,27 +73,27 @@
 }
 
 
-static void Update2DTexture(const Allocation *alloc, const void *ptr, uint32_t xoff, uint32_t yoff,
-                     uint32_t lod, RsAllocationCubemapFace face,
-                     uint32_t w, uint32_t h) {
+static void Update2DTexture(const Context *rsc, const Allocation *alloc, const void *ptr,
+                            uint32_t xoff, uint32_t yoff, uint32_t lod,
+                            RsAllocationCubemapFace face, uint32_t w, uint32_t h) {
     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
 
     rsAssert(drv->textureID);
-    glBindTexture(drv->glTarget, drv->textureID);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
+    RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
     GLenum t = GL_TEXTURE_2D;
     if (alloc->mHal.state.hasFaces) {
         t = gFaceOrder[face];
     }
-    glTexSubImage2D(t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr);
+    RSD_CALL_GL(glTexSubImage2D, t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr);
 }
 
 
 static void Upload2DTexture(const Context *rsc, const Allocation *alloc, bool isFirstUpload) {
     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
 
-    glBindTexture(drv->glTarget, drv->textureID);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
+    RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
 
     uint32_t faceCount = 1;
     if (alloc->mHal.state.hasFaces) {
@@ -112,12 +112,12 @@
             }
 
             if (isFirstUpload) {
-                glTexImage2D(t, lod, drv->glFormat,
+                RSD_CALL_GL(glTexImage2D, t, lod, drv->glFormat,
                              alloc->mHal.state.type->getLODDimX(lod),
                              alloc->mHal.state.type->getLODDimY(lod),
                              0, drv->glFormat, drv->glType, p);
             } else {
-                glTexSubImage2D(t, lod, 0, 0,
+                RSD_CALL_GL(glTexSubImage2D, t, lod, 0, 0,
                                 alloc->mHal.state.type->getLODDimX(lod),
                                 alloc->mHal.state.type->getLODDimY(lod),
                                 drv->glFormat, drv->glType, p);
@@ -126,7 +126,7 @@
     }
 
     if (alloc->mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
-        glGenerateMipmap(drv->glTarget);
+        RSD_CALL_GL(glGenerateMipmap, drv->glTarget);
     }
     rsdGLCheckError(rsc, "Upload2DTexture");
 }
@@ -145,7 +145,7 @@
     bool isFirstUpload = false;
 
     if (!drv->textureID) {
-        glGenTextures(1, &drv->textureID);
+        RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
         isFirstUpload = true;
     }
 
@@ -168,7 +168,7 @@
     }
 
     if (!drv->renderTargetID) {
-        glGenRenderbuffers(1, &drv->renderTargetID);
+        RSD_CALL_GL(glGenRenderbuffers, 1, &drv->renderTargetID);
 
         if (!drv->renderTargetID) {
             // This should generally not happen
@@ -176,8 +176,8 @@
             rsc->dumpDebug();
             return;
         }
-        glBindRenderbuffer(GL_RENDERBUFFER, drv->renderTargetID);
-        glRenderbufferStorage(GL_RENDERBUFFER, drv->glFormat,
+        RSD_CALL_GL(glBindRenderbuffer, GL_RENDERBUFFER, drv->renderTargetID);
+        RSD_CALL_GL(glRenderbufferStorage, GL_RENDERBUFFER, drv->glFormat,
                               alloc->mHal.state.dimensionX, alloc->mHal.state.dimensionY);
     }
     rsdGLCheckError(rsc, "AllocateRenderTarget");
@@ -192,17 +192,17 @@
     //alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
 
     if (!drv->bufferID) {
-        glGenBuffers(1, &drv->bufferID);
+        RSD_CALL_GL(glGenBuffers, 1, &drv->bufferID);
     }
     if (!drv->bufferID) {
         LOGE("Upload to buffer object failed");
         drv->uploadDeferred = true;
         return;
     }
-    glBindBuffer(drv->glTarget, drv->bufferID);
-    glBufferData(drv->glTarget, alloc->mHal.state.type->getSizeBytes(),
+    RSD_CALL_GL(glBindBuffer, drv->glTarget, drv->bufferID);
+    RSD_CALL_GL(glBufferData, drv->glTarget, alloc->mHal.state.type->getSizeBytes(),
                  drv->mallocPtr, GL_DYNAMIC_DRAW);
-    glBindBuffer(drv->glTarget, 0);
+    RSD_CALL_GL(glBindBuffer, drv->glTarget, 0);
     rsdGLCheckError(rsc, "UploadToBufferObject");
 }
 
@@ -261,11 +261,11 @@
         //mBufferID = 0;
     }
     if (drv->textureID) {
-        glDeleteTextures(1, &drv->textureID);
+        RSD_CALL_GL(glDeleteTextures, 1, &drv->textureID);
         drv->textureID = 0;
     }
     if (drv->renderTargetID) {
-        glDeleteRenderbuffers(1, &drv->renderTargetID);
+        RSD_CALL_GL(glDeleteRenderbuffers, 1, &drv->renderTargetID);
         drv->renderTargetID = 0;
     }
 
@@ -323,7 +323,7 @@
     drv->readBackFBO->setActive(rsc);
 
     // Do the readback
-    glReadPixels(0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(),
+    RSD_CALL_GL(glReadPixels, 0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(),
                  drv->glFormat, drv->glType, alloc->getPtr());
 
     // Revert framebuffer to its original
@@ -414,7 +414,7 @@
         }
         drv->uploadDeferred = true;
     } else {
-        Update2DTexture(alloc, data, xoff, yoff, lod, face, w, h);
+        Update2DTexture(rsc, alloc, data, xoff, yoff, lod, face, w, h);
     }
 }
 
diff --git a/libs/rs/driver/rsdFrameBufferObj.cpp b/libs/rs/driver/rsdFrameBufferObj.cpp
index 145bf34..91452b0 100644
--- a/libs/rs/driver/rsdFrameBufferObj.cpp
+++ b/libs/rs/driver/rsdFrameBufferObj.cpp
@@ -17,6 +17,7 @@
 
 #include "rsdFrameBufferObj.h"
 #include "rsdAllocation.h"
+#include "rsdGL.h"
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
@@ -124,9 +125,9 @@
     bool framebuffer = renderToFramebuffer();
     if (!framebuffer) {
         if(mFBOId == 0) {
-            glGenFramebuffers(1, &mFBOId);
+            RSD_CALL_GL(glGenFramebuffers, 1, &mFBOId);
         }
-        glBindFramebuffer(GL_FRAMEBUFFER, mFBOId);
+        RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, mFBOId);
 
         if (mDirty) {
             setDepthAttachment();
@@ -134,10 +135,10 @@
             mDirty = false;
         }
 
-        glViewport(0, 0, mWidth, mHeight);
+        RSD_CALL_GL(glViewport, 0, 0, mWidth, mHeight);
         checkError(rsc);
     } else {
-        glBindFramebuffer(GL_FRAMEBUFFER, 0);
-        glViewport(0, 0, rsc->getWidth(), rsc->getHeight());
+        RSD_CALL_GL(glBindFramebuffer, GL_FRAMEBUFFER, 0);
+        RSD_CALL_GL(glViewport, 0, 0, rsc->getWidth(), rsc->getHeight());
     }
 }
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 04446ad..c5b81db 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -135,18 +135,19 @@
     LOGV("%p, deinitEGL", rsc);
 
     if (dc->gl.egl.context != EGL_NO_CONTEXT) {
-        eglMakeCurrent(dc->gl.egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-        eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surfaceDefault);
+        RSD_CALL_GL(eglMakeCurrent, dc->gl.egl.display,
+                    EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+        RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surfaceDefault);
         if (dc->gl.egl.surface != EGL_NO_SURFACE) {
-            eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
+            RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surface);
         }
-        eglDestroyContext(dc->gl.egl.display, dc->gl.egl.context);
+        RSD_CALL_GL(eglDestroyContext, dc->gl.egl.display, dc->gl.egl.context);
         checkEglError("eglDestroyContext");
     }
 
     gGLContextCount--;
     if (!gGLContextCount) {
-        eglTerminate(dc->gl.egl.display);
+        RSD_CALL_GL(eglTerminate, dc->gl.egl.display);
     }
 }
 
@@ -202,21 +203,25 @@
     rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint))));
 
     LOGV("%p initEGL start", rsc);
+    rsc->setWatchdogGL("eglGetDisplay", __LINE__, __FILE__);
     dc->gl.egl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     checkEglError("eglGetDisplay");
 
-    eglInitialize(dc->gl.egl.display, &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion);
+    RSD_CALL_GL(eglInitialize, dc->gl.egl.display,
+                &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion);
     checkEglError("eglInitialize");
 
     EGLBoolean ret;
 
     EGLint numConfigs = -1, n = 0;
+    rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
     ret = eglChooseConfig(dc->gl.egl.display, configAttribs, 0, 0, &numConfigs);
     checkEglError("eglGetConfigs", ret);
 
     if (numConfigs) {
         EGLConfig* const configs = new EGLConfig[numConfigs];
 
+        rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
         ret = eglChooseConfig(dc->gl.egl.display,
                 configAttribs, configs, numConfigs, &n);
         if (!ret || !n) {
@@ -261,32 +266,38 @@
     }
     //}
 
+    rsc->setWatchdogGL("eglCreateContext", __LINE__, __FILE__);
     dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config,
                                           EGL_NO_CONTEXT, context_attribs2);
     checkEglError("eglCreateContext");
     if (dc->gl.egl.context == EGL_NO_CONTEXT) {
         LOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc);
+        rsc->setWatchdogGL(NULL, 0, NULL);
         return false;
     }
     gGLContextCount++;
 
 
     EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+    rsc->setWatchdogGL("eglCreatePbufferSurface", __LINE__, __FILE__);
     dc->gl.egl.surfaceDefault = eglCreatePbufferSurface(dc->gl.egl.display, dc->gl.egl.config,
                                                         pbuffer_attribs);
     checkEglError("eglCreatePbufferSurface");
     if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) {
         LOGE("eglCreatePbufferSurface returned EGL_NO_SURFACE");
         rsdGLShutdown(rsc);
+        rsc->setWatchdogGL(NULL, 0, NULL);
         return false;
     }
 
+    rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
     ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
                          dc->gl.egl.surfaceDefault, dc->gl.egl.context);
     if (ret == EGL_FALSE) {
         LOGE("eglMakeCurrent returned EGL_FALSE");
         checkEglError("eglMakeCurrent", ret);
         rsdGLShutdown(rsc);
+        rsc->setWatchdogGL(NULL, 0, NULL);
         return false;
     }
 
@@ -314,6 +325,7 @@
     if (!verptr) {
         LOGE("Error, OpenGL ES Lite not supported");
         rsdGLShutdown(rsc);
+        rsc->setWatchdogGL(NULL, 0, NULL);
         return false;
     } else {
         sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion);
@@ -352,6 +364,7 @@
     dc->gl.currentFrameBuffer = NULL;
 
     LOGV("initGLThread end %p", rsc);
+    rsc->setWatchdogGL(NULL, 0, NULL);
     return true;
 }
 
@@ -363,10 +376,12 @@
     // WAR: Some drivers fail to handle 0 size surfaces correcntly.
     // Use the pbuffer to avoid this pitfall.
     if ((dc->gl.egl.surface != NULL) || (w == 0) || (h == 0)) {
+        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
         ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
                              dc->gl.egl.surfaceDefault, dc->gl.egl.context);
         checkEglError("eglMakeCurrent", ret);
 
+        rsc->setWatchdogGL("eglDestroySurface", __LINE__, __FILE__);
         ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
         checkEglError("eglDestroySurface", ret);
 
@@ -385,6 +400,7 @@
         dc->gl.width = w;
         dc->gl.height = h;
 
+        rsc->setWatchdogGL("eglCreateWindowSurface", __LINE__, __FILE__);
         dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
                                                     dc->gl.wndSurface, NULL);
         checkEglError("eglCreateWindowSurface");
@@ -392,16 +408,18 @@
             LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
         }
 
+        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
         ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface,
                              dc->gl.egl.surface, dc->gl.egl.context);
         checkEglError("eglMakeCurrent", ret);
     }
+    rsc->setWatchdogGL(NULL, 0, NULL);
     return true;
 }
 
 void rsdGLSwap(const android::renderscript::Context *rsc) {
     RsdHal *dc = (RsdHal *)rsc->mHal.drv;
-    eglSwapBuffers(dc->gl.egl.display, dc->gl.egl.surface);
+    RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
 }
 
 void rsdGLCheckError(const android::renderscript::Context *rsc,
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 0d5b7e7..fc33885 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -20,6 +20,8 @@
 #include <rs_hal.h>
 #include <EGL/egl.h>
 
+#define RSD_CALL_GL(x, ...) rsc->setWatchdogGL(#x, __LINE__, __FILE__); x(__VA_ARGS__); rsc->setWatchdogGL(NULL, 0, NULL)
+
 class RsdShaderCache;
 class RsdVertexArrayState;
 class RsdFrameBufferObj;
@@ -73,7 +75,6 @@
 } RsdGL;
 
 
-
 bool rsdGLInit(const android::renderscript::Context *rsc);
 void rsdGLShutdown(const android::renderscript::Context *rsc);
 bool rsdGLSetSurface(const android::renderscript::Context *rsc,
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
index 4315c0d..019167b 100644
--- a/libs/rs/driver/rsdMeshObj.cpp
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -130,7 +130,8 @@
     return true;
 }
 
-void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
+void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex,
+                                      uint32_t start, uint32_t len) const {
     if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
         LOGE("Invalid mesh or parameters");
         return;
@@ -171,14 +172,16 @@
         }
 
         if (drvAlloc->bufferID) {
-            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drvAlloc->bufferID);
-            glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
+            RSD_CALL_GL(glBindBuffer, GL_ELEMENT_ARRAY_BUFFER, drvAlloc->bufferID);
+            RSD_CALL_GL(glDrawElements, mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT,
+                        (uint16_t *)(start * 2));
         } else {
-            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-            glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, drvAlloc->mallocPtr);
+            RSD_CALL_GL(glBindBuffer, GL_ELEMENT_ARRAY_BUFFER, 0);
+            RSD_CALL_GL(glDrawElements, mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT,
+                        drvAlloc->mallocPtr);
         }
     } else {
-        glDrawArrays(mGLPrimitives[primIndex], start, len);
+        RSD_CALL_GL(glDrawArrays, mGLPrimitives[primIndex], start, len);
     }
 
     rsdGLCheckError(rsc, "Mesh::renderPrimitiveRange");
diff --git a/libs/rs/driver/rsdProgramRaster.cpp b/libs/rs/driver/rsdProgramRaster.cpp
index 65995be..b493759 100644
--- a/libs/rs/driver/rsdProgramRaster.cpp
+++ b/libs/rs/driver/rsdProgramRaster.cpp
@@ -32,18 +32,18 @@
     return true;
 }
 
-void rsdProgramRasterSetActive(const Context *, const ProgramRaster *pr) {
+void rsdProgramRasterSetActive(const Context *rsc, const ProgramRaster *pr) {
     switch (pr->mHal.state.cull) {
         case RS_CULL_BACK:
-            glEnable(GL_CULL_FACE);
-            glCullFace(GL_BACK);
+            RSD_CALL_GL(glEnable, GL_CULL_FACE);
+            RSD_CALL_GL(glCullFace, GL_BACK);
             break;
         case RS_CULL_FRONT:
-            glEnable(GL_CULL_FACE);
-            glCullFace(GL_FRONT);
+            RSD_CALL_GL(glEnable, GL_CULL_FACE);
+            RSD_CALL_GL(glCullFace, GL_FRONT);
             break;
         case RS_CULL_NONE:
-            glDisable(GL_CULL_FACE);
+            RSD_CALL_GL(glDisable, GL_CULL_FACE);
             break;
     }
 
diff --git a/libs/rs/driver/rsdProgramStore.cpp b/libs/rs/driver/rsdProgramStore.cpp
index e591453..af44b02 100644
--- a/libs/rs/driver/rsdProgramStore.cpp
+++ b/libs/rs/driver/rsdProgramStore.cpp
@@ -156,29 +156,29 @@
 void rsdProgramStoreSetActive(const Context *rsc, const ProgramStore *ps) {
     DrvProgramStore *drv = (DrvProgramStore *)ps->mHal.drv;
 
-    glColorMask(ps->mHal.state.colorRWriteEnable,
+    RSD_CALL_GL(glColorMask, ps->mHal.state.colorRWriteEnable,
                 ps->mHal.state.colorGWriteEnable,
                 ps->mHal.state.colorBWriteEnable,
                 ps->mHal.state.colorAWriteEnable);
 
     if (drv->blendEnable) {
-        glEnable(GL_BLEND);
-        glBlendFunc(drv->blendSrc, drv->blendDst);
+        RSD_CALL_GL(glEnable, GL_BLEND);
+        RSD_CALL_GL(glBlendFunc, drv->blendSrc, drv->blendDst);
     } else {
-        glDisable(GL_BLEND);
+        RSD_CALL_GL(glDisable, GL_BLEND);
     }
 
     if (rsc->mUserSurfaceConfig.depthMin > 0) {
-        glDepthMask(ps->mHal.state.depthWriteEnable);
+        RSD_CALL_GL(glDepthMask, ps->mHal.state.depthWriteEnable);
         if (drv->depthTestEnable || ps->mHal.state.depthWriteEnable) {
-            glEnable(GL_DEPTH_TEST);
-            glDepthFunc(drv->depthFunc);
+            RSD_CALL_GL(glEnable, GL_DEPTH_TEST);
+            RSD_CALL_GL(glDepthFunc, drv->depthFunc);
         } else {
-            glDisable(GL_DEPTH_TEST);
+            RSD_CALL_GL(glDisable, GL_DEPTH_TEST);
         }
     } else {
-        glDepthMask(false);
-        glDisable(GL_DEPTH_TEST);
+        RSD_CALL_GL(glDepthMask, false);
+        RSD_CALL_GL(glDisable, GL_DEPTH_TEST);
     }
 
     /*
@@ -190,9 +190,9 @@
     */
 
     if (ps->mHal.state.ditherEnable) {
-        glEnable(GL_DITHER);
+        RSD_CALL_GL(glEnable, GL_DITHER);
     } else {
-        glDisable(GL_DITHER);
+        RSD_CALL_GL(glDisable, GL_DITHER);
     }
 }
 
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index 90fe4b2..16ff063 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -178,22 +178,22 @@
 
     if (mShaderID) {
         const char * ss = mShader.string();
-        glShaderSource(mShaderID, 1, &ss, NULL);
-        glCompileShader(mShaderID);
+        RSD_CALL_GL(glShaderSource, mShaderID, 1, &ss, NULL);
+        RSD_CALL_GL(glCompileShader, mShaderID);
 
         GLint compiled = 0;
-        glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
+        RSD_CALL_GL(glGetShaderiv, mShaderID, GL_COMPILE_STATUS, &compiled);
         if (!compiled) {
             GLint infoLen = 0;
-            glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
+            RSD_CALL_GL(glGetShaderiv, mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
             if (infoLen) {
                 char* buf = (char*) malloc(infoLen);
                 if (buf) {
-                    glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
+                    RSD_CALL_GL(glGetShaderInfoLog, mShaderID, infoLen, NULL, buf);
                     LOGE("Could not compile shader \n%s\n", buf);
                     free(buf);
                 }
-                glDeleteShader(mShaderID);
+                RSD_CALL_GL(glDeleteShader, mShaderID);
                 mShaderID = 0;
                 rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
                 return false;
@@ -297,24 +297,24 @@
                          int32_t slot, uint32_t arraySize ) {
     RsDataType dataType = field->getType();
     if (dataType == RS_TYPE_MATRIX_4X4) {
-        glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
+        RSD_CALL_GL(glUniformMatrix4fv, slot, arraySize, GL_FALSE, fd);
     } else if (dataType == RS_TYPE_MATRIX_3X3) {
-        glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
+        RSD_CALL_GL(glUniformMatrix3fv, slot, arraySize, GL_FALSE, fd);
     } else if (dataType == RS_TYPE_MATRIX_2X2) {
-        glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
+        RSD_CALL_GL(glUniformMatrix2fv, slot, arraySize, GL_FALSE, fd);
     } else {
         switch (field->getComponent().getVectorSize()) {
         case 1:
-            glUniform1fv(slot, arraySize, fd);
+            RSD_CALL_GL(glUniform1fv, slot, arraySize, fd);
             break;
         case 2:
-            glUniform2fv(slot, arraySize, fd);
+            RSD_CALL_GL(glUniform2fv, slot, arraySize, fd);
             break;
         case 3:
-            glUniform3fv(slot, arraySize, fd);
+            RSD_CALL_GL(glUniform3fv, slot, arraySize, fd);
             break;
         case 4:
-            glUniform4fv(slot, arraySize, fd);
+            RSD_CALL_GL(glUniform4fv, slot, arraySize, fd);
             break;
         default:
             rsAssert(0);
@@ -351,37 +351,44 @@
         if (tex->getHasGraphicsMipmaps() &&
             (dc->gl.gl.GL_NV_texture_npot_2D_mipmap || dc->gl.gl.GL_IMG_texture_npot)) {
             if (dc->gl.gl.GL_NV_texture_npot_2D_mipmap) {
-                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
+                RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+                            trans[s->mHal.state.minFilter]);
             } else {
                 switch (trans[s->mHal.state.minFilter]) {
                 case GL_LINEAR_MIPMAP_LINEAR:
-                    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+                    RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+                                GL_LINEAR_MIPMAP_NEAREST);
                     break;
                 default:
-                    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
+                    RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+                                trans[s->mHal.state.minFilter]);
                     break;
                 }
             }
         } else {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]);
+            RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+                        transNP[s->mHal.state.minFilter]);
         }
-        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[s->mHal.state.magFilter]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[s->mHal.state.wrapS]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[s->mHal.state.wrapT]);
+        RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MAG_FILTER,
+                    transNP[s->mHal.state.magFilter]);
+        RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_WRAP_S, transNP[s->mHal.state.wrapS]);
+        RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_WRAP_T, transNP[s->mHal.state.wrapT]);
     } else {
         if (tex->getHasGraphicsMipmaps()) {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
+            RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+                        trans[s->mHal.state.minFilter]);
         } else {
-            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]);
+            RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
+                        transNP[s->mHal.state.minFilter]);
         }
-        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[s->mHal.state.magFilter]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[s->mHal.state.wrapS]);
-        glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[s->mHal.state.wrapT]);
+        RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MAG_FILTER, trans[s->mHal.state.magFilter]);
+        RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_WRAP_S, trans[s->mHal.state.wrapS]);
+        RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_WRAP_T, trans[s->mHal.state.wrapT]);
     }
 
     float anisoValue = rsMin(dc->gl.gl.EXT_texture_max_aniso, s->mHal.state.aniso);
     if (dc->gl.gl.EXT_texture_max_aniso > 1.0f) {
-        glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue);
+        RSD_CALL_GL(glTexParameterf, target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue);
     }
 
     rsdGLCheckError(rsc, "Sampler::setup tex env");
@@ -404,12 +411,12 @@
     }
 
     for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
-        glActiveTexture(GL_TEXTURE0 + ct);
-        glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
+        RSD_CALL_GL(glActiveTexture, GL_TEXTURE0 + ct);
+        RSD_CALL_GL(glUniform1i, sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
 
         if (!mRSProgram->mHal.state.textures[ct].get()) {
             // if nothing is bound, reset to default GL texture
-            glBindTexture(mTextureTargets[ct], 0);
+            RSD_CALL_GL(glBindTexture, mTextureTargets[ct], 0);
             continue;
         }
 
@@ -418,21 +425,22 @@
             LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
             rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
         }
-        glBindTexture(drvTex->glTarget, drvTex->textureID);
+        RSD_CALL_GL(glBindTexture, drvTex->glTarget, drvTex->textureID);
         rsdGLCheckError(rsc, "ProgramFragment::setup tex bind");
         if (mRSProgram->mHal.state.samplers[ct].get()) {
-            setupSampler(rsc, mRSProgram->mHal.state.samplers[ct].get(), mRSProgram->mHal.state.textures[ct].get());
+            setupSampler(rsc, mRSProgram->mHal.state.samplers[ct].get(),
+                         mRSProgram->mHal.state.textures[ct].get());
         } else {
-            glTexParameteri(drvTex->glTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-            glTexParameteri(drvTex->glTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-            glTexParameteri(drvTex->glTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-            glTexParameteri(drvTex->glTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+            RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+            RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+            RSD_CALL_GL(glTexParameteri, drvTex->glTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
             rsdGLCheckError(rsc, "ProgramFragment::setup tex env");
         }
         rsdGLCheckError(rsc, "ProgramFragment::setup uniforms");
     }
 
-    glActiveTexture(GL_TEXTURE0);
+    RSD_CALL_GL(glActiveTexture, GL_TEXTURE0);
     mDirty = false;
     rsdGLCheckError(rsc, "ProgramFragment::setup");
 }
@@ -442,7 +450,8 @@
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
         Allocation *alloc = mRSProgram->mHal.state.constants[ct].get();
         if (!alloc) {
-            LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
+            LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set",
+                 (uint32_t)this, ct);
             rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
             continue;
         }
@@ -470,7 +479,8 @@
                 arraySize = sc->fragUniformSize(uidx);
             }
             if (rsc->props.mLogShadersUniforms) {
-                LOGV("Uniform  slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
+                LOGV("Uniform  slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s",
+                     slot, offset, ct, field, uidx, fieldName);
             }
             uidx ++;
             if (slot < 0) {
@@ -528,7 +538,8 @@
     }
 }
 
-void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
+void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths,
+                                   uint32_t *count, const char *prefix) {
     rsAssert(e->getFieldCount());
     for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
         const Element *ce = e->getField(ct);
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index e3a9cf8..948d51c 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -86,7 +86,9 @@
 uint32_t Context::runRootScript() {
     timerSet(RS_TIMER_SCRIPT);
     mStateFragmentStore.mLast.clear();
+    watchdog.inRoot = true;
     uint32_t ret = runScript(mRootScript.get());
+    watchdog.inRoot = false;
 
     return ret;
 }
@@ -317,6 +319,13 @@
     mExit = true;
 }
 
+void Context::printWatchdogInfo(void *ctx) {
+    Context *rsc = (Context *)ctx;
+    LOGE("RS watchdog timeout: %i  %s  line %i %s", rsc->watchdog.inRoot,
+         rsc->watchdog.command, rsc->watchdog.line, rsc->watchdog.file);
+}
+
+
 void Context::setPriority(int32_t p) {
     // Note: If we put this in the proper "background" policy
     // the wallpapers can become completly unresponsive at times.
@@ -368,6 +377,7 @@
     pthread_mutex_lock(&gInitMutex);
 
     mIO.init();
+    mIO.setTimoutCallback(printWatchdogInfo, this, 2e9);
 
     dev->addContext(this);
     mDev = dev;
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 3c7a3d2..199cc5a 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -191,6 +191,19 @@
         bool mLogVisual;
     } props;
 
+    mutable struct {
+        bool inRoot;
+        const char *command;
+        const char *file;
+        uint32_t line;
+    } watchdog;
+    static void printWatchdogInfo(void *ctx);
+    void setWatchdogGL(const char *cmd, uint32_t line, const char *file) const {
+        watchdog.command = cmd;
+        watchdog.file = file;
+        watchdog.line = line;
+    }
+
     void dumpDebug() const;
     void setError(RsError e, const char *msg = NULL) const;
 
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index 4d02269..8879805 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -22,6 +22,9 @@
 using namespace android::renderscript;
 
 LocklessCommandFifo::LocklessCommandFifo() : mBuffer(0), mInitialized(false) {
+    mTimeoutCallback = NULL;
+    mTimeoutCallbackData = NULL;
+    mTimeoutWait = 0;
 }
 
 LocklessCommandFifo::~LocklessCommandFifo() {
@@ -125,11 +128,21 @@
 void LocklessCommandFifo::flush() {
     //dumpState("flush 1");
     while (mPut != mGet) {
-        mSignalToControl.wait();
+        while (!mSignalToControl.wait(mTimeoutWait)) {
+            if (mTimeoutCallback) {
+                mTimeoutCallback(mTimeoutCallbackData);
+            }
+        }
     }
     //dumpState("flush 2");
 }
 
+void LocklessCommandFifo::setTimoutCallback(void (*cbk)(void *), void *data, uint64_t timeout) {
+    mTimeoutCallback = cbk;
+    mTimeoutCallbackData = data;
+    mTimeoutWait = timeout;
+}
+
 bool LocklessCommandFifo::wait(uint64_t timeout) {
     while (isEmpty() && !mInShutdown) {
         mSignalToControl.set();
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
index fa53d40..dafc512 100644
--- a/libs/rs/rsLocklessFifo.h
+++ b/libs/rs/rsLocklessFifo.h
@@ -34,6 +34,7 @@
 public:
     bool init(uint32_t size);
     void shutdown();
+    void setTimoutCallback(void (*)(void *), void *, uint64_t timeout);
 
     void printDebugData() const;
 
@@ -71,6 +72,10 @@
 
 private:
     void dumpState(const char *) const;
+
+    void (*mTimeoutCallback)(void *);
+    void * mTimeoutCallbackData;
+    uint64_t mTimeoutWait;
 };
 
 
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 3259cb4..7862f3c 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -158,7 +158,7 @@
     RsdVertexArray va(attribs, 2);
     va.setup(rsc);
 
-    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+    RSD_CALL_GL(glDrawArrays, GL_TRIANGLE_FAN, 0, 4);
 }
 
 void rsrDrawQuad(Context *rsc, Script *sc,
@@ -245,7 +245,7 @@
 }
 
 void rsrFinish(Context *rsc, Script *sc) {
-    glFinish();
+    RSD_CALL_GL(glFinish);
 }
 
 
@@ -253,16 +253,16 @@
     rsc->mFBOCache.setup(rsc);
     rsc->setupProgramStore();
 
-    glClearColor(r, g, b, a);
-    glClear(GL_COLOR_BUFFER_BIT);
+    RSD_CALL_GL(glClearColor, r, g, b, a);
+    RSD_CALL_GL(glClear, GL_COLOR_BUFFER_BIT);
 }
 
 void rsrClearDepth(Context *rsc, Script *sc, float v) {
     rsc->mFBOCache.setup(rsc);
     rsc->setupProgramStore();
 
-    glClearDepthf(v);
-    glClear(GL_DEPTH_BUFFER_BIT);
+    RSD_CALL_GL(glClearDepthf, v);
+    RSD_CALL_GL(glClear, GL_DEPTH_BUFFER_BIT);
 }
 
 uint32_t rsrGetWidth(Context *rsc, Script *sc) {
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index fe2c52e..b1a579a 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -112,6 +112,10 @@
     memcpy(data, &mToCoreRet, dataLen);
 }
 
+void ThreadIO::setTimoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
+    mToCore.setTimoutCallback(cb, dat, timeout);
+}
+
 
 bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand, uint64_t timeToWait) {
     bool ret = false;
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index 9036118..ebce0ab 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -39,6 +39,7 @@
     // Returns true if any commands were processed.
     bool playCoreCommands(Context *con, bool waitForCommand, uint64_t timeToWait);
 
+    void setTimoutCallback(void (*)(void *), void *, uint64_t timeout);
     //LocklessCommandFifo mToCore;