Merge "Fix a bug where non-cropped layer could be scaled incorrectly" into klp-dev
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 79b6689..9708ee3 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -198,6 +198,10 @@
     mPageFlipCount++;
 }
 
+status_t DisplayDevice::beginFrame() const {
+    return mDisplaySurface->beginFrame();
+}
+
 status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
     DisplaySurface::CompositionType compositionType;
     bool haveGles = hwc.hasGlesComposition(mHwcDisplayId);
@@ -218,13 +222,15 @@
 }
 
 void DisplayDevice::swapBuffers(HWComposer& hwc) const {
-    // We need to call eglSwapBuffers() unless:
-    // (a) there was no GLES composition this frame, or
-    // (b) we're using a legacy HWC with no framebuffer target support (in
-    //     which case HWComposer::commit() handles things).
+    // We need to call eglSwapBuffers() if:
+    //  (1) we don't have a hardware composer, or
+    //  (2) we did GLES composition this frame, and either
+    //    (a) we have framebuffer target support (not present on legacy
+    //        devices, where HWComposer::commit() handles things); or
+    //    (b) this is a virtual display
     if (hwc.initCheck() != NO_ERROR ||
             (hwc.hasGlesComposition(mHwcDisplayId) &&
-             hwc.supportsFramebufferTarget())) {
+             (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) {
         EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
         if (!success) {
             EGLint error = eglGetError();
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index eec0396..e0b1370 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -122,6 +122,7 @@
     int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }
     const wp<IBinder>&      getDisplayToken() const { return mDisplayToken; }
 
+    status_t beginFrame() const;
     status_t prepareFrame(const HWComposer& hwc) const;
 
     void swapBuffers(HWComposer& hwc) const;
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index 9192db5..48bf3f2 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -30,6 +30,11 @@
 
 class DisplaySurface : public virtual RefBase {
 public:
+    // beginFrame is called at the beginning of the composition loop, before
+    // the configuration is known. The DisplaySurface should do anything it
+    // needs to do to enable HWComposer to decide how to compose the frame.
+    virtual status_t beginFrame() = 0;
+
     // prepareFrame is called after the composition configuration is known but
     // before composition takes place. The DisplaySurface can use the
     // composition type to decide how to manage the flow of buffers between
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 807d4e1..8c634ed 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -68,6 +68,10 @@
     mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
 }
 
+status_t FramebufferSurface::beginFrame() {
+    return NO_ERROR;
+}
+
 status_t FramebufferSurface::prepareFrame(CompositionType compositionType) {
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index fcda287..1d67446 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -39,6 +39,7 @@
 public:
     FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
 
+    virtual status_t beginFrame();
     virtual status_t prepareFrame(CompositionType compositionType);
     virtual status_t compositionComplete();
     virtual status_t advanceFrame();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index ef07f18..e7d0d23 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -987,9 +987,9 @@
                         disp.list->numHwLayers, disp.list->flags);
 
                 result.append(
-                        "    type    |  handle  |   hints  |   flags  | tr | blend |  format  |       source crop         |           frame           name \n"
-                        "------------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
-                //      " __________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
+                        "    type    |  handle  |   hints  |   flags  | tr | blend |  format  |          source crop            |           frame           name \n"
+                        "------------+----------+----------+----------+----+-------+----------+---------------------------------+--------------------------------\n");
+                //      " __________ | ________ | ________ | ________ | __ | _____ | ________ | [_____._,_____._,_____._,_____._] | [_____,_____,_____,_____]
                 for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
                     const hwc_layer_1_t&l = disp.list->hwLayers[i];
                     int32_t format = -1;
@@ -1020,13 +1020,23 @@
                     if (type >= NELEM(compositionTypeName))
                         type = NELEM(compositionTypeName) - 1;
 
-                    result.appendFormat(
-                            " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
-                                    compositionTypeName[type],
-                                    intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
-                                    l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
-                                    l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
-                                    name.string());
+                    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+                        result.appendFormat(
+                                " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%7.1f,%7.1f,%7.1f,%7.1f] | [%5d,%5d,%5d,%5d] %s\n",
+                                        compositionTypeName[type],
+                                        intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
+                                        l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom,
+                                        l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+                                        name.string());
+                    } else {
+                        result.appendFormat(
+                                " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%7d,%7d,%7d,%7d] | [%5d,%5d,%5d,%5d] %s\n",
+                                        compositionTypeName[type],
+                                        intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
+                                        l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
+                                        l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+                                        name.string());
+                    }
                 }
             }
         }
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 89c87c7..01ca38a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -71,11 +71,26 @@
 VirtualDisplaySurface::~VirtualDisplaySurface() {
 }
 
-status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
+status_t VirtualDisplaySurface::beginFrame() {
     if (mDisplayId < 0)
         return NO_ERROR;
 
     VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
+            "Unexpected beginFrame() in %s state", dbgStateStr());
+    mDbgState = DBG_STATE_BEGUN;
+
+    uint32_t transformHint, numPendingBuffers;
+    mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
+            &transformHint, &numPendingBuffers);
+
+    return refreshOutputBuffer();
+}
+
+status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
+    if (mDisplayId < 0)
+        return NO_ERROR;
+
+    VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN,
             "Unexpected prepareFrame() in %s state", dbgStateStr());
     mDbgState = DBG_STATE_PREPARED;
 
@@ -109,31 +124,11 @@
     }
     mDbgState = DBG_STATE_HWC;
 
-    status_t result;
-    sp<Fence> outFence;
-    if (mCompositionType != COMPOSITION_GLES) {
-        // Dequeue an output buffer from the sink
-        uint32_t transformHint, numPendingBuffers;
-        mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
-                &transformHint, &numPendingBuffers);
-        int sslot;
-        result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence, false);
-        if (result < 0)
-            return result;
-        mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
-    }
-
     if (mCompositionType == COMPOSITION_HWC) {
-        // We just dequeued the output buffer, use it for FB as well
+        // Use the output buffer for the FB as well, though conceptually the
+        // FB is unused on this frame.
         mFbProducerSlot = mOutputProducerSlot;
-        mFbFence = outFence;
-    } else if (mCompositionType == COMPOSITION_GLES) {
-        mOutputProducerSlot = mFbProducerSlot;
-        outFence = mFbFence;
-    } else {
-        // mFbFence and mFbProducerSlot were set in queueBuffer,
-        // and mOutputProducerSlot and outFence were set above when dequeueing
-        // the sink buffer.
+        mFbFence = mOutputFence;
     }
 
     if (mFbProducerSlot < 0 || mOutputProducerSlot < 0) {
@@ -152,12 +147,7 @@
             mFbProducerSlot, fbBuffer.get(),
             mOutputProducerSlot, outBuffer.get());
 
-    result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
-    if (result == NO_ERROR) {
-        result = mHwc.setOutputBuffer(mDisplayId, outFence, outBuffer);
-    }
-
-    return result;
+    return mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
 }
 
 void VirtualDisplaySurface::onFrameCommitted() {
@@ -256,17 +246,39 @@
 
     VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
 
+    status_t result = NO_ERROR;
     mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER;
     Source source = fbSourceForCompositionType(mCompositionType);
+
     if (source == SOURCE_SINK) {
-        mSinkBufferWidth = w;
-        mSinkBufferHeight = h;
+        // We already dequeued the output buffer. If the GLES driver wants
+        // something incompatible, we have to cancel and get a new one. This
+        // will mean that HWC will see a different output buffer between
+        // prepare and set, but since we're in GLES-only mode already it
+        // shouldn't matter.
+
+        const sp<GraphicBuffer>& buf = mProducerBuffers[mOutputProducerSlot];
+        if ((mProducerUsage & ~buf->getUsage()) != 0 ||
+                (format != 0 && format != (uint32_t)buf->getPixelFormat()) ||
+                (w != 0 && w != mSinkBufferWidth) ||
+                (h != 0 && h != mSinkBufferHeight)) {
+            VDS_LOGV("dequeueBuffer: output buffer doesn't satisfy GLES "
+                    "request, getting a new buffer");
+            result = refreshOutputBuffer();
+            if (result < 0)
+                return result;
+        }
     }
 
-    int sslot;
-    status_t result = dequeueBuffer(source, format, &sslot, fence, async);
-    if (result >= 0) {
-        *pslot = mapSource2ProducerSlot(source, sslot);
+    if (source == SOURCE_SINK) {
+        *pslot = mOutputProducerSlot;
+        *fence = mOutputFence;
+    } else {
+        int sslot;
+        result = dequeueBuffer(source, format, &sslot, fence, async);
+        if (result >= 0) {
+            *pslot = mapSource2ProducerSlot(source, sslot);
+        }
     }
     return result;
 }
@@ -318,6 +330,7 @@
                 &transform, &async, &mFbFence);
 
         mFbProducerSlot = pslot;
+        mOutputFence = mFbFence;
     }
 
     *output = mQueueBufferOutput;
@@ -365,10 +378,30 @@
     mSinkBufferWidth = 0;
     mSinkBufferHeight = 0;
     mFbFence = Fence::NO_FENCE;
+    mOutputFence = Fence::NO_FENCE;
     mFbProducerSlot = -1;
     mOutputProducerSlot = -1;
 }
 
+status_t VirtualDisplaySurface::refreshOutputBuffer() {
+    if (mOutputProducerSlot >= 0) {
+        mSource[SOURCE_SINK]->cancelBuffer(
+                mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot),
+                mOutputFence);
+    }
+
+    int sslot;
+    status_t result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &mOutputFence, false);
+    if (result < 0)
+        return result;
+    mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
+
+    result = mHwc.setOutputBuffer(mDisplayId, mOutputFence,
+            mProducerBuffers[mOutputProducerSlot]);
+
+    return result;
+}
+
 // This slot mapping function is its own inverse, so two copies are unnecessary.
 // Both are kept to make the intent clear where the function is called, and for
 // the (unlikely) chance that we switch to a different mapping function.
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 64a8dce..4ab80e4 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -79,6 +79,7 @@
     //
     // DisplaySurface interface
     //
+    virtual status_t beginFrame();
     virtual status_t prepareFrame(CompositionType compositionType);
     virtual status_t compositionComplete();
     virtual status_t advanceFrame();
@@ -112,6 +113,7 @@
             int* sslot, sp<Fence>* fence, bool async);
     void updateQueueBufferOutput(const QueueBufferOutput& qbo);
     void resetPerFrameState();
+    status_t refreshOutputBuffer();
 
     // Both the sink and scratch buffer pools have their own set of slots
     // ("source slots", or "sslot"). We have to merge these into the single
@@ -169,6 +171,10 @@
     // target buffer.
     sp<Fence> mFbFence;
 
+    // mOutputFence is the fence HWC should wait for before writing to the
+    // output buffer.
+    sp<Fence> mOutputFence;
+
     // Producer slot numbers for the buffers to use for HWC framebuffer target
     // and output.
     int mFbProducerSlot;
@@ -181,7 +187,8 @@
     // +-----------+-------------------+-------------+
     // | State     | Event             || Next State |
     // +-----------+-------------------+-------------+
-    // | IDLE      | prepareFrame      || PREPARED   |
+    // | IDLE      | beginFrame        || BEGUN      |
+    // | BEGUN     | prepareFrame      || PREPARED   |
     // | PREPARED  | dequeueBuffer [1] || GLES       |
     // | PREPARED  | advanceFrame [2]  || HWC        |
     // | GLES      | queueBuffer       || GLES_DONE  |
@@ -194,7 +201,10 @@
     enum DbgState {
         // no buffer dequeued, don't know anything about the next frame
         DBG_STATE_IDLE,
-        // no buffer dequeued, but we know the buffer source for the frame
+        // output buffer dequeued, framebuffer source not yet known
+        DBG_STATE_BEGUN,
+        // output buffer dequeued, framebuffer source known but not provided
+        // to GLES yet.
         DBG_STATE_PREPARED,
         // GLES driver has a buffer dequeued
         DBG_STATE_GLES,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7e62dae..3058af7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -850,6 +850,10 @@
 }
 
 void SurfaceFlinger::setUpHWComposer() {
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        mDisplays[dpy]->beginFrame();
+    }
+
     HWComposer& hwc(getHwComposer());
     if (hwc.initCheck() == NO_ERROR) {
         // build the h/w work list