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 32using namespace android; 33using namespace android::uirenderer; 34using namespace android::uirenderer::renderthread; 35using namespace android::uirenderer::test; 36 37class ContextFactory : public IContextFactory { 38public: 39 virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override { 40 return new AnimationContext(clock); 41 } 42}; 43 44static 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 52static void endRecording(DisplayListCanvas* renderer, RenderNode* node) { 53 renderer->finish(); 54 node->setStagingDisplayList(renderer->finishRecording()); 55 delete renderer; 56} 57 58class TreeContentAnimation { 59public: 60 virtual ~TreeContentAnimation() {} 61 int frameCount = 150; 62 virtual int getFrameCount() { return frameCount; } 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> 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 127class ShadowGridAnimation : public TreeContentAnimation { 128public: 129 std::vector< sp<RenderNode> > cards; 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 } 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 } 152private: 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 168class ShadowGrid2Animation : public TreeContentAnimation { 169public: 170 std::vector< sp<RenderNode> > cards; 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 } 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 } 193private: 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 209class RectGridAnimation : public TreeContentAnimation { 210public: 211 sp<RenderNode> card; 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 } 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 } 227private: 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 257class OvalAnimation : public TreeContentAnimation { 258public: 259 sp<RenderNode> card; 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 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 } 276private: 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 294struct cstr_cmp { 295 bool operator()(const char *a, const char *b) const { 296 return std::strcmp(a, b) < 0; 297 } 298}; 299 300typedef void (*testProc)(int); 301 302std::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 309int 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