Add initial OpReorderer benchmarks

Change-Id: I6ca8ea89be2159331b2ad7031769c65f54161918
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 1a43658..842f575 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -263,4 +263,9 @@
     microbench/DisplayListCanvasBench.cpp \
     microbench/LinearAllocatorBench.cpp
 
+ifeq (true, $(HWUI_NEW_OPS))
+    LOCAL_SRC_FILES += \
+        microbench/OpReordererBench.cpp
+endif
+
 include $(BUILD_EXECUTABLE)
diff --git a/libs/hwui/microbench/OpReordererBench.cpp b/libs/hwui/microbench/OpReordererBench.cpp
new file mode 100644
index 0000000..4c8dedf
--- /dev/null
+++ b/libs/hwui/microbench/OpReordererBench.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <benchmark/Benchmark.h>
+
+#include "BakedOpState.h"
+#include "BakedOpRenderer.h"
+#include "OpReorderer.h"
+#include "RecordedOp.h"
+#include "RecordingCanvas.h"
+#include "unit_tests/TestUtils.h"
+#include "microbench/MicroBench.h"
+
+#include <vector>
+
+using namespace android;
+using namespace android::uirenderer;
+
+auto sReorderingDisplayList = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+    SkBitmap bitmap = TestUtils::createSkBitmap(10, 10);
+    SkPaint paint;
+
+    // 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.
+    canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    for (int i = 0; i < 30; i++) {
+        canvas.translate(0, 10);
+        canvas.drawRect(0, 0, 10, 10, paint);
+        canvas.drawBitmap(bitmap, 5, 0, nullptr);
+    }
+    canvas.restore();
+});
+
+BENCHMARK_NO_ARG(BM_OpReorderer_defer);
+void BM_OpReorderer_defer::Run(int iters) {
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; i++) {
+        OpReorderer reorderer;
+        reorderer.defer(200, 200, *sReorderingDisplayList);
+        MicroBench::DoNotOptimize(&reorderer);
+    }
+    StopBenchmarkTiming();
+}
+
+BENCHMARK_NO_ARG(BM_OpReorderer_deferAndRender);
+void BM_OpReorderer_deferAndRender::Run(int iters) {
+    TestUtils::runOnRenderThread([this, iters](RenderState& renderState, Caches& caches) {
+        StartBenchmarkTiming();
+        for (int i = 0; i < iters; i++) {
+            OpReorderer reorderer;
+            reorderer.defer(200, 200, *sReorderingDisplayList);
+            MicroBench::DoNotOptimize(&reorderer);
+
+            BakedOpRenderer::Info info(caches, renderState, 200, 200, true);
+            reorderer.replayBakedOps<BakedOpRenderer>(&info);
+        }
+        StopBenchmarkTiming();
+    });
+}
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 26aae90..15ccd6a 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -574,12 +574,7 @@
     RenderThread& thread = RenderThread::getInstance();
     void* retval;
     task->setReturnPtr(&retval);
-    Mutex mutex;
-    Condition condition;
-    SignalingRenderTask syncTask(task, &mutex, &condition);
-    AutoMutex _lock(mutex);
-    thread.queue(&syncTask);
-    condition.wait(mutex);
+    thread.queueAndWait(task);
     return retval;
 }
 
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 64075f1..8fcd109 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -312,6 +312,16 @@
     }
 }
 
+void RenderThread::queueAndWait(RenderTask* task) {
+    Mutex mutex;
+    Condition condition;
+    SignalingRenderTask syncTask(task, &mutex, &condition);
+
+    AutoMutex _lock(mutex);
+    queue(&syncTask);
+    condition.wait(mutex);
+}
+
 void RenderThread::queueAtFront(RenderTask* task) {
     AutoMutex _lock(mLock);
     mQueue.queueAtFront(task);
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 8096099..f3444a8 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -39,6 +39,7 @@
 namespace uirenderer {
 
 class RenderState;
+class TestUtils;
 
 namespace renderthread {
 
@@ -76,6 +77,7 @@
     // RenderThread takes complete ownership of tasks that are queued
     // and will delete them after they are run
     ANDROID_API void queue(RenderTask* task);
+    ANDROID_API void queueAndWait(RenderTask* task);
     ANDROID_API void queueAtFront(RenderTask* task);
     void queueAt(RenderTask* task, nsecs_t runAtNs);
     void remove(RenderTask* task);
@@ -101,6 +103,7 @@
     friend class Singleton<RenderThread>;
     friend class DispatchFrameCallbacks;
     friend class RenderProxy;
+    friend class android::uirenderer::TestUtils;
 
     RenderThread();
     virtual ~RenderThread();
diff --git a/libs/hwui/unit_tests/TestUtils.h b/libs/hwui/unit_tests/TestUtils.h
index bb58928..80d83a2 100644
--- a/libs/hwui/unit_tests/TestUtils.h
+++ b/libs/hwui/unit_tests/TestUtils.h
@@ -17,8 +17,11 @@
 #define TEST_UTILS_H
 
 #include <Matrix.h>
-#include <Snapshot.h>
+#include <Rect.h>
 #include <RenderNode.h>
+#include <renderstate/RenderState.h>
+#include <renderthread/RenderThread.h>
+#include <Snapshot.h>
 
 #include <memory>
 
@@ -48,7 +51,9 @@
 
     static SkBitmap createSkBitmap(int width, int height) {
         SkBitmap bitmap;
-        bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
+        SkImageInfo info = SkImageInfo::MakeUnknown(width, height);
+        bitmap.setInfo(info);
+        bitmap.allocPixels(info);
         return bitmap;
     }
 
@@ -78,6 +83,32 @@
         node->syncProperties();
         node->syncDisplayList();
     }
+
+    typedef std::function<void(RenderState& state, Caches& caches)> RtCallback;
+
+    class TestTask : public renderthread::RenderTask {
+    public:
+        TestTask(RtCallback rtCallback)
+                : rtCallback(rtCallback) {}
+        virtual ~TestTask() {}
+        virtual void run() override {
+            // RenderState only valid once RenderThread is running, so queried here
+            RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
+
+            renderState.onGLContextCreated();
+            rtCallback(renderState, Caches::getInstance());
+            renderState.onGLContextDestroyed();
+        };
+        RtCallback rtCallback;
+    };
+
+    /**
+     * NOTE: requires surfaceflinger to run, otherwise this method will wait indefinitely.
+     */
+    static void runOnRenderThread(RtCallback rtCallback) {
+        TestTask task(rtCallback);
+        renderthread::RenderThread::getInstance().queueAndWait(&task);
+    }
 }; // class TestUtils
 
 } /* namespace uirenderer */