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