Home | History | Annotate | Download | only in scenes
      1 /*
      2  * Copyright (C) 2017 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 "SkBlendMode.h"
     18 #include "TestSceneBase.h"
     19 #include "tests/common/BitmapAllocationTestUtils.h"
     20 #include "hwui/Paint.h"
     21 
     22 class TvApp;
     23 class TvAppNoRoundedCorner;
     24 class TvAppColorFilter;
     25 class TvAppNoRoundedCornerColorFilter;
     26 
     27 static bool _TvApp(BitmapAllocationTestUtils::registerBitmapAllocationScene<TvApp>(
     28         "tvapp",
     29         "A dense grid of cards:"
     30         "with rounded corner, using overlay RenderNode for dimming."));
     31 
     32 static bool _TvAppNoRoundedCorner(
     33         BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCorner>(
     34                 "tvapp_norc",
     35                 "A dense grid of cards:"
     36                 "no rounded corner, using overlay RenderNode for dimming"));
     37 
     38 static bool _TvAppColorFilter(
     39         BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppColorFilter>(
     40                 "tvapp_cf",
     41                 "A dense grid of cards:"
     42                 "with rounded corner, using ColorFilter for dimming"));
     43 
     44 static bool _TvAppNoRoundedCornerColorFilter(
     45         BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCornerColorFilter>(
     46                 "tvapp_norc_cf",
     47                 "A dense grid of cards:"
     48                 "no rounded corner, using ColorFilter for dimming"));
     49 
     50 class TvApp : public TestScene {
     51 public:
     52     explicit TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
     53             : TestScene(), mAllocator(allocator) {}
     54 
     55     sp<RenderNode> mBg;
     56     std::vector<sp<RenderNode>> mCards;
     57     std::vector<sp<RenderNode>> mInfoAreas;
     58     std::vector<sp<RenderNode>> mImages;
     59     std::vector<sp<RenderNode>> mOverlays;
     60     std::vector<sk_sp<Bitmap>> mCachedBitmaps;
     61     BitmapAllocationTestUtils::BitmapAllocator mAllocator;
     62     sk_sp<Bitmap> mSingleBitmap;
     63     int mSeed = 0;
     64     int mSeed2 = 0;
     65 
     66     void createContent(int width, int height, Canvas& canvas) override {
     67         mBg = createBitmapNode(canvas, 0xFF9C27B0, 0, 0, width, height);
     68         canvas.drawRenderNode(mBg.get());
     69 
     70         canvas.insertReorderBarrier(true);
     71         mSingleBitmap = mAllocator(dp(160), dp(120), kRGBA_8888_SkColorType,
     72                                    [](SkBitmap& skBitmap) { skBitmap.eraseColor(0xFF0000FF); });
     73 
     74         for (int y = dp(18) - dp(178); y < height - dp(18); y += dp(178)) {
     75             bool isFirstCard = true;
     76             for (int x = dp(18); x < width - dp(18); x += dp(178)) {
     77                 sp<RenderNode> card = createCard(x, y, dp(160), dp(160), isFirstCard);
     78                 isFirstCard = false;
     79                 canvas.drawRenderNode(card.get());
     80                 mCards.push_back(card);
     81             }
     82         }
     83         canvas.insertReorderBarrier(false);
     84     }
     85 
     86     void doFrame(int frameNr) override {
     87         size_t numCards = mCards.size();
     88         for (size_t ci = 0; ci < numCards; ci++) {
     89             updateCard(ci, frameNr);
     90         }
     91     }
     92 
     93 private:
     94     sp<RenderNode> createBitmapNode(Canvas& canvas, SkColor color, int left, int top, int width,
     95                                     int height) {
     96         return TestUtils::createNode(
     97                 left, top, left + width, top + height,
     98                 [this, width, height, color](RenderProperties& props, Canvas& canvas) {
     99                     sk_sp<Bitmap> bitmap =
    100                             mAllocator(width, height, kRGBA_8888_SkColorType,
    101                                        [color](SkBitmap& skBitmap) { skBitmap.eraseColor(color); });
    102                     canvas.drawBitmap(*bitmap, 0, 0, nullptr);
    103                 });
    104     }
    105 
    106     sp<RenderNode> createSharedBitmapNode(Canvas& canvas, int left, int top, int width, int height,
    107                                           sk_sp<Bitmap> bitmap) {
    108         return TestUtils::createNode(left, top, left + width, top + height,
    109                                      [bitmap](RenderProperties& props, Canvas& canvas) {
    110                                          canvas.drawBitmap(*bitmap, 0, 0, nullptr);
    111                                      });
    112     }
    113 
    114     sp<RenderNode> createInfoNode(Canvas& canvas, int left, int top, int width, int height,
    115                                   const char* text, const char* text2) {
    116         return TestUtils::createNode(left, top, left + width, top + height,
    117                                      [text, text2](RenderProperties& props, Canvas& canvas) {
    118                                          canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
    119 
    120                                          Paint paint;
    121                                          paint.setAntiAlias(true);
    122                                          paint.getSkFont().setSize(24);
    123 
    124                                          paint.setColor(Color::Black);
    125                                          TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 10, 30);
    126                                          paint.getSkFont().setSize(20);
    127                                          TestUtils::drawUtf8ToCanvas(&canvas, text2, paint, 10, 54);
    128 
    129                                      });
    130     }
    131 
    132     sp<RenderNode> createColorNode(Canvas& canvas, int left, int top, int width, int height,
    133                                    SkColor color) {
    134         return TestUtils::createNode(left, top, left + width, top + height,
    135                                      [color](RenderProperties& props, Canvas& canvas) {
    136                                          canvas.drawColor(color, SkBlendMode::kSrcOver);
    137                                      });
    138     }
    139 
    140     virtual bool useSingleBitmap() { return false; }
    141 
    142     virtual float roundedCornerRadius() { return dp(2); }
    143 
    144     // when true, use overlay RenderNode for dimming, otherwise apply a ColorFilter to dim image
    145     virtual bool useOverlay() { return true; }
    146 
    147     sp<RenderNode> createCard(int x, int y, int width, int height, bool selected) {
    148         return TestUtils::createNode(x, y, x + width, y + height, [width, height, selected, this](
    149                                                                           RenderProperties& props,
    150                                                                           Canvas& canvas) {
    151             if (selected) {
    152                 props.setElevation(dp(16));
    153                 props.setScaleX(1.2);
    154                 props.setScaleY(1.2);
    155             }
    156             props.mutableOutline().setRoundRect(0, 0, width, height, roundedCornerRadius(), 1);
    157             props.mutableOutline().setShouldClip(true);
    158 
    159             sk_sp<Bitmap> bitmap =
    160                     useSingleBitmap() ? mSingleBitmap
    161                                       : mAllocator(width, dp(120), kRGBA_8888_SkColorType,
    162                                                    [this](SkBitmap& skBitmap) {
    163                                                        skBitmap.eraseColor(0xFF000000 |
    164                                                                            ((mSeed << 3) & 0xFF));
    165                                                    });
    166             sp<RenderNode> cardImage = createSharedBitmapNode(canvas, 0, 0, width, dp(120), bitmap);
    167             canvas.drawRenderNode(cardImage.get());
    168             mCachedBitmaps.push_back(bitmap);
    169             mImages.push_back(cardImage);
    170 
    171             char buffer[128];
    172             sprintf(buffer, "Video %d-%d", mSeed, mSeed + 1);
    173             mSeed++;
    174             char buffer2[128];
    175             sprintf(buffer2, "Studio %d", mSeed2++);
    176             sp<RenderNode> infoArea =
    177                     createInfoNode(canvas, 0, dp(120), width, height, buffer, buffer2);
    178             canvas.drawRenderNode(infoArea.get());
    179             mInfoAreas.push_back(infoArea);
    180 
    181             if (useOverlay()) {
    182                 sp<RenderNode> overlayColor =
    183                         createColorNode(canvas, 0, 0, width, height, 0x00000000);
    184                 canvas.drawRenderNode(overlayColor.get());
    185                 mOverlays.push_back(overlayColor);
    186             }
    187         });
    188     }
    189 
    190     void updateCard(int ci, int curFrame) {
    191         // updating card's translation Y
    192         sp<RenderNode> card = mCards[ci];
    193         card->setPropertyFieldsDirty(RenderNode::Y);
    194         card->mutateStagingProperties().setTranslationY(curFrame % 150);
    195 
    196         // re-recording card's canvas, not necessary but to add some burden to CPU
    197         std::unique_ptr<Canvas> cardcanvas(Canvas::create_recording_canvas(
    198                 card->stagingProperties().getWidth(), card->stagingProperties().getHeight(),
    199                 card.get()));
    200         sp<RenderNode> image = mImages[ci];
    201         sp<RenderNode> infoArea = mInfoAreas[ci];
    202         cardcanvas->drawRenderNode(infoArea.get());
    203 
    204         if (useOverlay()) {
    205             cardcanvas->drawRenderNode(image.get());
    206             // re-recording card overlay's canvas, animating overlay color alpha
    207             sp<RenderNode> overlay = mOverlays[ci];
    208             std::unique_ptr<Canvas> canvas(
    209                     Canvas::create_recording_canvas(overlay->stagingProperties().getWidth(),
    210                                                     overlay->stagingProperties().getHeight(),
    211                                                     overlay.get()));
    212             canvas->drawColor((curFrame % 150) << 24, SkBlendMode::kSrcOver);
    213             overlay->setStagingDisplayList(canvas->finishRecording());
    214             cardcanvas->drawRenderNode(overlay.get());
    215         } else {
    216             // re-recording image node's canvas, animating ColorFilter
    217             std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
    218                     image->stagingProperties().getWidth(), image->stagingProperties().getHeight(),
    219                     image.get()));
    220             SkPaint paint;
    221             sk_sp<SkColorFilter> filter(
    222                     SkColorFilter::MakeModeFilter((curFrame % 150) << 24, SkBlendMode::kSrcATop));
    223             paint.setColorFilter(filter);
    224             sk_sp<Bitmap> bitmap = mCachedBitmaps[ci];
    225             canvas->drawBitmap(*bitmap, 0, 0, &paint);
    226             image->setStagingDisplayList(canvas->finishRecording());
    227             cardcanvas->drawRenderNode(image.get());
    228         }
    229 
    230         card->setStagingDisplayList(cardcanvas->finishRecording());
    231     }
    232 };
    233 
    234 class TvAppNoRoundedCorner : public TvApp {
    235 public:
    236     explicit TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
    237 
    238 private:
    239     virtual float roundedCornerRadius() override { return dp(0); }
    240 };
    241 
    242 class TvAppColorFilter : public TvApp {
    243 public:
    244     explicit TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
    245 
    246 private:
    247     virtual bool useOverlay() override { return false; }
    248 };
    249 
    250 class TvAppNoRoundedCornerColorFilter : public TvApp {
    251 public:
    252     explicit TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
    253             : TvApp(allocator) {}
    254 
    255 private:
    256     virtual float roundedCornerRadius() override { return dp(0); }
    257 
    258     virtual bool useOverlay() override { return false; }
    259 };
    260