frameworks/native: Propagate dirty region in hwc_layer.

This change propagates dirty rect value of each layer down to HWC
in hwc_layer structure.

Conflicts:
	include/gui/IGraphicBufferProducer.h
	libs/gui/BufferQueueProducer.cpp
	libs/gui/Surface.cpp
	services/surfaceflinger/Layer.cpp
	services/surfaceflinger/Layer.h

Change-Id: I91d87facf4a321b92539de5353faf09b553d4919
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index 5effd10..a78f1c9 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -59,6 +59,9 @@
     // mCrop is the current crop rectangle for this buffer slot.
     Rect mCrop;
 
+    // mDirtyRect is the dirty rectangle for this buffer slot.
+    Rect mDirtyRect;
+
     // mTransform is the current transform flags for this buffer slot.
     // refer to NATIVE_WINDOW_TRANSFORM_* in <window.h>
     uint32_t mTransform;
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index f91fe46..bd7b973 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -176,6 +176,9 @@
     // getCurrentCrop returns the cropping rectangle of the current buffer.
     Rect getCurrentCrop() const;
 
+    // getDirtyRegion returns the dirty rect associated with the current buffer.
+    Rect getCurrentDirtyRect() const;
+
     // getCurrentTransform returns the transform of the current buffer.
     uint32_t getCurrentTransform() const;
 
@@ -369,6 +372,10 @@
     // It gets set each time updateTexImage is called.
     Rect mCurrentCrop;
 
+    //mCurrentDirtyRect is the dirty rectangle associated with the current
+    //buffer.
+    Rect mCurrentDirtyRect;
+
     // mCurrentTransform is the transform identifier for the current texture. It
     // gets set each time updateTexImage is called.
     uint32_t mCurrentTransform;
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 15f51fe..e083f71 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -67,6 +67,9 @@
         // mCrop is the current crop rectangle for this buffer slot.
         Rect mCrop;
 
+        // mDirtyRect is the dirty rectangle for this buffer slot.
+        Rect mDirtyRect;
+
         // mTransform is the current transform flags for this buffer slot.
         // refer to NATIVE_WINDOW_TRANSFORM_* in <window.h>
         uint32_t mTransform;
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 4e9e810..48e32cc 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -281,6 +281,14 @@
         : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp), crop(crop),
           scalingMode(scalingMode), transform(transform), stickyTransform(sticky),
           async(async), fence(fence) { }
+
+        inline QueueBufferInput(int64_t timestamp, bool isAutoTimestamp,
+                const Rect& crop, const Rect& dirtyRect, int scalingMode, uint32_t transform, bool async,
+                const sp<Fence>& fence, uint32_t sticky = 0)
+        : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp), crop(crop),
+          dirtyRect(dirtyRect),scalingMode(scalingMode), transform(transform), stickyTransform(sticky),
+          async(async), fence(fence) { }
+
         inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp,
                 Rect* outCrop, int* outScalingMode, uint32_t* outTransform,
                 bool* outAsync, sp<Fence>* outFence,
@@ -297,6 +305,24 @@
             }
         }
 
+        inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp,
+                Rect* outCrop, Rect* outDirtyRect, int* outScalingMode, uint32_t* outTransform,
+                bool* outAsync, sp<Fence>* outFence,
+                uint32_t* outStickyTransform = NULL) const {
+            *outTimestamp = timestamp;
+            *outIsAutoTimestamp = bool(isAutoTimestamp);
+            *outCrop = crop;
+            *outDirtyRect = dirtyRect;
+            *outScalingMode = scalingMode;
+            *outTransform = transform;
+            *outAsync = bool(async);
+            *outFence = fence;
+            if (outStickyTransform != NULL) {
+                *outStickyTransform = stickyTransform;
+            }
+        }
+
+
         // Flattenable protocol
         size_t getFlattenedSize() const;
         size_t getFdCount() const;
@@ -307,6 +333,7 @@
         int64_t timestamp;
         int isAutoTimestamp;
         Rect crop;
+        Rect dirtyRect;
         int scalingMode;
         uint32_t transform;
         uint32_t stickyTransform;
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index f2cf018..31138e1 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -101,6 +101,10 @@
      */
     void allocateBuffers();
 
+    /* sets dirty rectangle of the buffer that gets queued next for the
+     * Surface */
+    status_t setDirtyRect(const Rect* dirtyRect);
+
 protected:
     virtual ~Surface();
 
@@ -226,6 +230,10 @@
     // that gets queued. It is set by calling setCrop.
     Rect mCrop;
 
+    // mDirtyRect is the dirty rectangle set for the next buffer that gets
+    // queued. It is set by calling setDirtyRect.
+    Rect mDirtyRect;
+
     // mScalingMode is the scaling mode that will be used for the next
     // buffers that get queued. It is set by calling setScalingMode.
     int mScalingMode;
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index d3fa43e..5924b05 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -34,6 +34,7 @@
     mAcquireCalled(false),
     mTransformToDisplayInverse(false) {
     mCrop.makeInvalid();
+    mDirtyRect.makeInvalid();
 }
 
 BufferItem::operator IGraphicBufferConsumer::BufferItem() const {
@@ -41,6 +42,7 @@
     bufferItem.mGraphicBuffer = mGraphicBuffer;
     bufferItem.mFence = mFence;
     bufferItem.mCrop = mCrop;
+    bufferItem.mDirtyRect = mDirtyRect;
     bufferItem.mTransform = mTransform;
     bufferItem.mScalingMode = mScalingMode;
     bufferItem.mTimestamp = mTimestamp;
@@ -55,6 +57,7 @@
 
 size_t BufferItem::getPodSize() const {
     size_t c =  sizeof(mCrop) +
+            sizeof(mDirtyRect) +
             sizeof(mTransform) +
             sizeof(mScalingMode) +
             sizeof(mTimestamp) +
@@ -125,6 +128,7 @@
     }
 
     FlattenableUtils::write(buffer, size, mCrop);
+    FlattenableUtils::write(buffer, size, mDirtyRect);
     FlattenableUtils::write(buffer, size, mTransform);
     FlattenableUtils::write(buffer, size, mScalingMode);
     FlattenableUtils::write(buffer, size, mTimestamp);
@@ -167,6 +171,7 @@
     }
 
     FlattenableUtils::read(buffer, size, mCrop);
+    FlattenableUtils::read(buffer, size, mDirtyRect);
     FlattenableUtils::read(buffer, size, mTransform);
     FlattenableUtils::read(buffer, size, mScalingMode);
     FlattenableUtils::read(buffer, size, mTimestamp);
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index d2fd3b0..6f2d214 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -512,12 +512,14 @@
     int64_t timestamp;
     bool isAutoTimestamp;
     Rect crop;
+    Rect dirtyRect;
     int scalingMode;
     uint32_t transform;
     uint32_t stickyTransform;
     bool async;
     sp<Fence> fence;
-    input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode, &transform,
+
+    input.deflate(&timestamp, &isAutoTimestamp, &crop, &dirtyRect, &scalingMode, &transform,
             &async, &fence, &stickyTransform);
 
     if (fence == NULL) {
@@ -601,6 +603,7 @@
         item.mAcquireCalled = mSlots[slot].mAcquireCalled;
         item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
         item.mCrop = crop;
+        item.mDirtyRect = dirtyRect;
         item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
         item.mTransformToDisplayInverse =
                 bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index ccafe81..215cc74 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -141,6 +141,7 @@
             sizeof(mCurrentTransformMatrix));
 
     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
+    mCurrentDirtyRect.clear();
 }
 
 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
@@ -437,6 +438,7 @@
     mCurrentTimestamp = item.mTimestamp;
     mCurrentFence = item.mFence;
     mCurrentFrameNumber = item.mFrameNumber;
+    mCurrentDirtyRect = item.mDirtyRect;
 
     computeCurrentTransformMatrixLocked();
 
@@ -983,6 +985,11 @@
     return NO_ERROR;
 }
 
+Rect GLConsumer::getCurrentDirtyRect() const {
+     Mutex::Autolock lock(mMutex);
+     return mCurrentDirtyRect;
+}
+
 void GLConsumer::freeBufferLocked(int slotIndex) {
     ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
     if (slotIndex == mCurrentTexture) {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 1e28f9b..649ab3b 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -433,6 +433,7 @@
     return sizeof(timestamp)
          + sizeof(isAutoTimestamp)
          + sizeof(crop)
+         + sizeof(dirtyRect)
          + sizeof(scalingMode)
          + sizeof(transform)
          + sizeof(stickyTransform)
@@ -453,6 +454,7 @@
     FlattenableUtils::write(buffer, size, timestamp);
     FlattenableUtils::write(buffer, size, isAutoTimestamp);
     FlattenableUtils::write(buffer, size, crop);
+    FlattenableUtils::write(buffer, size, dirtyRect);
     FlattenableUtils::write(buffer, size, scalingMode);
     FlattenableUtils::write(buffer, size, transform);
     FlattenableUtils::write(buffer, size, stickyTransform);
@@ -467,6 +469,7 @@
               sizeof(timestamp)
             + sizeof(isAutoTimestamp)
             + sizeof(crop)
+            + sizeof(dirtyRect)
             + sizeof(scalingMode)
             + sizeof(transform)
             + sizeof(stickyTransform)
@@ -479,6 +482,7 @@
     FlattenableUtils::read(buffer, size, timestamp);
     FlattenableUtils::read(buffer, size, isAutoTimestamp);
     FlattenableUtils::read(buffer, size, crop);
+    FlattenableUtils::read(buffer, size, dirtyRect);
     FlattenableUtils::read(buffer, size, scalingMode);
     FlattenableUtils::read(buffer, size, transform);
     FlattenableUtils::read(buffer, size, stickyTransform);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 295f3f9..c7b7bb4 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -65,6 +65,7 @@
     mReqUsage = 0;
     mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
     mCrop.clear();
+    mDirtyRect.clear();
     mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
     mTransform = 0;
     mStickyTransform = 0;
@@ -175,6 +176,12 @@
     return c->perform(operation, args);
 }
 
+status_t Surface::setDirtyRect(const Rect* dirtyRect) {
+    Mutex::Autolock lock(mMutex);
+    mDirtyRect = *dirtyRect;
+    return NO_ERROR;
+}
+
 int Surface::setSwapInterval(int interval) {
     ATRACE_CALL();
     // EGL specification states:
@@ -318,10 +325,13 @@
     Rect crop;
     mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
 
+    Rect dirtyRect = mDirtyRect.isEmpty() ?
+        Rect(buffer->width, buffer->height) : mDirtyRect;
+
     sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
     IGraphicBufferProducer::QueueBufferOutput output;
     IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
-            crop, mScalingMode, mTransform ^ mStickyTransform, mSwapIntervalZero,
+            crop, dirtyRect, mScalingMode, mTransform ^ mStickyTransform, mSwapIntervalZero,
             fence, mStickyTransform);
     status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
     if (err != OK)  {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index edfed49..64714cd 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -1020,11 +1020,28 @@
         SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects);
         visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data());
     }
+
     virtual void setSidebandStream(const sp<NativeHandle>& stream) {
         ALOG_ASSERT(stream->handle() != NULL);
         getLayer()->compositionType = HWC_SIDEBAND;
         getLayer()->sidebandStream = stream->handle();
     }
+
+    virtual void setDirtyRect(const Rect& dirtyRect) {
+        Rect srcCrop;
+        srcCrop.left = int(ceilf(getLayer()->sourceCropf.left));
+        srcCrop.right = int(ceilf(getLayer()->sourceCropf.right));
+        srcCrop.top = int(ceilf(getLayer()->sourceCropf.top));
+        srcCrop.bottom = int(ceilf(getLayer()->sourceCropf.bottom));
+
+        /* DirtyRect is generated for the full buffer resolution. Crop the value
+         * for the hwc_layer_1_t::sourceCrop resolution before sending to HWC.
+         */
+        Rect finalDR;
+        srcCrop.intersect(dirtyRect, &finalDR);
+        getLayer()->dirtyRect = reinterpret_cast<hwc_rect_t const&>(finalDR);
+    }
+
     virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
         if (buffer == 0 || buffer->handle == 0) {
             getLayer()->compositionType = HWC_FRAMEBUFFER;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 5cb56a0..9e21909 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -169,6 +169,7 @@
         virtual void setCrop(const FloatRect& crop) = 0;
         virtual void setVisibleRegionScreen(const Region& reg) = 0;
         virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
+        virtual void setDirtyRect(const Rect& dirtyRect) = 0;
         virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
         virtual void setAcquireFenceFd(int fenceFd) = 0;
         virtual void setPlaneAlpha(uint8_t alpha) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index c3d45ee..a154493 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -458,7 +458,7 @@
         uint32_t transform;
         bool async;
         input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode,
-                &transform, &async, &mFbFence);
+               &transform, &async, &mFbFence);
 
         mFbProducerSlot = pslot;
         mOutputFence = mFbFence;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index fa07656..03e1ea4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -80,7 +80,8 @@
         mProtectedByApp(false),
         mHasSurface(false),
         mClientRef(client),
-        mPotentialCursor(false)
+        mPotentialCursor(false),
+        mTransformHint(0)
 {
     mCurrentCrop.makeInvalid();
     mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -474,6 +475,55 @@
         // layer yet, or if we ran out of memory
         layer.setBuffer(mActiveBuffer);
     }
+
+    Rect dirtyRect =  mSurfaceFlingerConsumer->getCurrentDirtyRect();
+    if((mActiveBuffer != NULL) && mTransformHint &&
+       (mTransformHint != NATIVE_WINDOW_TRANSFORM_FLIP_H) &&
+       (mTransformHint != NATIVE_WINDOW_TRANSFORM_FLIP_V)) {
+        /* DirtyRect is generated by HWR without any knowledge of GPU
+         * pre-rotation. In case of pre-rotation, dirtyRect needs to be rotated
+         * accordingly.
+         *
+         * TODO: Generate and update dirtyRect from EGL and remove this code.
+         */
+
+        Rect srcRect = mActiveBuffer->getBounds();
+        Rect tempDR = dirtyRect;
+        int srcW = srcRect.getWidth();
+        int srcH = srcRect.getHeight();
+
+        if(mTransformHint & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+            swap(srcW, srcH);
+        }
+
+        int setOffsetW = -srcW/2;
+        int setOffsetH = -srcH/2;
+
+        int resetOffsetW = srcW/2;
+        int resetOffsetH = srcH/2;
+
+        if(mTransformHint & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+            swap(resetOffsetW, resetOffsetH);
+        }
+
+        /* - Move 2D space origin to srcRect origin.
+         * - Rotate
+         * - Move back the origin
+         */
+        Transform setOrigin;
+        setOrigin.set(setOffsetW, setOffsetH);
+        tempDR = setOrigin.transform(tempDR);
+        Transform rotate(mTransformHint);
+        tempDR = rotate.transform(tempDR);
+        Transform resetOrigin;
+        resetOrigin.set(resetOffsetW, resetOffsetH);
+        dirtyRect = resetOrigin.transform(tempDR);
+    }
+    layer.setDirtyRect(dirtyRect);
+
+    // NOTE: buffer can be NULL if the client never drew into this
+    // layer yet, or if we ran out of memory
+    layer.setBuffer(mActiveBuffer);
 }
 
 void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
@@ -1260,7 +1310,7 @@
     return usage;
 }
 
-void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {
+void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) {
     uint32_t orientation = 0;
     if (!mFlinger->mDebugDisableTransformHint) {
         // The transform hint is used to improve performance, but we can
@@ -1273,6 +1323,7 @@
         }
     }
     mSurfaceFlingerConsumer->setTransformHint(orientation);
+    mTransformHint = orientation;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f0fe58a..8804d9c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -273,7 +273,7 @@
 
     // Updates the transform hint in our SurfaceFlingerConsumer to match
     // the current orientation of the display device.
-    void updateTransformHint(const sp<const DisplayDevice>& hw) const;
+    void updateTransformHint(const sp<const DisplayDevice>& hw);
 
     /*
      * returns the rectangle that crops the content of the layer and scales it
@@ -403,6 +403,9 @@
 
     // This layer can be a cursor on some displays.
     bool mPotentialCursor;
+
+    // Transform hint assigned for the layer
+    uint32_t mTransformHint;
 };
 
 // ---------------------------------------------------------------------------