TestUtils.h revision 161f54b2d4160b8d3f3da9eba5746da5162e4821
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
48class TestUtils {
49public:
50    class SignalingDtor {
51    public:
52        SignalingDtor()
53                : mSignal(nullptr) {}
54        SignalingDtor(int* signal)
55                : mSignal(signal) {}
56        void setSignal(int* signal) {
57            mSignal = signal;
58        }
59        ~SignalingDtor() {
60            if (mSignal) {
61                (*mSignal)++;
62            }
63        }
64    private:
65        int* mSignal;
66    };
67
68    static bool matricesAreApproxEqual(const Matrix4& a, const Matrix4& b) {
69        for (int i = 0; i < 16; i++) {
70            if (!MathUtils::areEqual(a[i], b[i])) {
71                return false;
72            }
73        }
74        return true;
75    }
76
77    static std::unique_ptr<Snapshot> makeSnapshot(const Matrix4& transform, const Rect& clip) {
78        std::unique_ptr<Snapshot> snapshot(new Snapshot());
79        snapshot->clip(clip.left, clip.top, clip.right, clip.bottom, SkRegion::kReplace_Op);
80        *(snapshot->transform) = transform;
81        return snapshot;
82    }
83
84    static SkBitmap createSkBitmap(int width, int height) {
85        SkBitmap bitmap;
86        SkImageInfo info = SkImageInfo::MakeUnknown(width, height);
87        bitmap.setInfo(info);
88        bitmap.allocPixels(info);
89        return bitmap;
90    }
91
92    template<class CanvasType>
93    static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
94            std::function<void(CanvasType& canvas)> canvasCallback) {
95        CanvasType canvas(width, height);
96        canvasCallback(canvas);
97        return std::unique_ptr<DisplayList>(canvas.finishRecording());
98    }
99
100    static sp<RenderNode> createNode(int left, int top, int right, int bottom, bool onLayer = false) {
101        // if RenderNodes are being sync'd/used, device info will be needed, since
102        // DeviceInfo::maxTextureSize() affects layer property
103        DeviceInfo::initialize();
104
105        sp<RenderNode> node = new RenderNode();
106        node->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
107        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
108        if (onLayer) {
109            node->mutateStagingProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
110            node->setPropertyFieldsDirty(RenderNode::GENERIC);
111        }
112        return node;
113    }
114
115    template<class CanvasType>
116    static sp<RenderNode> createNode(int left, int top, int right, int bottom,
117            std::function<void(CanvasType& canvas)> canvasCallback, bool onLayer = false) {
118        sp<RenderNode> node = createNode(left, top, right, bottom, onLayer);
119
120        auto&& props = node->stagingProperties(); // staging, since not sync'd yet
121        CanvasType canvas(props.getWidth(), props.getHeight());
122        canvasCallback(canvas);
123        node->setStagingDisplayList(canvas.finishRecording());
124        return node;
125    }
126
127    static void syncHierarchyPropertiesAndDisplayList(sp<RenderNode>& node) {
128        syncHierarchyPropertiesAndDisplayListImpl(node.get());
129    }
130
131    typedef std::function<void(renderthread::RenderThread& thread)> RtCallback;
132
133    class TestTask : public renderthread::RenderTask {
134    public:
135        TestTask(RtCallback rtCallback)
136                : rtCallback(rtCallback) {}
137        virtual ~TestTask() {}
138        virtual void run() override {
139            // RenderState only valid once RenderThread is running, so queried here
140            RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
141
142            renderState.onGLContextCreated();
143            rtCallback(renderthread::RenderThread::getInstance());
144            renderState.onGLContextDestroyed();
145        };
146        RtCallback rtCallback;
147    };
148
149    /**
150     * NOTE: requires surfaceflinger to run, otherwise this method will wait indefinitely.
151     */
152    static void runOnRenderThread(RtCallback rtCallback) {
153        TestTask task(rtCallback);
154        renderthread::RenderThread::getInstance().queueAndWait(&task);
155    }
156private:
157    static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
158        node->syncProperties();
159        node->syncDisplayList();
160        auto displayList = node->getDisplayList();
161        if (displayList) {
162            for (auto&& childOp : displayList->getChildren()) {
163                syncHierarchyPropertiesAndDisplayListImpl(childOp->renderNode);
164            }
165        }
166    }
167
168}; // class TestUtils
169
170} /* namespace uirenderer */
171} /* namespace android */
172
173#endif /* TEST_UTILS_H */
174