Return the transform to apply in getLastQueuedBuffer

Bug: 28428955
Change-Id: Id48f7d3bf3f5deb074cf0a6a52a41caac875db41
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 73f61c5..3e26e05 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -31,6 +31,7 @@
 #include <gui/BufferItem.h>
 #include <gui/BufferQueueCore.h>
 #include <gui/BufferQueueProducer.h>
+#include <gui/GLConsumer.h>
 #include <gui/IConsumerListener.h>
 #include <gui/IGraphicBufferAlloc.h>
 #include <gui/IProducerListener.h>
@@ -923,6 +924,8 @@
         mLastQueueBufferFence->waitForever("Throttling EGL Production");
     }
     mLastQueueBufferFence = fence;
+    mLastQueuedCrop = item.mCrop;
+    mLastQueuedTransform = item.mTransform;
 
     return NO_ERROR;
 }
@@ -1372,7 +1375,7 @@
 }
 
 status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
-        sp<Fence>* outFence) {
+        sp<Fence>* outFence, float outTransformMatrix[16]) {
     ATRACE_CALL();
     BQ_LOGV("getLastQueuedBuffer");
 
@@ -1386,6 +1389,14 @@
     *outBuffer = mSlots[mCore->mLastQueuedSlot].mGraphicBuffer;
     *outFence = mLastQueueBufferFence;
 
+    // Currently only SurfaceFlinger internally ever changes
+    // GLConsumer's filtering mode, so we just use 'true' here as
+    // this is slightly specialized for the current client of this API,
+    // which does want filtering.
+    GLConsumer::computeTransformMatrix(outTransformMatrix,
+            mSlots[mCore->mLastQueuedSlot].mGraphicBuffer, mLastQueuedCrop,
+            mLastQueuedTransform, true /* filter */);
+
     return NO_ERROR;
 }
 
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 3acd3ab..9937399 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -787,26 +787,40 @@
 
 void GLConsumer::computeCurrentTransformMatrixLocked() {
     GLC_LOGV("computeCurrentTransformMatrixLocked");
+    sp<GraphicBuffer> buf = (mCurrentTextureImage == nullptr) ?
+            nullptr : mCurrentTextureImage->graphicBuffer();
+    if (buf == nullptr) {
+        GLC_LOGD("computeCurrentTransformMatrixLocked: "
+                "mCurrentTextureImage is NULL");
+    }
+    computeTransformMatrix(mCurrentTransformMatrix, buf,
+        isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
+        mCurrentTransform, mFilteringEnabled);
+}
+
+void GLConsumer::computeTransformMatrix(float outTransform[16],
+        const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
+        bool filtering) {
 
     float xform[16];
     for (int i = 0; i < 16; i++) {
         xform[i] = mtxIdentity[i];
     }
-    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
         float result[16];
         mtxMul(result, xform, mtxFlipH);
         for (int i = 0; i < 16; i++) {
             xform[i] = result[i];
         }
     }
-    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
         float result[16];
         mtxMul(result, xform, mtxFlipV);
         for (int i = 0; i < 16; i++) {
             xform[i] = result[i];
         }
     }
-    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
         float result[16];
         mtxMul(result, xform, mtxRot90);
         for (int i = 0; i < 16; i++) {
@@ -814,59 +828,49 @@
         }
     }
 
-    sp<GraphicBuffer> buf = (mCurrentTextureImage == NULL) ?
-            NULL : mCurrentTextureImage->graphicBuffer();
-
-    if (buf == NULL) {
-        GLC_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL");
-    }
-
     float mtxBeforeFlipV[16];
-    if (!isEglImageCroppable(mCurrentCrop)) {
-        Rect cropRect = mCurrentCrop;
+    if (!cropRect.isEmpty()) {
         float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
         float bufferWidth = buf->getWidth();
         float bufferHeight = buf->getHeight();
-        if (!cropRect.isEmpty()) {
-            float shrinkAmount = 0.0f;
-            if (mFilteringEnabled) {
-                // In order to prevent bilinear sampling beyond the edge of the
-                // crop rectangle we may need to shrink it by 2 texels in each
-                // dimension.  Normally this would just need to take 1/2 a texel
-                // off each end, but because the chroma channels of YUV420 images
-                // are subsampled we may need to shrink the crop region by a whole
-                // texel on each side.
-                switch (buf->getPixelFormat()) {
-                    case PIXEL_FORMAT_RGBA_8888:
-                    case PIXEL_FORMAT_RGBX_8888:
-                    case PIXEL_FORMAT_RGB_888:
-                    case PIXEL_FORMAT_RGB_565:
-                    case PIXEL_FORMAT_BGRA_8888:
-                        // We know there's no subsampling of any channels, so we
-                        // only need to shrink by a half a pixel.
-                        shrinkAmount = 0.5;
-                        break;
+        float shrinkAmount = 0.0f;
+        if (filtering) {
+            // In order to prevent bilinear sampling beyond the edge of the
+            // crop rectangle we may need to shrink it by 2 texels in each
+            // dimension.  Normally this would just need to take 1/2 a texel
+            // off each end, but because the chroma channels of YUV420 images
+            // are subsampled we may need to shrink the crop region by a whole
+            // texel on each side.
+            switch (buf->getPixelFormat()) {
+                case PIXEL_FORMAT_RGBA_8888:
+                case PIXEL_FORMAT_RGBX_8888:
+                case PIXEL_FORMAT_RGB_888:
+                case PIXEL_FORMAT_RGB_565:
+                case PIXEL_FORMAT_BGRA_8888:
+                    // We know there's no subsampling of any channels, so we
+                    // only need to shrink by a half a pixel.
+                    shrinkAmount = 0.5;
+                    break;
 
-                    default:
-                        // If we don't recognize the format, we must assume the
-                        // worst case (that we care about), which is YUV420.
-                        shrinkAmount = 1.0;
-                        break;
-                }
+                default:
+                    // If we don't recognize the format, we must assume the
+                    // worst case (that we care about), which is YUV420.
+                    shrinkAmount = 1.0;
+                    break;
             }
+        }
 
-            // Only shrink the dimensions that are not the size of the buffer.
-            if (cropRect.width() < bufferWidth) {
-                tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
-                sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
-                        bufferWidth;
-            }
-            if (cropRect.height() < bufferHeight) {
-                ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
-                        bufferHeight;
-                sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
-                        bufferHeight;
-            }
+        // Only shrink the dimensions that are not the size of the buffer.
+        if (cropRect.width() < bufferWidth) {
+            tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
+            sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
+                    bufferWidth;
+        }
+        if (cropRect.height() < bufferHeight) {
+            ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
+                    bufferHeight;
+            sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
+                    bufferHeight;
         }
         float crop[16] = {
             sx, 0, 0, 0,
@@ -886,7 +890,7 @@
     // coordinate of 0, so GLConsumer must behave the same way.  We don't
     // want to expose this to applications, however, so we must add an
     // additional vertical flip to the transform after all the other transforms.
-    mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
+    mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV);
 }
 
 nsecs_t GLConsumer::getTimestamp() {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 137a54b..2c48d83 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -382,7 +382,7 @@
     }
 
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
-            sp<Fence>* outFence) override {
+            sp<Fence>* outFence, float outTransformMatrix[16]) override {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
         status_t result = remote()->transact(GET_LAST_QUEUED_BUFFER, data,
@@ -400,6 +400,9 @@
         if (hasBuffer) {
             buffer = new GraphicBuffer();
             result = reply.read(*buffer);
+            if (result == NO_ERROR) {
+                result = reply.read(outTransformMatrix, sizeof(float) * 16);
+            }
         }
         if (result != NO_ERROR) {
             ALOGE("getLastQueuedBuffer failed to read buffer: %d", result);
@@ -630,7 +633,8 @@
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
             sp<GraphicBuffer> buffer(nullptr);
             sp<Fence> fence(Fence::NO_FENCE);
-            status_t result = getLastQueuedBuffer(&buffer, &fence);
+            float transform[16] = {};
+            status_t result = getLastQueuedBuffer(&buffer, &fence, transform);
             reply->writeInt32(result);
             if (result != NO_ERROR) {
                 return result;
@@ -640,6 +644,9 @@
             } else {
                 reply->writeBool(true);
                 result = reply->write(*buffer);
+                if (result == NO_ERROR) {
+                    reply->write(transform, sizeof(float) * 16);
+                }
             }
             if (result != NO_ERROR) {
                 ALOGE("getLastQueuedBuffer failed to write buffer: %d", result);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index b304633..6811269 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -128,8 +128,9 @@
 }
 
 status_t Surface::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
-        sp<Fence>* outFence) {
-    return mGraphicBufferProducer->getLastQueuedBuffer(outBuffer, outFence);
+        sp<Fence>* outFence, float outTransformMatrix[16]) {
+    return mGraphicBufferProducer->getLastQueuedBuffer(outBuffer, outFence,
+            outTransformMatrix);
 }
 
 int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 9876d94..85d63b4 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -842,8 +842,10 @@
     // Make sure we got the second buffer back
     sp<GraphicBuffer> returnedBuffer;
     sp<Fence> returnedFence;
+    float transform[16];
     ASSERT_EQ(OK,
-            mProducer->getLastQueuedBuffer(&returnedBuffer, &returnedFence));
+            mProducer->getLastQueuedBuffer(&returnedBuffer, &returnedFence,
+            transform));
     ASSERT_EQ(secondBuffer->getNativeBuffer()->handle,
             returnedBuffer->getNativeBuffer()->handle);
 }