| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 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 |  | 
| Chris Craik | 76caecf | 2015-11-02 19:17:45 -0800 | [diff] [blame] | 19 | #include <DeviceInfo.h> | 
| Chris Craik | 161f54b | 2015-11-05 11:08:52 -0800 | [diff] [blame] | 20 | #include <DisplayList.h> | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 21 | #include <Matrix.h> | 
| Chris Craik | 0a24b14 | 2015-10-19 17:10:19 -0700 | [diff] [blame] | 22 | #include <Rect.h> | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 23 | #include <RenderNode.h> | 
| Chris Craik | 0a24b14 | 2015-10-19 17:10:19 -0700 | [diff] [blame] | 24 | #include <renderstate/RenderState.h> | 
 | 25 | #include <renderthread/RenderThread.h> | 
 | 26 | #include <Snapshot.h> | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 27 |  | 
| Chris Craik | 161f54b | 2015-11-05 11:08:52 -0800 | [diff] [blame] | 28 | #if HWUI_NEW_OPS | 
 | 29 | #include <RecordedOp.h> | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 30 | #include <RecordingCanvas.h> | 
| Chris Craik | 161f54b | 2015-11-05 11:08:52 -0800 | [diff] [blame] | 31 | #else | 
 | 32 | #include <DisplayListOp.h> | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 33 | #include <DisplayListCanvas.h> | 
| Chris Craik | 161f54b | 2015-11-05 11:08:52 -0800 | [diff] [blame] | 34 | #endif | 
 | 35 |  | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 36 | #include <memory> | 
 | 37 |  | 
 | 38 | namespace android { | 
 | 39 | namespace uirenderer { | 
 | 40 |  | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 41 | #if HWUI_NEW_OPS | 
 | 42 | typedef RecordingCanvas TestCanvas; | 
 | 43 | #else | 
 | 44 | typedef DisplayListCanvas TestCanvas; | 
 | 45 | #endif | 
 | 46 |  | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 47 | #define EXPECT_MATRIX_APPROX_EQ(a, b) \ | 
 | 48 |     EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b)) | 
 | 49 |  | 
| Chris Craik | 6fe991e5 | 2015-10-20 09:39:42 -0700 | [diff] [blame] | 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 |  | 
| Chris Craik | 98787e6 | 2015-11-13 10:55:30 -0800 | [diff] [blame] | 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 |  | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 70 | class TestUtils { | 
 | 71 | public: | 
| Chris Craik | 76ace11 | 2015-10-29 12:46:19 -0700 | [diff] [blame] | 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 |  | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 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 |  | 
| Chris Craik | ddf2215 | 2015-10-14 17:42:47 -0700 | [diff] [blame] | 106 |     static SkBitmap createSkBitmap(int width, int height) { | 
 | 107 |         SkBitmap bitmap; | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 108 |         SkImageInfo info = SkImageInfo::Make(width, height, | 
 | 109 |                 kN32_SkColorType, kPremul_SkAlphaType); | 
| Chris Craik | 0a24b14 | 2015-10-19 17:10:19 -0700 | [diff] [blame] | 110 |         bitmap.setInfo(info); | 
 | 111 |         bitmap.allocPixels(info); | 
| Chris Craik | ddf2215 | 2015-10-14 17:42:47 -0700 | [diff] [blame] | 112 |         return bitmap; | 
 | 113 |     } | 
 | 114 |  | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 115 |     template<class CanvasType> | 
| Chris Craik | 003cc3d | 2015-10-16 10:24:55 -0700 | [diff] [blame] | 116 |     static std::unique_ptr<DisplayList> createDisplayList(int width, int height, | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 117 |             std::function<void(CanvasType& canvas)> canvasCallback) { | 
 | 118 |         CanvasType canvas(width, height); | 
 | 119 |         canvasCallback(canvas); | 
| Chris Craik | 003cc3d | 2015-10-16 10:24:55 -0700 | [diff] [blame] | 120 |         return std::unique_ptr<DisplayList>(canvas.finishRecording()); | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 121 |     } | 
 | 122 |  | 
| Chris Craik | d3daa31 | 2015-11-06 10:59:56 -0800 | [diff] [blame] | 123 |     static sp<RenderNode> createNode(int left, int top, int right, int bottom, | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 124 |             std::function<void(RenderProperties& props, TestCanvas& canvas)> setup = nullptr) { | 
| Chris Craik | 9fded23 | 2015-11-11 16:42:34 -0800 | [diff] [blame] | 125 | #if HWUI_NULL_GPU | 
| Chris Craik | 76caecf | 2015-11-02 19:17:45 -0800 | [diff] [blame] | 126 |         // if RenderNodes are being sync'd/used, device info will be needed, since | 
 | 127 |         // DeviceInfo::maxTextureSize() affects layer property | 
 | 128 |         DeviceInfo::initialize(); | 
| Chris Craik | 9fded23 | 2015-11-11 16:42:34 -0800 | [diff] [blame] | 129 | #endif | 
| Chris Craik | 76caecf | 2015-11-02 19:17:45 -0800 | [diff] [blame] | 130 |  | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 131 |         sp<RenderNode> node = new RenderNode(); | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 132 |         RenderProperties& props = node->mutateStagingProperties(); | 
 | 133 |         props.setLeftTopRightBottom(left, top, right, bottom); | 
 | 134 |         if (setup) { | 
 | 135 |             TestCanvas canvas(props.getWidth(), props.getHeight()); | 
 | 136 |             setup(props, canvas); | 
 | 137 |             node->setStagingDisplayList(canvas.finishRecording()); | 
| Chris Craik | 0b7e824 | 2015-10-28 16:50:44 -0700 | [diff] [blame] | 138 |         } | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 139 |         node->setPropertyFieldsDirty(0xFFFFFFFF); | 
| Chris Craik | 0b7e824 | 2015-10-28 16:50:44 -0700 | [diff] [blame] | 140 |         return node; | 
 | 141 |     } | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 142 |  | 
| Chris Craik | 0b7e824 | 2015-10-28 16:50:44 -0700 | [diff] [blame] | 143 |     static sp<RenderNode> createNode(int left, int top, int right, int bottom, | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 144 |             std::function<void(RenderProperties& props)> setup) { | 
 | 145 |         return createNode(left, top, right, bottom, | 
 | 146 |                 [&setup](RenderProperties& props, TestCanvas& canvas) { | 
 | 147 |             setup(props); | 
 | 148 |         }); | 
 | 149 |     } | 
| Chris Craik | 0b7e824 | 2015-10-28 16:50:44 -0700 | [diff] [blame] | 150 |  | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 151 |     static sp<RenderNode> createNode(int left, int top, int right, int bottom, | 
 | 152 |             std::function<void(TestCanvas& canvas)> setup) { | 
 | 153 |         return createNode(left, top, right, bottom, | 
 | 154 |                 [&setup](RenderProperties& props, TestCanvas& canvas) { | 
 | 155 |             setup(canvas); | 
 | 156 |         }); | 
 | 157 |     } | 
 | 158 |  | 
 | 159 |     static void recordNode(RenderNode& node, | 
 | 160 |             std::function<void(TestCanvas&)> contentCallback) { | 
 | 161 |        TestCanvas canvas(node.stagingProperties().getWidth(), | 
 | 162 |                node.stagingProperties().getHeight()); | 
 | 163 |        contentCallback(canvas); | 
 | 164 |        node.setStagingDisplayList(canvas.finishRecording()); | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 165 |     } | 
 | 166 |  | 
| Chris Craik | 161f54b | 2015-11-05 11:08:52 -0800 | [diff] [blame] | 167 |     static void syncHierarchyPropertiesAndDisplayList(sp<RenderNode>& node) { | 
 | 168 |         syncHierarchyPropertiesAndDisplayListImpl(node.get()); | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 169 |     } | 
| Chris Craik | 0a24b14 | 2015-10-19 17:10:19 -0700 | [diff] [blame] | 170 |  | 
| Chris Craik | 0b7e824 | 2015-10-28 16:50:44 -0700 | [diff] [blame] | 171 |     typedef std::function<void(renderthread::RenderThread& thread)> RtCallback; | 
| Chris Craik | 0a24b14 | 2015-10-19 17:10:19 -0700 | [diff] [blame] | 172 |  | 
 | 173 |     class TestTask : public renderthread::RenderTask { | 
 | 174 |     public: | 
 | 175 |         TestTask(RtCallback rtCallback) | 
 | 176 |                 : rtCallback(rtCallback) {} | 
 | 177 |         virtual ~TestTask() {} | 
 | 178 |         virtual void run() override { | 
 | 179 |             // RenderState only valid once RenderThread is running, so queried here | 
 | 180 |             RenderState& renderState = renderthread::RenderThread::getInstance().renderState(); | 
 | 181 |  | 
 | 182 |             renderState.onGLContextCreated(); | 
| Chris Craik | 0b7e824 | 2015-10-28 16:50:44 -0700 | [diff] [blame] | 183 |             rtCallback(renderthread::RenderThread::getInstance()); | 
| Chris Craik | 0a24b14 | 2015-10-19 17:10:19 -0700 | [diff] [blame] | 184 |             renderState.onGLContextDestroyed(); | 
 | 185 |         }; | 
 | 186 |         RtCallback rtCallback; | 
 | 187 |     }; | 
 | 188 |  | 
 | 189 |     /** | 
 | 190 |      * NOTE: requires surfaceflinger to run, otherwise this method will wait indefinitely. | 
 | 191 |      */ | 
 | 192 |     static void runOnRenderThread(RtCallback rtCallback) { | 
 | 193 |         TestTask task(rtCallback); | 
 | 194 |         renderthread::RenderThread::getInstance().queueAndWait(&task); | 
 | 195 |     } | 
| John Reck | 16c9d6a | 2015-11-17 15:51:08 -0800 | [diff] [blame] | 196 |  | 
 | 197 |     static SkColor interpolateColor(float fraction, SkColor start, SkColor end); | 
 | 198 |  | 
| Chris Craik | 161f54b | 2015-11-05 11:08:52 -0800 | [diff] [blame] | 199 | private: | 
 | 200 |     static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) { | 
 | 201 |         node->syncProperties(); | 
 | 202 |         node->syncDisplayList(); | 
 | 203 |         auto displayList = node->getDisplayList(); | 
 | 204 |         if (displayList) { | 
 | 205 |             for (auto&& childOp : displayList->getChildren()) { | 
 | 206 |                 syncHierarchyPropertiesAndDisplayListImpl(childOp->renderNode); | 
 | 207 |             } | 
 | 208 |         } | 
 | 209 |     } | 
 | 210 |  | 
| Chris Craik | b565df1 | 2015-10-05 13:00:52 -0700 | [diff] [blame] | 211 | }; // class TestUtils | 
 | 212 |  | 
 | 213 | } /* namespace uirenderer */ | 
 | 214 | } /* namespace android */ | 
 | 215 |  | 
 | 216 | #endif /* TEST_UTILS_H */ |