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