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 "gl/GrGpuGL.h"
     16 #include "GrBackendEffectFactory.h"
     17 #include "effects/GrConfigConversionEffect.h"
     18 
     19 #include "SkRandom.h"
     20 #include "Test.h"
     21 
     22 namespace {
     23 
     24 // SkRandoms nextU() values have patterns in the low bits
     25 // So using nextU() % array_count might never take some values.
     26 int random_int(SkRandom* r, int count) {
     27     return (int)(r->nextF() * count);
     28 }
     29 
     30 bool random_bool(SkRandom* r) {
     31     return r->nextF() > .5f;
     32 }
     33 
     34 const GrEffectRef* create_random_effect(SkRandom* random,
     35                                         GrContext* context,
     36                                         GrTexture* dummyTextures[]) {
     37 
     38     SkRandom sk_random;
     39     sk_random.setSeed(random->nextU());
     40     GrEffectRef* effect = GrEffectTestFactory::CreateStage(&sk_random, context, dummyTextures);
     41     GrAssert(effect);
     42     return effect;
     43 }
     44 }
     45 
     46 bool GrGpuGL::programUnitTest() {
     47 
     48     GrTextureDesc dummyDesc;
     49     dummyDesc.fConfig = kSkia8888_PM_GrPixelConfig;
     50     dummyDesc.fWidth = 34;
     51     dummyDesc.fHeight = 18;
     52     SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
     53     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
     54     dummyDesc.fWidth = 16;
     55     dummyDesc.fHeight = 22;
     56     SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
     57 
     58     static const int NUM_TESTS = 512;
     59 
     60     SkRandom random;
     61     for (int t = 0; t < NUM_TESTS; ++t) {
     62 
     63 #if 0
     64         GrPrintf("\nTest Program %d\n-------------\n", t);
     65         static const int stop = -1;
     66         if (t == stop) {
     67             int breakpointhere = 9;
     68         }
     69 #endif
     70 
     71         ProgramDesc pdesc;
     72         pdesc.fVertexLayout = 0;
     73         pdesc.fEmitsPointSize = random.nextF() > .5f;
     74         pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
     75         pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
     76 
     77         pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
     78 
     79         pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
     80 
     81         pdesc.fVertexLayout |= random_bool(&random) ?
     82                                     GrDrawState::kCoverage_VertexLayoutBit :
     83                                     0;
     84 
     85 #if GR_GL_EXPERIMENTAL_GS
     86         pdesc.fExperimentalGS = this->getCaps().geometryShaderSupport() &&
     87                                 random_bool(&random);
     88 #endif
     89 
     90         bool edgeAA = random_bool(&random);
     91         if (edgeAA) {
     92             pdesc.fVertexLayout |= GrDrawState::kEdge_VertexLayoutBit;
     93             if (this->getCaps().shaderDerivativeSupport()) {
     94                 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
     95                 pdesc.fDiscardIfOutsideEdge = random.nextBool();
     96             } else {
     97                 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
     98                 pdesc.fDiscardIfOutsideEdge = false;
     99             }
    100         } else {
    101         }
    102 
    103         if (this->getCaps().dualSourceBlendingSupport()) {
    104             pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
    105         } else {
    106             pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
    107         }
    108 
    109         GrEffectStage stages[GrDrawState::kNumStages];
    110 
    111         for (int s = 0; s < GrDrawState::kNumStages; ++s) {
    112             // enable the stage?
    113             if (random_bool(&random)) {
    114                 // use separate tex coords?
    115                 if (random_bool(&random)) {
    116                     int t = random_int(&random, GrDrawState::kMaxTexCoords);
    117                     pdesc.fVertexLayout |= GrDrawState::StageTexCoordVertexLayoutBit(s, t);
    118                 }
    119                 // use text-formatted verts?
    120                 if (random_bool(&random)) {
    121                     pdesc.fVertexLayout |= GrDrawState::kTextFormat_VertexLayoutBit;
    122                 }
    123 
    124                 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
    125                 SkAutoTUnref<const GrEffectRef> effect(create_random_effect(&random,
    126                                                                             getContext(),
    127                                                                             dummyTextures));
    128                 stages[s].setEffect(effect.get());
    129                 if (NULL != stages[s].getEffect()) {
    130                     pdesc.fEffectKeys[s] =
    131                         (*stages[s].getEffect())->getFactory().glEffectKey(stages[s],
    132                                                                            this->glCaps());
    133                 }
    134             }
    135         }
    136         const GrEffectStage* stagePtrs[GrDrawState::kNumStages];
    137         for (int s = 0; s < GrDrawState::kNumStages; ++s) {
    138             stagePtrs[s] = &stages[s];
    139         }
    140         SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContextInfo(),
    141                                                               pdesc,
    142                                                               stagePtrs));
    143         if (NULL == program.get()) {
    144             return false;
    145         }
    146     }
    147     return true;
    148 }
    149 
    150 static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
    151     GrGpuGL* shadersGpu = static_cast<GrGpuGL*>(context->getGpu());
    152     REPORTER_ASSERT(reporter, shadersGpu->programUnitTest());
    153 }
    154 
    155 #include "TestClassDef.h"
    156 DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
    157 
    158 // This is evil evil evil. The linker may throw away whole translation units as dead code if it
    159 // thinks none of the functions are called. It will do this even if there are static initializers
    160 // in the unit that could pass pointers to functions from the unit out to other translation units!
    161 // We force some of the effects that would otherwise be discarded to link here.
    162 
    163 #include "SkLightingImageFilter.h"
    164 #include "SkMagnifierImageFilter.h"
    165 #include "SkColorMatrixFilter.h"
    166 
    167 void forceLinking();
    168 
    169 void forceLinking() {
    170     SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
    171     SkMagnifierImageFilter mag(SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1);
    172     GrConfigConversionEffect::Create(NULL,
    173                                      false,
    174                                      GrConfigConversionEffect::kNone_PMConversion,
    175                                      SkMatrix::I());
    176     SkScalar matrix[20];
    177     SkColorMatrixFilter cmf(matrix);
    178 }
    179 
    180 #endif
    181