Home | History | Annotate | Download | only in tests
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 // This is a GPU-backend specific test. It relies on static intializers to work
     10 
     11 #include "SkTypes.h"
     12 
     13 #if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
     14 
     15 #include "GrAutoLocaleSetter.h"
     16 #include "GrBatchTest.h"
     17 #include "GrContextFactory.h"
     18 #include "GrDrawContext.h"
     19 #include "GrDrawingManager.h"
     20 #include "GrInvariantOutput.h"
     21 #include "GrPipeline.h"
     22 #include "GrResourceProvider.h"
     23 #include "GrTest.h"
     24 #include "GrXferProcessor.h"
     25 #include "SkChecksum.h"
     26 #include "SkRandom.h"
     27 #include "Test.h"
     28 
     29 #include "batches/GrDrawBatch.h"
     30 
     31 #include "effects/GrConfigConversionEffect.h"
     32 #include "effects/GrPorterDuffXferProcessor.h"
     33 #include "effects/GrXfermodeFragmentProcessor.h"
     34 
     35 #include "gl/GrGLGpu.h"
     36 #include "glsl/GrGLSLFragmentProcessor.h"
     37 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     38 #include "glsl/GrGLSLProgramBuilder.h"
     39 
     40 /*
     41  * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
     42  * whole thing correctly
     43  */
     44 static const uint32_t kMaxKeySize = 1024;
     45 
     46 class GLBigKeyProcessor : public GrGLSLFragmentProcessor {
     47 public:
     48     void emitCode(EmitArgs& args) override {
     49         // pass through
     50         GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
     51         if (args.fInputColor) {
     52             fragBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, args.fInputColor);
     53         } else {
     54             fragBuilder->codeAppendf("%s = vec4(1.0);\n", args.fOutputColor);
     55         }
     56     }
     57 
     58     static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
     59         for (uint32_t i = 0; i < kMaxKeySize; i++) {
     60             b->add32(i);
     61         }
     62     }
     63 
     64 private:
     65     typedef GrGLSLFragmentProcessor INHERITED;
     66 };
     67 
     68 class BigKeyProcessor : public GrFragmentProcessor {
     69 public:
     70     static GrFragmentProcessor* Create() {
     71         return new BigKeyProcessor;
     72     }
     73 
     74     const char* name() const override { return "Big Ole Key"; }
     75 
     76     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
     77         return new GLBigKeyProcessor;
     78     }
     79 
     80 private:
     81     BigKeyProcessor() {
     82         this->initClassID<BigKeyProcessor>();
     83     }
     84     virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
     85                                        GrProcessorKeyBuilder* b) const override {
     86         GLBigKeyProcessor::GenKey(*this, caps, b);
     87     }
     88     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
     89     void onComputeInvariantOutput(GrInvariantOutput* inout) const override { }
     90 
     91     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
     92 
     93     typedef GrFragmentProcessor INHERITED;
     94 };
     95 
     96 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
     97 
     98 const GrFragmentProcessor* BigKeyProcessor::TestCreate(GrProcessorTestData*) {
     99     return BigKeyProcessor::Create();
    100 }
    101 
    102 //////////////////////////////////////////////////////////////////////////////
    103 
    104 class BlockInputFragmentProcessor : public GrFragmentProcessor {
    105 public:
    106     static GrFragmentProcessor* Create(const GrFragmentProcessor* fp) {
    107         return new BlockInputFragmentProcessor(fp);
    108     }
    109 
    110     const char* name() const override { return "Block Input"; }
    111 
    112     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLFP; }
    113 
    114 private:
    115     class GLFP : public GrGLSLFragmentProcessor {
    116     public:
    117         void emitCode(EmitArgs& args) override {
    118             this->emitChild(0, nullptr, args);
    119         }
    120 
    121     private:
    122         typedef GrGLSLFragmentProcessor INHERITED;
    123     };
    124 
    125     BlockInputFragmentProcessor(const GrFragmentProcessor* child) {
    126         this->initClassID<BlockInputFragmentProcessor>();
    127         this->registerChildProcessor(child);
    128     }
    129 
    130     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {}
    131 
    132     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
    133 
    134     void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
    135         inout->setToOther(kRGBA_GrColorComponentFlags, GrColor_WHITE,
    136                           GrInvariantOutput::kWillNot_ReadInput);
    137         this->childProcessor(0).computeInvariantOutput(inout);
    138     }
    139 
    140     typedef GrFragmentProcessor INHERITED;
    141 };
    142 
    143 //////////////////////////////////////////////////////////////////////////////
    144 
    145 /*
    146  * Begin test code
    147  */
    148 static const int kRenderTargetHeight = 1;
    149 static const int kRenderTargetWidth = 1;
    150 
    151 static GrRenderTarget* random_render_target(GrTextureProvider* textureProvider, SkRandom* random,
    152                                             const GrCaps* caps) {
    153     // setup render target
    154     GrTextureParams params;
    155     GrSurfaceDesc texDesc;
    156     texDesc.fWidth = kRenderTargetWidth;
    157     texDesc.fHeight = kRenderTargetHeight;
    158     texDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    159     texDesc.fConfig = kRGBA_8888_GrPixelConfig;
    160     texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin :
    161                                                    kBottomLeft_GrSurfaceOrigin;
    162     texDesc.fSampleCnt = random->nextBool() == true ? SkTMin(4, caps->maxSampleCount()) : 0;
    163 
    164     GrUniqueKey key;
    165     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
    166     GrUniqueKey::Builder builder(&key, kDomain, 2);
    167     builder[0] = texDesc.fOrigin;
    168     builder[1] = texDesc.fSampleCnt;
    169     builder.finish();
    170 
    171     GrTexture* texture = textureProvider->findAndRefTextureByUniqueKey(key);
    172     if (!texture) {
    173         texture = textureProvider->createTexture(texDesc, SkBudgeted::kYes);
    174         if (texture) {
    175             textureProvider->assignUniqueKeyToTexture(key, texture);
    176         }
    177     }
    178     return texture ? texture->asRenderTarget() : nullptr;
    179 }
    180 
    181 static void set_random_xpf(GrPipelineBuilder* pipelineBuilder, GrProcessorTestData* d) {
    182     SkAutoTUnref<const GrXPFactory> xpf(GrProcessorTestFactory<GrXPFactory>::Create(d));
    183     SkASSERT(xpf);
    184     pipelineBuilder->setXPFactory(xpf.get());
    185 }
    186 
    187 static const GrFragmentProcessor* create_random_proc_tree(GrProcessorTestData* d,
    188                                                            int minLevels, int maxLevels) {
    189     SkASSERT(1 <= minLevels);
    190     SkASSERT(minLevels <= maxLevels);
    191 
    192     // Return a leaf node if maxLevels is 1 or if we randomly chose to terminate.
    193     // If returning a leaf node, make sure that it doesn't have children (e.g. another
    194     // GrComposeEffect)
    195     const float terminateProbability = 0.3f;
    196     if (1 == minLevels) {
    197         bool terminate = (1 == maxLevels) || (d->fRandom->nextF() < terminateProbability);
    198         if (terminate) {
    199             const GrFragmentProcessor* fp;
    200             while (true) {
    201                 fp = GrProcessorTestFactory<GrFragmentProcessor>::Create(d);
    202                 SkASSERT(fp);
    203                 if (0 == fp->numChildProcessors()) {
    204                     break;
    205                 }
    206                 fp->unref();
    207             }
    208             return fp;
    209         }
    210     }
    211     // If we didn't terminate, choose either the left or right subtree to fulfill
    212     // the minLevels requirement of this tree; the other child can have as few levels as it wants.
    213     // Also choose a random xfer mode that's supported by CreateFrom2Procs().
    214     if (minLevels > 1) {
    215         --minLevels;
    216     }
    217     SkAutoTUnref<const GrFragmentProcessor> minLevelsChild(create_random_proc_tree(d, minLevels,
    218                                                                                    maxLevels - 1));
    219     SkAutoTUnref<const GrFragmentProcessor> otherChild(create_random_proc_tree(d, 1,
    220                                                                                maxLevels - 1));
    221     SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(d->fRandom->nextRangeU(0,
    222                                                           SkXfermode::kLastCoeffMode));
    223     const GrFragmentProcessor* fp;
    224     if (d->fRandom->nextF() < 0.5f) {
    225         fp = GrXfermodeFragmentProcessor::CreateFromTwoProcessors(minLevelsChild, otherChild, mode);
    226         SkASSERT(fp);
    227     } else {
    228         fp = GrXfermodeFragmentProcessor::CreateFromTwoProcessors(otherChild, minLevelsChild, mode);
    229         SkASSERT(fp);
    230     }
    231     return fp;
    232 }
    233 
    234 static void set_random_color_coverage_stages(GrPipelineBuilder* pipelineBuilder,
    235                                              GrProcessorTestData* d, int maxStages) {
    236     // Randomly choose to either create a linear pipeline of procs or create one proc tree
    237     const float procTreeProbability = 0.5f;
    238     if (d->fRandom->nextF() < procTreeProbability) {
    239         // A full tree with 5 levels (31 nodes) may exceed the max allowed length of the gl
    240         // processor key; maxTreeLevels should be a number from 1 to 4 inclusive.
    241         const int maxTreeLevels = 4;
    242         SkAutoTUnref<const GrFragmentProcessor> fp(
    243                                         create_random_proc_tree(d, 2, maxTreeLevels));
    244         pipelineBuilder->addColorFragmentProcessor(fp);
    245     } else {
    246         int numProcs = d->fRandom->nextULessThan(maxStages + 1);
    247         int numColorProcs = d->fRandom->nextULessThan(numProcs + 1);
    248 
    249         for (int s = 0; s < numProcs;) {
    250             SkAutoTUnref<const GrFragmentProcessor> fp(
    251                 GrProcessorTestFactory<GrFragmentProcessor>::Create(d));
    252             SkASSERT(fp);
    253 
    254             // finally add the stage to the correct pipeline in the drawstate
    255             if (s < numColorProcs) {
    256                 pipelineBuilder->addColorFragmentProcessor(fp);
    257             } else {
    258                 pipelineBuilder->addCoverageFragmentProcessor(fp);
    259             }
    260             ++s;
    261         }
    262     }
    263 }
    264 
    265 static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
    266     int state = 0;
    267     for (int i = 1; i <= GrPipelineBuilder::kLast_Flag; i <<= 1) {
    268         state |= random->nextBool() * i;
    269     }
    270 
    271     // If we don't have an MSAA rendertarget then we have to disable useHWAA
    272     if ((state | GrPipelineBuilder::kHWAntialias_Flag) &&
    273         !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled()) {
    274         state &= ~GrPipelineBuilder::kHWAntialias_Flag;
    275     }
    276     pipelineBuilder->enableState(state);
    277 }
    278 
    279 // right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
    280 static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
    281     GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
    282                                  kReplace_StencilOp,
    283                                  kReplace_StencilOp,
    284                                  kAlways_StencilFunc,
    285                                  0xffff,
    286                                  0xffff,
    287                                  0xffff);
    288     GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil,
    289                                  kKeep_StencilOp,
    290                                  kKeep_StencilOp,
    291                                  kNever_StencilFunc,
    292                                  0xffff,
    293                                  0xffff,
    294                                  0xffff);
    295 
    296     if (random->nextBool()) {
    297         pipelineBuilder->setStencil(kDoesWriteStencil);
    298     } else {
    299         pipelineBuilder->setStencil(kDoesNotWriteStencil);
    300     }
    301 }
    302 
    303 bool GrDrawingManager::ProgramUnitTest(GrContext* context, int maxStages) {
    304     GrDrawingManager* drawingManager = context->drawingManager();
    305 
    306     // setup dummy textures
    307     GrSurfaceDesc dummyDesc;
    308     dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    309     dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    310     dummyDesc.fWidth = 34;
    311     dummyDesc.fHeight = 18;
    312     SkAutoTUnref<GrTexture> dummyTexture1(
    313         context->textureProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0));
    314     dummyDesc.fFlags = kNone_GrSurfaceFlags;
    315     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    316     dummyDesc.fWidth = 16;
    317     dummyDesc.fHeight = 22;
    318     SkAutoTUnref<GrTexture> dummyTexture2(
    319         context->textureProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0));
    320 
    321     if (!dummyTexture1 || ! dummyTexture2) {
    322         SkDebugf("Could not allocate dummy textures");
    323         return false;
    324     }
    325 
    326     GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
    327 
    328     // dummy scissor state
    329     GrScissorState scissor;
    330 
    331     // wide open clip
    332     GrClip clip;
    333 
    334     SkRandom random;
    335     static const int NUM_TESTS = 2048;
    336     for (int t = 0; t < NUM_TESTS; t++) {
    337         // setup random render target(can fail)
    338         SkAutoTUnref<GrRenderTarget> rt(random_render_target(
    339             context->textureProvider(), &random, context->caps()));
    340         if (!rt.get()) {
    341             SkDebugf("Could not allocate render target");
    342             return false;
    343         }
    344 
    345         GrPipelineBuilder pipelineBuilder;
    346         pipelineBuilder.setRenderTarget(rt.get());
    347         pipelineBuilder.setClip(clip);
    348 
    349         SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context));
    350         SkASSERT(batch);
    351 
    352         GrProcessorTestData ptd(&random, context, context->caps(), rt, dummyTextures);
    353         set_random_color_coverage_stages(&pipelineBuilder, &ptd, maxStages);
    354         set_random_xpf(&pipelineBuilder, &ptd);
    355         set_random_state(&pipelineBuilder, &random);
    356         set_random_stencil(&pipelineBuilder, &random);
    357 
    358         SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
    359         if (!drawContext) {
    360             SkDebugf("Could not allocate drawContext");
    361             return false;
    362         }
    363 
    364         drawContext->internal_drawBatch(pipelineBuilder, batch);
    365     }
    366     // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
    367     drawingManager->flush();
    368 
    369     // Validate that GrFPs work correctly without an input.
    370     GrSurfaceDesc rtDesc;
    371     rtDesc.fWidth = kRenderTargetWidth;
    372     rtDesc.fHeight = kRenderTargetHeight;
    373     rtDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    374     rtDesc.fConfig = kRGBA_8888_GrPixelConfig;
    375     SkAutoTUnref<GrRenderTarget> rt(
    376         context->textureProvider()->createTexture(rtDesc, SkBudgeted::kNo)->asRenderTarget());
    377     int fpFactoryCnt = GrProcessorTestFactory<GrFragmentProcessor>::Count();
    378     for (int i = 0; i < fpFactoryCnt; ++i) {
    379         // Since FP factories internally randomize, call each 10 times.
    380         for (int j = 0; j < 10; ++j) {
    381             SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context));
    382             SkASSERT(batch);
    383             GrProcessorTestData ptd(&random, context, context->caps(), rt, dummyTextures);
    384             GrPipelineBuilder builder;
    385             builder.setXPFactory(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
    386             builder.setRenderTarget(rt);
    387             builder.setClip(clip);
    388 
    389             SkAutoTUnref<const GrFragmentProcessor> fp(
    390                 GrProcessorTestFactory<GrFragmentProcessor>::CreateIdx(i, &ptd));
    391             SkAutoTUnref<const GrFragmentProcessor> blockFP(
    392                 BlockInputFragmentProcessor::Create(fp));
    393             builder.addColorFragmentProcessor(blockFP);
    394 
    395             SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
    396             if (!drawContext) {
    397                 SkDebugf("Could not allocate a drawcontext");
    398                 return false;
    399             }
    400 
    401             drawContext->internal_drawBatch(builder, batch);
    402             drawingManager->flush();
    403         }
    404     }
    405 
    406     return true;
    407 }
    408 
    409 static int get_glprograms_max_stages(GrContext* context) {
    410     GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());
    411     /*
    412      * For the time being, we only support the test with desktop GL or for android on
    413      * ARM platforms
    414      * TODO When we run ES 3.00 GLSL in more places, test again
    415      */
    416     if (kGL_GrGLStandard == gpu->glStandard() ||
    417         kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
    418         return 6;
    419     } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
    420                kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
    421         return 1;
    422     }
    423     return 0;
    424 }
    425 
    426 static void test_glprograms_native(skiatest::Reporter* reporter, GrContext* context) {
    427     int maxStages = get_glprograms_max_stages(context);
    428     if (maxStages == 0) {
    429         return;
    430     }
    431     REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(context, maxStages));
    432 }
    433 
    434 static void test_glprograms_other_contexts(skiatest::Reporter* reporter, GrContext* context) {
    435     int maxStages = get_glprograms_max_stages(context);
    436 #ifdef SK_BUILD_FOR_WIN
    437     // Some long shaders run out of temporary registers in the D3D compiler on ANGLE and
    438     // command buffer.
    439     maxStages = SkTMin(maxStages, 2);
    440 #endif
    441     if (maxStages == 0) {
    442         return;
    443     }
    444     REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(context, maxStages));
    445 }
    446 
    447 DEF_GPUTEST(GLPrograms, reporter, /*factory*/) {
    448     // Set a locale that would cause shader compilation to fail because of , as decimal separator.
    449     // skbug 3330
    450 #ifdef SK_BUILD_FOR_WIN
    451     GrAutoLocaleSetter als("sv-SE");
    452 #else
    453     GrAutoLocaleSetter als("sv_SE.UTF-8");
    454 #endif
    455 
    456     // We suppress prints to avoid spew
    457     GrContextOptions opts;
    458     opts.fSuppressPrints = true;
    459     GrContextFactory debugFactory(opts);
    460     skiatest::RunWithGPUTestContexts(test_glprograms_native, skiatest::kNative_GPUTestContexts,
    461                                      reporter, &debugFactory);
    462     skiatest::RunWithGPUTestContexts(test_glprograms_other_contexts,
    463                                      skiatest::kOther_GPUTestContexts, reporter, &debugFactory);
    464 }
    465 
    466 #endif
    467