Merge "Disregard alleged binder entities beyond parcel bounds" into mnc-dev
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 2cf7433..e318484 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -914,8 +914,8 @@
                     mCore->mSidebandStream.clear();
                     mCore->mDequeueCondition.broadcast();
                     listener = mCore->mConsumerListener;
-                } else if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
-                    BQ_LOGE("disconnect(P): still connected to another API "
+                } else {
+                    BQ_LOGE("disconnect(P): connected to another API "
                             "(cur=%d req=%d)", mCore->mConnectedApi, api);
                     status = BAD_VALUE;
                 }
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index 09b63a1..3009989 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -59,6 +59,9 @@
         if (result == NO_ERROR) {
             graphicBuffer = new GraphicBuffer();
             result = reply.read(*graphicBuffer);
+            if (result != NO_ERROR) {
+                graphicBuffer.clear();
+            }
             // reply.readStrongBinder();
             // here we don't even have to read the BufferReference from
             // the parcel, it'll die with the parcel.
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index d750cd0..1a50b24 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -27,6 +27,9 @@
 #include <utils/Log.h>
 #include <utils/Thread.h>
 
+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+#define CROP_EXT_STR "EGL_ANDROID_image_crop"
+
 namespace android {
 
 class SurfaceTextureClientTest : public ::testing::Test {
@@ -615,6 +618,18 @@
 }
 
 TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
+    // Query to see if the image crop extension exists
+    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
+    size_t cropExtLen = strlen(CROP_EXT_STR);
+    size_t extsLen = strlen(exts);
+    bool equal = !strcmp(CROP_EXT_STR, exts);
+    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
+    bool atEnd = (cropExtLen+1) < extsLen &&
+            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
+    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
+    bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle;
+
     android_native_buffer_t* buf[3];
     float mtx[16] = {};
     android_native_rect_t crop;
@@ -633,15 +648,17 @@
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
     mST->getTransformMatrix(mtx);
 
-    // This accounts for the .5 texel shrink for each edge that's included in the
-    // transform matrix to avoid texturing outside the crop region.
-    EXPECT_EQ(0.5, mtx[0]);
+    // If the egl image crop extension is not present, this accounts for the
+    // .5 texel shrink for each edge that's included in the transform matrix
+    // to avoid texturing outside the crop region. Otherwise the crop is not
+    // included in the transform matrix.
+    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]);
     EXPECT_EQ(0.f, mtx[1]);
     EXPECT_EQ(0.f, mtx[2]);
     EXPECT_EQ(0.f, mtx[3]);
 
     EXPECT_EQ(0.f, mtx[4]);
-    EXPECT_EQ(-0.5, mtx[5]);
+    EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]);
     EXPECT_EQ(0.f, mtx[6]);
     EXPECT_EQ(0.f, mtx[7]);
 
@@ -650,8 +667,8 @@
     EXPECT_EQ(1.f, mtx[10]);
     EXPECT_EQ(0.f, mtx[11]);
 
-    EXPECT_EQ(0.0625f, mtx[12]);
-    EXPECT_EQ(0.5625f, mtx[13]);
+    EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]);
+    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]);
     EXPECT_EQ(0.f, mtx[14]);
     EXPECT_EQ(1.f, mtx[15]);
 }
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 85e9675..9b265af 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -104,6 +104,9 @@
     // we have a h/w allocator and h/w buffer is requested
     status_t err;
 
+    // Filter out any usage bits that should not be passed to the gralloc module
+    usage &= GRALLOC_USAGE_ALLOC_MASK;
+
     int outStride = 0;
     err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
             static_cast<int>(height), format, static_cast<int>(usage), handle,
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 1feac8b..593d0c2 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -394,7 +394,13 @@
         depth.width   = width;
         depth.height  = height;
         depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                static_cast<uint64_t>(depth.height) * 2;
+        if (depth.stride < 0 || depth.height > INT_MAX ||
+                allocSize > UINT32_MAX) {
+            return setError(EGL_BAD_ALLOC, EGL_FALSE);
+        }
+        depth.data    = (GGLubyte*)malloc(allocSize);
         if (depth.data == 0) {
             return setError(EGL_BAD_ALLOC, EGL_FALSE);
         }
@@ -548,7 +554,14 @@
                 depth.width   = width;
                 depth.height  = height;
                 depth.stride  = buffer->stride;
-                depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+                uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                        static_cast<uint64_t>(depth.height) * 2;
+                if (depth.stride < 0 || depth.height > INT_MAX ||
+                        allocSize > UINT32_MAX) {
+                    setError(EGL_BAD_ALLOC, EGL_FALSE);
+                    return EGL_FALSE;
+                }
+                depth.data    = (GGLubyte*)malloc(allocSize);
                 if (depth.data == 0) {
                     setError(EGL_BAD_ALLOC, EGL_FALSE);
                     return EGL_FALSE;
@@ -666,7 +679,14 @@
         depth.width   = pixmap->width;
         depth.height  = pixmap->height;
         depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                static_cast<uint64_t>(depth.height) * 2;
+        if (depth.stride < 0 || depth.height > INT_MAX ||
+                allocSize > UINT32_MAX) {
+            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            return;
+        }
+        depth.data    = (GGLubyte*)malloc(allocSize);
         if (depth.data == 0) {
             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
         }
@@ -746,7 +766,14 @@
         depth.width   = pbuffer.width;
         depth.height  = pbuffer.height;
         depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                static_cast<uint64_t>(depth.height) * 2;
+        if (depth.stride < 0 || depth.height > INT_MAX ||
+                allocSize > UINT32_MAX) {
+            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            return;
+        }
+        depth.data    = (GGLubyte*)malloc(allocSize);
         if (depth.data == 0) {
             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
             return;
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 7c70fa0..4e0e5bc 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -292,6 +292,44 @@
     return (const GLubyte *)c->gl_extensions.string();
 }
 
+const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) {
+    // NOTE: returning NULL here will fall-back to the default
+    // implementation.
+
+    EGLContext context = egl_tls_t::getContext();
+    if (context == EGL_NO_CONTEXT)
+        return NULL;
+
+    egl_context_t const * const c = get_context(context);
+    if (c == NULL) // this should never happen, by construction
+        return NULL;
+
+    if (name != GL_EXTENSIONS)
+        return NULL;
+
+    // if index is out of bounds, assume it will be in the default
+    // implementation too, so we don't have to generate a GL error here
+    if (index >= c->tokenized_gl_extensions.size())
+        return NULL;
+
+    return (const GLubyte *)c->tokenized_gl_extensions.itemAt(index).string();
+}
+
+GLint egl_get_num_extensions_for_current_context() {
+    // NOTE: returning -1 here will fall-back to the default
+    // implementation.
+
+    EGLContext context = egl_tls_t::getContext();
+    if (context == EGL_NO_CONTEXT)
+        return -1;
+
+    egl_context_t const * const c = get_context(context);
+    if (c == NULL) // this should never happen, by construction
+        return -1;
+
+    return (GLint)c->tokenized_gl_extensions.size();
+}
+
 // ----------------------------------------------------------------------------
 
 // this mutex protects:
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 8dd052c..5444631 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -562,15 +562,6 @@
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     egl_surface_t * const s = get_surface(surface);
-    ANativeWindow* window = s->win.get();
-    if (window) {
-        int result = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-        if (result != OK) {
-            ALOGE("eglDestroySurface: native_window_api_disconnect (win=%p) "
-                  "failed (%#x)",
-                  window, result);
-        }
-    }
     EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
     if (result == EGL_TRUE) {
         _s.terminate();
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index d3ee76d..d511940 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -113,6 +113,18 @@
             temp.append(gl_extensions);
             gl_extensions.setTo(temp);
         }
+
+        // tokenize the supported extensions for the glGetStringi() wrapper
+        exts = gl_extensions.string();
+        while (1) {
+            const char *end = strchr(exts, ' ');
+            if (end == NULL) {
+                tokenized_gl_extensions.push(String8(exts));
+                break;
+            }
+            tokenized_gl_extensions.push(String8(exts, end - exts));
+            exts = end + 1;
+        }
     }
 }
 
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 518fdec..f5a9f58 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -27,6 +27,7 @@
 
 #include <utils/threads.h>
 #include <utils/String8.h>
+#include <utils/Vector.h>
 
 #include <system/window.h>
 
@@ -159,6 +160,7 @@
     egl_connection_t const* cnx;
     int version;
     String8 gl_extensions;
+    Vector<String8> tokenized_gl_extensions;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index d5dc012..6034a8e 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -205,13 +205,22 @@
 #undef CALL_GL_API_RETURN
 
 /*
- * glGetString() is special because we expose some extensions in the wrapper
+ * glGetString() and glGetStringi() are special because we expose some
+ * extensions in the wrapper. Also, wrapping glGetXXX() is required because
+ * the value returned for GL_NUM_EXTENSIONS may have been altered by the
+ * injection of the additional extensions.
  */
 
-extern "C" const GLubyte * __glGetString(GLenum name);
+extern "C" {
+    const GLubyte * __glGetString(GLenum name);
+    const GLubyte * __glGetStringi(GLenum name, GLuint index);
+    void __glGetBooleanv(GLenum pname, GLboolean * data);
+    void __glGetFloatv(GLenum pname, GLfloat * data);
+    void __glGetIntegerv(GLenum pname, GLint * data);
+    void __glGetInteger64v(GLenum pname, GLint64 * data);
+}
 
-const GLubyte * glGetString(GLenum name)
-{
+const GLubyte * glGetString(GLenum name) {
     const GLubyte * ret = egl_get_string_for_current_context(name);
     if (ret == NULL) {
         gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
@@ -219,3 +228,64 @@
     }
     return ret;
 }
+
+const GLubyte * glGetStringi(GLenum name, GLuint index) {
+    const GLubyte * ret = egl_get_string_for_current_context(name, index);
+    if (ret == NULL) {
+        gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+        if(_c) ret = _c->glGetStringi(name, index);
+    }
+    return ret;
+}
+
+void glGetBooleanv(GLenum pname, GLboolean * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = num_exts > 0 ? GL_TRUE : GL_FALSE;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetBooleanv(pname, data);
+}
+
+void glGetFloatv(GLenum pname, GLfloat * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = (GLfloat)num_exts;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetFloatv(pname, data);
+}
+
+void glGetIntegerv(GLenum pname, GLint * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = (GLint)num_exts;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetIntegerv(pname, data);
+}
+
+void glGetInteger64v(GLenum pname, GLint64 * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = (GLint64)num_exts;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetInteger64v(pname, data);
+}
diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in
index 8363960..09d8b00 100644
--- a/opengl/libs/GLES2/gl2_api.in
+++ b/opengl/libs/GLES2/gl2_api.in
@@ -172,7 +172,7 @@
 GLint API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar * name) {
     CALL_GL_API_RETURN(glGetAttribLocation, program, name);
 }
-void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean * data) {
+void API_ENTRY(__glGetBooleanv)(GLenum pname, GLboolean * data) {
     CALL_GL_API(glGetBooleanv, pname, data);
 }
 void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint * params) {
@@ -181,13 +181,13 @@
 GLenum API_ENTRY(glGetError)(void) {
     CALL_GL_API_RETURN(glGetError);
 }
-void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat * data) {
+void API_ENTRY(__glGetFloatv)(GLenum pname, GLfloat * data) {
     CALL_GL_API(glGetFloatv, pname, data);
 }
 void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint * params) {
     CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
 }
-void API_ENTRY(glGetIntegerv)(GLenum pname, GLint * data) {
+void API_ENTRY(__glGetIntegerv)(GLenum pname, GLint * data) {
     CALL_GL_API(glGetIntegerv, pname, data);
 }
 void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint * params) {
@@ -604,7 +604,7 @@
 void API_ENTRY(glClearBufferfi)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
     CALL_GL_API(glClearBufferfi, buffer, drawbuffer, depth, stencil);
 }
-const GLubyte * API_ENTRY(glGetStringi)(GLenum name, GLuint index) {
+const GLubyte * API_ENTRY(__glGetStringi)(GLenum name, GLuint index) {
     CALL_GL_API_RETURN(glGetStringi, name, index);
 }
 void API_ENTRY(glCopyBufferSubData)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
@@ -649,7 +649,7 @@
 void API_ENTRY(glWaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeout) {
     CALL_GL_API(glWaitSync, sync, flags, timeout);
 }
-void API_ENTRY(glGetInteger64v)(GLenum pname, GLint64 * data) {
+void API_ENTRY(__glGetInteger64v)(GLenum pname, GLint64 * data) {
     CALL_GL_API(glGetInteger64v, pname, data);
 }
 void API_ENTRY(glGetSynciv)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei * length, GLint * values) {
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index cb0e908..c0990ec 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -30,6 +30,9 @@
 // ----------------------------------------------------------------------------
 
 EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name);
+EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name,
+                                                          GLuint index);
+EGLAPI GLint egl_get_num_extensions_for_current_context();
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/opengl/tools/glgen2/glgen.py b/opengl/tools/glgen2/glgen.py
index ed6b451..9b30fd1 100755
--- a/opengl/tools/glgen2/glgen.py
+++ b/opengl/tools/glgen2/glgen.py
@@ -86,11 +86,25 @@
     return ', '.join(['"%s", %s' % (p[0], p[1]) for p in params])
 
 
-def overrideSymbolName(sym):
-    # The wrapper intercepts glGetString and (sometimes) calls the generated
-    # __glGetString thunk which dispatches to the driver's glGetString
-    if sym == 'glGetString':
-        return '__glGetString'
+def overrideSymbolName(sym, apiname):
+    # The wrapper intercepts various glGet and glGetString functions and
+    # (sometimes) calls the generated thunk which dispatches to the
+    # driver's implementation
+    wrapped_get_syms = {
+        'gles1' : [
+            'glGetString'
+        ],
+        'gles2' : [
+            'glGetString',
+            'glGetStringi',
+            'glGetBooleanv',
+            'glGetFloatv',
+            'glGetIntegerv',
+            'glGetInteger64v',
+        ],
+    }
+    if sym in wrapped_get_syms.get(apiname):
+        return '__' + sym
     else:
         return sym
 
@@ -115,8 +129,8 @@
         print('%s API_ENTRY(%s)(%s) {\n'
               '    %s(%s%s%s);\n'
               '}'
-              % (rtype, overrideSymbolName(fname), fmtParams(params),
-                 call, fname,
+              % (rtype, overrideSymbolName(fname, self.genOpts.apiname),
+                 fmtParams(params), call, fname,
                  ', ' if len(params) > 0 else '',
                  fmtArgs(params)),
               file=self.outFile)
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 96efc34..67142b6 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -139,7 +139,7 @@
     enum { MAX_RESYNC_SAMPLES = 32 };
     enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
     enum { NUM_PRESENT_SAMPLES = 8 };
-    enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 12 };
+    enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
 
     // mPeriod is the computed period of the modeled vsync events in
     // nanoseconds.
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 1adcd1f..0dab872 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -88,5 +88,9 @@
     mColorMatrixEnabled = (mtx != identity);
 }
 
+const mat4& Description::getColorMatrix() const {
+    return mColorMatrix;
+}
+
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 43b835f..8a3447c 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -66,6 +66,7 @@
     void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
     void setProjectionMatrix(const mat4& mtx);
     void setColorMatrix(const mat4& mtx);
+    const mat4& getColorMatrix() const;
 
 private:
     bool mUniformsDirty;
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 2e6af49..1a9f59b 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -262,14 +262,6 @@
     }
 }
 
-void GLES11RenderEngine::beginGroup(const mat4& /*colorTransform*/) {
-    // doesn't do anything in GLES 1.1
-}
-
-void GLES11RenderEngine::endGroup() {
-    // doesn't do anything in GLES 1.1
-}
-
 void GLES11RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
 }
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
index 87eb3e4..08de646 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
@@ -62,9 +62,6 @@
 
     virtual void drawMesh(const Mesh& mesh);
 
-    virtual void beginGroup(const mat4& colorTransform);
-    virtual void endGroup();
-
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
 };
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 8712c9a..1fabaf5 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -169,6 +169,12 @@
     mState.setTexture(texture);
 }
 
+mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
+    mat4 oldTransform = mState.getColorMatrix();
+    mState.setColorMatrix(colorTransform);
+    return oldTransform;
+}
+
 void GLES20RenderEngine::disableTexturing() {
     mState.disableTexture();
 }
@@ -237,78 +243,6 @@
     }
 }
 
-void GLES20RenderEngine::beginGroup(const mat4& colorTransform) {
-
-    GLuint tname, name;
-    // create the texture
-    glGenTextures(1, &tname);
-    glBindTexture(GL_TEXTURE_2D, tname);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mVpWidth, mVpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
-
-    // create a Framebuffer Object to render into
-    glGenFramebuffers(1, &name);
-    glBindFramebuffer(GL_FRAMEBUFFER, name);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
-
-    Group group;
-    group.texture = tname;
-    group.fbo = name;
-    group.width = mVpWidth;
-    group.height = mVpHeight;
-    group.colorTransform = colorTransform;
-
-    mGroupStack.push(group);
-}
-
-void GLES20RenderEngine::endGroup() {
-
-    const Group group(mGroupStack.top());
-    mGroupStack.pop();
-
-    // activate the previous render target
-    GLuint fbo = 0;
-    if (!mGroupStack.isEmpty()) {
-        fbo = mGroupStack.top().fbo;
-    }
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-
-    // set our state
-    Texture texture(Texture::TEXTURE_2D, group.texture);
-    texture.setDimensions(group.width, group.height);
-    glBindTexture(GL_TEXTURE_2D, group.texture);
-
-    mState.setPlaneAlpha(1.0f);
-    mState.setPremultipliedAlpha(true);
-    mState.setOpaque(false);
-    mState.setTexture(texture);
-    mState.setColorMatrix(group.colorTransform);
-    glDisable(GL_BLEND);
-
-    Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
-    Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-    Mesh::VertexArray<vec2> texCoord(mesh.getTexCoordArray<vec2>());
-    position[0] = vec2(0, 0);
-    position[1] = vec2(group.width, 0);
-    position[2] = vec2(group.width, group.height);
-    position[3] = vec2(0, group.height);
-    texCoord[0] = vec2(0, 0);
-    texCoord[1] = vec2(1, 0);
-    texCoord[2] = vec2(1, 1);
-    texCoord[3] = vec2(0, 1);
-    drawMesh(mesh);
-
-    // reset color matrix
-    mState.setColorMatrix(mat4());
-
-    // free our fbo and texture
-    glDeleteFramebuffers(1, &group.fbo);
-    glDeleteTextures(1, &group.texture);
-}
-
 void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
 }
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 3d6243e..819356a 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -72,14 +72,12 @@
     virtual void setupLayerTexturing(const Texture& texture);
     virtual void setupLayerBlackedOut();
     virtual void setupFillWithColor(float r, float g, float b, float a);
+    virtual mat4 setupColorTransform(const mat4& colorTransform);
     virtual void disableTexturing();
     virtual void disableBlending();
 
     virtual void drawMesh(const Mesh& mesh);
 
-    virtual void beginGroup(const mat4& colorTransform);
-    virtual void endGroup();
-
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
 };
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 8d7529c..31a961e 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -99,18 +99,16 @@
     virtual void setupLayerBlackedOut() = 0;
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
 
+    virtual mat4 setupColorTransform(const mat4& /* colorTransform */) {
+        return mat4();
+    }
+
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
 
-    // grouping
-    // creates a color-transform group, everything drawn in the group will be
-    // transformed by the given color transform when endGroup() is called.
-    virtual void beginGroup(const mat4& colorTransform) = 0;
-    virtual void endGroup() = 0;
-
     // queries
     virtual size_t getMaxTextureSize() const = 0;
     virtual size_t getMaxViewportDims() const = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c612026..1388ce8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1872,9 +1872,9 @@
         if (mDaltonize) {
             colorMatrix = colorMatrix * mDaltonizer();
         }
-        engine.beginGroup(colorMatrix);
+        mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
         doComposeSurfaces(hw, dirtyRegion);
-        engine.endGroup();
+        engine.setupColorTransform(oldMatrix);
     }
 
     // update the swap region and clear the dirty region