RenderNodeDrawableTests.cpp revision 021693b967a2c5556dddd183eb0247df4079e1ad
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 "renderthread/CanvasContext.h" 26#include "tests/common/TestUtils.h" 27#include "SkiaCanvas.h" 28#include <SkLiteRecorder.h> 29#include <string.h> 30 31 32using namespace android; 33using namespace android::uirenderer; 34using namespace android::uirenderer::renderthread; 35using namespace android::uirenderer::skiapipeline; 36 37static sp<RenderNode> createSkiaNode(int left, int top, int right, int bottom, 38 std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup, 39 const char* name = nullptr, SkiaDisplayList* displayList = nullptr) { 40#if HWUI_NULL_GPU 41 // if RenderNodes are being sync'd/used, device info will be needed, since 42 // DeviceInfo::maxTextureSize() affects layer property 43 DeviceInfo::initialize(); 44#endif 45 sp<RenderNode> node = new RenderNode(); 46 if (name) { 47 node->setName(name); 48 } 49 RenderProperties& props = node->mutateStagingProperties(); 50 props.setLeftTopRightBottom(left, top, right, bottom); 51 if (displayList) { 52 node->setStagingDisplayList(displayList, nullptr); 53 } 54 if (setup) { 55 std::unique_ptr<SkiaRecordingCanvas> canvas(new SkiaRecordingCanvas(nullptr, 56 props.getWidth(), props.getHeight())); 57 setup(props, *canvas.get()); 58 node->setStagingDisplayList(canvas->finishRecording(), nullptr); 59 } 60 node->setPropertyFieldsDirty(0xFFFFFFFF); 61 TestUtils::syncHierarchyPropertiesAndDisplayList(node); 62 return node; 63} 64 65TEST(RenderNodeDrawable, create) { 66 auto rootNode = TestUtils::createNode(0, 0, 200, 400, 67 [](RenderProperties& props, Canvas& canvas) { 68 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver); 69 }); 70 71 auto skLiteDL = SkLiteDL::New(SkRect::MakeWH(1, 1)); 72 SkLiteRecorder canvas; 73 canvas.reset(skLiteDL.get()); 74 canvas.translate(100, 100); 75 RenderNodeDrawable drawable(rootNode.get(), &canvas); 76 77 ASSERT_EQ(drawable.getRenderNode(), rootNode.get()); 78 ASSERT_EQ(&drawable.getNodeProperties(), &rootNode->properties()); 79 ASSERT_EQ(drawable.getRecordedMatrix(), canvas.getTotalMatrix()); 80} 81 82TEST(RenderNodeDrawable, drawContent) { 83 auto surface = SkSurface::MakeRasterN32Premul(1, 1); 84 SkCanvas& canvas = *surface->getCanvas(); 85 canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); 86 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 87 88 //create a RenderNodeDrawable backed by a RenderNode backed by a SkLiteRecorder 89 auto rootNode = createSkiaNode(0, 0, 1, 1, 90 [](RenderProperties& props, SkiaRecordingCanvas& recorder) { 91 recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); 92 }); 93 RenderNodeDrawable drawable(rootNode.get(), &canvas, false); 94 95 //negative and positive Z order are drawn out of order 96 rootNode->animatorProperties().setElevation(10.0f); 97 canvas.drawDrawable(&drawable); 98 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 99 rootNode->animatorProperties().setElevation(-10.0f); 100 canvas.drawDrawable(&drawable); 101 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 102 103 //zero Z are drawn immediately 104 rootNode->animatorProperties().setElevation(0.0f); 105 canvas.drawDrawable(&drawable); 106 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); 107} 108 109//TODO: another test that verifies equal z values are drawn in order, and barriers prevent Z 110//intermixing (model after FrameBuilder zReorder) 111TEST(RenderNodeDrawable, drawAndReorder) { 112 //this test exercises StartReorderBarrierDrawable, EndReorderBarrierDrawable and 113 //SkiaRecordingCanvas 114 auto surface = SkSurface::MakeRasterN32Premul(4, 4); 115 SkCanvas& canvas = *surface->getCanvas(); 116 117 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); 118 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE); 119 120 //-z draws to all 4 pixels (RED) 121 auto redNode = createSkiaNode(0, 0, 4, 4, 122 [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { 123 redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); 124 props.setElevation(-10.0f); 125 }, "redNode"); 126 127 //0z draws to bottom 2 pixels (GREEN) 128 auto bottomHalfGreenNode = createSkiaNode(0, 0, 4, 4, 129 [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) { 130 SkPaint greenPaint; 131 greenPaint.setColor(SK_ColorGREEN); 132 greenPaint.setStyle(SkPaint::kFill_Style); 133 bottomHalfGreenCanvas.drawRect(0, 2, 4, 4, greenPaint); 134 props.setElevation(0.0f); 135 }, "bottomHalfGreenNode"); 136 137 //+z draws to right 2 pixels (BLUE) 138 auto rightHalfBlueNode = createSkiaNode(0, 0, 4, 4, 139 [](RenderProperties& props, SkiaRecordingCanvas& rightHalfBlueCanvas) { 140 SkPaint bluePaint; 141 bluePaint.setColor(SK_ColorBLUE); 142 bluePaint.setStyle(SkPaint::kFill_Style); 143 rightHalfBlueCanvas.drawRect(2, 0, 4, 4, bluePaint); 144 props.setElevation(10.0f); 145 }, "rightHalfBlueNode"); 146 147 auto rootNode = createSkiaNode(0, 0, 4, 4, 148 [&](RenderProperties& props, SkiaRecordingCanvas& rootRecorder) { 149 rootRecorder.insertReorderBarrier(true); 150 //draw in reverse Z order, so Z alters draw order 151 rootRecorder.drawRenderNode(rightHalfBlueNode.get()); 152 rootRecorder.drawRenderNode(bottomHalfGreenNode.get()); 153 rootRecorder.drawRenderNode(redNode.get()); 154 }, "rootNode"); 155 156 RenderNodeDrawable drawable3(rootNode.get(), &canvas, false); 157 canvas.drawDrawable(&drawable3); 158 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); 159 ASSERT_EQ(TestUtils::getColor(surface, 0, 3), SK_ColorGREEN); 160 ASSERT_EQ(TestUtils::getColor(surface, 3, 3), SK_ColorBLUE); 161} 162 163TEST(RenderNodeDrawable, composeOnLayer) 164{ 165 auto surface = SkSurface::MakeRasterN32Premul(1, 1); 166 SkCanvas& canvas = *surface->getCanvas(); 167 canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); 168 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 169 170 auto rootNode = createSkiaNode(0, 0, 1, 1, 171 [](RenderProperties& props, SkiaRecordingCanvas& recorder) { 172 recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); 173 }); 174 175 //attach a layer to the render node 176 auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1); 177 auto canvas2 = surfaceLayer->getCanvas(); 178 canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); 179 rootNode->setLayerSurface( surfaceLayer ); 180 181 RenderNodeDrawable drawable1(rootNode.get(), &canvas, false); 182 canvas.drawDrawable(&drawable1); 183 ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0)); 184 185 RenderNodeDrawable drawable2(rootNode.get(), &canvas, true); 186 canvas.drawDrawable(&drawable2); 187 ASSERT_EQ(SK_ColorWHITE, TestUtils::getColor(surface, 0, 0)); 188 189 RenderNodeDrawable drawable3(rootNode.get(), &canvas, false); 190 canvas.drawDrawable(&drawable3); 191 ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0)); 192 193 rootNode->setLayerSurface( sk_sp<SkSurface>() ); 194} 195 196//TODO: refactor to cover test cases from FrameBuilderTests_projectionReorder 197//validate with bounds and projection path mask. 198//TODO: research if we could hook in and mock/validate different aspects of the drawing, 199//instead of validating pixels 200TEST(RenderNodeDrawable, projectDraw) { 201 auto surface = SkSurface::MakeRasterN32Premul(1, 1); 202 SkCanvas& canvas = *surface->getCanvas(); 203 canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); 204 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); 205 206 auto redNode = createSkiaNode(0, 0, 1, 1, 207 [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { 208 redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); 209 }, "redNode"); 210 211 auto greenNodeWithRedChild = createSkiaNode(0, 0, 1, 1, 212 [&](RenderProperties& props, SkiaRecordingCanvas& greenCanvasWithRedChild) { 213 greenCanvasWithRedChild.drawRenderNode(redNode.get()); 214 greenCanvasWithRedChild.drawColor(SK_ColorGREEN, SkBlendMode::kSrcOver); 215 }, "greenNodeWithRedChild"); 216 217 auto rootNode = createSkiaNode(0, 0, 1, 1, 218 [&](RenderProperties& props, SkiaRecordingCanvas& rootCanvas) { 219 rootCanvas.drawRenderNode(greenNodeWithRedChild.get()); 220 }, "rootNode"); 221 SkiaDisplayList* rootDisplayList = static_cast<SkiaDisplayList*>( 222 (const_cast<DisplayList*>(rootNode->getDisplayList()))); 223 224 RenderNodeDrawable rootDrawable(rootNode.get(), &canvas, false); 225 canvas.drawDrawable(&rootDrawable); 226 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorGREEN); 227 228 //project redNode on rootNode, which will change the test outcome, 229 //because redNode will draw after greenNodeWithRedChild 230 rootDisplayList->mIsProjectionReceiver = true; 231 redNode->animatorProperties().setProjectBackwards(true); 232 canvas.drawDrawable(&rootDrawable); 233 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); 234} 235