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);
999