1 /*
2  * Copyright 2021 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkRefCnt.h"
9 #include "include/core/SkSpan.h"
10 #include "include/core/SkString.h"
11 #include "include/private/base/SkTArray.h"
12 #include "src/base/SkTInternalLList.h"
13 #include "src/gpu/ganesh/GrRenderTask.h"
14 #include "src/gpu/ganesh/GrRenderTaskCluster.h"
15 #include "src/gpu/ganesh/GrSurfaceProxy.h"
16 #include "src/gpu/ganesh/mock/GrMockRenderTask.h"
17 #include "src/gpu/ganesh/mock/GrMockSurfaceProxy.h"
18 #include "tests/Test.h"
19 
20 #include <array>
21 #include <cstddef>
22 #include <utility>
23 
24 typedef void (*CreateGraphPF)(SkTArray<sk_sp<GrMockRenderTask>>* graph,
25                               SkTArray<sk_sp<GrMockRenderTask>>* expected);
26 
make_proxies(int count,SkTArray<sk_sp<GrSurfaceProxy>> * proxies)27 static void make_proxies(int count, SkTArray<sk_sp<GrSurfaceProxy>>* proxies) {
28     proxies->reset(count);
29     for (int i = 0; i < count; i++) {
30         auto name = SkStringPrintf("%c", 'A' + i);
31         proxies->at(i) = sk_make_sp<GrMockSurfaceProxy>(std::move(name),
32         /*label=*/"RenderTaskClusterTest");
33     }
34 }
35 
make_tasks(int count,SkTArray<sk_sp<GrMockRenderTask>> * tasks)36 static void make_tasks(int count, SkTArray<sk_sp<GrMockRenderTask>>* tasks) {
37     tasks->reset(count);
38     for (int i = 0; i < count; i++) {
39         tasks->at(i) = sk_make_sp<GrMockRenderTask>();
40     }
41 }
42 
43 /*
44  * In:  A1 B1 A2
45  * Out: B1 A1 A2
46  */
create_graph0(SkTArray<sk_sp<GrMockRenderTask>> * graph,SkTArray<sk_sp<GrMockRenderTask>> * expected)47 static void create_graph0(SkTArray<sk_sp<GrMockRenderTask>>* graph,
48                           SkTArray<sk_sp<GrMockRenderTask>>* expected) {
49     SkTArray<sk_sp<GrSurfaceProxy>> proxies;
50     make_proxies(2, &proxies);
51     make_tasks(3, graph);
52 
53     graph->at(0)->addTarget(proxies[0]);
54     graph->at(1)->addTarget(proxies[1]);
55     graph->at(2)->addTarget(proxies[0]);
56     graph->at(2)->addDependency(graph->at(1).get());
57 
58     expected->push_back(graph->at(1));
59     expected->push_back(graph->at(0));
60     expected->push_back(graph->at(2));
61 }
62 
63 /*
64  * In:  A1 B1 A2 C1 A3
65  * Out: B1 C1 A1 A2 A3
66  */
create_graph1(SkTArray<sk_sp<GrMockRenderTask>> * graph,SkTArray<sk_sp<GrMockRenderTask>> * expected)67 static void create_graph1(SkTArray<sk_sp<GrMockRenderTask>>* graph,
68                           SkTArray<sk_sp<GrMockRenderTask>>* expected) {
69     SkTArray<sk_sp<GrSurfaceProxy>> proxies;
70     make_proxies(3, &proxies);
71     make_tasks(5, graph);
72 
73     graph->at(0)->addTarget(proxies[0]);
74     graph->at(1)->addTarget(proxies[1]);
75     graph->at(2)->addTarget(proxies[0]);
76     graph->at(3)->addTarget(proxies[2]);
77     graph->at(4)->addTarget(proxies[0]);
78 
79     expected->push_back(graph->at(1));
80     expected->push_back(graph->at(3));
81     expected->push_back(graph->at(0));
82     expected->push_back(graph->at(2));
83     expected->push_back(graph->at(4));
84 }
85 
86 /*
87  * In:   A1 B1 A2.
88  * Srcs: A1->B1, B1->A2.
89  * Out:  A1 B1 A2. Can't reorder.
90  */
create_graph2(SkTArray<sk_sp<GrMockRenderTask>> * graph,SkTArray<sk_sp<GrMockRenderTask>> * expected)91 static void create_graph2(SkTArray<sk_sp<GrMockRenderTask>>* graph,
92                           SkTArray<sk_sp<GrMockRenderTask>>* expected) {
93     SkTArray<sk_sp<GrSurfaceProxy>> proxies;
94     make_proxies(2, &proxies);
95     make_tasks(3, graph);
96 
97     graph->at(0)->addTarget(proxies[0]);
98     graph->at(1)->addTarget(proxies[1]);
99     graph->at(2)->addTarget(proxies[0]);
100 
101     graph->at(1)->addDependency(graph->at(0).get());
102     graph->at(2)->addDependency(graph->at(1).get());
103 
104     // expected is empty. Can't reorder.
105 }
106 
107 /*
108  * Write-after-read case.
109  * In:   A1 B1 A2 B2
110  * Srcs: A1->B1, A2->B2
111  * Used: B1(A), B2(A)
112  * Out:  Can't reorder.
113  */
create_graph3(SkTArray<sk_sp<GrMockRenderTask>> * graph,SkTArray<sk_sp<GrMockRenderTask>> * expected)114 static void create_graph3(SkTArray<sk_sp<GrMockRenderTask>>* graph,
115                           SkTArray<sk_sp<GrMockRenderTask>>* expected) {
116     SkTArray<sk_sp<GrSurfaceProxy>> proxies;
117     make_proxies(2, &proxies);
118     make_tasks(4, graph);
119 
120     graph->at(0)->addTarget(proxies[0]);
121     graph->at(1)->addTarget(proxies[1]);
122     graph->at(2)->addTarget(proxies[0]);
123     graph->at(3)->addTarget(proxies[1]);
124 
125     graph->at(1)->addDependency(graph->at(0).get());
126     graph->at(3)->addDependency(graph->at(2).get());
127 
128     graph->at(1)->addUsed(proxies[0]);
129     graph->at(3)->addUsed(proxies[0]);
130 
131     // expected is empty. Can't reorder.
132 }
133 
DEF_TEST(GrRenderTaskCluster,reporter)134 DEF_TEST(GrRenderTaskCluster, reporter) {
135     CreateGraphPF tests[] = {
136         create_graph0,
137         create_graph1,
138         create_graph2,
139         create_graph3
140     };
141 
142     for (size_t i = 0; i < std::size(tests); ++i) {
143         SkTArray<sk_sp<GrMockRenderTask>> graph;
144         SkTArray<sk_sp<GrMockRenderTask>> expectedOutput;
145 
146         (tests[i])(&graph, &expectedOutput);
147 
148         SkTInternalLList<GrRenderTask> llist;
149         // TODO: Why does Span not want to convert from sk_sp<GrMockRenderTask> to
150         // `const sk_sp<GrRenderTask>`?
151         SkSpan<const sk_sp<GrRenderTask>> graphSpan(
152             reinterpret_cast<sk_sp<GrRenderTask>*>(graph.data()), graph.size());
153         bool actualResult = GrClusterRenderTasks(graphSpan, &llist);
154 
155         if (expectedOutput.empty()) {
156             REPORTER_ASSERT(reporter, !actualResult);
157             size_t newCount = 0;
158             for (const GrRenderTask* t : llist) {
159                 REPORTER_ASSERT(reporter, newCount < graphSpan.size() &&
160                                           t == graph[newCount].get());
161                 ++newCount;
162             }
163             REPORTER_ASSERT(reporter, newCount == graphSpan.size());
164         } else {
165             REPORTER_ASSERT(reporter, actualResult);
166             // SkTInternalLList::countEntries is debug-only and these tests run in release.
167             int newCount = 0;
168             for ([[maybe_unused]] GrRenderTask* t : llist) {
169                 newCount++;
170             }
171             REPORTER_ASSERT(reporter, newCount == expectedOutput.size());
172 
173             int j = 0;
174             for (GrRenderTask* n : llist) {
175                 REPORTER_ASSERT(reporter, n == expectedOutput[j++].get());
176             }
177         }
178 
179         //SkDEBUGCODE(print(graph);)
180     }
181 }
182