[3171580] SurfaceFlinger Bypass mode. (DO NOT MERGE)

This is a poor's man precursor to the h/w composer HAL.
Basically we detect when a window is full screen and in
that case we bypass surfaceflinger's composition step, which
yields to much improved performance.

Change-Id: Ie03796ae81a1c951949b771c9323044b980cb347
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index e2f8a74..41562f6 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -25,6 +25,7 @@
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
 	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
+	LOCAL_CFLAGS += -DUSE_COMPOSITION_BYPASS
 endif
 
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 28a512e..818774d 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -339,6 +339,12 @@
     //glClear(GL_COLOR_BUFFER_BIT);
 }
 
+status_t DisplayHardware::postBypassBuffer(const native_handle_t* handle) const
+{
+   framebuffer_device_t *fbDev = (framebuffer_device_t *)mNativeWindow->getDevice();
+   return fbDev->post(fbDev, handle);
+}
+
 uint32_t DisplayHardware::getFlags() const
 {
     return mFlags;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 2d7900c..79ef2a7 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -64,6 +64,7 @@
     // Flip the front and back buffers if the back buffer is "dirty".  Might
     // be instantaneous, might involve copying the frame buffer around.
     void flip(const Region& dirty) const;
+    status_t postBypassBuffer(const native_handle_t* handle) const;
 
     float       getDpiX() const;
     float       getDpiY() const;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 81cb15d..a18f473 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -57,7 +57,8 @@
         mSecure(false),
         mTextureManager(),
         mBufferManager(mTextureManager),
-        mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
+        mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false),
+        mBypassState(false)
 {
 }
 
@@ -251,6 +252,29 @@
         }
         return;
     }
+
+#ifdef USE_COMPOSITION_BYPASS
+    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
+    if ((buffer != NULL) && (buffer->transform)) {
+        // Here we have a "bypass" buffer, but we need to composite it
+        // most likely because it's not fullscreen anymore.
+        // Since the buffer may have a transformation applied by the client
+        // we need to inverse this transformation here.
+
+        // calculate the inverse of the buffer transform
+        const uint32_t mask = HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
+        const uint32_t bufferTransformInverse = buffer->transform ^ mask;
+
+        // To accomplish the inverse transform, we use "mBufferTransform"
+        // which is not used by Layer.cpp
+        const_cast<Layer*>(this)->mBufferTransform = bufferTransformInverse;
+        drawWithOpenGL(clip, tex);
+        // reset to "no transfrom"
+        const_cast<Layer*>(this)->mBufferTransform = 0;
+        return;
+    }
+#endif
+
     drawWithOpenGL(clip, tex);
 }
 
@@ -311,11 +335,12 @@
      * buffer 'index' as our front buffer.
      */
 
-    status_t err = NO_ERROR;
-    uint32_t w, h, f;
+    uint32_t w, h, f, bypass;
     { // scope for the lock
         Mutex::Autolock _l(mLock);
 
+        bypass = mBypassState;
+
         // zero means default
         mFixedSize = reqWidth && reqHeight;
         if (!reqFormat) reqFormat = mFormat;
@@ -340,9 +365,40 @@
     // here we have to reallocate a new buffer because the buffer could be
     // used as the front buffer, or by a client in our process
     // (eg: status bar), and we can't release the handle under its feet.
-    const uint32_t effectiveUsage = getEffectiveUsage(usage);
-    buffer = new GraphicBuffer(w, h, f, effectiveUsage);
-    err = buffer->initCheck();
+    uint32_t effectiveUsage = getEffectiveUsage(usage);
+
+    status_t err = NO_MEMORY;
+
+#ifdef USE_COMPOSITION_BYPASS
+    if (!mSecure && bypass && (effectiveUsage & GRALLOC_USAGE_HW_RENDER)) {
+        // always allocate a buffer matching the screen size. the size
+        // may be different from (w,h) if the buffer is rotated.
+        const DisplayHardware& hw(graphicPlane(0).displayHardware());
+        int32_t w = hw.getWidth();
+        int32_t h = hw.getHeight();
+        int32_t f = hw.getFormat();
+
+        buffer = new GraphicBuffer(w, h, f, effectiveUsage | GRALLOC_USAGE_HW_FB);
+        err = buffer->initCheck();
+        buffer->transform = uint8_t(getOrientation());
+
+        if (err != NO_ERROR) {
+            // allocation didn't succeed, probably because an older bypass
+            // window hasn't released all its resources yet.
+            ClientRef::Access sharedClient(mUserClientRef);
+            SharedBufferServer* lcblk(sharedClient.get());
+            if (lcblk) {
+                // all buffers need reallocation
+                lcblk->reallocateAll();
+            }
+        }
+    }
+#endif
+
+    if (err != NO_ERROR) {
+        buffer = new GraphicBuffer(w, h, f, effectiveUsage);
+        err = buffer->initCheck();
+    }
 
     if (err || buffer->handle == 0) {
         GraphicBuffer::dumpAllocationsToSystemLog();
@@ -389,6 +445,27 @@
     return usage;
 }
 
+bool Layer::setBypass(bool enable)
+{
+    Mutex::Autolock _l(mLock);
+
+    if (mNeedsScaling || mNeedsFiltering) {
+        return false;
+    }
+
+    if (mBypassState != enable) {
+        mBypassState = enable;
+        ClientRef::Access sharedClient(mUserClientRef);
+        SharedBufferServer* lcblk(sharedClient.get());
+        if (lcblk) {
+            // all buffers need reallocation
+            lcblk->reallocateAll();
+        }
+    }
+
+    return true;
+}
+
 uint32_t Layer::doTransaction(uint32_t flags)
 {
     const Layer::State& front(drawingState());
@@ -639,9 +716,9 @@
     snprintf(buffer, SIZE,
             "      "
             "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
-            " freezeLock=%p, dq-q-time=%u us\n",
+            " freezeLock=%p, bypass=%d, dq-q-time=%u us\n",
             mFormat, w0, h0, s0, w1, h1, s1,
-            getFreezeLock().get(), totalTime);
+            getFreezeLock().get(), mBypassState, totalTime);
 
     result.append(buffer);
 }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index a93fcb1..9ff5716 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -81,6 +81,10 @@
     virtual sp<Surface> createSurface() const;
     virtual status_t ditch();
     virtual void onRemoved();
+    virtual bool setBypass(bool enable);
+
+    inline sp<GraphicBuffer> getBypassBuffer() const {
+        return mBufferManager.getActiveBuffer(); }
 
     // only for debugging
     inline sp<GraphicBuffer> getBuffer(int i) const {
@@ -232,6 +236,7 @@
     uint32_t mReqFormat;
     bool mNeedsScaling;
     bool mFixedSize;
+    bool mBypassState;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 633df96..3ec8ac3 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -35,6 +35,7 @@
 
 #include <pixelflinger/pixelflinger.h>
 
+#include "DisplayHardware/DisplayHardware.h"
 #include "Transform.h"
 
 namespace android {
@@ -118,6 +119,11 @@
     virtual void drawForSreenShot() const;
     
     /**
+     * bypass mode
+     */
+    virtual bool setBypass(bool enable) { return false; }
+
+    /**
      * onDraw - draws the surface.
      */
     virtual void onDraw(const Region& clip) const = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a9b3965..5e9e06c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -61,6 +61,10 @@
 #define AID_GRAPHICS 1003
 #endif
 
+#ifdef USE_COMPOSITION_BYPASS
+#warning "using COMPOSITION_BYPASS"
+#endif
+
 #define DISPLAY_COUNT       1
 
 namespace android {
@@ -373,8 +377,15 @@
 
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     if (LIKELY(hw.canDraw() && !isFrozen())) {
-        // repaint the framebuffer (if needed)
 
+#ifdef USE_COMPOSITION_BYPASS
+        if (handleBypassLayer()) {
+            unlockClients();
+            return true;
+        }
+#endif
+
+        // repaint the framebuffer (if needed)
         const int index = hw.getCurrentBufferIndex();
         GraphicLog& logger(GraphicLog::getInstance());
 
@@ -401,6 +412,20 @@
     return true;
 }
 
+bool SurfaceFlinger::handleBypassLayer()
+{
+    sp<Layer> bypassLayer(mBypassLayer.promote());
+    if (bypassLayer != 0) {
+        sp<GraphicBuffer> buffer(bypassLayer->getBypassBuffer());
+        if (buffer!=0 && (buffer->usage & GRALLOC_USAGE_HW_FB)) {
+            const DisplayHardware& hw(graphicPlane(0).displayHardware());
+            hw.postBypassBuffer(buffer->handle);
+            return true;
+        }
+    }
+    return false;
+}
+
 void SurfaceFlinger::postFramebuffer()
 {
     if (!mInvalidRegion.isEmpty()) {
@@ -696,6 +721,28 @@
     mTransactionCV.broadcast();
 }
 
+void SurfaceFlinger::setBypassLayer(const sp<LayerBase>& layer)
+{
+    // if this layer is already the bypass layer, do nothing
+    sp<Layer> cur(mBypassLayer.promote());
+    if (mBypassLayer == layer)
+        return;
+
+    // clear the current bypass layer
+    mBypassLayer.clear();
+    if (cur != 0) {
+        cur->setBypass(false);
+        cur.clear();
+    }
+
+    // set new bypass layer
+    if (layer != 0) {
+        if (layer->setBypass(true)) {
+            mBypassLayer = static_cast<Layer*>(layer.get());
+        }
+    }
+}
+
 void SurfaceFlinger::handlePageFlip()
 {
     bool visibleRegions = mVisibleRegionsDirty;
@@ -721,6 +768,21 @@
                     mVisibleLayersSortedByZ.add(currentLayers[i]);
             }
 
+#ifdef USE_COMPOSITION_BYPASS
+            sp<LayerBase> bypassLayer;
+            const size_t numVisibleLayers = mVisibleLayersSortedByZ.size();
+            if (numVisibleLayers == 1) {
+                const sp<LayerBase>& candidate(mVisibleLayersSortedByZ[0]);
+                const Region& visibleRegion(candidate->visibleRegionScreen);
+                const Region reminder(screenRegion.subtract(visibleRegion));
+                if (reminder.isEmpty()) {
+                    // fullscreen candidate!
+                    bypassLayer = candidate;
+                }
+            }
+            setBypassLayer(bypassLayer);
+#endif
+
             mWormholeRegion = screenRegion.subtract(opaqueRegion);
             mVisibleRegionsDirty = false;
         }
@@ -1416,9 +1478,9 @@
         mWormholeRegion.dump(result, "WormholeRegion");
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
         snprintf(buffer, SIZE,
-                "  display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
+                "  display frozen: %s, freezeCount=%d, orientation=%d, bypass=%p, canDraw=%d\n",
                 mFreezeDisplay?"yes":"no", mFreezeCount,
-                mCurrentState.orientation, hw.canDraw());
+                mCurrentState.orientation, mBypassLayer.unsafe_get(), hw.canDraw());
         result.append(buffer);
         snprintf(buffer, SIZE,
                 "  last eglSwapBuffers() time: %f us\n"
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4262175..ca57292 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -307,6 +307,7 @@
             bool        lockPageFlip(const LayerVector& currentLayers);
             void        unlockPageFlip(const LayerVector& currentLayers);
             void        handleRepaint();
+            bool        handleBypassLayer();
             void        postFramebuffer();
             void        composeSurfaces(const Region& dirty);
             void        unlockClients();
@@ -322,6 +323,7 @@
             uint32_t    setTransactionFlags(uint32_t flags);
             void        commitTransaction();
 
+            void        setBypassLayer(const sp<LayerBase>& layer);
 
             status_t captureScreenImplLocked(DisplayID dpy,
                     sp<IMemoryHeap>* heap,
@@ -399,6 +401,7 @@
                 int32_t                     mFreezeCount;
                 nsecs_t                     mFreezeDisplayTime;
                 Vector< sp<LayerBase> >     mVisibleLayersSortedByZ;
+                wp<Layer>                   mBypassLayer;
 
 
                 // don't use a lock for these, we don't care