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
19class GrGeometryProcessor;
20
21GrProcessorTestData::GrProcessorTestData(SkRandom* random, GrRecordingContext* context,
22                                         int maxTreeDepth, int numViews, const ViewInfo views[])
23        : GrProcessorTestData(random, context, maxTreeDepth, numViews, views,
24                              /*inputFP=*/nullptr) {}
25
26GrProcessorTestData::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
37GrProcessorTestData::~GrProcessorTestData() {}
38
39GrProxyProvider* GrProcessorTestData::proxyProvider() { return fContext->priv().proxyProvider(); }
40
41const GrCaps* GrProcessorTestData::caps() { return fContext->priv().caps(); }
42
43std::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
53GrProcessorTestData::ViewInfo GrProcessorTestData::randomView() {
54    SkASSERT(!fViews.empty());
55    return fViews[fRandom->nextULessThan(fViews.count())];
56}
57
58GrProcessorTestData::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
75template <class ProcessorSmartPtr>
76GrProcessorTestFactory<ProcessorSmartPtr>::GrProcessorTestFactory(MakeProc makeProc,
77                                                                  const char* name)
78        : fMakeProc(makeProc), fName(name) {
79    GetFactories()->push_back(this);
80}
81
82template <class ProcessorSmartPtr>
83ProcessorSmartPtr 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
92template <class ProcessorSmartPtr>
93ProcessorSmartPtr 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
104template <class ProcessorSmartPtr>
105int GrProcessorTestFactory<ProcessorSmartPtr>::Count() {
106    return GetFactories()->count();
107}
108
109GrXPFactoryTestFactory::GrXPFactoryTestFactory(GetFn* getProc) : fGetProc(getProc) {
110    GetFactories()->push_back(this);
111}
112
113const 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 */
128template <>
129SkTArray<GrFragmentProcessorTestFactory*, true>* GrFragmentProcessorTestFactory::GetFactories() {
130    static SkTArray<GrFragmentProcessorTestFactory*, true> gFactories;
131    return &gFactories;
132}
133
134template <>
135SkTArray<GrGeometryProcessorTestFactory*, true>* GrGeometryProcessorTestFactory::GetFactories() {
136    static SkTArray<GrGeometryProcessorTestFactory*, true> gFactories;
137    return &gFactories;
138}
139
140SkTArray<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 */
150static constexpr int kFPFactoryCount = 16;
151static constexpr int kGPFactoryCount = 14;
152static constexpr int kXPFactoryCount = 4;
153
154template <> 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
162template <> 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
170void 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
178std::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
203std::unique_ptr<GrFragmentProcessor> GrProcessorUnitTest::MakeOptionalChildFP(
204        GrProcessorTestData* data) {
205    return data->fRandom->nextBool() ? MakeChildFP(data) : nullptr;
206}
207
208template class GrProcessorTestFactory<GrGeometryProcessor*>;
209template class GrProcessorTestFactory<std::unique_ptr<GrFragmentProcessor>>;
210
211#endif
212