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: TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)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 createContent(int width,int height,Canvas & canvas)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.enableZ(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.enableZ(false); 84 } 85 doFrame(int frameNr)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: createBitmapNode(Canvas & canvas,SkColor color,int left,int top,int width,int height)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 createSharedBitmapNode(Canvas & canvas,int left,int top,int width,int height,sk_sp<Bitmap> bitmap)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 createInfoNode(Canvas & canvas,int left,int top,int width,int height,const char * text,const char * text2)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 createColorNode(Canvas & canvas,int left,int top,int width,int height,SkColor color)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 useSingleBitmap()140 virtual bool useSingleBitmap() { return false; } 141 roundedCornerRadius()142 virtual float roundedCornerRadius() { return dp(2); } 143 144 // when true, use overlay RenderNode for dimming, otherwise apply a ColorFilter to dim image useOverlay()145 virtual bool useOverlay() { return true; } 146 createCard(int x,int y,int width,int height,bool selected)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 updateCard(int ci,int curFrame)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 canvas->finishRecording(overlay.get()); 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 Paint paint; 221 sk_sp<SkColorFilter> filter( 222 SkColorFilters::Blend((curFrame % 150) << 24, SkBlendMode::kSrcATop)); 223 paint.setColorFilter(filter); 224 sk_sp<Bitmap> bitmap = mCachedBitmaps[ci]; 225 canvas->drawBitmap(*bitmap, 0, 0, &paint); 226 canvas->finishRecording(image.get()); 227 cardcanvas->drawRenderNode(image.get()); 228 } 229 230 cardcanvas->finishRecording(card.get()); 231 } 232 }; 233 234 class TvAppNoRoundedCorner : public TvApp { 235 public: TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator)236 explicit TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {} 237 238 private: roundedCornerRadius()239 virtual float roundedCornerRadius() override { return dp(0); } 240 }; 241 242 class TvAppColorFilter : public TvApp { 243 public: TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)244 explicit TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {} 245 246 private: useOverlay()247 virtual bool useOverlay() override { return false; } 248 }; 249 250 class TvAppNoRoundedCornerColorFilter : public TvApp { 251 public: TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)252 explicit TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) 253 : TvApp(allocator) {} 254 255 private: roundedCornerRadius()256 virtual float roundedCornerRadius() override { return dp(0); } 257 useOverlay()258 virtual bool useOverlay() override { return false; } 259 }; 260