am 845ed8fd: Merge "DisplayDevice: initialize mDisplayToken correctly"

* commit '845ed8fdaa34d0f684c93bf4dbadb9162f769235':
  DisplayDevice: initialize mDisplayToken correctly
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index dffa788..479cd3e 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -84,6 +84,7 @@
     static KeyedVector<buffer_handle_t, alloc_rec_t> sAllocList;
     
     friend class Singleton<GraphicBufferAllocator>;
+    friend class BufferLiberatorThread;
     GraphicBufferAllocator();
     ~GraphicBufferAllocator();
     
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 590946a..086e298 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -314,9 +314,8 @@
                      * the consumer may still have pending reads of the
                      * buffers in flight.
                      */
-                    bool isOlder = mSlots[i].mFrameNumber <
-                            mSlots[found].mFrameNumber;
-                    if (found < 0 || isOlder) {
+                    if ((found < 0) ||
+                            mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
                         found = i;
                     }
                 }
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index ff550d9..fb43410 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -90,6 +90,105 @@
     ALOGD("%s", s.string());
 }
 
+class BufferLiberatorThread : public Thread {
+public:
+
+    static void queueCaptiveBuffer(buffer_handle_t handle) {
+        size_t queueSize;
+        {
+            Mutex::Autolock lock(sMutex);
+            if (sThread == NULL) {
+                sThread = new BufferLiberatorThread;
+                sThread->run("BufferLiberator");
+            }
+
+            sThread->mQueue.push_back(handle);
+            sThread->mQueuedCondition.signal();
+            queueSize = sThread->mQueue.size();
+        }
+    }
+
+    static void waitForLiberation() {
+        Mutex::Autolock lock(sMutex);
+
+        waitForLiberationLocked();
+    }
+
+    static void maybeWaitForLiberation() {
+        Mutex::Autolock lock(sMutex);
+        if (sThread != NULL) {
+            if (sThread->mQueue.size() > 8) {
+                waitForLiberationLocked();
+            }
+        }
+    }
+
+private:
+
+    BufferLiberatorThread() {}
+
+    virtual bool threadLoop() {
+        buffer_handle_t handle;
+        { // Scope for mutex
+            Mutex::Autolock lock(sMutex);
+            while (mQueue.isEmpty()) {
+                mQueuedCondition.wait(sMutex);
+            }
+            handle = mQueue[0];
+        }
+
+        status_t err;
+        GraphicBufferAllocator& gba(GraphicBufferAllocator::get());
+        { // Scope for tracing
+            ATRACE_NAME("gralloc::free");
+            err = gba.mAllocDev->free(gba.mAllocDev, handle);
+        }
+        ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
+
+        if (err == NO_ERROR) {
+            Mutex::Autolock _l(GraphicBufferAllocator::sLock);
+            KeyedVector<buffer_handle_t, GraphicBufferAllocator::alloc_rec_t>&
+                    list(GraphicBufferAllocator::sAllocList);
+            list.removeItem(handle);
+        }
+
+        { // Scope for mutex
+            Mutex::Autolock lock(sMutex);
+            mQueue.removeAt(0);
+            mFreedCondition.broadcast();
+        }
+
+        return true;
+    }
+
+    static void waitForLiberationLocked() {
+        if (sThread == NULL) {
+            return;
+        }
+
+        const nsecs_t timeout = 500 * 1000 * 1000;
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        nsecs_t timeToStop = now + timeout;
+        while (!sThread->mQueue.isEmpty() && now < timeToStop) {
+            sThread->mFreedCondition.waitRelative(sMutex, timeToStop - now);
+            now = systemTime(SYSTEM_TIME_MONOTONIC);
+        }
+
+        if (!sThread->mQueue.isEmpty()) {
+            ALOGW("waitForLiberationLocked timed out");
+        }
+    }
+
+    static Mutex sMutex;
+    static sp<BufferLiberatorThread> sThread;
+    Vector<buffer_handle_t> mQueue;
+    Condition mQueuedCondition;
+    Condition mFreedCondition;
+};
+
+Mutex BufferLiberatorThread::sMutex;
+sp<BufferLiberatorThread> BufferLiberatorThread::sThread;
+
 status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
         int usage, buffer_handle_t* handle, int32_t* stride)
 {
@@ -100,13 +199,24 @@
         w = h = 1;
 
     // we have a h/w allocator and h/w buffer is requested
-    status_t err; 
-    
+    status_t err;
+
+    // If too many async frees are queued up then wait for some of them to
+    // complete before attempting to allocate more memory.  This is exercised
+    // by the android.opengl.cts.GLSurfaceViewTest CTS test.
+    BufferLiberatorThread::maybeWaitForLiberation();
+
     err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
 
+    if (err != NO_ERROR) {
+        ALOGW("WOW! gralloc alloc failed, waiting for pending frees!");
+        BufferLiberatorThread::waitForLiberation();
+        err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
+    }
+
     ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
             w, h, format, usage, err, strerror(-err));
-    
+
     if (err == NO_ERROR) {
         Mutex::Autolock _l(sLock);
         KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
@@ -129,21 +239,11 @@
     return err;
 }
 
+
 status_t GraphicBufferAllocator::free(buffer_handle_t handle)
 {
-    ATRACE_CALL();
-    status_t err;
-
-    err = mAllocDev->free(mAllocDev, handle);
-
-    ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
-    if (err == NO_ERROR) {
-        Mutex::Autolock _l(sLock);
-        KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
-        list.removeItem(handle);
-    }
-
-    return err;
+    BufferLiberatorThread::queueCaptiveBuffer(handle);
+    return NO_ERROR;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 96e1cba..0d4bed5 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -124,6 +124,12 @@
 void initEglDebugLevel() {
     int propertyLevel = 0;
     char value[PROPERTY_VALUE_MAX];
+
+    // check system property only on userdebug or eng builds
+    property_get("ro.debuggable", value, "0");
+    if (value[0] == '0')
+        return;
+
     property_get("debug.egl.debug_proc", value, "");
     if (strlen(value) > 0) {
         long pid = getpid();
diff --git a/opengl/specs/EGL_ANDROID_native_fence_sync.txt b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
index 8273be4..ee05b40 100644
--- a/opengl/specs/EGL_ANDROID_native_fence_sync.txt
+++ b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
@@ -100,10 +100,10 @@
       EGL_SYNC_TYPE_KHR                  EGL_SYNC_NATIVE_FENCE_ANDROID
       EGL_SYNC_STATUS_KHR                EGL_UNSIGNALED_KHR
       EGL_SYNC_CONDITION_KHR             EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR
-      EGL_SYNC_NATIVE_FENCE_FD_ANDROID   EGL_NO_NATIVE_FENCE_ANDROID
+      EGL_SYNC_NATIVE_FENCE_FD_ANDROID   EGL_NO_NATIVE_FENCE_FD_ANDROID
 
     If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute is not
-    EGL_NO_NATIVE_FENCE_ANDROID then the EGL_SYNC_CONDITION_KHR attribute is
+    EGL_NO_NATIVE_FENCE_FD_ANDROID then the EGL_SYNC_CONDITION_KHR attribute is
     set to EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID and the EGL_SYNC_STATUS_KHR
     attribute is set to reflect the signal status of the native fence object.
     Additionally, the EGL implementation assumes ownership of the file
@@ -114,7 +114,7 @@
 
     "When a fence sync object is created or when an EGL native fence sync
     object is created with the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute set
-    to EGL_NO_NATIVE_FENCE_ANDROID, eglCreateSyncKHR also inserts a fence
+    to EGL_NO_NATIVE_FENCE_FD_ANDROID, eglCreateSyncKHR also inserts a fence
     command into the command stream of the bound client API's current context
     (i.e., the context returned by eglGetCurrentContext), and associates it
     with the newly created sync object.
@@ -157,8 +157,9 @@
         empty (containing only EGL_NONE), EGL_NO_SYNC_KHR is returned and an
         EGL_BAD_ATTRIBUTE error is generated.
       * If <type> is EGL_SYNC_NATIVE_FENCE_ANDROID and <attrib_list> contains
-        an attribute other than EGL_SYNC_NATIVE_FENCE_FD_ANDROID, EGL_NO_SYNC_KHR is
-        returned and an EGL_BAD_ATTRIBUTE error is generated.
+        an attribute other than EGL_SYNC_NATIVE_FENCE_FD_ANDROID,
+        EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is
+        generated.
       * If <type> is not a supported type of sync object,
         EGL_NO_SYNC_KHR is returned and an EGL_BAD_ATTRIBUTE error is
         generated.
@@ -193,8 +194,8 @@
     "If no errors are generated, EGL_TRUE is returned, and <sync> will no
     longer be the handle of a valid sync object.  Additionally, if <sync> is an
     EGL native fence sync object and the EGL_SYNC_NATIVE_FENCE_FD_ANDROID
-    attribute is not EGL_NO_NATIVE_FENCE_ANDROID then that file descriptor is
-    closed."
+    attribute is not EGL_NO_NATIVE_FENCE_FD_ANDROID then that file descriptor
+    is closed."
 
     Add the following after the last paragraph of Section 3.8.1 (Sync
     Objects), added by KHR_fence_sync
@@ -213,11 +214,11 @@
     ------
 
       * If <sync> is not a valid sync object for <dpy>,
-        EGL_NO_NATIVE_FENCE_ANDROID is returned and an EGL_BAD_PARAMETER
+        EGL_NO_NATIVE_FENCE_FD_ANDROID is returned and an EGL_BAD_PARAMETER
         error is generated.
       * If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of <sync> is
-        EGL_NO_NATIVE_FENCE_ANDROID, EGL_NO_NATIVE_FENCE_ANDROID is returned
-        and an EGL_BAD_PARAMETER error is generated.
+        EGL_NO_NATIVE_FENCE_FD_ANDROID, EGL_NO_NATIVE_FENCE_FD_ANDROID is
+        returned and an EGL_BAD_PARAMETER error is generated.
       * If <dpy> does not match the display passed to eglCreateSyncKHR
         when <sync> was created, the behaviour is undefined."
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 8d92bd3..068fdcd 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -793,7 +793,9 @@
     virtual void setAcquireFenceFd(int fenceFd) {
         getLayer()->acquireFenceFd = fenceFd;
     }
-
+    virtual void setPerFrameDefaultState() {
+        //getLayer()->compositionType = HWC_FRAMEBUFFER;
+    }
     virtual void setDefaultState() {
         getLayer()->compositionType = HWC_FRAMEBUFFER;
         getLayer()->hints = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index a78ffac..7c67407 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -141,6 +141,7 @@
         virtual int32_t getCompositionType() const = 0;
         virtual uint32_t getHints() const = 0;
         virtual int getAndResetReleaseFenceFd() = 0;
+        virtual void setPerFrameDefaultState() = 0;
         virtual void setDefaultState() = 0;
         virtual void setSkip(bool skip) = 0;
         virtual void setBlending(uint32_t blending) = 0;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 064f689..7edbdc5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -110,7 +110,8 @@
     mSurfaceTexture->setDefaultMaxBufferCount(3);
 #endif
 
-    updateTransformHint();
+    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
+    updateTransformHint(hw);
 }
 
 Layer::~Layer()
@@ -767,15 +768,12 @@
     return usage;
 }
 
-void Layer::updateTransformHint() const {
+void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {
     uint32_t orientation = 0;
     if (!mFlinger->mDebugDisableTransformHint) {
-        // The transform hint is used to improve performance on the main
-        // display -- we can only have a single transform hint, it cannot
+        // The transform hint is used to improve performance, but we can
+        // only have a single transform hint, it cannot
         // apply to all displays.
-        // This is why we use the default display here. This is not an
-        // oversight.
-        sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
         const Transform& planeTransform(hw->getTransform());
         orientation = planeTransform.getOrientation();
         if (orientation & Transform::ROT_INVALID) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6f75d8c..c5eb26b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -91,8 +91,8 @@
     inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
 
     // Updates the transform hint in our SurfaceTexture to match
-    // the current orientation of the default display device.
-    virtual void updateTransformHint() const;
+    // the current orientation of the display device.
+    virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
 
 protected:
     virtual void onFirstRef();
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index db4ef87..9b03c74 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -300,6 +300,7 @@
 
 void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw,
         HWComposer::HWCLayerInterface& layer) {
+    layer.setPerFrameDefaultState();
     // we have to set the visible region on every frame because
     // we currently free it during onLayerDisplayed(), which is called
     // after HWComposer::commit() -- every frame.
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 00c4ffe..4d5a5b0 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -246,7 +246,7 @@
      * Updates the SurfaceTexture's transform hint, for layers that have
      * a SurfaceTexture.
      */
-    virtual void updateTransformHint() const { }
+    virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const { }
 
     /** always call base class first */
     virtual void dump(String8& result, char* scratch, size_t size) const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3097965..9afa4c1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1076,7 +1076,7 @@
 
     if (transactionFlags & eTraversalNeeded) {
         for (size_t i=0 ; i<count ; i++) {
-            const sp<LayerBase>& layer = currentLayers[i];
+            const sp<LayerBase>& layer(currentLayers[i]);
             uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
             if (!trFlags) continue;
 
@@ -1149,18 +1149,6 @@
                             disp->setProjection(state.orientation,
                                     state.viewport, state.frame);
                         }
-
-                        // Walk through all the layers in currentLayers,
-                        // and update their transform hint.
-                        //
-                        // TODO: we could be much more clever about which
-                        // layers we touch and how often we do these updates
-                        // (e.g. only touch the layers associated with this
-                        // display, and only on a rotation).
-                        for (size_t i = 0; i < count; i++) {
-                            const sp<LayerBase>& layerBase = currentLayers[i];
-                            layerBase->updateTransformHint();
-                        }
                     }
                 }
             }
@@ -1209,6 +1197,61 @@
         }
     }
 
+    if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
+        // The transform hint might have changed for some layers
+        // (either because a display has changed, or because a layer
+        // as changed).
+        //
+        // Walk through all the layers in currentLayers,
+        // and update their transform hint.
+        //
+        // If a layer is visible only on a single display, then that
+        // display is used to calculate the hint, otherwise we use the
+        // default display.
+        //
+        // NOTE: we do this here, rather than in rebuildLayerStacks() so that
+        // the hint is set before we acquire a buffer from the surface texture.
+        //
+        // NOTE: layer transactions have taken place already, so we use their
+        // drawing state. However, SurfaceFlinger's own transaction has not
+        // happened yet, so we must use the current state layer list
+        // (soon to become the drawing state list).
+        //
+        sp<const DisplayDevice> disp;
+        uint32_t currentlayerStack = 0;
+        for (size_t i=0; i<count; i++) {
+            // NOTE: we rely on the fact that layers are sorted by
+            // layerStack first (so we don't have to traverse the list
+            // of displays for every layer).
+            const sp<LayerBase>& layerBase(currentLayers[i]);
+            uint32_t layerStack = layerBase->drawingState().layerStack;
+            if (i==0 || currentlayerStack != layerStack) {
+                currentlayerStack = layerStack;
+                // figure out if this layerstack is mirrored
+                // (more than one display) if so, pick the default display,
+                // if not, pick the only display it's on.
+                disp.clear();
+                for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+                    sp<const DisplayDevice> hw(mDisplays[dpy]);
+                    if (hw->getLayerStack() == currentlayerStack) {
+                        if (disp == NULL) {
+                            disp = hw;
+                        } else {
+                            disp = getDefaultDisplayDevice();
+                            break;
+                        }
+                    }
+                }
+            }
+            if (disp != NULL) {
+                // presumably this means this layer is using a layerStack
+                // that is not visible on any display
+                layerBase->updateTransformHint(disp);
+            }
+        }
+    }
+
+
     /*
      * Perform our own transaction if needed
      */