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