GLProgramsTest.cpp revision ec56e4545477e30d4f165ca55ed99f90525c6c38
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 "GrDrawEffect.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 25bool 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 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 43 bool dstRead = false; 44 bool fragPos = false; 45 bool vertexShader = false; 46 for (int s = 0; s < numStages; ++s) { 47 uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() + 48 kEffectKeyOffsetsAndLengthOffset + 49 s * 2 * sizeof(uint16_t)); 50 uint32_t effectKeyOffset = fKey.count(); 51 if (effectKeyOffset > SK_MaxU16) { 52 fKey.reset(); 53 return false; 54 } 55 GrDrawEffect drawEffect(*stages[s], useLocalCoords); 56 GrEffectKeyBuilder b(&fKey); 57 uint16_t effectKeySize; 58 if (!GetEffectKeyAndUpdateStats(*stages[s], gpu->glCaps(), useLocalCoords, &b, 59 &effectKeySize, &dstRead, &fragPos, &vertexShader)) { 60 fKey.reset(); 61 return false; 62 } 63 offsetAndSize[0] = effectKeyOffset; 64 offsetAndSize[1] = effectKeySize; 65 } 66 67 KeyHeader* header = this->header(); 68 memset(header, 0, kHeaderSize); 69 header->fEmitsPointSize = random->nextBool(); 70 71 header->fPositionAttributeIndex = 0; 72 73 // if the effects have used up all off the available attributes, 74 // don't try to use color or coverage attributes as input 75 do { 76 uint32_t colorRand = random->nextULessThan(2); 77 header->fColorInput = (0 == colorRand) ? GrGLProgramDesc::kAttribute_ColorInput : 78 GrGLProgramDesc::kUniform_ColorInput; 79 } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex && 80 kAttribute_ColorInput == header->fColorInput); 81 82 header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ? 83 currAttribIndex++ : 84 -1; 85 86 do { 87 header->fCoverageInput = static_cast<GrGLProgramDesc::ColorInput>( 88 random->nextULessThan(kColorInputCnt)); 89 } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex && 90 kAttribute_ColorInput == header->fCoverageInput); 91 header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ? 92 currAttribIndex++ : 93 -1; 94 95#if GR_GL_EXPERIMENTAL_GS 96 header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool(); 97#endif 98 99 header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1; 100 101 header->fColorEffectCnt = numColorStages; 102 header->fCoverageEffectCnt = numCoverageStages; 103 104 if (dstRead) { 105 header->fDstReadKey = SkToU8(GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture, 106 gpu->glCaps())); 107 } else { 108 header->fDstReadKey = 0; 109 } 110 if (fragPos) { 111 header->fFragPosKey = SkToU8(GrGLFragmentShaderBuilder::KeyForFragmentPosition(dstRenderTarget, 112 gpu->glCaps())); 113 } else { 114 header->fFragPosKey = 0; 115 } 116 117 header->fRequiresVertexShader = vertexShader || 118 useLocalCoords || 119 kAttribute_ColorInput == header->fColorInput || 120 kAttribute_ColorInput == header->fCoverageInput; 121 122 CoverageOutput coverageOutput; 123 bool illegalCoverageOutput; 124 do { 125 coverageOutput = static_cast<CoverageOutput>(random->nextULessThan(kCoverageOutputCnt)); 126 illegalCoverageOutput = (!gpu->caps()->dualSourceBlendingSupport() && 127 CoverageOutputUsesSecondaryOutput(coverageOutput)) || 128 (!dstRead && kCombineWithDst_CoverageOutput == coverageOutput); 129 } while (illegalCoverageOutput); 130 131 header->fCoverageOutput = coverageOutput; 132 133 this->finalize(); 134 return true; 135} 136 137bool GrGpuGL::programUnitTest(int maxStages) { 138 139 GrTextureDesc dummyDesc; 140 dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit; 141 dummyDesc.fConfig = kSkia8888_GrPixelConfig; 142 dummyDesc.fWidth = 34; 143 dummyDesc.fHeight = 18; 144 SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0)); 145 dummyDesc.fFlags = kNone_GrTextureFlags; 146 dummyDesc.fConfig = kAlpha_8_GrPixelConfig; 147 dummyDesc.fWidth = 16; 148 dummyDesc.fHeight = 22; 149 SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0)); 150 151 if (!dummyTexture1 || ! dummyTexture2) { 152 return false; 153 } 154 155 static const int NUM_TESTS = 512; 156 157 SkRandom random; 158 for (int t = 0; t < NUM_TESTS; ++t) { 159 160#if 0 161 GrPrintf("\nTest Program %d\n-------------\n", t); 162 static const int stop = -1; 163 if (t == stop) { 164 int breakpointhere = 9; 165 } 166#endif 167 168 GrGLProgramDesc pdesc; 169 170 int currAttribIndex = 1; // we need to always leave room for position 171 int currTextureCoordSet = 0; 172 int attribIndices[2] = { 0, 0 }; 173 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()}; 174 175 int numStages = random.nextULessThan(maxStages + 1); 176 int numColorStages = random.nextULessThan(numStages + 1); 177 int numCoverageStages = numStages - numColorStages; 178 179 SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages); 180 181 bool useFixedFunctionPathRendering = this->glCaps().pathRenderingSupport() && 182 this->glPathRendering()->texturingMode() == GrGLPathRendering::FixedFunction_TexturingMode; 183 184 for (int s = 0; s < numStages;) { 185 SkAutoTUnref<const GrEffect> effect(GrEffectTestFactory::CreateStage( 186 &random, 187 this->getContext(), 188 *this->caps(), 189 dummyTextures)); 190 SkASSERT(effect); 191 int numAttribs = effect->numVertexAttribs(); 192 193 // If adding this effect would exceed the max attrib count then generate a 194 // new random effect. 195 if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) { 196 continue; 197 } 198 199 200 // If adding this effect would exceed the max texture coord set count then generate a 201 // new random effect. 202 if (useFixedFunctionPathRendering && !effect->requiresVertexShader()) { 203 int numTransforms = effect->numTransforms(); 204 if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) { 205 continue; 206 } 207 currTextureCoordSet += numTransforms; 208 } 209 210 useFixedFunctionPathRendering = useFixedFunctionPathRendering && !effect->requiresVertexShader(); 211 212 for (int i = 0; i < numAttribs; ++i) { 213 attribIndices[i] = currAttribIndex++; 214 } 215 GrEffectStage* stage = SkNEW_ARGS(GrEffectStage, 216 (effect.get(), attribIndices[0], attribIndices[1])); 217 stages[s] = stage; 218 ++s; 219 } 220 const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1]; 221 if (!pdesc.setRandom(&random, 222 this, 223 dummyTextures[0]->asRenderTarget(), 224 dstTexture, 225 stages.get(), 226 numColorStages, 227 numCoverageStages, 228 currAttribIndex)) { 229 return false; 230 } 231 232 SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this, 233 pdesc, 234 stages, 235 stages + numColorStages)); 236 for (int s = 0; s < numStages; ++s) { 237 SkDELETE(stages[s]); 238 } 239 if (NULL == program.get()) { 240 return false; 241 } 242 } 243 return true; 244} 245 246DEF_GPUTEST(GLPrograms, reporter, factory) { 247 for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) { 248 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type)); 249 if (NULL != context) { 250 GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu()); 251 int maxStages = 6; 252#if SK_ANGLE 253 // Some long shaders run out of temporary registers in the D3D compiler on ANGLE. 254 if (type == GrContextFactory::kANGLE_GLContextType) { 255 maxStages = 3; 256 } 257#endif 258 REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages)); 259 } 260 } 261} 262 263// This is evil evil evil. The linker may throw away whole translation units as dead code if it 264// thinks none of the functions are called. It will do this even if there are static initializers 265// in the unit that could pass pointers to functions from the unit out to other translation units! 266// We force some of the effects that would otherwise be discarded to link here. 267 268#include "SkAlphaThresholdFilter.h" 269#include "SkColorMatrixFilter.h" 270#include "SkLightingImageFilter.h" 271#include "SkMagnifierImageFilter.h" 272 273void forceLinking(); 274 275void forceLinking() { 276 SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0); 277 SkAlphaThresholdFilter::Create(SkRegion(), .5f, .5f); 278 SkAutoTUnref<SkImageFilter> mag(SkMagnifierImageFilter::Create( 279 SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1)); 280 GrConfigConversionEffect::Create(NULL, 281 false, 282 GrConfigConversionEffect::kNone_PMConversion, 283 SkMatrix::I()); 284 SkScalar matrix[20]; 285 SkAutoTUnref<SkColorMatrixFilter> cmf(SkColorMatrixFilter::Create(matrix)); 286} 287 288#endif 289