1 /*
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
17 #include <cutils/log.h>
18 #include <gui/Surface.h>
19 #include <ui/PixelFormat.h>
20
21 #include <AnimationContext.h>
22 #include <DisplayListCanvas.h>
23 #include <RenderNode.h>
24 #include <renderthread/RenderProxy.h>
25 #include <renderthread/RenderTask.h>
26
27 #include "TestContext.h"
28
29 #include <stdio.h>
30 #include <unistd.h>
31
32 using namespace android;
33 using namespace android::uirenderer;
34 using namespace android::uirenderer::renderthread;
35 using namespace android::uirenderer::test;
36
37 class ContextFactory : public IContextFactory {
38 public:
createAnimationContext(renderthread::TimeLord & clock)39 virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
40 return new AnimationContext(clock);
41 }
42 };
43
startRecording(RenderNode * node)44 static DisplayListCanvas* startRecording(RenderNode* node) {
45 DisplayListCanvas* renderer = new DisplayListCanvas();
46 renderer->setViewport(node->stagingProperties().getWidth(),
47 node->stagingProperties().getHeight());
48 renderer->prepare();
49 return renderer;
50 }
51
endRecording(DisplayListCanvas * renderer,RenderNode * node)52 static void endRecording(DisplayListCanvas* renderer, RenderNode* node) {
53 renderer->finish();
54 node->setStagingDisplayList(renderer->finishRecording());
55 delete renderer;
56 }
57
58 class TreeContentAnimation {
59 public:
~TreeContentAnimation()60 virtual ~TreeContentAnimation() {}
61 int frameCount = 150;
getFrameCount()62 virtual int getFrameCount() { return frameCount; }
setFrameCount(int fc)63 virtual void setFrameCount(int fc) {
64 if (fc > 0) {
65 frameCount = fc;
66 }
67 }
68 virtual void createContent(int width, int height, DisplayListCanvas* renderer) = 0;
69 virtual void doFrame(int frameNr) = 0;
70
71 template <class T>
run(int frameCount)72 static void run(int frameCount) {
73 T animation;
74 animation.setFrameCount(frameCount);
75
76 TestContext testContext;
77
78 // create the native surface
79 const int width = gDisplay.w;
80 const int height = gDisplay.h;
81 sp<Surface> surface = testContext.surface();
82
83 RenderNode* rootNode = new RenderNode();
84 rootNode->incStrong(nullptr);
85 rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
86 rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
87 rootNode->mutateStagingProperties().setClipToBounds(false);
88 rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
89
90 ContextFactory factory;
91 std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory));
92 proxy->loadSystemProperties();
93 proxy->initialize(surface);
94 float lightX = width / 2.0;
95 proxy->setup(width, height, dp(800.0f), 255 * 0.075, 255 * 0.15);
96 proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
97
98 android::uirenderer::Rect DUMMY;
99
100 DisplayListCanvas* renderer = startRecording(rootNode);
101 animation.createContent(width, height, renderer);
102 endRecording(renderer, rootNode);
103
104 // Do a few cold runs then reset the stats so that the caches are all hot
105 for (int i = 0; i < 3; i++) {
106 testContext.waitForVsync();
107 proxy->syncAndDrawFrame();
108 }
109 proxy->resetProfileInfo();
110
111 for (int i = 0; i < animation.getFrameCount(); i++) {
112 testContext.waitForVsync();
113
114 ATRACE_NAME("UI-Draw Frame");
115 nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
116 UiFrameInfoBuilder(proxy->frameInfo())
117 .setVsync(vsync, vsync);
118 animation.doFrame(i);
119 proxy->syncAndDrawFrame();
120 }
121
122 proxy->dumpProfileInfo(STDOUT_FILENO, 0);
123 rootNode->decStrong(nullptr);
124 }
125 };
126
127 class ShadowGridAnimation : public TreeContentAnimation {
128 public:
129 std::vector< sp<RenderNode> > cards;
createContent(int width,int height,DisplayListCanvas * renderer)130 void createContent(int width, int height, DisplayListCanvas* renderer) override {
131 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
132 renderer->insertReorderBarrier(true);
133
134 for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
135 for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
136 sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
137 renderer->drawRenderNode(card.get());
138 cards.push_back(card);
139 }
140 }
141
142 renderer->insertReorderBarrier(false);
143 }
doFrame(int frameNr)144 void doFrame(int frameNr) override {
145 int curFrame = frameNr % 150;
146 for (size_t ci = 0; ci < cards.size(); ci++) {
147 cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
148 cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
149 cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
150 }
151 }
152 private:
createCard(int x,int y,int width,int height)153 sp<RenderNode> createCard(int x, int y, int width, int height) {
154 sp<RenderNode> node = new RenderNode();
155 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
156 node->mutateStagingProperties().setElevation(dp(16));
157 node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
158 node->mutateStagingProperties().mutableOutline().setShouldClip(true);
159 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
160
161 DisplayListCanvas* renderer = startRecording(node.get());
162 renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
163 endRecording(renderer, node.get());
164 return node;
165 }
166 };
167
168 class ShadowGrid2Animation : public TreeContentAnimation {
169 public:
170 std::vector< sp<RenderNode> > cards;
createContent(int width,int height,DisplayListCanvas * renderer)171 void createContent(int width, int height, DisplayListCanvas* renderer) override {
172 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
173 renderer->insertReorderBarrier(true);
174
175 for (int x = dp(8); x < (width - dp(58)); x += dp(58)) {
176 for (int y = dp(8); y < (height - dp(58)); y += dp(58)) {
177 sp<RenderNode> card = createCard(x, y, dp(50), dp(50));
178 renderer->drawRenderNode(card.get());
179 cards.push_back(card);
180 }
181 }
182
183 renderer->insertReorderBarrier(false);
184 }
doFrame(int frameNr)185 void doFrame(int frameNr) override {
186 int curFrame = frameNr % 150;
187 for (size_t ci = 0; ci < cards.size(); ci++) {
188 cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
189 cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
190 cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
191 }
192 }
193 private:
createCard(int x,int y,int width,int height)194 sp<RenderNode> createCard(int x, int y, int width, int height) {
195 sp<RenderNode> node = new RenderNode();
196 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
197 node->mutateStagingProperties().setElevation(dp(16));
198 node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(6), 1);
199 node->mutateStagingProperties().mutableOutline().setShouldClip(true);
200 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
201
202 DisplayListCanvas* renderer = startRecording(node.get());
203 renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
204 endRecording(renderer, node.get());
205 return node;
206 }
207 };
208
209 class RectGridAnimation : public TreeContentAnimation {
210 public:
211 sp<RenderNode> card;
createContent(int width,int height,DisplayListCanvas * renderer)212 void createContent(int width, int height, DisplayListCanvas* renderer) override {
213 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
214 renderer->insertReorderBarrier(true);
215
216 card = createCard(40, 40, 200, 200);
217 renderer->drawRenderNode(card.get());
218
219 renderer->insertReorderBarrier(false);
220 }
doFrame(int frameNr)221 void doFrame(int frameNr) override {
222 int curFrame = frameNr % 150;
223 card->mutateStagingProperties().setTranslationX(curFrame);
224 card->mutateStagingProperties().setTranslationY(curFrame);
225 card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
226 }
227 private:
createCard(int x,int y,int width,int height)228 sp<RenderNode> createCard(int x, int y, int width, int height) {
229 sp<RenderNode> node = new RenderNode();
230 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
231 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
232
233 DisplayListCanvas* renderer = startRecording(node.get());
234 renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
235
236 float rects[width * height];
237 int index = 0;
238 for (int xOffset = 0; xOffset < width; xOffset+=2) {
239 for (int yOffset = 0; yOffset < height; yOffset+=2) {
240 rects[index++] = xOffset;
241 rects[index++] = yOffset;
242 rects[index++] = xOffset + 1;
243 rects[index++] = yOffset + 1;
244 }
245 }
246 int count = width * height;
247
248 SkPaint paint;
249 paint.setColor(0xff00ffff);
250 renderer->drawRects(rects, count, &paint);
251
252 endRecording(renderer, node.get());
253 return node;
254 }
255 };
256
257 class OvalAnimation : public TreeContentAnimation {
258 public:
259 sp<RenderNode> card;
createContent(int width,int height,DisplayListCanvas * renderer)260 void createContent(int width, int height, DisplayListCanvas* renderer) override {
261 renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
262 renderer->insertReorderBarrier(true);
263
264 card = createCard(40, 40, 400, 400);
265 renderer->drawRenderNode(card.get());
266
267 renderer->insertReorderBarrier(false);
268 }
269
doFrame(int frameNr)270 void doFrame(int frameNr) override {
271 int curFrame = frameNr % 150;
272 card->mutateStagingProperties().setTranslationX(curFrame);
273 card->mutateStagingProperties().setTranslationY(curFrame);
274 card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
275 }
276 private:
createCard(int x,int y,int width,int height)277 sp<RenderNode> createCard(int x, int y, int width, int height) {
278 sp<RenderNode> node = new RenderNode();
279 node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
280 node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
281
282 DisplayListCanvas* renderer = startRecording(node.get());
283
284 SkPaint paint;
285 paint.setAntiAlias(true);
286 paint.setColor(0xFF000000);
287 renderer->drawOval(0, 0, width, height, paint);
288
289 endRecording(renderer, node.get());
290 return node;
291 }
292 };
293
294 struct cstr_cmp {
operator ()cstr_cmp295 bool operator()(const char *a, const char *b) const {
296 return std::strcmp(a, b) < 0;
297 }
298 };
299
300 typedef void (*testProc)(int);
301
302 std::map<const char*, testProc, cstr_cmp> gTestMap {
303 {"shadowgrid", TreeContentAnimation::run<ShadowGridAnimation>},
304 {"shadowgrid2", TreeContentAnimation::run<ShadowGrid2Animation>},
305 {"rectgrid", TreeContentAnimation::run<RectGridAnimation> },
306 {"oval", TreeContentAnimation::run<OvalAnimation> },
307 };
308
main(int argc,char * argv[])309 int main(int argc, char* argv[]) {
310 const char* testName = argc > 1 ? argv[1] : "shadowgrid";
311 testProc proc = gTestMap[testName];
312 if(!proc) {
313 printf("Error: couldn't find test %s\n", testName);
314 return 1;
315 }
316 int loopCount = 1;
317 if (argc > 2) {
318 loopCount = atoi(argv[2]);
319 if (!loopCount) {
320 printf("Invalid loop count!\n");
321 return 1;
322 }
323 }
324 int frameCount = 150;
325 if (argc > 3) {
326 frameCount = atoi(argv[3]);
327 if (frameCount < 1) {
328 printf("Invalid frame count!\n");
329 return 1;
330 }
331 }
332 if (loopCount < 0) {
333 loopCount = INT_MAX;
334 }
335 for (int i = 0; i < loopCount; i++) {
336 proc(frameCount);
337 }
338 printf("Success!\n");
339 return 0;
340 }
341