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