BakedOpDispatcherTests.cpp revision 92a5d4b99a5554adca0e94627d44d2bd7f4f0bc0
1419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik/*
2419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik * Copyright (C) 2016 The Android Open Source Project
3419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik *
4419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik * Licensed under the Apache License, Version 2.0 (the "License");
5419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik * you may not use this file except in compliance with the License.
6419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik * You may obtain a copy of the License at
7419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik *
8419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik *      http://www.apache.org/licenses/LICENSE-2.0
9419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik *
10419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik * Unless required by applicable law or agreed to in writing, software
11419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik * distributed under the License is distributed on an "AS IS" BASIS,
12419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik * See the License for the specific language governing permissions and
14419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik * limitations under the License.
15419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik */
16419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
17419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik#include <gtest/gtest.h>
18419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
19419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik#include <RecordedOp.h>
20419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik#include <BakedOpDispatcher.h>
21419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik#include <BakedOpRenderer.h>
22419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik#include <tests/common/TestUtils.h>
23419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
24419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craikusing namespace android::uirenderer;
25419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
26419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craikstatic BakedOpRenderer::LightInfo sLightInfo;
27419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craikstatic Rect sBaseClip(100, 100);
28419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
29419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craikclass ValidatingBakedOpRenderer : public BakedOpRenderer {
30419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craikpublic:
31419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    ValidatingBakedOpRenderer(RenderState& renderState, std::function<void(const Glop& glop)> validator)
32419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik            : BakedOpRenderer(Caches::getInstance(), renderState, true, sLightInfo)
33419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik            , mValidator(validator) {
34419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        mGlopReceiver = ValidatingGlopReceiver;
35419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    }
36419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craikprivate:
37419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    static void ValidatingGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
38419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik            const ClipBase* clip, const Glop& glop) {
39419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
40419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        auto vbor = reinterpret_cast<ValidatingBakedOpRenderer*>(&renderer);
41419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        vbor->mValidator(glop);
42419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    }
43419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    std::function<void(const Glop& glop)> mValidator;
44419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik};
45419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
46419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craiktypedef void (*BakedOpReceiver)(BakedOpRenderer&, const BakedOpState&);
47419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
48419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craikstatic void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op,
49419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        std::function<void(const Glop& glop)> glopVerifier) {
50419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    // Create op, and wrap with basic state.
51419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    LinearAllocator allocator;
52419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), sBaseClip);
53419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    auto state = BakedOpState::tryConstruct(allocator, *snapshot, *op);
54419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    ASSERT_NE(nullptr, state);
55419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
56419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    int glopCount = 0;
57419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    auto glopReceiver = [&glopVerifier, &glopCount] (const Glop& glop) {
58419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        ASSERT_EQ(glopCount++, 0) << "Only one Glop expected";
59419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        glopVerifier(glop);
60419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    };
61419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver);
62419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
63419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    // Dispatch based on op type created, similar to Frame/LayerBuilder dispatch behavior
64419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik#define X(Type) \
65419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        [](BakedOpRenderer& renderer, const BakedOpState& state) { \
66419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik            BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \
67419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        },
68419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
69419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik#undef X
70419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    unmergedReceivers[op->opId](renderer, *state);
71419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    ASSERT_EQ(1, glopCount) << "Exactly one Glop expected";
72419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik}
73419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
74419a1e7ef53468e494d21c66ea7f63c0c522d208Chris CraikRENDERTHREAD_TEST(BakedOpDispatcher, onArc_position) {
75419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    SkPaint strokePaint;
76419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    strokePaint.setStyle(SkPaint::kStroke_Style);
77419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    strokePaint.setStrokeWidth(4);
78419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    ArcOp op(Rect(10, 15, 20, 25), Matrix4::identity(), nullptr, &strokePaint, 0, 270, true);
79419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
80419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        // validate glop produced by renderPathTexture (so texture, unit quad)
81419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        auto texture = glop.fill.texture.texture;
82419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        ASSERT_NE(nullptr, texture);
83419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        float expectedOffset = floor(4 * 1.5f + 0.5f);
84419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        EXPECT_EQ(expectedOffset, reinterpret_cast<PathTexture*>(texture)->offset)
85419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik                << "Should see conservative offset from PathCache::computeBounds";
86419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        Rect expectedBounds(10, 15, 20, 25);
87419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        expectedBounds.outset(expectedOffset);
8870969ccde405ea410fc7ccfe869999a03f056686Chris Craik#if !HWUI_NEW_OPS
89419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        EXPECT_EQ(expectedBounds, glop.bounds) << "bounds outset by stroke 'offset'";
9070969ccde405ea410fc7ccfe869999a03f056686Chris Craik#endif
91419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        Matrix4 expectedModelView;
92419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        expectedModelView.loadTranslate(10 - expectedOffset, 15 - expectedOffset, 0);
93419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        expectedModelView.scale(10 + 2 * expectedOffset, 10 + 2 * expectedOffset, 1);
94419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        EXPECT_EQ(expectedModelView, glop.transform.modelView)
95419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik                << "X and Y offsets, and scale both applied to model view";
96419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    });
97419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik}
98419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik
99419a1e7ef53468e494d21c66ea7f63c0c522d208Chris CraikRENDERTHREAD_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
100419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    SkPaint layerPaint;
101419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    layerPaint.setAlpha(128);
102419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
103419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    LayerOp op(Rect(10, 10), Matrix4::identity(), nullptr, &layerPaint, &buffer);
104419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    testUnmergedGlopDispatch(renderThread, &op, [&renderThread] (const Glop& glop) {
105419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        // rect glop is dispatched with paint props applied
106419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        EXPECT_EQ(renderThread.renderState().meshState().getUnitQuadVBO(),
107419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik                glop.mesh.vertices.bufferObject) << "Unit quad should be drawn";
108419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        EXPECT_EQ(nullptr, glop.fill.texture.texture) << "Should be no texture when layer is null";
109419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik        EXPECT_FLOAT_EQ(128 / 255.0f, glop.fill.color.a) << "Rect quad should use op alpha";
110419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik    });
111419a1e7ef53468e494d21c66ea7f63c0c522d208Chris Craik}
11292a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv
11392a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyvstatic int getGlopTransformFlags(renderthread::RenderThread& renderThread, RecordedOp* op) {
11492a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    int result = 0;
11592a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    testUnmergedGlopDispatch(renderThread, op, [&result] (const Glop& glop) {
11692a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv        result = glop.transform.transformFlags;
11792a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    });
11892a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    return result;
11992a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv}
12092a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv
12192a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyvRENDERTHREAD_TEST(BakedOpDispatcher, offsetFlags) {
12292a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    Rect bounds(10, 15, 20, 25);
12392a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    SkPaint paint;
12492a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    SkPaint aaPaint;
12592a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    aaPaint.setAntiAlias(true);
12692a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv
12792a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    RoundRectOp roundRectOp(bounds, Matrix4::identity(), nullptr, &paint, 0, 270);
12892a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    EXPECT_EQ(TransformFlags::None, getGlopTransformFlags(renderThread, &roundRectOp))
12992a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv            << "Expect no offset for round rect op.";
13092a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv
13192a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    const float points[4] = {0.5, 0.5, 1.0, 1.0};
13292a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    PointsOp antiAliasedPointsOp(bounds, Matrix4::identity(), nullptr, &aaPaint, points, 4);
13392a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    EXPECT_EQ(TransformFlags::None, getGlopTransformFlags(renderThread, &antiAliasedPointsOp))
13492a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv                << "Expect no offset for AA points.";
13592a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    PointsOp pointsOp(bounds, Matrix4::identity(), nullptr, &paint, points, 4);
13692a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    EXPECT_EQ(TransformFlags::OffsetByFudgeFactor, getGlopTransformFlags(renderThread, &pointsOp))
13792a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv            << "Expect an offset for non-AA points.";
13892a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv
13992a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    LinesOp antiAliasedLinesOp(bounds, Matrix4::identity(), nullptr, &aaPaint, points, 4);
14092a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    EXPECT_EQ(TransformFlags::None, getGlopTransformFlags(renderThread, &antiAliasedLinesOp))
14192a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv            << "Expect no offset for AA lines.";
14292a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    LinesOp linesOp(bounds, Matrix4::identity(), nullptr, &paint, points, 4);
14392a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv    EXPECT_EQ(TransformFlags::OffsetByFudgeFactor, getGlopTransformFlags(renderThread, &linesOp))
14492a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv            << "Expect an offset for non-AA lines.";
14592a5d4b99a5554adca0e94627d44d2bd7f4f0bc0sergeyv}