Allow for resizing of Virtual Displays.

Modify SurfaceFlinger to use VirtualDisplaySurface in all cases when a virtual
display is used. Add functionality in VirtualDisplaySurface to resize the
buffers aquired in the QueueBufferOutput. Add transaction support in
SurfaceFlinger for resize. Add the modification of the size in DisplayDevice.

Change-Id: Iae7e3556dc06fd18d470adbbd76f7255f6e6dd6b
Tested: None
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index acdbd77..e95d8b6 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -81,6 +81,8 @@
     output.writeInt32(orientation);
     output.write(viewport);
     output.write(frame);
+    output.writeInt32(width);
+    output.writeInt32(height);
     return NO_ERROR;
 }
 
@@ -92,6 +94,8 @@
     orientation = input.readInt32();
     input.read(viewport);
     input.read(frame);
+    width = input.readInt32();
+    height = input.readInt32();
     return NO_ERROR;
 }
 
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e3e0b0a..2213259 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -102,6 +102,7 @@
     if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
         window->setSwapInterval(window, 0);
 
+    mConfig = config;
     mDisplay = display;
     mSurface = surface;
     mFormat  = format;
@@ -397,6 +398,22 @@
     return NO_ERROR;
 }
 
+void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
+    dirtyRegion.set(getBounds());
+
+    mDisplaySurface->resizeBuffers(newWidth, newHeight);
+
+    ANativeWindow* const window = mNativeWindow.get();
+    mSurface = eglCreateWindowSurface(mDisplay, mConfig, window, NULL);
+    eglQuerySurface(mDisplay, mSurface, EGL_WIDTH,  &mDisplayWidth);
+    eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mDisplayHeight);
+
+    LOG_FATAL_IF(mDisplayWidth != newWidth,
+                "Unable to set new width to %d", newWidth);
+    LOG_FATAL_IF(mDisplayHeight != newHeight,
+                "Unable to set new height to %d", newHeight);
+}
+
 void DisplayDevice::setProjection(int orientation,
         const Rect& newViewport, const Rect& newFrame) {
     Rect viewport(newViewport);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 615ca28..00e0918 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -109,6 +109,7 @@
     Region                  getDirtyRegion(bool repaintEverything) const;
 
     void                    setLayerStack(uint32_t stack);
+    void                    setDisplaySize(const int newWidth, const int newHeight);
     void                    setProjection(int orientation, const Rect& viewport, const Rect& frame);
 
     int                     getOrientation() const { return mOrientation; }
@@ -181,6 +182,7 @@
     sp<ANativeWindow> mNativeWindow;
     sp<DisplaySurface> mDisplaySurface;
 
+    EGLConfig       mConfig;
     EGLDisplay      mDisplay;
     EGLSurface      mSurface;
     int             mDisplayWidth;
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index 1db3eb8..e60c4fb 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -72,6 +72,8 @@
 
     virtual void dump(String8& result) const = 0;
 
+    virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
+
 protected:
     DisplaySurface() {}
     virtual ~DisplaySurface() {}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index ba72ce3..d0bf22b 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -49,6 +49,10 @@
     // has a non-virtual dump() with the same signature.
     virtual void dump(String8& result) const;
 
+    // Cannot resize a buffers in a FramebufferSurface. Only works with virtual
+    // displays.
+    virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { };
+
 private:
     virtual ~FramebufferSurface() { }; // this class cannot be overloaded
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index ad7cd25..ca04495 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -68,6 +68,8 @@
     int sinkWidth, sinkHeight;
     sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth);
     sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight);
+    mSinkBufferWidth = sinkWidth;
+    mSinkBufferHeight = sinkHeight;
 
     // Pick the buffer format to request from the sink when not rendering to it
     // with GLES. If the consumer needs CPU access, use the default format
@@ -104,10 +106,6 @@
             "Unexpected beginFrame() in %s state", dbgStateStr());
     mDbgState = DBG_STATE_BEGUN;
 
-    uint32_t transformHint, numPendingBuffers;
-    mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
-            &transformHint, &numPendingBuffers);
-
     return refreshOutputBuffer();
 }
 
@@ -259,8 +257,20 @@
 void VirtualDisplaySurface::dump(String8& /* result */) const {
 }
 
+void VirtualDisplaySurface::resizeBuffers(const uint32_t w, const uint32_t h) {
+    uint32_t tmpW, tmpH, transformHint, numPendingBuffers;
+    mQueueBufferOutput.deflate(&tmpW, &tmpH, &transformHint, &numPendingBuffers);
+    mQueueBufferOutput.inflate(w, h, transformHint, numPendingBuffers);
+
+    mSinkBufferWidth = w;
+    mSinkBufferHeight = h;
+}
+
 status_t VirtualDisplaySurface::requestBuffer(int pslot,
         sp<GraphicBuffer>* outBuf) {
+    if (mDisplayId < 0)
+        return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf);
+
     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
             "Unexpected requestBuffer pslot=%d in %s state",
             pslot, dbgStateStr());
@@ -275,6 +285,7 @@
 
 status_t VirtualDisplaySurface::dequeueBuffer(Source source,
         uint32_t format, uint32_t usage, int* sslot, sp<Fence>* fence) {
+    LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
     // Don't let a slow consumer block us
     bool async = (source == SOURCE_SINK);
 
@@ -319,6 +330,9 @@
 
 status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
         uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+    if (mDisplayId < 0)
+        return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, async, w, h, format, usage);
+
     VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
             "Unexpected dequeueBuffer() in %s state", dbgStateStr());
     mDbgState = DBG_STATE_GLES;
@@ -399,6 +413,9 @@
 
 status_t VirtualDisplaySurface::queueBuffer(int pslot,
         const QueueBufferInput& input, QueueBufferOutput* output) {
+    if (mDisplayId < 0)
+        return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output);
+
     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
             "Unexpected queueBuffer(pslot=%d) in %s state", pslot,
             dbgStateStr());
@@ -452,6 +469,9 @@
 }
 
 void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) {
+    if (mDisplayId < 0)
+        return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(source, pslot), fence);
+
     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
             "Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
             dbgStateStr());
@@ -462,7 +482,17 @@
 }
 
 int VirtualDisplaySurface::query(int what, int* value) {
-    return mSource[SOURCE_SINK]->query(what, value);
+    switch (what) {
+        case NATIVE_WINDOW_WIDTH:
+            *value = mSinkBufferWidth;
+            break;
+        case NATIVE_WINDOW_HEIGHT:
+            *value = mSinkBufferHeight;
+            break;
+        default:
+            return mSource[SOURCE_SINK]->query(what, value);
+    }
+    return NO_ERROR;
 }
 
 status_t VirtualDisplaySurface::connect(const sp<IProducerListener>& listener,
@@ -501,8 +531,6 @@
 
 void VirtualDisplaySurface::resetPerFrameState() {
     mCompositionType = COMPOSITION_UNKNOWN;
-    mSinkBufferWidth = 0;
-    mSinkBufferHeight = 0;
     mFbFence = Fence::NO_FENCE;
     mOutputFence = Fence::NO_FENCE;
     mOutputProducerSlot = -1;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 5c00ab4..363dce2 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -87,6 +87,7 @@
     virtual status_t advanceFrame();
     virtual void onFrameCommitted();
     virtual void dump(String8& result) const;
+    virtual void resizeBuffers(const uint32_t w, const uint32_t h);
 
 private:
     enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1};
@@ -168,6 +169,10 @@
     // to the sink, we have to return the previous version.
     QueueBufferOutput mQueueBufferOutput;
 
+    // Details of the current sink buffer. These become valid when a buffer is
+    // dequeued from the sink, and are used when queueing the buffer.
+    uint32_t mSinkBufferWidth, mSinkBufferHeight;
+
     //
     // Intra-frame state
     //
@@ -176,10 +181,6 @@
     // Valid after prepareFrame(), cleared in onFrameCommitted.
     CompositionType mCompositionType;
 
-    // Details of the current sink buffer. These become valid when a buffer is
-    // dequeued from the sink, and are used when queueing the buffer.
-    uint32_t mSinkBufferWidth, mSinkBufferHeight;
-
     // mFbFence is the fence HWC should wait for before reading the framebuffer
     // target buffer.
     sp<Fence> mFbFence;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 80cf643..6a034ec 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1258,6 +1258,9 @@
                             disp->setProjection(state.orientation,
                                     state.viewport, state.frame);
                         }
+                        if (state.width != draw[i].width || state.height != draw[i].height) {
+                            disp->setDisplaySize(state.width, state.height);
+                        }
                     }
                 }
             }
@@ -1288,13 +1291,7 @@
                                     bqProducer, bqConsumer, state.displayName);
 
                             dispSurface = vds;
-                            if (hwcDisplayId >= 0) {
-                                producer = vds;
-                            } else {
-                                // There won't be any interaction with HWC for this virtual display,
-                                // so the GLES driver can pass buffers directly to the sink.
-                                producer = state.surface;
-                            }
+                            producer = vds;
                         }
                     } else {
                         ALOGE_IF(state.surface!=NULL,
@@ -1992,6 +1989,16 @@
                 flags |= eDisplayTransactionNeeded;
             }
         }
+        if (what & DisplayState::eDisplaySizeChanged) {
+            if (disp.width != s.width) {
+                disp.width = s.width;
+                flags |= eDisplayTransactionNeeded;
+            }
+            if (disp.height != s.height) {
+                disp.height = s.height;
+                flags |= eDisplayTransactionNeeded;
+            }
+        }
     }
     return flags;
 }
@@ -2178,6 +2185,8 @@
     d.orientation = DisplayState::eOrientationDefault;
     d.frame.makeInvalid();
     d.viewport.makeInvalid();
+    d.width = 0;
+    d.height = 0;
     displays.add(d);
     setTransactionState(state, displays, 0);
     setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
@@ -3206,11 +3215,11 @@
 // ---------------------------------------------------------------------------
 
 SurfaceFlinger::DisplayDeviceState::DisplayDeviceState()
-    : type(DisplayDevice::DISPLAY_ID_INVALID) {
+    : type(DisplayDevice::DISPLAY_ID_INVALID), width(0), height(0) {
 }
 
 SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type)
-    : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0) {
+    : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0), width(0), height(0) {
     viewport.makeInvalid();
     frame.makeInvalid();
 }