SurfaceFlinger now uses GLES 2.x when available

Bug: 8679321

Change-Id: I2b152d01fb4e2de2ea9fe87f1ddbd6826d7520d7
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 891c464..00f38b4 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -19,8 +19,6 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
 
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/BufferQueue.h>
@@ -54,6 +52,8 @@
  * This class was previously called SurfaceTexture.
  */
 class GLConsumer : public ConsumerBase {
+protected:
+    enum { TEXTURE_EXTERNAL = 0x8D65 }; // GL_TEXTURE_EXTERNAL_OES
 public:
     typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
 
@@ -82,7 +82,7 @@
     // context to another. If such a transfer is not needed there is no
     // requirement that either of these methods be called.
     GLConsumer(const sp<IGraphicBufferConsumer>& bq,
-            GLuint tex, GLenum texTarget = GL_TEXTURE_EXTERNAL_OES,
+            uint32_t tex, uint32_t texureTarget = TEXTURE_EXTERNAL,
             bool useFenceSync = true, bool isControlledByApp = false);
 
     // updateTexImage acquires the most recently queued buffer, and sets the
@@ -160,7 +160,7 @@
 
     // getCurrentTextureTarget returns the texture target of the current
     // texture as returned by updateTexImage().
-    GLenum getCurrentTextureTarget() const;
+    uint32_t getCurrentTextureTarget() const;
 
     // getCurrentCrop returns the cropping rectangle of the current buffer.
     Rect getCurrentCrop() const;
@@ -215,7 +215,7 @@
     // call to attachToContext will result in this texture object being bound to
     // the texture target and populated with the image contents that were
     // current at the time of the last call to detachFromContext.
-    status_t attachToContext(GLuint tex);
+    status_t attachToContext(uint32_t tex);
 
 protected:
 
@@ -347,7 +347,7 @@
     // mTexName is the name of the OpenGL texture to which streamed images will
     // be bound when updateTexImage is called. It is set at construction time
     // and can be changed with a call to attachToContext.
-    GLuint mTexName;
+    uint32_t mTexName;
 
     // mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync
     // extension should be used to prevent buffers from being dequeued before
@@ -362,7 +362,7 @@
     // glCopyTexSubImage to read from the texture.  This is a hack to work
     // around a GL driver limitation on the number of FBO attachments, which the
     // browser's tile cache exceeds.
-    const GLenum mTexTarget;
+    const uint32_t mTexTarget;
 
     // EGLSlot contains the information and object references that
     // GLConsumer maintains about a BufferQueue buffer slot.
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 2f7406e..6f8a97c 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -18,7 +18,6 @@
 #define ANDROID_GUI_SURFACE_H
 
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/GLConsumer.h>
 #include <gui/BufferQueue.h>
 
 #include <ui/ANativeObjectBase.h>
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 482317f..0a2afbf 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -89,8 +89,8 @@
 Mutex GLConsumer::sStaticInitLock;
 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
 
-GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, GLuint tex,
-        GLenum texTarget, bool useFenceSync, bool isControlledByApp) :
+GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
+        uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
     ConsumerBase(bq, isControlledByApp),
     mCurrentTransform(0),
     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
@@ -523,7 +523,7 @@
     return OK;
 }
 
-status_t GLConsumer::attachToContext(GLuint tex) {
+status_t GLConsumer::attachToContext(uint32_t tex) {
     ATRACE_CALL();
     ST_LOGV("attachToContext");
     Mutex::Autolock lock(mMutex);
@@ -554,7 +554,7 @@
 
     // We need to bind the texture regardless of whether there's a current
     // buffer.
-    glBindTexture(mTexTarget, tex);
+    glBindTexture(mTexTarget, GLuint(tex));
 
     if (mCurrentTextureBuf != NULL) {
         // The EGLImageKHR that was associated with the slot was destroyed when
@@ -689,7 +689,7 @@
     return false;
 }
 
-GLenum GLConsumer::getCurrentTextureTarget() const {
+uint32_t GLConsumer::getCurrentTextureTarget() const {
     return mTexTarget;
 }
 
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 8dbb9c5..7a14fb0 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -19,10 +19,15 @@
     DisplayHardware/VirtualDisplaySurface.cpp \
     EventLog/EventLogTags.logtags \
     EventLog/EventLog.cpp \
+    RenderEngine/Description.cpp \
+    RenderEngine/Mesh.cpp \
+    RenderEngine/Program.cpp \
+    RenderEngine/ProgramCache.cpp \
     RenderEngine/GLExtensions.cpp \
     RenderEngine/RenderEngine.cpp \
     RenderEngine/GLES10RenderEngine.cpp \
-    RenderEngine/GLES11RenderEngine.cpp
+    RenderEngine/GLES11RenderEngine.cpp \
+    RenderEngine/GLES20RenderEngine.cpp
 
 
 LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
@@ -56,6 +61,7 @@
 	libutils \
 	libEGL \
 	libGLESv1_CM \
+	libGLESv2 \
 	libbinder \
 	libui \
 	libgui
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 8143227..79b6689 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -274,7 +274,7 @@
 void DisplayDevice::setViewportAndProjection() const {
     size_t w = mDisplayWidth;
     size_t h = mDisplayHeight;
-    mFlinger->getRenderEngine().setViewportAndProjection(w, h);
+    mFlinger->getRenderEngine().setViewportAndProjection(w, h, w, h, false);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2defe34..cf4ec57 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -80,7 +80,7 @@
         mClientRef(client)
 {
     mCurrentCrop.makeInvalid();
-    glGenTextures(1, &mTextureName);
+    mFlinger->getRenderEngine().genTextures(1, &mTextureName);
 
     uint32_t layerFlags = 0;
     if (flags & ISurfaceComposerClient::eHidden)
@@ -110,13 +110,10 @@
     mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
 }
 
-void Layer::onFirstRef()
-{
+void Layer::onFirstRef() {
     // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
     mBufferQueue = new SurfaceTextureLayer(mFlinger);
-    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName,
-            GL_TEXTURE_EXTERNAL_OES, false);
-
+    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
     mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
     mSurfaceFlingerConsumer->setFrameAvailableListener(this);
     mSurfaceFlingerConsumer->setName(mName);
@@ -495,14 +492,11 @@
 
 
 void Layer::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
-        GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const
+        float red, float green, float blue, float alpha) const
 {
-    LayerMesh mesh;
-    computeGeometry(hw, &mesh);
-
-    mFlinger->getRenderEngine().clearWithColor(
-        mesh.getVertices(), mesh.getVertexCount(),
-        red, green, blue, alpha);
+    Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
+    computeGeometry(hw, mesh);
+    mFlinger->getRenderEngine().fillWithColor(mesh, red, green, blue, alpha);
 }
 
 void Layer::clearWithOpenGL(
@@ -515,8 +509,8 @@
     const uint32_t fbHeight = hw->getHeight();
     const State& s(getDrawingState());
 
-    LayerMesh mesh;
-    computeGeometry(hw, &mesh);
+    Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
+    computeGeometry(hw, mesh);
 
     /*
      * NOTE: the way we compute the texture coordinates here produces
@@ -534,29 +528,27 @@
      */
     const Rect win(computeBounds());
 
-    GLfloat left   = GLfloat(win.left)   / GLfloat(s.active.w);
-    GLfloat top    = GLfloat(win.top)    / GLfloat(s.active.h);
-    GLfloat right  = GLfloat(win.right)  / GLfloat(s.active.w);
-    GLfloat bottom = GLfloat(win.bottom) / GLfloat(s.active.h);
+    float left   = float(win.left)   / float(s.active.w);
+    float top    = float(win.top)    / float(s.active.h);
+    float right  = float(win.right)  / float(s.active.w);
+    float bottom = float(win.bottom) / float(s.active.h);
 
     // TODO: we probably want to generate the texture coords with the mesh
     // here we assume that we only have 4 vertices
-    float texCoords[4][2];
-    texCoords[0][0] = left;
-    texCoords[0][1] = top;
-    texCoords[1][0] = left;
-    texCoords[1][1] = bottom;
-    texCoords[2][0] = right;
-    texCoords[2][1] = bottom;
-    texCoords[3][0] = right;
-    texCoords[3][1] = top;
-    for (int i = 0; i < 4; i++) {
-        texCoords[i][1] = 1.0f - texCoords[i][1];
-    }
+    size_t stride = mesh.getStride();
+    float* base = mesh.getTexCoords();
+    base[stride*0 + 0] = left;
+    base[stride*0 + 1] = 1.0f - top;
+    base[stride*1 + 0] = left;
+    base[stride*1 + 1] = 1.0f - bottom;
+    base[stride*2 + 0] = right;
+    base[stride*2 + 1] = 1.0f - bottom;
+    base[stride*3 + 0] = right;
+    base[stride*3 + 1] = 1.0f - top;
 
     RenderEngine& engine(mFlinger->getRenderEngine());
     engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(), s.alpha);
-    engine.drawMesh2D(mesh.getVertices(), texCoords, mesh.getVertexCount());
+    engine.drawMesh(mesh);
     engine.disableBlending();
 }
 
@@ -592,7 +584,7 @@
 // local state
 // ----------------------------------------------------------------------------
 
-void Layer::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const
+void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh) const
 {
     const Layer::State& s(getDrawingState());
     const Transform tr(hw->getTransform() * s.transform);
@@ -603,14 +595,13 @@
     }
     // subtract the transparent region and snap to the bounds
     win = reduce(win, s.activeTransparentRegion);
-    if (mesh) {
-        tr.transform(mesh->mVertices[0], win.left,  win.top);
-        tr.transform(mesh->mVertices[1], win.left,  win.bottom);
-        tr.transform(mesh->mVertices[2], win.right, win.bottom);
-        tr.transform(mesh->mVertices[3], win.right, win.top);
-        for (size_t i=0 ; i<4 ; i++) {
-            mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1];
-        }
+
+    tr.transform(mesh[0], win.left,  win.top);
+    tr.transform(mesh[1], win.left,  win.bottom);
+    tr.transform(mesh[2], win.right, win.bottom);
+    tr.transform(mesh[3], win.right, win.top);
+    for (size_t i=0 ; i<4 ; i++) {
+        mesh[i][1] = hw_h - mesh[i][1];
     }
 }
 
@@ -1195,6 +1186,12 @@
 }
 
 // ---------------------------------------------------------------------------
-
-
 }; // namespace android
+
+#if defined(__gl_h_)
+#error "don't include gl/gl.h in this file"
+#endif
+
+#if defined(__gl2_h_)
+#error "don't include gl2/gl2.h in this file"
+#endif
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8332a5a..27e0c69 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -44,6 +44,7 @@
 
 #include "DisplayHardware/HWComposer.h"
 #include "DisplayHardware/FloatRect.h"
+#include "RenderEngine/Mesh.h"
 
 namespace android {
 
@@ -109,23 +110,6 @@
         Region requestedTransparentRegion;
     };
 
-    class LayerMesh {
-        friend class Layer;
-        typedef GLfloat float2[2];
-        float2 mVertices[4];
-        size_t mNumVertices;
-    public:
-        LayerMesh() :
-                mNumVertices(4) {
-        }
-        float2 const* getVertices() const {
-            return mVertices;
-        }
-        size_t getVertexCount() const {
-            return mNumVertices;
-        }
-    };
-
     // -----------------------------------------------------------------------
 
     Layer(SurfaceFlinger* flinger, const sp<Client>& client,
@@ -150,7 +134,7 @@
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t setTransactionFlags(uint32_t flags);
 
-    void computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const;
+    void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh) const;
     Rect computeBounds() const;
 
     sp<IBinder> getHandle();
@@ -336,7 +320,7 @@
 
     // drawing
     void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
-            GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const;
+            float r, float g, float b, float alpha) const;
     void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
 
 
@@ -345,7 +329,7 @@
     // constants
     sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
     sp<BufferQueue> mBufferQueue;
-    GLuint mTextureName;
+    uint32_t mTextureName;
     bool mPremultipliedAlpha;
     String8 mName;
     mutable bool mDebug;
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
index 062ad46..4e82bab 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -43,11 +43,11 @@
 {
     const State& s(getDrawingState());
     if (s.alpha>0) {
-        LayerMesh mesh;
-        computeGeometry(hw, &mesh);
+        Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
+        computeGeometry(hw, mesh);
         RenderEngine& engine(mFlinger->getRenderEngine());
         engine.setupDimLayerBlending(s.alpha);
-        engine.drawMesh2D(mesh.getVertices(), NULL, mesh.getVertexCount());
+        engine.drawMesh(mesh);
         engine.disableBlending();
     }
 }
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
new file mode 100644
index 0000000..9611b02
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <utils/TypeHelpers.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "Description.h"
+
+namespace android {
+
+Description::Description() :
+    mUniformsDirty(true) {
+    mPlaneAlpha = 1.0f;
+    mPremultipliedAlpha = true;
+    mOpaque = true;
+    mTextureTarget = GL_TEXTURE_EXTERNAL_OES;
+
+    const GLfloat m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
+    memset(mColor, 0, sizeof(mColor));
+    memcpy(mProjectionMatrix, m, sizeof(mProjectionMatrix));
+    memcpy(mTextureMatrix, m, sizeof(mTextureMatrix));
+}
+
+Description::~Description() {
+}
+
+void Description::setPlaneAlpha(GLclampf planeAlpha) {
+    if (planeAlpha != mPlaneAlpha) {
+        mUniformsDirty = true;
+        mPlaneAlpha = planeAlpha;
+    }
+}
+
+void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
+    if (premultipliedAlpha != mPremultipliedAlpha) {
+        mPremultipliedAlpha = premultipliedAlpha;
+    }
+}
+
+void Description::setOpaque(bool opaque) {
+    if (opaque != mOpaque) {
+        mOpaque = opaque;
+    }
+}
+
+void Description::setTextureName(GLenum target, GLuint tname) {
+    if (target != mTextureTarget) {
+        mTextureTarget = target;
+    }
+    if (tname != mTextureName) {
+        mTextureName = tname;
+        mUniformsDirty = true;
+    }
+}
+
+void Description::disableTexture() {
+    if (mTextureTarget != 0) {
+        mTextureTarget = 0;
+    }
+    mTextureName = 0;
+}
+
+void Description::setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+    mColor[0] = red;
+    mColor[1] = green;
+    mColor[2] = blue;
+    mColor[3] = alpha;
+    mUniformsDirty = true;
+}
+
+void Description::setProjectionMatrix(GLfloat const* mtx) {
+    memcpy(mProjectionMatrix, mtx, sizeof(mProjectionMatrix));
+    mUniformsDirty = true;
+}
+
+void Description::setTextureMatrix(GLfloat const* mtx) {
+    memcpy(mTextureMatrix, mtx, sizeof(mTextureMatrix));
+    mUniformsDirty = true;
+}
+
+} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
new file mode 100644
index 0000000..47b0d8e
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES2/gl2.h>
+
+#ifndef SF_RENDER_ENGINE_DESCRIPTION_H_
+#define SF_RENDER_ENGINE_DESCRIPTION_H_
+
+namespace android {
+
+class Program;
+
+/*
+ * This holds the state of the rendering engine. This class is used
+ * to generate a corresponding GLSL program and set the appropriate
+ * uniform.
+ *
+ * Program and ProgramCache are friends and access the state directly
+ */
+class Description {
+    friend class Program;
+    friend class ProgramCache;
+
+    // value of the plane-alpha, between 0 and 1
+    GLclampf mPlaneAlpha;
+    // whether textures are premultiplied
+    bool mPremultipliedAlpha;
+    // whether this layer is marked as opaque
+    bool mOpaque;
+    // texture target, TEXTURE_2D or TEXTURE_EXTERNAL
+    GLenum mTextureTarget;
+
+    // name of the texture
+    GLuint mTextureName;
+    // color used when texturing is disabled
+    GLclampf mColor[4];
+    // projection matrix
+    GLfloat mProjectionMatrix[16];
+    // texture matrix
+    GLfloat mTextureMatrix[16];
+
+public:
+    Description();
+    ~Description();
+
+    void setPlaneAlpha(GLclampf planeAlpha);
+    void setPremultipliedAlpha(bool premultipliedAlpha);
+    void setOpaque(bool opaque);
+    void setTextureName(GLenum target, GLuint tname);
+    void disableTexture();
+    void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    void setProjectionMatrix(GLfloat const* mtx);
+    void setTextureMatrix(GLfloat const* mtx);
+
+private:
+    bool mUniformsDirty;
+};
+
+} /* namespace android */
+
+#endif /* SF_RENDER_ENGINE_DESCRIPTION_H_ */
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 19499c9..27105a2 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -21,6 +21,7 @@
 
 #include "GLES11RenderEngine.h"
 #include "GLExtensions.h"
+#include "Mesh.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -69,12 +70,14 @@
             mMaxViewportDims[0] : mMaxViewportDims[1];
 }
 
-void GLES11RenderEngine::setViewportAndProjection(size_t w, size_t h) {
-    glViewport(0, 0, w, h);
+void GLES11RenderEngine::setViewportAndProjection(
+        size_t vpw, size_t vph, size_t w, size_t h, bool yswap) {
+    glViewport(0, 0, vpw, vph);
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     // put the origin in the left-bottom corner
-    glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h
+    if (yswap)  glOrthof(0, w, h, 0, 0, 1);
+    else        glOrthof(0, w, 0, h, 0, 1);
     glMatrixMode(GL_MODELVIEW);
 }
 
@@ -87,7 +90,7 @@
 
     if (CC_UNLIKELY(alpha < 0xFF)) {
         // Cv = premultiplied ? Cs*alpha : Cs
-        // Av = !opaque       ? alpha*As : 1.0
+        // Av = !opaque       ? As*alpha : As
         combineRGB   = premultipliedAlpha ? GL_MODULATE : GL_REPLACE;
         combineAlpha = !opaque            ? GL_MODULATE : GL_REPLACE;
         src0Alpha    = GL_CONSTANT;
@@ -180,25 +183,37 @@
     glDisable(GL_BLEND);
 }
 
-void GLES11RenderEngine::clearWithColor(const float vertices[][2] , size_t count,
-    float red, float green, float blue, float alpha) {
-    glColor4f(red, green, blue, alpha);
+void GLES11RenderEngine::fillWithColor(const Mesh& mesh, float r, float g, float b, float a) {
+    glColor4f(r, g, b, a);
     glDisable(GL_TEXTURE_EXTERNAL_OES);
     glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
-    glVertexPointer(2, GL_FLOAT, 0, vertices);
-    glDrawArrays(GL_TRIANGLE_FAN, 0, count);
+
+    glVertexPointer(mesh.getVertexSize(),
+            GL_FLOAT,
+            mesh.getByteStride(),
+            mesh.getVertices());
+
+    glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
 }
 
-void GLES11RenderEngine::drawMesh2D(
-    const float vertices[][2], const float texCoords[][2], size_t count) {
-    if (texCoords) {
+void GLES11RenderEngine::drawMesh(const Mesh& mesh) {
+    if (mesh.getTexCoordsSize()) {
         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-        glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+        glTexCoordPointer(mesh.getTexCoordsSize(),
+                GL_FLOAT,
+                mesh.getByteStride(),
+                mesh.getTexCoords());
     }
-    glVertexPointer(2, GL_FLOAT, 0, vertices);
-    glDrawArrays(GL_TRIANGLE_FAN, 0, count);
-    if (texCoords) {
+
+    glVertexPointer(mesh.getVertexSize(),
+            GL_FLOAT,
+            mesh.getByteStride(),
+            mesh.getVertices());
+
+    glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+
+    if (mesh.getTexCoordsSize()) {
         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     }
 }
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
index 15054bd..8bb7ed1 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
@@ -30,6 +30,7 @@
 // ---------------------------------------------------------------------------
 
 class String8;
+class Mesh;
 
 class GLES11RenderEngine : public RenderEngine {
     GLuint mProtectedTexName;
@@ -43,7 +44,7 @@
     virtual ~GLES11RenderEngine();
 
     virtual void dump(String8& result);
-    virtual void setViewportAndProjection(size_t w, size_t h);
+    virtual void setViewportAndProjection(size_t vpw, size_t vph, size_t w, size_t h, bool yswap);
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha);
     virtual void setupDimLayerBlending(int alpha);
     virtual void setupLayerTexturing(size_t textureName, bool useFiltering, const float* textureMatrix);
@@ -51,10 +52,8 @@
     virtual void disableTexturing();
     virtual void disableBlending();
 
-    virtual void clearWithColor(const float vertices[][2], size_t count,
-        float red, float green, float blue, float alpha);
-
-    virtual void drawMesh2D(const float vertices[][2], const float texCoords[][2], size_t count);
+    virtual void fillWithColor(const Mesh& mesh, float r, float g, float b, float a) ;
+    virtual void drawMesh(const Mesh& mesh);
 
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
new file mode 100644
index 0000000..6786065
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <GLES2/gl2.h>
+
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+#include <cutils/compiler.h>
+
+#include "GLES20RenderEngine.h"
+#include "GLExtensions.h"
+#include "Program.h"
+#include "ProgramCache.h"
+#include "Description.h"
+#include "Mesh.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+GLES20RenderEngine::GLES20RenderEngine() {
+
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+    glPixelStorei(GL_PACK_ALIGNMENT, 4);
+
+    struct pack565 {
+        inline uint16_t operator() (int r, int g, int b) const {
+            return (r<<11)|(g<<5)|b;
+        }
+    } pack565;
+
+    const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) };
+    glGenTextures(1, &mProtectedTexName);
+    glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0,
+            GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
+}
+
+GLES20RenderEngine::~GLES20RenderEngine() {
+}
+
+
+size_t GLES20RenderEngine::getMaxTextureSize() const {
+    return mMaxTextureSize;
+}
+
+size_t GLES20RenderEngine::getMaxViewportDims() const {
+    return
+        mMaxViewportDims[0] < mMaxViewportDims[1] ?
+            mMaxViewportDims[0] : mMaxViewportDims[1];
+}
+
+void GLES20RenderEngine::setViewportAndProjection(
+        size_t vpw, size_t vph, size_t w, size_t h, bool yswap) {
+
+    struct ortho {
+        inline void operator() (GLfloat *m,
+                GLfloat left, GLfloat right, GLfloat bottom, GLfloat top,
+                GLfloat near, GLfloat far) const {
+            memset(m, 0, 16*sizeof(GLfloat));
+            m[ 0] = 2.0f / (right - left);
+            m[ 5] = 2.0f / (top   - bottom);
+            m[10] =-2.0f / (far   - near);
+            m[15] = 1.0f;
+            m[12] = -(right + left) / (right - left);
+            m[13] = -(top + bottom) / (top - bottom);
+            m[14] = -(far + near) / (far - near);
+        }
+    } ortho;
+
+    GLfloat m[16];
+    if (yswap)  ortho(m, 0, w, h, 0, 0, 1);
+    else        ortho(m, 0, w, 0, h, 0, 1);
+
+    glViewport(0, 0, vpw, vph);
+    mState.setProjectionMatrix(m);
+}
+
+void GLES20RenderEngine::setupLayerBlending(
+    bool premultipliedAlpha, bool opaque, int alpha) {
+
+    mState.setPremultipliedAlpha(premultipliedAlpha);
+    mState.setOpaque(opaque);
+    mState.setPlaneAlpha(alpha / 255.0f);
+
+    if (alpha < 0xFF || !opaque) {
+        glEnable(GL_BLEND);
+        glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    } else {
+        glDisable(GL_BLEND);
+    }
+}
+
+void GLES20RenderEngine::setupDimLayerBlending(int alpha) {
+    mState.setPlaneAlpha(alpha / 255.0f);
+
+    if (alpha == 0xFF) {
+        glDisable(GL_BLEND);
+    } else {
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+    }
+    disableTexturing();
+}
+
+void GLES20RenderEngine::setupLayerTexturing(size_t textureName,
+    bool useFiltering, const float* textureMatrix) {
+    glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureName);
+    GLenum filter = GL_NEAREST;
+    if (useFiltering) {
+        filter = GL_LINEAR;
+    }
+    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, filter);
+    glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, filter);
+
+    mState.setTextureName(GL_TEXTURE_EXTERNAL_OES, textureName);
+    mState.setTextureMatrix(textureMatrix);
+}
+
+void GLES20RenderEngine::setupLayerBlackedOut() {
+    const GLfloat m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
+    glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
+    mState.setTextureName(GL_TEXTURE_2D, mProtectedTexName);
+    mState.setTextureMatrix(m);
+}
+
+void GLES20RenderEngine::disableTexturing() {
+    mState.disableTexture();
+}
+
+void GLES20RenderEngine::disableBlending() {
+    glDisable(GL_BLEND);
+}
+
+void GLES20RenderEngine::fillWithColor(const Mesh& mesh, float r, float g, float b, float a) {
+    mState.setColor(r, g, b, a);
+    disableTexturing();
+    glDisable(GL_BLEND);
+
+    ProgramCache::getInstance().useProgram(mState);
+
+    glVertexAttribPointer(Program::position,
+            mesh.getVertexSize(),
+            GL_FLOAT, GL_FALSE,
+            mesh.getByteStride(),
+            mesh.getVertices());
+
+    glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+}
+
+void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
+
+    ProgramCache::getInstance().useProgram(mState);
+
+    if (mesh.getTexCoordsSize()) {
+        glEnableVertexAttribArray(Program::texCoords);
+        glVertexAttribPointer(Program::texCoords,
+                mesh.getTexCoordsSize(),
+                GL_FLOAT, GL_FALSE,
+                mesh.getByteStride(),
+                mesh.getTexCoords());
+    }
+
+    glVertexAttribPointer(Program::position,
+            mesh.getVertexSize(),
+            GL_FLOAT, GL_FALSE,
+            mesh.getByteStride(),
+            mesh.getVertices());
+
+    glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+
+    if (mesh.getTexCoordsSize()) {
+        glDisableVertexAttribArray(Program::texCoords);
+    }
+}
+
+void GLES20RenderEngine::dump(String8& result) {
+    const GLExtensions& extensions(GLExtensions::getInstance());
+    result.appendFormat("GLES: %s, %s, %s\n",
+            extensions.getVendor(),
+            extensions.getRenderer(),
+            extensions.getVersion());
+    result.appendFormat("%s\n", extensions.getExtension());
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
new file mode 100644
index 0000000..873a643
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef SF_GLES20RENDERENGINE_H_
+#define SF_GLES20RENDERENGINE_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <GLES2/gl2.h>
+
+#include "RenderEngine.h"
+#include "ProgramCache.h"
+#include "Description.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class String8;
+class Mesh;
+
+class GLES20RenderEngine : public RenderEngine {
+    GLuint mProtectedTexName;
+    GLint mMaxViewportDims[2];
+    GLint mMaxTextureSize;
+
+    Description mState;
+
+public:
+    GLES20RenderEngine();
+
+protected:
+    virtual ~GLES20RenderEngine();
+
+    virtual void dump(String8& result);
+    virtual void setViewportAndProjection(size_t vpw, size_t vph, size_t w, size_t h, bool yswap);
+    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha);
+    virtual void setupDimLayerBlending(int alpha);
+    virtual void setupLayerTexturing(size_t textureName, bool useFiltering, const float* textureMatrix);
+    virtual void setupLayerBlackedOut();
+    virtual void disableTexturing();
+    virtual void disableBlending();
+
+    virtual void fillWithColor(const Mesh& mesh, float r, float g, float b, float a);
+    virtual void drawMesh(const Mesh& mesh);
+
+    virtual size_t getMaxTextureSize() const;
+    virtual size_t getMaxViewportDims() const;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif /* SF_GLES20RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
new file mode 100644
index 0000000..a08eea6
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Mesh.h"
+
+namespace android {
+
+Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
+    : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize),
+      mPrimitive(primitive)
+{
+    mVertices = new float[(vertexSize + texCoordSize) * vertexCount];
+    mStride = mVertexSize + mTexCoordsSize;
+}
+
+Mesh::~Mesh() {
+    delete [] mVertices;
+}
+
+float const* Mesh::operator[](size_t index) const {
+    return &mVertices[index * mStride];
+}
+
+float* Mesh::operator[](size_t index) {
+    return &mVertices[index * mStride];
+}
+
+Mesh::Primitive Mesh::getPrimitive() const {
+    return mPrimitive;
+}
+
+
+float const* Mesh::getVertices() const {
+    return mVertices;
+}
+float* Mesh::getVertices() {
+    return mVertices;
+}
+
+float const* Mesh::getTexCoords() const {
+    return mVertices + mVertexSize;
+}
+float* Mesh::getTexCoords() {
+    return mVertices + mVertexSize;
+}
+
+
+size_t Mesh::getVertexCount() const {
+    return mVertexCount;
+}
+
+size_t Mesh::getVertexSize() const {
+    return mVertexSize;
+}
+
+size_t Mesh::getTexCoordsSize() const {
+    return mTexCoordsSize;
+}
+
+size_t Mesh::getByteStride() const {
+    return mStride*sizeof(float);
+}
+
+size_t Mesh::getStride() const {
+    return mStride;
+}
+
+} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Mesh.h b/services/surfaceflinger/RenderEngine/Mesh.h
new file mode 100644
index 0000000..599a150
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Mesh.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SF_RENDER_ENGINE_MESH_H
+#define SF_RENDER_ENGINE_MESH_H
+
+#include <stdint.h>
+
+namespace android {
+
+class Mesh {
+public:
+    enum Primitive {
+        TRIANGLES       = 0x0004,
+        TRIANGLE_STRIP  = 0x0005,
+        TRIANGLE_FAN    = 0x0006
+    };
+
+    Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordsSize = 0);
+    ~Mesh();
+
+    float const* operator[](size_t index) const;
+    float* operator[](size_t index);
+
+
+    Primitive getPrimitive() const;
+
+    float const* getVertices() const;
+    float* getVertices();
+
+    float const* getTexCoords() const;
+    float* getTexCoords();
+
+    size_t getVertexCount() const;
+    size_t getVertexSize() const;
+    size_t getTexCoordsSize() const;
+
+    size_t getByteStride() const;
+    size_t getStride() const;
+
+private:
+    float* mVertices;
+    size_t mVertexCount;
+    size_t mVertexSize;
+    size_t mTexCoordsSize;
+    size_t mStride;
+    Primitive mPrimitive;
+};
+
+
+} /* namespace android */
+#endif /* SF_RENDER_ENGINE_MESH_H */
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
new file mode 100644
index 0000000..586d1ad
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -0,0 +1,144 @@
+/*Gluint
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <log/log.h>
+
+#include "Program.h"
+#include "ProgramCache.h"
+#include "Description.h"
+#include <utils/String8.h>
+
+namespace android {
+
+Program::Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment)
+        : mInitialized(false) {
+    GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER);
+    GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER);
+    GLuint programId = glCreateProgram();
+    glAttachShader(programId, vertexId);
+    glAttachShader(programId, fragmentId);
+    glBindAttribLocation(programId, position, "position");
+    glBindAttribLocation(programId, texCoords, "texCoords");
+    glLinkProgram(programId);
+
+    GLint status;
+    glGetProgramiv(programId, GL_LINK_STATUS, &status);
+    if (status != GL_TRUE) {
+        ALOGE("Error while linking shaders:");
+        GLint infoLen = 0;
+        glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &infoLen);
+        if (infoLen > 1) {
+            GLchar log[infoLen];
+            glGetProgramInfoLog(programId, infoLen, 0, &log[0]);
+            ALOGE("%s", log);
+        }
+        glDetachShader(programId, vertexId);
+        glDetachShader(programId, fragmentId);
+        glDeleteShader(vertexId);
+        glDeleteShader(fragmentId);
+        glDeleteProgram(programId);
+    } else {
+        mProgram = programId;
+        mVertexShader = vertexId;
+        mFragmentShader = fragmentId;
+        mInitialized = true;
+
+        mProjectionMatrixLoc = glGetUniformLocation(programId, "projection");
+        mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
+        mSamplerLoc = glGetUniformLocation(programId, "sampler");
+        mColorLoc = glGetUniformLocation(programId, "color");
+        mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane");
+
+        // set-up the default values for our uniforms
+        glUseProgram(programId);
+        const GLfloat m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
+        glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, m);
+        glEnableVertexAttribArray(0);
+    }
+}
+
+Program::~Program() {
+}
+
+bool Program::isValid() const {
+    return mInitialized;
+}
+
+void Program::use() {
+    glUseProgram(mProgram);
+}
+
+GLuint Program::getAttrib(const char* name) const {
+    // TODO: maybe use a local cache
+    return glGetAttribLocation(mProgram, name);
+}
+
+GLint Program::getUniform(const char* name) const {
+    // TODO: maybe use a local cache
+    return glGetUniformLocation(mProgram, name);
+}
+
+GLuint Program::buildShader(const char* source, GLenum type) {
+    GLuint shader = glCreateShader(type);
+    glShaderSource(shader, 1, &source, 0);
+    glCompileShader(shader);
+    GLint status;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+    if (status != GL_TRUE) {
+        // Some drivers return wrong values for GL_INFO_LOG_LENGTH
+        // use a fixed size instead
+        GLchar log[512];
+        glGetShaderInfoLog(shader, sizeof(log), 0, log);
+        ALOGE("Error while compiling shader: \n%s\n%s", source, log);
+        glDeleteShader(shader);
+        return 0;
+    }
+    return shader;
+}
+
+String8& Program::dumpShader(String8& result, GLenum type) {
+    GLuint shader = GL_FRAGMENT_SHADER ? mFragmentShader : mVertexShader;
+    GLint l;
+    glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &l);
+    char* src = new char[l];
+    glGetShaderSource(shader, l, NULL, src);
+    result.append(src);
+    delete [] src;
+    return result;
+}
+
+void Program::setUniforms(const Description& desc) {
+
+    // TODO: we should have a mechanism here to not always reset uniforms that
+    // didn't change for this program.
+
+    if (mSamplerLoc >= 0) {
+        glUniform1i(mSamplerLoc, 0);
+        glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.mTextureMatrix);
+    }
+    if (mAlphaPlaneLoc >= 0) {
+        glUniform1f(mAlphaPlaneLoc, desc.mPlaneAlpha);
+    }
+    if (mColorLoc >= 0) {
+        glUniform4fv(mColorLoc, 1, desc.mColor);
+    }
+    // these uniforms are always present
+    glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix);
+}
+
+} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h
new file mode 100644
index 0000000..91bb3db
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Program.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SF_RENDER_ENGINE_PROGRAM_H
+#define SF_RENDER_ENGINE_PROGRAM_H
+
+#include <stdint.h>
+
+#include <GLES2/gl2.h>
+
+#include "Description.h"
+#include "ProgramCache.h"
+
+namespace android {
+
+class String8;
+
+/*
+ * Abstracts a GLSL program comprising a vertex and fragment shader
+ */
+class Program {
+public:
+    // known locations for position and texture coordinates
+    enum { position=0, texCoords=1 };
+
+    Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment);
+    ~Program();
+
+    /* whether this object is usable */
+    bool isValid() const;
+
+    /* Binds this program to the GLES context */
+    void use();
+
+    /* Returns the location of the specified attribute */
+    GLuint getAttrib(const char* name) const;
+
+    /* Returns the location of the specified uniform */
+    GLint getUniform(const char* name) const;
+
+    /* set-up uniforms from the description */
+    void setUniforms(const Description& desc);
+
+
+private:
+    GLuint buildShader(const char* source, GLenum type);
+    String8& dumpShader(String8& result, GLenum type);
+
+    // whether the initialization succeeded
+    bool mInitialized;
+
+    // Name of the OpenGL program and shaders
+    GLuint mProgram;
+    GLuint mVertexShader;
+    GLuint mFragmentShader;
+
+    /* location of the projection matrix uniform */
+    GLint mProjectionMatrixLoc;
+
+    /* location of the texture matrix uniform */
+    GLint mTextureMatrixLoc;
+
+    /* location of the sampler uniform */
+    GLint mSamplerLoc;
+
+    /* location of the alpha plane uniform */
+    GLint mAlphaPlaneLoc;
+
+    /* location of the color uniform */
+    GLint mColorLoc;
+};
+
+
+} /* namespace android */
+
+#endif /* SF_RENDER_ENGINE_PROGRAM_H */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
new file mode 100644
index 0000000..835ed8a
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/String8.h>
+
+#include "ProgramCache.h"
+#include "Program.h"
+#include "Description.h"
+
+namespace android {
+// -----------------------------------------------------------------------------------------------
+
+
+/*
+ * A simple formatter class to automatically add the endl and
+ * manage the indentation.
+ */
+
+class Formatter;
+static Formatter& indent(Formatter& f);
+static Formatter& dedent(Formatter& f);
+
+class Formatter {
+    String8 mString;
+    int mIndent;
+    typedef Formatter& (*FormaterManipFunc)(Formatter&);
+    friend Formatter& indent(Formatter& f);
+    friend Formatter& dedent(Formatter& f);
+public:
+    String8 getString() const {
+        return mString;
+    }
+
+    friend Formatter& operator << (Formatter& out, const char* in) {
+        for (int i=0 ; i<out.mIndent ; i++) {
+            out.mString.append("    ");
+        }
+        out.mString.append(in);
+        out.mString.append("\n");
+        return out;
+    }
+    friend inline Formatter& operator << (Formatter& out, const String8& in) {
+        return operator << (out, in.string());
+    }
+    friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
+        return (*func)(to);
+    }
+};
+Formatter& indent(Formatter& f) {
+    f.mIndent++;
+    return f;
+}
+Formatter& dedent(Formatter& f) {
+    f.mIndent--;
+    return f;
+}
+
+// -----------------------------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)
+
+
+ProgramCache::ProgramCache() {
+}
+
+ProgramCache::~ProgramCache() {
+}
+
+ProgramCache::Key ProgramCache::computeKey(const Description& description) {
+    Key needs;
+    needs.set(Key::TEXTURE_MASK,
+            (description.mTextureTarget == GL_TEXTURE_EXTERNAL_OES) ? Key::TEXTURE_EXT :
+            (description.mTextureTarget == GL_TEXTURE_2D)           ? Key::TEXTURE_2D :
+            Key::TEXTURE_OFF)
+    .set(Key::PLANE_ALPHA_MASK,
+            (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE)
+    .set(Key::BLEND_MASK,
+            description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
+    .set(Key::OPACITY_MASK,
+            description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
+    return needs;
+}
+
+String8 ProgramCache::generateVertexShader(const Key& needs) {
+    Formatter vs;
+    if (needs.isTexturing()) {
+        vs  << "attribute vec4 texCoords;"
+            << "varying vec2 outTexCoords;";
+    }
+    vs << "attribute vec4 position;"
+       << "uniform mat4 projection;"
+       << "uniform mat4 texture;"
+       << "void main(void) {" << indent
+       << "gl_Position = projection * position;";
+    if (needs.isTexturing()) {
+        vs << "outTexCoords = (texture * texCoords).st;";
+    }
+    vs << dedent << "}";
+    return vs.getString();
+}
+
+String8 ProgramCache::generateFragmentShader(const Key& needs) {
+    Formatter fs;
+    if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
+        fs << "#extension GL_OES_EGL_image_external : require";
+    }
+    if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
+        fs << "uniform samplerExternalOES sampler;"
+           << "varying vec2 outTexCoords;";
+    } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
+        fs << "uniform sampler2D sampler;"
+           << "varying vec2 outTexCoords;";
+    } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
+        fs << "uniform vec4 color;";
+    }
+    if (needs.hasPlaneAlpha()) {
+        fs << "uniform float alphaPlane;";
+    }
+    fs << "void main(void) {" << indent;
+    if (needs.isTexturing()) {
+        fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
+    } else {
+        fs << "gl_FragColor = color;";
+    }
+    if (needs.hasPlaneAlpha()) {
+        // modulate the alpha value with planeAlpha
+        if (needs.isPremultiplied()) {
+            // ... and the color too if we're premultiplied
+            if (needs.isOpaque()) {
+                // ... we're opaque, only premultiply the color component
+                fs << "gl_FragColor.rgb *= alphaPlane;"
+                   << "gl_FragColor.a = alphaPlane;";
+            } else {
+                fs << "gl_FragColor *= alphaPlane;";
+            }
+        } else {
+            // not premultiplied
+            if (needs.isOpaque()) {
+                fs << "gl_FragColor.a = alphaPlane;";
+            } else {
+                fs << "gl_FragColor.a *= alphaPlane;";
+            }
+        }
+    } else {
+        if (needs.isOpaque()) {
+            fs << "gl_FragColor.a = 1.0;";
+        }
+    }
+    fs << dedent << "}";
+    return fs.getString();
+}
+
+Program* ProgramCache::generateProgram(const Key& needs) {
+    // vertex shader
+    String8 vs = generateVertexShader(needs);
+
+    // fragment shader
+    String8 fs = generateFragmentShader(needs);
+
+    Program* program = new Program(needs, vs.string(), fs.string());
+    return program;
+}
+
+void ProgramCache::useProgram(const Description& description) {
+
+    // generate the key for the shader based on the description
+    Key needs(computeKey(description));
+
+     // look-up the program in the cache
+    Program* program = mCache.valueFor(needs);
+    if (program == NULL) {
+        // we didn't find our program, so generate one...
+        nsecs_t time = -systemTime();
+        program = generateProgram(needs);
+        mCache.add(needs, program);
+        time += systemTime();
+
+        //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)",
+        //        needs.mNeeds, uint32_t(ns2ms(time)), mCache.size());
+    }
+
+    // here we have a suitable program for this description
+    if (program->isValid()) {
+        program->use();
+        program->setUniforms(description);
+    }
+}
+
+
+} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
new file mode 100644
index 0000000..fcbeffd
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SF_RENDER_ENGINE_PROGRAMCACHE_H
+#define SF_RENDER_ENGINE_PROGRAMCACHE_H
+
+#include <GLES2/gl2.h>
+
+#include <utils/Singleton.h>
+#include <utils/KeyedVector.h>
+#include <utils/TypeHelpers.h>
+
+#include "Description.h"
+
+namespace android {
+
+class Description;
+class Program;
+class String8;
+
+/*
+ * This class generates GLSL programs suitable to handle a given
+ * Description. It's responsible for figuring out what to
+ * generate from a Description.
+ * It also maintains a cache of these Programs.
+ */
+class ProgramCache : public Singleton<ProgramCache> {
+public:
+    /*
+     * Key is used to retrieve a Program in the cache.
+     * A Key is generated from a Description.
+     */
+    class Key {
+        friend class ProgramCache;
+        typedef uint32_t key_t;
+        key_t mKey;
+    public:
+        enum {
+            BLEND_PREMULT           =       0x00000001,
+            BLEND_NORMAL            =       0x00000000,
+            BLEND_MASK              =       0x00000001,
+
+            OPACITY_OPAQUE          =       0x00000002,
+            OPACITY_TRANSLUCENT     =       0x00000000,
+            OPACITY_MASK            =       0x00000002,
+
+            PLANE_ALPHA_LT_ONE      =       0x00000004,
+            PLANE_ALPHA_EQ_ONE      =       0x00000000,
+            PLANE_ALPHA_MASK        =       0x00000004,
+
+            TEXTURE_OFF             =       0x00000000,
+            TEXTURE_EXT             =       0x00000008,
+            TEXTURE_2D              =       0x00000010,
+            TEXTURE_MASK            =       0x00000018,
+        };
+
+        inline Key() : mKey(0) { }
+        inline Key(const Key& rhs) : mKey(rhs.mKey) { }
+
+        inline Key& set(key_t mask, key_t value) {
+            mKey = (mKey & ~mask) | value;
+            return *this;
+        }
+
+        inline bool isTexturing() const {
+            return (mKey & TEXTURE_MASK) != TEXTURE_OFF;
+        }
+        inline int getTextureTarget() const {
+            return (mKey & TEXTURE_MASK);
+        }
+        inline bool isPremultiplied() const {
+            return (mKey & BLEND_MASK) == BLEND_PREMULT;
+        }
+        inline bool isOpaque() const {
+            return (mKey & OPACITY_MASK) == OPACITY_OPAQUE;
+        }
+        inline bool hasPlaneAlpha() const {
+            return (mKey & PLANE_ALPHA_MASK) == PLANE_ALPHA_LT_ONE;
+        }
+
+        // this is the definition of a friend function -- not a method of class Needs
+        friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
+            return  (lhs.mKey < rhs.mKey) ? 1 : 0;
+        }
+    };
+
+    ProgramCache();
+    ~ProgramCache();
+
+    // useProgram lookup a suitable program in the cache or generates one
+    // if none can be found.
+    void useProgram(const Description& description);
+
+private:
+    // compute a cache Key from a Description
+    static Key computeKey(const Description& description);
+    // generates a program from the Key
+    static Program* generateProgram(const Key& needs);
+    // generates the vertex shader from the Key
+    static String8 generateVertexShader(const Key& needs);
+    // generates the fragment shader from the Key
+    static String8 generateFragmentShader(const Key& needs);
+
+    // Key/Value map used for caching Programs. Currently the cache
+    // is never shrunk.
+    DefaultKeyedVector<Key, Program*> mCache;
+};
+
+
+ANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key)
+
+} /* namespace android */
+
+#endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index cb77e38..e8016ee 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -15,11 +15,15 @@
  */
 
 #include <cutils/log.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
 
 #include "RenderEngine.h"
 #include "GLES10RenderEngine.h"
 #include "GLES11RenderEngine.h"
+#include "GLES20RenderEngine.h"
 #include "GLExtensions.h"
+#include "Mesh.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -28,7 +32,7 @@
 RenderEngine* RenderEngine::create(EGLDisplay display, EGLConfig config) {
     // Also create our EGLContext
     EGLint contextAttributes[] = {
-//            EGL_CONTEXT_CLIENT_VERSION, 2,
+            EGL_CONTEXT_CLIENT_VERSION, 2,      // MUST be first
 #ifdef EGL_IMG_context_priority
 #ifdef HAS_CONTEXT_PRIORITY
 #warning "using EGL_IMG_context_priority"
@@ -79,7 +83,7 @@
         break;
     case GLES_VERSION_2_0:
     case GLES_VERSION_3_0:
-        //engine = new GLES20RenderEngine();
+        engine = new GLES20RenderEngine();
         break;
     }
     engine->setEGLContext(ctxt);
@@ -140,6 +144,85 @@
     return GLES_VERSION_1_0;
 }
 
+void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height,
+        float red, float green, float blue, float alpha) {
+    size_t c;
+    Rect const* r = region.getArray(&c);
+    Mesh mesh(Mesh::TRIANGLES, c*6, 2);
+    for (size_t i=0 ; i<c ; i++, r++) {
+        mesh[i*6 + 0][0] = r->left;
+        mesh[i*6 + 0][1] = height - r->top;
+        mesh[i*6 + 1][0] = r->left;
+        mesh[i*6 + 1][1] = height - r->bottom;
+        mesh[i*6 + 2][0] = r->right;
+        mesh[i*6 + 2][1] = height - r->bottom;
+        mesh[i*6 + 3][0] = r->left;
+        mesh[i*6 + 3][1] = height - r->top;
+        mesh[i*6 + 4][0] = r->right;
+        mesh[i*6 + 4][1] = height - r->bottom;
+        mesh[i*6 + 5][0] = r->right;
+        mesh[i*6 + 5][1] = height - r->top;
+    }
+    fillWithColor(mesh, red, green, blue, alpha);
+}
+
+void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+    glClearColor(red, green, blue, alpha);
+    glClear(GL_COLOR_BUFFER_BIT);
+}
+
+void RenderEngine::setScissor(
+        uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
+    glScissor(left, bottom, right, top);
+    glEnable(GL_SCISSOR_TEST);
+}
+
+void RenderEngine::disableScissor() {
+    glDisable(GL_SCISSOR_TEST);
+}
+
+void RenderEngine::genTextures(size_t count, uint32_t* names) {
+    glGenTextures(count, names);
+}
+
+void RenderEngine::deleteTextures(size_t count, uint32_t const* names) {
+    glDeleteTextures(count, names);
+}
+
+// ---------------------------------------------------------------------------
+
+RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
+        RenderEngine& engine, EGLImageKHR image) : mEngine(engine)
+{
+    GLuint tname, name;
+    // turn our EGLImage into a texture
+    glGenTextures(1, &tname);
+    glBindTexture(GL_TEXTURE_2D, tname);
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
+    // create a Framebuffer Object to render into
+    glGenFramebuffersOES(1, &name);
+    glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
+    glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
+            GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
+    mStatus = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
+    ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES,
+            "glCheckFramebufferStatusOES error %d", mStatus);
+    mTexName = tname;
+    mFbName = name;
+}
+
+RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() {
+    // back to main framebuffer
+    glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+    glDeleteFramebuffersOES(1, &mFbName);
+    glDeleteTextures(1, &mTexName);
+
+}
+
+status_t RenderEngine::BindImageAsFramebuffer::getStatus() const {
+    return mStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index e43bfa4..f4fa30b 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -22,12 +22,16 @@
 #include <sys/types.h>
 
 #include <EGL/egl.h>
+#include <EGL/eglext.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
 
 class String8;
+class Rect;
+class Region;
+class Mesh;
 
 class RenderEngine {
     enum GlesVersion {
@@ -48,10 +52,31 @@
 public:
     static RenderEngine* create(EGLDisplay display, EGLConfig config);
 
-    virtual void checkErrors() const;
+    // helpers
+    void clearWithColor(float red, float green, float blue, float alpha);
+    void fillRegionWithColor(const Region& region, uint32_t height,
+            float red, float green, float blue, float alpha);
 
+    // common to all GL versions
+    void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top);
+    void disableScissor();
+    void genTextures(size_t count, uint32_t* names);
+    void deleteTextures(size_t count, uint32_t const* names);
+
+    class BindImageAsFramebuffer {
+        RenderEngine& mEngine;
+        unsigned int mTexName, mFbName;
+        unsigned int mStatus;
+    public:
+        BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image);
+        ~BindImageAsFramebuffer();
+        int getStatus() const;
+    };
+
+    // set-up
+    virtual void checkErrors() const;
     virtual void dump(String8& result) = 0;
-    virtual void setViewportAndProjection(size_t w, size_t h) = 0;
+    virtual void setViewportAndProjection(size_t vpw, size_t vph, size_t w, size_t h, bool yswap) = 0;
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0;
     virtual void setupDimLayerBlending(int alpha) = 0;
     virtual void setupLayerTexturing(size_t textureName, bool useFiltering, const float* textureMatrix) = 0;
@@ -60,14 +85,16 @@
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
-    virtual void clearWithColor(const float vertices[][2], size_t count,
-        float red, float green, float blue, float alpha) = 0;
+    // drawing
+    virtual void fillWithColor(const Mesh& mesh, float r, float g, float b, float a) = 0;
+    virtual void drawMesh(const Mesh& mesh) = 0;
 
-    virtual void drawMesh2D(const float vertices[][2], const float texCoords[][2], size_t count) = 0;
-
+    // queries
     virtual size_t getMaxTextureSize() const = 0;
     virtual size_t getMaxViewportDims() const = 0;
 
+
+
     EGLContext getEGLContext() const;
 };
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b76cde7..68b9950 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -23,8 +23,6 @@
 #include <dlfcn.h>
 
 #include <EGL/egl.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
 
 #include <cutils/log.h>
 #include <cutils/properties.h>
@@ -72,6 +70,7 @@
 
 #include "RenderEngine/RenderEngine.h"
 
+
 #define DISPLAY_COUNT       1
 
 /*
@@ -268,19 +267,20 @@
     property_set("service.bootanim.exit", "1");
 }
 
-void SurfaceFlinger::deleteTextureAsync(GLuint texture) {
+void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
     class MessageDestroyGLTexture : public MessageBase {
-        GLuint texture;
+        RenderEngine& engine;
+        uint32_t texture;
     public:
-        MessageDestroyGLTexture(GLuint texture)
-            : texture(texture) {
+        MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture)
+            : engine(engine), texture(texture) {
         }
         virtual bool handler() {
-            glDeleteTextures(1, &texture);
+            engine.deleteTextures(1, &texture);
             return true;
         }
     };
-    postMessageAsync(new MessageDestroyGLTexture(texture));
+    postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
 }
 
 status_t SurfaceFlinger::selectConfigForAttribute(
@@ -750,24 +750,10 @@
                 doComposeSurfaces(hw, Region(hw->bounds()));
 
                 // and draw the dirty region
-                glDisable(GL_TEXTURE_EXTERNAL_OES);
-                glDisable(GL_TEXTURE_2D);
-                glDisable(GL_BLEND);
-                glColor4f(1, 0, 1, 1);
                 const int32_t height = hw->getHeight();
-                Region::const_iterator it = dirtyRegion.begin();
-                Region::const_iterator const end = dirtyRegion.end();
-                while (it != end) {
-                    const Rect& r = *it++;
-                    GLfloat vertices[][2] = {
-                            { (GLfloat) r.left,  (GLfloat) (height - r.top) },
-                            { (GLfloat) r.left,  (GLfloat) (height - r.bottom) },
-                            { (GLfloat) r.right, (GLfloat) (height - r.bottom) },
-                            { (GLfloat) r.right, (GLfloat) (height - r.top) }
-                    };
-                    glVertexPointer(2, GL_FLOAT, 0, vertices);
-                    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-                }
+                RenderEngine& engine(getRenderEngine());
+                engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
+
                 hw->compositionComplete();
                 hw->swapBuffers(getHwComposer());
             }
@@ -1512,6 +1498,7 @@
 
 void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
 {
+    RenderEngine& engine(getRenderEngine());
     const int32_t id = hw->getHwcDisplayId();
     HWComposer& hwc(getHwComposer());
     HWComposer::LayerListIterator cur = hwc.begin(id);
@@ -1525,20 +1512,15 @@
             return;
         }
 
-        // set the frame buffer
-        glMatrixMode(GL_MODELVIEW);
-        glLoadIdentity();
-
         // Never touch the framebuffer if we don't have any framebuffer layers
         const bool hasHwcComposition = hwc.hasHwcComposition(id);
         if (hasHwcComposition) {
             // when using overlays, we assume a fully transparent framebuffer
             // NOTE: we could reduce how much we need to clear, for instance
             // remove where there are opaque FB layers. however, on some
-            // GPUs doing a "clean slate" glClear might be more efficient.
+            // GPUs doing a "clean slate" clear might be more efficient.
             // We'll revisit later if needed.
-            glClearColor(0, 0, 0, 0);
-            glClear(GL_COLOR_BUFFER_BIT);
+            engine.clearWithColor(0, 0, 0, 0);
         } else {
             // we start with the whole screen area
             const Region bounds(hw->getBounds());
@@ -1571,11 +1553,11 @@
                 // scissor doesn't match the screen's dimensions, so we
                 // need to clear everything outside of it and enable
                 // the GL scissor so we don't draw anything where we shouldn't
-                const GLint height = hw->getHeight();
-                glScissor(scissor.left, height - scissor.bottom,
-                        scissor.getWidth(), scissor.getHeight());
+
                 // enable scissor for this frame
-                glEnable(GL_SCISSOR_TEST);
+                const uint32_t height = hw->getHeight();
+                engine.setScissor(scissor.left, height - scissor.bottom,
+                        scissor.getWidth(), scissor.getHeight());
             }
         }
     }
@@ -1632,31 +1614,13 @@
     }
 
     // disable scissor at the end of the frame
-    glDisable(GL_SCISSOR_TEST);
+    engine.disableScissor();
 }
 
-void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw,
-        const Region& region) const
-{
-    glDisable(GL_TEXTURE_EXTERNAL_OES);
-    glDisable(GL_TEXTURE_2D);
-    glDisable(GL_BLEND);
-    glColor4f(0,0,0,0);
-
+void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Region& region) const {
     const int32_t height = hw->getHeight();
-    Region::const_iterator it = region.begin();
-    Region::const_iterator const end = region.end();
-    while (it != end) {
-        const Rect& r = *it++;
-        GLfloat vertices[][2] = {
-                { (GLfloat) r.left,  (GLfloat) (height - r.top) },
-                { (GLfloat) r.left,  (GLfloat) (height - r.bottom) },
-                { (GLfloat) r.right, (GLfloat) (height - r.bottom) },
-                { (GLfloat) r.right, (GLfloat) (height - r.top) }
-        };
-        glVertexPointer(2, GL_FLOAT, 0, vertices);
-        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-    }
+    RenderEngine& engine(getRenderEngine());
+    engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
 }
 
 void SurfaceFlinger::addClientLayer(const sp<Client>& client,
@@ -1673,8 +1637,7 @@
     mGraphicBufferProducerList.add(gbc->asBinder());
 }
 
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer)
-{
+status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
     Mutex::Autolock _l(mStateLock);
     ssize_t index = mCurrentState.layersSortedByZ.remove(layer);
     if (index >= 0) {
@@ -1686,18 +1649,15 @@
     return status_t(index);
 }
 
-uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags)
-{
+uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags) {
     return android_atomic_release_load(&mTransactionFlags);
 }
 
-uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
-{
+uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
     return android_atomic_and(~flags, &mTransactionFlags) & flags;
 }
 
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags)
-{
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
     uint32_t old = android_atomic_or(flags, &mTransactionFlags);
     if ((old & flags)==0) { // wake the server up
         signalTransaction();
@@ -2739,31 +2699,22 @@
         bool yswap)
 {
     ATRACE_CALL();
+    RenderEngine& engine(getRenderEngine());
 
     // get screen geometry
     const uint32_t hw_w = hw->getWidth();
     const uint32_t hw_h = hw->getHeight();
-
     const bool filtering = reqWidth != hw_w || reqWidth != hw_h;
 
     // make sure to clear all GL error flags
-    while ( glGetError() != GL_NO_ERROR ) ;
+    engine.checkErrors();
 
     // set-up our viewport
-    glViewport(0, 0, reqWidth, reqHeight);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    if (yswap)  glOrthof(0, hw_w, hw_h, 0, 0, 1);
-    else        glOrthof(0, hw_w, 0, hw_h, 0, 1);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
+    engine.setViewportAndProjection(reqWidth, reqHeight, hw_w, hw_h, yswap);
+    engine.disableTexturing();
 
     // redraw the screen entirely...
-    glDisable(GL_SCISSOR_TEST);
-    glClearColor(0,0,0,1);
-    glClear(GL_COLOR_BUFFER_BIT);
-    glDisable(GL_TEXTURE_EXTERNAL_OES);
-    glDisable(GL_TEXTURE_2D);
+    engine.clearWithColor(0, 0, 0, 1);
 
     const LayerVector& layers( mDrawingState.layersSortedByZ );
     const size_t count = layers.size();
@@ -2834,20 +2785,10 @@
                 EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
                         EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
                 if (image != EGL_NO_IMAGE_KHR) {
-                    GLuint tname, name;
-
-                    // turn our EGLImage into a texture
-                    glGenTextures(1, &tname);
-                    glBindTexture(GL_TEXTURE_2D, tname);
-                    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
-                    // create a Framebuffer Object to render into
-                    glGenFramebuffersOES(1, &name);
-                    glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
-                    glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
-                            GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
-
-                    GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
-                    if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
+                    // this binds the given EGLImage as a framebuffer for the
+                    // duration of this scope.
+                    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
+                    if (imageBond.getStatus() == NO_ERROR) {
                         // this will in fact render into our dequeued buffer
                         // via an FBO, which means we didn't have to create
                         // an EGLSurface and therefore we're not
@@ -2858,12 +2799,6 @@
                         ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
                         result = INVALID_OPERATION;
                     }
-
-                    // back to main framebuffer
-                    glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
-                    glDeleteFramebuffersOES(1, &name);
-                    glDeleteTextures(1, &tname);
-
                     // destroy our image
                     eglDestroyImageKHR(mEGLDisplay, image);
                 } else {
@@ -2955,3 +2890,12 @@
 // ---------------------------------------------------------------------------
 
 }; // namespace android
+
+
+#if defined(__gl_h_)
+#error "don't include gl/gl.h in this file"
+#endif
+
+#if defined(__gl2_h_)
+#error "don't include gl2/gl2.h in this file"
+#endif
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 92fcc25..ce096d3 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -21,7 +21,10 @@
 #include <sys/types.h>
 
 #include <EGL/egl.h>
-#include <GLES/gl.h>        // needed for GLuint
+
+/*
+ * NOTE: Make sure this file doesn't include  anything from <gl/ > or <gl2/ >
+ */
 
 #include <cutils/compiler.h>
 
@@ -91,12 +94,10 @@
     };
 
     // post an asynchronous message to the main thread
-    status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0,
-        uint32_t flags = 0);
+    status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
 
     // post a synchronous message to the main thread
-    status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0,
-        uint32_t flags = 0);
+    status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
 
     // force full composition on all displays
     void repaintEverything();
@@ -107,7 +108,7 @@
     }
 
     // utility function to delete a texture on the main thread
-    void deleteTextureAsync(GLuint texture);
+    void deleteTextureAsync(uint32_t texture);
 
     // enable/disable h/w composer event
     // TODO: this should be made accessible only to EventThread
@@ -254,8 +255,7 @@
     uint32_t peekTransactionFlags(uint32_t flags);
     uint32_t setTransactionFlags(uint32_t flags);
     void commitTransaction();
-    uint32_t setClientStateLocked(const sp<Client>& client,
-        const layer_state_t& s);
+    uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s);
     uint32_t setDisplayStateLocked(const DisplayState& s);
 
     /* ------------------------------------------------------------------------
@@ -365,14 +365,11 @@
     void setUpHWComposer();
     void doComposition();
     void doDebugFlashRegions();
-    void doDisplayComposition(const sp<const DisplayDevice>& hw,
-            const Region& dirtyRegion);
-    void doComposeSurfaces(const sp<const DisplayDevice>& hw,
-            const Region& dirty);
+    void doDisplayComposition(const sp<const DisplayDevice>& hw, const Region& dirtyRegion);
+    void doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty);
 
     void postFramebuffer();
-    void drawWormhole(const sp<const DisplayDevice>& hw,
-            const Region& region) const;
+    void drawWormhole(const sp<const DisplayDevice>& hw, const Region& region) const;
 
     /* ------------------------------------------------------------------------
      * Display management
@@ -382,14 +379,10 @@
     /* ------------------------------------------------------------------------
      * Debugging & dumpsys
      */
-    void listLayersLocked(const Vector<String16>& args, size_t& index,
-        String8& result) const;
-    void dumpStatsLocked(const Vector<String16>& args, size_t& index,
-        String8& result) const;
-    void clearStatsLocked(const Vector<String16>& args, size_t& index,
-        String8& result);
-    void dumpAllLocked(const Vector<String16>& args, size_t& index,
-        String8& result) const;
+    void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
+    void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
+    void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
+    void dumpAllLocked(const Vector<String16>& args, size_t& index, String8& result) const;
     bool startDdmConnection();
     static void appendSfConfigString(String8& result);
     void checkScreenshot(const sp<GraphicBuffer>& buf, void const* vaddr,
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index e95e057..552372b 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -53,8 +53,6 @@
     err = acquireBufferLocked(&item, computeExpectedPresent());
     if (err != NO_ERROR) {
         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-            // This variant of updateTexImage does not guarantee that the
-            // texture is bound, so no need to call glBindTexture.
             err = NO_ERROR;
         } else if (err == BufferQueue::PRESENT_LATER) {
             // return the error, without logging
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index aa2b37f..c7fc164 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -27,10 +27,8 @@
  */
 class SurfaceFlingerConsumer : public GLConsumer {
 public:
-    SurfaceFlingerConsumer(const sp<BufferQueue>& bq, GLuint tex,
-            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES,
-            bool useFenceSync = true)
-        : GLConsumer(bq, tex, texTarget, useFenceSync)
+    SurfaceFlingerConsumer(const sp<BufferQueue>& bq, uint32_t tex)
+        : GLConsumer(bq, tex, GLConsumer::TEXTURE_EXTERNAL, false)
     {}
 
     class BufferRejecter {