1cb93a386Sopenharmony_ci// Copyright 2021 Google LLC.
2cb93a386Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3cb93a386Sopenharmony_ci
4cb93a386Sopenharmony_ci#include "experimental/sorttoy/Cmds.h"
5cb93a386Sopenharmony_ci#include "experimental/sorttoy/Fake.h"
6cb93a386Sopenharmony_ci#include "experimental/sorttoy/SortKey.h"
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
9cb93a386Sopenharmony_ci#include "include/core/SkGraphics.h"
10cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
11cb93a386Sopenharmony_ci#include "src/core/SkOSFile.h"
12cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
14cb93a386Sopenharmony_ci#include "src/utils/SkOSPath.h"
15cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
16cb93a386Sopenharmony_ci#include "tools/flags/CommandLineFlags.h"
17cb93a386Sopenharmony_ci#include "tools/gpu/GrContextFactory.h"
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ci#include <algorithm>
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci/*
22cb93a386Sopenharmony_ci * Questions this is trying to answer:
23cb93a386Sopenharmony_ci *   How to handle saveLayers (in w/ everything or separate)
24cb93a386Sopenharmony_ci *   How to handle blurs & other off screen draws
25cb93a386Sopenharmony_ci *   How to handle clipping
26cb93a386Sopenharmony_ci *   How does sorting stack up against buckets
27cb93a386Sopenharmony_ci *   How does creating batches interact w/ the sorting
28cb93a386Sopenharmony_ci *   How does batching work w/ text
29cb93a386Sopenharmony_ci *   How does text (esp. atlasing) work at all
30cb93a386Sopenharmony_ci *   Batching quality vs. existing
31cb93a386Sopenharmony_ci *   Memory churn/overhead vs existing (esp. wrt batching)
32cb93a386Sopenharmony_ci *   gpu vs cpu boundedness
33cb93a386Sopenharmony_ci *
34cb93a386Sopenharmony_ci * Futher Questions:
35cb93a386Sopenharmony_ci *   How can we collect uniforms & not store the fps -- seems complicated
36cb93a386Sopenharmony_ci *   Do all the blend modes (esp. advanced work front-to-back)?
37cb93a386Sopenharmony_ci *   skgpu::v2 perf vs. skgpu::v1 perf
38cb93a386Sopenharmony_ci *   Can we prepare any of the saveLayers or off-screen draw render passes in parallel?
39cb93a386Sopenharmony_ci *
40cb93a386Sopenharmony_ci * Small potatoes:
41cb93a386Sopenharmony_ci *   Incorporate CTM into the simulator
42cb93a386Sopenharmony_ci */
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_ci/*
45cb93a386Sopenharmony_ci * How does this all work:
46cb93a386Sopenharmony_ci *
47cb93a386Sopenharmony_ci * Each test is specified by a set of RectCmds (which have a unique ID and carry their material
48cb93a386Sopenharmony_ci * and MC state info) along with the order they are expected to be drawn in with the skgpu::v2.
49cb93a386Sopenharmony_ci *
50cb93a386Sopenharmony_ci * To generate an expected image, the RectCmds are replayed into an SkCanvas in the order
51cb93a386Sopenharmony_ci * provided.
52cb93a386Sopenharmony_ci *
53cb93a386Sopenharmony_ci * For the actual (v2) image, the RectCmds are replayed into a FakeCanvas - preserving the
54cb93a386Sopenharmony_ci * unique ID of the RectCmd. The FakeCanvas creates new RectCmd objects, sorts them using
55cb93a386Sopenharmony_ci * the SortKey and then performs a kludgey z-buffered rasterization. The FakeCanvas also
56cb93a386Sopenharmony_ci * preserves the RectCmd order it ultimately used for its rendering and this can be compared
57cb93a386Sopenharmony_ci * with the expected order from the test.
58cb93a386Sopenharmony_ci *
59cb93a386Sopenharmony_ci * The use of the RectCmds to create the tests is a mere convenience to avoid creating a
60cb93a386Sopenharmony_ci * separate representation of the desired draws.
61cb93a386Sopenharmony_ci *
62cb93a386Sopenharmony_ci ***************************
63cb93a386Sopenharmony_ci * Here are some of the simplifying assumptions of this simulation (and their justification):
64cb93a386Sopenharmony_ci *
65cb93a386Sopenharmony_ci * Only SkIRects are used for draws and clips - since MSAA should be taking care of AA for us in
66cb93a386Sopenharmony_ci * the skgpu::v2 we don't really need SkRects. This also greatly simplifies the z-buffered
67cb93a386Sopenharmony_ci * rasterization.
68cb93a386Sopenharmony_ci *
69cb93a386Sopenharmony_ci **************************
70cb93a386Sopenharmony_ci * Areas for improvement:
71cb93a386Sopenharmony_ci *   We should add strokes since there are two distinct drawing methods in the skgpu::v2 (fill v.
72cb93a386Sopenharmony_ci *   stroke)
73cb93a386Sopenharmony_ci */
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ciusing sk_gpu_test::GrContextFactory;
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_cistatic DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs.");
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_cistatic void exitf(const char* format, ...) {
80cb93a386Sopenharmony_ci    va_list args;
81cb93a386Sopenharmony_ci    va_start(args, format);
82cb93a386Sopenharmony_ci    vfprintf(stderr, format, args);
83cb93a386Sopenharmony_ci    va_end(args);
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ci    exit(1);
86cb93a386Sopenharmony_ci}
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_cistatic void save_files(int testID, Shape s, const SkBitmap& expected, const SkBitmap& actual) {
89cb93a386Sopenharmony_ci    if (FLAGS_writePath.isEmpty()) {
90cb93a386Sopenharmony_ci        return;
91cb93a386Sopenharmony_ci    }
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    const char* dir = FLAGS_writePath[0];
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci    SkString path = SkOSPath::Join(dir, s == Shape::kRect ? "rect-expected" : "oval-expected");
96cb93a386Sopenharmony_ci    path.appendU32(testID);
97cb93a386Sopenharmony_ci    path.append(".png");
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    if (!sk_mkdir(dir)) {
100cb93a386Sopenharmony_ci        exitf("failed to create directory for png \"%s\"", path.c_str());
101cb93a386Sopenharmony_ci    }
102cb93a386Sopenharmony_ci    if (!ToolUtils::EncodeImageToFile(path.c_str(), expected, SkEncodedImageFormat::kPNG, 100)) {
103cb93a386Sopenharmony_ci        exitf("failed to save png to \"%s\"", path.c_str());
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    path = SkOSPath::Join(dir, s == Shape::kRect ? "rect-actual" : "oval-actual");
107cb93a386Sopenharmony_ci    path.appendU32(testID);
108cb93a386Sopenharmony_ci    path.append(".png");
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci    if (!ToolUtils::EncodeImageToFile(path.c_str(), actual, SkEncodedImageFormat::kPNG, 100)) {
111cb93a386Sopenharmony_ci        exitf("failed to save png to \"%s\"", path.c_str());
112cb93a386Sopenharmony_ci    }
113cb93a386Sopenharmony_ci}
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci// Exercise basic SortKey behavior
116cb93a386Sopenharmony_cistatic void key_test() {
117cb93a386Sopenharmony_ci    SortKey k;
118cb93a386Sopenharmony_ci    SkASSERT(!k.transparent());
119cb93a386Sopenharmony_ci    SkASSERT(k.depth() == 0);
120cb93a386Sopenharmony_ci    SkASSERT(k.material() == 0);
121cb93a386Sopenharmony_ci//    k.dump();
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci    SortKey k1(false, 1, 3);
124cb93a386Sopenharmony_ci    SkASSERT(!k1.transparent());
125cb93a386Sopenharmony_ci    SkASSERT(k1.depth() == 1);
126cb93a386Sopenharmony_ci    SkASSERT(k1.material() == 3);
127cb93a386Sopenharmony_ci//    k1.dump();
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci    SortKey k2(true, 2, 1);
130cb93a386Sopenharmony_ci    SkASSERT(k2.transparent());
131cb93a386Sopenharmony_ci    SkASSERT(k2.depth() == 2);
132cb93a386Sopenharmony_ci    SkASSERT(k2.material() == 1);
133cb93a386Sopenharmony_ci//    k2.dump();
134cb93a386Sopenharmony_ci}
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_cistatic void check_state(FakeMCBlob* actualState,
137cb93a386Sopenharmony_ci                        SkIPoint expectedCTM,
138cb93a386Sopenharmony_ci                        const std::vector<SkIRect>& expectedClips) {
139cb93a386Sopenharmony_ci    SkASSERT(actualState->ctm() == expectedCTM);
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci    int i = 0;
142cb93a386Sopenharmony_ci    auto states = actualState->mcStates();
143cb93a386Sopenharmony_ci    for (auto& s : states) {
144cb93a386Sopenharmony_ci        for (const sk_sp<ClipCmd>& c : s.cmds()) {
145cb93a386Sopenharmony_ci            SkAssertResult(i < (int) expectedClips.size());
146cb93a386Sopenharmony_ci            SkAssertResult(c->rect() == expectedClips[i]);
147cb93a386Sopenharmony_ci            i++;
148cb93a386Sopenharmony_ci        }
149cb93a386Sopenharmony_ci    }
150cb93a386Sopenharmony_ci}
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci// Exercise the FakeMCBlob object
153cb93a386Sopenharmony_cistatic void mcstack_test() {
154cb93a386Sopenharmony_ci    const SkIRect r { 0, 0, 10, 10 };
155cb93a386Sopenharmony_ci    const SkIPoint s1Trans { 10, 10 };
156cb93a386Sopenharmony_ci    const SkIPoint s2TransA { -5, -2 };
157cb93a386Sopenharmony_ci    const SkIPoint s2TransB { -3, -1 };
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci    const std::vector<SkIRect> expectedS0Clips;
160cb93a386Sopenharmony_ci    const std::vector<SkIRect> expectedS1Clips {
161cb93a386Sopenharmony_ci        r.makeOffset(s1Trans)
162cb93a386Sopenharmony_ci    };
163cb93a386Sopenharmony_ci    const std::vector<SkIRect> expectedS2aClips {
164cb93a386Sopenharmony_ci        r.makeOffset(s1Trans),
165cb93a386Sopenharmony_ci        r.makeOffset(s2TransA)
166cb93a386Sopenharmony_ci    };
167cb93a386Sopenharmony_ci    const std::vector<SkIRect> expectedS2bClips {
168cb93a386Sopenharmony_ci        r.makeOffset(s1Trans),
169cb93a386Sopenharmony_ci        r.makeOffset(s2TransA),
170cb93a386Sopenharmony_ci        r.makeOffset(s2TransA + s2TransB)
171cb93a386Sopenharmony_ci    };
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci    //----------------
174cb93a386Sopenharmony_ci    FakeStateTracker s;
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci    auto state0 = s.snapState();
177cb93a386Sopenharmony_ci    // The initial state should have no translation & no clip
178cb93a386Sopenharmony_ci    check_state(state0.get(), { 0, 0 }, expectedS0Clips);
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ci    //----------------
181cb93a386Sopenharmony_ci    s.push();
182cb93a386Sopenharmony_ci    s.translate(s1Trans);
183cb93a386Sopenharmony_ci    s.clip(sk_make_sp<ClipCmd>(ID(1), Shape::kRect, r));
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci    auto state1 = s.snapState();
186cb93a386Sopenharmony_ci    check_state(state1.get(), s1Trans, expectedS1Clips);
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci    //----------------
189cb93a386Sopenharmony_ci    s.push();
190cb93a386Sopenharmony_ci    s.translate(s2TransA);
191cb93a386Sopenharmony_ci    s.clip(sk_make_sp<ClipCmd>(ID(2), Shape::kRect, r));
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci    auto state2a = s.snapState();
194cb93a386Sopenharmony_ci    check_state(state2a.get(), s1Trans + s2TransA, expectedS2aClips);
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_ci    s.translate(s2TransB);
197cb93a386Sopenharmony_ci    s.clip(sk_make_sp<ClipCmd>(ID(3), Shape::kRect, r));
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_ci    auto state2b = s.snapState();
200cb93a386Sopenharmony_ci    check_state(state2b.get(), s1Trans + s2TransA + s2TransB, expectedS2bClips);
201cb93a386Sopenharmony_ci    SkASSERT(state2a != state2b);
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_ci    //----------------
204cb93a386Sopenharmony_ci    s.pop(PaintersOrder(1));
205cb93a386Sopenharmony_ci    auto state3 = s.snapState();
206cb93a386Sopenharmony_ci    check_state(state3.get(), s1Trans, expectedS1Clips);
207cb93a386Sopenharmony_ci    SkASSERT(state1 == state3);
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_ci    //----------------
210cb93a386Sopenharmony_ci    s.pop(PaintersOrder(2));
211cb93a386Sopenharmony_ci    auto state4 = s.snapState();
212cb93a386Sopenharmony_ci    check_state(state4.get(), { 0, 0 }, expectedS0Clips);
213cb93a386Sopenharmony_ci    SkASSERT(state0 == state4);
214cb93a386Sopenharmony_ci}
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_cistatic void check_order(int testID,
217cb93a386Sopenharmony_ci                        const std::vector<ID>& actualOrder,
218cb93a386Sopenharmony_ci                        const std::vector<ID>& expectedOrder) {
219cb93a386Sopenharmony_ci    if (expectedOrder.size() != actualOrder.size()) {
220cb93a386Sopenharmony_ci        exitf("Op count mismatch in test %d. Expected %d - got %d\n",
221cb93a386Sopenharmony_ci              testID,
222cb93a386Sopenharmony_ci              expectedOrder.size(),
223cb93a386Sopenharmony_ci              actualOrder.size());
224cb93a386Sopenharmony_ci    }
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_ci    if (expectedOrder != actualOrder) {
227cb93a386Sopenharmony_ci        SkDebugf("order mismatch in test %d:\n", testID);
228cb93a386Sopenharmony_ci        SkDebugf("E %zu: ", expectedOrder.size());
229cb93a386Sopenharmony_ci        for (auto t : expectedOrder) {
230cb93a386Sopenharmony_ci            SkDebugf("%d", t.toInt());
231cb93a386Sopenharmony_ci        }
232cb93a386Sopenharmony_ci        SkDebugf("\n");
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci        SkDebugf("A %zu: ", actualOrder.size());
235cb93a386Sopenharmony_ci        for (auto t : actualOrder) {
236cb93a386Sopenharmony_ci            SkDebugf("%d", t.toInt());
237cb93a386Sopenharmony_ci        }
238cb93a386Sopenharmony_ci        SkDebugf("\n");
239cb93a386Sopenharmony_ci    }
240cb93a386Sopenharmony_ci}
241cb93a386Sopenharmony_ci
242cb93a386Sopenharmony_citypedef int (*PFTest)(std::vector<sk_sp<Cmd>>* test,
243cb93a386Sopenharmony_ci                      Shape shape,
244cb93a386Sopenharmony_ci                      std::vector<ID>* expectedOrder);
245cb93a386Sopenharmony_ci
246cb93a386Sopenharmony_cistatic void sort_test(PFTest testcase) {
247cb93a386Sopenharmony_ci
248cb93a386Sopenharmony_ci    for (Shape s : { Shape::kRect, Shape::kOval }) {
249cb93a386Sopenharmony_ci        std::vector<sk_sp<Cmd>> test;
250cb93a386Sopenharmony_ci        std::vector<ID> expectedOrder;
251cb93a386Sopenharmony_ci        int testID = testcase(&test, s, &expectedOrder);
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_ci
254cb93a386Sopenharmony_ci        SkBitmap expectedBM;
255cb93a386Sopenharmony_ci        expectedBM.allocPixels(SkImageInfo::MakeN32Premul(256, 256));
256cb93a386Sopenharmony_ci        expectedBM.eraseColor(SK_ColorBLACK);
257cb93a386Sopenharmony_ci        SkCanvas real(expectedBM);
258cb93a386Sopenharmony_ci
259cb93a386Sopenharmony_ci        SkBitmap actualBM;
260cb93a386Sopenharmony_ci        actualBM.allocPixels(SkImageInfo::MakeN32Premul(256, 256));
261cb93a386Sopenharmony_ci        actualBM.eraseColor(SK_ColorBLACK);
262cb93a386Sopenharmony_ci
263cb93a386Sopenharmony_ci        FakeCanvas fake(actualBM);
264cb93a386Sopenharmony_ci        for (const sk_sp<Cmd>& c : test) {
265cb93a386Sopenharmony_ci            c->execute(&fake);
266cb93a386Sopenharmony_ci            c->execute(&real);
267cb93a386Sopenharmony_ci        }
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_ci        fake.finalize();
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci        std::vector<ID> actualOrder = fake.getOrder();
272cb93a386Sopenharmony_ci        check_order(testID, actualOrder, expectedOrder);
273cb93a386Sopenharmony_ci
274cb93a386Sopenharmony_ci        save_files(testID, s, expectedBM, actualBM);
275cb93a386Sopenharmony_ci    }
276cb93a386Sopenharmony_ci}
277cb93a386Sopenharmony_ci
278cb93a386Sopenharmony_ci// Simple test - green rect should appear atop the red rect
279cb93a386Sopenharmony_cistatic int test1(std::vector<sk_sp<Cmd>>* test,
280cb93a386Sopenharmony_ci                 Shape shape,
281cb93a386Sopenharmony_ci                 std::vector<ID>* expectedOrder) {
282cb93a386Sopenharmony_ci    // front-to-back order bc all opaque
283cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(1));
284cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(0));
285cb93a386Sopenharmony_ci
286cb93a386Sopenharmony_ci    //---------------------------------------------------------------------------------------------
287cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<SaveCmd>());
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci    SkIRect r{0, 0, 100, 100};
290cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(0), shape, r.makeOffset(8, 8),   FakePaint(SK_ColorRED)));
291cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(1), shape, r.makeOffset(48, 48), FakePaint(SK_ColorGREEN)));
292cb93a386Sopenharmony_ci
293cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<RestoreCmd>());
294cb93a386Sopenharmony_ci    return 1;
295cb93a386Sopenharmony_ci}
296cb93a386Sopenharmony_ci
297cb93a386Sopenharmony_ci// Simple test - blue rect atop green rect atop red rect
298cb93a386Sopenharmony_cistatic int test2(std::vector<sk_sp<Cmd>>* test,
299cb93a386Sopenharmony_ci                 Shape shape,
300cb93a386Sopenharmony_ci                 std::vector<ID>* expectedOrder) {
301cb93a386Sopenharmony_ci    // front-to-back order bc all opaque
302cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(2));
303cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(1));
304cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(0));
305cb93a386Sopenharmony_ci
306cb93a386Sopenharmony_ci    //---------------------------------------------------------------------------------------------
307cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<SaveCmd>());
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci    SkIRect r{0, 0, 100, 100};
310cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(0), shape, r.makeOffset(8, 8),   FakePaint(SK_ColorRED)));
311cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(1), shape, r.makeOffset(48, 48), FakePaint(SK_ColorGREEN)));
312cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(2), shape, r.makeOffset(98, 98), FakePaint(SK_ColorBLUE)));
313cb93a386Sopenharmony_ci
314cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<RestoreCmd>());
315cb93a386Sopenharmony_ci    return 2;
316cb93a386Sopenharmony_ci}
317cb93a386Sopenharmony_ci
318cb93a386Sopenharmony_ci// Transparency test - opaque blue rect atop transparent green rect atop opaque red rect
319cb93a386Sopenharmony_cistatic int test3(std::vector<sk_sp<Cmd>>* test,
320cb93a386Sopenharmony_ci                 Shape shape,
321cb93a386Sopenharmony_ci                 std::vector<ID>* expectedOrder) {
322cb93a386Sopenharmony_ci    // opaque draws are first and are front-to-back. Transparent draw is last.
323cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(2));
324cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(0));
325cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(1));
326cb93a386Sopenharmony_ci
327cb93a386Sopenharmony_ci    //---------------------------------------------------------------------------------------------
328cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<SaveCmd>());
329cb93a386Sopenharmony_ci
330cb93a386Sopenharmony_ci    SkIRect r{0, 0, 100, 100};
331cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(0), shape, r.makeOffset(8, 8),   FakePaint(SK_ColorRED)));
332cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(1), shape, r.makeOffset(48, 48), FakePaint(0x8000FF00)));
333cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(2), shape, r.makeOffset(98, 98), FakePaint(SK_ColorBLUE)));
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<RestoreCmd>());
336cb93a386Sopenharmony_ci    return 3;
337cb93a386Sopenharmony_ci}
338cb93a386Sopenharmony_ci
339cb93a386Sopenharmony_ci// Multi-transparency test - transparent blue rect atop transparent green rect atop
340cb93a386Sopenharmony_ci// transparent red rect
341cb93a386Sopenharmony_cistatic int test4(std::vector<sk_sp<Cmd>>* test,
342cb93a386Sopenharmony_ci                 Shape shape,
343cb93a386Sopenharmony_ci                 std::vector<ID>* expectedOrder) {
344cb93a386Sopenharmony_ci    // All in back-to-front order bc they're all transparent
345cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(0));
346cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(1));
347cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(2));
348cb93a386Sopenharmony_ci
349cb93a386Sopenharmony_ci    //---------------------------------------------------------------------------------------------
350cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<SaveCmd>());
351cb93a386Sopenharmony_ci
352cb93a386Sopenharmony_ci    SkIRect r{0, 0, 100, 100};
353cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(0), shape, r.makeOffset(8, 8),   FakePaint(0x80FF0000)));
354cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(1), shape, r.makeOffset(48, 48), FakePaint(0x8000FF00)));
355cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(2), shape, r.makeOffset(98, 98), FakePaint(0x800000FF)));
356cb93a386Sopenharmony_ci
357cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<RestoreCmd>());
358cb93a386Sopenharmony_ci    return 4;
359cb93a386Sopenharmony_ci}
360cb93a386Sopenharmony_ci
361cb93a386Sopenharmony_ci// Multiple opaque materials test
362cb93a386Sopenharmony_ci// All opaque:
363cb93a386Sopenharmony_ci//   normal1, linear1, radial1, normal2, linear2, radial2
364cb93a386Sopenharmony_ci// Which gets sorted to:
365cb93a386Sopenharmony_ci//   normal2, normal1, linear2, linear1, radial2, radial1
366cb93a386Sopenharmony_ci// So, front to back w/in each material type.
367cb93a386Sopenharmony_cistatic int test5(std::vector<sk_sp<Cmd>>* test,
368cb93a386Sopenharmony_ci                 Shape shape,
369cb93a386Sopenharmony_ci                 std::vector<ID>* expectedOrder) {
370cb93a386Sopenharmony_ci    // Note: This pushes sorting by material above sorting by Z. Thus we'll get less front to
371cb93a386Sopenharmony_ci    // back benefit.
372cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(3));
373cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(0));
374cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(4));
375cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(1));
376cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(5));
377cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(2));
378cb93a386Sopenharmony_ci
379cb93a386Sopenharmony_ci    //---------------------------------------------------------------------------------------------
380cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<SaveCmd>());
381cb93a386Sopenharmony_ci
382cb93a386Sopenharmony_ci    FakePaint p;
383cb93a386Sopenharmony_ci
384cb93a386Sopenharmony_ci    SkIRect r{0, 0, 100, 100};
385cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(0), shape, r.makeOffset(8, 8),     FakePaint(SK_ColorRED)));
386cb93a386Sopenharmony_ci    p.setLinear(SK_ColorGREEN,   SK_ColorWHITE);
387cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(1), shape, r.makeOffset(48, 48),   p));
388cb93a386Sopenharmony_ci    p.setRadial(SK_ColorBLUE,    SK_ColorBLACK);
389cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(2), shape, r.makeOffset(98, 98),   p));
390cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(3), shape, r.makeOffset(148, 148), FakePaint(SK_ColorCYAN)));
391cb93a386Sopenharmony_ci    p.setLinear(SK_ColorMAGENTA, SK_ColorWHITE);
392cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(4), shape, r.makeOffset(148, 8),   p));
393cb93a386Sopenharmony_ci    p.setRadial(SK_ColorYELLOW,  SK_ColorBLACK);
394cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(5), shape, r.makeOffset(8, 148),   p));
395cb93a386Sopenharmony_ci
396cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<RestoreCmd>());
397cb93a386Sopenharmony_ci    return 5;
398cb93a386Sopenharmony_ci}
399cb93a386Sopenharmony_ci
400cb93a386Sopenharmony_ci// simple clipping test - two shapes w/ 1 clip of the opposite shape
401cb93a386Sopenharmony_cistatic int test6(std::vector<sk_sp<Cmd>>* test,
402cb93a386Sopenharmony_ci                 Shape shape,
403cb93a386Sopenharmony_ci                 std::vector<ID>* expectedOrder) {
404cb93a386Sopenharmony_ci    // The expected is front to back after the clip
405cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(2));
406cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(1));
407cb93a386Sopenharmony_ci
408cb93a386Sopenharmony_ci    Shape clipShape = shape == Shape::kRect ? Shape::kOval : Shape::kRect;
409cb93a386Sopenharmony_ci    //---------------------------------------------------------------------------------------------
410cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<SaveCmd>());
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<ClipCmd>(ID(0), clipShape, SkIRect::MakeXYWH(28, 28, 40, 40)));
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ci    SkIRect r{0, 0, 100, 100};
415cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(1), shape, r.makeOffset(8, 8),   FakePaint(SK_ColorRED)));
416cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(2), shape, r.makeOffset(48, 48), FakePaint(SK_ColorGREEN)));
417cb93a386Sopenharmony_ci
418cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<RestoreCmd>());
419cb93a386Sopenharmony_ci    return 6;
420cb93a386Sopenharmony_ci}
421cb93a386Sopenharmony_ci
422cb93a386Sopenharmony_ci// more complicated clipping w/ opaque draws -> should reorder
423cb93a386Sopenharmony_cistatic int test7(std::vector<sk_sp<Cmd>>* test,
424cb93a386Sopenharmony_ci                 Shape shape,
425cb93a386Sopenharmony_ci                 std::vector<ID>* expectedOrder) {
426cb93a386Sopenharmony_ci    // The expected is front to back modulated by the two clip states
427cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(7));
428cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(6));
429cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(2));
430cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(1));
431cb93a386Sopenharmony_ci
432cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(5));
433cb93a386Sopenharmony_ci    expectedOrder->push_back(ID(4));
434cb93a386Sopenharmony_ci
435cb93a386Sopenharmony_ci    Shape clipShape = shape == Shape::kRect ? Shape::kOval : Shape::kRect;
436cb93a386Sopenharmony_ci    //---------------------------------------------------------------------------------------------
437cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<SaveCmd>());
438cb93a386Sopenharmony_ci    // select the middle third in x
439cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<ClipCmd>(ID(0), clipShape, SkIRect::MakeXYWH(85, 0, 86, 256)));
440cb93a386Sopenharmony_ci
441cb93a386Sopenharmony_ci    SkIRect r{0, 0, 100, 100};
442cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(1), shape, r.makeOffset(8, 8),     FakePaint(SK_ColorRED)));
443cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(2), shape, r.makeOffset(48, 48),   FakePaint(SK_ColorGREEN)));
444cb93a386Sopenharmony_ci
445cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<SaveCmd>());
446cb93a386Sopenharmony_ci    // intersect w/ the middle third in y
447cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<ClipCmd>(ID(3), clipShape, SkIRect::MakeXYWH(0, 85, 256, 86)));
448cb93a386Sopenharmony_ci
449cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(4), shape, r.makeOffset(98, 98),   FakePaint(SK_ColorBLUE)));
450cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(5), shape, r.makeOffset(148, 148), FakePaint(SK_ColorCYAN)));
451cb93a386Sopenharmony_ci
452cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<RestoreCmd>());
453cb93a386Sopenharmony_ci
454cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(6), shape, r.makeOffset(148, 8),   FakePaint(SK_ColorMAGENTA)));
455cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<DrawCmd>(ID(7), shape, r.makeOffset(8, 148),   FakePaint(SK_ColorYELLOW)));
456cb93a386Sopenharmony_ci
457cb93a386Sopenharmony_ci    test->push_back(sk_make_sp<RestoreCmd>());
458cb93a386Sopenharmony_ci    return 7;
459cb93a386Sopenharmony_ci}
460cb93a386Sopenharmony_ci
461cb93a386Sopenharmony_ciint main(int argc, char** argv) {
462cb93a386Sopenharmony_ci    CommandLineFlags::Parse(argc, argv);
463cb93a386Sopenharmony_ci
464cb93a386Sopenharmony_ci    SkGraphics::Init();
465cb93a386Sopenharmony_ci
466cb93a386Sopenharmony_ci    key_test();
467cb93a386Sopenharmony_ci    mcstack_test();
468cb93a386Sopenharmony_ci    sort_test(test1);
469cb93a386Sopenharmony_ci    sort_test(test2);
470cb93a386Sopenharmony_ci    sort_test(test3);
471cb93a386Sopenharmony_ci    sort_test(test4);
472cb93a386Sopenharmony_ci    sort_test(test5);
473cb93a386Sopenharmony_ci    sort_test(test6);
474cb93a386Sopenharmony_ci    sort_test(test7);
475cb93a386Sopenharmony_ci
476cb93a386Sopenharmony_ci    return 0;
477cb93a386Sopenharmony_ci}
478