make transform hint multi-display aware

if a layer is not mirrored, we now use its display
as the source for the transfrom hint calculation
instead of always using the default (main) display.

this change does two thing:
1) we make updateTransformHint take a DisplayDevice
   as a parameter instead of hard-coding the
   main display.

2) each time we do a transaction that could change
   the hint, we go through all layers and
   figure out which display should be used for their
   transform hint.

Bug: 7599344
Change-Id: I9b04a95e6c372dd770bacf81d8ef6f8e31b87b83
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.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 ce10c78..842471f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1069,7 +1069,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;
 
@@ -1142,18 +1142,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();
-                        }
                     }
                 }
             }
@@ -1208,6 +1196,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
      */