Merged op dispatch in OpReorderer

bug:22480459

Also switches std::functions to function pointers on OpReorderer, and
switches AssetAtlas' entry getter methods to using pixelRef pointers,
so it's clear they're the keys.

Change-Id: I3040ce5ff4e178a8364e0fd7ab0876ada7d4de05
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index 9cbd9c2d..9460361 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -202,6 +202,9 @@
         if (newClipSideFlags & OpClipSideFlags::Bottom) mClipRect.bottom = opClip.bottom;
     }
 
+    bool getClipSideFlags() const { return mClipSideFlags; }
+    const Rect& getClipRect() const { return mClipRect; }
+
 private:
     int mClipSideFlags = 0;
     Rect mClipRect;
@@ -291,12 +294,31 @@
     }
 }
 
-void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const {
+void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg,
+        BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const {
     ATRACE_NAME("flush drawing commands");
     for (const BatchBase* batch : mBatches) {
-        // TODO: different behavior based on batch->isMerging()
-        for (const BakedOpState* op : batch->getOps()) {
-            receivers[op->op->opId](arg, *op->op, *op);
+        size_t size = batch->getOps().size();
+        if (size > 1 && batch->isMerging()) {
+            int opId = batch->getOps()[0]->op->opId;
+            const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch);
+            MergedBakedOpList data = {
+                    batch->getOps().data(),
+                    size,
+                    mergingBatch->getClipSideFlags(),
+                    mergingBatch->getClipRect()
+            };
+            if (data.clipSideFlags) {
+                // if right or bottom sides aren't used to clip, init them to viewport bounds
+                // in the clip rect, so it can be used to scissor
+                if (!(data.clipSideFlags & OpClipSideFlags::Right)) data.clip.right = width;
+                if (!(data.clipSideFlags & OpClipSideFlags::Bottom)) data.clip.bottom = height;
+            }
+            mergedReceivers[opId](arg, data);
+        } else {
+            for (const BakedOpState* op : batch->getOps()) {
+                unmergedReceivers[op->op->opId](arg, *op);
+            }
         }
     }
 }
@@ -639,7 +661,8 @@
 #define OP_RECEIVER(Type) \
         [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); },
 void OpReorderer::deferNodeOps(const RenderNode& renderNode) {
-    static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = {
+    typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op);
+    static OpDispatcher receivers[] = {
         MAP_OPS(OP_RECEIVER)
     };
 
@@ -692,42 +715,57 @@
 }
 
 void OpReorderer::onBitmapOp(const BitmapOp& op) {
-    BakedOpState* bakedStateOp = tryBakeOpState(op);
-    if (!bakedStateOp) return; // quick rejected
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
 
-    mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID();
-    // TODO: AssetAtlas
-    currentLayer().deferMergeableOp(mAllocator, bakedStateOp, OpBatchType::Bitmap, mergeId);
+    // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
+    // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
+    // MergingDrawBatch::canMergeWith()
+    if (bakedState->computedState.transform.isSimple()
+            && bakedState->computedState.transform.positiveScale()
+            && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode
+            && op.bitmap->colorType() != kAlpha_8_SkColorType) {
+        mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID();
+        // TODO: AssetAtlas in mergeId
+        currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId);
+    } else {
+        currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+    }
 }
 
 void OpReorderer::onLinesOp(const LinesOp& op) {
-    BakedOpState* bakedStateOp = tryBakeOpState(op);
-    if (!bakedStateOp) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, OpBatchType::Vertices);
-
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, tessellatedBatchId(*op.paint));
 }
 
 void OpReorderer::onRectOp(const RectOp& op) {
-    BakedOpState* bakedStateOp = tryBakeOpState(op);
-    if (!bakedStateOp) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, tessellatedBatchId(*op.paint));
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, tessellatedBatchId(*op.paint));
 }
 
 void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) {
-    BakedOpState* bakedStateOp = tryBakeOpState(op);
-    if (!bakedStateOp) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, OpBatchType::Vertices);
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
 }
 
 void OpReorderer::onTextOp(const TextOp& op) {
-    BakedOpState* bakedStateOp = tryBakeOpState(op);
-    if (!bakedStateOp) return; // quick rejected
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
 
     // TODO: better handling of shader (since we won't care about color then)
     batchid_t batchId = op.paint->getColor() == SK_ColorBLACK
             ? OpBatchType::Text : OpBatchType::ColorText;
-    mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor());
-    currentLayer().deferMergeableOp(mAllocator, bakedStateOp, batchId, mergeId);
+
+    if (bakedState->computedState.transform.isPureTranslate()
+            && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) {
+        mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor());
+        currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId);
+    } else {
+        currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
+    }
 }
 
 void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,