Home | History | Annotate | Download | only in tests
      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:
     39     virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
     40         return new AnimationContext(clock);
     41     }
     42 };
     43 
     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 
     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:
     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 
    127 class ShadowGridAnimation : public TreeContentAnimation {
    128 public:
    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     }
    152 private:
    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;
    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     }
    193 private:
    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;
    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     }
    227 private:
    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;
    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     }
    276 private:
    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 {
    295     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 
    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