diff options
Diffstat (limited to 'libs/hwui/tests/main.cpp')
-rw-r--r-- | libs/hwui/tests/main.cpp | 422 |
1 files changed, 138 insertions, 284 deletions
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp index 80d7029857c4..aee84de3ae7b 100644 --- a/libs/hwui/tests/main.cpp +++ b/libs/hwui/tests/main.cpp @@ -14,327 +14,181 @@ * limitations under the License. */ -#include <cutils/log.h> -#include <gui/Surface.h> -#include <ui/PixelFormat.h> +#include "Benchmark.h" -#include <AnimationContext.h> -#include <DisplayListCanvas.h> -#include <RenderNode.h> -#include <renderthread/RenderProxy.h> -#include <renderthread/RenderTask.h> - -#include "TestContext.h" +#include "protos/hwui.pb.h" +#include <getopt.h> #include <stdio.h> +#include <string> #include <unistd.h> +#include <unordered_map> +#include <vector> using namespace android; using namespace android::uirenderer; -using namespace android::uirenderer::renderthread; -using namespace android::uirenderer::test; - -class ContextFactory : public IContextFactory { -public: - virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override { - return new AnimationContext(clock); - } -}; -static DisplayListCanvas* startRecording(RenderNode* node) { - DisplayListCanvas* renderer = new DisplayListCanvas(); - renderer->setViewport(node->stagingProperties().getWidth(), - node->stagingProperties().getHeight()); - renderer->prepare(); - return renderer; +// Not a static global because we need to force the map to be constructed +// before we try to add things to it. +std::unordered_map<std::string, BenchmarkInfo>& testMap() { + static std::unordered_map<std::string, BenchmarkInfo> testMap; + return testMap; } -static void endRecording(DisplayListCanvas* renderer, RenderNode* node) { - renderer->finish(); - node->setStagingDisplayList(renderer->finishRecording()); - delete renderer; +void Benchmark::registerBenchmark(const BenchmarkInfo& info) { + testMap()[info.name] = info; } -class TreeContentAnimation { -public: - virtual ~TreeContentAnimation() {} - int frameCount = 150; - virtual int getFrameCount() { return frameCount; } - virtual void setFrameCount(int fc) { - if (fc > 0) { - frameCount = fc; - } - } - virtual void createContent(int width, int height, DisplayListCanvas* renderer) = 0; - virtual void doFrame(int frameNr) = 0; - - template <class T> - static void run(int frameCount) { - T animation; - animation.setFrameCount(frameCount); - - TestContext testContext; - - // create the native surface - const int width = gDisplay.w; - const int height = gDisplay.h; - sp<Surface> surface = testContext.surface(); - - RenderNode* rootNode = new RenderNode(); - rootNode->incStrong(nullptr); - rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height); - rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); - rootNode->mutateStagingProperties().setClipToBounds(false); - rootNode->setPropertyFieldsDirty(RenderNode::GENERIC); - - ContextFactory factory; - std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory)); - proxy->loadSystemProperties(); - proxy->initialize(surface); - float lightX = width / 2.0; - proxy->setup(width, height, dp(800.0f), 255 * 0.075, 255 * 0.15); - proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)}); - - android::uirenderer::Rect DUMMY; - - DisplayListCanvas* renderer = startRecording(rootNode); - animation.createContent(width, height, renderer); - endRecording(renderer, rootNode); - - // Do a few cold runs then reset the stats so that the caches are all hot - for (int i = 0; i < 3; i++) { - testContext.waitForVsync(); - proxy->syncAndDrawFrame(); - } - proxy->resetProfileInfo(); - - for (int i = 0; i < animation.getFrameCount(); i++) { - testContext.waitForVsync(); - - ATRACE_NAME("UI-Draw Frame"); - nsecs_t vsync = systemTime(CLOCK_MONOTONIC); - UiFrameInfoBuilder(proxy->frameInfo()) - .setVsync(vsync, vsync); - animation.doFrame(i); - proxy->syncAndDrawFrame(); - } - - proxy->dumpProfileInfo(STDOUT_FILENO, 0); - rootNode->decStrong(nullptr); - } -}; - -class ShadowGridAnimation : public TreeContentAnimation { -public: - std::vector< sp<RenderNode> > cards; - void createContent(int width, int height, DisplayListCanvas* renderer) override { - renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); - renderer->insertReorderBarrier(true); +static int gFrameCount = 150; +static int gRepeatCount = 1; +static std::vector<BenchmarkInfo> gRunTests; + +static void printHelp() { + printf("\ +USAGE: hwuitest [OPTIONS] <TESTNAME>\n\ +\n\ +OPTIONS:\n\ + -c, --count=NUM NUM loops a test should run (example, number of frames)\n\ + -r, --runs=NUM Repeat the test(s) NUM times\n\ + -h, --help Display this help\n\ + --list List all tests\n\ +\n"); +} - for (int x = dp(16); x < (width - dp(116)); x += dp(116)) { - for (int y = dp(16); y < (height - dp(116)); y += dp(116)) { - sp<RenderNode> card = createCard(x, y, dp(100), dp(100)); - renderer->drawRenderNode(card.get()); - cards.push_back(card); +static void listTests() { + printf("Tests: \n"); + for (auto&& test : testMap()) { + auto&& info = test.second; + const char* col1 = info.name.c_str(); + int dlen = info.description.length(); + const char* col2 = info.description.c_str(); + // World's best line breaking algorithm. + do { + int toPrint = dlen; + if (toPrint > 50) { + char* found = (char*) memrchr(col2, ' ', 50); + if (found) { + toPrint = found - col2; + } else { + toPrint = 50; + } } - } - - renderer->insertReorderBarrier(false); - } - void doFrame(int frameNr) override { - int curFrame = frameNr % 150; - for (size_t ci = 0; ci < cards.size(); ci++) { - cards[ci]->mutateStagingProperties().setTranslationX(curFrame); - cards[ci]->mutateStagingProperties().setTranslationY(curFrame); - cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); - } + printf("%-20s %.*s\n", col1, toPrint, col2); + col1 = ""; + col2 += toPrint; + dlen -= toPrint; + while (*col2 == ' ') { + col2++; dlen--; + } + } while (dlen > 0); + printf("\n"); } -private: - sp<RenderNode> createCard(int x, int y, int width, int height) { - sp<RenderNode> node = new RenderNode(); - node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height); - node->mutateStagingProperties().setElevation(dp(16)); - node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1); - node->mutateStagingProperties().mutableOutline().setShouldClip(true); - node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z); +} - DisplayListCanvas* renderer = startRecording(node.get()); - renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode); - endRecording(renderer, node.get()); - return node; - } +static const struct option LONG_OPTIONS[] = { + { "frames", required_argument, nullptr, 'f' }, + { "repeat", required_argument, nullptr, 'r' }, + { "help", no_argument, nullptr, 'h' }, + { "list", no_argument, nullptr, 'l' }, + { 0, 0, 0, 0 } }; -class ShadowGrid2Animation : public TreeContentAnimation { -public: - std::vector< sp<RenderNode> > cards; - void createContent(int width, int height, DisplayListCanvas* renderer) override { - renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); - renderer->insertReorderBarrier(true); +static const char* SHORT_OPTIONS = "c:r:h"; - for (int x = dp(8); x < (width - dp(58)); x += dp(58)) { - for (int y = dp(8); y < (height - dp(58)); y += dp(58)) { - sp<RenderNode> card = createCard(x, y, dp(50), dp(50)); - renderer->drawRenderNode(card.get()); - cards.push_back(card); - } - } +void parseOptions(int argc, char* argv[]) { + int c; + // temporary variable + int count; + bool error = false; + opterr = 0; - renderer->insertReorderBarrier(false); - } - void doFrame(int frameNr) override { - int curFrame = frameNr % 150; - for (size_t ci = 0; ci < cards.size(); ci++) { - cards[ci]->mutateStagingProperties().setTranslationX(curFrame); - cards[ci]->mutateStagingProperties().setTranslationY(curFrame); - cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); - } - } -private: - sp<RenderNode> createCard(int x, int y, int width, int height) { - sp<RenderNode> node = new RenderNode(); - node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height); - node->mutateStagingProperties().setElevation(dp(16)); - node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(6), 1); - node->mutateStagingProperties().mutableOutline().setShouldClip(true); - node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z); + while (true) { - DisplayListCanvas* renderer = startRecording(node.get()); - renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode); - endRecording(renderer, node.get()); - return node; - } -}; + /* getopt_long stores the option index here. */ + int option_index = 0; -class RectGridAnimation : public TreeContentAnimation { -public: - sp<RenderNode> card; - void createContent(int width, int height, DisplayListCanvas* renderer) override { - renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); - renderer->insertReorderBarrier(true); + c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index); - card = createCard(40, 40, 200, 200); - renderer->drawRenderNode(card.get()); + if (c == -1) + break; - renderer->insertReorderBarrier(false); - } - void doFrame(int frameNr) override { - int curFrame = frameNr % 150; - card->mutateStagingProperties().setTranslationX(curFrame); - card->mutateStagingProperties().setTranslationY(curFrame); - card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); - } -private: - sp<RenderNode> createCard(int x, int y, int width, int height) { - sp<RenderNode> node = new RenderNode(); - node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height); - node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + switch (c) { + case 0: + // Option set a flag, don't need to do anything + // (although none of the current LONG_OPTIONS do this...) + break; - DisplayListCanvas* renderer = startRecording(node.get()); - renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode); + case 'l': + listTests(); + exit(EXIT_SUCCESS); + break; - float rects[width * height]; - int index = 0; - for (int xOffset = 0; xOffset < width; xOffset+=2) { - for (int yOffset = 0; yOffset < height; yOffset+=2) { - rects[index++] = xOffset; - rects[index++] = yOffset; - rects[index++] = xOffset + 1; - rects[index++] = yOffset + 1; + case 'c': + count = atoi(optarg); + if (!count) { + fprintf(stderr, "Invalid frames argument '%s'\n", optarg); + error = true; + } else { + gFrameCount = (count > 0 ? count : INT_MAX); + } + break; + + case 'r': + count = atoi(optarg); + if (!count) { + fprintf(stderr, "Invalid repeat argument '%s'\n", optarg); + error = true; + } else { + gRepeatCount = (count > 0 ? count : INT_MAX); } + break; + + case 'h': + printHelp(); + exit(EXIT_SUCCESS); + break; + + case '?': + fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]); + // fall-through + default: + error = true; + break; } - int count = width * height; - - SkPaint paint; - paint.setColor(0xff00ffff); - renderer->drawRects(rects, count, &paint); - - endRecording(renderer, node.get()); - return node; - } -}; - -class OvalAnimation : public TreeContentAnimation { -public: - sp<RenderNode> card; - void createContent(int width, int height, DisplayListCanvas* renderer) override { - renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); - renderer->insertReorderBarrier(true); - - card = createCard(40, 40, 400, 400); - renderer->drawRenderNode(card.get()); - - renderer->insertReorderBarrier(false); - } - - void doFrame(int frameNr) override { - int curFrame = frameNr % 150; - card->mutateStagingProperties().setTranslationX(curFrame); - card->mutateStagingProperties().setTranslationY(curFrame); - card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); } -private: - sp<RenderNode> createCard(int x, int y, int width, int height) { - sp<RenderNode> node = new RenderNode(); - node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height); - node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); - - DisplayListCanvas* renderer = startRecording(node.get()); - SkPaint paint; - paint.setAntiAlias(true); - paint.setColor(0xFF000000); - renderer->drawOval(0, 0, width, height, paint); - - endRecording(renderer, node.get()); - return node; + if (error) { + fprintf(stderr, "Try 'hwuitest --help' for more information.\n"); + exit(EXIT_FAILURE); } -}; -struct cstr_cmp { - bool operator()(const char *a, const char *b) const { - return std::strcmp(a, b) < 0; + /* Print any remaining command line arguments (not options). */ + if (optind < argc) { + do { + const char* test = argv[optind++]; + auto pos = testMap().find(test); + if (pos == testMap().end()) { + fprintf(stderr, "Unknown test '%s'\n", test); + exit(EXIT_FAILURE); + } else { + gRunTests.push_back(pos->second); + } + } while (optind < argc); + } else { + gRunTests.push_back(testMap()["shadowgrid"]); } -}; - -typedef void (*testProc)(int); - -std::map<const char*, testProc, cstr_cmp> gTestMap { - {"shadowgrid", TreeContentAnimation::run<ShadowGridAnimation>}, - {"shadowgrid2", TreeContentAnimation::run<ShadowGrid2Animation>}, - {"rectgrid", TreeContentAnimation::run<RectGridAnimation> }, - {"oval", TreeContentAnimation::run<OvalAnimation> }, -}; +} int main(int argc, char* argv[]) { - const char* testName = argc > 1 ? argv[1] : "shadowgrid"; - testProc proc = gTestMap[testName]; - if(!proc) { - printf("Error: couldn't find test %s\n", testName); - return 1; - } - int loopCount = 1; - if (argc > 2) { - loopCount = atoi(argv[2]); - if (!loopCount) { - printf("Invalid loop count!\n"); - return 1; - } - } - int frameCount = 150; - if (argc > 3) { - frameCount = atoi(argv[3]); - if (frameCount < 1) { - printf("Invalid frame count!\n"); - return 1; + parseOptions(argc, argv); + + BenchmarkOptions opts; + opts.count = gFrameCount; + for (int i = 0; i < gRepeatCount; i++) { + for (auto&& test : gRunTests) { + test.functor(opts); } } - if (loopCount < 0) { - loopCount = INT_MAX; - } - for (int i = 0; i < loopCount; i++) { - proc(frameCount); - } printf("Success!\n"); return 0; } |