Always create OpenGL accelerated windows in RGBA 8888.

Bug #3081600

The OpenGL renderer in libhwui uses a single EGL context per process and
thus create it with an RGBA 8888 EGL configuration. To ensure that all
windows are compatible with this configuration, this change modifies
the window manager and SurfaceFlinger.

The window manager now checks the window's flags and if the window is
hardware accelerated, it forces the window's pixel format to be
translucent when creating the surface. The window itself is still
marked as opaque if we know that the window will be opaque on screen.
This keeps existing optimizations in place.

Similarly in SurfaceFlinger, a translucent Surface can now be created
with the Surface.OPAQUE flag, indicating SurfaceFlinger that the surface
does not require blending, despite its RGBA 8888 configuration.

Change-Id: Ic747b6b12564ba064412d842117880fcc199eb7c
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 69bdef0..0247f6a 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -216,9 +216,11 @@
 
         /**
          * Return a string for the EGL error code, or the hex representation
-         * if an unknown error.
-         * @param error EGL error.
-         * @return Error string.
+         * if the error is unknown.
+         * 
+         * @param error The EGL error to convert into a String.
+         * 
+         * @return An error string correponding to the EGL error code.
          */
         static String getEGLErrorString(int error) {
             switch (error) {
@@ -446,11 +448,9 @@
         }
         
         /**
-         * Defines the EGL configuration for this renderer. The default configuration
-         * is RGBX, no depth, no stencil.
+         * Defines the EGL configuration for this renderer.
          * 
          * @return An {@link android.view.HardwareRenderer.GlRenderer.EglConfigChooser}.
-         * @param glVersion
          */
         EglConfigChooser getConfigChooser(int glVersion) {
             return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0);
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index cd0ae3b..d596a7f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -86,6 +86,15 @@
      * play back.
      */
     public static final int PUSH_BUFFERS        = 0x00000200;
+    /**
+     * Indicates that the surface must be considered opaque, even if its
+     * pixel format is set to translucent. This can be useful if an
+     * application needs full RGBA 8888 support for instance but will
+     * still draw every pixel opaque.
+     * 
+     * @hide
+     */
+    public static final int OPAQUE              = 0x00000400;
     
     /** Creates a normal surface. This is the default */
     public static final int FX_SURFACE_NORMAL   = 0x00000000;
@@ -269,7 +278,7 @@
             }
             mOrigMatrix.set(m);
         }
-    };
+    }
 
     /**
      * Sets the display metrics used to provide canva's width/height in compatibility mode.
@@ -422,16 +431,20 @@
     /* no user serviceable parts here ... */
     @Override
     protected void finalize() throws Throwable {
-        if (mNativeSurface != 0 || mSurfaceControl != 0) {
-            if (DEBUG_RELEASE) {
-                Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() (" 
-                        + mNativeSurface + ", " + mSurfaceControl + ")", mCreationStack);
-            } else {
-                Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() (" 
-                        + mNativeSurface + ", " + mSurfaceControl + ")");
+        try {
+            super.finalize();
+        } finally {
+            if (mNativeSurface != 0 || mSurfaceControl != 0) {
+                if (DEBUG_RELEASE) {
+                    Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() (" 
+                            + mNativeSurface + ", " + mSurfaceControl + ")", mCreationStack);
+                } else {
+                    Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() (" 
+                            + mNativeSurface + ", " + mSurfaceControl + ")");
+                }
             }
+            release();            
         }
-        release();
     }
     
     private native void init(SurfaceSession s,
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 6533600..b181781 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -43,6 +43,7 @@
         eSecure             = 0x00000080,
         eNonPremultiplied   = 0x00000100,
         ePushBuffers        = 0x00000200,
+        eOpaque             = 0x00000400,
 
         eFXSurfaceNormal    = 0x00000000,
         eFXSurfaceBlur      = 0x00010000,
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 8be980f..92c5cc8 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -6832,10 +6832,16 @@
                 mSurfaceW = w;
                 mSurfaceH = h;
                 try {
+                    final boolean isHwAccelerated = (mAttrs.flags &
+                            WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+                    final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : mAttrs.format;
+                    if (isHwAccelerated && mAttrs.format == PixelFormat.OPAQUE) {
+                        flags |= Surface.OPAQUE;
+                    }
                     mSurface = new Surface(
                             mSession.mSurfaceSession, mSession.mPid,
                             mAttrs.getTitle().toString(),
-                            0, w, h, mAttrs.format, flags);
+                            0, w, h, format, flags);
                     if (SHOW_TRANSACTIONS) Slog.i(TAG, "  CREATE SURFACE "
                             + mSurface + " IN SESSION "
                             + mSession.mSurfaceSession
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index fb76720..1b06843 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -171,7 +171,8 @@
     mReqHeight = h;
 
     mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
-    mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+    mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
+            (flags & ISurfaceComposer::eOpaque) == 0;
 
     // we use the red index
     int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);