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 "GrGpuResource.h"
     16 #include "GrRenderTargetContext.h"
     17 #include "GrRenderTargetContextPriv.h"
     18 #include "GrResourceProvider.h"
     19 #include "glsl/GrGLSLFragmentProcessor.h"
     20 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     21 #include "ops/GrMeshDrawOp.h"
     22 #include "ops/GrRectOpFactory.h"
     23 
     24 namespace {
     25 class TestOp : public GrMeshDrawOp {
     26 public:
     27     DEFINE_OP_CLASS_ID
     28     const char* name() const override { return "TestOp"; }
     29 
     30     static std::unique_ptr<GrDrawOp> Make(sk_sp<GrFragmentProcessor> fp) {
     31         return std::unique_ptr<GrDrawOp>(new TestOp(std::move(fp)));
     32     }
     33 
     34     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
     35 
     36     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
     37         static constexpr GrProcessorAnalysisColor kUnknownColor;
     38         GrColor overrideColor;
     39         fProcessors.finalize(kUnknownColor, GrProcessorAnalysisCoverage::kNone, clip, false, caps,
     40                              &overrideColor);
     41         return RequiresDstTexture::kNo;
     42     }
     43 
     44 private:
     45     TestOp(sk_sp<GrFragmentProcessor> fp) : INHERITED(ClassID()), fProcessors(std::move(fp)) {
     46         this->setBounds(SkRect::MakeWH(100, 100), HasAABloat::kNo, IsZeroArea::kNo);
     47     }
     48 
     49     void onPrepareDraws(Target* target) const override { return; }
     50 
     51     bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
     52 
     53     GrProcessorSet fProcessors;
     54 
     55     typedef GrMeshDrawOp INHERITED;
     56 };
     57 
     58 /**
     59  * FP used to test ref/IO counts on owned GrGpuResources. Can also be a parent FP to test counts
     60  * of resources owned by child FPs.
     61  */
     62 class TestFP : public GrFragmentProcessor {
     63 public:
     64     struct Image {
     65         Image(sk_sp<GrTextureProxy> proxy, GrIOType ioType) : fProxy(proxy), fIOType(ioType) {}
     66         sk_sp<GrTextureProxy> fProxy;
     67         GrIOType fIOType;
     68     };
     69     static sk_sp<GrFragmentProcessor> Make(sk_sp<GrFragmentProcessor> child) {
     70         return sk_sp<GrFragmentProcessor>(new TestFP(std::move(child)));
     71     }
     72     static sk_sp<GrFragmentProcessor> Make(const SkTArray<sk_sp<GrTextureProxy>>& proxies,
     73                                            const SkTArray<sk_sp<GrBuffer>>& buffers,
     74                                            const SkTArray<Image>& images) {
     75         return sk_sp<GrFragmentProcessor>(new TestFP(proxies, buffers, images));
     76     }
     77 
     78     const char* name() const override { return "test"; }
     79 
     80     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
     81         // We don't really care about reusing these.
     82         static int32_t gKey = 0;
     83         b->add32(sk_atomic_inc(&gKey));
     84     }
     85 
     86 private:
     87     TestFP(const SkTArray<sk_sp<GrTextureProxy>>& proxies,
     88            const SkTArray<sk_sp<GrBuffer>>& buffers,
     89            const SkTArray<Image>& images)
     90             : INHERITED(kNone_OptimizationFlags), fSamplers(4), fBuffers(4), fImages(4) {
     91         for (const auto& proxy : proxies) {
     92             this->addTextureSampler(&fSamplers.emplace_back(proxy));
     93         }
     94         for (const auto& buffer : buffers) {
     95             this->addBufferAccess(&fBuffers.emplace_back(kRGBA_8888_GrPixelConfig, buffer.get()));
     96         }
     97         for (const Image& image : images) {
     98             fImages.emplace_back(image.fProxy, image.fIOType,
     99                                  GrSLMemoryModel::kNone, GrSLRestrict::kNo);
    100             this->addImageStorageAccess(&fImages.back());
    101         }
    102     }
    103 
    104     TestFP(sk_sp<GrFragmentProcessor> child)
    105             : INHERITED(kNone_OptimizationFlags), fSamplers(4), fBuffers(4), fImages(4) {
    106         this->registerChildProcessor(std::move(child));
    107     }
    108 
    109     virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
    110         class TestGLSLFP : public GrGLSLFragmentProcessor {
    111         public:
    112             TestGLSLFP() {}
    113             void emitCode(EmitArgs& args) override {
    114                 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    115                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor);
    116             }
    117 
    118         private:
    119         };
    120         return new TestGLSLFP();
    121     }
    122 
    123     bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
    124 
    125     GrTAllocator<TextureSampler> fSamplers;
    126     GrTAllocator<BufferAccess> fBuffers;
    127     GrTAllocator<ImageStorageAccess> fImages;
    128     typedef GrFragmentProcessor INHERITED;
    129 };
    130 }
    131 
    132 template <typename T>
    133 inline void testingOnly_getIORefCnts(const T* resource, int* refCnt, int* readCnt, int* writeCnt) {
    134     *refCnt = resource->fRefCnt;
    135     *readCnt = resource->fPendingReads;
    136     *writeCnt = resource->fPendingWrites;
    137 }
    138 
    139 void testingOnly_getIORefCnts(GrTextureProxy* proxy, int* refCnt, int* readCnt, int* writeCnt) {
    140     *refCnt = proxy->getBackingRefCnt_TestOnly();
    141     *readCnt = proxy->getPendingReadCnt_TestOnly();
    142     *writeCnt = proxy->getPendingWriteCnt_TestOnly();
    143 }
    144 
    145 DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) {
    146     GrContext* context = ctxInfo.grContext();
    147 
    148     GrTextureDesc desc;
    149     desc.fConfig = kRGBA_8888_GrPixelConfig;
    150     desc.fWidth = 10;
    151     desc.fHeight = 10;
    152 
    153     for (int parentCnt = 0; parentCnt < 2; parentCnt++) {
    154         sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
    155                 SkBackingFit::kApprox, 1, 1, kRGBA_8888_GrPixelConfig, nullptr));
    156         {
    157             bool texelBufferSupport = context->caps()->shaderCaps()->texelBufferSupport();
    158             bool imageLoadStoreSupport = context->caps()->shaderCaps()->imageLoadStoreSupport();
    159             sk_sp<GrTextureProxy> proxy1(GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
    160                                                                       desc, SkBackingFit::kExact,
    161                                                                       SkBudgeted::kYes));
    162             sk_sp<GrTextureProxy> proxy2(GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
    163                                                                       desc, SkBackingFit::kExact,
    164                                                                       SkBudgeted::kYes));
    165             sk_sp<GrTextureProxy> proxy3(GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
    166                                                                       desc, SkBackingFit::kExact,
    167                                                                       SkBudgeted::kYes));
    168             sk_sp<GrTextureProxy> proxy4(GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
    169                                                                       desc, SkBackingFit::kExact,
    170                                                                       SkBudgeted::kYes));
    171             sk_sp<GrBuffer> buffer(texelBufferSupport
    172                                            ? context->resourceProvider()->createBuffer(
    173                                                      1024, GrBufferType::kTexel_GrBufferType,
    174                                                      GrAccessPattern::kStatic_GrAccessPattern, 0)
    175                                            : nullptr);
    176             {
    177                 SkTArray<sk_sp<GrTextureProxy>> proxies;
    178                 SkTArray<sk_sp<GrBuffer>> buffers;
    179                 SkTArray<TestFP::Image> images;
    180                 proxies.push_back(proxy1);
    181                 if (texelBufferSupport) {
    182                     buffers.push_back(buffer);
    183                 }
    184                 if (imageLoadStoreSupport) {
    185                     images.emplace_back(proxy2, GrIOType::kRead_GrIOType);
    186                     images.emplace_back(proxy3, GrIOType::kWrite_GrIOType);
    187                     images.emplace_back(proxy4, GrIOType::kRW_GrIOType);
    188                 }
    189                 auto fp = TestFP::Make(std::move(proxies), std::move(buffers), std::move(images));
    190                 for (int i = 0; i < parentCnt; ++i) {
    191                     fp = TestFP::Make(std::move(fp));
    192                 }
    193                 std::unique_ptr<GrDrawOp> op(TestOp::Make(std::move(fp)));
    194                 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
    195             }
    196             int refCnt, readCnt, writeCnt;
    197 
    198             testingOnly_getIORefCnts(proxy1.get(), &refCnt, &readCnt, &writeCnt);
    199             REPORTER_ASSERT(reporter, 1 == refCnt);
    200             REPORTER_ASSERT(reporter, 1 == readCnt);
    201             REPORTER_ASSERT(reporter, 0 == writeCnt);
    202 
    203             if (texelBufferSupport) {
    204                 testingOnly_getIORefCnts(buffer.get(), &refCnt, &readCnt, &writeCnt);
    205                 REPORTER_ASSERT(reporter, 1 == refCnt);
    206                 REPORTER_ASSERT(reporter, 1 == readCnt);
    207                 REPORTER_ASSERT(reporter, 0 == writeCnt);
    208             }
    209 
    210             if (imageLoadStoreSupport) {
    211                 testingOnly_getIORefCnts(proxy2.get(), &refCnt, &readCnt, &writeCnt);
    212                 REPORTER_ASSERT(reporter, 1 == refCnt);
    213                 REPORTER_ASSERT(reporter, 1 == readCnt);
    214                 REPORTER_ASSERT(reporter, 0 == writeCnt);
    215 
    216                 testingOnly_getIORefCnts(proxy3.get(), &refCnt, &readCnt, &writeCnt);
    217                 REPORTER_ASSERT(reporter, 1 == refCnt);
    218                 REPORTER_ASSERT(reporter, 0 == readCnt);
    219                 REPORTER_ASSERT(reporter, 1 == writeCnt);
    220 
    221                 testingOnly_getIORefCnts(proxy4.get(), &refCnt, &readCnt, &writeCnt);
    222                 REPORTER_ASSERT(reporter, 1 == refCnt);
    223                 REPORTER_ASSERT(reporter, 1 == readCnt);
    224                 REPORTER_ASSERT(reporter, 1 == 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, 0 == readCnt);
    232             REPORTER_ASSERT(reporter, 0 == writeCnt);
    233 
    234             if (texelBufferSupport) {
    235                 testingOnly_getIORefCnts(buffer.get(), &refCnt, &readCnt, &writeCnt);
    236                 REPORTER_ASSERT(reporter, 1 == refCnt);
    237                 REPORTER_ASSERT(reporter, 0 == readCnt);
    238                 REPORTER_ASSERT(reporter, 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, 0 == readCnt);
    245                 REPORTER_ASSERT(reporter, 0 == writeCnt);
    246 
    247                 testingOnly_getIORefCnts(proxy3.get(), &refCnt, &readCnt, &writeCnt);
    248                 REPORTER_ASSERT(reporter, 1 == refCnt);
    249                 REPORTER_ASSERT(reporter, 0 == readCnt);
    250                 REPORTER_ASSERT(reporter, 0 == writeCnt);
    251 
    252                 testingOnly_getIORefCnts(proxy4.get(), &refCnt, &readCnt, &writeCnt);
    253                 REPORTER_ASSERT(reporter, 1 == refCnt);
    254                 REPORTER_ASSERT(reporter, 0 == readCnt);
    255                 REPORTER_ASSERT(reporter, 0 == writeCnt);
    256             }
    257         }
    258     }
    259 }
    260 
    261 // This test uses the random GrFragmentProcessor test factory, which relies on static initializers.
    262 #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
    263 
    264 static GrColor texel_color(int i, int j) {
    265     SkASSERT((unsigned)i < 256 && (unsigned)j < 256);
    266     GrColor color = GrColorPackRGBA(j, (uint8_t)(i + j), (uint8_t)(2 * j - i), i);
    267     return GrPremulColor(color);
    268 }
    269 
    270 static GrColor4f texel_color4f(int i, int j) { return GrColor4f::FromGrColor(texel_color(i, j)); }
    271 
    272 void test_draw_op(GrRenderTargetContext* rtc, sk_sp<GrFragmentProcessor> fp,
    273                   sk_sp<GrTextureProxy> inputDataProxy) {
    274     GrPaint paint;
    275     paint.addColorTextureProcessor(std::move(inputDataProxy), nullptr, SkMatrix::I());
    276     paint.addColorFragmentProcessor(std::move(fp));
    277     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
    278 
    279     auto op = GrRectOpFactory::MakeNonAAFill(std::move(paint), SkMatrix::I(),
    280                                              SkRect::MakeWH(rtc->width(), rtc->height()),
    281                                              GrAAType::kNone);
    282     rtc->addDrawOp(GrNoClip(), std::move(op));
    283 }
    284 
    285 #include "SkCommandLineFlags.h"
    286 DEFINE_bool(randomProcessorTest, false, "Use non-deterministic seed for random processor tests?");
    287 
    288 #if GR_TEST_UTILS
    289 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) {
    290     GrContext* context = ctxInfo.grContext();
    291     using FPFactory = GrProcessorTestFactory<GrFragmentProcessor>;
    292 
    293     uint32_t seed = 0;
    294     if (FLAGS_randomProcessorTest) {
    295         std::random_device rd;
    296         seed = rd();
    297     }
    298     // If a non-deterministic bot fails this test, check the output to see what seed it used, then
    299     // hard-code that value here:
    300     SkRandom random(seed);
    301 
    302     sk_sp<GrRenderTargetContext> rtc = context->makeDeferredRenderTargetContext(
    303             SkBackingFit::kExact, 256, 256, kRGBA_8888_GrPixelConfig, nullptr);
    304     GrSurfaceDesc desc;
    305     desc.fWidth = 256;
    306     desc.fHeight = 256;
    307     desc.fFlags = kRenderTarget_GrSurfaceFlag;
    308     desc.fConfig = kRGBA_8888_GrPixelConfig;
    309 
    310     sk_sp<GrTextureProxy> proxies[2];
    311 
    312     // Put premul data into the RGBA texture that the test FPs can optionally use.
    313     std::unique_ptr<GrColor[]> rgbaData(new GrColor[256 * 256]);
    314     for (int y = 0; y < 256; ++y) {
    315         for (int x = 0; x < 256; ++x) {
    316             rgbaData.get()[256 * y + x] =
    317                     texel_color(random.nextULessThan(256), random.nextULessThan(256));
    318         }
    319     }
    320     proxies[0] = GrSurfaceProxy::MakeDeferred(context->resourceProvider(), desc, SkBudgeted::kYes,
    321                                               rgbaData.get(), 256 * sizeof(GrColor));
    322 
    323     // Put random values into the alpha texture that the test FPs can optionally use.
    324     desc.fConfig = kAlpha_8_GrPixelConfig;
    325     std::unique_ptr<uint8_t[]> alphaData(new uint8_t[256 * 256]);
    326     for (int y = 0; y < 256; ++y) {
    327         for (int x = 0; x < 256; ++x) {
    328             alphaData.get()[256 * y + x] = random.nextULessThan(256);
    329         }
    330     }
    331     proxies[1] = GrSurfaceProxy::MakeDeferred(context->resourceProvider(), desc, SkBudgeted::kYes,
    332                                               alphaData.get(), 256);
    333 
    334     if (!proxies[0] || !proxies[1]) {
    335         return;
    336     }
    337 
    338     GrProcessorTestData testData(&random, context, rtc.get(), proxies);
    339 
    340     // Use a different array of premul colors for the output of the fragment processor that preceeds
    341     // the fragment processor under test.
    342     for (int y = 0; y < 256; ++y) {
    343         for (int x = 0; x < 256; ++x) {
    344             rgbaData.get()[256 * y + x] = texel_color(x, y);
    345         }
    346     }
    347     desc.fConfig = kRGBA_8888_GrPixelConfig;
    348 
    349     sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
    350                                                                    desc, SkBudgeted::kYes,
    351                                                                    rgbaData.get(),
    352                                                                    256 * sizeof(GrColor));
    353 
    354     // Because processors factories configure themselves in random ways, this is not exhaustive.
    355     for (int i = 0; i < FPFactory::Count(); ++i) {
    356         int timesToInvokeFactory = 5;
    357         // Increase the number of attempts if the FP has child FPs since optimizations likely depend
    358         // on child optimizations being present.
    359         sk_sp<GrFragmentProcessor> fp = FPFactory::MakeIdx(i, &testData);
    360         for (int j = 0; j < fp->numChildProcessors(); ++j) {
    361             // This value made a reasonable trade off between time and coverage when this test was
    362             // written.
    363             timesToInvokeFactory *= FPFactory::Count() / 2;
    364         }
    365         for (int j = 0; j < timesToInvokeFactory; ++j) {
    366             fp = FPFactory::MakeIdx(i, &testData);
    367             if (!fp->instantiate(context->resourceProvider())) {
    368                 continue;
    369             }
    370 
    371             if (!fp->hasConstantOutputForConstantInput() && !fp->preservesOpaqueInput() &&
    372                 !fp->compatibleWithCoverageAsAlpha()) {
    373                 continue;
    374             }
    375             test_draw_op(rtc.get(), fp, dataProxy);
    376             memset(rgbaData.get(), 0x0, sizeof(GrColor) * 256 * 256);
    377             rtc->readPixels(
    378                     SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
    379                     rgbaData.get(), 0, 0, 0);
    380             bool passing = true;
    381             if (0) {  // Useful to see what FPs are being tested.
    382                 SkString children;
    383                 for (int c = 0; c < fp->numChildProcessors(); ++c) {
    384                     if (!c) {
    385                         children.append("(");
    386                     }
    387                     children.append(fp->childProcessor(c).name());
    388                     children.append(c == fp->numChildProcessors() - 1 ? ")" : ", ");
    389                 }
    390                 SkDebugf("%s %s\n", fp->name(), children.c_str());
    391             }
    392             for (int y = 0; y < 256 && passing; ++y) {
    393                 for (int x = 0; x < 256 && passing; ++x) {
    394                     GrColor input = texel_color(x, y);
    395                     GrColor output = rgbaData.get()[y * 256 + x];
    396                     if (fp->compatibleWithCoverageAsAlpha()) {
    397                         // A modulating processor is allowed to modulate either the input color or
    398                         // just the input alpha.
    399                         bool legalColorModulation =
    400                                 GrColorUnpackA(output) <= GrColorUnpackA(input) &&
    401                                 GrColorUnpackR(output) <= GrColorUnpackR(input) &&
    402                                 GrColorUnpackG(output) <= GrColorUnpackG(input) &&
    403                                 GrColorUnpackB(output) <= GrColorUnpackB(input);
    404                         bool legalAlphaModulation =
    405                                 GrColorUnpackA(output) <= GrColorUnpackA(input) &&
    406                                 GrColorUnpackR(output) <= GrColorUnpackA(input) &&
    407                                 GrColorUnpackG(output) <= GrColorUnpackA(input) &&
    408                                 GrColorUnpackB(output) <= GrColorUnpackA(input);
    409                         if (!legalColorModulation && !legalAlphaModulation) {
    410                             ERRORF(reporter,
    411                                    "\"Modulating\" processor %s made color/alpha value larger. "
    412                                    "Input: 0x%08x, Output: 0x%08x.",
    413                                    fp->name(), input, output);
    414                             passing = false;
    415                         }
    416                     }
    417                     GrColor4f input4f = texel_color4f(x, y);
    418                     GrColor4f output4f = GrColor4f::FromGrColor(output);
    419                     GrColor4f expected4f;
    420                     if (fp->hasConstantOutputForConstantInput(input4f, &expected4f)) {
    421                         float rDiff = fabsf(output4f.fRGBA[0] - expected4f.fRGBA[0]);
    422                         float gDiff = fabsf(output4f.fRGBA[1] - expected4f.fRGBA[1]);
    423                         float bDiff = fabsf(output4f.fRGBA[2] - expected4f.fRGBA[2]);
    424                         float aDiff = fabsf(output4f.fRGBA[3] - expected4f.fRGBA[3]);
    425                         static constexpr float kTol = 4 / 255.f;
    426                         if (rDiff > kTol || gDiff > kTol || bDiff > kTol || aDiff > kTol) {
    427                             ERRORF(reporter,
    428                                    "Processor %s claimed output for const input doesn't match "
    429                                    "actual output. Error: %f, Tolerance: %f, input: (%f, %f, %f, "
    430                                    "%f), actual: (%f, %f, %f, %f), expected(%f, %f, %f, %f)",
    431                                    fp->name(), SkTMax(rDiff, SkTMax(gDiff, SkTMax(bDiff, aDiff))),
    432                                    kTol, input4f.fRGBA[0], input4f.fRGBA[1], input4f.fRGBA[2],
    433                                    input4f.fRGBA[3], output4f.fRGBA[0], output4f.fRGBA[1],
    434                                    output4f.fRGBA[2], output4f.fRGBA[3], expected4f.fRGBA[0],
    435                                    expected4f.fRGBA[1], expected4f.fRGBA[2], expected4f.fRGBA[3]);
    436                             passing = false;
    437                         }
    438                     }
    439                     if (GrColorIsOpaque(input) && fp->preservesOpaqueInput() &&
    440                         !GrColorIsOpaque(output)) {
    441                         ERRORF(reporter,
    442                                "Processor %s claimed opaqueness is preserved but it is not. Input: "
    443                                "0x%08x, Output: 0x%08x.",
    444                                fp->name(), input, output);
    445                         passing = false;
    446                     }
    447                     if (!passing) {
    448                         ERRORF(reporter, "Seed: 0x%08x, Processor details: %s",
    449                                seed, fp->dumpInfo().c_str());
    450                     }
    451                 }
    452             }
    453         }
    454     }
    455 }
    456 
    457 #endif  // GR_TEST_UTILS
    458 #endif  // SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
    459 #endif  // SK_SUPPORT_GPU
    460