implement: "Add an ANativeWindow API for SurfaceFlinger to suggest an optimal buffer orientation"

Bug: 4487161
Change-Id: I883f34efe542c2a566d04966f873374f40c50092
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 37a9b4a..e764425 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -78,7 +78,12 @@
     // client for this buffer. The timestamp is measured in nanoseconds, and
     // must be monotonically increasing. Its other properties (zero point, etc)
     // are client-dependent, and should be documented by the client.
-    virtual status_t queueBuffer(int slot, int64_t timestamp) = 0;
+    //
+    // outWidth, outHeight and outTransform are filed with the default width
+    // default height of the window and current transform applied to buffers,
+    // respectively.
+    virtual status_t queueBuffer(int slot, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) = 0;
 
     // cancelBuffer indicates that the client does not wish to fill in the
     // buffer associated with slot and transfers ownership of the slot back to
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index e46765e..945f4bc 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -84,7 +84,8 @@
     // nanoseconds, and must be monotonically increasing. Its other semantics
     // (zero point, etc) are client-dependent and should be documented by the
     // client.
-    virtual status_t queueBuffer(int buf, int64_t timestamp);
+    virtual status_t queueBuffer(int buf, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
     virtual void cancelBuffer(int buf);
     virtual status_t setCrop(const Rect& reg);
     virtual status_t setTransform(uint32_t transform);
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 76e7119..829d8ab 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -151,6 +151,18 @@
     // dequeued format or to mReqFormat if no buffer was dequeued.
     uint32_t mQueryFormat;
 
+    // mDefaultWidth is default width of the window, regardless of the
+    // set_dimension call
+    uint32_t mDefaultWidth;
+
+    // mDefaultHeight is default width of the window, regardless of the
+    // set_dimension call
+    uint32_t mDefaultHeight;
+
+    // mTransformHint is the transform probably applied to buffers of this
+    // window. this is only a hint, actual transform may differ.
+    uint32_t mTransformHint;
+
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index b4b7492..be90e2e 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -93,12 +93,16 @@
         return result;
     }
 
-    virtual status_t queueBuffer(int buf, int64_t timestamp) {
+    virtual status_t queueBuffer(int buf, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(buf);
         data.writeInt64(timestamp);
         remote()->transact(QUEUE_BUFFER, data, &reply);
+        *outWidth = reply.readInt32();
+        *outHeight = reply.readInt32();
+        *outTransform = reply.readInt32();
         status_t result = reply.readInt32();
         return result;
     }
@@ -226,7 +230,12 @@
             CHECK_INTERFACE(ISurfaceTexture, data, reply);
             int buf = data.readInt32();
             int64_t timestamp = data.readInt64();
-            status_t result = queueBuffer(buf, timestamp);
+            uint32_t outWidth, outHeight, outTransform;
+            status_t result = queueBuffer(buf, timestamp,
+                    &outWidth, &outHeight, &outTransform);
+            reply->writeInt32(outWidth);
+            reply->writeInt32(outHeight);
+            reply->writeInt32(outTransform);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 3ab6c79..0f08570 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -402,7 +402,8 @@
     return err;
 }
 
-status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) {
+status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
     LOGV("SurfaceTexture::queueBuffer");
 
     sp<FrameAvailableListener> listener;
@@ -463,6 +464,11 @@
     if (listener != 0) {
         listener->onFrameAvailable();
     }
+
+    *outWidth = mDefaultWidth;
+    *outHeight = mDefaultHeight;
+    *outTransform = 0;
+
     return OK;
 }
 
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 68475e9..1dc6cd2 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -222,26 +222,38 @@
     if (i < 0) {
         return i;
     }
-    mSurfaceTexture->queueBuffer(i, timestamp);
+    mSurfaceTexture->queueBuffer(i, timestamp,
+            &mDefaultWidth, &mDefaultHeight, &mTransformHint);
     return OK;
 }
 
 int SurfaceTextureClient::query(int what, int* value) const {
     LOGV("SurfaceTextureClient::query");
-    switch (what) {
-    case NATIVE_WINDOW_FORMAT:
-        if (mReqFormat) {
-            *value = mReqFormat;
-            return NO_ERROR;
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        switch (what) {
+            case NATIVE_WINDOW_FORMAT:
+                if (mReqFormat) {
+                    *value = mReqFormat;
+                    return NO_ERROR;
+                }
+                break;
+            case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+                *value = 0;
+                return NO_ERROR;
+            case NATIVE_WINDOW_CONCRETE_TYPE:
+                *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_WIDTH:
+                *value = mDefaultWidth;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_HEIGHT:
+                *value = mDefaultHeight;
+                return NO_ERROR;
+            case NATIVE_WINDOW_TRANSFORM_HINT:
+                *value = mTransformHint;
+                return NO_ERROR;
         }
-        break;
-    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
-        // TODO: this is not needed anymore
-        *value = 0;
-        return NO_ERROR;
-    case NATIVE_WINDOW_CONCRETE_TYPE:
-        *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
-        return NO_ERROR;
     }
     return mSurfaceTexture->query(what, value);
 }
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index e2772a7..412552e 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -289,6 +289,18 @@
         case NATIVE_WINDOW_CONCRETE_TYPE:
             *value = NATIVE_WINDOW_FRAMEBUFFER;
             return NO_ERROR;
+        case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+            *value = 0;
+            return NO_ERROR;
+        case NATIVE_WINDOW_DEFAULT_WIDTH:
+            *value = fb->width;
+            return NO_ERROR;
+        case NATIVE_WINDOW_DEFAULT_HEIGHT:
+            *value = fb->height;
+            return NO_ERROR;
+        case NATIVE_WINDOW_TRANSFORM_HINT:
+            *value = 0;
+            return NO_ERROR;
     }
     *value = 0;
     return BAD_VALUE;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c29aeca..e0268fa 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -44,10 +44,6 @@
 
 namespace android {
 
-template <typename T> inline T min(T a, T b) {
-    return a<b ? a : b;
-}
-
 // ---------------------------------------------------------------------------
 
 Layer::Layer(SurfaceFlinger* flinger,
@@ -457,13 +453,22 @@
         // FIXME: mPostedDirtyRegion = dirty & bounds
         mPostedDirtyRegion.set(front.w, front.h);
 
-        sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
-        if ((newFrontBuffer->getWidth()  == front.requested_w &&
-            newFrontBuffer->getHeight() == front.requested_h) ||
-            isFixedSize())
+
+        if ((front.w != front.requested_w) ||
+            (front.h != front.requested_h))
         {
-            if ((front.w != front.requested_w) ||
-                (front.h != front.requested_h))
+            // check that we received a buffer of the right size
+            // (Take the buffer's orientation into account)
+            sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
+            uint32_t bufWidth  = newFrontBuffer->getWidth();
+            uint32_t bufHeight = newFrontBuffer->getHeight();
+            if (mCurrentTransform & Transform::ROT_90) {
+                swap(bufWidth, bufHeight);
+            }
+
+            if (isFixedSize() ||
+                    (bufWidth == front.requested_w &&
+                    bufHeight == front.requested_h))
             {
                 // Here we pretend the transaction happened by updating the
                 // current and drawing states. Drawing state is only accessed
@@ -483,10 +488,10 @@
 
                 // recompute visible region
                 recomputeVisibleRegions = true;
-            }
 
-            // we now have the correct size, unfreeze the screen
-            mFreezeLock.clear();
+                // we now have the correct size, unfreeze the screen
+                mFreezeLock.clear();
+            }
         }
     }
 }
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index a586d59..11f61cc 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -52,6 +52,20 @@
     return res;
 }
 
+status_t SurfaceTextureLayer::queueBuffer(int buf, int64_t timestamp,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+
+    status_t res = SurfaceTexture::queueBuffer(buf, timestamp,
+            outWidth, outHeight, outTransform);
+
+    sp<Layer> layer(mLayer.promote());
+    if (layer != NULL) {
+        *outTransform = layer->getOrientation();
+    }
+
+    return res;
+}
+
 status_t SurfaceTextureLayer::dequeueBuffer(int *buf,
         uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
 
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
index 7faff54..29a9cbe 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.h
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -45,6 +45,9 @@
     virtual status_t setBufferCount(int bufferCount);
 
 protected:
+    virtual status_t queueBuffer(int buf, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+
     virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
             uint32_t format, uint32_t usage);
 };
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 4cedcbf..24d5f9a 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -20,6 +20,7 @@
 #include <utils/String8.h>
 #include <ui/Region.h>
 
+#include "clz.h"
 #include "Transform.h"
 
 // ---------------------------------------------------------------------------
@@ -28,42 +29,6 @@
 
 // ---------------------------------------------------------------------------
 
-template <typename T>
-static inline T min(T a, T b) {
-    return a<b ? a : b;
-}
-template <typename T>
-static inline T min(T a, T b, T c) {
-    return min(a, min(b, c));
-}
-template <typename T>
-static inline T min(T a, T b, T c, T d) {
-    return min(a, b, min(c, d));
-}
-
-template <typename T>
-static inline T max(T a, T b) {
-    return a>b ? a : b;
-}
-template <typename T>
-static inline T max(T a, T b, T c) {
-    return max(a, max(b, c));
-}
-template <typename T>
-static inline T max(T a, T b, T c, T d) {
-    return max(a, b, max(c, d));
-}
-
-template <typename T>
-static inline
-void swap(T& a, T& b) {
-    T t(a);
-    a = b;
-    b = t;
-}
-
-// ---------------------------------------------------------------------------
-
 Transform::Transform() {
     reset();
 }
diff --git a/services/surfaceflinger/clz.h b/services/surfaceflinger/clz.h
index ca445553..a4c5262 100644
--- a/services/surfaceflinger/clz.h
+++ b/services/surfaceflinger/clz.h
@@ -24,6 +24,41 @@
     return __builtin_clz(x);
 }
 
+template <typename T>
+static inline T min(T a, T b) {
+    return a<b ? a : b;
+}
+template <typename T>
+static inline T min(T a, T b, T c) {
+    return min(a, min(b, c));
+}
+template <typename T>
+static inline T min(T a, T b, T c, T d) {
+    return min(a, b, min(c, d));
+}
+
+template <typename T>
+static inline T max(T a, T b) {
+    return a>b ? a : b;
+}
+template <typename T>
+static inline T max(T a, T b, T c) {
+    return max(a, max(b, c));
+}
+template <typename T>
+static inline T max(T a, T b, T c, T d) {
+    return max(a, b, max(c, d));
+}
+
+template <typename T>
+static inline
+void swap(T& a, T& b) {
+    T t(a);
+    a = b;
+    b = t;
+}
+
+
 }; // namespace android
 
 #endif /* ANDROID_SURFACE_FLINGER_CLZ_H */