SkiaPipelineTests.cpp revision 66b9d4486abb9e6d1edc624cd9ff522b12acece0
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(T *canvas) 205 : SkSurface_Base(canvas->imageInfo(), nullptr) 206 , mCanvas(canvas) { 207 } 208 SkCanvas* onNewCanvas() override { 209 return mCanvas; 210 } 211 sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { 212 return sk_sp<SkSurface>(); 213 } 214 sk_sp<SkImage> onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode) override { 215 return sk_sp<SkImage>(); 216 } 217 void onCopyOnWrite(ContentChangeMode) override {} 218 T* mCanvas; // bare pointer, not owned/ref'd 219}; 220} 221 222RENDERTHREAD_TEST(SkiaPipeline, deferRenderNodeScene) { 223 class DeferTestCanvas : public SkCanvas { 224 public: 225 DeferTestCanvas() : SkCanvas(800, 600) {} 226 void onDrawRect(const SkRect& rect, const SkPaint& paint) override { 227 SkMatrix expected; 228 switch (mDrawCounter++) { 229 case 0: 230 // background - left side 231 EXPECT_EQ(SkRect::MakeLTRB(600, 100, 700, 500), TestUtils::getClipBounds(this)); 232 expected.setTranslate(100, 100); 233 break; 234 case 1: 235 // background - top side 236 EXPECT_EQ(SkRect::MakeLTRB(100, 400, 600, 500), TestUtils::getClipBounds(this)); 237 expected.setTranslate(100, 100); 238 break; 239 case 2: 240 // content 241 EXPECT_EQ(SkRect::MakeLTRB(100, 100, 700, 500), TestUtils::getClipBounds(this)); 242 expected.setTranslate(-50, -50); 243 break; 244 case 3: 245 // overlay 246 EXPECT_EQ(SkRect::MakeLTRB(0, 0, 800, 600), TestUtils::getClipBounds(this)); 247 expected.reset(); 248 break; 249 default: 250 ADD_FAILURE() << "Too many rects observed"; 251 } 252 EXPECT_EQ(expected, getTotalMatrix()); 253 } 254 int mDrawCounter = 0; 255 }; 256 257 std::vector<sp<RenderNode>> nodes; 258 SkPaint transparentPaint; 259 transparentPaint.setAlpha(128); 260 261 // backdrop 262 nodes.push_back(TestUtils::createSkiaNode(100, 100, 700, 500, // 600x400 263 [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) { 264 canvas.drawRect(0, 0, 600, 400, transparentPaint); 265 })); 266 267 // content 268 android::uirenderer::Rect contentDrawBounds(150, 150, 650, 450); // 500x300 269 nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600, 270 [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) { 271 canvas.drawRect(0, 0, 800, 600, transparentPaint); 272 })); 273 274 // overlay 275 nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600, 276 [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) { 277 canvas.drawRect(0, 0, 800, 200, transparentPaint); 278 })); 279 280 LayerUpdateQueue layerUpdateQueue; 281 SkRect dirty = SkRect::MakeWH(800, 600); 282 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 283 DeferTestCanvas canvas; 284 sk_sp<SkSurface> surface(new DeferLayer<DeferTestCanvas>(&canvas)); 285 pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface); 286 EXPECT_EQ(4, canvas.mDrawCounter); 287} 288 289RENDERTHREAD_TEST(SkiaPipeline, clipped) { 290 static const int CANVAS_WIDTH = 200; 291 static const int CANVAS_HEIGHT = 200; 292 class ClippedTestCanvas : public SkCanvas { 293 public: 294 ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) { 295 } 296 void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override { 297 EXPECT_EQ(0, mDrawCounter++); 298 EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(this)); 299 EXPECT_TRUE(getTotalMatrix().isIdentity()); 300 } 301 int mDrawCounter = 0; 302 }; 303 304 std::vector<sp<RenderNode>> nodes; 305 nodes.push_back(TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 306 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { 307 sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT)); 308 canvas.drawBitmap(*bitmap, 0, 0, nullptr); 309 })); 310 311 LayerUpdateQueue layerUpdateQueue; 312 SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40); 313 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 314 ClippedTestCanvas canvas; 315 sk_sp<SkSurface> surface(new DeferLayer<ClippedTestCanvas>(&canvas)); 316 pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, 317 SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface); 318 EXPECT_EQ(1, canvas.mDrawCounter); 319} 320 321RENDERTHREAD_TEST(SkiaPipeline, clip_replace) { 322 static const int CANVAS_WIDTH = 50; 323 static const int CANVAS_HEIGHT = 50; 324 class ClipReplaceTestCanvas : public SkCanvas { 325 public: 326 ClipReplaceTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) { 327 } 328 void onDrawPaint(const SkPaint&) { 329 EXPECT_EQ(0, mDrawCounter++); 330 //TODO: this unit test is failing on the commented check below, because of a missing 331 //feature. In Snapshot::applyClip HWUI is intersecting the clip with the clip root, 332 //even for kReplace_Op clips. We need to implement the same for Skia pipelines. 333 //EXPECT_EQ(SkRect::MakeLTRB(20, 10, 30, 40), TestUtils::getClipBounds(this)) //got instead 20 0 30 50 334 // << "Expect resolved clip to be intersection of viewport clip and clip op"; 335 } 336 int mDrawCounter = 0; 337 }; 338 339 std::vector<sp<RenderNode>> nodes; 340 nodes.push_back(TestUtils::createSkiaNode(20, 20, 30, 30, 341 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { 342 canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace); 343 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); 344 })); 345 346 LayerUpdateQueue layerUpdateQueue; 347 SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40); 348 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); 349 ClipReplaceTestCanvas canvas; 350 sk_sp<SkSurface> surface(new DeferLayer<ClipReplaceTestCanvas>(&canvas)); 351 pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, 352 SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface); 353 EXPECT_EQ(1, canvas.mDrawCounter); 354} 355