blob: 0bbf08c76c90dbc37fe789da3f1a69b99fa95989 [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>
33
John Reck94c40fe2014-10-08 09:28:43 -070034using namespace android;
35using namespace android::uirenderer;
36using namespace android::uirenderer::renderthread;
John Reck84e390c2015-01-05 09:42:52 -080037using namespace android::uirenderer::test;
John Reck94c40fe2014-10-08 09:28:43 -070038
39class ContextFactory : public IContextFactory {
40public:
Chris Craikd41c4d82015-01-05 15:51:13 -080041 virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
John Reck94c40fe2014-10-08 09:28:43 -070042 return new AnimationContext(clock);
43 }
44};
45
Chris Craikdb663fe2015-04-20 13:34:45 -070046static DisplayListCanvas* startRecording(RenderNode* node) {
Derek Sollenbergercc882b62015-07-09 15:51:20 -040047 DisplayListCanvas* renderer = new DisplayListCanvas(
48 node->stagingProperties().getWidth(), node->stagingProperties().getHeight());
John Reck94c40fe2014-10-08 09:28:43 -070049 return renderer;
50}
51
Chris Craikdb663fe2015-04-20 13:34:45 -070052static void endRecording(DisplayListCanvas* renderer, RenderNode* node) {
John Reck94c40fe2014-10-08 09:28:43 -070053 node->setStagingDisplayList(renderer->finishRecording());
54 delete renderer;
55}
56
Chris Craik03188872015-02-02 18:39:33 -080057class TreeContentAnimation {
58public:
59 virtual ~TreeContentAnimation() {}
Tim Murraybfbcd882015-05-06 12:38:05 -070060 int frameCount = 150;
61 virtual int getFrameCount() { return frameCount; }
62 virtual void setFrameCount(int fc) {
63 if (fc > 0) {
64 frameCount = fc;
65 }
66 }
Chris Craikdb663fe2015-04-20 13:34:45 -070067 virtual void createContent(int width, int height, DisplayListCanvas* renderer) = 0;
Chris Craik03188872015-02-02 18:39:33 -080068 virtual void doFrame(int frameNr) = 0;
John Reck94c40fe2014-10-08 09:28:43 -070069
Chris Craik03188872015-02-02 18:39:33 -080070 template <class T>
Tim Murraybfbcd882015-05-06 12:38:05 -070071 static void run(int frameCount) {
Chris Craik03188872015-02-02 18:39:33 -080072 T animation;
Tim Murraybfbcd882015-05-06 12:38:05 -070073 animation.setFrameCount(frameCount);
John Reck94c40fe2014-10-08 09:28:43 -070074
Chris Craik03188872015-02-02 18:39:33 -080075 TestContext testContext;
John Reck94c40fe2014-10-08 09:28:43 -070076
Chris Craik03188872015-02-02 18:39:33 -080077 // create the native surface
78 const int width = gDisplay.w;
79 const int height = gDisplay.h;
80 sp<Surface> surface = testContext.surface();
John Reck94c40fe2014-10-08 09:28:43 -070081
Chris Craik03188872015-02-02 18:39:33 -080082 RenderNode* rootNode = new RenderNode();
83 rootNode->incStrong(nullptr);
84 rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
85 rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
86 rootNode->mutateStagingProperties().setClipToBounds(false);
87 rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
John Reck94c40fe2014-10-08 09:28:43 -070088
Chris Craik03188872015-02-02 18:39:33 -080089 ContextFactory factory;
90 std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory));
91 proxy->loadSystemProperties();
92 proxy->initialize(surface);
93 float lightX = width / 2.0;
Alan Viverette50210d92015-05-14 18:05:36 -070094 proxy->setup(width, height, dp(800.0f), 255 * 0.075, 255 * 0.15);
95 proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
John Reck94c40fe2014-10-08 09:28:43 -070096
Chris Craik03188872015-02-02 18:39:33 -080097 android::uirenderer::Rect DUMMY;
John Reck94c40fe2014-10-08 09:28:43 -070098
Chris Craikdb663fe2015-04-20 13:34:45 -070099 DisplayListCanvas* renderer = startRecording(rootNode);
Chris Craik03188872015-02-02 18:39:33 -0800100 animation.createContent(width, height, renderer);
101 endRecording(renderer, rootNode);
John Reck94c40fe2014-10-08 09:28:43 -0700102
John Reck7f2e5e32015-05-05 11:00:53 -0700103 // Do a few cold runs then reset the stats so that the caches are all hot
104 for (int i = 0; i < 3; i++) {
Chris Craik03188872015-02-02 18:39:33 -0800105 testContext.waitForVsync();
John Reck7f2e5e32015-05-05 11:00:53 -0700106 proxy->syncAndDrawFrame();
107 }
108 proxy->resetProfileInfo();
John Reck94c40fe2014-10-08 09:28:43 -0700109
John Reck7f2e5e32015-05-05 11:00:53 -0700110 for (int i = 0; i < animation.getFrameCount(); i++) {
111 testContext.waitForVsync();
112
Chris Craik03188872015-02-02 18:39:33 -0800113 ATRACE_NAME("UI-Draw Frame");
John Reck7f2e5e32015-05-05 11:00:53 -0700114 nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
115 UiFrameInfoBuilder(proxy->frameInfo())
116 .setVsync(vsync, vsync);
Chris Craik03188872015-02-02 18:39:33 -0800117 animation.doFrame(i);
John Reckba6adf62015-02-19 14:36:50 -0800118 proxy->syncAndDrawFrame();
John Reck94c40fe2014-10-08 09:28:43 -0700119 }
Chris Craik03188872015-02-02 18:39:33 -0800120
John Reck7f2e5e32015-05-05 11:00:53 -0700121 proxy->dumpProfileInfo(STDOUT_FILENO, 0);
Chris Craik03188872015-02-02 18:39:33 -0800122 rootNode->decStrong(nullptr);
John Reck94c40fe2014-10-08 09:28:43 -0700123 }
Chris Craik03188872015-02-02 18:39:33 -0800124};
John Reck94c40fe2014-10-08 09:28:43 -0700125
Chris Craik03188872015-02-02 18:39:33 -0800126class ShadowGridAnimation : public TreeContentAnimation {
127public:
128 std::vector< sp<RenderNode> > cards;
Chris Craikdb663fe2015-04-20 13:34:45 -0700129 void createContent(int width, int height, DisplayListCanvas* renderer) override {
Chris Craik03188872015-02-02 18:39:33 -0800130 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
131 renderer->insertReorderBarrier(true);
John Reck84e390c2015-01-05 09:42:52 -0800132
Chris Craik03188872015-02-02 18:39:33 -0800133 for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
134 for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
135 sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
Chris Craik956f3402015-04-27 16:41:00 -0700136 renderer->drawRenderNode(card.get());
Chris Craik03188872015-02-02 18:39:33 -0800137 cards.push_back(card);
138 }
139 }
140
141 renderer->insertReorderBarrier(false);
142 }
143 void doFrame(int frameNr) override {
Tim Murraybfbcd882015-05-06 12:38:05 -0700144 int curFrame = frameNr % 150;
Andreas Gampe2ab82982014-11-21 14:19:06 -0800145 for (size_t ci = 0; ci < cards.size(); ci++) {
Tim Murraybfbcd882015-05-06 12:38:05 -0700146 cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
147 cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
John Reck94c40fe2014-10-08 09:28:43 -0700148 cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
149 }
John Reck94c40fe2014-10-08 09:28:43 -0700150 }
Chris Craik03188872015-02-02 18:39:33 -0800151private:
152 sp<RenderNode> createCard(int x, int y, int width, int height) {
153 sp<RenderNode> node = new RenderNode();
154 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
155 node->mutateStagingProperties().setElevation(dp(16));
156 node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
157 node->mutateStagingProperties().mutableOutline().setShouldClip(true);
158 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
John Reck94c40fe2014-10-08 09:28:43 -0700159
Chris Craikdb663fe2015-04-20 13:34:45 -0700160 DisplayListCanvas* renderer = startRecording(node.get());
Chris Craik03188872015-02-02 18:39:33 -0800161 renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
162 endRecording(renderer, node.get());
163 return node;
164 }
165};
John Reck94c40fe2014-10-08 09:28:43 -0700166
Tim Murraybfbcd882015-05-06 12:38:05 -0700167class ShadowGrid2Animation : public TreeContentAnimation {
168public:
169 std::vector< sp<RenderNode> > cards;
170 void createContent(int width, int height, DisplayListCanvas* renderer) override {
171 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
172 renderer->insertReorderBarrier(true);
173
174 for (int x = dp(8); x < (width - dp(58)); x += dp(58)) {
175 for (int y = dp(8); y < (height - dp(58)); y += dp(58)) {
176 sp<RenderNode> card = createCard(x, y, dp(50), dp(50));
177 renderer->drawRenderNode(card.get());
178 cards.push_back(card);
179 }
180 }
181
182 renderer->insertReorderBarrier(false);
183 }
184 void doFrame(int frameNr) override {
185 int curFrame = frameNr % 150;
186 for (size_t ci = 0; ci < cards.size(); ci++) {
187 cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
188 cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
189 cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
190 }
191 }
192private:
193 sp<RenderNode> createCard(int x, int y, int width, int height) {
194 sp<RenderNode> node = new RenderNode();
195 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
196 node->mutateStagingProperties().setElevation(dp(16));
197 node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(6), 1);
198 node->mutateStagingProperties().mutableOutline().setShouldClip(true);
199 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
200
201 DisplayListCanvas* renderer = startRecording(node.get());
202 renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
203 endRecording(renderer, node.get());
204 return node;
205 }
206};
207
Chris Craik03188872015-02-02 18:39:33 -0800208class RectGridAnimation : public TreeContentAnimation {
209public:
210 sp<RenderNode> card;
Chris Craikdb663fe2015-04-20 13:34:45 -0700211 void createContent(int width, int height, DisplayListCanvas* renderer) override {
Chris Craik03188872015-02-02 18:39:33 -0800212 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
213 renderer->insertReorderBarrier(true);
214
215 card = createCard(40, 40, 200, 200);
Chris Craik956f3402015-04-27 16:41:00 -0700216 renderer->drawRenderNode(card.get());
Chris Craik03188872015-02-02 18:39:33 -0800217
218 renderer->insertReorderBarrier(false);
219 }
220 void doFrame(int frameNr) override {
Tim Murraybfbcd882015-05-06 12:38:05 -0700221 int curFrame = frameNr % 150;
222 card->mutateStagingProperties().setTranslationX(curFrame);
223 card->mutateStagingProperties().setTranslationY(curFrame);
Chris Craik03188872015-02-02 18:39:33 -0800224 card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
225 }
226private:
227 sp<RenderNode> createCard(int x, int y, int width, int height) {
228 sp<RenderNode> node = new RenderNode();
229 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
230 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
231
Chris Craikdb663fe2015-04-20 13:34:45 -0700232 DisplayListCanvas* renderer = startRecording(node.get());
Chris Craik03188872015-02-02 18:39:33 -0800233 renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
234
Derek Sollenberger94394b32015-07-10 09:58:41 -0400235 SkRegion region;
Chris Craik03188872015-02-02 18:39:33 -0800236 for (int xOffset = 0; xOffset < width; xOffset+=2) {
237 for (int yOffset = 0; yOffset < height; yOffset+=2) {
Derek Sollenberger94394b32015-07-10 09:58:41 -0400238 region.op(xOffset, yOffset, xOffset + 1, yOffset + 1, SkRegion::kUnion_Op);
Chris Craik03188872015-02-02 18:39:33 -0800239 }
240 }
Chris Craik03188872015-02-02 18:39:33 -0800241
242 SkPaint paint;
243 paint.setColor(0xff00ffff);
Derek Sollenberger94394b32015-07-10 09:58:41 -0400244 renderer->drawRegion(region, paint);
Chris Craik03188872015-02-02 18:39:33 -0800245
246 endRecording(renderer, node.get());
247 return node;
248 }
249};
250
Chris Craik117bdbc2015-02-05 10:12:38 -0800251class OvalAnimation : public TreeContentAnimation {
252public:
253 sp<RenderNode> card;
Chris Craikdb663fe2015-04-20 13:34:45 -0700254 void createContent(int width, int height, DisplayListCanvas* renderer) override {
Chris Craik117bdbc2015-02-05 10:12:38 -0800255 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
256 renderer->insertReorderBarrier(true);
257
Chris Craik08fa43f2015-02-09 18:58:32 -0800258 card = createCard(40, 40, 400, 400);
Chris Craik956f3402015-04-27 16:41:00 -0700259 renderer->drawRenderNode(card.get());
Chris Craik117bdbc2015-02-05 10:12:38 -0800260
261 renderer->insertReorderBarrier(false);
262 }
263
264 void doFrame(int frameNr) override {
Tim Murraybfbcd882015-05-06 12:38:05 -0700265 int curFrame = frameNr % 150;
266 card->mutateStagingProperties().setTranslationX(curFrame);
267 card->mutateStagingProperties().setTranslationY(curFrame);
Chris Craik117bdbc2015-02-05 10:12:38 -0800268 card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
269 }
270private:
271 sp<RenderNode> createCard(int x, int y, int width, int height) {
272 sp<RenderNode> node = new RenderNode();
273 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
274 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
275
Chris Craikdb663fe2015-04-20 13:34:45 -0700276 DisplayListCanvas* renderer = startRecording(node.get());
Chris Craik117bdbc2015-02-05 10:12:38 -0800277
278 SkPaint paint;
279 paint.setAntiAlias(true);
Chris Craik08fa43f2015-02-09 18:58:32 -0800280 paint.setColor(0xFF000000);
Chris Craik117bdbc2015-02-05 10:12:38 -0800281 renderer->drawOval(0, 0, width, height, paint);
282
283 endRecording(renderer, node.get());
284 return node;
285 }
286};
287
John Reck149173d2015-08-10 09:52:29 -0700288class PartialInvalTest : public TreeContentAnimation {
289public:
290 std::vector< sp<RenderNode> > cards;
291 void createContent(int width, int height, DisplayListCanvas* renderer) override {
292 static SkColor COLORS[] = {
293 0xFFF44336,
294 0xFF9C27B0,
295 0xFF2196F3,
296 0xFF4CAF50,
297 };
298
299 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
300
301 for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
302 for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
303 sp<RenderNode> card = createCard(x, y, dp(100), dp(100),
304 COLORS[static_cast<int>((y / dp(116))) % 4]);
305 renderer->drawRenderNode(card.get());
306 cards.push_back(card);
307 }
308 }
309 }
310 void doFrame(int frameNr) override {
311 int curFrame = frameNr % 150;
312 cards[0]->mutateStagingProperties().setTranslationX(curFrame);
313 cards[0]->mutateStagingProperties().setTranslationY(curFrame);
314 cards[0]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
315
316 DisplayListCanvas* renderer = startRecording(cards[0].get());
317 renderer->drawColor(interpolateColor(curFrame / 150.0f, 0xFFF44336, 0xFFF8BBD0),
318 SkXfermode::kSrcOver_Mode);
319 endRecording(renderer, cards[0].get());
320 }
321
322 static SkColor interpolateColor(float fraction, SkColor start, SkColor end) {
323 int startA = (start >> 24) & 0xff;
324 int startR = (start >> 16) & 0xff;
325 int startG = (start >> 8) & 0xff;
326 int startB = start & 0xff;
327
328 int endA = (end >> 24) & 0xff;
329 int endR = (end >> 16) & 0xff;
330 int endG = (end >> 8) & 0xff;
331 int endB = end & 0xff;
332
333 return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
334 (int)((startR + (int)(fraction * (endR - startR))) << 16) |
335 (int)((startG + (int)(fraction * (endG - startG))) << 8) |
336 (int)((startB + (int)(fraction * (endB - startB))));
337 }
338private:
339 sp<RenderNode> createCard(int x, int y, int width, int height, SkColor color) {
340 sp<RenderNode> node = new RenderNode();
341 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
342 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
343
344 DisplayListCanvas* renderer = startRecording(node.get());
345 renderer->drawColor(color, SkXfermode::kSrcOver_Mode);
346 endRecording(renderer, node.get());
347 return node;
348 }
349};
350
Chris Craik03188872015-02-02 18:39:33 -0800351struct cstr_cmp {
352 bool operator()(const char *a, const char *b) const {
353 return std::strcmp(a, b) < 0;
354 }
355};
356
Tim Murraybfbcd882015-05-06 12:38:05 -0700357typedef void (*testProc)(int);
Chris Craik03188872015-02-02 18:39:33 -0800358
359std::map<const char*, testProc, cstr_cmp> gTestMap {
360 {"shadowgrid", TreeContentAnimation::run<ShadowGridAnimation>},
Tim Murraybfbcd882015-05-06 12:38:05 -0700361 {"shadowgrid2", TreeContentAnimation::run<ShadowGrid2Animation>},
Chris Craik03188872015-02-02 18:39:33 -0800362 {"rectgrid", TreeContentAnimation::run<RectGridAnimation> },
Chris Craik117bdbc2015-02-05 10:12:38 -0800363 {"oval", TreeContentAnimation::run<OvalAnimation> },
John Reck149173d2015-08-10 09:52:29 -0700364 {"partialinval", TreeContentAnimation::run<PartialInvalTest> },
Chris Craik03188872015-02-02 18:39:33 -0800365};
366
367int main(int argc, char* argv[]) {
368 const char* testName = argc > 1 ? argv[1] : "shadowgrid";
369 testProc proc = gTestMap[testName];
370 if(!proc) {
371 printf("Error: couldn't find test %s\n", testName);
372 return 1;
373 }
Tim Murray1a0f1c72015-05-06 11:37:37 -0700374 int loopCount = 1;
375 if (argc > 2) {
376 loopCount = atoi(argv[2]);
377 if (!loopCount) {
378 printf("Invalid loop count!\n");
379 return 1;
380 }
381 }
Tim Murraybfbcd882015-05-06 12:38:05 -0700382 int frameCount = 150;
383 if (argc > 3) {
384 frameCount = atoi(argv[3]);
385 if (frameCount < 1) {
386 printf("Invalid frame count!\n");
387 return 1;
388 }
389 }
Tim Murray1a0f1c72015-05-06 11:37:37 -0700390 if (loopCount < 0) {
391 loopCount = INT_MAX;
392 }
393 for (int i = 0; i < loopCount; i++) {
Tim Murraybfbcd882015-05-06 12:38:05 -0700394 proc(frameCount);
Tim Murray1a0f1c72015-05-06 11:37:37 -0700395 }
John Reck94c40fe2014-10-08 09:28:43 -0700396 printf("Success!\n");
397 return 0;
398}