Better error handling in the OpenGL renderer.

Add a glGetError() check on every frame
Don't attempt to create textures larger than the maximum size allowed

Change-Id: Iee4afae16089406dbe8bf10fc93b674f1271a0ca
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 11a5d69..e0c4b14 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -148,9 +148,15 @@
     void onPreDraw() {
         nPrepare(mRenderer);
     }
-    
+
     private native void nPrepare(int renderer);
 
+    void onPostDraw() {
+        nFinish(mRenderer);
+    }
+    
+    private native void nFinish(int renderer);
+
     @Override
     public boolean acquireContext() {
         if (!mContextLocked) {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 5d85076a..3796994 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -210,7 +210,7 @@
          * is invoked and the requested flag is turned off. The error code is
          * also logged as a warning.
          */
-        void checkErrors() {
+        void checkEglErrors() {
             if (isEnabled()) {
                 int error = sEgl.eglGetError();
                 if (error != EGL10.EGL_SUCCESS) {
@@ -221,7 +221,7 @@
                         // we'll try again if it was context lost
                         setRequested(false);
                     }
-                    Log.w(LOG_TAG, "OpenGL error: " + error);
+                    Log.w(LOG_TAG, "EGL error: " + Integer.toHexString(error));
                 }
             }
         }
@@ -348,7 +348,7 @@
         void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
                 SurfaceHolder holder) {
             if (isRequested()) {
-                checkErrors();
+                checkEglErrors();
                 super.initializeIfNeeded(width, height, attachInfo, holder);
             }
         }
@@ -386,6 +386,9 @@
         void onPreDraw() {
         }
 
+        void onPostDraw() {
+        }
+        
         /**
          * Defines the EGL configuration for this renderer. The default configuration
          * is RGBX, no depth, no stencil.
@@ -418,10 +421,12 @@
                     canvas.restoreToCount(saveCount);
                 }
 
+                onPostDraw();
+
                 attachInfo.mIgnoreDirtyState = false;
 
                 sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
-                checkErrors();
+                checkEglErrors();
             }
         }
 
@@ -570,6 +575,11 @@
             mGlCanvas.onPreDraw();
         }
 
+        @Override
+        void onPostDraw() {
+            mGlCanvas.onPostDraw();
+        }
+
         static HardwareRenderer create(boolean translucent) {
             if (GLES20Canvas.isAvailable()) {
                 return new Gl20Renderer(translucent);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index aa71746..a61a9d1 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -84,6 +84,11 @@
     renderer->prepare();
 }
 
+static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer) {
+    renderer->finish();
+}
+
 static void android_view_GLES20Canvas_acquireContext(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer) {
     renderer->acquireContext();
@@ -384,6 +389,7 @@
     { "nDestroyRenderer",   "(I)V",            (void*) android_view_GLES20Canvas_destroyRenderer },
     { "nSetViewport",       "(III)V",          (void*) android_view_GLES20Canvas_setViewport },
     { "nPrepare",           "(I)V",            (void*) android_view_GLES20Canvas_prepare },
+    { "nFinish",            "(I)V",            (void*) android_view_GLES20Canvas_finish },
     { "nAcquireContext",    "(I)V",            (void*) android_view_GLES20Canvas_acquireContext },
     { "nReleaseContext",    "(I)V",            (void*) android_view_GLES20Canvas_releaseContext },
 
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 1a18766..39c3111 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -110,11 +110,9 @@
         layer = new Layer;
         layer->blend = true;
 
-        // Generate the texture in which the FBO will draw
         glGenTextures(1, &layer->texture);
         glBindTexture(GL_TEXTURE_2D, layer->texture);
 
-        // The FBO will not be scaled, so we can use lower quality filtering
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f187d3e..670d049 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -124,6 +124,8 @@
     if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
         LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
     }
+
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -161,6 +163,15 @@
     mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);
 }
 
+void OpenGLRenderer::finish() {
+#if DEBUG_OPENGL
+    GLenum status = GL_NO_ERROR;
+    while ((status = glGetError()) != GL_NO_ERROR) {
+        LOGD("GL error from OpenGLRenderer: 0x%x", status);
+    }
+#endif
+}
+
 void OpenGLRenderer::acquireContext() {
     if (mCaches.currentProgram) {
         if (mCaches.currentProgram->isInUse()) {
@@ -342,7 +353,10 @@
 
     // Layers only make sense if they are in the framebuffer's bounds
     bounds.intersect(*mSnapshot->clipRect);
-    if (bounds.isEmpty()) return false;
+    if (bounds.isEmpty() || bounds.getWidth() > mMaxTextureSize ||
+            bounds.getHeight() > mMaxTextureSize) {
+        return false;
+    }
 
     LayerSize size(bounds.getWidth(), bounds.getHeight());
     Layer* layer = mCaches.layerCache.get(size);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 49a69f9..387fb12 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -45,6 +45,13 @@
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#define DEBUG_OPENGL 1
+
+///////////////////////////////////////////////////////////////////////////////
 // Renderer
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -59,6 +66,7 @@
 
     void setViewport(int width, int height);
     void prepare();
+    void finish();
     void acquireContext();
     void releaseContext();
 
@@ -395,6 +403,8 @@
     // List of rectangles to clear due to calls to saveLayer()
     Vector<Rect*> mLayers;
 
+    GLint mMaxTextureSize;
+
 }; // class OpenGLRenderer
 
 }; // namespace uirenderer