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>
228cd3edfa15cc9cdbffa935d19ab894426b08d174Greg Daniel#include <GlLayer.h>
238ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik#include <LayerUpdateQueue.h>
24b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <RecordedOp.h>
25b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <RecordingCanvas.h>
268160f20b0aca8c6595d4b385d673f59b6bcd16a4Chris Craik#include <tests/common/TestUtils.h>
27b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
28b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <unordered_map>
29b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
30b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace android {
31b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace uirenderer {
32b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
336e068c0182f6f85bccb855a647510724d1c65a13Chris Craikconst FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
346e068c0182f6f85bccb855a647510724d1c65a13Chris Craik
356fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik/**
365854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual class implemented by each test to redirect static operation / state transitions to
375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * virtual methods.
386fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
405854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * and allows Renderer vs Dispatching behavior to be merged.
416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
426fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * onXXXOp methods fail by default - tests should override ops they expect
43d3daa3198e2212c985c634821682d5819346b653Chris Craik * startRepaintLayer fails by default - tests should override if expected
446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * startFrame/endFrame do nothing by default - tests should override to intercept
456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik */
465854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestRendererBase {
476fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikpublic:
485854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    virtual ~TestRendererBase() {}
49d3daa3198e2212c985c634821682d5819346b653Chris Craik    virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
5074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        ADD_FAILURE() << "Temporary layers not expected in this test";
51a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        return nullptr;
52a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
5374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    virtual void recycleTemporaryLayer(OffscreenBuffer*) {
5474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        ADD_FAILURE() << "Temporary layers not expected in this test";
5574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    }
5698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
57a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer repaint not expected in this test";
58a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
59a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void endLayer() {
60a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer updates not expected in this test";
61a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
6298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
63e4db79de127cfe961195f52907af8451026eaa20Chris Craik    virtual void endFrame(const Rect& repaintRect) {}
645854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
6515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for single draw methods
6615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
67a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void on##Type(const Type&, const BakedOpState&) { \
68a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << #Type " not expected in this test"; \
69a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
707cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X)
7115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
7315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for merged draw methods
7415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
7515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
7615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
7715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
787cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X)
7915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
8015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
815854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int getIndex() { return mIndex; }
825854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
835854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikprotected:
845854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int mIndex = 0;
855854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik};
866fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
875854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik/**
885854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Dispatches all static methods to similar formed methods on renderer, which fail by default but
898ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * are overridden by subclasses per test.
905854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik */
915854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestDispatcher {
925854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikpublic:
9315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define single op methods, which redirect to TestRendererBase
9415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
955854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
965854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik        renderer.on##Type(op, state); \
976fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
987cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X);
9915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
10015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
10115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define merged op methods, which redirect to TestRendererBase
10215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
10315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
10415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        renderer.onMerged##Type##s(opList); \
10515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
1067cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X);
10715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
1086fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik};
109b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1105854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass FailRenderer : public TestRendererBase {};
1116fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
11298c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simple) {
113d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleTestRenderer : public TestRendererBase {
114d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
11598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
116d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
117d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(100u, width);
118d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(200u, height);
119d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
120d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
121d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
122d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
123d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
124d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
125d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
126e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
127d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
128d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
129d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
130d3daa3198e2212c985c634821682d5819346b653Chris Craik
13106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 200,
1328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
133aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
134b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 200, SkPaint());
135aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 10, 10, nullptr);
136b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
1379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
1389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
1399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
1409cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1415854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleTestRenderer renderer;
142f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1435854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
1446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
1456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
14698c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleStroke) {
147386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    class SimpleStrokeTestRenderer : public TestRendererBase {
148386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    public:
149386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
150386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(0, mIndex++);
151386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            // even though initial bounds are empty...
152386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_TRUE(op.unmappedBounds.isEmpty())
153386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "initial bounds should be empty, since they're unstroked";
154386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
155386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "final bounds should account for stroke";
156386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        }
157386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    };
158386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
15906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 200,
160386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
161386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        SkPaint strokedPaint;
162386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        strokedPaint.setStrokeWidth(10);
163386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        canvas.drawPoint(50, 50, strokedPaint);
164386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    });
1659cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
1669cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
1679cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
1689cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
169386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    SimpleStrokeTestRenderer renderer;
170f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
171386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    EXPECT_EQ(1, renderer.getIndex());
172386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik}
173386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
17449b403dc9c47ada51c8e5b883347682a868515f8Chris Craik
17549b403dc9c47ada51c8e5b883347682a868515f8Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, arcStrokeClip) {
17649b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    class ArcStrokeClipTestRenderer : public TestRendererBase {
17749b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    public:
17849b403dc9c47ada51c8e5b883347682a868515f8Chris Craik        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
17949b403dc9c47ada51c8e5b883347682a868515f8Chris Craik            EXPECT_EQ(0, mIndex++);
18049b403dc9c47ada51c8e5b883347682a868515f8Chris Craik            EXPECT_EQ(Rect(25, 25, 175, 175), op.unmappedBounds);
18149b403dc9c47ada51c8e5b883347682a868515f8Chris Craik            EXPECT_EQ(Rect(25, 25, 175, 175), state.computedState.clippedBounds);
18249b403dc9c47ada51c8e5b883347682a868515f8Chris Craik            EXPECT_EQ(OpClipSideFlags::Full, state.computedState.clipSideFlags)
18349b403dc9c47ada51c8e5b883347682a868515f8Chris Craik                    << "Arc op clipped conservatively, since path texture may be expanded";
18449b403dc9c47ada51c8e5b883347682a868515f8Chris Craik        }
18549b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    };
18649b403dc9c47ada51c8e5b883347682a868515f8Chris Craik
18749b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
18849b403dc9c47ada51c8e5b883347682a868515f8Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
18949b403dc9c47ada51c8e5b883347682a868515f8Chris Craik        canvas.clipRect(25, 25, 175, 175, SkClipOp::kIntersect);
19049b403dc9c47ada51c8e5b883347682a868515f8Chris Craik        SkPaint aaPaint;
19149b403dc9c47ada51c8e5b883347682a868515f8Chris Craik        aaPaint.setAntiAlias(true);
19249b403dc9c47ada51c8e5b883347682a868515f8Chris Craik        canvas.drawArc(25, 25, 175, 175, 40, 180, true, aaPaint);
19349b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    });
19449b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
19549b403dc9c47ada51c8e5b883347682a868515f8Chris Craik            sLightGeometry, Caches::getInstance());
19649b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
19749b403dc9c47ada51c8e5b883347682a868515f8Chris Craik
19849b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    ArcStrokeClipTestRenderer renderer;
19949b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
20049b403dc9c47ada51c8e5b883347682a868515f8Chris Craik    EXPECT_EQ(1, renderer.getIndex());
20149b403dc9c47ada51c8e5b883347682a868515f8Chris Craik}
20249b403dc9c47ada51c8e5b883347682a868515f8Chris Craik
20398c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleRejection) {
20406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
2058d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
206eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
2076c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect); // intersection should be empty
2086fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
2096fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
2106fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
2119cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
2129cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
2139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
214b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
2155854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
216f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
217b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
218b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
21998c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleBatching) {
220a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
221d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleBatchingTestRenderer : public TestRendererBase {
222d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
223d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
224a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
225d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
226d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
227a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
228d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
229d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
230d3daa3198e2212c985c634821682d5819346b653Chris Craik
23106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
2328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
233aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv
234aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(10, 10,
235aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv                kAlpha_8_SkColorType)); // Disable merging by using alpha 8 bitmap
236b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
237b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
238b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
239eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
240a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
241b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.translate(0, 10);
242b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawRect(0, 0, 10, 10, SkPaint());
243aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv            canvas.drawBitmap(*bitmap, 5, 0, nullptr);
244b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
245b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.restore();
246b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
2479cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
2489cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
2499cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
250b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
2515854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleBatchingTestRenderer renderer;
252f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
253a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
25415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            << "Expect number of ops = 2 * loop count";
255a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik}
256a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
25798c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNode_translateClip) {
2589cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    class DeferRenderNodeTranslateClipTestRenderer : public TestRendererBase {
2599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    public:
2609cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
2619cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(0, mIndex++);
2629cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(Rect(5, 10, 55, 60), state.computedState.clippedBounds);
2639cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom,
2649cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                    state.computedState.clipSideFlags);
2659cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        }
2669cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    };
2679cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
26806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2699cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
2709cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
2719cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    });
2729cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2739cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
2759cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node
2769cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            *TestUtils::getSyncedNode(node));
2779cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    DeferRenderNodeTranslateClipTestRenderer renderer;
2799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2809cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    EXPECT_EQ(1, renderer.getIndex());
2819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik}
2829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
28398c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNodeScene) {
2849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    class DeferRenderNodeSceneTestRenderer : public TestRendererBase {
2859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    public:
2869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
2879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            const Rect& clippedBounds = state.computedState.clippedBounds;
2889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            Matrix4 expected;
2899cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            switch (mIndex++) {
2909cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 0:
2919cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // background - left side
2929cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds);
2939cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                expected.loadTranslate(100, 100, 0);
2949cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
2959cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 1:
2969cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // background - top side
2979cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds);
2989cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                expected.loadTranslate(100, 100, 0);
2999cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
3009cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 2:
3019cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // content
3029cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds);
3039cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                expected.loadTranslate(-50, -50, 0);
3049cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
3059cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 3:
3069cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // overlay
3079cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds);
3089cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
3099cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            default:
3109cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                ADD_FAILURE() << "Too many rects observed";
3119cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            }
3129cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(expected, state.computedState.transform);
3139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        }
3149cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    };
3159cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3169cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    std::vector<sp<RenderNode>> nodes;
3179cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    SkPaint transparentPaint;
3189cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    transparentPaint.setAlpha(128);
3199cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3209cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // backdrop
32106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    nodes.push_back(TestUtils::createNode<RecordingCanvas>(100, 100, 700, 500, // 600x400
3229cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
3239cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 600, 400, transparentPaint);
3249cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }));
3259cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3269cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // content
3279cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    Rect contentDrawBounds(150, 150, 650, 450); // 500x300
32806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    nodes.push_back(TestUtils::createNode<RecordingCanvas>(0, 0, 800, 600,
3299cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
3309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 800, 600, transparentPaint);
3319cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }));
3329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // overlay
33406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    nodes.push_back(TestUtils::createNode<RecordingCanvas>(0, 0, 800, 600,
3359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
3369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 800, 200, transparentPaint);
3379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }));
3389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    for (auto& node : nodes) {
3409cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        TestUtils::syncHierarchyPropertiesAndDisplayList(node);
3419cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }
3429cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
34347aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck    {
34447aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
34547aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck                sLightGeometry, Caches::getInstance());
34647aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
34747aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck
34847aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        DeferRenderNodeSceneTestRenderer renderer;
34947aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        frameBuilder.replayBakedOps<TestDispatcher>(renderer);
35047aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        EXPECT_EQ(4, renderer.getIndex());
35147aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck    }
3529cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
35347aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck    for (auto& node : nodes) {
3542de950d5a8b47c7b4648ada1b1260ce4b7342798John Reck        EXPECT_TRUE(node->isValid());
35547aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        EXPECT_FALSE(node->nothingToDraw());
3562de950d5a8b47c7b4648ada1b1260ce4b7342798John Reck        node->setStagingDisplayList(nullptr);
3572de950d5a8b47c7b4648ada1b1260ce4b7342798John Reck        EXPECT_FALSE(node->isValid());
3582de950d5a8b47c7b4648ada1b1260ce4b7342798John Reck        EXPECT_FALSE(node->nothingToDraw());
3592de950d5a8b47c7b4648ada1b1260ce4b7342798John Reck        node->destroyHardwareResources();
36047aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        EXPECT_TRUE(node->nothingToDraw());
3612de950d5a8b47c7b4648ada1b1260ce4b7342798John Reck        EXPECT_FALSE(node->isValid());
36247aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck    }
36347aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck
36447aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck    {
36547aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        // Validate no crashes if any nodes are missing DisplayLists
36647aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
36747aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck                sLightGeometry, Caches::getInstance());
36847aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
36947aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck
37047aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        FailRenderer renderer;
37147aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck        frameBuilder.replayBakedOps<TestDispatcher>(renderer);
37247aa8d1477d1bacdb3b45e0463ef99dcf5c9cc09John Reck    }
3739cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik}
3749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
37598c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_noFbo0) {
3766246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class EmptyNoFbo0TestRenderer : public TestRendererBase {
3776246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
3786246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
3796246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
3806246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3816246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
3826246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
3836246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3846246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
3856246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
3869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // Use layer update constructor, so no work is enqueued for Fbo0
3879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    LayerUpdateQueue emptyLayerUpdateQueue;
3889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(emptyLayerUpdateQueue, sLightGeometry, Caches::getInstance());
3896246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EmptyNoFbo0TestRenderer renderer;
3906246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3916246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
3926246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
39398c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_withFbo0) {
3946246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class EmptyWithFbo0TestRenderer : public TestRendererBase {
3956246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
3966246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
3976246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(0, mIndex++);
3986246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3996246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
4006246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(1, mIndex++);
4016246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
4026246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
40306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
4046246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
4056246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        // no drawn content
4066246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    });
4076246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
4089cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // Draw, but pass node without draw content, so no work is done for primary frame
4099cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
4109cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
4119cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
4129cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
4136246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EmptyWithFbo0TestRenderer renderer;
4146246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
4156246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
4166246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            " but fbo0 update lifecycle should still be observed";
4176246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
4186246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
41998c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_rects) {
42080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    class AvoidOverdrawRectsTestRenderer : public TestRendererBase {
42180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    public:
42280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
42380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            EXPECT_EQ(mIndex++, 0) << "Should be one rect";
42480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds)
42580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                    << "Last rect should occlude others.";
42680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        }
42780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    };
42806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
42980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
43080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
43180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
43280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
43380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    });
43480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
43580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    // Damage (and therefore clip) is same as last draw, subset of renderable area.
43680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    // This means last op occludes other contents, and they'll be rejected to avoid overdraw.
4379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200,
4389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
4399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
44080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
44180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
44280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            << "Recording must not have rejected ops, in order for this test to be valid";
44380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
44480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    AvoidOverdrawRectsTestRenderer renderer;
44580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
44680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op";
44780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik}
44880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
44998c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
450aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv    static sk_sp<Bitmap> opaqueBitmap(TestUtils::createBitmap(50, 50,
451aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv            SkColorType::kRGB_565_SkColorType));
452aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv    static sk_sp<Bitmap> transpBitmap(TestUtils::createBitmap(50, 50,
453aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv            SkColorType::kAlpha_8_SkColorType));
45480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
45580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    public:
45680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
45780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            switch(mIndex++) {
45880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            case 0:
459ec4a4b13eae2241d1613890c1c1c096bed891845sergeyv                EXPECT_EQ(opaqueBitmap.get(), op.bitmap);
46080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                break;
46180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            case 1:
462ec4a4b13eae2241d1613890c1c1c096bed891845sergeyv                EXPECT_EQ(transpBitmap.get(), op.bitmap);
46380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                break;
46480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            default:
46580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                ADD_FAILURE() << "Only two ops expected.";
46680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            }
46780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        }
46880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    };
46980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
47006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 50, 50,
47180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
47280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 50, 50, SkPaint());
47380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 50, 50, SkPaint());
474aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
47580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
47680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        // only the below draws should remain, since they're
477aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*opaqueBitmap, 0, 0, nullptr);
478aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
47980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    });
4809cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50,
4819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
4829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
48380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
48480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
48580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            << "Recording must not have rejected ops, in order for this test to be valid";
48680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
48780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    AvoidOverdrawBitmapsTestRenderer renderer;
48880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
489a82ffc549bd6dbf8cfc6f4d646d0f458dca54014sergeyv    EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
49080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik}
49180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
49298c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clippedMerging) {
49393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    class ClippedMergingTestRenderer : public TestRendererBase {
49493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    public:
49593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        void onMergedBitmapOps(const MergedBakedOpList& opList) override {
49693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(0, mIndex);
49793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            mIndex += opList.count;
49893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(4u, opList.count);
49993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
50093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
50193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik                    opList.clipSideFlags);
50293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        }
50393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    };
50406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
50506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
506aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(20, 20));
50793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
50893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // left side clipped (to inset left half)
509a0a74d5f8ee1dbd04772ffb1775d045ce6b5934bMike Reed        canvas.clipRect(10, 0, 50, 100, SkClipOp::kReplace_deprecated);
510aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 0, 40, nullptr);
51193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
51293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // top side clipped (to inset top half)
513a0a74d5f8ee1dbd04772ffb1775d045ce6b5934bMike Reed        canvas.clipRect(0, 10, 100, 50, SkClipOp::kReplace_deprecated);
514aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 40, 0, nullptr);
51593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
51693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // right side clipped (to inset right half)
517a0a74d5f8ee1dbd04772ffb1775d045ce6b5934bMike Reed        canvas.clipRect(50, 0, 90, 100, SkClipOp::kReplace_deprecated);
518aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 80, 40, nullptr);
51993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
52093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // bottom not clipped, just abutting (inset bottom half)
521a0a74d5f8ee1dbd04772ffb1775d045ce6b5934bMike Reed        canvas.clipRect(0, 50, 100, 90, SkClipOp::kReplace_deprecated);
522aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 40, 70, nullptr);
52393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    });
52493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
5259cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
5269cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
5279cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
5289cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
52993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    ClippedMergingTestRenderer renderer;
530f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
53193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    EXPECT_EQ(4, renderer.getIndex());
53293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik}
53393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
53498c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, regionClipStopsMerge) {
535f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    class RegionClipStopsMergeTestRenderer : public TestRendererBase {
536f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    public:
537f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
538f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    };
539f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
540f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
541f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        SkPath path;
542f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        path.addCircle(200, 200, 200, SkPath::kCW_Direction);
543f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        canvas.save(SaveFlags::MatrixClip);
5446c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipPath(&path, SkClipOp::kIntersect);
545f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        SkPaint paint;
546f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
547f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        paint.setAntiAlias(true);
548f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        paint.setTextSize(50);
549f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
550f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
551f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        canvas.restore();
552f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    });
553f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik
554f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
555f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik            sLightGeometry, Caches::getInstance());
556f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
557f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik
558f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    RegionClipStopsMergeTestRenderer renderer;
559f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
560f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    EXPECT_EQ(2, renderer.getIndex());
561f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik}
562f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik
56398c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textMerging) {
564d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    class TextMergingTestRenderer : public TestRendererBase {
565d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    public:
566d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
567d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(0, mIndex);
568d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            mIndex += opList.count;
569d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(2u, opList.count);
570d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
571d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
572d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
573d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        }
574d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    };
57506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
57606152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
577d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        SkPaint paint;
578d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
579d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setAntiAlias(true);
580d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextSize(50);
581dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
582dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
583d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    });
5849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
5859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
5869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
5879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
588d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    TextMergingTestRenderer renderer;
589f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
590d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
591d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik}
592d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
59398c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStrikethrough) {
594a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
595a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    class TextStrikethroughTestRenderer : public TestRendererBase {
596a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    public:
597a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
598a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
599a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
60015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
60115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(0, mIndex);
60215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            mIndex += opList.count;
60315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(5u, opList.count);
604a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
605a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    };
60606152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 2000,
6078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
608a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        SkPaint textPaint;
609a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setAntiAlias(true);
610a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setTextSize(20);
611f77ca0872102116f58693d26703af8279573d014Derek Sollenberger        textPaint.setFlags(textPaint.getFlags() | SkPaint::kStrikeThruText_ReserveFlag);
61242a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
613a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
614dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
615a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
616a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    });
6179cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
6189cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000,
6199cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
6209cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
6219cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
622a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    TextStrikethroughTestRenderer renderer;
623f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
624a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
625d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            << "Expect number of ops = 2 * loop count";
626b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
627b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
6287c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craikstatic auto styles = {
6297c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
6307c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
63198c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStyle) {
6327c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    class TextStyleTestRenderer : public TestRendererBase {
6337c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    public:
6347c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
6357c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(0, mIndex);
6367c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(3u, opList.count);
6377c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            mIndex += opList.count;
6387c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
6397c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            int index = 0;
6407c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            for (auto style : styles) {
6417c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                auto state = opList.states[index++];
6427c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(style, state->op->paint->getStyle())
6437c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Remainder of validation relies upon stable merged order";
6447c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(0, state->computedState.clipSideFlags)
6457c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Clipped bounds validation requires unclipped ops";
6467c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            }
6477c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
6487c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect fill = opList.states[0]->computedState.clippedBounds;
6497c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect stroke = opList.states[1]->computedState.clippedBounds;
6507c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
6517c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                    << "Stroke+Fill should be same as stroke";
6527c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
6537c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_TRUE(stroke.contains(fill));
6547c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_FALSE(fill.contains(stroke));
6557c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
65679abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            // outset by half the stroke width
6577c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect outsetFill(fill);
65879abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            outsetFill.outset(5);
6597c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, outsetFill);
6607c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
6617c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    };
66206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
66306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
6647c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint paint;
6657c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
6667c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setAntiAlias(true);
6677c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextSize(50);
6687c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setStrokeWidth(10);
6697c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
6707c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // draw 3 copies of the same text overlapping, each with a different style.
6717c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // They'll get merged, but with
6727c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        for (auto style : styles) {
6737c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            paint.setStyle(style);
674dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
6757c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
6767c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    });
6779cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
6789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
6799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
6807c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    TextStyleTestRenderer renderer;
6817c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
6827c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
6837c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik}
6847c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
68598c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
686aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
687d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    public:
688d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
689d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(0, mIndex++);
690e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
691d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
692d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
693d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            Matrix4 expected;
694d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            expected.loadTranslate(5, 5, 0);
695d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
696d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        }
697d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    };
698d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
699d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
700243e85b2e443def1ef47a180e824b36f513c8db8Chris Craik            SkMatrix::MakeTrans(5, 5));
701d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
70206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
703d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
704eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
7056c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(50, 50, 150, 150, SkClipOp::kIntersect);
706d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawLayer(layerUpdater.get());
707d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.restore();
708d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
7099cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
7109cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
7119cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
7129cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
7139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
714aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerClipLocalMatrixTestRenderer renderer;
715f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
716d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    EXPECT_EQ(1, renderer.getIndex());
717d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
718d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
71998c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_combineMatrices) {
720aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
721aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    public:
722aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
723aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_EQ(0, mIndex++);
724aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
725aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            Matrix4 expected;
726aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            expected.loadTranslate(35, 45, 0);
727aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
728aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        }
729aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    };
730aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
731aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
732aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
733aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
73406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
735aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
736aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.save(SaveFlags::MatrixClip);
737aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.translate(30, 40);
738aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
739aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.restore();
740aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
741aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
7429cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
7439cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
7449cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
7459cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
746aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerCombineMatricesTestRenderer renderer;
747aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
748aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    EXPECT_EQ(1, renderer.getIndex());
749aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
750aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
75198c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_reject) {
752aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
753aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
75498c78dad1969e2321cfee2085faa55d95bba7e29Greg Daniel    EXPECT_EQ(Layer::Api::OpenGL, layerUpdater->backingLayer()->getApi());
7558cd3edfa15cc9cdbffa935d19ab894426b08d174Greg Daniel
7568cd3edfa15cc9cdbffa935d19ab894426b08d174Greg Daniel    GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
7578cd3edfa15cc9cdbffa935d19ab894426b08d174Greg Daniel    glLayer->setRenderTarget(GL_NONE); // Should be rejected
758aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
75906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
760aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
761aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
762aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
7639cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
7649cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
7659cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
7669cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
7679cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
768aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    FailRenderer renderer;
769aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
770aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
771aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
77298c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, functor_reject) {
773223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    class FunctorTestRenderer : public TestRendererBase {
774223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    public:
775223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
776223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            EXPECT_EQ(0, mIndex++);
777223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        }
778223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    };
779223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    Functor noopFunctor;
780223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
781223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    // 1 million pixel tall view, scrolled down 80%
78206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto scrolledFunctorView = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 1000000,
783223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
784223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.translate(0, -800000);
785cd1c3eba69d044b551cededad75474038f919890John Reck        canvas.callDrawGLFunction(&noopFunctor, nullptr);
786223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    });
787223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
7889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
7893a5811b50157e7ba50854caf957e806aee794d39Chris Craik            sLightGeometry, Caches::getInstance());
7909cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(scrolledFunctorView));
7919cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
792223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FunctorTestRenderer renderer;
793223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
794223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
795223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik}
796223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
79798c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferColorOp_unbounded) {
798a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    class ColorTestRenderer : public TestRendererBase {
799a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    public:
800a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
801a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(0, mIndex++);
802a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
803a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik                    << "Color op should be expanded to bounds of surrounding";
804a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        }
805a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    };
806a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
80706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto unclippedColorView = TestUtils::createNode<RecordingCanvas>(0, 0, 10, 10,
808a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
809a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        props.setClipToBounds(false);
810260ab726486317496bc12a57d599ea96dcde3284Mike Reed        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
811a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    });
812a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
8139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
814a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            sLightGeometry, Caches::getInstance());
8159cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(unclippedColorView));
8169cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
817a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    ColorTestRenderer renderer;
818a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
819a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
820a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik}
821a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
822e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderNode) {
823d3daa3198e2212c985c634821682d5819346b653Chris Craik    class RenderNodeTestRenderer : public TestRendererBase {
824d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
825d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
826d3daa3198e2212c985c634821682d5819346b653Chris Craik            switch(mIndex++) {
827d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 0:
8285430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
829d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
830d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
831d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 1:
832d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
833d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
834d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
835d3daa3198e2212c985c634821682d5819346b653Chris Craik            default:
836d3daa3198e2212c985c634821682d5819346b653Chris Craik                ADD_FAILURE();
837d3daa3198e2212c985c634821682d5819346b653Chris Craik            }
838d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
839d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
840d3daa3198e2212c985c634821682d5819346b653Chris Craik
84106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
8428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
843b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        SkPaint paint;
844b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        paint.setColor(SK_ColorWHITE);
845b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
846b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
847b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
84806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
849d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&child](RenderProperties& props, RecordingCanvas& canvas) {
850ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkPaint paint;
851ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        paint.setColor(SK_ColorDKGRAY);
852ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawRect(0, 0, 200, 200, paint);
853ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
854eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
855ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.translate(40, 40);
856d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawRenderNode(child.get());
857ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.restore();
858b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
859b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
8609cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
8619cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
8629cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
8639cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
8645854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    RenderNodeTestRenderer renderer;
865f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
866223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(2, renderer.getIndex());
867b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
868b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
86998c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clipped) {
870d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ClippedTestRenderer : public TestRendererBase {
871d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
872d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
873d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
874d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
875e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
876d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
877d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
878d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
879d3daa3198e2212c985c634821682d5819346b653Chris Craik
88006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
8818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
882aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(200, 200));
883aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 0, 0, nullptr);
884ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik    });
885ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
8869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // clip to small area, should see in receiver
8879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200,
8889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
8899cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
8909cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
8915854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ClippedTestRenderer renderer;
892f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
893ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik}
894ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
89598c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_simple) {
896d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerSimpleTestRenderer : public TestRendererBase {
897d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
898d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
899d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
900d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, width);
901d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, height);
902d3daa3198e2212c985c634821682d5819346b653Chris Craik            return nullptr;
903d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
904d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
905d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
906d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
907d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
908d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
909d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
9105430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
911e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
912d3daa3198e2212c985c634821682d5819346b653Chris Craik
913d3daa3198e2212c985c634821682d5819346b653Chris Craik            Matrix4 expectedTransform;
914d3daa3198e2212c985c634821682d5819346b653Chris Craik            expectedTransform.loadTranslate(-10, -10, 0);
915d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
916d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
917d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
918d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
919d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
920e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
921d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
922d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
92374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
92474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(4, mIndex++);
92574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(nullptr, offscreenBuffer);
92674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
927d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
928d3daa3198e2212c985c634821682d5819346b653Chris Craik
92906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
9308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
931eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
9326fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
9336fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
9346fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
9359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
9369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
9379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
9389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
9399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
9405854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerSimpleTestRenderer renderer;
941f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
94274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(5, renderer.getIndex());
943b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
9446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
94598c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_nested) {
946d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
947d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer2, rect2 endLayer2
948d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
949d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, layerOp1, endFrame
950d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
951d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerNestedTestRenderer : public TestRendererBase {
952d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
953d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
954d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
955d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
956d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, width);
957d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, height);
958d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x400;
959d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 3) {
960d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, width);
961d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, height);
962d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x800;
963d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
964d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*) nullptr;
965d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
966d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
967d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
968d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 6);
969d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
97098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
971d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(7, mIndex++);
972d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
973e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
974d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(9, mIndex++);
975d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
976d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
977d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
978d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
9795430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
980d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 4) {
9815430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
982d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
983d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
984d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
985d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
986d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 5) {
987d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
9885430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
989d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
990d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
9915430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
992d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
993d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
99474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
99574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            const int index = mIndex++;
99674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            // order isn't important, but we need to see both
99774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            if (index == 10) {
99874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer);
99974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            } else if (index == 11) {
100074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer);
100174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            } else { ADD_FAILURE(); }
100274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
1003d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1004d3daa3198e2212c985c634821682d5819346b653Chris Craik
100506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 800, 800,
10068d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1007eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
10086fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        {
10096fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.drawRect(0, 0, 800, 800, SkPaint());
1010eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
10116fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            {
10126fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                canvas.drawRect(0, 0, 400, 400, SkPaint());
10136fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            }
10146fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.restore();
10156fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
10166fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
10176fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
10186fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
10199cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800,
10209cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
10219cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
10229cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
10235854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerNestedTestRenderer renderer;
1024f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
102574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(12, renderer.getIndex());
10266fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
10276fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
102898c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_contentRejection) {
102906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev        auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
10308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                [](RenderProperties& props, RecordingCanvas& canvas) {
1031eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
10326c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect);
1033eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
10346fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
10356fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // draw within save layer may still be recorded, but shouldn't be drawn
10366fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(200, 200, 400, 400, SkPaint());
10376fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
10386fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
10396fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
10406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
10419cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
10429cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
10439cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
10449cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
10456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
10465854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
10476fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // should see no ops, even within the layer, since the layer should be rejected
1048f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1049b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
10506fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
105198c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_simple) {
1052b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
1053b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
1054b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1055b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++);
1056b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
10577435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
1058b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1059b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1060b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
1061b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(1, mIndex++);
1062b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_NE(nullptr, op.paint);
1063260ab726486317496bc12a57d599ea96dcde3284Mike Reed            ASSERT_EQ(SkBlendMode::kClear, PaintUtils::getBlendModeDirect(op.paint));
1064b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1065b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1066b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(2, mIndex++);
1067b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
1068b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
1069b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
1070b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1071b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1072b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1073b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
1074b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
10757435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
1076b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1077b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1078b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
1079b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
108006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1081b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1082eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
1083b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
1084b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1085b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
10869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
10879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
10889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
10899cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
10909cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1091b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedSimpleTestRenderer renderer;
1092f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1093b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(4, renderer.getIndex());
1094b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1095b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
109698c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_round) {
1097d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    class SaveLayerUnclippedRoundTestRenderer : public TestRendererBase {
1098d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    public:
1099d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1100d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            EXPECT_EQ(0, mIndex++);
1101d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
1102d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik                    << "Bounds rect should round out";
1103d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        }
1104d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {}
1105d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {}
1106d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1107d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            EXPECT_EQ(1, mIndex++);
1108d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
1109d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik                    << "Bounds rect should round out";
1110d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        }
1111d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    };
1112d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik
111306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1114d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1115d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out
1116d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik                128, (SaveFlags::Flags)(0));
1117d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
1118d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        canvas.restore();
1119d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    });
1120d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik
1121d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
1122d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            sLightGeometry, Caches::getInstance());
1123d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
1124d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik
1125d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    SaveLayerUnclippedRoundTestRenderer renderer;
1126d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1127d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    EXPECT_EQ(2, renderer.getIndex());
1128d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik}
1129d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik
113098c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
1131b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
1132b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
1133b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1134b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1135b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_GT(4, index);
1136b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getWidth());
1137b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getHeight());
1138b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            if (index == 0) {
1139b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
1140b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 1) {
1141b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
1142b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 2) {
1143b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
1144b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 3) {
1145b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
1146b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
1147b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1148b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
1149b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(4, mIndex++);
1150b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(op.vertexCount, 16u);
1151b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            for (size_t i = 0; i < op.vertexCount; i++) {
1152b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                auto v = op.vertices[i];
1153b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
1154b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
1155b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
1156b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1157b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1158b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
1159b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1160b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1161b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_LT(5, mIndex++);
1162b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1163b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
1164b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
116506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1166b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1167b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1168eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int restoreTo = canvas.save(SaveFlags::MatrixClip);
1169b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.scale(2, 2);
1170eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
1171eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
1172eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
1173eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
1174b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
1175b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restoreToCount(restoreTo);
1176b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
11779cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
11789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
11799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
11809cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
11819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1182b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedMergedClearsTestRenderer renderer;
1183f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1184b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(10, renderer.getIndex())
1185b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
1186b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1187b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
118898c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
11894876de16e34622634266d09522c9153c78c7c2fbChris Craik    class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
11904876de16e34622634266d09522c9153c78c7c2fbChris Craik    public:
11914876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
11924876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(0, mIndex++);
11934876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
11944876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
11954876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(1, mIndex++);
11964876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, op.paint);
1197260ab726486317496bc12a57d599ea96dcde3284Mike Reed            EXPECT_EQ(SkBlendMode::kClear, PaintUtils::getBlendModeDirect(op.paint));
11984876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
11994876de16e34622634266d09522c9153c78c7c2fbChris Craik                    << "Expect dirty rect as clip";
12004876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
12014876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
12024876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
12034876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
12044876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
12054876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(2, mIndex++);
12064876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
12074876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
12084876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(3, mIndex++);
12094876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
12104876de16e34622634266d09522c9153c78c7c2fbChris Craik    };
12114876de16e34622634266d09522c9153c78c7c2fbChris Craik
121206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
12134876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
12144876de16e34622634266d09522c9153c78c7c2fbChris Craik        // save smaller than clip, so we get unclipped behavior
12154876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
12164876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
12174876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
12184876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
12194876de16e34622634266d09522c9153c78c7c2fbChris Craik
12204876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty, and assert we see that rect later
12219cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
12229cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
12239cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
12249cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
12254876de16e34622634266d09522c9153c78c7c2fbChris Craik    SaveLayerUnclippedClearClipTestRenderer renderer;
12264876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
12274876de16e34622634266d09522c9153c78c7c2fbChris Craik    EXPECT_EQ(4, renderer.getIndex());
12284876de16e34622634266d09522c9153c78c7c2fbChris Craik}
12294876de16e34622634266d09522c9153c78c7c2fbChris Craik
123098c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_reject) {
123106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
12324876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
12334876de16e34622634266d09522c9153c78c7c2fbChris Craik        // unclipped savelayer + rect both in area that won't intersect with dirty
12344876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
12354876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(100, 100, 200, 200, SkPaint());
12364876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
12374876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
12384876de16e34622634266d09522c9153c78c7c2fbChris Craik
12394876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty that doesn't intersect with savelayer
12409cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
12419cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
12429cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
12439cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
12444876de16e34622634266d09522c9153c78c7c2fbChris Craik    FailRenderer renderer;
12454876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
12464876de16e34622634266d09522c9153c78c7c2fbChris Craik}
12474876de16e34622634266d09522c9153c78c7c2fbChris Craik
1248b87eadda1818034ce03d85f30388384d1ac65916Chris Craik/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
1249b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
1250b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
1251b87eadda1818034ce03d85f30388384d1ac65916Chris Craik */
125298c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_complex) {
1253b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
1254b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
1255b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
1256b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++); // savelayer first
1257b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            return (OffscreenBuffer*)0xabcd;
1258b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1259b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1260b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1261b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 1 || index == 7);
1262b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1263b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
1264b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1265b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 2 || index == 8);
1266b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1267b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1268b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
1269b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            Matrix4 expected;
1270b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            expected.loadTranslate(-100, -100, 0);
1271b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
1272b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
1273b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1274b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1275b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1276b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 4 || index == 10);
1277b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1278b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endLayer() override {
1279b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
1280b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1281b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1282b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(6, mIndex++);
1283b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1284b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1285b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(9, mIndex++);
128674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
1287b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1288b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endFrame(const Rect& repaintRect) override {
1289b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(11, mIndex++);
1290b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
129174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
129274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(12, mIndex++);
129374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer);
129474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
1295b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
1296b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
129706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 600, 600, // 500x500 triggers clipping
1298b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1299eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
1300eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
1301eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
1302b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(200, 200, 300, 300, SkPaint());
1303b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1304b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1305b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1306b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
13079cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
13089cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600,
13099cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
13109cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
13119cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1312b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedComplexTestRenderer renderer;
1313f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
131474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(13, renderer.getIndex());
1315b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1316b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
131798c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_simple) {
1318d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerSimpleTestRenderer : public TestRendererBase {
1319d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
132098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1321d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
132298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
132398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
132498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
1325d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1326d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1327d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
13280b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1329d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
1330d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Transform should be reset within layer";
1331d3daa3198e2212c985c634821682d5819346b653Chris Craik
1332e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
1333d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Damage rect should be used to clip layer content";
1334d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1335d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
1336d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
1337d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
133898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1339d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
1340d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1341d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1342d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(4, mIndex++);
1343d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1344e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
1345d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(5, mIndex++);
1346d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1347d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
13480b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
134906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
135016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
135116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
13520b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
13530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
13540b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
135516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
135698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
13570b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
135898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would
135998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
136098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
13610b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13629cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(node);
13630b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13640b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // only enqueue partial damage
136598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
13660b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
13670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13689cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
13699cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
13709cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
13719cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
13729cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
13730b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerSimpleTestRenderer renderer;
1374f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
13750b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(6, renderer.getIndex());
13760b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13770b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
137898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
13790b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
13800b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
138198c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_complex) {
1382d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
1383d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(child), rect(grey), endLayer
1384d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer, drawLayer(child), endLayer
1385d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
1386d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, drawLayer(parent), endLayerb
1387d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
1388d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerComplexTestRenderer : public TestRendererBase {
1389d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1390d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
1391d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++); // savelayer first
1392d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*)0xabcd;
1393d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
139498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1395d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1396d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
1397d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting inner layer
139898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
139998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
1400d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 6) {
1401d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting outer layer
140298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
140398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
1404d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1405d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1406d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1407d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1408d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
1409d3daa3198e2212c985c634821682d5819346b653Chris Craik                // inner layer's rect (white)
1410d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
1411d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 7) {
1412d3daa3198e2212c985c634821682d5819346b653Chris Craik                // outer layer's rect (grey)
1413d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1414d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1415d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1416d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
1417d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1418d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
1419d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
142098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1421d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(10, mIndex++);
1422d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1423d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
142498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            OffscreenBuffer* layer = *op.layerHandle;
1425d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1426d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 4) {
142798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportWidth);
142898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportHeight);
1429d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
1430d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
1431d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 11) {
143298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportWidth);
143398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportHeight);
1434d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1435d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1436e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
1437d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(12, mIndex++);
1438d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
143974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
144074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(13, mIndex++);
144174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
1442d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1443d3daa3198e2212c985c634821682d5819346b653Chris Craik
144406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(50, 50, 150, 150,
144516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
144616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
14470b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
14480b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
14490b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
145016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
145198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
145298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(child->getLayerHandle()) = &childLayer;
14530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14540b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    RenderNode* childPtr = child.get();
145506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
145616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
145716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
14580b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
14590b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorDKGRAY);
14600b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 200, 200, paint);
14610b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1462eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
14630b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRenderNode(childPtr);
14640b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.restore();
146516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
146698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
146798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(parent->getLayerHandle()) = &parentLayer;
14680b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14699cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(parent);
14700b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
147198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
14720b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
14730b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
14740b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14759cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
14769cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
14779cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
14789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
14799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
14800b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerComplexTestRenderer renderer;
1481f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
148274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(14, renderer.getIndex());
14830b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14840b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointers, so we can safely destruct RenderNodes
14850b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(child->getLayerHandle()) = nullptr;
14860b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(parent->getLayerHandle()) = nullptr;
14870b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
14880b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14896246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
149098c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, buildLayer) {
14916246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class BuildLayerTestRenderer : public TestRendererBase {
14926246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
14936246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
14946246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(0, mIndex++);
14956246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
14966246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
14976246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
14986246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14996246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
15006246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(1, mIndex++);
15016246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
15026246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
15036246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik                    << "Transform should be reset within layer";
15046246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
15056246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
15066246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik                    << "Damage rect should be used to clip layer content";
15076246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
15086246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endLayer() override {
15096246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(2, mIndex++);
15106246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
15116246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
15126246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
15136246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
15146246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
15156246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
15166246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
15176246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
15186246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
151906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
15206246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
15216246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        props.mutateLayerProperties().setType(LayerType::RenderLayer);
1522260ab726486317496bc12a57d599ea96dcde3284Mike Reed        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
15236246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    });
15246246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
15256246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
15266246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // create RenderNode's layer here in same way prepareTree would
15276246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
15286246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    *layerHandle = &layer;
15296246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
15309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    TestUtils::syncHierarchyPropertiesAndDisplayList(node);
15316246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
15326246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // only enqueue partial damage
15336246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
15346246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
15356246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
15366246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // Draw, but pass empty node list, so no work is done for primary frame
15379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, sLightGeometry, Caches::getInstance());
15386246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    BuildLayerTestRenderer renderer;
15396246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
15406246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EXPECT_EQ(3, renderer.getIndex());
15416246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
15426246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
15436246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    *layerHandle = nullptr;
15446246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
15456246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
1546db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievnamespace {
1547db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
154806152cdd06da50762716cd455dcf7ab0117f25b0Stan Ilievstatic void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
1549161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    SkPaint paint;
1550814ee6a9218aa339a4757b2c0ba1ad268f8dbc8aChris Craik    // order put in blue channel, transparent so overlapped content doesn't get rejected
1551814ee6a9218aa339a4757b2c0ba1ad268f8dbc8aChris Craik    paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
1552161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRect(0, 0, 100, 100, paint);
1553161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
155406152cdd06da50762716cd455dcf7ab0117f25b0Stan Ilievstatic void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
155506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
15568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
1557161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, expectedDrawOrder);
1558161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1559161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->mutateStagingProperties().setTranslationZ(z);
1560161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
1561161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
1562161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
1563db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
1564db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievstatic void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder,
1565db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        std::function<void(RenderProperties& props, RecordingCanvas& canvas)> setup) {
1566db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
1567db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [expectedDrawOrder, setup](RenderProperties& props, RecordingCanvas& canvas) {
1568db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedRect(&canvas, expectedDrawOrder);
1569db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        if (setup) {
1570db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev             setup(props, canvas);
1571d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1572db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    });
1573db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
1574db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
1575db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
1576db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievclass ZReorderTestRenderer : public TestRendererBase {
1577db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievpublic:
1578db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    void onRectOp(const RectOp& op, const BakedOpState& state) override {
1579db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
1580db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
1581db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }
1582db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev};
1583db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
1584db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev} // end anonymous namespace
1585d3daa3198e2212c985c634821682d5819346b653Chris Craik
158698c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, zReorder) {
158706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
15888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1589347691f8d87157be0eaeca26f4003d8a06a275e3Stan Iliev        canvas.insertReorderBarrier(true);
1590347691f8d87157be0eaeca26f4003d8a06a275e3Stan Iliev        canvas.insertReorderBarrier(false);
1591161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
1592161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 1);
1593161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(true);
1594161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 6, 2.0f);
1595161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 3);
1596161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 4, 0.0f);
1597161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 5);
1598161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 2, -2.0f);
1599161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 7, 2.0f);
1600161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(false);
1601161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 8);
1602161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
160388e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
160488e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        drawOrderedRect(&canvas, 11);
160588e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        drawOrderedNode(&canvas, 10, -1.0f);
160688e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(false);
160788e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(true); //test with two empty reorder sections
160888e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(true);
160988e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(false);
161088e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        drawOrderedRect(&canvas, 12);
1611161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
16129cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
16139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
16149cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
16159cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1616161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    ZReorderTestRenderer renderer;
1617f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
161888e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev    EXPECT_EQ(13, renderer.getIndex());
1619161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik};
1620161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
162198c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorder) {
16228d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollX = 5;
16238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollY = 10;
16248d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    class ProjectionReorderTestRenderer : public TestRendererBase {
16258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    public:
16268d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
16278d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            const int index = mIndex++;
16288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
16298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            Matrix4 expectedMatrix;
16308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            switch (index) {
16318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 0:
16328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
16338d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
16348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadIdentity();
1635678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
16368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
16378d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 1:
16388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
16398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1640678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
1641678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1642678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(Rect(-35, -30, 45, 50),
1643678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                        Rect(state.computedState.localProjectionPathMask->getBounds()));
16448d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
16458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 2:
16468d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
16478d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
16488d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
1649678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
16508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
16518d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            default:
16528d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                ADD_FAILURE();
16538d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            }
1654678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expectedMatrix, state.computedState.transform);
16558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        }
16568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    };
16578d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
16588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    /**
16598d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
16608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
16618d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * draw, but because it is projected backwards, it's drawn in between B and C.
16628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     *
16638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
16648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * (which isn't affected by scroll).
16658d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     */
166606152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
16678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
16688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectionReceiver(true);
16698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
16708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
16718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationX(scrollX);
16728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationY(scrollY);
16738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
16748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
16758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorWHITE);
16768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 100, paint);
16778d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
167806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto projectingRipple = TestUtils::createNode<RecordingCanvas>(50, 0, 100, 50,
16798d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
16808d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectBackwards(true);
16818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setClipToBounds(false);
16828d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
16838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorDKGRAY);
16848d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(-10, -10, 60, 60, paint);
16858d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
168606152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(0, 50, 100, 100,
16878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
16888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
16898d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorBLUE);
16908d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 50, paint);
16918d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(projectingRipple.get());
16928d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
169306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
16948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1695678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1696678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
1697678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1698eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
16998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
17008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(receiverBackground.get());
17018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(child.get());
17028d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.restore();
17038d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
17048d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
17059cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
17069cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
17079cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
17089cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
17098d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    ProjectionReorderTestRenderer renderer;
1710f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
17118d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    EXPECT_EQ(3, renderer.getIndex());
17128d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik}
17138d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
171498c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionHwLayer) {
1715678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollX = 5;
1716678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollY = 10;
1717678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    class ProjectionHwLayerTestRenderer : public TestRendererBase {
1718678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    public:
1719678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1720678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(0, mIndex++);
1721678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1722678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
1723678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(1, mIndex++);
1724678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1725678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1726678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void endLayer() override {
1727678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(2, mIndex++);
1728678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1729678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1730678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(3, mIndex++);
1731678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1732678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1733678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1734678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(4, mIndex++);
1735678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1736678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            Matrix4 expected;
1737678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
1738678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expected, state.computedState.transform);
1739678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(Rect(-85, -80, 295, 300),
1740678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                    Rect(state.computedState.localProjectionPathMask->getBounds()));
1741678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1742678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1743678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(5, mIndex++);
1744678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1745678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1746678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    };
174706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1748678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1749678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectionReceiver(true);
1750678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1751678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1752678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationX(scrollX);
1753678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationY(scrollY);
1754678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1755678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1756678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
175706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto projectingRipple = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1758678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1759678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectBackwards(true);
1760678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setClipToBounds(false);
1761678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
1762678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
176306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(100, 100, 300, 300,
1764678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1765678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
1766678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(projectingRipple.get());
1767678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
1768678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
176906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1770678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1771678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1772678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
1773678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1774678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(receiverBackground.get());
1775678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(child.get());
1776678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1777678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1778678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer** layerHandle = child->getLayerHandle();
1779678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1780678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1781678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
1782678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    Matrix4 windowTransform;
1783678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
1784678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layer.setWindowTransform(windowTransform);
1785678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = &layer;
1786678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
17879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(parent);
17889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1789678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1790678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
17919cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
17929cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
17939cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
17949cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
17959cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
17969cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1797678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    ProjectionHwLayerTestRenderer renderer;
1798678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1799678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    EXPECT_EQ(6, renderer.getIndex());
1800678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1801678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // clean up layer pointer, so we can safely destruct RenderNode
1802678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = nullptr;
1803678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik}
1804678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
180598c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionChildScroll) {
1806a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollX = 500000;
1807a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollY = 0;
1808a748c08241e43fc68c7c34767d819aef5183936eChris Craik    class ProjectionChildScrollTestRenderer : public TestRendererBase {
1809a748c08241e43fc68c7c34767d819aef5183936eChris Craik    public:
1810a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1811a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(0, mIndex++);
1812a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1813a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1814a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1815a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(1, mIndex++);
1816a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
1817a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
1818a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
1819a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1820a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1821a748c08241e43fc68c7c34767d819aef5183936eChris Craik    };
182206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1823a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1824a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectionReceiver(true);
1825a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1826a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
182706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto projectingRipple = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1828a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1829a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1830a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1831a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationX(scrollX);
1832a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationY(scrollY);
1833a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectBackwards(true);
1834a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setClipToBounds(false);
1835a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawOval(0, 0, 200, 200, SkPaint());
1836a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
183706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1838a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1839a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // Record time clip will be ignored by projectee
18406c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
1841a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1842a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1843a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(projectingRipple.get());
1844a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
184506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1846a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1847a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(receiverBackground.get());
1848a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(child.get());
1849a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1850a748c08241e43fc68c7c34767d819aef5183936eChris Craik
18519cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
18529cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
18539cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
18549cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1855a748c08241e43fc68c7c34767d819aef5183936eChris Craik    ProjectionChildScrollTestRenderer renderer;
1856a748c08241e43fc68c7c34767d819aef5183936eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1857a748c08241e43fc68c7c34767d819aef5183936eChris Craik    EXPECT_EQ(2, renderer.getIndex());
1858a748c08241e43fc68c7c34767d819aef5183936eChris Craik}
1859a748c08241e43fc68c7c34767d819aef5183936eChris Craik
186098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik// creates a 100x100 shadow casting node with provided translationZ
186198787e6c9b2c10b1ab7820bdac168686025b924aChris Craikstatic sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
186206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    return TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
18638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
186416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.setTranslationZ(translationZ);
186516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
186698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        SkPaint paint;
186798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        paint.setColor(SK_ColorWHITE);
186898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
186998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
187098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
187198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
187298c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadow) {
1873d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ShadowTestRenderer : public TestRendererBase {
1874d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1875d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1876d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
187798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
18786e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
18796e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
188098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
188198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            Matrix4 expectedZ;
188298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            expectedZ.loadTranslate(0, 0, 5);
18836e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
1884d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1885d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1886d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
1887d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1888d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1889161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
189006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
18918d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
189298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
189398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1894d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
189598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
18969cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
18979cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
18989cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
18999cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
190098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowTestRenderer renderer;
1901f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
190298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(2, renderer.getIndex());
190398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
190498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
190598c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowSaveLayer) {
190698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowSaveLayerTestRenderer : public TestRendererBase {
190798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
190898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
190998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
191098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            return nullptr;
191198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
191298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
191398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
19146e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
19156e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
191698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
191798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
191898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
191998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
192098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
192198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
192298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
192398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
192498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
192598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
192674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
192774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(5, mIndex++);
192874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
192998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
193098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
193106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
19328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
193398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        // save/restore outside of reorderBarrier, so they don't get moved out of place
193498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
1935eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
1936d3daa3198e2212c985c634821682d5819346b653Chris Craik        canvas.insertReorderBarrier(true);
193798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
193898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(false);
193998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restoreToCount(count);
1940d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
1941d3daa3198e2212c985c634821682d5819346b653Chris Craik
19429cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
19433a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
19449cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
19459cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
194698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowSaveLayerTestRenderer renderer;
1947f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
194874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(6, renderer.getIndex());
194998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
1950d3daa3198e2212c985c634821682d5819346b653Chris Craik
195198c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowHwLayer) {
195298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowHwLayerTestRenderer : public TestRendererBase {
195398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
195498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
195598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
195698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
195798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
195898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
19596e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
19606e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
19616e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
196298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
196398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
196498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
196598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
196698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
196798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
196898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
196998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
197098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
197198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
197298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
1973d3daa3198e2212c985c634821682d5819346b653Chris Craik
197406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(50, 60, 150, 160,
197516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
197616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
197798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
1978eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
197998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
198098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
198198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restore();
198216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
198398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = parent->getLayerHandle();
198498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
198598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
198698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
198798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    Matrix4 windowTransform;
198898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
198998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layer.setWindowTransform(windowTransform);
199098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
199198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
19929cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(parent);
199398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
199498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
19959cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
19969cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
19973a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
19989cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
19999cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
20009cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
200198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowHwLayerTestRenderer renderer;
2002f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
200398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
200498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
200598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
200698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
2007d3daa3198e2212c985c634821682d5819346b653Chris Craik}
200876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
200998c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowLayering) {
201098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowLayeringTestRenderer : public TestRendererBase {
201198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
201298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
201398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
201498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 0 || index == 1);
201598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
201698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
201798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
201898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 2 || index == 3);
201998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
202098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
202106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
20228d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
202398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
202498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
202598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
202698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
20279cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
20283a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
20299cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
20309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
203198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowLayeringTestRenderer renderer;
2032f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
203398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(4, renderer.getIndex());
203498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
203598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
203698c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowClipping) {
2037d645640180c25c2711e99aa82ec629155f8e91baChris Craik    class ShadowClippingTestRenderer : public TestRendererBase {
2038d645640180c25c2711e99aa82ec629155f8e91baChris Craik    public:
2039d645640180c25c2711e99aa82ec629155f8e91baChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
2040d645640180c25c2711e99aa82ec629155f8e91baChris Craik            EXPECT_EQ(0, mIndex++);
2041d645640180c25c2711e99aa82ec629155f8e91baChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipState->rect)
2042d645640180c25c2711e99aa82ec629155f8e91baChris Craik                    << "Shadow must respect pre-barrier canvas clip value.";
2043d645640180c25c2711e99aa82ec629155f8e91baChris Craik        }
2044d645640180c25c2711e99aa82ec629155f8e91baChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
2045d645640180c25c2711e99aa82ec629155f8e91baChris Craik            EXPECT_EQ(1, mIndex++);
2046d645640180c25c2711e99aa82ec629155f8e91baChris Craik        }
2047d645640180c25c2711e99aa82ec629155f8e91baChris Craik    };
204806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2049d645640180c25c2711e99aa82ec629155f8e91baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
2050d645640180c25c2711e99aa82ec629155f8e91baChris Craik        // Apply a clip before the reorder barrier/shadow casting child is drawn.
2051d645640180c25c2711e99aa82ec629155f8e91baChris Craik        // This clip must be applied to the shadow cast by the child.
20526c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(25, 25, 75, 75, SkClipOp::kIntersect);
2053d645640180c25c2711e99aa82ec629155f8e91baChris Craik        canvas.insertReorderBarrier(true);
2054d645640180c25c2711e99aa82ec629155f8e91baChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
2055d645640180c25c2711e99aa82ec629155f8e91baChris Craik    });
2056d645640180c25c2711e99aa82ec629155f8e91baChris Craik
20579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2058d645640180c25c2711e99aa82ec629155f8e91baChris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
20599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
20609cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2061d645640180c25c2711e99aa82ec629155f8e91baChris Craik    ShadowClippingTestRenderer renderer;
2062d645640180c25c2711e99aa82ec629155f8e91baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2063d645640180c25c2711e99aa82ec629155f8e91baChris Craik    EXPECT_EQ(2, renderer.getIndex());
2064d645640180c25c2711e99aa82ec629155f8e91baChris Craik}
2065d645640180c25c2711e99aa82ec629155f8e91baChris Craik
206616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
206776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
2068d3daa3198e2212c985c634821682d5819346b653Chris Craik    class PropertyTestRenderer : public TestRendererBase {
2069d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
2070d53e3bed1ca4a14b2a86d53eaef6969bd043176eChih-Hung Hsieh        explicit PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
2071d3daa3198e2212c985c634821682d5819346b653Chris Craik                : mCallback(callback) {}
2072d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
2073d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(mIndex++, 0);
2074d3daa3198e2212c985c634821682d5819346b653Chris Craik            mCallback(op, state);
2075d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
2076d3daa3198e2212c985c634821682d5819346b653Chris Craik        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
2077d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
2078d3daa3198e2212c985c634821682d5819346b653Chris Craik
207906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
208016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
208116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(props);
208276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkPaint paint;
208376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        paint.setColor(SK_ColorWHITE);
208476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
208516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
208676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
20889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
20899cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
20909cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
209176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    PropertyTestRenderer renderer(opValidateCallback);
2092f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
209376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
209476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
209576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
209698c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
209776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
209876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAlpha(0.5f);
209976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setHasOverlappingRendering(false);
210076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
210176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
210276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
210376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
210476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
210598c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropClipping) {
210676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
210776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipToBounds(true);
210876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipBounds(Rect(10, 20, 300, 400));
210976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
211076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
211176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Clip rect should be intersection of node bounds and clip bounds";
211276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
211376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
211476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
211598c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropRevealClip) {
211676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
211776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableRevealClip().set(true, 50, 50, 25);
211876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
211976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
212076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_TRUE(state.roundRectClipState->highPriority);
212176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(25, state.roundRectClipState->radius);
212276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
212376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
212476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
212576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
212698c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOutlineClip) {
212776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
212876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setShouldClip(true);
212976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
213076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
213176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
213276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_FALSE(state.roundRectClipState->highPriority);
213376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(5, state.roundRectClipState->radius);
213476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
213576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
213676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
213776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
213898c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropTransform) {
213976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
214076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setLeftTopRightBottom(10, 10, 110, 110);
214176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
214276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
214376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setStaticMatrix(&staticMatrix);
214476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
214576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignored, since static overrides animation
214676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
214776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAnimationMatrix(&animationMatrix);
214876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
214976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationX(10);
215076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationY(20);
215176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleX(0.5f);
215276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleY(0.7f);
215376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
215476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        Matrix4 matrix;
215576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.loadTranslate(10, 10, 0); // left, top
215676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(1.2f, 1.2f, 1); // static matrix
215776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignore animation matrix, since static overrides it
215876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
215976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // translation xy
216076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(10, 20);
216176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
216276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // scale xy (from default pivot - center)
216376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(50, 50);
216476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(0.5f, 0.7f, 1);
216576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(-50, -50);
216676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
216776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Op draw matrix must match expected combination of transformation properties";
216876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
216976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
2170161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
21718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikstruct SaveLayerAlphaData {
21728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerWidth = 0;
21738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerHeight = 0;
21748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Rect rectClippedBounds;
21758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 rectMatrix;
2176c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck    Matrix4 drawLayerMatrix;
21778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik};
21788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik/**
21798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Constructs a view to hit the temporary layer alpha property implementation:
21808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     a) 0 < alpha < 1
21818ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     b) too big for layer (larger than maxTextureSize)
21828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     c) overlapping rendering content
21838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * returning observed data about layer size and content clip/transform.
21848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *
21858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
21868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * (for efficiency, and to fit in layer size constraints) based on parent clip.
21878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik */
21888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
218916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        std::function<void(RenderProperties&)> propSetupCallback) {
21908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
21918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    public:
2192d53e3bed1ca4a14b2a86d53eaef6969bd043176eChih-Hung Hsieh        explicit SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
21938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik                : mOutData(outData) {}
21948ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21958ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
21968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(0, mIndex++);
21978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerWidth = width;
21988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerHeight = height;
21998ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            return nullptr;
22008ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
22018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
22028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(1, mIndex++);
22038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
22048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectClippedBounds = state.computedState.clippedBounds;
22058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectMatrix = state.computedState.transform;
22068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
22078ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void endLayer() override {
22088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(2, mIndex++);
22098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
22108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
22118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(3, mIndex++);
2212c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck            mOutData->drawLayerMatrix = state.computedState.transform;
22138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
221474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
221574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(4, mIndex++);
221674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
22178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    private:
22188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaData* mOutData;
22198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    };
22208ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
22218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
22228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "Node must be bigger than max texture size to exercise saveLayer codepath";
222306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 10000, 10000,
222416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
22258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setHasOverlappingRendering(true);
22268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
22278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // apply other properties
222816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(properties);
222916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
223016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        SkPaint paint;
223116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        paint.setColor(SK_ColorWHITE);
223216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        canvas.drawRect(0, 0, 10000, 10000, paint);
22338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
22349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height
22359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
22369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
22379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                sLightGeometry, Caches::getInstance());
22389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
22398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
22408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
2241f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
22428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
22438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // assert, since output won't be valid if we haven't seen a save layer triggered
224474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
22458ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
22468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
224798c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
22488ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
22498ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
22508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(10); // offset rendering content
22518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(-2000); // offset rendering content
22528ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
22538ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(190u, observedData.layerWidth);
22548ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(200u, observedData.layerHeight);
22555430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
22568ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be clipped to screen area";
22578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 expected;
22588ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    expected.loadTranslate(0, -2000, 0);
22598ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
22608ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be translated as part of being clipped";
2261c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck    expected.loadTranslate(10, 0, 0);
2262c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck    EXPECT_MATRIX_APPROX_EQ(expected, observedData.drawLayerMatrix)
2263c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck                << "expect drawLayer to be translated as part of being clipped";
22648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
22658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
226698c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
22678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
22688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
22698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // Translate and rotate the view so that the only visible part is the top left corner of
22708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // the view. It will form an isosceles right triangle with a long side length of 200 at the
22718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // bottom of the viewport.
22728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(100);
22738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(100);
22748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
22758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
22768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setRotation(45);
22778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
22788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // ceil(sqrt(2) / 2 * 200) = 142
22798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerWidth);
22808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerHeight);
22815430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
22828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
22838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
22848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
228598c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
22868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
22878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
22888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
22898ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
22908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleX(2);
22918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleY(0.5f);
22928ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
22938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(100u, observedData.layerWidth);
22948ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(400u, observedData.layerHeight);
22955430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
22968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
22978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
22988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
229998c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clip_replace) {
230004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    class ClipReplaceTestRenderer : public TestRendererBase {
230104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    public:
230204d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
230304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_EQ(0, mIndex++);
230404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_TRUE(op.localClip->intersectWithRoot);
230504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_EQ(Rect(20, 10, 30, 40), state.computedState.clipState->rect)
230604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik                    << "Expect resolved clip to be intersection of viewport clip and clip op";
230704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        }
230804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    };
230906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(20, 20, 30, 30,
231004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
2311a0a74d5f8ee1dbd04772ffb1775d045ce6b5934bMike Reed        canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
2312260ab726486317496bc12a57d599ea96dcde3284Mike Reed        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
231304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    });
231404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
23159cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50,
23169cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
23179cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
23189cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
231904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    ClipReplaceTestRenderer renderer;
232004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
232104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    EXPECT_EQ(1, renderer.getIndex());
232204d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik}
232304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
2324e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedInMiddle) {
2325db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B
2326db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2327db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2328db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2329db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
2330db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
2331db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2332db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2333db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2334db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
2335db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2336db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2337db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
2338db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2339db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2340db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2341db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2342db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2343db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2344db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2345db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2346db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2347db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2348db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2349db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2350db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2351db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2352db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2353db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2354e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectLast) {
2355db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on E
2356db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  A
2357db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                / | \
2358db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /  |  \
2359db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C   E
2360db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
2361db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
2362db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2363db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2364db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2365db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0,  nullptr); //nodeB
2366db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2367db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //drawn as 2
2368db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2369db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2370db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2371db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2372db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //drawn as 3
2373db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2374db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeE
2375db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2376db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2377db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2378db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2379db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2380db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2381db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2382db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2383db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, renderer.getIndex());
2384db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2385db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2386e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderNoReceivable) {
2387db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected without receiver
2388db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2389db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2390db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2391db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
2392db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
2393db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2394db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2395db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2396db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
2397db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2398db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255,  [](RenderProperties& props, RecordingCanvas& canvas) {
2399db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                //not having a projection receiver is an undefined behavior
2400db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2401db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2402db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2403db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2404db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2405db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2406db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2407db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2408db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2409db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2410db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2411db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2412db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(2, renderer.getIndex());
2413db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2414db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2415e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderParentReceivable) {
2416db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on C
2417db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2418db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2419db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2420db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
2421db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
2422db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2423db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2424db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2425db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
2426db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2427db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2428db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
2429db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2430db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2431db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2432db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2433db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2434db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2435db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2436db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2437db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2438db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2439db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2440db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2441db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2442db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2443db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2444e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderSameNodeReceivable) {
2445db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2446db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2447db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
2448db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2449db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) {
2450db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                //having a node that is projected on itself is an undefined/unexpected behavior
2451db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2452db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2453db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2454db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2455db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2456db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2457db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2458db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2459db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2460db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2461db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2462db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2463db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2464db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(2, renderer.getIndex());
2465db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2466db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2467e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling) {
2468db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //TODO: this test together with the next "projectionReorderProjectedSibling2" likely expose a
2469db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //bug in HWUI. First test draws R, while the second test does not draw R for a nearly identical
2470db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //tree setup. The correct behaviour is to not draw R, because the receiver cannot be a sibling
2471db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B. R is not expected to be drawn (see Sibling2 outcome below),
2472db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev       but for some reason it is drawn.
2473db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2474db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /|\
2475db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              / | \
2476db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev             B  C  R
2477db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2478db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2479db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2480db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
2481db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2482db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2483db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
2484db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2485db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2486db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectBackwards(true);
2487db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setClipToBounds(false);
2488db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeR
2489db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2490db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2491db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2492db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2493db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2494db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2495db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2496db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2497db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2498db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2499db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2500e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling2) {
2501db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
2502db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2503db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
2504db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G
2505db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /|\
2506db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              / | \
2507db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev             B  C  R
2508db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2509db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2510db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2511db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //G
2512db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //B
2513db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2514db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeB
2515db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
2516db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeC
2517db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) { //R
2518db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2519db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2520db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2521db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeG
2522db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2523db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2524db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2525db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2526db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2527db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2528db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2529db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2530db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2531db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2532db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2533e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderGrandparentReceivable) {
2534db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B
2535db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2536db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
2537db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                B
2538db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
2539db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                C
2540db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
2541db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                R
2542db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2543db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2544db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2545db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
2546db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2547db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2548db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
2549db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setProjectBackwards(true);
2550db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setClipToBounds(false);
2551db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                } ); //nodeR
2552db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeC
2553db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2554db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2555db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2556db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2557db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2558db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2559db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2560db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2561db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2562db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2563db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2564db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2565e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivables) {
2566db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* B and G are receivables, R is backward projected
2567db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2568db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2569db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2570db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                 / \
2571db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G   R
2572db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2573db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2574db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2575db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
2576db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2577db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2578db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
2579db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //G
2580db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2581db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeG
2582db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //R
2583db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2584db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2585db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2586db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2587db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2588db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2589db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2590db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2591db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2592db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2593db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2594db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2595db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, renderer.getIndex());
2596db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2597db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2598e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesLikelyScenario) {
2599db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* B and G are receivables, G is backward projected
2600db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2601db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2602db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2603db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                 / \
2604db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G   R
2605db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2606db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2607db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2608db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
2609db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2610db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2611db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
2612db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //G
2613db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2614db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2615db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2616db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeG
2617db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //R
2618db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2619db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2620db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2621db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2622db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2623db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2624db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2625db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2626db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2627db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2628db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, renderer.getIndex());
2629db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2630db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2631e681bf6b5c798cce3858e1d39e4fe629cab721f0Chris CraikRENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesDeeper) {
2632db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* B and G are receivables, R is backward projected
2633db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2634db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2635db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2636db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                 / \
2637db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G   D
2638db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    |
2639db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    R
2640db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2641db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2642db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2643db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
2644db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2645db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2646db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //C
2647db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //G
2648db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2649db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeG
2650db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 4, [](RenderProperties& props, RecordingCanvas& canvas) { //D
2651db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //R
2652db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setProjectBackwards(true);
2653db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setClipToBounds(false);
2654db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                } ); //nodeR
2655db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeD
2656db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2657db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2658db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2659db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2660db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2661db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2662db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2663db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2664db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2665db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(5, renderer.getIndex());
2666db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2667db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
26686fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace uirenderer
26696fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace android
2670