Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2011 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 // This is a GPU-backend specific test. It relies on static intializers to work
      9 
     10 #include "SkTypes.h"
     11 
     12 #if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
     13 
     14 #include "GrAutoLocaleSetter.h"
     15 #include "GrContextFactory.h"
     16 #include "GrContextPriv.h"
     17 #include "GrDrawOpTest.h"
     18 #include "GrDrawingManager.h"
     19 #include "GrPipeline.h"
     20 #include "GrRenderTargetContextPriv.h"
     21 #include "GrTest.h"
     22 #include "GrXferProcessor.h"
     23 #include "SkChecksum.h"
     24 #include "SkRandom.h"
     25 #include "Test.h"
     26 
     27 #include "ops/GrDrawOp.h"
     28 
     29 #include "effects/GrConfigConversionEffect.h"
     30 #include "effects/GrPorterDuffXferProcessor.h"
     31 #include "effects/GrXfermodeFragmentProcessor.h"
     32 
     33 #include "gl/GrGLGpu.h"
     34 #include "glsl/GrGLSLFragmentProcessor.h"
     35 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     36 #include "glsl/GrGLSLProgramBuilder.h"
     37 
     38 /*
     39  * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
     40  * whole thing correctly
     41  */
     42 static const uint32_t kMaxKeySize = 1024;
     43 
     44 class GLBigKeyProcessor : public GrGLSLFragmentProcessor {
     45 public:
     46     void emitCode(EmitArgs& args) override {
     47         // pass through
     48         GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
     49         if (args.fInputColor) {
     50             fragBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, args.fInputColor);
     51         } else {
     52             fragBuilder->codeAppendf("%s = vec4(1.0);\n", args.fOutputColor);
     53         }
     54     }
     55 
     56     static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
     57         for (uint32_t i = 0; i < kMaxKeySize; i++) {
     58             b->add32(i);
     59         }
     60     }
     61 
     62 private:
     63     typedef GrGLSLFragmentProcessor INHERITED;
     64 };
     65 
     66 class BigKeyProcessor : public GrFragmentProcessor {
     67 public:
     68     static std::unique_ptr<GrFragmentProcessor> Make() {
     69         return std::unique_ptr<GrFragmentProcessor>(new BigKeyProcessor);
     70     }
     71 
     72     const char* name() const override { return "Big Ole Key"; }
     73 
     74     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
     75         return new GLBigKeyProcessor;
     76     }
     77 
     78     std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
     79 
     80 private:
     81     BigKeyProcessor() : INHERITED(kBigKeyProcessor_ClassID, kNone_OptimizationFlags) { }
     82     virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
     83                                        GrProcessorKeyBuilder* b) const override {
     84         GLBigKeyProcessor::GenKey(*this, caps, b);
     85     }
     86     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
     87 
     88     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
     89 
     90     typedef GrFragmentProcessor INHERITED;
     91 };
     92 
     93 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
     94 
     95 #if GR_TEST_UTILS
     96 std::unique_ptr<GrFragmentProcessor> BigKeyProcessor::TestCreate(GrProcessorTestData*) {
     97     return BigKeyProcessor::Make();
     98 }
     99 #endif
    100 
    101 //////////////////////////////////////////////////////////////////////////////
    102 
    103 class BlockInputFragmentProcessor : public GrFragmentProcessor {
    104 public:
    105     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
    106         return std::unique_ptr<GrFragmentProcessor>(new BlockInputFragmentProcessor(std::move(fp)));
    107     }
    108 
    109     const char* name() const override { return "Block Input"; }
    110 
    111     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLFP; }
    112 
    113     std::unique_ptr<GrFragmentProcessor> clone() const override {
    114         return Make(this->childProcessor(0).clone());
    115     }
    116 
    117 private:
    118     class GLFP : public GrGLSLFragmentProcessor {
    119     public:
    120         void emitCode(EmitArgs& args) override {
    121             this->emitChild(0, args);
    122         }
    123 
    124     private:
    125         typedef GrGLSLFragmentProcessor INHERITED;
    126     };
    127 
    128     BlockInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> child)
    129             : INHERITED(kBlockInputFragmentProcessor_ClassID, kNone_OptimizationFlags) {
    130         this->registerChildProcessor(std::move(child));
    131     }
    132 
    133     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {}
    134 
    135     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
    136 
    137     typedef GrFragmentProcessor INHERITED;
    138 };
    139 
    140 //////////////////////////////////////////////////////////////////////////////
    141 
    142 /*
    143  * Begin test code
    144  */
    145 static const int kRenderTargetHeight = 1;
    146 static const int kRenderTargetWidth = 1;
    147 
    148 static sk_sp<GrRenderTargetContext> random_render_target_context(GrContext* context,
    149                                                                  SkRandom* random,
    150                                                                  const GrCaps* caps) {
    151     GrSurfaceOrigin origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin
    152                                                 : kBottomLeft_GrSurfaceOrigin;
    153     int sampleCnt =
    154             random->nextBool() ? caps->getRenderTargetSampleCount(2, kRGBA_8888_GrPixelConfig) : 1;
    155     // Above could be 0 if msaa isn't supported.
    156     sampleCnt = SkTMax(1, sampleCnt);
    157 
    158     sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
    159                                                                            SkBackingFit::kExact,
    160                                                                            kRenderTargetWidth,
    161                                                                            kRenderTargetHeight,
    162                                                                            kRGBA_8888_GrPixelConfig,
    163                                                                            nullptr,
    164                                                                            sampleCnt,
    165                                                                            GrMipMapped::kNo,
    166                                                                            origin));
    167     return renderTargetContext;
    168 }
    169 
    170 #if GR_TEST_UTILS
    171 static void set_random_xpf(GrPaint* paint, GrProcessorTestData* d) {
    172     paint->setXPFactory(GrXPFactoryTestFactory::Get(d));
    173 }
    174 
    175 static std::unique_ptr<GrFragmentProcessor> create_random_proc_tree(GrProcessorTestData* d,
    176                                                                     int minLevels, int maxLevels) {
    177     SkASSERT(1 <= minLevels);
    178     SkASSERT(minLevels <= maxLevels);
    179 
    180     // Return a leaf node if maxLevels is 1 or if we randomly chose to terminate.
    181     // If returning a leaf node, make sure that it doesn't have children (e.g. another
    182     // GrComposeEffect)
    183     const float terminateProbability = 0.3f;
    184     if (1 == minLevels) {
    185         bool terminate = (1 == maxLevels) || (d->fRandom->nextF() < terminateProbability);
    186         if (terminate) {
    187             std::unique_ptr<GrFragmentProcessor> fp;
    188             while (true) {
    189                 fp = GrFragmentProcessorTestFactory::Make(d);
    190                 SkASSERT(fp);
    191                 if (0 == fp->numChildProcessors()) {
    192                     break;
    193                 }
    194             }
    195             return fp;
    196         }
    197     }
    198     // If we didn't terminate, choose either the left or right subtree to fulfill
    199     // the minLevels requirement of this tree; the other child can have as few levels as it wants.
    200     // Also choose a random xfer mode.
    201     if (minLevels > 1) {
    202         --minLevels;
    203     }
    204     auto minLevelsChild = create_random_proc_tree(d, minLevels, maxLevels - 1);
    205     std::unique_ptr<GrFragmentProcessor> otherChild(create_random_proc_tree(d, 1, maxLevels - 1));
    206     SkBlendMode mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0,
    207                                                                (int)SkBlendMode::kLastMode));
    208     std::unique_ptr<GrFragmentProcessor> fp;
    209     if (d->fRandom->nextF() < 0.5f) {
    210         fp = GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(minLevelsChild),
    211                                                                 std::move(otherChild), mode);
    212         SkASSERT(fp);
    213     } else {
    214         fp = GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(otherChild),
    215                                                                 std::move(minLevelsChild), mode);
    216         SkASSERT(fp);
    217     }
    218     return fp;
    219 }
    220 
    221 static void set_random_color_coverage_stages(GrPaint* paint,
    222                                              GrProcessorTestData* d,
    223                                              int maxStages,
    224                                              int maxTreeLevels) {
    225     // Randomly choose to either create a linear pipeline of procs or create one proc tree
    226     const float procTreeProbability = 0.5f;
    227     if (d->fRandom->nextF() < procTreeProbability) {
    228         std::unique_ptr<GrFragmentProcessor> fp(create_random_proc_tree(d, 2, maxTreeLevels));
    229         if (fp) {
    230             paint->addColorFragmentProcessor(std::move(fp));
    231         }
    232     } else {
    233         int numProcs = d->fRandom->nextULessThan(maxStages + 1);
    234         int numColorProcs = d->fRandom->nextULessThan(numProcs + 1);
    235 
    236         for (int s = 0; s < numProcs;) {
    237             std::unique_ptr<GrFragmentProcessor> fp(GrFragmentProcessorTestFactory::Make(d));
    238             SkASSERT(fp);
    239 
    240             // finally add the stage to the correct pipeline in the drawstate
    241             if (s < numColorProcs) {
    242                 paint->addColorFragmentProcessor(std::move(fp));
    243             } else {
    244                 paint->addCoverageFragmentProcessor(std::move(fp));
    245             }
    246             ++s;
    247         }
    248     }
    249 }
    250 
    251 static void set_random_state(GrPaint* paint, SkRandom* random) {
    252     if (random->nextBool()) {
    253         paint->setDisableOutputConversionToSRGB(true);
    254     }
    255     if (random->nextBool()) {
    256         paint->setAllowSRGBInputs(true);
    257     }
    258 }
    259 
    260 #endif
    261 
    262 #if !GR_TEST_UTILS
    263 bool GrDrawingManager::ProgramUnitTest(GrContext*, int) { return true; }
    264 #else
    265 bool GrDrawingManager::ProgramUnitTest(GrContext* context, int maxStages, int maxLevels) {
    266     GrDrawingManager* drawingManager = context->contextPriv().drawingManager();
    267     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
    268 
    269     sk_sp<GrTextureProxy> proxies[2];
    270 
    271     // setup dummy textures
    272     {
    273         GrSurfaceDesc dummyDesc;
    274         dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    275         dummyDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
    276         dummyDesc.fWidth = 34;
    277         dummyDesc.fHeight = 18;
    278         dummyDesc.fConfig = kRGBA_8888_GrPixelConfig;
    279         proxies[0] = proxyProvider->createProxy(dummyDesc, SkBackingFit::kExact, SkBudgeted::kNo);
    280     }
    281     {
    282         GrSurfaceDesc dummyDesc;
    283         dummyDesc.fFlags = kNone_GrSurfaceFlags;
    284         dummyDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
    285         dummyDesc.fWidth = 16;
    286         dummyDesc.fHeight = 22;
    287         dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    288         proxies[1] = proxyProvider->createProxy(dummyDesc, SkBackingFit::kExact, SkBudgeted::kNo);
    289     }
    290 
    291     if (!proxies[0] || !proxies[1]) {
    292         SkDebugf("Could not allocate dummy textures");
    293         return false;
    294     }
    295 
    296     // dummy scissor state
    297     GrScissorState scissor;
    298 
    299     SkRandom random;
    300     static const int NUM_TESTS = 1024;
    301     for (int t = 0; t < NUM_TESTS; t++) {
    302         // setup random render target(can fail)
    303         sk_sp<GrRenderTargetContext> renderTargetContext(random_render_target_context(
    304             context, &random, context->caps()));
    305         if (!renderTargetContext) {
    306             SkDebugf("Could not allocate renderTargetContext");
    307             return false;
    308         }
    309 
    310         GrPaint paint;
    311         GrProcessorTestData ptd(&random, context, renderTargetContext.get(), proxies);
    312         set_random_color_coverage_stages(&paint, &ptd, maxStages, maxLevels);
    313         set_random_xpf(&paint, &ptd);
    314         set_random_state(&paint, &random);
    315         GrDrawRandomOp(&random, renderTargetContext.get(), std::move(paint));
    316     }
    317     // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
    318     drawingManager->flush(nullptr);
    319 
    320     // Validate that GrFPs work correctly without an input.
    321     sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
    322                                                                            SkBackingFit::kExact,
    323                                                                            kRenderTargetWidth,
    324                                                                            kRenderTargetHeight,
    325                                                                            kRGBA_8888_GrPixelConfig,
    326                                                                            nullptr));
    327     if (!renderTargetContext) {
    328         SkDebugf("Could not allocate a renderTargetContext");
    329         return false;
    330     }
    331 
    332     int fpFactoryCnt = GrFragmentProcessorTestFactory::Count();
    333     for (int i = 0; i < fpFactoryCnt; ++i) {
    334         // Since FP factories internally randomize, call each 10 times.
    335         for (int j = 0; j < 10; ++j) {
    336             GrProcessorTestData ptd(&random, context, renderTargetContext.get(), proxies);
    337 
    338             GrPaint paint;
    339             paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
    340             auto fp = GrFragmentProcessorTestFactory::MakeIdx(i, &ptd);
    341             auto blockFP = BlockInputFragmentProcessor::Make(std::move(fp));
    342             paint.addColorFragmentProcessor(std::move(blockFP));
    343             GrDrawRandomOp(&random, renderTargetContext.get(), std::move(paint));
    344             drawingManager->flush(nullptr);
    345         }
    346     }
    347 
    348     return true;
    349 }
    350 #endif
    351 
    352 static int get_glprograms_max_stages(const sk_gpu_test::ContextInfo& ctxInfo) {
    353     GrContext* context = ctxInfo.grContext();
    354     GrGLGpu* gpu = static_cast<GrGLGpu*>(context->contextPriv().getGpu());
    355     int maxStages = 6;
    356     if (kGLES_GrGLStandard == gpu->glStandard()) {
    357     // We've had issues with driver crashes and HW limits being exceeded with many effects on
    358     // Android devices. We have passes on ARM devices with the default number of stages.
    359     // TODO When we run ES 3.00 GLSL in more places, test again
    360 #ifdef SK_BUILD_FOR_ANDROID
    361         if (kARM_GrGLVendor != gpu->ctxInfo().vendor()) {
    362             maxStages = 1;
    363         }
    364 #endif
    365     // On iOS we can exceed the maximum number of varyings. http://skbug.com/6627.
    366 #ifdef SK_BUILD_FOR_IOS
    367         maxStages = 3;
    368 #endif
    369     }
    370     if (ctxInfo.type() == sk_gpu_test::GrContextFactory::kANGLE_D3D9_ES2_ContextType ||
    371         ctxInfo.type() == sk_gpu_test::GrContextFactory::kANGLE_D3D11_ES2_ContextType) {
    372         // On Angle D3D we will hit a limit of out variables if we use too many stages.
    373         maxStages = 3;
    374     }
    375     return maxStages;
    376 }
    377 
    378 static int get_glprograms_max_levels(const sk_gpu_test::ContextInfo& ctxInfo) {
    379     // A full tree with 5 levels (31 nodes) may cause a program that exceeds shader limits
    380     // (e.g. uniform or varying limits); maxTreeLevels should be a number from 1 to 4 inclusive.
    381     int maxTreeLevels = 4;
    382     // On iOS we can exceed the maximum number of varyings. http://skbug.com/6627.
    383 #ifdef SK_BUILD_FOR_IOS
    384     maxTreeLevels = 2;
    385 #endif
    386     if (ctxInfo.type() == sk_gpu_test::GrContextFactory::kANGLE_D3D9_ES2_ContextType ||
    387         ctxInfo.type() == sk_gpu_test::GrContextFactory::kANGLE_D3D11_ES2_ContextType) {
    388         // On Angle D3D we will hit a limit of out variables if we use too many stages.
    389         maxTreeLevels = 2;
    390     }
    391     return maxTreeLevels;
    392 }
    393 
    394 static void test_glprograms(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& ctxInfo) {
    395     int maxStages = get_glprograms_max_stages(ctxInfo);
    396     if (maxStages == 0) {
    397         return;
    398     }
    399     int maxLevels = get_glprograms_max_levels(ctxInfo);
    400     if (maxLevels == 0) {
    401         return;
    402     }
    403 
    404     REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(ctxInfo.grContext(), maxStages,
    405                                                                 maxLevels));
    406 }
    407 
    408 DEF_GPUTEST(GLPrograms, reporter, options) {
    409     // Set a locale that would cause shader compilation to fail because of , as decimal separator.
    410     // skbug 3330
    411 #ifdef SK_BUILD_FOR_WIN
    412     GrAutoLocaleSetter als("sv-SE");
    413 #else
    414     GrAutoLocaleSetter als("sv_SE.UTF-8");
    415 #endif
    416 
    417     // We suppress prints to avoid spew
    418     GrContextOptions opts = options;
    419     opts.fSuppressPrints = true;
    420     sk_gpu_test::GrContextFactory debugFactory(opts);
    421     skiatest::RunWithGPUTestContexts(test_glprograms, &skiatest::IsRenderingGLContextType, reporter,
    422                                      opts);
    423 }
    424 
    425 #endif
    426