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