blob: f7945074316ca2f99a91f2ad34efd7cc1bb0bdf1 [file] [log] [blame]
John Reck94c40fe2014-10-08 09:28:43 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
John Reck94c40fe2014-10-08 09:28:43 -070017#include <cutils/log.h>
18#include <gui/Surface.h>
19#include <ui/PixelFormat.h>
20
21#include <AnimationContext.h>
Chris Craikdb663fe2015-04-20 13:34:45 -070022#include <DisplayListCanvas.h>
John Reck94c40fe2014-10-08 09:28:43 -070023#include <RenderNode.h>
24#include <renderthread/RenderProxy.h>
John Reck84e390c2015-01-05 09:42:52 -080025#include <renderthread/RenderTask.h>
John Reck94c40fe2014-10-08 09:28:43 -070026
27#include "TestContext.h"
28
John Recke248bd12015-08-05 13:53:53 -070029#include "protos/hwui.pb.h"
30
John Reck7f2e5e32015-05-05 11:00:53 -070031#include <stdio.h>
32#include <unistd.h>
John Reckb7dd29e2015-10-06 13:28:17 -070033#include <getopt.h>
34#include <vector>
John Reck7f2e5e32015-05-05 11:00:53 -070035
John Reck94c40fe2014-10-08 09:28:43 -070036using namespace android;
37using namespace android::uirenderer;
38using namespace android::uirenderer::renderthread;
John Reck84e390c2015-01-05 09:42:52 -080039using namespace android::uirenderer::test;
John Reck94c40fe2014-10-08 09:28:43 -070040
41class ContextFactory : public IContextFactory {
42public:
Chris Craikd41c4d82015-01-05 15:51:13 -080043 virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
John Reck94c40fe2014-10-08 09:28:43 -070044 return new AnimationContext(clock);
45 }
46};
47
Chris Craikdb663fe2015-04-20 13:34:45 -070048static DisplayListCanvas* startRecording(RenderNode* node) {
Derek Sollenbergercc882b62015-07-09 15:51:20 -040049 DisplayListCanvas* renderer = new DisplayListCanvas(
50 node->stagingProperties().getWidth(), node->stagingProperties().getHeight());
John Reck94c40fe2014-10-08 09:28:43 -070051 return renderer;
52}
53
Chris Craikdb663fe2015-04-20 13:34:45 -070054static void endRecording(DisplayListCanvas* renderer, RenderNode* node) {
John Reck94c40fe2014-10-08 09:28:43 -070055 node->setStagingDisplayList(renderer->finishRecording());
56 delete renderer;
57}
58
Chris Craik03188872015-02-02 18:39:33 -080059class TreeContentAnimation {
60public:
61 virtual ~TreeContentAnimation() {}
Tim Murraybfbcd882015-05-06 12:38:05 -070062 int frameCount = 150;
63 virtual int getFrameCount() { return frameCount; }
64 virtual void setFrameCount(int fc) {
65 if (fc > 0) {
66 frameCount = fc;
67 }
68 }
Chris Craikdb663fe2015-04-20 13:34:45 -070069 virtual void createContent(int width, int height, DisplayListCanvas* renderer) = 0;
Chris Craik03188872015-02-02 18:39:33 -080070 virtual void doFrame(int frameNr) = 0;
John Reck94c40fe2014-10-08 09:28:43 -070071
Chris Craik03188872015-02-02 18:39:33 -080072 template <class T>
Tim Murraybfbcd882015-05-06 12:38:05 -070073 static void run(int frameCount) {
Chris Craik03188872015-02-02 18:39:33 -080074 T animation;
Tim Murraybfbcd882015-05-06 12:38:05 -070075 animation.setFrameCount(frameCount);
John Reck94c40fe2014-10-08 09:28:43 -070076
Chris Craik03188872015-02-02 18:39:33 -080077 TestContext testContext;
John Reck94c40fe2014-10-08 09:28:43 -070078
Chris Craik03188872015-02-02 18:39:33 -080079 // create the native surface
80 const int width = gDisplay.w;
81 const int height = gDisplay.h;
82 sp<Surface> surface = testContext.surface();
John Reck94c40fe2014-10-08 09:28:43 -070083
Chris Craik03188872015-02-02 18:39:33 -080084 RenderNode* rootNode = new RenderNode();
85 rootNode->incStrong(nullptr);
86 rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
87 rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
88 rootNode->mutateStagingProperties().setClipToBounds(false);
89 rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
John Reck94c40fe2014-10-08 09:28:43 -070090
Chris Craik03188872015-02-02 18:39:33 -080091 ContextFactory factory;
92 std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory));
93 proxy->loadSystemProperties();
94 proxy->initialize(surface);
95 float lightX = width / 2.0;
Alan Viverette50210d92015-05-14 18:05:36 -070096 proxy->setup(width, height, dp(800.0f), 255 * 0.075, 255 * 0.15);
97 proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
John Reck94c40fe2014-10-08 09:28:43 -070098
Chris Craik03188872015-02-02 18:39:33 -080099 android::uirenderer::Rect DUMMY;
John Reck94c40fe2014-10-08 09:28:43 -0700100
Chris Craikdb663fe2015-04-20 13:34:45 -0700101 DisplayListCanvas* renderer = startRecording(rootNode);
Chris Craik03188872015-02-02 18:39:33 -0800102 animation.createContent(width, height, renderer);
103 endRecording(renderer, rootNode);
John Reck94c40fe2014-10-08 09:28:43 -0700104
John Reck7f2e5e32015-05-05 11:00:53 -0700105 // Do a few cold runs then reset the stats so that the caches are all hot
106 for (int i = 0; i < 3; i++) {
Chris Craik03188872015-02-02 18:39:33 -0800107 testContext.waitForVsync();
John Reck7f2e5e32015-05-05 11:00:53 -0700108 proxy->syncAndDrawFrame();
109 }
110 proxy->resetProfileInfo();
John Reck94c40fe2014-10-08 09:28:43 -0700111
John Reck7f2e5e32015-05-05 11:00:53 -0700112 for (int i = 0; i < animation.getFrameCount(); i++) {
113 testContext.waitForVsync();
114
Chris Craik03188872015-02-02 18:39:33 -0800115 ATRACE_NAME("UI-Draw Frame");
John Reck7f2e5e32015-05-05 11:00:53 -0700116 nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
117 UiFrameInfoBuilder(proxy->frameInfo())
118 .setVsync(vsync, vsync);
Chris Craik03188872015-02-02 18:39:33 -0800119 animation.doFrame(i);
John Reckba6adf62015-02-19 14:36:50 -0800120 proxy->syncAndDrawFrame();
John Reck94c40fe2014-10-08 09:28:43 -0700121 }
Chris Craik03188872015-02-02 18:39:33 -0800122
John Reck7f2e5e32015-05-05 11:00:53 -0700123 proxy->dumpProfileInfo(STDOUT_FILENO, 0);
Chris Craik03188872015-02-02 18:39:33 -0800124 rootNode->decStrong(nullptr);
John Reck94c40fe2014-10-08 09:28:43 -0700125 }
Chris Craik03188872015-02-02 18:39:33 -0800126};
John Reck94c40fe2014-10-08 09:28:43 -0700127
Chris Craik03188872015-02-02 18:39:33 -0800128class ShadowGridAnimation : public TreeContentAnimation {
129public:
130 std::vector< sp<RenderNode> > cards;
Chris Craikdb663fe2015-04-20 13:34:45 -0700131 void createContent(int width, int height, DisplayListCanvas* renderer) override {
Chris Craik03188872015-02-02 18:39:33 -0800132 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
133 renderer->insertReorderBarrier(true);
John Reck84e390c2015-01-05 09:42:52 -0800134
Chris Craik03188872015-02-02 18:39:33 -0800135 for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
136 for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
137 sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
Chris Craik956f3402015-04-27 16:41:00 -0700138 renderer->drawRenderNode(card.get());
Chris Craik03188872015-02-02 18:39:33 -0800139 cards.push_back(card);
140 }
141 }
142
143 renderer->insertReorderBarrier(false);
144 }
145 void doFrame(int frameNr) override {
Tim Murraybfbcd882015-05-06 12:38:05 -0700146 int curFrame = frameNr % 150;
Andreas Gampe2ab82982014-11-21 14:19:06 -0800147 for (size_t ci = 0; ci < cards.size(); ci++) {
Tim Murraybfbcd882015-05-06 12:38:05 -0700148 cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
149 cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
John Reck94c40fe2014-10-08 09:28:43 -0700150 cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
151 }
John Reck94c40fe2014-10-08 09:28:43 -0700152 }
Chris Craik03188872015-02-02 18:39:33 -0800153private:
154 sp<RenderNode> createCard(int x, int y, int width, int height) {
155 sp<RenderNode> node = new RenderNode();
156 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
157 node->mutateStagingProperties().setElevation(dp(16));
158 node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
159 node->mutateStagingProperties().mutableOutline().setShouldClip(true);
160 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
John Reck94c40fe2014-10-08 09:28:43 -0700161
Chris Craikdb663fe2015-04-20 13:34:45 -0700162 DisplayListCanvas* renderer = startRecording(node.get());
Chris Craik03188872015-02-02 18:39:33 -0800163 renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
164 endRecording(renderer, node.get());
165 return node;
166 }
167};
John Reck94c40fe2014-10-08 09:28:43 -0700168
Tim Murraybfbcd882015-05-06 12:38:05 -0700169class ShadowGrid2Animation : public TreeContentAnimation {
170public:
171 std::vector< sp<RenderNode> > cards;
172 void createContent(int width, int height, DisplayListCanvas* renderer) override {
173 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
174 renderer->insertReorderBarrier(true);
175
176 for (int x = dp(8); x < (width - dp(58)); x += dp(58)) {
177 for (int y = dp(8); y < (height - dp(58)); y += dp(58)) {
178 sp<RenderNode> card = createCard(x, y, dp(50), dp(50));
179 renderer->drawRenderNode(card.get());
180 cards.push_back(card);
181 }
182 }
183
184 renderer->insertReorderBarrier(false);
185 }
186 void doFrame(int frameNr) override {
187 int curFrame = frameNr % 150;
188 for (size_t ci = 0; ci < cards.size(); ci++) {
189 cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
190 cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
191 cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
192 }
193 }
194private:
195 sp<RenderNode> createCard(int x, int y, int width, int height) {
196 sp<RenderNode> node = new RenderNode();
197 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
198 node->mutateStagingProperties().setElevation(dp(16));
199 node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(6), 1);
200 node->mutateStagingProperties().mutableOutline().setShouldClip(true);
201 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
202
203 DisplayListCanvas* renderer = startRecording(node.get());
204 renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
205 endRecording(renderer, node.get());
206 return node;
207 }
208};
209
Chris Craik03188872015-02-02 18:39:33 -0800210class RectGridAnimation : public TreeContentAnimation {
211public:
212 sp<RenderNode> card;
Chris Craikdb663fe2015-04-20 13:34:45 -0700213 void createContent(int width, int height, DisplayListCanvas* renderer) override {
Chris Craik03188872015-02-02 18:39:33 -0800214 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
215 renderer->insertReorderBarrier(true);
216
217 card = createCard(40, 40, 200, 200);
Chris Craik956f3402015-04-27 16:41:00 -0700218 renderer->drawRenderNode(card.get());
Chris Craik03188872015-02-02 18:39:33 -0800219
220 renderer->insertReorderBarrier(false);
221 }
222 void doFrame(int frameNr) override {
Tim Murraybfbcd882015-05-06 12:38:05 -0700223 int curFrame = frameNr % 150;
224 card->mutateStagingProperties().setTranslationX(curFrame);
225 card->mutateStagingProperties().setTranslationY(curFrame);
Chris Craik03188872015-02-02 18:39:33 -0800226 card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
227 }
228private:
229 sp<RenderNode> createCard(int x, int y, int width, int height) {
230 sp<RenderNode> node = new RenderNode();
231 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
232 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
233
Chris Craikdb663fe2015-04-20 13:34:45 -0700234 DisplayListCanvas* renderer = startRecording(node.get());
Chris Craik03188872015-02-02 18:39:33 -0800235 renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
236
Derek Sollenberger94394b32015-07-10 09:58:41 -0400237 SkRegion region;
Chris Craik03188872015-02-02 18:39:33 -0800238 for (int xOffset = 0; xOffset < width; xOffset+=2) {
239 for (int yOffset = 0; yOffset < height; yOffset+=2) {
Derek Sollenberger94394b32015-07-10 09:58:41 -0400240 region.op(xOffset, yOffset, xOffset + 1, yOffset + 1, SkRegion::kUnion_Op);
Chris Craik03188872015-02-02 18:39:33 -0800241 }
242 }
Chris Craik03188872015-02-02 18:39:33 -0800243
244 SkPaint paint;
245 paint.setColor(0xff00ffff);
Derek Sollenberger94394b32015-07-10 09:58:41 -0400246 renderer->drawRegion(region, paint);
Chris Craik03188872015-02-02 18:39:33 -0800247
248 endRecording(renderer, node.get());
249 return node;
250 }
251};
252
Chris Craik117bdbc2015-02-05 10:12:38 -0800253class OvalAnimation : public TreeContentAnimation {
254public:
255 sp<RenderNode> card;
Chris Craikdb663fe2015-04-20 13:34:45 -0700256 void createContent(int width, int height, DisplayListCanvas* renderer) override {
Chris Craik117bdbc2015-02-05 10:12:38 -0800257 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
258 renderer->insertReorderBarrier(true);
259
Chris Craik08fa43f2015-02-09 18:58:32 -0800260 card = createCard(40, 40, 400, 400);
Chris Craik956f3402015-04-27 16:41:00 -0700261 renderer->drawRenderNode(card.get());
Chris Craik117bdbc2015-02-05 10:12:38 -0800262
263 renderer->insertReorderBarrier(false);
264 }
265
266 void doFrame(int frameNr) override {
Tim Murraybfbcd882015-05-06 12:38:05 -0700267 int curFrame = frameNr % 150;
268 card->mutateStagingProperties().setTranslationX(curFrame);
269 card->mutateStagingProperties().setTranslationY(curFrame);
Chris Craik117bdbc2015-02-05 10:12:38 -0800270 card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
271 }
272private:
273 sp<RenderNode> createCard(int x, int y, int width, int height) {
274 sp<RenderNode> node = new RenderNode();
275 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
276 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
277
Chris Craikdb663fe2015-04-20 13:34:45 -0700278 DisplayListCanvas* renderer = startRecording(node.get());
Chris Craik117bdbc2015-02-05 10:12:38 -0800279
280 SkPaint paint;
281 paint.setAntiAlias(true);
Chris Craik08fa43f2015-02-09 18:58:32 -0800282 paint.setColor(0xFF000000);
Chris Craik117bdbc2015-02-05 10:12:38 -0800283 renderer->drawOval(0, 0, width, height, paint);
284
285 endRecording(renderer, node.get());
286 return node;
287 }
288};
289
John Reck149173d2015-08-10 09:52:29 -0700290class PartialInvalTest : public TreeContentAnimation {
291public:
292 std::vector< sp<RenderNode> > cards;
293 void createContent(int width, int height, DisplayListCanvas* renderer) override {
294 static SkColor COLORS[] = {
295 0xFFF44336,
296 0xFF9C27B0,
297 0xFF2196F3,
298 0xFF4CAF50,
299 };
300
301 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
302
303 for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
304 for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
305 sp<RenderNode> card = createCard(x, y, dp(100), dp(100),
306 COLORS[static_cast<int>((y / dp(116))) % 4]);
307 renderer->drawRenderNode(card.get());
308 cards.push_back(card);
309 }
310 }
311 }
312 void doFrame(int frameNr) override {
313 int curFrame = frameNr % 150;
314 cards[0]->mutateStagingProperties().setTranslationX(curFrame);
315 cards[0]->mutateStagingProperties().setTranslationY(curFrame);
316 cards[0]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
317
318 DisplayListCanvas* renderer = startRecording(cards[0].get());
319 renderer->drawColor(interpolateColor(curFrame / 150.0f, 0xFFF44336, 0xFFF8BBD0),
320 SkXfermode::kSrcOver_Mode);
321 endRecording(renderer, cards[0].get());
322 }
323
324 static SkColor interpolateColor(float fraction, SkColor start, SkColor end) {
325 int startA = (start >> 24) & 0xff;
326 int startR = (start >> 16) & 0xff;
327 int startG = (start >> 8) & 0xff;
328 int startB = start & 0xff;
329
330 int endA = (end >> 24) & 0xff;
331 int endR = (end >> 16) & 0xff;
332 int endG = (end >> 8) & 0xff;
333 int endB = end & 0xff;
334
335 return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
336 (int)((startR + (int)(fraction * (endR - startR))) << 16) |
337 (int)((startG + (int)(fraction * (endG - startG))) << 8) |
338 (int)((startB + (int)(fraction * (endB - startB))));
339 }
340private:
341 sp<RenderNode> createCard(int x, int y, int width, int height, SkColor color) {
342 sp<RenderNode> node = new RenderNode();
343 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
344 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
345
346 DisplayListCanvas* renderer = startRecording(node.get());
347 renderer->drawColor(color, SkXfermode::kSrcOver_Mode);
348 endRecording(renderer, node.get());
349 return node;
350 }
351};
352
Chris Craik03188872015-02-02 18:39:33 -0800353struct cstr_cmp {
354 bool operator()(const char *a, const char *b) const {
355 return std::strcmp(a, b) < 0;
356 }
357};
358
Tim Murraybfbcd882015-05-06 12:38:05 -0700359typedef void (*testProc)(int);
Chris Craik03188872015-02-02 18:39:33 -0800360
361std::map<const char*, testProc, cstr_cmp> gTestMap {
362 {"shadowgrid", TreeContentAnimation::run<ShadowGridAnimation>},
Tim Murraybfbcd882015-05-06 12:38:05 -0700363 {"shadowgrid2", TreeContentAnimation::run<ShadowGrid2Animation>},
Chris Craik03188872015-02-02 18:39:33 -0800364 {"rectgrid", TreeContentAnimation::run<RectGridAnimation> },
Chris Craik117bdbc2015-02-05 10:12:38 -0800365 {"oval", TreeContentAnimation::run<OvalAnimation> },
John Reck149173d2015-08-10 09:52:29 -0700366 {"partialinval", TreeContentAnimation::run<PartialInvalTest> },
Chris Craik03188872015-02-02 18:39:33 -0800367};
368
John Reckb7dd29e2015-10-06 13:28:17 -0700369static int gFrameCount = 150;
370static int gRepeatCount = 1;
371static std::vector<testProc> gRunTests;
372
373static void printHelp() {
374 printf("\
375USAGE: hwuitest [OPTIONS] <TESTNAME>\n\
376\n\
377OPTIONS:\n\
378 -c, --count=NUM NUM loops a test should run (example, number of frames)\n\
379 -r, --runs=NUM Repeat the test(s) NUM times\n\
380 -h, --help Display this help\n\
381 --list List all tests\n\
382\n");
383}
384
385static void listTests() {
386 printf("Tests: \n");
387 for (auto&& test : gTestMap) {
388 printf("%-20s <TODO DESCRIPTION>\n", test.first);
389 }
390}
391
392static const struct option LONG_OPTIONS[] = {
393 { "frames", required_argument, nullptr, 'f' },
394 { "repeat", required_argument, nullptr, 'r' },
395 { "help", no_argument, nullptr, 'h' },
396 { "list", no_argument, nullptr, 'l' },
397 { 0, 0, 0, 0 }
398};
399
400static const char* SHORT_OPTIONS = "c:r:h";
401
402void parseOptions(int argc, char* argv[]) {
403 int c;
404 // temporary variable
405 int count;
406 bool error = false;
407 opterr = 0;
408
409 while (true) {
410
411 /* getopt_long stores the option index here. */
412 int option_index = 0;
413
414 c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
415
416 if (c == -1)
417 break;
418
419 switch (c) {
420 case 0:
421 // Option set a flag, don't need to do anything
422 // (although none of the current LONG_OPTIONS do this...)
423 break;
424
425 case 'l':
426 listTests();
427 exit(EXIT_SUCCESS);
428 break;
429
430 case 'c':
431 count = atoi(optarg);
432 if (!count) {
433 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
434 error = true;
435 } else {
436 gFrameCount = (count > 0 ? count : INT_MAX);
437 }
438 break;
439
440 case 'r':
441 count = atoi(optarg);
442 if (!count) {
443 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
444 error = true;
445 } else {
446 gRepeatCount = (count > 0 ? count : INT_MAX);
447 }
448 break;
449
450 case 'h':
451 printHelp();
452 exit(EXIT_SUCCESS);
453 break;
454
455 case '?':
456 fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
457 // fall-through
458 default:
459 error = true;
460 break;
461 }
462 }
463
464 if (error) {
465 fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
466 exit(EXIT_FAILURE);
467 }
468
469 /* Print any remaining command line arguments (not options). */
470 if (optind < argc) {
471 do {
472 const char* test = argv[optind++];
473 auto pos = gTestMap.find(test);
474 if (pos == gTestMap.end()) {
475 fprintf(stderr, "Unknown test '%s'\n", test);
476 exit(EXIT_FAILURE);
477 } else {
478 gRunTests.push_back(pos->second);
479 }
480 } while (optind < argc);
481 } else {
482 gRunTests.push_back(gTestMap["shadowgrid"]);
483 }
484}
485
Chris Craik03188872015-02-02 18:39:33 -0800486int main(int argc, char* argv[]) {
John Reckb7dd29e2015-10-06 13:28:17 -0700487 parseOptions(argc, argv);
488
489 for (int i = 0; i < gRepeatCount; i++) {
490 for (auto&& test : gRunTests) {
491 test(gFrameCount);
Tim Murray1a0f1c72015-05-06 11:37:37 -0700492 }
493 }
John Reck94c40fe2014-10-08 09:28:43 -0700494 printf("Success!\n");
495 return 0;
496}