diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 1a4365806a1bb..842f575553a5a 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -263,4 +263,9 @@ LOCAL_SRC_FILES += \ 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 0000000000000..4c8dedfa5a15f --- /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 + +#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 + +using namespace android; +using namespace android::uirenderer; + +auto sReorderingDisplayList = TestUtils::createDisplayList(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(&info); + } + StopBenchmarkTiming(); + }); +} diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 26aae90d59906..15ccd6ac5b6bc 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -574,12 +574,7 @@ void* RenderProxy::staticPostAndWait(MethodInvokeRenderTask* task) { 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 64075f1c346a6..8fcd10967e179 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -312,6 +312,16 @@ void RenderThread::queue(RenderTask* task) { } } +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 80960999ef539..f3444a85a3360 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -39,6 +39,7 @@ class DisplayEventReceiver; namespace uirenderer { class RenderState; +class TestUtils; namespace renderthread { @@ -76,6 +77,7 @@ public: // 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 @@ private: friend class Singleton; 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 bb5892867b6de..80d83a2e47a13 100644 --- a/libs/hwui/unit_tests/TestUtils.h +++ b/libs/hwui/unit_tests/TestUtils.h @@ -17,8 +17,11 @@ #define TEST_UTILS_H #include -#include +#include #include +#include +#include +#include #include @@ -48,7 +51,9 @@ public: 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 @@ public: node->syncProperties(); node->syncDisplayList(); } + + typedef std::function 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 */