TestUtils.h revision 15c3f19a445b8df575911a16e8a6dba755a084b5
1/* 2 * Copyright (C) 2015 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#ifndef TEST_UTILS_H 17#define TEST_UTILS_H 18 19#include <DeviceInfo.h> 20#include <DisplayList.h> 21#include <Matrix.h> 22#include <Rect.h> 23#include <RenderNode.h> 24#include <renderstate/RenderState.h> 25#include <renderthread/RenderThread.h> 26#include <Snapshot.h> 27 28#if HWUI_NEW_OPS 29#include <RecordedOp.h> 30#include <RecordingCanvas.h> 31#else 32#include <DisplayListOp.h> 33#include <DisplayListCanvas.h> 34#endif 35 36#include <memory> 37 38namespace android { 39namespace uirenderer { 40 41#if HWUI_NEW_OPS 42typedef RecordingCanvas TestCanvas; 43#else 44typedef DisplayListCanvas TestCanvas; 45#endif 46 47#define EXPECT_MATRIX_APPROX_EQ(a, b) \ 48 EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b)) 49 50#define EXPECT_RECT_APPROX_EQ(a, b) \ 51 EXPECT_TRUE(MathUtils::areEqual(a.left, b.left) \ 52 && MathUtils::areEqual(a.top, b.top) \ 53 && MathUtils::areEqual(a.right, b.right) \ 54 && MathUtils::areEqual(a.bottom, b.bottom)); 55 56/** 57 * Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope 58 * (for e.g. accessing its RenderState) 59 */ 60#define RENDERTHREAD_TEST(test_case_name, test_name) \ 61 class test_case_name##_##test_name##_RenderThreadTest { \ 62 public: \ 63 static void doTheThing(renderthread::RenderThread& renderThread); \ 64 }; \ 65 TEST(test_case_name, test_name) { \ 66 TestUtils::runOnRenderThread(test_case_name##_##test_name##_RenderThreadTest::doTheThing); \ 67 }; \ 68 void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread) 69 70class TestUtils { 71public: 72 class SignalingDtor { 73 public: 74 SignalingDtor() 75 : mSignal(nullptr) {} 76 SignalingDtor(int* signal) 77 : mSignal(signal) {} 78 void setSignal(int* signal) { 79 mSignal = signal; 80 } 81 ~SignalingDtor() { 82 if (mSignal) { 83 (*mSignal)++; 84 } 85 } 86 private: 87 int* mSignal; 88 }; 89 90 static bool matricesAreApproxEqual(const Matrix4& a, const Matrix4& b) { 91 for (int i = 0; i < 16; i++) { 92 if (!MathUtils::areEqual(a[i], b[i])) { 93 return false; 94 } 95 } 96 return true; 97 } 98 99 static std::unique_ptr<Snapshot> makeSnapshot(const Matrix4& transform, const Rect& clip) { 100 std::unique_ptr<Snapshot> snapshot(new Snapshot()); 101 snapshot->clip(clip.left, clip.top, clip.right, clip.bottom, SkRegion::kReplace_Op); 102 *(snapshot->transform) = transform; 103 return snapshot; 104 } 105 106 static SkBitmap createSkBitmap(int width, int height, 107 SkColorType colorType = kN32_SkColorType) { 108 SkBitmap bitmap; 109 SkImageInfo info = SkImageInfo::Make(width, height, 110 colorType, kPremul_SkAlphaType); 111 bitmap.setInfo(info); 112 bitmap.allocPixels(info); 113 return bitmap; 114 } 115 116 template<class CanvasType> 117 static std::unique_ptr<DisplayList> createDisplayList(int width, int height, 118 std::function<void(CanvasType& canvas)> canvasCallback) { 119 CanvasType canvas(width, height); 120 canvasCallback(canvas); 121 return std::unique_ptr<DisplayList>(canvas.finishRecording()); 122 } 123 124 static sp<RenderNode> createNode(int left, int top, int right, int bottom, 125 std::function<void(RenderProperties& props, TestCanvas& canvas)> setup) { 126#if HWUI_NULL_GPU 127 // if RenderNodes are being sync'd/used, device info will be needed, since 128 // DeviceInfo::maxTextureSize() affects layer property 129 DeviceInfo::initialize(); 130#endif 131 132 sp<RenderNode> node = new RenderNode(); 133 RenderProperties& props = node->mutateStagingProperties(); 134 props.setLeftTopRightBottom(left, top, right, bottom); 135 if (setup) { 136 TestCanvas canvas(props.getWidth(), props.getHeight()); 137 setup(props, canvas); 138 node->setStagingDisplayList(canvas.finishRecording()); 139 } 140 node->setPropertyFieldsDirty(0xFFFFFFFF); 141 return node; 142 } 143 144 static void recordNode(RenderNode& node, 145 std::function<void(TestCanvas&)> contentCallback) { 146 TestCanvas canvas(node.stagingProperties().getWidth(), 147 node.stagingProperties().getHeight()); 148 contentCallback(canvas); 149 node.setStagingDisplayList(canvas.finishRecording()); 150 } 151 152 /** 153 * Forces a sync of a tree of RenderNode, such that every descendant will have its staging 154 * properties and DisplayList moved to the render copies. 155 * 156 * Note: does not check dirtiness bits, so any non-staging DisplayLists will be discarded. 157 * For this reason, this should generally only be called once on a tree. 158 */ 159 static void syncHierarchyPropertiesAndDisplayList(sp<RenderNode>& node) { 160 syncHierarchyPropertiesAndDisplayListImpl(node.get()); 161 } 162 163 typedef std::function<void(renderthread::RenderThread& thread)> RtCallback; 164 165 class TestTask : public renderthread::RenderTask { 166 public: 167 TestTask(RtCallback rtCallback) 168 : rtCallback(rtCallback) {} 169 virtual ~TestTask() {} 170 virtual void run() override { 171 // RenderState only valid once RenderThread is running, so queried here 172 RenderState& renderState = renderthread::RenderThread::getInstance().renderState(); 173 174 renderState.onGLContextCreated(); 175 rtCallback(renderthread::RenderThread::getInstance()); 176 renderState.onGLContextDestroyed(); 177 }; 178 RtCallback rtCallback; 179 }; 180 181 /** 182 * NOTE: requires surfaceflinger to run, otherwise this method will wait indefinitely. 183 */ 184 static void runOnRenderThread(RtCallback rtCallback) { 185 TestTask task(rtCallback); 186 renderthread::RenderThread::getInstance().queueAndWait(&task); 187 } 188 189 static SkColor interpolateColor(float fraction, SkColor start, SkColor end); 190 191 static void drawTextToCanvas(TestCanvas* canvas, const char* text, 192 const SkPaint& paint, float x, float y); 193 194private: 195 static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) { 196 node->syncProperties(); 197 node->syncDisplayList(); 198 auto displayList = node->getDisplayList(); 199 if (displayList) { 200 for (auto&& childOp : displayList->getChildren()) { 201 syncHierarchyPropertiesAndDisplayListImpl(childOp->renderNode); 202 } 203 } 204 } 205 206}; // class TestUtils 207 208} /* namespace uirenderer */ 209} /* namespace android */ 210 211#endif /* TEST_UTILS_H */ 212