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(SkRandom* 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 = static_cast<GrGLProgramDesc::ColorInput>(
     48                                   random->nextULessThan(kColorInputCnt));
     49     } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex &&
     50              kAttribute_ColorInput == header->fColorInput);
     51     header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ?
     52                                         currAttribIndex++ :
     53                                         -1;
     54 
     55     do {
     56         header->fCoverageInput = static_cast<GrGLProgramDesc::ColorInput>(
     57                                      random->nextULessThan(kColorInputCnt));
     58     } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex  &&
     59              kAttribute_ColorInput == header->fCoverageInput);
     60     header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ?
     61                                         currAttribIndex++ :
     62                                         -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     bool vertexCode = false;
     79     int numStages = numColorStages + numCoverageStages;
     80     for (int s = 0; s < numStages; ++s) {
     81         const GrBackendEffectFactory& factory = (*stages[s]->getEffect())->getFactory();
     82         GrDrawEffect drawEffect(*stages[s], useLocalCoords);
     83         this->effectKeys()[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
     84         if ((*stages[s]->getEffect())->willReadDstColor()) {
     85             dstRead = true;
     86         }
     87         if ((*stages[s]->getEffect())->willReadFragmentPosition()) {
     88             fragPos = true;
     89         }
     90         if ((*stages[s]->getEffect())->hasVertexCode()) {
     91             vertexCode = true;
     92         }
     93     }
     94 
     95     if (dstRead) {
     96         header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
     97     } else {
     98         header->fDstReadKey = 0;
     99     }
    100     if (fragPos) {
    101         header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
    102                                                                          gpu->glCaps());
    103     } else {
    104         header->fFragPosKey = 0;
    105     }
    106 
    107     header->fHasVertexCode = vertexCode ||
    108                              useLocalCoords ||
    109                              kAttribute_ColorInput == header->fColorInput ||
    110                              kAttribute_ColorInput == header->fCoverageInput;
    111 
    112     CoverageOutput coverageOutput;
    113     bool illegalCoverageOutput;
    114     do {
    115         coverageOutput = static_cast<CoverageOutput>(random->nextULessThan(kCoverageOutputCnt));
    116         illegalCoverageOutput = (!gpu->caps()->dualSourceBlendingSupport() &&
    117                                  CoverageOutputUsesSecondaryOutput(coverageOutput)) ||
    118                                 (!dstRead && kCombineWithDst_CoverageOutput == coverageOutput);
    119     } while (illegalCoverageOutput);
    120 
    121     header->fCoverageOutput = coverageOutput;
    122 
    123     *this->checksum() = 0;
    124     *this->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.get()), keyLength);
    125     fInitialized = true;
    126 }
    127 
    128 bool GrGpuGL::programUnitTest(int maxStages) {
    129 
    130     GrTextureDesc dummyDesc;
    131     dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
    132     dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    133     dummyDesc.fWidth = 34;
    134     dummyDesc.fHeight = 18;
    135     SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
    136     dummyDesc.fFlags = kNone_GrTextureFlags;
    137     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    138     dummyDesc.fWidth = 16;
    139     dummyDesc.fHeight = 22;
    140     SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
    141 
    142     static const int NUM_TESTS = 512;
    143 
    144     SkRandom random;
    145     for (int t = 0; t < NUM_TESTS; ++t) {
    146 
    147 #if 0
    148         GrPrintf("\nTest Program %d\n-------------\n", t);
    149         static const int stop = -1;
    150         if (t == stop) {
    151             int breakpointhere = 9;
    152         }
    153 #endif
    154 
    155         GrGLProgramDesc pdesc;
    156 
    157         int currAttribIndex = 1;  // we need to always leave room for position
    158         int currTextureCoordSet = 0;
    159         int attribIndices[2];
    160         GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
    161 
    162         int numStages = random.nextULessThan(maxStages + 1);
    163         int numColorStages = random.nextULessThan(numStages + 1);
    164         int numCoverageStages = numStages - numColorStages;
    165 
    166         SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages);
    167 
    168         bool useFixedFunctionTexturing = this->shouldUseFixedFunctionTexturing();
    169 
    170         for (int s = 0; s < numStages;) {
    171             SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage(
    172                                                                             &random,
    173                                                                             this->getContext(),
    174                                                                             *this->caps(),
    175                                                                             dummyTextures));
    176             int numAttribs = (*effect)->numVertexAttribs();
    177 
    178             // If adding this effect would exceed the max attrib count then generate a
    179             // new random effect.
    180             if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) {
    181                 continue;
    182             }
    183 
    184 
    185             // If adding this effect would exceed the max texture coord set count then generate a
    186             // new random effect.
    187             if (useFixedFunctionTexturing && !(*effect)->hasVertexCode()) {
    188                 int numTransforms = (*effect)->numTransforms();
    189                 if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) {
    190                     continue;
    191                 }
    192                 currTextureCoordSet += numTransforms;
    193             }
    194 
    195             useFixedFunctionTexturing = useFixedFunctionTexturing && !(*effect)->hasVertexCode();
    196 
    197             for (int i = 0; i < numAttribs; ++i) {
    198                 attribIndices[i] = currAttribIndex++;
    199             }
    200             GrEffectStage* stage = SkNEW_ARGS(GrEffectStage,
    201                                               (effect.get(), attribIndices[0], attribIndices[1]));
    202             stages[s] = stage;
    203             ++s;
    204         }
    205         const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
    206         pdesc.setRandom(&random,
    207                         this,
    208                         dummyTextures[0]->asRenderTarget(),
    209                         dstTexture,
    210                         stages.get(),
    211                         numColorStages,
    212                         numCoverageStages,
    213                         currAttribIndex);
    214 
    215         SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this,
    216                                                               pdesc,
    217                                                               stages,
    218                                                               stages + numColorStages));
    219         for (int s = 0; s < numStages; ++s) {
    220             SkDELETE(stages[s]);
    221         }
    222         if (NULL == program.get()) {
    223             return false;
    224         }
    225     }
    226     return true;
    227 }
    228 
    229 static void GLProgramsTest(skiatest::Reporter* reporter, GrContextFactory* factory) {
    230     for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
    231         GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
    232         if (NULL != context) {
    233             GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu());
    234             int maxStages = 6;
    235 #if SK_ANGLE
    236             // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
    237             if (type == GrContextFactory::kANGLE_GLContextType) {
    238                 maxStages = 3;
    239             }
    240 #endif
    241             REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages));
    242         }
    243     }
    244 }
    245 
    246 #include "TestClassDef.h"
    247 DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
    248 
    249 // This is evil evil evil. The linker may throw away whole translation units as dead code if it
    250 // thinks none of the functions are called. It will do this even if there are static initializers
    251 // in the unit that could pass pointers to functions from the unit out to other translation units!
    252 // We force some of the effects that would otherwise be discarded to link here.
    253 
    254 #include "SkLightingImageFilter.h"
    255 #include "SkMagnifierImageFilter.h"
    256 #include "SkColorMatrixFilter.h"
    257 #include "SkBitmapAlphaThresholdShader.h"
    258 
    259 void forceLinking();
    260 
    261 void forceLinking() {
    262     SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
    263     SkMagnifierImageFilter mag(SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1);
    264     GrConfigConversionEffect::Create(NULL,
    265                                      false,
    266                                      GrConfigConversionEffect::kNone_PMConversion,
    267                                      SkMatrix::I());
    268     SkScalar matrix[20];
    269     SkColorMatrixFilter cmf(matrix);
    270     SkBitmapAlphaThresholdShader::Create(SkBitmap(), SkRegion(), 0x80);
    271 }
    272 
    273 #endif
    274