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