Home | History | Annotate | Download | only in tests
      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
     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 
     34     const char* name() const override { return "TestOp"; }
     35 
     36     void visitProxies(const VisitProxyFunc& func) const override {
     37         fProcessors.visitProxies(func);
     38     }
     39 
     40     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
     41 
     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:
     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 
     57     void onPrepareDraws(Target* target) override { return; }
     58 
     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:
     72     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child) {
     73         return std::unique_ptr<GrFragmentProcessor>(new TestFP(std::move(child)));
     74     }
     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 
     80     const char* name() const override { return "test"; }
     81 
     82     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 
     88     std::unique_ptr<GrFragmentProcessor> clone() const override {
     89         return std::unique_ptr<GrFragmentProcessor>(new TestFP(*this));
     90     }
     91 
     92 private:
     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 
    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 
    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 
    123     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 
    137     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>
    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 
    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 
    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 
    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 
    275 static GrColor4f input_texel_color4f(int i, int j) {
    276     return GrColor4f::FromGrColor(input_texel_color(i, j));
    277 }
    278 
    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. */
    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().
    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 
    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.
    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