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 "GrBackendProcessorFactory.h"
     16 #include "GrContextFactory.h"
     17 #include "GrOptDrawState.h"
     18 #include "effects/GrConfigConversionEffect.h"
     19 #include "gl/GrGLPathRendering.h"
     20 #include "gl/GrGpuGL.h"
     21 #include "SkChecksum.h"
     22 #include "SkRandom.h"
     23 #include "Test.h"
     24 
     25 static void get_stage_stats(const GrFragmentStage stage, bool* readsDst,
     26                             bool* readsFragPosition, bool* requiresVertexShader) {
     27     if (stage.getFragmentProcessor()->willReadDstColor()) {
     28         *readsDst = true;
     29     }
     30     if (stage.getProcessor()->willReadFragmentPosition()) {
     31         *readsFragPosition = true;
     32     }
     33 }
     34 
     35 bool GrGLProgramDesc::setRandom(SkRandom* random,
     36                                 GrGpuGL* gpu,
     37                                 const GrRenderTarget* dstRenderTarget,
     38                                 const GrTexture* dstCopyTexture,
     39                                 const GrGeometryStage* geometryProcessor,
     40                                 const GrFragmentStage* stages[],
     41                                 int numColorStages,
     42                                 int numCoverageStages,
     43                                 int currAttribIndex,
     44                                 GrGpu::DrawType drawType) {
     45     bool isPathRendering = GrGpu::IsPathRenderingDrawType(drawType);
     46     bool useLocalCoords = !isPathRendering &&
     47                           random->nextBool() &&
     48                           currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
     49 
     50     int numStages = numColorStages + numCoverageStages;
     51     fKey.reset();
     52 
     53     GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
     54 
     55     // Make room for everything up to and including the array of offsets to effect keys.
     56     fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * (numStages +
     57             (geometryProcessor ? 1 : 0)));
     58 
     59     bool dstRead = false;
     60     bool fragPos = false;
     61     bool vertexShader = SkToBool(geometryProcessor);
     62     int offset = 0;
     63     if (geometryProcessor) {
     64         const GrGeometryStage* stage = geometryProcessor;
     65         uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() +
     66                                                               kEffectKeyOffsetsAndLengthOffset +
     67                                                               offset * 2 * sizeof(uint16_t));
     68         uint32_t effectKeyOffset = fKey.count();
     69         if (effectKeyOffset > SK_MaxU16) {
     70             fKey.reset();
     71             return false;
     72         }
     73         GrProcessorKeyBuilder b(&fKey);
     74         uint16_t effectKeySize;
     75         if (!GetProcessorKey(*stage, gpu->glCaps(), useLocalCoords, &b, &effectKeySize)) {
     76             fKey.reset();
     77             return false;
     78         }
     79         vertexShader = true;
     80         fragPos = stage->getProcessor()->willReadFragmentPosition();
     81         offsetAndSize[0] = effectKeyOffset;
     82         offsetAndSize[1] = effectKeySize;
     83         offset++;
     84     }
     85 
     86     for (int s = 0; s < numStages; ++s, ++offset) {
     87         const GrFragmentStage* stage = stages[s];
     88         uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() +
     89                                                               kEffectKeyOffsetsAndLengthOffset +
     90                                                               offset * 2 * sizeof(uint16_t));
     91         uint32_t effectKeyOffset = fKey.count();
     92         if (effectKeyOffset > SK_MaxU16) {
     93             fKey.reset();
     94             return false;
     95         }
     96         GrProcessorKeyBuilder b(&fKey);
     97         uint16_t effectKeySize;
     98         if (!GetProcessorKey(*stages[s], gpu->glCaps(), useLocalCoords, &b, &effectKeySize)) {
     99             fKey.reset();
    100             return false;
    101         }
    102         get_stage_stats(*stage, &dstRead, &fragPos, &vertexShader);
    103         offsetAndSize[0] = effectKeyOffset;
    104         offsetAndSize[1] = effectKeySize;
    105     }
    106 
    107     KeyHeader* header = this->header();
    108     memset(header, 0, kHeaderSize);
    109     header->fEmitsPointSize = random->nextBool();
    110 
    111     header->fPositionAttributeIndex = 0;
    112 
    113     // if the effects have used up all off the available attributes,
    114     // don't try to use color or coverage attributes as input
    115     do {
    116         header->fColorInput = static_cast<GrGLProgramDesc::ColorInput>(
    117                                      random->nextULessThan(kColorInputCnt));
    118     } while ((GrDrawState::kMaxVertexAttribCnt <= currAttribIndex || isPathRendering) &&
    119              kAttribute_ColorInput == header->fColorInput);
    120     header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ?
    121                                         currAttribIndex++ :
    122                                         -1;
    123 
    124     do {
    125         header->fCoverageInput = static_cast<GrGLProgramDesc::ColorInput>(
    126                                      random->nextULessThan(kColorInputCnt));
    127     } while ((GrDrawState::kMaxVertexAttribCnt <= currAttribIndex || isPathRendering)  &&
    128              kAttribute_ColorInput == header->fCoverageInput);
    129     header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ?
    130                                         currAttribIndex++ :
    131                                         -1;
    132     bool useGS = random->nextBool();
    133 #if GR_GL_EXPERIMENTAL_GS
    134     header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && useGS;
    135 #else
    136     (void) useGS;
    137 #endif
    138 
    139     header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
    140 
    141     header->fColorEffectCnt = numColorStages;
    142     header->fCoverageEffectCnt = numCoverageStages;
    143 
    144     if (dstRead) {
    145         header->fDstReadKey = SkToU8(GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
    146                                                                       gpu->glCaps()));
    147     } else {
    148         header->fDstReadKey = 0;
    149     }
    150     if (fragPos) {
    151         header->fFragPosKey = SkToU8(GrGLFragmentShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
    152                                                                                gpu->glCaps()));
    153     } else {
    154         header->fFragPosKey = 0;
    155     }
    156 
    157     header->fUseFragShaderOnly = isPathRendering && gpu->glPathRendering()->texturingMode() ==
    158                                                     GrGLPathRendering::FixedFunction_TexturingMode;
    159     header->fHasGeometryProcessor = vertexShader;
    160 
    161     GrOptDrawState::PrimaryOutputType primaryOutput;
    162     GrOptDrawState::SecondaryOutputType secondaryOutput;
    163     if (!dstRead) {
    164         primaryOutput = GrOptDrawState::kModulate_PrimaryOutputType;
    165     } else {
    166         primaryOutput = static_cast<GrOptDrawState::PrimaryOutputType>(
    167             random->nextULessThan(GrOptDrawState::kPrimaryOutputTypeCnt));
    168     }
    169 
    170     if (GrOptDrawState::kCombineWithDst_PrimaryOutputType == primaryOutput ||
    171         !gpu->caps()->dualSourceBlendingSupport()) {
    172         secondaryOutput = GrOptDrawState::kNone_SecondaryOutputType;
    173     } else {
    174         secondaryOutput = static_cast<GrOptDrawState::SecondaryOutputType>(
    175             random->nextULessThan(GrOptDrawState::kSecondaryOutputTypeCnt));
    176     }
    177 
    178     header->fPrimaryOutputType = primaryOutput;
    179     header->fSecondaryOutputType = secondaryOutput;
    180 
    181     this->finalize();
    182     return true;
    183 }
    184 
    185 // TODO clean this up, we have to do this to test geometry processors but there has got to be
    186 // a better way.  In the mean time, we actually fill out these generic vertex attribs below with
    187 // the correct vertex attribs from the GP.  We have to ensure, however, we don't try to add more
    188 // than two attributes.
    189 GrVertexAttrib genericVertexAttribs[] = {
    190     { kVec2f_GrVertexAttribType, 0,   kPosition_GrVertexAttribBinding },
    191     { kVec2f_GrVertexAttribType, 0,   kGeometryProcessor_GrVertexAttribBinding },
    192     { kVec2f_GrVertexAttribType, 0,   kGeometryProcessor_GrVertexAttribBinding }
    193 };
    194 
    195 /*
    196  * convert sl type to vertexattrib type, not a complete implementation, only use for debugging
    197  */
    198 GrVertexAttribType convert_sltype_to_attribtype(GrSLType type) {
    199     switch (type) {
    200         case kFloat_GrSLType:
    201             return kFloat_GrVertexAttribType;
    202         case kVec2f_GrSLType:
    203             return kVec2f_GrVertexAttribType;
    204         case kVec3f_GrSLType:
    205             return kVec3f_GrVertexAttribType;
    206         case kVec4f_GrSLType:
    207             return kVec4f_GrVertexAttribType;
    208         default:
    209             SkFAIL("Type isn't convertible");
    210             return kFloat_GrVertexAttribType;
    211     }
    212 }
    213 // TODO end test hack
    214 
    215 
    216 bool GrGpuGL::programUnitTest(int maxStages) {
    217 
    218     GrTextureDesc dummyDesc;
    219     dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
    220     dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    221     dummyDesc.fWidth = 34;
    222     dummyDesc.fHeight = 18;
    223     SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
    224     dummyDesc.fFlags = kNone_GrTextureFlags;
    225     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    226     dummyDesc.fWidth = 16;
    227     dummyDesc.fHeight = 22;
    228     SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
    229 
    230     if (!dummyTexture1 || ! dummyTexture2) {
    231         return false;
    232     }
    233 
    234     static const int NUM_TESTS = 512;
    235 
    236     SkRandom random;
    237     for (int t = 0; t < NUM_TESTS; ++t) {
    238 
    239 #if 0
    240         GrPrintf("\nTest Program %d\n-------------\n", t);
    241         static const int stop = -1;
    242         if (t == stop) {
    243             int breakpointhere = 9;
    244         }
    245 #endif
    246 
    247         GrGLProgramDesc pdesc;
    248 
    249         int currAttribIndex = 1;  // we need to always leave room for position
    250         int currTextureCoordSet = 0;
    251         GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
    252 
    253         int numStages = random.nextULessThan(maxStages + 1);
    254         int numColorStages = random.nextULessThan(numStages + 1);
    255         int numCoverageStages = numStages - numColorStages;
    256 
    257         SkAutoSTMalloc<8, const GrFragmentStage*> stages(numStages);
    258 
    259         bool usePathRendering = this->glCaps().pathRenderingSupport() && random.nextBool();
    260 
    261         GrGpu::DrawType drawType = usePathRendering ? GrGpu::kDrawPath_DrawType :
    262                                                       GrGpu::kDrawPoints_DrawType;
    263 
    264         SkAutoTDelete<GrGeometryStage> geometryProcessor;
    265         bool hasGeometryProcessor = usePathRendering ? false : random.nextBool();
    266         if (hasGeometryProcessor) {
    267             while (true) {
    268                 SkAutoTUnref<const GrGeometryProcessor> effect(
    269                         GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(&random, this->getContext(), *this->caps(),
    270                                                          dummyTextures));
    271                 SkASSERT(effect);
    272                 // Only geometryProcessor can use vertex shader
    273                 GrGeometryStage* stage = SkNEW_ARGS(GrGeometryStage, (effect.get()));
    274                 geometryProcessor.reset(stage);
    275 
    276                 // we have to set dummy vertex attribs
    277                 const GrGeometryProcessor::VertexAttribArray& v = effect->getVertexAttribs();
    278                 int numVertexAttribs = v.count();
    279 
    280                 SkASSERT(GrGeometryProcessor::kMaxVertexAttribs == 2 &&
    281                          GrGeometryProcessor::kMaxVertexAttribs >= numVertexAttribs);
    282                 size_t runningStride = GrVertexAttribTypeSize(genericVertexAttribs[0].fType);
    283                 for (int i = 0; i < numVertexAttribs; i++) {
    284                     genericVertexAttribs[i + 1].fOffset = runningStride;
    285                     genericVertexAttribs[i + 1].fType =
    286                             convert_sltype_to_attribtype(v[i].getType());
    287                     runningStride += GrVertexAttribTypeSize(genericVertexAttribs[i + 1].fType);
    288                 }
    289 
    290                 // update the vertex attributes with the ds
    291                 GrDrawState* ds = this->drawState();
    292                 ds->setVertexAttribs<genericVertexAttribs>(numVertexAttribs + 1, runningStride);
    293                 currAttribIndex = numVertexAttribs + 1;
    294                 break;
    295             }
    296         }
    297         for (int s = 0; s < numStages;) {
    298             SkAutoTUnref<const GrFragmentProcessor> effect(
    299                     GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(
    300                                                                             &random,
    301                                                                             this->getContext(),
    302                                                                             *this->caps(),
    303                                                                             dummyTextures));
    304             SkASSERT(effect);
    305 
    306             // If adding this effect would exceed the max texture coord set count then generate a
    307             // new random effect.
    308             if (usePathRendering && this->glPathRendering()->texturingMode() ==
    309                                     GrGLPathRendering::FixedFunction_TexturingMode) {;
    310                 int numTransforms = effect->numTransforms();
    311                 if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) {
    312                     continue;
    313                 }
    314                 currTextureCoordSet += numTransforms;
    315             }
    316             GrFragmentStage* stage = SkNEW_ARGS(GrFragmentStage, (effect.get()));
    317 
    318             stages[s] = stage;
    319             ++s;
    320         }
    321         const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
    322         if (!pdesc.setRandom(&random,
    323                              this,
    324                              dummyTextures[0]->asRenderTarget(),
    325                              dstTexture,
    326                              geometryProcessor.get(),
    327                              stages.get(),
    328                              numColorStages,
    329                              numCoverageStages,
    330                              currAttribIndex,
    331                              drawType)) {
    332             return false;
    333         }
    334 
    335         SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this,
    336                                                               pdesc,
    337                                                               geometryProcessor.get(),
    338                                                               stages,
    339                                                               stages + numColorStages));
    340         for (int s = 0; s < numStages; ++s) {
    341             SkDELETE(stages[s]);
    342         }
    343         if (NULL == program.get()) {
    344             return false;
    345         }
    346 
    347         // We have to reset the drawstate because we might have added a gp
    348         this->drawState()->reset();
    349     }
    350     return true;
    351 }
    352 
    353 DEF_GPUTEST(GLPrograms, reporter, factory) {
    354     for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
    355         GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
    356         if (context) {
    357             GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu());
    358             int maxStages = 6;
    359 #if SK_ANGLE
    360             // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
    361             if (type == GrContextFactory::kANGLE_GLContextType) {
    362                 maxStages = 3;
    363             }
    364 #endif
    365             REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages));
    366         }
    367     }
    368 }
    369 
    370 // This is evil evil evil. The linker may throw away whole translation units as dead code if it
    371 // thinks none of the functions are called. It will do this even if there are static initializers
    372 // in the unit that could pass pointers to functions from the unit out to other translation units!
    373 // We force some of the effects that would otherwise be discarded to link here.
    374 
    375 #include "SkAlphaThresholdFilter.h"
    376 #include "SkColorMatrixFilter.h"
    377 #include "SkLightingImageFilter.h"
    378 #include "SkMagnifierImageFilter.h"
    379 
    380 void forceLinking();
    381 
    382 void forceLinking() {
    383     SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
    384     SkAlphaThresholdFilter::Create(SkRegion(), .5f, .5f);
    385     SkAutoTUnref<SkImageFilter> mag(SkMagnifierImageFilter::Create(
    386         SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1));
    387     GrConfigConversionEffect::Create(NULL,
    388                                      false,
    389                                      GrConfigConversionEffect::kNone_PMConversion,
    390                                      SkMatrix::I());
    391     SkScalar matrix[20];
    392     SkAutoTUnref<SkColorMatrixFilter> cmf(SkColorMatrixFilter::Create(matrix));
    393 }
    394 
    395 #endif
    396