FrameBuilderTests.cpp revision 79abbf22d4f672208327546661e694d837f564a9
1b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik/*
25ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * Copyright (C) 2016 The Android Open Source Project
3b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
4b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Licensed under the Apache License, Version 2.0 (the "License");
5b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * you may not use this file except in compliance with the License.
6b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * You may obtain a copy of the License at
7b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
8b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *      http://www.apache.org/licenses/LICENSE-2.0
9b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
10b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Unless required by applicable law or agreed to in writing, software
11b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * distributed under the License is distributed on an "AS IS" BASIS,
12b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * See the License for the specific language governing permissions and
14b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * limitations under the License.
15b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik */
16b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
17b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <gtest/gtest.h>
18b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
19b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <BakedOpState.h>
20d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik#include <DeferredLayerUpdater.h>
21f158b49c888f722194afe5a80539a2b020c130bcChris Craik#include <FrameBuilder.h>
228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik#include <LayerUpdateQueue.h>
23b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <RecordedOp.h>
24b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <RecordingCanvas.h>
258160f20b0aca8c6595d4b385d673f59b6bcd16a4Chris Craik#include <tests/common/TestUtils.h>
26b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
27b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <unordered_map>
28b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
29b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace android {
30b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace uirenderer {
31b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikconst LayerUpdateQueue sEmptyLayerUpdateQueue;
336e068c0182f6f85bccb855a647510724d1c65a13Chris Craikconst FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
346e068c0182f6f85bccb855a647510724d1c65a13Chris Craik
3598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
366fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik/**
375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual class implemented by each test to redirect static operation / state transitions to
385854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * virtual methods.
396fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
405854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
415854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * and allows Renderer vs Dispatching behavior to be merged.
426fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * onXXXOp methods fail by default - tests should override ops they expect
44d3daa3198e2212c985c634821682d5819346b653Chris Craik * startRepaintLayer fails by default - tests should override if expected
456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * startFrame/endFrame do nothing by default - tests should override to intercept
466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik */
475854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestRendererBase {
486fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikpublic:
495854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    virtual ~TestRendererBase() {}
50d3daa3198e2212c985c634821682d5819346b653Chris Craik    virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
51a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer creation not expected in this test";
52a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        return nullptr;
53a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
5498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
55a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer repaint not expected in this test";
56a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
57a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void endLayer() {
58a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer updates not expected in this test";
59a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
6098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
61e4db79de127cfe961195f52907af8451026eaa20Chris Craik    virtual void endFrame(const Rect& repaintRect) {}
625854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
6315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for single draw methods
6415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
65a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void on##Type(const Type&, const BakedOpState&) { \
66a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << #Type " not expected in this test"; \
67a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
687cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X)
6915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
7115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for merged draw methods
7215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
7315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
7415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
7515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
767cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X)
7715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
795854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int getIndex() { return mIndex; }
805854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
815854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikprotected:
825854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int mIndex = 0;
835854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik};
846fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
855854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik/**
865854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Dispatches all static methods to similar formed methods on renderer, which fail by default but
878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * are overridden by subclasses per test.
885854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik */
895854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestDispatcher {
905854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikpublic:
9115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define single op methods, which redirect to TestRendererBase
9215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
935854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
945854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik        renderer.on##Type(op, state); \
956fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
967cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X);
9715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
9815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
9915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define merged op methods, which redirect to TestRendererBase
10015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
10115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
10215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        renderer.onMerged##Type##s(opList); \
10315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
1047cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X);
10515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
1066fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik};
107b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1085854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass FailRenderer : public TestRendererBase {};
1096fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
1103a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simple) {
111d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleTestRenderer : public TestRendererBase {
112d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
11398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
114d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
115d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(100u, width);
116d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(200u, height);
117d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
118d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
119d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
120d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
121d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
122d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
123d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
124e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
125d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
126d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
127d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
128d3daa3198e2212c985c634821682d5819346b653Chris Craik
1298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
1308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
131ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
132b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 200, SkPaint());
133b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawBitmap(bitmap, 10, 10, nullptr);
134b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
135f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1363a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
1375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleTestRenderer renderer;
138f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
1406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
1416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
1423a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleStroke) {
143386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    class SimpleStrokeTestRenderer : public TestRendererBase {
144386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    public:
145386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
146386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(0, mIndex++);
147386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            // even though initial bounds are empty...
148386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_TRUE(op.unmappedBounds.isEmpty())
149386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "initial bounds should be empty, since they're unstroked";
150386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
151386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "final bounds should account for stroke";
152386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        }
153386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    };
154386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
155386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
156386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
157386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        SkPaint strokedPaint;
158386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        strokedPaint.setStrokeWidth(10);
159386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        canvas.drawPoint(50, 50, strokedPaint);
160386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    });
161f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1623a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
163386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    SimpleStrokeTestRenderer renderer;
164f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
165386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    EXPECT_EQ(1, renderer.getIndex());
166386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik}
167386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
1683a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleRejection) {
1698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
171eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
1726fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
1736fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1746fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
1756fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
176f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
1773a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
178b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1795854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
180f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
181b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
182b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1833a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleBatching) {
184a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
185d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleBatchingTestRenderer : public TestRendererBase {
186d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
187d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
188a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
189d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
190d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
191a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
192d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
193d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
194d3daa3198e2212c985c634821682d5819346b653Chris Craik
1958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
19715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
19815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik                kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
199b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
200b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
201b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
202eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
203a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
204b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.translate(0, 10);
205b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawRect(0, 0, 10, 10, SkPaint());
206b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawBitmap(bitmap, 5, 0, nullptr);
207b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
208b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.restore();
209b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
210b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
211f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
2123a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
2135854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleBatchingTestRenderer renderer;
214f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
215a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
21615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            << "Expect number of ops = 2 * loop count";
217a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik}
218a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
2193a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
22093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    class ClippedMergingTestRenderer : public TestRendererBase {
22193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    public:
22293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        void onMergedBitmapOps(const MergedBakedOpList& opList) override {
22393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(0, mIndex);
22493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            mIndex += opList.count;
22593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(4u, opList.count);
22693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
22793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
22893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik                    opList.clipSideFlags);
22993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        }
23093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    };
23193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    auto node = TestUtils::createNode(0, 0, 100, 100,
23293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
23393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
23493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
23593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // left side clipped (to inset left half)
23693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
23793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 0, 40, nullptr);
23893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
23993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // top side clipped (to inset top half)
24093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
24193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 0, nullptr);
24293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
24393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // right side clipped (to inset right half)
24493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
24593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 80, 40, nullptr);
24693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
24793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // bottom not clipped, just abutting (inset bottom half)
24893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
24993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 70, nullptr);
25093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    });
25193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
252f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
2533a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
25493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    ClippedMergingTestRenderer renderer;
255f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
25693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    EXPECT_EQ(4, renderer.getIndex());
25793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik}
25893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
2593a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textMerging) {
260d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    class TextMergingTestRenderer : public TestRendererBase {
261d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    public:
262d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
263d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(0, mIndex);
264d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            mIndex += opList.count;
265d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(2u, opList.count);
266d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
267d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
268d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
269d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        }
270d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    };
271d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
272d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            [](RenderProperties& props, TestCanvas& canvas) {
273d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        SkPaint paint;
274d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
275d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setAntiAlias(true);
276d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextSize(50);
277dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
278dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
279d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    });
280f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
2813a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
282d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    TextMergingTestRenderer renderer;
283f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
284d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
285d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik}
286d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
2873a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStrikethrough) {
288a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
289a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    class TextStrikethroughTestRenderer : public TestRendererBase {
290a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    public:
291a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
292a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
293a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
29415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
29515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(0, mIndex);
29615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            mIndex += opList.count;
29715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(5u, opList.count);
298a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
299a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    };
3008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 2000,
3018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
302a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        SkPaint textPaint;
303a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setAntiAlias(true);
304a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setTextSize(20);
305a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setStrikeThruText(true);
30642a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
307a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
308dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
309a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
310a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    });
311f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
3123a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
313a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    TextStrikethroughTestRenderer renderer;
314f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
315a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
316d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            << "Expect number of ops = 2 * loop count";
317b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
318b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
3197c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craikstatic auto styles = {
3207c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
3217c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3223a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStyle) {
3237c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    class TextStyleTestRenderer : public TestRendererBase {
3247c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    public:
3257c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
3267c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(0, mIndex);
3277c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(3u, opList.count);
3287c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            mIndex += opList.count;
3297c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3307c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            int index = 0;
3317c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            for (auto style : styles) {
3327c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                auto state = opList.states[index++];
3337c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(style, state->op->paint->getStyle())
3347c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Remainder of validation relies upon stable merged order";
3357c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(0, state->computedState.clipSideFlags)
3367c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Clipped bounds validation requires unclipped ops";
3377c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            }
3387c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3397c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect fill = opList.states[0]->computedState.clippedBounds;
3407c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect stroke = opList.states[1]->computedState.clippedBounds;
3417c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
3427c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                    << "Stroke+Fill should be same as stroke";
3437c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3447c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_TRUE(stroke.contains(fill));
3457c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_FALSE(fill.contains(stroke));
3467c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
34779abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            // outset by half the stroke width
3487c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect outsetFill(fill);
34979abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            outsetFill.outset(5);
3507c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, outsetFill);
3517c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
3527c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    };
3537c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
3547c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
3557c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint paint;
3567c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
3577c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setAntiAlias(true);
3587c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextSize(50);
3597c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setStrokeWidth(10);
3607c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3617c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // draw 3 copies of the same text overlapping, each with a different style.
3627c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // They'll get merged, but with
3637c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        for (auto style : styles) {
3647c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            paint.setStyle(style);
365dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
3667c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
3677c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    });
3687c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
3693a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
3707c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    TextStyleTestRenderer renderer;
3717c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3727c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
3737c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik}
3747c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
375f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer) {
376d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    class TextureLayerTestRenderer : public TestRendererBase {
377d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    public:
378d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
379d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(0, mIndex++);
380e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
381d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
382d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
383d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            Matrix4 expected;
384d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            expected.loadTranslate(5, 5, 0);
385d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
386d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        }
387d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    };
388d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
389d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
390d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [](Matrix4* transform) {
391d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        transform->loadTranslate(5, 5, 0);
392d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
393d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
394d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
395d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
396eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
397d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
398d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawLayer(layerUpdater.get());
399d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.restore();
400d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
401f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4023a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
403d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    TextureLayerTestRenderer renderer;
404f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
405d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    EXPECT_EQ(1, renderer.getIndex());
406d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
407d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
4083a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, functor_reject) {
409223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    class FunctorTestRenderer : public TestRendererBase {
410223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    public:
411223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
412223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            EXPECT_EQ(0, mIndex++);
413223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        }
414223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    };
415223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    Functor noopFunctor;
416223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
417223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    // 1 million pixel tall view, scrolled down 80%
418223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000,
419223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
420223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.translate(0, -800000);
421223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.callDrawGLFunction(&noopFunctor);
422223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    });
423223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
424223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4253a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(scrolledFunctorView),
4263a5811b50157e7ba50854caf957e806aee794d39Chris Craik            sLightGeometry, Caches::getInstance());
427223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FunctorTestRenderer renderer;
428223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
429223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
430223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik}
431223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
4323a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderNode) {
433d3daa3198e2212c985c634821682d5819346b653Chris Craik    class RenderNodeTestRenderer : public TestRendererBase {
434d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
435d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
436d3daa3198e2212c985c634821682d5819346b653Chris Craik            switch(mIndex++) {
437d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 0:
4385430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
439d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
440d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
441d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 1:
442d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
443d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
444d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
445d3daa3198e2212c985c634821682d5819346b653Chris Craik            default:
446d3daa3198e2212c985c634821682d5819346b653Chris Craik                ADD_FAILURE();
447d3daa3198e2212c985c634821682d5819346b653Chris Craik            }
448d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
449d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
450d3daa3198e2212c985c634821682d5819346b653Chris Craik
4518d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(10, 10, 110, 110,
4528d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
453b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        SkPaint paint;
454b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        paint.setColor(SK_ColorWHITE);
455b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
456b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
457b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
459d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&child](RenderProperties& props, RecordingCanvas& canvas) {
460ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkPaint paint;
461ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        paint.setColor(SK_ColorDKGRAY);
462ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawRect(0, 0, 200, 200, paint);
463ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
464eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
465ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.translate(40, 40);
466d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawRenderNode(child.get());
467ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.restore();
468b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
469b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
470f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4713a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
4725854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    RenderNodeTestRenderer renderer;
473f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
474223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(2, renderer.getIndex());
475b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
476b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4773a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clipped) {
478d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ClippedTestRenderer : public TestRendererBase {
479d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
480d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
481d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
482d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
483e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
484d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
485d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
486d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
487d3daa3198e2212c985c634821682d5819346b653Chris Craik
4888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
4898d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
490ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
491ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawBitmap(bitmap, 0, 0, nullptr);
492ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik    });
493ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
494f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
4950b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
4963a5811b50157e7ba50854caf957e806aee794d39Chris Craik            200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
4975854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ClippedTestRenderer renderer;
498f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
499ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik}
500ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
5013a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_simple) {
502d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerSimpleTestRenderer : public TestRendererBase {
503d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
504d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
505d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
506d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, width);
507d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, height);
508d3daa3198e2212c985c634821682d5819346b653Chris Craik            return nullptr;
509d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
510d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
511d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
512d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
513d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
514d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
515d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
5165430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
517e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
518d3daa3198e2212c985c634821682d5819346b653Chris Craik
519d3daa3198e2212c985c634821682d5819346b653Chris Craik            Matrix4 expectedTransform;
520d3daa3198e2212c985c634821682d5819346b653Chris Craik            expectedTransform.loadTranslate(-10, -10, 0);
521d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
522d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
523d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
524d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
525d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
526e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
527d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
528d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
529d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
530d3daa3198e2212c985c634821682d5819346b653Chris Craik
5318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
5328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
533eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
5346fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
5356fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
5366fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
537f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
5383a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
5395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerSimpleTestRenderer renderer;
540f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
5415854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex());
542b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
5436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
5443a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
545d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
546d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer2, rect2 endLayer2
547d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
548d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, layerOp1, endFrame
549d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
550d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerNestedTestRenderer : public TestRendererBase {
551d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
552d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
553d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
554d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
555d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, width);
556d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, height);
557d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x400;
558d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 3) {
559d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, width);
560d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, height);
561d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x800;
562d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
563d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*) nullptr;
564d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
565d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
566d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
567d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 6);
568d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
56998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
570d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(7, mIndex++);
571d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
572e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
573d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(9, mIndex++);
574d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
575d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
576d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
577d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
5785430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
579d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 4) {
5805430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
581d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
582d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
583d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
584d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
585d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 5) {
586d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
5875430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
588d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
589d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
5905430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
591d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
592d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
593d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
594d3daa3198e2212c985c634821682d5819346b653Chris Craik
5958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 800, 800,
5968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
597eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
5986fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        {
5996fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.drawRect(0, 0, 800, 800, SkPaint());
600eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
6016fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            {
6026fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                canvas.drawRect(0, 0, 400, 400, SkPaint());
6036fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            }
6046fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.restore();
6056fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
6066fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6076fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
6086fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
609f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
6103a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
6115854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerNestedTestRenderer renderer;
612f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
6135854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(10, renderer.getIndex());
6146fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
6156fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6163a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
6178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        auto node = TestUtils::createNode(0, 0, 200, 200,
6188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                [](RenderProperties& props, RecordingCanvas& canvas) {
619eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
6206fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
621eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
6226fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6236fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // draw within save layer may still be recorded, but shouldn't be drawn
6246fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(200, 200, 400, 400, SkPaint());
6256fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6266fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6276fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6286fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
629f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6303a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
6316fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6325854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
6336fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // should see no ops, even within the layer, since the layer should be rejected
634f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
635b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
6366fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6373a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_simple) {
638b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
639b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
640b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
641b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++);
642b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
6437435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
644b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
645b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
646b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
647b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(1, mIndex++);
648b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_NE(nullptr, op.paint);
649b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
650b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
651b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
652b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(2, mIndex++);
653b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
654b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
655b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
656b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
657b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
658b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
659b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
660b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
6617435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
662b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
663b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
664b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
665b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
666b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
667b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
668eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
669b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
670b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
671b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
672f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6733a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
674b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedSimpleTestRenderer renderer;
675f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
676b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(4, renderer.getIndex());
677b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
678b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
6793a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
680b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
681b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
682b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
683b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
684b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_GT(4, index);
685b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getWidth());
686b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getHeight());
687b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            if (index == 0) {
688b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
689b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 1) {
690b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
691b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 2) {
692b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
693b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 3) {
694b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
695b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
696b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
697b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
698b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(4, mIndex++);
699b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(op.vertexCount, 16u);
700b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            for (size_t i = 0; i < op.vertexCount; i++) {
701b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                auto v = op.vertices[i];
702b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
703b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
704b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
705b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
706b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
707b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
708b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
709b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
710b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_LT(5, mIndex++);
711b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
712b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
713b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
714b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
715b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
716b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
717eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int restoreTo = canvas.save(SaveFlags::MatrixClip);
718b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.scale(2, 2);
719eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
720eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
721eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
722eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
723b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
724b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restoreToCount(restoreTo);
725b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
726f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
7273a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
728b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedMergedClearsTestRenderer renderer;
729f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
730b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(10, renderer.getIndex())
731b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
732b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
733b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
7343a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
7354876de16e34622634266d09522c9153c78c7c2fbChris Craik    class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
7364876de16e34622634266d09522c9153c78c7c2fbChris Craik    public:
7374876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
7384876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(0, mIndex++);
7394876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
7404876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
7414876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(1, mIndex++);
7424876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, op.paint);
7434876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
7444876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
7454876de16e34622634266d09522c9153c78c7c2fbChris Craik                    << "Expect dirty rect as clip";
7464876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
7474876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
7484876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
7494876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
7504876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
7514876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(2, mIndex++);
7524876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
7534876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
7544876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(3, mIndex++);
7554876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
7564876de16e34622634266d09522c9153c78c7c2fbChris Craik    };
7574876de16e34622634266d09522c9153c78c7c2fbChris Craik
7584876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
7594876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
7604876de16e34622634266d09522c9153c78c7c2fbChris Craik        // save smaller than clip, so we get unclipped behavior
7614876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
7624876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
7634876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
7644876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
7654876de16e34622634266d09522c9153c78c7c2fbChris Craik
7664876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty, and assert we see that rect later
7674876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
7683a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
7694876de16e34622634266d09522c9153c78c7c2fbChris Craik    SaveLayerUnclippedClearClipTestRenderer renderer;
7704876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
7714876de16e34622634266d09522c9153c78c7c2fbChris Craik    EXPECT_EQ(4, renderer.getIndex());
7724876de16e34622634266d09522c9153c78c7c2fbChris Craik}
7734876de16e34622634266d09522c9153c78c7c2fbChris Craik
7743a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_reject) {
7754876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
7764876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
7774876de16e34622634266d09522c9153c78c7c2fbChris Craik        // unclipped savelayer + rect both in area that won't intersect with dirty
7784876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
7794876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(100, 100, 200, 200, SkPaint());
7804876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
7814876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
7824876de16e34622634266d09522c9153c78c7c2fbChris Craik
7834876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty that doesn't intersect with savelayer
7844876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
7853a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
7864876de16e34622634266d09522c9153c78c7c2fbChris Craik    FailRenderer renderer;
7874876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
7884876de16e34622634266d09522c9153c78c7c2fbChris Craik}
7894876de16e34622634266d09522c9153c78c7c2fbChris Craik
790b87eadda1818034ce03d85f30388384d1ac65916Chris Craik/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
791b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
792b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
793b87eadda1818034ce03d85f30388384d1ac65916Chris Craik */
7943a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_complex) {
795b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
796b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
797b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
798b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++); // savelayer first
799b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            return (OffscreenBuffer*)0xabcd;
800b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
801b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
802b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
803b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 1 || index == 7);
804b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
805b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
806b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
807b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 2 || index == 8);
808b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
809b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
810b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
811b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            Matrix4 expected;
812b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            expected.loadTranslate(-100, -100, 0);
813b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
814b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
815b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
816b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
817b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
818b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 4 || index == 10);
819b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
820b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endLayer() override {
821b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
822b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
823b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
824b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(6, mIndex++);
825b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
826b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
827b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(9, mIndex++);
828b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
829b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endFrame(const Rect& repaintRect) override {
830b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(11, mIndex++);
831b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
832b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
833b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
834b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
835b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
836eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
837eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
838eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
839b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(200, 200, 300, 300, SkPaint());
840b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
841b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
842b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
843b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
844f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
8453a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
846b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedComplexTestRenderer renderer;
847f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
848b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(12, renderer.getIndex());
849b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
850b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
851f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
852d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerSimpleTestRenderer : public TestRendererBase {
853d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
85498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
855d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
85698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
85798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
85898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
859d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
860d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
861d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
8620b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
863d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
864d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Transform should be reset within layer";
865d3daa3198e2212c985c634821682d5819346b653Chris Craik
866e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
867d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Damage rect should be used to clip layer content";
868d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
869d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
870d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
871d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
87298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
873d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
874d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
875d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
876d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(4, mIndex++);
877d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
878e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
879d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(5, mIndex++);
880d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
881d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
8820b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
88416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
88516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
8860b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
8870b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
8880b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
88916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
89098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
8910b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
89298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would
89398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
89498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
8950b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8967db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
8970b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8980b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // only enqueue partial damage
89998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
9000b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
9010b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
902f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
9033a5811b50157e7ba50854caf957e806aee794d39Chris Craik            syncedNodeList, sLightGeometry, Caches::getInstance());
9040b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerSimpleTestRenderer renderer;
905f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
9060b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(6, renderer.getIndex());
9070b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9080b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
90998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
9100b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
9110b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
912f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
913d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
914d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(child), rect(grey), endLayer
915d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer, drawLayer(child), endLayer
916d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
917d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, drawLayer(parent), endLayerb
918d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
919d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerComplexTestRenderer : public TestRendererBase {
920d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
921d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
922d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++); // savelayer first
923d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*)0xabcd;
924d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
92598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
926d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
927d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
928d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting inner layer
92998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
93098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
931d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 6) {
932d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting outer layer
93398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
93498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
935d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
936d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
937d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
938d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
939d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
940d3daa3198e2212c985c634821682d5819346b653Chris Craik                // inner layer's rect (white)
941d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
942d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 7) {
943d3daa3198e2212c985c634821682d5819346b653Chris Craik                // outer layer's rect (grey)
944d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
945d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
946d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
947d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
948d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
949d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
950d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
95198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
952d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(10, mIndex++);
953d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
954d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
95598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            OffscreenBuffer* layer = *op.layerHandle;
956d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
957d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 4) {
95898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportWidth);
95998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportHeight);
960d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
961d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
962d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 11) {
96398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportWidth);
96498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportHeight);
965d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
966d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
967e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
968d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(12, mIndex++);
969d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
970d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
971d3daa3198e2212c985c634821682d5819346b653Chris Craik
97216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto child = TestUtils::createNode(50, 50, 150, 150,
97316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
97416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
9750b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
9760b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
9770b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
97816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
97998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
98098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(child->getLayerHandle()) = &childLayer;
9810b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9820b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    RenderNode* childPtr = child.get();
98316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 200, 200,
98416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
98516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
9860b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
9870b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorDKGRAY);
9880b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 200, 200, paint);
9890b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
990eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
9910b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRenderNode(childPtr);
9920b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.restore();
99316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
99498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
99598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(parent->getLayerHandle()) = &parentLayer;
9960b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9977db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
9980b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
99998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
10000b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
10010b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
10020b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1003f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
10043a5811b50157e7ba50854caf957e806aee794d39Chris Craik            syncedList, sLightGeometry, Caches::getInstance());
10050b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerComplexTestRenderer renderer;
1006f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
10070b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(13, renderer.getIndex());
10080b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
10090b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointers, so we can safely destruct RenderNodes
10100b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(child->getLayerHandle()) = nullptr;
10110b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(parent->getLayerHandle()) = nullptr;
10120b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
10130b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1014161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
1015161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    SkPaint paint;
1016161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
1017161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRect(0, 0, 100, 100, paint);
1018161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
1019161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
102016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
10218d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
1022161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, expectedDrawOrder);
1023161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1024161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->mutateStagingProperties().setTranslationZ(z);
1025161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
1026161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
1027161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
10283a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, zReorder) {
1029d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ZReorderTestRenderer : public TestRendererBase {
1030d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1031d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1032d3daa3198e2212c985c634821682d5819346b653Chris Craik            int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
1033d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
1034d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1035d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1036d3daa3198e2212c985c634821682d5819346b653Chris Craik
103716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 100, 100,
10388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1039161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
1040161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 1);
1041161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(true);
1042161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 6, 2.0f);
1043161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 3);
1044161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 4, 0.0f);
1045161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 5);
1046161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 2, -2.0f);
1047161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 7, 2.0f);
1048161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(false);
1049161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 8);
1050161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
1051161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1052f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
10533a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
1054161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    ZReorderTestRenderer renderer;
1055f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1056161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    EXPECT_EQ(10, renderer.getIndex());
1057161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik};
1058161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
10593a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
10608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollX = 5;
10618d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollY = 10;
10628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    class ProjectionReorderTestRenderer : public TestRendererBase {
10638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    public:
10648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
10658d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            const int index = mIndex++;
10668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
10678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            Matrix4 expectedMatrix;
10688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            switch (index) {
10698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 0:
10708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
10718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
10728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadIdentity();
1073678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
10748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
10758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 1:
10768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
10778d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1078678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
1079678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1080678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(Rect(-35, -30, 45, 50),
1081678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                        Rect(state.computedState.localProjectionPathMask->getBounds()));
10828d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
10838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 2:
10848d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
10858d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
10868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
1087678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
10888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
10898d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            default:
10908d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                ADD_FAILURE();
10918d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            }
1092678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expectedMatrix, state.computedState.transform);
10938d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        }
10948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    };
10958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
10968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    /**
10978d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
10988d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
10998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * draw, but because it is projected backwards, it's drawn in between B and C.
11008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     *
11018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
11028d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * (which isn't affected by scroll).
11038d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     */
11048d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
11058d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
11068d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectionReceiver(true);
11078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
11088d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
11098d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationX(scrollX);
11108d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationY(scrollY);
11118d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
11128d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
11138d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorWHITE);
11148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 100, paint);
11158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11168d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
11178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
11188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectBackwards(true);
11198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setClipToBounds(false);
11208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
11218d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorDKGRAY);
11228d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(-10, -10, 60, 60, paint);
11238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11248d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(0, 50, 100, 100,
11258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
11268d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
11278d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorBLUE);
11288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 50, paint);
11298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(projectingRipple.get());
11308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 100, 100,
11328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1133678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1134678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
1135678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1136eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
11378d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
11388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(receiverBackground.get());
11398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(child.get());
11408d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.restore();
11418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1143f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
11443a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
11458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    ProjectionReorderTestRenderer renderer;
1146f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
11478d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    EXPECT_EQ(3, renderer.getIndex());
11488d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik}
11498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1150678ff81105753656aa4822f4f675ef96dc9d2b83Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
1151678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollX = 5;
1152678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollY = 10;
1153678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    class ProjectionHwLayerTestRenderer : public TestRendererBase {
1154678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    public:
1155678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1156678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(0, mIndex++);
1157678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1158678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
1159678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(1, mIndex++);
1160678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1161678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1162678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void endLayer() override {
1163678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(2, mIndex++);
1164678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1165678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1166678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(3, mIndex++);
1167678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1168678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1169678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1170678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(4, mIndex++);
1171678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1172678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            Matrix4 expected;
1173678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
1174678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expected, state.computedState.transform);
1175678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(Rect(-85, -80, 295, 300),
1176678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                    Rect(state.computedState.localProjectionPathMask->getBounds()));
1177678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1178678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1179678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(5, mIndex++);
1180678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1181678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1182678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    };
1183678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1184678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1185678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectionReceiver(true);
1186678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1187678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1188678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationX(scrollX);
1189678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationY(scrollY);
1190678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1191678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1192678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1193678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1194678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1195678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectBackwards(true);
1196678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setClipToBounds(false);
1197678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
1198678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1199678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto child = TestUtils::createNode(100, 100, 300, 300,
1200678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1201678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
1202678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(projectingRipple.get());
1203678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
1204678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1205678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1206678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1207678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1208678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
1209678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1210678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(receiverBackground.get());
1211678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(child.get());
1212678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1213678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1214678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer** layerHandle = child->getLayerHandle();
1215678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1216678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1217678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
1218678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    Matrix4 windowTransform;
1219678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
1220678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layer.setWindowTransform(windowTransform);
1221678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = &layer;
1222678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1223678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto syncedList = TestUtils::createSyncedNodeList(parent);
1224678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1225678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
1226678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
12273a5811b50157e7ba50854caf957e806aee794d39Chris Craik            syncedList, sLightGeometry, Caches::getInstance());
1228678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    ProjectionHwLayerTestRenderer renderer;
1229678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1230678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    EXPECT_EQ(6, renderer.getIndex());
1231678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1232678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // clean up layer pointer, so we can safely destruct RenderNode
1233678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = nullptr;
1234678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik}
1235678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1236a748c08241e43fc68c7c34767d819aef5183936eChris CraikRENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
1237a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollX = 500000;
1238a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollY = 0;
1239a748c08241e43fc68c7c34767d819aef5183936eChris Craik    class ProjectionChildScrollTestRenderer : public TestRendererBase {
1240a748c08241e43fc68c7c34767d819aef5183936eChris Craik    public:
1241a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1242a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(0, mIndex++);
1243a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1244a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1245a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1246a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(1, mIndex++);
1247a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
1248a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
1249a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
1250a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1251a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1252a748c08241e43fc68c7c34767d819aef5183936eChris Craik    };
1253a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1254a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1255a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectionReceiver(true);
1256a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1257a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1258a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1259a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1260a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1261a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1262a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationX(scrollX);
1263a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationY(scrollY);
1264a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectBackwards(true);
1265a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setClipToBounds(false);
1266a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawOval(0, 0, 200, 200, SkPaint());
1267a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1268a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto child = TestUtils::createNode(0, 0, 400, 400,
1269a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1270a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // Record time clip will be ignored by projectee
1271a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
1272a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1273a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1274a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(projectingRipple.get());
1275a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1276a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1277a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1278a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(receiverBackground.get());
1279a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(child.get());
1280a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1281a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1282a748c08241e43fc68c7c34767d819aef5183936eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
12833a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
1284a748c08241e43fc68c7c34767d819aef5183936eChris Craik    ProjectionChildScrollTestRenderer renderer;
1285a748c08241e43fc68c7c34767d819aef5183936eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1286a748c08241e43fc68c7c34767d819aef5183936eChris Craik    EXPECT_EQ(2, renderer.getIndex());
1287a748c08241e43fc68c7c34767d819aef5183936eChris Craik}
1288a748c08241e43fc68c7c34767d819aef5183936eChris Craik
128998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik// creates a 100x100 shadow casting node with provided translationZ
129098787e6c9b2c10b1ab7820bdac168686025b924aChris Craikstatic sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
129116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    return TestUtils::createNode(0, 0, 100, 100,
12928d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
129316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.setTranslationZ(translationZ);
129416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
129598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        SkPaint paint;
129698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        paint.setColor(SK_ColorWHITE);
129798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
129898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
129998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
130098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
13016e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadow) {
1302d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ShadowTestRenderer : public TestRendererBase {
1303d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1304d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1305d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
130698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
13076e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
13086e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
130998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
131098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            Matrix4 expectedZ;
131198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            expectedZ.loadTranslate(0, 0, 5);
13126e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
1313d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1314d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1315d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
1316d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1317d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1318161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
13198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
13208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
132198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
132298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1323d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
132498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1325f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
13263a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
132798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowTestRenderer renderer;
1328f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
132998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(2, renderer.getIndex());
133098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
133198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
13326e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
133398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowSaveLayerTestRenderer : public TestRendererBase {
133498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
133598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
133698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
133798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            return nullptr;
133898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
133998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
134098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
13416e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
13426e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
134398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
134498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
134598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
134698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
134798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
134898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
134998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
135098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
135198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
135298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
135398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
135498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
13558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
13568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
135798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        // save/restore outside of reorderBarrier, so they don't get moved out of place
135898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
1359eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
1360d3daa3198e2212c985c634821682d5819346b653Chris Craik        canvas.insertReorderBarrier(true);
136198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
136298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(false);
136398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restoreToCount(count);
1364d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
1365d3daa3198e2212c985c634821682d5819346b653Chris Craik
1366f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
13676e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
13683a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
136998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowSaveLayerTestRenderer renderer;
1370f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
137198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
137298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
1373d3daa3198e2212c985c634821682d5819346b653Chris Craik
1374f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
137598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowHwLayerTestRenderer : public TestRendererBase {
137698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
137798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
137898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
137998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
138098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
138198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
13826e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
13836e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
13846e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
138598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
138698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
138798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
138898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
138998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
139098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
139198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
139298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
139398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
139498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
139598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
1396d3daa3198e2212c985c634821682d5819346b653Chris Craik
13978d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(50, 60, 150, 160,
139816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
139916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
140098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
1401eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
140298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
140398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
140498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restore();
140516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
140698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = parent->getLayerHandle();
140798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
140898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
140998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
141098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    Matrix4 windowTransform;
141198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
141298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layer.setWindowTransform(windowTransform);
141398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
141498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
14157db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
141698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
141798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
1418f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
14196e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            syncedList,
14203a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
142198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowHwLayerTestRenderer renderer;
1422f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
142398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
142498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
142598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
142698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
1427d3daa3198e2212c985c634821682d5819346b653Chris Craik}
142876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
14293a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
143098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowLayeringTestRenderer : public TestRendererBase {
143198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
143298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
143398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
143498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 0 || index == 1);
143598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
143698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
143798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
143898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 2 || index == 3);
143998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
144098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
14418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
14428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
144398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
144498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
144598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
144698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
144798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1448f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
14496e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
14503a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
145198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowLayeringTestRenderer renderer;
1452f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
145398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(4, renderer.getIndex());
145498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
145598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
145616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
145776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
1458d3daa3198e2212c985c634821682d5819346b653Chris Craik    class PropertyTestRenderer : public TestRendererBase {
1459d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1460d3daa3198e2212c985c634821682d5819346b653Chris Craik        PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1461d3daa3198e2212c985c634821682d5819346b653Chris Craik                : mCallback(callback) {}
1462d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1463d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(mIndex++, 0);
1464d3daa3198e2212c985c634821682d5819346b653Chris Craik            mCallback(op, state);
1465d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1466d3daa3198e2212c985c634821682d5819346b653Chris Craik        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1467d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1468d3daa3198e2212c985c634821682d5819346b653Chris Craik
146916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
147016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
147116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(props);
147276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkPaint paint;
147376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        paint.setColor(SK_ColorWHITE);
147476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
147516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
147676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1477f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
14783a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
147976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    PropertyTestRenderer renderer(opValidateCallback);
1480f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
148176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
148276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
148376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
14843a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
148576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
148676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAlpha(0.5f);
148776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setHasOverlappingRendering(false);
148876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
148976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
149076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
149176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
149276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
14933a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropClipping) {
149476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
149576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipToBounds(true);
149676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipBounds(Rect(10, 20, 300, 400));
149776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
149876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
149976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Clip rect should be intersection of node bounds and clip bounds";
150076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
150176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
150276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
15033a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropRevealClip) {
150476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
150576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableRevealClip().set(true, 50, 50, 25);
150676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
150776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
150876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_TRUE(state.roundRectClipState->highPriority);
150976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(25, state.roundRectClipState->radius);
151076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
151176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
151276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
151376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
15143a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOutlineClip) {
151576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
151676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setShouldClip(true);
151776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
151876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
151976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
152076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_FALSE(state.roundRectClipState->highPriority);
152176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(5, state.roundRectClipState->radius);
152276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
152376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
152476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
152576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
15263a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropTransform) {
152776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
152876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setLeftTopRightBottom(10, 10, 110, 110);
152976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
153076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
153176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setStaticMatrix(&staticMatrix);
153276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
153376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignored, since static overrides animation
153476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
153576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAnimationMatrix(&animationMatrix);
153676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
153776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationX(10);
153876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationY(20);
153976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleX(0.5f);
154076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleY(0.7f);
154176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
154276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        Matrix4 matrix;
154376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.loadTranslate(10, 10, 0); // left, top
154476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(1.2f, 1.2f, 1); // static matrix
154576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignore animation matrix, since static overrides it
154676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
154776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // translation xy
154876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(10, 20);
154976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
155076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // scale xy (from default pivot - center)
155176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(50, 50);
155276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(0.5f, 0.7f, 1);
155376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(-50, -50);
155476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
155576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Op draw matrix must match expected combination of transformation properties";
155676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
155776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
1558161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
15598ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikstruct SaveLayerAlphaData {
15608ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerWidth = 0;
15618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerHeight = 0;
15628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Rect rectClippedBounds;
15638ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 rectMatrix;
15648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik};
15658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik/**
15668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Constructs a view to hit the temporary layer alpha property implementation:
15678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     a) 0 < alpha < 1
15688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     b) too big for layer (larger than maxTextureSize)
15698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     c) overlapping rendering content
15708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * returning observed data about layer size and content clip/transform.
15718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *
15728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
15738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * (for efficiency, and to fit in layer size constraints) based on parent clip.
15748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik */
15758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
157616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        std::function<void(RenderProperties&)> propSetupCallback) {
15778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
15788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    public:
15798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
15808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik                : mOutData(outData) {}
15818ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
15828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
15838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(0, mIndex++);
15848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerWidth = width;
15858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerHeight = height;
15868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            return nullptr;
15878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
15898ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(1, mIndex++);
15908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
15918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectClippedBounds = state.computedState.clippedBounds;
15928ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectMatrix = state.computedState.transform;
15938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15948ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void endLayer() override {
15958ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(2, mIndex++);
15968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
15988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(3, mIndex++);
15998ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
16008ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    private:
16018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaData* mOutData;
16028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    };
16038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
16058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "Node must be bigger than max texture size to exercise saveLayer codepath";
160616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 10000, 10000,
160716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
16088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setHasOverlappingRendering(true);
16098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
16108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // apply other properties
161116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(properties);
161216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
161316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        SkPaint paint;
161416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        paint.setColor(SK_ColorWHITE);
161516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        canvas.drawRect(0, 0, 10000, 10000, paint);
16168ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16177db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
16188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16196e068c0182f6f85bccb855a647510724d1c65a13Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
16203a5811b50157e7ba50854caf957e806aee794d39Chris Craik            nodes, sLightGeometry, Caches::getInstance());
16218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
1622f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
16238ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // assert, since output won't be valid if we haven't seen a save layer triggered
16258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
16268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16283a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
16298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
16308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
16318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(10); // offset rendering content
16328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(-2000); // offset rendering content
16338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(190u, observedData.layerWidth);
16358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(200u, observedData.layerHeight);
16365430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
16378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be clipped to screen area";
16388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 expected;
16398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    expected.loadTranslate(0, -2000, 0);
16408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
16418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be translated as part of being clipped";
16428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16443a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
16458ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
16468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
16478ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // Translate and rotate the view so that the only visible part is the top left corner of
16488d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // the view. It will form an isosceles right triangle with a long side length of 200 at the
16498ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // bottom of the viewport.
16508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(100);
16518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(100);
16528ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
16538ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
16548ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setRotation(45);
16558ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16568ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // ceil(sqrt(2) / 2 * 200) = 142
16578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerWidth);
16588ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerHeight);
16595430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
16608ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
16618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16633a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
16648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
16658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
16668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
16678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
16688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleX(2);
16698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleY(0.5f);
16708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(100u, observedData.layerWidth);
16728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(400u, observedData.layerHeight);
16735430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
16748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
16758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16776fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace uirenderer
16786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace android
1679