• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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 "SkTypes.h"
9 #include "Test.h"
10 
11 #if SK_SUPPORT_GPU
12 #include <random>
13 #include "GrClip.h"
14 #include "GrContext.h"
15 #include "GrContextPriv.h"
16 #include "GrGpuResource.h"
17 #include "GrProxyProvider.h"
18 #include "GrRenderTargetContext.h"
19 #include "GrRenderTargetContextPriv.h"
20 #include "GrResourceProvider.h"
21 #include "glsl/GrGLSLFragmentProcessor.h"
22 #include "glsl/GrGLSLFragmentShaderBuilder.h"
23 #include "ops/GrMeshDrawOp.h"
24 #include "ops/GrRectOpFactory.h"
25 
26 namespace {
27 class TestOp : public GrMeshDrawOp {
28 public:
29     DEFINE_OP_CLASS_ID
Make(std::unique_ptr<GrFragmentProcessor> fp)30     static std::unique_ptr<GrDrawOp> Make(std::unique_ptr<GrFragmentProcessor> fp) {
31         return std::unique_ptr<GrDrawOp>(new TestOp(std::move(fp)));
32     }
33 
name() const34     const char* name() const override { return "TestOp"; }
35 
visitProxies(const VisitProxyFunc & func) const36     void visitProxies(const VisitProxyFunc& func) const override {
37         fProcessors.visitProxies(func);
38     }
39 
fixedFunctionFlags() const40     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
41 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrPixelConfigIsClamped dstIsClamped)42     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip,
43                                 GrPixelConfigIsClamped dstIsClamped) override {
44         static constexpr GrProcessorAnalysisColor kUnknownColor;
45         GrColor overrideColor;
46         fProcessors.finalize(kUnknownColor, GrProcessorAnalysisCoverage::kNone, clip, false, caps,
47                              dstIsClamped, &overrideColor);
48         return RequiresDstTexture::kNo;
49     }
50 
51 private:
TestOp(std::unique_ptr<GrFragmentProcessor> fp)52     TestOp(std::unique_ptr<GrFragmentProcessor> fp)
53             : INHERITED(ClassID()), fProcessors(std::move(fp)) {
54         this->setBounds(SkRect::MakeWH(100, 100), HasAABloat::kNo, IsZeroArea::kNo);
55     }
56 
onPrepareDraws(Target * target)57     void onPrepareDraws(Target* target) override { return; }
58 
onCombineIfPossible(GrOp * op,const GrCaps & caps)59     bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
60 
61     GrProcessorSet fProcessors;
62 
63     typedef GrMeshDrawOp INHERITED;
64 };
65 
66 /**
67  * FP used to test ref/IO counts on owned GrGpuResources. Can also be a parent FP to test counts
68  * of resources owned by child FPs.
69  */
70 class TestFP : public GrFragmentProcessor {
71 public:
Make(std::unique_ptr<GrFragmentProcessor> child)72     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child) {
73         return std::unique_ptr<GrFragmentProcessor>(new TestFP(std::move(child)));
74     }
Make(const SkTArray<sk_sp<GrTextureProxy>> & proxies,const SkTArray<sk_sp<GrBuffer>> & buffers)75     static std::unique_ptr<GrFragmentProcessor> Make(const SkTArray<sk_sp<GrTextureProxy>>& proxies,
76                                                      const SkTArray<sk_sp<GrBuffer>>& buffers) {
77         return std::unique_ptr<GrFragmentProcessor>(new TestFP(proxies, buffers));
78     }
79 
name() const80     const char* name() const override { return "test"; }
81 
onGetGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder * b) const82     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
83         // We don't really care about reusing these.
84         static int32_t gKey = 0;
85         b->add32(sk_atomic_inc(&gKey));
86     }
87 
clone() const88     std::unique_ptr<GrFragmentProcessor> clone() const override {
89         return std::unique_ptr<GrFragmentProcessor>(new TestFP(*this));
90     }
91 
92 private:
TestFP(const SkTArray<sk_sp<GrTextureProxy>> & proxies,const SkTArray<sk_sp<GrBuffer>> & buffers)93     TestFP(const SkTArray<sk_sp<GrTextureProxy>>& proxies, const SkTArray<sk_sp<GrBuffer>>& buffers)
94             : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags), fSamplers(4), fBuffers(4) {
95         for (const auto& proxy : proxies) {
96             this->addTextureSampler(&fSamplers.emplace_back(proxy));
97         }
98         for (const auto& buffer : buffers) {
99             this->addBufferAccess(&fBuffers.emplace_back(kRGBA_8888_GrPixelConfig, buffer.get()));
100         }
101     }
102 
TestFP(std::unique_ptr<GrFragmentProcessor> child)103     TestFP(std::unique_ptr<GrFragmentProcessor> child)
104             : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags), fSamplers(4), fBuffers(4) {
105         this->registerChildProcessor(std::move(child));
106     }
107 
TestFP(const TestFP & that)108     explicit TestFP(const TestFP& that)
109             : INHERITED(kTestFP_ClassID, that.optimizationFlags()), fSamplers(4), fBuffers(4) {
110         for (int i = 0; i < that.fSamplers.count(); ++i) {
111             fSamplers.emplace_back(that.fSamplers[i]);
112             this->addTextureSampler(&fSamplers.back());
113         }
114         for (int i = 0; i < that.fBuffers.count(); ++i) {
115             fBuffers.emplace_back(that.fBuffers[i]);
116             this->addBufferAccess(&fBuffers.back());
117         }
118         for (int i = 0; i < that.numChildProcessors(); ++i) {
119             this->registerChildProcessor(that.childProcessor(i).clone());
120         }
121     }
122 
onCreateGLSLInstance() const123     virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
124         class TestGLSLFP : public GrGLSLFragmentProcessor {
125         public:
126             TestGLSLFP() {}
127             void emitCode(EmitArgs& args) override {
128                 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
129                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor);
130             }
131 
132         private:
133         };
134         return new TestGLSLFP();
135     }
136 
onIsEqual(const GrFragmentProcessor &) const137     bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
138 
139     GrTAllocator<TextureSampler> fSamplers;
140     GrTAllocator<BufferAccess> fBuffers;
141     typedef GrFragmentProcessor INHERITED;
142 };
143 }
144 
145 template <typename T>
testingOnly_getIORefCnts(const T * resource,int * refCnt,int * readCnt,int * writeCnt)146 inline void testingOnly_getIORefCnts(const T* resource, int* refCnt, int* readCnt, int* writeCnt) {
147     *refCnt = resource->fRefCnt;
148     *readCnt = resource->fPendingReads;
149     *writeCnt = resource->fPendingWrites;
150 }
151 
testingOnly_getIORefCnts(GrTextureProxy * proxy,int * refCnt,int * readCnt,int * writeCnt)152 void testingOnly_getIORefCnts(GrTextureProxy* proxy, int* refCnt, int* readCnt, int* writeCnt) {
153     *refCnt = proxy->getBackingRefCnt_TestOnly();
154     *readCnt = proxy->getPendingReadCnt_TestOnly();
155     *writeCnt = proxy->getPendingWriteCnt_TestOnly();
156 }
157 
DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest,reporter,ctxInfo)158 DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) {
159     GrContext* context = ctxInfo.grContext();
160     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
161     GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider();
162 
163     GrSurfaceDesc desc;
164     desc.fOrigin = kTopLeft_GrSurfaceOrigin;
165     desc.fWidth = 10;
166     desc.fHeight = 10;
167     desc.fConfig = kRGBA_8888_GrPixelConfig;
168 
169     for (bool makeClone : {false, true}) {
170         for (int parentCnt = 0; parentCnt < 2; parentCnt++) {
171             sk_sp<GrRenderTargetContext> renderTargetContext(
172                     context->makeDeferredRenderTargetContext( SkBackingFit::kApprox, 1, 1,
173                                                               kRGBA_8888_GrPixelConfig, nullptr));
174             {
175                 bool texelBufferSupport = context->caps()->shaderCaps()->texelBufferSupport();
176                 sk_sp<GrTextureProxy> proxy1 =
177                         proxyProvider->createProxy(desc, SkBackingFit::kExact, SkBudgeted::kYes);
178                 sk_sp<GrTextureProxy> proxy2 =
179                         proxyProvider->createProxy(desc, SkBackingFit::kExact, SkBudgeted::kYes);
180                 sk_sp<GrTextureProxy> proxy3 =
181                         proxyProvider->createProxy(desc, SkBackingFit::kExact, SkBudgeted::kYes);
182                 sk_sp<GrTextureProxy> proxy4 =
183                         proxyProvider->createProxy(desc, SkBackingFit::kExact, SkBudgeted::kYes);
184                 sk_sp<GrBuffer> buffer(texelBufferSupport
185                         ? resourceProvider->createBuffer(
186                                   1024, GrBufferType::kTexel_GrBufferType,
187                                   GrAccessPattern::kStatic_GrAccessPattern, 0)
188                         : nullptr);
189                 {
190                     SkTArray<sk_sp<GrTextureProxy>> proxies;
191                     SkTArray<sk_sp<GrBuffer>> buffers;
192                     proxies.push_back(proxy1);
193                     if (texelBufferSupport) {
194                         buffers.push_back(buffer);
195                     }
196                     auto fp = TestFP::Make(std::move(proxies), std::move(buffers));
197                     for (int i = 0; i < parentCnt; ++i) {
198                         fp = TestFP::Make(std::move(fp));
199                     }
200                     std::unique_ptr<GrFragmentProcessor> clone;
201                     if (makeClone) {
202                         clone = fp->clone();
203                     }
204                     std::unique_ptr<GrDrawOp> op(TestOp::Make(std::move(fp)));
205                     renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
206                     if (clone) {
207                         op = TestOp::Make(std::move(clone));
208                         renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
209                     }
210                 }
211                 int refCnt, readCnt, writeCnt;
212 
213                 testingOnly_getIORefCnts(proxy1.get(), &refCnt, &readCnt, &writeCnt);
214                 // IO counts should be double if there is a clone of the FP.
215                 int ioRefMul = makeClone ? 2 : 1;
216                 REPORTER_ASSERT(reporter, 1 == refCnt);
217                 REPORTER_ASSERT(reporter, ioRefMul * 1 == readCnt);
218                 REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt);
219 
220                 if (texelBufferSupport) {
221                     testingOnly_getIORefCnts(buffer.get(), &refCnt, &readCnt, &writeCnt);
222                     REPORTER_ASSERT(reporter, 1 == refCnt);
223                     REPORTER_ASSERT(reporter, ioRefMul * 1 == readCnt);
224                     REPORTER_ASSERT(reporter, ioRefMul *  0 == writeCnt);
225                 }
226 
227                 context->flush();
228 
229                 testingOnly_getIORefCnts(proxy1.get(), &refCnt, &readCnt, &writeCnt);
230                 REPORTER_ASSERT(reporter, 1 == refCnt);
231                 REPORTER_ASSERT(reporter, ioRefMul * 0 == readCnt);
232                 REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt);
233 
234                 if (texelBufferSupport) {
235                     testingOnly_getIORefCnts(buffer.get(), &refCnt, &readCnt, &writeCnt);
236                     REPORTER_ASSERT(reporter, 1 == refCnt);
237                     REPORTER_ASSERT(reporter, ioRefMul * 0 == readCnt);
238                     REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt);
239                 }
240 
241                 if (texelBufferSupport) {
242                     testingOnly_getIORefCnts(proxy2.get(), &refCnt, &readCnt, &writeCnt);
243                     REPORTER_ASSERT(reporter, 1 == refCnt);
244                     REPORTER_ASSERT(reporter, ioRefMul * 0 == readCnt);
245                     REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt);
246 
247                     testingOnly_getIORefCnts(proxy3.get(), &refCnt, &readCnt, &writeCnt);
248                     REPORTER_ASSERT(reporter, 1 == refCnt);
249                     REPORTER_ASSERT(reporter, ioRefMul * 0 == readCnt);
250                     REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt);
251 
252                     testingOnly_getIORefCnts(proxy4.get(), &refCnt, &readCnt, &writeCnt);
253                     REPORTER_ASSERT(reporter, 1 == refCnt);
254                     REPORTER_ASSERT(reporter, ioRefMul * 0 == readCnt);
255                     REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt);
256                 }
257             }
258         }
259     }
260 }
261 
262 // This test uses the random GrFragmentProcessor test factory, which relies on static initializers.
263 #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
264 
265 #include "SkCommandLineFlags.h"
266 DEFINE_bool(randomProcessorTest, false, "Use non-deterministic seed for random processor tests?");
267 
268 #if GR_TEST_UTILS
269 
input_texel_color(int i,int j)270 static GrColor input_texel_color(int i, int j) {
271     GrColor color = GrColorPackRGBA((uint8_t)j, (uint8_t)(i + j), (uint8_t)(2 * j - i), (uint8_t)i);
272     return GrPremulColor(color);
273 }
274 
input_texel_color4f(int i,int j)275 static GrColor4f input_texel_color4f(int i, int j) {
276     return GrColor4f::FromGrColor(input_texel_color(i, j));
277 }
278 
test_draw_op(GrRenderTargetContext * rtc,std::unique_ptr<GrFragmentProcessor> fp,sk_sp<GrTextureProxy> inputDataProxy)279 void test_draw_op(GrRenderTargetContext* rtc, std::unique_ptr<GrFragmentProcessor> fp,
280                   sk_sp<GrTextureProxy> inputDataProxy) {
281     GrPaint paint;
282     paint.addColorTextureProcessor(std::move(inputDataProxy), SkMatrix::I());
283     paint.addColorFragmentProcessor(std::move(fp));
284     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
285 
286     auto op = GrRectOpFactory::MakeNonAAFill(std::move(paint), SkMatrix::I(),
287                                              SkRect::MakeWH(rtc->width(), rtc->height()),
288                                              GrAAType::kNone);
289     rtc->addDrawOp(GrNoClip(), std::move(op));
290 }
291 
292 /** Initializes the two test texture proxies that are available to the FP test factories. */
init_test_textures(GrProxyProvider * proxyProvider,SkRandom * random,sk_sp<GrTextureProxy> proxies[2])293 bool init_test_textures(GrProxyProvider* proxyProvider, SkRandom* random,
294                         sk_sp<GrTextureProxy> proxies[2]) {
295     static const int kTestTextureSize = 256;
296     GrSurfaceDesc desc;
297     desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
298     desc.fWidth = kTestTextureSize;
299     desc.fHeight = kTestTextureSize;
300     desc.fConfig = kRGBA_8888_GrPixelConfig;
301 
302     {
303         // Put premul data into the RGBA texture that the test FPs can optionally use.
304         std::unique_ptr<GrColor[]> rgbaData(new GrColor[kTestTextureSize * kTestTextureSize]);
305         for (int y = 0; y < kTestTextureSize; ++y) {
306             for (int x = 0; x < kTestTextureSize; ++x) {
307                 rgbaData[kTestTextureSize * y + x] =
308                         input_texel_color(random->nextULessThan(256), random->nextULessThan(256));
309             }
310         }
311 
312         proxies[0] = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes,
313                                                        rgbaData.get(),
314                                                        kTestTextureSize * sizeof(GrColor));
315     }
316 
317     {
318         // Put random values into the alpha texture that the test FPs can optionally use.
319         desc.fConfig = kAlpha_8_GrPixelConfig;
320         std::unique_ptr<uint8_t[]> alphaData(new uint8_t[kTestTextureSize * kTestTextureSize]);
321         for (int y = 0; y < kTestTextureSize; ++y) {
322             for (int x = 0; x < kTestTextureSize; ++x) {
323                 alphaData[kTestTextureSize * y + x] = random->nextULessThan(256);
324             }
325         }
326 
327         proxies[1] = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes,
328                                                        alphaData.get(), kTestTextureSize);
329     }
330 
331     return proxies[0] && proxies[1];
332 }
333 
334 // Creates a texture of premul colors used as the output of the fragment processor that precedes
335 // the fragment processor under test. Color values are those provided by input_texel_color().
make_input_texture(GrProxyProvider * proxyProvider,int width,int height)336 sk_sp<GrTextureProxy> make_input_texture(GrProxyProvider* proxyProvider, int width, int height) {
337     std::unique_ptr<GrColor[]> data(new GrColor[width * height]);
338     for (int y = 0; y < width; ++y) {
339         for (int x = 0; x < height; ++x) {
340             data.get()[width * y + x] = input_texel_color(x, y);
341         }
342     }
343     GrSurfaceDesc desc;
344     desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
345     desc.fWidth = width;
346     desc.fHeight = height;
347     desc.fConfig = kRGBA_8888_GrPixelConfig;
348 
349     return proxyProvider->createTextureProxy(desc, SkBudgeted::kYes,
350                                              data.get(), width * sizeof(GrColor));
351 }
352 
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest,reporter,ctxInfo)353 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) {
354     GrContext* context = ctxInfo.grContext();
355     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
356     auto resourceProvider = context->contextPriv().resourceProvider();
357     using FPFactory = GrFragmentProcessorTestFactory;
358 
359     uint32_t seed = 0;
360     if (FLAGS_randomProcessorTest) {
361         std::random_device rd;
362         seed = rd();
363     }
364     // If a non-deterministic bot fails this test, check the output to see what seed it used, then
365     // hard-code that value here:
366     SkRandom random(seed);
367 
368     // Make the destination context for the test.
369     static constexpr int kRenderSize = 256;
370     sk_sp<GrRenderTargetContext> rtc = context->makeDeferredRenderTargetContext(
371             SkBackingFit::kExact, kRenderSize, kRenderSize, kRGBA_8888_GrPixelConfig, nullptr);
372 
373     sk_sp<GrTextureProxy> proxies[2];
374     if (!init_test_textures(proxyProvider, &random, proxies)) {
375         ERRORF(reporter, "Could not create test textures");
376         return;
377     }
378     GrProcessorTestData testData(&random, context, rtc.get(), proxies);
379 
380     auto inputTexture = make_input_texture(proxyProvider, kRenderSize, kRenderSize);
381 
382     std::unique_ptr<GrColor[]> readData(new GrColor[kRenderSize * kRenderSize]);
383     // Because processor factories configure themselves in random ways, this is not exhaustive.
384     for (int i = 0; i < FPFactory::Count(); ++i) {
385         int timesToInvokeFactory = 5;
386         // Increase the number of attempts if the FP has child FPs since optimizations likely depend
387         // on child optimizations being present.
388         std::unique_ptr<GrFragmentProcessor> fp = FPFactory::MakeIdx(i, &testData);
389         for (int j = 0; j < fp->numChildProcessors(); ++j) {
390             // This value made a reasonable trade off between time and coverage when this test was
391             // written.
392             timesToInvokeFactory *= FPFactory::Count() / 2;
393         }
394         for (int j = 0; j < timesToInvokeFactory; ++j) {
395             fp = FPFactory::MakeIdx(i, &testData);
396             if (!fp->instantiate(resourceProvider)) {
397                 continue;
398             }
399 
400             if (!fp->hasConstantOutputForConstantInput() && !fp->preservesOpaqueInput() &&
401                 !fp->compatibleWithCoverageAsAlpha()) {
402                 continue;
403             }
404 
405             // Since we transfer away ownership of the original FP, we make a clone.
406             auto clone = fp->clone();
407 
408             test_draw_op(rtc.get(), std::move(fp), inputTexture);
409             memset(readData.get(), 0x0, sizeof(GrColor) * kRenderSize * kRenderSize);
410             rtc->readPixels(SkImageInfo::Make(kRenderSize, kRenderSize, kRGBA_8888_SkColorType,
411                                               kPremul_SkAlphaType),
412                             readData.get(), 0, 0, 0);
413             bool passing = true;
414             if (0) {  // Useful to see what FPs are being tested.
415                 SkString children;
416                 for (int c = 0; c < clone->numChildProcessors(); ++c) {
417                     if (!c) {
418                         children.append("(");
419                     }
420                     children.append(clone->name());
421                     children.append(c == clone->numChildProcessors() - 1 ? ")" : ", ");
422                 }
423                 SkDebugf("%s %s\n", clone->name(), children.c_str());
424             }
425             for (int y = 0; y < kRenderSize && passing; ++y) {
426                 for (int x = 0; x < kRenderSize && passing; ++x) {
427                     GrColor input = input_texel_color(x, y);
428                     GrColor output = readData.get()[y * kRenderSize + x];
429                     if (clone->compatibleWithCoverageAsAlpha()) {
430                         // A modulating processor is allowed to modulate either the input color or
431                         // just the input alpha.
432                         bool legalColorModulation =
433                                 GrColorUnpackA(output) <= GrColorUnpackA(input) &&
434                                 GrColorUnpackR(output) <= GrColorUnpackR(input) &&
435                                 GrColorUnpackG(output) <= GrColorUnpackG(input) &&
436                                 GrColorUnpackB(output) <= GrColorUnpackB(input);
437                         bool legalAlphaModulation =
438                                 GrColorUnpackA(output) <= GrColorUnpackA(input) &&
439                                 GrColorUnpackR(output) <= GrColorUnpackA(input) &&
440                                 GrColorUnpackG(output) <= GrColorUnpackA(input) &&
441                                 GrColorUnpackB(output) <= GrColorUnpackA(input);
442                         if (!legalColorModulation && !legalAlphaModulation) {
443                             ERRORF(reporter,
444                                    "\"Modulating\" processor %s made color/alpha value larger. "
445                                    "Input: 0x%08x, Output: 0x%08x, pixel (%d, %d).",
446                                    clone->name(), input, output, x, y);
447                             passing = false;
448                         }
449                     }
450                     GrColor4f input4f = input_texel_color4f(x, y);
451                     GrColor4f output4f = GrColor4f::FromGrColor(output);
452                     GrColor4f expected4f;
453                     if (clone->hasConstantOutputForConstantInput(input4f, &expected4f)) {
454                         float rDiff = fabsf(output4f.fRGBA[0] - expected4f.fRGBA[0]);
455                         float gDiff = fabsf(output4f.fRGBA[1] - expected4f.fRGBA[1]);
456                         float bDiff = fabsf(output4f.fRGBA[2] - expected4f.fRGBA[2]);
457                         float aDiff = fabsf(output4f.fRGBA[3] - expected4f.fRGBA[3]);
458                         static constexpr float kTol = 4 / 255.f;
459                         if (rDiff > kTol || gDiff > kTol || bDiff > kTol || aDiff > kTol) {
460                             ERRORF(reporter,
461                                    "Processor %s claimed output for const input doesn't match "
462                                    "actual output. Error: %f, Tolerance: %f, input: (%f, %f, %f, "
463                                    "%f), actual: (%f, %f, %f, %f), expected(%f, %f, %f, %f)",
464                                    clone->name(),
465                                    SkTMax(rDiff, SkTMax(gDiff, SkTMax(bDiff, aDiff))), kTol,
466                                    input4f.fRGBA[0], input4f.fRGBA[1], input4f.fRGBA[2],
467                                    input4f.fRGBA[3], output4f.fRGBA[0], output4f.fRGBA[1],
468                                    output4f.fRGBA[2], output4f.fRGBA[3], expected4f.fRGBA[0],
469                                    expected4f.fRGBA[1], expected4f.fRGBA[2], expected4f.fRGBA[3]);
470                             passing = false;
471                         }
472                     }
473                     if (GrColorIsOpaque(input) && clone->preservesOpaqueInput() &&
474                         !GrColorIsOpaque(output)) {
475                         ERRORF(reporter,
476                                "Processor %s claimed opaqueness is preserved but it is not. Input: "
477                                "0x%08x, Output: 0x%08x.",
478                                clone->name(), input, output);
479                         passing = false;
480                     }
481                     if (!passing) {
482                         ERRORF(reporter, "Seed: 0x%08x, Processor details: %s", seed,
483                                clone->dumpInfo().c_str());
484                     }
485                 }
486             }
487         }
488     }
489 }
490 
491 // Tests that fragment processors returned by GrFragmentProcessor::clone() are equivalent to their
492 // progenitors.
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorCloneTest,reporter,ctxInfo)493 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorCloneTest, reporter, ctxInfo) {
494     GrContext* context = ctxInfo.grContext();
495     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
496     auto resourceProvider = context->contextPriv().resourceProvider();
497 
498     SkRandom random;
499 
500     // Make the destination context for the test.
501     static constexpr int kRenderSize = 1024;
502     sk_sp<GrRenderTargetContext> rtc = context->makeDeferredRenderTargetContext(
503             SkBackingFit::kExact, kRenderSize, kRenderSize, kRGBA_8888_GrPixelConfig, nullptr);
504 
505     sk_sp<GrTextureProxy> proxies[2];
506     if (!init_test_textures(proxyProvider, &random, proxies)) {
507         ERRORF(reporter, "Could not create test textures");
508         return;
509     }
510     GrProcessorTestData testData(&random, context, rtc.get(), proxies);
511 
512     auto inputTexture = make_input_texture(proxyProvider, kRenderSize, kRenderSize);
513     std::unique_ptr<GrColor[]> readData1(new GrColor[kRenderSize * kRenderSize]);
514     std::unique_ptr<GrColor[]> readData2(new GrColor[kRenderSize * kRenderSize]);
515     auto readInfo = SkImageInfo::Make(kRenderSize, kRenderSize, kRGBA_8888_SkColorType,
516                                       kPremul_SkAlphaType);
517 
518     // Because processor factories configure themselves in random ways, this is not exhaustive.
519     for (int i = 0; i < GrFragmentProcessorTestFactory::Count(); ++i) {
520         static constexpr int kTimesToInvokeFactory = 10;
521         for (int j = 0; j < kTimesToInvokeFactory; ++j) {
522             auto fp = GrFragmentProcessorTestFactory::MakeIdx(i, &testData);
523             auto clone = fp->clone();
524             if (!clone) {
525                 ERRORF(reporter, "Clone of processor %s failed.", fp->name());
526                 continue;
527             }
528             const char* name = fp->name();
529             if (!fp->instantiate(resourceProvider) || !clone->instantiate(resourceProvider)) {
530                 continue;
531             }
532             REPORTER_ASSERT(reporter, !strcmp(fp->name(), clone->name()));
533             REPORTER_ASSERT(reporter, fp->compatibleWithCoverageAsAlpha() ==
534                                       clone->compatibleWithCoverageAsAlpha());
535             REPORTER_ASSERT(reporter, fp->isEqual(*clone));
536             REPORTER_ASSERT(reporter, fp->preservesOpaqueInput() == clone->preservesOpaqueInput());
537             REPORTER_ASSERT(reporter, fp->hasConstantOutputForConstantInput() ==
538                                       clone->hasConstantOutputForConstantInput());
539             REPORTER_ASSERT(reporter, fp->numChildProcessors() == clone->numChildProcessors());
540             REPORTER_ASSERT(reporter, fp->usesLocalCoords() == clone->usesLocalCoords());
541             // Draw with original and read back the results.
542             test_draw_op(rtc.get(), std::move(fp), inputTexture);
543             memset(readData1.get(), 0x0, sizeof(GrColor) * kRenderSize * kRenderSize);
544             rtc->readPixels(readInfo, readData1.get(), 0, 0, 0);
545 
546             // Draw with clone and read back the results.
547             test_draw_op(rtc.get(), std::move(clone), inputTexture);
548             memset(readData2.get(), 0x0, sizeof(GrColor) * kRenderSize * kRenderSize);
549             rtc->readPixels(readInfo, readData2.get(), 0, 0, 0);
550 
551             // Check that the results are the same.
552             bool passing = true;
553             for (int y = 0; y < kRenderSize && passing; ++y) {
554                 for (int x = 0; x < kRenderSize && passing; ++x) {
555                     int idx = y * kRenderSize + x;
556                     if (readData1[idx] != readData2[idx]) {
557                         ERRORF(reporter,
558                                "Processor %s made clone produced different output. "
559                                "Input color: 0x%08x, Original Output Color: 0x%08x, "
560                                "Clone Output Color: 0x%08x..",
561                                name, input_texel_color(x, y), readData1[idx], readData2[idx]);
562                         passing = false;
563                     }
564                 }
565             }
566         }
567     }
568 }
569 
570 #endif  // GR_TEST_UTILS
571 #endif  // SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
572 #endif  // SK_SUPPORT_GPU
573