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