| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 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 |  | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 17 | #include <VectorDrawable.h> | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 18 | #include <gtest/gtest.h> | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 19 |  | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 20 | #include <SkClipStack.h> | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 21 | #include <SkSurface_Base.h> | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 22 | #include <string.h> | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 23 | #include "AnimationContext.h" | 
|  | 24 | #include "DamageAccumulator.h" | 
|  | 25 | #include "IContextFactory.h" | 
| Mike Reed | c2dbc03 | 2019-07-25 12:28:29 -0400 | [diff] [blame] | 26 | #include "hwui/Paint.h" | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 27 | #include "SkiaCanvas.h" | 
|  | 28 | #include "pipeline/skia/SkiaDisplayList.h" | 
|  | 29 | #include "pipeline/skia/SkiaOpenGLPipeline.h" | 
|  | 30 | #include "pipeline/skia/SkiaRecordingCanvas.h" | 
| John Reck | 283bb46 | 2018-12-13 16:40:14 -0800 | [diff] [blame] | 31 | #include "pipeline/skia/SkiaUtils.h" | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 32 | #include "renderthread/CanvasContext.h" | 
| John Reck | 23462d8 | 2019-05-29 16:55:06 -0700 | [diff] [blame] | 33 | #include "tests/common/TestContext.h" | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 34 | #include "tests/common/TestUtils.h" | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 35 |  | 
| John Reck | 0fa0cbc | 2019-04-05 16:57:46 -0700 | [diff] [blame] | 36 | #include <gui/BufferItemConsumer.h> | 
|  | 37 | #include <gui/Surface.h> | 
|  | 38 |  | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 39 | using namespace android; | 
|  | 40 | using namespace android::uirenderer; | 
|  | 41 | using namespace android::uirenderer::renderthread; | 
|  | 42 | using namespace android::uirenderer::skiapipeline; | 
|  | 43 |  | 
| Greg Daniel | 98c78dad | 2017-01-04 14:45:56 -0500 | [diff] [blame] | 44 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) { | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 45 | auto redNode = TestUtils::createSkiaNode( | 
|  | 46 | 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { | 
|  | 47 | redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); | 
|  | 48 | }); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 49 | LayerUpdateQueue layerUpdateQueue; | 
| Mike Reed | f3338bd | 2018-10-09 11:54:39 -0400 | [diff] [blame] | 50 | SkRect dirty = SkRectMakeLargest(); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 51 | std::vector<sp<RenderNode>> renderNodes; | 
|  | 52 | renderNodes.push_back(redNode); | 
|  | 53 | bool opaque = true; | 
|  | 54 | android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1); | 
|  | 55 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
|  | 56 | auto surface = SkSurface::MakeRasterN32Premul(1, 1); | 
|  | 57 | surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); | 
|  | 58 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 59 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 60 | SkMatrix::I()); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 61 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); | 
|  | 62 | } | 
|  | 63 |  | 
| Greg Daniel | 98c78dad | 2017-01-04 14:45:56 -0500 | [diff] [blame] | 64 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) { | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 65 | auto halfGreenNode = TestUtils::createSkiaNode( | 
|  | 66 | 0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) { | 
| Mike Reed | c2dbc03 | 2019-07-25 12:28:29 -0400 | [diff] [blame] | 67 | Paint greenPaint; | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 68 | greenPaint.setColor(SK_ColorGREEN); | 
|  | 69 | greenPaint.setStyle(SkPaint::kFill_Style); | 
|  | 70 | bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint); | 
|  | 71 | }); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 72 | LayerUpdateQueue layerUpdateQueue; | 
| Mike Reed | f3338bd | 2018-10-09 11:54:39 -0400 | [diff] [blame] | 73 | SkRect dirty = SkRectMakeLargest(); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 74 | std::vector<sp<RenderNode>> renderNodes; | 
|  | 75 | renderNodes.push_back(halfGreenNode); | 
|  | 76 | android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2); | 
|  | 77 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
|  | 78 | auto surface = SkSurface::MakeRasterN32Premul(2, 2); | 
|  | 79 | surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); | 
|  | 80 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 81 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface, | 
|  | 82 | SkMatrix::I()); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 83 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); | 
|  | 84 | ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 85 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface, | 
|  | 86 | SkMatrix::I()); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 87 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT); | 
|  | 88 | ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); | 
|  | 89 | } | 
|  | 90 |  | 
| Greg Daniel | 98c78dad | 2017-01-04 14:45:56 -0500 | [diff] [blame] | 91 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) { | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 92 | auto redNode = TestUtils::createSkiaNode( | 
|  | 93 | 0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { | 
|  | 94 | redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); | 
|  | 95 | }); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 96 | LayerUpdateQueue layerUpdateQueue; | 
|  | 97 | SkRect dirty = SkRect::MakeXYWH(0, 1, 2, 1); | 
|  | 98 | std::vector<sp<RenderNode>> renderNodes; | 
|  | 99 | renderNodes.push_back(redNode); | 
|  | 100 | android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2); | 
|  | 101 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
|  | 102 | auto surface = SkSurface::MakeRasterN32Premul(2, 2); | 
|  | 103 | surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); | 
|  | 104 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 105 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface, | 
|  | 106 | SkMatrix::I()); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 107 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); | 
|  | 108 | ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE); | 
|  | 109 | ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED); | 
|  | 110 | ASSERT_EQ(TestUtils::getColor(surface, 1, 1), SK_ColorRED); | 
|  | 111 | } | 
|  | 112 |  | 
| Greg Daniel | 98c78dad | 2017-01-04 14:45:56 -0500 | [diff] [blame] | 113 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) { | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 114 | auto redNode = TestUtils::createSkiaNode( | 
|  | 115 | 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { | 
|  | 116 | redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); | 
|  | 117 | }); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 118 | auto surfaceLayer1 = SkSurface::MakeRasterN32Premul(1, 1); | 
|  | 119 | surfaceLayer1->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); | 
|  | 120 | ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorWHITE); | 
|  | 121 | redNode->setLayerSurface(surfaceLayer1); | 
|  | 122 |  | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 123 | // create a 2nd 2x2 layer and add it to the queue as well. | 
|  | 124 | // make the layer's dirty area one half of the layer and verify only the dirty half is updated. | 
|  | 125 | auto blueNode = TestUtils::createSkiaNode( | 
|  | 126 | 0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) { | 
|  | 127 | blueCanvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); | 
|  | 128 | }); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 129 | auto surfaceLayer2 = SkSurface::MakeRasterN32Premul(2, 2); | 
|  | 130 | surfaceLayer2->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); | 
|  | 131 | ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorWHITE); | 
|  | 132 | blueNode->setLayerSurface(surfaceLayer2); | 
|  | 133 |  | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 134 | // attach both layers to the update queue | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 135 | LayerUpdateQueue layerUpdateQueue; | 
| Mike Reed | f3338bd | 2018-10-09 11:54:39 -0400 | [diff] [blame] | 136 | SkRect dirty = SkRectMakeLargest(); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 137 | layerUpdateQueue.enqueueLayerWithDamage(redNode.get(), dirty); | 
|  | 138 | layerUpdateQueue.enqueueLayerWithDamage(blueNode.get(), SkRect::MakeWH(2, 1)); | 
|  | 139 | ASSERT_EQ(layerUpdateQueue.entries().size(), 2UL); | 
|  | 140 |  | 
|  | 141 | bool opaque = true; | 
| John Reck | d9d7f12 | 2018-05-03 14:40:56 -0700 | [diff] [blame] | 142 | LightGeometry lightGeometry; | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 143 | lightGeometry.radius = 1.0f; | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 144 | lightGeometry.center = {0.0f, 0.0f, 0.0f}; | 
| John Reck | d9d7f12 | 2018-05-03 14:40:56 -0700 | [diff] [blame] | 145 | LightInfo lightInfo; | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 146 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
| Peiyong Lin | 1f6aa12 | 2018-09-10 16:28:08 -0700 | [diff] [blame] | 147 | pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, lightInfo); | 
| Stan Iliev | 500a0c3 | 2016-10-26 10:30:09 -0400 | [diff] [blame] | 148 | ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED); | 
|  | 149 | ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorBLUE); | 
|  | 150 | ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 1), SK_ColorWHITE); | 
|  | 151 | ASSERT_TRUE(layerUpdateQueue.entries().empty()); | 
|  | 152 | redNode->setLayerSurface(sk_sp<SkSurface>()); | 
|  | 153 | blueNode->setLayerSurface(sk_sp<SkSurface>()); | 
|  | 154 | } | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 155 |  | 
| Greg Daniel | 98c78dad | 2017-01-04 14:45:56 -0500 | [diff] [blame] | 156 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) { | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 157 | ScopedProperty<bool> prop(Properties::debugOverdraw, true); | 
|  | 158 |  | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 159 | auto whiteNode = TestUtils::createSkiaNode( | 
|  | 160 | 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { | 
|  | 161 | canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); | 
|  | 162 | }); | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 163 | LayerUpdateQueue layerUpdateQueue; | 
|  | 164 | SkRect dirty = SkRect::MakeXYWH(0, 0, 1, 1); | 
|  | 165 | std::vector<sp<RenderNode>> renderNodes; | 
|  | 166 | renderNodes.push_back(whiteNode); | 
|  | 167 | bool opaque = true; | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 168 | // empty contentDrawBounds is avoiding backdrop/content logic, which would lead to less overdraw | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 169 | android::uirenderer::Rect contentDrawBounds(0, 0, 0, 0); | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 170 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
|  | 171 | auto surface = SkSurface::MakeRasterN32Premul(1, 1); | 
|  | 172 |  | 
|  | 173 | // Initialize the canvas to blue. | 
|  | 174 | surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); | 
|  | 175 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); | 
|  | 176 |  | 
|  | 177 | // Single draw, should be white. | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 178 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 179 | SkMatrix::I()); | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 180 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE); | 
|  | 181 |  | 
|  | 182 | // 1 Overdraw, should be blue blended onto white. | 
| Matt Sarett | 341480b | 2017-01-23 19:45:42 -0500 | [diff] [blame] | 183 | renderNodes.push_back(whiteNode); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 184 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 185 | SkMatrix::I()); | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 186 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0d0ff); | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 187 |  | 
|  | 188 | // 2 Overdraw, should be green blended onto white | 
|  | 189 | renderNodes.push_back(whiteNode); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 190 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 191 | SkMatrix::I()); | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 192 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0ffd0); | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 193 |  | 
|  | 194 | // 3 Overdraw, should be pink blended onto white. | 
|  | 195 | renderNodes.push_back(whiteNode); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 196 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 197 | SkMatrix::I()); | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 198 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffffc0c0); | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 199 |  | 
|  | 200 | // 4 Overdraw, should be red blended onto white. | 
|  | 201 | renderNodes.push_back(whiteNode); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 202 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 203 | SkMatrix::I()); | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 204 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080); | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 205 |  | 
|  | 206 | // 5 Overdraw, should be red blended onto white. | 
|  | 207 | renderNodes.push_back(whiteNode); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 208 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 209 | SkMatrix::I()); | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 210 | ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080); | 
| Matt Sarett | f58cc92 | 2016-11-14 18:33:38 -0500 | [diff] [blame] | 211 | } | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 212 |  | 
|  | 213 | namespace { | 
|  | 214 | template <typename T> | 
|  | 215 | class DeferLayer : public SkSurface_Base { | 
|  | 216 | public: | 
| Derek Sollenberger | 624ad83 | 2017-01-11 11:09:48 -0500 | [diff] [blame] | 217 | DeferLayer() : SkSurface_Base(T().imageInfo(), nullptr) {} | 
|  | 218 | virtual ~DeferLayer() {} | 
|  | 219 |  | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 220 | SkCanvas* onNewCanvas() override { return new T(); } | 
|  | 221 | sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; } | 
| Derek Sollenberger | dbb4bc8 | 2018-11-21 08:47:31 -0500 | [diff] [blame] | 222 | sk_sp<SkImage> onNewImageSnapshot(const SkIRect* bounds) override { return nullptr; } | 
| Stan Iliev | ed4d58c | 2016-12-14 14:05:04 -0500 | [diff] [blame] | 223 | T* canvas() { return static_cast<T*>(getCanvas()); } | 
| Ben Wagner | 9b87556 | 2021-10-28 21:42:35 +0000 | [diff] [blame] | 224 | bool onCopyOnWrite(ContentChangeMode) override { return true; } | 
| Leon Scroggins III | 71195ab | 2018-02-08 17:14:28 -0500 | [diff] [blame] | 225 | void onWritePixels(const SkPixmap&, int x, int y) override {} | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 226 | }; | 
|  | 227 | } | 
|  | 228 |  | 
| Greg Daniel | 98c78dad | 2017-01-04 14:45:56 -0500 | [diff] [blame] | 229 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, deferRenderNodeScene) { | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 230 | class DeferTestCanvas : public SkCanvas { | 
|  | 231 | public: | 
|  | 232 | DeferTestCanvas() : SkCanvas(800, 600) {} | 
|  | 233 | void onDrawRect(const SkRect& rect, const SkPaint& paint) override { | 
|  | 234 | SkMatrix expected; | 
|  | 235 | switch (mDrawCounter++) { | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 236 | case 0: | 
|  | 237 | // background - left side | 
|  | 238 | EXPECT_EQ(SkRect::MakeLTRB(600, 100, 700, 500), TestUtils::getClipBounds(this)); | 
|  | 239 | expected.setTranslate(100, 100); | 
|  | 240 | break; | 
|  | 241 | case 1: | 
|  | 242 | // background - top side | 
|  | 243 | EXPECT_EQ(SkRect::MakeLTRB(100, 400, 600, 500), TestUtils::getClipBounds(this)); | 
|  | 244 | expected.setTranslate(100, 100); | 
|  | 245 | break; | 
|  | 246 | case 2: | 
|  | 247 | // content | 
|  | 248 | EXPECT_EQ(SkRect::MakeLTRB(100, 100, 700, 500), TestUtils::getClipBounds(this)); | 
|  | 249 | expected.setTranslate(-50, -50); | 
|  | 250 | break; | 
|  | 251 | case 3: | 
|  | 252 | // overlay | 
|  | 253 | EXPECT_EQ(SkRect::MakeLTRB(0, 0, 800, 600), TestUtils::getClipBounds(this)); | 
|  | 254 | expected.reset(); | 
|  | 255 | break; | 
|  | 256 | default: | 
|  | 257 | ADD_FAILURE() << "Too many rects observed"; | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 258 | } | 
|  | 259 | EXPECT_EQ(expected, getTotalMatrix()); | 
|  | 260 | } | 
|  | 261 | int mDrawCounter = 0; | 
|  | 262 | }; | 
|  | 263 |  | 
|  | 264 | std::vector<sp<RenderNode>> nodes; | 
| Mike Reed | c2dbc03 | 2019-07-25 12:28:29 -0400 | [diff] [blame] | 265 | Paint transparentPaint; | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 266 | transparentPaint.setAlpha(128); | 
|  | 267 |  | 
|  | 268 | // backdrop | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 269 | nodes.push_back(TestUtils::createSkiaNode( | 
|  | 270 | 100, 100, 700, 500,  // 600x400 | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 271 | [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) { | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 272 | canvas.drawRect(0, 0, 600, 400, transparentPaint); | 
|  | 273 | })); | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 274 |  | 
|  | 275 | // content | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 276 | android::uirenderer::Rect contentDrawBounds(150, 150, 650, 450);  // 500x300 | 
|  | 277 | nodes.push_back(TestUtils::createSkiaNode( | 
|  | 278 | 0, 0, 800, 600, | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 279 | [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) { | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 280 | canvas.drawRect(0, 0, 800, 600, transparentPaint); | 
|  | 281 | })); | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 282 |  | 
|  | 283 | // overlay | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 284 | nodes.push_back(TestUtils::createSkiaNode( | 
|  | 285 | 0, 0, 800, 600, | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 286 | [&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) { | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 287 | canvas.drawRect(0, 0, 800, 200, transparentPaint); | 
|  | 288 | })); | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 289 |  | 
|  | 290 | LayerUpdateQueue layerUpdateQueue; | 
|  | 291 | SkRect dirty = SkRect::MakeWH(800, 600); | 
|  | 292 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
| Stan Iliev | ed4d58c | 2016-12-14 14:05:04 -0500 | [diff] [blame] | 293 | sk_sp<DeferLayer<DeferTestCanvas>> surface(new DeferLayer<DeferTestCanvas>()); | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 294 | pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface, | 
|  | 295 | SkMatrix::I()); | 
| Stan Iliev | ed4d58c | 2016-12-14 14:05:04 -0500 | [diff] [blame] | 296 | EXPECT_EQ(4, surface->canvas()->mDrawCounter); | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 297 | } | 
|  | 298 |  | 
| Greg Daniel | 98c78dad | 2017-01-04 14:45:56 -0500 | [diff] [blame] | 299 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped) { | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 300 | static const int CANVAS_WIDTH = 200; | 
|  | 301 | static const int CANVAS_HEIGHT = 200; | 
|  | 302 | class ClippedTestCanvas : public SkCanvas { | 
|  | 303 | public: | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 304 | ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {} | 
| Mike Reed | 2d1279f | 2020-12-30 09:57:25 -0500 | [diff] [blame] | 305 | void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, | 
|  | 306 | const SkPaint*) override { | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 307 | EXPECT_EQ(0, mDrawCounter++); | 
|  | 308 | EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(this)); | 
|  | 309 | EXPECT_TRUE(getTotalMatrix().isIdentity()); | 
|  | 310 | } | 
|  | 311 | int mDrawCounter = 0; | 
|  | 312 | }; | 
|  | 313 |  | 
|  | 314 | std::vector<sp<RenderNode>> nodes; | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 315 | nodes.push_back(TestUtils::createSkiaNode( | 
|  | 316 | 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 317 | [](RenderProperties& props, SkiaRecordingCanvas& canvas) { | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 318 | sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT)); | 
|  | 319 | canvas.drawBitmap(*bitmap, 0, 0, nullptr); | 
|  | 320 | })); | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 321 |  | 
|  | 322 | LayerUpdateQueue layerUpdateQueue; | 
|  | 323 | SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40); | 
|  | 324 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
| Stan Iliev | ed4d58c | 2016-12-14 14:05:04 -0500 | [diff] [blame] | 325 | sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>()); | 
| Peiyong Lin | 1f6aa12 | 2018-09-10 16:28:08 -0700 | [diff] [blame] | 326 | pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 327 | SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface, SkMatrix::I()); | 
|  | 328 | EXPECT_EQ(1, surface->canvas()->mDrawCounter); | 
|  | 329 | } | 
|  | 330 |  | 
|  | 331 | // Test renderFrame with a dirty clip and a pre-transform matrix. | 
|  | 332 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped_rotated) { | 
|  | 333 | static const int CANVAS_WIDTH = 200; | 
|  | 334 | static const int CANVAS_HEIGHT = 100; | 
|  | 335 | static const SkMatrix rotateMatrix = SkMatrix::MakeAll(0, -1, CANVAS_HEIGHT, 1, 0, 0, 0, 0, 1); | 
|  | 336 | static const SkRect dirty = SkRect::MakeLTRB(10, 20, 20, 40); | 
|  | 337 | class ClippedTestCanvas : public SkCanvas { | 
|  | 338 | public: | 
|  | 339 | ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {} | 
| Mike Reed | 2d1279f | 2020-12-30 09:57:25 -0500 | [diff] [blame] | 340 | void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, | 
|  | 341 | const SkPaint*) override { | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 342 | EXPECT_EQ(0, mDrawCounter++); | 
|  | 343 | // Expect clip to be rotated. | 
|  | 344 | EXPECT_EQ(SkRect::MakeLTRB(CANVAS_HEIGHT - dirty.fTop - dirty.height(), dirty.fLeft, | 
|  | 345 | CANVAS_HEIGHT - dirty.fTop, dirty.fLeft + dirty.width()), | 
|  | 346 | TestUtils::getClipBounds(this)); | 
|  | 347 | EXPECT_EQ(rotateMatrix, getTotalMatrix()); | 
|  | 348 | } | 
|  | 349 | int mDrawCounter = 0; | 
|  | 350 | }; | 
|  | 351 |  | 
|  | 352 | std::vector<sp<RenderNode>> nodes; | 
|  | 353 | nodes.push_back(TestUtils::createSkiaNode( | 
|  | 354 | 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, | 
|  | 355 | [](RenderProperties& props, SkiaRecordingCanvas& canvas) { | 
|  | 356 | sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT)); | 
|  | 357 | canvas.drawBitmap(*bitmap, 0, 0, nullptr); | 
|  | 358 | })); | 
|  | 359 |  | 
|  | 360 | LayerUpdateQueue layerUpdateQueue; | 
|  | 361 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
|  | 362 | sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>()); | 
|  | 363 | pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, | 
|  | 364 | SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface, rotateMatrix); | 
| Stan Iliev | ed4d58c | 2016-12-14 14:05:04 -0500 | [diff] [blame] | 365 | EXPECT_EQ(1, surface->canvas()->mDrawCounter); | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 366 | } | 
|  | 367 |  | 
| Greg Daniel | 98c78dad | 2017-01-04 14:45:56 -0500 | [diff] [blame] | 368 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) { | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 369 | static const int CANVAS_WIDTH = 50; | 
|  | 370 | static const int CANVAS_HEIGHT = 50; | 
|  | 371 | class ClipReplaceTestCanvas : public SkCanvas { | 
|  | 372 | public: | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 373 | ClipReplaceTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {} | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 374 | void onDrawPaint(const SkPaint&) { | 
|  | 375 | EXPECT_EQ(0, mDrawCounter++); | 
| Stan Iliev | b66b8bb | 2016-12-15 18:17:42 -0500 | [diff] [blame] | 376 | EXPECT_EQ(SkRect::MakeLTRB(20, 10, 30, 40), TestUtils::getClipBounds(this)) | 
|  | 377 | << "Expect resolved clip to be intersection of viewport clip and clip op"; | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 378 | } | 
|  | 379 | int mDrawCounter = 0; | 
|  | 380 | }; | 
|  | 381 |  | 
|  | 382 | std::vector<sp<RenderNode>> nodes; | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 383 | nodes.push_back(TestUtils::createSkiaNode( | 
|  | 384 | 20, 20, 30, 30, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { | 
| Michael Ludwig | 70cf50c2 | 2021-07-21 17:02:39 +0000 | [diff] [blame] | 385 | canvas.replaceClipRect_deprecated(0, -20, 10, 30); | 
| John Reck | 1bcacfd | 2017-11-03 10:12:19 -0700 | [diff] [blame] | 386 | canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); | 
|  | 387 | })); | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 388 |  | 
|  | 389 | LayerUpdateQueue layerUpdateQueue; | 
|  | 390 | SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40); | 
|  | 391 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
| Stan Iliev | ed4d58c | 2016-12-14 14:05:04 -0500 | [diff] [blame] | 392 | sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>()); | 
| Peiyong Lin | 1f6aa12 | 2018-09-10 16:28:08 -0700 | [diff] [blame] | 393 | pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, | 
| Greg Daniel | c407678 | 2019-01-08 16:01:18 -0500 | [diff] [blame] | 394 | SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface, SkMatrix::I()); | 
| Stan Iliev | ed4d58c | 2016-12-14 14:05:04 -0500 | [diff] [blame] | 395 | EXPECT_EQ(1, surface->canvas()->mDrawCounter); | 
| Stan Iliev | 5277127 | 2016-11-17 09:54:38 -0500 | [diff] [blame] | 396 | } | 
| Derek Sollenberger | 5a5a648 | 2018-09-19 13:52:13 -0400 | [diff] [blame] | 397 |  | 
|  | 398 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) { | 
| John Reck | 23462d8 | 2019-05-29 16:55:06 -0700 | [diff] [blame] | 399 | test::TestContext context; | 
|  | 400 | auto surface = context.surface(); | 
| Derek Sollenberger | 5a5a648 | 2018-09-19 13:52:13 -0400 | [diff] [blame] | 401 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
|  | 402 | EXPECT_FALSE(pipeline->isSurfaceReady()); | 
| John Reck | 8ddbc59 | 2020-05-07 16:11:18 -0700 | [diff] [blame] | 403 | EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default)); | 
| Derek Sollenberger | 5a5a648 | 2018-09-19 13:52:13 -0400 | [diff] [blame] | 404 | EXPECT_TRUE(pipeline->isSurfaceReady()); | 
| John Reck | 283bb46 | 2018-12-13 16:40:14 -0800 | [diff] [blame] | 405 | renderThread.destroyRenderingContext(); | 
| Derek Sollenberger | 5a5a648 | 2018-09-19 13:52:13 -0400 | [diff] [blame] | 406 | EXPECT_FALSE(pipeline->isSurfaceReady()); | 
| John Reck | d34d6ce | 2021-01-19 21:29:24 -0500 | [diff] [blame] | 407 | LOG_ALWAYS_FATAL_IF(pipeline->isSurfaceReady()); | 
| Derek Sollenberger | 5a5a648 | 2018-09-19 13:52:13 -0400 | [diff] [blame] | 408 | } | 
| Derek Sollenberger | 5f9753d | 2020-04-01 15:59:02 -0400 | [diff] [blame] | 409 |  | 
|  | 410 | RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, pictureCallback) { | 
|  | 411 | // create a pipeline and add a picture callback | 
|  | 412 | auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); | 
|  | 413 | int callbackCount = 0; | 
|  | 414 | pipeline->setPictureCapturedCallback( | 
|  | 415 | [&callbackCount](sk_sp<SkPicture>&& picture) { callbackCount += 1; }); | 
|  | 416 |  | 
|  | 417 | // create basic red frame and render it | 
|  | 418 | auto redNode = TestUtils::createSkiaNode( | 
|  | 419 | 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { | 
|  | 420 | redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); | 
|  | 421 | }); | 
|  | 422 | LayerUpdateQueue layerUpdateQueue; | 
|  | 423 | SkRect dirty = SkRectMakeLargest(); | 
|  | 424 | std::vector<sp<RenderNode>> renderNodes; | 
|  | 425 | renderNodes.push_back(redNode); | 
|  | 426 | bool opaque = true; | 
|  | 427 | android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1); | 
|  | 428 | auto surface = SkSurface::MakeRasterN32Premul(1, 1); | 
|  | 429 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 430 | SkMatrix::I()); | 
|  | 431 |  | 
|  | 432 | // verify the callback was called | 
|  | 433 | EXPECT_EQ(1, callbackCount); | 
|  | 434 |  | 
|  | 435 | // render a second frame and check the callback count | 
|  | 436 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 437 | SkMatrix::I()); | 
|  | 438 | EXPECT_EQ(2, callbackCount); | 
|  | 439 |  | 
|  | 440 | // unset the callback, render another frame, check callback was not invoked | 
|  | 441 | pipeline->setPictureCapturedCallback(nullptr); | 
|  | 442 | pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, | 
|  | 443 | SkMatrix::I()); | 
|  | 444 | EXPECT_EQ(2, callbackCount); | 
|  | 445 | } |