1 /*
2 * Copyright 2015 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 "src/gpu/ganesh/GrProcessorUnitTest.h"
9
10 #if defined(GPU_TEST_UTILS)
11
12 #include "include/gpu/ganesh/GrRecordingContext.h"
13 #include "include/private/SkColorData.h"
14 #include "include/private/base/SkDebug.h"
15 #include "include/private/gpu/ganesh/GrTypesPriv.h"
16 #include "src/base/SkArenaAlloc.h"
17 #include "src/base/SkRandom.h"
18 #include "src/gpu/ganesh/GrFragmentProcessor.h"
19 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
20
21 #include <cstdint>
22 #include <memory>
23 #include <utility>
24
25 using namespace skia_private;
26
GrProcessorTestData(SkRandom * random,GrRecordingContext * context,int maxTreeDepth,int numViews,const ViewInfo views[])27 GrProcessorTestData::GrProcessorTestData(SkRandom* random, GrRecordingContext* context,
28 int maxTreeDepth, int numViews, const ViewInfo views[])
29 : GrProcessorTestData(random, context, maxTreeDepth, numViews, views,
30 /*inputFP=*/nullptr) {}
31
GrProcessorTestData(SkRandom * random,GrRecordingContext * context,int maxTreeDepth,int numViews,const ViewInfo views[],std::unique_ptr<GrFragmentProcessor> inputFP)32 GrProcessorTestData::GrProcessorTestData(SkRandom* random, GrRecordingContext* context,
33 int maxTreeDepth, int numViews, const ViewInfo views[],
34 std::unique_ptr<GrFragmentProcessor> inputFP)
35 : fRandom(random)
36 , fMaxTreeDepth(maxTreeDepth)
37 , fContext(context)
38 , fInputFP(std::move(inputFP)) {
39 fViews.reset(views, numViews);
40 fArena = std::make_unique<SkArenaAlloc>(1000);
41 }
42
~GrProcessorTestData()43 GrProcessorTestData::~GrProcessorTestData() {}
44
proxyProvider()45 GrProxyProvider* GrProcessorTestData::proxyProvider() { return fContext->priv().proxyProvider(); }
46
caps()47 const GrCaps* GrProcessorTestData::caps() { return fContext->priv().caps(); }
48
inputFP()49 std::unique_ptr<GrFragmentProcessor> GrProcessorTestData::inputFP() {
50 if (fCurrentTreeDepth == 0) {
51 // At the top level of the tree, provide the input FP from the test data.
52 return fInputFP ? fInputFP->clone() : nullptr;
53 } else {
54 // At deeper levels of recursion, synthesize a random input.
55 return GrProcessorUnitTest::MakeChildFP(this);
56 }
57 }
58
randomView()59 GrProcessorTestData::ViewInfo GrProcessorTestData::randomView() {
60 SkASSERT(!fViews.empty());
61 return fViews[fRandom->nextULessThan(fViews.size())];
62 }
63
randomAlphaOnlyView()64 GrProcessorTestData::ViewInfo GrProcessorTestData::randomAlphaOnlyView() {
65 int numAlphaOnly = 0;
66 for (const auto& [v, ct, at] : fViews) {
67 if (GrColorTypeIsAlphaOnly(ct)) {
68 ++numAlphaOnly;
69 }
70 }
71 SkASSERT(numAlphaOnly);
72 int idx = fRandom->nextULessThan(numAlphaOnly);
73 for (const auto& [v, ct, at] : fViews) {
74 if (GrColorTypeIsAlphaOnly(ct) && !idx--) {
75 return {v, ct, at};
76 }
77 }
78 SkUNREACHABLE;
79 }
80
81 template <class ProcessorSmartPtr>
GrProcessorTestFactory(MakeProc makeProc,const char * name)82 GrProcessorTestFactory<ProcessorSmartPtr>::GrProcessorTestFactory(MakeProc makeProc,
83 const char* name)
84 : fMakeProc(makeProc), fName(name) {
85 GetFactories()->push_back(this);
86 }
87
88 template <class ProcessorSmartPtr>
Make(GrProcessorTestData * data)89 ProcessorSmartPtr GrProcessorTestFactory<ProcessorSmartPtr>::Make(GrProcessorTestData* data) {
90 VerifyFactoryCount();
91 if (GetFactories()->size() == 0) {
92 return nullptr;
93 }
94 uint32_t idx = data->fRandom->nextULessThan(GetFactories()->size());
95 return MakeIdx(idx, data);
96 }
97
98 template <class ProcessorSmartPtr>
MakeIdx(int idx,GrProcessorTestData * data)99 ProcessorSmartPtr GrProcessorTestFactory<ProcessorSmartPtr>::MakeIdx(int idx,
100 GrProcessorTestData* data) {
101 SkASSERT(idx < GetFactories()->size());
102 GrProcessorTestFactory<ProcessorSmartPtr>* factory = (*GetFactories())[idx];
103 ProcessorSmartPtr processor = factory->fMakeProc(data);
104 if (processor == nullptr) {
105 SK_ABORT("%s: TestCreate returned null", factory->fName.c_str());
106 }
107 return processor;
108 }
109
110 template <class ProcessorSmartPtr>
Count()111 int GrProcessorTestFactory<ProcessorSmartPtr>::Count() {
112 return GetFactories()->size();
113 }
114
GrXPFactoryTestFactory(GetFn * getProc)115 GrXPFactoryTestFactory::GrXPFactoryTestFactory(GetFn* getProc) : fGetProc(getProc) {
116 GetFactories()->push_back(this);
117 }
118
Get(GrProcessorTestData * data)119 const GrXPFactory* GrXPFactoryTestFactory::Get(GrProcessorTestData* data) {
120 VerifyFactoryCount();
121 if (GetFactories()->size() == 0) {
122 return nullptr;
123 }
124 uint32_t idx = data->fRandom->nextRangeU(0, GetFactories()->size() - 1);
125 const GrXPFactory* xpf = (*GetFactories())[idx]->fGetProc(data);
126 SkASSERT(xpf);
127 return xpf;
128 }
129
130 /*
131 * Originally these were both in the processor unit test header, but then it seemed to cause linker
132 * problems on android.
133 */
134 template <>
GetFactories()135 TArray<GrFragmentProcessorTestFactory*, true>* GrFragmentProcessorTestFactory::GetFactories() {
136 static TArray<GrFragmentProcessorTestFactory*, true> gFactories;
137 return &gFactories;
138 }
139
140 template <>
GetFactories()141 TArray<GrGeometryProcessorTestFactory*, true>* GrGeometryProcessorTestFactory::GetFactories() {
142 static TArray<GrGeometryProcessorTestFactory*, true> gFactories;
143 return &gFactories;
144 }
145
GetFactories()146 TArray<GrXPFactoryTestFactory*, true>* GrXPFactoryTestFactory::GetFactories() {
147 static TArray<GrXPFactoryTestFactory*, true> gFactories;
148 return &gFactories;
149 }
150
151 /*
152 * To ensure we always have successful static initialization, before creating from the factories
153 * we verify the count is as expected. If a new factory is added, then these numbers must be
154 * manually adjusted.
155 */
156 static constexpr int kFPFactoryCount = 10;
157 static constexpr int kGPFactoryCount = 14;
158 static constexpr int kXPFactoryCount = 4;
159
VerifyFactoryCount()160 template <> void GrFragmentProcessorTestFactory::VerifyFactoryCount() {
161 if (kFPFactoryCount != GetFactories()->size()) {
162 SkDebugf("\nExpected %d fragment processor factories, found %d.\n", kFPFactoryCount,
163 GetFactories()->size());
164 SK_ABORT("Wrong number of fragment processor factories!");
165 }
166 }
167
VerifyFactoryCount()168 template <> void GrGeometryProcessorTestFactory::VerifyFactoryCount() {
169 if (kGPFactoryCount != GetFactories()->size()) {
170 SkDebugf("\nExpected %d geometry processor factories, found %d.\n", kGPFactoryCount,
171 GetFactories()->size());
172 SK_ABORT("Wrong number of geometry processor factories!");
173 }
174 }
175
VerifyFactoryCount()176 void GrXPFactoryTestFactory::VerifyFactoryCount() {
177 if (kXPFactoryCount != GetFactories()->size()) {
178 SkDebugf("\nExpected %d xp factory factories, found %d.\n", kXPFactoryCount,
179 GetFactories()->size());
180 SK_ABORT("Wrong number of xp factory factories!");
181 }
182 }
183
MakeChildFP(GrProcessorTestData * data)184 std::unique_ptr<GrFragmentProcessor> GrProcessorUnitTest::MakeChildFP(GrProcessorTestData* data) {
185 std::unique_ptr<GrFragmentProcessor> fp;
186
187 ++data->fCurrentTreeDepth;
188 if (data->fCurrentTreeDepth > data->fMaxTreeDepth) {
189 // We've gone too deep, but we can't necessarily return null without risking an assertion.
190 // Instead, return a known-simple zero-child FP. This limits the recursion, and the
191 // generated FP will be rejected by the numNonNullChildProcessors check below.
192 fp = GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT);
193 } else {
194 for (;;) {
195 fp = GrFragmentProcessorTestFactory::Make(data);
196 SkASSERT(fp);
197 // If our tree has already reached its max depth, we must reject FPs that have children.
198 if (data->fCurrentTreeDepth < data->fMaxTreeDepth ||
199 fp->numNonNullChildProcessors() == 0) {
200 break;
201 }
202 }
203 }
204
205 --data->fCurrentTreeDepth;
206 return fp;
207 }
208
MakeOptionalChildFP(GrProcessorTestData * data)209 std::unique_ptr<GrFragmentProcessor> GrProcessorUnitTest::MakeOptionalChildFP(
210 GrProcessorTestData* data) {
211 return data->fRandom->nextBool() ? MakeChildFP(data) : nullptr;
212 }
213
214 template class GrProcessorTestFactory<GrGeometryProcessor*>;
215 template class GrProcessorTestFactory<std::unique_ptr<GrFragmentProcessor>>;
216
217 #endif
218