TestUtils.h revision 98787e6c9b2c10b1ab7820bdac168686025b924a
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#else
31#include <DisplayListOp.h>
32#endif
33
34#include <memory>
35
36namespace android {
37namespace uirenderer {
38
39#define EXPECT_MATRIX_APPROX_EQ(a, b) \
40    EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b))
41
42#define EXPECT_RECT_APPROX_EQ(a, b) \
43    EXPECT_TRUE(MathUtils::areEqual(a.left, b.left) \
44            && MathUtils::areEqual(a.top, b.top) \
45            && MathUtils::areEqual(a.right, b.right) \
46            && MathUtils::areEqual(a.bottom, b.bottom));
47
48/**
49 * Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope
50 * (for e.g. accessing its RenderState)
51 */
52#define RENDERTHREAD_TEST(test_case_name, test_name) \
53    class test_case_name##_##test_name##_RenderThreadTest { \
54    public: \
55        static void doTheThing(renderthread::RenderThread& renderThread); \
56    }; \
57    TEST(test_case_name, test_name) { \
58        TestUtils::runOnRenderThread(test_case_name##_##test_name##_RenderThreadTest::doTheThing); \
59    }; \
60    void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
61
62class TestUtils {
63public:
64    class SignalingDtor {
65    public:
66        SignalingDtor()
67                : mSignal(nullptr) {}
68        SignalingDtor(int* signal)
69                : mSignal(signal) {}
70        void setSignal(int* signal) {
71            mSignal = signal;
72        }
73        ~SignalingDtor() {
74            if (mSignal) {
75                (*mSignal)++;
76            }
77        }
78    private:
79        int* mSignal;
80    };
81
82    static bool matricesAreApproxEqual(const Matrix4& a, const Matrix4& b) {
83        for (int i = 0; i < 16; i++) {
84            if (!MathUtils::areEqual(a[i], b[i])) {
85                return false;
86            }
87        }
88        return true;
89    }
90
91    static std::unique_ptr<Snapshot> makeSnapshot(const Matrix4& transform, const Rect& clip) {
92        std::unique_ptr<Snapshot> snapshot(new Snapshot());
93        snapshot->clip(clip.left, clip.top, clip.right, clip.bottom, SkRegion::kReplace_Op);
94        *(snapshot->transform) = transform;
95        return snapshot;
96    }
97
98    static SkBitmap createSkBitmap(int width, int height) {
99        SkBitmap bitmap;
100        SkImageInfo info = SkImageInfo::MakeUnknown(width, height);
101        bitmap.setInfo(info);
102        bitmap.allocPixels(info);
103        return bitmap;
104    }
105
106    template<class CanvasType>
107    static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
108            std::function<void(CanvasType& canvas)> canvasCallback) {
109        CanvasType canvas(width, height);
110        canvasCallback(canvas);
111        return std::unique_ptr<DisplayList>(canvas.finishRecording());
112    }
113
114    typedef std::function<int(RenderProperties&)> PropSetupCallback;
115
116    static PropSetupCallback getHwLayerSetupCallback() {
117        static PropSetupCallback sLayerSetupCallback = [] (RenderProperties& properties) {
118            properties.mutateLayerProperties().setType(LayerType::RenderLayer);
119            return RenderNode::GENERIC;
120        };
121        return sLayerSetupCallback;
122    }
123
124    static sp<RenderNode> createNode(int left, int top, int right, int bottom,
125            PropSetupCallback propSetupCallback = nullptr) {
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        node->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
134        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
135        if (propSetupCallback) {
136            node->setPropertyFieldsDirty(propSetupCallback(node->mutateStagingProperties()));
137        }
138        return node;
139    }
140
141    template<class CanvasType>
142    static sp<RenderNode> createNode(int left, int top, int right, int bottom,
143            std::function<void(CanvasType& canvas)> canvasCallback,
144            PropSetupCallback propSetupCallback = nullptr) {
145        sp<RenderNode> node = createNode(left, top, right, bottom, propSetupCallback);
146
147        auto&& props = node->stagingProperties(); // staging, since not sync'd yet
148        CanvasType canvas(props.getWidth(), props.getHeight());
149        canvasCallback(canvas);
150        node->setStagingDisplayList(canvas.finishRecording());
151        return node;
152    }
153
154    static void syncHierarchyPropertiesAndDisplayList(sp<RenderNode>& node) {
155        syncHierarchyPropertiesAndDisplayListImpl(node.get());
156    }
157
158    typedef std::function<void(renderthread::RenderThread& thread)> RtCallback;
159
160    class TestTask : public renderthread::RenderTask {
161    public:
162        TestTask(RtCallback rtCallback)
163                : rtCallback(rtCallback) {}
164        virtual ~TestTask() {}
165        virtual void run() override {
166            // RenderState only valid once RenderThread is running, so queried here
167            RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
168
169            renderState.onGLContextCreated();
170            rtCallback(renderthread::RenderThread::getInstance());
171            renderState.onGLContextDestroyed();
172        };
173        RtCallback rtCallback;
174    };
175
176    /**
177     * NOTE: requires surfaceflinger to run, otherwise this method will wait indefinitely.
178     */
179    static void runOnRenderThread(RtCallback rtCallback) {
180        TestTask task(rtCallback);
181        renderthread::RenderThread::getInstance().queueAndWait(&task);
182    }
183private:
184    static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
185        node->syncProperties();
186        node->syncDisplayList();
187        auto displayList = node->getDisplayList();
188        if (displayList) {
189            for (auto&& childOp : displayList->getChildren()) {
190                syncHierarchyPropertiesAndDisplayListImpl(childOp->renderNode);
191            }
192        }
193    }
194
195}; // class TestUtils
196
197} /* namespace uirenderer */
198} /* namespace android */
199
200#endif /* TEST_UTILS_H */
201