color blindness enhancement

This is an attempt at improving the experience of
users with color vision impairement.

At this time this feature can only be enabled for
debugging:

  adb shell service call SurfaceFlinger 1014 i32 PARAM

  with PARAM:
   0 : disabled
   1 : protanomaly/protanopia simulation
   2 : deuteranomaly/deuteranopia simulation
   3 : tritanopia/tritanomaly simulation
  11, 12, 13: same as above w/ attempted correction/enhancement

The enhancement algorithm tries to spread the "error"
such that tones that would otherwise appear similar can be
distinguished.

Bug: 9465644

Change-Id: I860f7eed0cb81f54ef9cf24ad78155b6395ade48
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 9754758..7112ca8 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -35,7 +35,8 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-GLES20RenderEngine::GLES20RenderEngine() {
+GLES20RenderEngine::GLES20RenderEngine() :
+        mVpWidth(0), mVpHeight(0) {
 
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
@@ -58,6 +59,8 @@
     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);
+
+    //mColorBlindnessCorrection = M;
 }
 
 GLES20RenderEngine::~GLES20RenderEngine() {
@@ -82,6 +85,8 @@
 
     glViewport(0, 0, vpw, vph);
     mState.setProjectionMatrix(m);
+    mVpWidth = vpw;
+    mVpHeight = vph;
 }
 
 void GLES20RenderEngine::setupLayerBlending(
@@ -156,8 +161,7 @@
     // 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);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
 
     *status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
     *texName = tname;
@@ -205,6 +209,78 @@
     }
 }
 
+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);
 }