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 "GrContextFactory.h"
     18 #include "GrDrawEffect.h"
     19 #include "effects/GrConfigConversionEffect.h"
     20 
     21 #include "SkChecksum.h"
     22 #include "SkRandom.h"
     23 #include "Test.h"
     24 
     25 void GrGLProgramDesc::setRandom(SkMWCRandom* random,
     26                                 const GrGpuGL* gpu,
     27                                 const GrRenderTarget* dstRenderTarget,
     28                                 const GrTexture* dstCopyTexture,
     29                                 const GrEffectStage* stages[],
     30                                 int numColorStages,
     31                                 int numCoverageStages,
     32                                 int currAttribIndex) {
     33     int numEffects = numColorStages + numCoverageStages;
     34     size_t keyLength = KeyLength(numEffects);
     35     fKey.reset(keyLength);
     36     *this->atOffset<uint32_t, kLengthOffset>() = static_cast<uint32_t>(keyLength);
     37     memset(this->header(), 0, kHeaderSize);
     38 
     39     KeyHeader* header = this->header();
     40     header->fEmitsPointSize = random->nextBool();
     41 
     42     header->fPositionAttributeIndex = 0;
     43 
     44     // if the effects have used up all off the available attributes,
     45     // don't try to use color or coverage attributes as input
     46     do {
     47         header->fColorInput = random->nextULessThan(kColorInputCnt);
     48     } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex &&
     49              kAttribute_ColorInput == header->fColorInput);
     50     header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ?
     51                                         currAttribIndex++ :
     52                                         -1;
     53 
     54     do {
     55         header->fCoverageInput = random->nextULessThan(kColorInputCnt);
     56     } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex  &&
     57              kAttribute_ColorInput == header->fCoverageInput);
     58     header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ?
     59                                         currAttribIndex++ :
     60                                         -1;
     61 
     62     header->fColorFilterXfermode = random->nextULessThan(SkXfermode::kLastCoeffMode + 1);
     63 
     64 #if GR_GL_EXPERIMENTAL_GS
     65     header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool();
     66 #endif
     67 
     68     header->fDiscardIfZeroCoverage = random->nextBool();
     69 
     70     bool useLocalCoords = random->nextBool() && currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
     71     header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
     72 
     73     header->fColorEffectCnt = numColorStages;
     74     header->fCoverageEffectCnt = numCoverageStages;
     75 
     76     bool dstRead = false;
     77     bool fragPos = false;
     78     int numStages = numColorStages + numCoverageStages;
     79     for (int s = 0; s < numStages; ++s) {
     80         const GrBackendEffectFactory& factory = (*stages[s]->getEffect())->getFactory();
     81         GrDrawEffect drawEffect(*stages[s], useLocalCoords);
     82         this->effectKeys()[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
     83         if ((*stages[s]->getEffect())->willReadDstColor()) {
     84             dstRead = true;
     85         }
     86         if ((*stages[s]->getEffect())->willReadFragmentPosition()) {
     87             fragPos = true;
     88         }
     89     }
     90 
     91     if (dstRead) {
     92         header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
     93     } else {
     94         header->fDstReadKey = 0;
     95     }
     96     if (fragPos) {
     97         header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
     98                                                                          gpu->glCaps());
     99     } else {
    100         header->fFragPosKey = 0;
    101     }
    102 
    103     CoverageOutput coverageOutput;
    104     bool illegalCoverageOutput;
    105     do {
    106         coverageOutput = static_cast<CoverageOutput>(random->nextULessThan(kCoverageOutputCnt));
    107         illegalCoverageOutput = (!gpu->caps()->dualSourceBlendingSupport() &&
    108                                  CoverageOutputUsesSecondaryOutput(coverageOutput)) ||
    109                                 (!dstRead && kCombineWithDst_CoverageOutput == coverageOutput);
    110     } while (illegalCoverageOutput);
    111 
    112     header->fCoverageOutput = coverageOutput;
    113 
    114     *this->checksum() = 0;
    115     *this->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.get()), keyLength);
    116     fInitialized = true;
    117 }
    118 
    119 bool GrGpuGL::programUnitTest(int maxStages) {
    120 
    121     GrTextureDesc dummyDesc;
    122     dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
    123     dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    124     dummyDesc.fWidth = 34;
    125     dummyDesc.fHeight = 18;
    126     SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
    127     dummyDesc.fFlags = kNone_GrTextureFlags;
    128     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    129     dummyDesc.fWidth = 16;
    130     dummyDesc.fHeight = 22;
    131     SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
    132 
    133     static const int NUM_TESTS = 512;
    134 
    135     SkMWCRandom random;
    136     for (int t = 0; t < NUM_TESTS; ++t) {
    137 
    138 #if 0
    139         GrPrintf("\nTest Program %d\n-------------\n", t);
    140         static const int stop = -1;
    141         if (t == stop) {
    142             int breakpointhere = 9;
    143         }
    144 #endif
    145 
    146         GrGLProgramDesc pdesc;
    147 
    148         int currAttribIndex = 1;  // we need to always leave room for position
    149         int attribIndices[2];
    150         GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
    151 
    152         int numStages = random.nextULessThan(maxStages + 1);
    153         int numColorStages = random.nextULessThan(numStages + 1);
    154         int numCoverageStages = numStages - numColorStages;
    155 
    156         SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages);
    157 
    158         for (int s = 0; s < numStages; ++s) {
    159             SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage(
    160                                                                             &random,
    161                                                                             this->getContext(),
    162                                                                             *this->caps(),
    163                                                                             dummyTextures));
    164             int numAttribs = (*effect)->numVertexAttribs();
    165 
    166             // If adding this effect would exceed the max attrib count then generate a
    167             // new random effect.
    168             if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) {
    169                 --s;
    170                 continue;
    171             }
    172             for (int i = 0; i < numAttribs; ++i) {
    173                 attribIndices[i] = currAttribIndex++;
    174             }
    175             GrEffectStage* stage = SkNEW_ARGS(GrEffectStage,
    176                                               (effect.get(), attribIndices[0], attribIndices[1]));
    177             stages[s] = stage;
    178         }
    179         const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
    180         pdesc.setRandom(&random,
    181                         this,
    182                         dummyTextures[0]->asRenderTarget(),
    183                         dstTexture,
    184                         stages.get(),
    185                         numColorStages,
    186                         numCoverageStages,
    187                         currAttribIndex);
    188 
    189         SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContext(),
    190                                                               pdesc,
    191                                                               stages,
    192                                                               stages + numColorStages));
    193         for (int s = 0; s < numStages; ++s) {
    194             SkDELETE(stages[s]);
    195         }
    196         if (NULL == program.get()) {
    197             return false;
    198         }
    199     }
    200     return true;
    201 }
    202 
    203 static void GLProgramsTest(skiatest::Reporter* reporter, GrContextFactory* factory) {
    204     for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
    205         GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
    206         if (NULL != context) {
    207             GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu());
    208             int maxStages = 6;
    209 #if SK_ANGLE
    210             // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
    211             if (type == GrContextFactory::kANGLE_GLContextType) {
    212                 maxStages = 3;
    213             }
    214 #endif
    215             REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages));
    216         }
    217     }
    218 }
    219 
    220 #include "TestClassDef.h"
    221 DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
    222 
    223 // This is evil evil evil. The linker may throw away whole translation units as dead code if it
    224 // thinks none of the functions are called. It will do this even if there are static initializers
    225 // in the unit that could pass pointers to functions from the unit out to other translation units!
    226 // We force some of the effects that would otherwise be discarded to link here.
    227 
    228 #include "SkLightingImageFilter.h"
    229 #include "SkMagnifierImageFilter.h"
    230 #include "SkColorMatrixFilter.h"
    231 
    232 void forceLinking();
    233 
    234 void forceLinking() {
    235     SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
    236     SkMagnifierImageFilter mag(SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1);
    237     GrConfigConversionEffect::Create(NULL,
    238                                      false,
    239                                      GrConfigConversionEffect::kNone_PMConversion,
    240                                      SkMatrix::I());
    241     SkScalar matrix[20];
    242     SkColorMatrixFilter cmf(matrix);
    243 }
    244 
    245 #endif
    246