xref: /aosp_15_r20/external/skia/tests/TopoSortTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTTopoSort.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
18*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
19*c8dee2aaSAndroid Build Coastguard Worker 
20*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
21*c8dee2aaSAndroid Build Coastguard Worker 
22*c8dee2aaSAndroid Build Coastguard Worker typedef void (*CreateGraphPF)(TArray<sk_sp<ToolUtils::TopoTestNode>>* graph);
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker /* Simple diamond
25*c8dee2aaSAndroid Build Coastguard Worker  *       3
26*c8dee2aaSAndroid Build Coastguard Worker  *      . .
27*c8dee2aaSAndroid Build Coastguard Worker  *     /   \
28*c8dee2aaSAndroid Build Coastguard Worker  *    1     2
29*c8dee2aaSAndroid Build Coastguard Worker  *    .     .
30*c8dee2aaSAndroid Build Coastguard Worker  *     \   /
31*c8dee2aaSAndroid Build Coastguard Worker  *       0
32*c8dee2aaSAndroid Build Coastguard Worker  */
create_graph0(TArray<sk_sp<ToolUtils::TopoTestNode>> * graph)33*c8dee2aaSAndroid Build Coastguard Worker static void create_graph0(TArray<sk_sp<ToolUtils::TopoTestNode>>* graph) {
34*c8dee2aaSAndroid Build Coastguard Worker     ToolUtils::TopoTestNode::AllocNodes(graph, 4);
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[0]->dependsOn((*graph)[1].get());
37*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[0]->dependsOn((*graph)[2].get());
38*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[1]->dependsOn((*graph)[3].get());
39*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[2]->dependsOn((*graph)[3].get());
40*c8dee2aaSAndroid Build Coastguard Worker }
41*c8dee2aaSAndroid Build Coastguard Worker 
create_simple_chain(TArray<sk_sp<ToolUtils::TopoTestNode>> * graph,int n)42*c8dee2aaSAndroid Build Coastguard Worker static void create_simple_chain(TArray<sk_sp<ToolUtils::TopoTestNode>>* graph, int n) {
43*c8dee2aaSAndroid Build Coastguard Worker     ToolUtils::TopoTestNode::AllocNodes(graph, n);
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < n - 1; ++i) {
46*c8dee2aaSAndroid Build Coastguard Worker         (*graph)[i+1]->dependsOn((*graph)[i].get());
47*c8dee2aaSAndroid Build Coastguard Worker     }
48*c8dee2aaSAndroid Build Coastguard Worker }
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker /* Simple chain
51*c8dee2aaSAndroid Build Coastguard Worker  *     0
52*c8dee2aaSAndroid Build Coastguard Worker  *     ^
53*c8dee2aaSAndroid Build Coastguard Worker  *     |
54*c8dee2aaSAndroid Build Coastguard Worker  *     1
55*c8dee2aaSAndroid Build Coastguard Worker  *     ^
56*c8dee2aaSAndroid Build Coastguard Worker  *     |
57*c8dee2aaSAndroid Build Coastguard Worker  *     2
58*c8dee2aaSAndroid Build Coastguard Worker  *     ^
59*c8dee2aaSAndroid Build Coastguard Worker  *     |
60*c8dee2aaSAndroid Build Coastguard Worker  *     3
61*c8dee2aaSAndroid Build Coastguard Worker  */
create_graph1(TArray<sk_sp<ToolUtils::TopoTestNode>> * graph)62*c8dee2aaSAndroid Build Coastguard Worker static void create_graph1(TArray<sk_sp<ToolUtils::TopoTestNode>>* graph) {
63*c8dee2aaSAndroid Build Coastguard Worker     create_simple_chain(graph, 4);
64*c8dee2aaSAndroid Build Coastguard Worker }
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker /* Simple Loop
67*c8dee2aaSAndroid Build Coastguard Worker  *       2
68*c8dee2aaSAndroid Build Coastguard Worker  *      / .
69*c8dee2aaSAndroid Build Coastguard Worker  *     /   \
70*c8dee2aaSAndroid Build Coastguard Worker  *    .     \
71*c8dee2aaSAndroid Build Coastguard Worker  *    0 ---> 1
72*c8dee2aaSAndroid Build Coastguard Worker  */
create_graph2(TArray<sk_sp<ToolUtils::TopoTestNode>> * graph)73*c8dee2aaSAndroid Build Coastguard Worker static void create_graph2(TArray<sk_sp<ToolUtils::TopoTestNode>>* graph) {
74*c8dee2aaSAndroid Build Coastguard Worker     ToolUtils::TopoTestNode::AllocNodes(graph, 3);
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[0]->dependsOn((*graph)[1].get());
77*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[1]->dependsOn((*graph)[2].get());
78*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[2]->dependsOn((*graph)[0].get());
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker /* Double diamond
82*c8dee2aaSAndroid Build Coastguard Worker  *       6
83*c8dee2aaSAndroid Build Coastguard Worker  *      . .
84*c8dee2aaSAndroid Build Coastguard Worker  *     /   \
85*c8dee2aaSAndroid Build Coastguard Worker  *    4     5
86*c8dee2aaSAndroid Build Coastguard Worker  *    .     .
87*c8dee2aaSAndroid Build Coastguard Worker  *     \   /
88*c8dee2aaSAndroid Build Coastguard Worker  *       3
89*c8dee2aaSAndroid Build Coastguard Worker  *      . .
90*c8dee2aaSAndroid Build Coastguard Worker  *     /   \
91*c8dee2aaSAndroid Build Coastguard Worker  *    1     2
92*c8dee2aaSAndroid Build Coastguard Worker  *    .     .
93*c8dee2aaSAndroid Build Coastguard Worker  *     \   /
94*c8dee2aaSAndroid Build Coastguard Worker  *       0
95*c8dee2aaSAndroid Build Coastguard Worker  */
create_graph3(TArray<sk_sp<ToolUtils::TopoTestNode>> * graph)96*c8dee2aaSAndroid Build Coastguard Worker static void create_graph3(TArray<sk_sp<ToolUtils::TopoTestNode>>* graph) {
97*c8dee2aaSAndroid Build Coastguard Worker     ToolUtils::TopoTestNode::AllocNodes(graph, 7);
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[0]->dependsOn((*graph)[1].get());
100*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[0]->dependsOn((*graph)[2].get());
101*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[1]->dependsOn((*graph)[3].get());
102*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[2]->dependsOn((*graph)[3].get());
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[3]->dependsOn((*graph)[4].get());
105*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[3]->dependsOn((*graph)[5].get());
106*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[4]->dependsOn((*graph)[6].get());
107*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[5]->dependsOn((*graph)[6].get());
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker /* Two independent diamonds
111*c8dee2aaSAndroid Build Coastguard Worker  *       3           7
112*c8dee2aaSAndroid Build Coastguard Worker  *      . .         . .
113*c8dee2aaSAndroid Build Coastguard Worker  *     /   \       /   \
114*c8dee2aaSAndroid Build Coastguard Worker  *    1     2     5     6
115*c8dee2aaSAndroid Build Coastguard Worker  *    .     .     .     .
116*c8dee2aaSAndroid Build Coastguard Worker  *     \   /       \   /
117*c8dee2aaSAndroid Build Coastguard Worker  *       0           4
118*c8dee2aaSAndroid Build Coastguard Worker  */
create_graph4(TArray<sk_sp<ToolUtils::TopoTestNode>> * graph)119*c8dee2aaSAndroid Build Coastguard Worker static void create_graph4(TArray<sk_sp<ToolUtils::TopoTestNode>>* graph) {
120*c8dee2aaSAndroid Build Coastguard Worker     ToolUtils::TopoTestNode::AllocNodes(graph, 8);
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[0]->dependsOn((*graph)[1].get());
123*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[0]->dependsOn((*graph)[2].get());
124*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[1]->dependsOn((*graph)[3].get());
125*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[2]->dependsOn((*graph)[3].get());
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[4]->dependsOn((*graph)[5].get());
128*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[4]->dependsOn((*graph)[6].get());
129*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[5]->dependsOn((*graph)[7].get());
130*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[6]->dependsOn((*graph)[7].get());
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker /* Two linked diamonds w/ two loops
134*c8dee2aaSAndroid Build Coastguard Worker  *       5     6
135*c8dee2aaSAndroid Build Coastguard Worker  *      / .   . \
136*c8dee2aaSAndroid Build Coastguard Worker  *     .   \ /   .
137*c8dee2aaSAndroid Build Coastguard Worker  *    2     3     4
138*c8dee2aaSAndroid Build Coastguard Worker  *     \    .    /
139*c8dee2aaSAndroid Build Coastguard Worker  *      .  / \  .
140*c8dee2aaSAndroid Build Coastguard Worker  *       0     1
141*c8dee2aaSAndroid Build Coastguard Worker  */
create_graph5(TArray<sk_sp<ToolUtils::TopoTestNode>> * graph)142*c8dee2aaSAndroid Build Coastguard Worker static void create_graph5(TArray<sk_sp<ToolUtils::TopoTestNode>>* graph) {
143*c8dee2aaSAndroid Build Coastguard Worker     ToolUtils::TopoTestNode::AllocNodes(graph, 7);
144*c8dee2aaSAndroid Build Coastguard Worker 
145*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[0]->dependsOn((*graph)[3].get());
146*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[1]->dependsOn((*graph)[3].get());
147*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[2]->dependsOn((*graph)[0].get());
148*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[3]->dependsOn((*graph)[5].get());
149*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[3]->dependsOn((*graph)[6].get());
150*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[4]->dependsOn((*graph)[1].get());
151*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[5]->dependsOn((*graph)[2].get());
152*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[6]->dependsOn((*graph)[4].get());
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker 
155*c8dee2aaSAndroid Build Coastguard Worker /* Two disjoint loops
156*c8dee2aaSAndroid Build Coastguard Worker  *       2          5
157*c8dee2aaSAndroid Build Coastguard Worker  *      / .        / .
158*c8dee2aaSAndroid Build Coastguard Worker  *     /   \      /   \
159*c8dee2aaSAndroid Build Coastguard Worker  *    .     \    .     \
160*c8dee2aaSAndroid Build Coastguard Worker  *    0 ---> 1   3 ---> 4
161*c8dee2aaSAndroid Build Coastguard Worker  */
create_graph6(TArray<sk_sp<ToolUtils::TopoTestNode>> * graph)162*c8dee2aaSAndroid Build Coastguard Worker static void create_graph6(TArray<sk_sp<ToolUtils::TopoTestNode>>* graph) {
163*c8dee2aaSAndroid Build Coastguard Worker     ToolUtils::TopoTestNode::AllocNodes(graph, 6);
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[0]->dependsOn((*graph)[1].get());
166*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[1]->dependsOn((*graph)[2].get());
167*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[2]->dependsOn((*graph)[0].get());
168*c8dee2aaSAndroid Build Coastguard Worker 
169*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[3]->dependsOn((*graph)[4].get());
170*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[4]->dependsOn((*graph)[5].get());
171*c8dee2aaSAndroid Build Coastguard Worker     (*graph)[5]->dependsOn((*graph)[3].get());
172*c8dee2aaSAndroid Build Coastguard Worker }
173*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(TopoSort,reporter)174*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(TopoSort, reporter) {
175*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker     struct {
178*c8dee2aaSAndroid Build Coastguard Worker         CreateGraphPF fCreate;
179*c8dee2aaSAndroid Build Coastguard Worker         bool          fExpectedResult;
180*c8dee2aaSAndroid Build Coastguard Worker     } tests[] = {
181*c8dee2aaSAndroid Build Coastguard Worker         { create_graph0, true  },
182*c8dee2aaSAndroid Build Coastguard Worker         { create_graph1, true  },
183*c8dee2aaSAndroid Build Coastguard Worker         { create_graph2, false },
184*c8dee2aaSAndroid Build Coastguard Worker         { create_graph3, true  },
185*c8dee2aaSAndroid Build Coastguard Worker         { create_graph4, true  },
186*c8dee2aaSAndroid Build Coastguard Worker         { create_graph5, false },
187*c8dee2aaSAndroid Build Coastguard Worker         { create_graph6, false },
188*c8dee2aaSAndroid Build Coastguard Worker     };
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::size(tests); ++i) {
191*c8dee2aaSAndroid Build Coastguard Worker         TArray<sk_sp<ToolUtils::TopoTestNode>> graph;
192*c8dee2aaSAndroid Build Coastguard Worker 
193*c8dee2aaSAndroid Build Coastguard Worker         (tests[i].fCreate)(&graph);
194*c8dee2aaSAndroid Build Coastguard Worker 
195*c8dee2aaSAndroid Build Coastguard Worker         const int numNodes = graph.size();
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker         ToolUtils::TopoTestNode::Shuffle(graph, &rand);
198*c8dee2aaSAndroid Build Coastguard Worker 
199*c8dee2aaSAndroid Build Coastguard Worker         bool actualResult = GrTTopoSort<ToolUtils::TopoTestNode>(graph);
200*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, actualResult == tests[i].fExpectedResult);
201*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, numNodes == graph.size());
202*c8dee2aaSAndroid Build Coastguard Worker 
203*c8dee2aaSAndroid Build Coastguard Worker         if (tests[i].fExpectedResult) {
204*c8dee2aaSAndroid Build Coastguard Worker             for (const auto& node : graph) {
205*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, node->check());
206*c8dee2aaSAndroid Build Coastguard Worker             }
207*c8dee2aaSAndroid Build Coastguard Worker         } else {
208*c8dee2aaSAndroid Build Coastguard Worker             // When the topological sort fails all the nodes should still appear in the result
209*c8dee2aaSAndroid Build Coastguard Worker             // but their order can be somewhat arbitrary.
210*c8dee2aaSAndroid Build Coastguard Worker             std::vector<bool> seen(numNodes, false);
211*c8dee2aaSAndroid Build Coastguard Worker 
212*c8dee2aaSAndroid Build Coastguard Worker             for (const auto& node : graph) {
213*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(node);
214*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(!seen[node->id()]);
215*c8dee2aaSAndroid Build Coastguard Worker                 seen[node->id()] = true;
216*c8dee2aaSAndroid Build Coastguard Worker             }
217*c8dee2aaSAndroid Build Coastguard Worker         }
218*c8dee2aaSAndroid Build Coastguard Worker 
219*c8dee2aaSAndroid Build Coastguard Worker         //SkDEBUGCODE(print(graph);)
220*c8dee2aaSAndroid Build Coastguard Worker     }
221*c8dee2aaSAndroid Build Coastguard Worker 
222*c8dee2aaSAndroid Build Coastguard Worker     // Some additional tests that do multiple partial sorts of graphs where we know nothing in an
223*c8dee2aaSAndroid Build Coastguard Worker     // earlier partion depends on anything in a later partition.
224*c8dee2aaSAndroid Build Coastguard Worker     for (int n = 2; n < 6; ++n) {
225*c8dee2aaSAndroid Build Coastguard Worker         for (int split = 1; split < n; ++split) {
226*c8dee2aaSAndroid Build Coastguard Worker             TArray<sk_sp<ToolUtils::TopoTestNode>> graph;
227*c8dee2aaSAndroid Build Coastguard Worker             create_simple_chain(&graph, n);
228*c8dee2aaSAndroid Build Coastguard Worker             SkSpan spanA = SkSpan(graph.begin(), split);
229*c8dee2aaSAndroid Build Coastguard Worker             SkSpan spanB = SkSpan(graph.begin() + split, n - split);
230*c8dee2aaSAndroid Build Coastguard Worker             ToolUtils::TopoTestNode::Shuffle(spanA, &rand);
231*c8dee2aaSAndroid Build Coastguard Worker             ToolUtils::TopoTestNode::Shuffle(spanB, &rand);
232*c8dee2aaSAndroid Build Coastguard Worker             bool result = GrTTopoSort(spanA);
233*c8dee2aaSAndroid Build Coastguard Worker             if (!result) {
234*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(reporter, "Topo sort on partial chain failed.");
235*c8dee2aaSAndroid Build Coastguard Worker                 return;
236*c8dee2aaSAndroid Build Coastguard Worker             }
237*c8dee2aaSAndroid Build Coastguard Worker             // Nothing outside of the processed span should have been output.
238*c8dee2aaSAndroid Build Coastguard Worker             for (const auto& node : spanB) {
239*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, !ToolUtils::TopoTestNode::WasOutput(node.get()));
240*c8dee2aaSAndroid Build Coastguard Worker             }
241*c8dee2aaSAndroid Build Coastguard Worker             result = GrTTopoSort(spanB, split);
242*c8dee2aaSAndroid Build Coastguard Worker             if (!result) {
243*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(reporter, "Topo sort on partial chain failed.");
244*c8dee2aaSAndroid Build Coastguard Worker                 return;
245*c8dee2aaSAndroid Build Coastguard Worker             }
246*c8dee2aaSAndroid Build Coastguard Worker             for (const auto& node : graph) {
247*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(reporter, node->check());
248*c8dee2aaSAndroid Build Coastguard Worker             }
249*c8dee2aaSAndroid Build Coastguard Worker         }
250*c8dee2aaSAndroid Build Coastguard Worker     }
251*c8dee2aaSAndroid Build Coastguard Worker }
252