summaryrefslogtreecommitdiff
path: root/libs/hwui/tests
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/tests')
-rw-r--r--libs/hwui/tests/common/LeakChecker.cpp94
-rw-r--r--libs/hwui/tests/common/LeakChecker.h29
-rw-r--r--libs/hwui/tests/common/TestContext.cpp51
-rw-r--r--libs/hwui/tests/common/TestContext.h18
-rw-r--r--libs/hwui/tests/common/TestListViewSceneBase.cpp78
-rw-r--r--libs/hwui/tests/common/TestListViewSceneBase.h44
-rw-r--r--libs/hwui/tests/common/TestScene.h14
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp24
-rw-r--r--libs/hwui/tests/common/TestUtils.h15
-rw-r--r--libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp60
-rw-r--r--libs/hwui/tests/common/scenes/ListViewAnimation.cpp116
-rw-r--r--libs/hwui/tests/common/scenes/TestSceneBase.h7
-rw-r--r--libs/hwui/tests/macrobench/TestSceneRunner.cpp73
-rw-r--r--libs/hwui/tests/macrobench/main.cpp83
-rw-r--r--libs/hwui/tests/microbench/DisplayListCanvasBench.cpp42
-rw-r--r--libs/hwui/tests/microbench/TaskManagerBench.cpp2
-rwxr-xr-xlibs/hwui/tests/microbench/how_to_run.txt5
-rw-r--r--libs/hwui/tests/microbench/main.cpp15
-rwxr-xr-xlibs/hwui/tests/scripts/prep_buller.sh49
-rwxr-xr-xlibs/hwui/tests/scripts/prep_volantis.sh10
-rw-r--r--libs/hwui/tests/scripts/stopruntime.sh27
-rw-r--r--libs/hwui/tests/unit/FrameBuilderTests.cpp4
-rw-r--r--libs/hwui/tests/unit/GlopBuilderTests.cpp6
-rw-r--r--libs/hwui/tests/unit/MeshStateTests.cpp36
-rw-r--r--libs/hwui/tests/unit/RecordingCanvasTests.cpp4
-rw-r--r--libs/hwui/tests/unit/RenderNodeTests.cpp9
-rw-r--r--libs/hwui/tests/unit/main.cpp80
28 files changed, 752 insertions, 247 deletions
diff --git a/libs/hwui/tests/common/LeakChecker.cpp b/libs/hwui/tests/common/LeakChecker.cpp
new file mode 100644
index 000000000000..d935382cc9a4
--- /dev/null
+++ b/libs/hwui/tests/common/LeakChecker.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 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 "LeakChecker.h"
+
+#include "Caches.h"
+#include "TestUtils.h"
+
+#include <cstdio>
+#include <iostream>
+#include <memunreachable/memunreachable.h>
+#include <unistd.h>
+#include <unordered_set>
+
+using namespace std;
+
+namespace android {
+namespace uirenderer {
+namespace test {
+
+static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) {
+ // merge them all
+ UnreachableMemoryInfo merged;
+ unordered_set<uintptr_t> addrs;
+ merged.allocation_bytes = 0;
+ merged.leak_bytes = 0;
+ merged.num_allocations = 0;
+ merged.num_leaks = 0;
+ for (auto& info : infolist) {
+ // We'll be a little hazzy about these ones and just hope the biggest
+ // is the most accurate
+ merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes);
+ merged.num_allocations = max(merged.num_allocations, info.num_allocations);
+ for (auto& leak : info.leaks) {
+ if (addrs.find(leak.begin) == addrs.end()) {
+ merged.leaks.push_back(leak);
+ merged.num_leaks++;
+ merged.leak_bytes += leak.size;
+ addrs.insert(leak.begin);
+ }
+ }
+ }
+
+ // Now log the result
+ if (merged.num_leaks) {
+ cout << endl << "Leaked memory!" << endl;
+ if (!merged.leaks[0].backtrace.num_frames) {
+ cout << "Re-run with 'setprop libc.debug.malloc.program hwui_unit_test'"
+ << endl << "and 'setprop libc.debug.malloc.options backtrace=8'"
+ << " to get backtraces" << endl;
+ }
+ cout << merged.ToString(false);
+ }
+}
+
+void LeakChecker::checkForLeaks() {
+ // TODO: Until we can shutdown the RT thread we need to do this in
+ // two passes as GetUnreachableMemory has limited insight into
+ // thread-local caches so some leaks will not be properly tagged as leaks
+ UnreachableMemoryInfo rtMemInfo;
+ TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().tasks.stop();
+ }
+ // Check for leaks
+ if (!GetUnreachableMemory(rtMemInfo)) {
+ cerr << "Failed to get unreachable memory!" << endl;
+ return;
+ }
+ });
+ UnreachableMemoryInfo uiMemInfo;
+ if (!GetUnreachableMemory(uiMemInfo)) {
+ cerr << "Failed to get unreachable memory!" << endl;
+ return;
+ }
+ logUnreachable({rtMemInfo, uiMemInfo});
+}
+
+} /* namespace test */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/tests/common/LeakChecker.h b/libs/hwui/tests/common/LeakChecker.h
new file mode 100644
index 000000000000..cdf47d6bda80
--- /dev/null
+++ b/libs/hwui/tests/common/LeakChecker.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#pragma once
+
+namespace android {
+namespace uirenderer {
+namespace test {
+
+class LeakChecker {
+public:
+ static void checkForLeaks();
+}; // class TestUtils
+
+} /* namespace test */
+} /* namespace uirenderer */
+} /* namespace android */ \ No newline at end of file
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index 146e735839d1..1c7e7eef7626 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -62,20 +62,53 @@ TestContext::TestContext() {
TestContext::~TestContext() {}
sp<Surface> TestContext::surface() {
- if (!mSurfaceControl.get()) {
- mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"),
- gDisplay.w, gDisplay.h, PIXEL_FORMAT_RGBX_8888);
-
- SurfaceComposerClient::openGlobalTransaction();
- mSurfaceControl->setLayer(0x7FFFFFF);
- mSurfaceControl->show();
- SurfaceComposerClient::closeGlobalTransaction();
+ if (!mSurface.get()) {
+ createSurface();
}
+ return mSurface;
+}
+
+void TestContext::createSurface() {
+ if (mRenderOffscreen) {
+ createOffscreenSurface();
+ } else {
+ createWindowSurface();
+ }
+}
- return mSurfaceControl->getSurface();
+void TestContext::createWindowSurface() {
+ mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"),
+ gDisplay.w, gDisplay.h, PIXEL_FORMAT_RGBX_8888);
+
+ SurfaceComposerClient::openGlobalTransaction();
+ mSurfaceControl->setLayer(0x7FFFFFF);
+ mSurfaceControl->show();
+ SurfaceComposerClient::closeGlobalTransaction();
+ mSurface = mSurfaceControl->getSurface();
+}
+
+void TestContext::createOffscreenSurface() {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ producer->setMaxDequeuedBufferCount(3);
+ producer->setAsyncMode(true);
+ mConsumer = new BufferItemConsumer(consumer, GRALLOC_USAGE_HW_COMPOSER, 4);
+ mConsumer->setDefaultBufferSize(gDisplay.w, gDisplay.h);
+ mSurface = new Surface(producer);
}
void TestContext::waitForVsync() {
+ if (mConsumer.get()) {
+ BufferItem buffer;
+ if (mConsumer->acquireBuffer(&buffer, 0, false) == OK) {
+ // We assume the producer is internally ordered enough such that
+ // it is unneccessary to set a release fence
+ mConsumer->releaseBuffer(buffer);
+ }
+ // We running free, go go go!
+ return;
+ }
#if !HWUI_NULL_GPU
// Request vsync
mDisplayEventReceiver.requestNextVsync();
diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h
index 2bbe5dffd9b8..312988b968de 100644
--- a/libs/hwui/tests/common/TestContext.h
+++ b/libs/hwui/tests/common/TestContext.h
@@ -19,12 +19,16 @@
#include <gui/DisplayEventReceiver.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/BufferItemConsumer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
#include <gui/Surface.h>
#include <ui/DisplayInfo.h>
#include <utils/Looper.h>
+#include <thread>
+#include <atomic>
+
namespace android {
namespace uirenderer {
namespace test {
@@ -39,15 +43,29 @@ public:
TestContext();
~TestContext();
+ // Must be called before surface();
+ void setRenderOffscreen(bool renderOffscreen) {
+ LOG_ALWAYS_FATAL_IF(mSurface.get(),
+ "Must be called before surface is created");
+ mRenderOffscreen = renderOffscreen;
+ }
+
sp<Surface> surface();
void waitForVsync();
private:
+ void createSurface();
+ void createWindowSurface();
+ void createOffscreenSurface();
+
sp<SurfaceComposerClient> mSurfaceComposerClient;
sp<SurfaceControl> mSurfaceControl;
+ sp<BufferItemConsumer> mConsumer;
DisplayEventReceiver mDisplayEventReceiver;
sp<Looper> mLooper;
+ sp<Surface> mSurface;
+ bool mRenderOffscreen;
};
} // namespace test
diff --git a/libs/hwui/tests/common/TestListViewSceneBase.cpp b/libs/hwui/tests/common/TestListViewSceneBase.cpp
new file mode 100644
index 000000000000..847a6ff1181d
--- /dev/null
+++ b/libs/hwui/tests/common/TestListViewSceneBase.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 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 "TestListViewSceneBase.h"
+
+#include "TestContext.h"
+#include "TestUtils.h"
+
+#include <utils/Color.h>
+
+namespace android {
+namespace uirenderer {
+namespace test {
+
+void TestListViewSceneBase::createContent(int width, int height, TestCanvas& canvas) {
+ srand(0);
+ mItemHeight = dp(60);
+ mItemSpacing = dp(16);
+ mItemWidth = std::min((height - mItemSpacing * 2), (int)dp(300));
+ mItemLeft = (width - mItemWidth) / 2;
+ int heightWithSpacing = mItemHeight + mItemSpacing;
+ for (int y = 0; y < height + (heightWithSpacing - 1); y += heightWithSpacing) {
+ int id = mListItems.size();
+ auto setup = std::bind(&TestListViewSceneBase::createListItem, this, std::placeholders::_1,
+ std::placeholders::_2, id, mItemWidth, mItemHeight);
+ auto node = TestUtils::createNode(mItemLeft, y, mItemLeft + mItemWidth,
+ y + mItemHeight, setup);
+ mListItems.push_back(node);
+ }
+ mListView = TestUtils::createNode(0, 0, width, height,
+ [this](RenderProperties& props, TestCanvas& canvas) {
+ for (size_t ci = 0; ci < mListItems.size(); ci++) {
+ canvas.drawRenderNode(mListItems[ci].get());
+ }
+ });
+
+ canvas.drawColor(Color::Grey_500, SkXfermode::kSrcOver_Mode);
+ canvas.drawRenderNode(mListView.get());
+}
+
+void TestListViewSceneBase::doFrame(int frameNr) {
+ int scrollPx = dp(frameNr) * 3;
+ int itemIndexOffset = scrollPx / (mItemSpacing + mItemHeight);
+ int pxOffset = -(scrollPx % (mItemSpacing + mItemHeight));
+
+ TestCanvas canvas(
+ mListView->stagingProperties().getWidth(),
+ mListView->stagingProperties().getHeight());
+ for (size_t ci = 0; ci < mListItems.size(); ci++) {
+ // update item position
+ auto listItem = mListItems[(ci + itemIndexOffset) % mListItems.size()];
+ int top = ((int)ci) * (mItemSpacing + mItemHeight) + pxOffset;
+ listItem->mutateStagingProperties().setLeftTopRightBottom(
+ mItemLeft, top, mItemLeft + mItemWidth, top + mItemHeight);
+ listItem->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+
+ // draw it to parent DisplayList
+ canvas.drawRenderNode(mListItems[ci].get());
+ }
+ mListView->setStagingDisplayList(canvas.finishRecording(), nullptr);
+}
+
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestListViewSceneBase.h b/libs/hwui/tests/common/TestListViewSceneBase.h
new file mode 100644
index 000000000000..8ffe9929bbd9
--- /dev/null
+++ b/libs/hwui/tests/common/TestListViewSceneBase.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#pragma once
+
+#include "TestScene.h"
+#include <RenderNode.h>
+#include <RenderProperties.h>
+
+namespace android {
+namespace uirenderer {
+namespace test {
+
+class TestListViewSceneBase : public TestScene {
+public:
+ virtual void createListItem(RenderProperties& props, TestCanvas& canvas, int id,
+ int itemWidth, int itemHeight) = 0;
+private:
+ int mItemHeight;
+ int mItemSpacing;
+ int mItemWidth;
+ int mItemLeft;
+ sp<RenderNode> mListView;
+ std::vector< sp<RenderNode> > mListItems;
+
+ void createContent(int width, int height, TestCanvas& canvas) override;
+ void doFrame(int frameNr) override;
+};
+
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index 706f2ff75222..4813ff0de174 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef TESTS_TESTSCENE_H
-#define TESTS_TESTSCENE_H
+
+#pragma once
#include <string>
#include <unordered_map>
@@ -22,14 +22,9 @@
namespace android {
namespace uirenderer {
class RenderNode;
-
-#if HWUI_NEW_OPS
class RecordingCanvas;
+
typedef RecordingCanvas TestCanvas;
-#else
-class DisplayListCanvas;
-typedef DisplayListCanvas TestCanvas;
-#endif
namespace test {
@@ -38,6 +33,7 @@ public:
struct Options {
int count = 0;
int reportFrametimeWeight = 0;
+ bool renderOffscreen = false;
};
template <class T>
@@ -75,5 +71,3 @@ public:
} // namespace test
} // namespace uirenderer
} // namespace android
-
-#endif /* TESTS_TESTSCENE_H */
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index c762eed616e4..930067a9b2cc 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -20,6 +20,9 @@
#include "DeferredLayerUpdater.h"
#include "LayerRenderer.h"
+#include <renderthread/EglManager.h>
+#include <utils/Unicode.h>
+
namespace android {
namespace uirenderer {
@@ -68,7 +71,10 @@ void TestUtils::layoutTextUnscaled(const SkPaint& paint, const char* text,
SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
while (*text != '\0') {
- SkUnichar unichar = SkUTF8_NextUnichar(&text);
+ size_t nextIndex = 0;
+ int32_t unichar = utf32_from_utf8_at(text, 4, 0, &nextIndex);
+ text += nextIndex;
+
glyph_t glyph = autoCache.getCache()->unicharToGlyph(unichar);
autoCache.getCache()->unicharToGlyph(unichar);
@@ -107,12 +113,18 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text,
void TestUtils::TestTask::run() {
// RenderState only valid once RenderThread is running, so queried here
- RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
+ renderthread::RenderThread& renderThread = renderthread::RenderThread::getInstance();
+ bool hasEglContext = renderThread.eglManager().hasEglContext();
+ RenderState& renderState = renderThread.renderState();
+ if (!hasEglContext) {
+ renderState.onGLContextCreated();
+ }
- renderState.onGLContextCreated();
- rtCallback(renderthread::RenderThread::getInstance());
- renderState.flush(Caches::FlushMode::Full);
- renderState.onGLContextDestroyed();
+ rtCallback(renderThread);
+ if (!hasEglContext) {
+ renderState.flush(Caches::FlushMode::Full);
+ renderState.onGLContextDestroyed();
+ }
}
std::unique_ptr<uint16_t[]> TestUtils::asciiToUtf16(const char* str) {
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 4536bef6d391..9f7fee262acf 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef TEST_UTILS_H
-#define TEST_UTILS_H
+
+#pragma once
#include <DeviceInfo.h>
#include <DisplayList.h>
@@ -25,24 +25,15 @@
#include <renderthread/RenderThread.h>
#include <Snapshot.h>
-#if HWUI_NEW_OPS
#include <RecordedOp.h>
#include <RecordingCanvas.h>
-#else
-#include <DisplayListOp.h>
-#include <DisplayListCanvas.h>
-#endif
#include <memory>
namespace android {
namespace uirenderer {
-#if HWUI_NEW_OPS
typedef RecordingCanvas TestCanvas;
-#else
-typedef DisplayListCanvas TestCanvas;
-#endif
#define EXPECT_MATRIX_APPROX_EQ(a, b) \
EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b))
@@ -251,5 +242,3 @@ private:
} /* namespace uirenderer */
} /* namespace android */
-
-#endif /* TEST_UTILS_H */
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
index f184411b4139..a61f6d0f1e7c 100644
--- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -17,8 +17,8 @@
#include "TestSceneBase.h"
#include "utils/Color.h"
-#include <minikin/Layout.h>
#include <hwui/Paint.h>
+#include <minikin/Layout.h>
#include <cstdio>
@@ -56,7 +56,7 @@ public:
for (int i = 0; i < 5; i++) {
paint.setTextSize(10 + (frameNr % 20) + i * 20);
canvas.drawText(text.get(), 0, textLength, textLength,
- 0, 100 * (i + 2), kBidi_Force_LTR, paint, nullptr);
+ 0, 100 * (i + 2), minikin::kBidi_Force_LTR, paint, nullptr);
}
container->setStagingDisplayList(canvas.finishRecording(), nullptr);
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
new file mode 100644
index 000000000000..ba6074fa7840
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 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 "TestSceneBase.h"
+#include "tests/common/TestListViewSceneBase.h"
+
+#include <SkGradientShader.h>
+
+class ListOfFadedTextAnimation;
+
+static TestScene::Registrar _ListOfFadedTextAnimation(TestScene::Info{
+ "fadingedges",
+ "A mock ListView of scrolling text with faded edge. Doesn't re-bind/re-record views"
+ "as they are recycled, so won't upload much content (either glyphs, or bitmaps).",
+ TestScene::simpleCreateScene<ListOfFadedTextAnimation>
+});
+
+class ListOfFadedTextAnimation : public TestListViewSceneBase {
+ void createListItem(RenderProperties& props, TestCanvas& canvas, int id,
+ int itemWidth, int itemHeight) override {
+ canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
+ int length = dp(100);
+ canvas.saveLayer(0, 0, length, itemHeight, nullptr, SaveFlags::HasAlphaLayer);
+ SkPaint textPaint;
+ textPaint.setTextSize(dp(20));
+ textPaint.setAntiAlias(true);
+ TestUtils::drawUtf8ToCanvas(&canvas, "not that long long text", textPaint, dp(10), dp(30));
+
+ SkPoint pts[2];
+ pts[0].set(0, 0);
+ pts[1].set(0, 1);
+
+ SkColor colors[2] = {Color::Black, Color::Transparent};
+ SkAutoTUnref<SkShader> s(SkGradientShader::CreateLinear(pts, colors, NULL, 2,
+ SkShader::kClamp_TileMode));
+
+ SkMatrix matrix;
+ matrix.setScale(1, length);
+ matrix.postRotate(-90);
+ SkPaint fadingPaint;
+ fadingPaint.setShader(s->newWithLocalMatrix(matrix))->unref();
+ SkXfermode* mode = SkXfermode::Create(SkXfermode::kDstOut_Mode);
+ fadingPaint.setXfermode(mode);
+ canvas.drawRect(0, 0, length, itemHeight, fadingPaint);
+ canvas.restore();
+ }
+};
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index 8035dc45f23c..a614044b2468 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -15,7 +15,7 @@
*/
#include "TestSceneBase.h"
-#include "utils/Color.h"
+#include "tests/common/TestListViewSceneBase.h"
#include <cstdio>
@@ -28,58 +28,8 @@ static TestScene::Registrar _ListView(TestScene::Info{
TestScene::simpleCreateScene<ListViewAnimation>
});
-class ListViewAnimation : public TestScene {
-public:
- int cardHeight;
- int cardSpacing;
- int cardWidth;
- int cardLeft;
- sp<RenderNode> listView;
- std::vector< sp<RenderNode> > cards;
- void createContent(int width, int height, TestCanvas& canvas) override {
- srand(0);
- cardHeight = dp(60);
- cardSpacing = dp(16);
- cardWidth = std::min((height - cardSpacing * 2), (int)dp(300));
- cardLeft = (width - cardWidth) / 2;
-
- for (int y = 0; y < height + (cardHeight + cardSpacing - 1); y += (cardHeight + cardSpacing)) {
- cards.push_back(createCard(cards.size(), y));
- }
- listView = TestUtils::createNode(0, 0, width, height,
- [this](RenderProperties& props, TestCanvas& canvas) {
- for (size_t ci = 0; ci < cards.size(); ci++) {
- canvas.drawRenderNode(cards[ci].get());
- }
- });
-
- canvas.drawColor(Color::Grey_500, SkXfermode::kSrcOver_Mode);
- canvas.drawRenderNode(listView.get());
- }
-
- void doFrame(int frameNr) override {
- int scrollPx = dp(frameNr) * 3;
- int cardIndexOffset = scrollPx / (cardSpacing + cardHeight);
- int pxOffset = -(scrollPx % (cardSpacing + cardHeight));
-
- TestCanvas canvas(
- listView->stagingProperties().getWidth(),
- listView->stagingProperties().getHeight());
- for (size_t ci = 0; ci < cards.size(); ci++) {
- // update card position
- auto card = cards[(ci + cardIndexOffset) % cards.size()];
- int top = ((int)ci) * (cardSpacing + cardHeight) + pxOffset;
- card->mutateStagingProperties().setLeftTopRightBottom(
- cardLeft, top, cardLeft + cardWidth, top + cardHeight);
- card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
-
- // draw it to parent DisplayList
- canvas.drawRenderNode(cards[ci].get());
- }
- listView->setStagingDisplayList(canvas.finishRecording(), nullptr);
- }
-private:
- SkBitmap createRandomCharIcon() {
+class ListViewAnimation : public TestListViewSceneBase {
+ SkBitmap createRandomCharIcon(int cardHeight) {
int size = cardHeight - (dp(10) * 2);
SkBitmap bitmap = TestUtils::createSkBitmap(size, size);
SkCanvas canvas(bitmap);
@@ -97,7 +47,10 @@ private:
paint.setTextAlign(SkPaint::kCenter_Align);
paint.setTextSize(size / 2);
char charToShow = 'A' + (rand() % 26);
- canvas.drawText(&charToShow, 1, size / 2, /*approximate centering*/ size * 0.7, paint);
+ const SkPoint pos[] = {{
+ SkIntToScalar(size / 2),
+ /*approximate centering*/ SkFloatToScalar(size * 0.7f)}};
+ canvas.drawPosText(&charToShow, 1, pos, paint);
return bitmap;
}
@@ -117,34 +70,31 @@ private:
return bitmap;
}
- sp<RenderNode> createCard(int cardId, int top) {
- return TestUtils::createNode(cardLeft, top, cardLeft + cardWidth, top + cardHeight,
- [this, cardId](RenderProperties& props, TestCanvas& canvas) {
- static SkBitmap filledBox = createBoxBitmap(true);
- static SkBitmap strokedBox = createBoxBitmap(false);
-
- // TODO: switch to using round rect clipping, once merging correctly handles that
- SkPaint roundRectPaint;
- roundRectPaint.setAntiAlias(true);
- roundRectPaint.setColor(Color::White);
- canvas.drawRoundRect(0, 0, cardWidth, cardHeight, dp(6), dp(6), roundRectPaint);
-
- SkPaint textPaint;
- textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500);
- textPaint.setTextSize(dp(20));
- textPaint.setAntiAlias(true);
- char buf[256];
- snprintf(buf, sizeof(buf), "This card is #%d", cardId);
- TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, cardHeight, dp(25));
- textPaint.setTextSize(dp(15));
- TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint,
- cardHeight, dp(45));
-
- canvas.drawBitmap(createRandomCharIcon(), dp(10), dp(10), nullptr);
-
- const SkBitmap& boxBitmap = rand() % 2 ? filledBox : strokedBox;
- canvas.drawBitmap(boxBitmap, cardWidth - dp(10) - boxBitmap.width(), dp(10), nullptr);
- });
+ void createListItem(RenderProperties& props, TestCanvas& canvas, int cardId,
+ int itemWidth, int itemHeight) override {
+ static SkBitmap filledBox = createBoxBitmap(true);
+ static SkBitmap strokedBox = createBoxBitmap(false);
+ // TODO: switch to using round rect clipping, once merging correctly handles that
+ SkPaint roundRectPaint;
+ roundRectPaint.setAntiAlias(true);
+ roundRectPaint.setColor(Color::White);
+ canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint);
+
+ SkPaint textPaint;
+ textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500);
+ textPaint.setTextSize(dp(20));
+ textPaint.setAntiAlias(true);
+ char buf[256];
+ snprintf(buf, sizeof(buf), "This card is #%d", cardId);
+ TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, itemHeight, dp(25));
+ textPaint.setTextSize(dp(15));
+ TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint,
+ itemHeight, dp(45));
+
+ canvas.drawBitmap(createRandomCharIcon(itemHeight), dp(10), dp(10), nullptr);
+
+ const SkBitmap& boxBitmap = rand() % 2 ? filledBox : strokedBox;
+ canvas.drawBitmap(boxBitmap, itemWidth - dp(10) - boxBitmap.width(), dp(10), nullptr);
}
};
diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h
index 935ddcf9212d..792312a6a7a4 100644
--- a/libs/hwui/tests/common/scenes/TestSceneBase.h
+++ b/libs/hwui/tests/common/scenes/TestSceneBase.h
@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef TESTS_SCENES_TESTSCENEBASE_H
-#define TESTS_SCENES_TESTSCENEBASE_H
-#include "DisplayListCanvas.h"
+#pragma once
+
#include "RecordingCanvas.h"
#include "RenderNode.h"
#include "tests/common/TestContext.h"
@@ -30,5 +29,3 @@ using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
using namespace android::uirenderer::test;
-
-#endif /* TESTS_SCENES_TESTSCENEBASE_H_ */
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index c5af06160b62..f03dcbf4c24c 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -22,6 +22,7 @@
#include "renderthread/RenderProxy.h"
#include "renderthread/RenderTask.h"
+#include <benchmark/benchmark.h>
#include <cutils/log.h>
#include <gui/Surface.h>
#include <ui/PixelFormat.h>
@@ -41,7 +42,7 @@ public:
template<class T>
class ModifiedMovingAverage {
public:
- ModifiedMovingAverage(int weight) : mWeight(weight) {}
+ explicit ModifiedMovingAverage(int weight) : mWeight(weight) {}
T add(T today) {
if (!mHasValue) {
@@ -62,13 +63,62 @@ private:
T mAverage;
};
-void run(const TestScene::Info& info, const TestScene::Options& opts) {
+void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options& opts,
+ benchmark::BenchmarkReporter* reporter, RenderProxy* proxy,
+ double durationInS) {
+ using namespace benchmark;
+
+ struct ReportInfo {
+ int percentile;
+ const char* suffix;
+ };
+
+ static std::array<ReportInfo, 4> REPORTS = {
+ ReportInfo { 50, "_50th" },
+ ReportInfo { 90, "_90th" },
+ ReportInfo { 95, "_95th" },
+ ReportInfo { 99, "_99th" },
+ };
+
+ // Although a vector is used, it must stay with only a single element
+ // otherwise the BenchmarkReporter will automatically compute
+ // mean and stddev which doesn't make sense for our usage
+ std::vector<BenchmarkReporter::Run> reports;
+ BenchmarkReporter::Run report;
+ report.benchmark_name = info.name;
+ report.iterations = static_cast<int64_t>(opts.count);
+ report.real_accumulated_time = durationInS;
+ report.cpu_accumulated_time = durationInS;
+ report.items_per_second = opts.count / durationInS;
+ reports.push_back(report);
+ reporter->ReportRuns(reports);
+
+ // Pretend the percentiles are single-iteration runs of the test
+ // If rendering offscreen skip this as it's fps that's more interesting
+ // in that test case than percentiles.
+ if (!opts.renderOffscreen) {
+ for (auto& ri : REPORTS) {
+ reports[0].benchmark_name = info.name;
+ reports[0].benchmark_name += ri.suffix;
+ durationInS = proxy->frameTimePercentile(ri.percentile) / 1000.0;
+ reports[0].real_accumulated_time = durationInS;
+ reports[0].cpu_accumulated_time = durationInS;
+ reports[0].iterations = 1;
+ reports[0].items_per_second = 0;
+ reporter->ReportRuns(reports);
+ }
+ }
+}
+
+void run(const TestScene::Info& info, const TestScene::Options& opts,
+ benchmark::BenchmarkReporter* reporter) {
// Switch to the real display
gDisplay = getBuiltInDisplay();
std::unique_ptr<TestScene> scene(info.createScene(opts));
TestContext testContext;
+ testContext.setRenderOffscreen(opts.renderOffscreen);
// create the native surface
const int width = gDisplay.w;
@@ -87,11 +137,16 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) {
proxy->loadSystemProperties();
proxy->initialize(surface);
float lightX = width / 2.0;
- proxy->setup(width, height, dp(800.0f), 255 * 0.075, 255 * 0.15);
+ proxy->setup(dp(800.0f), 255 * 0.075, 255 * 0.15);
proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
// Do a few cold runs then reset the stats so that the caches are all hot
- for (int i = 0; i < 5; i++) {
+ int warmupFrameCount = 5;
+ if (opts.renderOffscreen) {
+ // Do a few more warmups to try and boost the clocks up
+ warmupFrameCount = 10;
+ }
+ for (int i = 0; i < warmupFrameCount; i++) {
testContext.waitForVsync();
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
@@ -103,6 +158,7 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) {
ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
+ nsecs_t start = systemTime(CLOCK_MONOTONIC);
for (int i = 0; i < opts.count; i++) {
testContext.waitForVsync();
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
@@ -121,6 +177,13 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) {
}
}
}
+ proxy->fence();
+ nsecs_t end = systemTime(CLOCK_MONOTONIC);
- proxy->dumpProfileInfo(STDOUT_FILENO, DumpFlags::JankStats);
+ if (reporter) {
+ outputBenchmarkReport(info, opts, reporter, proxy.get(),
+ (end - start) / (double) s2ns(1));
+ } else {
+ proxy->dumpProfileInfo(STDOUT_FILENO, DumpFlags::JankStats);
+ }
}
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 02a39501e647..ffeef4599774 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+#include "tests/common/LeakChecker.h"
#include "tests/common/TestScene.h"
#include "protos/hwui.pb.h"
#include "Properties.h"
+#include <benchmark/benchmark.h>
+#include <../src/sysinfo.h>
#include <getopt.h>
#include <stdio.h>
#include <string>
@@ -39,8 +42,10 @@ using namespace android::uirenderer::test;
static int gRepeatCount = 1;
static std::vector<TestScene::Info> gRunTests;
static TestScene::Options gOpts;
+std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
-void run(const TestScene::Info& info, const TestScene::Options& opts);
+void run(const TestScene::Info& info, const TestScene::Options& opts,
+ benchmark::BenchmarkReporter* reporter);
static void printHelp() {
printf(R"(
@@ -121,6 +126,20 @@ static void moveToCpuSet(const char* cpusetName) {
close(fd);
}
+static bool setBenchmarkFormat(const char* format) {
+ if (!strcmp(format, "tabular")) {
+ gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
+ } else if (!strcmp(format, "json")) {
+ gBenchmarkReporter.reset(new benchmark::JSONReporter());
+ } else if (!strcmp(format, "csv")) {
+ gBenchmarkReporter.reset(new benchmark::CSVReporter());
+ } else {
+ fprintf(stderr, "Unknown format '%s'", format);
+ return false;
+ }
+ return true;
+}
+
// For options that only exist in long-form. Anything in the
// 0-255 range is reserved for short options (which just use their ASCII value)
namespace LongOpts {
@@ -130,6 +149,8 @@ enum {
WaitForGpu,
ReportFrametime,
CpuSet,
+ BenchmarkFormat,
+ Offscreen,
};
}
@@ -141,6 +162,8 @@ static const struct option LONG_OPTIONS[] = {
{ "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
{ "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
{ "cpuset", required_argument, nullptr, LongOpts::CpuSet },
+ { "benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat },
+ { "offscreen", no_argument, nullptr, LongOpts::Offscreen },
{ 0, 0, 0, 0 }
};
@@ -214,6 +237,20 @@ void parseOptions(int argc, char* argv[]) {
moveToCpuSet(optarg);
break;
+ case LongOpts::BenchmarkFormat:
+ if (!optarg) {
+ error = true;
+ break;
+ }
+ if (!setBenchmarkFormat(optarg)) {
+ error = true;
+ }
+ break;
+
+ case LongOpts::Offscreen:
+ gOpts.renderOffscreen = true;
+ break;
+
case 'h':
printHelp();
exit(EXIT_SUCCESS);
@@ -237,12 +274,18 @@ void parseOptions(int argc, char* argv[]) {
if (optind < argc) {
do {
const char* test = argv[optind++];
- auto pos = TestScene::testMap().find(test);
- if (pos == TestScene::testMap().end()) {
- fprintf(stderr, "Unknown test '%s'\n", test);
- exit(EXIT_FAILURE);
+ if (!strcmp(test, "all")) {
+ for (auto& iter : TestScene::testMap()) {
+ gRunTests.push_back(iter.second);
+ }
} else {
- gRunTests.push_back(pos->second);
+ auto pos = TestScene::testMap().find(test);
+ if (pos == TestScene::testMap().end()) {
+ fprintf(stderr, "Unknown test '%s'\n", test);
+ exit(EXIT_FAILURE);
+ } else {
+ gRunTests.push_back(pos->second);
+ }
}
} while (optind < argc);
} else {
@@ -255,12 +298,36 @@ int main(int argc, char* argv[]) {
gOpts.count = 150;
parseOptions(argc, argv);
+ if (!gBenchmarkReporter && gOpts.renderOffscreen) {
+ gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
+ }
+
+ if (gBenchmarkReporter) {
+ size_t name_field_width = 10;
+ for (auto&& test : gRunTests) {
+ name_field_width = std::max<size_t>(name_field_width, test.name.size());
+ }
+ // _50th, _90th, etc...
+ name_field_width += 5;
+
+ benchmark::BenchmarkReporter::Context context;
+ context.num_cpus = benchmark::NumCPUs();
+ context.mhz_per_cpu = benchmark::CyclesPerSecond() / 1000000.0f;
+ context.cpu_scaling_enabled = benchmark::CpuScalingEnabled();
+ context.name_field_width = name_field_width;
+ gBenchmarkReporter->ReportContext(context);
+ }
for (int i = 0; i < gRepeatCount; i++) {
for (auto&& test : gRunTests) {
- run(test, gOpts);
+ run(test, gOpts, gBenchmarkReporter.get());
}
}
- printf("Success!\n");
+
+ if (gBenchmarkReporter) {
+ gBenchmarkReporter->Finalize();
+ }
+
+ LeakChecker::checkForLeaks();
return 0;
}
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 06b68d1dea8f..ed3b84753eeb 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -17,21 +17,13 @@
#include <benchmark/benchmark.h>
#include "DisplayList.h"
-#if HWUI_NEW_OPS
#include "RecordingCanvas.h"
-#else
-#include "DisplayListCanvas.h"
-#endif
#include "tests/common/TestUtils.h"
using namespace android;
using namespace android::uirenderer;
-#if HWUI_NEW_OPS
typedef RecordingCanvas TestCanvas;
-#else
-typedef DisplayListCanvas TestCanvas;
-#endif
void BM_DisplayList_alloc(benchmark::State& benchState) {
while (benchState.KeepRunning()) {
@@ -169,3 +161,37 @@ void BM_CanvasState_translate(benchmark::State& benchState) {
}
}
BENCHMARK(BM_CanvasState_translate);
+
+void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) {
+ sp<RenderNode> child = TestUtils::createNode(50, 50, 100, 100,
+ [](auto& props, auto& canvas) {
+ canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+ });
+
+ TestCanvas canvas(100, 100);
+ delete canvas.finishRecording();
+
+ while (benchState.KeepRunning()) {
+ canvas.resetRecording(200, 200);
+ canvas.setHighContrastText(false);
+ canvas.translate(0, 0); // mScrollX, mScrollY
+
+ // Clip to padding
+ // Can expect ~25% of views to have clip to padding with a non-null padding
+ int clipRestoreCount = canvas.save(SaveFlags::MatrixClip);
+ canvas.clipRect(1, 1, 199, 199, SkRegion::kIntersect_Op);
+
+ canvas.insertReorderBarrier(true);
+
+ // Draw child loop
+ for (int i = 0; i < benchState.range_x(); i++) {
+ canvas.drawRenderNode(child.get());
+ }
+
+ canvas.insertReorderBarrier(false);
+ canvas.restoreToCount(clipRestoreCount);
+
+ delete canvas.finishRecording();
+ }
+}
+BENCHMARK(BM_DisplayListCanvas_basicViewGroupDraw)->Arg(1)->Arg(5)->Arg(10);
diff --git a/libs/hwui/tests/microbench/TaskManagerBench.cpp b/libs/hwui/tests/microbench/TaskManagerBench.cpp
index c6b9f3bca55f..cf47f273c144 100644
--- a/libs/hwui/tests/microbench/TaskManagerBench.cpp
+++ b/libs/hwui/tests/microbench/TaskManagerBench.cpp
@@ -29,7 +29,7 @@ class TrivialTask : public Task<char> {};
class TrivialProcessor : public TaskProcessor<char> {
public:
- TrivialProcessor(TaskManager* manager)
+ explicit TrivialProcessor(TaskManager* manager)
: TaskProcessor(manager) {}
virtual ~TrivialProcessor() {}
virtual void onProcess(const sp<Task<char> >& task) override {
diff --git a/libs/hwui/tests/microbench/how_to_run.txt b/libs/hwui/tests/microbench/how_to_run.txt
index e6f80b278276..915fe5d959f9 100755
--- a/libs/hwui/tests/microbench/how_to_run.txt
+++ b/libs/hwui/tests/microbench/how_to_run.txt
@@ -1,4 +1,3 @@
mmm -j8 frameworks/base/libs/hwui &&
-adb push $ANDROID_PRODUCT_OUT/data/local/tmp/hwuimicro \
- /data/local/tmp/hwuimicro &&
- adb shell /data/local/tmp/hwuimicro
+adb push $OUT/data/benchmarktest/hwuimicro/hwuimicro /data/benchmarktest/hwuimicro/hwuimicro &&
+adb shell /data/benchmarktest/hwuimicro/hwuimicro
diff --git a/libs/hwui/tests/microbench/main.cpp b/libs/hwui/tests/microbench/main.cpp
index a0157bc4f9ef..9771c85382b4 100644
--- a/libs/hwui/tests/microbench/main.cpp
+++ b/libs/hwui/tests/microbench/main.cpp
@@ -14,6 +14,19 @@
* limitations under the License.
*/
+#include "debug/GlesDriver.h"
+#include "debug/NullGlesDriver.h"
+
#include <benchmark/benchmark.h>
-BENCHMARK_MAIN();
+#include <memory>
+
+using namespace android;
+using namespace android::uirenderer;
+
+int main(int argc, char** argv) {
+ debug::GlesDriver::replace(std::make_unique<debug::NullGlesDriver>());
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ return 0;
+}
diff --git a/libs/hwui/tests/scripts/prep_buller.sh b/libs/hwui/tests/scripts/prep_buller.sh
new file mode 100755
index 000000000000..b2f68bd44e7d
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_buller.sh
@@ -0,0 +1,49 @@
+#buller is bullhead & angler (☞゚ヮ゚)☞
+
+nr=$(adb shell cat /proc/cpuinfo | grep processor | wc -l)
+cpubase=/sys/devices/system/cpu
+gov=cpufreq/scaling_governor
+
+adb root
+adb wait-for-device
+adb shell stop thermal-engine
+adb shell stop perfd
+
+# LITTLE cores
+# 384000 460800 600000 672000 787200 864000 960000 1248000 1440000
+# BIG cores
+# 384000 480000 633600 768000 864000 960000 1248000 1344000 1440000
+# 1536000 1632000 1689600 1824000
+
+cpu=0
+S=960000
+while [ $((cpu < 4)) -eq 1 ]; do
+ echo "Setting cpu $cpu to $S hz"
+ adb shell "echo 1 > $cpubase/cpu${cpu}/online"
+ adb shell "echo userspace > $cpubase/cpu${cpu}/$gov"
+ adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_max_freq"
+ adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_min_freq"
+ adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_setspeed"
+ cpu=$(($cpu + 1))
+done
+
+while [ $((cpu < $nr)) -eq 1 ]; do
+ echo "disable cpu $cpu"
+ adb shell "echo 0 > $cpubase/cpu${cpu}/online"
+ cpu=$(($cpu + 1))
+done
+
+echo "setting GPU bus and idle timer"
+adb shell "echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split"
+adb shell "echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on"
+adb shell "echo 10000 > /sys/class/kgsl/kgsl-3d0/idle_timer"
+
+#0 762 1144 1525 2288 3509 4173 5271 5928 7904 9887 11863
+adb shell "echo 11863 > /sys/class/devfreq/qcom,gpubw.70/min_freq" &> /dev/null
+adb shell "echo 11863 > /sys/class/devfreq/qcom,gpubw.19/min_freq" &> /dev/null
+
+#600000000 510000000 450000000 390000000 305000000 180000000
+echo "performance mode, 305 MHz"
+adb shell "echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor"
+adb shell "echo 305000000 > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq"
+adb shell "echo 305000000 > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq"
diff --git a/libs/hwui/tests/scripts/prep_volantis.sh b/libs/hwui/tests/scripts/prep_volantis.sh
index 0572ee55c9b9..6407844afa90 100755
--- a/libs/hwui/tests/scripts/prep_volantis.sh
+++ b/libs/hwui/tests/scripts/prep_volantis.sh
@@ -16,16 +16,8 @@
adb root
adb wait-for-device
-adb shell stop mpdecision
adb shell stop perfd
-adb shell stop
-for pid in $( adb shell ps | awk '{ if ( $9 == "surfaceflinger" ) { print $2 } }' ); do
- adb shell kill $pid
-done
-adb shell setprop debug.egl.traceGpuCompletion 1
-adb shell daemonize surfaceflinger
-sleep 3
-adb shell setprop service.bootanim.exit 1
+adb shell stop thermal-engine
# cpu possible frequencies
# 204000 229500 255000 280500 306000 331500 357000 382500 408000 433500 459000
diff --git a/libs/hwui/tests/scripts/stopruntime.sh b/libs/hwui/tests/scripts/stopruntime.sh
new file mode 100644
index 000000000000..bb8fcb6f3ee2
--- /dev/null
+++ b/libs/hwui/tests/scripts/stopruntime.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Copyright (C) 2016 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.
+
+adb root
+adb wait-for-device
+adb shell stop
+
+for pid in $( adb shell ps | awk '{ if ( $9 == "surfaceflinger" ) { print $2 } }' ); do
+ adb shell kill $pid
+done
+adb shell setprop debug.egl.traceGpuCompletion 1
+adb shell daemonize surfaceflinger
+sleep 3
+adb shell setprop service.bootanim.exit 1
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index af54e079daab..e5fc55611be3 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -1953,7 +1953,7 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac
std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
class PropertyTestRenderer : public TestRendererBase {
public:
- PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
+ explicit PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
: mCallback(callback) {}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(mIndex++, 0);
@@ -2075,7 +2075,7 @@ void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
std::function<void(RenderProperties&)> propSetupCallback) {
class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
public:
- SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
+ explicit SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
: mOutData(outData) {}
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
index 95543d33b1ef..67e58e2aba0d 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -85,9 +85,6 @@ static void expectTransformEq(Glop::Transform& expectedTransform, Glop::Transfor
}
static void expectGlopEq(Glop& expectedGlop, Glop& builtGlop) {
-#if !HWUI_NEW_OPS
- EXPECT_EQ(expectedGlop.bounds, builtGlop.bounds);
-#endif
expectBlendEq(expectedGlop.blend, builtGlop.blend);
expectFillEq(expectedGlop.fill, builtGlop.fill);
expectMeshEq(expectedGlop.mesh, builtGlop.mesh);
@@ -138,9 +135,6 @@ RENDERTHREAD_TEST(GlopBuilder, rectSnapTest) {
// unit quad also should be translate by additional (0.3, 0.3) to snap to exact pixels.
goldenGlop->transform.modelView.loadTranslate(1.3, 1.3, 0);
goldenGlop->transform.modelView.scale(99, 99, 1);
-#if !HWUI_NEW_OPS
- goldenGlop->bounds = android::uirenderer::Rect(1.70, 1.70, 100.70, 100.70);
-#endif
goldenGlop->transform.canvas = simpleTranslate;
goldenGlop->fill.texture.filter = GL_NEAREST;
expectGlopEq(*goldenGlop, glop);
diff --git a/libs/hwui/tests/unit/MeshStateTests.cpp b/libs/hwui/tests/unit/MeshStateTests.cpp
new file mode 100644
index 000000000000..0881fa246afd
--- /dev/null
+++ b/libs/hwui/tests/unit/MeshStateTests.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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 <debug/MockGlesDriver.h>
+#include <debug/ScopedReplaceDriver.h>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <renderstate/MeshState.h>
+#include <tests/common/TestUtils.h>
+
+using namespace android::uirenderer;
+using namespace testing;
+
+RENDERTHREAD_TEST(MeshState, genOrUpdate) {
+ debug::ScopedReplaceDriver<debug::MockGlesDriver> driverRef;
+ auto& mockGlDriver = driverRef.get();
+ EXPECT_CALL(mockGlDriver, glGenBuffers_(_, _)).WillOnce(SetArgPointee<1>(35));
+ EXPECT_CALL(mockGlDriver, glBindBuffer_(_, 35));
+ EXPECT_CALL(mockGlDriver, glBufferData_(_, _, _, _));
+
+ GLuint buffer = 0;
+ renderThread.renderState().meshState().genOrUpdateMeshBuffer(&buffer, 10, nullptr, GL_DYNAMIC_DRAW);
+} \ No newline at end of file
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 9cd504ec0af7..d75ceb200a88 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -746,7 +746,7 @@ TEST(RecordingCanvas, drawText) {
paint.setTextSize(20);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
- canvas.drawText(dst.get(), 0, 5, 5, 25, 25, kBidi_Force_LTR, paint, NULL);
+ canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::kBidi_Force_LTR, paint, NULL);
});
int count = 0;
@@ -770,7 +770,7 @@ TEST(RecordingCanvas, drawTextInHighContrast) {
paint.setTextSize(20);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
- canvas.drawText(dst.get(), 0, 5, 5, 25, 25, kBidi_Force_LTR, paint, NULL);
+ canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::kBidi_Force_LTR, paint, NULL);
});
int count = 0;
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index cf76a8691dcd..132601efb543 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -68,7 +68,7 @@ TEST(RenderNode, hasParents) {
TEST(RenderNode, releasedCallback) {
class DecRefOnReleased : public GlFunctorLifecycleListener {
public:
- DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {}
+ explicit DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {}
void onGlFunctorReleased(Functor* functor) override {
*mRefCnt -= 1;
}
@@ -105,8 +105,9 @@ TEST(RenderNode, releasedCallback) {
RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
ContextFactory contextFactory;
- CanvasContext canvasContext(renderThread, false, nullptr, &contextFactory);
- TreeInfo info(TreeInfo::MODE_RT_ONLY, canvasContext);
+ std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
+ renderThread, false, nullptr, &contextFactory));
+ TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
info.observer = nullptr;
@@ -128,5 +129,5 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
nullDLNode->prepareTree(info);
}
- canvasContext.destroy(nullptr);
+ canvasContext->destroy(nullptr);
}
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
index 409a12d37693..d05bdbf1709e 100644
--- a/libs/hwui/tests/unit/main.cpp
+++ b/libs/hwui/tests/unit/main.cpp
@@ -15,19 +15,15 @@
*/
#include "gtest/gtest.h"
+#include "gmock/gmock.h"
#include "Caches.h"
+#include "debug/GlesDriver.h"
+#include "debug/NullGlesDriver.h"
#include "thread/TaskManager.h"
-#include "tests/common/TestUtils.h"
+#include "tests/common/LeakChecker.h"
-#include <memunreachable/memunreachable.h>
-
-#include <cstdio>
-#include <iostream>
-#include <map>
-#include <unordered_set>
#include <signal.h>
-#include <unistd.h>
using namespace std;
using namespace android;
@@ -54,67 +50,6 @@ static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) {
raise(sig);
}
-static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) {
- // merge them all
- UnreachableMemoryInfo merged;
- unordered_set<uintptr_t> addrs;
- merged.allocation_bytes = 0;
- merged.leak_bytes = 0;
- merged.num_allocations = 0;
- merged.num_leaks = 0;
- for (auto& info : infolist) {
- // We'll be a little hazzy about these ones and just hope the biggest
- // is the most accurate
- merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes);
- merged.num_allocations = max(merged.num_allocations, info.num_allocations);
- for (auto& leak : info.leaks) {
- if (addrs.find(leak.begin) == addrs.end()) {
- merged.leaks.push_back(leak);
- merged.num_leaks++;
- merged.leak_bytes += leak.size;
- addrs.insert(leak.begin);
- }
- }
- }
-
- // Now log the result
- if (merged.num_leaks) {
- cout << endl << "Leaked memory!" << endl;
- if (!merged.leaks[0].backtrace.num_frames) {
- cout << "Re-run with 'setprop libc.debug.malloc.program hwui_unit_test'"
- << endl << "and 'setprop libc.debug.malloc.options backtrace=8'"
- << " to get backtraces" << endl;
- }
- cout << merged.ToString(false);
- }
-}
-
-static void checkForLeaks() {
- // TODO: Until we can shutdown the RT thread we need to do this in
- // two passes as GetUnreachableMemory has limited insight into
- // thread-local caches so some leaks will not be properly tagged as leaks
- nsecs_t before = systemTime();
- UnreachableMemoryInfo rtMemInfo;
- TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) {
- if (Caches::hasInstance()) {
- Caches::getInstance().tasks.stop();
- }
- // Check for leaks
- if (!GetUnreachableMemory(rtMemInfo)) {
- cerr << "Failed to get unreachable memory!" << endl;
- return;
- }
- });
- UnreachableMemoryInfo uiMemInfo;
- if (!GetUnreachableMemory(uiMemInfo)) {
- cerr << "Failed to get unreachable memory!" << endl;
- return;
- }
- logUnreachable({rtMemInfo, uiMemInfo});
- nsecs_t after = systemTime();
- cout << "Leak check took " << ns2ms(after - before) << "ms" << endl;
-}
-
int main(int argc, char* argv[]) {
// Register a crash handler
struct sigaction sa;
@@ -127,10 +62,15 @@ int main(int argc, char* argv[]) {
gSigChain.insert(pair<int, struct sigaction>(sig, old_sa));
}
+ // Replace the default GLES driver
+ debug::GlesDriver::replace(std::make_unique<debug::NullGlesDriver>());
+
// Run the tests
testing::InitGoogleTest(&argc, argv);
+ testing::InitGoogleMock(&argc, argv);
+
int ret = RUN_ALL_TESTS();
- checkForLeaks();
+ test::LeakChecker::checkForLeaks();
return ret;
}