Add partial damage support to new draw path

Change-Id: I612578fd181240de71297c9a28bc9a8f350764a7
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index 1d8be2b..2e02306 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -212,10 +212,11 @@
         : mCanvasState(sNullClient) {
 }
 
-void OpReorderer::defer(int viewportWidth, int viewportHeight,
+void OpReorderer::defer(const SkRect& clip, int viewportWidth, int viewportHeight,
         const std::vector< sp<RenderNode> >& nodes) {
     mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
-            0, 0, viewportWidth, viewportHeight, Vector3());
+            clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
+            Vector3());
     for (const sp<RenderNode>& node : nodes) {
         if (node->nothingToDraw()) continue;
 
@@ -325,7 +326,7 @@
 // if no target, merging ops still interate to find similar batch to insert after
 void OpReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds,
         BatchBase** targetBatch, size_t* insertBatchIndex) const {
-    for (size_t i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) {
+    for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) {
         BatchBase* overBatch = mBatches[i];
 
         if (overBatch == *targetBatch) break;
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index b99172c..395a1ba 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -25,6 +25,8 @@
 #include <vector>
 #include <unordered_map>
 
+struct SkRect;
+
 namespace android {
 namespace uirenderer {
 
@@ -57,7 +59,8 @@
     OpReorderer();
 
     // TODO: not final, just presented this way for simplicity. Layers too?
-    void defer(int viewportWidth, int viewportHeight, const std::vector< sp<RenderNode> >& nodes);
+    void defer(const SkRect& clip, int viewportWidth, int viewportHeight,
+            const std::vector< sp<RenderNode> >& nodes);
 
     void defer(int viewportWidth, int viewportHeight,
             const std::vector<DisplayListData::Chunk>& chunks, const std::vector<RecordedOp*>& ops);
@@ -133,7 +136,7 @@
     // contains ResolvedOps and Batches
     LinearAllocator mAllocator;
 
-    size_t mEarliestBatchIndex = 0;
+    int mEarliestBatchIndex = 0;
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e1d8abd..238cf06 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -266,11 +266,11 @@
 
     Frame frame = mEglManager.beginFrame(mEglSurface);
 
-#if !HWUI_NEW_OPS
-    if (frame.width() != mCanvas->getViewportWidth()
-            || frame.height() != mCanvas->getViewportHeight()) {
+    if (frame.width() != lastFrameWidth || frame.height() != lastFrameHeight) {
         // can't rely on prior content of window if viewport size changes
         dirty.setEmpty();
+        lastFrameWidth = frame.width();
+        lastFrameHeight = frame.height();
     } else if (mHaveNewSurface || frame.bufferAge() == 0) {
         // New surface needs a full draw
         dirty.setEmpty();
@@ -316,6 +316,18 @@
     mDamageHistory.next() = screenDirty;
 
     mEglManager.damageFrame(frame, dirty);
+
+#if HWUI_NEW_OPS
+    OpReorderer reorderer;
+    reorderer.defer(dirty, frame.width(), frame.height(), mRenderNodes);
+    BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(),
+            frame.width(), frame.height(), mOpaque);
+    // TODO: profiler().draw(mCanvas);
+    reorderer.replayBakedOps<BakedOpRenderer>(&info);
+
+    bool drew = info.didDraw;
+
+#else
     mCanvas->prepareDirty(frame.width(), frame.height(),
             dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque);
 
@@ -426,20 +438,10 @@
     profiler().draw(mCanvas);
 
     bool drew = mCanvas->finish();
-
+#endif
     // Even if we decided to cancel the frame, from the perspective of jank
     // metrics the frame was swapped at this point
     mCurrentFrameInfo->markSwapBuffers();
-#else
-    OpReorderer reorderer;
-    reorderer.defer(frame.width(), frame.height(), mRenderNodes);
-    BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(),
-            frame.width(), frame.height(), mOpaque);
-    reorderer.replayBakedOps<BakedOpRenderer>(&info);
-
-    bool drew = info.didDraw;
-    SkRect screenDirty = SkRect::MakeWH(frame.width(), frame.height());
-#endif
 
     if (drew) {
         if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index e0cbabd..16956e6 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -141,6 +141,9 @@
 
     void freePrefetechedLayers();
 
+    int lastFrameWidth = 0;
+    int lastFrameHeight = 0;
+
     RenderThread& mRenderThread;
     EglManager& mEglManager;
     sp<ANativeWindow> mNativeWindow;
diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp
index fcaea1e..cbfbb23 100644
--- a/libs/hwui/unit_tests/OpReordererTests.cpp
+++ b/libs/hwui/unit_tests/OpReordererTests.cpp
@@ -50,9 +50,7 @@
 };
 TEST(OpReorderer, simple) {
     auto dld = TestUtils::createDLD<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
-        SkBitmap bitmap;
-        bitmap.setInfo(SkImageInfo::MakeUnknown(25, 25));
-
+        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
         canvas.drawRect(0, 0, 100, 200, SkPaint());
         canvas.drawBitmap(bitmap, 10, 10, nullptr);
     });
@@ -81,8 +79,7 @@
 };
 TEST(OpReorderer, simpleBatching) {
     auto dld = TestUtils::createDLD<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
-        SkBitmap bitmap;
-        bitmap.setInfo(SkImageInfo::MakeUnknown(10, 10));
+        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10);
 
         // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
         // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
@@ -134,14 +131,14 @@
 
     RenderNode* childPtr = child.get();
     sp<RenderNode> parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [childPtr](RecordingCanvas& canvas) {
-            SkPaint paint;
-            paint.setColor(SK_ColorDKGRAY);
-            canvas.drawRect(0, 0, 200, 200, paint);
+        SkPaint paint;
+        paint.setColor(SK_ColorDKGRAY);
+        canvas.drawRect(0, 0, 200, 200, paint);
 
-            canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-            canvas.translate(40, 40);
-            canvas.drawRenderNode(childPtr);
-            canvas.restore();
+        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        canvas.translate(40, 40);
+        canvas.drawRenderNode(childPtr);
+        canvas.restore();
     });
 
     TestUtils::syncNodePropertiesAndDisplayList(child);
@@ -151,11 +148,42 @@
     nodes.push_back(parent.get());
 
     OpReorderer reorderer;
-    reorderer.defer(200, 200, nodes);
+    reorderer.defer(SkRect::MakeWH(200, 200), 200, 200, nodes);
 
     Info info;
     reorderer.replayBakedOps<RenderNodeReceiver>(&info);
 }
 
+class ClippedReceiver {
+public:
+    static void onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) {
+        EXPECT_EQ(0, info->index++);
+        EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
+        EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
+        EXPECT_TRUE(state.computedState.transform.isIdentity());
+    }
+    UNSUPPORTED_OP(Info, RectOp)
+    UNSUPPORTED_OP(Info, RenderNodeOp)
+    UNSUPPORTED_OP(Info, SimpleRectsOp)
+    static void startFrame(Info& info) {}
+    static void endFrame(Info& info) {}
+};
+TEST(OpReorderer, clipped) {
+    sp<RenderNode> node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RecordingCanvas& canvas) {
+        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
+        canvas.drawBitmap(bitmap, 0, 0, nullptr);
+    });
+    TestUtils::syncNodePropertiesAndDisplayList(node);
+    std::vector< sp<RenderNode> > nodes;
+    nodes.push_back(node.get());
+
+    OpReorderer reorderer;
+    reorderer.defer(SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
+            200, 200, nodes);
+
+    Info info;
+    reorderer.replayBakedOps<ClippedReceiver>(&info);
+}
+
 }
 }
diff --git a/libs/hwui/unit_tests/TestUtils.h b/libs/hwui/unit_tests/TestUtils.h
index 257dd28..9b7d1b9 100644
--- a/libs/hwui/unit_tests/TestUtils.h
+++ b/libs/hwui/unit_tests/TestUtils.h
@@ -46,6 +46,12 @@
         return snapshot;
     }
 
+    static SkBitmap createSkBitmap(int width, int height) {
+        SkBitmap bitmap;
+        bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
+        return bitmap;
+    }
+
     template<class CanvasType>
     static std::unique_ptr<DisplayListData> createDLD(int width, int height,
             std::function<void(CanvasType& canvas)> canvasCallback) {