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 #include "GrClip.h"
     12 #include "GrContext.h"
     13 #include "GrContextPriv.h"
     14 #include "GrGpuResource.h"
     15 #include "GrMemoryPool.h"
     16 #include "GrProxyProvider.h"
     17 #include "GrRenderTargetContext.h"
     18 #include "GrRenderTargetContextPriv.h"
     19 #include "GrResourceProvider.h"
     20 #include "glsl/GrGLSLFragmentProcessor.h"
     21 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     22 #include "ops/GrFillRectOp.h"
     23 #include "ops/GrMeshDrawOp.h"
     24 #include "TestUtils.h"
     25 
     26 #include <atomic>
     27 #include <random>
     28 
     29 namespace {
     30 class TestOp : public GrMeshDrawOp {
     31 public:
     32     DEFINE_OP_CLASS_ID
     33     static std::unique_ptr<GrDrawOp> Make(GrContext* context,
     34                                           std::unique_ptr<GrFragmentProcessor> fp) {
     35         GrOpMemoryPool* pool = context->priv().opMemoryPool();
     36 
     37         return pool->allocate<TestOp>(std::move(fp));
     38     }
     39 
     40     const char* name() const override { return "TestOp"; }
     41 
     42     void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
     43         fProcessors.visitProxies(func);
     44     }
     45 
     46     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
     47 
     48     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
     49                                       GrFSAAType fsaaType, GrClampType clampType) override {
     50         static constexpr GrProcessorAnalysisColor kUnknownColor;
     51         SkPMColor4f overrideColor;
     52         return fProcessors.finalize(
     53                 kUnknownColor, GrProcessorAnalysisCoverage::kNone, clip,
     54                 &GrUserStencilSettings::kUnused, fsaaType, caps, clampType, &overrideColor);
     55     }
     56 
     57 private:
     58     friend class ::GrOpMemoryPool; // for ctor
     59 
     60     TestOp(std::unique_ptr<GrFragmentProcessor> fp)
     61             : INHERITED(ClassID()), fProcessors(std::move(fp)) {
     62         this->setBounds(SkRect::MakeWH(100, 100), HasAABloat::kNo, IsZeroArea::kNo);
     63     }
     64 
     65     void onPrepareDraws(Target* target) override { return; }
     66     void onExecute(GrOpFlushState*, const SkRect&) override { return; }
     67 
     68     GrProcessorSet fProcessors;
     69 
     70     typedef GrMeshDrawOp INHERITED;
     71 };
     72 
     73 /**
     74  * FP used to test ref/IO counts on owned GrGpuResources. Can also be a parent FP to test counts
     75  * of resources owned by child FPs.
     76  */
     77 class TestFP : public GrFragmentProcessor {
     78 public:
     79     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child) {
     80         return std::unique_ptr<GrFragmentProcessor>(new TestFP(std::move(child)));
     81     }
     82     static std::unique_ptr<GrFragmentProcessor> Make(const SkTArray<sk_sp<GrTextureProxy>>& proxies,
     83                                                      const SkTArray<sk_sp<GrGpuBuffer>>& buffers) {
     84         return std::unique_ptr<GrFragmentProcessor>(new TestFP(proxies, buffers));
     85     }
     86 
     87     const char* name() const override { return "test"; }
     88 
     89     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
     90         static std::atomic<int32_t> nextKey{0};
     91         b->add32(nextKey++);
     92     }
     93 
     94     std::unique_ptr<GrFragmentProcessor> clone() const override {
     95         return std::unique_ptr<GrFragmentProcessor>(new TestFP(*this));
     96     }
     97 
     98 private:
     99     TestFP(const SkTArray<sk_sp<GrTextureProxy>>& proxies,
    100            const SkTArray<sk_sp<GrGpuBuffer>>& buffers)
    101             : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags), fSamplers(4) {
    102         for (const auto& proxy : proxies) {
    103             fSamplers.emplace_back(proxy);
    104         }
    105         this->setTextureSamplerCnt(fSamplers.count());
    106     }
    107 
    108     TestFP(std::unique_ptr<GrFragmentProcessor> child)
    109             : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags), fSamplers(4) {
    110         this->registerChildProcessor(std::move(child));
    111     }
    112 
    113     explicit TestFP(const TestFP& that)
    114             : INHERITED(kTestFP_ClassID, that.optimizationFlags()), fSamplers(4) {
    115         for (int i = 0; i < that.fSamplers.count(); ++i) {
    116             fSamplers.emplace_back(that.fSamplers[i]);
    117         }
    118         for (int i = 0; i < that.numChildProcessors(); ++i) {
    119             this->registerChildProcessor(that.childProcessor(i).clone());
    120         }
    121         this->setTextureSamplerCnt(fSamplers.count());
    122     }
    123 
    124     virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
    125         class TestGLSLFP : public GrGLSLFragmentProcessor {
    126         public:
    127             TestGLSLFP() {}
    128             void emitCode(EmitArgs& args) override {
    129                 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    130                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor);
    131             }
    132 
    133         private:
    134         };
    135         return new TestGLSLFP();
    136     }
    137 
    138     bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
    139     const TextureSampler& onTextureSampler(int i) const override { return fSamplers[i]; }
    140 
    141     GrTAllocator<TextureSampler> fSamplers;
    142     typedef GrFragmentProcessor INHERITED;
    143 };
    144 }
    145 
    146 template <typename T>
    147 inline void testingOnly_getIORefCnts(const T* resource, int* refCnt, int* readCnt, int* writeCnt) {
    148     *refCnt = resource->fRefCnt;
    149     *readCnt = resource->fPendingReads;
    150     *writeCnt = resource->fPendingWrites;
    151 }
    152 
    153 void testingOnly_getIORefCnts(GrTextureProxy* proxy, int* refCnt, int* readCnt, int* writeCnt) {
    154     *refCnt = proxy->getBackingRefCnt_TestOnly();
    155     *readCnt = proxy->getPendingReadCnt_TestOnly();
    156     *writeCnt = proxy->getPendingWriteCnt_TestOnly();
    157 }
    158 
    159 DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) {
    160     GrContext* context = ctxInfo.grContext();
    161     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
    162 
    163     GrSurfaceDesc desc;
    164     desc.fWidth = 10;
    165     desc.fHeight = 10;
    166     desc.fConfig = kRGBA_8888_GrPixelConfig;
    167 
    168     const GrBackendFormat format =
    169             context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
    170 
    171     for (bool makeClone : {false, true}) {
    172         for (int parentCnt = 0; parentCnt < 2; parentCnt++) {
    173             sk_sp<GrRenderTargetContext> renderTargetContext(
    174                     context->priv().makeDeferredRenderTargetContext(
    175                                                              format, SkBackingFit::kApprox, 1, 1,
    176                                                              kRGBA_8888_GrPixelConfig, nullptr));
    177             {
    178                 sk_sp<GrTextureProxy> proxy1 = proxyProvider->createProxy(
    179                         format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact,
    180                         SkBudgeted::kYes);
    181                 sk_sp<GrTextureProxy> proxy2 = proxyProvider->createProxy(
    182                         format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact,
    183                         SkBudgeted::kYes);
    184                 sk_sp<GrTextureProxy> proxy3 = proxyProvider->createProxy(
    185                         format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact,
    186                         SkBudgeted::kYes);
    187                 sk_sp<GrTextureProxy> proxy4 = proxyProvider->createProxy(
    188                         format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact,
    189                         SkBudgeted::kYes);
    190                 {
    191                     SkTArray<sk_sp<GrTextureProxy>> proxies;
    192                     SkTArray<sk_sp<GrGpuBuffer>> buffers;
    193                     proxies.push_back(proxy1);
    194                     auto fp = TestFP::Make(std::move(proxies), std::move(buffers));
    195                     for (int i = 0; i < parentCnt; ++i) {
    196                         fp = TestFP::Make(std::move(fp));
    197                     }
    198                     std::unique_ptr<GrFragmentProcessor> clone;
    199                     if (makeClone) {
    200                         clone = fp->clone();
    201                     }
    202                     std::unique_ptr<GrDrawOp> op(TestOp::Make(context, std::move(fp)));
    203                     renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
    204                     if (clone) {
    205                         op = TestOp::Make(context, std::move(clone));
    206                         renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
    207                     }
    208                 }
    209                 int refCnt, readCnt, writeCnt;
    210 
    211                 testingOnly_getIORefCnts(proxy1.get(), &refCnt, &readCnt, &writeCnt);
    212                 // IO counts should be double if there is a clone of the FP.
    213                 int ioRefMul = makeClone ? 2 : 1;
    214                 REPORTER_ASSERT(reporter, -1 == refCnt);
    215                 REPORTER_ASSERT(reporter, ioRefMul * 1 == readCnt);
    216                 REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt);
    217 
    218                 context->flush();
    219 
    220                 testingOnly_getIORefCnts(proxy1.get(), &refCnt, &readCnt, &writeCnt);
    221                 REPORTER_ASSERT(reporter, 1 == refCnt);
    222                 REPORTER_ASSERT(reporter, ioRefMul * 0 == readCnt);
    223                 REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt);
    224 
    225             }
    226         }
    227     }
    228 }
    229 
    230 // This test uses the random GrFragmentProcessor test factory, which relies on static initializers.
    231 #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
    232 
    233 #include "SkCommandLineFlags.h"
    234 DEFINE_bool(randomProcessorTest, false, "Use non-deterministic seed for random processor tests?");
    235 DEFINE_uint32(processorSeed, 0, "Use specific seed for processor tests. Overridden by " \
    236                                 "--randomProcessorTest.");
    237 
    238 #if GR_TEST_UTILS
    239 
    240 static GrColor input_texel_color(int i, int j, SkScalar delta) {
    241     // Delta must be less than 0.5 to prevent over/underflow issues with the input color
    242     SkASSERT(delta <= 0.5);
    243 
    244     SkColor color = SkColorSetARGB((uint8_t)(i & 0xFF),
    245                                    (uint8_t)(j & 0xFF),
    246                                    (uint8_t)((i + j) & 0xFF),
    247                                    (uint8_t)((2 * j - i) & 0xFF));
    248     SkColor4f color4f = SkColor4f::FromColor(color);
    249     for (int i = 0; i < 4; i++) {
    250         if (color4f[i] > 0.5) {
    251             color4f[i] -= delta;
    252         } else {
    253             color4f[i] += delta;
    254         }
    255     }
    256     return color4f.premul().toBytes_RGBA();
    257 }
    258 
    259 void test_draw_op(GrContext* context,
    260                   GrRenderTargetContext* rtc,
    261                   std::unique_ptr<GrFragmentProcessor> fp,
    262                   sk_sp<GrTextureProxy> inputDataProxy) {
    263     GrPaint paint;
    264     paint.addColorTextureProcessor(std::move(inputDataProxy), SkMatrix::I());
    265     paint.addColorFragmentProcessor(std::move(fp));
    266     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    267 
    268     auto op = GrFillRectOp::Make(context, std::move(paint), GrAAType::kNone, SkMatrix::I(),
    269                                  SkRect::MakeWH(rtc->width(), rtc->height()));
    270     rtc->addDrawOp(GrNoClip(), std::move(op));
    271 }
    272 
    273 // This assumes that the output buffer will be the same size as inputDataProxy
    274 void render_fp(GrContext* context, GrRenderTargetContext* rtc, GrFragmentProcessor* fp,
    275                sk_sp<GrTextureProxy> inputDataProxy, GrColor* buffer) {
    276     int width = inputDataProxy->width();
    277     int height = inputDataProxy->height();
    278 
    279     // test_draw_op needs to take ownership of an FP, so give it a clone that it can own
    280     test_draw_op(context, rtc, fp->clone(), inputDataProxy);
    281     memset(buffer, 0x0, sizeof(GrColor) * width * height);
    282            rtc->readPixels(SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
    283                                              kPremul_SkAlphaType),
    284                            buffer, 0, 0, 0);
    285 }
    286 
    287 /** Initializes the two test texture proxies that are available to the FP test factories. */
    288 bool init_test_textures(GrProxyProvider* proxyProvider, SkRandom* random,
    289                         sk_sp<GrTextureProxy> proxies[2]) {
    290     static const int kTestTextureSize = 256;
    291 
    292     {
    293         // Put premul data into the RGBA texture that the test FPs can optionally use.
    294         std::unique_ptr<GrColor[]> rgbaData(new GrColor[kTestTextureSize * kTestTextureSize]);
    295         for (int y = 0; y < kTestTextureSize; ++y) {
    296             for (int x = 0; x < kTestTextureSize; ++x) {
    297                 rgbaData[kTestTextureSize * y + x] = input_texel_color(
    298                         random->nextULessThan(256), random->nextULessThan(256), 0.0f);
    299             }
    300         }
    301 
    302         SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize,
    303                                            kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    304         SkPixmap pixmap(ii, rgbaData.get(), ii.minRowBytes());
    305         sk_sp<SkImage> img = SkImage::MakeRasterCopy(pixmap);
    306         proxies[0] = proxyProvider->createTextureProxy(img, kNone_GrSurfaceFlags, 1,
    307                                                        SkBudgeted::kYes, SkBackingFit::kExact);
    308     }
    309 
    310     {
    311         // Put random values into the alpha texture that the test FPs can optionally use.
    312         std::unique_ptr<uint8_t[]> alphaData(new uint8_t[kTestTextureSize * kTestTextureSize]);
    313         for (int y = 0; y < kTestTextureSize; ++y) {
    314             for (int x = 0; x < kTestTextureSize; ++x) {
    315                 alphaData[kTestTextureSize * y + x] = random->nextULessThan(256);
    316             }
    317         }
    318 
    319         SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize,
    320                                            kAlpha_8_SkColorType, kPremul_SkAlphaType);
    321         SkPixmap pixmap(ii, alphaData.get(), ii.minRowBytes());
    322         sk_sp<SkImage> img = SkImage::MakeRasterCopy(pixmap);
    323         proxies[1] = proxyProvider->createTextureProxy(img, kNone_GrSurfaceFlags, 1,
    324                                                        SkBudgeted::kYes, SkBackingFit::kExact);
    325     }
    326 
    327     return proxies[0] && proxies[1];
    328 }
    329 
    330 // Creates a texture of premul colors used as the output of the fragment processor that precedes
    331 // the fragment processor under test. Color values are those provided by input_texel_color().
    332 sk_sp<GrTextureProxy> make_input_texture(GrProxyProvider* proxyProvider, int width, int height,
    333                                          SkScalar delta) {
    334     std::unique_ptr<GrColor[]> data(new GrColor[width * height]);
    335     for (int y = 0; y < width; ++y) {
    336         for (int x = 0; x < height; ++x) {
    337             data.get()[width * y + x] = input_texel_color(x, y, delta);
    338         }
    339     }
    340 
    341     SkImageInfo ii = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    342     SkPixmap pixmap(ii, data.get(), ii.minRowBytes());
    343     sk_sp<SkImage> img = SkImage::MakeRasterCopy(pixmap);
    344     return proxyProvider->createTextureProxy(img, kNone_GrSurfaceFlags, 1,
    345                                              SkBudgeted::kYes, SkBackingFit::kExact);
    346 }
    347 
    348 bool log_surface_context(sk_sp<GrSurfaceContext> src, SkString* dst) {
    349     SkImageInfo ii = SkImageInfo::Make(src->width(), src->height(), kRGBA_8888_SkColorType,
    350                                        kPremul_SkAlphaType);
    351     SkBitmap bm;
    352     SkAssertResult(bm.tryAllocPixels(ii));
    353     SkAssertResult(src->readPixels(ii, bm.getPixels(), bm.rowBytes(), 0, 0));
    354 
    355     return bitmap_to_base64_data_uri(bm, dst);
    356 }
    357 
    358 bool log_surface_proxy(GrContext* context, sk_sp<GrSurfaceProxy> src, SkString* dst) {
    359     sk_sp<GrSurfaceContext> sContext(context->priv().makeWrappedSurfaceContext(src));
    360     return log_surface_context(sContext, dst);
    361 }
    362 
    363 bool fuzzy_color_equals(const SkPMColor4f& c1, const SkPMColor4f& c2) {
    364     // With the loss of precision of rendering into 32-bit color, then estimating the FP's output
    365     // from that, it is not uncommon for a valid output to differ from estimate by up to 0.01
    366     // (really 1/128 ~ .0078, but frequently floating point issues make that tolerance a little
    367     // too unforgiving).
    368     static constexpr SkScalar kTolerance = 0.01f;
    369     for (int i = 0; i < 4; i++) {
    370         if (!SkScalarNearlyEqual(c1[i], c2[i], kTolerance)) {
    371             return false;
    372         }
    373     }
    374     return true;
    375 }
    376 
    377 int modulation_index(int channelIndex, bool alphaModulation) {
    378     return alphaModulation ? 3 : channelIndex;
    379 }
    380 
    381 // Given three input colors (color preceding the FP being tested), and the output of the FP, this
    382 // ensures that the out1 = fp * in1.a, out2 = fp * in2.a, and out3 = fp * in3.a, where fp is the
    383 // pre-modulated color that should not be changing across frames (FP's state doesn't change).
    384 //
    385 // When alphaModulation is false, this tests the very similar conditions that out1 = fp * in1,
    386 // etc. using per-channel modulation instead of modulation by just the input alpha channel.
    387 // - This estimates the pre-modulated fp color from one of the input/output pairs and confirms the
    388 //   conditions hold for the other two pairs.
    389 bool legal_modulation(const GrColor& in1, const GrColor& in2, const GrColor& in3,
    390                       const GrColor& out1, const GrColor& out2, const GrColor& out3,
    391                       bool alphaModulation) {
    392     // Convert to floating point, which is the number space the FP operates in (more or less)
    393     SkPMColor4f in1f = SkPMColor4f::FromBytes_RGBA(in1);
    394     SkPMColor4f in2f = SkPMColor4f::FromBytes_RGBA(in2);
    395     SkPMColor4f in3f = SkPMColor4f::FromBytes_RGBA(in3);
    396     SkPMColor4f out1f = SkPMColor4f::FromBytes_RGBA(out1);
    397     SkPMColor4f out2f = SkPMColor4f::FromBytes_RGBA(out2);
    398     SkPMColor4f out3f = SkPMColor4f::FromBytes_RGBA(out3);
    399 
    400     // Reconstruct the output of the FP before the shader modulated its color with the input value.
    401     // When the original input is very small, it may cause the final output color to round
    402     // to 0, in which case we estimate the pre-modulated color using one of the stepped frames that
    403     // will then have a guaranteed larger channel value (since the offset will be added to it).
    404     SkPMColor4f fpPreModulation;
    405     for (int i = 0; i < 4; i++) {
    406         int modulationIndex = modulation_index(i, alphaModulation);
    407         if (in1f[modulationIndex] < 0.2f) {
    408             // Use the stepped frame
    409             fpPreModulation[i] = out2f[i] / in2f[modulationIndex];
    410         } else {
    411             fpPreModulation[i] = out1f[i] / in1f[modulationIndex];
    412         }
    413     }
    414 
    415     // With reconstructed pre-modulated FP output, derive the expected value of fp * input for each
    416     // of the transformed input colors.
    417     SkPMColor4f expected1 = alphaModulation ? (fpPreModulation * in1f.fA)
    418                                             : (fpPreModulation * in1f);
    419     SkPMColor4f expected2 = alphaModulation ? (fpPreModulation * in2f.fA)
    420                                             : (fpPreModulation * in2f);
    421     SkPMColor4f expected3 = alphaModulation ? (fpPreModulation * in3f.fA)
    422                                             : (fpPreModulation * in3f);
    423 
    424     return fuzzy_color_equals(out1f, expected1) &&
    425            fuzzy_color_equals(out2f, expected2) &&
    426            fuzzy_color_equals(out3f, expected3);
    427 }
    428 
    429 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) {
    430     GrContext* context = ctxInfo.grContext();
    431     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
    432     auto resourceProvider = context->priv().resourceProvider();
    433     using FPFactory = GrFragmentProcessorTestFactory;
    434 
    435     uint32_t seed = FLAGS_processorSeed;
    436     if (FLAGS_randomProcessorTest) {
    437         std::random_device rd;
    438         seed = rd();
    439     }
    440     // If a non-deterministic bot fails this test, check the output to see what seed it used, then
    441     // use --processorSeed <seed> (without --randomProcessorTest) to reproduce.
    442     SkRandom random(seed);
    443 
    444     const GrBackendFormat format =
    445             context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
    446 
    447     // Make the destination context for the test.
    448     static constexpr int kRenderSize = 256;
    449     sk_sp<GrRenderTargetContext> rtc = context->priv().makeDeferredRenderTargetContext(
    450             format, SkBackingFit::kExact, kRenderSize, kRenderSize, kRGBA_8888_GrPixelConfig,
    451             nullptr);
    452 
    453     sk_sp<GrTextureProxy> proxies[2];
    454     if (!init_test_textures(proxyProvider, &random, proxies)) {
    455         ERRORF(reporter, "Could not create test textures");
    456         return;
    457     }
    458     GrProcessorTestData testData(&random, context, rtc.get(), proxies);
    459 
    460     // Coverage optimization uses three frames with a linearly transformed input texture.  The first
    461     // frame has no offset, second frames add .2 and .4, which should then be present as a fixed
    462     // difference between the frame outputs if the FP is properly following the modulation
    463     // requirements of the coverage optimization.
    464     static constexpr SkScalar kInputDelta = 0.2f;
    465     auto inputTexture1 = make_input_texture(proxyProvider, kRenderSize, kRenderSize, 0.0f);
    466     auto inputTexture2 = make_input_texture(proxyProvider, kRenderSize, kRenderSize, kInputDelta);
    467     auto inputTexture3 = make_input_texture(proxyProvider, kRenderSize, kRenderSize, 2*kInputDelta);
    468 
    469     // Encoded images are very verbose and this tests many potential images, so only export the
    470     // first failure (subsequent failures have a reasonable chance of being related).
    471     bool loggedFirstFailure = false;
    472     bool loggedFirstWarning = false;
    473 
    474     // Storage for the three frames required for coverage compatibility optimization. Each frame
    475     // uses the correspondingly numbered inputTextureX.
    476     std::unique_ptr<GrColor[]> readData1(new GrColor[kRenderSize * kRenderSize]);
    477     std::unique_ptr<GrColor[]> readData2(new GrColor[kRenderSize * kRenderSize]);
    478     std::unique_ptr<GrColor[]> readData3(new GrColor[kRenderSize * kRenderSize]);
    479 
    480     // Because processor factories configure themselves in random ways, this is not exhaustive.
    481     for (int i = 0; i < FPFactory::Count(); ++i) {
    482         int timesToInvokeFactory = 5;
    483         // Increase the number of attempts if the FP has child FPs since optimizations likely depend
    484         // on child optimizations being present.
    485         std::unique_ptr<GrFragmentProcessor> fp = FPFactory::MakeIdx(i, &testData);
    486         for (int j = 0; j < fp->numChildProcessors(); ++j) {
    487             // This value made a reasonable trade off between time and coverage when this test was
    488             // written.
    489             timesToInvokeFactory *= FPFactory::Count() / 2;
    490         }
    491 #if defined(__MSVC_RUNTIME_CHECKS)
    492         // This test is infuriatingly slow with MSVC runtime checks enabled
    493         timesToInvokeFactory = 1;
    494 #endif
    495         for (int j = 0; j < timesToInvokeFactory; ++j) {
    496             fp = FPFactory::MakeIdx(i, &testData);
    497             if (!fp->instantiate(resourceProvider)) {
    498                 continue;
    499             }
    500 
    501             if (!fp->hasConstantOutputForConstantInput() && !fp->preservesOpaqueInput() &&
    502                 !fp->compatibleWithCoverageAsAlpha()) {
    503                 continue;
    504             }
    505 
    506             if (fp->compatibleWithCoverageAsAlpha()) {
    507                 // 2nd and 3rd frames are only used when checking coverage optimization
    508                 render_fp(context, rtc.get(), fp.get(), inputTexture2, readData2.get());
    509                 render_fp(context, rtc.get(), fp.get(), inputTexture3, readData3.get());
    510             }
    511             // Draw base frame last so that rtc holds the original FP behavior if we need to
    512             // dump the image to the log.
    513             render_fp(context, rtc.get(), fp.get(), inputTexture1, readData1.get());
    514 
    515             if (0) {  // Useful to see what FPs are being tested.
    516                 SkString children;
    517                 for (int c = 0; c < fp->numChildProcessors(); ++c) {
    518                     if (!c) {
    519                         children.append("(");
    520                     }
    521                     children.append(fp->childProcessor(c).name());
    522                     children.append(c == fp->numChildProcessors() - 1 ? ")" : ", ");
    523                 }
    524                 SkDebugf("%s %s\n", fp->name(), children.c_str());
    525             }
    526 
    527             // This test has a history of being flaky on a number of devices. If an FP is logically
    528             // violating the optimizations, it's reasonable to expect it to violate requirements on
    529             // a large number of pixels in the image. Sporadic pixel violations are more indicative
    530             // of device errors and represents a separate problem.
    531 #if defined(SK_BUILD_FOR_SKQP)
    532             static constexpr int kMaxAcceptableFailedPixels = 0; // Strict when running as SKQP
    533 #else
    534             static constexpr int kMaxAcceptableFailedPixels = 2 * kRenderSize; // ~0.7% of the image
    535 #endif
    536 
    537             int failedPixelCount = 0;
    538             // Collect first optimization failure message, to be output later as a warning or an
    539             // error depending on whether the rendering "passed" or failed.
    540             SkString coverageMessage;
    541             SkString opaqueMessage;
    542             SkString constMessage;
    543             for (int y = 0; y < kRenderSize; ++y) {
    544                 for (int x = 0; x < kRenderSize; ++x) {
    545                     bool passing = true;
    546                     GrColor input = input_texel_color(x, y, 0.0f);
    547                     GrColor output = readData1.get()[y * kRenderSize + x];
    548 
    549                     if (fp->compatibleWithCoverageAsAlpha()) {
    550                         GrColor i2 = input_texel_color(x, y, kInputDelta);
    551                         GrColor i3 = input_texel_color(x, y, 2 * kInputDelta);
    552 
    553                         GrColor o2 = readData2.get()[y * kRenderSize + x];
    554                         GrColor o3 = readData3.get()[y * kRenderSize + x];
    555 
    556                         // A compatible processor is allowed to modulate either the input color or
    557                         // just the input alpha.
    558                         bool legalAlphaModulation = legal_modulation(input, i2, i3, output, o2, o3,
    559                                                                      /* alpha */ true);
    560                         bool legalColorModulation = legal_modulation(input, i2, i3, output, o2, o3,
    561                                                                      /* alpha */ false);
    562 
    563                         if (!legalColorModulation && !legalAlphaModulation) {
    564                             passing = false;
    565 
    566                             if (coverageMessage.isEmpty()) {
    567                                 coverageMessage.printf("\"Modulating\" processor %s did not match "
    568                                         "alpha-modulation nor color-modulation rules. "
    569                                         "Input: 0x%08x, Output: 0x%08x, pixel (%d, %d).",
    570                                         fp->name(), input, output, x, y);
    571                             }
    572                         }
    573                     }
    574 
    575                     SkPMColor4f input4f = SkPMColor4f::FromBytes_RGBA(input);
    576                     SkPMColor4f output4f = SkPMColor4f::FromBytes_RGBA(output);
    577                     SkPMColor4f expected4f;
    578                     if (fp->hasConstantOutputForConstantInput(input4f, &expected4f)) {
    579                         float rDiff = fabsf(output4f.fR - expected4f.fR);
    580                         float gDiff = fabsf(output4f.fG - expected4f.fG);
    581                         float bDiff = fabsf(output4f.fB - expected4f.fB);
    582                         float aDiff = fabsf(output4f.fA - expected4f.fA);
    583                         static constexpr float kTol = 4 / 255.f;
    584                         if (rDiff > kTol || gDiff > kTol || bDiff > kTol || aDiff > kTol) {
    585                             if (constMessage.isEmpty()) {
    586                                 passing = false;
    587 
    588                                 constMessage.printf("Processor %s claimed output for const input "
    589                                         "doesn't match actual output. Error: %f, Tolerance: %f, "
    590                                         "input: (%f, %f, %f, %f), actual: (%f, %f, %f, %f), "
    591                                         "expected(%f, %f, %f, %f)", fp->name(),
    592                                         SkTMax(rDiff, SkTMax(gDiff, SkTMax(bDiff, aDiff))), kTol,
    593                                         input4f.fR, input4f.fG, input4f.fB, input4f.fA,
    594                                         output4f.fR, output4f.fG, output4f.fB, output4f.fA,
    595                                         expected4f.fR, expected4f.fG, expected4f.fB, expected4f.fA);
    596                             }
    597                         }
    598                     }
    599                     if (input4f.isOpaque() && fp->preservesOpaqueInput() && !output4f.isOpaque()) {
    600                         passing = false;
    601 
    602                         if (opaqueMessage.isEmpty()) {
    603                             opaqueMessage.printf("Processor %s claimed opaqueness is preserved but "
    604                                     "it is not. Input: 0x%08x, Output: 0x%08x.",
    605                                     fp->name(), input, output);
    606                         }
    607                     }
    608 
    609                     if (!passing) {
    610                         // Regardless of how many optimizations the pixel violates, count it as a
    611                         // single bad pixel.
    612                         failedPixelCount++;
    613                     }
    614                 }
    615             }
    616 
    617             // Finished analyzing the entire image, see if the number of pixel failures meets the
    618             // threshold for an FP violating the optimization requirements.
    619             if (failedPixelCount > kMaxAcceptableFailedPixels) {
    620                 ERRORF(reporter, "Processor violated %d of %d pixels, seed: 0x%08x, processor: %s"
    621                        ", first failing pixel details are below:",
    622                        failedPixelCount, kRenderSize * kRenderSize, seed,
    623                        fp->dumpInfo().c_str());
    624 
    625                 // Print first failing pixel's details.
    626                 if (!coverageMessage.isEmpty()) {
    627                     ERRORF(reporter, coverageMessage.c_str());
    628                 }
    629                 if (!constMessage.isEmpty()) {
    630                     ERRORF(reporter, constMessage.c_str());
    631                 }
    632                 if (!opaqueMessage.isEmpty()) {
    633                     ERRORF(reporter, opaqueMessage.c_str());
    634                 }
    635 
    636                 if (!loggedFirstFailure) {
    637                     // Print with ERRORF to make sure the encoded image is output
    638                     SkString input;
    639                     log_surface_proxy(context, inputTexture1, &input);
    640                     SkString output;
    641                     log_surface_context(rtc, &output);
    642                     ERRORF(reporter, "Input image: %s\n\n"
    643                            "===========================================================\n\n"
    644                            "Output image: %s\n", input.c_str(), output.c_str());
    645                     loggedFirstFailure = true;
    646                 }
    647             } else if(failedPixelCount > 0) {
    648                 // Don't trigger an error, but don't just hide the failures either.
    649                 INFOF(reporter, "Processor violated %d of %d pixels (below error threshold), seed: "
    650                       "0x%08x, processor: %s", failedPixelCount, kRenderSize * kRenderSize,
    651                       seed, fp->dumpInfo().c_str());
    652                 if (!coverageMessage.isEmpty()) {
    653                     INFOF(reporter, coverageMessage.c_str());
    654                 }
    655                 if (!constMessage.isEmpty()) {
    656                     INFOF(reporter, constMessage.c_str());
    657                 }
    658                 if (!opaqueMessage.isEmpty()) {
    659                     INFOF(reporter, opaqueMessage.c_str());
    660                 }
    661                 if (!loggedFirstWarning) {
    662                     SkString input;
    663                     log_surface_proxy(context, inputTexture1, &input);
    664                     SkString output;
    665                     log_surface_context(rtc, &output);
    666                     INFOF(reporter, "Input image: %s\n\n"
    667                           "===========================================================\n\n"
    668                           "Output image: %s\n", input.c_str(), output.c_str());
    669                     loggedFirstWarning = true;
    670                 }
    671             }
    672         }
    673     }
    674 }
    675 
    676 // Tests that fragment processors returned by GrFragmentProcessor::clone() are equivalent to their
    677 // progenitors.
    678 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorCloneTest, reporter, ctxInfo) {
    679     GrContext* context = ctxInfo.grContext();
    680     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
    681     auto resourceProvider = context->priv().resourceProvider();
    682 
    683     SkRandom random;
    684 
    685     const GrBackendFormat format =
    686             context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
    687 
    688     // Make the destination context for the test.
    689     static constexpr int kRenderSize = 1024;
    690     sk_sp<GrRenderTargetContext> rtc = context->priv().makeDeferredRenderTargetContext(
    691             format, SkBackingFit::kExact, kRenderSize, kRenderSize, kRGBA_8888_GrPixelConfig,
    692             nullptr);
    693 
    694     sk_sp<GrTextureProxy> proxies[2];
    695     if (!init_test_textures(proxyProvider, &random, proxies)) {
    696         ERRORF(reporter, "Could not create test textures");
    697         return;
    698     }
    699     GrProcessorTestData testData(&random, context, rtc.get(), proxies);
    700 
    701     auto inputTexture = make_input_texture(proxyProvider, kRenderSize, kRenderSize, 0.0f);
    702     std::unique_ptr<GrColor[]> readData1(new GrColor[kRenderSize * kRenderSize]);
    703     std::unique_ptr<GrColor[]> readData2(new GrColor[kRenderSize * kRenderSize]);
    704     auto readInfo = SkImageInfo::Make(kRenderSize, kRenderSize, kRGBA_8888_SkColorType,
    705                                       kPremul_SkAlphaType);
    706 
    707     // Because processor factories configure themselves in random ways, this is not exhaustive.
    708     for (int i = 0; i < GrFragmentProcessorTestFactory::Count(); ++i) {
    709         static constexpr int kTimesToInvokeFactory = 10;
    710         for (int j = 0; j < kTimesToInvokeFactory; ++j) {
    711             auto fp = GrFragmentProcessorTestFactory::MakeIdx(i, &testData);
    712             auto clone = fp->clone();
    713             if (!clone) {
    714                 ERRORF(reporter, "Clone of processor %s failed.", fp->name());
    715                 continue;
    716             }
    717             const char* name = fp->name();
    718             if (!fp->instantiate(resourceProvider) || !clone->instantiate(resourceProvider)) {
    719                 continue;
    720             }
    721             REPORTER_ASSERT(reporter, !strcmp(fp->name(), clone->name()));
    722             REPORTER_ASSERT(reporter, fp->compatibleWithCoverageAsAlpha() ==
    723                                       clone->compatibleWithCoverageAsAlpha());
    724             REPORTER_ASSERT(reporter, fp->isEqual(*clone));
    725             REPORTER_ASSERT(reporter, fp->preservesOpaqueInput() == clone->preservesOpaqueInput());
    726             REPORTER_ASSERT(reporter, fp->hasConstantOutputForConstantInput() ==
    727                                       clone->hasConstantOutputForConstantInput());
    728             REPORTER_ASSERT(reporter, fp->numChildProcessors() == clone->numChildProcessors());
    729             REPORTER_ASSERT(reporter, fp->usesLocalCoords() == clone->usesLocalCoords());
    730             // Draw with original and read back the results.
    731             render_fp(context, rtc.get(), fp.get(), inputTexture, readData1.get());
    732 
    733             // Draw with clone and read back the results.
    734             render_fp(context, rtc.get(), clone.get(), inputTexture, readData2.get());
    735 
    736             // Check that the results are the same.
    737             bool passing = true;
    738             for (int y = 0; y < kRenderSize && passing; ++y) {
    739                 for (int x = 0; x < kRenderSize && passing; ++x) {
    740                     int idx = y * kRenderSize + x;
    741                     if (readData1[idx] != readData2[idx]) {
    742                         ERRORF(reporter,
    743                                "Processor %s made clone produced different output. "
    744                                "Input color: 0x%08x, Original Output Color: 0x%08x, "
    745                                "Clone Output Color: 0x%08x..",
    746                                name, input_texel_color(x, y, 0.0f), readData1[idx], readData2[idx]);
    747                         passing = false;
    748                     }
    749                 }
    750             }
    751         }
    752     }
    753 }
    754 
    755 #endif  // GR_TEST_UTILS
    756 #endif  // SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
    757