SkiaPipelineTests.cpp revision e59dc4124a337881c0a585d3a5ce612ecd8f5e97
1/* 2 * Copyright (C) 2016 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 <gtest/gtest.h> 18#include <VectorDrawable.h> 19 20#include "AnimationContext.h" 21#include "DamageAccumulator.h" 22#include "IContextFactory.h" 23#include "pipeline/skia/SkiaDisplayList.h" 24#include "pipeline/skia/SkiaRecordingCanvas.h" 25#include "pipeline/skia/SkiaOpenGLPipeline.h" 26#include "renderthread/CanvasContext.h" 27#include "tests/common/TestUtils.h" 28#include "SkiaCanvas.h" 29#include <SkClipStack.h> 30#include <SkLiteRecorder.h> 31#include <SkSurface_Base.h> 32#include <string.h> 33 34using namespace android; 35using namespace android::uirenderer; 36using namespace android::uirenderer::renderthread; 37using namespace android::uirenderer::skiapipeline; 38 39RENDERTHREAD_TEST(SkiaPipeline, renderFrame) { 40 auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1, 41 [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { 42 redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); 43 }); 44 LayerUpdateQueue layerUpdateQueue; 45 SkRect dirty = SkRect::MakeLargest(); 46 std::vector<sp<RenderNode>> renderNodes; 47 renderNodes.push_back(redNode); 48 bool opaque = true; 49 android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1); 50 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 51 auto surface = SkSurface::MakeRasterN32Premul(1, 1); 52 surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); 53 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 54 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); 55 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); 56} 57 58RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckOpaque) { 59 auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2, 60 [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) { 61 SkPaint greenPaint; 62 greenPaint.setColor(SK_ColorGREEN); 63 greenPaint.setStyle(SkPaint::kFill_Style); 64 bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint); 65 }); 66 LayerUpdateQueue layerUpdateQueue; 67 SkRect dirty = SkRect::MakeLargest(); 68 std::vector<sp<RenderNode>> renderNodes; 69 renderNodes.push_back(halfGreenNode); 70 android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2); 71 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 72 auto surface = SkSurface::MakeRasterN32Premul(2, 2); 73 surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); 74 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 75 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface); 76 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 77 ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); 78 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface); 79 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT); 80 ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); 81} 82 83RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckDirtyRect) { 84 auto redNode = TestUtils::createSkiaNode(0, 0, 2, 2, 85 [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { 86 redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); 87 }); 88 LayerUpdateQueue layerUpdateQueue; 89 SkRect dirty = SkRect::MakeXYWH(0, 1, 2, 1); 90 std::vector<sp<RenderNode>> renderNodes; 91 renderNodes.push_back(redNode); 92 android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2); 93 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 94 auto surface = SkSurface::MakeRasterN32Premul(2, 2); 95 surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); 96 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 97 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface); 98 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 99 ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE); 100 ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED); 101 ASSERT_EQ(TestUtils::getColor(surface, 1, 1), SK_ColorRED); 102} 103 104RENDERTHREAD_TEST(SkiaPipeline, renderLayer) { 105 auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1, 106 [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { 107 redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); 108 }); 109 auto surfaceLayer1 = SkSurface::MakeRasterN32Premul(1, 1); 110 surfaceLayer1->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); 111 ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorWHITE); 112 redNode->setLayerSurface(surfaceLayer1); 113 114 //create a 2nd 2x2 layer and add it to the queue as well. 115 //make the layer's dirty area one half of the layer and verify only the dirty half is updated. 116 auto blueNode = TestUtils::createSkiaNode(0, 0, 2, 2, 117 [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) { 118 blueCanvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); 119 }); 120 auto surfaceLayer2 = SkSurface::MakeRasterN32Premul(2, 2); 121 surfaceLayer2->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); 122 ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorWHITE); 123 blueNode->setLayerSurface(surfaceLayer2); 124 125 //attach both layers to the update queue 126 LayerUpdateQueue layerUpdateQueue; 127 SkRect dirty = SkRect::MakeLargest(); 128 layerUpdateQueue.enqueueLayerWithDamage(redNode.get(), dirty); 129 layerUpdateQueue.enqueueLayerWithDamage(blueNode.get(), SkRect::MakeWH(2, 1)); 130 ASSERT_EQ(layerUpdateQueue.entries().size(), 2UL); 131 132 bool opaque = true; 133 FrameBuilder::LightGeometry lightGeometry; 134 lightGeometry.radius = 1.0f; 135 lightGeometry.center = { 0.0f, 0.0f, 0.0f }; 136 BakedOpRenderer::LightInfo lightInfo; 137 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 138 pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, lightInfo); 139 ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED); 140 ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorBLUE); 141 ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 1), SK_ColorWHITE); 142 ASSERT_TRUE(layerUpdateQueue.entries().empty()); 143 redNode->setLayerSurface(sk_sp<SkSurface>()); 144 blueNode->setLayerSurface(sk_sp<SkSurface>()); 145} 146 147RENDERTHREAD_TEST(SkiaPipeline, renderOverdraw) { 148 ScopedProperty<bool> prop(Properties::debugOverdraw, true); 149 150 auto whiteNode = TestUtils::createSkiaNode(0, 0, 1, 1, 151 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { 152 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); 153 }); 154 LayerUpdateQueue layerUpdateQueue; 155 SkRect dirty = SkRect::MakeXYWH(0, 0, 1, 1); 156 std::vector<sp<RenderNode>> renderNodes; 157 renderNodes.push_back(whiteNode); 158 bool opaque = true; 159 //empty contentDrawBounds is avoiding backdrop/content logic, which would lead to less overdraw 160 android::uirenderer::Rect contentDrawBounds(0, 0, 0, 0); 161 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 162 auto surface = SkSurface::MakeRasterN32Premul(1, 1); 163 164 // Initialize the canvas to blue. 165 surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); 166 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 167 168 // Single draw, should be white. 169 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); 170 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE); 171 172 // 1 Overdraw, should be blue blended onto white. 173 renderNodes.push_back(whiteNode); //this is the "content" node 174 renderNodes.push_back(whiteNode); //the "content" node above does not cause an overdraw, because 175 //it clips the first "background" node 176 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); 177 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0d0ff); 178 179 // 2 Overdraw, should be green blended onto white 180 renderNodes.push_back(whiteNode); 181 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); 182 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0ffd0); 183 184 // 3 Overdraw, should be pink blended onto white. 185 renderNodes.push_back(whiteNode); 186 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); 187 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffffc0c0); 188 189 // 4 Overdraw, should be red blended onto white. 190 renderNodes.push_back(whiteNode); 191 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); 192 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080); 193 194 // 5 Overdraw, should be red blended onto white. 195 renderNodes.push_back(whiteNode); 196 pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); 197 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080); 198} 199 200namespace { 201template <typename T> 202class DeferLayer : public SkSurface_Base { 203public: 204 DeferLayer() 205 : SkSurface_Base(T().imageInfo(), nullptr) { 206 } 207 SkCanvas* onNewCanvas() override { 208 return new T(); 209 } 210 sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { 211 return sk_sp<SkSurface>(); 212 } 213 sk_sp<SkImage> onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode) override { 214 return sk_sp<SkImage>(); 215 } 216 T* canvas() { return static_cast<T*>(getCanvas()); } 217 void onCopyOnWrite(ContentChangeMode) override {} 218}; 219} 220 221RENDERTHREAD_TEST(SkiaPipeline, deferRenderNodeScene) { 222 class DeferTestCanvas : public SkCanvas { 223 public: 224 DeferTestCanvas() : SkCanvas(800, 600) {} 225 void onDrawRect(const SkRect& rect, const SkPaint& paint) override { 226 SkMatrix expected; 227 switch (mDrawCounter++) { 228 case 0: 229 // background - left side 230 EXPECT_EQ(SkRect::MakeLTRB(600, 100, 700, 500), TestUtils::getClipBounds(this)); 231 expected.setTranslate(100, 100); 232 break; 233 case 1: 234 // background - top side 235 EXPECT_EQ(SkRect::MakeLTRB(100, 400, 600, 500), TestUtils::getClipBounds(this)); 236 expected.setTranslate(100, 100); 237 break; 238 case 2: 239 // content 240 EXPECT_EQ(SkRect::MakeLTRB(100, 100, 700, 500), TestUtils::getClipBounds(this)); 241 expected.setTranslate(-50, -50); 242 break; 243 case 3: 244 // overlay 245 EXPECT_EQ(SkRect::MakeLTRB(0, 0, 800, 600), TestUtils::getClipBounds(this)); 246 expected.reset(); 247 break; 248 default: 249 ADD_FAILURE() << "Too many rects observed"; 250 } 251 EXPECT_EQ(expected, getTotalMatrix()); 252 } 253 int mDrawCounter = 0; 254 }; 255 256 std::vector<sp<RenderNode>> nodes; 257 SkPaint transparentPaint; 258 transparentPaint.setAlpha(128); 259 260 // backdrop 261 nodes.push_back(TestUtils::createSkiaNode(100, 100, 700, 500, // 600x400 262 [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) { 263 canvas.drawRect(0, 0, 600, 400, transparentPaint); 264 })); 265 266 // content 267 android::uirenderer::Rect contentDrawBounds(150, 150, 650, 450); // 500x300 268 nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600, 269 [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) { 270 canvas.drawRect(0, 0, 800, 600, transparentPaint); 271 })); 272 273 // overlay 274 nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600, 275 [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) { 276 canvas.drawRect(0, 0, 800, 200, transparentPaint); 277 })); 278 279 LayerUpdateQueue layerUpdateQueue; 280 SkRect dirty = SkRect::MakeWH(800, 600); 281 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 282 sk_sp<DeferLayer<DeferTestCanvas>> surface(new DeferLayer<DeferTestCanvas>()); 283 pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface); 284 EXPECT_EQ(4, surface->canvas()->mDrawCounter); 285} 286 287RENDERTHREAD_TEST(SkiaPipeline, clipped) { 288 static const int CANVAS_WIDTH = 200; 289 static const int CANVAS_HEIGHT = 200; 290 class ClippedTestCanvas : public SkCanvas { 291 public: 292 ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) { 293 } 294 void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override { 295 EXPECT_EQ(0, mDrawCounter++); 296 EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(this)); 297 EXPECT_TRUE(getTotalMatrix().isIdentity()); 298 } 299 int mDrawCounter = 0; 300 }; 301 302 std::vector<sp<RenderNode>> nodes; 303 nodes.push_back(TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 304 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { 305 sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT)); 306 canvas.drawBitmap(*bitmap, 0, 0, nullptr); 307 })); 308 309 LayerUpdateQueue layerUpdateQueue; 310 SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40); 311 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 312 sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>()); 313 pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, 314 SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface); 315 EXPECT_EQ(1, surface->canvas()->mDrawCounter); 316} 317 318RENDERTHREAD_TEST(SkiaPipeline, clip_replace) { 319 static const int CANVAS_WIDTH = 50; 320 static const int CANVAS_HEIGHT = 50; 321 class ClipReplaceTestCanvas : public SkCanvas { 322 public: 323 ClipReplaceTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) { 324 } 325 void onDrawPaint(const SkPaint&) { 326 EXPECT_EQ(0, mDrawCounter++); 327 //TODO: this unit test is failing on the commented check below, because of a missing 328 //feature. In Snapshot::applyClip HWUI is intersecting the clip with the clip root, 329 //even for kReplace_Op clips. We need to implement the same for Skia pipelines. 330 //EXPECT_EQ(SkRect::MakeLTRB(20, 10, 30, 40), TestUtils::getClipBounds(this)) //got instead 20 0 30 50 331 // << "Expect resolved clip to be intersection of viewport clip and clip op"; 332 } 333 int mDrawCounter = 0; 334 }; 335 336 std::vector<sp<RenderNode>> nodes; 337 nodes.push_back(TestUtils::createSkiaNode(20, 20, 30, 30, 338 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { 339 canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_private_internal_do_not_use); 340 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); 341 })); 342 343 LayerUpdateQueue layerUpdateQueue; 344 SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40); 345 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 346 sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>()); 347 pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, 348 SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface); 349 EXPECT_EQ(1, surface->canvas()->mDrawCounter); 350} 351